]> git.karo-electronics.de Git - mv-sheeva.git/commitdiff
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/djbw/async_tx
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 30 May 2010 16:12:43 +0000 (09:12 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 30 May 2010 16:12:43 +0000 (09:12 -0700)
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/djbw/async_tx:
  DMAENGINE: DMA40 U8500 platform configuration
  DMA: PL330: Add dma api driver

2079 files changed:
Documentation/ABI/testing/sysfs-bus-pci
Documentation/ABI/testing/sysfs-class-power [new file with mode: 0644]
Documentation/ABI/testing/sysfs-devices-node [new file with mode: 0644]
Documentation/ABI/testing/sysfs-firmware-sfi [new file with mode: 0644]
Documentation/DMA-API-HOWTO.txt
Documentation/DocBook/mtdnand.tmpl
Documentation/PCI/pcieaer-howto.txt
Documentation/SubmitChecklist
Documentation/SubmittingDrivers
Documentation/acpi/apei/einj.txt [new file with mode: 0644]
Documentation/arm/Samsung-S3C24XX/GPIO.txt
Documentation/arm/Samsung-S3C24XX/Overview.txt
Documentation/arm/Samsung/GPIO.txt [new file with mode: 0644]
Documentation/arm/Samsung/Overview.txt
Documentation/cgroups/cgroups.txt
Documentation/cgroups/memory.txt
Documentation/development-process/2.Process
Documentation/development-process/7.AdvancedTopics
Documentation/devices.txt
Documentation/feature-removal-schedule.txt
Documentation/filesystems/Locking
Documentation/filesystems/squashfs.txt
Documentation/filesystems/tmpfs.txt
Documentation/filesystems/vfs.txt
Documentation/filesystems/xfs-delayed-logging-design.txt [new file with mode: 0644]
Documentation/hwmon/dme1737
Documentation/hwmon/lm63
Documentation/hwmon/ltc4245
Documentation/hwmon/sysfs-interface
Documentation/hwmon/tmp102 [new file with mode: 0644]
Documentation/kernel-parameters.txt
Documentation/kvm/api.txt
Documentation/kvm/cpuid.txt [new file with mode: 0644]
Documentation/kvm/mmu.txt [new file with mode: 0644]
Documentation/laptops/thinkpad-acpi.txt
Documentation/oops-tracing.txt
Documentation/power/pci.txt
Documentation/spi/ep93xx_spi [new file with mode: 0644]
Documentation/spi/spidev_fdx.c
Documentation/sysctl/vm.txt
Documentation/timers/hpet_example.c
Documentation/vm/map_hugetlb.c
Documentation/vm/numa
Documentation/watchdog/00-INDEX
Documentation/watchdog/watchdog-parameters.txt [new file with mode: 0644]
Documentation/watchdog/wdt.txt
MAINTAINERS
arch/alpha/Kconfig
arch/alpha/include/asm/bitops.h
arch/alpha/include/asm/scatterlist.h
arch/alpha/kernel/time.c
arch/alpha/mm/fault.c
arch/arm/Kconfig
arch/arm/Makefile
arch/arm/boot/bootp/bootp.lds
arch/arm/configs/mx51_defconfig
arch/arm/configs/s3c2410_defconfig
arch/arm/configs/s3c6400_defconfig
arch/arm/configs/s5p6440_defconfig
arch/arm/configs/s5p6442_defconfig
arch/arm/configs/s5pc100_defconfig
arch/arm/configs/s5pc110_defconfig
arch/arm/configs/s5pv210_defconfig
arch/arm/include/asm/hardirq.h
arch/arm/include/asm/scatterlist.h
arch/arm/kernel/setup.c
arch/arm/kernel/unwind.c
arch/arm/mach-at91/board-sam9m10g45ek.c
arch/arm/mach-clps711x/Makefile.boot
arch/arm/mach-davinci/include/mach/mmc.h
arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h [new file with mode: 0644]
arch/arm/mach-footbridge/ebsa285-pci.c
arch/arm/mach-h720x/common.h
arch/arm/mach-msm/board-msm7x27.c
arch/arm/mach-msm/board-msm7x30.c
arch/arm/mach-msm/board-qsd8x50.c
arch/arm/mach-mx2/devices.c
arch/arm/mach-mx2/mach-pca100.c
arch/arm/mach-mx2/mach-pcm038.c
arch/arm/mach-mx25/devices.c
arch/arm/mach-mx25/devices.h
arch/arm/mach-mx3/Kconfig
arch/arm/mach-mx3/devices.c
arch/arm/mach-mx3/devices.h
arch/arm/mach-mx3/mach-mx31_3ds.c
arch/arm/mach-mx3/mach-mx31lilly.c
arch/arm/mach-mx3/mach-mx31moboard.c
arch/arm/mach-mx3/mach-pcm037.c
arch/arm/mach-mx3/mach-pcm043.c
arch/arm/mach-mx3/mx31lite-db.c
arch/arm/mach-mx3/mx31moboard-devboard.c
arch/arm/mach-mx3/mx31moboard-marxbot.c
arch/arm/mach-mx3/mx31moboard-smartbot.c
arch/arm/mach-mx5/board-mx51_babbage.c
arch/arm/mach-mx5/clock-mx51.c
arch/arm/mach-mx5/devices.c
arch/arm/mach-mx5/devices.h
arch/arm/mach-nomadik/clock.c
arch/arm/mach-omap2/board-3430sdp.c
arch/arm/mach-omap2/board-ldp.c
arch/arm/mach-omap2/board-omap3evm.c
arch/arm/mach-omap2/board-omap3pandora.c
arch/arm/mach-omap2/board-omap3touchbook.c
arch/arm/mach-orion5x/dns323-setup.c
arch/arm/mach-s3c2410/include/mach/map.h
arch/arm/mach-s3c2440/mach-gta02.c
arch/arm/mach-s3c64xx/Kconfig
arch/arm/mach-s3c64xx/Makefile
arch/arm/mach-s3c64xx/clock.c
arch/arm/mach-s3c64xx/dev-onenand1.c [new file with mode: 0644]
arch/arm/mach-s3c64xx/include/mach/irqs.h
arch/arm/mach-s3c64xx/include/mach/map.h
arch/arm/mach-s3c64xx/mach-smartq.c [new file with mode: 0644]
arch/arm/mach-s3c64xx/mach-smartq.h [new file with mode: 0644]
arch/arm/mach-s3c64xx/mach-smartq5.c [new file with mode: 0644]
arch/arm/mach-s3c64xx/mach-smartq7.c [new file with mode: 0644]
arch/arm/mach-s3c64xx/mach-smdk6410.c
arch/arm/mach-s3c64xx/pm.c
arch/arm/mach-s3c64xx/s3c6400.c
arch/arm/mach-s3c64xx/s3c6410.c
arch/arm/mach-s5p6440/Kconfig
arch/arm/mach-s5p6440/Makefile
arch/arm/mach-s5p6440/cpu.c
arch/arm/mach-s5p6440/dev-spi.c [new file with mode: 0644]
arch/arm/mach-s5p6440/gpio.c
arch/arm/mach-s5p6440/include/mach/irqs.h
arch/arm/mach-s5p6440/include/mach/map.h
arch/arm/mach-s5p6440/include/mach/spi-clocks.h [new file with mode: 0644]
arch/arm/mach-s5p6440/mach-smdk6440.c
arch/arm/mach-s5p6442/Makefile
arch/arm/mach-s5p6442/dev-spi.c [new file with mode: 0644]
arch/arm/mach-s5p6442/include/mach/irqs.h
arch/arm/mach-s5p6442/include/mach/map.h
arch/arm/mach-s5p6442/include/mach/spi-clocks.h [new file with mode: 0644]
arch/arm/mach-s5pc100/Kconfig
arch/arm/mach-s5pc100/Makefile
arch/arm/mach-s5pc100/cpu.c
arch/arm/mach-s5pc100/dev-audio.c [new file with mode: 0644]
arch/arm/mach-s5pc100/dev-spi.c [new file with mode: 0644]
arch/arm/mach-s5pc100/dma.c [new file with mode: 0644]
arch/arm/mach-s5pc100/gpiolib.c
arch/arm/mach-s5pc100/include/mach/debug-macro.S
arch/arm/mach-s5pc100/include/mach/dma.h [new file with mode: 0644]
arch/arm/mach-s5pc100/include/mach/entry-macro.S
arch/arm/mach-s5pc100/include/mach/gpio.h
arch/arm/mach-s5pc100/include/mach/irqs.h
arch/arm/mach-s5pc100/include/mach/map.h
arch/arm/mach-s5pc100/include/mach/regs-clock.h
arch/arm/mach-s5pc100/include/mach/regs-gpio.h
arch/arm/mach-s5pc100/include/mach/regs-irq.h
arch/arm/mach-s5pc100/include/mach/spi-clocks.h [new file with mode: 0644]
arch/arm/mach-s5pc100/include/mach/system.h
arch/arm/mach-s5pc100/include/mach/tick.h
arch/arm/mach-s5pc100/init.c [moved from arch/arm/plat-s5pc1xx/s5pc100-init.c with 68% similarity]
arch/arm/mach-s5pc100/irq-gpio.c [moved from arch/arm/plat-s5pc1xx/irq-gpio.c with 72% similarity]
arch/arm/mach-s5pc100/mach-smdkc100.c
arch/arm/mach-s5pc100/setup-sdhci-gpio.c [moved from arch/arm/plat-s5pc1xx/setup-sdhci-gpio.c with 95% similarity]
arch/arm/mach-s5pv210/Kconfig
arch/arm/mach-s5pv210/Makefile
arch/arm/mach-s5pv210/cpu.c
arch/arm/mach-s5pv210/dev-onenand.c [new file with mode: 0644]
arch/arm/mach-s5pv210/dev-spi.c [new file with mode: 0644]
arch/arm/mach-s5pv210/include/mach/irqs.h
arch/arm/mach-s5pv210/include/mach/map.h
arch/arm/mach-s5pv210/include/mach/regs-clock.h
arch/arm/mach-s5pv210/include/mach/regs-fb.h [new file with mode: 0644]
arch/arm/mach-s5pv210/include/mach/regs-gpio.h [new file with mode: 0644]
arch/arm/mach-s5pv210/include/mach/spi-clocks.h [new file with mode: 0644]
arch/arm/mach-s5pv210/mach-aquila.c [new file with mode: 0644]
arch/arm/mach-s5pv210/mach-goni.c [new file with mode: 0644]
arch/arm/mach-s5pv210/mach-smdkc110.c
arch/arm/mach-s5pv210/mach-smdkv210.c
arch/arm/mach-s5pv210/setup-fb-24bpp.c [new file with mode: 0644]
arch/arm/mach-s5pv210/setup-i2c0.c
arch/arm/mach-s5pv210/setup-i2c1.c [new file with mode: 0644]
arch/arm/mach-s5pv210/setup-i2c2.c [new file with mode: 0644]
arch/arm/mach-s5pv210/setup-sdhci-gpio.c [new file with mode: 0644]
arch/arm/mach-s5pv210/setup-sdhci.c [new file with mode: 0644]
arch/arm/mach-sa1100/leds.c
arch/arm/mach-shark/pci.c
arch/arm/mach-spear6xx/spear6xx.c
arch/arm/mach-w90x900/dev.c
arch/arm/mach-w90x900/include/mach/mfp.h [new file with mode: 0644]
arch/arm/mach-w90x900/mfp.c
arch/arm/mm/cache-v7.S
arch/arm/nwfpe/ChangeLog
arch/arm/nwfpe/fpsr.h
arch/arm/plat-mxc/ehci.c
arch/arm/plat-mxc/gpio.c
arch/arm/plat-mxc/include/mach/board-mx31moboard.h
arch/arm/plat-mxc/include/mach/iomux-mx3.h
arch/arm/plat-mxc/include/mach/iomux-mx51.h
arch/arm/plat-mxc/include/mach/mxc_ehci.h
arch/arm/plat-mxc/time.c
arch/arm/plat-mxc/tzic.c
arch/arm/plat-omap/gpio.c
arch/arm/plat-s3c24xx/devs.c
arch/arm/plat-s5p/Kconfig
arch/arm/plat-s5p/Makefile
arch/arm/plat-s5p/clock.c
arch/arm/plat-s5p/cpu.c
arch/arm/plat-s5p/include/plat/irqs.h
arch/arm/plat-s5p/include/plat/s5pc100.h [new file with mode: 0644]
arch/arm/plat-s5p/irq-eint.c [new file with mode: 0644]
arch/arm/plat-s5pc1xx/Kconfig [deleted file]
arch/arm/plat-s5pc1xx/Makefile [deleted file]
arch/arm/plat-s5pc1xx/clock.c [deleted file]
arch/arm/plat-s5pc1xx/cpu.c [deleted file]
arch/arm/plat-s5pc1xx/dev-uart.c [deleted file]
arch/arm/plat-s5pc1xx/include/plat/gpio-ext.h [deleted file]
arch/arm/plat-s5pc1xx/include/plat/irqs.h [deleted file]
arch/arm/plat-s5pc1xx/include/plat/pll.h [deleted file]
arch/arm/plat-s5pc1xx/include/plat/regs-clock.h [deleted file]
arch/arm/plat-s5pc1xx/include/plat/regs-power.h [deleted file]
arch/arm/plat-s5pc1xx/include/plat/s5pc100.h [deleted file]
arch/arm/plat-s5pc1xx/irq-eint.c [deleted file]
arch/arm/plat-s5pc1xx/irq.c [deleted file]
arch/arm/plat-s5pc1xx/s5pc100-clock.c [deleted file]
arch/arm/plat-samsung/Kconfig
arch/arm/plat-samsung/Makefile
arch/arm/plat-samsung/adc.c
arch/arm/plat-samsung/dev-i2c2.c [new file with mode: 0644]
arch/arm/plat-samsung/dev-onenand.c [new file with mode: 0644]
arch/arm/plat-samsung/dev-wdt.c [new file with mode: 0644]
arch/arm/plat-samsung/include/plat/devs.h
arch/arm/plat-samsung/include/plat/fb.h
arch/arm/plat-samsung/include/plat/gpio-cfg.h
arch/arm/plat-samsung/include/plat/iic-core.h
arch/arm/plat-samsung/include/plat/iic.h
arch/arm/plat-samsung/include/plat/onenand-core.h [new file with mode: 0644]
arch/arm/plat-samsung/include/plat/regs-onenand.h [new file with mode: 0644]
arch/arm/plat-samsung/include/plat/regs-rtc.h
arch/arm/plat-samsung/include/plat/s3c64xx-spi.h
arch/arm/plat-samsung/include/plat/sdhci.h
arch/arm/plat-samsung/include/plat/wakeup-mask.h [new file with mode: 0644]
arch/arm/plat-samsung/pm-gpio.c
arch/arm/plat-samsung/wakeup-mask.c [new file with mode: 0644]
arch/avr32/include/asm/scatterlist.h
arch/blackfin/Kconfig
arch/blackfin/Kconfig.debug
arch/blackfin/include/asm/bfin-global.h
arch/blackfin/include/asm/bug.h
arch/blackfin/include/asm/cache.h
arch/blackfin/include/asm/gpio.h
arch/blackfin/include/asm/pgtable.h
arch/blackfin/include/asm/pseudo_instructions.h [new file with mode: 0644]
arch/blackfin/include/asm/scatterlist.h
arch/blackfin/include/asm/string.h
arch/blackfin/include/asm/tlbflush.h
arch/blackfin/include/asm/trace.h
arch/blackfin/kernel/Makefile
arch/blackfin/kernel/bfin_gpio.c
arch/blackfin/kernel/bfin_ksyms.c
arch/blackfin/kernel/dumpstack.c [new file with mode: 0644]
arch/blackfin/kernel/exception.c [new file with mode: 0644]
arch/blackfin/kernel/kgdb.c
arch/blackfin/kernel/pseudodbg.c [new file with mode: 0644]
arch/blackfin/kernel/ptrace.c
arch/blackfin/kernel/setup.c
arch/blackfin/kernel/sys_bfin.c
arch/blackfin/kernel/trace.c [new file with mode: 0644]
arch/blackfin/kernel/traps.c
arch/blackfin/lib/memset.S
arch/blackfin/lib/strcmp.S [new file with mode: 0644]
arch/blackfin/lib/strcmp.c [deleted file]
arch/blackfin/lib/strcpy.S [new file with mode: 0644]
arch/blackfin/lib/strcpy.c [deleted file]
arch/blackfin/lib/strncmp.S [new file with mode: 0644]
arch/blackfin/lib/strncmp.c [deleted file]
arch/blackfin/lib/strncpy.S [new file with mode: 0644]
arch/blackfin/lib/strncpy.c [deleted file]
arch/blackfin/mach-bf527/boards/cm_bf527.c
arch/blackfin/mach-bf527/boards/ezbrd.c
arch/blackfin/mach-bf527/boards/ezkit.c
arch/blackfin/mach-bf537/boards/minotaur.c
arch/blackfin/mach-bf537/include/mach/defBF534.h
arch/blackfin/mach-bf537/include/mach/irq.h
arch/blackfin/mach-bf538/include/mach/defBF539.h
arch/blackfin/mach-bf548/boards/cm_bf548.c
arch/blackfin/mach-bf548/boards/ezkit.c
arch/blackfin/mach-bf548/include/mach/defBF54x_base.h
arch/blackfin/mach-bf561/boards/acvilon.c
arch/blackfin/mach-common/ints-priority.c
arch/blackfin/mach-common/pm.c
arch/blackfin/mach-common/smp.c
arch/blackfin/mm/init.c
arch/blackfin/mm/isram-driver.c
arch/blackfin/mm/sram-alloc.c
arch/cris/arch-v10/drivers/eeprom.c
arch/cris/include/asm/scatterlist.h
arch/frv/include/asm/gdb-stub.h
arch/frv/include/asm/mem-layout.h
arch/frv/include/asm/scatterlist.h
arch/frv/kernel/gdb-io.c
arch/frv/kernel/gdb-stub.c
arch/frv/kernel/ptrace.c
arch/frv/kernel/sysctl.c
arch/h8300/include/asm/scatterlist.h
arch/ia64/Kconfig
arch/ia64/include/asm/acpi.h
arch/ia64/include/asm/scatterlist.h
arch/ia64/include/asm/topology.h
arch/ia64/kernel/pci-swiotlb.c
arch/ia64/kernel/ptrace.c
arch/ia64/kernel/smpboot.c
arch/ia64/kvm/kvm-ia64.c
arch/ia64/kvm/vmm.c
arch/ia64/mm/numa.c
arch/ia64/pci/pci.c
arch/ia64/sn/kernel/sn2/sn_hwperf.c
arch/m32r/include/asm/scatterlist.h
arch/m68k/Kconfig
arch/m68k/amiga/config.c
arch/m68k/amiga/platform.c
arch/m68k/include/asm/amigayle.h
arch/m68k/include/asm/atomic.h
arch/m68k/include/asm/cache.h
arch/m68k/include/asm/m520xsim.h
arch/m68k/include/asm/m523xsim.h
arch/m68k/include/asm/m5249sim.h
arch/m68k/include/asm/m527xsim.h
arch/m68k/include/asm/m528xsim.h
arch/m68k/include/asm/m532xsim.h
arch/m68k/include/asm/mcfqspi.h [new file with mode: 0644]
arch/m68k/include/asm/mcfsmc.h [deleted file]
arch/m68k/include/asm/processor.h
arch/m68k/include/asm/scatterlist.h
arch/m68knommu/Kconfig
arch/m68knommu/mm/fault.c
arch/m68knommu/platform/520x/config.c
arch/m68knommu/platform/523x/config.c
arch/m68knommu/platform/5249/config.c
arch/m68knommu/platform/527x/config.c
arch/m68knommu/platform/528x/config.c
arch/m68knommu/platform/5307/Makefile
arch/m68knommu/platform/5307/nettel.c [new file with mode: 0644]
arch/m68knommu/platform/532x/config.c
arch/m68knommu/platform/68360/commproc.c
arch/microblaze/include/asm/device.h
arch/microblaze/include/asm/of_device.h
arch/microblaze/include/asm/scatterlist.h
arch/microblaze/kernel/of_device.c
arch/microblaze/kernel/of_platform.c
arch/mips/include/asm/scatterlist.h
arch/mn10300/include/asm/atomic.h
arch/mn10300/include/asm/cache.h
arch/mn10300/include/asm/scatterlist.h
arch/parisc/Kconfig
arch/parisc/include/asm/bug.h
arch/parisc/include/asm/cacheflush.h
arch/parisc/include/asm/scatterlist.h
arch/parisc/kernel/asm-offsets.c
arch/parisc/kernel/entry.S
arch/parisc/kernel/syscall.S
arch/parisc/math-emu/decode_exc.c
arch/parisc/mm/fault.c
arch/powerpc/Kconfig
arch/powerpc/include/asm/asm-compat.h
arch/powerpc/include/asm/bug.h
arch/powerpc/include/asm/device.h
arch/powerpc/include/asm/kvm.h
arch/powerpc/include/asm/kvm_asm.h
arch/powerpc/include/asm/kvm_book3s.h
arch/powerpc/include/asm/kvm_book3s_32.h [new file with mode: 0644]
arch/powerpc/include/asm/kvm_book3s_64.h [new file with mode: 0644]
arch/powerpc/include/asm/kvm_book3s_asm.h [moved from arch/powerpc/include/asm/kvm_book3s_64_asm.h with 82% similarity]
arch/powerpc/include/asm/kvm_booke.h [new file with mode: 0644]
arch/powerpc/include/asm/kvm_fpu.h [new file with mode: 0644]
arch/powerpc/include/asm/kvm_host.h
arch/powerpc/include/asm/kvm_ppc.h
arch/powerpc/include/asm/macio.h
arch/powerpc/include/asm/mmu_context.h
arch/powerpc/include/asm/mpc52xx_psc.h
arch/powerpc/include/asm/of_device.h
arch/powerpc/include/asm/paca.h
arch/powerpc/include/asm/processor.h
arch/powerpc/include/asm/reg.h
arch/powerpc/include/asm/scatterlist.h
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kernel/dma-swiotlb.c
arch/powerpc/kernel/dma.c
arch/powerpc/kernel/head_32.S
arch/powerpc/kernel/head_64.S
arch/powerpc/kernel/ibmebus.c
arch/powerpc/kernel/of_device.c
arch/powerpc/kernel/of_platform.c
arch/powerpc/kernel/pci-common.c
arch/powerpc/kernel/ppc_ksyms.c
arch/powerpc/kernel/vio.c
arch/powerpc/kvm/44x.c
arch/powerpc/kvm/Kconfig
arch/powerpc/kvm/Makefile
arch/powerpc/kvm/book3s.c
arch/powerpc/kvm/book3s_32_mmu.c
arch/powerpc/kvm/book3s_32_mmu_host.c [new file with mode: 0644]
arch/powerpc/kvm/book3s_32_sr.S [new file with mode: 0644]
arch/powerpc/kvm/book3s_64_mmu.c
arch/powerpc/kvm/book3s_64_mmu_host.c
arch/powerpc/kvm/book3s_64_slb.S
arch/powerpc/kvm/book3s_emulate.c [moved from arch/powerpc/kvm/book3s_64_emulate.c with 58% similarity]
arch/powerpc/kvm/book3s_exports.c [moved from arch/powerpc/kvm/book3s_64_exports.c with 100% similarity]
arch/powerpc/kvm/book3s_interrupts.S [moved from arch/powerpc/kvm/book3s_64_interrupts.S with 62% similarity]
arch/powerpc/kvm/book3s_paired_singles.c [new file with mode: 0644]
arch/powerpc/kvm/book3s_rmhandlers.S [moved from arch/powerpc/kvm/book3s_64_rmhandlers.S with 62% similarity]
arch/powerpc/kvm/book3s_segment.S [new file with mode: 0644]
arch/powerpc/kvm/booke.c
arch/powerpc/kvm/e500.c
arch/powerpc/kvm/emulate.c
arch/powerpc/kvm/fpu.S [new file with mode: 0644]
arch/powerpc/kvm/powerpc.c
arch/powerpc/mm/mmu_context_hash32.c
arch/powerpc/platforms/512x/mpc512x_shared.c
arch/powerpc/platforms/52xx/mpc52xx_gpio.c
arch/powerpc/platforms/52xx/mpc52xx_gpt.c
arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c
arch/powerpc/platforms/82xx/ep8248e.c
arch/powerpc/platforms/83xx/suspend.c
arch/powerpc/platforms/cell/axon_msi.c
arch/powerpc/platforms/cell/iommu.c
arch/powerpc/platforms/cell/spufs/file.c
arch/powerpc/platforms/cell/spufs/inode.c
arch/powerpc/platforms/pasemi/gpio_mdio.c
arch/powerpc/platforms/pasemi/setup.c
arch/powerpc/platforms/ps3/system-bus.c
arch/powerpc/platforms/pseries/hvCall_inst.c
arch/powerpc/platforms/pseries/iommu.c
arch/powerpc/sysdev/axonram.c
arch/powerpc/sysdev/bestcomm/bestcomm.c
arch/powerpc/sysdev/fsl_msi.c
arch/powerpc/sysdev/fsl_pmc.c
arch/powerpc/sysdev/fsl_rio.c
arch/powerpc/sysdev/pmi.c
arch/powerpc/sysdev/qe_lib/qe.c
arch/s390/Kconfig
arch/s390/boot/compressed/Makefile
arch/s390/boot/compressed/misc.c
arch/s390/include/asm/atomic.h
arch/s390/include/asm/bug.h
arch/s390/include/asm/ccwdev.h
arch/s390/include/asm/scatterlist.h
arch/s390/kernel/asm-offsets.c
arch/s390/kernel/entry64.S
arch/s390/kernel/kprobes.c
arch/s390/kernel/setup.c
arch/s390/kernel/smp.c
arch/s390/kvm/Kconfig
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/kvm-s390.h
arch/s390/kvm/sie64a.S
arch/s390/mm/cmm.c
arch/score/include/asm/scatterlist.h
arch/sh/Kconfig
arch/sh/boards/mach-ecovec24/setup.c
arch/sh/boards/mach-kfr2r09/setup.c
arch/sh/boards/mach-migor/setup.c
arch/sh/boards/mach-se/7724/setup.c
arch/sh/configs/sh7785lcr_32bit_defconfig
arch/sh/include/asm/bug.h
arch/sh/include/asm/dmaengine.h [deleted file]
arch/sh/include/asm/siu.h
arch/sh/include/cpu-sh4/cpu/sh7722.h
arch/sh/include/cpu-sh4/cpu/sh7724.h
arch/sh/kernel/cpu/sh4a/clock-sh7786.c
arch/sh/kernel/cpu/sh4a/setup-sh7722.c
arch/sh/kernel/cpu/sh4a/setup-sh7724.c
arch/sh/kernel/cpu/sh4a/setup-sh7780.c
arch/sh/kernel/cpu/sh4a/setup-sh7785.c
arch/sh/kernel/cpu/sh4a/setup-sh7786.c
arch/sh/kernel/dwarf.c
arch/sh/kernel/ptrace_32.c
arch/sh/lib/strlen.S
arch/sparc/Kconfig
arch/sparc/include/asm/device.h
arch/sparc/include/asm/fb.h
arch/sparc/include/asm/floppy_64.h
arch/sparc/include/asm/of_device.h
arch/sparc/include/asm/parport.h
arch/sparc/include/asm/scatterlist.h
arch/sparc/kernel/apc.c
arch/sparc/kernel/auxio_64.c
arch/sparc/kernel/central.c
arch/sparc/kernel/chmc.c
arch/sparc/kernel/ioport.c
arch/sparc/kernel/of_device_32.c
arch/sparc/kernel/of_device_64.c
arch/sparc/kernel/of_device_common.c
arch/sparc/kernel/pci.c
arch/sparc/kernel/pci_common.c
arch/sparc/kernel/pci_fire.c
arch/sparc/kernel/pci_msi.c
arch/sparc/kernel/pci_psycho.c
arch/sparc/kernel/pci_sabre.c
arch/sparc/kernel/pci_schizo.c
arch/sparc/kernel/pci_sun4v.c
arch/sparc/kernel/perf_event.c
arch/sparc/kernel/pmc.c
arch/sparc/kernel/power.c
arch/sparc/kernel/psycho_common.c
arch/sparc/kernel/sbus.c
arch/sparc/kernel/time_32.c
arch/sparc/kernel/time_64.c
arch/um/drivers/harddog_kern.c
arch/um/drivers/hostaudio_kern.c
arch/um/drivers/mmapper_kern.c
arch/x86/Kconfig
arch/x86/include/asm/acpi.h
arch/x86/include/asm/cpufeature.h
arch/x86/include/asm/intel_scu_ipc.h [new file with mode: 0644]
arch/x86/include/asm/kvm.h
arch/x86/include/asm/kvm_emulate.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/kvm_para.h
arch/x86/include/asm/mce.h
arch/x86/include/asm/msr-index.h
arch/x86/include/asm/pci_x86.h
arch/x86/include/asm/perf_event_p4.h
arch/x86/include/asm/pvclock-abi.h
arch/x86/include/asm/pvclock.h
arch/x86/include/asm/scatterlist.h
arch/x86/include/asm/svm.h
arch/x86/include/asm/thread_info.h
arch/x86/include/asm/topology.h
arch/x86/include/asm/vmx.h
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/acpi/sleep.c
arch/x86/kernel/apic/apic.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/cpufreq/powernow-k8.c
arch/x86/kernel/cpu/mcheck/Makefile
arch/x86/kernel/cpu/mcheck/mce-apei.c [new file with mode: 0644]
arch/x86/kernel/cpu/mcheck/mce-internal.h
arch/x86/kernel/cpu/mcheck/mce.c
arch/x86/kernel/cpu/mcheck/therm_throt.c
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/cpu/perf_event_p4.c
arch/x86/kernel/cpuid.c
arch/x86/kernel/kvmclock.c
arch/x86/kernel/microcode_core.c
arch/x86/kernel/msr.c
arch/x86/kernel/pci-swiotlb.c
arch/x86/kernel/pvclock.c
arch/x86/kernel/setup.c
arch/x86/kernel/setup_percpu.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/tboot.c
arch/x86/kvm/emulate.c
arch/x86/kvm/i8259.c
arch/x86/kvm/irq.h
arch/x86/kvm/kvm_timer.h
arch/x86/kvm/mmu.c
arch/x86/kvm/mmutrace.h
arch/x86/kvm/paging_tmpl.h
arch/x86/kvm/svm.c
arch/x86/kvm/timer.c
arch/x86/kvm/trace.h
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/kvm/x86.h
arch/x86/lguest/boot.c
arch/x86/mm/numa_64.c
arch/x86/mm/pat.c
arch/x86/mm/pat_internal.h
arch/x86/mm/pat_rbtree.c
arch/x86/mm/pf_in.c
arch/x86/mm/pgtable_32.c
arch/x86/pci/Makefile
arch/x86/pci/acpi.c
arch/x86/pci/broadcom_bus.c [new file with mode: 0644]
arch/x86/pci/common.c
arch/x86/pci/direct.c
arch/x86/pci/irq.c
arch/x86/pci/mmconfig-shared.c
arch/x86/pci/mmconfig_32.c
arch/x86/pci/numaq_32.c
arch/x86/pci/pcbios.c
arch/xtensa/include/asm/cache.h
arch/xtensa/include/asm/hardirq.h
arch/xtensa/include/asm/scatterlist.h
arch/xtensa/kernel/irq.c
arch/xtensa/kernel/vectors.S
drivers/Makefile
drivers/acpi/Kconfig
drivers/acpi/Makefile
drivers/acpi/acpi_pad.c
drivers/acpi/acpica/evxfevnt.c
drivers/acpi/acpica/hwacpi.c
drivers/acpi/apei/Kconfig [new file with mode: 0644]
drivers/acpi/apei/Makefile [new file with mode: 0644]
drivers/acpi/apei/apei-base.c [new file with mode: 0644]
drivers/acpi/apei/apei-internal.h [new file with mode: 0644]
drivers/acpi/apei/cper.c [new file with mode: 0644]
drivers/acpi/apei/einj.c [new file with mode: 0644]
drivers/acpi/apei/erst.c [new file with mode: 0644]
drivers/acpi/apei/ghes.c [new file with mode: 0644]
drivers/acpi/apei/hest.c [new file with mode: 0644]
drivers/acpi/atomicio.c [new file with mode: 0644]
drivers/acpi/bus.c
drivers/acpi/ec.c
drivers/acpi/hed.c [new file with mode: 0644]
drivers/acpi/hest.c [deleted file]
drivers/acpi/osl.c
drivers/acpi/pci_root.c
drivers/acpi/processor_driver.c
drivers/acpi/processor_idle.c
drivers/acpi/sleep.c
drivers/acpi/sleep.h
drivers/acpi/tables.c
drivers/acpi/video.c
drivers/acpi/video_detect.c
drivers/ata/Kconfig
drivers/ata/Makefile
drivers/ata/ata_generic.c
drivers/ata/ata_piix.c
drivers/ata/libata-core.c
drivers/ata/libata-sff.c
drivers/ata/pata_acpi.c
drivers/ata/pata_ali.c
drivers/ata/pata_amd.c
drivers/ata/pata_artop.c
drivers/ata/pata_atiixp.c
drivers/ata/pata_atp867x.c
drivers/ata/pata_bf54x.c
drivers/ata/pata_cmd64x.c
drivers/ata/pata_cs5520.c
drivers/ata/pata_cs5530.c
drivers/ata/pata_cs5535.c
drivers/ata/pata_cs5536.c
drivers/ata/pata_cypress.c
drivers/ata/pata_efar.c
drivers/ata/pata_hpt366.c
drivers/ata/pata_hpt37x.c
drivers/ata/pata_hpt3x2n.c
drivers/ata/pata_hpt3x3.c
drivers/ata/pata_icside.c
drivers/ata/pata_it8213.c
drivers/ata/pata_it821x.c
drivers/ata/pata_jmicron.c
drivers/ata/pata_macio.c
drivers/ata/pata_marvell.c
drivers/ata/pata_mpc52xx.c
drivers/ata/pata_netcell.c
drivers/ata/pata_ninja32.c
drivers/ata/pata_ns87415.c
drivers/ata/pata_octeon_cf.c
drivers/ata/pata_of_platform.c
drivers/ata/pata_oldpiix.c
drivers/ata/pata_optidma.c
drivers/ata/pata_pdc2027x.c
drivers/ata/pata_pdc202xx_old.c
drivers/ata/pata_piccolo.c
drivers/ata/pata_radisys.c
drivers/ata/pata_rdc.c
drivers/ata/pata_sc1200.c
drivers/ata/pata_scc.c
drivers/ata/pata_sch.c
drivers/ata/pata_serverworks.c
drivers/ata/pata_sil680.c
drivers/ata/pata_sis.c
drivers/ata/pata_sl82c105.c
drivers/ata/pata_triflex.c
drivers/ata/pata_via.c
drivers/ata/sata_fsl.c
drivers/ata/sata_mv.c
drivers/ata/sata_nv.c
drivers/ata/sata_qstor.c
drivers/ata/sata_sil.c
drivers/ata/sata_sis.c
drivers/ata/sata_svw.c
drivers/ata/sata_uli.c
drivers/ata/sata_via.c
drivers/ata/sata_vsc.c
drivers/atm/fore200e.c
drivers/auxdisplay/cfag12864bfb.c
drivers/base/node.c
drivers/base/topology.c
drivers/block/loop.c
drivers/block/swim3.c
drivers/block/virtio_blk.c
drivers/block/xsysace.c
drivers/cdrom/viocd.c
drivers/char/Kconfig
drivers/char/Makefile
drivers/char/agp/amd64-agp.c
drivers/char/amiserial.c
drivers/char/apm-emulation.c
drivers/char/applicom.c
drivers/char/ds1620.c
drivers/char/dtlk.c
drivers/char/generic_nvram.c
drivers/char/genrtc.c
drivers/char/hangcheck-timer.c
drivers/char/hpet.c
drivers/char/hvsi.c
drivers/char/hw_random/n2-drv.c
drivers/char/hw_random/nomadik-rng.c
drivers/char/hw_random/pasemi-rng.c
drivers/char/hw_random/virtio-rng.c
drivers/char/ipmi/ipmi_devintf.c
drivers/char/ipmi/ipmi_msghandler.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/ipmi/ipmi_watchdog.c
drivers/char/misc.c
drivers/char/nvram.c
drivers/char/nwflash.c
drivers/char/ppdev.c
drivers/char/ps3flash.c
drivers/char/ramoops.c [new file with mode: 0644]
drivers/char/raw.c
drivers/char/viotape.c
drivers/char/virtio_console.c
drivers/char/vt.c
drivers/char/xilinx_hwicap/xilinx_hwicap.c
drivers/cpuidle/cpuidle.c
drivers/cpuidle/cpuidle.h
drivers/cpuidle/driver.c
drivers/cpuidle/governors/menu.c
drivers/cpuidle/sysfs.c
drivers/crypto/amcc/crypto4xx_core.c
drivers/crypto/talitos.c
drivers/dma/fsldma.c
drivers/dma/ppc4xx/adma.c
drivers/dma/shdma.c
drivers/dma/timb_dma.c
drivers/edac/amd76x_edac.c
drivers/edac/i5000_edac.c
drivers/edac/i5400_edac.c
drivers/edac/i82443bxgx_edac.c
drivers/edac/mpc85xx_edac.c
drivers/edac/ppc4xx_edac.c
drivers/edac/r82600_edac.c
drivers/firewire/core-card.c
drivers/firewire/core-cdev.c
drivers/firewire/core-transaction.c
drivers/firewire/core.h
drivers/firewire/ohci.c
drivers/firewire/ohci.h
drivers/gpio/Kconfig
drivers/gpio/cs5535-gpio.c
drivers/gpio/gpiolib.c
drivers/gpio/it8761e_gpio.c
drivers/gpio/langwell_gpio.c
drivers/gpio/max732x.c
drivers/gpio/pca953x.c
drivers/gpio/pl061.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nv40_graph.c
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_agp.c
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_state.c
drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/hid-core.c
drivers/hid/hid-debug.c
drivers/hid/hid-gyration.c
drivers/hid/hid-ids.h
drivers/hid/hid-roccat-kone.c
drivers/hid/hid-roccat-kone.h
drivers/hid/hid-roccat.c [new file with mode: 0644]
drivers/hid/hid-roccat.h [new file with mode: 0644]
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/adm1031.c
drivers/hwmon/ads7871.c [new file with mode: 0644]
drivers/hwmon/applesmc.c
drivers/hwmon/asus_atk0110.c
drivers/hwmon/coretemp.c
drivers/hwmon/dme1737.c
drivers/hwmon/emc1403.c [new file with mode: 0644]
drivers/hwmon/f71882fg.c
drivers/hwmon/fschmd.c
drivers/hwmon/lis3lv02d.c
drivers/hwmon/lis3lv02d.h
drivers/hwmon/lm63.c
drivers/hwmon/lm75.c
drivers/hwmon/lm90.c
drivers/hwmon/ltc4245.c
drivers/hwmon/tmp102.c [new file with mode: 0644]
drivers/hwmon/tmp401.c
drivers/hwmon/ultra45_env.c
drivers/hwmon/w83793.c
drivers/i2c/busses/i2c-cpm.c
drivers/i2c/busses/i2c-ibm_iic.c
drivers/i2c/busses/i2c-mpc.c
drivers/i2c/i2c-core.c
drivers/ide/cmd640.c
drivers/ide/gayle.c
drivers/ide/ide_platform.c
drivers/ide/pdc202xx_old.c
drivers/ide/pmac.c
drivers/idle/Kconfig
drivers/idle/Makefile
drivers/idle/intel_idle.c [new file with mode: 0755]
drivers/ieee1394/dv1394.c
drivers/ieee1394/raw1394.c
drivers/ieee1394/video1394.c
drivers/infiniband/Kconfig
drivers/infiniband/Makefile
drivers/infiniband/core/core_priv.h
drivers/infiniband/core/device.c
drivers/infiniband/core/mad.c
drivers/infiniband/core/sysfs.c
drivers/infiniband/core/ucm.c
drivers/infiniband/hw/amso1100/c2_provider.c
drivers/infiniband/hw/cxgb3/iwch_provider.c
drivers/infiniband/hw/cxgb4/cq.c
drivers/infiniband/hw/cxgb4/device.c
drivers/infiniband/hw/cxgb4/iw_cxgb4.h
drivers/infiniband/hw/cxgb4/mem.c
drivers/infiniband/hw/cxgb4/provider.c
drivers/infiniband/hw/cxgb4/qp.c
drivers/infiniband/hw/cxgb4/t4.h
drivers/infiniband/hw/ehca/ehca_irq.c
drivers/infiniband/hw/ehca/ehca_main.c
drivers/infiniband/hw/ipath/Kconfig
drivers/infiniband/hw/ipath/Makefile
drivers/infiniband/hw/ipath/ipath_driver.c
drivers/infiniband/hw/ipath/ipath_iba6120.c [deleted file]
drivers/infiniband/hw/ipath/ipath_iba7220.c [deleted file]
drivers/infiniband/hw/ipath/ipath_kernel.h
drivers/infiniband/hw/ipath/ipath_verbs.c
drivers/infiniband/hw/mlx4/main.c
drivers/infiniband/hw/mthca/mthca_provider.c
drivers/infiniband/hw/nes/nes_hw.c
drivers/infiniband/hw/nes/nes_nic.c
drivers/infiniband/hw/nes/nes_verbs.c
drivers/infiniband/hw/qib/Kconfig [new file with mode: 0644]
drivers/infiniband/hw/qib/Makefile [new file with mode: 0644]
drivers/infiniband/hw/qib/qib.h [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_6120_regs.h [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_7220.h [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_7220_regs.h [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_7322_regs.h [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_common.h [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_cq.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_diag.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_dma.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_driver.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_eeprom.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_file_ops.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_fs.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_iba6120.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_iba7220.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_iba7322.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_init.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_intr.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_keys.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_mad.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_mad.h [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_mmap.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_mr.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_pcie.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_pio_copy.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_qp.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_qsfp.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_qsfp.h [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_rc.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_ruc.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_sd7220.c [moved from drivers/infiniband/hw/ipath/ipath_sd7220.c with 57% similarity]
drivers/infiniband/hw/qib/qib_sd7220_img.c [moved from drivers/infiniband/hw/ipath/ipath_sd7220_img.c with 99% similarity]
drivers/infiniband/hw/qib/qib_sdma.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_srq.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_sysfs.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_twsi.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_tx.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_uc.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_ud.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_user_pages.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_user_sdma.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_user_sdma.h [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_verbs.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_verbs.h [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_verbs_mcast.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_wc_ppc64.c [moved from drivers/infiniband/hw/ipath/ipath_7220.h with 57% similarity]
drivers/infiniband/hw/qib/qib_wc_x86_64.c [new file with mode: 0644]
drivers/input/joydev.c
drivers/input/keyboard/amikbd.c
drivers/input/misc/Kconfig
drivers/input/misc/Makefile
drivers/input/misc/hp_sdc_rtc.c
drivers/input/misc/max8925_onkey.c [new file with mode: 0644]
drivers/input/misc/sparcspkr.c
drivers/input/misc/twl4030-vibra.c
drivers/input/misc/uinput.c
drivers/input/mouse/amimouse.c
drivers/input/serio/i8042-sparcio.h
drivers/input/serio/xilinx_ps2.c
drivers/input/touchscreen/ads7846.c
drivers/input/touchscreen/s3c2410_ts.c
drivers/input/touchscreen/usbtouchscreen.c
drivers/isdn/capi/capi.c
drivers/isdn/capi/kcapi.c
drivers/isdn/gigaset/capi.c
drivers/isdn/hisax/hisax_fcpcipnp.c
drivers/isdn/i4l/isdn_common.c
drivers/isdn/mISDN/timerdev.c
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/led-class.c
drivers/leds/leds-88pm860x.c
drivers/leds/leds-gpio.c
drivers/leds/leds-lp3944.c
drivers/leds/leds-mc13783.c [new file with mode: 0644]
drivers/leds/leds-net5501.c [new file with mode: 0644]
drivers/leds/leds-ss4200.c
drivers/macintosh/macio_asic.c
drivers/macintosh/macio_sysfs.c
drivers/macintosh/mediabay.c
drivers/macintosh/nvram.c
drivers/macintosh/rack-meter.c
drivers/macintosh/smu.c
drivers/macintosh/therm_pm72.c
drivers/macintosh/therm_windtunnel.c
drivers/macintosh/via-pmu.c
drivers/md/bitmap.c
drivers/md/raid5.c
drivers/media/dvb/dvb-core/dmxdev.c
drivers/media/dvb/dvb-core/dvb_ca_en50221.c
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-core/dvb_net.c
drivers/media/dvb/dvb-core/dvbdev.c
drivers/media/dvb/dvb-core/dvbdev.h
drivers/media/dvb/firewire/firedtv-ci.c
drivers/media/dvb/ttpci/av7110.c
drivers/media/dvb/ttpci/av7110_av.c
drivers/media/dvb/ttpci/av7110_ca.c
drivers/message/fusion/mptscsih.c
drivers/message/i2o/i2o_config.c
drivers/mfd/88pm860x-core.c
drivers/mfd/Kconfig
drivers/mfd/mc13783-core.c
drivers/mfd/pcf50633-core.c
drivers/mfd/sh_mobile_sdhi.c
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/ad525x_dpot-i2c.c [new file with mode: 0644]
drivers/misc/ad525x_dpot-spi.c [new file with mode: 0644]
drivers/misc/ad525x_dpot.c
drivers/misc/ad525x_dpot.h [new file with mode: 0644]
drivers/misc/lkdtm.c
drivers/mmc/core/core.c
drivers/mmc/core/sd_ops.c
drivers/mmc/core/sdio.c
drivers/mmc/core/sdio_io.c
drivers/mmc/host/Kconfig
drivers/mmc/host/Makefile
drivers/mmc/host/at91_mci.c
drivers/mmc/host/atmel-mci.c
drivers/mmc/host/au1xmmc.c
drivers/mmc/host/bfin_sdh.c
drivers/mmc/host/cb710-mmc.c
drivers/mmc/host/davinci_mmc.c
drivers/mmc/host/imxmmc.c
drivers/mmc/host/mmci.c
drivers/mmc/host/msm_sdcc.c
drivers/mmc/host/mvsdio.c
drivers/mmc/host/mxcmmc.c
drivers/mmc/host/of_mmc_spi.c
drivers/mmc/host/omap.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/pxamci.c
drivers/mmc/host/s3cmci.c
drivers/mmc/host/sdhci-of-core.c
drivers/mmc/host/sdhci-of-esdhc.c
drivers/mmc/host/sdhci-of-hlwd.c
drivers/mmc/host/sdhci-pci.c
drivers/mmc/host/sdhci-pltfm.c
drivers/mmc/host/sdhci-s3c.c
drivers/mmc/host/sdhci-spear.c [new file with mode: 0644]
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
drivers/mmc/host/sdricoh_cs.c
drivers/mmc/host/sh_mmcif.c [new file with mode: 0644]
drivers/mmc/host/tifm_sd.c
drivers/mmc/host/tmio_mmc.c
drivers/mmc/host/tmio_mmc.h
drivers/mmc/host/via-sdmmc.c
drivers/mmc/host/wbsd.c
drivers/mtd/maps/physmap_of.c
drivers/mtd/maps/sun_uflash.c
drivers/mtd/mtdchar.c
drivers/mtd/nand/fsl_elbc_nand.c
drivers/mtd/nand/fsl_upm.c
drivers/mtd/nand/ndfc.c
drivers/mtd/nand/pasemi_nand.c
drivers/mtd/nand/socrates_nand.c
drivers/mtd/ubi/cdev.c
drivers/net/3c507.c
drivers/net/benet/be.h
drivers/net/benet/be_cmds.c
drivers/net/benet/be_main.c
drivers/net/bfin_mac.c
drivers/net/can/mscan/mpc5xxx_can.c
drivers/net/can/sja1000/sja1000.c
drivers/net/can/sja1000/sja1000_of_platform.c
drivers/net/cnic.c
drivers/net/cnic_if.h
drivers/net/ehea/ehea_main.c
drivers/net/enic/enic_main.c
drivers/net/ethoc.c
drivers/net/fec.c
drivers/net/fec.h
drivers/net/fec_mpc52xx.c
drivers/net/fec_mpc52xx_phy.c
drivers/net/fs_enet/fs_enet-main.c
drivers/net/fs_enet/mac-fcc.c
drivers/net/fs_enet/mac-fec.c
drivers/net/fs_enet/mac-scc.c
drivers/net/fs_enet/mii-bitbang.c
drivers/net/fs_enet/mii-fec.c
drivers/net/fsl_pq_mdio.c
drivers/net/gianfar.c
drivers/net/greth.c
drivers/net/hamradio/yam.c
drivers/net/ibm_newemac/core.c
drivers/net/ibm_newemac/debug.c
drivers/net/ibm_newemac/debug.h
drivers/net/ibm_newemac/mal.c
drivers/net/ibm_newemac/rgmii.c
drivers/net/ibm_newemac/tah.c
drivers/net/ibm_newemac/zmii.c
drivers/net/irda/bfin_sir.c
drivers/net/ixgbe/ixgbe.h
drivers/net/ixgbe/ixgbe_82598.c
drivers/net/ixgbe/ixgbe_82599.c
drivers/net/ixgbe/ixgbe_main.c
drivers/net/ixgbe/ixgbe_phy.c
drivers/net/ixgbe/ixgbe_phy.h
drivers/net/ixgbe/ixgbe_type.h
drivers/net/ll_temac.h
drivers/net/ll_temac_main.c
drivers/net/macvlan.c
drivers/net/mlx4/icm.c
drivers/net/myri_sbus.c
drivers/net/niu.c
drivers/net/phy/mdio-gpio.c
drivers/net/ppp_generic.c
drivers/net/pppoe.c
drivers/net/sh_eth.c
drivers/net/sunbmac.c
drivers/net/sunhme.c
drivers/net/sunlance.c
drivers/net/sunqe.c
drivers/net/tun.c
drivers/net/ucc_geth.c
drivers/net/usb/asix.c
drivers/net/usb/hso.c
drivers/net/virtio_net.c
drivers/net/wimax/i2400m/rx.c
drivers/net/wireless/airo.c
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath9k/beacon.c
drivers/net/wireless/ath/ath9k/hif_usb.c
drivers/net/wireless/ath/ath9k/htc.h
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/pci.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/iwlwifi/iwl-agn-ict.c
drivers/net/wireless/iwlwifi/iwl-scan.c
drivers/net/wireless/iwlwifi/iwl-sta.c
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rt2x00/rt2400pci.c
drivers/net/wireless/rt2x00/rt2500pci.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt2x00pci.c
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/wl12xx/wl1271_rx.c
drivers/net/xilinx_emaclite.c
drivers/of/device.c
drivers/of/fdt.c
drivers/of/of_i2c.c
drivers/of/of_mdio.c
drivers/of/of_spi.c
drivers/of/platform.c
drivers/parport/parport_amiga.c
drivers/parport/parport_sunbpp.c
drivers/pci/Kconfig
drivers/pci/access.c
drivers/pci/dmar.c
drivers/pci/hotplug/cpqphp_core.c
drivers/pci/hotplug/pciehp_pci.c
drivers/pci/intel-iommu.c
drivers/pci/intr_remapping.c
drivers/pci/pci-sysfs.c
drivers/pci/pci.c
drivers/pci/pcie/aer/aer_inject.c
drivers/pci/pcie/aer/aerdrv.c
drivers/pci/pcie/aer/aerdrv.h
drivers/pci/pcie/aer/aerdrv_acpi.c
drivers/pci/pcie/aer/aerdrv_core.c
drivers/pci/probe.c
drivers/pci/quirks.c
drivers/pci/slot.c
drivers/pcmcia/electra_cf.c
drivers/pcmcia/m8xx_pcmcia.c
drivers/pcmcia/pcmcia_ioctl.c
drivers/platform/x86/Kconfig
drivers/platform/x86/Makefile
drivers/platform/x86/classmate-laptop.c
drivers/platform/x86/eeepc-wmi.c
drivers/platform/x86/fujitsu-laptop.c
drivers/platform/x86/intel_scu_ipc.c [new file with mode: 0644]
drivers/platform/x86/msi-laptop.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/wmi.c
drivers/power/Kconfig
drivers/power/Makefile
drivers/power/ds2760_battery.c
drivers/power/ds2782_battery.c
drivers/power/pda_power.c
drivers/power/power_supply.h
drivers/power/power_supply_core.c
drivers/power/power_supply_sysfs.c
drivers/power/test_power.c [new file with mode: 0644]
drivers/power/tosa_battery.c
drivers/power/wm831x_power.c
drivers/power/wm97xx_battery.c
drivers/power/z2_battery.c [new file with mode: 0644]
drivers/rapidio/Kconfig
drivers/rapidio/Makefile
drivers/rapidio/rio-scan.c
drivers/rapidio/rio.c
drivers/rapidio/rio.h
drivers/rapidio/switches/Kconfig [new file with mode: 0644]
drivers/rapidio/switches/Makefile
drivers/rapidio/switches/idtcps.c [new file with mode: 0644]
drivers/rapidio/switches/tsi500.c
drivers/rapidio/switches/tsi568.c [new file with mode: 0644]
drivers/rapidio/switches/tsi57x.c [new file with mode: 0644]
drivers/regulator/88pm8607.c
drivers/regulator/ab3100.c
drivers/regulator/bq24022.c
drivers/regulator/core.c
drivers/regulator/mc13783-regulator.c
drivers/regulator/twl-regulator.c
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-ab8500.c [new file with mode: 0644]
drivers/rtc/rtc-cmos.c
drivers/rtc/rtc-ds1302.c
drivers/rtc/rtc-isl1208.c
drivers/rtc/rtc-m41t80.c
drivers/rtc/rtc-mxc.c
drivers/rtc/rtc-s3c.c
drivers/rtc/rtc-wm831x.c
drivers/s390/block/dasd.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_int.h
drivers/s390/cio/ccwgroup.c
drivers/s390/cio/ccwreq.c
drivers/s390/cio/ioasm.h
drivers/sbus/char/bbc_envctrl.c
drivers/sbus/char/bbc_i2c.c
drivers/sbus/char/display7seg.c
drivers/sbus/char/envctrl.c
drivers/sbus/char/flash.c
drivers/sbus/char/openprom.c
drivers/sbus/char/uctrl.c
drivers/scsi/3w-9xxx.c
drivers/scsi/3w-sas.c
drivers/scsi/3w-xxxx.c
drivers/scsi/a2091.c
drivers/scsi/a2091.h
drivers/scsi/a3000.c
drivers/scsi/a3000.h
drivers/scsi/a4000t.c
drivers/scsi/aacraid/commctrl.c
drivers/scsi/aacraid/linit.c
drivers/scsi/arcmsr/arcmsr.h
drivers/scsi/arcmsr/arcmsr_attr.c
drivers/scsi/arcmsr/arcmsr_hba.c
drivers/scsi/be2iscsi/be_mgmt.c
drivers/scsi/bfa/bfa_core.c
drivers/scsi/dpt_i2o.c
drivers/scsi/fcoe/fcoe.c
drivers/scsi/gdth.c
drivers/scsi/gvp11.c
drivers/scsi/gvp11.h
drivers/scsi/ibmvscsi/ibmvfc.c
drivers/scsi/ibmvscsi/ibmvscsi.c
drivers/scsi/ipr.c
drivers/scsi/ipr.h
drivers/scsi/iscsi_tcp.c
drivers/scsi/megaraid.c
drivers/scsi/megaraid.h
drivers/scsi/megaraid/megaraid_mm.c
drivers/scsi/mpt2sas/mpt2sas_base.c
drivers/scsi/mpt2sas/mpt2sas_config.c
drivers/scsi/mvme147.c
drivers/scsi/osst.c
drivers/scsi/qlogicpti.c
drivers/scsi/scsi_scan.c
drivers/scsi/sg.c
drivers/scsi/st.c
drivers/scsi/sun_esp.c
drivers/serial/68328serial.c
drivers/serial/apbuart.c
drivers/serial/cpm_uart/cpm_uart_core.c
drivers/serial/mpc52xx_uart.c
drivers/serial/nwpserial.c
drivers/serial/of_serial.c
drivers/serial/pmac_zilog.c
drivers/serial/s5pv210.c
drivers/serial/sh-sci.c
drivers/serial/sunhv.c
drivers/serial/sunsab.c
drivers/serial/sunsu.c
drivers/serial/sunzilog.c
drivers/serial/uartlite.c
drivers/serial/ucc_uart.c
drivers/sfi/sfi_acpi.c
drivers/sfi/sfi_core.c
drivers/sfi/sfi_core.h
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/amba-pl022.c
drivers/spi/davinci_spi.c
drivers/spi/ep93xx_spi.c [new file with mode: 0644]
drivers/spi/mpc512x_psc_spi.c [new file with mode: 0644]
drivers/spi/mpc52xx_psc_spi.c
drivers/spi/mpc52xx_spi.c
drivers/spi/omap2_mcspi.c
drivers/spi/spi_bitbang_txrx.h [new file with mode: 0644]
drivers/spi/spi_butterfly.c
drivers/spi/spi_gpio.c
drivers/spi/spi_lm70llp.c
drivers/spi/spi_mpc8xxx.c
drivers/spi/spi_ppc4xx.c
drivers/spi/spi_s3c24xx_gpio.c
drivers/spi/spi_sh_sci.c
drivers/spi/xilinx_spi_of.c
drivers/staging/go7007/saa7134-go7007.c
drivers/staging/pohmelfs/inode.c
drivers/staging/rt2860/common/rtmp_init.c
drivers/staging/rt2860/rtmp.h
drivers/telephony/ixj.c
drivers/usb/atm/speedtch.c
drivers/usb/gadget/fsl_qe_udc.c
drivers/usb/gadget/printer.c
drivers/usb/gadget/storage_common.c
drivers/usb/host/ehci-mxc.c
drivers/usb/host/ehci-ppc-of.c
drivers/usb/host/ehci-xilinx-of.c
drivers/usb/host/fhci-hcd.c
drivers/usb/host/isp1760-if.c
drivers/usb/host/ohci-ppc-of.c
drivers/usb/mon/mon_bin.c
drivers/usb/mon/mon_stat.c
drivers/vhost/net.c
drivers/vhost/vhost.c
drivers/video/arcfb.c
drivers/video/aty/atyfb_base.c
drivers/video/backlight/88pm860x_bl.c
drivers/video/backlight/Kconfig
drivers/video/backlight/Makefile
drivers/video/backlight/adp8860_bl.c [new file with mode: 0644]
drivers/video/backlight/adx_bl.c
drivers/video/backlight/ep93xx_bl.c [new file with mode: 0644]
drivers/video/backlight/l4f00242t03.c
drivers/video/backlight/max8925_bl.c
drivers/video/backlight/mbp_nvidia_bl.c
drivers/video/backlight/pcf50633-backlight.c [new file with mode: 0644]
drivers/video/backlight/s6e63m0.c [new file with mode: 0644]
drivers/video/backlight/s6e63m0_gamma.h [new file with mode: 0644]
drivers/video/bf54x-lq043fb.c
drivers/video/bfin-lq035q1-fb.c
drivers/video/bfin-t350mcqb-fb.c
drivers/video/bw2.c
drivers/video/cg14.c
drivers/video/cg3.c
drivers/video/cg6.c
drivers/video/da8xx-fb.c
drivers/video/fb_defio.c
drivers/video/fbmem.c
drivers/video/ffb.c
drivers/video/fsl-diu-fb.c
drivers/video/hgafb.c
drivers/video/hitfb.c
drivers/video/intelfb/intelfb.h
drivers/video/leo.c
drivers/video/mb862xx/mb862xxfb.c
drivers/video/nuc900fb.c
drivers/video/p9100.c
drivers/video/platinumfb.c
drivers/video/s3c2410fb.c
drivers/video/s3fb.c
drivers/video/sgivwfb.c
drivers/video/sis/sis_main.c
drivers/video/sunxvr1000.c
drivers/video/tcx.c
drivers/video/vfb.c
drivers/video/vga16fb.c
drivers/video/via/viafbdev.c
drivers/video/w100fb.c
drivers/video/xilinxfb.c
drivers/virtio/virtio_balloon.c
drivers/virtio/virtio_ring.c
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/bfin_wdt.c
drivers/watchdog/booke_wdt.c
drivers/watchdog/cpwd.c
drivers/watchdog/eurotechwdt.c
drivers/watchdog/gef_wdt.c
drivers/watchdog/iTCO_vendor_support.c
drivers/watchdog/iTCO_wdt.c
drivers/watchdog/imx2_wdt.c [new file with mode: 0644]
drivers/watchdog/mpc8xxx_wdt.c
drivers/watchdog/pc87413_wdt.c
drivers/watchdog/pnx833x_wdt.c
drivers/watchdog/riowd.c
drivers/watchdog/s3c2410_wdt.c
drivers/watchdog/shwdt.c
drivers/watchdog/twl4030_wdt.c
drivers/watchdog/wdt.c
drivers/watchdog/wdt977.c
drivers/xen/manage.c
fs/9p/v9fs_vfs.h
fs/9p/vfs_dir.c
fs/9p/vfs_file.c
fs/9p/vfs_inode.c
fs/9p/vfs_super.c
fs/Makefile
fs/adfs/dir.c
fs/adfs/file.c
fs/adfs/inode.c
fs/affs/affs.h
fs/affs/file.c
fs/affs/namei.c
fs/afs/dir.c
fs/afs/file.c
fs/afs/internal.h
fs/afs/mntpt.c
fs/afs/write.c
fs/aio.c
fs/attr.c
fs/autofs/root.c
fs/autofs4/dev-ioctl.c
fs/autofs4/root.c
fs/bad_inode.c
fs/bfs/dir.c
fs/block_dev.c
fs/btrfs/acl.c
fs/btrfs/async-thread.c
fs/btrfs/btrfs_inode.h
fs/btrfs/ctree.c
fs/btrfs/ctree.h
fs/btrfs/delayed-ref.c
fs/btrfs/delayed-ref.h
fs/btrfs/disk-io.c
fs/btrfs/disk-io.h
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/extent_io.h
fs/btrfs/file-item.c
fs/btrfs/file.c
fs/btrfs/inode-item.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/ordered-data.c
fs/btrfs/ordered-data.h
fs/btrfs/relocation.c
fs/btrfs/root-tree.c
fs/btrfs/super.c
fs/btrfs/transaction.c
fs/btrfs/transaction.h
fs/btrfs/tree-defrag.c
fs/btrfs/tree-log.c
fs/btrfs/tree-log.h
fs/btrfs/volumes.c
fs/btrfs/xattr.c
fs/btrfs/xattr.h
fs/buffer.c
fs/ceph/addr.c
fs/ceph/auth.c
fs/ceph/auth.h
fs/ceph/auth_none.c
fs/ceph/auth_x.c
fs/ceph/caps.c
fs/ceph/ceph_fs.h
fs/ceph/ceph_strings.c
fs/ceph/debugfs.c
fs/ceph/dir.c
fs/ceph/export.c
fs/ceph/file.c
fs/ceph/inode.c
fs/ceph/ioctl.c
fs/ceph/mds_client.c
fs/ceph/mds_client.h
fs/ceph/messenger.c
fs/ceph/messenger.h
fs/ceph/mon_client.c
fs/ceph/mon_client.h
fs/ceph/msgpool.c
fs/ceph/msgpool.h
fs/ceph/msgr.h
fs/ceph/osd_client.c
fs/ceph/osdmap.c
fs/ceph/pagelist.c
fs/ceph/rados.h
fs/ceph/snap.c
fs/ceph/super.c
fs/ceph/super.h
fs/ceph/xattr.c
fs/cifs/cifsfs.h
fs/cifs/file.c
fs/coda/coda_int.h
fs/coda/file.c
fs/coda/pioctl.c
fs/coda/psdev.c
fs/compat.c
fs/configfs/inode.c
fs/dcache.c
fs/debugfs/file.c
fs/devpts/inode.c
fs/direct-io.c
fs/drop_caches.c
fs/ecryptfs/ecryptfs_kernel.h
fs/ecryptfs/file.c
fs/ecryptfs/inode.c
fs/ecryptfs/main.c
fs/ecryptfs/mmap.c
fs/ecryptfs/read_write.c
fs/ecryptfs/super.c
fs/exec.c
fs/exofs/dir.c
fs/exofs/file.c
fs/exofs/inode.c
fs/ext2/acl.c
fs/ext2/ext2.h
fs/ext2/file.c
fs/ext2/ialloc.c
fs/ext2/inode.c
fs/ext2/super.c
fs/ext2/xattr.c
fs/ext2/xattr.h
fs/ext2/xattr_security.c
fs/ext2/xattr_trusted.c
fs/ext2/xattr_user.c
fs/ext3/acl.c
fs/ext3/dir.c
fs/ext3/fsync.c
fs/ext3/ialloc.c
fs/ext3/super.c
fs/ext3/xattr.c
fs/ext3/xattr.h
fs/ext3/xattr_security.c
fs/ext3/xattr_trusted.c
fs/ext3/xattr_user.c
fs/ext4/acl.c
fs/ext4/balloc.c
fs/ext4/block_validity.c
fs/ext4/dir.c
fs/ext4/ext4.h
fs/ext4/ext4_jbd2.h
fs/ext4/extents.c
fs/ext4/file.c
fs/ext4/fsync.c
fs/ext4/ialloc.c
fs/ext4/inode.c
fs/ext4/ioctl.c
fs/ext4/mballoc.c
fs/ext4/migrate.c
fs/ext4/move_extent.c
fs/ext4/namei.c
fs/ext4/resize.c
fs/ext4/super.c
fs/ext4/symlink.c
fs/ext4/xattr.c
fs/ext4/xattr.h
fs/ext4/xattr_security.c
fs/ext4/xattr_trusted.c
fs/ext4/xattr_user.c
fs/fat/cache.c
fs/fat/dir.c
fs/fat/fat.h
fs/fat/file.c
fs/fat/inode.c
fs/fat/misc.c
fs/file_table.c
fs/freevxfs/vxfs_lookup.c
fs/fs-writeback.c
fs/fscache/object-list.c
fs/fuse/dev.c
fs/fuse/dir.c
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/generic_acl.c
fs/gfs2/acl.c
fs/gfs2/acl.h
fs/gfs2/aops.c
fs/gfs2/file.c
fs/gfs2/inode.c
fs/gfs2/inode.h
fs/gfs2/log.c
fs/gfs2/log.h
fs/gfs2/ops_inode.c
fs/gfs2/rgrp.c
fs/gfs2/super.h
fs/gfs2/xattr.c
fs/hfsplus/dir.c
fs/hfsplus/hfsplus_fs.h
fs/hfsplus/inode.c
fs/hfsplus/ioctl.c
fs/hostfs/hostfs_kern.c
fs/hpfs/file.c
fs/hpfs/hpfs_fn.h
fs/hppfs/hppfs.c
fs/hugetlbfs/inode.c
fs/inode.c
fs/internal.h
fs/ioctl.c
fs/isofs/dir.c
fs/jbd2/transaction.c
fs/jffs2/acl.c
fs/jffs2/acl.h
fs/jffs2/file.c
fs/jffs2/fs.c
fs/jffs2/os-linux.h
fs/jffs2/security.c
fs/jffs2/xattr.c
fs/jffs2/xattr.h
fs/jffs2/xattr_trusted.c
fs/jffs2/xattr_user.c
fs/jfs/file.c
fs/jfs/jfs_inode.c
fs/jfs/jfs_inode.h
fs/jfs/super.c
fs/libfs.c
fs/logfs/file.c
fs/logfs/inode.c
fs/logfs/logfs.h
fs/minix/bitmap.c
fs/minix/dir.c
fs/minix/file.c
fs/minix/itree_v2.c
fs/minix/minix.h
fs/minix/namei.c
fs/namei.c
fs/ncpfs/dir.c
fs/ncpfs/file.c
fs/ncpfs/ioctl.c
fs/nfs/dir.c
fs/nfs/file.c
fs/nfs/super.c
fs/nfs/write.c
fs/nfsd/nfs4recover.c
fs/nfsd/nfsctl.c
fs/nfsd/vfs.c
fs/nilfs2/file.c
fs/nilfs2/inode.c
fs/nilfs2/nilfs.h
fs/notify/inotify/inotify.c
fs/ntfs/dir.c
fs/ntfs/file.c
fs/ocfs2/acl.c
fs/ocfs2/blockcheck.c
fs/ocfs2/file.c
fs/ocfs2/namei.c
fs/ocfs2/super.c
fs/ocfs2/xattr.c
fs/ocfs2/xattr.h
fs/omfs/file.c
fs/omfs/inode.c
fs/open.c
fs/partitions/efi.c
fs/partitions/ldm.c
fs/partitions/mac.c
fs/partitions/msdos.c
fs/pipe.c
fs/proc/array.c
fs/proc/base.c
fs/proc/generic.c
fs/proc/kcore.c
fs/proc/root.c
fs/proc/task_mmu.c
fs/qnx4/dir.c
fs/quota/dquot.c
fs/quota/quota.c
fs/ramfs/file-mmu.c
fs/ramfs/file-nommu.c
fs/ramfs/inode.c
fs/read_write.c
fs/reiserfs/dir.c
fs/reiserfs/file.c
fs/reiserfs/namei.c
fs/reiserfs/super.c
fs/reiserfs/xattr.c
fs/reiserfs/xattr_acl.c
fs/reiserfs/xattr_security.c
fs/reiserfs/xattr_trusted.c
fs/reiserfs/xattr_user.c
fs/smbfs/dir.c
fs/smbfs/file.c
fs/smbfs/inode.c
fs/smbfs/ioctl.c
fs/smbfs/proto.h
fs/smbfs/symlink.c
fs/squashfs/Kconfig
fs/squashfs/Makefile
fs/squashfs/inode.c
fs/squashfs/namei.c
fs/squashfs/squashfs.h
fs/squashfs/squashfs_fs.h
fs/squashfs/squashfs_fs_i.h
fs/squashfs/squashfs_fs_sb.h
fs/squashfs/super.c
fs/squashfs/symlink.c
fs/squashfs/xattr.c [new file with mode: 0644]
fs/squashfs/xattr.h [new file with mode: 0644]
fs/squashfs/xattr_id.c [new file with mode: 0644]
fs/statfs.c [new file with mode: 0644]
fs/super.c
fs/sync.c
fs/sysfs/inode.c
fs/sysv/dir.c
fs/sysv/file.c
fs/sysv/ialloc.c
fs/sysv/inode.c
fs/ubifs/dir.c
fs/ubifs/file.c
fs/ubifs/ubifs.h
fs/udf/balloc.c
fs/udf/dir.c
fs/udf/file.c
fs/udf/ialloc.c
fs/udf/inode.c
fs/udf/namei.c
fs/udf/super.c
fs/udf/udfdecl.h
fs/ufs/balloc.c
fs/ufs/dir.c
fs/ufs/file.c
fs/ufs/ialloc.c
fs/ufs/inode.c
fs/ufs/namei.c
fs/ufs/super.c
fs/ufs/truncate.c
fs/ufs/ufs_fs.h
fs/xattr.c
fs/xfs/Makefile
fs/xfs/linux-2.6/xfs_acl.c
fs/xfs/linux-2.6/xfs_buf.c
fs/xfs/linux-2.6/xfs_file.c
fs/xfs/linux-2.6/xfs_quotaops.c
fs/xfs/linux-2.6/xfs_super.c
fs/xfs/linux-2.6/xfs_super.h
fs/xfs/linux-2.6/xfs_trace.h
fs/xfs/linux-2.6/xfs_xattr.c
fs/xfs/quota/xfs_dquot.c
fs/xfs/xfs_acl.h
fs/xfs/xfs_ag.h
fs/xfs/xfs_alloc.c
fs/xfs/xfs_alloc.h
fs/xfs/xfs_alloc_btree.c
fs/xfs/xfs_buf_item.c
fs/xfs/xfs_buf_item.h
fs/xfs/xfs_error.c
fs/xfs/xfs_log.c
fs/xfs/xfs_log.h
fs/xfs/xfs_log_cil.c [new file with mode: 0644]
fs/xfs/xfs_log_priv.h
fs/xfs/xfs_log_recover.c
fs/xfs/xfs_log_recover.h
fs/xfs/xfs_mount.h
fs/xfs/xfs_trans.c
fs/xfs/xfs_trans.h
fs/xfs/xfs_trans_buf.c
fs/xfs/xfs_trans_item.c
fs/xfs/xfs_trans_priv.h
fs/xfs/xfs_types.h
include/acpi/acpi_bus.h
include/acpi/acpi_drivers.h
include/acpi/acpi_hest.h [deleted file]
include/acpi/apei.h [new file with mode: 0644]
include/acpi/atomicio.h [new file with mode: 0644]
include/acpi/hed.h [new file with mode: 0644]
include/acpi/processor.h
include/acpi/video.h
include/asm-generic/atomic.h
include/asm-generic/bug.h
include/asm-generic/dma-mapping-common.h
include/asm-generic/gpio.h
include/asm-generic/kmap_types.h
include/asm-generic/scatterlist.h
include/asm-generic/topology.h
include/asm-generic/vmlinux.lds.h
include/linux/acpi.h
include/linux/aio.h
include/linux/amba/pl022.h
include/linux/buffer_head.h
include/linux/cgroup.h
include/linux/compaction.h [new file with mode: 0644]
include/linux/compat.h
include/linux/completion.h
include/linux/cper.h [new file with mode: 0644]
include/linux/cpuidle.h
include/linux/cpuset.h
include/linux/cred.h
include/linux/crypto.h
include/linux/debugfs.h
include/linux/device.h
include/linux/dma-mapping.h
include/linux/ds2782_battery.h [new file with mode: 0644]
include/linux/dynamic_debug.h
include/linux/elfcore.h
include/linux/err.h
include/linux/ext3_fs.h
include/linux/fb.h
include/linux/fec.h [new file with mode: 0644]
include/linux/file.h
include/linux/firewire.h
include/linux/fs.h
include/linux/ftrace_event.h
include/linux/generic_acl.h
include/linux/gfp.h
include/linux/gpio.h
include/linux/highmem.h
include/linux/i2c.h
include/linux/i2c/adp8860.h [new file with mode: 0644]
include/linux/i2c/max732x.h
include/linux/i2c/pca953x.h
include/linux/ide.h
include/linux/init_task.h
include/linux/input.h
include/linux/ioport.h
include/linux/isapnp.h
include/linux/ivtvfb.h
include/linux/joystick.h
include/linux/kernel.h
include/linux/kmod.h
include/linux/kvm.h
include/linux/kvm_host.h
include/linux/lcd.h
include/linux/leds.h
include/linux/libata.h
include/linux/lis3lv02d.h
include/linux/matroxfb.h
include/linux/memcontrol.h
include/linux/memory_hotplug.h
include/linux/mempolicy.h
include/linux/mfd/88pm860x.h
include/linux/mfd/mc13783.h
include/linux/mfd/pcf50633/backlight.h [new file with mode: 0644]
include/linux/mfd/pcf50633/core.h
include/linux/mfd/sh_mobile_sdhi.h
include/linux/mfd/tmio.h
include/linux/migrate.h
include/linux/miscdevice.h
include/linux/mm.h
include/linux/mmc/host.h
include/linux/mmc/sdhci-spear.h [new file with mode: 0644]
include/linux/mmc/sdio_func.h
include/linux/mmc/sh_mmcif.h [new file with mode: 0644]
include/linux/mmzone.h
include/linux/mod_devicetable.h
include/linux/ncp_fs.h
include/linux/netdevice.h
include/linux/netfilter/x_tables.h
include/linux/notifier.h
include/linux/of_device.h
include/linux/of_fdt.h
include/linux/of_platform.h
include/linux/page_cgroup.h
include/linux/pci.h
include/linux/pci_ids.h
include/linux/pci_regs.h
include/linux/pda_power.h
include/linux/perf_event.h
include/linux/power_supply.h
include/linux/quota.h
include/linux/quotaops.h
include/linux/ramfs.h
include/linux/random.h
include/linux/ratelimit.h
include/linux/regulator/machine.h
include/linux/reiserfs_acl.h
include/linux/reiserfs_xattr.h
include/linux/rio.h
include/linux/rio_drv.h
include/linux/rio_ids.h
include/linux/rio_regs.h
include/linux/rmap.h
include/linux/sched.h
include/linux/sdhci-pltfm.h [new file with mode: 0644]
include/linux/sem.h
include/linux/sfi.h
include/linux/slab_def.h
include/linux/slob_def.h
include/linux/slub_def.h
include/linux/spi/spi_bitbang.h
include/linux/swap.h
include/linux/swiotlb.h
include/linux/syscalls.h
include/linux/tboot.h
include/linux/threads.h
include/linux/topology.h
include/linux/tracepoint.h
include/linux/uinput.h
include/linux/usb/audio-v2.h
include/linux/uuid.h [new file with mode: 0644]
include/linux/virtio.h
include/linux/virtio_blk.h
include/linux/virtio_console.h
include/linux/vmstat.h
include/linux/xattr.h
include/linux/z2_battery.h [new file with mode: 0644]
include/net/9p/9p.h
include/net/9p/client.h
include/net/caif/cfctrl.h
include/net/cls_cgroup.h [new file with mode: 0644]
include/net/ip.h
include/net/ipv6.h
include/net/mac80211.h
include/net/netfilter/nf_conntrack_core.h
include/net/sctp/structs.h
include/net/sock.h
include/rdma/ib_verbs.h
include/trace/events/ext4.h
include/trace/events/kvm.h
include/trace/ftrace.h
include/trace/syscall.h
include/video/da8xx-fb.h
include/video/sh_mobile_lcdc.h
init/main.c
ipc/msg.c
ipc/sem.c
ipc/shm.c
ipc/util.c
kernel/cgroup.c
kernel/cpu.c
kernel/cpuset.c
kernel/cred.c
kernel/exit.c
kernel/fork.c
kernel/hrtimer.c
kernel/kmod.c
kernel/module.c
kernel/padata.c
kernel/panic.c
kernel/perf_event.c
kernel/pid.c
kernel/posix-cpu-timers.c
kernel/posix-timers.c
kernel/profile.c
kernel/ptrace.c
kernel/relay.c
kernel/resource.c
kernel/sched.c
kernel/sched_debug.c
kernel/signal.c
kernel/smp.c
kernel/softirq.c
kernel/sys.c
kernel/sysctl.c
kernel/sysctl_binary.c
kernel/time.c
kernel/timer.c
kernel/trace/blktrace.c
kernel/trace/ftrace.c
kernel/trace/kmemtrace.c
kernel/trace/trace.c
kernel/trace/trace.h
kernel/trace/trace_branch.c
kernel/trace/trace_event_perf.c
kernel/trace/trace_events.c
kernel/trace/trace_events_filter.c
kernel/trace/trace_export.c
kernel/trace/trace_functions_graph.c
kernel/trace/trace_kprobe.c
kernel/trace/trace_output.c
kernel/trace/trace_output.h
kernel/trace/trace_sched_switch.c
kernel/trace/trace_sched_wakeup.c
kernel/trace/trace_syscalls.c
kernel/trace/trace_workqueue.c
kernel/tracepoint.c
kernel/workqueue.c
lib/Kconfig.debug
lib/Makefile
lib/atomic64_test.c
lib/bug.c
lib/cpu-notifier-error-inject.c [new file with mode: 0644]
lib/crc32.c
lib/dynamic_debug.c
lib/gen_crc32table.c
lib/hexdump.c
lib/idr.c
lib/radix-tree.c
lib/random32.c
lib/swiotlb.c
lib/uuid.c [new file with mode: 0644]
lib/vsprintf.c
mm/Kconfig
mm/Makefile
mm/compaction.c [new file with mode: 0644]
mm/filemap.c
mm/highmem.c
mm/hugetlb.c
mm/ksm.c
mm/memcontrol.c
mm/memory.c
mm/memory_hotplug.c
mm/mempolicy.c
mm/migrate.c
mm/mincore.c
mm/msync.c
mm/nommu.c
mm/oom_kill.c
mm/page_alloc.c
mm/readahead.c
mm/rmap.c
mm/shmem.c
mm/slab.c
mm/slob.c
mm/slub.c
mm/sparse.c
mm/truncate.c
mm/vmscan.c
mm/vmstat.c
net/9p/client.c
net/9p/protocol.c
net/9p/trans_virtio.c
net/caif/Kconfig
net/caif/caif_socket.c
net/caif/cfctrl.c
net/caif/cfmuxl.c
net/caif/cfpkt_skbuff.c
net/caif/cfserl.c
net/caif/cfsrvl.c
net/core/datagram.c
net/core/dev.c
net/core/drop_monitor.c
net/core/neighbour.c
net/core/rtnetlink.c
net/core/skbuff.c
net/core/sock.c
net/dccp/input.c
net/dccp/options.c
net/ieee802154/wpan-class.c
net/ipv4/ipmr.c
net/ipv4/udp.c
net/ipv6/ip6_output.c
net/ipv6/ip6mr.c
net/ipv6/udp.c
net/iucv/af_iucv.c
net/iucv/iucv.c
net/mac80211/key.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_sip.c
net/netfilter/xt_TEE.c
net/phonet/pep.c
net/sched/cls_cgroup.c
net/sched/sch_api.c
net/socket.c
net/sunrpc/cache.c
net/sunrpc/rpc_pipe.c
net/sunrpc/rpcb_clnt.c
net/sunrpc/xprt.c
net/sunrpc/xprtsock.c
net/wireless/chan.c
net/wireless/nl80211.c
net/wireless/scan.c
samples/tracepoints/tp-samples-trace.h
samples/tracepoints/tracepoint-probe-sample.c
samples/tracepoints/tracepoint-probe-sample2.c
scripts/checkpatch.pl
scripts/gen_initramfs_list.sh
scripts/get_maintainer.pl
scripts/mod/file2alias.c
security/keys/internal.h
security/keys/keyctl.c
security/keys/keyring.c
security/keys/process_keys.c
security/keys/request_key.c
security/selinux/hooks.c
security/selinux/include/objsec.h
sound/aoa/fabrics/layout.c
sound/aoa/soundbus/core.c
sound/aoa/soundbus/i2sbus/control.c
sound/aoa/soundbus/i2sbus/core.c
sound/aoa/soundbus/sysfs.c
sound/core/pcm_lib.c
sound/core/pcm_native.c
sound/mips/au1x00.c
sound/oss/dmasound/dmasound_atari.c
sound/pci/asihpi/hpi.h
sound/pci/asihpi/hpi6000.c
sound/pci/asihpi/hpi6205.c
sound/pci/asihpi/hpi_internal.h
sound/pci/asihpi/hpicmn.c
sound/pci/asihpi/hpifunc.c
sound/pci/asihpi/hpios.c
sound/pci/asihpi/hpios.h
sound/pci/aw2/aw2-alsa.c
sound/pci/emu10k1/emufx.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/soc/codecs/wm8350.c
sound/soc/codecs/wm8400.c
sound/soc/codecs/wm8990.c
sound/soc/fsl/mpc5200_dma.c
sound/soc/fsl/mpc5200_psc_ac97.c
sound/soc/fsl/mpc5200_psc_i2s.c
sound/soc/fsl/mpc8610_hpcd.c
sound/soc/imx/imx-pcm-dma-mx2.c
sound/soc/sh/siu.h
sound/soc/sh/siu_dai.c
sound/soc/sh/siu_pcm.c
sound/sparc/amd7930.c
sound/sparc/cs4231.c
sound/sparc/dbri.c
sound/usb/caiaq/control.c
sound/usb/caiaq/device.c
sound/usb/caiaq/input.c
sound/usb/endpoint.c
sound/usb/format.c
sound/usb/format.h
sound/usb/midi.c
sound/usb/midi.h
sound/usb/mixer.c
sound/usb/pcm.c
sound/usb/quirks-table.h
sound/usb/quirks.c
sound/usb/usbaudio.h
tools/perf/Documentation/perf-stat.txt
tools/perf/builtin-annotate.c
tools/perf/builtin-probe.c
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-stat.c
tools/perf/perf.c
tools/perf/util/abspath.c
tools/perf/util/build-id.c
tools/perf/util/build-id.h
tools/perf/util/cache.h
tools/perf/util/callchain.c
tools/perf/util/callchain.h
tools/perf/util/config.c
tools/perf/util/exec_cmd.c
tools/perf/util/exec_cmd.h
tools/perf/util/header.c
tools/perf/util/help.c
tools/perf/util/hist.c
tools/perf/util/hist.h
tools/perf/util/newt.c
tools/perf/util/path.c
tools/perf/util/probe-finder.c
tools/perf/util/probe-finder.h
tools/perf/util/quote.c
tools/perf/util/quote.h
tools/perf/util/run-command.c
tools/perf/util/run-command.h
tools/perf/util/session.c
tools/perf/util/session.h
tools/perf/util/sigchain.c
tools/perf/util/sigchain.h
tools/perf/util/strbuf.c
tools/perf/util/strbuf.h
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/perf/util/trace-event-read.c
tools/perf/util/trace-event.h
tools/perf/util/util.h
tools/perf/util/wrapper.c
usr/Makefile
usr/initramfs_data.lzo.S [new file with mode: 0644]
virt/kvm/assigned-dev.c
virt/kvm/coalesced_mmio.c
virt/kvm/iommu.c
virt/kvm/kvm_main.c

index 25be3250f7d66f17c0a4d88974441ced8f4ca633..428676cfa61e51917d1fabf0b66e442c943c3768 100644 (file)
@@ -133,6 +133,46 @@ Description:
                The symbolic link points to the PCI device sysfs entry of the
                Physical Function this device associates with.
 
+
+What:          /sys/bus/pci/slots/...
+Date:          April 2005 (possibly older)
+KernelVersion: 2.6.12 (possibly older)
+Contact:       linux-pci@vger.kernel.org
+Description:
+               When the appropriate driver is loaded, it will create a
+               directory per claimed physical PCI slot in
+               /sys/bus/pci/slots/.  The names of these directories are
+               specific to the driver, which in turn, are specific to the
+               platform, but in general, should match the label on the
+               machine's physical chassis.
+
+               The drivers that can create slot directories include the
+               PCI hotplug drivers, and as of 2.6.27, the pci_slot driver.
+
+               The slot directories contain, at a minimum, a file named
+               'address' which contains the PCI bus:device:function tuple.
+               Other files may appear as well, but are specific to the
+               driver.
+
+What:          /sys/bus/pci/slots/.../function[0-7]
+Date:          March 2010
+KernelVersion: 2.6.35
+Contact:       linux-pci@vger.kernel.org
+Description:
+               If PCI slot directories (as described above) are created,
+               and the physical slot is actually populated with a device,
+               symbolic links in the slot directory pointing to the
+               device's PCI functions are created as well.
+
+What:          /sys/bus/pci/devices/.../slot
+Date:          March 2010
+KernelVersion: 2.6.35
+Contact:       linux-pci@vger.kernel.org
+Description:
+               If PCI slot directories (as described above) are created,
+               a symbolic link pointing to the slot directory will be
+               created as well.
+
 What:          /sys/bus/pci/slots/.../module
 Date:          June 2009
 Contact:       linux-pci@vger.kernel.org
diff --git a/Documentation/ABI/testing/sysfs-class-power b/Documentation/ABI/testing/sysfs-class-power
new file mode 100644 (file)
index 0000000..78c7bac
--- /dev/null
@@ -0,0 +1,20 @@
+What:          /sys/class/power/ds2760-battery.*/charge_now
+Date:          May 2010
+KernelVersion: 2.6.35
+Contact:       Daniel Mack <daniel@caiaq.de>
+Description:
+               This file is writeable and can be used to set the current
+               coloumb counter value inside the battery monitor chip. This
+               is needed for unavoidable corrections of aging batteries.
+               A userspace daemon can monitor the battery charging logic
+               and once the counter drops out of considerable bounds, take
+               appropriate action.
+
+What:          /sys/class/power/ds2760-battery.*/charge_full
+Date:          May 2010
+KernelVersion: 2.6.35
+Contact:       Daniel Mack <daniel@caiaq.de>
+Description:
+               This file is writeable and can be used to set the assumed
+               battery 'full level'. As batteries age, this value has to be
+               amended over time.
diff --git a/Documentation/ABI/testing/sysfs-devices-node b/Documentation/ABI/testing/sysfs-devices-node
new file mode 100644 (file)
index 0000000..453a210
--- /dev/null
@@ -0,0 +1,7 @@
+What:          /sys/devices/system/node/nodeX/compact
+Date:          February 2010
+Contact:       Mel Gorman <mel@csn.ul.ie>
+Description:
+               When this file is written to, all memory within that node
+               will be compacted. When it completes, memory will be freed
+               into blocks which have as many contiguous pages as possible
diff --git a/Documentation/ABI/testing/sysfs-firmware-sfi b/Documentation/ABI/testing/sysfs-firmware-sfi
new file mode 100644 (file)
index 0000000..4be7d44
--- /dev/null
@@ -0,0 +1,15 @@
+What:          /sys/firmware/sfi/tables/
+Date:          May 2010
+Contact:       Len Brown <lenb@kernel.org>
+Description:
+               SFI defines a number of small static memory tables
+               so the kernel can get platform information from firmware.
+
+               The tables are defined in the latest SFI specification:
+               http://simplefirmware.org/documentation
+
+               While the tables are used by the kernel, user-space
+               can observe them this way:
+
+               # cd /sys/firmware/sfi/tables
+               # cat $TABLENAME > $TABLENAME.bin
index 2e435adfbd6bbedfbe913c38e1c51a9c2db036e9..98ce51796f711317f567a3b5144955178d0fd8da 100644 (file)
@@ -639,6 +639,36 @@ is planned to completely remove virt_to_bus() and bus_to_virt() as
 they are entirely deprecated.  Some ports already do not provide these
 as it is impossible to correctly support them.
 
+                       Handling Errors
+
+DMA address space is limited on some architectures and an allocation
+failure can be determined by:
+
+- checking if dma_alloc_coherent returns NULL or dma_map_sg returns 0
+
+- checking the returned dma_addr_t of dma_map_single and dma_map_page
+  by using dma_mapping_error():
+
+       dma_addr_t dma_handle;
+
+       dma_handle = dma_map_single(dev, addr, size, direction);
+       if (dma_mapping_error(dev, dma_handle)) {
+               /*
+                * reduce current DMA mapping usage,
+                * delay and try again later or
+                * reset driver.
+                */
+       }
+
+Networking drivers must call dev_kfree_skb to free the socket buffer
+and return NETDEV_TX_OK if the DMA mapping fails on the transmit hook
+(ndo_start_xmit). This means that the socket buffer is just dropped in
+the failure case.
+
+SCSI drivers must return SCSI_MLQUEUE_HOST_BUSY if the DMA mapping
+fails in the queuecommand hook. This means that the SCSI subsystem
+passes the command to the driver again later.
+
                Optimizing Unmap State Space Consumption
 
 On many platforms, dma_unmap_{single,page}() is simply a nop.
@@ -703,42 +733,25 @@ to "Closing".
 
 1) Struct scatterlist requirements.
 
-   Struct scatterlist must contain, at a minimum, the following
-   members:
-
-       struct page *page;
-       unsigned int offset;
-       unsigned int length;
-
-   The base address is specified by a "page+offset" pair.
-
-   Previous versions of struct scatterlist contained a "void *address"
-   field that was sometimes used instead of page+offset.  As of Linux
-   2.5., page+offset is always used, and the "address" field has been
-   deleted.
-
-2) More to come...
-
-                       Handling Errors
-
-DMA address space is limited on some architectures and an allocation
-failure can be determined by:
-
-- checking if dma_alloc_coherent returns NULL or dma_map_sg returns 0
-
-- checking the returned dma_addr_t of dma_map_single and dma_map_page
-  by using dma_mapping_error():
-
-       dma_addr_t dma_handle;
-
-       dma_handle = dma_map_single(dev, addr, size, direction);
-       if (dma_mapping_error(dev, dma_handle)) {
-               /*
-                * reduce current DMA mapping usage,
-                * delay and try again later or
-                * reset driver.
-                */
-       }
+   Don't invent the architecture specific struct scatterlist; just use
+   <asm-generic/scatterlist.h>. You need to enable
+   CONFIG_NEED_SG_DMA_LENGTH if the architecture supports IOMMUs
+   (including software IOMMU).
+
+2) ARCH_KMALLOC_MINALIGN
+
+   Architectures must ensure that kmalloc'ed buffer is
+   DMA-safe. Drivers and subsystems depend on it. If an architecture
+   isn't fully DMA-coherent (i.e. hardware doesn't ensure that data in
+   the CPU cache is identical to data in main memory),
+   ARCH_KMALLOC_MINALIGN must be set so that the memory allocator
+   makes sure that kmalloc'ed buffer doesn't share a cache line with
+   the others. See arch/arm/include/asm/cache.h as an example.
+
+   Note that ARCH_KMALLOC_MINALIGN is about DMA memory alignment
+   constraints. You don't need to worry about the architecture data
+   alignment constraints (e.g. the alignment constraints about 64-bit
+   objects).
 
                           Closing
 
index 133cd6c3f3c15658986209f65859719d7407aca6..020ac80d4682b0af1ce06fb58c8fa4a2a949ccea 100644 (file)
@@ -269,7 +269,7 @@ static void board_hwcontrol(struct mtd_info *mtd, int cmd)
                        information about the device.
                </para>
                <programlisting>
-int __init board_init (void)
+static int __init board_init (void)
 {
        struct nand_chip *this;
        int err = 0;
index be21001ab14475f8f95cafc33dd3dd3efd7ee8e8..26d3d945c3c21aa965cd9b48c49cc42abf09df3f 100644 (file)
@@ -13,7 +13,7 @@ Reporting (AER) driver and provides information on how to use it, as
 well as how to enable the drivers of endpoint devices to conform with
 PCI Express AER driver.
 
-1.2 Copyright © Intel Corporation 2006.
+1.2 Copyright (C) Intel Corporation 2006.
 
 1.3 What is the PCI Express AER Driver?
 
@@ -71,15 +71,11 @@ console. If it's a correctable error, it is outputed as a warning.
 Otherwise, it is printed as an error. So users could choose different
 log level to filter out correctable error messages.
 
-Below shows an example.
-+------ PCI-Express Device Error -----+
-Error Severity          : Uncorrected (Fatal)
-PCIE Bus Error type     : Transaction Layer
-Unsupported Request     : First
-Requester ID            : 0500
-VendorID=8086h, DeviceID=0329h, Bus=05h, Device=00h, Function=00h
-TLB Header:
-04000001 00200a03 05010000 00050100
+Below shows an example:
+0000:50:00.0: PCIe Bus Error: severity=Uncorrected (Fatal), type=Transaction Layer, id=0500(Requester ID)
+0000:50:00.0:   device [8086:0329] error status/mask=00100000/00000000
+0000:50:00.0:    [20] Unsupported Request    (First)
+0000:50:00.0:   TLP Header: 04000001 00200a03 05010000 00050100
 
 In the example, 'Requester ID' means the ID of the device who sends
 the error message to root port. Pls. refer to pci express specs for
@@ -112,7 +108,7 @@ but the PCI Express link itself is fully functional. Fatal errors, on
 the other hand, cause the link to be unreliable.
 
 When AER is enabled, a PCI Express device will automatically send an
-error message to the PCIE root port above it when the device captures
+error message to the PCIe root port above it when the device captures
 an error. The Root Port, upon receiving an error reporting message,
 internally processes and logs the error message in its PCI Express
 capability structure. Error information being logged includes storing
@@ -198,8 +194,9 @@ to reset link, AER port service driver is required to provide the
 function to reset link. Firstly, kernel looks for if the upstream
 component has an aer driver. If it has, kernel uses the reset_link
 callback of the aer driver. If the upstream component has no aer driver
-and the port is downstream port, we will use the aer driver of the
-root port who reports the AER error. As for upstream ports,
+and the port is downstream port, we will perform a hot reset as the
+default by setting the Secondary Bus Reset bit of the Bridge Control
+register associated with the downstream port. As for upstream ports,
 they should provide their own aer service drivers with reset_link
 function. If error_detected returns PCI_ERS_RESULT_CAN_RECOVER and
 reset_link returns PCI_ERS_RESULT_RECOVERED, the error handling goes
@@ -253,11 +250,11 @@ cleanup uncorrectable status register. Pls. refer to section 3.3.
 
 4. Software error injection
 
-Debugging PCIE AER error recovery code is quite difficult because it
+Debugging PCIe AER error recovery code is quite difficult because it
 is hard to trigger real hardware errors. Software based error
-injection can be used to fake various kinds of PCIE errors.
+injection can be used to fake various kinds of PCIe errors.
 
-First you should enable PCIE AER software error injection in kernel
+First you should enable PCIe AER software error injection in kernel
 configuration, that is, following item should be in your .config.
 
 CONFIG_PCIEAER_INJECT=y or CONFIG_PCIEAER_INJECT=m
index 8916ca48bc95f943c59adbf30cd0cec9a9e144b6..da0382daa39556939dcc94717b658b5917e4009f 100644 (file)
@@ -18,6 +18,8 @@ kernel patches.
 
 2b: Passes allnoconfig, allmodconfig
 
+2c: Builds successfully when using O=builddir
+
 3: Builds on multiple CPU architectures by using local cross-compile tools
    or some other build farm.
 
@@ -95,3 +97,13 @@ kernel patches.
 
 25: If any ioctl's are added by the patch, then also update
     Documentation/ioctl/ioctl-number.txt.
+
+26: If your modified source code depends on or uses any of the kernel
+    APIs or features that are related to the following kconfig symbols,
+    then test multiple builds with the related kconfig symbols disabled
+    and/or =m (if that option is available) [not all of these at the
+    same time, just various/random combinations of them]:
+
+    CONFIG_SMP, CONFIG_SYSFS, CONFIG_PROC_FS, CONFIG_INPUT, CONFIG_PCI,
+    CONFIG_BLOCK, CONFIG_PM, CONFIG_HOTPLUG, CONFIG_MAGIC_SYSRQ,
+    CONFIG_NET, CONFIG_INET=n (but latter with CONFIG_NET=y)
index 99e72a81fa2fac5570708ed419e7a89b19040f1c..4947fd8fb1827a2d9c8a9cbcdb734d6b6f5eb98d 100644 (file)
@@ -130,6 +130,8 @@ Linux kernel master tree:
        ftp.??.kernel.org:/pub/linux/kernel/...
        ?? == your country code, such as "us", "uk", "fr", etc.
 
+       http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git
+
 Linux kernel mailing list:
        linux-kernel@vger.kernel.org
        [mail majordomo@vger.kernel.org to subscribe]
@@ -160,3 +162,6 @@ How to NOT write kernel driver by Arjan van de Ven:
 
 Kernel Janitor:
        http://janitor.kernelnewbies.org/
+
+GIT, Fast Version Control System:
+       http://git-scm.com/
diff --git a/Documentation/acpi/apei/einj.txt b/Documentation/acpi/apei/einj.txt
new file mode 100644 (file)
index 0000000..dfab718
--- /dev/null
@@ -0,0 +1,59 @@
+                       APEI Error INJection
+                       ~~~~~~~~~~~~~~~~~~~~
+
+EINJ provides a hardware error injection mechanism
+It is very useful for debugging and testing of other APEI and RAS features.
+
+To use EINJ, make sure the following are enabled in your kernel
+configuration:
+
+CONFIG_DEBUG_FS
+CONFIG_ACPI_APEI
+CONFIG_ACPI_APEI_EINJ
+
+The user interface of EINJ is debug file system, under the
+directory apei/einj. The following files are provided.
+
+- available_error_type
+  Reading this file returns the error injection capability of the
+  platform, that is, which error types are supported. The error type
+  definition is as follow, the left field is the error type value, the
+  right field is error description.
+
+    0x00000001 Processor Correctable
+    0x00000002 Processor Uncorrectable non-fatal
+    0x00000004 Processor Uncorrectable fatal
+    0x00000008  Memory Correctable
+    0x00000010  Memory Uncorrectable non-fatal
+    0x00000020  Memory Uncorrectable fatal
+    0x00000040 PCI Express Correctable
+    0x00000080 PCI Express Uncorrectable fatal
+    0x00000100 PCI Express Uncorrectable non-fatal
+    0x00000200 Platform Correctable
+    0x00000400 Platform Uncorrectable non-fatal
+    0x00000800 Platform Uncorrectable fatal
+
+  The format of file contents are as above, except there are only the
+  available error type lines.
+
+- error_type
+  This file is used to set the error type value. The error type value
+  is defined in "available_error_type" description.
+
+- error_inject
+  Write any integer to this file to trigger the error
+  injection. Before this, please specify all necessary error
+  parameters.
+
+- param1
+  This file is used to set the first error parameter value. Effect of
+  parameter depends on error_type specified. For memory error, this is
+  physical memory address.
+
+- param2
+  This file is used to set the second error parameter value. Effect of
+  parameter depends on error_type specified. For memory error, this is
+  physical memory address mask.
+
+For more information about EINJ, please refer to ACPI specification
+version 4.0, section 17.5.
index 2af2cf39915f5209a4dceafd26bc7b9050f7e7d2..816d6071669e75380dc72da99fb9a27739e0a2d8 100644 (file)
@@ -12,6 +12,8 @@ Introduction
   of the s3c2410 GPIO system, please read the Samsung provided
   data-sheet/users manual to find out the complete list.
 
+  See Documentation/arm/Samsung/GPIO.txt for the core implemetation.
+
 
 GPIOLIB
 -------
@@ -24,8 +26,60 @@ GPIOLIB
   listed below will be removed (they may be marked as __deprecated
   in the near future).
 
-  - s3c2410_gpio_getpin
-  - s3c2410_gpio_setpin
+  The following functions now either have a s3c_ specific variant
+  or are merged into gpiolib. See the definitions in
+  arch/arm/plat-samsung/include/plat/gpio-cfg.h:
+
+  s3c2410_gpio_setpin()                gpio_set_value() or gpio_direction_output()
+  s3c2410_gpio_getpin()                gpio_get_value() or gpio_direction_input()
+  s3c2410_gpio_getirq()                gpio_to_irq()
+  s3c2410_gpio_cfgpin()                s3c_gpio_cfgpin()
+  s3c2410_gpio_getcfg()                s3c_gpio_getcfg()
+  s3c2410_gpio_pullup()                s3c_gpio_setpull()
+
+
+GPIOLIB conversion
+------------------
+
+If you need to convert your board or driver to use gpiolib from the exiting
+s3c2410 api, then here are some notes on the process.
+
+1) If your board is exclusively using an GPIO, say to control peripheral
+   power, then it will require to claim the gpio with gpio_request() before
+   it can use it.
+
+   It is recommended to check the return value, with at least WARN_ON()
+   during initialisation.
+
+2) The s3c2410_gpio_cfgpin() can be directly replaced with s3c_gpio_cfgpin()
+   as they have the same arguments, and can either take the pin specific
+   values, or the more generic special-function-number arguments.
+
+3) s3c2410_gpio_pullup() changs have the problem that whilst the 
+   s3c2410_gpio_pullup(x, 1) can be easily translated to the
+   s3c_gpio_setpull(x, S3C_GPIO_PULL_NONE), the s3c2410_gpio_pullup(x, 0)
+   are not so easy.
+
+   The s3c2410_gpio_pullup(x, 0) case enables the pull-up (or in the case
+   of some of the devices, a pull-down) and as such the new API distinguishes
+   between the UP and DOWN case. There is currently no 'just turn on' setting
+   which may be required if this becomes a problem.
+
+4) s3c2410_gpio_setpin() can be replaced by gpio_set_value(), the old call
+   does not implicitly configure the relevant gpio to output. The gpio
+   direction should be changed before using gpio_set_value().
+
+5) s3c2410_gpio_getpin() is replaceable by gpio_get_value() if the pin
+   has been set to input. It is currently unknown what the behaviour is
+   when using gpio_get_value() on an output pin (s3c2410_gpio_getpin
+   would return the value the pin is supposed to be outputting).
+
+6) s3c2410_gpio_getirq() should be directly replacable with the
+   gpio_to_irq() call.
+
+The s3c2410_gpio and gpio_ calls have always operated on the same gpio
+numberspace, so there is no problem with converting the gpio numbering
+between the calls.
 
 
 Headers
@@ -54,6 +108,11 @@ PIN Numbers
   eg S3C2410_GPA(0) or S3C2410_GPF(1). These defines are used to tell
   the GPIO functions which pin is to be used.
 
+  With the conversion to gpiolib, there is no longer a direct conversion
+  from gpio pin number to register base address as in earlier kernels. This
+  is due to the number space required for newer SoCs where the later
+  GPIOs are not contiguous.
+
 
 Configuring a pin
 -----------------
@@ -71,6 +130,8 @@ Configuring a pin
    which would turn GPA(0) into the lowest Address line A0, and set
    GPE(8) to be connected to the SDIO/MMC controller's SDDAT1 line.
 
+   The s3c_gpio_cfgpin() call is a functional replacement for this call.
+
 
 Reading the current configuration
 ---------------------------------
@@ -82,6 +143,9 @@ Reading the current configuration
   The return value will be from the same set of values which can be
   passed to s3c2410_gpio_cfgpin().
 
+  The s3c_gpio_getcfg() call should be a functional replacement for
+  this call.
+
 
 Configuring a pull-up resistor
 ------------------------------
@@ -95,6 +159,10 @@ Configuring a pull-up resistor
   Where the to value is zero to set the pull-up off, and 1 to enable
   the specified pull-up. Any other values are currently undefined.
 
+  The s3c_gpio_setpull() offers similar functionality, but with the
+  ability to encode whether the pull is up or down. Currently there
+  is no 'just on' state, so up or down must be selected.
+
 
 Getting the state of a PIN
 --------------------------
@@ -106,6 +174,9 @@ Getting the state of a PIN
   This will return either zero or non-zero. Do not count on this
   function returning 1 if the pin is set.
 
+  This call is now implemented by the relevant gpiolib calls, convert
+  your board or driver to use gpiolib.
+
 
 Setting the state of a PIN
 --------------------------
@@ -117,6 +188,9 @@ Setting the state of a PIN
   Which sets the given pin to the value. Use 0 to write 0, and 1 to
   set the output to 1.
 
+  This call is now implemented by the relevant gpiolib calls, convert
+  your board or driver to use gpiolib.
+
 
 Getting the IRQ number associated with a PIN
 --------------------------------------------
@@ -128,6 +202,9 @@ Getting the IRQ number associated with a PIN
 
   Note, not all pins have an IRQ.
 
+  This call is now implemented by the relevant gpiolib calls, convert
+  your board or driver to use gpiolib.
+
 
 Authour
 -------
index 081892df4fdaf5b0fa8504bf78fb0bf0f96abc9c..c12bfc1a00c9812ebfa8c95314f34228dc7a1a1f 100644 (file)
@@ -8,10 +8,16 @@ Introduction
 
   The Samsung S3C24XX range of ARM9 System-on-Chip CPUs are supported
   by the 's3c2410' architecture of ARM Linux. Currently the S3C2410,
-  S3C2412, S3C2413, S3C2440, S3C2442 and S3C2443 devices are supported.
+  S3C2412, S3C2413, S3C2416 S3C2440, S3C2442, S3C2443 and S3C2450 devices
+  are supported.
 
   Support for the S3C2400 and S3C24A0 series are in progress.
 
+  The S3C2416 and S3C2450 devices are very similar and S3C2450 support is
+  included under the arch/arm/mach-s3c2416 directory. Note, whilst core
+  support for these SoCs is in, work on some of the extra peripherals
+  and extra interrupts is still ongoing.
+
 
 Configuration
 -------------
@@ -209,6 +215,13 @@ GPIO
   Newer kernels carry GPIOLIB, and support is being moved towards
   this with some of the older support in line to be removed.
 
+  As of v2.6.34, the move towards using gpiolib support is almost
+  complete, and very little of the old calls are left.
+
+  See Documentation/arm/Samsung-S3C24XX/GPIO.txt for the S3C24XX specific
+  support and Documentation/arm/Samsung/GPIO.txt for the core Samsung
+  implementation.
+
 
 Clock Management
 ----------------
diff --git a/Documentation/arm/Samsung/GPIO.txt b/Documentation/arm/Samsung/GPIO.txt
new file mode 100644 (file)
index 0000000..05850c6
--- /dev/null
@@ -0,0 +1,42 @@
+               Samsung GPIO implementation
+               ===========================
+
+Introduction
+------------
+
+This outlines the Samsung GPIO implementation and the architecture
+specfic calls provided alongisde the drivers/gpio core.
+
+
+S3C24XX (Legacy)
+----------------
+
+See Documentation/arm/Samsung-S3C24XX/GPIO.txt for more information
+about these devices. Their implementation is being brought into line
+with the core samsung implementation described in this document.
+
+
+GPIOLIB integration
+-------------------
+
+The gpio implementation uses gpiolib as much as possible, only providing
+specific calls for the items that require Samsung specific handling, such
+as pin special-function or pull resistor control.
+
+GPIO numbering is synchronised between the Samsung and gpiolib system.
+
+
+PIN configuration
+-----------------
+
+Pin configuration is specific to the Samsung architecutre, with each SoC
+registering the necessary information for the core gpio configuration
+implementation to configure pins as necessary.
+
+The s3c_gpio_cfgpin() and s3c_gpio_setpull() provide the means for a
+driver or machine to change gpio configuration.
+
+See arch/arm/plat-samsung/include/plat/gpio-cfg.h for more information
+on these functions.
+
+
index 7cced1fea9c3fdad45a36971806ea01dca0202ae..c3094ea51aa758745d7c9bcf9661164d0ecbac6f 100644 (file)
@@ -13,9 +13,10 @@ Introduction
 
   - S3C24XX: See Documentation/arm/Samsung-S3C24XX/Overview.txt for full list
   - S3C64XX: S3C6400 and S3C6410
-  - S5PC6440
-
-  S5PC100 and S5PC110 support is currently being merged
+  - S5P6440
+  - S5P6442
+  - S5PC100
+  - S5PC110 / S5PV210
 
 
 S3C24XX Systems
@@ -35,7 +36,10 @@ Configuration
   unifying all the SoCs into one kernel.
 
   s5p6440_defconfig - S5P6440 specific default configuration
+  s5p6442_defconfig - S5P6442 specific default configuration
   s5pc100_defconfig - S5PC100 specific default configuration
+  s5pc110_defconfig - S5PC110 specific default configuration
+  s5pv210_defconfig - S5PV210 specific default configuration
 
 
 Layout
@@ -50,18 +54,27 @@ Layout
   specific information. It contains the base clock, GPIO and device definitions
   to get the system running.
 
-  plat-s3c is the s3c24xx/s3c64xx platform directory, although it is currently
-  involved in other builds this will be phased out once the relevant code is
-  moved elsewhere.
-
   plat-s3c24xx is for s3c24xx specific builds, see the S3C24XX docs.
 
-  plat-s3c64xx is for the s3c64xx specific bits, see the S3C24XX docs.
+  plat-s5p is for s5p specific builds, and contains common support for the
+  S5P specific systems. Not all S5Ps use all the features in this directory
+  due to differences in the hardware.
+
+
+Layout changes
+--------------
+
+  The old plat-s3c and plat-s5pc1xx directories have been removed, with
+  support moved to either plat-samsung or plat-s5p as necessary. These moves
+  where to simplify the include and dependency issues involved with having
+  so many different platform directories.
 
-  plat-s5p is for s5p specific builds, more to be added.
+  It was decided to remove plat-s5pc1xx as some of the support was already
+  in plat-s5p or plat-samsung, with the S5PC110 support added with S5PV210
+  the only user was the S5PC100. The S5PC100 specific items where moved to
+  arch/arm/mach-s5pc100.
 
 
-  [ to finish ]
 
 
 Port Contributors
index 57444c2609fcb408131c45b4edfab02b05f5b435..b34823ff16469a0e6d57bbca9d659f5968d1e410 100644 (file)
@@ -339,7 +339,7 @@ To mount a cgroup hierarchy with all available subsystems, type:
 The "xxx" is not interpreted by the cgroup code, but will appear in
 /proc/mounts so may be any useful identifying string that you like.
 
-To mount a cgroup hierarchy with just the cpuset and numtasks
+To mount a cgroup hierarchy with just the cpuset and memory
 subsystems, type:
 # mount -t cgroup -o cpuset,memory hier1 /dev/cgroup
 
index 6cab1f29da4c9b94b35c603fd9a91a252c0231aa..7781857dc940ea01d60e7bc0b249cbd15623182d 100644 (file)
@@ -1,18 +1,15 @@
 Memory Resource Controller
 
 NOTE: The Memory Resource Controller has been generically been referred
-to as the memory controller in this document. Do not confuse memory controller
-used here with the memory controller that is used in hardware.
+      to as the memory controller in this document. Do not confuse memory
+      controller used here with the memory controller that is used in hardware.
 
-Salient features
-
-a. Enable control of Anonymous, Page Cache (mapped and unmapped) and
-   Swap Cache memory pages.
-b. The infrastructure allows easy addition of other types of memory to control
-c. Provides *zero overhead* for non memory controller users
-d. Provides a double LRU: global memory pressure causes reclaim from the
-   global LRU; a cgroup on hitting a limit, reclaims from the per
-   cgroup LRU
+(For editors)
+In this document:
+      When we mention a cgroup (cgroupfs's directory) with memory controller,
+      we call it "memory cgroup". When you see git-log and source code, you'll
+      see patch's title and function names tend to use "memcg".
+      In this document, we avoid using it.
 
 Benefits and Purpose of the memory controller
 
@@ -33,6 +30,45 @@ d. A CD/DVD burner could control the amount of memory used by the
 e. There are several other use cases, find one or use the controller just
    for fun (to learn and hack on the VM subsystem).
 
+Current Status: linux-2.6.34-mmotm(development version of 2010/April)
+
+Features:
+ - accounting anonymous pages, file caches, swap caches usage and limiting them.
+ - private LRU and reclaim routine. (system's global LRU and private LRU
+   work independently from each other)
+ - optionally, memory+swap usage can be accounted and limited.
+ - hierarchical accounting
+ - soft limit
+ - moving(recharging) account at moving a task is selectable.
+ - usage threshold notifier
+ - oom-killer disable knob and oom-notifier
+ - Root cgroup has no limit controls.
+
+ Kernel memory and Hugepages are not under control yet. We just manage
+ pages on LRU. To add more controls, we have to take care of performance.
+
+Brief summary of control files.
+
+ tasks                          # attach a task(thread) and show list of threads
+ cgroup.procs                   # show list of processes
+ cgroup.event_control           # an interface for event_fd()
+ memory.usage_in_bytes          # show current memory(RSS+Cache) usage.
+ memory.memsw.usage_in_bytes    # show current memory+Swap usage
+ memory.limit_in_bytes          # set/show limit of memory usage
+ memory.memsw.limit_in_bytes    # set/show limit of memory+Swap usage
+ memory.failcnt                         # show the number of memory usage hits limits
+ memory.memsw.failcnt           # show the number of memory+Swap hits limits
+ memory.max_usage_in_bytes      # show max memory usage recorded
+ memory.memsw.usage_in_bytes    # show max memory+Swap usage recorded
+ memory.soft_limit_in_bytes     # set/show soft limit of memory usage
+ memory.stat                    # show various statistics
+ memory.use_hierarchy           # set/show hierarchical account enabled
+ memory.force_empty             # trigger forced move charge to parent
+ memory.swappiness              # set/show swappiness parameter of vmscan
+                                (See sysctl's vm.swappiness)
+ memory.move_charge_at_immigrate # set/show controls of moving charges
+ memory.oom_control             # set/show oom controls.
+
 1. History
 
 The memory controller has a long history. A request for comments for the memory
@@ -106,14 +142,14 @@ the necessary data structures and check if the cgroup that is being charged
 is over its limit. If it is then reclaim is invoked on the cgroup.
 More details can be found in the reclaim section of this document.
 If everything goes well, a page meta-data-structure called page_cgroup is
-allocated and associated with the page.  This routine also adds the page to
-the per cgroup LRU.
+updated. page_cgroup has its own LRU on cgroup.
+(*) page_cgroup structure is allocated at boot/memory-hotplug time.
 
 2.2.1 Accounting details
 
 All mapped anon pages (RSS) and cache pages (Page Cache) are accounted.
-(some pages which never be reclaimable and will not be on global LRU
- are not accounted. we just accounts pages under usual vm management.)
+Some pages which are never reclaimable and will not be on the global LRU
+are not accounted. We just account pages under usual VM management.
 
 RSS pages are accounted at page_fault unless they've already been accounted
 for earlier. A file page will be accounted for as Page Cache when it's
@@ -121,12 +157,19 @@ inserted into inode (radix-tree). While it's mapped into the page tables of
 processes, duplicate accounting is carefully avoided.
 
 A RSS page is unaccounted when it's fully unmapped. A PageCache page is
-unaccounted when it's removed from radix-tree.
+unaccounted when it's removed from radix-tree. Even if RSS pages are fully
+unmapped (by kswapd), they may exist as SwapCache in the system until they
+are really freed. Such SwapCaches also also accounted.
+A swapped-in page is not accounted until it's mapped.
+
+Note: The kernel does swapin-readahead and read multiple swaps at once.
+This means swapped-in pages may contain pages for other tasks than a task
+causing page fault. So, we avoid accounting at swap-in I/O.
 
 At page migration, accounting information is kept.
 
-Note: we just account pages-on-lru because our purpose is to control amount
-of used pages. not-on-lru pages are tend to be out-of-control from vm view.
+Note: we just account pages-on-LRU because our purpose is to control amount
+of used pages; not-on-LRU pages tend to be out-of-control from VM view.
 
 2.3 Shared Page Accounting
 
@@ -143,6 +186,7 @@ caller of swapoff rather than the users of shmem.
 
 
 2.4 Swap Extension (CONFIG_CGROUP_MEM_RES_CTLR_SWAP)
+
 Swap Extension allows you to record charge for swap. A swapped-in page is
 charged back to original page allocator if possible.
 
@@ -150,13 +194,20 @@ When swap is accounted, following files are added.
  - memory.memsw.usage_in_bytes.
  - memory.memsw.limit_in_bytes.
 
-usage of mem+swap is limited by memsw.limit_in_bytes.
+memsw means memory+swap. Usage of memory+swap is limited by
+memsw.limit_in_bytes.
 
-* why 'mem+swap' rather than swap.
+Example: Assume a system with 4G of swap. A task which allocates 6G of memory
+(by mistake) under 2G memory limitation will use all swap.
+In this case, setting memsw.limit_in_bytes=3G will prevent bad use of swap.
+By using memsw limit, you can avoid system OOM which can be caused by swap
+shortage.
+
+* why 'memory+swap' rather than swap.
 The global LRU(kswapd) can swap out arbitrary pages. Swap-out means
 to move account from memory to swap...there is no change in usage of
-mem+swap. In other words, when we want to limit the usage of swap without
-affecting global LRU, mem+swap limit is better than just limiting swap from
+memory+swap. In other words, when we want to limit the usage of swap without
+affecting global LRU, memory+swap limit is better than just limiting swap from
 OS point of view.
 
 * What happens when a cgroup hits memory.memsw.limit_in_bytes
@@ -168,12 +219,12 @@ it by cgroup.
 
 2.5 Reclaim
 
-Each cgroup maintains a per cgroup LRU that consists of an active
-and inactive list. When a cgroup goes over its limit, we first try
+Each cgroup maintains a per cgroup LRU which has the same structure as
+global VM. When a cgroup goes over its limit, we first try
 to reclaim memory from the cgroup so as to make space for the new
 pages that the cgroup has touched. If the reclaim is unsuccessful,
 an OOM routine is invoked to select and kill the bulkiest task in the
-cgroup.
+cgroup. (See 10. OOM Control below.)
 
 The reclaim algorithm has not been modified for cgroups, except that
 pages that are selected for reclaiming come from the per cgroup LRU
@@ -184,13 +235,22 @@ limits on the root cgroup.
 
 Note2: When panic_on_oom is set to "2", the whole system will panic.
 
-2. Locking
+When oom event notifier is registered, event will be delivered.
+(See oom_control section)
+
+2.6 Locking
 
-The memory controller uses the following hierarchy
+   lock_page_cgroup()/unlock_page_cgroup() should not be called under
+   mapping->tree_lock.
 
-1. zone->lru_lock is used for selecting pages to be isolated
-2. mem->per_zone->lru_lock protects the per cgroup LRU (per zone)
-3. lock_page_cgroup() is used to protect page->page_cgroup
+   Other lock order is following:
+   PG_locked.
+   mm->page_table_lock
+       zone->lru_lock
+         lock_page_cgroup.
+  In many cases, just lock_page_cgroup() is called.
+  per-zone-per-cgroup LRU (cgroup's private LRU) is just guarded by
+  zone->lru_lock, it has no lock of its own.
 
 3. User Interface
 
@@ -199,6 +259,7 @@ The memory controller uses the following hierarchy
 a. Enable CONFIG_CGROUPS
 b. Enable CONFIG_RESOURCE_COUNTERS
 c. Enable CONFIG_CGROUP_MEM_RES_CTLR
+d. Enable CONFIG_CGROUP_MEM_RES_CTLR_SWAP (to use swap extension)
 
 1. Prepare the cgroups
 # mkdir -p /cgroups
@@ -206,31 +267,28 @@ c. Enable CONFIG_CGROUP_MEM_RES_CTLR
 
 2. Make the new group and move bash into it
 # mkdir /cgroups/0
-# echo $$ >  /cgroups/0/tasks
+# echo $$ > /cgroups/0/tasks
 
-Since now we're in the 0 cgroup,
-We can alter the memory limit:
+Since now we're in the 0 cgroup, we can alter the memory limit:
 # echo 4M > /cgroups/0/memory.limit_in_bytes
 
 NOTE: We can use a suffix (k, K, m, M, g or G) to indicate values in kilo,
-mega or gigabytes.
+mega or gigabytes. (Here, Kilo, Mega, Giga are Kibibytes, Mebibytes, Gibibytes.)
+
 NOTE: We can write "-1" to reset the *.limit_in_bytes(unlimited).
 NOTE: We cannot set limits on the root cgroup any more.
 
 # cat /cgroups/0/memory.limit_in_bytes
 4194304
 
-NOTE: The interface has now changed to display the usage in bytes
-instead of pages
-
 We can check the usage:
 # cat /cgroups/0/memory.usage_in_bytes
 1216512
 
 A successful write to this file does not guarantee a successful set of
-this limit to the value written into the file.  This can be due to a
+this limit to the value written into the file. This can be due to a
 number of factors, such as rounding up to page boundaries or the total
-availability of memory on the system.  The user is required to re-read
+availability of memory on the system. The user is required to re-read
 this file after a write to guarantee the value committed by the kernel.
 
 # echo 1 > memory.limit_in_bytes
@@ -245,15 +303,23 @@ caches, RSS and Active pages/Inactive pages are shown.
 
 4. Testing
 
-Balbir posted lmbench, AIM9, LTP and vmmstress results [10] and [11].
-Apart from that v6 has been tested with several applications and regular
-daily use. The controller has also been tested on the PPC64, x86_64 and
-UML platforms.
+For testing features and implementation, see memcg_test.txt.
+
+Performance test is also important. To see pure memory controller's overhead,
+testing on tmpfs will give you good numbers of small overheads.
+Example: do kernel make on tmpfs.
+
+Page-fault scalability is also important. At measuring parallel
+page fault test, multi-process test may be better than multi-thread
+test because it has noise of shared objects/status.
+
+But the above two are testing extreme situations.
+Trying usual test under memory controller is always helpful.
 
 4.1 Troubleshooting
 
 Sometimes a user might find that the application under a cgroup is
-terminated. There are several causes for this:
+terminated by OOM killer. There are several causes for this:
 
 1. The cgroup limit is too low (just too low to do anything useful)
 2. The user is using anonymous memory and swap is turned off or too low
@@ -261,6 +327,9 @@ terminated. There are several causes for this:
 A sync followed by echo 1 > /proc/sys/vm/drop_caches will help get rid of
 some of the pages cached in the cgroup (page cache pages).
 
+To know what happens, disable OOM_Kill by 10. OOM Control(see below) and
+seeing what happens will be helpful.
+
 4.2 Task migration
 
 When a task migrates from one cgroup to another, its charge is not
@@ -268,16 +337,19 @@ carried forward by default. The pages allocated from the original cgroup still
 remain charged to it, the charge is dropped when the page is freed or
 reclaimed.
 
-Note: You can move charges of a task along with task migration. See 8.
+You can move charges of a task along with task migration.
+See 8. "Move charges at task migration"
 
 4.3 Removing a cgroup
 
 A cgroup can be removed by rmdir, but as discussed in sections 4.1 and 4.2, a
 cgroup might have some charge associated with it, even though all
-tasks have migrated away from it.
-Such charges are freed(at default) or moved to its parent. When moved,
-both of RSS and CACHES are moved to parent.
-If both of them are busy, rmdir() returns -EBUSY. See 5.1 Also.
+tasks have migrated away from it. (because we charge against pages, not
+against tasks.)
+
+Such charges are freed or moved to their parent. At moving, both of RSS
+and CACHES are moved to parent.
+rmdir() may return -EBUSY if freeing/moving fails. See 5.1 also.
 
 Charges recorded in swap information is not updated at removal of cgroup.
 Recorded information is discarded and a cgroup which uses swap (swapcache)
@@ -293,10 +365,10 @@ will be charged as a new owner of it.
 
   # echo 0 > memory.force_empty
 
-  Almost all pages tracked by this memcg will be unmapped and freed. Some of
-  pages cannot be freed because it's locked or in-use. Such pages are moved
-  to parent and this cgroup will be empty. But this may return -EBUSY in
-  some too busy case.
+  Almost all pages tracked by this memory cgroup will be unmapped and freed.
+  Some pages cannot be freed because they are locked or in-use. Such pages are
+  moved to parent and this cgroup will be empty. This may return -EBUSY if
+  VM is too busy to free/move all pages immediately.
 
   Typical use case of this interface is that calling this before rmdir().
   Because rmdir() moves all pages to parent, some out-of-use page caches can be
@@ -306,19 +378,41 @@ will be charged as a new owner of it.
 
 memory.stat file includes following statistics
 
+# per-memory cgroup local status
 cache          - # of bytes of page cache memory.
 rss            - # of bytes of anonymous and swap cache memory.
+mapped_file    - # of bytes of mapped file (includes tmpfs/shmem)
 pgpgin         - # of pages paged in (equivalent to # of charging events).
 pgpgout                - # of pages paged out (equivalent to # of uncharging events).
-active_anon    - # of bytes of anonymous and  swap cache memory on active
-                 lru list.
+swap           - # of bytes of swap usage
 inactive_anon  - # of bytes of anonymous memory and swap cache memory on
-                 inactive lru list.
-active_file    - # of bytes of file-backed memory on active lru list.
-inactive_file  - # of bytes of file-backed memory on inactive lru list.
+               LRU list.
+active_anon    - # of bytes of anonymous and swap cache memory on active
+               inactive LRU list.
+inactive_file  - # of bytes of file-backed memory on inactive LRU list.
+active_file    - # of bytes of file-backed memory on active LRU list.
 unevictable    - # of bytes of memory that cannot be reclaimed (mlocked etc).
 
-The following additional stats are dependent on CONFIG_DEBUG_VM.
+# status considering hierarchy (see memory.use_hierarchy settings)
+
+hierarchical_memory_limit - # of bytes of memory limit with regard to hierarchy
+                       under which the memory cgroup is
+hierarchical_memsw_limit - # of bytes of memory+swap limit with regard to
+                       hierarchy under which memory cgroup is.
+
+total_cache            - sum of all children's "cache"
+total_rss              - sum of all children's "rss"
+total_mapped_file      - sum of all children's "cache"
+total_pgpgin           - sum of all children's "pgpgin"
+total_pgpgout          - sum of all children's "pgpgout"
+total_swap             - sum of all children's "swap"
+total_inactive_anon    - sum of all children's "inactive_anon"
+total_active_anon      - sum of all children's "active_anon"
+total_inactive_file    - sum of all children's "inactive_file"
+total_active_file      - sum of all children's "active_file"
+total_unevictable      - sum of all children's "unevictable"
+
+# The following additional stats are dependent on CONFIG_DEBUG_VM.
 
 inactive_ratio         - VM internal parameter. (see mm/page_alloc.c)
 recent_rotated_anon    - VM internal parameter. (see mm/vmscan.c)
@@ -327,24 +421,37 @@ recent_scanned_anon       - VM internal parameter. (see mm/vmscan.c)
 recent_scanned_file    - VM internal parameter. (see mm/vmscan.c)
 
 Memo:
-       recent_rotated means recent frequency of lru rotation.
-       recent_scanned means recent # of scans to lru.
+       recent_rotated means recent frequency of LRU rotation.
+       recent_scanned means recent # of scans to LRU.
        showing for better debug please see the code for meanings.
 
 Note:
        Only anonymous and swap cache memory is listed as part of 'rss' stat.
        This should not be confused with the true 'resident set size' or the
-       amount of physical memory used by the cgroup. Per-cgroup rss
-       accounting is not done yet.
+       amount of physical memory used by the cgroup.
+       'rss + file_mapped" will give you resident set size of cgroup.
+       (Note: file and shmem may be shared among other cgroups. In that case,
+        file_mapped is accounted only when the memory cgroup is owner of page
+        cache.)
 
 5.3 swappiness
-  Similar to /proc/sys/vm/swappiness, but affecting a hierarchy of groups only.
 
-  Following cgroups' swappiness can't be changed.
-  - root cgroup (uses /proc/sys/vm/swappiness).
-  - a cgroup which uses hierarchy and it has child cgroup.
-  - a cgroup which uses hierarchy and not the root of hierarchy.
+Similar to /proc/sys/vm/swappiness, but affecting a hierarchy of groups only.
 
+Following cgroups' swappiness can't be changed.
+- root cgroup (uses /proc/sys/vm/swappiness).
+- a cgroup which uses hierarchy and it has other cgroup(s) below it.
+- a cgroup which uses hierarchy and not the root of hierarchy.
+
+5.4 failcnt
+
+A memory cgroup provides memory.failcnt and memory.memsw.failcnt files.
+This failcnt(== failure count) shows the number of times that a usage counter
+hit its limit. When a memory cgroup hits a limit, failcnt increases and
+memory under it will be reclaimed.
+
+You can reset failcnt by writing 0 to failcnt file.
+# echo 0 > .../memory.failcnt
 
 6. Hierarchy support
 
@@ -363,13 +470,13 @@ hierarchy
 
 In the diagram above, with hierarchical accounting enabled, all memory
 usage of e, is accounted to its ancestors up until the root (i.e, c and root),
-that has memory.use_hierarchy enabled.  If one of the ancestors goes over its
+that has memory.use_hierarchy enabled. If one of the ancestors goes over its
 limit, the reclaim algorithm reclaims from the tasks in the ancestor and the
 children of the ancestor.
 
 6.1 Enabling hierarchical accounting and reclaim
 
-The memory controller by default disables the hierarchy feature. Support
+A memory cgroup by default disables the hierarchy feature. Support
 can be enabled by writing 1 to memory.use_hierarchy file of the root cgroup
 
 # echo 1 > memory.use_hierarchy
@@ -379,10 +486,10 @@ The feature can be disabled by
 # echo 0 > memory.use_hierarchy
 
 NOTE1: Enabling/disabling will fail if the cgroup already has other
-cgroups created below it.
+       cgroups created below it.
 
 NOTE2: When panic_on_oom is set to "2", the whole system will panic in
-case of an oom event in any cgroup.
+       case of an OOM event in any cgroup.
 
 7. Soft limits
 
@@ -392,7 +499,7 @@ is to allow control groups to use as much of the memory as needed, provided
 a. There is no memory contention
 b. They do not exceed their hard limit
 
-When the system detects memory contention or low memory control groups
+When the system detects memory contention or low memory, control groups
 are pushed back to their soft limits. If the soft limit of each control
 group is very high, they are pushed back as much as possible to make
 sure that one control group does not starve the others of memory.
@@ -406,7 +513,7 @@ it gets invoked from balance_pgdat (kswapd).
 7.1 Interface
 
 Soft limits can be setup by using the following commands (in this example we
-assume a soft limit of 256 megabytes)
+assume a soft limit of 256 MiB)
 
 # echo 256M > memory.soft_limit_in_bytes
 
@@ -442,7 +549,7 @@ Note: Charges are moved only when you move mm->owner, IOW, a leader of a thread
 Note: If we cannot find enough space for the task in the destination cgroup, we
       try to make space by reclaiming memory. Task migration may fail if we
       cannot make enough space.
-Note: It can take several seconds if you move charges in giga bytes order.
+Note: It can take several seconds if you move charges much.
 
 And if you want disable it again:
 
@@ -451,21 +558,27 @@ And if you want disable it again:
 8.2 Type of charges which can be move
 
 Each bits of move_charge_at_immigrate has its own meaning about what type of
-charges should be moved.
+charges should be moved. But in any cases, it must be noted that an account of
+a page or a swap can be moved only when it is charged to the task's current(old)
+memory cgroup.
 
   bit | what type of charges would be moved ?
  -----+------------------------------------------------------------------------
    0  | A charge of an anonymous page(or swap of it) used by the target task.
       | Those pages and swaps must be used only by the target task. You must
       | enable Swap Extension(see 2.4) to enable move of swap charges.
-
-Note: Those pages and swaps must be charged to the old cgroup.
-Note: More type of pages(e.g. file cache, shmem,) will be supported by other
-      bits in future.
+ -----+------------------------------------------------------------------------
+   1  | A charge of file pages(normal file, tmpfs file(e.g. ipc shared memory)
+      | and swaps of tmpfs file) mmapped by the target task. Unlike the case of
+      | anonymous pages, file pages(and swaps) in the range mmapped by the task
+      | will be moved even if the task hasn't done page fault, i.e. they might
+      | not be the task's "RSS", but other task's "RSS" that maps the same file.
+      | And mapcount of the page is ignored(the page can be moved even if
+      | page_mapcount(page) > 1). You must enable Swap Extension(see 2.4) to
+      | enable move of swap charges.
 
 8.3 TODO
 
-- Add support for other types of pages(e.g. file cache, shmem, etc.).
 - Implement madvise(2) to let users decide the vma to be moved or not to be
   moved.
 - All of moving charge operations are done under cgroup_mutex. It's not good
@@ -473,22 +586,61 @@ Note: More type of pages(e.g. file cache, shmem,) will be supported by other
 
 9. Memory thresholds
 
-Memory controler implements memory thresholds using cgroups notification
+Memory cgroup implements memory thresholds using cgroups notification
 API (see cgroups.txt). It allows to register multiple memory and memsw
 thresholds and gets notifications when it crosses.
 
 To register a threshold application need:
- - create an eventfd using eventfd(2);
- - open memory.usage_in_bytes or memory.memsw.usage_in_bytes;
- - write string like "<event_fd> <memory.usage_in_bytes> <threshold>" to
-   cgroup.event_control.
+- create an eventfd using eventfd(2);
+- open memory.usage_in_bytes or memory.memsw.usage_in_bytes;
+- write string like "<event_fd> <fd of memory.usage_in_bytes> <threshold>" to
+  cgroup.event_control.
 
 Application will be notified through eventfd when memory usage crosses
 threshold in any direction.
 
 It's applicable for root and non-root cgroup.
 
-10. TODO
+10. OOM Control
+
+memory.oom_control file is for OOM notification and other controls.
+
+Memory cgroup implements OOM notifier using cgroup notification
+API (See cgroups.txt). It allows to register multiple OOM notification
+delivery and gets notification when OOM happens.
+
+To register a notifier, application need:
+ - create an eventfd using eventfd(2)
+ - open memory.oom_control file
+ - write string like "<event_fd> <fd of memory.oom_control>" to
+   cgroup.event_control
+
+Application will be notified through eventfd when OOM happens.
+OOM notification doesn't work for root cgroup.
+
+You can disable OOM-killer by writing "1" to memory.oom_control file, as:
+
+       #echo 1 > memory.oom_control
+
+This operation is only allowed to the top cgroup of sub-hierarchy.
+If OOM-killer is disabled, tasks under cgroup will hang/sleep
+in memory cgroup's OOM-waitqueue when they request accountable memory.
+
+For running them, you have to relax the memory cgroup's OOM status by
+       * enlarge limit or reduce usage.
+To reduce usage,
+       * kill some tasks.
+       * move some tasks to other group with account migration.
+       * remove some files (on tmpfs?)
+
+Then, stopped tasks will work again.
+
+At reading, current status of OOM is shown.
+       oom_kill_disable 0 or 1 (if 1, oom-killer is disabled)
+       under_oom        0 or 1 (if 1, the memory cgroup is under OOM, tasks may
+                                be stopped.)
+
+11. TODO
 
 1. Add support for accounting huge pages (as a separate controller)
 2. Make per-cgroup scanner reclaim not-shared pages first
index d750321acd5a42560b0746d31c189ee3b3688f3e..97726eba6102ca31410028391d8f637b3d7a01c5 100644 (file)
@@ -151,7 +151,7 @@ The stages that a patch goes through are, generally:
    well.
 
  - Wider review.  When the patch is getting close to ready for mainline
-   inclusion, it will be accepted by a relevant subsystem maintainer -
+   inclusion, it should be accepted by a relevant subsystem maintainer -
    though this acceptance is not a guarantee that the patch will make it
    all the way to the mainline.  The patch will show up in the maintainer's
    subsystem tree and into the staging trees (described below).  When the
@@ -159,6 +159,15 @@ The stages that a patch goes through are, generally:
    the discovery of any problems resulting from the integration of this
    patch with work being done by others.
 
+-  Please note that most maintainers also have day jobs, so merging
+   your patch may not be their highest priority.  If your patch is
+   getting feedback about changes that are needed, you should either
+   make those changes or justify why they should not be made.  If your
+   patch has no review complaints but is not being merged by its
+   appropriate subsystem or driver maintainer, you should be persistent
+   in updating the patch to the current kernel so that it applies cleanly
+   and keep sending it for review and merging.
+
  - Merging into the mainline.  Eventually, a successful patch will be
    merged into the mainline repository managed by Linus Torvalds.  More
    comments and/or problems may surface at this time; it is important that
@@ -258,12 +267,8 @@ an appropriate subsystem tree or be sent directly to Linus.  In a typical
 development cycle, approximately 10% of the patches going into the mainline
 get there via -mm.
 
-The current -mm patch can always be found from the front page of
-
-       http://kernel.org/
-
-Those who want to see the current state of -mm can get the "-mm of the
-moment" tree, found at:
+The current -mm patch is available in the "mmotm" (-mm of the moment)
+directory at:
 
        http://userweb.kernel.org/~akpm/mmotm/
 
@@ -298,6 +303,12 @@ volatility of linux-next tends to make it a difficult development target.
 See http://lwn.net/Articles/289013/ for more information on this topic, and
 stay tuned; much is still in flux where linux-next is involved.
 
+Besides the mmotm and linux-next trees, the kernel source tree now contains
+the drivers/staging/ directory and many sub-directories for drivers or
+filesystems that are on their way to being added to the kernel tree
+proper, but they remain in drivers/staging/ while they still need more
+work.
+
 
 2.5: TOOLS
 
@@ -319,9 +330,9 @@ developers; even if they do not use it for their own work, they'll need git
 to keep up with what other developers (and the mainline) are doing.
 
 Git is now packaged by almost all Linux distributions.  There is a home
-page at 
+page at:
 
-       http://git.or.cz/
+       http://git-scm.com/
 
 That page has pointers to documentation and tutorials.  One should be
 aware, in particular, of the Kernel Hacker's Guide to git, which has
index a2cf74093aa1f1b1ddd468d3e8cb7a2c40e3f82c..837179447e17f0e423d5b2e5f2bc54eb04bde3db 100644 (file)
@@ -25,7 +25,7 @@ long document in its own right.  Instead, the focus here will be on how git
 fits into the kernel development process in particular.  Developers who
 wish to come up to speed with git will find more information at:
 
-       http://git.or.cz/
+       http://git-scm.com/
 
        http://www.kernel.org/pub/software/scm/git/docs/user-manual.html
 
index 53d64d382343f13ff429906f9740e8d15de18739..1d83d124056c61854c87d6fed2d68cf870b5b3af 100644 (file)
@@ -443,6 +443,8 @@ Your cooperation is appreciated.
                231 = /dev/snapshot     System memory snapshot device
                232 = /dev/kvm          Kernel-based virtual machine (hardware virtualization extensions)
                233 = /dev/kmview       View-OS A process with a view
+               234 = /dev/btrfs-control        Btrfs control device
+               235 = /dev/autofs       Autofs control device
                240-254                 Reserved for local use
                255                     Reserved for MISC_DYNAMIC_MINOR
 
index a86152ae2f6f6b5fc8e43b458f750d58df2e700d..672be0109d02617dfa03536c9a4fae7ad4ae4831 100644 (file)
@@ -646,3 +646,13 @@ Who:       Thomas Gleixner <tglx@linutronix.de>
 
 ----------------------------
 
+What:  old ieee1394 subsystem (CONFIG_IEEE1394)
+When:  2.6.37
+Files: drivers/ieee1394/ except init_ohci1394_dma.c
+Why:   superseded by drivers/firewire/ (CONFIG_FIREWIRE) which offers more
+       features, better performance, and better security, all with smaller
+       and more modern code base
+Who:   Stefan Richter <stefanr@s5r6.in-berlin.de>
+
+----------------------------
+
index af1608070cd599341df31c2040f8aa1b1e502a9f..96d4293607ecfe22ed30e8d0ab518a8ddacbbba9 100644 (file)
@@ -380,7 +380,7 @@ prototypes:
        int (*open) (struct inode *, struct file *);
        int (*flush) (struct file *);
        int (*release) (struct inode *, struct file *);
-       int (*fsync) (struct file *, struct dentry *, int datasync);
+       int (*fsync) (struct file *, int datasync);
        int (*aio_fsync) (struct kiocb *, int datasync);
        int (*fasync) (int, struct file *, int);
        int (*lock) (struct file *, int, struct file_lock *);
@@ -429,8 +429,9 @@ check_flags:                no
 implementations.  If your fs is not using generic_file_llseek, you
 need to acquire and release the appropriate locks in your ->llseek().
 For many filesystems, it is probably safe to acquire the inode
-mutex.  Note some filesystems (i.e. remote ones) provide no
-protection for i_size so you will need to use the BKL.
+mutex or just to use i_size_read() instead.
+Note: this does not protect the file->f_pos against concurrent modifications
+since this is something the userspace has to take care about.
 
 Note: ext2_release() was *the* source of contention on fs-intensive
 loads and dropping BKL on ->release() helps to get rid of that (we still
index b324c033035ad097fda59b86897ae0720df9f09b..203f7202cc9e3439607d4131b5b0196b83ab7ea1 100644 (file)
@@ -38,7 +38,8 @@ Hard link support:            yes                     no
 Real inode numbers:            yes                     no
 32-bit uids/gids:              yes                     no
 File creation time:            yes                     no
-Xattr and ACL support:         no                      no
+Xattr support:                 yes                     no
+ACL support:                   no                      no
 
 Squashfs compresses data, inodes and directories.  In addition, inode and
 directory data are highly compacted, and packed on byte boundaries.  Each
@@ -58,7 +59,7 @@ obtained from this site also.
 3. SQUASHFS FILESYSTEM DESIGN
 -----------------------------
 
-A squashfs filesystem consists of seven parts, packed together on a byte
+A squashfs filesystem consists of a maximum of eight parts, packed together on a byte
 alignment:
 
         ---------------
@@ -80,6 +81,9 @@ alignment:
        |---------------|
        |    uid/gid    |
        |  lookup table |
+       |---------------|
+       |     xattr     |
+       |     table     |
         ---------------
 
 Compressed data blocks are written to the filesystem as files are read from
@@ -192,6 +196,26 @@ This table is stored compressed into metadata blocks.  A second index table is
 used to locate these.  This second index table for speed of access (and because
 it is small) is read at mount time and cached in memory.
 
+3.7 Xattr table
+---------------
+
+The xattr table contains extended attributes for each inode.  The xattrs
+for each inode are stored in a list, each list entry containing a type,
+name and value field.  The type field encodes the xattr prefix
+("user.", "trusted." etc) and it also encodes how the name/value fields
+should be interpreted.  Currently the type indicates whether the value
+is stored inline (in which case the value field contains the xattr value),
+or if it is stored out of line (in which case the value field stores a
+reference to where the actual value is stored).  This allows large values
+to be stored out of line improving scanning and lookup performance and it
+also allows values to be de-duplicated, the value being stored once, and
+all other occurences holding an out of line reference to that value.
+
+The xattr lists are packed into compressed 8K metadata blocks.
+To reduce overhead in inodes, rather than storing the on-disk
+location of the xattr list inside each inode, a 32-bit xattr id
+is stored.  This xattr id is mapped into the location of the xattr
+list using a second xattr id lookup table.
 
 4. TODOS AND OUTSTANDING ISSUES
 -------------------------------
@@ -199,9 +223,7 @@ it is small) is read at mount time and cached in memory.
 4.1 Todo list
 -------------
 
-Implement Xattr and ACL support.  The Squashfs 4.0 filesystem layout has hooks
-for these but the code has not been written.  Once the code has been written
-the existing layout should not require modification.
+Implement ACL support.
 
 4.2 Squashfs internal cache
 ---------------------------
index fe09a2cb1858de038b39746bdc862af3f6dc21bc..98ef5512415817376b4ccd71eff83ca27db3c706 100644 (file)
@@ -94,11 +94,19 @@ NodeList format is a comma-separated list of decimal numbers and ranges,
 a range being two hyphen-separated decimal numbers, the smallest and
 largest node numbers in the range.  For example, mpol=bind:0-3,5,7,9-15
 
+A memory policy with a valid NodeList will be saved, as specified, for
+use at file creation time.  When a task allocates a file in the file
+system, the mount option memory policy will be applied with a NodeList,
+if any, modified by the calling task's cpuset constraints
+[See Documentation/cgroups/cpusets.txt] and any optional flags, listed
+below.  If the resulting NodeLists is the empty set, the effective memory
+policy for the file will revert to "default" policy.
+
 NUMA memory allocation policies have optional flags that can be used in
 conjunction with their modes.  These optional flags can be specified
 when tmpfs is mounted by appending them to the mode before the NodeList.
 See Documentation/vm/numa_memory_policy.txt for a list of all available
-memory allocation policy mode flags.
+memory allocation policy mode flags and their effect on memory policy.
 
        =static         is equivalent to        MPOL_F_STATIC_NODES
        =relative       is equivalent to        MPOL_F_RELATIVE_NODES
index b66858538df5e3f09493a4181adbe1ef83ff1d3e..94677e7dcb1311ac504c7f171fd6139deecddb5a 100644 (file)
@@ -401,11 +401,16 @@ otherwise noted.
        started might not be in the page cache at the end of the
        walk).
 
-  truncate: called by the VFS to change the size of a file.  The
+  truncate: Deprecated. This will not be called if ->setsize is defined.
+       Called by the VFS to change the size of a file.  The
        i_size field of the inode is set to the desired size by the
        VFS before this method is called.  This method is called by
        the truncate(2) system call and related functionality.
 
+       Note: ->truncate and vmtruncate are deprecated. Do not add new
+       instances/calls of these. Filesystems should be converted to do their
+       truncate sequence via ->setattr().
+
   permission: called by the VFS to check for access rights on a POSIX-like
        filesystem.
 
@@ -729,7 +734,7 @@ struct file_operations {
        int (*open) (struct inode *, struct file *);
        int (*flush) (struct file *);
        int (*release) (struct inode *, struct file *);
-       int (*fsync) (struct file *, struct dentry *, int datasync);
+       int (*fsync) (struct file *, int datasync);
        int (*aio_fsync) (struct kiocb *, int datasync);
        int (*fasync) (int, struct file *, int);
        int (*lock) (struct file *, int, struct file_lock *);
diff --git a/Documentation/filesystems/xfs-delayed-logging-design.txt b/Documentation/filesystems/xfs-delayed-logging-design.txt
new file mode 100644 (file)
index 0000000..d8119e9
--- /dev/null
@@ -0,0 +1,816 @@
+XFS Delayed Logging Design
+--------------------------
+
+Introduction to Re-logging in XFS
+---------------------------------
+
+XFS logging is a combination of logical and physical logging. Some objects,
+such as inodes and dquots, are logged in logical format where the details
+logged are made up of the changes to in-core structures rather than on-disk
+structures. Other objects - typically buffers - have their physical changes
+logged. The reason for these differences is to reduce the amount of log space
+required for objects that are frequently logged. Some parts of inodes are more
+frequently logged than others, and inodes are typically more frequently logged
+than any other object (except maybe the superblock buffer) so keeping the
+amount of metadata logged low is of prime importance.
+
+The reason that this is such a concern is that XFS allows multiple separate
+modifications to a single object to be carried in the log at any given time.
+This allows the log to avoid needing to flush each change to disk before
+recording a new change to the object. XFS does this via a method called
+"re-logging". Conceptually, this is quite simple - all it requires is that any
+new change to the object is recorded with a *new copy* of all the existing
+changes in the new transaction that is written to the log.
+
+That is, if we have a sequence of changes A through to F, and the object was
+written to disk after change D, we would see in the log the following series
+of transactions, their contents and the log sequence number (LSN) of the
+transaction:
+
+       Transaction             Contents        LSN
+          A                       A               X
+          B                      A+B             X+n
+          C                     A+B+C           X+n+m
+          D                    A+B+C+D         X+n+m+o
+           <object written to disk>
+          E                       E               Y (> X+n+m+o)
+          F                      E+F             Yٍ+p
+
+In other words, each time an object is relogged, the new transaction contains
+the aggregation of all the previous changes currently held only in the log.
+
+This relogging technique also allows objects to be moved forward in the log so
+that an object being relogged does not prevent the tail of the log from ever
+moving forward.  This can be seen in the table above by the changing
+(increasing) LSN of each subsquent transaction - the LSN is effectively a
+direct encoding of the location in the log of the transaction.
+
+This relogging is also used to implement long-running, multiple-commit
+transactions.  These transaction are known as rolling transactions, and require
+a special log reservation known as a permanent transaction reservation. A
+typical example of a rolling transaction is the removal of extents from an
+inode which can only be done at a rate of two extents per transaction because
+of reservation size limitations. Hence a rolling extent removal transaction
+keeps relogging the inode and btree buffers as they get modified in each
+removal operation. This keeps them moving forward in the log as the operation
+progresses, ensuring that current operation never gets blocked by itself if the
+log wraps around.
+
+Hence it can be seen that the relogging operation is fundamental to the correct
+working of the XFS journalling subsystem. From the above description, most
+people should be able to see why the XFS metadata operations writes so much to
+the log - repeated operations to the same objects write the same changes to
+the log over and over again. Worse is the fact that objects tend to get
+dirtier as they get relogged, so each subsequent transaction is writing more
+metadata into the log.
+
+Another feature of the XFS transaction subsystem is that most transactions are
+asynchronous. That is, they don't commit to disk until either a log buffer is
+filled (a log buffer can hold multiple transactions) or a synchronous operation
+forces the log buffers holding the transactions to disk. This means that XFS is
+doing aggregation of transactions in memory - batching them, if you like - to
+minimise the impact of the log IO on transaction throughput.
+
+The limitation on asynchronous transaction throughput is the number and size of
+log buffers made available by the log manager. By default there are 8 log
+buffers available and the size of each is 32kB - the size can be increased up
+to 256kB by use of a mount option.
+
+Effectively, this gives us the maximum bound of outstanding metadata changes
+that can be made to the filesystem at any point in time - if all the log
+buffers are full and under IO, then no more transactions can be committed until
+the current batch completes. It is now common for a single current CPU core to
+be to able to issue enough transactions to keep the log buffers full and under
+IO permanently. Hence the XFS journalling subsystem can be considered to be IO
+bound.
+
+Delayed Logging: Concepts
+-------------------------
+
+The key thing to note about the asynchronous logging combined with the
+relogging technique XFS uses is that we can be relogging changed objects
+multiple times before they are committed to disk in the log buffers. If we
+return to the previous relogging example, it is entirely possible that
+transactions A through D are committed to disk in the same log buffer.
+
+That is, a single log buffer may contain multiple copies of the same object,
+but only one of those copies needs to be there - the last one "D", as it
+contains all the changes from the previous changes. In other words, we have one
+necessary copy in the log buffer, and three stale copies that are simply
+wasting space. When we are doing repeated operations on the same set of
+objects, these "stale objects" can be over 90% of the space used in the log
+buffers. It is clear that reducing the number of stale objects written to the
+log would greatly reduce the amount of metadata we write to the log, and this
+is the fundamental goal of delayed logging.
+
+From a conceptual point of view, XFS is already doing relogging in memory (where
+memory == log buffer), only it is doing it extremely inefficiently. It is using
+logical to physical formatting to do the relogging because there is no
+infrastructure to keep track of logical changes in memory prior to physically
+formatting the changes in a transaction to the log buffer. Hence we cannot avoid
+accumulating stale objects in the log buffers.
+
+Delayed logging is the name we've given to keeping and tracking transactional
+changes to objects in memory outside the log buffer infrastructure. Because of
+the relogging concept fundamental to the XFS journalling subsystem, this is
+actually relatively easy to do - all the changes to logged items are already
+tracked in the current infrastructure. The big problem is how to accumulate
+them and get them to the log in a consistent, recoverable manner.
+Describing the problems and how they have been solved is the focus of this
+document.
+
+One of the key changes that delayed logging makes to the operation of the
+journalling subsystem is that it disassociates the amount of outstanding
+metadata changes from the size and number of log buffers available. In other
+words, instead of there only being a maximum of 2MB of transaction changes not
+written to the log at any point in time, there may be a much greater amount
+being accumulated in memory. Hence the potential for loss of metadata on a
+crash is much greater than for the existing logging mechanism.
+
+It should be noted that this does not change the guarantee that log recovery
+will result in a consistent filesystem. What it does mean is that as far as the
+recovered filesystem is concerned, there may be many thousands of transactions
+that simply did not occur as a result of the crash. This makes it even more
+important that applications that care about their data use fsync() where they
+need to ensure application level data integrity is maintained.
+
+It should be noted that delayed logging is not an innovative new concept that
+warrants rigorous proofs to determine whether it is correct or not. The method
+of accumulating changes in memory for some period before writing them to the
+log is used effectively in many filesystems including ext3 and ext4. Hence
+no time is spent in this document trying to convince the reader that the
+concept is sound. Instead it is simply considered a "solved problem" and as
+such implementing it in XFS is purely an exercise in software engineering.
+
+The fundamental requirements for delayed logging in XFS are simple:
+
+       1. Reduce the amount of metadata written to the log by at least
+          an order of magnitude.
+       2. Supply sufficient statistics to validate Requirement #1.
+       3. Supply sufficient new tracing infrastructure to be able to debug
+          problems with the new code.
+       4. No on-disk format change (metadata or log format).
+       5. Enable and disable with a mount option.
+       6. No performance regressions for synchronous transaction workloads.
+
+Delayed Logging: Design
+-----------------------
+
+Storing Changes
+
+The problem with accumulating changes at a logical level (i.e. just using the
+existing log item dirty region tracking) is that when it comes to writing the
+changes to the log buffers, we need to ensure that the object we are formatting
+is not changing while we do this. This requires locking the object to prevent
+concurrent modification. Hence flushing the logical changes to the log would
+require us to lock every object, format them, and then unlock them again.
+
+This introduces lots of scope for deadlocks with transactions that are already
+running. For example, a transaction has object A locked and modified, but needs
+the delayed logging tracking lock to commit the transaction. However, the
+flushing thread has the delayed logging tracking lock already held, and is
+trying to get the lock on object A to flush it to the log buffer. This appears
+to be an unsolvable deadlock condition, and it was solving this problem that
+was the barrier to implementing delayed logging for so long.
+
+The solution is relatively simple - it just took a long time to recognise it.
+Put simply, the current logging code formats the changes to each item into an
+vector array that points to the changed regions in the item. The log write code
+simply copies the memory these vectors point to into the log buffer during
+transaction commit while the item is locked in the transaction. Instead of
+using the log buffer as the destination of the formatting code, we can use an
+allocated memory buffer big enough to fit the formatted vector.
+
+If we then copy the vector into the memory buffer and rewrite the vector to
+point to the memory buffer rather than the object itself, we now have a copy of
+the changes in a format that is compatible with the log buffer writing code.
+that does not require us to lock the item to access. This formatting and
+rewriting can all be done while the object is locked during transaction commit,
+resulting in a vector that is transactionally consistent and can be accessed
+without needing to lock the owning item.
+
+Hence we avoid the need to lock items when we need to flush outstanding
+asynchronous transactions to the log. The differences between the existing
+formatting method and the delayed logging formatting can be seen in the
+diagram below.
+
+Current format log vector:
+
+Object    +---------------------------------------------+
+Vector 1      +----+
+Vector 2                    +----+
+Vector 3                                   +----------+
+
+After formatting:
+
+Log Buffer    +-V1-+-V2-+----V3----+
+
+Delayed logging vector:
+
+Object    +---------------------------------------------+
+Vector 1      +----+
+Vector 2                    +----+
+Vector 3                                   +----------+
+
+After formatting:
+
+Memory Buffer +-V1-+-V2-+----V3----+
+Vector 1      +----+
+Vector 2           +----+
+Vector 3                +----------+
+
+The memory buffer and associated vector need to be passed as a single object,
+but still need to be associated with the parent object so if the object is
+relogged we can replace the current memory buffer with a new memory buffer that
+contains the latest changes.
+
+The reason for keeping the vector around after we've formatted the memory
+buffer is to support splitting vectors across log buffer boundaries correctly.
+If we don't keep the vector around, we do not know where the region boundaries
+are in the item, so we'd need a new encapsulation method for regions in the log
+buffer writing (i.e. double encapsulation). This would be an on-disk format
+change and as such is not desirable.  It also means we'd have to write the log
+region headers in the formatting stage, which is problematic as there is per
+region state that needs to be placed into the headers during the log write.
+
+Hence we need to keep the vector, but by attaching the memory buffer to it and
+rewriting the vector addresses to point at the memory buffer we end up with a
+self-describing object that can be passed to the log buffer write code to be
+handled in exactly the same manner as the existing log vectors are handled.
+Hence we avoid needing a new on-disk format to handle items that have been
+relogged in memory.
+
+
+Tracking Changes
+
+Now that we can record transactional changes in memory in a form that allows
+them to be used without limitations, we need to be able to track and accumulate
+them so that they can be written to the log at some later point in time.  The
+log item is the natural place to store this vector and buffer, and also makes sense
+to be the object that is used to track committed objects as it will always
+exist once the object has been included in a transaction.
+
+The log item is already used to track the log items that have been written to
+the log but not yet written to disk. Such log items are considered "active"
+and as such are stored in the Active Item List (AIL) which is a LSN-ordered
+double linked list. Items are inserted into this list during log buffer IO
+completion, after which they are unpinned and can be written to disk. An object
+that is in the AIL can be relogged, which causes the object to be pinned again
+and then moved forward in the AIL when the log buffer IO completes for that
+transaction.
+
+Essentially, this shows that an item that is in the AIL can still be modified
+and relogged, so any tracking must be separate to the AIL infrastructure. As
+such, we cannot reuse the AIL list pointers for tracking committed items, nor
+can we store state in any field that is protected by the AIL lock. Hence the
+committed item tracking needs it's own locks, lists and state fields in the log
+item.
+
+Similar to the AIL, tracking of committed items is done through a new list
+called the Committed Item List (CIL).  The list tracks log items that have been
+committed and have formatted memory buffers attached to them. It tracks objects
+in transaction commit order, so when an object is relogged it is removed from
+it's place in the list and re-inserted at the tail. This is entirely arbitrary
+and done to make it easy for debugging - the last items in the list are the
+ones that are most recently modified. Ordering of the CIL is not necessary for
+transactional integrity (as discussed in the next section) so the ordering is
+done for convenience/sanity of the developers.
+
+
+Delayed Logging: Checkpoints
+
+When we have a log synchronisation event, commonly known as a "log force",
+all the items in the CIL must be written into the log via the log buffers.
+We need to write these items in the order that they exist in the CIL, and they
+need to be written as an atomic transaction. The need for all the objects to be
+written as an atomic transaction comes from the requirements of relogging and
+log replay - all the changes in all the objects in a given transaction must
+either be completely replayed during log recovery, or not replayed at all. If
+a transaction is not replayed because it is not complete in the log, then
+no later transactions should be replayed, either.
+
+To fulfill this requirement, we need to write the entire CIL in a single log
+transaction. Fortunately, the XFS log code has no fixed limit on the size of a
+transaction, nor does the log replay code. The only fundamental limit is that
+the transaction cannot be larger than just under half the size of the log.  The
+reason for this limit is that to find the head and tail of the log, there must
+be at least one complete transaction in the log at any given time. If a
+transaction is larger than half the log, then there is the possibility that a
+crash during the write of a such a transaction could partially overwrite the
+only complete previous transaction in the log. This will result in a recovery
+failure and an inconsistent filesystem and hence we must enforce the maximum
+size of a checkpoint to be slightly less than a half the log.
+
+Apart from this size requirement, a checkpoint transaction looks no different
+to any other transaction - it contains a transaction header, a series of
+formatted log items and a commit record at the tail. From a recovery
+perspective, the checkpoint transaction is also no different - just a lot
+bigger with a lot more items in it. The worst case effect of this is that we
+might need to tune the recovery transaction object hash size.
+
+Because the checkpoint is just another transaction and all the changes to log
+items are stored as log vectors, we can use the existing log buffer writing
+code to write the changes into the log. To do this efficiently, we need to
+minimise the time we hold the CIL locked while writing the checkpoint
+transaction. The current log write code enables us to do this easily with the
+way it separates the writing of the transaction contents (the log vectors) from
+the transaction commit record, but tracking this requires us to have a
+per-checkpoint context that travels through the log write process through to
+checkpoint completion.
+
+Hence a checkpoint has a context that tracks the state of the current
+checkpoint from initiation to checkpoint completion. A new context is initiated
+at the same time a checkpoint transaction is started. That is, when we remove
+all the current items from the CIL during a checkpoint operation, we move all
+those changes into the current checkpoint context. We then initialise a new
+context and attach that to the CIL for aggregation of new transactions.
+
+This allows us to unlock the CIL immediately after transfer of all the
+committed items and effectively allow new transactions to be issued while we
+are formatting the checkpoint into the log. It also allows concurrent
+checkpoints to be written into the log buffers in the case of log force heavy
+workloads, just like the existing transaction commit code does. This, however,
+requires that we strictly order the commit records in the log so that
+checkpoint sequence order is maintained during log replay.
+
+To ensure that we can be writing an item into a checkpoint transaction at
+the same time another transaction modifies the item and inserts the log item
+into the new CIL, then checkpoint transaction commit code cannot use log items
+to store the list of log vectors that need to be written into the transaction.
+Hence log vectors need to be able to be chained together to allow them to be
+detatched from the log items. That is, when the CIL is flushed the memory
+buffer and log vector attached to each log item needs to be attached to the
+checkpoint context so that the log item can be released. In diagrammatic form,
+the CIL would look like this before the flush:
+
+       CIL Head
+          |
+          V
+       Log Item <-> log vector 1       -> memory buffer
+          |                            -> vector array
+          V
+       Log Item <-> log vector 2       -> memory buffer
+          |                            -> vector array
+          V
+       ......
+          |
+          V
+       Log Item <-> log vector N-1     -> memory buffer
+          |                            -> vector array
+          V
+       Log Item <-> log vector N       -> memory buffer
+                                       -> vector array
+
+And after the flush the CIL head is empty, and the checkpoint context log
+vector list would look like:
+
+       Checkpoint Context
+          |
+          V
+       log vector 1    -> memory buffer
+          |            -> vector array
+          |            -> Log Item
+          V
+       log vector 2    -> memory buffer
+          |            -> vector array
+          |            -> Log Item
+          V
+       ......
+          |
+          V
+       log vector N-1  -> memory buffer
+          |            -> vector array
+          |            -> Log Item
+          V
+       log vector N    -> memory buffer
+                       -> vector array
+                       -> Log Item
+
+Once this transfer is done, the CIL can be unlocked and new transactions can
+start, while the checkpoint flush code works over the log vector chain to
+commit the checkpoint.
+
+Once the checkpoint is written into the log buffers, the checkpoint context is
+attached to the log buffer that the commit record was written to along with a
+completion callback. Log IO completion will call that callback, which can then
+run transaction committed processing for the log items (i.e. insert into AIL
+and unpin) in the log vector chain and then free the log vector chain and
+checkpoint context.
+
+Discussion Point: I am uncertain as to whether the log item is the most
+efficient way to track vectors, even though it seems like the natural way to do
+it. The fact that we walk the log items (in the CIL) just to chain the log
+vectors and break the link between the log item and the log vector means that
+we take a cache line hit for the log item list modification, then another for
+the log vector chaining. If we track by the log vectors, then we only need to
+break the link between the log item and the log vector, which means we should
+dirty only the log item cachelines. Normally I wouldn't be concerned about one
+vs two dirty cachelines except for the fact I've seen upwards of 80,000 log
+vectors in one checkpoint transaction. I'd guess this is a "measure and
+compare" situation that can be done after a working and reviewed implementation
+is in the dev tree....
+
+Delayed Logging: Checkpoint Sequencing
+
+One of the key aspects of the XFS transaction subsystem is that it tags
+committed transactions with the log sequence number of the transaction commit.
+This allows transactions to be issued asynchronously even though there may be
+future operations that cannot be completed until that transaction is fully
+committed to the log. In the rare case that a dependent operation occurs (e.g.
+re-using a freed metadata extent for a data extent), a special, optimised log
+force can be issued to force the dependent transaction to disk immediately.
+
+To do this, transactions need to record the LSN of the commit record of the
+transaction. This LSN comes directly from the log buffer the transaction is
+written into. While this works just fine for the existing transaction
+mechanism, it does not work for delayed logging because transactions are not
+written directly into the log buffers. Hence some other method of sequencing
+transactions is required.
+
+As discussed in the checkpoint section, delayed logging uses per-checkpoint
+contexts, and as such it is simple to assign a sequence number to each
+checkpoint. Because the switching of checkpoint contexts must be done
+atomically, it is simple to ensure that each new context has a monotonically
+increasing sequence number assigned to it without the need for an external
+atomic counter - we can just take the current context sequence number and add
+one to it for the new context.
+
+Then, instead of assigning a log buffer LSN to the transaction commit LSN
+during the commit, we can assign the current checkpoint sequence. This allows
+operations that track transactions that have not yet completed know what
+checkpoint sequence needs to be committed before they can continue. As a
+result, the code that forces the log to a specific LSN now needs to ensure that
+the log forces to a specific checkpoint.
+
+To ensure that we can do this, we need to track all the checkpoint contexts
+that are currently committing to the log. When we flush a checkpoint, the
+context gets added to a "committing" list which can be searched. When a
+checkpoint commit completes, it is removed from the committing list. Because
+the checkpoint context records the LSN of the commit record for the checkpoint,
+we can also wait on the log buffer that contains the commit record, thereby
+using the existing log force mechanisms to execute synchronous forces.
+
+It should be noted that the synchronous forces may need to be extended with
+mitigation algorithms similar to the current log buffer code to allow
+aggregation of multiple synchronous transactions if there are already
+synchronous transactions being flushed. Investigation of the performance of the
+current design is needed before making any decisions here.
+
+The main concern with log forces is to ensure that all the previous checkpoints
+are also committed to disk before the one we need to wait for. Therefore we
+need to check that all the prior contexts in the committing list are also
+complete before waiting on the one we need to complete. We do this
+synchronisation in the log force code so that we don't need to wait anywhere
+else for such serialisation - it only matters when we do a log force.
+
+The only remaining complexity is that a log force now also has to handle the
+case where the forcing sequence number is the same as the current context. That
+is, we need to flush the CIL and potentially wait for it to complete. This is a
+simple addition to the existing log forcing code to check the sequence numbers
+and push if required. Indeed, placing the current sequence checkpoint flush in
+the log force code enables the current mechanism for issuing synchronous
+transactions to remain untouched (i.e. commit an asynchronous transaction, then
+force the log at the LSN of that transaction) and so the higher level code
+behaves the same regardless of whether delayed logging is being used or not.
+
+Delayed Logging: Checkpoint Log Space Accounting
+
+The big issue for a checkpoint transaction is the log space reservation for the
+transaction. We don't know how big a checkpoint transaction is going to be
+ahead of time, nor how many log buffers it will take to write out, nor the
+number of split log vector regions are going to be used. We can track the
+amount of log space required as we add items to the commit item list, but we
+still need to reserve the space in the log for the checkpoint.
+
+A typical transaction reserves enough space in the log for the worst case space
+usage of the transaction. The reservation accounts for log record headers,
+transaction and region headers, headers for split regions, buffer tail padding,
+etc. as well as the actual space for all the changed metadata in the
+transaction. While some of this is fixed overhead, much of it is dependent on
+the size of the transaction and the number of regions being logged (the number
+of log vectors in the transaction).
+
+An example of the differences would be logging directory changes versus logging
+inode changes. If you modify lots of inode cores (e.g. chmod -R g+w *), then
+there are lots of transactions that only contain an inode core and an inode log
+format structure. That is, two vectors totaling roughly 150 bytes. If we modify
+10,000 inodes, we have about 1.5MB of metadata to write in 20,000 vectors. Each
+vector is 12 bytes, so the total to be logged is approximately 1.75MB. In
+comparison, if we are logging full directory buffers, they are typically 4KB
+each, so we in 1.5MB of directory buffers we'd have roughly 400 buffers and a
+buffer format structure for each buffer - roughly 800 vectors or 1.51MB total
+space.  From this, it should be obvious that a static log space reservation is
+not particularly flexible and is difficult to select the "optimal value" for
+all workloads.
+
+Further, if we are going to use a static reservation, which bit of the entire
+reservation does it cover? We account for space used by the transaction
+reservation by tracking the space currently used by the object in the CIL and
+then calculating the increase or decrease in space used as the object is
+relogged. This allows for a checkpoint reservation to only have to account for
+log buffer metadata used such as log header records.
+
+However, even using a static reservation for just the log metadata is
+problematic. Typically log record headers use at least 16KB of log space per
+1MB of log space consumed (512 bytes per 32k) and the reservation needs to be
+large enough to handle arbitrary sized checkpoint transactions. This
+reservation needs to be made before the checkpoint is started, and we need to
+be able to reserve the space without sleeping.  For a 8MB checkpoint, we need a
+reservation of around 150KB, which is a non-trivial amount of space.
+
+A static reservation needs to manipulate the log grant counters - we can take a
+permanent reservation on the space, but we still need to make sure we refresh
+the write reservation (the actual space available to the transaction) after
+every checkpoint transaction completion. Unfortunately, if this space is not
+available when required, then the regrant code will sleep waiting for it.
+
+The problem with this is that it can lead to deadlocks as we may need to commit
+checkpoints to be able to free up log space (refer back to the description of
+rolling transactions for an example of this).  Hence we *must* always have
+space available in the log if we are to use static reservations, and that is
+very difficult and complex to arrange. It is possible to do, but there is a
+simpler way.
+
+The simpler way of doing this is tracking the entire log space used by the
+items in the CIL and using this to dynamically calculate the amount of log
+space required by the log metadata. If this log metadata space changes as a
+result of a transaction commit inserting a new memory buffer into the CIL, then
+the difference in space required is removed from the transaction that causes
+the change. Transactions at this level will *always* have enough space
+available in their reservation for this as they have already reserved the
+maximal amount of log metadata space they require, and such a delta reservation
+will always be less than or equal to the maximal amount in the reservation.
+
+Hence we can grow the checkpoint transaction reservation dynamically as items
+are added to the CIL and avoid the need for reserving and regranting log space
+up front. This avoids deadlocks and removes a blocking point from the
+checkpoint flush code.
+
+As mentioned early, transactions can't grow to more than half the size of the
+log. Hence as part of the reservation growing, we need to also check the size
+of the reservation against the maximum allowed transaction size. If we reach
+the maximum threshold, we need to push the CIL to the log. This is effectively
+a "background flush" and is done on demand. This is identical to
+a CIL push triggered by a log force, only that there is no waiting for the
+checkpoint commit to complete. This background push is checked and executed by
+transaction commit code.
+
+If the transaction subsystem goes idle while we still have items in the CIL,
+they will be flushed by the periodic log force issued by the xfssyncd. This log
+force will push the CIL to disk, and if the transaction subsystem stays idle,
+allow the idle log to be covered (effectively marked clean) in exactly the same
+manner that is done for the existing logging method. A discussion point is
+whether this log force needs to be done more frequently than the current rate
+which is once every 30s.
+
+
+Delayed Logging: Log Item Pinning
+
+Currently log items are pinned during transaction commit while the items are
+still locked. This happens just after the items are formatted, though it could
+be done any time before the items are unlocked. The result of this mechanism is
+that items get pinned once for every transaction that is committed to the log
+buffers. Hence items that are relogged in the log buffers will have a pin count
+for every outstanding transaction they were dirtied in. When each of these
+transactions is completed, they will unpin the item once. As a result, the item
+only becomes unpinned when all the transactions complete and there are no
+pending transactions. Thus the pinning and unpinning of a log item is symmetric
+as there is a 1:1 relationship with transaction commit and log item completion.
+
+For delayed logging, however, we have an assymetric transaction commit to
+completion relationship. Every time an object is relogged in the CIL it goes
+through the commit process without a corresponding completion being registered.
+That is, we now have a many-to-one relationship between transaction commit and
+log item completion. The result of this is that pinning and unpinning of the
+log items becomes unbalanced if we retain the "pin on transaction commit, unpin
+on transaction completion" model.
+
+To keep pin/unpin symmetry, the algorithm needs to change to a "pin on
+insertion into the CIL, unpin on checkpoint completion". In other words, the
+pinning and unpinning becomes symmetric around a checkpoint context. We have to
+pin the object the first time it is inserted into the CIL - if it is already in
+the CIL during a transaction commit, then we do not pin it again. Because there
+can be multiple outstanding checkpoint contexts, we can still see elevated pin
+counts, but as each checkpoint completes the pin count will retain the correct
+value according to it's context.
+
+Just to make matters more slightly more complex, this checkpoint level context
+for the pin count means that the pinning of an item must take place under the
+CIL commit/flush lock. If we pin the object outside this lock, we cannot
+guarantee which context the pin count is associated with. This is because of
+the fact pinning the item is dependent on whether the item is present in the
+current CIL or not. If we don't pin the CIL first before we check and pin the
+object, we have a race with CIL being flushed between the check and the pin
+(or not pinning, as the case may be). Hence we must hold the CIL flush/commit
+lock to guarantee that we pin the items correctly.
+
+Delayed Logging: Concurrent Scalability
+
+A fundamental requirement for the CIL is that accesses through transaction
+commits must scale to many concurrent commits. The current transaction commit
+code does not break down even when there are transactions coming from 2048
+processors at once. The current transaction code does not go any faster than if
+there was only one CPU using it, but it does not slow down either.
+
+As a result, the delayed logging transaction commit code needs to be designed
+for concurrency from the ground up. It is obvious that there are serialisation
+points in the design - the three important ones are:
+
+       1. Locking out new transaction commits while flushing the CIL
+       2. Adding items to the CIL and updating item space accounting
+       3. Checkpoint commit ordering
+
+Looking at the transaction commit and CIL flushing interactions, it is clear
+that we have a many-to-one interaction here. That is, the only restriction on
+the number of concurrent transactions that can be trying to commit at once is
+the amount of space available in the log for their reservations. The practical
+limit here is in the order of several hundred concurrent transactions for a
+128MB log, which means that it is generally one per CPU in a machine.
+
+The amount of time a transaction commit needs to hold out a flush is a
+relatively long period of time - the pinning of log items needs to be done
+while we are holding out a CIL flush, so at the moment that means it is held
+across the formatting of the objects into memory buffers (i.e. while memcpy()s
+are in progress). Ultimately a two pass algorithm where the formatting is done
+separately to the pinning of objects could be used to reduce the hold time of
+the transaction commit side.
+
+Because of the number of potential transaction commit side holders, the lock
+really needs to be a sleeping lock - if the CIL flush takes the lock, we do not
+want every other CPU in the machine spinning on the CIL lock. Given that
+flushing the CIL could involve walking a list of tens of thousands of log
+items, it will get held for a significant time and so spin contention is a
+significant concern. Preventing lots of CPUs spinning doing nothing is the
+main reason for choosing a sleeping lock even though nothing in either the
+transaction commit or CIL flush side sleeps with the lock held.
+
+It should also be noted that CIL flushing is also a relatively rare operation
+compared to transaction commit for asynchronous transaction workloads - only
+time will tell if using a read-write semaphore for exclusion will limit
+transaction commit concurrency due to cache line bouncing of the lock on the
+read side.
+
+The second serialisation point is on the transaction commit side where items
+are inserted into the CIL. Because transactions can enter this code
+concurrently, the CIL needs to be protected separately from the above
+commit/flush exclusion. It also needs to be an exclusive lock but it is only
+held for a very short time and so a spin lock is appropriate here. It is
+possible that this lock will become a contention point, but given the short
+hold time once per transaction I think that contention is unlikely.
+
+The final serialisation point is the checkpoint commit record ordering code
+that is run as part of the checkpoint commit and log force sequencing. The code
+path that triggers a CIL flush (i.e. whatever triggers the log force) will enter
+an ordering loop after writing all the log vectors into the log buffers but
+before writing the commit record. This loop walks the list of committing
+checkpoints and needs to block waiting for checkpoints to complete their commit
+record write. As a result it needs a lock and a wait variable. Log force
+sequencing also requires the same lock, list walk, and blocking mechanism to
+ensure completion of checkpoints.
+
+These two sequencing operations can use the mechanism even though the
+events they are waiting for are different. The checkpoint commit record
+sequencing needs to wait until checkpoint contexts contain a commit LSN
+(obtained through completion of a commit record write) while log force
+sequencing needs to wait until previous checkpoint contexts are removed from
+the committing list (i.e. they've completed). A simple wait variable and
+broadcast wakeups (thundering herds) has been used to implement these two
+serialisation queues. They use the same lock as the CIL, too. If we see too
+much contention on the CIL lock, or too many context switches as a result of
+the broadcast wakeups these operations can be put under a new spinlock and
+given separate wait lists to reduce lock contention and the number of processes
+woken by the wrong event.
+
+
+Lifecycle Changes
+
+The existing log item life cycle is as follows:
+
+       1. Transaction allocate
+       2. Transaction reserve
+       3. Lock item
+       4. Join item to transaction
+               If not already attached,
+                       Allocate log item
+                       Attach log item to owner item
+               Attach log item to transaction
+       5. Modify item
+               Record modifications in log item
+       6. Transaction commit
+               Pin item in memory
+               Format item into log buffer
+               Write commit LSN into transaction
+               Unlock item
+               Attach transaction to log buffer
+
+       <log buffer IO dispatched>
+       <log buffer IO completes>
+
+       7. Transaction completion
+               Mark log item committed
+               Insert log item into AIL
+                       Write commit LSN into log item
+               Unpin log item
+       8. AIL traversal
+               Lock item
+               Mark log item clean
+               Flush item to disk
+
+       <item IO completion>
+
+       9. Log item removed from AIL
+               Moves log tail
+               Item unlocked
+
+Essentially, steps 1-6 operate independently from step 7, which is also
+independent of steps 8-9. An item can be locked in steps 1-6 or steps 8-9
+at the same time step 7 is occurring, but only steps 1-6 or 8-9 can occur
+at the same time. If the log item is in the AIL or between steps 6 and 7
+and steps 1-6 are re-entered, then the item is relogged. Only when steps 8-9
+are entered and completed is the object considered clean.
+
+With delayed logging, there are new steps inserted into the life cycle:
+
+       1. Transaction allocate
+       2. Transaction reserve
+       3. Lock item
+       4. Join item to transaction
+               If not already attached,
+                       Allocate log item
+                       Attach log item to owner item
+               Attach log item to transaction
+       5. Modify item
+               Record modifications in log item
+       6. Transaction commit
+               Pin item in memory if not pinned in CIL
+               Format item into log vector + buffer
+               Attach log vector and buffer to log item
+               Insert log item into CIL
+               Write CIL context sequence into transaction
+               Unlock item
+
+       <next log force>
+
+       7. CIL push
+               lock CIL flush
+               Chain log vectors and buffers together
+               Remove items from CIL
+               unlock CIL flush
+               write log vectors into log
+               sequence commit records
+               attach checkpoint context to log buffer
+
+       <log buffer IO dispatched>
+       <log buffer IO completes>
+
+       8. Checkpoint completion
+               Mark log item committed
+               Insert item into AIL
+                       Write commit LSN into log item
+               Unpin log item
+       9. AIL traversal
+               Lock item
+               Mark log item clean
+               Flush item to disk
+       <item IO completion>
+       10. Log item removed from AIL
+               Moves log tail
+               Item unlocked
+
+From this, it can be seen that the only life cycle differences between the two
+logging methods are in the middle of the life cycle - they still have the same
+beginning and end and execution constraints. The only differences are in the
+commiting of the log items to the log itself and the completion processing.
+Hence delayed logging should not introduce any constraints on log item
+behaviour, allocation or freeing that don't already exist.
+
+As a result of this zero-impact "insertion" of delayed logging infrastructure
+and the design of the internal structures to avoid on disk format changes, we
+can basically switch between delayed logging and the existing mechanism with a
+mount option. Fundamentally, there is no reason why the log manager would not
+be able to swap methods automatically and transparently depending on load
+characteristics, but this should not be necessary if delayed logging works as
+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:
+               => gain confidence and fix problems reported by early
+                  adopters (a.k.a. guinea pigs)
+               => address worst performance regressions and undesired
+                  behaviours
+               => start tuning/optimising code for parallelism
+               => start tuning/optimising algorithms consuming
+                  excessive CPU time
+
+2.6.39 Switch default mount option to use delayed logging
+       => should be roughly 12 months after initial merge
+       => enough time to shake out remaining problems before next round of
+          enterprise distro kernel rebases
index 001d2e70bc1125f404274734f6ad0b4b7825ca34..fc5df7654d6380be504fb1dc66b12032b336b934 100644 (file)
@@ -9,11 +9,15 @@ Supported chips:
   * SMSC SCH3112, SCH3114, SCH3116
     Prefix: 'sch311x'
     Addresses scanned: none, address read from Super-I/O config space
-    Datasheet: http://www.nuhorizons.com/FeaturedProducts/Volume1/SMSC/311x.pdf
+    Datasheet: Available on the Internet
   * SMSC SCH5027
     Prefix: 'sch5027'
     Addresses scanned: I2C 0x2c, 0x2d, 0x2e
     Datasheet: Provided by SMSC upon request and under NDA
+  * SMSC SCH5127
+    Prefix: 'sch5127'
+    Addresses scanned: none, address read from Super-I/O config space
+    Datasheet: Provided by SMSC upon request and under NDA
 
 Authors:
     Juerg Haefliger <juergh@gmail.com>
@@ -36,8 +40,8 @@ Description
 -----------
 
 This driver implements support for the hardware monitoring capabilities of the
-SMSC DME1737 and Asus A8000 (which are the same), SMSC SCH5027, and SMSC
-SCH311x Super-I/O chips. These chips feature monitoring of 3 temp sensors
+SMSC DME1737 and Asus A8000 (which are the same), SMSC SCH5027, SCH311x,
+and SCH5127 Super-I/O chips. These chips feature monitoring of 3 temp sensors
 temp[1-3] (2 remote diodes and 1 internal), 7 voltages in[0-6] (6 external and
 1 internal) and up to 6 fan speeds fan[1-6]. Additionally, the chips implement
 up to 5 PWM outputs pwm[1-3,5-6] for controlling fan speeds both manually and
@@ -48,14 +52,14 @@ Fan[3-6] and pwm[3,5-6] are optional features and their availability depends on
 the configuration of the chip. The driver will detect which features are
 present during initialization and create the sysfs attributes accordingly.
 
-For the SCH311x, fan[1-3] and pwm[1-3] are always present and fan[4-6] and
-pwm[5-6] don't exist.
+For the SCH311x and SCH5127, fan[1-3] and pwm[1-3] are always present and
+fan[4-6] and pwm[5-6] don't exist.
 
 The hardware monitoring features of the DME1737, A8000, and SCH5027 are only
-accessible via SMBus, while the SCH311x only provides access via the ISA bus.
-The driver will therefore register itself as an I2C client driver if it detects
-a DME1737, A8000, or SCH5027 and as a platform driver if it detects a SCH311x
-chip.
+accessible via SMBus, while the SCH311x and SCH5127 only provide access via
+the ISA bus. The driver will therefore register itself as an I2C client driver
+if it detects a DME1737, A8000, or SCH5027 and as a platform driver if it
+detects a SCH311x or SCH5127 chip.
 
 
 Voltage Monitoring
@@ -76,7 +80,7 @@ DME1737, A8000:
        in6: Vbat       (+3.0V)                 0V - 4.38V
 
 SCH311x:
-       in0: +2.5V                              0V - 6.64V
+       in0: +2.5V                              0V - 3.32V
        in1: Vccp       (processor core)        0V - 2V
        in2: VCC        (internal +3.3V)        0V - 4.38V
        in3: +5V                                0V - 6.64V
@@ -93,6 +97,15 @@ SCH5027:
        in5: VTR        (+3.3V standby)         0V - 4.38V
        in6: Vbat       (+3.0V)                 0V - 4.38V
 
+SCH5127:
+       in0: +2.5                               0V - 3.32V
+       in1: Vccp       (processor core)        0V - 3V
+       in2: VCC        (internal +3.3V)        0V - 4.38V
+       in3: V2_IN                              0V - 1.5V
+       in4: V1_IN                              0V - 1.5V
+       in5: VTR        (+3.3V standby)         0V - 4.38V
+       in6: Vbat       (+3.0V)                 0V - 4.38V
+
 Each voltage input has associated min and max limits which trigger an alarm
 when crossed.
 
@@ -293,3 +306,21 @@ pwm[1-3]_auto_point1_pwm   RW      Auto PWM pwm point. Auto_point1 is the
 pwm[1-3]_auto_point2_pwm       RO      Auto PWM pwm point. Auto_point2 is the
                                        full-speed duty-cycle which is hard-
                                        wired to 255 (100% duty-cycle).
+
+Chip Differences
+----------------
+
+Feature                        dme1737 sch311x sch5027 sch5127
+-------------------------------------------------------
+temp[1-3]_offset       yes     yes
+vid                    yes
+zone3                  yes     yes     yes
+zone[1-3]_hyst         yes     yes
+pwm min/off            yes     yes
+fan3                   opt     yes     opt     yes
+pwm3                   opt     yes     opt     yes
+fan4                   opt             opt
+fan5                   opt             opt
+pwm5                   opt             opt
+fan6                   opt             opt
+pwm6                   opt             opt
index 31660bf979795a68dc6b9918e4fd1ae32cf80892..b9843eab1afb107d6ffb13239b6df435bd7c8c54 100644 (file)
@@ -7,6 +7,11 @@ Supported chips:
     Addresses scanned: I2C 0x4c
     Datasheet: Publicly available at the National Semiconductor website
                http://www.national.com/pf/LM/LM63.html
+  * National Semiconductor LM64
+    Prefix: 'lm64'
+    Addresses scanned: I2C 0x18 and 0x4e
+    Datasheet: Publicly available at the National Semiconductor website
+               http://www.national.com/pf/LM/LM64.html
 
 Author: Jean Delvare <khali@linux-fr.org>
 
@@ -55,3 +60,5 @@ The lm63 driver will not update its values more frequently than every
 second; reading them more often will do no harm, but will return 'old'
 values.
 
+The LM64 is effectively an LM63 with GPIO lines. The driver does not
+support these GPIO lines at present.
index 02838a47d86210fa8bee469f595c94851594bd44..86b5880d8502b123e508c94330e61ea255db1292 100644 (file)
@@ -72,9 +72,7 @@ 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 #1 voltage data
-in10_input             GPIO #2 voltage data
-in11_input             GPIO #3 voltage data
+in9_input              GPIO voltage data
 
 power1_input           12v power usage (mW)
 power2_input           5v  power usage (mW)
index 3de6b0bcb1474ecda75e9aa4ff275d3b3af67a6f..d4e2917c6f18b69d9e9a36e39d228ab36bd3d87b 100644 (file)
@@ -80,9 +80,9 @@ All entries (except name) are optional, and should only be created in a
 given driver if the chip has the feature.
 
 
-********
-* Name *
-********
+*********************
+* Global attributes *
+*********************
 
 name           The chip name.
                This should be a short, lowercase string, not containing
@@ -91,6 +91,13 @@ name         The chip name.
                I2C devices get this attribute created automatically.
                RO
 
+update_rate    The rate at which the chip will update readings.
+               Unit: millisecond
+               RW
+               Some devices have a variable update rate. This attribute
+               can be used to change the update rate to the desired
+               frequency.
+
 
 ************
 * Voltages *
diff --git a/Documentation/hwmon/tmp102 b/Documentation/hwmon/tmp102
new file mode 100644 (file)
index 0000000..8454a77
--- /dev/null
@@ -0,0 +1,26 @@
+Kernel driver tmp102
+====================
+
+Supported chips:
+  * Texas Instruments TMP102
+    Prefix: 'tmp102'
+    Addresses scanned: none
+    Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp102.html
+
+Author:
+       Steven King <sfking@fdwdc.com>
+
+Description
+-----------
+
+The Texas Instruments TMP102 implements one temperature sensor.  Limits can be
+set through the Overtemperature Shutdown register and Hysteresis register.  The
+sensor is accurate to 0.5 degree over the range of -25 to +85 C, and to 1.0
+degree from -40 to +125 C. Resolution of the sensor is 0.0625 degree.  The
+operating temperature has a minimum of -55 C and a maximum of +150 C.
+
+The TMP102 has a programmable update rate that can select between 8, 4, 1, and
+0.5 Hz. (Currently the driver only supports the default of 4 Hz).
+
+The driver provides the common sysfs-interface for temperatures (see
+Documentation/hwmon/sysfs-interface under Temperatures).
index f5fce483930cf933d0eb7928f1a4fa6cfe8ff921..1808f1157f30ae5a187f4a8783d973875cd675dd 100644 (file)
@@ -145,11 +145,10 @@ and is between 256 and 4096 characters. It is defined in the file
 
        acpi=           [HW,ACPI,X86]
                        Advanced Configuration and Power Interface
-                       Format: { force | off | ht | strict | noirq | rsdt }
+                       Format: { force | off | strict | noirq | rsdt }
                        force -- enable ACPI if default was off
                        off -- disable ACPI if default was on
                        noirq -- do not use ACPI for IRQ routing
-                       ht -- run only enough ACPI to enable Hyper Threading
                        strict -- Be less tolerant of platforms that are not
                                strictly ACPI specification compliant.
                        rsdt -- prefer RSDT over (default) XSDT
@@ -290,9 +289,6 @@ and is between 256 and 4096 characters. It is defined in the file
        advansys=       [HW,SCSI]
                        See header of drivers/scsi/advansys.c.
 
-       advwdt=         [HW,WDT] Advantech WDT
-                       Format: <iostart>,<iostop>
-
        aedsp16=        [HW,OSS] Audio Excel DSP 16
                        Format: <io>,<irq>,<dma>,<mss_io>,<mpu_io>,<mpu_irq>
                        See also header of sound/oss/aedsp16.c.
@@ -761,13 +757,14 @@ and is between 256 and 4096 characters. It is defined in the file
                        Default value is 0.
                        Value can be changed at runtime via /selinux/enforce.
 
+       erst_disable    [ACPI]
+                       Disable Error Record Serialization Table (ERST)
+                       support.
+
        ether=          [HW,NET] Ethernet cards parameters
                        This option is obsoleted by the "netdev=" option, which
                        has equivalent usage. See its documentation for details.
 
-       eurwdt=         [HW,WDT] Eurotech CPU-1220/1410 onboard watchdog.
-                       Format: <io>[,<irq>]
-
        failslab=
        fail_page_alloc=
        fail_make_request=[KNL]
@@ -858,6 +855,11 @@ and is between 256 and 4096 characters. It is defined in the file
        hd=             [EIDE] (E)IDE hard drive subsystem geometry
                        Format: <cyl>,<head>,<sect>
 
+       hest_disable    [ACPI]
+                       Disable Hardware Error Source Table (HEST) support;
+                       corresponding firmware-first mode error processing
+                       logic will be disabled.
+
        highmem=nn[KMG] [KNL,BOOT] forces the highmem zone to have an exact
                        size of <nn>. This works even on boxes that have no
                        highmem otherwise. This also works to reduce highmem
@@ -1258,6 +1260,8 @@ and is between 256 and 4096 characters. It is defined in the file
                        * nohrst, nosrst, norst: suppress hard, soft
                           and both resets.
 
+                       * dump_id: dump IDENTIFY data.
+
                        If there are multiple matching configurations changing
                        the same attribute, the last one is used.
 
@@ -2267,9 +2271,6 @@ and is between 256 and 4096 characters. It is defined in the file
 
        sched_debug     [KNL] Enables verbose scheduler debug messages.
 
-       sc1200wdt=      [HW,WDT] SC1200 WDT (watchdog) driver
-                       Format: <io>[,<timeout>[,<isapnp>]]
-
        scsi_debug_*=   [SCSI]
                        See drivers/scsi/scsi_debug.c.
 
@@ -2858,8 +2859,10 @@ and is between 256 and 4096 characters. It is defined in the file
        wd7000=         [HW,SCSI]
                        See header of drivers/scsi/wd7000.c.
 
-       wdt=            [WDT] Watchdog
-                       See Documentation/watchdog/wdt.txt.
+       watchdog timers [HW,WDT] For information on watchdog timers,
+                       see Documentation/watchdog/watchdog-parameters.txt
+                       or other driver-specific files in the
+                       Documentation/watchdog/ directory.
 
        x2apic_phys     [X86-64,APIC] Use x2apic physical mode instead of
                        default x2apic cluster mode on platforms
index c6416a398163155bc64341754b99039aba529502..a237518e51b971e9beafab8209e96ffeff7f8242 100644 (file)
@@ -656,6 +656,7 @@ struct kvm_clock_data {
 4.29 KVM_GET_VCPU_EVENTS
 
 Capability: KVM_CAP_VCPU_EVENTS
+Extended by: KVM_CAP_INTR_SHADOW
 Architectures: x86
 Type: vm ioctl
 Parameters: struct kvm_vcpu_event (out)
@@ -676,7 +677,7 @@ struct kvm_vcpu_events {
                __u8 injected;
                __u8 nr;
                __u8 soft;
-               __u8 pad;
+               __u8 shadow;
        } interrupt;
        struct {
                __u8 injected;
@@ -688,9 +689,13 @@ struct kvm_vcpu_events {
        __u32 flags;
 };
 
+KVM_VCPUEVENT_VALID_SHADOW may be set in the flags field to signal that
+interrupt.shadow contains a valid state. Otherwise, this field is undefined.
+
 4.30 KVM_SET_VCPU_EVENTS
 
 Capability: KVM_CAP_VCPU_EVENTS
+Extended by: KVM_CAP_INTR_SHADOW
 Architectures: x86
 Type: vm ioctl
 Parameters: struct kvm_vcpu_event (in)
@@ -709,6 +714,183 @@ current in-kernel state. The bits are:
 KVM_VCPUEVENT_VALID_NMI_PENDING - transfer nmi.pending to the kernel
 KVM_VCPUEVENT_VALID_SIPI_VECTOR - transfer sipi_vector
 
+If KVM_CAP_INTR_SHADOW is available, KVM_VCPUEVENT_VALID_SHADOW can be set in
+the flags field to signal that interrupt.shadow contains a valid state and
+shall be written into the VCPU.
+
+4.32 KVM_GET_DEBUGREGS
+
+Capability: KVM_CAP_DEBUGREGS
+Architectures: x86
+Type: vm ioctl
+Parameters: struct kvm_debugregs (out)
+Returns: 0 on success, -1 on error
+
+Reads debug registers from the vcpu.
+
+struct kvm_debugregs {
+       __u64 db[4];
+       __u64 dr6;
+       __u64 dr7;
+       __u64 flags;
+       __u64 reserved[9];
+};
+
+4.33 KVM_SET_DEBUGREGS
+
+Capability: KVM_CAP_DEBUGREGS
+Architectures: x86
+Type: vm ioctl
+Parameters: struct kvm_debugregs (in)
+Returns: 0 on success, -1 on error
+
+Writes debug registers into the vcpu.
+
+See KVM_GET_DEBUGREGS for the data structure. The flags field is unused
+yet and must be cleared on entry.
+
+4.34 KVM_SET_USER_MEMORY_REGION
+
+Capability: KVM_CAP_USER_MEM
+Architectures: all
+Type: vm ioctl
+Parameters: struct kvm_userspace_memory_region (in)
+Returns: 0 on success, -1 on error
+
+struct kvm_userspace_memory_region {
+       __u32 slot;
+       __u32 flags;
+       __u64 guest_phys_addr;
+       __u64 memory_size; /* bytes */
+       __u64 userspace_addr; /* start of the userspace allocated memory */
+};
+
+/* for kvm_memory_region::flags */
+#define KVM_MEM_LOG_DIRTY_PAGES  1UL
+
+This ioctl allows the user to create or modify a guest physical memory
+slot.  When changing an existing slot, it may be moved in the guest
+physical memory space, or its flags may be modified.  It may not be
+resized.  Slots may not overlap in guest physical address space.
+
+Memory for the region is taken starting at the address denoted by the
+field userspace_addr, which must point at user addressable memory for
+the entire memory slot size.  Any object may back this memory, including
+anonymous memory, ordinary files, and hugetlbfs.
+
+It is recommended that the lower 21 bits of guest_phys_addr and userspace_addr
+be identical.  This allows large pages in the guest to be backed by large
+pages in the host.
+
+The flags field supports just one flag, KVM_MEM_LOG_DIRTY_PAGES, which
+instructs kvm to keep track of writes to memory within the slot.  See
+the KVM_GET_DIRTY_LOG ioctl.
+
+When the KVM_CAP_SYNC_MMU capability, changes in the backing of the memory
+region are automatically reflected into the guest.  For example, an mmap()
+that affects the region will be made visible immediately.  Another example
+is madvise(MADV_DROP).
+
+It is recommended to use this API instead of the KVM_SET_MEMORY_REGION ioctl.
+The KVM_SET_MEMORY_REGION does not allow fine grained control over memory
+allocation and is deprecated.
+
+4.35 KVM_SET_TSS_ADDR
+
+Capability: KVM_CAP_SET_TSS_ADDR
+Architectures: x86
+Type: vm ioctl
+Parameters: unsigned long tss_address (in)
+Returns: 0 on success, -1 on error
+
+This ioctl defines the physical address of a three-page region in the guest
+physical address space.  The region must be within the first 4GB of the
+guest physical address space and must not conflict with any memory slot
+or any mmio address.  The guest may malfunction if it accesses this memory
+region.
+
+This ioctl is required on Intel-based hosts.  This is needed on Intel hardware
+because of a quirk in the virtualization implementation (see the internals
+documentation when it pops into existence).
+
+4.36 KVM_ENABLE_CAP
+
+Capability: KVM_CAP_ENABLE_CAP
+Architectures: ppc
+Type: vcpu ioctl
+Parameters: struct kvm_enable_cap (in)
+Returns: 0 on success; -1 on error
+
++Not all extensions are enabled by default. Using this ioctl the application
+can enable an extension, making it available to the guest.
+
+On systems that do not support this ioctl, it always fails. On systems that
+do support it, it only works for extensions that are supported for enablement.
+
+To check if a capability can be enabled, the KVM_CHECK_EXTENSION ioctl should
+be used.
+
+struct kvm_enable_cap {
+       /* in */
+       __u32 cap;
+
+The capability that is supposed to get enabled.
+
+       __u32 flags;
+
+A bitfield indicating future enhancements. Has to be 0 for now.
+
+       __u64 args[4];
+
+Arguments for enabling a feature. If a feature needs initial values to
+function properly, this is the place to put them.
+
+       __u8  pad[64];
+};
+
+4.37 KVM_GET_MP_STATE
+
+Capability: KVM_CAP_MP_STATE
+Architectures: x86, ia64
+Type: vcpu ioctl
+Parameters: struct kvm_mp_state (out)
+Returns: 0 on success; -1 on error
+
+struct kvm_mp_state {
+       __u32 mp_state;
+};
+
+Returns the vcpu's current "multiprocessing state" (though also valid on
+uniprocessor guests).
+
+Possible values are:
+
+ - KVM_MP_STATE_RUNNABLE:        the vcpu is currently running
+ - KVM_MP_STATE_UNINITIALIZED:   the vcpu is an application processor (AP)
+                                 which has not yet received an INIT signal
+ - KVM_MP_STATE_INIT_RECEIVED:   the vcpu has received an INIT signal, and is
+                                 now ready for a SIPI
+ - KVM_MP_STATE_HALTED:          the vcpu has executed a HLT instruction and
+                                 is waiting for an interrupt
+ - KVM_MP_STATE_SIPI_RECEIVED:   the vcpu has just received a SIPI (vector
+                                 accesible via KVM_GET_VCPU_EVENTS)
+
+This ioctl is only useful after KVM_CREATE_IRQCHIP.  Without an in-kernel
+irqchip, the multiprocessing state must be maintained by userspace.
+
+4.38 KVM_SET_MP_STATE
+
+Capability: KVM_CAP_MP_STATE
+Architectures: x86, ia64
+Type: vcpu ioctl
+Parameters: struct kvm_mp_state (in)
+Returns: 0 on success; -1 on error
+
+Sets the vcpu's current "multiprocessing state"; see KVM_GET_MP_STATE for
+arguments.
+
+This ioctl is only useful after KVM_CREATE_IRQCHIP.  Without an in-kernel
+irqchip, the multiprocessing state must be maintained by userspace.
 
 5. The kvm_run structure
 
@@ -820,6 +1002,13 @@ executed a memory-mapped I/O instruction which could not be satisfied
 by kvm.  The 'data' member contains the written data if 'is_write' is
 true, and should be filled by application code otherwise.
 
+NOTE: For KVM_EXIT_IO, KVM_EXIT_MMIO and KVM_EXIT_OSI, the corresponding
+operations are complete (and guest state is consistent) only after userspace
+has re-entered the kernel with KVM_RUN.  The kernel side will first finish
+incomplete operations and then check for pending signals.  Userspace
+can re-enter the guest with an unmasked signal pending to complete
+pending operations.
+
                /* KVM_EXIT_HYPERCALL */
                struct {
                        __u64 nr;
@@ -829,7 +1018,9 @@ true, and should be filled by application code otherwise.
                        __u32 pad;
                } hypercall;
 
-Unused.
+Unused.  This was once used for 'hypercall to userspace'.  To implement
+such functionality, use KVM_EXIT_IO (x86) or KVM_EXIT_MMIO (all except s390).
+Note KVM_EXIT_IO is significantly faster than KVM_EXIT_MMIO.
 
                /* KVM_EXIT_TPR_ACCESS */
                struct {
@@ -870,6 +1061,19 @@ s390 specific.
 
 powerpc specific.
 
+               /* KVM_EXIT_OSI */
+               struct {
+                       __u64 gprs[32];
+               } osi;
+
+MOL uses a special hypercall interface it calls 'OSI'. To enable it, we catch
+hypercalls and exit with this exit struct that contains all the guest gprs.
+
+If exit_reason is KVM_EXIT_OSI, then the vcpu has triggered such a hypercall.
+Userspace can now handle the hypercall and when it's done modify the gprs as
+necessary. Upon guest entry all guest GPRs will then be replaced by the values
+in this struct.
+
                /* Fix the size of the union. */
                char padding[256];
        };
diff --git a/Documentation/kvm/cpuid.txt b/Documentation/kvm/cpuid.txt
new file mode 100644 (file)
index 0000000..14a12ea
--- /dev/null
@@ -0,0 +1,42 @@
+KVM CPUID bits
+Glauber Costa <glommer@redhat.com>, Red Hat Inc, 2010
+=====================================================
+
+A guest running on a kvm host, can check some of its features using
+cpuid. This is not always guaranteed to work, since userspace can
+mask-out some, or even all KVM-related cpuid features before launching
+a guest.
+
+KVM cpuid functions are:
+
+function: KVM_CPUID_SIGNATURE (0x40000000)
+returns : eax = 0,
+          ebx = 0x4b4d564b,
+          ecx = 0x564b4d56,
+          edx = 0x4d.
+Note that this value in ebx, ecx and edx corresponds to the string "KVMKVMKVM".
+This function queries the presence of KVM cpuid leafs.
+
+
+function: define KVM_CPUID_FEATURES (0x40000001)
+returns : ebx, ecx, edx = 0
+          eax = and OR'ed group of (1 << flag), where each flags is:
+
+
+flag                               || value || meaning
+=============================================================================
+KVM_FEATURE_CLOCKSOURCE            ||     0 || kvmclock available at msrs
+                                   ||       || 0x11 and 0x12.
+------------------------------------------------------------------------------
+KVM_FEATURE_NOP_IO_DELAY           ||     1 || not necessary to perform delays
+                                   ||       || on PIO operations.
+------------------------------------------------------------------------------
+KVM_FEATURE_MMU_OP                 ||     2 || deprecated.
+------------------------------------------------------------------------------
+KVM_FEATURE_CLOCKSOURCE2           ||     3 || kvmclock available at msrs
+                                   ||       || 0x4b564d00 and 0x4b564d01
+------------------------------------------------------------------------------
+KVM_FEATURE_CLOCKSOURCE_STABLE_BIT ||    24 || host will warn if no guest-side
+                                   ||       || per-cpu warps are expected in
+                                   ||       || kvmclock.
+------------------------------------------------------------------------------
diff --git a/Documentation/kvm/mmu.txt b/Documentation/kvm/mmu.txt
new file mode 100644 (file)
index 0000000..aaed6ab
--- /dev/null
@@ -0,0 +1,304 @@
+The x86 kvm shadow mmu
+======================
+
+The mmu (in arch/x86/kvm, files mmu.[ch] and paging_tmpl.h) is responsible
+for presenting a standard x86 mmu to the guest, while translating guest
+physical addresses to host physical addresses.
+
+The mmu code attempts to satisfy the following requirements:
+
+- correctness: the guest should not be able to determine that it is running
+               on an emulated mmu except for timing (we attempt to comply
+               with the specification, not emulate the characteristics of
+               a particular implementation such as tlb size)
+- security:    the guest must not be able to touch host memory not assigned
+               to it
+- performance: minimize the performance penalty imposed by the mmu
+- scaling:     need to scale to large memory and large vcpu guests
+- hardware:    support the full range of x86 virtualization hardware
+- integration: Linux memory management code must be in control of guest memory
+               so that swapping, page migration, page merging, transparent
+               hugepages, and similar features work without change
+- dirty tracking: report writes to guest memory to enable live migration
+               and framebuffer-based displays
+- footprint:   keep the amount of pinned kernel memory low (most memory
+               should be shrinkable)
+- reliablity:  avoid multipage or GFP_ATOMIC allocations
+
+Acronyms
+========
+
+pfn   host page frame number
+hpa   host physical address
+hva   host virtual address
+gfn   guest frame number
+gpa   guest physical address
+gva   guest virtual address
+ngpa  nested guest physical address
+ngva  nested guest virtual address
+pte   page table entry (used also to refer generically to paging structure
+      entries)
+gpte  guest pte (referring to gfns)
+spte  shadow pte (referring to pfns)
+tdp   two dimensional paging (vendor neutral term for NPT and EPT)
+
+Virtual and real hardware supported
+===================================
+
+The mmu supports first-generation mmu hardware, which allows an atomic switch
+of the current paging mode and cr3 during guest entry, as well as
+two-dimensional paging (AMD's NPT and Intel's EPT).  The emulated hardware
+it exposes is the traditional 2/3/4 level x86 mmu, with support for global
+pages, pae, pse, pse36, cr0.wp, and 1GB pages.  Work is in progress to support
+exposing NPT capable hardware on NPT capable hosts.
+
+Translation
+===========
+
+The primary job of the mmu is to program the processor's mmu to translate
+addresses for the guest.  Different translations are required at different
+times:
+
+- when guest paging is disabled, we translate guest physical addresses to
+  host physical addresses (gpa->hpa)
+- when guest paging is enabled, we translate guest virtual addresses, to
+  guest physical addresses, to host physical addresses (gva->gpa->hpa)
+- when the guest launches a guest of its own, we translate nested guest
+  virtual addresses, to nested guest physical addresses, to guest physical
+  addresses, to host physical addresses (ngva->ngpa->gpa->hpa)
+
+The primary challenge is to encode between 1 and 3 translations into hardware
+that support only 1 (traditional) and 2 (tdp) translations.  When the
+number of required translations matches the hardware, the mmu operates in
+direct mode; otherwise it operates in shadow mode (see below).
+
+Memory
+======
+
+Guest memory (gpa) is part of the user address space of the process that is
+using kvm.  Userspace defines the translation between guest addresses and user
+addresses (gpa->hva); note that two gpas may alias to the same gva, but not
+vice versa.
+
+These gvas may be backed using any method available to the host: anonymous
+memory, file backed memory, and device memory.  Memory might be paged by the
+host at any time.
+
+Events
+======
+
+The mmu is driven by events, some from the guest, some from the host.
+
+Guest generated events:
+- writes to control registers (especially cr3)
+- invlpg/invlpga instruction execution
+- access to missing or protected translations
+
+Host generated events:
+- changes in the gpa->hpa translation (either through gpa->hva changes or
+  through hva->hpa changes)
+- memory pressure (the shrinker)
+
+Shadow pages
+============
+
+The principal data structure is the shadow page, 'struct kvm_mmu_page'.  A
+shadow page contains 512 sptes, which can be either leaf or nonleaf sptes.  A
+shadow page may contain a mix of leaf and nonleaf sptes.
+
+A nonleaf spte allows the hardware mmu to reach the leaf pages and
+is not related to a translation directly.  It points to other shadow pages.
+
+A leaf spte corresponds to either one or two translations encoded into
+one paging structure entry.  These are always the lowest level of the
+translation stack, with optional higher level translations left to NPT/EPT.
+Leaf ptes point at guest pages.
+
+The following table shows translations encoded by leaf ptes, with higher-level
+translations in parentheses:
+
+ Non-nested guests:
+  nonpaging:     gpa->hpa
+  paging:        gva->gpa->hpa
+  paging, tdp:   (gva->)gpa->hpa
+ Nested guests:
+  non-tdp:       ngva->gpa->hpa  (*)
+  tdp:           (ngva->)ngpa->gpa->hpa
+
+(*) the guest hypervisor will encode the ngva->gpa translation into its page
+    tables if npt is not present
+
+Shadow pages contain the following information:
+  role.level:
+    The level in the shadow paging hierarchy that this shadow page belongs to.
+    1=4k sptes, 2=2M sptes, 3=1G sptes, etc.
+  role.direct:
+    If set, leaf sptes reachable from this page are for a linear range.
+    Examples include real mode translation, large guest pages backed by small
+    host pages, and gpa->hpa translations when NPT or EPT is active.
+    The linear range starts at (gfn << PAGE_SHIFT) and its size is determined
+    by role.level (2MB for first level, 1GB for second level, 0.5TB for third
+    level, 256TB for fourth level)
+    If clear, this page corresponds to a guest page table denoted by the gfn
+    field.
+  role.quadrant:
+    When role.cr4_pae=0, the guest uses 32-bit gptes while the host uses 64-bit
+    sptes.  That means a guest page table contains more ptes than the host,
+    so multiple shadow pages are needed to shadow one guest page.
+    For first-level shadow pages, role.quadrant can be 0 or 1 and denotes the
+    first or second 512-gpte block in the guest page table.  For second-level
+    page tables, each 32-bit gpte is converted to two 64-bit sptes
+    (since each first-level guest page is shadowed by two first-level
+    shadow pages) so role.quadrant takes values in the range 0..3.  Each
+    quadrant maps 1GB virtual address space.
+  role.access:
+    Inherited guest access permissions in the form uwx.  Note execute
+    permission is positive, not negative.
+  role.invalid:
+    The page is invalid and should not be used.  It is a root page that is
+    currently pinned (by a cpu hardware register pointing to it); once it is
+    unpinned it will be destroyed.
+  role.cr4_pae:
+    Contains the value of cr4.pae for which the page is valid (e.g. whether
+    32-bit or 64-bit gptes are in use).
+  role.cr4_nxe:
+    Contains the value of efer.nxe for which the page is valid.
+  role.cr0_wp:
+    Contains the value of cr0.wp for which the page is valid.
+  gfn:
+    Either the guest page table containing the translations shadowed by this
+    page, or the base page frame for linear translations.  See role.direct.
+  spt:
+    A pageful of 64-bit sptes containing the translations for this page.
+    Accessed by both kvm and hardware.
+    The page pointed to by spt will have its page->private pointing back
+    at the shadow page structure.
+    sptes in spt point either at guest pages, or at lower-level shadow pages.
+    Specifically, if sp1 and sp2 are shadow pages, then sp1->spt[n] may point
+    at __pa(sp2->spt).  sp2 will point back at sp1 through parent_pte.
+    The spt array forms a DAG structure with the shadow page as a node, and
+    guest pages as leaves.
+  gfns:
+    An array of 512 guest frame numbers, one for each present pte.  Used to
+    perform a reverse map from a pte to a gfn.
+  slot_bitmap:
+    A bitmap containing one bit per memory slot.  If the page contains a pte
+    mapping a page from memory slot n, then bit n of slot_bitmap will be set
+    (if a page is aliased among several slots, then it is not guaranteed that
+    all slots will be marked).
+    Used during dirty logging to avoid scanning a shadow page if none if its
+    pages need tracking.
+  root_count:
+    A counter keeping track of how many hardware registers (guest cr3 or
+    pdptrs) are now pointing at the page.  While this counter is nonzero, the
+    page cannot be destroyed.  See role.invalid.
+  multimapped:
+    Whether there exist multiple sptes pointing at this page.
+  parent_pte/parent_ptes:
+    If multimapped is zero, parent_pte points at the single spte that points at
+    this page's spt.  Otherwise, parent_ptes points at a data structure
+    with a list of parent_ptes.
+  unsync:
+    If true, then the translations in this page may not match the guest's
+    translation.  This is equivalent to the state of the tlb when a pte is
+    changed but before the tlb entry is flushed.  Accordingly, unsync ptes
+    are synchronized when the guest executes invlpg or flushes its tlb by
+    other means.  Valid for leaf pages.
+  unsync_children:
+    How many sptes in the page point at pages that are unsync (or have
+    unsynchronized children).
+  unsync_child_bitmap:
+    A bitmap indicating which sptes in spt point (directly or indirectly) at
+    pages that may be unsynchronized.  Used to quickly locate all unsychronized
+    pages reachable from a given page.
+
+Reverse map
+===========
+
+The mmu maintains a reverse mapping whereby all ptes mapping a page can be
+reached given its gfn.  This is used, for example, when swapping out a page.
+
+Synchronized and unsynchronized pages
+=====================================
+
+The guest uses two events to synchronize its tlb and page tables: tlb flushes
+and page invalidations (invlpg).
+
+A tlb flush means that we need to synchronize all sptes reachable from the
+guest's cr3.  This is expensive, so we keep all guest page tables write
+protected, and synchronize sptes to gptes when a gpte is written.
+
+A special case is when a guest page table is reachable from the current
+guest cr3.  In this case, the guest is obliged to issue an invlpg instruction
+before using the translation.  We take advantage of that by removing write
+protection from the guest page, and allowing the guest to modify it freely.
+We synchronize modified gptes when the guest invokes invlpg.  This reduces
+the amount of emulation we have to do when the guest modifies multiple gptes,
+or when the a guest page is no longer used as a page table and is used for
+random guest data.
+
+As a side effect we have to resynchronize all reachable unsynchronized shadow
+pages on a tlb flush.
+
+
+Reaction to events
+==================
+
+- guest page fault (or npt page fault, or ept violation)
+
+This is the most complicated event.  The cause of a page fault can be:
+
+  - a true guest fault (the guest translation won't allow the access) (*)
+  - access to a missing translation
+  - access to a protected translation
+    - when logging dirty pages, memory is write protected
+    - synchronized shadow pages are write protected (*)
+  - access to untranslatable memory (mmio)
+
+  (*) not applicable in direct mode
+
+Handling a page fault is performed as follows:
+
+ - if needed, walk the guest page tables to determine the guest translation
+   (gva->gpa or ngpa->gpa)
+   - if permissions are insufficient, reflect the fault back to the guest
+ - determine the host page
+   - if this is an mmio request, there is no host page; call the emulator
+     to emulate the instruction instead
+ - walk the shadow page table to find the spte for the translation,
+   instantiating missing intermediate page tables as necessary
+ - try to unsynchronize the page
+   - if successful, we can let the guest continue and modify the gpte
+ - emulate the instruction
+   - if failed, unshadow the page and let the guest continue
+ - update any translations that were modified by the instruction
+
+invlpg handling:
+
+  - walk the shadow page hierarchy and drop affected translations
+  - try to reinstantiate the indicated translation in the hope that the
+    guest will use it in the near future
+
+Guest control register updates:
+
+- mov to cr3
+  - look up new shadow roots
+  - synchronize newly reachable shadow pages
+
+- mov to cr0/cr4/efer
+  - set up mmu context for new paging mode
+  - look up new shadow roots
+  - synchronize newly reachable shadow pages
+
+Host translation updates:
+
+  - mmu notifier called with updated hva
+  - look up affected sptes through reverse map
+  - drop (or update) translations
+
+Further reading
+===============
+
+- NPT presentation from KVM Forum 2008
+  http://www.linux-kvm.org/wiki/images/c/c8/KvmForum2008%24kdf2008_21.pdf
+
index 39c0a09d0105414b1eaba23e4196398be8412332..fc15538d8b460928262bdd8a6e97477e0df50791 100644 (file)
@@ -292,13 +292,13 @@ sysfs notes:
 
                Warning: when in NVRAM mode, the volume up/down/mute
                keys are synthesized according to changes in the mixer,
-               so you have to use volume up or volume down to unmute,
-               as per the ThinkPad volume mixer user interface.  When
-               in ACPI event mode, volume up/down/mute are reported as
-               separate events, but this behaviour may be corrected in
-               future releases of this driver, in which case the
-               ThinkPad volume mixer user interface semantics will be
-               enforced.
+               which uses a single volume up or volume down hotkey
+               press to unmute, as per the ThinkPad volume mixer user
+               interface.  When in ACPI event mode, volume up/down/mute
+               events are reported by the firmware and can behave
+               differently (and that behaviour changes with firmware
+               version -- not just with firmware models -- as well as
+               OSI(Linux) state).
 
        hotkey_poll_freq:
                frequency in Hz for hot key polling. It must be between
@@ -309,7 +309,7 @@ sysfs notes:
                will cause hot key presses that require NVRAM polling
                to never be reported.
 
-               Setting hotkey_poll_freq too low will cause repeated
+               Setting hotkey_poll_freq too low may cause repeated
                pressings of the same hot key to be misreported as a
                single key press, or to not even be detected at all.
                The recommended polling frequency is 10Hz.
@@ -397,6 +397,7 @@ ACPI        Scan
 event  code    Key             Notes
 
 0x1001 0x00    FN+F1           -
+
 0x1002 0x01    FN+F2           IBM: battery (rare)
                                Lenovo: Screen lock
 
@@ -404,7 +405,8 @@ event       code    Key             Notes
                                this hot key, even with hot keys
                                disabled or with Fn+F3 masked
                                off
-                               IBM: screen lock
+                               IBM: screen lock, often turns
+                               off the ThinkLight as side-effect
                                Lenovo: battery
 
 0x1004 0x03    FN+F4           Sleep button (ACPI sleep button
@@ -433,7 +435,8 @@ event       code    Key             Notes
                                Do you feel lucky today?
 
 0x1008 0x07    FN+F8           IBM: toggle screen expand
-                               Lenovo: configure UltraNav
+                               Lenovo: configure UltraNav,
+                               or toggle screen expand
 
 0x1009 0x08    FN+F9           -
        ..      ..              ..
@@ -444,7 +447,7 @@ event       code    Key             Notes
                                either through the ACPI event,
                                or through a hotkey event.
                                The firmware may refuse to
-                               generate further FN+F4 key
+                               generate further FN+F12 key
                                press events until a S3 or S4
                                ACPI sleep cycle is performed,
                                or some time passes.
@@ -512,15 +515,19 @@ events for switches:
 SW_RFKILL_ALL  T60 and later hardware rfkill rocker switch
 SW_TABLET_MODE Tablet ThinkPads HKEY events 0x5009 and 0x500A
 
-Non hot-key ACPI HKEY event map:
+Non hotkey ACPI HKEY event map:
+-------------------------------
+
+Events that are not propagated by the driver, except for legacy
+compatibility purposes when hotkey_report_mode is set to 1:
+
 0x5001         Lid closed
 0x5002         Lid opened
 0x5009         Tablet swivel: switched to tablet mode
 0x500A         Tablet swivel: switched to normal mode
 0x7000         Radio Switch may have changed state
 
-The above events are not propagated by the driver, except for legacy
-compatibility purposes when hotkey_report_mode is set to 1.
+Events that are never propagated by the driver:
 
 0x2304         System is waking up from suspend to undock
 0x2305         System is waking up from suspend to eject bay
@@ -528,14 +535,39 @@ compatibility purposes when hotkey_report_mode is set to 1.
 0x2405         System is waking up from hibernation to eject bay
 0x5010         Brightness level changed/control event
 
-The above events are never propagated by the driver.
+Events that are propagated by the driver to userspace:
 
+0x2313         ALARM: System is waking up from suspend because
+               the battery is nearly empty
+0x2413         ALARM: System is waking up from hibernation because
+               the battery is nearly empty
 0x3003         Bay ejection (see 0x2x05) complete, can sleep again
+0x3006         Bay hotplug request (hint to power up SATA link when
+               the optical drive tray is ejected)
 0x4003         Undocked (see 0x2x04), can sleep again
 0x500B         Tablet pen inserted into its storage bay
 0x500C         Tablet pen removed from its storage bay
-
-The above events are propagated by the driver.
+0x6011         ALARM: battery is too hot
+0x6012         ALARM: battery is extremely hot
+0x6021         ALARM: a sensor is too hot
+0x6022         ALARM: a sensor is extremely hot
+0x6030         System thermal table changed
+
+Battery nearly empty alarms are a last resort attempt to get the
+operating system to hibernate or shutdown cleanly (0x2313), or shutdown
+cleanly (0x2413) before power is lost.  They must be acted upon, as the
+wake up caused by the firmware will have negated most safety nets...
+
+When any of the "too hot" alarms happen, according to Lenovo the user
+should suspend or hibernate the laptop (and in the case of battery
+alarms, unplug the AC adapter) to let it cool down.  These alarms do
+signal that something is wrong, they should never happen on normal
+operating conditions.
+
+The "extremely hot" alarms are emergencies.  According to Lenovo, the
+operating system is to force either an immediate suspend or hibernate
+cycle, or a system shutdown.  Obviously, something is very wrong if this
+happens.
 
 Compatibility notes:
 
index c10c022b911cb7b1dd46bd61baabde516cd92bed..6fe9001b92634ec306a745d5842883640db79597 100644 (file)
@@ -256,9 +256,13 @@ characters, each representing a particular tainted value.
   9: 'A' if the ACPI table has been overridden.
 
  10: 'W' if a warning has previously been issued by the kernel.
+     (Though some warnings may set more specific taint flags.)
 
  11: 'C' if a staging driver has been loaded.
 
+ 12: 'I' if the kernel is working around a severe bug in the platform
+     firmware (BIOS or similar).
+
 The primary reason for the 'Tainted: ' string is to tell kernel
 debuggers if this is a clean kernel or if anything unusual has
 occurred.  Tainting is permanent: even if an offending module is
index dd8fe43888d3e3d6449a1819c84c204a6d197fc6..62328d76b55bd9cfc59294666b49a70e0ddca5da 100644 (file)
-
 PCI Power Management
-~~~~~~~~~~~~~~~~~~~~
 
-An overview of the concepts and the related functions in the Linux kernel
+Copyright (c) 2010 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
+
+An overview of concepts and the Linux kernel's interfaces related to PCI power
+management.  Based on previous work by Patrick Mochel <mochel@transmeta.com>
+(and others).
 
-Patrick Mochel <mochel@transmeta.com>
-(and others)
+This document only covers the aspects of power management specific to PCI
+devices.  For general description of the kernel's interfaces related to device
+power management refer to Documentation/power/devices.txt and
+Documentation/power/runtime_pm.txt.
 
 ---------------------------------------------------------------------------
 
-1. Overview
-2. How the PCI Subsystem Does Power Management
-3. PCI Utility Functions
-4. PCI Device Drivers
-5. Resources
-
-1. Overview
-~~~~~~~~~~~
-
-The PCI Power Management Specification was introduced between the PCI 2.1 and
-PCI 2.2 Specifications. It a standard interface for controlling various 
-power management operations.
-
-Implementation of the PCI PM Spec is optional, as are several sub-components of
-it. If a device supports the PCI PM Spec, the device will have an 8 byte
-capability field in its PCI configuration space. This field is used to describe
-and control the standard PCI power management features.
-
-The PCI PM spec defines 4 operating states for devices (D0 - D3) and for buses
-(B0 - B3). The higher the number, the less power the device consumes. However,
-the higher the number, the longer the latency is for the device to return to 
-an operational state (D0).
-
-There are actually two D3 states.  When someone talks about D3, they usually
-mean D3hot, which corresponds to an ACPI D2 state (power is reduced, the
-device may lose some context).  But they may also mean D3cold, which is an
-ACPI D3 state (power is fully off, all state was discarded); or both.
-
-Bus power management is not covered in this version of this document.
-
-Note that all PCI devices support D0 and D3cold by default, regardless of
-whether or not they implement any of the PCI PM spec.
-
-The possible state transitions that a device can undergo are:
-
-+---------------------------+
-| Current State | New State |
-+---------------------------+
-| D0            | D1, D2, D3|
-+---------------------------+
-| D1            | D2, D3    |
-+---------------------------+
-| D2            | D3        |
-+---------------------------+
-| D1, D2, D3    | D0        |
-+---------------------------+
-
-Note that when the system is entering a global suspend state, all devices will
-be placed into D3 and when resuming, all devices will be placed into D0.
-However, when the system is running, other state transitions are possible.
-
-2. How The PCI Subsystem Handles Power Management
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The PCI suspend/resume functionality is accessed indirectly via the Power
-Management subsystem. At boot, the PCI driver registers a power management
-callback with that layer. Upon entering a suspend state, the PM layer iterates
-through all of its registered callbacks. This currently takes place only during
-APM state transitions.
-
-Upon going to sleep, the PCI subsystem walks its device tree twice. Both times,
-it does a depth first walk of the device tree. The first walk saves each of the
-device's state and checks for devices that will prevent the system from entering
-a global power state. The next walk then places the devices in a low power
+1. Hardware and Platform Support for PCI Power Management
+2. PCI Subsystem and Device Power Management
+3. PCI Device Drivers and Power Management
+4. Resources
+
+
+1. Hardware and Platform Support for PCI Power Management
+=========================================================
+
+1.1. Native and Platform-Based Power Management
+-----------------------------------------------
+In general, power management is a feature allowing one to save energy by putting
+devices into states in which they draw less power (low-power states) at the
+price of reduced functionality or performance.
+
+Usually, a device is put into a low-power state when it is underutilized or
+completely inactive.  However, when it is necessary to use the device once
+again, it has to be put back into the "fully functional" state (full-power
+state).  This may happen when there are some data for the device to handle or
+as a result of an external event requiring the device to be active, which may
+be signaled by the device itself.
+
+PCI devices may be put into low-power states in two ways, by using the device
+capabilities introduced by the PCI Bus Power Management Interface Specification,
+or with the help of platform firmware, such as an ACPI BIOS.  In the first
+approach, that is referred to as the native PCI power management (native PCI PM)
+in what follows, the device power state is changed as a result of writing a
+specific value into one of its standard configuration registers.  The second
+approach requires the platform firmware to provide special methods that may be
+used by the kernel to change the device's power state.
+
+Devices supporting the native PCI PM usually can generate wakeup signals called
+Power Management Events (PMEs) to let the kernel know about external events
+requiring the device to be active.  After receiving a PME the kernel is supposed
+to put the device that sent it into the full-power state.  However, the PCI Bus
+Power Management Interface Specification doesn't define any standard method of
+delivering the PME from the device to the CPU and the operating system kernel.
+It is assumed that the platform firmware will perform this task and therefore,
+even though a PCI device is set up to generate PMEs, it also may be necessary to
+prepare the platform firmware for notifying the CPU of the PMEs coming from the
+device (e.g. by generating interrupts).
+
+In turn, if the methods provided by the platform firmware are used for changing
+the power state of a device, usually the platform also provides a method for
+preparing the device to generate wakeup signals.  In that case, however, it
+often also is necessary to prepare the device for generating PMEs using the
+native PCI PM mechanism, because the method provided by the platform depends on
+that.
+
+Thus in many situations both the native and the platform-based power management
+mechanisms have to be used simultaneously to obtain the desired result.
+
+1.2. Native PCI Power Management
+--------------------------------
+The PCI Bus Power Management Interface Specification (PCI PM Spec) was
+introduced between the PCI 2.1 and PCI 2.2 Specifications.  It defined a
+standard interface for performing various operations related to power
+management.
+
+The implementation of the PCI PM Spec is optional for conventional PCI devices,
+but it is mandatory for PCI Express devices.  If a device supports the PCI PM
+Spec, it has an 8 byte power management capability field in its PCI
+configuration space.  This field is used to describe and control the standard
+features related to the native PCI power management.
+
+The PCI PM Spec defines 4 operating states for devices (D0-D3) and for buses
+(B0-B3).  The higher the number, the less power is drawn by the device or bus
+in that state.  However, the higher the number, the longer the latency for
+the device or bus to return to the full-power state (D0 or B0, respectively).
+
+There are two variants of the D3 state defined by the specification.  The first
+one is D3hot, referred to as the software accessible D3, because devices can be
+programmed to go into it.  The second one, D3cold, is the state that PCI devices
+are in when the supply voltage (Vcc) is removed from them.  It is not possible
+to program a PCI device to go into D3cold, although there may be a programmable
+interface for putting the bus the device is on into a state in which Vcc is
+removed from all devices on the bus.
+
+PCI bus power management, however, is not supported by the Linux kernel at the
+time of this writing and therefore it is not covered by this document.
+
+Note that every PCI device can be in the full-power state (D0) or in D3cold,
+regardless of whether or not it implements the PCI PM Spec.  In addition to
+that, if the PCI PM Spec is implemented by the device, it must support D3hot
+as well as D0.  The support for the D1 and D2 power states is optional.
+
+PCI devices supporting the PCI PM Spec can be programmed to go to any of the
+supported low-power states (except for D3cold).  While in D1-D3hot the
+standard configuration registers of the device must be accessible to software
+(i.e. the device is required to respond to PCI configuration accesses), although
+its I/O and memory spaces are then disabled.  This allows the device to be
+programmatically put into D0.  Thus the kernel can switch the device back and
+forth between D0 and the supported low-power states (except for D3cold) and the
+possible power state transitions the device can undergo are the following:
+
++----------------------------+
+| Current State | New State  |
++----------------------------+
+| D0            | D1, D2, D3 |
++----------------------------+
+| D1            | D2, D3     |
++----------------------------+
+| D2            | D3         |
++----------------------------+
+| D1, D2, D3    | D0         |
++----------------------------+
+
+The transition from D3cold to D0 occurs when the supply voltage is provided to
+the device (i.e. power is restored).  In that case the device returns to D0 with
+a full power-on reset sequence and the power-on defaults are restored to the
+device by hardware just as at initial power up.
+
+PCI devices supporting the PCI PM Spec can be programmed to generate PMEs
+while in a low-power state (D1-D3), but they are not required to be capable
+of generating PMEs from all supported low-power states.  In particular, the
+capability of generating PMEs from D3cold is optional and depends on the
+presence of additional voltage (3.3Vaux) allowing the device to remain
+sufficiently active to generate a wakeup signal.
+
+1.3. ACPI Device Power Management
+---------------------------------
+The platform firmware support for the power management of PCI devices is
+system-specific.  However, if the system in question is compliant with the
+Advanced Configuration and Power Interface (ACPI) Specification, like the
+majority of x86-based systems, it is supposed to implement device power
+management interfaces defined by the ACPI standard.
+
+For this purpose the ACPI BIOS provides special functions called "control
+methods" that may be executed by the kernel to perform specific tasks, such as
+putting a device into a low-power state.  These control methods are encoded
+using special byte-code language called the ACPI Machine Language (AML) and
+stored in the machine's BIOS.  The kernel loads them from the BIOS and executes
+them as needed using an AML interpreter that translates the AML byte code into
+computations and memory or I/O space accesses.  This way, in theory, a BIOS
+writer can provide the kernel with a means to perform actions depending
+on the system design in a system-specific fashion.
+
+ACPI control methods may be divided into global control methods, that are not
+associated with any particular devices, and device control methods, that have
+to be defined separately for each device supposed to be handled with the help of
+the platform.  This means, in particular, that ACPI device control methods can
+only be used to handle devices that the BIOS writer knew about in advance.  The
+ACPI methods used for device power management fall into that category.
+
+The ACPI specification assumes that devices can be in one of four power states
+labeled as D0, D1, D2, and D3 that roughly correspond to the native PCI PM
+D0-D3 states (although the difference between D3hot and D3cold is not taken
+into account by ACPI).  Moreover, for each power state of a device there is a
+set of power resources that have to be enabled for the device to be put into
+that state.  These power resources are controlled (i.e. enabled or disabled)
+with the help of their own control methods, _ON and _OFF, that have to be
+defined individually for each of them.
+
+To put a device into the ACPI power state Dx (where x is a number between 0 and
+3 inclusive) the kernel is supposed to (1) enable the power resources required
+by the device in this state using their _ON control methods and (2) execute the
+_PSx control method defined for the device.  In addition to that, if the device
+is going to be put into a low-power state (D1-D3) and is supposed to generate
+wakeup signals from that state, the _DSW (or _PSW, replaced with _DSW by ACPI
+3.0) control method defined for it has to be executed before _PSx.  Power
+resources that are not required by the device in the target power state and are
+not required any more by any other device should be disabled (by executing their
+_OFF control methods).  If the current power state of the device is D3, it can
+only be put into D0 this way.
+
+However, quite often the power states of devices are changed during a
+system-wide transition into a sleep state or back into the working state.  ACPI
+defines four system sleep states, S1, S2, S3, and S4, and denotes the system
+working state as S0.  In general, the target system sleep (or working) state
+determines the highest power (lowest number) state the device can be put
+into and the kernel is supposed to obtain this information by executing the
+device's _SxD control method (where x is a number between 0 and 4 inclusive).
+If the device is required to wake up the system from the target sleep state, the
+lowest power (highest number) state it can be put into is also determined by the
+target state of the system.  The kernel is then supposed to use the device's
+_SxW control method to obtain the number of that state.  It also is supposed to
+use the device's _PRW control method to learn which power resources need to be
+enabled for the device to be able to generate wakeup signals.
+
+1.4. Wakeup Signaling
+---------------------
+Wakeup signals generated by PCI devices, either as native PCI PMEs, or as
+a result of the execution of the _DSW (or _PSW) ACPI control method before
+putting the device into a low-power state, have to be caught and handled as
+appropriate.  If they are sent while the system is in the working state
+(ACPI S0), they should be translated into interrupts so that the kernel can
+put the devices generating them into the full-power state and take care of the
+events that triggered them.  In turn, if they are sent while the system is
+sleeping, they should cause the system's core logic to trigger wakeup.
+
+On ACPI-based systems wakeup signals sent by conventional PCI devices are
+converted into ACPI General-Purpose Events (GPEs) which are hardware signals
+from the system core logic generated in response to various events that need to
+be acted upon.  Every GPE is associated with one or more sources of potentially
+interesting events.  In particular, a GPE may be associated with a PCI device
+capable of signaling wakeup.  The information on the connections between GPEs
+and event sources is recorded in the system's ACPI BIOS from where it can be
+read by the kernel.
+
+If a PCI device known to the system's ACPI BIOS signals wakeup, the GPE
+associated with it (if there is one) is triggered.  The GPEs associated with PCI
+bridges may also be triggered in response to a wakeup signal from one of the
+devices below the bridge (this also is the case for root bridges) and, for
+example, native PCI PMEs from devices unknown to the system's ACPI BIOS may be
+handled this way.
+
+A GPE may be triggered when the system is sleeping (i.e. when it is in one of
+the ACPI S1-S4 states), in which case system wakeup is started by its core logic
+(the device that was the source of the signal causing the system wakeup to occur
+may be identified later).  The GPEs used in such situations are referred to as
+wakeup GPEs.
+
+Usually, however, GPEs are also triggered when the system is in the working
+state (ACPI S0) and in that case the system's core logic generates a System
+Control Interrupt (SCI) to notify the kernel of the event.  Then, the SCI
+handler identifies the GPE that caused the interrupt to be generated which,
+in turn, allows the kernel to identify the source of the event (that may be
+a PCI device signaling wakeup).  The GPEs used for notifying the kernel of
+events occurring while the system is in the working state are referred to as
+runtime GPEs.
+
+Unfortunately, there is no standard way of handling wakeup signals sent by
+conventional PCI devices on systems that are not ACPI-based, but there is one
+for PCI Express devices.  Namely, the PCI Express Base Specification introduced
+a native mechanism for converting native PCI PMEs into interrupts generated by
+root ports.  For conventional PCI devices native PMEs are out-of-band, so they
+are routed separately and they need not pass through bridges (in principle they
+may be routed directly to the system's core logic), but for PCI Express devices
+they are in-band messages that have to pass through the PCI Express hierarchy,
+including the root port on the path from the device to the Root Complex.  Thus
+it was possible to introduce a mechanism by which a root port generates an
+interrupt whenever it receives a PME message from one of the devices below it.
+The PCI Express Requester ID of the device that sent the PME message is then
+recorded in one of the root port's configuration registers from where it may be
+read by the interrupt handler allowing the device to be identified.  [PME
+messages sent by PCI Express endpoints integrated with the Root Complex don't
+pass through root ports, but instead they cause a Root Complex Event Collector
+(if there is one) to generate interrupts.]
+
+In principle the native PCI Express PME signaling may also be used on ACPI-based
+systems along with the GPEs, but to use it the kernel has to ask the system's
+ACPI BIOS to release control of root port configuration registers.  The ACPI
+BIOS, however, is not required to allow the kernel to control these registers
+and if it doesn't do that, the kernel must not modify their contents.  Of course
+the native PCI Express PME signaling cannot be used by the kernel in that case.
+
+
+2. PCI Subsystem and Device Power Management
+============================================
+
+2.1. Device Power Management Callbacks
+--------------------------------------
+The PCI Subsystem participates in the power management of PCI devices in a
+number of ways.  First of all, it provides an intermediate code layer between
+the device power management core (PM core) and PCI device drivers.
+Specifically, the pm field of the PCI subsystem's struct bus_type object,
+pci_bus_type, points to a struct dev_pm_ops object, pci_dev_pm_ops, containing
+pointers to several device power management callbacks:
+
+const struct dev_pm_ops pci_dev_pm_ops = {
+       .prepare = pci_pm_prepare,
+       .complete = pci_pm_complete,
+       .suspend = pci_pm_suspend,
+       .resume = pci_pm_resume,
+       .freeze = pci_pm_freeze,
+       .thaw = pci_pm_thaw,
+       .poweroff = pci_pm_poweroff,
+       .restore = pci_pm_restore,
+       .suspend_noirq = pci_pm_suspend_noirq,
+       .resume_noirq = pci_pm_resume_noirq,
+       .freeze_noirq = pci_pm_freeze_noirq,
+       .thaw_noirq = pci_pm_thaw_noirq,
+       .poweroff_noirq = pci_pm_poweroff_noirq,
+       .restore_noirq = pci_pm_restore_noirq,
+       .runtime_suspend = pci_pm_runtime_suspend,
+       .runtime_resume = pci_pm_runtime_resume,
+       .runtime_idle = pci_pm_runtime_idle,
+};
+
+These callbacks are executed by the PM core in various situations related to
+device power management and they, in turn, execute power management callbacks
+provided by PCI device drivers.  They also perform power management operations
+involving some standard configuration registers of PCI devices that device
+drivers need not know or care about.
+
+The structure representing a PCI device, struct pci_dev, contains several fields
+that these callbacks operate on:
+
+struct pci_dev {
+       ...
+       pci_power_t     current_state;  /* Current operating state. */
+       int             pm_cap;         /* PM capability offset in the
+                                          configuration space */
+       unsigned int    pme_support:5;  /* Bitmask of states from which PME#
+                                          can be generated */
+       unsigned int    pme_interrupt:1;/* Is native PCIe PME signaling used? */
+       unsigned int    d1_support:1;   /* Low power state D1 is supported */
+       unsigned int    d2_support:1;   /* Low power state D2 is supported */
+       unsigned int    no_d1d2:1;      /* D1 and D2 are forbidden */
+       unsigned int    wakeup_prepared:1;  /* Device prepared for wake up */
+       unsigned int    d3_delay;       /* D3->D0 transition time in ms */
+       ...
+};
+
+They also indirectly use some fields of the struct device that is embedded in
+struct pci_dev.
+
+2.2. Device Initialization
+--------------------------
+The PCI subsystem's first task related to device power management is to
+prepare the device for power management and initialize the fields of struct
+pci_dev used for this purpose.  This happens in two functions defined in
+drivers/pci/pci.c, pci_pm_init() and platform_pci_wakeup_init().
+
+The first of these functions checks if the device supports native PCI PM
+and if that's the case the offset of its power management capability structure
+in the configuration space is stored in the pm_cap field of the device's struct
+pci_dev object.  Next, the function checks which PCI low-power states are
+supported by the device and from which low-power states the device can generate
+native PCI PMEs.  The power management fields of the device's struct pci_dev and
+the struct device embedded in it are updated accordingly and the generation of
+PMEs by the device is disabled.
+
+The second function checks if the device can be prepared to signal wakeup with
+the help of the platform firmware, such as the ACPI BIOS.  If that is the case,
+the function updates the wakeup fields in struct device embedded in the
+device's struct pci_dev and uses the firmware-provided method to prevent the
+device from signaling wakeup.
+
+At this point the device is ready for power management.  For driverless devices,
+however, this functionality is limited to a few basic operations carried out
+during system-wide transitions to a sleep state and back to the working state.
+
+2.3. Runtime Device Power Management
+------------------------------------
+The PCI subsystem plays a vital role in the runtime power management of PCI
+devices.  For this purpose it uses the general runtime power management
+(runtime PM) framework described in Documentation/power/runtime_pm.txt.
+Namely, it provides subsystem-level callbacks:
+
+       pci_pm_runtime_suspend()
+       pci_pm_runtime_resume()
+       pci_pm_runtime_idle()
+
+that are executed by the core runtime PM routines.  It also implements the
+entire mechanics necessary for handling runtime wakeup signals from PCI devices
+in low-power states, which at the time of this writing works for both the native
+PCI Express PME signaling and the ACPI GPE-based wakeup signaling described in
+Section 1.
+
+First, a PCI device is put into a low-power state, or suspended, with the help
+of pm_schedule_suspend() or pm_runtime_suspend() which for PCI devices call
+pci_pm_runtime_suspend() to do the actual job.  For this to work, the device's
+driver has to provide a pm->runtime_suspend() callback (see below), which is
+run by pci_pm_runtime_suspend() as the first action.  If the driver's callback
+returns successfully, the device's standard configuration registers are saved,
+the device is prepared to generate wakeup signals and, finally, it is put into
+the target low-power state.
+
+The low-power state to put the device into is the lowest-power (highest number)
+state from which it can signal wakeup.  The exact method of signaling wakeup is
+system-dependent and is determined by the PCI subsystem on the basis of the
+reported capabilities of the device and the platform firmware.  To prepare the
+device for signaling wakeup and put it into the selected low-power state, the
+PCI subsystem can use the platform firmware as well as the device's native PCI
+PM capabilities, if supported.
+
+It is expected that the device driver's pm->runtime_suspend() callback will
+not attempt to prepare the device for signaling wakeup or to put it into a
+low-power state.  The driver ought to leave these tasks to the PCI subsystem
+that has all of the information necessary to perform them.
+
+A suspended device is brought back into the "active" state, or resumed,
+with the help of pm_request_resume() or pm_runtime_resume() which both call
+pci_pm_runtime_resume() for PCI devices.  Again, this only works if the device's
+driver provides a pm->runtime_resume() callback (see below).  However, before
+the driver's callback is executed, pci_pm_runtime_resume() brings the device
+back into the full-power state, prevents it from signaling wakeup while in that
+state and restores its standard configuration registers.  Thus the driver's
+callback need not worry about the PCI-specific aspects of the device resume.
+
+Note that generally pci_pm_runtime_resume() may be called in two different
+situations.  First, it may be called at the request of the device's driver, for
+example if there are some data for it to process.  Second, it may be called
+as a result of a wakeup signal from the device itself (this sometimes is
+referred to as "remote wakeup").  Of course, for this purpose the wakeup signal
+is handled in one of the ways described in Section 1 and finally converted into
+a notification for the PCI subsystem after the source device has been
+identified.
+
+The pci_pm_runtime_idle() function, called for PCI devices by pm_runtime_idle()
+and pm_request_idle(), executes the device driver's pm->runtime_idle()
+callback, if defined, and if that callback doesn't return error code (or is not
+present at all), suspends the device with the help of pm_runtime_suspend().
+Sometimes pci_pm_runtime_idle() is called automatically by the PM core (for
+example, it is called right after the device has just been resumed), in which
+cases it is expected to suspend the device if that makes sense.  Usually,
+however, the PCI subsystem doesn't really know if the device really can be
+suspended, so it lets the device's driver decide by running its
+pm->runtime_idle() callback.
+
+2.4. System-Wide Power Transitions
+----------------------------------
+There are a few different types of system-wide power transitions, described in
+Documentation/power/devices.txt.  Each of them requires devices to be handled
+in a specific way and the PM core executes subsystem-level power management
+callbacks for this purpose.  They are executed in phases such that each phase
+involves executing the same subsystem-level callback for every device belonging
+to the given subsystem before the next phase begins.  These phases always run
+after tasks have been frozen.
+
+2.4.1. System Suspend
+
+When the system is going into a sleep state in which the contents of memory will
+be preserved, such as one of the ACPI sleep states S1-S3, the phases are:
+
+       prepare, suspend, suspend_noirq.
+
+The following PCI bus type's callbacks, respectively, are used in these phases:
+
+       pci_pm_prepare()
+       pci_pm_suspend()
+       pci_pm_suspend_noirq()
+
+The pci_pm_prepare() routine first puts the device into the "fully functional"
+state with the help of pm_runtime_resume().  Then, it executes the device
+driver's pm->prepare() callback if defined (i.e. if the driver's struct
+dev_pm_ops object is present and the prepare pointer in that object is valid).
+
+The pci_pm_suspend() routine first checks if the device's driver implements
+legacy PCI suspend routines (see Section 3), in which case the driver's legacy
+suspend callback is executed, if present, and its result is returned.  Next, if
+the device's driver doesn't provide a struct dev_pm_ops object (containing
+pointers to the driver's callbacks), pci_pm_default_suspend() is called, which
+simply turns off the device's bus master capability and runs
+pcibios_disable_device() to disable it, unless the device is a bridge (PCI
+bridges are ignored by this routine).  Next, the device driver's pm->suspend()
+callback is executed, if defined, and its result is returned if it fails.
+Finally, pci_fixup_device() is called to apply hardware suspend quirks related
+to the device if necessary.
+
+Note that the suspend phase is carried out asynchronously for PCI devices, so
+the pci_pm_suspend() callback may be executed in parallel for any pair of PCI
+devices that don't depend on each other in a known way (i.e. none of the paths
+in the device tree from the root bridge to a leaf device contains both of them).
+
+The pci_pm_suspend_noirq() routine is executed after suspend_device_irqs() has
+been called, which means that the device driver's interrupt handler won't be
+invoked while this routine is running.  It first checks if the device's driver
+implements legacy PCI suspends routines (Section 3), in which case the legacy
+late suspend routine is called and its result is returned (the standard
+configuration registers of the device are saved if the driver's callback hasn't
+done that).  Second, if the device driver's struct dev_pm_ops object is not
+present, the device's standard configuration registers are saved and the routine
+returns success.  Otherwise the device driver's pm->suspend_noirq() callback is
+executed, if present, and its result is returned if it fails.  Next, if the
+device's standard configuration registers haven't been saved yet (one of the
+device driver's callbacks executed before might do that), pci_pm_suspend_noirq()
+saves them, prepares the device to signal wakeup (if necessary) and puts it into
+a low-power state.
+
+The low-power state to put the device into is the lowest-power (highest number)
+state from which it can signal wakeup while the system is in the target sleep
+state.  Just like in the runtime PM case described above, the mechanism of
+signaling wakeup is system-dependent and determined by the PCI subsystem, which
+is also responsible for preparing the device to signal wakeup from the system's
+target sleep state as appropriate.
+
+PCI device drivers (that don't implement legacy power management callbacks) are
+generally not expected to prepare devices for signaling wakeup or to put them
+into low-power states.  However, if one of the driver's suspend callbacks
+(pm->suspend() or pm->suspend_noirq()) saves the device's standard configuration
+registers, pci_pm_suspend_noirq() will assume that the device has been prepared
+to signal wakeup and put into a low-power state by the driver (the driver is
+then assumed to have used the helper functions provided by the PCI subsystem for
+this purpose).  PCI device drivers are not encouraged to do that, but in some
+rare cases doing that in the driver may be the optimum approach.
+
+2.4.2. System Resume
+
+When the system is undergoing a transition from a sleep state in which the
+contents of memory have been preserved, such as one of the ACPI sleep states
+S1-S3, into the working state (ACPI S0), the phases are:
+
+       resume_noirq, resume, complete.
+
+The following PCI bus type's callbacks, respectively, are executed in these
+phases:
+
+       pci_pm_resume_noirq()
+       pci_pm_resume()
+       pci_pm_complete()
+
+The pci_pm_resume_noirq() routine first puts the device into the full-power
+state, restores its standard configuration registers and applies early resume
+hardware quirks related to the device, if necessary.  This is done
+unconditionally, regardless of whether or not the device's driver implements
+legacy PCI power management callbacks (this way all PCI devices are in the
+full-power state and their standard configuration registers have been restored
+when their interrupt handlers are invoked for the first time during resume,
+which allows the kernel to avoid problems with the handling of shared interrupts
+by drivers whose devices are still suspended).  If legacy PCI power management
+callbacks (see Section 3) are implemented by the device's driver, the legacy
+early resume callback is executed and its result is returned.  Otherwise, the
+device driver's pm->resume_noirq() callback is executed, if defined, and its
+result is returned.
+
+The pci_pm_resume() routine first checks if the device's standard configuration
+registers have been restored and restores them if that's not the case (this
+only is necessary in the error path during a failing suspend).  Next, resume
+hardware quirks related to the device are applied, if necessary, and if the
+device's driver implements legacy PCI power management callbacks (see
+Section 3), the driver's legacy resume callback is executed and its result is
+returned.  Otherwise, the device's wakeup signaling mechanisms are blocked and
+its driver's pm->resume() callback is executed, if defined (the callback's
+result is then returned).
+
+The resume phase is carried out asynchronously for PCI devices, like the
+suspend phase described above, which means that if two PCI devices don't depend
+on each other in a known way, the pci_pm_resume() routine may be executed for
+the both of them in parallel.
+
+The pci_pm_complete() routine only executes the device driver's pm->complete()
+callback, if defined.
+
+2.4.3. System Hibernation
+
+System hibernation is more complicated than system suspend, because it requires
+a system image to be created and written into a persistent storage medium.  The
+image is created atomically and all devices are quiesced, or frozen, before that
+happens.
+
+The freezing of devices is carried out after enough memory has been freed (at
+the time of this writing the image creation requires at least 50% of system RAM
+to be free) in the following three phases:
+
+       prepare, freeze, freeze_noirq
+
+that correspond to the PCI bus type's callbacks:
+
+       pci_pm_prepare()
+       pci_pm_freeze()
+       pci_pm_freeze_noirq()
+
+This means that the prepare phase is exactly the same as for system suspend.
+The other two phases, however, are different.
+
+The pci_pm_freeze() routine is quite similar to pci_pm_suspend(), but it runs
+the device driver's pm->freeze() callback, if defined, instead of pm->suspend(),
+and it doesn't apply the suspend-related hardware quirks.  It is executed
+asynchronously for different PCI devices that don't depend on each other in a
+known way.
+
+The pci_pm_freeze_noirq() routine, in turn, is similar to
+pci_pm_suspend_noirq(), but it calls the device driver's pm->freeze_noirq()
+routine instead of pm->suspend_noirq().  It also doesn't attempt to prepare the
+device for signaling wakeup and put it into a low-power state.  Still, it saves
+the device's standard configuration registers if they haven't been saved by one
+of the driver's callbacks.
+
+Once the image has been created, it has to be saved.  However, at this point all
+devices are frozen and they cannot handle I/O, while their ability to handle
+I/O is obviously necessary for the image saving.  Thus they have to be brought
+back to the fully functional state and this is done in the following phases:
+
+       thaw_noirq, thaw, complete
+
+using the following PCI bus type's callbacks:
+
+       pci_pm_thaw_noirq()
+       pci_pm_thaw()
+       pci_pm_complete()
+
+respectively.
+
+The first of them, pci_pm_thaw_noirq(), is analogous to pci_pm_resume_noirq(),
+but it doesn't put the device into the full power state and doesn't attempt to
+restore its standard configuration registers.  It also executes the device
+driver's pm->thaw_noirq() callback, if defined, instead of pm->resume_noirq().
+
+The pci_pm_thaw() routine is similar to pci_pm_resume(), but it runs the device
+driver's pm->thaw() callback instead of pm->resume().  It is executed
+asynchronously for different PCI devices that don't depend on each other in a
+known way.
+
+The complete phase it the same as for system resume.
+
+After saving the image, devices need to be powered down before the system can
+enter the target sleep state (ACPI S4 for ACPI-based systems).  This is done in
+three phases:
+
+       prepare, poweroff, poweroff_noirq
+
+where the prepare phase is exactly the same as for system suspend.  The other
+two phases are analogous to the suspend and suspend_noirq phases, respectively.
+The PCI subsystem-level callbacks they correspond to
+
+       pci_pm_poweroff()
+       pci_pm_poweroff_noirq()
+
+work in analogy with pci_pm_suspend() and pci_pm_poweroff_noirq(), respectively,
+although they don't attempt to save the device's standard configuration
+registers.
+
+2.4.4. System Restore
+
+System restore requires a hibernation image to be loaded into memory and the
+pre-hibernation memory contents to be restored before the pre-hibernation system
+activity can be resumed.
+
+As described in Documentation/power/devices.txt, the hibernation image is loaded
+into memory by a fresh instance of the kernel, called the boot kernel, which in
+turn is loaded and run by a boot loader in the usual way.  After the boot kernel
+has loaded the image, it needs to replace its own code and data with the code
+and data of the "hibernated" kernel stored within the image, called the image
+kernel.  For this purpose all devices are frozen just like before creating
+the image during hibernation, in the
+
+       prepare, freeze, freeze_noirq
+
+phases described above.  However, the devices affected by these phases are only
+those having drivers in the boot kernel; other devices will still be in whatever
+state the boot loader left them.
+
+Should the restoration of the pre-hibernation memory contents fail, the boot
+kernel would go through the "thawing" procedure described above, using the
+thaw_noirq, thaw, and complete phases (that will only affect the devices having
+drivers in the boot kernel), and then continue running normally.
+
+If the pre-hibernation memory contents are restored successfully, which is the
+usual situation, control is passed to the image kernel, which then becomes
+responsible for bringing the system back to the working state.  To achieve this,
+it must restore the devices' pre-hibernation functionality, which is done much
+like waking up from the memory sleep state, although it involves different
+phases:
+
+       restore_noirq, restore, complete
+
+The first two of these are analogous to the resume_noirq and resume phases
+described above, respectively, and correspond to the following PCI subsystem
+callbacks:
+
+       pci_pm_restore_noirq()
+       pci_pm_restore()
+
+These callbacks work in analogy with pci_pm_resume_noirq() and pci_pm_resume(),
+respectively, but they execute the device driver's pm->restore_noirq() and
+pm->restore() callbacks, if available.
+
+The complete phase is carried out in exactly the same way as during system
+resume.
+
+
+3. PCI Device Drivers and Power Management
+==========================================
+
+3.1. Power Management Callbacks
+-------------------------------
+PCI device drivers participate in power management by providing callbacks to be
+executed by the PCI subsystem's power management routines described above and by
+controlling the runtime power management of their devices.
+
+At the time of this writing there are two ways to define power management
+callbacks for a PCI device driver, the recommended one, based on using a
+dev_pm_ops structure described in Documentation/power/devices.txt, and the
+"legacy" one, in which the .suspend(), .suspend_late(), .resume_early(), and
+.resume() callbacks from struct pci_driver are used.  The legacy approach,
+however, doesn't allow one to define runtime power management callbacks and is
+not really suitable for any new drivers.  Therefore it is not covered by this
+document (refer to the source code to learn more about it).
+
+It is recommended that all PCI device drivers define a struct dev_pm_ops object
+containing pointers to power management (PM) callbacks that will be executed by
+the PCI subsystem's PM routines in various circumstances.  A pointer to the
+driver's struct dev_pm_ops object has to be assigned to the driver.pm field in
+its struct pci_driver object.  Once that has happened, the "legacy" PM callbacks
+in struct pci_driver are ignored (even if they are not NULL).
+
+The PM callbacks in struct dev_pm_ops are not mandatory and if they are not
+defined (i.e. the respective fields of struct dev_pm_ops are unset) the PCI
+subsystem will handle the device in a simplified default manner.  If they are
+defined, though, they are expected to behave as described in the following
+subsections.
+
+3.1.1. prepare()
+
+The prepare() callback is executed during system suspend, during hibernation
+(when a hibernation image is about to be created), during power-off after
+saving a hibernation image and during system restore, when a hibernation image
+has just been loaded into memory.
+
+This callback is only necessary if the driver's device has children that in
+general may be registered at any time.  In that case the role of the prepare()
+callback is to prevent new children of the device from being registered until
+one of the resume_noirq(), thaw_noirq(), or restore_noirq() callbacks is run.
+
+In addition to that the prepare() callback may carry out some operations
+preparing the device to be suspended, although it should not allocate memory
+(if additional memory is required to suspend the device, it has to be
+preallocated earlier, for example in a suspend/hibernate notifier as described
+in Documentation/power/notifiers.txt).
+
+3.1.2. suspend()
+
+The suspend() callback is only executed during system suspend, after prepare()
+callbacks have been executed for all devices in the system.
+
+This callback is expected to quiesce the device and prepare it to be put into a
+low-power state by the PCI subsystem.  It is not required (in fact it even is
+not recommended) that a PCI driver's suspend() callback save the standard
+configuration registers of the device, prepare it for waking up the system, or
+put it into a low-power state.  All of these operations can very well be taken
+care of by the PCI subsystem, without the driver's participation.
+
+However, in some rare case it is convenient to carry out these operations in
+a PCI driver.  Then, pci_save_state(), pci_prepare_to_sleep(), and
+pci_set_power_state() should be used to save the device's standard configuration
+registers, to prepare it for system wakeup (if necessary), and to put it into a
+low-power state, respectively.  Moreover, if the driver calls pci_save_state(),
+the PCI subsystem will not execute either pci_prepare_to_sleep(), or
+pci_set_power_state() for its device, so the driver is then responsible for
+handling the device as appropriate.
+
+While the suspend() callback is being executed, the driver's interrupt handler
+can be invoked to handle an interrupt from the device, so all suspend-related
+operations relying on the driver's ability to handle interrupts should be
+carried out in this callback.
+
+3.1.3. suspend_noirq()
+
+The suspend_noirq() callback is only executed during system suspend, after
+suspend() callbacks have been executed for all devices in the system and
+after device interrupts have been disabled by the PM core.
+
+The difference between suspend_noirq() and suspend() is that the driver's
+interrupt handler will not be invoked while suspend_noirq() is running.  Thus
+suspend_noirq() can carry out operations that would cause race conditions to
+arise if they were performed in suspend().
+
+3.1.4. freeze()
+
+The freeze() callback is hibernation-specific and is executed in two situations,
+during hibernation, after prepare() callbacks have been executed for all devices
+in preparation for the creation of a system image, and during restore,
+after a system image has been loaded into memory from persistent storage and the
+prepare() callbacks have been executed for all devices.
+
+The role of this callback is analogous to the role of the suspend() callback
+described above.  In fact, they only need to be different in the rare cases when
+the driver takes the responsibility for putting the device into a low-power
 state.
 
-The first walk allows a graceful recovery in the event of a failure, since none
-of the devices have actually been powered down.
-
-In both walks, in particular the second, all children of a bridge are touched
-before the actual bridge itself. This allows the bridge to retain power while
-its children are being accessed.
-
-Upon resuming from sleep, just the opposite must be true: all bridges must be
-powered on and restored before their children are powered on. This is easily
-accomplished with a breadth-first walk of the PCI device tree.
-
-
-3. PCI Utility Functions
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-These are helper functions designed to be called by individual device drivers.
-Assuming that a device behaves as advertised, these should be applicable in most
-cases. However, results may vary.
-
-Note that these functions are never implicitly called for the driver. The driver
-is always responsible for deciding when and if to call these.
-
-
-pci_save_state
---------------
-
-Usage:
-       pci_save_state(struct pci_dev *dev);
-
-Description:
-       Save first 64 bytes of PCI config space, along with any additional
-       PCI-Express or PCI-X information.
-
-
-pci_restore_state
------------------
-
-Usage:
-       pci_restore_state(struct pci_dev *dev);
-
-Description:
-       Restore previously saved config space.
-
-
-pci_set_power_state
--------------------
-
-Usage:
-       pci_set_power_state(struct pci_dev *dev, pci_power_t state);
-
-Description:
-       Transition device to low power state using PCI PM Capabilities
-       registers.
-
-       Will fail under one of the following conditions:
-       - If state is less than current state, but not D0 (illegal transition)
-       - Device doesn't support PM Capabilities
-       - Device does not support requested state
-
-
-pci_enable_wake
----------------
-
-Usage:
-       pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable);
-
-Description:
-       Enable device to generate PME# during low power state using PCI PM 
-       Capabilities.
-
-       Checks whether if device supports generating PME# from requested state
-       and fail if it does not, unless enable == 0 (request is to disable wake
-       events, which is implicit if it doesn't even support it in the first
-       place).
-
-       Note that the PMC Register in the device's PM Capabilities has a bitmask
-       of the states it supports generating PME# from. D3hot is bit 3 and
-       D3cold is bit 4. So, while a value of 4 as the state may not seem
-       semantically correct, it is. 
-
-
-4. PCI Device Drivers
-~~~~~~~~~~~~~~~~~~~~~
-
-These functions are intended for use by individual drivers, and are defined in 
-struct pci_driver:
-
-        int  (*suspend) (struct pci_dev *dev, pm_message_t state);
-        int  (*resume) (struct pci_dev *dev);
-
-
-suspend
--------
-
-Usage:
-
-if (dev->driver && dev->driver->suspend)
-       dev->driver->suspend(dev,state);
-
-A driver uses this function to actually transition the device into a low power
-state. This should include disabling I/O, IRQs, and bus-mastering, as well as
-physically transitioning the device to a lower power state; it may also include
-calls to pci_enable_wake().
-
-Bus mastering may be disabled by doing:
-
-pci_disable_device(dev);
-
-For devices that support the PCI PM Spec, this may be used to set the device's
-power state to match the suspend() parameter:
-
-pci_set_power_state(dev,state);
-
-The driver is also responsible for disabling any other device-specific features
-(e.g blanking screen, turning off on-card memory, etc).
-
-The driver should be sure to track the current state of the device, as it may
-obviate the need for some operations.
-
-The driver should update the current_state field in its pci_dev structure in
-this function, except for PM-capable devices when pci_set_power_state is used.
-
-resume
-------
-
-Usage:
-
-if (dev->driver && dev->driver->resume)
-       dev->driver->resume(dev)
+In that cases the freeze() callback should not prepare the device system wakeup
+or put it into a low-power state.  Still, either it or freeze_noirq() should
+save the device's standard configuration registers using pci_save_state().
 
-The resume callback may be called from any power state, and is always meant to
-transition the device to the D0 state. 
+3.1.5. freeze_noirq()
 
-The driver is responsible for reenabling any features of the device that had
-been disabled during previous suspend calls, such as IRQs and bus mastering,
-as well as calling pci_restore_state().
+The freeze_noirq() callback is hibernation-specific.  It is executed during
+hibernation, after prepare() and freeze() callbacks have been executed for all
+devices in preparation for the creation of a system image, and during restore,
+after a system image has been loaded into memory and after prepare() and
+freeze() callbacks have been executed for all devices.  It is always executed
+after device interrupts have been disabled by the PM core.
 
-If the device is currently in D3, it may need to be reinitialized in resume().
+The role of this callback is analogous to the role of the suspend_noirq()
+callback described above and it very rarely is necessary to define
+freeze_noirq().
 
-  * Some types of devices, like bus controllers, will preserve context in D3hot
-    (using Vcc power).  Their drivers will often want to avoid re-initializing
-    them after re-entering D0 (perhaps to avoid resetting downstream devices).
+The difference between freeze_noirq() and freeze() is analogous to the
+difference between suspend_noirq() and suspend().
 
-  * Other kinds of devices in D3hot will discard device context as part of a
-    soft reset when re-entering the D0 state.
-    
-  * Devices resuming from D3cold always go through a power-on reset.  Some
-    device context can also be preserved using Vaux power.
+3.1.6. poweroff()
 
-  * Some systems hide D3cold resume paths from drivers.  For example, on PCs
-    the resume path for suspend-to-disk often runs BIOS powerup code, which
-    will sometimes re-initialize the device.
+The poweroff() callback is hibernation-specific.  It is executed when the system
+is about to be powered off after saving a hibernation image to a persistent
+storage.  prepare() callbacks are executed for all devices before poweroff() is
+called.
 
-To handle resets during D3 to D0 transitions, it may be convenient to share
-device initialization code between probe() and resume().  Device parameters
-can also be saved before the driver suspends into D3, avoiding re-probe.
+The role of this callback is analogous to the role of the suspend() and freeze()
+callbacks described above, although it does not need to save the contents of
+the device's registers.  In particular, if the driver wants to put the device
+into a low-power state itself instead of allowing the PCI subsystem to do that,
+the poweroff() callback should use pci_prepare_to_sleep() and
+pci_set_power_state() to prepare the device for system wakeup and to put it
+into a low-power state, respectively, but it need not save the device's standard
+configuration registers.
 
-If the device supports the PCI PM Spec, it can use this to physically transition
-the device to D0:
+3.1.7. poweroff_noirq()
 
-pci_set_power_state(dev,0);
+The poweroff_noirq() callback is hibernation-specific.  It is executed after
+poweroff() callbacks have been executed for all devices in the system.
 
-Note that if the entire system is transitioning out of a global sleep state, all
-devices will be placed in the D0 state, so this is not necessary. However, in
-the event that the device is placed in the D3 state during normal operation,
-this call is necessary. It is impossible to determine which of the two events is
-taking place in the driver, so it is always a good idea to make that call.
+The role of this callback is analogous to the role of the suspend_noirq() and
+freeze_noirq() callbacks described above, but it does not need to save the
+contents of the device's registers.
 
-The driver should take note of the state that it is resuming from in order to
-ensure correct (and speedy) operation.
+The difference between poweroff_noirq() and poweroff() is analogous to the
+difference between suspend_noirq() and suspend().
 
-The driver should update the current_state field in its pci_dev structure in
-this function, except for PM-capable devices when pci_set_power_state is used.
+3.1.8. resume_noirq()
 
+The resume_noirq() callback is only executed during system resume, after the
+PM core has enabled the non-boot CPUs.  The driver's interrupt handler will not
+be invoked while resume_noirq() is running, so this callback can carry out
+operations that might race with the interrupt handler.
 
+Since the PCI subsystem unconditionally puts all devices into the full power
+state in the resume_noirq phase of system resume and restores their standard
+configuration registers, resume_noirq() is usually not necessary.  In general
+it should only be used for performing operations that would lead to race
+conditions if carried out by resume().
 
-A reference implementation
--------------------------
-.suspend()
-{
-       /* driver specific operations */
+3.1.9. resume()
 
-       /* Disable IRQ */
-       free_irq();
-       /* If using MSI */
-       pci_disable_msi();
+The resume() callback is only executed during system resume, after
+resume_noirq() callbacks have been executed for all devices in the system and
+device interrupts have been enabled by the PM core.
 
-       pci_save_state();
-       pci_enable_wake();
-       /* Disable IO/bus master/irq router */
-       pci_disable_device();
-       pci_set_power_state(pci_choose_state());
-}
+This callback is responsible for restoring the pre-suspend configuration of the
+device and bringing it back to the fully functional state.  The device should be
+able to process I/O in a usual way after resume() has returned.
 
-.resume()
-{
-       pci_set_power_state(PCI_D0);
-       pci_restore_state();
-       /* device's irq possibly is changed, driver should take care */
-       pci_enable_device();
-       pci_set_master();
+3.1.10. thaw_noirq()
 
-       /* if using MSI, device's vector possibly is changed */
-       pci_enable_msi();
+The thaw_noirq() callback is hibernation-specific.  It is executed after a
+system image has been created and the non-boot CPUs have been enabled by the PM
+core, in the thaw_noirq phase of hibernation.  It also may be executed if the
+loading of a hibernation image fails during system restore (it is then executed
+after enabling the non-boot CPUs).  The driver's interrupt handler will not be
+invoked while thaw_noirq() is running.
 
-       request_irq();
-       /* driver specific operations; */
-}
+The role of this callback is analogous to the role of resume_noirq().  The
+difference between these two callbacks is that thaw_noirq() is executed after
+freeze() and freeze_noirq(), so in general it does not need to modify the
+contents of the device's registers.
 
-This is a typical implementation. Drivers can slightly change the order
-of the operations in the implementation, ignore some operations or add
-more driver specific operations in it, but drivers should do something like
-this on the whole.
+3.1.11. thaw()
 
-5. Resources
-~~~~~~~~~~~~
+The thaw() callback is hibernation-specific.  It is executed after thaw_noirq()
+callbacks have been executed for all devices in the system and after device
+interrupts have been enabled by the PM core.
 
-PCI Local Bus Specification 
-PCI Bus Power Management Interface Specification
+This callback is responsible for restoring the pre-freeze configuration of
+the device, so that it will work in a usual way after thaw() has returned.
 
-  http://www.pcisig.com
+3.1.12. restore_noirq()
 
+The restore_noirq() callback is hibernation-specific.  It is executed in the
+restore_noirq phase of hibernation, when the boot kernel has passed control to
+the image kernel and the non-boot CPUs have been enabled by the image kernel's
+PM core.
+
+This callback is analogous to resume_noirq() with the exception that it cannot
+make any assumption on the previous state of the device, even if the BIOS (or
+generally the platform firmware) is known to preserve that state over a
+suspend-resume cycle.
+
+For the vast majority of PCI device drivers there is no difference between
+resume_noirq() and restore_noirq().
+
+3.1.13. restore()
+
+The restore() callback is hibernation-specific.  It is executed after
+restore_noirq() callbacks have been executed for all devices in the system and
+after the PM core has enabled device drivers' interrupt handlers to be invoked.
+
+This callback is analogous to resume(), just like restore_noirq() is analogous
+to resume_noirq().  Consequently, the difference between restore_noirq() and
+restore() is analogous to the difference between resume_noirq() and resume().
+
+For the vast majority of PCI device drivers there is no difference between
+resume() and restore().
+
+3.1.14. complete()
+
+The complete() callback is executed in the following situations:
+  - during system resume, after resume() callbacks have been executed for all
+    devices,
+  - during hibernation, before saving the system image, after thaw() callbacks
+    have been executed for all devices,
+  - during system restore, when the system is going back to its pre-hibernation
+    state, after restore() callbacks have been executed for all devices.
+It also may be executed if the loading of a hibernation image into memory fails
+(in that case it is run after thaw() callbacks have been executed for all
+devices that have drivers in the boot kernel).
+
+This callback is entirely optional, although it may be necessary if the
+prepare() callback performs operations that need to be reversed.
+
+3.1.15. runtime_suspend()
+
+The runtime_suspend() callback is specific to device runtime power management
+(runtime PM).  It is executed by the PM core's runtime PM framework when the
+device is about to be suspended (i.e. quiesced and put into a low-power state)
+at run time.
+
+This callback is responsible for freezing the device and preparing it to be
+put into a low-power state, but it must allow the PCI subsystem to perform all
+of the PCI-specific actions necessary for suspending the device.
+
+3.1.16. runtime_resume()
+
+The runtime_resume() callback is specific to device runtime PM.  It is executed
+by the PM core's runtime PM framework when the device is about to be resumed
+(i.e. put into the full-power state and programmed to process I/O normally) at
+run time.
+
+This callback is responsible for restoring the normal functionality of the
+device after it has been put into the full-power state by the PCI subsystem.
+The device is expected to be able to process I/O in the usual way after
+runtime_resume() has returned.
+
+3.1.17. runtime_idle()
+
+The runtime_idle() callback is specific to device runtime PM.  It is executed
+by the PM core's runtime PM framework whenever it may be desirable to suspend
+the device according to the PM core's information.  In particular, it is
+automatically executed right after runtime_resume() has returned in case the
+resume of the device has happened as a result of a spurious event.
+
+This callback is optional, but if it is not implemented or if it returns 0, the
+PCI subsystem will call pm_runtime_suspend() for the device, which in turn will
+cause the driver's runtime_suspend() callback to be executed.
+
+3.1.18. Pointing Multiple Callback Pointers to One Routine
+
+Although in principle each of the callbacks described in the previous
+subsections can be defined as a separate function, it often is convenient to
+point two or more members of struct dev_pm_ops to the same routine.  There are
+a few convenience macros that can be used for this purpose.
+
+The SIMPLE_DEV_PM_OPS macro declares a struct dev_pm_ops object with one
+suspend routine pointed to by the .suspend(), .freeze(), and .poweroff()
+members and one resume routine pointed to by the .resume(), .thaw(), and
+.restore() members.  The other function pointers in this struct dev_pm_ops are
+unset.
+
+The UNIVERSAL_DEV_PM_OPS macro is similar to SIMPLE_DEV_PM_OPS, but it
+additionally sets the .runtime_resume() pointer to the same value as
+.resume() (and .thaw(), and .restore()) and the .runtime_suspend() pointer to
+the same value as .suspend() (and .freeze() and .poweroff()).
+
+The SET_SYSTEM_SLEEP_PM_OPS can be used inside of a declaration of struct
+dev_pm_ops to indicate that one suspend routine is to be pointed to by the
+.suspend(), .freeze(), and .poweroff() members and one resume routine is to
+be pointed to by the .resume(), .thaw(), and .restore() members.
+
+3.2. Device Runtime Power Management
+------------------------------------
+In addition to providing device power management callbacks PCI device drivers
+are responsible for controlling the runtime power management (runtime PM) of
+their devices.
+
+The PCI device runtime PM is optional, but it is recommended that PCI device
+drivers implement it at least in the cases where there is a reliable way of
+verifying that the device is not used (like when the network cable is detached
+from an Ethernet adapter or there are no devices attached to a USB controller).
+
+To support the PCI runtime PM the driver first needs to implement the
+runtime_suspend() and runtime_resume() callbacks.  It also may need to implement
+the runtime_idle() callback to prevent the device from being suspended again
+every time right after the runtime_resume() callback has returned
+(alternatively, the runtime_suspend() callback will have to check if the
+device should really be suspended and return -EAGAIN if that is not the case).
+
+The runtime PM of PCI devices is disabled by default.  It is also blocked by
+pci_pm_init() that runs the pm_runtime_forbid() helper function.  If a PCI
+driver implements the runtime PM callbacks and intends to use the runtime PM
+framework provided by the PM core and the PCI subsystem, it should enable this
+feature by executing the pm_runtime_enable() helper function.  However, the
+driver should not call the pm_runtime_allow() helper function unblocking
+the runtime PM of the device.  Instead, it should allow user space or some
+platform-specific code to do that (user space can do it via sysfs), although
+once it has called pm_runtime_enable(), it must be prepared to handle the
+runtime PM of the device correctly as soon as pm_runtime_allow() is called
+(which may happen at any time).  [It also is possible that user space causes
+pm_runtime_allow() to be called via sysfs before the driver is loaded, so in
+fact the driver has to be prepared to handle the runtime PM of the device as
+soon as it calls pm_runtime_enable().]
+
+The runtime PM framework works by processing requests to suspend or resume
+devices, or to check if they are idle (in which cases it is reasonable to
+subsequently request that they be suspended).  These requests are represented
+by work items put into the power management workqueue, pm_wq.  Although there
+are a few situations in which power management requests are automatically
+queued by the PM core (for example, after processing a request to resume a
+device the PM core automatically queues a request to check if the device is
+idle), device drivers are generally responsible for queuing power management
+requests for their devices.  For this purpose they should use the runtime PM
+helper functions provided by the PM core, discussed in
+Documentation/power/runtime_pm.txt.
+
+Devices can also be suspended and resumed synchronously, without placing a
+request into pm_wq.  In the majority of cases this also is done by their
+drivers that use helper functions provided by the PM core for this purpose.
+
+For more information on the runtime PM of devices refer to
+Documentation/power/runtime_pm.txt.
+
+
+4. Resources
+============
+
+PCI Local Bus Specification, Rev. 3.0
+PCI Bus Power Management Interface Specification, Rev. 1.2
+Advanced Configuration and Power Interface (ACPI) Specification, Rev. 3.0b
+PCI Express Base Specification, Rev. 2.0
+Documentation/power/devices.txt
+Documentation/power/runtime_pm.txt
diff --git a/Documentation/spi/ep93xx_spi b/Documentation/spi/ep93xx_spi
new file mode 100644 (file)
index 0000000..6325f5b
--- /dev/null
@@ -0,0 +1,95 @@
+Cirrus EP93xx SPI controller driver HOWTO
+=========================================
+
+ep93xx_spi driver brings SPI master support for EP93xx SPI controller.  Chip
+selects are implemented with GPIO lines.
+
+NOTE: If possible, don't use SFRMOUT (SFRM1) signal as a chip select. It will
+not work correctly (it cannot be controlled by software). Use GPIO lines
+instead.
+
+Sample configuration
+====================
+
+Typically driver configuration is done in platform board files (the files under
+arch/arm/mach-ep93xx/*.c). In this example we configure MMC over SPI through
+this driver on TS-7260 board. You can adapt the code to suit your needs.
+
+This example uses EGPIO9 as SD/MMC card chip select (this is wired in DIO1
+header on the board).
+
+You need to select CONFIG_MMC_SPI to use mmc_spi driver.
+
+arch/arm/mach-ep93xx/ts72xx.c:
+
+...
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+
+#include <mach/ep93xx_spi.h>
+
+/* this is our GPIO line used for chip select */
+#define MMC_CHIP_SELECT_GPIO EP93XX_GPIO_LINE_EGPIO9
+
+static int ts72xx_mmc_spi_setup(struct spi_device *spi)
+{
+       int err;
+
+       err = gpio_request(MMC_CHIP_SELECT_GPIO, spi->modalias);
+       if (err)
+               return err;
+
+       gpio_direction_output(MMC_CHIP_SELECT_GPIO, 1);
+
+       return 0;
+}
+
+static void ts72xx_mmc_spi_cleanup(struct spi_device *spi)
+{
+       gpio_set_value(MMC_CHIP_SELECT_GPIO, 1);
+       gpio_direction_input(MMC_CHIP_SELECT_GPIO);
+       gpio_free(MMC_CHIP_SELECT_GPIO);
+}
+
+static void ts72xx_mmc_spi_cs_control(struct spi_device *spi, int value)
+{
+       gpio_set_value(MMC_CHIP_SELECT_GPIO, value);
+}
+
+static struct ep93xx_spi_chip_ops ts72xx_mmc_spi_ops = {
+       .setup          = ts72xx_mmc_spi_setup,
+       .cleanup        = ts72xx_mmc_spi_cleanup,
+       .cs_control     = ts72xx_mmc_spi_cs_control,
+};
+
+static struct spi_board_info ts72xx_spi_devices[] __initdata = {
+       {
+               .modalias               = "mmc_spi",
+               .controller_data        = &ts72xx_mmc_spi_ops,
+               /*
+                * We use 10 MHz even though the maximum is 7.4 MHz. The driver
+                * will limit it automatically to max. frequency.
+                */
+               .max_speed_hz           = 10 * 1000 * 1000,
+               .bus_num                = 0,
+               .chip_select            = 0,
+               .mode                   = SPI_MODE_0,
+       },
+};
+
+static struct ep93xx_spi_info ts72xx_spi_info = {
+       .num_chipselect = ARRAY_SIZE(ts72xx_spi_devices),
+};
+
+static void __init ts72xx_init_machine(void)
+{
+       ...
+       ep93xx_register_spi(&ts72xx_spi_info, ts72xx_spi_devices,
+                           ARRAY_SIZE(ts72xx_spi_devices));
+}
+
+Thanks to
+=========
+Martin Guy, H. Hartley Sweeten and others who helped me during development of
+the driver. Simplemachines.it donated me a Sim.One board which I used testing
+the driver on EP9307.
index fc354f760384d40d2ef3481a74685c93b9818a35..36ec0774ca0b0e17dc9454378bc472189e901620 100644 (file)
@@ -58,10 +58,10 @@ static void do_msg(int fd, int len)
                len = sizeof buf;
 
        buf[0] = 0xaa;
-       xfer[0].tx_buf = (__u64) buf;
+       xfer[0].tx_buf = (unsigned long)buf;
        xfer[0].len = 1;
 
-       xfer[1].rx_buf = (__u64) buf;
+       xfer[1].rx_buf = (unsigned long) buf;
        xfer[1].len = len;
 
        status = ioctl(fd, SPI_IOC_MESSAGE(2), xfer);
index 6c7d18c53f8454c7d9ea93317595e7c22da953ed..5fdbb612aeb840af5c5eec80103c660be3da6c06 100644 (file)
@@ -19,6 +19,7 @@ files can be found in mm/swap.c.
 Currently, these files are in /proc/sys/vm:
 
 - block_dump
+- compact_memory
 - dirty_background_bytes
 - dirty_background_ratio
 - dirty_bytes
@@ -26,6 +27,7 @@ Currently, these files are in /proc/sys/vm:
 - dirty_ratio
 - dirty_writeback_centisecs
 - drop_caches
+- extfrag_threshold
 - hugepages_treat_as_movable
 - hugetlb_shm_group
 - laptop_mode
@@ -64,6 +66,15 @@ information on block I/O debugging is in Documentation/laptops/laptop-mode.txt.
 
 ==============================================================
 
+compact_memory
+
+Available only when CONFIG_COMPACTION is set. When 1 is written to the file,
+all zones are compacted such that free memory is available in contiguous
+blocks where possible. This can be important for example in the allocation of
+huge pages although processes will also directly compact memory as required.
+
+==============================================================
+
 dirty_background_bytes
 
 Contains the amount of dirty memory at which the pdflush background writeback
@@ -139,6 +150,20 @@ user should run `sync' first.
 
 ==============================================================
 
+extfrag_threshold
+
+This parameter affects whether the kernel will compact memory or direct
+reclaim to satisfy a high-order allocation. /proc/extfrag_index shows what
+the fragmentation index for each order is in each zone in the system. Values
+tending towards 0 imply allocations would fail due to lack of memory,
+values towards 1000 imply failures are due to fragmentation and -1 implies
+that the allocation will succeed as long as watermarks are met.
+
+The kernel will not compact memory in a zone if the
+fragmentation index is <= extfrag_threshold. The default value is 500.
+
+==============================================================
+
 hugepages_treat_as_movable
 
 This parameter is only useful when kernelcore= is specified at boot time to
index f9ce2d9fdfd5becebf0ed9a7a3db3cd60ed7ae55..4bfafb7bc4c5852b2796fa15572a753bcb717a6e 100644 (file)
@@ -10,7 +10,6 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <signal.h>
-#include <fcntl.h>
 #include <errno.h>
 #include <sys/time.h>
 #include <linux/hpet.h>
@@ -24,7 +23,6 @@ extern void hpet_read(int, const char **);
 
 #include <sys/poll.h>
 #include <sys/ioctl.h>
-#include <signal.h>
 
 struct hpet_command {
        char            *command;
index 9969c7d9f9855486096a5c9e01b88c14034e6efd..eda1a6d3578ab64a99931b716ab164841d8de310 100644 (file)
@@ -19,7 +19,7 @@
 #define PROTECTION (PROT_READ | PROT_WRITE)
 
 #ifndef MAP_HUGETLB
-#define MAP_HUGETLB 0x40
+#define MAP_HUGETLB 0x40000 /* arch specific */
 #endif
 
 /* Only ia64 requires this */
index e93ad9425e2a162b949b015c53da2b155a897b29..a200a386429d568776c3737e860b0b2c81672c52 100644 (file)
 Started Nov 1999 by Kanoj Sarcar <kanoj@sgi.com>
 
-The intent of this file is to have an uptodate, running commentary 
-from different people about NUMA specific code in the Linux vm.
-
-What is NUMA? It is an architecture where the memory access times
-for different regions of memory from a given processor varies
-according to the "distance" of the memory region from the processor.
-Each region of memory to which access times are the same from any 
-cpu, is called a node. On such architectures, it is beneficial if
-the kernel tries to minimize inter node communications. Schemes
-for this range from kernel text and read-only data replication
-across nodes, and trying to house all the data structures that
-key components of the kernel need on memory on that node.
-
-Currently, all the numa support is to provide efficient handling
-of widely discontiguous physical memory, so architectures which 
-are not NUMA but can have huge holes in the physical address space
-can use the same code. All this code is bracketed by CONFIG_DISCONTIGMEM.
-
-The initial port includes NUMAizing the bootmem allocator code by
-encapsulating all the pieces of information into a bootmem_data_t
-structure. Node specific calls have been added to the allocator. 
-In theory, any platform which uses the bootmem allocator should 
-be able to put the bootmem and mem_map data structures anywhere
-it deems best.
-
-Each node's page allocation data structures have also been encapsulated
-into a pg_data_t. The bootmem_data_t is just one part of this. To 
-make the code look uniform between NUMA and regular UMA platforms, 
-UMA platforms have a statically allocated pg_data_t too (contig_page_data).
-For the sake of uniformity, the function num_online_nodes() is also defined
-for all platforms. As we run benchmarks, we might decide to NUMAize 
-more variables like low_on_memory, nr_free_pages etc into the pg_data_t.
-
-The NUMA aware page allocation code currently tries to allocate pages 
-from different nodes in a round robin manner.  This will be changed to 
-do concentratic circle search, starting from current node, once the 
-NUMA port achieves more maturity. The call alloc_pages_node has been 
-added, so that drivers can make the call and not worry about whether 
-it is running on a NUMA or UMA platform.
+What is NUMA?
+
+This question can be answered from a couple of perspectives:  the
+hardware view and the Linux software view.
+
+From the hardware perspective, a NUMA system is a computer platform that
+comprises multiple components or assemblies each of which may contain 0
+or more CPUs, local memory, and/or IO buses.  For brevity and to
+disambiguate the hardware view of these physical components/assemblies
+from the software abstraction thereof, we'll call the components/assemblies
+'cells' in this document.
+
+Each of the 'cells' may be viewed as an SMP [symmetric multi-processor] subset
+of the system--although some components necessary for a stand-alone SMP system
+may not be populated on any given cell.   The cells of the NUMA system are
+connected together with some sort of system interconnect--e.g., a crossbar or
+point-to-point link are common types of NUMA system interconnects.  Both of
+these types of interconnects can be aggregated to create NUMA platforms with
+cells at multiple distances from other cells.
+
+For Linux, the NUMA platforms of interest are primarily what is known as Cache
+Coherent NUMA or ccNUMA systems.   With ccNUMA systems, all memory is visible
+to and accessible from any CPU attached to any cell and cache coherency
+is handled in hardware by the processor caches and/or the system interconnect.
+
+Memory access time and effective memory bandwidth varies depending on how far
+away the cell containing the CPU or IO bus making the memory access is from the
+cell containing the target memory.  For example, access to memory by CPUs
+attached to the same cell will experience faster access times and higher
+bandwidths than accesses to memory on other, remote cells.  NUMA platforms
+can have cells at multiple remote distances from any given cell.
+
+Platform vendors don't build NUMA systems just to make software developers'
+lives interesting.  Rather, this architecture is a means to provide scalable
+memory bandwidth.  However, to achieve scalable memory bandwidth, system and
+application software must arrange for a large majority of the memory references
+[cache misses] to be to "local" memory--memory on the same cell, if any--or
+to the closest cell with memory.
+
+This leads to the Linux software view of a NUMA system:
+
+Linux divides the system's hardware resources into multiple software
+abstractions called "nodes".  Linux maps the nodes onto the physical cells
+of the hardware platform, abstracting away some of the details for some
+architectures.  As with physical cells, software nodes may contain 0 or more
+CPUs, memory and/or IO buses.  And, again, memory accesses to memory on
+"closer" nodes--nodes that map to closer cells--will generally experience
+faster access times and higher effective bandwidth than accesses to more
+remote cells.
+
+For some architectures, such as x86, Linux will "hide" any node representing a
+physical cell that has no memory attached, and reassign any CPUs attached to
+that cell to a node representing a cell that does have memory.  Thus, on
+these architectures, one cannot assume that all CPUs that Linux associates with
+a given node will see the same local memory access times and bandwidth.
+
+In addition, for some architectures, again x86 is an example, Linux supports
+the emulation of additional nodes.  For NUMA emulation, linux will carve up
+the existing nodes--or the system memory for non-NUMA platforms--into multiple
+nodes.  Each emulated node will manage a fraction of the underlying cells'
+physical memory.  NUMA emluation is useful for testing NUMA kernel and
+application features on non-NUMA platforms, and as a sort of memory resource
+management mechanism when used together with cpusets.
+[see Documentation/cgroups/cpusets.txt]
+
+For each node with memory, Linux constructs an independent memory management
+subsystem, complete with its own free page lists, in-use page lists, usage
+statistics and locks to mediate access.  In addition, Linux constructs for
+each memory zone [one or more of DMA, DMA32, NORMAL, HIGH_MEMORY, MOVABLE],
+an ordered "zonelist".  A zonelist specifies the zones/nodes to visit when a
+selected zone/node cannot satisfy the allocation request.  This situation,
+when a zone has no available memory to satisfy a request, is called
+"overflow" or "fallback".
+
+Because some nodes contain multiple zones containing different types of
+memory, Linux must decide whether to order the zonelists such that allocations
+fall back to the same zone type on a different node, or to a different zone
+type on the same node.  This is an important consideration because some zones,
+such as DMA or DMA32, represent relatively scarce resources.  Linux chooses
+a default zonelist order based on the sizes of the various zone types relative
+to the total memory of the node and the total memory of the system.  The
+default zonelist order may be overridden using the numa_zonelist_order kernel
+boot parameter or sysctl.  [see Documentation/kernel-parameters.txt and
+Documentation/sysctl/vm.txt]
+
+By default, Linux will attempt to satisfy memory allocation requests from the
+node to which the CPU that executes the request is assigned.  Specifically,
+Linux will attempt to allocate from the first node in the appropriate zonelist
+for the node where the request originates.  This is called "local allocation."
+If the "local" node cannot satisfy the request, the kernel will examine other
+nodes' zones in the selected zonelist looking for the first zone in the list
+that can satisfy the request.
+
+Local allocation will tend to keep subsequent access to the allocated memory
+"local" to the underlying physical resources and off the system interconnect--
+as long as the task on whose behalf the kernel allocated some memory does not
+later migrate away from that memory.  The Linux scheduler is aware of the
+NUMA topology of the platform--embodied in the "scheduling domains" data
+structures [see Documentation/scheduler/sched-domains.txt]--and the scheduler
+attempts to minimize task migration to distant scheduling domains.  However,
+the scheduler does not take a task's NUMA footprint into account directly.
+Thus, under sufficient imbalance, tasks can migrate between nodes, remote
+from their initial node and kernel data structures.
+
+System administrators and application designers can restrict a task's migration
+to improve NUMA locality using various CPU affinity command line interfaces,
+such as taskset(1) and numactl(1), and program interfaces such as
+sched_setaffinity(2).  Further, one can modify the kernel's default local
+allocation behavior using Linux NUMA memory policy.
+[see Documentation/vm/numa_memory_policy.]
+
+System administrators can restrict the CPUs and nodes' memories that a non-
+privileged user can specify in the scheduling or NUMA commands and functions
+using control groups and CPUsets.  [see Documentation/cgroups/CPUsets.txt]
+
+On architectures that do not hide memoryless nodes, Linux will include only
+zones [nodes] with memory in the zonelists.  This means that for a memoryless
+node the "local memory node"--the node of the first zone in CPU's node's
+zonelist--will not be the node itself.  Rather, it will be the node that the
+kernel selected as the nearest node with memory when it built the zonelists.
+So, default, local allocations will succeed with the kernel supplying the
+closest available memory.  This is a consequence of the same mechanism that
+allows such allocations to fallback to other nearby nodes when a node that
+does contain memory overflows.
+
+Some kernel allocations do not want or cannot tolerate this allocation fallback
+behavior.  Rather they want to be sure they get memory from the specified node
+or get notified that the node has no free memory.  This is usually the case when
+a subsystem allocates per CPU memory resources, for example.
+
+A typical model for making such an allocation is to obtain the node id of the
+node to which the "current CPU" is attached using one of the kernel's
+numa_node_id() or CPU_to_node() functions and then request memory from only
+the node id returned.  When such an allocation fails, the requesting subsystem
+may revert to its own fallback path.  The slab kernel memory allocator is an
+example of this.  Or, the subsystem may choose to disable or not to enable
+itself on allocation failure.  The kernel profiling subsystem is an example of
+this.
+
+If the architecture supports--does not hide--memoryless nodes, then CPUs
+attached to memoryless nodes would always incur the fallback path overhead
+or some subsystems would fail to initialize if they attempted to allocated
+memory exclusively from a node without memory.  To support such
+architectures transparently, kernel subsystems can use the numa_mem_id()
+or cpu_to_mem() function to locate the "local memory node" for the calling or
+specified CPU.  Again, this is the same node from which default, local page
+allocations will be attempted.
index c3ea47e507fe65c529251e7afef0e2f0b8dc84a1..ee994513a9b1dff1799361d10ad56c7c6cf50128 100644 (file)
@@ -1,10 +1,15 @@
 00-INDEX
        - this file.
+hpwdt.txt
+       - information on the HP iLO2 NMI watchdog
 pcwd-watchdog.txt
        - documentation for Berkshire Products PC Watchdog ISA cards.
 src/
        - directory holding watchdog related example programs.
 watchdog-api.txt
        - description of the Linux Watchdog driver API.
+watchdog-parameters.txt
+       - information on driver parameters (for drivers other than
+         the ones that have driver-specific files here)
 wdt.txt
        - description of the Watchdog Timer Interfaces for Linux.
diff --git a/Documentation/watchdog/watchdog-parameters.txt b/Documentation/watchdog/watchdog-parameters.txt
new file mode 100644 (file)
index 0000000..41c95cc
--- /dev/null
@@ -0,0 +1,390 @@
+This file provides information on the module parameters of many of
+the Linux watchdog drivers.  Watchdog driver parameter specs should
+be listed here unless the driver has its own driver-specific information
+file.
+
+
+See Documentation/kernel-parameters.txt for information on
+providing kernel parameters for builtin drivers versus loadable
+modules.
+
+
+-------------------------------------------------
+acquirewdt:
+wdt_stop: Acquire WDT 'stop' io port (default 0x43)
+wdt_start: Acquire WDT 'start' io port (default 0x443)
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+advantechwdt:
+wdt_stop: Advantech WDT 'stop' io port (default 0x443)
+wdt_start: Advantech WDT 'start' io port (default 0x443)
+timeout: Watchdog timeout in seconds. 1<= timeout <=63, default=60.
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+alim1535_wdt:
+timeout: Watchdog timeout in seconds. (0 < timeout < 18000, default=60
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+alim7101_wdt:
+timeout: Watchdog timeout in seconds. (1<=timeout<=3600, default=30
+use_gpio: Use the gpio watchdog (required by old cobalt boards).
+       default=0/off/no
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+ar7_wdt:
+margin: Watchdog margin in seconds (default=60)
+nowayout: Disable watchdog shutdown on close
+       (default=kernel config parameter)
+-------------------------------------------------
+at32ap700x_wdt:
+timeout: Timeout value. Limited to be 1 or 2 seconds. (default=2)
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+at91rm9200_wdt:
+wdt_time: Watchdog time in seconds. (default=5)
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+at91sam9_wdt:
+heartbeat: Watchdog heartbeats in seconds. (default = 15)
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+bcm47xx_wdt:
+wdt_time: Watchdog time in seconds. (default=30)
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+bfin_wdt:
+timeout: Watchdog timeout in seconds. (1<=timeout<=((2^32)/SCLK), default=20)
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+coh901327_wdt:
+margin: Watchdog margin in seconds (default 60s)
+-------------------------------------------------
+cpu5wdt:
+port: base address of watchdog card, default is 0x91
+verbose: be verbose, default is 0 (no)
+ticks: count down ticks, default is 10000
+-------------------------------------------------
+cpwd:
+wd0_timeout: Default watchdog0 timeout in 1/10secs
+wd1_timeout: Default watchdog1 timeout in 1/10secs
+wd2_timeout: Default watchdog2 timeout in 1/10secs
+-------------------------------------------------
+davinci_wdt:
+heartbeat: Watchdog heartbeat period in seconds from 1 to 600, default 60
+-------------------------------------------------
+ep93xx_wdt:
+nowayout: Watchdog cannot be stopped once started
+timeout: Watchdog timeout in seconds. (1<=timeout<=3600, default=TBD)
+-------------------------------------------------
+eurotechwdt:
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+io: Eurotech WDT io port (default=0x3f0)
+irq: Eurotech WDT irq (default=10)
+ev: Eurotech WDT event type (default is `int')
+-------------------------------------------------
+gef_wdt:
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+geodewdt:
+timeout: Watchdog timeout in seconds. 1<= timeout <=131, default=60.
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+i6300esb:
+heartbeat: Watchdog heartbeat in seconds. (1<heartbeat<2046, default=30)
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+iTCO_wdt:
+heartbeat: Watchdog heartbeat in seconds.
+       (2<heartbeat<39 (TCO v1) or 613 (TCO v2), default=30)
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+iTCO_vendor_support:
+vendorsupport: iTCO vendor specific support mode, default=0 (none),
+       1=SuperMicro Pent3, 2=SuperMicro Pent4+, 911=Broken SMI BIOS
+-------------------------------------------------
+ib700wdt:
+timeout: Watchdog timeout in seconds. 0<= timeout <=30, default=30.
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+ibmasr:
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+indydog:
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+iop_wdt:
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+it8712f_wdt:
+margin: Watchdog margin in seconds (default 60)
+nowayout: Disable watchdog shutdown on close
+       (default=kernel config parameter)
+-------------------------------------------------
+it87_wdt:
+nogameport: Forbid the activation of game port, default=0
+exclusive: Watchdog exclusive device open, default=1
+timeout: Watchdog timeout in seconds, default=60
+testmode: Watchdog test mode (1 = no reboot), default=0
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+ixp2000_wdt:
+heartbeat: Watchdog heartbeat in seconds (default 60s)
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+ixp4xx_wdt:
+heartbeat: Watchdog heartbeat in seconds (default 60s)
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+ks8695_wdt:
+wdt_time: Watchdog time in seconds. (default=5)
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+machzwd:
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+action: after watchdog resets, generate:
+       0 = RESET(*)  1 = SMI  2 = NMI  3 = SCI
+-------------------------------------------------
+max63xx_wdt:
+heartbeat: Watchdog heartbeat period in seconds from 1 to 60, default 60
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+nodelay: Force selection of a timeout setting without initial delay
+       (max6373/74 only, default=0)
+-------------------------------------------------
+mixcomwd:
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+mpc8xxx_wdt:
+timeout: Watchdog timeout in ticks. (0<timeout<65536, default=65535)
+reset: Watchdog Interrupt/Reset Mode. 0 = interrupt, 1 = reset
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+mpcore_wdt:
+mpcore_margin: MPcore timer margin in seconds.
+       (0 < mpcore_margin < 65536, default=60)
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+mpcore_noboot: MPcore watchdog action, set to 1 to ignore reboots,
+       0 to reboot (default=0
+-------------------------------------------------
+mv64x60_wdt:
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+nuc900_wdt:
+heartbeat: Watchdog heartbeats in seconds.
+       (default = 15)
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+omap_wdt:
+timer_margin: initial watchdog timeout (in seconds)
+-------------------------------------------------
+orion_wdt:
+heartbeat: Initial watchdog heartbeat in seconds
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+pc87413_wdt:
+io: pc87413 WDT I/O port (default: io).
+timeout: Watchdog timeout in minutes (default=timeout).
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+pika_wdt:
+heartbeat: Watchdog heartbeats in seconds. (default = 15)
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+pnx4008_wdt:
+heartbeat: Watchdog heartbeat period in seconds from 1 to 60, default 19
+nowayout: Set to 1 to keep watchdog running after device release
+-------------------------------------------------
+pnx833x_wdt:
+timeout: Watchdog timeout in Mhz. (68Mhz clock), default=2040000000 (30 seconds)
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+start_enabled: Watchdog is started on module insertion (default=1)
+-------------------------------------------------
+rc32434_wdt:
+timeout: Watchdog timeout value, in seconds (default=20)
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+riowd:
+riowd_timeout: Watchdog timeout in minutes (default=1)
+-------------------------------------------------
+s3c2410_wdt:
+tmr_margin: Watchdog tmr_margin in seconds. (default=15)
+tmr_atboot: Watchdog is started at boot time if set to 1, default=0
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+soft_noboot: Watchdog action, set to 1 to ignore reboots, 0 to reboot
+debug: Watchdog debug, set to >1 for debug, (default 0)
+-------------------------------------------------
+sa1100_wdt:
+margin: Watchdog margin in seconds (default 60s)
+-------------------------------------------------
+sb_wdog:
+timeout: Watchdog timeout in microseconds (max/default 8388607 or 8.3ish secs)
+-------------------------------------------------
+sbc60xxwdt:
+wdt_stop: SBC60xx WDT 'stop' io port (default 0x45)
+wdt_start: SBC60xx WDT 'start' io port (default 0x443)
+timeout: Watchdog timeout in seconds. (1<=timeout<=3600, default=30)
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+sbc7240_wdt:
+timeout: Watchdog timeout in seconds. (1<=timeout<=255, default=30)
+nowayout: Disable watchdog when closing device file
+-------------------------------------------------
+sbc8360:
+timeout: Index into timeout table (0-63) (default=27 (60s))
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+sbc_epx_c3:
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+sbc_fitpc2_wdt:
+margin: Watchdog margin in seconds (default 60s)
+nowayout: Watchdog cannot be stopped once started
+-------------------------------------------------
+sc1200wdt:
+isapnp: When set to 0 driver ISA PnP support will be disabled (default=1)
+io: io port
+timeout: range is 0-255 minutes, default is 1
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+sc520_wdt:
+timeout: Watchdog timeout in seconds. (1 <= timeout <= 3600, default=30)
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+sch311x_wdt:
+force_id: Override the detected device ID
+therm_trip: Should a ThermTrip trigger the reset generator
+timeout: Watchdog timeout in seconds. 1<= timeout <=15300, default=60
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+scx200_wdt:
+margin: Watchdog margin in seconds
+nowayout: Disable watchdog shutdown on close
+-------------------------------------------------
+shwdt:
+clock_division_ratio: Clock division ratio. Valid ranges are from 0x5 (1.31ms)
+       to 0x7 (5.25ms). (default=7)
+heartbeat: Watchdog heartbeat in seconds. (1 <= heartbeat <= 3600, default=30
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+smsc37b787_wdt:
+timeout: range is 1-255 units, default is 60
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+softdog:
+soft_margin: Watchdog soft_margin in seconds.
+       (0 < soft_margin < 65536, default=60)
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+soft_noboot: Softdog action, set to 1 to ignore reboots, 0 to reboot
+       (default=0)
+-------------------------------------------------
+stmp3xxx_wdt:
+heartbeat: Watchdog heartbeat period in seconds from 1 to 4194304, default 19
+-------------------------------------------------
+ts72xx_wdt:
+timeout: Watchdog timeout in seconds. (1 <= timeout <= 8, default=8)
+nowayout: Disable watchdog shutdown on close
+-------------------------------------------------
+twl4030_wdt:
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+txx9wdt:
+timeout: Watchdog timeout in seconds. (0<timeout<N, default=60)
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+w83627hf_wdt:
+wdt_io: w83627hf/thf WDT io port (default 0x2E)
+timeout: Watchdog timeout in seconds. 1 <= timeout <= 255, default=60.
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+w83697hf_wdt:
+wdt_io: w83697hf/hg WDT io port (default 0x2e, 0 = autodetect)
+timeout: Watchdog timeout in seconds. 1<= timeout <=255 (default=60)
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+early_disable: Watchdog gets disabled at boot time (default=1)
+-------------------------------------------------
+w83697ug_wdt:
+wdt_io: w83697ug/uf WDT io port (default 0x2e)
+timeout: Watchdog timeout in seconds. 1<= timeout <=255 (default=60)
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+w83877f_wdt:
+timeout: Watchdog timeout in seconds. (1<=timeout<=3600, default=30)
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+w83977f_wdt:
+timeout: Watchdog timeout in seconds (15..7635), default=45)
+testmode: Watchdog testmode (1 = no reboot), default=0
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+wafer5823wdt:
+timeout: Watchdog timeout in seconds. 1 <= timeout <= 255, default=60.
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+wdt285:
+soft_margin: Watchdog timeout in seconds (default=60)
+-------------------------------------------------
+wdt977:
+timeout: Watchdog timeout in seconds (60..15300, default=60)
+testmode: Watchdog testmode (1 = no reboot), default=0
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+wm831x_wdt:
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
+wm8350_wdt:
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
index 03fd756d976d339b0bfdf81c56e42afc3b6b9c13..061c2e35384f5eb6354bba48e2da565f18040731 100644 (file)
@@ -14,14 +14,22 @@ reboot will depend on the state of the machines and interrupts. The hardware
 boards physically pull the machine down off their own onboard timers and
 will reboot from almost anything.
 
-A second temperature monitoring interface is available on the WDT501P cards
+A second temperature monitoring interface is available on the WDT501P cards.
 This provides /dev/temperature. This is the machine internal temperature in
 degrees Fahrenheit. Each read returns a single byte giving the temperature.
 
 The third interface logs kernel messages on additional alert events.
 
-The wdt card cannot be safely probed for. Instead you need to pass
-wdt=ioaddr,irq as a boot parameter - eg "wdt=0x240,11".
+The ICS ISA-bus wdt card cannot be safely probed for. Instead you need to
+pass IO address and IRQ boot parameters.  E.g.:
+       wdt.io=0x240 wdt.irq=11
+
+Other "wdt" driver parameters are:
+       heartbeat       Watchdog heartbeat in seconds (default 60)
+       nowayout        Watchdog cannot be stopped once started (kernel
+                               build parameter)
+       tachometer      WDT501-P Fan Tachometer support (0=disable, default=0)
+       type            WDT501-P Card type (500 or 501, default=500)
 
 Features
 --------
@@ -40,4 +48,3 @@ Minor numbers are however allocated for it.
 
 
 Example Watchdog Driver:  see Documentation/watchdog/src/watchdog-simple.c
-
index a8fe9b461e09c64df9e4cf618ced7f588a4fea7b..13608bd2e7913941bae445f08c201912f798c2fd 100644 (file)
@@ -969,6 +969,18 @@ M: Wan ZongShun <mcuos.com@gmail.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 W:     http://www.mcuos.com
 S:     Maintained
+F:     arch/arm/mach-w90x900/
+F:     arch/arm/mach-nuc93x/
+F:     drivers/input/keyboard/w90p910_keypad.c
+F:     drivers/input/touchscreen/w90p910_ts.c
+F:     drivers/watchdog/nuc900_wdt.c
+F:     drivers/net/arm/w90p910_ether.c
+F:     drivers/mtd/nand/w90p910_nand.c
+F:     drivers/rtc/rtc-nuc900.c
+F:     drivers/spi/spi_nuc900.c
+F:     drivers/usb/host/ehci-w90x900.c
+F:     drivers/video/nuc900fb.c
+F:     drivers/sound/soc/nuc900/
 
 ARM/U300 MACHINE SUPPORT
 M:     Linus Walleij <linus.walleij@stericsson.com>
@@ -2875,6 +2887,13 @@ T:       git git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git
 S:     Maintained
 F:     drivers/input/
 
+INTEL IDLE DRIVER
+M:     Len Brown <lenb@kernel.org>
+L:     linux-pm@lists.linux-foundation.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-idle-2.6.git
+S:     Supported
+F:     drivers/idle/intel_idle.c
+
 INTEL FRAMEBUFFER DRIVER (excluding 810 and 815)
 M:     Maik Broemme <mbroemme@plusserver.de>
 L:     linux-fbdev@vger.kernel.org
@@ -4824,6 +4843,9 @@ W:        http://www.ibm.com/developerworks/linux/linux390/
 S:     Supported
 F:     arch/s390/
 F:     drivers/s390/
+F:     fs/partitions/ibm.c
+F:     Documentation/s390/
+F:     Documentation/DocBook/s390*
 
 S390 NETWORK DRIVERS
 M:     Ursula Braun <ursula.braun@de.ibm.com>
@@ -4992,6 +5014,12 @@ L:       linux-mmc@vger.kernel.org
 S:     Maintained
 F:     drivers/mmc/host/sdhci-s3c.c
 
+SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) ST SPEAR DRIVER
+M:     Viresh Kumar <viresh.kumar@st.com>
+L:     linux-mmc@vger.kernel.org
+S:     Maintained
+F:     drivers/mmc/host/sdhci-spear.c
+
 SECURITY SUBSYSTEM
 M:     James Morris <jmorris@namei.org>
 L:     linux-security-module@vger.kernel.org (suggested Cc:)
index b7193986cbf98989468283f898744d79b3cd08c2..3e2e540a0f2a85ce92aa0a70f604bc4a461c3517 100644 (file)
@@ -51,10 +51,6 @@ config GENERIC_TIME
        bool
        default y
 
-config ARCH_USES_GETTIMEOFFSET
-       bool
-       default y
-
 config GENERIC_CMOS_UPDATE
         def_bool y
 
@@ -65,6 +61,9 @@ config ZONE_DMA
 config NEED_DMA_MAP_STATE
        def_bool y
 
+config NEED_SG_DMA_LENGTH
+       def_bool y
+
 config GENERIC_ISA_DMA
        bool
        default y
index 296da1d5ed57a5caff0fa2111545ef44d9ede953..1dce24bc455a7ff9a13495517c53743a142cd49d 100644 (file)
@@ -438,22 +438,20 @@ static inline unsigned int __arch_hweight8(unsigned int w)
 
 /*
  * Every architecture must define this function. It's the fastest
- * way of searching a 140-bit bitmap where the first 100 bits are
- * unlikely to be set. It's guaranteed that at least one of the 140
- * bits is set.
+ * way of searching a 100-bit bitmap.  It's guaranteed that at least
+ * one of the 100 bits is cleared.
  */
 static inline unsigned long
-sched_find_first_bit(unsigned long b[3])
+sched_find_first_bit(const unsigned long b[2])
 {
-       unsigned long b0 = b[0], b1 = b[1], b2 = b[2];
-       unsigned long ofs;
+       unsigned long b0, b1, ofs, tmp;
 
-       ofs = (b1 ? 64 : 128);
-       b1 = (b1 ? b1 : b2);
-       ofs = (b0 ? 0 : ofs);
-       b0 = (b0 ? b0 : b1);
+       b0 = b[0];
+       b1 = b[1];
+       ofs = (b0 ? 0 : 64);
+       tmp = (b0 ? b0 : b1);
 
-       return __ffs(b0) + ofs;
+       return __ffs(tmp) + ofs;
 }
 
 #include <asm-generic/bitops/ext2-non-atomic.h>
index 440747ca6349058d31f04b6191ed2de0870ce557..5728c52a7412307c49c78098b72918d42499ac8b 100644 (file)
@@ -1,24 +1,7 @@
 #ifndef _ALPHA_SCATTERLIST_H
 #define _ALPHA_SCATTERLIST_H
 
-#include <asm/page.h>
-#include <asm/types.h>
-  
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-       unsigned long sg_magic;
-#endif
-       unsigned long page_link;
-       unsigned int offset;
-
-       unsigned int length;
-
-       dma_addr_t dma_address;
-       __u32 dma_length;
-};
-
-#define sg_dma_address(sg)     ((sg)->dma_address)
-#define sg_dma_len(sg)         ((sg)->dma_length)
+#include <asm-generic/scatterlist.h>
 
 #define ISA_DMA_THRESHOLD (~0UL)
 
index 5465e932e568ed3d07f6b9915a2a355188eed057..1efbed82c0fd38a2bb0ecd925d80bef884801642 100644 (file)
@@ -51,6 +51,7 @@
 #include <linux/mc146818rtc.h>
 #include <linux/time.h>
 #include <linux/timex.h>
+#include <linux/clocksource.h>
 
 #include "proto.h"
 #include "irq_impl.h"
@@ -332,6 +333,34 @@ rpcc_after_update_in_progress(void)
        return rpcc();
 }
 
+#ifndef CONFIG_SMP
+/* Until and unless we figure out how to get cpu cycle counters
+   in sync and keep them there, we can't use the rpcc.  */
+static cycle_t read_rpcc(struct clocksource *cs)
+{
+       cycle_t ret = (cycle_t)rpcc();
+       return ret;
+}
+
+static struct clocksource clocksource_rpcc = {
+       .name                   = "rpcc",
+       .rating                 = 300,
+       .read                   = read_rpcc,
+       .mask                   = CLOCKSOURCE_MASK(32),
+       .flags                  = CLOCK_SOURCE_IS_CONTINUOUS
+};
+
+static inline void register_rpcc_clocksource(long cycle_freq)
+{
+       clocksource_calc_mult_shift(&clocksource_rpcc, cycle_freq, 4);
+       clocksource_register(&clocksource_rpcc);
+}
+#else /* !CONFIG_SMP */
+static inline void register_rpcc_clocksource(long cycle_freq)
+{
+}
+#endif /* !CONFIG_SMP */
+
 void __init
 time_init(void)
 {
@@ -385,6 +414,8 @@ time_init(void)
                __you_loose();
        }
 
+       register_rpcc_clocksource(cycle_freq);
+
        state.last_time = cc1;
        state.scaled_ticks_per_cycle
                = ((unsigned long) HZ << FIX_SHIFT) / cycle_freq;
@@ -394,44 +425,6 @@ time_init(void)
        alpha_mv.init_rtc();
 }
 
-/*
- * Use the cycle counter to estimate an displacement from the last time
- * tick.  Unfortunately the Alpha designers made only the low 32-bits of
- * the cycle counter active, so we overflow on 8.2 seconds on a 500MHz
- * part.  So we can't do the "find absolute time in terms of cycles" thing
- * that the other ports do.
- */
-u32 arch_gettimeoffset(void)
-{
-#ifdef CONFIG_SMP
-       /* Until and unless we figure out how to get cpu cycle counters
-          in sync and keep them there, we can't use the rpcc tricks.  */
-       return 0;
-#else
-       unsigned long delta_cycles, delta_usec, partial_tick;
-
-       delta_cycles = rpcc() - state.last_time;
-       partial_tick = state.partial_tick;
-       /*
-        * usec = cycles * ticks_per_cycle * 2**48 * 1e6 / (2**48 * ticks)
-        *      = cycles * (s_t_p_c) * 1e6 / (2**48 * ticks)
-        *      = cycles * (s_t_p_c) * 15625 / (2**42 * ticks)
-        *
-        * which, given a 600MHz cycle and a 1024Hz tick, has a
-        * dynamic range of about 1.7e17, which is less than the
-        * 1.8e19 in an unsigned long, so we are safe from overflow.
-        *
-        * Round, but with .5 up always, since .5 to even is harder
-        * with no clear gain.
-        */
-
-       delta_usec = (delta_cycles * state.scaled_ticks_per_cycle 
-                     + partial_tick) * 15625;
-       delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2;
-       return delta_usec * 1000;
-#endif
-}
-
 /*
  * In order to set the CMOS clock precisely, set_rtc_mmss has to be
  * called 500 ms after the second nowtime has started, because when
index 00a31deaa96e0cc1d54e3fc2a34e4944cfb4609b..fadd5f882ff9182e89bb8fdddbed626b8a4a5c1d 100644 (file)
@@ -142,7 +142,6 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
                        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.  */
@@ -188,16 +187,10 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
        /* 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:
-       if (is_global_init(current)) {
-               yield();
-               down_read(&mm->mmap_sem);
-               goto survive;
-       }
-       printk(KERN_ALERT "VM: killing process %s(%d)\n",
-              current->comm, task_pid_nr(current));
        if (!user_mode(regs))
                goto no_context;
-       do_group_exit(SIGKILL);
+       pagefault_out_of_memory();
+       return;
 
  do_sigbus:
        /* Send a sigbus, regardless of whether we were in kernel
index 2d70cece2ea2f390856d84c8c4515310082e9e2a..1f254bd6c937ece2e6d6a6b1040d954cc923cd7a 100644 (file)
@@ -671,6 +671,7 @@ config ARCH_S5P6440
        select CPU_V6
        select GENERIC_GPIO
        select HAVE_CLK
+       select ARCH_USES_GETTIMEOFFSET
        help
          Samsung S5P6440 CPU based systems
 
@@ -679,17 +680,19 @@ config ARCH_S5P6442
        select CPU_V6
        select GENERIC_GPIO
        select HAVE_CLK
+       select ARCH_USES_GETTIMEOFFSET
        help
          Samsung S5P6442 CPU based systems
 
-config ARCH_S5PC1XX
-       bool "Samsung S5PC1XX"
+config ARCH_S5PC100
+       bool "Samsung S5PC100"
        select GENERIC_GPIO
        select HAVE_CLK
        select CPU_V7
        select ARM_L1_CACHE_SHIFT_6
+       select ARCH_USES_GETTIMEOFFSET
        help
-         Samsung S5PC1XX series based systems
+         Samsung S5PC100 series based systems
 
 config ARCH_S5PV210
        bool "Samsung S5PV210/S5PC110"
@@ -697,6 +700,7 @@ config ARCH_S5PV210
        select GENERIC_GPIO
        select HAVE_CLK
        select ARM_L1_CACHE_SHIFT_6
+       select ARCH_USES_GETTIMEOFFSET
        help
          Samsung S5PV210/S5PC110 series based systems
 
@@ -876,7 +880,7 @@ source "arch/arm/mach-sa1100/Kconfig"
 source "arch/arm/plat-samsung/Kconfig"
 source "arch/arm/plat-s3c24xx/Kconfig"
 source "arch/arm/plat-s5p/Kconfig"
-source "arch/arm/plat-s5pc1xx/Kconfig"
+
 source "arch/arm/plat-spear/Kconfig"
 
 if ARCH_S3C2410
@@ -896,9 +900,7 @@ source "arch/arm/mach-s5p6440/Kconfig"
 
 source "arch/arm/mach-s5p6442/Kconfig"
 
-if ARCH_S5PC1XX
 source "arch/arm/mach-s5pc100/Kconfig"
-endif
 
 source "arch/arm/mach-s5pv210/Kconfig"
 
@@ -1419,6 +1421,17 @@ config CMDLINE
          time by entering them here. As a minimum, you should specify the
          memory size and the root device (e.g., mem=64M root=/dev/nfs).
 
+config CMDLINE_FORCE
+       bool "Always use the default kernel command string"
+       depends on CMDLINE != ""
+       help
+         Always use the default kernel command string, even if the boot
+         loader passes other arguments to the kernel.
+         This is useful if you cannot or don't want to change the
+         command-line options your boot loader passes to the kernel.
+
+         If unsure, say N.
+
 config XIP_KERNEL
        bool "Kernel Execute-In-Place from ROM"
        depends on !ZBOOT_ROM
index 4b857fbe4314d028c9a457ab69a2f3f1295e9fe7..64ba313724d2377fda7e439e130d7ad69dd1a83c 100644 (file)
@@ -168,7 +168,7 @@ machine-$(CONFIG_ARCH_S3C24A0)              := s3c24a0
 machine-$(CONFIG_ARCH_S3C64XX)         := s3c64xx
 machine-$(CONFIG_ARCH_S5P6440)         := s5p6440
 machine-$(CONFIG_ARCH_S5P6442)         := s5p6442
-machine-$(CONFIG_ARCH_S5PC1XX)         := s5pc100
+machine-$(CONFIG_ARCH_S5PC100)         := s5pc100
 machine-$(CONFIG_ARCH_S5PV210)         := s5pv210
 machine-$(CONFIG_ARCH_SA1100)          := sa1100
 machine-$(CONFIG_ARCH_SHARK)           := shark
@@ -198,7 +198,6 @@ plat-$(CONFIG_PLAT_NOMADIK) := nomadik
 plat-$(CONFIG_PLAT_ORION)      := orion
 plat-$(CONFIG_PLAT_PXA)                := pxa
 plat-$(CONFIG_PLAT_S3C24XX)    := s3c24xx samsung
-plat-$(CONFIG_PLAT_S5PC1XX)    := s5pc1xx samsung
 plat-$(CONFIG_PLAT_S5P)                := s5p samsung
 plat-$(CONFIG_PLAT_SPEAR)      := spear
 plat-$(CONFIG_PLAT_VERSATILE)  := versatile
index 8e3d81ce695eab3f760285bd6772a97d90ba8afa..fc54394f4340ad63fc0e295b0b212faac64177c3 100644 (file)
@@ -19,7 +19,7 @@ SECTIONS
    initrd_size = initrd_end - initrd_start;
    _etext = .;
   }
-  
+
   .stab 0 : { *(.stab) }
   .stabstr 0 : { *(.stabstr) }
   .stab.excl 0 : { *(.stab.excl) }
index c88e9527a8ecd812ad50d776e6aedd2e27506143..a708fd6d6ffe6fbfd7554e9962feb41f859f0c12 100644 (file)
@@ -809,7 +809,22 @@ CONFIG_SSB_POSSIBLE=y
 CONFIG_DUMMY_CONSOLE=y
 # CONFIG_SOUND is not set
 # CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT 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
+
+#
+# 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_MMC=y
 # CONFIG_MMC_DEBUG is not set
 # CONFIG_MMC_UNSAFE_RESUME is not set
index 8e94c3caeb8c70bd27597c5be01b814203852187..44cea2ddd22bd4c19cc2bc2a64d47570b795a211 100644 (file)
@@ -1,14 +1,15 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc2
+# Linux kernel version: 2.6.34
+# Fri May 28 19:15:48 2010
 #
 CONFIG_ARM=y
 CONFIG_HAVE_PWM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
 CONFIG_GENERIC_GPIO=y
-# CONFIG_GENERIC_TIME is not set
-# CONFIG_GENERIC_CLOCKEVENTS is not set
-CONFIG_MMU=y
+CONFIG_GENERIC_TIME=y
+CONFIG_ARCH_USES_GETTIMEOFFSET=y
+CONFIG_HAVE_PROC_CPU=y
 CONFIG_NO_IOPORT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_STACKTRACE_SUPPORT=y
@@ -18,13 +19,14 @@ CONFIG_TRACE_IRQFLAGS_SUPPORT=y
 CONFIG_HARDIRQS_SW_RESEND=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_ARCH_HAS_ILOG2_U32 is not set
-# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_HAS_CPUFREQ=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"
+CONFIG_CONSTRUCTORS=y
 
 #
 # General setup
@@ -34,6 +36,13 @@ CONFIG_BROKEN_ON_SMP=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
@@ -45,15 +54,16 @@ CONFIG_SYSVIPC_SYSCTL=y
 #
 # RCU Subsystem
 #
-CONFIG_CLASSIC_RCU=y
-# CONFIG_TREE_RCU is not set
-# CONFIG_PREEMPT_RCU is not set
+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_PREEMPT_RCU_TRACE is not set
 CONFIG_IKCONFIG=m
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=16
-# CONFIG_GROUP_SCHED is not set
 # CONFIG_CGROUPS is not set
 CONFIG_SYSFS_DEPRECATED=y
 CONFIG_SYSFS_DEPRECATED_V2=y
@@ -69,6 +79,7 @@ CONFIG_INITRAMFS_SOURCE=""
 CONFIG_RD_GZIP=y
 CONFIG_RD_BZIP2=y
 CONFIG_RD_LZMA=y
+CONFIG_RD_LZO=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -78,7 +89,6 @@ CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -91,19 +101,30 @@ 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_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
 CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_CLK=y
-# CONFIG_SLOW_WORK is not set
+
+#
+# GCOV-based kernel profiling
+#
+CONFIG_SLOW_WORK=y
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -115,7 +136,7 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_BLK_DEV_INTEGRITY is not set
 
@@ -123,32 +144,64 @@ CONFIG_BLOCK=y
 # IO Schedulers
 #
 CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
-CONFIG_DEFAULT_AS=y
 # CONFIG_DEFAULT_DEADLINE is not set
-# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_CFQ=y
 # CONFIG_DEFAULT_NOOP is not set
-CONFIG_DEFAULT_IOSCHED="anticipatory"
+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=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_GEMINI is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_STMP3XXX is not set
 # CONFIG_ARCH_NETX is not set
 # CONFIG_ARCH_H720X is not set
-# CONFIG_ARCH_IMX is not set
 # CONFIG_ARCH_IOP13XX is not set
 # CONFIG_ARCH_IOP32X is not set
 # CONFIG_ARCH_IOP33X is not set
@@ -156,42 +209,37 @@ CONFIG_FREEZER=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_KS8695 is not set
-# CONFIG_ARCH_NS9XXX is not set
 # CONFIG_ARCH_LOKI is not set
 # CONFIG_ARCH_MV78XX0 is not set
-# CONFIG_ARCH_MXC 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_MMP 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=y
 # 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_ARCH_MSM is not set
-# CONFIG_ARCH_W90X900 is not set
-CONFIG_PLAT_S3C24XX=y
-CONFIG_S3C2410_CLOCK=y
-CONFIG_S3C24XX_DCLK=y
-CONFIG_CPU_S3C244X=y
-CONFIG_S3C24XX_PWM=y
-CONFIG_S3C24XX_GPIO_EXTRA=128
-CONFIG_S3C24XX_GPIO_EXTRA64=y
-CONFIG_S3C24XX_GPIO_EXTRA128=y
-CONFIG_PM_SIMTEC=y
-CONFIG_S3C2410_DMA=y
-# CONFIG_S3C2410_DMA_DEBUG is not set
-CONFIG_S3C_ADC=y
-CONFIG_MACH_SMDK=y
-CONFIG_PLAT_S3C=y
-CONFIG_CPU_LLSERIAL_S3C2410=y
-CONFIG_CPU_LLSERIAL_S3C2440=y
+# CONFIG_PLAT_SPEAR is not set
+CONFIG_PLAT_SAMSUNG=y
 
 #
 # Boot options
@@ -199,15 +247,44 @@ CONFIG_CPU_LLSERIAL_S3C2440=y
 # CONFIG_S3C_BOOT_WATCHDOG is not set
 CONFIG_S3C_BOOT_ERROR_RESET=y
 CONFIG_S3C_BOOT_UART_FORCE_FIFO=y
+CONFIG_S3C_LOWLEVEL_UART_PORT=0
+CONFIG_SAMSUNG_CLKSRC=y
+CONFIG_S3C_GPIO_CFG_S3C24XX=y
+CONFIG_S3C_GPIO_PULL_UPDOWN=y
+CONFIG_S3C_GPIO_PULL_UP=y
+CONFIG_SAMSUNG_GPIO_EXTRA=0
+CONFIG_S3C_GPIO_SPACE=0
+CONFIG_S3C_ADC=y
+CONFIG_S3C_DEV_HSMMC=y
+CONFIG_S3C_DEV_HSMMC1=y
+CONFIG_S3C_DEV_HWMON=y
+CONFIG_S3C_DEV_FB=y
+CONFIG_S3C_DEV_USB_HOST=y
+CONFIG_S3C_DEV_WDT=y
+CONFIG_S3C_DEV_NAND=y
+CONFIG_S3C_DMA=y
 
 #
 # Power management
 #
 # CONFIG_SAMSUNG_PM_DEBUG is not set
 # CONFIG_SAMSUNG_PM_CHECK is not set
-CONFIG_S3C_LOWLEVEL_UART_PORT=0
-CONFIG_S3C_GPIO_SPACE=0
-CONFIG_S3C_DEV_HSMMC=y
+CONFIG_PLAT_S3C24XX=y
+CONFIG_CPU_LLSERIAL_S3C2410=y
+CONFIG_CPU_LLSERIAL_S3C2440=y
+CONFIG_S3C2410_CLOCK=y
+CONFIG_S3C2443_CLOCK=y
+CONFIG_S3C24XX_DCLK=y
+CONFIG_S3C24XX_PWM=y
+CONFIG_S3C24XX_GPIO_EXTRA=128
+CONFIG_S3C24XX_GPIO_EXTRA64=y
+CONFIG_S3C24XX_GPIO_EXTRA128=y
+CONFIG_PM_SIMTEC=y
+CONFIG_S3C2410_DMA=y
+# CONFIG_S3C2410_DMA_DEBUG is not set
+CONFIG_MACH_SMDK=y
+CONFIG_S3C24XX_SIMTEC_AUDIO=y
+CONFIG_S3C2410_SETUP_TS=y
 
 #
 # S3C2400 Machines
@@ -224,8 +301,10 @@ CONFIG_MACH_BAST_IDE=y
 #
 CONFIG_ARCH_SMDK2410=y
 CONFIG_ARCH_H1940=y
+# CONFIG_H1940BT is not set
 CONFIG_PM_H1940=y
 CONFIG_MACH_N30=y
+CONFIG_MACH_N35=y
 CONFIG_ARCH_BAST=y
 CONFIG_MACH_OTOM=y
 CONFIG_MACH_AML_M5900=y
@@ -246,26 +325,35 @@ CONFIG_MACH_SMDK2413=y
 CONFIG_MACH_S3C2413=y
 CONFIG_MACH_SMDK2412=y
 CONFIG_MACH_VSTMS=y
+CONFIG_CPU_S3C2416=y
+CONFIG_S3C2416_DMA=y
+
+#
+# S3C2416 Machines
+#
+CONFIG_MACH_SMDK2416=y
 CONFIG_CPU_S3C2440=y
+CONFIG_CPU_S3C2442=y
+CONFIG_CPU_S3C244X=y
+CONFIG_S3C2440_XTAL_12000000=y
+CONFIG_S3C2440_XTAL_16934400=y
 CONFIG_S3C2440_DMA=y
 
 #
-# S3C2440 Machines
+# S3C2440 and S3C2442 Machines
 #
 CONFIG_MACH_ANUBIS=y
+CONFIG_MACH_NEO1973_GTA02=y
 CONFIG_MACH_OSIRIS=y
+CONFIG_MACH_OSIRIS_DVS=m
 CONFIG_MACH_RX3715=y
 CONFIG_ARCH_S3C2440=y
 CONFIG_MACH_NEXCODER_2440=y
 CONFIG_SMDK2440_CPU2440=y
+CONFIG_SMDK2440_CPU2442=y
 CONFIG_MACH_AT2440EVB=y
-CONFIG_CPU_S3C2442=y
 CONFIG_MACH_MINI2440=y
-
-#
-# S3C2442 Machines
-#
-CONFIG_SMDK2440_CPU2442=y
+CONFIG_MACH_RX1950=y
 CONFIG_CPU_S3C2443=y
 CONFIG_S3C2443_DMA=y
 
@@ -283,7 +371,7 @@ CONFIG_CPU_32v4T=y
 CONFIG_CPU_32v5=y
 CONFIG_CPU_ABRT_EV4T=y
 CONFIG_CPU_ABRT_EV5TJ=y
-CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_PABRT_LEGACY=y
 CONFIG_CPU_CACHE_V4WT=y
 CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_COPY_V4WB=y
@@ -299,7 +387,7 @@ CONFIG_CPU_CP15_MMU=y
 # CONFIG_CPU_DCACHE_DISABLE is not set
 # CONFIG_CPU_DCACHE_WRITETHROUGH is not set
 # CONFIG_CPU_CACHE_ROUND_ROBIN is not set
-# CONFIG_OUTER_CACHE is not set
+CONFIG_ARM_L1_CACHE_SHIFT=5
 
 #
 # Bus support
@@ -316,10 +404,11 @@ CONFIG_VMSPLIT_3G=y
 # CONFIG_VMSPLIT_2G is not set
 # CONFIG_VMSPLIT_1G is not set
 CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
 # CONFIG_PREEMPT is not set
 CONFIG_HZ=200
 # CONFIG_AEABI is not set
-CONFIG_ARCH_FLATMEM_HAS_HOLES=y
 # CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
 # CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
 # CONFIG_HIGHMEM is not set
@@ -330,14 +419,14 @@ CONFIG_FLATMEM_MANUAL=y
 CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 CONFIG_PAGEFLAGS_EXTENDED=y
-CONFIG_SPLIT_PTLOCK_CPUS=4096
+CONFIG_SPLIT_PTLOCK_CPUS=999999
 # CONFIG_PHYS_ADDR_T_64BIT is not set
 CONFIG_ZONE_DMA_FLAG=0
 CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=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
+# CONFIG_UACCESS_WITH_MEMCPY is not set
 
 #
 # Boot options
@@ -345,12 +434,14 @@ CONFIG_ALIGNMENT_TRAP=y
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="root=/dev/hda1 ro init=/bin/bash console=ttySAC0"
+# CONFIG_CMDLINE_FORCE is not set
 # CONFIG_XIP_KERNEL is not set
 # CONFIG_KEXEC is not set
 
 #
 # CPU Power Management
 #
+# CONFIG_CPU_FREQ is not set
 # CONFIG_CPU_IDLE is not set
 
 #
@@ -384,6 +475,8 @@ CONFIG_PM_SLEEP=y
 CONFIG_SUSPEND=y
 CONFIG_SUSPEND_FREEZER=y
 CONFIG_APM_EMULATION=m
+# CONFIG_PM_RUNTIME is not set
+CONFIG_PM_OPS=y
 CONFIG_ARCH_SUSPEND_POSSIBLE=y
 CONFIG_NET=y
 
@@ -391,7 +484,6 @@ CONFIG_NET=y
 # Networking options
 #
 CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
 CONFIG_XFRM=y
 CONFIG_XFRM_USER=m
@@ -442,7 +534,9 @@ CONFIG_TCP_CONG_ILLINOIS=m
 # CONFIG_DEFAULT_BIC is not set
 CONFIG_DEFAULT_CUBIC=y
 # CONFIG_DEFAULT_HTCP is not set
+# CONFIG_DEFAULT_HYBLA is not set
 # CONFIG_DEFAULT_VEGAS is not set
+# CONFIG_DEFAULT_VENO is not set
 # CONFIG_DEFAULT_WESTWOOD is not set
 # CONFIG_DEFAULT_RENO is not set
 CONFIG_DEFAULT_TCP_CONG="cubic"
@@ -463,6 +557,7 @@ CONFIG_INET6_XFRM_MODE_TUNNEL=m
 CONFIG_INET6_XFRM_MODE_BEET=m
 CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
 CONFIG_IPV6_SIT=m
+# CONFIG_IPV6_SIT_6RD is not set
 CONFIG_IPV6_NDISC_NODETYPE=y
 CONFIG_IPV6_TUNNEL=m
 # CONFIG_IPV6_MULTIPLE_TABLES is not set
@@ -498,8 +593,19 @@ CONFIG_NF_CONNTRACK_TFTP=m
 CONFIG_NF_CT_NETLINK=m
 # CONFIG_NETFILTER_TPROXY is not set
 CONFIG_NETFILTER_XTABLES=m
+
+#
+# Xtables combined modules
+#
+CONFIG_NETFILTER_XT_MARK=m
+CONFIG_NETFILTER_XT_CONNMARK=m
+
+#
+# Xtables targets
+#
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
 CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+# CONFIG_NETFILTER_XT_TARGET_CT is not set
 # CONFIG_NETFILTER_XT_TARGET_DSCP is not set
 CONFIG_NETFILTER_XT_TARGET_HL=m
 CONFIG_NETFILTER_XT_TARGET_LED=m
@@ -508,9 +614,14 @@ CONFIG_NETFILTER_XT_TARGET_NFLOG=m
 CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
 # CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
 CONFIG_NETFILTER_XT_TARGET_RATEEST=m
+# CONFIG_NETFILTER_XT_TARGET_TEE is not set
 # CONFIG_NETFILTER_XT_TARGET_TRACE is not set
 CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
 # CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set
+
+#
+# Xtables matches
+#
 CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
 CONFIG_NETFILTER_XT_MATCH_COMMENT=m
 CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
@@ -529,6 +640,7 @@ CONFIG_NETFILTER_XT_MATCH_LIMIT=m
 CONFIG_NETFILTER_XT_MATCH_MAC=m
 CONFIG_NETFILTER_XT_MATCH_MARK=m
 CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+# CONFIG_NETFILTER_XT_MATCH_OSF is not set
 CONFIG_NETFILTER_XT_MATCH_OWNER=m
 CONFIG_NETFILTER_XT_MATCH_POLICY=m
 CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
@@ -536,7 +648,6 @@ CONFIG_NETFILTER_XT_MATCH_QUOTA=m
 CONFIG_NETFILTER_XT_MATCH_RATEEST=m
 CONFIG_NETFILTER_XT_MATCH_REALM=m
 CONFIG_NETFILTER_XT_MATCH_RECENT=m
-# CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT is not set
 CONFIG_NETFILTER_XT_MATCH_SCTP=m
 CONFIG_NETFILTER_XT_MATCH_STATE=m
 CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
@@ -556,6 +667,7 @@ CONFIG_IP_VS_TAB_BITS=12
 # CONFIG_IP_VS_PROTO_UDP is not set
 # CONFIG_IP_VS_PROTO_ESP is not set
 # CONFIG_IP_VS_PROTO_AH is not set
+# CONFIG_IP_VS_PROTO_SCTP is not set
 
 #
 # IPVS scheduler
@@ -639,8 +751,10 @@ CONFIG_IP6_NF_MANGLE=m
 CONFIG_IP6_NF_RAW=m
 # 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
@@ -653,6 +767,7 @@ CONFIG_IP6_NF_RAW=m
 # 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_NET_CLS_ROUTE=y
 # CONFIG_DCB is not set
@@ -666,6 +781,7 @@ CONFIG_NET_CLS_ROUTE=y
 # CONFIG_IRDA is not set
 CONFIG_BT=m
 CONFIG_BT_L2CAP=m
+# CONFIG_BT_L2CAP_EXT_FEATURES is not set
 CONFIG_BT_SCO=m
 CONFIG_BT_RFCOMM=m
 CONFIG_BT_RFCOMM_TTY=y
@@ -687,19 +803,22 @@ CONFIG_BT_HCIBCM203X=m
 CONFIG_BT_HCIBPA10X=m
 CONFIG_BT_HCIBFUSB=m
 CONFIG_BT_HCIVHCI=m
+# CONFIG_BT_MRVL is not set
 # CONFIG_AF_RXRPC is not set
 CONFIG_WIRELESS=y
+CONFIG_WEXT_CORE=y
+CONFIG_WEXT_PROC=y
 CONFIG_CFG80211=m
+# CONFIG_NL80211_TESTMODE is not set
+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
 # CONFIG_CFG80211_REG_DEBUG is not set
-# CONFIG_WIRELESS_OLD_REGULATORY is not set
-CONFIG_WIRELESS_EXT=y
+CONFIG_CFG80211_DEFAULT_PS=y
+# CONFIG_CFG80211_INTERNAL_REGDB is not set
+CONFIG_CFG80211_WEXT=y
 CONFIG_WIRELESS_EXT_SYSFS=y
 # CONFIG_LIB80211 is not set
 CONFIG_MAC80211=m
-
-#
-# Rate control algorithm selection
-#
+CONFIG_MAC80211_HAS_RC=y
 CONFIG_MAC80211_RC_MINSTREL=y
 # CONFIG_MAC80211_RC_DEFAULT_PID is not set
 CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
@@ -710,6 +829,7 @@ CONFIG_MAC80211_LEDS=y
 # CONFIG_WIMAX is not set
 # CONFIG_RFKILL is not set
 # CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
 
 #
 # Device Drivers
@@ -719,6 +839,7 @@ CONFIG_MAC80211_LEDS=y
 # 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
@@ -730,9 +851,9 @@ CONFIG_EXTRA_FIRMWARE=""
 # 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_TESTS is not set
 CONFIG_MTD_REDBOOT_PARTS=y
 CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
 CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
@@ -752,6 +873,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
 
 #
@@ -793,6 +915,7 @@ CONFIG_MTD_ROM=y
 #
 # 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
@@ -805,9 +928,12 @@ CONFIG_MTD_ROM=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_S3C2410=y
@@ -843,6 +969,10 @@ CONFIG_BLK_DEV=y
 # CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
+
+#
+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
+#
 CONFIG_BLK_DEV_NBD=m
 CONFIG_BLK_DEV_UB=m
 CONFIG_BLK_DEV_RAM=y
@@ -851,19 +981,26 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_BLK_DEV_XIP is not set
 # CONFIG_CDROM_PKTCDVD is not set
 CONFIG_ATA_OVER_ETH=m
+# CONFIG_MG_DISK 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=m
+CONFIG_EEPROM_AT24=y
 CONFIG_EEPROM_AT25=m
 CONFIG_EEPROM_LEGACY=m
+# CONFIG_EEPROM_MAX6875 is not set
 CONFIG_EEPROM_93CX6=m
+# CONFIG_IWMC3200TOP is not set
 CONFIG_HAVE_IDE=y
 CONFIG_IDE=y
 
@@ -890,6 +1027,7 @@ CONFIG_BLK_DEV_PLATFORM=y
 #
 # SCSI device support
 #
+CONFIG_SCSI_MOD=y
 # CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
 CONFIG_SCSI_DMA=y
@@ -907,10 +1045,6 @@ CONFIG_BLK_DEV_SR=m
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=y
 CONFIG_CHR_DEV_SCH=m
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
 CONFIG_SCSI_MULTI_LUN=y
 CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOGGING is not set
@@ -951,7 +1085,6 @@ CONFIG_SCSI_LOWLEVEL=y
 CONFIG_HAVE_PATA_PLATFORM=y
 # CONFIG_MD is not set
 CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
 # CONFIG_MACVLAN is not set
@@ -989,16 +1122,30 @@ CONFIG_DM9000_DEBUGLEVEL=4
 # CONFIG_NET_PCI is not set
 # 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_NET_POCKET is not set
 CONFIG_NETDEV_1000=y
 CONFIG_NETDEV_10000=y
 # CONFIG_TR is not set
-
-#
-# Wireless LAN
-#
-# CONFIG_WLAN_PRE80211 is not set
-# CONFIG_WLAN_80211 is not set
+CONFIG_WLAN=y
+# CONFIG_LIBERTAS_THINFIRM is not set
+# CONFIG_AT76C50X_USB is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_USB_NET_RNDIS_WLAN is not set
+# CONFIG_RTL8187 is not set
+# CONFIG_MAC80211_HWSIM is not set
+# CONFIG_ATH_COMMON is not set
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_IWM is not set
+# CONFIG_LIBERTAS is not set
+# CONFIG_P54_COMMON is not set
+# CONFIG_RT2X00 is not set
+# CONFIG_WL12XX is not set
+# CONFIG_ZD1211RW is not set
 
 #
 # Enable WiMAX (Networking options) to see the WiMAX drivers
@@ -1012,6 +1159,7 @@ CONFIG_NETDEV_10000=y
 # 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_PLIP is not set
 # CONFIG_PPP is not set
@@ -1020,6 +1168,7 @@ CONFIG_NETDEV_10000=y
 # 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
@@ -1027,6 +1176,7 @@ CONFIG_NETDEV_10000=y
 CONFIG_INPUT=y
 CONFIG_INPUT_FF_MEMLESS=m
 # CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
 
 #
 # Userland interfaces
@@ -1043,13 +1193,20 @@ CONFIG_INPUT_EVDEV=y
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
 CONFIG_KEYBOARD_ATKBD=y
-# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_QT2160 is not set
 # CONFIG_KEYBOARD_LKKBD is not set
-# CONFIG_KEYBOARD_XTKBD 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_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
 # CONFIG_KEYBOARD_STOWAWAY is not set
-# CONFIG_KEYBOARD_GPIO 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=y
@@ -1057,6 +1214,7 @@ CONFIG_MOUSE_PS2_LOGIPS2PP=y
 CONFIG_MOUSE_PS2_SYNAPTICS=y
 CONFIG_MOUSE_PS2_TRACKPOINT=y
 # 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_APPLETOUCH=m
@@ -1066,6 +1224,7 @@ CONFIG_MOUSE_BCM5974=m
 # CONFIG_MOUSE_PC110PAD is not set
 # CONFIG_MOUSE_VSXXXAA is not set
 # CONFIG_MOUSE_GPIO is not set
+# CONFIG_MOUSE_SYNAPTICS_I2C is not set
 CONFIG_INPUT_JOYSTICK=y
 CONFIG_JOYSTICK_ANALOG=m
 CONFIG_JOYSTICK_A3D=m
@@ -1102,10 +1261,15 @@ CONFIG_INPUT_TOUCHSCREEN=y
 # 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_S3C2410 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
@@ -1126,9 +1290,16 @@ CONFIG_TOUCHSCREEN_USB_IRTOUCH=y
 CONFIG_TOUCHSCREEN_USB_IDEALTEK=y
 CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH=y
 CONFIG_TOUCHSCREEN_USB_GOTOP=y
+CONFIG_TOUCHSCREEN_USB_JASTEC=y
+CONFIG_TOUCHSCREEN_USB_E2I=y
+CONFIG_TOUCHSCREEN_USB_ZYTRONIC=y
+CONFIG_TOUCHSCREEN_USB_ETT_TC5UH=y
+CONFIG_TOUCHSCREEN_USB_NEXIO=y
 # CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
 # CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_TOUCHSCREEN_W90X900 is not set
 CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_AD714X is not set
 CONFIG_INPUT_ATI_REMOTE=m
 CONFIG_INPUT_ATI_REMOTE2=m
 CONFIG_INPUT_KEYSPAN_REMOTE=m
@@ -1136,6 +1307,8 @@ CONFIG_INPUT_POWERMATE=m
 CONFIG_INPUT_YEALINK=m
 CONFIG_INPUT_CM109=m
 CONFIG_INPUT_UINPUT=m
+# CONFIG_INPUT_PCF50633_PMU is not set
+# CONFIG_INPUT_PCF8574 is not set
 CONFIG_INPUT_GPIO_ROTARY_ENCODER=m
 
 #
@@ -1146,6 +1319,7 @@ CONFIG_SERIO_SERPORT=y
 # CONFIG_SERIO_PARKBD is not set
 CONFIG_SERIO_LIBPS2=y
 # CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_ALTERA_PS2 is not set
 CONFIG_GAMEPORT=m
 # CONFIG_GAMEPORT_NS558 is not set
 # CONFIG_GAMEPORT_L4 is not set
@@ -1167,10 +1341,9 @@ CONFIG_SERIAL_NONSTANDARD=y
 # CONFIG_MOXA_INTELLIO is not set
 # CONFIG_MOXA_SMARTIO is not set
 # CONFIG_N_HDLC is not set
+# CONFIG_N_GSM is not set
 # CONFIG_RISCOM8 is not set
 # CONFIG_SPECIALIX is not set
-# CONFIG_SX is not set
-# CONFIG_RIO is not set
 # CONFIG_STALDRV is not set
 
 #
@@ -1195,6 +1368,7 @@ CONFIG_SERIAL_8250_SHARE_IRQ=y
 # Non-8250 serial port support
 #
 CONFIG_SERIAL_SAMSUNG=y
+CONFIG_SERIAL_SAMSUNG_UARTS_4=y
 CONFIG_SERIAL_SAMSUNG_UARTS=4
 # CONFIG_SERIAL_SAMSUNG_DEBUG is not set
 CONFIG_SERIAL_SAMSUNG_CONSOLE=y
@@ -1204,6 +1378,9 @@ CONFIG_SERIAL_S3C2440=y
 # CONFIG_SERIAL_MAX3100 is not set
 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=y
@@ -1221,6 +1398,7 @@ CONFIG_HW_RANDOM=y
 CONFIG_DEVPORT=y
 CONFIG_I2C=y
 CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
 CONFIG_I2C_CHARDEV=m
 CONFIG_I2C_HELPER_AUTO=y
 CONFIG_I2C_ALGOBIT=y
@@ -1232,10 +1410,12 @@ CONFIG_I2C_ALGOBIT=y
 #
 # 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_S3C2410=y
 CONFIG_I2C_SIMTEC=y
+# CONFIG_I2C_XILINX is not set
 
 #
 # External I2C/SMBus adapter drivers
@@ -1252,20 +1432,9 @@ CONFIG_I2C_SIMTEC=y
 # CONFIG_I2C_PCA_ISA is not set
 # CONFIG_I2C_PCA_PLATFORM is not set
 # CONFIG_I2C_STUB is not set
-
-#
-# Miscellaneous I2C Chip support
-#
-# CONFIG_DS1682 is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_PCF8575 is not set
-# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 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=y
 # CONFIG_SPI_DEBUG is not set
 CONFIG_SPI_MASTER=y
@@ -1278,13 +1447,21 @@ CONFIG_SPI_BITBANG=m
 CONFIG_SPI_GPIO=m
 # CONFIG_SPI_LM70_LLP is not set
 CONFIG_SPI_S3C24XX=m
+# CONFIG_SPI_S3C24XX_FIQ is not set
 CONFIG_SPI_S3C24XX_GPIO=m
+# CONFIG_SPI_XILINX is not set
+# CONFIG_SPI_DESIGNWARE is not set
 
 #
 # SPI Protocol Masters
 #
 CONFIG_SPI_SPIDEV=m
 CONFIG_SPI_TLE62X0=m
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
 CONFIG_ARCH_REQUIRE_GPIOLIB=y
 CONFIG_GPIOLIB=y
 # CONFIG_DEBUG_GPIO is not set
@@ -1293,13 +1470,16 @@ 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_ADP5588 is not set
 
 #
 # PCI GPIO expanders:
@@ -1310,10 +1490,29 @@ CONFIG_GPIOLIB=y
 #
 # CONFIG_GPIO_MAX7301 is not set
 # CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+
+#
+# AC97 GPIO expanders:
+#
 # CONFIG_W1 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_APM_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_CHARGER_PCF50633 is not set
 CONFIG_HWMON=y
 CONFIG_HWMON_VID=m
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
 # CONFIG_SENSORS_AD7414 is not set
 # CONFIG_SENSORS_AD7418 is not set
 # CONFIG_SENSORS_ADCXX is not set
@@ -1323,10 +1522,11 @@ CONFIG_HWMON_VID=m
 # CONFIG_SENSORS_ADM1029 is not set
 # CONFIG_SENSORS_ADM1031 is not set
 # CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7411 is not set
 # CONFIG_SENSORS_ADT7462 is not set
 # CONFIG_SENSORS_ADT7470 is not set
-# CONFIG_SENSORS_ADT7473 is not set
 # CONFIG_SENSORS_ADT7475 is not set
+# CONFIG_SENSORS_ASC7621 is not set
 # CONFIG_SENSORS_ATXP1 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_F71805F is not set
@@ -1338,6 +1538,7 @@ CONFIG_HWMON_VID=m
 # CONFIG_SENSORS_IT87 is not set
 # CONFIG_SENSORS_LM63 is not set
 # CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_LM73 is not set
 CONFIG_SENSORS_LM75=m
 # CONFIG_SENSORS_LM77 is not set
 CONFIG_SENSORS_LM78=m
@@ -1358,12 +1559,17 @@ CONFIG_SENSORS_LM85=m
 # CONFIG_SENSORS_PC87427 is not set
 # CONFIG_SENSORS_PCF8591 is not set
 # CONFIG_SENSORS_SHT15 is not set
+# CONFIG_SENSORS_S3C is not set
 # CONFIG_SENSORS_DME1737 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_SMSC47M192 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
 # CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_ADS7871 is not set
+# CONFIG_SENSORS_AMC6821 is not set
 # CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
+# CONFIG_SENSORS_TMP421 is not set
 # CONFIG_SENSORS_VT1211 is not set
 # CONFIG_SENSORS_W83781D is not set
 # CONFIG_SENSORS_W83791D is not set
@@ -1374,9 +1580,8 @@ CONFIG_SENSORS_LM85=m
 # CONFIG_SENSORS_W83627HF is not set
 # CONFIG_SENSORS_W83627EHF is not set
 # CONFIG_SENSORS_LIS3_SPI is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
+# CONFIG_SENSORS_LIS3_I2C is not set
 # CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
 CONFIG_WATCHDOG=y
 # CONFIG_WATCHDOG_NOWAYOUT is not set
 
@@ -1385,6 +1590,7 @@ CONFIG_WATCHDOG=y
 #
 # CONFIG_SOFT_WATCHDOG is not set
 CONFIG_S3C2410_WATCHDOG=y
+# CONFIG_MAX63XX_WATCHDOG is not set
 
 #
 # ISA-based Watchdog Cards
@@ -1408,213 +1614,36 @@ CONFIG_SSB_POSSIBLE=y
 # Multifunction device drivers
 #
 # CONFIG_MFD_CORE is not set
+# CONFIG_MFD_88PM860X is not set
 CONFIG_MFD_SM501=y
 # CONFIG_MFD_SM501_GPIO 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_TPS65010=m
 # 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_PCF50633 is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-CONFIG_VIDEO_DEV=m
-CONFIG_VIDEO_V4L2_COMMON=m
-CONFIG_VIDEO_ALLOW_V4L1=y
-CONFIG_VIDEO_V4L1_COMPAT=y
-CONFIG_DVB_CORE=m
-CONFIG_VIDEO_MEDIA=m
-
-#
-# Multimedia drivers
-#
-CONFIG_MEDIA_ATTACH=y
-CONFIG_MEDIA_TUNER=m
-# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
-CONFIG_MEDIA_TUNER_SIMPLE=m
-CONFIG_MEDIA_TUNER_TDA8290=m
-CONFIG_MEDIA_TUNER_TDA827X=m
-CONFIG_MEDIA_TUNER_TDA18271=m
-CONFIG_MEDIA_TUNER_TDA9887=m
-CONFIG_MEDIA_TUNER_TEA5761=m
-CONFIG_MEDIA_TUNER_TEA5767=m
-CONFIG_MEDIA_TUNER_MT20XX=m
-CONFIG_MEDIA_TUNER_MT2060=m
-CONFIG_MEDIA_TUNER_MT2266=m
-CONFIG_MEDIA_TUNER_QT1010=m
-CONFIG_MEDIA_TUNER_XC2028=m
-CONFIG_MEDIA_TUNER_XC5000=m
-CONFIG_MEDIA_TUNER_MXL5005S=m
-CONFIG_MEDIA_TUNER_MXL5007T=m
-CONFIG_MEDIA_TUNER_MC44S803=m
-CONFIG_VIDEO_V4L2=m
-CONFIG_VIDEO_V4L1=m
-CONFIG_VIDEOBUF_GEN=m
-CONFIG_VIDEOBUF_VMALLOC=m
-CONFIG_VIDEO_TVEEPROM=m
-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=m
-CONFIG_VIDEO_PMS=m
-CONFIG_VIDEO_BWQCAM=m
-CONFIG_VIDEO_CQCAM=m
-CONFIG_VIDEO_W9966=m
-CONFIG_VIDEO_CPIA=m
-CONFIG_VIDEO_CPIA_PP=m
-CONFIG_VIDEO_CPIA_USB=m
-CONFIG_VIDEO_CPIA2=m
-CONFIG_VIDEO_SAA5246A=m
-CONFIG_VIDEO_SAA5249=m
-CONFIG_VIDEO_AU0828=m
-# 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=m
-# CONFIG_USB_M5602 is not set
-# CONFIG_USB_STV06XX is not set
-# CONFIG_USB_GSPCA_CONEX is not set
-# CONFIG_USB_GSPCA_ETOMS is not set
-# CONFIG_USB_GSPCA_FINEPIX 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_PAC207 is not set
-# CONFIG_USB_GSPCA_PAC7311 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_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_VICAM is not set
-# CONFIG_USB_IBMCAM is not set
-# CONFIG_USB_KONICAWC is not set
-# CONFIG_USB_QUICKCAM_MESSENGER is not set
-# CONFIG_USB_ET61X251 is not set
-# CONFIG_VIDEO_OVCAMCHIP is not set
-# CONFIG_USB_OV511 is not set
-# CONFIG_USB_SE401 is not set
-# CONFIG_USB_SN9C102 is not set
-# CONFIG_USB_STV680 is not set
-# CONFIG_USB_ZC0301 is not set
-# CONFIG_USB_PWC is not set
-CONFIG_USB_PWC_INPUT_EVDEV=y
-# CONFIG_USB_ZR364XX is not set
-# CONFIG_USB_STKWEBCAM is not set
-# CONFIG_USB_S2255 is not set
-CONFIG_RADIO_ADAPTERS=y
-CONFIG_RADIO_CADET=m
-CONFIG_RADIO_RTRACK=m
-CONFIG_RADIO_RTRACK2=m
-CONFIG_RADIO_AZTECH=m
-CONFIG_RADIO_GEMTEK=m
-CONFIG_RADIO_SF16FMI=m
-CONFIG_RADIO_SF16FMR2=m
-CONFIG_RADIO_TERRATEC=m
-CONFIG_RADIO_TRUST=m
-CONFIG_RADIO_TYPHOON=m
-CONFIG_RADIO_TYPHOON_PROC_FS=y
-CONFIG_RADIO_ZOLTRIX=m
-CONFIG_USB_DSBR=m
-CONFIG_USB_SI470X=m
-CONFIG_USB_MR800=m
-CONFIG_RADIO_TEA5764=m
-CONFIG_DVB_DYNAMIC_MINORS=y
-CONFIG_DVB_CAPTURE_DRIVERS=y
-# CONFIG_TTPCI_EEPROM is not set
-
-#
-# Supported USB Adapters
-#
-CONFIG_DVB_USB=m
-# CONFIG_DVB_USB_DEBUG is not set
-# CONFIG_DVB_USB_A800 is not set
-CONFIG_DVB_USB_DIBUSB_MB=m
-# CONFIG_DVB_USB_DIBUSB_MB_FAULTY is not set
-CONFIG_DVB_USB_DIBUSB_MC=m
-CONFIG_DVB_USB_DIB0700=m
-CONFIG_DVB_USB_UMT_010=m
-CONFIG_DVB_USB_CXUSB=m
-CONFIG_DVB_USB_M920X=m
-# CONFIG_DVB_USB_GL861 is not set
-# CONFIG_DVB_USB_AU6610 is not set
-# CONFIG_DVB_USB_DIGITV is not set
-# CONFIG_DVB_USB_VP7045 is not set
-# CONFIG_DVB_USB_VP702X is not set
-# CONFIG_DVB_USB_GP8PSK is not set
-# CONFIG_DVB_USB_NOVA_T_USB2 is not set
-# CONFIG_DVB_USB_TTUSB2 is not set
-# CONFIG_DVB_USB_DTT200U is not set
-# CONFIG_DVB_USB_OPERA1 is not set
-CONFIG_DVB_USB_AF9005=m
-# CONFIG_DVB_USB_AF9005_REMOTE is not set
-# CONFIG_DVB_USB_DW2102 is not set
-# CONFIG_DVB_USB_CINERGY_T2 is not set
-# CONFIG_DVB_USB_ANYSEE is not set
-# CONFIG_DVB_USB_DTV5100 is not set
-# CONFIG_DVB_USB_AF9015 is not set
-# CONFIG_DVB_USB_CE6230 is not set
-# CONFIG_DVB_SIANO_SMS1XXX is not set
-
-#
-# Supported FlexCopII (B2C2) Adapters
-#
-# CONFIG_DVB_B2C2_FLEXCOP is not set
-
-#
-# Supported DVB Frontends
-#
-# CONFIG_DVB_FE_CUSTOMISE is not set
-CONFIG_DVB_CX22702=m
-CONFIG_DVB_TDA1004X=m
-CONFIG_DVB_MT352=m
-CONFIG_DVB_ZL10353=m
-CONFIG_DVB_DIB3000MB=m
-CONFIG_DVB_DIB3000MC=m
-CONFIG_DVB_DIB7000M=m
-CONFIG_DVB_DIB7000P=m
-CONFIG_DVB_LGDT330X=m
-CONFIG_DVB_LGDT3305=m
-CONFIG_DVB_AU8522=m
-CONFIG_DVB_S5H1411=m
-CONFIG_DVB_PLL=m
-CONFIG_DVB_TUNER_DIB0070=m
-CONFIG_DVB_LGS8GL5=m
-CONFIG_DAB=y
-CONFIG_USB_DABUSB=m
+# CONFIG_MFD_WM8994 is not set
+CONFIG_MFD_PCF50633=y
+# CONFIG_MFD_MC13783 is not set
+# CONFIG_PCF50633_ADC is not set
+CONFIG_PCF50633_GPIO=y
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_AB4500_CORE is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
 
 #
 # Graphics support
@@ -1653,6 +1682,8 @@ CONFIG_FB_SM501=y
 # CONFIG_FB_BROADSHEET is not set
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=m
+# CONFIG_LCD_L4F00242T03 is not set
+# CONFIG_LCD_LMS283GF05 is not set
 # CONFIG_LCD_LTV350QV is not set
 # CONFIG_LCD_ILI9320 is not set
 # CONFIG_LCD_TDO24M is not set
@@ -1682,6 +1713,7 @@ CONFIG_FONT_8x16=y
 # CONFIG_LOGO is not set
 CONFIG_SOUND=y
 CONFIG_SOUND_OSS_CORE=y
+CONFIG_SOUND_OSS_CORE_PRECLAIM=y
 CONFIG_SND=y
 CONFIG_SND_TIMER=y
 CONFIG_SND_PCM=y
@@ -1701,36 +1733,44 @@ CONFIG_SND_VERBOSE_PROCFS=y
 CONFIG_SND_VERBOSE_PRINTK=y
 # CONFIG_SND_DEBUG is not set
 CONFIG_SND_VMASTER=y
+CONFIG_SND_RAWMIDI_SEQ=m
+# 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_AC97_CODEC=m
 # CONFIG_SND_DRIVERS is not set
 # CONFIG_SND_ARM is not set
 # CONFIG_SND_SPI is not set
 CONFIG_SND_USB=y
 CONFIG_SND_USB_AUDIO=m
+# CONFIG_SND_USB_UA101 is not set
 CONFIG_SND_USB_CAIAQ=m
 # CONFIG_SND_USB_CAIAQ_INPUT is not set
 CONFIG_SND_SOC=y
 CONFIG_SND_SOC_AC97_BUS=y
 CONFIG_SND_S3C24XX_SOC=y
-CONFIG_SND_S3C24XX_SOC_I2S=m
+CONFIG_SND_S3C24XX_SOC_I2S=y
 CONFIG_SND_S3C_I2SV2_SOC=m
 CONFIG_SND_S3C2412_SOC_I2S=m
-CONFIG_SND_S3C2443_SOC_AC97=m
+CONFIG_SND_S3C_SOC_AC97=m
+# CONFIG_SND_S3C24XX_SOC_NEO1973_GTA02_WM8753 is not set
 CONFIG_SND_S3C24XX_SOC_JIVE_WM8750=m
 CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710=m
 CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650=m
-CONFIG_SND_S3C24XX_SOC_S3C24XX_UDA134X=m
+CONFIG_SND_S3C24XX_SOC_S3C24XX_UDA134X=y
+# CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23 is not set
+# CONFIG_SND_S3C24XX_SOC_SIMTEC_HERMES is not set
 CONFIG_SND_SOC_I2C_AND_SPI=y
 # CONFIG_SND_SOC_ALL_CODECS is not set
 CONFIG_SND_SOC_AC97_CODEC=m
-CONFIG_SND_SOC_L3=m
-CONFIG_SND_SOC_UDA134X=m
+CONFIG_SND_SOC_L3=y
+CONFIG_SND_SOC_UDA134X=y
 CONFIG_SND_SOC_WM8750=m
 # CONFIG_SOUND_PRIME is not set
 CONFIG_AC97_BUS=y
 CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
-# CONFIG_HID_DEBUG is not set
 # CONFIG_HIDRAW is not set
 
 #
@@ -1743,6 +1783,8 @@ CONFIG_HID=y
 # Special HID drivers
 #
 CONFIG_HID_APPLE=m
+# CONFIG_HID_MAGICMOUSE is not set
+# CONFIG_HID_WACOM is not set
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
@@ -1757,8 +1799,6 @@ CONFIG_USB=y
 CONFIG_USB_DEVICEFS=y
 CONFIG_USB_DEVICE_CLASS=y
 # CONFIG_USB_DYNAMIC_MINORS is not set
-# CONFIG_USB_SUSPEND is not set
-# CONFIG_USB_OTG is not set
 CONFIG_USB_MON=y
 # CONFIG_USB_WUSB is not set
 # CONFIG_USB_WUSB_CBAF is not set
@@ -1770,6 +1810,7 @@ CONFIG_USB_MON=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_OHCI_HCD=y
 # CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
 # CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
@@ -1854,6 +1895,7 @@ CONFIG_USB_SERIAL_FTDI_SIO=y
 CONFIG_USB_SERIAL_NAVMAN=m
 CONFIG_USB_SERIAL_PL2303=y
 # CONFIG_USB_SERIAL_OTI6858 is not set
+# CONFIG_USB_SERIAL_QCAUX is not set
 # CONFIG_USB_SERIAL_QUALCOMM is not set
 # CONFIG_USB_SERIAL_SPCP8X5 is not set
 # CONFIG_USB_SERIAL_HP4X is not set
@@ -1864,9 +1906,12 @@ CONFIG_USB_SERIAL_PL2303=y
 # CONFIG_USB_SERIAL_TI is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
+CONFIG_USB_SERIAL_WWAN=m
 CONFIG_USB_SERIAL_OPTION=m
 # CONFIG_USB_SERIAL_OMNINET is not set
 # CONFIG_USB_SERIAL_OPTICON is not set
+# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set
+# CONFIG_USB_SERIAL_ZIO is not set
 # CONFIG_USB_SERIAL_DEBUG is not set
 
 #
@@ -1879,7 +1924,6 @@ CONFIG_USB_SEVSEG=m
 CONFIG_USB_RIO500=m
 CONFIG_USB_LEGOTOWER=m
 CONFIG_USB_LCD=m
-CONFIG_USB_BERRY_CHARGE=m
 CONFIG_USB_LED=m
 CONFIG_USB_CYPRESS_CY7C63=m
 CONFIG_USB_CYTHERM=m
@@ -1891,13 +1935,13 @@ CONFIG_USB_TRANCEVIBRATOR=m
 CONFIG_USB_IOWARRIOR=m
 CONFIG_USB_TEST=m
 # CONFIG_USB_ISIGHTFW is not set
-# CONFIG_USB_VST 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
@@ -1915,10 +1959,15 @@ CONFIG_MMC_TEST=m
 # MMC/SD/SDIO Host Controller Drivers
 #
 CONFIG_MMC_SDHCI=m
+# CONFIG_MMC_SDHCI_PLTFM is not set
+# CONFIG_MMC_SDHCI_S3C is not set
 CONFIG_MMC_SPI=m
 CONFIG_MMC_S3C=y
+# CONFIG_MMC_S3C_HW_SDIO_IRQ is not set
+CONFIG_MMC_S3C_PIO=y
+# CONFIG_MMC_S3C_DMA is not set
+# CONFIG_MMC_S3C_PIODMA is not set
 # CONFIG_MEMSTICK is not set
-# CONFIG_ACCESSIBILITY is not set
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=m
 
@@ -1930,26 +1979,28 @@ CONFIG_LEDS_H1940=m
 CONFIG_LEDS_PCA9532=m
 CONFIG_LEDS_GPIO=m
 CONFIG_LEDS_GPIO_PLATFORM=y
-CONFIG_LEDS_LP5521=m
+# CONFIG_LEDS_LP3944 is not set
 CONFIG_LEDS_PCA955X=m
 CONFIG_LEDS_DAC124S085=m
 CONFIG_LEDS_PWM=m
 CONFIG_LEDS_BD2802=m
+# CONFIG_LEDS_LT3593 is not set
+CONFIG_LEDS_TRIGGERS=y
 
 #
 # LED Triggers
 #
-CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_TIMER=m
 # CONFIG_LEDS_TRIGGER_IDE_DISK is not set
 CONFIG_LEDS_TRIGGER_HEARTBEAT=m
-CONFIG_LEDS_TRIGGER_BACKLIGHT=m
+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
 CONFIG_LEDS_TRIGGER_GPIO=m
 CONFIG_LEDS_TRIGGER_DEFAULT_ON=m
 
 #
 # 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
@@ -1978,9 +2029,11 @@ CONFIG_RTC_INTF_DEV=y
 # 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
@@ -1992,6 +2045,7 @@ CONFIG_RTC_INTF_DEV=y
 # 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
@@ -2005,8 +2059,11 @@ CONFIG_RTC_INTF_DEV=y
 # 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
+# CONFIG_RTC_DRV_PCF50633 is not set
 
 #
 # on-CPU RTC drivers
@@ -2014,7 +2071,6 @@ CONFIG_RTC_INTF_DEV=y
 CONFIG_RTC_DRV_S3C=y
 # CONFIG_DMADEVICES is not set
 # CONFIG_AUXDISPLAY is not set
-# CONFIG_REGULATOR is not set
 # CONFIG_UIO is not set
 # CONFIG_STAGING is not set
 
@@ -2032,20 +2088,23 @@ CONFIG_EXT3_FS_XATTR=y
 CONFIG_EXT3_FS_POSIX_ACL=y
 # CONFIG_EXT3_FS_SECURITY is not set
 CONFIG_EXT4_FS=m
-# CONFIG_EXT4DEV_COMPAT is not set
 CONFIG_EXT4_FS_XATTR=y
 CONFIG_EXT4_FS_POSIX_ACL=y
 # CONFIG_EXT4_FS_SECURITY is not set
+# CONFIG_EXT4_DEBUG is not set
 CONFIG_JBD=y
 CONFIG_JBD2=m
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
-CONFIG_FILE_LOCKING=y
 # 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
@@ -2053,6 +2112,7 @@ CONFIG_INOTIFY_USER=y
 CONFIG_AUTOFS_FS=m
 CONFIG_AUTOFS4_FS=m
 CONFIG_FUSE_FS=m
+# CONFIG_CUSE is not set
 CONFIG_GENERIC_ACL=y
 
 #
@@ -2111,6 +2171,7 @@ CONFIG_JFFS2_ZLIB=y
 # CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
+# CONFIG_LOGFS is not set
 CONFIG_CRAMFS=y
 CONFIG_SQUASHFS=m
 # CONFIG_SQUASHFS_EMBEDDED is not set
@@ -2127,7 +2188,6 @@ CONFIG_ROMFS_BACKED_BY_BLOCK=y
 CONFIG_ROMFS_ON_BLOCK=y
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
-# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
@@ -2149,6 +2209,7 @@ CONFIG_SUNRPC_GSS=m
 CONFIG_RPCSEC_GSS_KRB5=m
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
+# CONFIG_CEPH_FS is not set
 CONFIG_CIFS=m
 # CONFIG_CIFS_STATS is not set
 # CONFIG_CIFS_WEAK_PW_HASH is not set
@@ -2230,6 +2291,7 @@ 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
@@ -2246,6 +2308,7 @@ CONFIG_SCHED_DEBUG=y
 # CONFIG_TIMER_STATS is not set
 # CONFIG_DEBUG_OBJECTS is not set
 # CONFIG_DEBUG_SLAB 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
@@ -2264,32 +2327,34 @@ CONFIG_DEBUG_MEMORY_INIT=y
 # 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_FRAME_POINTER=y
 # CONFIG_BOOT_PRINTK_DELAY 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_PAGE_POISONING is not set
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
 # CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
 # CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING 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_ATOMIC64_SELFTEST is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
@@ -2297,7 +2362,9 @@ CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_ERRORS=y
 # CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUG_LL=y
+# CONFIG_EARLY_PRINTK is not set
 # CONFIG_DEBUG_ICEDCC is not set
+# CONFIG_OC_ETM is not set
 CONFIG_DEBUG_S3C_UART=0
 
 #
@@ -2306,13 +2373,16 @@ CONFIG_DEBUG_S3C_UART=0
 # 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
 
 #
 # Crypto core or helper
 #
-# CONFIG_CRYPTO_FIPS is not set
 CONFIG_CRYPTO_ALGAPI=m
 CONFIG_CRYPTO_ALGAPI2=m
 CONFIG_CRYPTO_AEAD=m
@@ -2355,11 +2425,13 @@ CONFIG_CRYPTO_ECB=m
 #
 CONFIG_CRYPTO_HMAC=m
 # CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
 
 #
 # Digest
 #
 CONFIG_CRYPTO_CRC32C=m
+# CONFIG_CRYPTO_GHASH is not set
 # CONFIG_CRYPTO_MD4 is not set
 CONFIG_CRYPTO_MD5=m
 # CONFIG_CRYPTO_MICHAEL_MIC is not set
@@ -2420,9 +2492,11 @@ CONFIG_CRC7=m
 CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_DECOMPRESS=y
 CONFIG_DECOMPRESS_GZIP=y
 CONFIG_DECOMPRESS_BZIP2=y
 CONFIG_DECOMPRESS_LZMA=y
+CONFIG_DECOMPRESS_LZO=y
 CONFIG_TEXTSEARCH=y
 CONFIG_TEXTSEARCH_KMP=m
 CONFIG_TEXTSEARCH_BM=m
@@ -2430,3 +2504,4 @@ CONFIG_TEXTSEARCH_FSM=m
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_DMA=y
 CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
index 5e7d4c1b8fc1f7fe59735805f24246f96fea10db..2b642386f03012d3f1de1e9a9f79efddb5817d1e 100644 (file)
@@ -1,11 +1,15 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.33-rc4
-# Tue Jan 19 13:12:40 2010
+# Linux kernel version: 2.6.34
+# Fri May 28 19:05:39 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=y
+CONFIG_HAVE_PROC_CPU=y
 CONFIG_NO_IOPORT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_STACKTRACE_SUPPORT=y
@@ -18,6 +22,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_ARCH_HAS_CPUFREQ=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"
@@ -32,6 +37,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
@@ -53,7 +59,6 @@ CONFIG_RCU_FANOUT=32
 # CONFIG_TREE_RCU_TRACE is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_LOG_BUF_SHIFT=17
-# CONFIG_GROUP_SCHED is not set
 # CONFIG_CGROUPS is not set
 CONFIG_SYSFS_DEPRECATED=y
 CONFIG_SYSFS_DEPRECATED_V2=y
@@ -89,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_SLUB_DEBUG=y
 CONFIG_COMPAT_BRK=y
@@ -164,7 +173,7 @@ CONFIG_DEFAULT_IOSCHED="cfq"
 # 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 is not set
+CONFIG_FREEZER=y
 
 #
 # System Type
@@ -174,8 +183,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
@@ -184,7 +196,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
@@ -201,70 +212,89 @@ 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
+# 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=y
 # CONFIG_ARCH_S5P6440 is not set
-# CONFIG_ARCH_S5PC1XX 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
 CONFIG_PLAT_SAMSUNG=y
+
+#
+# Boot options
+#
+CONFIG_S3C_BOOT_ERROR_RESET=y
+CONFIG_S3C_BOOT_UART_FORCE_FIFO=y
+CONFIG_S3C_LOWLEVEL_UART_PORT=0
 CONFIG_SAMSUNG_CLKSRC=y
 CONFIG_SAMSUNG_IRQ_VIC_TIMER=y
 CONFIG_SAMSUNG_IRQ_UART=y
+CONFIG_SAMSUNG_GPIOLIB_4BIT=y
 CONFIG_S3C_GPIO_CFG_S3C24XX=y
 CONFIG_S3C_GPIO_CFG_S3C64XX=y
 CONFIG_S3C_GPIO_PULL_UPDOWN=y
 CONFIG_SAMSUNG_GPIO_EXTRA=0
+CONFIG_S3C_GPIO_SPACE=0
+CONFIG_S3C_GPIO_TRACK=y
 # CONFIG_S3C_ADC is not set
 CONFIG_S3C_DEV_HSMMC=y
 CONFIG_S3C_DEV_HSMMC1=y
+CONFIG_S3C_DEV_HSMMC2=y
+CONFIG_S3C_DEV_HWMON=y
 CONFIG_S3C_DEV_I2C1=y
 CONFIG_S3C_DEV_FB=y
 CONFIG_S3C_DEV_USB_HOST=y
 CONFIG_S3C_DEV_USB_HSOTG=y
+CONFIG_S3C_DEV_WDT=y
 CONFIG_S3C_DEV_NAND=y
-CONFIG_PLAT_S3C64XX=y
-CONFIG_CPU_S3C6400_INIT=y
-CONFIG_CPU_S3C6400_CLOCK=y
-# CONFIG_S3C64XX_DMA is not set
-CONFIG_S3C64XX_SETUP_I2C0=y
-CONFIG_S3C64XX_SETUP_I2C1=y
-CONFIG_S3C64XX_SETUP_FB_24BPP=y
-CONFIG_S3C64XX_SETUP_SDHCI_GPIO=y
-CONFIG_PLAT_S3C=y
-
-#
-# Boot options
-#
-CONFIG_S3C_BOOT_ERROR_RESET=y
-CONFIG_S3C_BOOT_UART_FORCE_FIFO=y
+CONFIG_S3C_DEV_RTC=y
+CONFIG_SAMSUNG_DEV_ADC=y
+CONFIG_SAMSUNG_DEV_TS=y
+CONFIG_S3C_DMA=y
 
 #
 # Power management
 #
-CONFIG_S3C_LOWLEVEL_UART_PORT=0
-CONFIG_S3C_GPIO_SPACE=0
-CONFIG_S3C_GPIO_TRACK=y
-# CONFIG_MACH_SMDK6400 is not set
+# CONFIG_SAMSUNG_PM_DEBUG is not set
+# CONFIG_S3C_PM_DEBUG_LED_SMDK is not set
+# CONFIG_SAMSUNG_PM_CHECK is not set
+CONFIG_SAMSUNG_WAKEMASK=y
+CONFIG_PLAT_S3C64XX=y
+CONFIG_CPU_S3C6400=y
 CONFIG_CPU_S3C6410=y
-CONFIG_S3C6410_SETUP_SDHCI=y
-# CONFIG_MACH_ANW6410 is not set
+CONFIG_S3C64XX_DMA=y
+CONFIG_S3C64XX_SETUP_SDHCI=y
+CONFIG_S3C64XX_SETUP_I2C0=y
+CONFIG_S3C64XX_SETUP_I2C1=y
+CONFIG_S3C64XX_SETUP_FB_24BPP=y
+CONFIG_S3C64XX_SETUP_SDHCI_GPIO=y
+CONFIG_MACH_SMDK6400=y
+CONFIG_MACH_ANW6410=y
 CONFIG_MACH_SMDK6410=y
 CONFIG_SMDK6410_SD_CH0=y
 # CONFIG_SMDK6410_SD_CH1 is not set
 # CONFIG_SMDK6410_WM1190_EV1 is not set
-# CONFIG_MACH_NCP is not set
-# CONFIG_MACH_HMT is not set
+# CONFIG_SMDK6410_WM1192_EV1 is not set
+CONFIG_MACH_NCP=y
+CONFIG_MACH_HMT=y
+CONFIG_MACH_SMARTQ=y
+CONFIG_MACH_SMARTQ5=y
+CONFIG_MACH_SMARTQ7=y
 
 #
 # Processor Type
@@ -290,6 +320,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_ARM_VIC=y
 CONFIG_ARM_VIC_NR=2
@@ -339,6 +371,7 @@ CONFIG_ALIGNMENT_TRAP=y
 CONFIG_ZBOOT_ROM_TEXT=0
 CONFIG_ZBOOT_ROM_BSS=0
 CONFIG_CMDLINE="console=ttySAC0,115200 root=/dev/ram init=/linuxrc initrd=0x51000000,6M ramdisk_size=6144"
+# CONFIG_CMDLINE_FORCE is not set
 # CONFIG_XIP_KERNEL is not set
 # CONFIG_KEXEC is not set
 
@@ -371,7 +404,14 @@ CONFIG_HAVE_AOUT=y
 #
 # Power management options
 #
-# CONFIG_PM is not set
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+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 is not set
 
@@ -392,7 +432,96 @@ CONFIG_EXTRA_FIRMWARE=""
 # CONFIG_DEBUG_DRIVER is not set
 # CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
-# CONFIG_MTD 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 is not set
+
+#
+# User Modules And Translation Layers
+#
+# CONFIG_MTD_CHAR is not set
+# CONFIG_MTD_BLKDEVS is not set
+# CONFIG_MTD_BLOCK is not set
+# CONFIG_MTD_BLOCK_RO is not set
+# 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 is not set
+# CONFIG_MTD_JEDECPROBE 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_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_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_S3C2410=y
+# CONFIG_MTD_NAND_S3C2410_DEBUG is not set
+# CONFIG_MTD_NAND_S3C2410_HWECC is not set
+# CONFIG_MTD_NAND_S3C2410_CLKSTOP is not set
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA 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_PARPORT is not set
 CONFIG_BLK_DEV=y
 # CONFIG_BLK_DEV_COW_COMMON is not set
@@ -402,6 +531,7 @@ CONFIG_BLK_DEV_LOOP=y
 #
 # DRBD disabled because PROC_FS, INET or CONNECTOR not selected
 #
+# CONFIG_BLK_DEV_UB is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
@@ -413,13 +543,16 @@ CONFIG_MISC_DEVICES=y
 # 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
@@ -430,6 +563,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
@@ -466,6 +600,7 @@ 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
@@ -527,12 +662,17 @@ CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # Non-8250 serial port support
 #
 CONFIG_SERIAL_SAMSUNG=y
+CONFIG_SERIAL_SAMSUNG_UARTS_4=y
 CONFIG_SERIAL_SAMSUNG_UARTS=4
 # CONFIG_SERIAL_SAMSUNG_DEBUG is not set
 CONFIG_SERIAL_SAMSUNG_CONSOLE=y
 CONFIG_SERIAL_S3C6400=y
+# CONFIG_SERIAL_MAX3100 is not set
 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=y
@@ -561,28 +701,41 @@ CONFIG_I2C_HELPER_AUTO=y
 # CONFIG_I2C_OCORES is not set
 CONFIG_I2C_S3C2410=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_STUB is not set
-
-#
-# Miscellaneous I2C Chip support
-#
-# 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_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=m
+CONFIG_SPI_GPIO=m
+CONFIG_SPI_S3C64XX=m
+# 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
@@ -596,10 +749,12 @@ 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
@@ -612,6 +767,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:
@@ -627,16 +785,18 @@ CONFIG_HWMON=y
 #
 # CONFIG_SENSORS_AD7414 is not set
 # CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADCXX is not set
 # CONFIG_SENSORS_ADM1021 is not set
 # CONFIG_SENSORS_ADM1025 is not set
 # CONFIG_SENSORS_ADM1026 is not set
 # CONFIG_SENSORS_ADM1029 is not set
 # CONFIG_SENSORS_ADM1031 is not set
 # CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7411 is not set
 # CONFIG_SENSORS_ADT7462 is not set
 # CONFIG_SENSORS_ADT7470 is not set
-# CONFIG_SENSORS_ADT7473 is not set
 # CONFIG_SENSORS_ADT7475 is not set
+# CONFIG_SENSORS_ASC7621 is not set
 # CONFIG_SENSORS_ATXP1 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_F71805F is not set
@@ -647,6 +807,7 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
 # CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
 # CONFIG_SENSORS_LM73 is not set
 # CONFIG_SENSORS_LM75 is not set
 # CONFIG_SENSORS_LM77 is not set
@@ -661,6 +822,7 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_LTC4215 is not set
 # CONFIG_SENSORS_LTC4245 is not set
 # CONFIG_SENSORS_LM95241 is not set
+# CONFIG_SENSORS_MAX1111 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_MAX6650 is not set
 # CONFIG_SENSORS_PC87360 is not set
@@ -672,6 +834,7 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_SMSC47M192 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
 # CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_ADS7871 is not set
 # CONFIG_SENSORS_AMC6821 is not set
 # CONFIG_SENSORS_THMC50 is not set
 # CONFIG_SENSORS_TMP401 is not set
@@ -685,9 +848,11 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_W83L786NG is not set
 # CONFIG_SENSORS_W83627HF is not set
 # CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_SENSORS_LIS3_SPI is not set
 # CONFIG_SENSORS_LIS3_I2C is not set
 # CONFIG_THERMAL is not set
 # CONFIG_WATCHDOG is not set
+CONFIG_HAVE_S3C2410_WATCHDOG=y
 CONFIG_SSB_POSSIBLE=y
 
 #
@@ -699,10 +864,13 @@ CONFIG_SSB_POSSIBLE=y
 # 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
@@ -711,12 +879,16 @@ CONFIG_SSB_POSSIBLE=y
 # 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_MFD_88PM8607 is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_AB4500_CORE is not set
 # CONFIG_REGULATOR is not set
 # CONFIG_MEDIA_SUPPORT is not set
 
@@ -725,8 +897,47 @@ CONFIG_SSB_POSSIBLE=y
 #
 # CONFIG_VGASTATE is not set
 # CONFIG_VIDEO_OUTPUT_CONTROL is not set
-# CONFIG_FB is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT 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_FB_S1D13XXX is not set
+CONFIG_FB_S3C=y
+# CONFIG_FB_S3C_DEBUG_REGWRITE 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=y
+CONFIG_LCD_CLASS_DEVICE=y
+# CONFIG_LCD_L4F00242T03 is not set
+# CONFIG_LCD_LMS283GF05 is not set
+CONFIG_LCD_LTV350QV=y
+# CONFIG_LCD_ILI9320 is not set
+# CONFIG_LCD_TDO24M is not set
+# CONFIG_LCD_VGG2432A4 is not set
+# CONFIG_LCD_PLATFORM is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=y
+CONFIG_BACKLIGHT_PWM=y
 
 #
 # Display device support
@@ -738,33 +949,246 @@ 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 is not set
+CONFIG_SOUND=y
+CONFIG_SOUND_OSS_CORE=y
+CONFIG_SOUND_OSS_CORE_PRECLAIM=y
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_JACK=y
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# 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=m
+CONFIG_SND_SOC_AC97_BUS=y
+CONFIG_SND_S3C24XX_SOC=m
+CONFIG_SND_S3C_SOC_AC97=m
+# CONFIG_SND_S3C64XX_SOC_WM8580 is not set
+CONFIG_SND_SOC_SMDK_WM9713=m
+CONFIG_SND_SOC_I2C_AND_SPI=m
+# CONFIG_SND_SOC_ALL_CODECS is not set
+CONFIG_SND_SOC_WM9713=m
+# CONFIG_SOUND_PRIME is not set
+CONFIG_AC97_BUS=m
 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=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+# CONFIG_HID_CANDO is not set
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+# CONFIG_HID_PRODIKEYS is not set
+CONFIG_HID_CYPRESS=y
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EGALAX is not set
+CONFIG_HID_EZKEY=y
+CONFIG_HID_KYE=y
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_TWINHAN is not set
+CONFIG_HID_KENSINGTON=y
+CONFIG_HID_LOGITECH=y
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+# CONFIG_LOGIG940_FF is not set
+CONFIG_HID_MICROSOFT=y
+# CONFIG_HID_MOSART is not set
+CONFIG_HID_MONTEREY=y
+# 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=y
 # CONFIG_USB_ARCH_HAS_EHCI is not set
-# CONFIG_USB is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+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_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# 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
 
 #
-# Enable Host or Gadget support to see Inventra options
+# USB Device Class drivers
 #
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+# 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=m
+# CONFIG_USB_EZUSB is not set
+CONFIG_USB_SERIAL_GENERIC=y
+# CONFIG_USB_SERIAL_AIRCABLE is not set
+# CONFIG_USB_SERIAL_ARK3116 is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_CH341 is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_CP210X is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+# CONFIG_USB_SERIAL_FUNSOFT is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_IUU is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_MOS7720 is not set
+# CONFIG_USB_SERIAL_MOS7840 is not set
+# CONFIG_USB_SERIAL_MOTOROLA is not set
+# CONFIG_USB_SERIAL_NAVMAN is not set
+CONFIG_USB_SERIAL_PL2303=m
+# CONFIG_USB_SERIAL_OTI6858 is not set
+# CONFIG_USB_SERIAL_QCAUX is not set
+# CONFIG_USB_SERIAL_QUALCOMM is not set
+# CONFIG_USB_SERIAL_SPCP8X5 is not set
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_SIEMENS_MPI is not set
+# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
+# CONFIG_USB_SERIAL_SYMBOL is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OPTION is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_OPTICON is not set
+# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set
+# CONFIG_USB_SERIAL_ZIO is not set
+# CONFIG_USB_SERIAL_DEBUG 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=y
 CONFIG_MMC_UNSAFE_RESUME=y
@@ -784,20 +1208,80 @@ CONFIG_MMC_SDHCI=y
 # CONFIG_MMC_SDHCI_PLTFM is not set
 CONFIG_MMC_SDHCI_S3C=y
 # CONFIG_MMC_SDHCI_S3C_DMA is not set
-# CONFIG_MMC_AT91 is not set
-# CONFIG_MMC_ATMELMCI is not set
+# CONFIG_MMC_SPI is not set
 # 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
+
+#
+# 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_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_V3020 is not set
 
 #
-# TI VLYNQ
+# on-CPU RTC drivers
 #
+CONFIG_RTC_DRV_S3C=y
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
 # CONFIG_STAGING is not set
 
 #
@@ -869,6 +1353,8 @@ CONFIG_MISC_FILESYSTEMS=y
 # 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_LOGFS is not set
 CONFIG_CRAMFS=y
 # CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
@@ -889,7 +1375,46 @@ CONFIG_ROMFS_ON_BLOCK=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
@@ -952,6 +1477,7 @@ CONFIG_HAVE_FUNCTION_TRACER=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
@@ -962,6 +1488,7 @@ CONFIG_BRANCH_PROFILE_NONE=y
 # CONFIG_KMEMTRACE is not set
 # CONFIG_WORKQUEUE_TRACER is not set
 # CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
index 279a15e53114c8bcd3ebf9a7a2db068ddadc60da..532e987beb4d0d051e5709482b8bb1ddcded2b5f 100644 (file)
@@ -1,11 +1,14 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.33-rc2
-# Sat Jan  9 16:33:55 2010
+# Linux kernel version: 2.6.34
+# Wed May 26 19:04:32 2010
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
 CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_ARCH_USES_GETTIMEOFFSET=y
+CONFIG_HAVE_PROC_CPU=y
 CONFIG_NO_IOPORT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_STACKTRACE_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"
@@ -30,6 +34,13 @@ CONFIG_BROKEN_ON_SMP=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 is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
@@ -46,7 +57,6 @@ CONFIG_RCU_FANOUT=32
 # CONFIG_TREE_RCU_TRACE is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_LOG_BUF_SHIFT=17
-# CONFIG_GROUP_SCHED is not set
 # CONFIG_CGROUPS is not set
 CONFIG_SYSFS_DEPRECATED=y
 CONFIG_SYSFS_DEPRECATED_V2=y
@@ -60,6 +70,7 @@ CONFIG_INITRAMFS_SOURCE=""
 CONFIG_RD_GZIP=y
 CONFIG_RD_BZIP2=y
 CONFIG_RD_LZMA=y
+CONFIG_RD_LZO=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -81,10 +92,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_SLUB_DEBUG=y
 CONFIG_COMPAT_BRK=y
@@ -166,8 +181,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
@@ -176,7 +194,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
@@ -193,44 +210,56 @@ 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
+# 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=y
-# CONFIG_ARCH_S5PC1XX 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
 CONFIG_PLAT_SAMSUNG=y
-CONFIG_SAMSUNG_CLKSRC=y
-CONFIG_SAMSUNG_IRQ_VIC_TIMER=y
-CONFIG_SAMSUNG_IRQ_UART=y
-CONFIG_SAMSUNG_GPIO_EXTRA=0
-CONFIG_PLAT_S3C=y
 
 #
 # Boot options
 #
 CONFIG_S3C_BOOT_ERROR_RESET=y
 CONFIG_S3C_BOOT_UART_FORCE_FIFO=y
+CONFIG_S3C_LOWLEVEL_UART_PORT=1
+CONFIG_SAMSUNG_CLKSRC=y
+CONFIG_SAMSUNG_IRQ_VIC_TIMER=y
+CONFIG_SAMSUNG_IRQ_UART=y
+CONFIG_SAMSUNG_GPIOLIB_4BIT=y
+CONFIG_S3C_GPIO_CFG_S3C24XX=y
+CONFIG_S3C_GPIO_CFG_S3C64XX=y
+CONFIG_S3C_GPIO_PULL_UPDOWN=y
+CONFIG_S5P_GPIO_DRVSTR=y
+CONFIG_SAMSUNG_GPIO_EXTRA=0
+CONFIG_S3C_GPIO_SPACE=0
+CONFIG_S3C_GPIO_TRACK=y
+# CONFIG_S3C_ADC is not set
+CONFIG_S3C_DEV_WDT=y
+CONFIG_SAMSUNG_DEV_ADC=y
+CONFIG_SAMSUNG_DEV_TS=y
+CONFIG_S3C_PL330_DMA=y
 
 #
 # Power management
 #
-CONFIG_S3C_LOWLEVEL_UART_PORT=1
-CONFIG_S3C_GPIO_SPACE=0
-CONFIG_S3C_GPIO_TRACK=y
 CONFIG_PLAT_S5P=y
-CONFIG_CPU_S5P6440_INIT=y
-CONFIG_CPU_S5P6440_CLOCK=y
 CONFIG_CPU_S5P6440=y
 CONFIG_MACH_SMDK6440=y
 
@@ -258,9 +287,12 @@ 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_ARM_VIC=y
 CONFIG_ARM_VIC_NR=2
+CONFIG_PL330=y
 
 #
 # Bus support
@@ -307,6 +339,7 @@ CONFIG_ALIGNMENT_TRAP=y
 CONFIG_ZBOOT_ROM_TEXT=0
 CONFIG_ZBOOT_ROM_BSS=0
 CONFIG_CMDLINE="root=/dev/ram0 rw ramdisk=8192 initrd=0x20800000,8M console=ttySAC1,115200 init=/linuxrc"
+# CONFIG_CMDLINE_FORCE is not set
 # CONFIG_XIP_KERNEL is not set
 # CONFIG_KEXEC is not set
 
@@ -382,6 +415,7 @@ CONFIG_HAVE_IDE=y
 #
 # SCSI device support
 #
+CONFIG_SCSI_MOD=y
 # CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
 CONFIG_SCSI_DMA=y
@@ -470,7 +504,9 @@ CONFIG_MOUSE_PS2_TRACKPOINT=y
 CONFIG_INPUT_TOUCHSCREEN=y
 # CONFIG_TOUCHSCREEN_AD7879 is not set
 # CONFIG_TOUCHSCREEN_DYNAPRO is not set
+# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set
 # CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_S3C2410 is not set
 # CONFIG_TOUCHSCREEN_GUNZE is not set
 # CONFIG_TOUCHSCREEN_ELO is not set
 # CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
@@ -518,12 +554,16 @@ CONFIG_SERIAL_8250_RUNTIME_UARTS=3
 # Non-8250 serial port support
 #
 CONFIG_SERIAL_SAMSUNG=y
+CONFIG_SERIAL_SAMSUNG_UARTS_4=y
 CONFIG_SERIAL_SAMSUNG_UARTS=4
 # CONFIG_SERIAL_SAMSUNG_DEBUG is not set
 CONFIG_SERIAL_SAMSUNG_CONSOLE=y
-CONFIG_SERIAL_S5P6440=y
+CONFIG_SERIAL_S3C6400=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=y
@@ -549,6 +589,7 @@ CONFIG_GPIOLIB=y
 #
 # Memory mapped GPIO expanders:
 #
+# CONFIG_GPIO_IT8761E is not set
 
 #
 # I2C GPIO expanders:
@@ -570,6 +611,7 @@ CONFIG_GPIOLIB=y
 # CONFIG_HWMON is not set
 # CONFIG_THERMAL is not set
 # CONFIG_WATCHDOG is not set
+CONFIG_HAVE_S3C2410_WATCHDOG=y
 CONFIG_SSB_POSSIBLE=y
 
 #
@@ -626,10 +668,6 @@ CONFIG_RTC_LIB=y
 # CONFIG_DMADEVICES is not set
 # CONFIG_AUXDISPLAY is not set
 # CONFIG_UIO is not set
-
-#
-# TI VLYNQ
-#
 # CONFIG_STAGING is not set
 
 #
@@ -704,6 +742,7 @@ CONFIG_MISC_FILESYSTEMS=y
 # 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=y
 # CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
@@ -826,6 +865,7 @@ CONFIG_HAVE_FUNCTION_TRACER=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
@@ -836,6 +876,7 @@ CONFIG_BRANCH_PROFILE_NONE=y
 # CONFIG_KMEMTRACE is not set
 # CONFIG_WORKQUEUE_TRACER is not set
 # CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
@@ -962,8 +1003,10 @@ CONFIG_CRC32=y
 # CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
+CONFIG_LZO_DECOMPRESS=y
 CONFIG_DECOMPRESS_GZIP=y
 CONFIG_DECOMPRESS_BZIP2=y
 CONFIG_DECOMPRESS_LZMA=y
+CONFIG_DECOMPRESS_LZO=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_DMA=y
index 74e20bfc04874fa21a2c70c9f755c90563bde005..068219b360f50b1e113937500d3eacfbe46e9243 100644 (file)
@@ -1,11 +1,14 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.33-rc4
-# Mon Jan 25 08:50:28 2010
+# Linux kernel version: 2.6.34
+# Wed May 26 19:04:34 2010
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
 CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_ARCH_USES_GETTIMEOFFSET=y
+CONFIG_HAVE_PROC_CPU=y
 CONFIG_NO_IOPORT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_STACKTRACE_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
@@ -52,7 +57,6 @@ CONFIG_RCU_FANOUT=32
 # CONFIG_TREE_RCU_TRACE is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_LOG_BUF_SHIFT=17
-# CONFIG_GROUP_SCHED is not set
 # CONFIG_CGROUPS is not set
 CONFIG_SYSFS_DEPRECATED=y
 CONFIG_SYSFS_DEPRECATED_V2=y
@@ -88,10 +92,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_SLUB_DEBUG=y
 CONFIG_COMPAT_BRK=y
@@ -173,8 +181,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
@@ -183,7 +194,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
@@ -200,24 +210,35 @@ 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
+# 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=y
-# CONFIG_ARCH_S5PC1XX 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
 CONFIG_PLAT_SAMSUNG=y
+
+#
+# Boot options
+#
+# CONFIG_S3C_BOOT_ERROR_RESET is not set
+CONFIG_S3C_BOOT_UART_FORCE_FIFO=y
+CONFIG_S3C_LOWLEVEL_UART_PORT=1
 CONFIG_SAMSUNG_CLKSRC=y
 CONFIG_SAMSUNG_IRQ_VIC_TIMER=y
 CONFIG_SAMSUNG_IRQ_UART=y
@@ -225,22 +246,16 @@ CONFIG_SAMSUNG_GPIOLIB_4BIT=y
 CONFIG_S3C_GPIO_CFG_S3C24XX=y
 CONFIG_S3C_GPIO_CFG_S3C64XX=y
 CONFIG_S3C_GPIO_PULL_UPDOWN=y
+CONFIG_S5P_GPIO_DRVSTR=y
 CONFIG_SAMSUNG_GPIO_EXTRA=0
+CONFIG_S3C_GPIO_SPACE=0
+CONFIG_S3C_GPIO_TRACK=y
 # CONFIG_S3C_ADC is not set
+CONFIG_S3C_PL330_DMA=y
 
 #
 # Power management
 #
-CONFIG_PLAT_S3C=y
-
-#
-# Boot options
-#
-# CONFIG_S3C_BOOT_ERROR_RESET is not set
-CONFIG_S3C_BOOT_UART_FORCE_FIFO=y
-CONFIG_S3C_LOWLEVEL_UART_PORT=1
-CONFIG_S3C_GPIO_SPACE=0
-CONFIG_S3C_GPIO_TRACK=y
 CONFIG_PLAT_S5P=y
 CONFIG_CPU_S5P6442=y
 CONFIG_MACH_SMDK6442=y
@@ -269,9 +284,12 @@ 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_ARM_VIC=y
 CONFIG_ARM_VIC_NR=2
+CONFIG_PL330=y
 
 #
 # Bus support
@@ -318,6 +336,7 @@ CONFIG_ALIGNMENT_TRAP=y
 CONFIG_ZBOOT_ROM_TEXT=0
 CONFIG_ZBOOT_ROM_BSS=0
 CONFIG_CMDLINE="root=/dev/ram0 rw ramdisk=8192 initrd=0x20800000,8M console=ttySAC1,115200 init=/linuxrc"
+# CONFIG_CMDLINE_FORCE is not set
 # CONFIG_XIP_KERNEL is not set
 # CONFIG_KEXEC is not set
 
@@ -394,6 +413,7 @@ CONFIG_HAVE_IDE=y
 #
 # SCSI device support
 #
+CONFIG_SCSI_MOD=y
 # CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
 CONFIG_SCSI_DMA=y
@@ -462,6 +482,7 @@ CONFIG_INPUT_EVDEV=y
 CONFIG_INPUT_TOUCHSCREEN=y
 # CONFIG_TOUCHSCREEN_AD7879 is not set
 # CONFIG_TOUCHSCREEN_DYNAPRO is not set
+# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set
 # CONFIG_TOUCHSCREEN_FUJITSU is not set
 # CONFIG_TOUCHSCREEN_GUNZE is not set
 # CONFIG_TOUCHSCREEN_ELO is not set
@@ -515,6 +536,9 @@ CONFIG_SERIAL_SAMSUNG_CONSOLE=y
 CONFIG_SERIAL_S5PV210=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=y
@@ -540,6 +564,7 @@ CONFIG_GPIOLIB=y
 #
 # Memory mapped GPIO expanders:
 #
+# CONFIG_GPIO_IT8761E is not set
 
 #
 # I2C GPIO expanders:
@@ -613,10 +638,6 @@ CONFIG_RTC_LIB=y
 # CONFIG_DMADEVICES is not set
 # CONFIG_AUXDISPLAY is not set
 # CONFIG_UIO is not set
-
-#
-# TI VLYNQ
-#
 # CONFIG_STAGING is not set
 
 #
@@ -685,6 +706,7 @@ CONFIG_MISC_FILESYSTEMS=y
 # 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=y
 # CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
@@ -824,6 +846,7 @@ CONFIG_HAVE_FUNCTION_TRACER=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
@@ -834,6 +857,7 @@ CONFIG_BRANCH_PROFILE_NONE=y
 # CONFIG_KMEMTRACE is not set
 # CONFIG_WORKQUEUE_TRACER is not set
 # CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
index dc108afc060c0d433a3ab9c293d311f673c963c2..ebc6245b9fcaee85e37b74425937f059730b2077 100644 (file)
@@ -1,12 +1,14 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30
-# Wed Jul  1 15:53:07 2009
+# Linux kernel version: 2.6.34
+# Wed May 26 19:04:35 2010
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
 CONFIG_GENERIC_GPIO=y
-CONFIG_MMU=y
+CONFIG_GENERIC_TIME=y
+CONFIG_ARCH_USES_GETTIMEOFFSET=y
+CONFIG_HAVE_PROC_CPU=y
 CONFIG_NO_IOPORT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_STACKTRACE_SUPPORT=y
@@ -18,7 +20,9 @@ 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_ARM_L1_CACHE_SHIFT_6=y
 CONFIG_VECTORS_BASE=0xffff0000
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 CONFIG_CONSTRUCTORS=y
@@ -31,6 +35,13 @@ CONFIG_BROKEN_ON_SMP=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 is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
@@ -38,14 +49,15 @@ CONFIG_SWAP=y
 #
 # RCU Subsystem
 #
-CONFIG_CLASSIC_RCU=y
-# CONFIG_TREE_RCU is not set
-# CONFIG_PREEMPT_RCU is not set
+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_PREEMPT_RCU_TRACE is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_LOG_BUF_SHIFT=17
-# CONFIG_GROUP_SCHED is not set
 # CONFIG_CGROUPS is not set
 CONFIG_SYSFS_DEPRECATED=y
 CONFIG_SYSFS_DEPRECATED_V2=y
@@ -59,6 +71,7 @@ CONFIG_INITRAMFS_SOURCE=""
 CONFIG_RD_GZIP=y
 CONFIG_RD_BZIP2=y
 CONFIG_RD_LZMA=y
+CONFIG_RD_LZO=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -80,19 +93,21 @@ CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
 CONFIG_AIO=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
 
 #
-# Performance Counters
+# Kernel Performance Events And Counters
 #
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERF_COUNTERS is not set
 CONFIG_VM_EVENT_COUNTERS=y
 CONFIG_SLUB_DEBUG=y
-# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_COMPAT_BRK=y
 # CONFIG_SLAB is not set
 CONFIG_SLUB=y
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
 CONFIG_HAVE_KPROBES=y
@@ -122,25 +137,56 @@ 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 is not set
 
 #
 # 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
@@ -156,6 +202,7 @@ CONFIG_DEFAULT_IOSCHED="cfq"
 # 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
@@ -164,39 +211,64 @@ CONFIG_DEFAULT_IOSCHED="cfq"
 # 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_S5PC1XX=y
+# CONFIG_ARCH_S5P6440 is not set
+# CONFIG_ARCH_S5P6442 is not set
+CONFIG_ARCH_S5PC100=y
+# 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_S3C=y
+# CONFIG_PLAT_SPEAR is not set
+CONFIG_PLAT_SAMSUNG=y
 
 #
 # Boot options
 #
 # CONFIG_S3C_BOOT_ERROR_RESET is not set
 CONFIG_S3C_BOOT_UART_FORCE_FIFO=y
+CONFIG_S3C_LOWLEVEL_UART_PORT=0
+CONFIG_SAMSUNG_CLKSRC=y
+CONFIG_SAMSUNG_IRQ_VIC_TIMER=y
+CONFIG_SAMSUNG_IRQ_UART=y
+CONFIG_SAMSUNG_GPIOLIB_4BIT=y
+CONFIG_S3C_GPIO_CFG_S3C24XX=y
+CONFIG_S3C_GPIO_CFG_S3C64XX=y
+CONFIG_S3C_GPIO_PULL_UPDOWN=y
+CONFIG_S5P_GPIO_DRVSTR=y
+CONFIG_SAMSUNG_GPIO_EXTRA=0
+CONFIG_S3C_GPIO_SPACE=0
+CONFIG_S3C_GPIO_TRACK=y
+# CONFIG_S3C_ADC is not set
+CONFIG_S3C_DEV_HSMMC=y
+CONFIG_S3C_DEV_HSMMC1=y
+CONFIG_S3C_DEV_HSMMC2=y
+CONFIG_S3C_DEV_I2C1=y
+CONFIG_S3C_DEV_FB=y
+CONFIG_S3C_PL330_DMA=y
 
 #
 # Power management
 #
-CONFIG_S3C_LOWLEVEL_UART_PORT=0
-CONFIG_S3C_GPIO_SPACE=0
-CONFIG_S3C_GPIO_TRACK=y
-CONFIG_S3C_GPIO_PULL_UPDOWN=y
-CONFIG_PLAT_S5PC1XX=y
-CONFIG_CPU_S5PC100_INIT=y
-CONFIG_CPU_S5PC100_CLOCK=y
-CONFIG_S5PC100_SETUP_I2C0=y
+CONFIG_PLAT_S5P=y
+CONFIG_S5P_EXT_INT=y
 CONFIG_CPU_S5PC100=y
+CONFIG_S5PC100_SETUP_FB_24BPP=y
+CONFIG_S5PC100_SETUP_I2C1=y
+CONFIG_S5PC100_SETUP_SDHCI=y
+CONFIG_S5PC100_SETUP_SDHCI_GPIO=y
 CONFIG_MACH_SMDKC100=y
 
 #
@@ -206,7 +278,7 @@ CONFIG_CPU_32v6K=y
 CONFIG_CPU_V7=y
 CONFIG_CPU_32v7=y
 CONFIG_CPU_ABRT_EV7=y
-CONFIG_CPU_PABRT_IFAR=y
+CONFIG_CPU_PABRT_V7=y
 CONFIG_CPU_CACHE_V7=y
 CONFIG_CPU_CACHE_VIPT=y
 CONFIG_CPU_COPY_V6=y
@@ -224,11 +296,15 @@ CONFIG_ARM_THUMB=y
 # CONFIG_CPU_DCACHE_DISABLE is not set
 # CONFIG_CPU_BPREDICT_DISABLE is not set
 CONFIG_HAS_TLS_REG=y
+CONFIG_ARM_L1_CACHE_SHIFT=6
+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
 CONFIG_ARM_VIC=y
 CONFIG_ARM_VIC_NR=2
+CONFIG_PL330=y
 
 #
 # Bus support
@@ -244,8 +320,11 @@ CONFIG_VMSPLIT_3G=y
 # CONFIG_VMSPLIT_2G is not set
 # CONFIG_VMSPLIT_1G is not set
 CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
 # CONFIG_PREEMPT is not set
 CONFIG_HZ=100
+# CONFIG_THUMB2_KERNEL is not set
 CONFIG_AEABI=y
 CONFIG_OABI_COMPAT=y
 # CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
@@ -258,12 +337,11 @@ CONFIG_FLATMEM_MANUAL=y
 CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 CONFIG_PAGEFLAGS_EXTENDED=y
-CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_SPLIT_PTLOCK_CPUS=999999
 # 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
 # CONFIG_UACCESS_WITH_MEMCPY is not set
@@ -274,6 +352,7 @@ CONFIG_ALIGNMENT_TRAP=y
 CONFIG_ZBOOT_ROM_TEXT=0
 CONFIG_ZBOOT_ROM_BSS=0
 CONFIG_CMDLINE="root=/dev/mtdblock2 rootfstype=cramfs init=/linuxrc console=ttySAC2,115200 mem=128M"
+# CONFIG_CMDLINE_FORCE is not set
 # CONFIG_XIP_KERNEL is not set
 # CONFIG_KEXEC is not set
 
@@ -317,6 +396,7 @@ CONFIG_ARCH_SUSPEND_POSSIBLE=y
 # 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
@@ -331,6 +411,10 @@ CONFIG_BLK_DEV=y
 # CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
+
+#
+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
+#
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=8192
@@ -338,9 +422,12 @@ CONFIG_BLK_DEV_RAM_SIZE=8192
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_MG_DISK 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_C2PORT is not set
 
 #
@@ -350,18 +437,21 @@ CONFIG_EEPROM_AT24=y
 # 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_PHONE is not set
 
 #
 # Input device support
@@ -369,6 +459,7 @@ CONFIG_HAVE_IDE=y
 CONFIG_INPUT=y
 # CONFIG_INPUT_FF_MEMLESS is not set
 # CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
 
 #
 # Userland interfaces
@@ -385,13 +476,19 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
 CONFIG_KEYBOARD_ATKBD=y
-# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_QT2160 is not set
 # CONFIG_KEYBOARD_LKKBD is not set
-# CONFIG_KEYBOARD_XTKBD 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_GPIO 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=y
@@ -399,6 +496,7 @@ CONFIG_MOUSE_PS2_LOGIPS2PP=y
 CONFIG_MOUSE_PS2_SYNAPTICS=y
 CONFIG_MOUSE_PS2_TRACKPOINT=y
 # 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_APPLETOUCH is not set
@@ -418,6 +516,7 @@ 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
 
 #
@@ -444,11 +543,16 @@ CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # Non-8250 serial port support
 #
 CONFIG_SERIAL_SAMSUNG=y
-CONFIG_SERIAL_SAMSUNG_UARTS=3
+CONFIG_SERIAL_SAMSUNG_UARTS_4=y
+CONFIG_SERIAL_SAMSUNG_UARTS=4
 # CONFIG_SERIAL_SAMSUNG_DEBUG is not set
 CONFIG_SERIAL_SAMSUNG_CONSOLE=y
+CONFIG_SERIAL_S3C6400=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=y
@@ -461,6 +565,7 @@ CONFIG_HW_RANDOM=y
 # 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
 
@@ -471,9 +576,11 @@ CONFIG_I2C_HELPER_AUTO=y
 #
 # 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_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
 
 #
 # External I2C/SMBus adapter drivers
@@ -486,20 +593,15 @@ CONFIG_I2C_HELPER_AUTO=y
 #
 # CONFIG_I2C_PCA_PLATFORM is not set
 # CONFIG_I2C_STUB is not set
-
-#
-# Miscellaneous I2C Chip support
-#
-# CONFIG_DS1682 is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_PCF8575 is not set
-# CONFIG_SENSORS_PCA9539 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
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
 CONFIG_ARCH_REQUIRE_GPIOLIB=y
 CONFIG_GPIOLIB=y
 # CONFIG_DEBUG_GPIO is not set
@@ -508,13 +610,16 @@ 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_ADP5588 is not set
 
 #
 # PCI GPIO expanders:
@@ -523,10 +628,19 @@ CONFIG_GPIOLIB=y
 #
 # SPI GPIO expanders:
 #
+
+#
+# AC97 GPIO expanders:
+#
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
 # CONFIG_SENSORS_AD7414 is not set
 # CONFIG_SENSORS_AD7418 is not set
 # CONFIG_SENSORS_ADM1021 is not set
@@ -535,10 +649,11 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_ADM1029 is not set
 # CONFIG_SENSORS_ADM1031 is not set
 # CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7411 is not set
 # CONFIG_SENSORS_ADT7462 is not set
 # CONFIG_SENSORS_ADT7470 is not set
-# CONFIG_SENSORS_ADT7473 is not set
 # CONFIG_SENSORS_ADT7475 is not set
+# CONFIG_SENSORS_ASC7621 is not set
 # CONFIG_SENSORS_ATXP1 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_F71805F is not set
@@ -549,6 +664,7 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
 # CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM73 is not set
 # CONFIG_SENSORS_LM75 is not set
 # CONFIG_SENSORS_LM77 is not set
 # CONFIG_SENSORS_LM78 is not set
@@ -573,8 +689,10 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_SMSC47M192 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
 # CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_AMC6821 is not set
 # CONFIG_SENSORS_THMC50 is not set
 # CONFIG_SENSORS_TMP401 is not set
+# CONFIG_SENSORS_TMP421 is not set
 # CONFIG_SENSORS_VT1211 is not set
 # CONFIG_SENSORS_W83781D is not set
 # CONFIG_SENSORS_W83791D is not set
@@ -584,9 +702,8 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_W83L786NG is not set
 # CONFIG_SENSORS_W83627HF is not set
 # CONFIG_SENSORS_W83627EHF is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
+# CONFIG_SENSORS_LIS3_I2C is not set
 # CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
 # CONFIG_WATCHDOG is not set
 CONFIG_SSB_POSSIBLE=y
 
@@ -599,10 +716,12 @@ CONFIG_SSB_POSSIBLE=y
 # 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_TPS65010 is not set
 # CONFIG_TWL4030_CORE is not set
 # CONFIG_MFD_TMIO is not set
@@ -610,10 +729,15 @@ 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_I2C is not set
+# CONFIG_MFD_WM8994 is not set
 # CONFIG_MFD_PCF50633 is not set
 # CONFIG_AB3100_CORE is not set
+# CONFIG_REGULATOR is not set
 # CONFIG_MEDIA_SUPPORT is not set
 
 #
@@ -637,7 +761,6 @@ CONFIG_DUMMY_CONSOLE=y
 # CONFIG_SOUND is not set
 CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
-CONFIG_HID_DEBUG=y
 # CONFIG_HIDRAW is not set
 # CONFIG_HID_PID is not set
 
@@ -680,13 +803,12 @@ CONFIG_SDIO_UART=y
 CONFIG_MMC_SDHCI=y
 # CONFIG_MMC_SDHCI_PLTFM is not set
 # CONFIG_MEMSTICK is not set
-# CONFIG_ACCESSIBILITY 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_REGULATOR is not set
 # CONFIG_UIO is not set
 # CONFIG_STAGING is not set
 
@@ -710,6 +832,7 @@ CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
 # CONFIG_GFS2_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
@@ -758,6 +881,7 @@ CONFIG_MISC_FILESYSTEMS=y
 # 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=y
 # CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
@@ -772,7 +896,6 @@ CONFIG_ROMFS_BACKED_BY_BLOCK=y
 CONFIG_ROMFS_ON_BLOCK=y
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
-# CONFIG_NILFS2_FS is not set
 
 #
 # Partition Types
@@ -789,6 +912,7 @@ 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
@@ -826,11 +950,13 @@ CONFIG_DEBUG_MEMORY_INIT=y
 # 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_BOOT_PRINTK_DELAY 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
@@ -839,6 +965,7 @@ CONFIG_HAVE_FUNCTION_TRACER=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
@@ -849,6 +976,7 @@ CONFIG_BRANCH_PROFILE_NONE=y
 # CONFIG_KMEMTRACE is not set
 # CONFIG_WORKQUEUE_TRACER is not set
 # CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
@@ -857,8 +985,9 @@ CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_ERRORS=y
 # CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUG_LL=y
+# CONFIG_EARLY_PRINTK is not set
 # CONFIG_DEBUG_ICEDCC is not set
-CONFIG_DEBUG_S3C_PORT=y
+# CONFIG_OC_ETM is not set
 CONFIG_DEBUG_S3C_UART=0
 
 #
@@ -867,7 +996,11 @@ CONFIG_DEBUG_S3C_UART=0
 # 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 is not set
 # CONFIG_BINARY_PRINTF is not set
 
@@ -884,8 +1017,10 @@ CONFIG_CRC32=y
 # CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
+CONFIG_LZO_DECOMPRESS=y
 CONFIG_DECOMPRESS_GZIP=y
 CONFIG_DECOMPRESS_BZIP2=y
 CONFIG_DECOMPRESS_LZMA=y
+CONFIG_DECOMPRESS_LZO=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_DMA=y
index 6ea636131ac852b42df7b972703975ab11633a31..c4de360b0f692dffb9fb791add523d373eff8247 100644 (file)
@@ -1,11 +1,14 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.33-rc4
-# Wed Feb 24 15:36:54 2010
+# Linux kernel version: 2.6.34
+# Wed May 26 19:04:37 2010
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
 CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_ARCH_USES_GETTIMEOFFSET=y
+CONFIG_HAVE_PROC_CPU=y
 CONFIG_NO_IOPORT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_STACKTRACE_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_ARM_L1_CACHE_SHIFT_6=y
 CONFIG_VECTORS_BASE=0xffff0000
@@ -33,6 +37,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,7 +59,6 @@ CONFIG_RCU_FANOUT=32
 # CONFIG_TREE_RCU_TRACE is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_LOG_BUF_SHIFT=17
-# CONFIG_GROUP_SCHED is not set
 # CONFIG_CGROUPS is not set
 CONFIG_SYSFS_DEPRECATED=y
 CONFIG_SYSFS_DEPRECATED_V2=y
@@ -90,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_SLUB_DEBUG=y
 CONFIG_COMPAT_BRK=y
@@ -175,8 +183,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
@@ -185,7 +196,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
@@ -202,24 +212,27 @@ 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
+# 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_S5PC100 is not set
 CONFIG_ARCH_S5PV210=y
 # 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
 CONFIG_PLAT_SAMSUNG=y
 
 #
@@ -235,16 +248,22 @@ CONFIG_SAMSUNG_GPIOLIB_4BIT=y
 CONFIG_S3C_GPIO_CFG_S3C24XX=y
 CONFIG_S3C_GPIO_CFG_S3C64XX=y
 CONFIG_S3C_GPIO_PULL_UPDOWN=y
+CONFIG_S5P_GPIO_DRVSTR=y
 CONFIG_SAMSUNG_GPIO_EXTRA=0
 CONFIG_S3C_GPIO_SPACE=0
 CONFIG_S3C_GPIO_TRACK=y
 # CONFIG_S3C_ADC is not set
+CONFIG_S3C_DEV_WDT=y
+CONFIG_S3C_PL330_DMA=y
 
 #
 # Power management
 #
 CONFIG_PLAT_S5P=y
+CONFIG_S5P_EXT_INT=y
 CONFIG_CPU_S5PV210=y
+# CONFIG_MACH_AQUILA is not set
+# CONFIG_MACH_GONI is not set
 # CONFIG_MACH_SMDKV210 is not set
 CONFIG_MACH_SMDKC110=y
 
@@ -274,11 +293,14 @@ CONFIG_ARM_THUMB=y
 # CONFIG_CPU_BPREDICT_DISABLE is not set
 CONFIG_HAS_TLS_REG=y
 CONFIG_ARM_L1_CACHE_SHIFT=6
+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
 CONFIG_ARM_VIC=y
 CONFIG_ARM_VIC_NR=2
+CONFIG_PL330=y
 
 #
 # Bus support
@@ -327,6 +349,7 @@ CONFIG_ALIGNMENT_TRAP=y
 CONFIG_ZBOOT_ROM_TEXT=0
 CONFIG_ZBOOT_ROM_BSS=0
 CONFIG_CMDLINE="root=/dev/ram0 rw ramdisk=8192 initrd=0x20800000,8M console=ttySAC1,115200 init=/linuxrc"
+# CONFIG_CMDLINE_FORCE is not set
 # CONFIG_XIP_KERNEL is not set
 # CONFIG_KEXEC is not set
 
@@ -404,6 +427,7 @@ CONFIG_HAVE_IDE=y
 #
 # SCSI device support
 #
+CONFIG_SCSI_MOD=y
 # CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
 CONFIG_SCSI_DMA=y
@@ -472,6 +496,7 @@ CONFIG_INPUT_EVDEV=y
 CONFIG_INPUT_TOUCHSCREEN=y
 # CONFIG_TOUCHSCREEN_AD7879 is not set
 # CONFIG_TOUCHSCREEN_DYNAPRO is not set
+# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set
 # CONFIG_TOUCHSCREEN_FUJITSU is not set
 # CONFIG_TOUCHSCREEN_GUNZE is not set
 # CONFIG_TOUCHSCREEN_ELO is not set
@@ -526,6 +551,9 @@ CONFIG_SERIAL_SAMSUNG_CONSOLE=y
 CONFIG_SERIAL_S5PV210=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=y
@@ -551,6 +579,7 @@ CONFIG_GPIOLIB=y
 #
 # Memory mapped GPIO expanders:
 #
+# CONFIG_GPIO_IT8761E is not set
 
 #
 # I2C GPIO expanders:
@@ -572,6 +601,7 @@ CONFIG_GPIOLIB=y
 # CONFIG_HWMON is not set
 # CONFIG_THERMAL is not set
 # CONFIG_WATCHDOG is not set
+CONFIG_HAVE_S3C2410_WATCHDOG=y
 CONFIG_SSB_POSSIBLE=y
 
 #
@@ -624,10 +654,6 @@ CONFIG_RTC_LIB=y
 # CONFIG_DMADEVICES is not set
 # CONFIG_AUXDISPLAY is not set
 # CONFIG_UIO is not set
-
-#
-# TI VLYNQ
-#
 # CONFIG_STAGING is not set
 
 #
@@ -696,6 +722,7 @@ CONFIG_MISC_FILESYSTEMS=y
 # 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=y
 # CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
@@ -835,6 +862,8 @@ CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_TRACING_SUPPORT=y
 CONFIG_FTRACE=y
 # CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
 # CONFIG_ENABLE_DEFAULT_TRACERS is not set
 # CONFIG_BOOT_TRACER is not set
@@ -845,6 +874,7 @@ CONFIG_BRANCH_PROFILE_NONE=y
 # CONFIG_KMEMTRACE is not set
 # CONFIG_WORKQUEUE_TRACER is not set
 # CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
index 3f7d47491b54a3442ba7d66752d82b8f1a50f581..e2f5bce29828fc072eaef38cfbe244dca518b875 100644 (file)
@@ -1,11 +1,14 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.33-rc4
-# Wed Feb 24 15:36:16 2010
+# Linux kernel version: 2.6.34
+# Wed May 26 19:04:39 2010
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
 CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_ARCH_USES_GETTIMEOFFSET=y
+CONFIG_HAVE_PROC_CPU=y
 CONFIG_NO_IOPORT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_STACKTRACE_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_ARM_L1_CACHE_SHIFT_6=y
 CONFIG_VECTORS_BASE=0xffff0000
@@ -33,6 +37,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,7 +59,6 @@ CONFIG_RCU_FANOUT=32
 # CONFIG_TREE_RCU_TRACE is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_LOG_BUF_SHIFT=17
-# CONFIG_GROUP_SCHED is not set
 # CONFIG_CGROUPS is not set
 CONFIG_SYSFS_DEPRECATED=y
 CONFIG_SYSFS_DEPRECATED_V2=y
@@ -90,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_SLUB_DEBUG=y
 CONFIG_COMPAT_BRK=y
@@ -175,8 +183,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
@@ -185,7 +196,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
@@ -202,24 +212,27 @@ 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
+# 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_S5PC100 is not set
 CONFIG_ARCH_S5PV210=y
 # 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
 CONFIG_PLAT_SAMSUNG=y
 
 #
@@ -235,16 +248,24 @@ CONFIG_SAMSUNG_GPIOLIB_4BIT=y
 CONFIG_S3C_GPIO_CFG_S3C24XX=y
 CONFIG_S3C_GPIO_CFG_S3C64XX=y
 CONFIG_S3C_GPIO_PULL_UPDOWN=y
+CONFIG_S5P_GPIO_DRVSTR=y
 CONFIG_SAMSUNG_GPIO_EXTRA=0
 CONFIG_S3C_GPIO_SPACE=0
 CONFIG_S3C_GPIO_TRACK=y
 # CONFIG_S3C_ADC is not set
+CONFIG_S3C_DEV_WDT=y
+CONFIG_SAMSUNG_DEV_ADC=y
+CONFIG_SAMSUNG_DEV_TS=y
+CONFIG_S3C_PL330_DMA=y
 
 #
 # Power management
 #
 CONFIG_PLAT_S5P=y
+CONFIG_S5P_EXT_INT=y
 CONFIG_CPU_S5PV210=y
+# CONFIG_MACH_AQUILA is not set
+# CONFIG_MACH_GONI is not set
 CONFIG_MACH_SMDKV210=y
 # CONFIG_MACH_SMDKC110 is not set
 
@@ -274,11 +295,14 @@ CONFIG_ARM_THUMB=y
 # CONFIG_CPU_BPREDICT_DISABLE is not set
 CONFIG_HAS_TLS_REG=y
 CONFIG_ARM_L1_CACHE_SHIFT=6
+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
 CONFIG_ARM_VIC=y
 CONFIG_ARM_VIC_NR=2
+CONFIG_PL330=y
 
 #
 # Bus support
@@ -327,6 +351,7 @@ CONFIG_ALIGNMENT_TRAP=y
 CONFIG_ZBOOT_ROM_TEXT=0
 CONFIG_ZBOOT_ROM_BSS=0
 CONFIG_CMDLINE="root=/dev/ram0 rw ramdisk=8192 initrd=0x20800000,8M console=ttySAC1,115200 init=/linuxrc"
+# CONFIG_CMDLINE_FORCE is not set
 # CONFIG_XIP_KERNEL is not set
 # CONFIG_KEXEC is not set
 
@@ -404,6 +429,7 @@ CONFIG_HAVE_IDE=y
 #
 # SCSI device support
 #
+CONFIG_SCSI_MOD=y
 # CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
 CONFIG_SCSI_DMA=y
@@ -472,7 +498,9 @@ CONFIG_INPUT_EVDEV=y
 CONFIG_INPUT_TOUCHSCREEN=y
 # CONFIG_TOUCHSCREEN_AD7879 is not set
 # CONFIG_TOUCHSCREEN_DYNAPRO is not set
+# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set
 # CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_S3C2410 is not set
 # CONFIG_TOUCHSCREEN_GUNZE is not set
 # CONFIG_TOUCHSCREEN_ELO is not set
 # CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
@@ -526,6 +554,9 @@ CONFIG_SERIAL_SAMSUNG_CONSOLE=y
 CONFIG_SERIAL_S5PV210=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=y
@@ -551,6 +582,7 @@ CONFIG_GPIOLIB=y
 #
 # Memory mapped GPIO expanders:
 #
+# CONFIG_GPIO_IT8761E is not set
 
 #
 # I2C GPIO expanders:
@@ -572,6 +604,7 @@ CONFIG_GPIOLIB=y
 # CONFIG_HWMON is not set
 # CONFIG_THERMAL is not set
 # CONFIG_WATCHDOG is not set
+CONFIG_HAVE_S3C2410_WATCHDOG=y
 CONFIG_SSB_POSSIBLE=y
 
 #
@@ -624,10 +657,6 @@ CONFIG_RTC_LIB=y
 # CONFIG_DMADEVICES is not set
 # CONFIG_AUXDISPLAY is not set
 # CONFIG_UIO is not set
-
-#
-# TI VLYNQ
-#
 # CONFIG_STAGING is not set
 
 #
@@ -696,6 +725,7 @@ CONFIG_MISC_FILESYSTEMS=y
 # 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=y
 # CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
@@ -835,6 +865,8 @@ CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_TRACING_SUPPORT=y
 CONFIG_FTRACE=y
 # CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
 # CONFIG_ENABLE_DEFAULT_TRACERS is not set
 # CONFIG_BOOT_TRACER is not set
@@ -845,6 +877,7 @@ CONFIG_BRANCH_PROFILE_NONE=y
 # CONFIG_KMEMTRACE is not set
 # CONFIG_WORKQUEUE_TRACER is not set
 # CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
index 182310b991950b6e22d69930b376d3337335d80a..6d7485aff9558dcfba7de1f1cfb4a648778a6c6b 100644 (file)
@@ -12,7 +12,9 @@ typedef struct {
 
 #include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
 
-#if NR_IRQS > 256
+#if NR_IRQS > 512
+#define HARDIRQ_BITS   10
+#elif NR_IRQS > 256
 #define HARDIRQ_BITS   9
 #else
 #define HARDIRQ_BITS   8
index bcda59f399417d3d3493a7a9800a59c900094751..2f87870d93471d79d9913da8fadfcb9f1b3efe67 100644 (file)
@@ -3,9 +3,6 @@
 
 #include <asm/memory.h>
 #include <asm/types.h>
-
 #include <asm-generic/scatterlist.h>
 
-#undef ARCH_HAS_SG_CHAIN
-
 #endif /* _ASMARM_SCATTERLIST_H */
index c91c77b54dea151be9e04bee8355d0d78d3b1445..122d999bdc7ca0c8f690355a101f59f1ea8152f8 100644 (file)
@@ -593,6 +593,7 @@ static int __init parse_tag_revision(const struct tag *tag)
 
 __tagtable(ATAG_REVISION, parse_tag_revision);
 
+#ifndef CONFIG_CMDLINE_FORCE
 static int __init parse_tag_cmdline(const struct tag *tag)
 {
        strlcpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE);
@@ -600,6 +601,7 @@ static int __init parse_tag_cmdline(const struct tag *tag)
 }
 
 __tagtable(ATAG_CMDLINE, parse_tag_cmdline);
+#endif /* CONFIG_CMDLINE_FORCE */
 
 /*
  * Scan the tag table for this tag, and call its parse function.
index 50292cd9c120aca1600c2bc2f8542697bc1bccca..dd81a918c106ea30029c0b8ce4eb60885f8a69a1 100644 (file)
@@ -26,6 +26,7 @@
  * http://infocenter.arm.com/help/topic/com.arm.doc.subset.swdev.abi/index.html
  */
 
+#ifndef __CHECKER__
 #if !defined (__ARM_EABI__)
 #warning Your compiler does not have EABI support.
 #warning    ARM unwind is known to compile only with EABI compilers.
@@ -34,6 +35,7 @@
 #warning Your compiler is too buggy; it is known to not compile ARM unwind support.
 #warning    Change compiler or disable ARM_UNWIND option.
 #endif
+#endif /* __CHECKER__ */
 
 #include <linux/kernel.h>
 #include <linux/init.h>
index 98f9f4bc93962ea07afd5f1b7deae906768f6bfe..ee800595594d3fa790f6d4737f59d3c9c4b8c473 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/leds.h>
 #include <linux/clk.h>
 
-#include <mach/hardware.h>
 #include <video/atmel_lcdc.h>
 
 #include <asm/setup.h>
index d3d29339e149f3464afeb9cf14d5ac6902e32be3..a51fcef64fe0bb2324db6a1225c6d06dff9913d6 100644 (file)
@@ -1,7 +1,6 @@
 # The standard locations for stuff on CLPS711x type processors
-   zreladdr-y                          := 0xc0028000 
+   zreladdr-y                          := 0xc0028000
 params_phys-y                          := 0xc0000100
 # Should probably have some agreement on these...
 initrd_phys-$(CONFIG_ARCH_P720T)       := 0xc0400000
 initrd_phys-$(CONFIG_ARCH_CDB89712)    := 0x00700000
-
index 5a85e24f36730c759173da5810ca5f6a9fa298d1..d4f1e9675069514015bce168140bb46fa2322d42 100644 (file)
@@ -22,6 +22,9 @@ struct davinci_mmc_config {
 
        /* Version of the MMC/SD controller */
        u8      version;
+
+       /* Number of sg segments */
+       u8      nr_sg;
 };
 void davinci_setup_mmc(int module, struct davinci_mmc_config *config);
 
diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h b/arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h
new file mode 100644 (file)
index 0000000..0a37961
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef __ASM_MACH_EP93XX_SPI_H
+#define __ASM_MACH_EP93XX_SPI_H
+
+struct spi_device;
+
+/**
+ * struct ep93xx_spi_info - EP93xx specific SPI descriptor
+ * @num_chipselect: number of chip selects on this board, must be
+ *                  at least one
+ */
+struct ep93xx_spi_info {
+       int     num_chipselect;
+};
+
+/**
+ * struct ep93xx_spi_chip_ops - operation callbacks for SPI slave device
+ * @setup: setup the chip select mechanism
+ * @cleanup: cleanup the chip select mechanism
+ * @cs_control: control the device chip select
+ */
+struct ep93xx_spi_chip_ops {
+       int     (*setup)(struct spi_device *spi);
+       void    (*cleanup)(struct spi_device *spi);
+       void    (*cs_control)(struct spi_device *spi, int value);
+};
+
+#endif /* __ASM_MACH_EP93XX_SPI_H */
index 720c0bac1702e00e6f678946c4ecd7a0b6a50682..e5ab5bddbc8c87613ddc1e14e644b913b859d54f 100644 (file)
@@ -20,9 +20,9 @@ static int __init ebsa285_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
        if (dev->vendor == PCI_VENDOR_ID_CONTAQ &&
            dev->device == PCI_DEVICE_ID_CONTAQ_82C693)
                switch (PCI_FUNC(dev->devfn)) {
-                       case 1: return 14;
-                       case 2: return 15;
-                       case 3: return 12;
+               case 1: return 14;
+               case 2: return 15;
+               case 3: return 12;
                }
 
        return irqmap_ebsa285[(slot + pin) & 3];
index d8798dbc44f8ef34f469c99b88f69fb1eda42328..7dd5fa604efc503affc28c4e53de1763365b3b9a 100644 (file)
  */
 
 extern unsigned long h720x_gettimeoffset(void);
-extern void __init h720x_init_irq (void);
+extern void __init h720x_init_irq(void);
 extern void __init h720x_map_io(void);
 
 #ifdef CONFIG_ARCH_H7202
 extern struct sys_timer h7202_timer;
 extern void __init init_hw_h7202(void);
-extern void __init h7202_init_irq (void);
+extern void __init h7202_init_irq(void);
 extern void __init h7202_init_time(void);
 #endif
 
index cccb9f3c9d01c52018845cd6b06f14bd3437defd..db9381b85bf031542e1fca1837d15b68242aa201 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/input.h>
 #include <linux/io.h>
 #include <linux/delay.h>
-#include <linux/bootmem.h>
 #include <linux/power_supply.h>
 
 #include <mach/hardware.h>
index bac1f3c38a3b897c8be6ad33b72dc39ee94be7f3..e32981928c7701e2032414d69ef099fd6a1bd9db 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/gpio.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
-#include <linux/bootmem.h>
 #include <linux/io.h>
 #include <linux/smsc911x.h>
 
index ec4606643d2c86e75f521c26fbf56855dac5b728..e3cc80792d6c2bafbcb9bb68ce9505434d71c176 100644 (file)
@@ -19,7 +19,6 @@
 #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>
index b91e412f7b3e96e5b6dc090540212ce1c13b72ea..a0aeb8a4adc19ef419a0a045ad3b882131597106 100644 (file)
@@ -109,12 +109,7 @@ DEFINE_IMX_GPT_DEVICE(4, MX27_GPT5_BASE_ADDR, MX27_INT_GPT5);
 DEFINE_IMX_GPT_DEVICE(5, MX27_GPT6_BASE_ADDR, MX27_INT_GPT6);
 #endif
 
-/*
- * Watchdog:
- * - i.MX1
- * - i.MX21
- * - i.MX27
- */
+/* Watchdog: i.MX1 has seperate driver, i.MX21 and i.MX27 are equal */
 static struct resource mxc_wdt_resources[] = {
        {
                .start = MX2x_WDOG_BASE_ADDR,
@@ -124,7 +119,7 @@ static struct resource mxc_wdt_resources[] = {
 };
 
 struct platform_device mxc_wdt = {
-       .name = "mxc_wdt",
+       .name = "imx2-wdt",
        .id = 0,
        .num_resources = ARRAY_SIZE(mxc_wdt_resources),
        .resource = mxc_wdt_resources,
@@ -483,8 +478,8 @@ int __init mxc_register_gpios(void)
 #ifdef CONFIG_MACH_MX21
 static struct resource mx21_usbhc_resources[] = {
        {
-               .start  = MX21_BASE_ADDR,
-               .end    = MX21_BASE_ADDR + 0x1FFF,
+               .start  = MX21_USBOTG_BASE_ADDR,
+               .end    = MX21_USBOTG_BASE_ADDR + SZ_8K - 1,
                .flags  = IORESOURCE_MEM,
        },
        {
index 778fff230918c93977b702944c4132067c27cd6e..a87422ed4ff5a1ea9bd4f07605092bc646842ca9 100644 (file)
@@ -145,6 +145,7 @@ static struct mxc_nand_platform_data pca100_nand_board_info = {
 static struct platform_device *platform_devices[] __initdata = {
        &mxc_w1_master_device,
        &mxc_fec_device,
+       &mxc_wdt,
 };
 
 static struct imxi2c_platform_data pca100_i2c_1_data = {
index 035fbe046ec0d01610621fd9663056481f8dc579..36c89431679a93edd5e66118ce9eb9b5838b9045 100644 (file)
@@ -182,6 +182,7 @@ static struct platform_device *platform_devices[] __initdata = {
        &mxc_w1_master_device,
        &mxc_fec_device,
        &pcm038_sram_mtd_device,
+       &mxc_wdt,
 };
 
 /* On pcm038 there's a sram attached to CS1, we enable the chipselect here and
index 3f4b8a0b5facf9d1c7200ce7f21d1b85890f37b6..3a405fa400eb064a6a8e612027709b7601cb4d34 100644 (file)
@@ -500,3 +500,18 @@ struct platform_device mx25_fb_device = {
                .coherent_dma_mask = 0xFFFFFFFF,
        },
 };
+
+static struct resource mxc_wdt_resources[] = {
+       {
+               .start = MX25_WDOG_BASE_ADDR,
+               .end = MX25_WDOG_BASE_ADDR + SZ_16K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+};
+
+struct platform_device mxc_wdt = {
+       .name = "imx2-wdt",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(mxc_wdt_resources),
+       .resource = mxc_wdt_resources,
+};
index 39560e13bc0d5c93cdf6d7d0da2ba9c41e6734dd..cee12c0a0be68e5988fcc8f914c94705dfe92beb 100644 (file)
@@ -21,3 +21,4 @@ extern struct platform_device mx25_fec_device;
 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;
index 170f68e46dd5caceb5bd83bb000e5eaf846e538a..344753fdf25ef47ac6856ff5058f9cc8a193120a 100644 (file)
@@ -82,6 +82,7 @@ config MACH_MX31MOBOARD
 config MACH_MX31LILLY
        bool "Support MX31 LILLY-1131 platforms (INCO startec)"
        select ARCH_MX31
+       select MXC_ULPI if USB_ULPI
        help
          Include support for mx31 based LILLY1131 modules. This includes
          specific configurations for the board and its peripherals.
index f8911154a9fa8cac1badb0ab45c6265675d93a92..db7acd6e910160cc230736ff3eb441eff255f2d0 100644 (file)
@@ -582,12 +582,50 @@ static struct resource imx_wdt_resources[] = {
 };
 
 struct platform_device imx_wdt_device0 = {
-       .name           = "imx-wdt",
+       .name           = "imx2-wdt",
        .id             = 0,
        .num_resources  = ARRAY_SIZE(imx_wdt_resources),
        .resource       = imx_wdt_resources,
 };
 
+static struct resource imx_rtc_resources[] = {
+       {
+               .start  = MX31_RTC_BASE_ADDR,
+               .end    = MX31_RTC_BASE_ADDR + 0x3fff,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = MX31_INT_RTC,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device imx_rtc_device0 = {
+       .name           = "mxc_rtc",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(imx_rtc_resources),
+       .resource       = imx_rtc_resources,
+};
+
+static struct resource imx_kpp_resources[] = {
+       {
+               .start  = MX3x_KPP_BASE_ADDR,
+               .end    = MX3x_KPP_BASE_ADDR + 0xf,
+               .flags  = IORESOURCE_MEM
+       }, {
+               .start  = MX3x_INT_KPP,
+               .end    = MX3x_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,
+};
+
 static int __init mx3_devices_init(void)
 {
        if (cpu_is_mx31()) {
index 4f77eb501274c0fcf5406252d158641de3efd159..2c3c8646a29ef701c3872483ddf44901332b4858 100644 (file)
@@ -27,3 +27,5 @@ extern struct platform_device imx_ssi_device0;
 extern struct platform_device imx_ssi_device1;
 extern struct platform_device imx_ssi_device1;
 extern struct platform_device imx_wdt_device0;
+extern struct platform_device imx_rtc_device0;
+extern struct platform_device imx_kpp_device;
index f54af1e29ca48a9dfcb142887d5f85d1b770e6b6..58e57291b79d876fb6bdf04fe6da2020c36d9e1b 100644 (file)
@@ -16,6 +16,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include <linux/delay.h>
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/clk.h>
@@ -26,6 +27,8 @@
 #include <linux/mfd/mc13783.h>
 #include <linux/spi/spi.h>
 #include <linux/regulator/machine.h>
+#include <linux/fsl_devices.h>
+#include <linux/input/matrix_keypad.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -65,6 +68,50 @@ static int mx31_3ds_pins[] = {
        MX31_PIN_CSPI2_SS2__SS2, /*CS for MC13783 */
        /* MC13783 IRQ */
        IOMUX_MODE(MX31_PIN_GPIO1_3, IOMUX_CONFIG_GPIO),
+       /* USB OTG reset */
+       IOMUX_MODE(MX31_PIN_USB_PWR, IOMUX_CONFIG_GPIO),
+       /* USB OTG */
+       MX31_PIN_USBOTG_DATA0__USBOTG_DATA0,
+       MX31_PIN_USBOTG_DATA1__USBOTG_DATA1,
+       MX31_PIN_USBOTG_DATA2__USBOTG_DATA2,
+       MX31_PIN_USBOTG_DATA3__USBOTG_DATA3,
+       MX31_PIN_USBOTG_DATA4__USBOTG_DATA4,
+       MX31_PIN_USBOTG_DATA5__USBOTG_DATA5,
+       MX31_PIN_USBOTG_DATA6__USBOTG_DATA6,
+       MX31_PIN_USBOTG_DATA7__USBOTG_DATA7,
+       MX31_PIN_USBOTG_CLK__USBOTG_CLK,
+       MX31_PIN_USBOTG_DIR__USBOTG_DIR,
+       MX31_PIN_USBOTG_NXT__USBOTG_NXT,
+       MX31_PIN_USBOTG_STP__USBOTG_STP,
+       /*Keyboard*/
+       MX31_PIN_KEY_ROW0_KEY_ROW0,
+       MX31_PIN_KEY_ROW1_KEY_ROW1,
+       MX31_PIN_KEY_ROW2_KEY_ROW2,
+       MX31_PIN_KEY_COL0_KEY_COL0,
+       MX31_PIN_KEY_COL1_KEY_COL1,
+       MX31_PIN_KEY_COL2_KEY_COL2,
+       MX31_PIN_KEY_COL3_KEY_COL3,
+};
+
+/*
+ * Matrix keyboard
+ */
+
+static const uint32_t mx31_3ds_keymap[] = {
+       KEY(0, 0, KEY_UP),
+       KEY(0, 1, KEY_DOWN),
+       KEY(1, 0, KEY_RIGHT),
+       KEY(1, 1, KEY_LEFT),
+       KEY(1, 2, KEY_ENTER),
+       KEY(2, 0, KEY_F6),
+       KEY(2, 1, KEY_F8),
+       KEY(2, 2, KEY_F9),
+       KEY(2, 3, KEY_F10),
+};
+
+static struct matrix_keymap_data mx31_3ds_keymap_data = {
+       .keymap         = mx31_3ds_keymap,
+       .keymap_size    = ARRAY_SIZE(mx31_3ds_keymap),
 };
 
 /* Regulators */
@@ -126,6 +173,41 @@ static struct mxc_nand_platform_data imx31_3ds_nand_flash_pdata = {
 #endif
 };
 
+/*
+ * USB OTG
+ */
+
+#define USB_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST | PAD_CTL_HYS_CMOS | \
+                    PAD_CTL_ODE_CMOS | PAD_CTL_100K_PU)
+
+#define USBOTG_RST_B IOMUX_TO_GPIO(MX31_PIN_USB_PWR)
+
+static void mx31_3ds_usbotg_init(void)
+{
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA0, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA1, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA2, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA3, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA4, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA5, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA6, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA7, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_CLK, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DIR, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_NXT, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_STP, USB_PAD_CFG);
+
+       gpio_request(USBOTG_RST_B, "otgusb-reset");
+       gpio_direction_output(USBOTG_RST_B, 0);
+       mdelay(1);
+       gpio_set_value(USBOTG_RST_B, 1);
+}
+
+static struct fsl_usb2_platform_data usbotg_pdata = {
+       .operating_mode = FSL_USB2_DR_DEVICE,
+       .phy_mode       = FSL_USB2_PHY_ULPI,
+};
+
 static struct imxuart_platform_data uart_pdata = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
@@ -315,6 +397,11 @@ static void __init mxc_board_init(void)
        spi_register_board_info(mx31_3ds_spi_devs,
                                                ARRAY_SIZE(mx31_3ds_spi_devs));
 
+       mxc_register_device(&imx_kpp_device, &mx31_3ds_keymap_data);
+
+       mx31_3ds_usbotg_init();
+       mxc_register_device(&mxc_otg_udc_device, &usbotg_pdata);
+
        if (!mx31_3ds_init_expio())
                platform_device_register(&smsc911x_device);
 }
index 80847b04c063ac2f4a9ef6d1c397b6f2aef0a437..d3d5877c750ef2c3ca427a7a2d445a820c500a7c 100644 (file)
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/clk.h>
+#include <linux/gpio.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/smsc911x.h>
 #include <linux/mtd/physmap.h>
 #include <linux/spi/spi.h>
 #include <linux/mfd/mc13783.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/ulpi.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -44,6 +47,8 @@
 #include <mach/iomux-mx3.h>
 #include <mach/board-mx31lilly.h>
 #include <mach/spi.h>
+#include <mach/mxc_ehci.h>
+#include <mach/ulpi.h>
 
 #include "devices.h"
 
@@ -108,6 +113,137 @@ static struct platform_device physmap_flash_device = {
        .num_resources = 1,
 };
 
+/* USB */
+
+#define USB_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST | PAD_CTL_HYS_CMOS | \
+                       PAD_CTL_ODE_CMOS | PAD_CTL_100K_PU)
+
+static int usbotg_init(struct platform_device *pdev)
+{
+       unsigned int pins[] = {
+               MX31_PIN_USBOTG_DATA0__USBOTG_DATA0,
+               MX31_PIN_USBOTG_DATA1__USBOTG_DATA1,
+               MX31_PIN_USBOTG_DATA2__USBOTG_DATA2,
+               MX31_PIN_USBOTG_DATA3__USBOTG_DATA3,
+               MX31_PIN_USBOTG_DATA4__USBOTG_DATA4,
+               MX31_PIN_USBOTG_DATA5__USBOTG_DATA5,
+               MX31_PIN_USBOTG_DATA6__USBOTG_DATA6,
+               MX31_PIN_USBOTG_DATA7__USBOTG_DATA7,
+               MX31_PIN_USBOTG_CLK__USBOTG_CLK,
+               MX31_PIN_USBOTG_DIR__USBOTG_DIR,
+               MX31_PIN_USBOTG_NXT__USBOTG_NXT,
+               MX31_PIN_USBOTG_STP__USBOTG_STP,
+       };
+
+       mxc_iomux_setup_multiple_pins(pins, ARRAY_SIZE(pins), "USB OTG");
+
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA0, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA1, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA2, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA3, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA4, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA5, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA6, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA7, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_CLK, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DIR, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_NXT, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_STP, USB_PAD_CFG);
+
+       mxc_iomux_set_gpr(MUX_PGP_USB_4WIRE, true);
+       mxc_iomux_set_gpr(MUX_PGP_USB_COMMON, true);
+
+       /* chip select */
+       mxc_iomux_alloc_pin(IOMUX_MODE(MX31_PIN_DTR_DCE2, IOMUX_CONFIG_GPIO),
+                               "USBOTG_CS");
+       gpio_request(IOMUX_TO_GPIO(MX31_PIN_DTR_DCE2), "USBH1 CS");
+       gpio_direction_output(IOMUX_TO_GPIO(MX31_PIN_DTR_DCE2), 0);
+
+       return 0;
+}
+
+static int usbh1_init(struct platform_device *pdev)
+{
+       int pins[] = {
+               MX31_PIN_CSPI1_MOSI__USBH1_RXDM,
+               MX31_PIN_CSPI1_MISO__USBH1_RXDP,
+               MX31_PIN_CSPI1_SS0__USBH1_TXDM,
+               MX31_PIN_CSPI1_SS1__USBH1_TXDP,
+               MX31_PIN_CSPI1_SS2__USBH1_RCV,
+               MX31_PIN_CSPI1_SCLK__USBH1_OEB,
+               MX31_PIN_CSPI1_SPI_RDY__USBH1_FS,
+       };
+
+       mxc_iomux_setup_multiple_pins(pins, ARRAY_SIZE(pins), "USB H1");
+
+       mxc_iomux_set_pad(MX31_PIN_CSPI1_MOSI, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_CSPI1_MISO, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_CSPI1_SS0, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_CSPI1_SS1, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_CSPI1_SS2, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_CSPI1_SCLK, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_CSPI1_SPI_RDY, USB_PAD_CFG);
+
+       mxc_iomux_set_gpr(MUX_PGP_USB_SUSPEND, true);
+
+       return 0;
+}
+
+static int usbh2_init(struct platform_device *pdev)
+{
+       int pins[] = {
+               MX31_PIN_USBH2_DATA0__USBH2_DATA0,
+               MX31_PIN_USBH2_DATA1__USBH2_DATA1,
+               MX31_PIN_USBH2_CLK__USBH2_CLK,
+               MX31_PIN_USBH2_DIR__USBH2_DIR,
+               MX31_PIN_USBH2_NXT__USBH2_NXT,
+               MX31_PIN_USBH2_STP__USBH2_STP,
+       };
+
+       mxc_iomux_setup_multiple_pins(pins, ARRAY_SIZE(pins), "USB H2");
+
+       mxc_iomux_set_pad(MX31_PIN_USBH2_CLK, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBH2_DIR, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBH2_NXT, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBH2_STP, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBH2_DATA0, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBH2_DATA1, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_SRXD6, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_STXD6, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_SFS3, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_SCK3, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_SRXD3, USB_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_STXD3, USB_PAD_CFG);
+
+       mxc_iomux_set_gpr(MUX_PGP_UH2, true);
+
+       /* chip select */
+       mxc_iomux_alloc_pin(IOMUX_MODE(MX31_PIN_DTR_DCE1, IOMUX_CONFIG_GPIO),
+                               "USBH2_CS");
+       gpio_request(IOMUX_TO_GPIO(MX31_PIN_DTR_DCE1), "USBH2 CS");
+       gpio_direction_output(IOMUX_TO_GPIO(MX31_PIN_DTR_DCE1), 0);
+
+       return 0;
+}
+
+static struct mxc_usbh_platform_data usbotg_pdata = {
+       .init   = usbotg_init,
+       .portsc = MXC_EHCI_MODE_ULPI | MXC_EHCI_UTMI_8BIT,
+       .flags  = MXC_EHCI_POWER_PINS_ENABLED,
+};
+
+static struct mxc_usbh_platform_data usbh1_pdata = {
+       .init   = usbh1_init,
+       .portsc = MXC_EHCI_MODE_UTMI | MXC_EHCI_SERIAL,
+       .flags  = MXC_EHCI_POWER_PINS_ENABLED | MXC_EHCI_INTERFACE_SINGLE_UNI,
+};
+
+static struct mxc_usbh_platform_data usbh2_pdata = {
+       .init   = usbh2_init,
+       .portsc = MXC_EHCI_MODE_ULPI | MXC_EHCI_UTMI_8BIT,
+       .flags  = MXC_EHCI_POWER_PINS_ENABLED,
+};
+
 static struct platform_device *devices[] __initdata = {
        &smsc91x_device,
        &physmap_flash_device,
@@ -183,6 +319,15 @@ static void __init mx31lilly_board_init(void)
        spi_register_board_info(&mc13783_dev, 1);
 
        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);
 }
 
 static void __init mx31lilly_timer_init(void)
index fccb9207b78d75112bed0b7ac0d3d45a17367e1b..62b5e40165dfea0692b06c97865f2094d053439d 100644 (file)
@@ -18,7 +18,6 @@
 
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
-#include <linux/fsl_devices.h>
 #include <linux/gfp.h>
 #include <linux/gpio.h>
 #include <linux/init.h>
@@ -221,11 +220,54 @@ static struct mc13783_regulator_init_data moboard_regulators[] = {
        },
 };
 
+static struct mc13783_led_platform_data moboard_led[] = {
+       {
+               .id = MC13783_LED_R1,
+               .name = "coreboard-led-4:red",
+               .max_current = 2,
+       },
+       {
+               .id = MC13783_LED_G1,
+               .name = "coreboard-led-4:green",
+               .max_current = 2,
+       },
+       {
+               .id = MC13783_LED_B1,
+               .name = "coreboard-led-4:blue",
+               .max_current = 2,
+       },
+       {
+               .id = MC13783_LED_R2,
+               .name = "coreboard-led-5:red",
+               .max_current = 3,
+       },
+       {
+               .id = MC13783_LED_G2,
+               .name = "coreboard-led-5:green",
+               .max_current = 3,
+       },
+       {
+               .id = MC13783_LED_B2,
+               .name = "coreboard-led-5:blue",
+               .max_current = 3,
+       },
+};
+
+static struct mc13783_leds_platform_data moboard_leds = {
+       .num_leds = ARRAY_SIZE(moboard_led),
+       .led = moboard_led,
+       .flags = MC13783_LED_SLEWLIMTC,
+       .abmode = MC13783_LED_AB_DISABLED,
+       .tc1_period = MC13783_LED_PERIOD_10MS,
+       .tc2_period = MC13783_LED_PERIOD_10MS,
+};
+
 static struct mc13783_platform_data moboard_pmic = {
        .regulators = moboard_regulators,
        .num_regulators = ARRAY_SIZE(moboard_regulators),
+       .leds = &moboard_leds,
        .flags = MC13783_USE_REGULATOR | MC13783_USE_RTC |
-               MC13783_USE_ADC,
+               MC13783_USE_ADC | MC13783_USE_LED,
 };
 
 static struct spi_board_info moboard_spi_board_info[] __initdata = {
@@ -306,84 +348,56 @@ static struct imxmmc_platform_data sdhc1_pdata = {
  * this pin is dedicated for all mx31moboard systems, so we do it here
  */
 #define USB_RESET_B    IOMUX_TO_GPIO(MX31_PIN_GPIO1_0)
-
-static void usb_xcvr_reset(void)
-{
-       gpio_request(USB_RESET_B, "usb-reset");
-       gpio_direction_output(USB_RESET_B, 0);
-       mdelay(1);
-       gpio_set_value(USB_RESET_B, 1);
-}
-
 #define USB_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST | PAD_CTL_HYS_CMOS | \
-                       PAD_CTL_ODE_CMOS | PAD_CTL_100K_PU)
+                     PAD_CTL_ODE_CMOS)
 
 #define OTG_EN_B IOMUX_TO_GPIO(MX31_PIN_USB_OC)
-
-static void moboard_usbotg_init(void)
-{
-       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA0, USB_PAD_CFG);
-       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA1, USB_PAD_CFG);
-       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA2, USB_PAD_CFG);
-       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA3, USB_PAD_CFG);
-       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA4, USB_PAD_CFG);
-       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA5, USB_PAD_CFG);
-       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA6, USB_PAD_CFG);
-       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA7, USB_PAD_CFG);
-       mxc_iomux_set_pad(MX31_PIN_USBOTG_CLK, USB_PAD_CFG);
-       mxc_iomux_set_pad(MX31_PIN_USBOTG_DIR, USB_PAD_CFG);
-       mxc_iomux_set_pad(MX31_PIN_USBOTG_NXT, USB_PAD_CFG);
-       mxc_iomux_set_pad(MX31_PIN_USBOTG_STP, USB_PAD_CFG);
-
-       gpio_request(OTG_EN_B, "usb-udc-en");
-       gpio_direction_output(OTG_EN_B, 0);
-}
-
-static struct fsl_usb2_platform_data usb_pdata = {
-       .operating_mode = FSL_USB2_DR_DEVICE,
-       .phy_mode       = FSL_USB2_PHY_ULPI,
-};
-
-#if defined(CONFIG_USB_ULPI)
-
 #define USBH2_EN_B IOMUX_TO_GPIO(MX31_PIN_SCK6)
 
-static int moboard_usbh2_hw_init(struct platform_device *pdev)
+static void usb_xcvr_reset(void)
 {
-       int ret;
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA0, USB_PAD_CFG | PAD_CTL_100K_PD);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA1, USB_PAD_CFG | PAD_CTL_100K_PD);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA2, USB_PAD_CFG | PAD_CTL_100K_PD);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA3, USB_PAD_CFG | PAD_CTL_100K_PD);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA4, USB_PAD_CFG | PAD_CTL_100K_PD);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA5, USB_PAD_CFG | PAD_CTL_100K_PD);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA6, USB_PAD_CFG | PAD_CTL_100K_PD);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA7, USB_PAD_CFG | PAD_CTL_100K_PD);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_CLK, USB_PAD_CFG | PAD_CTL_100K_PU);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DIR, USB_PAD_CFG | PAD_CTL_100K_PU);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_NXT, USB_PAD_CFG | PAD_CTL_100K_PU);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_STP, USB_PAD_CFG | PAD_CTL_100K_PU);
 
        mxc_iomux_set_gpr(MUX_PGP_UH2, true);
+       mxc_iomux_set_pad(MX31_PIN_USBH2_CLK, USB_PAD_CFG | PAD_CTL_100K_PU);
+       mxc_iomux_set_pad(MX31_PIN_USBH2_DIR, USB_PAD_CFG | PAD_CTL_100K_PU);
+       mxc_iomux_set_pad(MX31_PIN_USBH2_NXT, USB_PAD_CFG | PAD_CTL_100K_PU);
+       mxc_iomux_set_pad(MX31_PIN_USBH2_STP, USB_PAD_CFG | PAD_CTL_100K_PU);
+       mxc_iomux_set_pad(MX31_PIN_USBH2_DATA0, USB_PAD_CFG | PAD_CTL_100K_PD);
+       mxc_iomux_set_pad(MX31_PIN_USBH2_DATA1, USB_PAD_CFG | PAD_CTL_100K_PD);
+       mxc_iomux_set_pad(MX31_PIN_SRXD6, USB_PAD_CFG | PAD_CTL_100K_PD);
+       mxc_iomux_set_pad(MX31_PIN_STXD6, USB_PAD_CFG | PAD_CTL_100K_PD);
+       mxc_iomux_set_pad(MX31_PIN_SFS3, USB_PAD_CFG | PAD_CTL_100K_PD);
+       mxc_iomux_set_pad(MX31_PIN_SCK3, USB_PAD_CFG | PAD_CTL_100K_PD);
+       mxc_iomux_set_pad(MX31_PIN_SRXD3, USB_PAD_CFG | PAD_CTL_100K_PD);
+       mxc_iomux_set_pad(MX31_PIN_STXD3, USB_PAD_CFG | PAD_CTL_100K_PD);
 
-       mxc_iomux_set_pad(MX31_PIN_USBH2_CLK, USB_PAD_CFG);
-       mxc_iomux_set_pad(MX31_PIN_USBH2_DIR, USB_PAD_CFG);
-       mxc_iomux_set_pad(MX31_PIN_USBH2_NXT, USB_PAD_CFG);
-       mxc_iomux_set_pad(MX31_PIN_USBH2_STP, USB_PAD_CFG);
-       mxc_iomux_set_pad(MX31_PIN_USBH2_DATA0, USB_PAD_CFG);
-       mxc_iomux_set_pad(MX31_PIN_USBH2_DATA1, USB_PAD_CFG);
-       mxc_iomux_set_pad(MX31_PIN_SRXD6, USB_PAD_CFG);
-       mxc_iomux_set_pad(MX31_PIN_STXD6, USB_PAD_CFG);
-       mxc_iomux_set_pad(MX31_PIN_SFS3, USB_PAD_CFG);
-       mxc_iomux_set_pad(MX31_PIN_SCK3, USB_PAD_CFG);
-       mxc_iomux_set_pad(MX31_PIN_SRXD3, USB_PAD_CFG);
-       mxc_iomux_set_pad(MX31_PIN_STXD3, USB_PAD_CFG);
-
-       ret = gpio_request(USBH2_EN_B, "usbh2-en");
-       if (ret)
-               return ret;
+       gpio_request(OTG_EN_B, "usb-udc-en");
+       gpio_direction_output(OTG_EN_B, 0);
+       gpio_request(USBH2_EN_B, "usbh2-en");
        gpio_direction_output(USBH2_EN_B, 0);
 
-       return 0;
+       gpio_request(USB_RESET_B, "usb-reset");
+       gpio_direction_output(USB_RESET_B, 0);
+       mdelay(1);
+       gpio_set_value(USB_RESET_B, 1);
+       mdelay(1);
 }
 
-static int moboard_usbh2_hw_exit(struct platform_device *pdev)
-{
-       gpio_free(USBH2_EN_B);
-       return 0;
-}
+#if defined(CONFIG_USB_ULPI)
 
 static struct mxc_usbh_platform_data usbh2_pdata = {
-       .init   = moboard_usbh2_hw_init,
-       .exit   = moboard_usbh2_hw_exit,
        .portsc = MXC_EHCI_MODE_ULPI | MXC_EHCI_UTMI_8BIT,
        .flags  = MXC_EHCI_POWER_PINS_ENABLED,
 };
@@ -508,8 +522,6 @@ static void __init mxc_board_init(void)
 
        usb_xcvr_reset();
 
-       moboard_usbotg_init();
-       mxc_register_device(&mxc_otg_udc_device, &usb_pdata);
        moboard_usbh2_init();
 
        switch (mx31moboard_baseboard) {
@@ -522,7 +534,8 @@ static void __init mxc_board_init(void)
                mx31moboard_marxbot_init();
                break;
        case MX31SMARTBOT:
-               mx31moboard_smartbot_init();
+       case MX31EYEBOT:
+               mx31moboard_smartbot_init(mx31moboard_baseboard);
                break;
        default:
                printk(KERN_ERR "Illegal mx31moboard_baseboard type %d\n",
index 78ecd751549b68e0ef2894ad49fba56208601b24..cce41066238338d4c09284835227b0dcd33deca4 100644 (file)
@@ -449,6 +449,7 @@ static int __init pcm037_camera_alloc_dma(const size_t buf_size)
 static struct platform_device *devices[] __initdata = {
        &pcm037_flash,
        &pcm037_sram_device,
+       &imx_wdt_device0,
        &pcm037_mt9t031,
        &pcm037_mt9v022,
 };
index 1bf1ec2eef5e62459f67dbe30190d548b3a3b278..78d9185a9d4ba7f46937f47ffe893935e897b4bb 100644 (file)
@@ -150,6 +150,7 @@ static struct i2c_board_info pcm043_i2c_devices[] = {
 static struct platform_device *devices[] __initdata = {
        &pcm043_flash,
        &mxc_fec_device,
+       &imx_wdt_device0,
 };
 
 static struct pad_desc pcm043_pads[] = {
index 093c595ca58119e2fef5d7924b84c8e0d92c36d2..5f05bfbec38054187324565e3d421a3da01110c9 100644 (file)
@@ -206,5 +206,6 @@ void __init mx31lite_db_init(void)
        mxc_register_device(&mxc_spi_device0, &spi0_pdata);
        platform_device_register(&litekit_led_device);
        mxc_register_device(&imx_wdt_device0, NULL);
+       mxc_register_device(&imx_rtc_device0, NULL);
 }
 
index 11b906ce7eae45c92c405b107412686043db4f0a..582299cb2c08be52c6d0cbd9f8c010d123fca33e 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/types.h>
+#include <linux/fsl_devices.h>
 
 #include <linux/usb/otg.h>
 
@@ -213,6 +214,12 @@ static int __init devboard_usbh1_init(void)
        return mxc_register_device(&mxc_usbh1, &usbh1_pdata);
 }
 
+
+static struct fsl_usb2_platform_data usb_pdata = {
+       .operating_mode = FSL_USB2_DR_DEVICE,
+       .phy_mode       = FSL_USB2_PHY_ULPI,
+};
+
 /*
  * system init for baseboard usage. Will be called by mx31moboard init.
  */
@@ -229,5 +236,7 @@ void __init mx31moboard_devboard_init(void)
 
        devboard_init_sel_gpios();
 
+       mxc_register_device(&mxc_otg_udc_device, &usb_pdata);
+
        devboard_usbh1_init();
 }
index ffb105e14d88d10a77d54fa86267e04db8515d71..4930f8c27e661fd5c8612c0369d7e79779f1cf7d 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/slab.h>
 #include <linux/platform_device.h>
 #include <linux/types.h>
+#include <linux/fsl_devices.h>
 
 #include <linux/usb/otg.h>
 
@@ -329,6 +330,11 @@ static int __init marxbot_usbh1_init(void)
        return mxc_register_device(&mxc_usbh1, &usbh1_pdata);
 }
 
+static struct fsl_usb2_platform_data usb_pdata = {
+       .operating_mode = FSL_USB2_DR_DEVICE,
+       .phy_mode       = FSL_USB2_PHY_ULPI,
+};
+
 /*
  * system init for baseboard usage. Will be called by mx31moboard init.
  */
@@ -356,5 +362,7 @@ void __init mx31moboard_marxbot_init(void)
        gpio_direction_input(IOMUX_TO_GPIO(MX31_PIN_LCS0));
        gpio_export(IOMUX_TO_GPIO(MX31_PIN_LCS0), false);
 
+       mxc_register_device(&mxc_otg_udc_device, &usb_pdata);
+
        marxbot_usbh1_init();
 }
index 52a69fc8b14fcc92925842b92d632d930b8abce2..293eea6d9d97cbd9ffb5cdcbed1409ab685e6a31 100644 (file)
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/types.h>
+#include <linux/fsl_devices.h>
+
+#include <linux/usb/otg.h>
+#include <linux/usb/ulpi.h>
 
 #include <mach/common.h>
 #include <mach/hardware.h>
 #include <mach/imx-uart.h>
 #include <mach/iomux-mx3.h>
+#include <mach/board-mx31moboard.h>
+#include <mach/mxc_ehci.h>
+#include <mach/ulpi.h>
 
 #include <media/soc_camera.h>
 
@@ -116,10 +123,33 @@ static int __init smartbot_cam_init(void)
        return 0;
 }
 
+static struct fsl_usb2_platform_data usb_pdata = {
+       .operating_mode = FSL_USB2_DR_DEVICE,
+       .phy_mode       = FSL_USB2_PHY_ULPI,
+};
+
+#if defined(CONFIG_USB_ULPI)
+
+static struct mxc_usbh_platform_data otg_host_pdata = {
+       .portsc = MXC_EHCI_MODE_ULPI | MXC_EHCI_UTMI_8BIT,
+       .flags  = MXC_EHCI_POWER_PINS_ENABLED,
+};
+
+static int __init smartbot_otg_host_init(void)
+{
+       otg_host_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
+                       USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT);
+
+       return mxc_register_device(&mxc_otg_host, &otg_host_pdata);
+}
+#else
+static inline int smartbot_otg_host_init(void) { return 0; }
+#endif
+
 #define POWER_EN IOMUX_TO_GPIO(MX31_PIN_DTR_DCE1)
 #define DSPIC_RST_B IOMUX_TO_GPIO(MX31_PIN_DSR_DCE1)
 #define TRSLAT_RST_B IOMUX_TO_GPIO(MX31_PIN_RI_DCE1)
-#define SEL3 IOMUX_TO_GPIO(MX31_PIN_DCD_DCE1)
+#define TRSLAT_SRC_CHOICE IOMUX_TO_GPIO(MX31_PIN_DCD_DCE1)
 
 static void smartbot_resets_init(void)
 {
@@ -138,15 +168,15 @@ static void smartbot_resets_init(void)
                gpio_export(TRSLAT_RST_B, false);
        }
 
-       if (!gpio_request(SEL3, "sel3")) {
-               gpio_direction_input(SEL3);
-               gpio_export(SEL3, true);
+       if (!gpio_request(TRSLAT_SRC_CHOICE, "translator-src-choice")) {
+               gpio_direction_output(TRSLAT_SRC_CHOICE, 0);
+               gpio_export(TRSLAT_SRC_CHOICE, false);
        }
 }
 /*
  * system init for baseboard usage. Will be called by mx31moboard init.
  */
-void __init mx31moboard_smartbot_init(void)
+void __init mx31moboard_smartbot_init(int board)
 {
        printk(KERN_INFO "Initializing mx31smartbot peripherals\n");
 
@@ -155,6 +185,19 @@ void __init mx31moboard_smartbot_init(void)
 
        mxc_register_device(&mxc_uart_device1, &uart_pdata);
 
+
+       switch (board) {
+       case MX31SMARTBOT:
+               mxc_register_device(&mxc_otg_udc_device, &usb_pdata);
+               break;
+       case MX31EYEBOT:
+               smartbot_otg_host_init();
+               break;
+       default:
+               printk(KERN_WARNING "Unknown board %d, USB OTG not initialized",
+                       board);
+       }
+
        smartbot_resets_init();
 
        smartbot_cam_init();
index ee67a71db80d9b136f4c4322fac7820e6ed94740..ed885f9d7b73d51e0c19e4ba1c227e95f6dbb09e 100644 (file)
 
 #include <linux/init.h>
 #include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/fsl_devices.h>
 
 #include <mach/common.h>
 #include <mach/hardware.h>
 #include <mach/imx-uart.h>
 #include <mach/iomux-mx51.h>
+#include <mach/mxc_ehci.h>
 
 #include <asm/irq.h>
 #include <asm/setup.h>
 
 #include "devices.h"
 
+#define BABBAGE_USB_HUB_RESET  (0*32 + 7)      /* GPIO_1_7 */
+#define BABBAGE_USBH1_STP      (0*32 + 27)     /* GPIO_1_27 */
+#define BABBAGE_PHY_RESET (1*32 +5)    /* GPIO_2_5 */
+
+/* USB_CTRL_1 */
+#define MX51_USB_CTRL_1_OFFSET                 0x10
+#define MX51_USB_CTRL_UH1_EXT_CLK_EN           (1 << 25)
+
+#define        MX51_USB_PLLDIV_12_MHZ          0x00
+#define        MX51_USB_PLL_DIV_19_2_MHZ       0x01
+#define        MX51_USB_PLL_DIV_24_MHZ 0x02
+
 static struct platform_device *devices[] __initdata = {
        &mxc_fec_device,
 };
@@ -46,6 +63,22 @@ static struct pad_desc mx51babbage_pads[] = {
        MX51_PAD_EIM_D26__UART3_TXD,
        MX51_PAD_EIM_D27__UART3_RTS,
        MX51_PAD_EIM_D24__UART3_CTS,
+
+       /* USB HOST1 */
+       MX51_PAD_USBH1_CLK__USBH1_CLK,
+       MX51_PAD_USBH1_DIR__USBH1_DIR,
+       MX51_PAD_USBH1_NXT__USBH1_NXT,
+       MX51_PAD_USBH1_DATA0__USBH1_DATA0,
+       MX51_PAD_USBH1_DATA1__USBH1_DATA1,
+       MX51_PAD_USBH1_DATA2__USBH1_DATA2,
+       MX51_PAD_USBH1_DATA3__USBH1_DATA3,
+       MX51_PAD_USBH1_DATA4__USBH1_DATA4,
+       MX51_PAD_USBH1_DATA5__USBH1_DATA5,
+       MX51_PAD_USBH1_DATA6__USBH1_DATA6,
+       MX51_PAD_USBH1_DATA7__USBH1_DATA7,
+
+       /* USB HUB reset line*/
+       MX51_PAD_GPIO_1_7__GPIO1_7,
 };
 
 /* Serial ports */
@@ -66,15 +99,149 @@ static inline void mxc_init_imx_uart(void)
 }
 #endif /* SERIAL_IMX */
 
+static int gpio_usbh1_active(void)
+{
+       struct pad_desc usbh1stp_gpio = MX51_PAD_USBH1_STP__GPIO_1_27;
+       struct pad_desc phyreset_gpio = MX51_PAD_EIM_D21__GPIO_2_5;
+       int ret;
+
+       /* Set USBH1_STP to GPIO and toggle it */
+       mxc_iomux_v3_setup_pad(&usbh1stp_gpio);
+       ret = gpio_request(BABBAGE_USBH1_STP, "usbh1_stp");
+
+       if (ret) {
+               pr_debug("failed to get MX51_PAD_USBH1_STP__GPIO_1_27: %d\n", ret);
+               return ret;
+       }
+       gpio_direction_output(BABBAGE_USBH1_STP, 0);
+       gpio_set_value(BABBAGE_USBH1_STP, 1);
+       msleep(100);
+       gpio_free(BABBAGE_USBH1_STP);
+
+       /* De-assert USB PHY RESETB */
+       mxc_iomux_v3_setup_pad(&phyreset_gpio);
+       ret = gpio_request(BABBAGE_PHY_RESET, "phy_reset");
+
+       if (ret) {
+               pr_debug("failed to get MX51_PAD_EIM_D21__GPIO_2_5: %d\n", ret);
+               return ret;
+       }
+       gpio_direction_output(BABBAGE_PHY_RESET, 1);
+       return 0;
+}
+
+static inline void babbage_usbhub_reset(void)
+{
+       int ret;
+
+       /* Bring USB hub out of reset */
+       ret = gpio_request(BABBAGE_USB_HUB_RESET, "GPIO1_7");
+       if (ret) {
+               printk(KERN_ERR"failed to get GPIO_USB_HUB_RESET: %d\n", ret);
+               return;
+       }
+       gpio_direction_output(BABBAGE_USB_HUB_RESET, 0);
+
+       /* USB HUB RESET - De-assert USB HUB RESET_N */
+       msleep(1);
+       gpio_set_value(BABBAGE_USB_HUB_RESET, 0);
+       msleep(1);
+       gpio_set_value(BABBAGE_USB_HUB_RESET, 1);
+}
+
+/* This function is board specific as the bit mask for the plldiv will also
+be different for other Freescale SoCs, thus a common bitmask is not
+possible and cannot get place in /plat-mxc/ehci.c.*/
+static int initialize_otg_port(struct platform_device *pdev)
+{
+       u32 v;
+       void __iomem *usb_base;
+       u32 usbother_base;
+
+       usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K);
+       usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET;
+
+       /* Set the PHY clock to 19.2MHz */
+       v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET);
+       v &= ~MX5_USB_UTMI_PHYCTRL1_PLLDIV_MASK;
+       v |= MX51_USB_PLL_DIV_19_2_MHZ;
+       __raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET);
+       iounmap(usb_base);
+       return 0;
+}
+
+static int initialize_usbh1_port(struct platform_device *pdev)
+{
+       u32 v;
+       void __iomem *usb_base;
+       u32 usbother_base;
+
+       usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K);
+       usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET;
+
+       /* The clock for the USBH1 ULPI port will come externally from the PHY. */
+       v = __raw_readl(usbother_base + MX51_USB_CTRL_1_OFFSET);
+       __raw_writel(v | MX51_USB_CTRL_UH1_EXT_CLK_EN, usbother_base + MX51_USB_CTRL_1_OFFSET);
+       iounmap(usb_base);
+       return 0;
+}
+
+static struct mxc_usbh_platform_data dr_utmi_config = {
+       .init           = initialize_otg_port,
+       .portsc = MXC_EHCI_UTMI_16BIT,
+       .flags  = MXC_EHCI_INTERNAL_PHY,
+};
+
+static struct fsl_usb2_platform_data usb_pdata = {
+       .operating_mode = FSL_USB2_DR_DEVICE,
+       .phy_mode       = FSL_USB2_PHY_UTMI_WIDE,
+};
+
+static struct mxc_usbh_platform_data usbh1_config = {
+       .init           = initialize_usbh1_port,
+       .portsc = MXC_EHCI_MODE_ULPI,
+       .flags  = (MXC_EHCI_POWER_PINS_ENABLED | MXC_EHCI_ITC_NO_THRESHOLD),
+};
+
+static int otg_mode_host;
+
+static int __init babbage_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=", babbage_otg_mode);
+
 /*
  * Board specific initialization.
  */
 static void __init mxc_board_init(void)
 {
+       struct pad_desc usbh1stp = MX51_PAD_USBH1_STP__USBH1_STP;
+
        mxc_iomux_v3_setup_multiple_pads(mx51babbage_pads,
                                        ARRAY_SIZE(mx51babbage_pads));
        mxc_init_imx_uart();
        platform_add_devices(devices, ARRAY_SIZE(devices));
+
+       if (otg_mode_host)
+               mxc_register_device(&mxc_usbdr_host_device, &dr_utmi_config);
+       else {
+               initialize_otg_port(NULL);
+               mxc_register_device(&mxc_usbdr_udc_device, &usb_pdata);
+       }
+
+       gpio_usbh1_active();
+       mxc_register_device(&mxc_usbh1_device, &usbh1_config);
+       /* setback USBH1_STP to be function */
+       mxc_iomux_v3_setup_pad(&usbh1stp);
+       babbage_usbhub_reset();
 }
 
 static void __init mx51_babbage_timer_init(void)
index 1ee6ce4087b84cd001dce69600359a234a78102f..d9f612d3370e8849bea8bfb568bc3d0c4f3839ec 100644 (file)
@@ -37,6 +37,7 @@ static struct clk lp_apm_clk;
 static struct clk periph_apm_clk;
 static struct clk ahb_clk;
 static struct clk ipg_clk;
+static struct clk usboh3_clk;
 
 #define MAX_DPLL_WAIT_TRIES    1000 /* 1000 * udelay(1) = 1ms */
 
@@ -570,6 +571,35 @@ static int _clk_uart_set_parent(struct clk *clk, struct clk *parent)
        return 0;
 }
 
+static unsigned long clk_usboh3_get_rate(struct clk *clk)
+{
+       u32 reg, prediv, podf;
+       unsigned long parent_rate;
+
+       parent_rate = clk_get_rate(clk->parent);
+
+       reg = __raw_readl(MXC_CCM_CSCDR1);
+       prediv = ((reg & MXC_CCM_CSCDR1_USBOH3_CLK_PRED_MASK) >>
+                 MXC_CCM_CSCDR1_USBOH3_CLK_PRED_OFFSET) + 1;
+       podf = ((reg & MXC_CCM_CSCDR1_USBOH3_CLK_PODF_MASK) >>
+               MXC_CCM_CSCDR1_USBOH3_CLK_PODF_OFFSET) + 1;
+
+       return parent_rate / (prediv * podf);
+}
+
+static int _clk_usboh3_set_parent(struct clk *clk, struct clk *parent)
+{
+       u32 reg, mux;
+
+       mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk,
+                      &lp_apm_clk);
+       reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_USBOH3_CLK_SEL_MASK;
+       reg |= mux << MXC_CCM_CSCMR1_USBOH3_CLK_SEL_OFFSET;
+       __raw_writel(reg, MXC_CCM_CSCMR1);
+
+       return 0;
+}
+
 static unsigned long get_high_reference_clock_rate(struct clk *clk)
 {
        return external_high_reference;
@@ -691,6 +721,12 @@ static struct clk uart_root_clk = {
        .set_parent = _clk_uart_set_parent,
 };
 
+static struct clk usboh3_clk = {
+       .parent = &pll2_sw_clk,
+       .get_rate = clk_usboh3_get_rate,
+       .set_parent = _clk_usboh3_set_parent,
+};
+
 static struct clk ahb_max_clk = {
        .parent = &ahb_clk,
        .enable_reg = MXC_CCM_CCGR0,
@@ -779,6 +815,12 @@ 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("mxc-ehci.0", "usb", usboh3_clk)
+       _REGISTER_CLOCK("mxc-ehci.0", "usb_ahb", ahb_clk)
+       _REGISTER_CLOCK("mxc-ehci.1", "usb", usboh3_clk)
+       _REGISTER_CLOCK("mxc-ehci.1", "usb_ahb", ahb_clk)
+       _REGISTER_CLOCK("fsl-usb2-udc", "usb", usboh3_clk)
+       _REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", ahb_clk)
 };
 
 static void clk_tree_init(void)
@@ -819,6 +861,9 @@ int __init mx51_clocks_init(unsigned long ckil, unsigned long osc,
        clk_enable(&cpu_clk);
        clk_enable(&main_bus_clk);
 
+       /* set the usboh3_clk parent to pll2_sw_clk */
+       clk_set_parent(&usboh3_clk, &pll2_sw_clk);
+
        /* System timer */
        mxc_timer_init(&gpt_clk, MX51_IO_ADDRESS(MX51_GPT1_BASE_ADDR),
                MX51_MXC_INT_GPT);
index d6fd3961ade9a6f26bee32ffe280900e91eee9b3..7130449aacdcff6671cea5fe794a418916bdac34 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright 2009 Amit Kucheria <amit.kucheria@canonical.com>
+ * Copyright (C) 2010 Freescale Semiconductor, Inc.
  *
  * The code contained herein is licensed under the GNU General Public
  * License. You may obtain a copy of the GNU General Public License
  */
 
 #include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/gpio.h>
 #include <mach/hardware.h>
 #include <mach/imx-uart.h>
+#include <mach/irqs.h>
 
 static struct resource uart0[] = {
        {
@@ -89,8 +93,109 @@ struct platform_device mxc_fec_device = {
        .resource = mxc_fec_resources,
 };
 
-/* Dummy definition to allow compiling in AVIC and TZIC simultaneously */
+static u64 usb_dma_mask = DMA_BIT_MASK(32);
+
+static struct resource usbotg_resources[] = {
+       {
+               .start = MX51_OTG_BASE_ADDR,
+               .end = MX51_OTG_BASE_ADDR + 0x1ff,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = MX51_MXC_INT_USB_OTG,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+/* OTG gadget device */
+struct platform_device mxc_usbdr_udc_device = {
+       .name           = "fsl-usb2-udc",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(usbotg_resources),
+       .resource       = usbotg_resources,
+       .dev            = {
+               .dma_mask               = &usb_dma_mask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+       },
+};
+
+struct platform_device mxc_usbdr_host_device = {
+       .name = "mxc-ehci",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(usbotg_resources),
+       .resource = usbotg_resources,
+       .dev = {
+               .dma_mask = &usb_dma_mask,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
+       },
+};
+
+static struct resource usbh1_resources[] = {
+       {
+               .start = MX51_OTG_BASE_ADDR + 0x200,
+               .end = MX51_OTG_BASE_ADDR + 0x200 + 0x1ff,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = MX51_MXC_INT_USB_H1,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device mxc_usbh1_device = {
+       .name = "mxc-ehci",
+       .id = 1,
+       .num_resources = ARRAY_SIZE(usbh1_resources),
+       .resource = usbh1_resources,
+       .dev = {
+               .dma_mask = &usb_dma_mask,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
+       },
+};
+
+static struct resource mxc_wdt_resources[] = {
+       {
+               .start = MX51_WDOG_BASE_ADDR,
+               .end = MX51_WDOG_BASE_ADDR + SZ_16K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+};
+
+struct platform_device mxc_wdt = {
+       .name = "imx2-wdt",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(mxc_wdt_resources),
+       .resource = mxc_wdt_resources,
+};
+
+static struct mxc_gpio_port mxc_gpio_ports[] = {
+       {
+               .chip.label = "gpio-0",
+               .base = MX51_IO_ADDRESS(MX51_GPIO1_BASE_ADDR),
+               .irq = MX51_MXC_INT_GPIO1_LOW,
+               .virtual_irq_start = MXC_GPIO_IRQ_START
+       },
+       {
+               .chip.label = "gpio-1",
+               .base = MX51_IO_ADDRESS(MX51_GPIO2_BASE_ADDR),
+               .irq = MX51_MXC_INT_GPIO2_LOW,
+               .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 1
+       },
+       {
+               .chip.label = "gpio-2",
+               .base = MX51_IO_ADDRESS(MX51_GPIO3_BASE_ADDR),
+               .irq = MX51_MXC_INT_GPIO3_LOW,
+               .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 2
+       },
+       {
+               .chip.label = "gpio-3",
+               .base = MX51_IO_ADDRESS(MX51_GPIO4_BASE_ADDR),
+               .irq = MX51_MXC_INT_GPIO4_LOW,
+               .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 3
+       },
+};
+
 int __init mxc_register_gpios(void)
 {
-       return 0;
+       return mxc_gpio_init(mxc_gpio_ports, ARRAY_SIZE(mxc_gpio_ports));
 }
index f339ab8c19beca88c9ac93a9d441a4c83ca438bb..c879ae71cd5b03e2995b3cee1d45f550d857ca47 100644 (file)
@@ -2,3 +2,7 @@ extern struct platform_device mxc_uart_device0;
 extern struct platform_device mxc_uart_device1;
 extern struct platform_device mxc_uart_device2;
 extern struct platform_device mxc_fec_device;
+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;
index 60f5bee09f2e5beba127efc7a728768278dd71a3..2c471fc451d743a590bd22c9cbdd07a985191c1d 100644 (file)
@@ -56,6 +56,7 @@ static struct clk_lookup lookups[] = {
        CLK(&clk_default, "gpio.1"),
        CLK(&clk_default, "gpio.2"),
        CLK(&clk_default, "gpio.3"),
+       CLK(&clk_default, "rng"),
 };
 
 static int __init clk_init(void)
index e7d629b3c76aca4c20038863cc78cf3cf6a008aa..f474a80b886733582af7f3dba04929ce02cd561b 100644 (file)
@@ -137,9 +137,7 @@ static void ads7846_dev_init(void)
        }
 
        gpio_direction_input(ts_gpio);
-
-       omap_set_gpio_debounce(ts_gpio, 1);
-       omap_set_gpio_debounce_time(ts_gpio, 0xa);
+       gpio_set_debounce(ts_gpio, 310);
 }
 
 static int ads7846_get_pendown_state(void)
index 5fcb52e71298a8846f29734f3f96951546ff2d90..fefd7e6e97796a9ede0ce8076de96f9ee437fb9d 100644 (file)
@@ -209,8 +209,7 @@ static void ads7846_dev_init(void)
        }
 
        gpio_direction_input(ts_gpio);
-       omap_set_gpio_debounce(ts_gpio, 1);
-       omap_set_gpio_debounce_time(ts_gpio, 0xa);
+       gpio_set_debounce(ts_gpio, 310);
 }
 
 static int ads7846_get_pendown_state(void)
index 81bba194b030b46804f4e215a99a849a3ab03159..b952610138121862368aab2296ef30552bdc5528 100644 (file)
@@ -579,9 +579,7 @@ static void ads7846_dev_init(void)
                printk(KERN_ERR "can't get ads7846 pen down GPIO\n");
 
        gpio_direction_input(OMAP3_EVM_TS_GPIO);
-
-       omap_set_gpio_debounce(OMAP3_EVM_TS_GPIO, 1);
-       omap_set_gpio_debounce_time(OMAP3_EVM_TS_GPIO, 0xa);
+       gpio_set_debounce(OMAP3_EVM_TS_GPIO, 310);
 }
 
 static int ads7846_get_pendown_state(void)
index 395d049bf010ad8f67e050cd4877ab7c54f4399e..db06dc910ba755c6988cc11155c3f047dff3c792 100644 (file)
@@ -130,8 +130,8 @@ static struct platform_device pandora_keys_gpio = {
 static void __init pandora_keys_gpio_init(void)
 {
        /* set debounce time for GPIO banks 4 and 6 */
-       omap_set_gpio_debounce_time(32 * 3, GPIO_DEBOUNCE_TIME);
-       omap_set_gpio_debounce_time(32 * 5, GPIO_DEBOUNCE_TIME);
+       gpio_set_debounce(32 * 3, GPIO_DEBOUNCE_TIME);
+       gpio_set_debounce(32 * 5, GPIO_DEBOUNCE_TIME);
 }
 
 static int board_keymap[] = {
index 2504d41f923e01bcbf6dd82b92ceb03139c1c8bf..2f5f8233dd5b8857bcfddb29d178f802fbd1271f 100644 (file)
@@ -328,8 +328,7 @@ static void __init omap3_ads7846_init(void)
        }
 
        gpio_direction_input(OMAP3_TS_GPIO);
-       omap_set_gpio_debounce(OMAP3_TS_GPIO, 1);
-       omap_set_gpio_debounce_time(OMAP3_TS_GPIO, 0xa);
+       gpio_set_debounce(OMAP3_TS_GPIO, 310);
 }
 
 static struct ads7846_platform_data ads7846_config = {
index 685f34a9634bf262029cd8b9b69947db24065a74..fe0de1698edc95c9e4aedf78aac576d2fc9e69b8 100644 (file)
@@ -240,22 +240,23 @@ error_fail:
 
 #define ORION_BLINK_HALF_PERIOD 100 /* ms */
 
-static int dns323_gpio_blink_set(unsigned gpio,
+static int dns323_gpio_blink_set(unsigned gpio, int state,
        unsigned long *delay_on, unsigned long *delay_off)
 {
-       static int value = 0;
 
-       if (!*delay_on && !*delay_off)
+       if (delay_on && delay_off && !*delay_on && !*delay_off)
                *delay_on = *delay_off = ORION_BLINK_HALF_PERIOD;
 
-       if (ORION_BLINK_HALF_PERIOD == *delay_on
-           && ORION_BLINK_HALF_PERIOD == *delay_off) {
-               value = !value;
-               orion_gpio_set_blink(gpio, value);
-               return 0;
+       switch(state) {
+       case GPIO_LED_NO_BLINK_LOW:
+       case GPIO_LED_NO_BLINK_HIGH:
+               orion_gpio_set_blink(gpio, 0);
+               gpio_set_value(gpio, state);
+               break;
+       case GPIO_LED_BLINK:
+               orion_gpio_set_blink(gpio, 1);
        }
-
-       return -EINVAL;
+       return 0;
 }
 
 static struct gpio_led dns323_leds[] = {
@@ -263,6 +264,7 @@ static struct gpio_led dns323_leds[] = {
                .name = "power:blue",
                .gpio = DNS323_GPIO_LED_POWER2,
                .default_trigger = "timer",
+               .active_low = 1,
        }, {
                .name = "right:amber",
                .gpio = DNS323_GPIO_LED_RIGHT_AMBER,
index 091c98a639d9896f2234343c29fc713592026198..cd3983ad41604ee71234b2d14ce79e51563bad91 100644 (file)
 #define S3C_PA_USBHOST S3C2410_PA_USBHOST
 #define S3C_PA_HSMMC0      S3C2443_PA_HSMMC
 #define S3C_PA_HSMMC1      S3C2416_PA_HSMMC0
+#define S3C_PA_WDT         S3C2410_PA_WATCHDOG
 #define S3C_PA_NAND        S3C24XX_PA_NAND
 
 #endif /* __ASM_ARCH_MAP_H */
index 45799c608d8f0e822273f3796b1a8f6e2142aca2..9e39faa283b981bf72d93f9c45ea8c2fb7b754b8 100644 (file)
@@ -49,7 +49,6 @@
 #include <linux/io.h>
 
 #include <linux/i2c.h>
-#include <linux/backlight.h>
 #include <linux/regulator/machine.h>
 
 #include <linux/mfd/pcf50633/core.h>
@@ -57,6 +56,7 @@
 #include <linux/mfd/pcf50633/adc.h>
 #include <linux/mfd/pcf50633/gpio.h>
 #include <linux/mfd/pcf50633/pmic.h>
+#include <linux/mfd/pcf50633/backlight.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -254,6 +254,12 @@ static char *gta02_batteries[] = {
        "battery",
 };
 
+static struct pcf50633_bl_platform_data gta02_backlight_data = {
+       .default_brightness = 0x3f,
+       .default_brightness_limit = 0,
+       .ramp_time = 5,
+};
+
 struct pcf50633_platform_data gta02_pcf_pdata = {
        .resumers = {
                [0] =   PCF50633_INT1_USBINS |
@@ -271,6 +277,8 @@ struct pcf50633_platform_data gta02_pcf_pdata = {
 
        .charger_reference_current_ma = 1000,
 
+       .backlight_data = &gta02_backlight_data,
+
        .reg_init_data = {
                [PCF50633_REGULATOR_AUTO] = {
                        .constraints = {
@@ -478,71 +486,6 @@ static struct s3c2410_udc_mach_info gta02_udc_cfg = {
 
 };
 
-
-
-static void gta02_bl_set_intensity(int intensity)
-{
-       struct pcf50633 *pcf = gta02_pcf;
-       int old_intensity = pcf50633_reg_read(pcf, PCF50633_REG_LEDOUT);
-
-       /* We map 8-bit intensity to 6-bit intensity in hardware. */
-       intensity >>= 2;
-
-       /*
-        * This can happen during, eg, print of panic on blanked console,
-        * but we can't service i2c without interrupts active, so abort.
-        */
-       if (in_atomic()) {
-               printk(KERN_ERR "gta02_bl_set_intensity called while atomic\n");
-               return;
-       }
-
-       old_intensity = pcf50633_reg_read(pcf, PCF50633_REG_LEDOUT);
-       if (intensity == old_intensity)
-               return;
-
-       /* We can't do this anywhere else. */
-       pcf50633_reg_write(pcf, PCF50633_REG_LEDDIM, 5);
-
-       if (!(pcf50633_reg_read(pcf, PCF50633_REG_LEDENA) & 3))
-               old_intensity = 0;
-
-       /*
-        * The PCF50633 cannot handle LEDOUT = 0 (datasheet p60)
-        * if seen, you have to re-enable the LED unit.
-        */
-       if (!intensity || !old_intensity)
-               pcf50633_reg_write(pcf, PCF50633_REG_LEDENA, 0);
-
-       /* Illegal to set LEDOUT to 0. */
-       if (!intensity)
-               pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_LEDOUT, 0x3f, 2);
-       else
-               pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_LEDOUT, 0x3f,
-                                         intensity);
-
-       if (intensity)
-               pcf50633_reg_write(pcf, PCF50633_REG_LEDENA, 2);
-
-}
-
-static struct generic_bl_info gta02_bl_info = {
-       .name                   = "gta02-bl",
-       .max_intensity          = 0xff,
-       .default_intensity      = 0xff,
-       .set_bl_intensity       = gta02_bl_set_intensity,
-};
-
-static struct platform_device gta02_bl_dev = {
-       .name                   = "generic-bl",
-       .id                     = 1,
-       .dev = {
-               .platform_data = &gta02_bl_info,
-       },
-};
-
-
-
 /* USB */
 static struct s3c2410_hcd_info gta02_usb_info __initdata = {
        .port[0]        = {
@@ -579,7 +522,6 @@ static struct platform_device *gta02_devices[] __initdata = {
 /* These guys DO need to be children of PMU. */
 
 static struct platform_device *gta02_devices_pmu_children[] = {
-       &gta02_bl_dev,
 };
 
 
index 69e9fbfea9175a7e09b5e86c500a9e47ebd82d8c..f5a59727949fa33e96bceb3a376eb12fe637d42e 100644 (file)
@@ -7,6 +7,7 @@
 config PLAT_S3C64XX
        bool
        depends on ARCH_S3C64XX
+       select SAMSUNG_WAKEMASK
        default y
        help
          Base platform code for any Samsung S3C64XX device
@@ -35,6 +36,11 @@ config S3C64XX_SETUP_SDHCI
          Internal configuration for default SDHCI setup for S3C6400 and
          S3C6410 SoCs.
 
+config S3C64XX_DEV_ONENAND1
+       bool
+       help
+         Compile in platform device definition for OneNAND1 controller
+
 # platform specific device setup
 
 config S3C64XX_SETUP_I2C0
@@ -90,8 +96,11 @@ config MACH_SMDK6410
        select S3C_DEV_HSMMC1
        select S3C_DEV_I2C1
        select S3C_DEV_FB
+       select SAMSUNG_DEV_TS
        select S3C_DEV_USB_HOST
        select S3C_DEV_USB_HSOTG
+       select S3C_DEV_WDT
+       select HAVE_S3C2410_WATCHDOG
        select S3C64XX_SETUP_SDHCI
        select S3C64XX_SETUP_I2C1
        select S3C64XX_SETUP_FB_24BPP
@@ -179,3 +188,34 @@ config MACH_HMT
        select HAVE_PWM
        help
          Machine support for the Airgoo HMT
+
+config MACH_SMARTQ
+       bool
+       select CPU_S3C6410
+       select S3C_DEV_HSMMC
+       select S3C_DEV_HSMMC1
+       select S3C_DEV_HSMMC2
+       select S3C_DEV_FB
+       select S3C_DEV_HWMON
+       select S3C_DEV_RTC
+       select S3C_DEV_USB_HSOTG
+       select S3C_DEV_USB_HOST
+       select S3C64XX_SETUP_SDHCI
+       select S3C64XX_SETUP_FB_24BPP
+       select SAMSUNG_DEV_ADC
+       select SAMSUNG_DEV_TS
+       select HAVE_PWM
+       help
+           Shared machine support for SmartQ 5/7
+
+config MACH_SMARTQ5
+       bool "SmartQ 5"
+       select MACH_SMARTQ
+       help
+           Machine support for the SmartQ 5
+
+config MACH_SMARTQ7
+       bool "SmartQ 7"
+       select MACH_SMARTQ
+       help
+           Machine support for the SmartQ 7
index a10f1fc6b023441b5b7dd3960d7c45906117b773..9d1006938f5cc18dd604774dc11ea793aef4ccdf 100644 (file)
@@ -52,6 +52,9 @@ obj-$(CONFIG_MACH_SMDK6400)   += mach-smdk6400.o
 obj-$(CONFIG_MACH_SMDK6410)    += mach-smdk6410.o
 obj-$(CONFIG_MACH_NCP)         += mach-ncp.o
 obj-$(CONFIG_MACH_HMT)         += mach-hmt.o
+obj-$(CONFIG_MACH_SMARTQ)      += mach-smartq.o
+obj-$(CONFIG_MACH_SMARTQ5)     += mach-smartq5.o
+obj-$(CONFIG_MACH_SMARTQ7)     += mach-smartq7.o
 
 # device support
 
@@ -59,3 +62,4 @@ obj-y                         += dev-uart.o
 obj-y                          += dev-audio.o
 obj-$(CONFIG_S3C64XX_DEV_SPI)  += dev-spi.o
 obj-$(CONFIG_S3C64XX_DEV_TS)   += dev-ts.o
+obj-$(CONFIG_S3C64XX_DEV_ONENAND1)     += dev-onenand1.o
index 7a4138beb665a1391dd5fe6137da1f584fc31107..fbd85a9b7bbfa1ee279a502f8b3a6393ae8228c3 100644 (file)
@@ -258,6 +258,12 @@ static struct clk init_clocks[] = {
                .parent         = &clk_h,
                .enable         = s3c64xx_hclk_ctrl,
                .ctrlbit        = S3C_CLKCON_HCLK_HSMMC2,
+       }, {
+               .name           = "otg",
+               .id             = -1,
+               .parent         = &clk_h,
+               .enable         = s3c64xx_hclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_HCLK_USB,
        }, {
                .name           = "timers",
                .id             = -1,
diff --git a/arch/arm/mach-s3c64xx/dev-onenand1.c b/arch/arm/mach-s3c64xx/dev-onenand1.c
new file mode 100644 (file)
index 0000000..92ffd5b
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * linux/arch/arm/mach-s3c64xx/dev-onenand1.c
+ *
+ *  Copyright (c) 2008-2010 Samsung Electronics
+ *  Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * S3C64XX series device definition for OneNAND devices
+ *
+ * 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/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/onenand.h>
+
+#include <mach/irqs.h>
+#include <mach/map.h>
+
+static struct resource s3c64xx_onenand1_resources[] = {
+       [0] = {
+               .start  = S3C64XX_PA_ONENAND1,
+               .end    = S3C64XX_PA_ONENAND1 + 0x400 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = S3C64XX_PA_ONENAND1_BUF,
+               .end    = S3C64XX_PA_ONENAND1_BUF + S3C64XX_SZ_ONENAND1_BUF - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [2] = {
+               .start  = IRQ_ONENAND1,
+               .end    = IRQ_ONENAND1,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device s3c64xx_device_onenand1 = {
+       .name           = "samsung-onenand",
+       .id             = 1,
+       .num_resources  = ARRAY_SIZE(s3c64xx_onenand1_resources),
+       .resource       = s3c64xx_onenand1_resources,
+};
+
+void s3c64xx_onenand1_set_platdata(struct onenand_platform_data *pdata)
+{
+       struct onenand_platform_data *pd;
+
+       pd = kmemdup(pdata, sizeof(struct onenand_platform_data), GFP_KERNEL);
+       if (!pd)
+               printk(KERN_ERR "%s: no memory for platform data\n", __func__);
+       s3c64xx_device_onenand1.dev.platform_data = pd;
+}
index e9ab4ac0b9a822e9288fa193678c7219c711889e..8e2df26cf14a5dac4e643e9167163c671fcdae02 100644 (file)
 
 #define NR_IRQS        (IRQ_BOARD_END + 1)
 
+/* Compatibility */
+
+#define IRQ_ONENAND    IRQ_ONENAND0
+
 #endif /* __ASM_MACH_S3C64XX_IRQS_H */
 
index 9fdd50c8c767473fed80df430b89de0a38bf7ec3..e1eab3c94aea9b5110dc438b586bbe49e154f892 100644 (file)
 
 #define S3C64XX_PA_SROM                (0x70000000)
 
+#define S3C64XX_PA_ONENAND0    (0x70100000)
+#define S3C64XX_PA_ONENAND0_BUF        (0x20000000)
+#define S3C64XX_SZ_ONENAND0_BUF (SZ_64M)
+
+/* NAND and OneNAND1 controllers occupy the same register region
+   (depending on SoC POP version) */
+#define S3C64XX_PA_ONENAND1    (0x70200000)
+#define S3C64XX_PA_ONENAND1_BUF        (0x28000000)
+#define S3C64XX_SZ_ONENAND1_BUF        (SZ_64M)
+
 #define S3C64XX_PA_NAND                (0x70200000)
 #define S3C64XX_PA_FB          (0x77100000)
 #define S3C64XX_PA_USB_HSOTG   (0x7C000000)
 #define S3C_PA_IIC             S3C64XX_PA_IIC0
 #define S3C_PA_IIC1            S3C64XX_PA_IIC1
 #define S3C_PA_NAND            S3C64XX_PA_NAND
+#define S3C_PA_ONENAND         S3C64XX_PA_ONENAND0
+#define S3C_PA_ONENAND_BUF     S3C64XX_PA_ONENAND0_BUF
+#define S3C_SZ_ONENAND_BUF     S3C64XX_SZ_ONENAND0_BUF
 #define S3C_PA_FB              S3C64XX_PA_FB
 #define S3C_PA_USBHOST         S3C64XX_PA_USBHOST
 #define S3C_PA_USB_HSOTG       S3C64XX_PA_USB_HSOTG
 #define S3C_VA_USB_HSPHY       S3C64XX_VA_USB_HSPHY
 #define S3C_PA_RTC             S3C64XX_PA_RTC
+#define S3C_PA_WDT             S3C64XX_PA_WATCHDOG
 
 #define SAMSUNG_PA_ADC         S3C64XX_PA_ADC
 
diff --git a/arch/arm/mach-s3c64xx/mach-smartq.c b/arch/arm/mach-s3c64xx/mach-smartq.c
new file mode 100644 (file)
index 0000000..028d080
--- /dev/null
@@ -0,0 +1,363 @@
+/*
+ * linux/arch/arm/mach-s3c64xx/mach-smartq.c
+ *
+ * Copyright (C) 2010 Maurus Cuelenaere
+ *
+ * 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/delay.h>
+#include <linux/fb.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/pwm_backlight.h>
+#include <linux/serial_core.h>
+#include <linux/usb/gpio_vbus.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/map.h>
+
+#include <mach/map.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-modem.h>
+
+#include <plat/clock.h>
+#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/iic.h>
+#include <plat/gpio-cfg.h>
+#include <plat/hwmon.h>
+#include <plat/regs-serial.h>
+#include <plat/udc-hs.h>
+#include <plat/usb-control.h>
+#include <plat/sdhci.h>
+#include <plat/ts.h>
+
+#include <video/platform_lcd.h>
+
+#define UCON S3C2410_UCON_DEFAULT
+#define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE)
+#define UFCON (S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE)
+
+static struct s3c2410_uartcfg smartq_uartcfgs[] __initdata = {
+       [0] = {
+               .hwport      = 0,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       },
+       [1] = {
+               .hwport      = 1,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       },
+       [2] = {
+               .hwport      = 2,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       },
+};
+
+static void smartq_usb_host_powercontrol(int port, int to)
+{
+       pr_debug("%s(%d, %d)\n", __func__, port, to);
+
+       if (port == 0) {
+               gpio_set_value(S3C64XX_GPL(0), to);
+               gpio_set_value(S3C64XX_GPL(1), to);
+       }
+}
+
+static irqreturn_t smartq_usb_host_ocirq(int irq, void *pw)
+{
+       struct s3c2410_hcd_info *info = pw;
+
+       if (gpio_get_value(S3C64XX_GPL(10)) == 0) {
+               pr_debug("%s: over-current irq (oc detected)\n", __func__);
+               s3c2410_usb_report_oc(info, 3);
+       } else {
+               pr_debug("%s: over-current irq (oc cleared)\n", __func__);
+               s3c2410_usb_report_oc(info, 0);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static void smartq_usb_host_enableoc(struct s3c2410_hcd_info *info, int on)
+{
+       int ret;
+
+       /* This isn't present on a SmartQ 5 board */
+       if (machine_is_smartq5())
+               return;
+
+       if (on) {
+               ret = request_irq(gpio_to_irq(S3C64XX_GPL(10)),
+                                 smartq_usb_host_ocirq, IRQF_DISABLED |
+                                 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+                                 "USB host overcurrent", info);
+               if (ret != 0)
+                       pr_err("failed to request usb oc irq: %d\n", ret);
+       } else {
+               free_irq(gpio_to_irq(S3C64XX_GPL(10)), info);
+       }
+}
+
+static struct s3c2410_hcd_info smartq_usb_host_info = {
+       .port[0]        = {
+               .flags  = S3C_HCDFLG_USED
+       },
+       .port[1]        = {
+               .flags  = 0
+       },
+
+       .power_control  = smartq_usb_host_powercontrol,
+       .enable_oc      = smartq_usb_host_enableoc,
+};
+
+static struct gpio_vbus_mach_info smartq_usb_otg_vbus_pdata = {
+       .gpio_vbus              = S3C64XX_GPL(9),
+       .gpio_pullup            = -1,
+       .gpio_vbus_inverted     = true,
+};
+
+static struct platform_device smartq_usb_otg_vbus_dev = {
+       .name                   = "gpio-vbus",
+       .dev.platform_data      = &smartq_usb_otg_vbus_pdata,
+};
+
+static int __init smartq_bl_init(struct device *dev)
+{
+    s3c_gpio_cfgpin(S3C64XX_GPF(15), S3C_GPIO_SFN(2));
+
+    return 0;
+}
+
+static struct platform_pwm_backlight_data smartq_backlight_data = {
+       .pwm_id         = 1,
+       .max_brightness = 1000,
+       .dft_brightness = 600,
+       .pwm_period_ns  = 1000000000 / (1000 * 20),
+       .init           = smartq_bl_init,
+};
+
+static struct platform_device smartq_backlight_device = {
+       .name           = "pwm-backlight",
+       .dev            = {
+               .parent = &s3c_device_timer[1].dev,
+               .platform_data = &smartq_backlight_data,
+       },
+};
+
+static struct s3c2410_ts_mach_info smartq_touchscreen_pdata __initdata = {
+       .delay                  = 65535,
+       .presc                  = 99,
+       .oversampling_shift     = 4,
+};
+
+static struct s3c_sdhci_platdata smartq_internal_hsmmc_pdata = {
+       .max_width              = 4,
+       /*.broken_card_detection        = true,*/
+};
+
+static struct s3c_hwmon_pdata smartq_hwmon_pdata __initdata = {
+       /* Battery voltage (?-4.2V) */
+       .in[0] = &(struct s3c_hwmon_chcfg) {
+               .name           = "smartq:battery-voltage",
+               .mult           = 3300,
+               .div            = 2048,
+       },
+       /* Reference voltage (1.2V) */
+       .in[1] = &(struct s3c_hwmon_chcfg) {
+               .name           = "smartq:reference-voltage",
+               .mult           = 3300,
+               .div            = 4096,
+       },
+};
+
+static void smartq_lcd_power_set(struct plat_lcd_data *pd, unsigned int power)
+{
+       gpio_direction_output(S3C64XX_GPM(3), power);
+}
+
+static struct plat_lcd_data smartq_lcd_power_data = {
+       .set_power      = smartq_lcd_power_set,
+};
+
+static struct platform_device smartq_lcd_power_device = {
+       .name                   = "platform-lcd",
+       .dev.parent             = &s3c_device_fb.dev,
+       .dev.platform_data      = &smartq_lcd_power_data,
+};
+
+
+static struct platform_device *smartq_devices[] __initdata = {
+       &s3c_device_hsmmc1,     /* Init iNAND first, ... */
+       &s3c_device_hsmmc0,     /* ... then the external SD card */
+       &s3c_device_hsmmc2,
+       &s3c_device_adc,
+       &s3c_device_fb,
+       &s3c_device_hwmon,
+       &s3c_device_i2c0,
+       &s3c_device_ohci,
+       &s3c_device_rtc,
+       &s3c_device_timer[1],
+       &s3c_device_ts,
+       &s3c_device_usb_hsotg,
+       &smartq_backlight_device,
+       &smartq_lcd_power_device,
+       &smartq_usb_otg_vbus_dev,
+};
+
+static void __init smartq_lcd_mode_set(void)
+{
+       u32 tmp;
+
+       /* set the LCD type */
+       tmp = __raw_readl(S3C64XX_SPCON);
+       tmp &= ~S3C64XX_SPCON_LCD_SEL_MASK;
+       tmp |= S3C64XX_SPCON_LCD_SEL_RGB;
+       __raw_writel(tmp, S3C64XX_SPCON);
+
+       /* remove the LCD bypass */
+       tmp = __raw_readl(S3C64XX_MODEM_MIFPCON);
+       tmp &= ~MIFPCON_LCD_BYPASS;
+       __raw_writel(tmp, S3C64XX_MODEM_MIFPCON);
+}
+
+static void smartq_power_off(void)
+{
+       gpio_direction_output(S3C64XX_GPK(15), 1);
+}
+
+static int __init smartq_power_off_init(void)
+{
+       int ret;
+
+       ret = gpio_request(S3C64XX_GPK(15), "Power control");
+       if (ret < 0) {
+               pr_err("%s: failed to get GPK15\n", __func__);
+               return ret;
+       }
+
+       /* leave power on */
+       gpio_direction_output(S3C64XX_GPK(15), 0);
+
+
+       pm_power_off = smartq_power_off;
+
+       return ret;
+}
+
+static int __init smartq_usb_host_init(void)
+{
+       int ret;
+
+       ret = gpio_request(S3C64XX_GPL(0), "USB power control");
+       if (ret < 0) {
+               pr_err("%s: failed to get GPL0\n", __func__);
+               return ret;
+       }
+
+       ret = gpio_request(S3C64XX_GPL(1), "USB host power control");
+       if (ret < 0) {
+               pr_err("%s: failed to get GPL1\n", __func__);
+               goto err;
+       }
+
+       if (!machine_is_smartq5()) {
+               /* This isn't present on a SmartQ 5 board */
+               ret = gpio_request(S3C64XX_GPL(10), "USB host overcurrent");
+               if (ret < 0) {
+                       pr_err("%s: failed to get GPL10\n", __func__);
+                       goto err2;
+               }
+       }
+
+       /* turn power off */
+       gpio_direction_output(S3C64XX_GPL(0), 0);
+       gpio_direction_output(S3C64XX_GPL(1), 0);
+       if (!machine_is_smartq5())
+               gpio_direction_input(S3C64XX_GPL(10));
+
+       s3c_device_ohci.dev.platform_data = &smartq_usb_host_info;
+
+       return 0;
+
+err2:
+       gpio_free(S3C64XX_GPL(1));
+err:
+       gpio_free(S3C64XX_GPL(0));
+       return ret;
+}
+
+static int __init smartq_usb_otg_init(void)
+{
+       clk_xusbxti.rate = 12000000;
+
+       return 0;
+}
+
+static int __init smartq_wifi_init(void)
+{
+       int ret;
+
+       ret = gpio_request(S3C64XX_GPK(1), "wifi control");
+       if (ret < 0) {
+               pr_err("%s: failed to get GPK1\n", __func__);
+               return ret;
+       }
+
+       ret = gpio_request(S3C64XX_GPK(2), "wifi reset");
+       if (ret < 0) {
+               pr_err("%s: failed to get GPK2\n", __func__);
+               gpio_free(S3C64XX_GPK(1));
+               return ret;
+       }
+
+       /* turn power on */
+       gpio_direction_output(S3C64XX_GPK(1), 1);
+
+       /* reset device */
+       gpio_direction_output(S3C64XX_GPK(2), 0);
+       mdelay(100);
+       gpio_set_value(S3C64XX_GPK(2), 1);
+       gpio_direction_input(S3C64XX_GPK(2));
+
+       return 0;
+}
+
+static struct map_desc smartq_iodesc[] __initdata = {};
+void __init smartq_map_io(void)
+{
+       s3c64xx_init_io(smartq_iodesc, ARRAY_SIZE(smartq_iodesc));
+       s3c24xx_init_clocks(12000000);
+       s3c24xx_init_uarts(smartq_uartcfgs, ARRAY_SIZE(smartq_uartcfgs));
+
+       smartq_lcd_mode_set();
+}
+
+void __init smartq_machine_init(void)
+{
+       s3c_i2c0_set_platdata(NULL);
+       s3c_hwmon_set_platdata(&smartq_hwmon_pdata);
+       s3c_sdhci1_set_platdata(&smartq_internal_hsmmc_pdata);
+       s3c_sdhci2_set_platdata(&smartq_internal_hsmmc_pdata);
+       s3c24xx_ts_set_platdata(&smartq_touchscreen_pdata);
+
+       WARN_ON(smartq_power_off_init());
+       WARN_ON(smartq_usb_host_init());
+       WARN_ON(smartq_usb_otg_init());
+       WARN_ON(smartq_wifi_init());
+
+       platform_add_devices(smartq_devices, ARRAY_SIZE(smartq_devices));
+}
diff --git a/arch/arm/mach-s3c64xx/mach-smartq.h b/arch/arm/mach-s3c64xx/mach-smartq.h
new file mode 100644 (file)
index 0000000..8e8b693
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * linux/arch/arm/mach-s3c64xx/mach-smartq.h
+ *
+ * Copyright (C) 2010 Maurus Cuelenaere
+ *
+ * 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 __MACH_SMARTQ_H
+#define __MACH_SMARTQ_H __FILE__
+
+#include <linux/init.h>
+
+extern void __init smartq_map_io(void);
+extern void __init smartq_machine_init(void);
+
+#endif /* __MACH_SMARTQ_H */
diff --git a/arch/arm/mach-s3c64xx/mach-smartq5.c b/arch/arm/mach-s3c64xx/mach-smartq5.c
new file mode 100644 (file)
index 0000000..1d0326e
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * linux/arch/arm/mach-s3c64xx/mach-smartq5.c
+ *
+ * Copyright (C) 2010 Maurus Cuelenaere
+ *
+ * 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/fb.h>
+#include <linux/gpio.h>
+#include <linux/gpio_keys.h>
+#include <linux/i2c-gpio.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <mach/map.h>
+#include <mach/regs-fb.h>
+#include <mach/regs-gpio.h>
+#include <mach/s3c6410.h>
+
+#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/fb.h>
+#include <plat/gpio-cfg.h>
+
+#include "mach-smartq.h"
+
+static void __init smartq5_lcd_setup_gpio(void)
+{
+       gpio_request(S3C64XX_GPM(0), "LCD SCEN pin");
+       gpio_request(S3C64XX_GPM(1), "LCD SCL pin");
+       gpio_request(S3C64XX_GPM(2), "LCD SDA pin");
+       gpio_request(S3C64XX_GPM(3), "LCD power");
+
+       /* turn power off */
+       gpio_direction_output(S3C64XX_GPM(0), 1);
+       gpio_direction_input(S3C64XX_GPM(1));
+       gpio_direction_input(S3C64XX_GPM(2));
+       gpio_direction_output(S3C64XX_GPM(3), 0);
+}
+
+static struct i2c_gpio_platform_data smartq5_lcd_control = {
+       .sda_pin                = S3C64XX_GPM(2),
+       .scl_pin                = S3C64XX_GPM(1),
+};
+
+static struct platform_device smartq5_lcd_control_device = {
+       .name                   = "i2c-gpio",
+       .id                     = 1,
+       .dev.platform_data      = &smartq5_lcd_control,
+};
+
+static struct gpio_led smartq5_leds[] __initdata = {
+       {
+               .name                   = "smartq5:green",
+               .active_low             = 1,
+               .gpio                   = S3C64XX_GPN(8),
+       },
+       {
+               .name                   = "smartq5:red",
+               .active_low             = 1,
+               .gpio                   = S3C64XX_GPN(9),
+       },
+};
+
+static struct gpio_led_platform_data smartq5_led_data = {
+       .num_leds = ARRAY_SIZE(smartq5_leds),
+       .leds = smartq5_leds,
+};
+
+static struct platform_device smartq5_leds_device = {
+       .name                   = "leds-gpio",
+       .id                     = -1,
+       .dev.platform_data      = &smartq5_led_data,
+};
+
+/* Labels according to the SmartQ manual */
+static struct gpio_keys_button smartq5_buttons[] = {
+       {
+               .gpio                   = S3C64XX_GPL(14),
+               .code                   = KEY_POWER,
+               .desc                   = "Power",
+               .active_low             = 1,
+               .debounce_interval      = 5,
+               .type                   = EV_KEY,
+       },
+       {
+               .gpio                   = S3C64XX_GPN(2),
+               .code                   = KEY_KPMINUS,
+               .desc                   = "Minus",
+               .active_low             = 1,
+               .debounce_interval      = 5,
+               .type                   = EV_KEY,
+       },
+       {
+               .gpio                   = S3C64XX_GPN(12),
+               .code                   = KEY_KPPLUS,
+               .desc                   = "Plus",
+               .active_low             = 1,
+               .debounce_interval      = 5,
+               .type                   = EV_KEY,
+       },
+       {
+               .gpio                   = S3C64XX_GPN(15),
+               .code                   = KEY_ENTER,
+               .desc                   = "Move",
+               .active_low             = 1,
+               .debounce_interval      = 5,
+               .type                   = EV_KEY,
+       },
+};
+
+static struct gpio_keys_platform_data smartq5_buttons_data  = {
+       .buttons        = smartq5_buttons,
+       .nbuttons       = ARRAY_SIZE(smartq5_buttons),
+};
+
+static struct platform_device smartq5_buttons_device  = {
+       .name           = "gpio-keys",
+       .id             = 0,
+       .num_resources  = 0,
+       .dev            = {
+               .platform_data  = &smartq5_buttons_data,
+       }
+};
+
+static struct s3c_fb_pd_win smartq5_fb_win0 = {
+       .win_mode       = {
+               .pixclock       = 1000000000000ULL /
+                               ((40+1+216+800)*(10+1+35+480)*80),
+               .left_margin    = 40,
+               .right_margin   = 216,
+               .upper_margin   = 10,
+               .lower_margin   = 35,
+               .hsync_len      = 1,
+               .vsync_len      = 1,
+               .xres           = 800,
+               .yres           = 480,
+       },
+       .max_bpp        = 32,
+       .default_bpp    = 16,
+};
+
+static struct s3c_fb_platdata smartq5_lcd_pdata __initdata = {
+       .setup_gpio     = s3c64xx_fb_gpio_setup_24bpp,
+       .win[0]         = &smartq5_fb_win0,
+       .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
+       .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC |
+                         VIDCON1_INV_VDEN,
+};
+
+static struct platform_device *smartq5_devices[] __initdata = {
+       &smartq5_leds_device,
+       &smartq5_buttons_device,
+       &smartq5_lcd_control_device,
+};
+
+static void __init smartq5_machine_init(void)
+{
+       s3c_fb_set_platdata(&smartq5_lcd_pdata);
+
+       smartq_machine_init();
+       smartq5_lcd_setup_gpio();
+
+       platform_add_devices(smartq5_devices, ARRAY_SIZE(smartq5_devices));
+}
+
+MACHINE_START(SMARTQ5, "SmartQ 5")
+       /* Maintainer: Maurus Cuelenaere <mcuelenaere AT gmail DOT com> */
+       .phys_io        = S3C_PA_UART & 0xfff00000,
+       .io_pg_offst    = (((u32)S3C_VA_UART) >> 18) & 0xfffc,
+       .boot_params    = S3C64XX_PA_SDRAM + 0x100,
+       .init_irq       = s3c6410_init_irq,
+       .map_io         = smartq_map_io,
+       .init_machine   = smartq5_machine_init,
+       .timer          = &s3c24xx_timer,
+MACHINE_END
diff --git a/arch/arm/mach-s3c64xx/mach-smartq7.c b/arch/arm/mach-s3c64xx/mach-smartq7.c
new file mode 100644 (file)
index 0000000..e0bc78e
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * linux/arch/arm/mach-s3c64xx/mach-smartq7.c
+ *
+ * Copyright (C) 2010 Maurus Cuelenaere
+ *
+ * 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/fb.h>
+#include <linux/gpio.h>
+#include <linux/gpio_keys.h>
+#include <linux/i2c-gpio.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <mach/map.h>
+#include <mach/regs-fb.h>
+#include <mach/regs-gpio.h>
+#include <mach/s3c6410.h>
+
+#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/fb.h>
+#include <plat/gpio-cfg.h>
+
+#include "mach-smartq.h"
+
+static void __init smartq7_lcd_setup_gpio(void)
+{
+       gpio_request(S3C64XX_GPM(0), "LCD CSB pin");
+       gpio_request(S3C64XX_GPM(3), "LCD power");
+       gpio_request(S3C64XX_GPM(4), "LCD power status");
+
+       /* turn power off */
+       gpio_direction_output(S3C64XX_GPM(0), 1);
+       gpio_direction_output(S3C64XX_GPM(3), 0);
+       gpio_direction_input(S3C64XX_GPM(4));
+}
+
+static struct i2c_gpio_platform_data smartq7_lcd_control = {
+       .sda_pin                = S3C64XX_GPM(2),
+       .scl_pin                = S3C64XX_GPM(1),
+       .sda_is_open_drain      = 1,
+       .scl_is_open_drain      = 1,
+};
+
+static struct platform_device smartq7_lcd_control_device = {
+       .name                   = "i2c-gpio",
+       .id                     = 1,
+       .dev.platform_data      = &smartq7_lcd_control,
+};
+
+static struct gpio_led smartq7_leds[] __initdata = {
+       {
+               .name                   = "smartq7:red",
+               .active_low             = 1,
+               .gpio                   = S3C64XX_GPN(8),
+       },
+       {
+               .name                   = "smartq7:green",
+               .active_low             = 1,
+               .gpio                   = S3C64XX_GPN(9),
+       },
+};
+
+static struct gpio_led_platform_data smartq7_led_data = {
+       .num_leds = ARRAY_SIZE(smartq7_leds),
+       .leds = smartq7_leds,
+};
+
+static struct platform_device smartq7_leds_device = {
+       .name                   = "leds-gpio",
+       .id                     = -1,
+       .dev.platform_data      = &smartq7_led_data,
+};
+
+/* Labels according to the SmartQ manual */
+static struct gpio_keys_button smartq7_buttons[] = {
+       {
+               .gpio                   = S3C64XX_GPL(14),
+               .code                   = KEY_POWER,
+               .desc                   = "Power",
+               .active_low             = 1,
+               .debounce_interval      = 5,
+               .type                   = EV_KEY,
+       },
+       {
+               .gpio                   = S3C64XX_GPN(2),
+               .code                   = KEY_FN,
+               .desc                   = "Function",
+               .active_low             = 1,
+               .debounce_interval      = 5,
+               .type                   = EV_KEY,
+       },
+       {
+               .gpio                   = S3C64XX_GPN(3),
+               .code                   = KEY_KPMINUS,
+               .desc                   = "Minus",
+               .active_low             = 1,
+               .debounce_interval      = 5,
+               .type                   = EV_KEY,
+       },
+       {
+               .gpio                   = S3C64XX_GPN(4),
+               .code                   = KEY_KPPLUS,
+               .desc                   = "Plus",
+               .active_low             = 1,
+               .debounce_interval      = 5,
+               .type                   = EV_KEY,
+       },
+       {
+               .gpio                   = S3C64XX_GPN(12),
+               .code                   = KEY_ENTER,
+               .desc                   = "Enter",
+               .active_low             = 1,
+               .debounce_interval      = 5,
+               .type                   = EV_KEY,
+       },
+       {
+               .gpio                   = S3C64XX_GPN(15),
+               .code                   = KEY_ESC,
+               .desc                   = "Cancel",
+               .active_low             = 1,
+               .debounce_interval      = 5,
+               .type                   = EV_KEY,
+       },
+};
+
+static struct gpio_keys_platform_data smartq7_buttons_data  = {
+       .buttons        = smartq7_buttons,
+       .nbuttons       = ARRAY_SIZE(smartq7_buttons),
+};
+
+static struct platform_device smartq7_buttons_device  = {
+       .name           = "gpio-keys",
+       .id             = 0,
+       .num_resources  = 0,
+       .dev            = {
+               .platform_data  = &smartq7_buttons_data,
+       }
+};
+
+static struct s3c_fb_pd_win smartq7_fb_win0 = {
+       .win_mode       = {
+               .pixclock       = 1000000000000ULL /
+                               ((3+10+5+800)*(1+3+20+480)*80),
+               .left_margin    = 3,
+               .right_margin   = 5,
+               .upper_margin   = 1,
+               .lower_margin   = 20,
+               .hsync_len      = 10,
+               .vsync_len      = 3,
+               .xres           = 800,
+               .yres           = 480,
+       },
+       .max_bpp        = 32,
+       .default_bpp    = 16,
+};
+
+static struct s3c_fb_platdata smartq7_lcd_pdata __initdata = {
+       .setup_gpio     = s3c64xx_fb_gpio_setup_24bpp,
+       .win[0]         = &smartq7_fb_win0,
+       .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
+       .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC |
+                         VIDCON1_INV_VCLK,
+};
+
+static struct platform_device *smartq7_devices[] __initdata = {
+       &smartq7_leds_device,
+       &smartq7_buttons_device,
+       &smartq7_lcd_control_device,
+};
+
+static void __init smartq7_machine_init(void)
+{
+       s3c_fb_set_platdata(&smartq7_lcd_pdata);
+
+       smartq_machine_init();
+       smartq7_lcd_setup_gpio();
+
+       platform_add_devices(smartq7_devices, ARRAY_SIZE(smartq7_devices));
+}
+
+MACHINE_START(SMARTQ7, "SmartQ 7")
+       /* Maintainer: Maurus Cuelenaere <mcuelenaere AT gmail DOT com> */
+       .phys_io        = S3C_PA_UART & 0xfff00000,
+       .io_pg_offst    = (((u32)S3C_VA_UART) >> 18) & 0xfffc,
+       .boot_params    = S3C64XX_PA_SDRAM + 0x100,
+       .init_irq       = s3c6410_init_irq,
+       .map_io         = smartq_map_io,
+       .init_machine   = smartq7_machine_init,
+       .timer          = &s3c24xx_timer,
+MACHINE_END
index 9d51455feb31ac2d3383aff8af77cebd20b2743f..d9a03555f88bdfed473a2780774436eb7872e3e7 100644 (file)
@@ -64,6 +64,8 @@
 #include <plat/clock.h>
 #include <plat/devs.h>
 #include <plat/cpu.h>
+#include <plat/adc.h>
+#include <plat/ts.h>
 
 #define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
 #define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
@@ -262,6 +264,9 @@ static struct platform_device *smdk6410_devices[] __initdata = {
        &smdk6410_lcd_powerdev,
 
        &smdk6410_smsc911x,
+       &s3c_device_adc,
+       &s3c_device_ts,
+       &s3c_device_wdt,
 };
 
 #ifdef CONFIG_REGULATOR
@@ -596,6 +601,12 @@ static struct i2c_board_info i2c_devs1[] __initdata = {
        { I2C_BOARD_INFO("24c128", 0x57), },    /* Samsung S524AD0XD1 */
 };
 
+static struct s3c2410_ts_mach_info s3c_ts_platform __initdata = {
+       .delay                  = 10000,
+       .presc                  = 49,
+       .oversampling_shift     = 2,
+};
+
 static void __init smdk6410_map_io(void)
 {
        u32 tmp;
@@ -625,6 +636,8 @@ static void __init smdk6410_machine_init(void)
        s3c_i2c1_set_platdata(NULL);
        s3c_fb_set_platdata(&smdk6410_lcd_pdata);
 
+       s3c24xx_ts_set_platdata(&s3c_ts_platform);
+
        /* configure nCS1 width to 16 bits */
 
        cs1 = __raw_readl(S3C64XX_SROM_BW) &
index b8ac4597fad70c9e0f87023385f1ed53c0ea7ee7..79412f735a8da99aecd222574cd6cae0c9799f65 100644 (file)
 #include <linux/io.h>
 
 #include <mach/map.h>
+#include <mach/irqs.h>
 
 #include <plat/pm.h>
+#include <plat/wakeup-mask.h>
+
 #include <mach/regs-sys.h>
 #include <mach/regs-gpio.h>
 #include <mach/regs-clock.h>
@@ -153,8 +156,25 @@ static void s3c64xx_cpu_suspend(void)
        panic("sleep resumed to originator?");
 }
 
+/* mapping of interrupts to parts of the wakeup mask */
+static struct samsung_wakeup_mask wake_irqs[] = {
+       { .irq = IRQ_RTC_ALARM, .bit = S3C64XX_PWRCFG_RTC_ALARM_DISABLE, },
+       { .irq = IRQ_RTC_TIC,   .bit = S3C64XX_PWRCFG_RTC_TICK_DISABLE, },
+       { .irq = IRQ_PENDN,     .bit = S3C64XX_PWRCFG_TS_DISABLE, },
+       { .irq = IRQ_HSMMC0,    .bit = S3C64XX_PWRCFG_MMC0_DISABLE, },
+       { .irq = IRQ_HSMMC1,    .bit = S3C64XX_PWRCFG_MMC1_DISABLE, },
+       { .irq = IRQ_HSMMC2,    .bit = S3C64XX_PWRCFG_MMC2_DISABLE, },
+       { .irq = NO_WAKEUP_IRQ, .bit = S3C64XX_PWRCFG_BATF_DISABLE},
+       { .irq = NO_WAKEUP_IRQ, .bit = S3C64XX_PWRCFG_MSM_DISABLE },
+       { .irq = NO_WAKEUP_IRQ, .bit = S3C64XX_PWRCFG_HSI_DISABLE },
+       { .irq = NO_WAKEUP_IRQ, .bit = S3C64XX_PWRCFG_MSM_DISABLE },
+};
+
 static void s3c64xx_pm_prepare(void)
 {
+       samsung_sync_wakemask(S3C64XX_PWR_CFG,
+                             wake_irqs, ARRAY_SIZE(wake_irqs));
+
        /* store address of resume. */
        __raw_writel(virt_to_phys(s3c_cpu_resume), S3C64XX_INFORM0);
 
index 707e34e3afd1a7fc9cc5abd37fd4bba74330cbd2..5e93fe3f3f409a16f4232d8e0fb5326de99652c3 100644 (file)
@@ -37,6 +37,7 @@
 #include <plat/clock.h>
 #include <plat/sdhci.h>
 #include <plat/iic-core.h>
+#include <plat/onenand-core.h>
 #include <mach/s3c6400.h>
 
 void __init s3c6400_map_io(void)
@@ -51,6 +52,9 @@ void __init s3c6400_map_io(void)
        s3c_i2c0_setname("s3c2440-i2c");
 
        s3c_device_nand.name = "s3c6400-nand";
+
+       s3c_onenand_setname("s3c6400-onenand");
+       s3c64xx_onenand1_setname("s3c6400-onenand");
 }
 
 void __init s3c6400_init_clocks(int xtal)
index 3ab695c691eefe05018d91f934779e1fc01cd3f6..014401c39f36239f51105a13033fbf3f3c46a1e9 100644 (file)
@@ -39,6 +39,7 @@
 #include <plat/sdhci.h>
 #include <plat/iic-core.h>
 #include <plat/adc.h>
+#include <plat/onenand-core.h>
 #include <mach/s3c6400.h>
 #include <mach/s3c6410.h>
 
@@ -55,6 +56,8 @@ void __init s3c6410_map_io(void)
 
        s3c_device_adc.name     = "s3c64xx-adc";
        s3c_device_nand.name = "s3c6400-nand";
+       s3c_onenand_setname("s3c6410-onenand");
+       s3c64xx_onenand1_setname("s3c6410-onenand");
 }
 
 void __init s3c6410_init_clocks(int xtal)
index 77aeffd17330614e439524fd73d59fbfd7820996..f066fae07c5755ca232b0d878bc3feb66c5d8e7f 100644 (file)
@@ -16,6 +16,10 @@ config CPU_S5P6440
 config MACH_SMDK6440
        bool "SMDK6440"
        select CPU_S5P6440
+       select SAMSUNG_DEV_TS
+       select SAMSUNG_DEV_ADC
+       select S3C_DEV_WDT
+       select HAVE_S3C2410_WATCHDOG
        help
          Machine support for the Samsung SMDK6440
 
index 44facf43d59f998e40beb1143b68f084188c65c1..be3c53aab23fe93e4f3fb2f67292c1963793b5ed 100644 (file)
@@ -21,3 +21,4 @@ obj-$(CONFIG_MACH_SMDK6440)   += mach-smdk6440.o
 
 # device support
 obj-y                          += dev-audio.o
+obj-$(CONFIG_S3C64XX_DEV_SPI)  += dev-spi.o
index ca3b3206e6f86d999d789fc05947a44bd38be314..b2fe6a58155a66915dc745402f8221ebf3b7fd0f 100644 (file)
@@ -61,6 +61,7 @@ static void s5p6440_idle(void)
 void __init s5p6440_map_io(void)
 {
        /* initialize any device information early */
+       s3c_device_adc.name     = "s3c64xx-adc";
 }
 
 void __init s5p6440_init_clocks(int xtal)
diff --git a/arch/arm/mach-s5p6440/dev-spi.c b/arch/arm/mach-s5p6440/dev-spi.c
new file mode 100644 (file)
index 0000000..0a30280
--- /dev/null
@@ -0,0 +1,176 @@
+/* linux/arch/arm/mach-s5p6440/dev-spi.c
+ *
+ * Copyright (C) 2010 Samsung Electronics Co. Ltd.
+ *     Jaswinder Singh <jassi.brar@samsung.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/platform_device.h>
+#include <linux/dma-mapping.h>
+
+#include <mach/dma.h>
+#include <mach/map.h>
+#include <mach/irqs.h>
+#include <mach/gpio.h>
+#include <mach/spi-clocks.h>
+
+#include <plat/s3c64xx-spi.h>
+#include <plat/gpio-cfg.h>
+
+static char *spi_src_clks[] = {
+       [S5P6440_SPI_SRCCLK_PCLK] = "pclk",
+       [S5P6440_SPI_SRCCLK_SCLK] = "spi_epll",
+};
+
+/* SPI Controller platform_devices */
+
+/* Since we emulate multi-cs capability, we do not touch the CS.
+ * The emulated CS is toggled by board specific mechanism, as it can
+ * be either some immediate GPIO or some signal out of some other
+ * chip in between ... or some yet another way.
+ * We simply do not assume anything about CS.
+ */
+static int s5p6440_spi_cfg_gpio(struct platform_device *pdev)
+{
+       switch (pdev->id) {
+       case 0:
+               s3c_gpio_cfgpin(S5P6440_GPC(0), S3C_GPIO_SFN(2));
+               s3c_gpio_cfgpin(S5P6440_GPC(1), S3C_GPIO_SFN(2));
+               s3c_gpio_cfgpin(S5P6440_GPC(2), S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(S5P6440_GPC(0), S3C_GPIO_PULL_UP);
+               s3c_gpio_setpull(S5P6440_GPC(1), S3C_GPIO_PULL_UP);
+               s3c_gpio_setpull(S5P6440_GPC(2), S3C_GPIO_PULL_UP);
+               break;
+
+       case 1:
+               s3c_gpio_cfgpin(S5P6440_GPC(4), S3C_GPIO_SFN(2));
+               s3c_gpio_cfgpin(S5P6440_GPC(5), S3C_GPIO_SFN(2));
+               s3c_gpio_cfgpin(S5P6440_GPC(6), S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(S5P6440_GPC(4), S3C_GPIO_PULL_UP);
+               s3c_gpio_setpull(S5P6440_GPC(5), S3C_GPIO_PULL_UP);
+               s3c_gpio_setpull(S5P6440_GPC(6), S3C_GPIO_PULL_UP);
+               break;
+
+       default:
+               dev_err(&pdev->dev, "Invalid SPI Controller number!");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static struct resource s5p6440_spi0_resource[] = {
+       [0] = {
+               .start = S5P6440_PA_SPI0,
+               .end   = S5P6440_PA_SPI0 + 0x100 - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = DMACH_SPI0_TX,
+               .end   = DMACH_SPI0_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = DMACH_SPI0_RX,
+               .end   = DMACH_SPI0_RX,
+               .flags = IORESOURCE_DMA,
+       },
+       [3] = {
+               .start = IRQ_SPI0,
+               .end   = IRQ_SPI0,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct s3c64xx_spi_info s5p6440_spi0_pdata = {
+       .cfg_gpio = s5p6440_spi_cfg_gpio,
+       .fifo_lvl_mask = 0x1ff,
+       .rx_lvl_offset = 15,
+};
+
+static u64 spi_dmamask = DMA_BIT_MASK(32);
+
+struct platform_device s5p6440_device_spi0 = {
+       .name             = "s3c64xx-spi",
+       .id               = 0,
+       .num_resources    = ARRAY_SIZE(s5p6440_spi0_resource),
+       .resource         = s5p6440_spi0_resource,
+       .dev = {
+               .dma_mask               = &spi_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+               .platform_data = &s5p6440_spi0_pdata,
+       },
+};
+
+static struct resource s5p6440_spi1_resource[] = {
+       [0] = {
+               .start = S5P6440_PA_SPI1,
+               .end   = S5P6440_PA_SPI1 + 0x100 - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = DMACH_SPI1_TX,
+               .end   = DMACH_SPI1_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = DMACH_SPI1_RX,
+               .end   = DMACH_SPI1_RX,
+               .flags = IORESOURCE_DMA,
+       },
+       [3] = {
+               .start = IRQ_SPI1,
+               .end   = IRQ_SPI1,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct s3c64xx_spi_info s5p6440_spi1_pdata = {
+       .cfg_gpio = s5p6440_spi_cfg_gpio,
+       .fifo_lvl_mask = 0x7f,
+       .rx_lvl_offset = 15,
+};
+
+struct platform_device s5p6440_device_spi1 = {
+       .name             = "s3c64xx-spi",
+       .id               = 1,
+       .num_resources    = ARRAY_SIZE(s5p6440_spi1_resource),
+       .resource         = s5p6440_spi1_resource,
+       .dev = {
+               .dma_mask               = &spi_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+               .platform_data = &s5p6440_spi1_pdata,
+       },
+};
+
+void __init s5p6440_spi_set_info(int cntrlr, int src_clk_nr, int num_cs)
+{
+       struct s3c64xx_spi_info *pd;
+
+       /* Reject invalid configuration */
+       if (!num_cs || src_clk_nr < 0
+                       || src_clk_nr > S5P6440_SPI_SRCCLK_SCLK) {
+               printk(KERN_ERR "%s: Invalid SPI configuration\n", __func__);
+               return;
+       }
+
+       switch (cntrlr) {
+       case 0:
+               pd = &s5p6440_spi0_pdata;
+               break;
+       case 1:
+               pd = &s5p6440_spi1_pdata;
+               break;
+       default:
+               printk(KERN_ERR "%s: Invalid SPI controller(%d)\n",
+                                                       __func__, cntrlr);
+               return;
+       }
+
+       pd->num_cs = num_cs;
+       pd->src_clk_nr = src_clk_nr;
+       pd->src_clk_name = spi_src_clks[src_clk_nr];
+}
index 262dc75d5bea1fac922e8817fafbe2eb214bc10a..92efc05b1ba29490542305184c48a2e5e52339d1 100644 (file)
@@ -46,6 +46,7 @@ static int s5p6440_gpiolib_rbank_4bit2_input(struct gpio_chip *chip,
        void __iomem *base = ourchip->base;
        void __iomem *regcon = base;
        unsigned long con;
+       unsigned long flags;
 
        switch (offset) {
        case 6:
@@ -63,10 +64,14 @@ static int s5p6440_gpiolib_rbank_4bit2_input(struct gpio_chip *chip,
                break;
        }
 
+       s3c_gpio_lock(ourchip, flags);
+
        con = __raw_readl(regcon);
        con &= ~(0xf << con_4bit_shift(offset));
        __raw_writel(con, regcon);
 
+       s3c_gpio_unlock(ourchip, flags);
+
        return 0;
 }
 
@@ -78,6 +83,7 @@ static int s5p6440_gpiolib_rbank_4bit2_output(struct gpio_chip *chip,
        void __iomem *regcon = base;
        unsigned long con;
        unsigned long dat;
+       unsigned long flags;
        unsigned con_offset  = offset;
 
        switch (con_offset) {
@@ -96,6 +102,8 @@ static int s5p6440_gpiolib_rbank_4bit2_output(struct gpio_chip *chip,
                break;
        }
 
+       s3c_gpio_lock(ourchip, flags);
+
        con = __raw_readl(regcon);
        con &= ~(0xf << con_4bit_shift(con_offset));
        con |= 0x1 << con_4bit_shift(con_offset);
@@ -109,6 +117,8 @@ static int s5p6440_gpiolib_rbank_4bit2_output(struct gpio_chip *chip,
        __raw_writel(con, regcon);
        __raw_writel(dat, base + GPIODAT_OFF);
 
+       s3c_gpio_unlock(ourchip, flags);
+
        return 0;
 }
 
@@ -117,6 +127,7 @@ int s5p6440_gpio_setcfg_4bit_rbank(struct s3c_gpio_chip *chip,
 {
        void __iomem *reg = chip->base;
        unsigned int shift;
+       unsigned long flags;
        u32 con;
 
        switch (off) {
@@ -142,11 +153,15 @@ int s5p6440_gpio_setcfg_4bit_rbank(struct s3c_gpio_chip *chip,
                cfg <<= shift;
        }
 
+       s3c_gpio_lock(chip, flags);
+
        con = __raw_readl(reg);
        con &= ~(0xf << shift);
        con |= cfg;
        __raw_writel(con, reg);
 
+       s3c_gpio_unlock(chip, flags);
+
        return 0;
 }
 
index a4b9b40d18f249926811a84ff64294749def83d2..911854d9ad4247b7803f7218ae657f86d91ac08e 100644 (file)
 #define S5P_IRQ_EINT_BASE      (S5P_IRQ_VIC1(31) + 6)
 
 #define S5P_EINT(x)            ((x) + S5P_IRQ_EINT_BASE)
-#define IRQ_EINT(x)            S5P_EINT(x)
+
+#define S5P_EINT_BASE1         (S5P_IRQ_EINT_BASE)
+/*
+ * S5P6440 has 0-15 external interrupts in group 0. Only these can be used
+ * to wake up from sleep. If request is beyond this range, by mistake, a large
+ * return value for an irq number should be indication of something amiss.
+ */
+#define S5P_EINT_BASE2         (0xf0000000)
 
 /*
  * Next the external interrupt groups. These are similar to the IRQ_EINT(x)
index 72aedadd412cd405747725993054c554dff03fe8..44011b91fbd1fefa19674340eccbb04a46f2f24b 100644 (file)
@@ -54,6 +54,9 @@
 
 #define S5P6440_PA_IIC0                (0xEC104000)
 
+#define S5P6440_PA_SPI0                0xEC400000
+#define S5P6440_PA_SPI1                0xEC500000
+
 #define S5P6440_PA_HSOTG       (0xED100000)
 
 #define S5P6440_PA_HSMMC0      (0xED800000)
 /* PCM */
 #define S5P6440_PA_PCM         0xF2100000
 
+#define S5P6440_PA_ADC         (0xF3000000)
+
 /* compatibiltiy defines. */
 #define S3C_PA_UART            S5P6440_PA_UART
 #define S3C_PA_IIC             S5P6440_PA_IIC0
+#define S3C_PA_WDT             S5P6440_PA_WDT
+
+#define SAMSUNG_PA_ADC         S5P6440_PA_ADC
 
 #endif /* __ASM_ARCH_MAP_H */
diff --git a/arch/arm/mach-s5p6440/include/mach/spi-clocks.h b/arch/arm/mach-s5p6440/include/mach/spi-clocks.h
new file mode 100644 (file)
index 0000000..5fbca50
--- /dev/null
@@ -0,0 +1,17 @@
+/* linux/arch/arm/mach-s5p6440/include/mach/spi-clocks.h
+ *
+ * Copyright (C) 2010 Samsung Electronics Co. Ltd.
+ *     Jaswinder Singh <jassi.brar@samsung.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 __S5P6440_PLAT_SPI_CLKS_H
+#define __S5P6440_PLAT_SPI_CLKS_H __FILE__
+
+#define S5P6440_SPI_SRCCLK_PCLK                0
+#define S5P6440_SPI_SRCCLK_SCLK                1
+
+#endif /* __S5P6440_PLAT_SPI_CLKS_H */
index d7fede971ca6cc5c65abd2951020571803284730..8291fecc701ad94ef6a78e78488ad94410668b5e 100644 (file)
@@ -38,6 +38,8 @@
 #include <plat/devs.h>
 #include <plat/cpu.h>
 #include <plat/pll.h>
+#include <plat/adc.h>
+#include <plat/ts.h>
 
 #define S5P6440_UCON_DEFAULT    (S3C2410_UCON_TXILEVEL |       \
                                S3C2410_UCON_RXILEVEL |         \
@@ -85,6 +87,15 @@ static struct s3c2410_uartcfg smdk6440_uartcfgs[] __initdata = {
 
 static struct platform_device *smdk6440_devices[] __initdata = {
        &s5p6440_device_iis,
+       &s3c_device_adc,
+       &s3c_device_ts,
+       &s3c_device_wdt,
+};
+
+static struct s3c2410_ts_mach_info s3c_ts_platform __initdata = {
+       .delay                  = 10000,
+       .presc                  = 49,
+       .oversampling_shift     = 2,
 };
 
 static void __init smdk6440_map_io(void)
@@ -96,6 +107,8 @@ static void __init smdk6440_map_io(void)
 
 static void __init smdk6440_machine_init(void)
 {
+       s3c24xx_ts_set_platdata(&s3c_ts_platform);
+
        platform_add_devices(smdk6440_devices, ARRAY_SIZE(smdk6440_devices));
 }
 
index e30a7f76aee6a5c77a9f74e815681b9592f18dce..90a3d8373416922726234f4fb675ed60d592c8a2 100644 (file)
@@ -21,3 +21,4 @@ obj-$(CONFIG_MACH_SMDK6442)   += mach-smdk6442.o
 
 # device support
 obj-y                          += dev-audio.o
+obj-$(CONFIG_S3C64XX_DEV_SPI)  += dev-spi.o
diff --git a/arch/arm/mach-s5p6442/dev-spi.c b/arch/arm/mach-s5p6442/dev-spi.c
new file mode 100644 (file)
index 0000000..3019952
--- /dev/null
@@ -0,0 +1,123 @@
+/* linux/arch/arm/mach-s5p6442/dev-spi.c
+ *
+ * Copyright (C) 2010 Samsung Electronics Co. Ltd.
+ *     Jaswinder Singh <jassi.brar@samsung.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/platform_device.h>
+#include <linux/dma-mapping.h>
+
+#include <mach/dma.h>
+#include <mach/map.h>
+#include <mach/irqs.h>
+#include <mach/gpio.h>
+#include <mach/spi-clocks.h>
+
+#include <plat/s3c64xx-spi.h>
+#include <plat/gpio-cfg.h>
+
+static char *spi_src_clks[] = {
+       [S5P6442_SPI_SRCCLK_PCLK] = "pclk",
+       [S5P6442_SPI_SRCCLK_SCLK] = "spi_epll",
+};
+
+/* SPI Controller platform_devices */
+
+/* Since we emulate multi-cs capability, we do not touch the CS.
+ * The emulated CS is toggled by board specific mechanism, as it can
+ * be either some immediate GPIO or some signal out of some other
+ * chip in between ... or some yet another way.
+ * We simply do not assume anything about CS.
+ */
+static int s5p6442_spi_cfg_gpio(struct platform_device *pdev)
+{
+       switch (pdev->id) {
+       case 0:
+               s3c_gpio_cfgpin(S5P6442_GPB(0), S3C_GPIO_SFN(2));
+               s3c_gpio_cfgpin(S5P6442_GPB(2), S3C_GPIO_SFN(2));
+               s3c_gpio_cfgpin(S5P6442_GPB(3), S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(S5P6442_GPB(0), S3C_GPIO_PULL_UP);
+               s3c_gpio_setpull(S5P6442_GPB(2), S3C_GPIO_PULL_UP);
+               s3c_gpio_setpull(S5P6442_GPB(3), S3C_GPIO_PULL_UP);
+               break;
+
+       default:
+               dev_err(&pdev->dev, "Invalid SPI Controller number!");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static struct resource s5p6442_spi0_resource[] = {
+       [0] = {
+               .start = S5P6442_PA_SPI,
+               .end   = S5P6442_PA_SPI + 0x100 - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = DMACH_SPI0_TX,
+               .end   = DMACH_SPI0_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = DMACH_SPI0_RX,
+               .end   = DMACH_SPI0_RX,
+               .flags = IORESOURCE_DMA,
+       },
+       [3] = {
+               .start = IRQ_SPI0,
+               .end   = IRQ_SPI0,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct s3c64xx_spi_info s5p6442_spi0_pdata = {
+       .cfg_gpio = s5p6442_spi_cfg_gpio,
+       .fifo_lvl_mask = 0x1ff,
+       .rx_lvl_offset = 15,
+};
+
+static u64 spi_dmamask = DMA_BIT_MASK(32);
+
+struct platform_device s5p6442_device_spi = {
+       .name             = "s3c64xx-spi",
+       .id               = 0,
+       .num_resources    = ARRAY_SIZE(s5p6442_spi0_resource),
+       .resource         = s5p6442_spi0_resource,
+       .dev = {
+               .dma_mask               = &spi_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+               .platform_data = &s5p6442_spi0_pdata,
+       },
+};
+
+void __init s5p6442_spi_set_info(int cntrlr, int src_clk_nr, int num_cs)
+{
+       struct s3c64xx_spi_info *pd;
+
+       /* Reject invalid configuration */
+       if (!num_cs || src_clk_nr < 0
+                       || src_clk_nr > S5P6442_SPI_SRCCLK_SCLK) {
+               printk(KERN_ERR "%s: Invalid SPI configuration\n", __func__);
+               return;
+       }
+
+       switch (cntrlr) {
+       case 0:
+               pd = &s5p6442_spi0_pdata;
+               break;
+       default:
+               printk(KERN_ERR "%s: Invalid SPI controller(%d)\n",
+                                                       __func__, cntrlr);
+               return;
+       }
+
+       pd->num_cs = num_cs;
+       pd->src_clk_nr = src_clk_nr;
+       pd->src_clk_name = spi_src_clks[src_clk_nr];
+}
index da665809f6e44e61d9d48e6af9c73fcdc99c8d0d..02c23749c0230414659e0e2825fa7d9f209dea50 100644 (file)
@@ -77,8 +77,9 @@
 
 #define S5P_IRQ_EINT_BASE      (IRQ_VIC_END + 1)
 
-#define IRQ_EINT(x)             ((x) < 16 ? S5P_IRQ_VIC0(x) : \
-                                       (S5P_IRQ_EINT_BASE + (x)-16))
+#define S5P_EINT_BASE1         (S5P_IRQ_VIC0(0))
+#define S5P_EINT_BASE2         (S5P_IRQ_EINT_BASE)
+
 /* Set the default NR_IRQS */
 
 #define NR_IRQS                (IRQ_EINT(31) + 1)
index 7568dc0d6be07722aee678620352708e970a42bd..32ca424ef7f9db57bb42005b5a4de26a781fcd59 100644 (file)
@@ -54,6 +54,8 @@
 #define S5P6442_PA_SDRAM       (0x20000000)
 #define S5P_PA_SDRAM           S5P6442_PA_SDRAM
 
+#define S5P6442_PA_SPI         0xEC300000
+
 /* I2S */
 #define S5P6442_PA_I2S0                0xC0B00000
 #define S5P6442_PA_I2S1                0xF2200000
diff --git a/arch/arm/mach-s5p6442/include/mach/spi-clocks.h b/arch/arm/mach-s5p6442/include/mach/spi-clocks.h
new file mode 100644 (file)
index 0000000..7fd8820
--- /dev/null
@@ -0,0 +1,17 @@
+/* linux/arch/arm/mach-s5p6442/include/mach/spi-clocks.h
+ *
+ * Copyright (C) 2010 Samsung Electronics Co. Ltd.
+ *     Jaswinder Singh <jassi.brar@samsung.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 __S5P6442_PLAT_SPI_CLKS_H
+#define __S5P6442_PLAT_SPI_CLKS_H __FILE__
+
+#define S5P6442_SPI_SRCCLK_PCLK                0
+#define S5P6442_SPI_SRCCLK_SCLK                1
+
+#endif /* __S5P6442_PLAT_SPI_CLKS_H */
index 8593337784e16756d2c0545996b28c01b8d2b559..b2a11dfa3399f040ef7458b336a48113fff7dc35 100644 (file)
@@ -5,10 +5,13 @@
 
 # Configuration options for the S5PC100 CPU
 
+if ARCH_S5PC100
+
 config CPU_S5PC100
        bool
-       select CPU_S5PC100_INIT
-       select CPU_S5PC100_CLOCK
+       select PLAT_S5P
+       select S5P_EXT_INT
+       select S3C_PL330_DMA
        help
          Enable S5PC100 CPU support
 
@@ -17,17 +20,22 @@ config S5PC100_SETUP_FB_24BPP
        help
          Common setup code for S5PC1XX with an 24bpp RGB display helper.
 
-config S5PC100_SETUP_SDHCI
-        bool
-        select S5PC1XX_SETUP_SDHCI_GPIO
-        help
-          Internal helper functions for S5PC100 based SDHCI systems
-
 config S5PC100_SETUP_I2C1
        bool
        help
          Common setup code for i2c bus 1.
 
+config S5PC100_SETUP_SDHCI
+       bool
+       select S5PC100_SETUP_SDHCI_GPIO
+       help
+         Internal helper functions for S5PC100 based SDHCI systems
+
+config S5PC100_SETUP_SDHCI_GPIO
+       bool
+       help
+         Common setup code for SDHCI gpio.
+
 config MACH_SMDKC100
        bool "SMDKC100"
        select CPU_S5PC100
@@ -41,3 +49,5 @@ config MACH_SMDKC100
        select S5PC100_SETUP_SDHCI
        help
          Machine support for the Samsung SMDKC100
+
+endif
index 373bc546eae8bb87c36b8ad4f854b39966f164f2..543f3de5131e272f52efaad4e0c78165519b1031 100644 (file)
@@ -11,14 +11,24 @@ obj-                                :=
 
 # Core support for S5PC100 system
 
-obj-$(CONFIG_CPU_S5PC100)      += cpu.o gpiolib.o
+obj-$(CONFIG_CPU_S5PC100)      += cpu.o init.o clock.o gpiolib.o irq-gpio.o
 obj-$(CONFIG_CPU_S5PC100)      += setup-i2c0.o
+obj-$(CONFIG_CPU_S5PC100)      += dma.o
 
 # Helper and device support
 
 obj-$(CONFIG_S5PC100_SETUP_FB_24BPP)   += setup-fb-24bpp.o
 obj-$(CONFIG_S5PC100_SETUP_I2C1)       += setup-i2c1.o
-obj-$(CONFIG_S5PC100_SETUP_SDHCI)       += setup-sdhci.o
+obj-$(CONFIG_S5PC100_SETUP_SDHCI)      += setup-sdhci.o
+obj-$(CONFIG_S5PC100_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o
+
+# device support
+obj-y                          += dev-audio.o
+obj-$(CONFIG_S3C64XX_DEV_SPI)  += dev-spi.o
 
 # machine support
+
 obj-$(CONFIG_MACH_SMDKC100)    += mach-smdkc100.o
+
+# device support
+obj-y                          += dev-audio.o
index d79e7574a8524c8bb4fa22124c552f0b6fcb0729..7b5bdbc9a5df32a1e182cf6864af2bf8620676e3 100644 (file)
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
 
-#include <asm/proc-fns.h>
-
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
+#include <asm/proc-fns.h>
+
 #include <mach/hardware.h>
 #include <mach/map.h>
 #include <asm/irq.h>
 
-#include <plat/cpu-freq.h>
 #include <plat/regs-serial.h>
-#include <plat/regs-power.h>
+#include <mach/regs-clock.h>
 
 #include <plat/cpu.h>
 #include <plat/devs.h>
 #include <plat/clock.h>
-#include <plat/sdhci.h>
 #include <plat/iic-core.h>
+#include <plat/sdhci.h>
+#include <plat/onenand-core.h>
+
 #include <plat/s5pc100.h>
 
 /* Initial IO mappings */
 
 static struct map_desc s5pc100_iodesc[] __initdata = {
+       {
+               .virtual        = (unsigned long)S5P_VA_SYSTIMER,
+               .pfn            = __phys_to_pfn(S5PC100_PA_SYSTIMER),
+               .length         = SZ_16K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)VA_VIC2,
+               .pfn            = __phys_to_pfn(S5P_PA_VIC2),
+               .length         = SZ_16K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)S5PC100_VA_OTHERS,
+               .pfn            = __phys_to_pfn(S5PC100_PA_OTHERS),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       }
 };
 
 static void s5pc100_idle(void)
 {
-       unsigned long tmp;
-
-       tmp = __raw_readl(S5PC100_PWR_CFG);
-       tmp &= ~S5PC100_PWRCFG_CFG_DEEP_IDLE;
-       tmp &= ~S5PC100_PWRCFG_CFG_WFI_MASK;
-       tmp |= S5PC100_PWRCFG_CFG_WFI_DEEP_IDLE;
-       __raw_writel(tmp, S5PC100_PWR_CFG);
-
-       tmp = __raw_readl(S5PC100_OTHERS);
-       tmp |= S5PC100_PMU_INT_DISABLE;
-       __raw_writel(tmp, S5PC100_OTHERS);
+       if (!need_resched())
+               cpu_do_idle();
 
-       cpu_do_idle();
+       local_irq_enable();
 }
 
 /* s5pc100_map_io
@@ -82,26 +90,29 @@ void __init s5pc100_map_io(void)
        /* the i2c devices are directly compatible with s3c2440 */
        s3c_i2c0_setname("s3c2440-i2c");
        s3c_i2c1_setname("s3c2440-i2c");
+
+       s3c_onenand_setname("s5pc100-onenand");
 }
 
 void __init s5pc100_init_clocks(int xtal)
 {
-       printk(KERN_DEBUG "%s: initialising clocks\n", __func__);
+       printk(KERN_DEBUG "%s: initializing clocks\n", __func__);
+
        s3c24xx_register_baseclocks(xtal);
-       s5pc1xx_register_clocks();
+       s5p_register_clocks(xtal);
        s5pc100_register_clocks();
        s5pc100_setup_clocks();
 }
 
 void __init s5pc100_init_irq(void)
 {
-       u32 vic_valid[] = {~0, ~0, ~0};
+       u32 vic[] = {~0, ~0, ~0};
 
        /* VIC0, VIC1, and VIC2 are fully populated. */
-       s5pc1xx_init_irq(vic_valid, ARRAY_SIZE(vic_valid));
+       s5p_init_irq(vic, ARRAY_SIZE(vic));
 }
 
-struct sysdev_class s5pc100_sysclass = {
+static struct sysdev_class s5pc100_sysclass = {
        .name   = "s5pc100-core",
 };
 
@@ -118,9 +129,10 @@ core_initcall(s5pc100_core_init);
 
 int __init s5pc100_init(void)
 {
-       printk(KERN_DEBUG "S5PC100: Initialising architecture\n");
+       printk(KERN_INFO "S5PC100: Initializing architecture\n");
 
-       s5pc1xx_idle = s5pc100_idle;
+       /* set idle function */
+       pm_idle = s5pc100_idle;
 
        return sysdev_register(&s5pc100_sysdev);
 }
diff --git a/arch/arm/mach-s5pc100/dev-audio.c b/arch/arm/mach-s5pc100/dev-audio.c
new file mode 100644 (file)
index 0000000..18cfe9a
--- /dev/null
@@ -0,0 +1,287 @@
+/* linux/arch/arm/mach-s5pc100/dev-audio.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd
+ *     Jaswinder Singh <jassi.brar@samsung.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/platform_device.h>
+#include <linux/dma-mapping.h>
+
+#include <plat/gpio-cfg.h>
+#include <plat/audio.h>
+
+#include <mach/gpio.h>
+#include <mach/map.h>
+#include <mach/dma.h>
+#include <mach/irqs.h>
+
+static int s5pc100_cfg_i2s(struct platform_device *pdev)
+{
+       /* configure GPIO for i2s port */
+       switch (pdev->id) {
+       case 1:
+               s3c_gpio_cfgpin(S5PC100_GPC(0), S3C_GPIO_SFN(2));
+               s3c_gpio_cfgpin(S5PC100_GPC(1), S3C_GPIO_SFN(2));
+               s3c_gpio_cfgpin(S5PC100_GPC(2), S3C_GPIO_SFN(2));
+               s3c_gpio_cfgpin(S5PC100_GPC(3), S3C_GPIO_SFN(2));
+               s3c_gpio_cfgpin(S5PC100_GPC(4), S3C_GPIO_SFN(2));
+               break;
+
+       case 2:
+               s3c_gpio_cfgpin(S5PC100_GPG3(0), S3C_GPIO_SFN(4));
+               s3c_gpio_cfgpin(S5PC100_GPG3(1), S3C_GPIO_SFN(4));
+               s3c_gpio_cfgpin(S5PC100_GPG3(2), S3C_GPIO_SFN(4));
+               s3c_gpio_cfgpin(S5PC100_GPG3(3), S3C_GPIO_SFN(4));
+               s3c_gpio_cfgpin(S5PC100_GPG3(4), S3C_GPIO_SFN(4));
+               break;
+
+       case -1: /* Dedicated pins */
+               break;
+
+       default:
+               printk(KERN_ERR "Invalid Device %d\n", pdev->id);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static struct s3c_audio_pdata s3c_i2s_pdata = {
+       .cfg_gpio = s5pc100_cfg_i2s,
+};
+
+static struct resource s5pc100_iis0_resource[] = {
+       [0] = {
+               .start = S5PC100_PA_I2S0,
+               .end   = S5PC100_PA_I2S0 + 0x100 - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = DMACH_I2S0_TX,
+               .end   = DMACH_I2S0_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = DMACH_I2S0_RX,
+               .end   = DMACH_I2S0_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+struct platform_device s5pc100_device_iis0 = {
+       .name             = "s3c64xx-iis-v4",
+       .id               = -1,
+       .num_resources    = ARRAY_SIZE(s5pc100_iis0_resource),
+       .resource         = s5pc100_iis0_resource,
+       .dev = {
+               .platform_data = &s3c_i2s_pdata,
+       },
+};
+
+static struct resource s5pc100_iis1_resource[] = {
+       [0] = {
+               .start = S5PC100_PA_I2S1,
+               .end   = S5PC100_PA_I2S1 + 0x100 - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = DMACH_I2S1_TX,
+               .end   = DMACH_I2S1_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = DMACH_I2S1_RX,
+               .end   = DMACH_I2S1_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+struct platform_device s5pc100_device_iis1 = {
+       .name             = "s3c64xx-iis",
+       .id               = 1,
+       .num_resources    = ARRAY_SIZE(s5pc100_iis1_resource),
+       .resource         = s5pc100_iis1_resource,
+       .dev = {
+               .platform_data = &s3c_i2s_pdata,
+       },
+};
+
+static struct resource s5pc100_iis2_resource[] = {
+       [0] = {
+               .start = S5PC100_PA_I2S2,
+               .end   = S5PC100_PA_I2S2 + 0x100 - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = DMACH_I2S2_TX,
+               .end   = DMACH_I2S2_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = DMACH_I2S2_RX,
+               .end   = DMACH_I2S2_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+struct platform_device s5pc100_device_iis2 = {
+       .name             = "s3c64xx-iis",
+       .id               = 2,
+       .num_resources    = ARRAY_SIZE(s5pc100_iis2_resource),
+       .resource         = s5pc100_iis2_resource,
+       .dev = {
+               .platform_data = &s3c_i2s_pdata,
+       },
+};
+
+/* PCM Controller platform_devices */
+
+static int s5pc100_pcm_cfg_gpio(struct platform_device *pdev)
+{
+       switch (pdev->id) {
+       case 0:
+               s3c_gpio_cfgpin(S5PC100_GPG3(0), S3C_GPIO_SFN(5));
+               s3c_gpio_cfgpin(S5PC100_GPG3(1), S3C_GPIO_SFN(5));
+               s3c_gpio_cfgpin(S5PC100_GPG3(2), S3C_GPIO_SFN(5));
+               s3c_gpio_cfgpin(S5PC100_GPG3(3), S3C_GPIO_SFN(5));
+               s3c_gpio_cfgpin(S5PC100_GPG3(4), S3C_GPIO_SFN(5));
+               break;
+
+       case 1:
+               s3c_gpio_cfgpin(S5PC100_GPC(0), S3C_GPIO_SFN(3));
+               s3c_gpio_cfgpin(S5PC100_GPC(1), S3C_GPIO_SFN(3));
+               s3c_gpio_cfgpin(S5PC100_GPC(2), S3C_GPIO_SFN(3));
+               s3c_gpio_cfgpin(S5PC100_GPC(3), S3C_GPIO_SFN(3));
+               s3c_gpio_cfgpin(S5PC100_GPC(4), S3C_GPIO_SFN(3));
+               break;
+
+       default:
+               printk(KERN_DEBUG "Invalid PCM Controller number!");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static struct s3c_audio_pdata s3c_pcm_pdata = {
+       .cfg_gpio = s5pc100_pcm_cfg_gpio,
+};
+
+static struct resource s5pc100_pcm0_resource[] = {
+       [0] = {
+               .start = S5PC100_PA_PCM0,
+               .end   = S5PC100_PA_PCM0 + 0x100 - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = DMACH_PCM0_TX,
+               .end   = DMACH_PCM0_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = DMACH_PCM0_RX,
+               .end   = DMACH_PCM0_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+struct platform_device s5pc100_device_pcm0 = {
+       .name             = "samsung-pcm",
+       .id               = 0,
+       .num_resources    = ARRAY_SIZE(s5pc100_pcm0_resource),
+       .resource         = s5pc100_pcm0_resource,
+       .dev = {
+               .platform_data = &s3c_pcm_pdata,
+       },
+};
+
+static struct resource s5pc100_pcm1_resource[] = {
+       [0] = {
+               .start = S5PC100_PA_PCM1,
+               .end   = S5PC100_PA_PCM1 + 0x100 - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = DMACH_PCM1_TX,
+               .end   = DMACH_PCM1_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = DMACH_PCM1_RX,
+               .end   = DMACH_PCM1_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+struct platform_device s5pc100_device_pcm1 = {
+       .name             = "samsung-pcm",
+       .id               = 1,
+       .num_resources    = ARRAY_SIZE(s5pc100_pcm1_resource),
+       .resource         = s5pc100_pcm1_resource,
+       .dev = {
+               .platform_data = &s3c_pcm_pdata,
+       },
+};
+
+/* AC97 Controller platform devices */
+
+static int s5pc100_ac97_cfg_gpio(struct platform_device *pdev)
+{
+       s3c_gpio_cfgpin(S5PC100_GPC(0), S3C_GPIO_SFN(4));
+       s3c_gpio_cfgpin(S5PC100_GPC(1), S3C_GPIO_SFN(4));
+       s3c_gpio_cfgpin(S5PC100_GPC(2), S3C_GPIO_SFN(4));
+       s3c_gpio_cfgpin(S5PC100_GPC(3), S3C_GPIO_SFN(4));
+       s3c_gpio_cfgpin(S5PC100_GPC(4), S3C_GPIO_SFN(4));
+
+       return 0;
+}
+
+static struct resource s5pc100_ac97_resource[] = {
+       [0] = {
+               .start = S5PC100_PA_AC97,
+               .end   = S5PC100_PA_AC97 + 0x100 - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = DMACH_AC97_PCMOUT,
+               .end   = DMACH_AC97_PCMOUT,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = DMACH_AC97_PCMIN,
+               .end   = DMACH_AC97_PCMIN,
+               .flags = IORESOURCE_DMA,
+       },
+       [3] = {
+               .start = DMACH_AC97_MICIN,
+               .end   = DMACH_AC97_MICIN,
+               .flags = IORESOURCE_DMA,
+       },
+       [4] = {
+               .start = IRQ_AC97,
+               .end   = IRQ_AC97,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct s3c_audio_pdata s3c_ac97_pdata = {
+       .cfg_gpio = s5pc100_ac97_cfg_gpio,
+};
+
+static u64 s5pc100_ac97_dmamask = DMA_BIT_MASK(32);
+
+struct platform_device s5pc100_device_ac97 = {
+       .name             = "s3c-ac97",
+       .id               = -1,
+       .num_resources    = ARRAY_SIZE(s5pc100_ac97_resource),
+       .resource         = s5pc100_ac97_resource,
+       .dev = {
+               .platform_data = &s3c_ac97_pdata,
+               .dma_mask = &s5pc100_ac97_dmamask,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
+       },
+};
diff --git a/arch/arm/mach-s5pc100/dev-spi.c b/arch/arm/mach-s5pc100/dev-spi.c
new file mode 100644 (file)
index 0000000..14618c3
--- /dev/null
@@ -0,0 +1,233 @@
+/* linux/arch/arm/mach-s5pc100/dev-spi.c
+ *
+ * Copyright (C) 2010 Samsung Electronics Co. Ltd.
+ *     Jaswinder Singh <jassi.brar@samsung.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/platform_device.h>
+#include <linux/dma-mapping.h>
+
+#include <mach/dma.h>
+#include <mach/map.h>
+#include <mach/gpio.h>
+#include <mach/spi-clocks.h>
+
+#include <plat/s3c64xx-spi.h>
+#include <plat/gpio-cfg.h>
+#include <plat/irqs.h>
+
+static char *spi_src_clks[] = {
+       [S5PC100_SPI_SRCCLK_PCLK] = "pclk",
+       [S5PC100_SPI_SRCCLK_48M] = "spi_48m",
+       [S5PC100_SPI_SRCCLK_SPIBUS] = "spi_bus",
+};
+
+/* SPI Controller platform_devices */
+
+/* Since we emulate multi-cs capability, we do not touch the CS.
+ * The emulated CS is toggled by board specific mechanism, as it can
+ * be either some immediate GPIO or some signal out of some other
+ * chip in between ... or some yet another way.
+ * We simply do not assume anything about CS.
+ */
+static int s5pc100_spi_cfg_gpio(struct platform_device *pdev)
+{
+       switch (pdev->id) {
+       case 0:
+               s3c_gpio_cfgpin(S5PC100_GPB(0), S3C_GPIO_SFN(2));
+               s3c_gpio_cfgpin(S5PC100_GPB(1), S3C_GPIO_SFN(2));
+               s3c_gpio_cfgpin(S5PC100_GPB(2), S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(S5PC100_GPB(0), S3C_GPIO_PULL_UP);
+               s3c_gpio_setpull(S5PC100_GPB(1), S3C_GPIO_PULL_UP);
+               s3c_gpio_setpull(S5PC100_GPB(2), S3C_GPIO_PULL_UP);
+               break;
+
+       case 1:
+               s3c_gpio_cfgpin(S5PC100_GPB(4), S3C_GPIO_SFN(2));
+               s3c_gpio_cfgpin(S5PC100_GPB(5), S3C_GPIO_SFN(2));
+               s3c_gpio_cfgpin(S5PC100_GPB(6), S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(S5PC100_GPB(4), S3C_GPIO_PULL_UP);
+               s3c_gpio_setpull(S5PC100_GPB(5), S3C_GPIO_PULL_UP);
+               s3c_gpio_setpull(S5PC100_GPB(6), S3C_GPIO_PULL_UP);
+               break;
+
+       case 2:
+               s3c_gpio_cfgpin(S5PC100_GPG3(0), S3C_GPIO_SFN(3));
+               s3c_gpio_cfgpin(S5PC100_GPG3(2), S3C_GPIO_SFN(3));
+               s3c_gpio_cfgpin(S5PC100_GPG3(3), S3C_GPIO_SFN(3));
+               s3c_gpio_setpull(S5PC100_GPG3(0), S3C_GPIO_PULL_UP);
+               s3c_gpio_setpull(S5PC100_GPG3(2), S3C_GPIO_PULL_UP);
+               s3c_gpio_setpull(S5PC100_GPG3(3), S3C_GPIO_PULL_UP);
+               break;
+
+       default:
+               dev_err(&pdev->dev, "Invalid SPI Controller number!");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static struct resource s5pc100_spi0_resource[] = {
+       [0] = {
+               .start = S5PC100_PA_SPI0,
+               .end   = S5PC100_PA_SPI0 + 0x100 - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = DMACH_SPI0_TX,
+               .end   = DMACH_SPI0_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = DMACH_SPI0_RX,
+               .end   = DMACH_SPI0_RX,
+               .flags = IORESOURCE_DMA,
+       },
+       [3] = {
+               .start = IRQ_SPI0,
+               .end   = IRQ_SPI0,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct s3c64xx_spi_info s5pc100_spi0_pdata = {
+       .cfg_gpio = s5pc100_spi_cfg_gpio,
+       .fifo_lvl_mask = 0x7f,
+       .rx_lvl_offset = 13,
+       .high_speed = 1,
+};
+
+static u64 spi_dmamask = DMA_BIT_MASK(32);
+
+struct platform_device s5pc100_device_spi0 = {
+       .name             = "s3c64xx-spi",
+       .id               = 0,
+       .num_resources    = ARRAY_SIZE(s5pc100_spi0_resource),
+       .resource         = s5pc100_spi0_resource,
+       .dev = {
+               .dma_mask               = &spi_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+               .platform_data = &s5pc100_spi0_pdata,
+       },
+};
+
+static struct resource s5pc100_spi1_resource[] = {
+       [0] = {
+               .start = S5PC100_PA_SPI1,
+               .end   = S5PC100_PA_SPI1 + 0x100 - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = DMACH_SPI1_TX,
+               .end   = DMACH_SPI1_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = DMACH_SPI1_RX,
+               .end   = DMACH_SPI1_RX,
+               .flags = IORESOURCE_DMA,
+       },
+       [3] = {
+               .start = IRQ_SPI1,
+               .end   = IRQ_SPI1,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct s3c64xx_spi_info s5pc100_spi1_pdata = {
+       .cfg_gpio = s5pc100_spi_cfg_gpio,
+       .fifo_lvl_mask = 0x7f,
+       .rx_lvl_offset = 13,
+       .high_speed = 1,
+};
+
+struct platform_device s5pc100_device_spi1 = {
+       .name             = "s3c64xx-spi",
+       .id               = 1,
+       .num_resources    = ARRAY_SIZE(s5pc100_spi1_resource),
+       .resource         = s5pc100_spi1_resource,
+       .dev = {
+               .dma_mask               = &spi_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+               .platform_data = &s5pc100_spi1_pdata,
+       },
+};
+
+static struct resource s5pc100_spi2_resource[] = {
+       [0] = {
+               .start = S5PC100_PA_SPI2,
+               .end   = S5PC100_PA_SPI2 + 0x100 - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = DMACH_SPI2_TX,
+               .end   = DMACH_SPI2_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = DMACH_SPI2_RX,
+               .end   = DMACH_SPI2_RX,
+               .flags = IORESOURCE_DMA,
+       },
+       [3] = {
+               .start = IRQ_SPI2,
+               .end   = IRQ_SPI2,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct s3c64xx_spi_info s5pc100_spi2_pdata = {
+       .cfg_gpio = s5pc100_spi_cfg_gpio,
+       .fifo_lvl_mask = 0x7f,
+       .rx_lvl_offset = 13,
+       .high_speed = 1,
+};
+
+struct platform_device s5pc100_device_spi2 = {
+       .name             = "s3c64xx-spi",
+       .id               = 2,
+       .num_resources    = ARRAY_SIZE(s5pc100_spi2_resource),
+       .resource         = s5pc100_spi2_resource,
+       .dev = {
+               .dma_mask               = &spi_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+               .platform_data = &s5pc100_spi2_pdata,
+       },
+};
+
+void __init s5pc100_spi_set_info(int cntrlr, int src_clk_nr, int num_cs)
+{
+       struct s3c64xx_spi_info *pd;
+
+       /* Reject invalid configuration */
+       if (!num_cs || src_clk_nr < 0
+                       || src_clk_nr > S5PC100_SPI_SRCCLK_SPIBUS) {
+               printk(KERN_ERR "%s: Invalid SPI configuration\n", __func__);
+               return;
+       }
+
+       switch (cntrlr) {
+       case 0:
+               pd = &s5pc100_spi0_pdata;
+               break;
+       case 1:
+               pd = &s5pc100_spi1_pdata;
+               break;
+       case 2:
+               pd = &s5pc100_spi2_pdata;
+               break;
+       default:
+               printk(KERN_ERR "%s: Invalid SPI controller(%d)\n",
+                                                       __func__, cntrlr);
+               return;
+       }
+
+       pd->num_cs = num_cs;
+       pd->src_clk_nr = src_clk_nr;
+       pd->src_clk_name = spi_src_clks[src_clk_nr];
+}
diff --git a/arch/arm/mach-s5pc100/dma.c b/arch/arm/mach-s5pc100/dma.c
new file mode 100644 (file)
index 0000000..0f55175
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2010 Samsung Electronics Co. Ltd.
+ *     Jaswinder Singh <jassi.brar@samsung.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.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+
+#include <plat/devs.h>
+
+#include <mach/map.h>
+#include <mach/irqs.h>
+
+#include <plat/s3c-pl330-pdata.h>
+
+static u64 dma_dmamask = DMA_BIT_MASK(32);
+
+static struct resource s5pc100_pdma0_resource[] = {
+       [0] = {
+               .start  = S5PC100_PA_PDMA0,
+               .end    = S5PC100_PA_PDMA0 + SZ_4K,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = IRQ_PDMA0,
+               .end    = IRQ_PDMA0,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct s3c_pl330_platdata s5pc100_pdma0_pdata = {
+       .peri = {
+               [0] = DMACH_UART0_RX,
+               [1] = DMACH_UART0_TX,
+               [2] = DMACH_UART1_RX,
+               [3] = DMACH_UART1_TX,
+               [4] = DMACH_UART2_RX,
+               [5] = DMACH_UART2_TX,
+               [6] = DMACH_UART3_RX,
+               [7] = DMACH_UART3_TX,
+               [8] = DMACH_IRDA,
+               [9] = DMACH_I2S0_RX,
+               [10] = DMACH_I2S0_TX,
+               [11] = DMACH_I2S0S_TX,
+               [12] = DMACH_I2S1_RX,
+               [13] = DMACH_I2S1_TX,
+               [14] = DMACH_I2S2_RX,
+               [15] = DMACH_I2S2_TX,
+               [16] = DMACH_SPI0_RX,
+               [17] = DMACH_SPI0_TX,
+               [18] = DMACH_SPI1_RX,
+               [19] = DMACH_SPI1_TX,
+               [20] = DMACH_SPI2_RX,
+               [21] = DMACH_SPI2_TX,
+               [22] = DMACH_AC97_MICIN,
+               [23] = DMACH_AC97_PCMIN,
+               [24] = DMACH_AC97_PCMOUT,
+               [25] = DMACH_EXTERNAL,
+               [26] = DMACH_PWM,
+               [27] = DMACH_SPDIF,
+               [28] = DMACH_HSI_RX,
+               [29] = DMACH_HSI_TX,
+               [30] = DMACH_MAX,
+               [31] = DMACH_MAX,
+       },
+};
+
+static struct platform_device s5pc100_device_pdma0 = {
+       .name           = "s3c-pl330",
+       .id             = 1,
+       .num_resources  = ARRAY_SIZE(s5pc100_pdma0_resource),
+       .resource       = s5pc100_pdma0_resource,
+       .dev            = {
+               .dma_mask = &dma_dmamask,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
+               .platform_data = &s5pc100_pdma0_pdata,
+       },
+};
+
+static struct resource s5pc100_pdma1_resource[] = {
+       [0] = {
+               .start  = S5PC100_PA_PDMA1,
+               .end    = S5PC100_PA_PDMA1 + SZ_4K,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = IRQ_PDMA1,
+               .end    = IRQ_PDMA1,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct s3c_pl330_platdata s5pc100_pdma1_pdata = {
+       .peri = {
+               [0] = DMACH_UART0_RX,
+               [1] = DMACH_UART0_TX,
+               [2] = DMACH_UART1_RX,
+               [3] = DMACH_UART1_TX,
+               [4] = DMACH_UART2_RX,
+               [5] = DMACH_UART2_TX,
+               [6] = DMACH_UART3_RX,
+               [7] = DMACH_UART3_TX,
+               [8] = DMACH_IRDA,
+               [9] = DMACH_I2S0_RX,
+               [10] = DMACH_I2S0_TX,
+               [11] = DMACH_I2S0S_TX,
+               [12] = DMACH_I2S1_RX,
+               [13] = DMACH_I2S1_TX,
+               [14] = DMACH_I2S2_RX,
+               [15] = DMACH_I2S2_TX,
+               [16] = DMACH_SPI0_RX,
+               [17] = DMACH_SPI0_TX,
+               [18] = DMACH_SPI1_RX,
+               [19] = DMACH_SPI1_TX,
+               [20] = DMACH_SPI2_RX,
+               [21] = DMACH_SPI2_TX,
+               [22] = DMACH_PCM0_RX,
+               [23] = DMACH_PCM0_TX,
+               [24] = DMACH_PCM1_RX,
+               [25] = DMACH_PCM1_TX,
+               [26] = DMACH_MSM_REQ0,
+               [27] = DMACH_MSM_REQ1,
+               [28] = DMACH_MSM_REQ2,
+               [29] = DMACH_MSM_REQ3,
+               [30] = DMACH_MAX,
+               [31] = DMACH_MAX,
+       },
+};
+
+static struct platform_device s5pc100_device_pdma1 = {
+       .name           = "s3c-pl330",
+       .id             = 2,
+       .num_resources  = ARRAY_SIZE(s5pc100_pdma1_resource),
+       .resource       = s5pc100_pdma1_resource,
+       .dev            = {
+               .dma_mask = &dma_dmamask,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
+               .platform_data = &s5pc100_pdma1_pdata,
+       },
+};
+
+static struct platform_device *s5pc100_dmacs[] __initdata = {
+       &s5pc100_device_pdma0,
+       &s5pc100_device_pdma1,
+};
+
+static int __init s5pc100_dma_init(void)
+{
+       platform_add_devices(s5pc100_dmacs, ARRAY_SIZE(s5pc100_dmacs));
+
+       return 0;
+}
+arch_initcall(s5pc100_dma_init);
index c8e8336a3a127fd4e14ae356e69b2e09d23ea18b..0fab7f2cd8bfaacd395737cd0a0f847e1daf5525 100644 (file)
@@ -1,10 +1,10 @@
 /*
- * arch/arm/plat-s5pc1xx/gpiolib.c
+ * arch/arm/plat-s5pc100/gpiolib.c
  *
  *  Copyright 2009 Samsung Electronics Co
  *  Kyungmin Park <kyungmin.park@samsung.com>
  *
- * S5PC1XX - GPIOlib support
+ * S5PC100 - GPIOlib support
  *
  * 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
  * L3  8       4Bit    None
  */
 
-#if 0
-static int s5pc1xx_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset)
+static int s5pc100_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset)
 {
        return S3C_IRQ_GPIO(chip->base + offset);
 }
 
-static int s5pc1xx_gpiolib_to_eint(struct gpio_chip *chip, unsigned int offset)
+static int s5pc100_gpiolib_to_eint(struct gpio_chip *chip, unsigned int offset)
 {
        int base;
 
@@ -85,7 +84,7 @@ static int s5pc1xx_gpiolib_to_eint(struct gpio_chip *chip, unsigned int offset)
                return IRQ_EINT(24 + offset);
        return -EINVAL;
 }
-#endif
+
 static struct s3c_gpio_cfg gpio_cfg = {
        .set_config     = s3c_gpio_setcfg_s3c64xx_4bit,
        .set_pull       = s3c_gpio_setpull_updown,
@@ -382,31 +381,30 @@ static struct s3c_gpio_chip s5pc100_gpio_chips[] = {
 };
 
 /* FIXME move from irq-gpio.c */
-extern struct irq_chip s5pc1xx_gpioint;
-extern void s5pc1xx_irq_gpioint_handler(unsigned int irq, struct irq_desc *desc);
+extern struct irq_chip s5pc100_gpioint;
+extern void s5pc100_irq_gpioint_handler(unsigned int irq, struct irq_desc *desc);
 
 static __init void s5pc100_gpiolib_link(struct s3c_gpio_chip *chip)
 {
-#if 0
        /* Interrupt */
        if (chip->config == &gpio_cfg) {
                int i, irq;
 
-               chip->chip.to_irq = s5pc1xx_gpiolib_to_irq;
+               chip->chip.to_irq = s5pc100_gpiolib_to_irq;
 
                for (i = 0;  i < chip->chip.ngpio; i++) {
                        irq = S3C_IRQ_GPIO_BASE + chip->chip.base + i;
-                       set_irq_chip(irq, &s5pc1xx_gpioint);
+                       set_irq_chip(irq, &s5pc100_gpioint);
                        set_irq_data(irq, &chip->chip);
                        set_irq_handler(irq, handle_level_irq);
                        set_irq_flags(irq, IRQF_VALID);
                }
-       } else if (chip->config == &gpio_cfg_eint)
-               chip->chip.to_irq = s5pc1xx_gpiolib_to_eint;
-#endif
+       } else if (chip->config == &gpio_cfg_eint) {
+               chip->chip.to_irq = s5pc100_gpiolib_to_eint;
+       }
 }
 
-static __init int s5pc1xx_gpiolib_init(void)
+static __init int s5pc100_gpiolib_init(void)
 {
        struct s3c_gpio_chip *chip;
        int nr_chips;
@@ -419,10 +417,10 @@ static __init int s5pc1xx_gpiolib_init(void)
 
        samsung_gpiolib_add_4bit_chips(s5pc100_gpio_chips,
                                       ARRAY_SIZE(s5pc100_gpio_chips));
-#if 0
+
        /* Interrupt */
-       set_irq_chained_handler(IRQ_GPIOINT, s5pc1xx_irq_gpioint_handler);
-#endif
+       set_irq_chained_handler(IRQ_GPIOINT, s5pc100_irq_gpioint_handler);
+
        return 0;
 }
-core_initcall(s5pc1xx_gpiolib_init);
+core_initcall(s5pc100_gpiolib_init);
index e181f5789482fcd7943777b1343d99eb86654ff1..70e02e91ee3c99602b2864f5a07cd8da820f8d32 100644 (file)
         * aligned and add in the offset when we load the value here.
         */
 
-       .macro addruart, rx, tmp
+       .macro addruart, rx, rtmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1
                ldreq   \rx, = S3C_PA_UART
-               ldrne   \rx, = (S3C_VA_UART + S3C_PA_UART & 0xfffff)
+               ldrne   \rx, = S3C_VA_UART
+#if CONFIG_DEBUG_S3C_UART != 0
                add     \rx, \rx, #(0x400 * CONFIG_DEBUG_S3C_UART)
+#endif
        .endm
 
 /* include the reset of the code which will do the work, we're only
diff --git a/arch/arm/mach-s5pc100/include/mach/dma.h b/arch/arm/mach-s5pc100/include/mach/dma.h
new file mode 100644 (file)
index 0000000..81209eb
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2010 Samsung Electronics Co. Ltd.
+ *     Jaswinder Singh <jassi.brar@samsung.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.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __MACH_DMA_H
+#define __MACH_DMA_H
+
+/* This platform uses the common S3C DMA API driver for PL330 */
+#include <plat/s3c-dma-pl330.h>
+
+#endif /* __MACH_DMA_H */
index 67131939e626d02e937503cd4c31b3925526b69a..ba76af052c81fac1183584e33bf0e337246f9d48 100644 (file)
@@ -20,7 +20,7 @@
        .endm
 
        .macro  get_irqnr_preamble, base, tmp
-       ldr     \base, =S3C_VA_VIC0
+       ldr     \base, =VA_VIC0
        .endm
 
        .macro  arch_ret_to_user, tmp1, tmp2
        .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
 
        @ check the vic0
-       mov     \irqnr, # S3C_IRQ_OFFSET + 31
+       mov     \irqnr, # S5P_IRQ_OFFSET + 31
        ldr     \irqstat, [ \base, # VIC_IRQ_STATUS ]
        teq     \irqstat, #0
 
        @ otherwise try vic1
-       addeq   \tmp, \base, #(S3C_VA_VIC1 - S3C_VA_VIC0)
+       addeq   \tmp, \base, #(VA_VIC1 - VA_VIC0)
        addeq   \irqnr, \irqnr, #32
        ldreq   \irqstat, [ \tmp, # VIC_IRQ_STATUS ]
        teqeq   \irqstat, #0
 
        @ otherwise try vic2
-       addeq   \tmp, \base, #(S3C_VA_VIC2 - S3C_VA_VIC0)
+       addeq   \tmp, \base, #(VA_VIC2 - VA_VIC0)
        addeq   \irqnr, \irqnr, #32
        ldreq   \irqstat, [ \tmp, # VIC_IRQ_STATUS ]
        teqeq   \irqstat, #0
index 29a8a12d9b4f9046a4cce984917329b74683bf2b..71ae1f52df1d27bb511a878bbca6eb8d25457404 100644 (file)
@@ -146,6 +146,13 @@ enum s5p_gpio_number {
 /* define the number of gpios we need to the one after the MP04() range */
 #define ARCH_NR_GPIOS          (S5PC100_GPIO_END + 1)
 
+#define EINT_MODE              S3C_GPIO_SFN(0x2)
+
+#define EINT_GPIO_0(x)         S5PC100_GPH0(x)
+#define EINT_GPIO_1(x)         S5PC100_GPH1(x)
+#define EINT_GPIO_2(x)         S5PC100_GPH2(x)
+#define EINT_GPIO_3(x)         S5PC100_GPH3(x)
+
 #include <asm-generic/gpio.h>
 
 #endif /* __ASM_ARCH_GPIO_H */
index b53fa48a52c69712a8a896c61143315a97624434..28aa551dc3a8345a4cfe298e3091327a133ba0d8 100644 (file)
 
 #include <plat/irqs.h>
 
-/* LCD */
+/* VIC0: system, DMA, timer */
+#define IRQ_EINT16_31          S5P_IRQ_VIC0(16)
+#define IRQ_BATF               S5P_IRQ_VIC0(17)
+#define IRQ_MDMA               S5P_IRQ_VIC0(18)
+#define IRQ_PDMA0              S5P_IRQ_VIC0(19)
+#define IRQ_PDMA1              S5P_IRQ_VIC0(20)
+#define IRQ_TIMER0_VIC         S5P_IRQ_VIC0(21)
+#define IRQ_TIMER1_VIC         S5P_IRQ_VIC0(22)
+#define IRQ_TIMER2_VIC         S5P_IRQ_VIC0(23)
+#define IRQ_TIMER3_VIC         S5P_IRQ_VIC0(24)
+#define IRQ_TIMER4_VIC         S5P_IRQ_VIC0(25)
+#define IRQ_SYSTIMER           S5P_IRQ_VIC0(26)
+#define IRQ_WDT                        S5P_IRQ_VIC0(27)
+#define IRQ_RTC_ALARM          S5P_IRQ_VIC0(28)
+#define IRQ_RTC_TIC            S5P_IRQ_VIC0(29)
+#define IRQ_GPIOINT            S5P_IRQ_VIC0(30)
+
+/* VIC1: ARM, power, memory, connectivity */
+#define IRQ_CORTEX0            S5P_IRQ_VIC1(0)
+#define IRQ_CORTEX1            S5P_IRQ_VIC1(1)
+#define IRQ_CORTEX2            S5P_IRQ_VIC1(2)
+#define IRQ_CORTEX3            S5P_IRQ_VIC1(3)
+#define IRQ_CORTEX4            S5P_IRQ_VIC1(4)
+#define IRQ_IEMAPC             S5P_IRQ_VIC1(5)
+#define IRQ_IEMIEC             S5P_IRQ_VIC1(6)
+#define IRQ_ONENAND            S5P_IRQ_VIC1(7)
+#define IRQ_NFC                        S5P_IRQ_VIC1(8)
+#define IRQ_CFC                        S5P_IRQ_VIC1(9)
+#define IRQ_UART0              S5P_IRQ_VIC1(10)
+#define IRQ_UART1              S5P_IRQ_VIC1(11)
+#define IRQ_UART2              S5P_IRQ_VIC1(12)
+#define IRQ_UART3              S5P_IRQ_VIC1(13)
+#define IRQ_IIC                        S5P_IRQ_VIC1(14)
+#define IRQ_SPI0               S5P_IRQ_VIC1(15)
+#define IRQ_SPI1               S5P_IRQ_VIC1(16)
+#define IRQ_SPI2               S5P_IRQ_VIC1(17)
+#define IRQ_IRDA               S5P_IRQ_VIC1(18)
+#define IRQ_CAN0               S5P_IRQ_VIC1(19)
+#define IRQ_CAN1               S5P_IRQ_VIC1(20)
+#define IRQ_HSIRX              S5P_IRQ_VIC1(21)
+#define IRQ_HSITX              S5P_IRQ_VIC1(22)
+#define IRQ_UHOST              S5P_IRQ_VIC1(23)
+#define IRQ_OTG                        S5P_IRQ_VIC1(24)
+#define IRQ_MSM                        S5P_IRQ_VIC1(25)
+#define IRQ_HSMMC0             S5P_IRQ_VIC1(26)
+#define IRQ_HSMMC1             S5P_IRQ_VIC1(27)
+#define IRQ_HSMMC2             S5P_IRQ_VIC1(28)
+#define IRQ_MIPICSI            S5P_IRQ_VIC1(29)
+#define IRQ_MIPIDSI            S5P_IRQ_VIC1(30)
+
+/* VIC2: multimedia, audio, security */
+#define IRQ_LCD0               S5P_IRQ_VIC2(0)
+#define IRQ_LCD1               S5P_IRQ_VIC2(1)
+#define IRQ_LCD2               S5P_IRQ_VIC2(2)
+#define IRQ_LCD3               S5P_IRQ_VIC2(3)
+#define IRQ_ROTATOR            S5P_IRQ_VIC2(4)
+#define IRQ_FIMC0              S5P_IRQ_VIC2(5)
+#define IRQ_FIMC1              S5P_IRQ_VIC2(6)
+#define IRQ_FIMC2              S5P_IRQ_VIC2(7)
+#define IRQ_JPEG               S5P_IRQ_VIC2(8)
+#define IRQ_2D                 S5P_IRQ_VIC2(9)
+#define IRQ_3D                 S5P_IRQ_VIC2(10)
+#define IRQ_MIXER              S5P_IRQ_VIC2(11)
+#define IRQ_HDMI               S5P_IRQ_VIC2(12)
+#define IRQ_IIC1               S5P_IRQ_VIC2(13)
+#define IRQ_MFC                        S5P_IRQ_VIC2(14)
+#define IRQ_TVENC              S5P_IRQ_VIC2(15)
+#define IRQ_I2S0               S5P_IRQ_VIC2(16)
+#define IRQ_I2S1               S5P_IRQ_VIC2(17)
+#define IRQ_I2S2               S5P_IRQ_VIC2(18)
+#define IRQ_AC97               S5P_IRQ_VIC2(19)
+#define IRQ_PCM0               S5P_IRQ_VIC2(20)
+#define IRQ_PCM1               S5P_IRQ_VIC2(21)
+#define IRQ_SPDIF              S5P_IRQ_VIC2(22)
+#define IRQ_ADC                        S5P_IRQ_VIC2(23)
+#define IRQ_PENDN              S5P_IRQ_VIC2(24)
+#define IRQ_TC                 IRQ_PENDN
+#define IRQ_KEYPAD             S5P_IRQ_VIC2(25)
+#define IRQ_CG                 S5P_IRQ_VIC2(26)
+#define IRQ_SEC                        S5P_IRQ_VIC2(27)
+#define IRQ_SECRX              S5P_IRQ_VIC2(28)
+#define IRQ_SECTX              S5P_IRQ_VIC2(29)
+#define IRQ_SDMIRQ             S5P_IRQ_VIC2(30)
+#define IRQ_SDMFIQ             S5P_IRQ_VIC2(31)
+#define IRQ_VIC_END            S5P_IRQ_VIC2(31)
+
+#define S5P_EINT_BASE1         (S5P_IRQ_VIC0(0))
+#define S5P_EINT_BASE2         (IRQ_VIC_END + 1)
+
+#define S3C_IRQ_GPIO_BASE      (IRQ_EINT(31) + 1)
+#define S3C_IRQ_GPIO(x)                (S3C_IRQ_GPIO_BASE + (x))
+
+/* Until MP04 Groups -> 40 (exactly 39) Groups * 8 ~= 320 GPIOs */
+#define NR_IRQS                (S3C_IRQ_GPIO(320) + 1)
+
+/* Compatibility */
 #define IRQ_LCD_FIFO           IRQ_LCD0
 #define IRQ_LCD_VSYNC          IRQ_LCD1
 #define IRQ_LCD_SYSTEM         IRQ_LCD2
 
-#endif /* __ASM_ARCH_IRQ_H */
+#endif /* __ASM_ARCH_IRQS_H */
index 4681ebe8bef66defff9757e0b2a854dc29db7c39..cadae4305688e83e3328383d8701fd6ee0e467d3 100644 (file)
@@ -3,9 +3,7 @@
  * Copyright 2009 Samsung Electronics Co.
  *     Byungho Min <bhmin@samsung.com>
  *
- * Based on mach-s3c6400/include/mach/map.h
- *
- * S5PC1XX - Memory map definitions
+ * S5PC100 - Memory map definitions
  *
  * 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
@@ -16,6 +14,7 @@
 #define __ASM_ARCH_MAP_H __FILE__
 
 #include <plat/map-base.h>
+#include <plat/map-s5p.h>
 
 /*
  * map-base.h has already defined virtual memory address
  *
  */
 
+#define S5PC100_PA_ONENAND_BUF (0xB0000000)
+#define S5PC100_SZ_ONENAND_BUF (SZ_256M - SZ_32M)
+
 /* Chip ID */
+
 #define S5PC100_PA_CHIPID      (0xE0000000)
-#define S5PC1XX_PA_CHIPID      S5PC100_PA_CHIPID
-#define S5PC1XX_VA_CHIPID      S3C_VA_SYS
-
-/* System */
-#define S5PC100_PA_CLK         (0xE0100000)
-#define S5PC100_PA_CLK_OTHER   (0xE0200000)
-#define S5PC100_PA_PWR         (0xE0108000)
-#define S5PC1XX_PA_CLK         S5PC100_PA_CLK
-#define S5PC1XX_PA_PWR         S5PC100_PA_PWR
-#define S5PC1XX_PA_CLK_OTHER   S5PC100_PA_CLK_OTHER
-#define S5PC1XX_VA_CLK         (S3C_VA_SYS + 0x10000)
-#define S5PC1XX_VA_PWR         (S3C_VA_SYS + 0x20000)
-#define S5PC1XX_VA_CLK_OTHER   (S3C_VA_SYS + 0x30000)
-
-/* GPIO */
-#define S5PC100_PA_GPIO                (0xE0300000)
-#define S5PC1XX_PA_GPIO                S5PC100_PA_GPIO
+#define S5P_PA_CHIPID          S5PC100_PA_CHIPID
+
+#define S5PC100_PA_SYSCON      (0xE0100000)
+#define S5P_PA_SYSCON          S5PC100_PA_SYSCON
+
+#define S5PC100_PA_OTHERS      (0xE0200000)
+#define S5PC100_VA_OTHERS      (S3C_VA_SYS + 0x10000)
+
+#define S5P_PA_GPIO            (0xE0300000)
 #define S5PC1XX_VA_GPIO                S3C_ADDR(0x00500000)
 
 /* Interrupt */
 #define S5PC100_VA_VIC_OFFSET  0x10000
 #define S5PC1XX_PA_VIC(x)      (S5PC100_PA_VIC + ((x) * S5PC100_PA_VIC_OFFSET))
 #define S5PC1XX_VA_VIC(x)      (S5PC100_VA_VIC + ((x) * S5PC100_VA_VIC_OFFSET))
+#define S5P_PA_VIC0            S5PC1XX_PA_VIC(0)
+#define S5P_PA_VIC1            S5PC1XX_PA_VIC(1)
+#define S5P_PA_VIC2            S5PC1XX_PA_VIC(2)
+
+
+#define S5PC100_PA_ONENAND     (0xE7100000)
 
 /* DMA */
 #define S5PC100_PA_MDMA                (0xE8100000)
 
 /* Timer */
 #define S5PC100_PA_TIMER       (0xEA000000)
-#define S5PC1XX_PA_TIMER       S5PC100_PA_TIMER
-#define S5PC1XX_VA_TIMER       S3C_VA_TIMER
+#define S5P_PA_TIMER           S5PC100_PA_TIMER
 
-/* RTC */
-#define S5PC100_PA_RTC         (0xEA300000)
+#define S5PC100_PA_SYSTIMER    (0xEA100000)
 
-/* UART */
 #define S5PC100_PA_UART                (0xEC000000)
-#define S5PC1XX_PA_UART                S5PC100_PA_UART
-#define S5PC1XX_VA_UART                S3C_VA_UART
 
-/* I2C */
-#define S5PC100_PA_I2C         (0xEC100000)
-#define S5PC100_PA_I2C1                (0xEC200000)
+#define S5P_PA_UART0           (S5PC100_PA_UART + 0x0)
+#define S5P_PA_UART1           (S5PC100_PA_UART + 0x400)
+#define S5P_PA_UART2           (S5PC100_PA_UART + 0x800)
+#define S5P_PA_UART3           (S5PC100_PA_UART + 0xC00)
+#define S5P_SZ_UART            SZ_256
+
+#define S5PC100_PA_IIC0                (0xEC100000)
+#define S5PC100_PA_IIC1                (0xEC200000)
+
+/* SPI */
+#define S5PC100_PA_SPI0                0xEC300000
+#define S5PC100_PA_SPI1                0xEC400000
+#define S5PC100_PA_SPI2                0xEC500000
 
 /* USB HS OTG */
 #define S5PC100_PA_USB_HSOTG   (0xED200000)
 #define S5PC100_PA_USB_HSPHY   (0xED300000)
 
-/* SD/MMC */
-#define S5PC100_PA_HSMMC(x)    (0xED800000 + ((x) * 0x100000))
-#define S5PC100_PA_HSMMC0      S5PC100_PA_HSMMC(0)
-#define S5PC100_PA_HSMMC1      S5PC100_PA_HSMMC(1)
-#define S5PC100_PA_HSMMC2      S5PC100_PA_HSMMC(2)
-
-/* LCD */
 #define S5PC100_PA_FB          (0xEE000000)
 
-/* Multimedia */
-#define S5PC100_PA_G2D         (0xEE800000)
-#define S5PC100_PA_JPEG                (0xEE500000)
-#define S5PC100_PA_ROTATOR     (0xEE100000)
-#define S5PC100_PA_G3D         (0xEF000000)
-
-/* I2S */
 #define S5PC100_PA_I2S0                (0xF2000000)
 #define S5PC100_PA_I2S1                (0xF2100000)
 #define S5PC100_PA_I2S2                (0xF2200000)
 
+#define S5PC100_PA_AC97                0xF2300000
+
+/* PCM */
+#define S5PC100_PA_PCM0                0xF2400000
+#define S5PC100_PA_PCM1                0xF2500000
+
 /* KEYPAD */
 #define S5PC100_PA_KEYPAD      (0xF3100000)
 
-/* ADC & TouchScreen */
-#define S5PC100_PA_TSADC       (0xF3000000)
+#define S5PC100_PA_HSMMC(x)    (0xED800000 + ((x) * 0x100000))
 
-/* ETC */
 #define S5PC100_PA_SDRAM       (0x20000000)
-#define S5PC1XX_PA_SDRAM       S5PC100_PA_SDRAM
+#define S5P_PA_SDRAM           S5PC100_PA_SDRAM
 
-/* compatibility defines. */
-#define S3C_PA_RTC             S5PC100_PA_RTC
+/* compatibiltiy defines. */
 #define S3C_PA_UART            S5PC100_PA_UART
-#define S3C_PA_UART0           (S5PC100_PA_UART + 0x0)
-#define S3C_PA_UART1           (S5PC100_PA_UART + 0x400)
-#define S3C_PA_UART2           (S5PC100_PA_UART + 0x800)
-#define S3C_PA_UART3           (S5PC100_PA_UART + 0xC00)
-#define S3C_VA_UART0           (S3C_VA_UART + 0x0)
-#define S3C_VA_UART1           (S3C_VA_UART + 0x400)
-#define S3C_VA_UART2           (S3C_VA_UART + 0x800)
-#define S3C_VA_UART3           (S3C_VA_UART + 0xC00)
-#define S3C_UART_OFFSET                0x400
-#define S3C_VA_UARTx(x)                (S3C_VA_UART + ((x) * S3C_UART_OFFSET))
+#define S3C_PA_IIC             S5PC100_PA_IIC0
+#define S3C_PA_IIC1            S5PC100_PA_IIC1
 #define S3C_PA_FB              S5PC100_PA_FB
 #define S3C_PA_G2D             S5PC100_PA_G2D
 #define S3C_PA_G3D             S5PC100_PA_G3D
 #define S3C_PA_JPEG            S5PC100_PA_JPEG
 #define S3C_PA_ROTATOR         S5PC100_PA_ROTATOR
-#define S3C_VA_VIC0            (S3C_VA_IRQ + 0x0)
-#define S3C_VA_VIC1            (S3C_VA_IRQ + 0x10000)
-#define S3C_VA_VIC2            (S3C_VA_IRQ + 0x20000)
-#define S3C_PA_IIC             S5PC100_PA_I2C
-#define S3C_PA_IIC1            S5PC100_PA_I2C1
+#define S5P_VA_VIC0            S5PC1XX_VA_VIC(0)
+#define S5P_VA_VIC1            S5PC1XX_VA_VIC(1)
+#define S5P_VA_VIC2            S5PC1XX_VA_VIC(2)
 #define S3C_PA_USB_HSOTG       S5PC100_PA_USB_HSOTG
 #define S3C_PA_USB_HSPHY       S5PC100_PA_USB_HSPHY
-#define S3C_PA_HSMMC0          S5PC100_PA_HSMMC0
-#define S3C_PA_HSMMC1          S5PC100_PA_HSMMC1
-#define S3C_PA_HSMMC2          S5PC100_PA_HSMMC2
+#define S3C_PA_HSMMC0          S5PC100_PA_HSMMC(0)
+#define S3C_PA_HSMMC1          S5PC100_PA_HSMMC(1)
+#define S3C_PA_HSMMC2          S5PC100_PA_HSMMC(2)
 #define S3C_PA_KEYPAD          S5PC100_PA_KEYPAD
 #define S3C_PA_TSADC           S5PC100_PA_TSADC
+#define S3C_PA_ONENAND         S5PC100_PA_ONENAND
+#define S3C_PA_ONENAND_BUF     S5PC100_PA_ONENAND_BUF
+#define S3C_SZ_ONENAND_BUF     S5PC100_SZ_ONENAND_BUF
 
 #endif /* __ASM_ARCH_C100_MAP_H */
index f2283bdc941e3a16ba7df5e43e57bcf564f6b1b4..5d27d286d50490cb5ed86d6b53146043b872b88c 100644 (file)
@@ -17,6 +17,8 @@
 
 #define S5P_CLKREG(x)          (S3C_VA_SYS + (x))
 
+#define S5PC100_REG_OTHERS(x)  (S5PC100_VA_OTHERS + (x))
+
 #define S5P_APLL_LOCK          S5P_CLKREG(0x00)
 #define S5P_MPLL_LOCK          S5P_CLKREG(0x04)
 #define S5P_EPLL_LOCK          S5P_CLKREG(0x08)
@@ -68,4 +70,8 @@
 #define S5P_CLKDIV1_PCLKD1_MASK                (0x7<<16)
 #define S5P_CLKDIV1_PCLKD1_SHIFT       (16)
 
+#define S5PC100_SWRESET                S5PC100_REG_OTHERS(0x000)
+
+#define S5PC100_SWRESET_RESETVAL       0xc100
+
 #endif /* __ASM_ARCH_REGS_CLOCK_H */
index 68666913354ce1f59e998915aa8913cdbf912a2d..dd6295e1251dbb0161c044fe335fa088c44aa91e 100644 (file)
@@ -1,4 +1,4 @@
-/* linux/arch/arm/plat-s5pc1xx/include/plat/regs-gpio.h
+/* linux/arch/arm/plat-s5pc100/include/plat/regs-gpio.h
  *
  * Copyright 2009 Samsung Electronics Co.
  *      Byungho Min <bhmin@samsung.com>
@@ -12,7 +12,7 @@
 #include <mach/map.h>
 
 /* S5PC100 */
-#define S5PC100_GPIO_BASE      S5PC1XX_VA_GPIO
+#define S5PC100_GPIO_BASE      S5P_VA_GPIO
 #define S5PC100_GPA0_BASE      (S5PC100_GPIO_BASE + 0x0000)
 #define S5PC100_GPA1_BASE      (S5PC100_GPIO_BASE + 0x0020)
 #define S5PC100_GPB_BASE       (S5PC100_GPIO_BASE + 0x0040)
 #define S5PC100_GPL2_BASE      (S5PC100_GPIO_BASE + 0x0360)
 #define S5PC100_GPL3_BASE      (S5PC100_GPIO_BASE + 0x0380)
 #define S5PC100_GPL4_BASE      (S5PC100_GPIO_BASE + 0x03A0)
-#define S5PC100_EINT_BASE      (S5PC100_GPIO_BASE + 0x0E00)
 
-#define S5PC100_UHOST          (S5PC100_GPIO_BASE + 0x0B68)
-#define S5PC100_PDNEN          (S5PC100_GPIO_BASE + 0x0F80)
+#define S5PC100EINT30CON               (S5P_VA_GPIO + 0xE00)
+#define S5P_EINT_CON(x)                        (S5PC100EINT30CON + ((x) * 0x4))
 
-/* PDNEN */
-#define S5PC100_PDNEN_CFG_PDNEN        (1 << 1)
-#define S5PC100_PDNEN_CFG_AUTO (0 << 1)
-#define S5PC100_PDNEN_POWERDOWN        (1 << 0)
-#define S5PC100_PDNEN_NORMAL   (0 << 0)
+#define S5PC100EINT30FLTCON0           (S5P_VA_GPIO + 0xE80)
+#define S5P_EINT_FLTCON(x)             (S5PC100EINT30FLTCON0 + ((x) * 0x4))
 
-/* Common part */
-/* External interrupt base is same at both s5pc100 and s5pc110 */
-#define S5PC1XX_EINT_BASE      (S5PC100_EINT_BASE)
+#define S5PC100EINT30MASK              (S5P_VA_GPIO + 0xF00)
+#define S5P_EINT_MASK(x)               (S5PC100EINT30MASK + ((x) * 0x4))
 
-#define S5PC100_GPx_INPUT(__gpio)      (0x0 << ((__gpio) * 4))
-#define S5PC100_GPx_OUTPUT(__gpio)     (0x1 << ((__gpio) * 4))
-#define S5PC100_GPx_CONMASK(__gpio)    (0xf << ((__gpio) * 4))
+#define S5PC100EINT30PEND              (S5P_VA_GPIO + 0xF40)
+#define S5P_EINT_PEND(x)               (S5PC100EINT30PEND + ((x) * 0x4))
+
+#define EINT_REG_NR(x)                 (EINT_OFFSET(x) >> 3)
+
+#define eint_irq_to_bit(irq)           (1 << (EINT_OFFSET(irq) & 0x7))
+
+/* values for S5P_EXTINT0 */
+#define S5P_EXTINT_LOWLEV              (0x00)
+#define S5P_EXTINT_HILEV               (0x01)
+#define S5P_EXTINT_FALLEDGE            (0x02)
+#define S5P_EXTINT_RISEEDGE            (0x03)
+#define S5P_EXTINT_BOTHEDGE            (0x04)
 
 #endif /* __ASM_MACH_S5PC100_REGS_GPIO_H */
 
index 751ac15438c8680df300ddadf6de481e148ace9e..4d9036d0f28854177a2fa37be1e8ce627af6b634 100644 (file)
@@ -3,7 +3,7 @@
  * Copyright 2009 Samsung Electronics Co.
  *     Byungho Min <bhmin@samsung.com>
  *
- * S5PC1XX - IRQ register definitions
+ * S5PC100 - IRQ register definitions
  *
  * 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
@@ -16,9 +16,4 @@
 #include <mach/map.h>
 #include <asm/hardware/vic.h>
 
-/* interrupt controller */
-#define S5PC1XX_VIC0REG(x)                     ((x) + S5PC1XX_VA_VIC(0))
-#define S5PC1XX_VIC1REG(x)                     ((x) + S5PC1XX_VA_VIC(1))
-#define S5PC1XX_VIC2REG(x)                     ((x) + S5PC1XX_VA_VIC(2))
-
 #endif /* __ASM_ARCH_REGS_IRQ_H */
diff --git a/arch/arm/mach-s5pc100/include/mach/spi-clocks.h b/arch/arm/mach-s5pc100/include/mach/spi-clocks.h
new file mode 100644 (file)
index 0000000..65e4263
--- /dev/null
@@ -0,0 +1,18 @@
+/* linux/arch/arm/mach-s5pc100/include/mach/spi-clocks.h
+ *
+ * Copyright (C) 2010 Samsung Electronics Co. Ltd.
+ *     Jaswinder Singh <jassi.brar@samsung.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 __S5PC100_PLAT_SPI_CLKS_H
+#define __S5PC100_PLAT_SPI_CLKS_H __FILE__
+
+#define S5PC100_SPI_SRCCLK_PCLK                0
+#define S5PC100_SPI_SRCCLK_48M         1
+#define S5PC100_SPI_SRCCLK_SPIBUS      2
+
+#endif /* __S5PC100_PLAT_SPI_CLKS_H */
index f0d31a2a598c3f71ebeb187250a0945e52969519..681f626a9ae17e3b2e8b563e4a4f812b7d1980d2 100644 (file)
@@ -3,7 +3,7 @@
  * Copyright 2009 Samsung Electronics Co.
  *      Byungho Min <bhmin@samsung.com>
  *
- * S5PC1XX - system implementation
+ * S5PC100 - system implementation
  *
  * Based on mach-s3c6400/include/mach/system.h
  */
 
 #include <linux/io.h>
 #include <mach/map.h>
-#include <plat/regs-clock.h>
-
-void (*s5pc1xx_idle)(void);
+#include <mach/regs-clock.h>
 
 static void arch_idle(void)
 {
-       if (s5pc1xx_idle)
-               s5pc1xx_idle();
+       /* nothing here yet */
 }
 
 static void arch_reset(char mode, const char *cmd)
index f338c9eec7176d510d50947a75dc5cfe0bbf105c..20f68730ed180d50cefcfe19426f58dbc468a779 100644 (file)
@@ -20,8 +20,8 @@
  */
 static inline u32 s3c24xx_ostimer_pending(void)
 {
-       u32 pend = __raw_readl(S3C_VA_VIC0 + VIC_RAW_STATUS);
-       return pend & 1 << (IRQ_TIMER4_VIC - S5PC1XX_IRQ_VIC0(0));
+       u32 pend = __raw_readl(VA_VIC0 + VIC_RAW_STATUS);
+       return pend & (1 << (IRQ_TIMER4_VIC - S5P_IRQ_VIC0(0)));
 }
 
 #define TICK_MAX       (0xffffffff)
similarity index 68%
rename from arch/arm/plat-s5pc1xx/s5pc100-init.c
rename to arch/arm/mach-s5pc100/init.c
index c58710884cebd5765259143b2956e5dd9c8aa543..19d7b523c1377396c0b3a01222b6f46a8e747f2c 100644 (file)
@@ -1,9 +1,8 @@
-/* linux/arch/arm/plat-s5pc1xx/s5pc100-init.c
+/* linux/arch/arm/plat-s5pc100/s5pc100-init.c
  *
  * Copyright 2009 Samsung Electronics Co.
  *      Byungho Min <bhmin@samsung.com>
  *
- * S5PC100 - CPU initialisation (common with other S5PC1XX chips)
  *
  * 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
@@ -19,9 +18,7 @@
 #include <plat/s5pc100.h>
 
 /* uart registration process */
-
 void __init s5pc100_common_init_uarts(struct s3c2410_uartcfg *cfg, int no)
 {
-       /* The driver name is s3c6400-uart to reuse s3c6400_serial_drv  */
-       s3c24xx_init_uartdevs("s3c6400-uart", s5pc1xx_uart_resources, cfg, no);
+       s3c24xx_init_uartdevs("s3c6400-uart", s5p_uart_resources, cfg, no);
 }
similarity index 72%
rename from arch/arm/plat-s5pc1xx/irq-gpio.c
rename to arch/arm/mach-s5pc100/irq-gpio.c
index fecca7a679b0b0330b6d3c5079bc672b1db44341..2bf86c18bc73a3aeae8ead9341789e76f32ab4eb 100644 (file)
@@ -1,9 +1,9 @@
 /*
- * arch/arm/plat-s5pc1xx/irq-gpio.c
+ * arch/arm/mach-s5pc100/irq-gpio.c
  *
  * Copyright (C) 2009 Samsung Electronics
  *
- * S5PC1XX - Interrupt handling for IRQ_GPIO${group}(x)
+ * S5PC100 - Interrupt handling for IRQ_GPIO${group}(x)
  *
  * 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
@@ -19,7 +19,7 @@
 #include <mach/map.h>
 #include <plat/gpio-cfg.h>
 
-#define S5PC1XX_GPIOREG(x)             (S5PC1XX_VA_GPIO + (x))
+#define S5P_GPIOREG(x)         (S5P_VA_GPIO + (x))
 
 #define CON_OFFSET                     0x700
 #define MASK_OFFSET                    0x900
@@ -49,7 +49,7 @@ static int group_to_pend_offset(int group)
        return group << 2;
 }
 
-static int s5pc1xx_get_start(unsigned int group)
+static int s5pc100_get_start(unsigned int group)
 {
        switch (group) {
        case 0: return S5PC100_GPIO_A0_START;
@@ -80,7 +80,7 @@ static int s5pc1xx_get_start(unsigned int group)
        return -EINVAL;
 }
 
-static int s5pc1xx_get_group(unsigned int irq)
+static int s5pc100_get_group(unsigned int irq)
 {
        irq -= S3C_IRQ_GPIO(0);
 
@@ -134,67 +134,67 @@ static int s5pc1xx_get_group(unsigned int irq)
        return -EINVAL;
 }
 
-static int s5pc1xx_get_offset(unsigned int irq)
+static int s5pc100_get_offset(unsigned int irq)
 {
        struct gpio_chip *chip = get_irq_data(irq);
        return irq - S3C_IRQ_GPIO(chip->base);
 }
 
-static void s5pc1xx_gpioint_ack(unsigned int irq)
+static void s5pc100_gpioint_ack(unsigned int irq)
 {
        int group, offset, pend_offset;
        unsigned int value;
 
-       group = s5pc1xx_get_group(irq);
-       offset = s5pc1xx_get_offset(irq);
+       group = s5pc100_get_group(irq);
+       offset = s5pc100_get_offset(irq);
        pend_offset = group_to_pend_offset(group);
 
-       value = __raw_readl(S5PC1XX_GPIOREG(PEND_OFFSET) + pend_offset);
+       value = __raw_readl(S5P_GPIOREG(PEND_OFFSET) + pend_offset);
        value |= 1 << offset;
-       __raw_writel(value, S5PC1XX_GPIOREG(PEND_OFFSET) + pend_offset);
+       __raw_writel(value, S5P_GPIOREG(PEND_OFFSET) + pend_offset);
 }
 
-static void s5pc1xx_gpioint_mask(unsigned int irq)
+static void s5pc100_gpioint_mask(unsigned int irq)
 {
        int group, offset, mask_offset;
        unsigned int value;
 
-       group = s5pc1xx_get_group(irq);
-       offset = s5pc1xx_get_offset(irq);
+       group = s5pc100_get_group(irq);
+       offset = s5pc100_get_offset(irq);
        mask_offset = group_to_mask_offset(group);
 
-       value = __raw_readl(S5PC1XX_GPIOREG(MASK_OFFSET) + mask_offset);
+       value = __raw_readl(S5P_GPIOREG(MASK_OFFSET) + mask_offset);
        value |= 1 << offset;
-       __raw_writel(value, S5PC1XX_GPIOREG(MASK_OFFSET) + mask_offset);
+       __raw_writel(value, S5P_GPIOREG(MASK_OFFSET) + mask_offset);
 }
 
-static void s5pc1xx_gpioint_unmask(unsigned int irq)
+static void s5pc100_gpioint_unmask(unsigned int irq)
 {
        int group, offset, mask_offset;
        unsigned int value;
 
-       group = s5pc1xx_get_group(irq);
-       offset = s5pc1xx_get_offset(irq);
+       group = s5pc100_get_group(irq);
+       offset = s5pc100_get_offset(irq);
        mask_offset = group_to_mask_offset(group);
 
-       value = __raw_readl(S5PC1XX_GPIOREG(MASK_OFFSET) + mask_offset);
+       value = __raw_readl(S5P_GPIOREG(MASK_OFFSET) + mask_offset);
        value &= ~(1 << offset);
-       __raw_writel(value, S5PC1XX_GPIOREG(MASK_OFFSET) + mask_offset);
+       __raw_writel(value, S5P_GPIOREG(MASK_OFFSET) + mask_offset);
 }
 
-static void s5pc1xx_gpioint_mask_ack(unsigned int irq)
+static void s5pc100_gpioint_mask_ack(unsigned int irq)
 {
-       s5pc1xx_gpioint_mask(irq);
-       s5pc1xx_gpioint_ack(irq);
+       s5pc100_gpioint_mask(irq);
+       s5pc100_gpioint_ack(irq);
 }
 
-static int s5pc1xx_gpioint_set_type(unsigned int irq, unsigned int type)
+static int s5pc100_gpioint_set_type(unsigned int irq, unsigned int type)
 {
        int group, offset, con_offset;
        unsigned int value;
 
-       group = s5pc1xx_get_group(irq);
-       offset = s5pc1xx_get_offset(irq);
+       group = s5pc100_get_group(irq);
+       offset = s5pc100_get_offset(irq);
        con_offset = group_to_con_offset(group);
 
        switch (type) {
@@ -221,24 +221,24 @@ static int s5pc1xx_gpioint_set_type(unsigned int irq, unsigned int type)
        }
 
 
-       value = __raw_readl(S5PC1XX_GPIOREG(CON_OFFSET) + con_offset);
+       value = __raw_readl(S5P_GPIOREG(CON_OFFSET) + con_offset);
        value &= ~(0xf << (offset * 0x4));
        value |= (type << (offset * 0x4));
-       __raw_writel(value, S5PC1XX_GPIOREG(CON_OFFSET) + con_offset);
+       __raw_writel(value, S5P_GPIOREG(CON_OFFSET) + con_offset);
 
        return 0;
 }
 
-struct irq_chip s5pc1xx_gpioint = {
+struct irq_chip s5pc100_gpioint = {
        .name           = "GPIO",
-       .ack            = s5pc1xx_gpioint_ack,
-       .mask           = s5pc1xx_gpioint_mask,
-       .mask_ack       = s5pc1xx_gpioint_mask_ack,
-       .unmask         = s5pc1xx_gpioint_unmask,
-       .set_type       = s5pc1xx_gpioint_set_type,
+       .ack            = s5pc100_gpioint_ack,
+       .mask           = s5pc100_gpioint_mask,
+       .mask_ack       = s5pc100_gpioint_mask_ack,
+       .unmask         = s5pc100_gpioint_unmask,
+       .set_type       = s5pc100_gpioint_set_type,
 };
 
-void s5pc1xx_irq_gpioint_handler(unsigned int irq, struct irq_desc *desc)
+void s5pc100_irq_gpioint_handler(unsigned int irq, struct irq_desc *desc)
 {
        int group, offset, pend_offset, mask_offset;
        int real_irq, group_end;
@@ -248,17 +248,17 @@ void s5pc1xx_irq_gpioint_handler(unsigned int irq, struct irq_desc *desc)
 
        for (group = 0; group < group_end; group++) {
                pend_offset = group_to_pend_offset(group);
-               pend = __raw_readl(S5PC1XX_GPIOREG(PEND_OFFSET) + pend_offset);
+               pend = __raw_readl(S5P_GPIOREG(PEND_OFFSET) + pend_offset);
                if (!pend)
                        continue;
 
                mask_offset = group_to_mask_offset(group);
-               mask = __raw_readl(S5PC1XX_GPIOREG(MASK_OFFSET) + mask_offset);
+               mask = __raw_readl(S5P_GPIOREG(MASK_OFFSET) + mask_offset);
                pend &= ~mask;
 
                for (offset = 0; offset < 8; offset++) {
                        if (pend & (1 << offset)) {
-                               real_irq = s5pc1xx_get_start(group) + offset;
+                               real_irq = s5pc100_get_start(group) + offset;
                                generic_handle_irq(S3C_IRQ_GPIO(real_irq));
                        }
                }
index bfe67db34f047ebd6c95d73c9bef8d5c77b5fb0c..af22f8202a0711b35f0f76929d364a9b05f2e49b 100644 (file)
 #include <plat/fb.h>
 #include <plat/iic.h>
 
-#define UCON (S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK)
-#define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB)
-#define UFCON (S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE)
+/* Following are default values for UCON, ULCON and UFCON UART registers */
+#define S5PC100_UCON_DEFAULT   (S3C2410_UCON_TXILEVEL |        \
+                                S3C2410_UCON_RXILEVEL |        \
+                                S3C2410_UCON_TXIRQMODE |       \
+                                S3C2410_UCON_RXIRQMODE |       \
+                                S3C2410_UCON_RXFIFO_TOI |      \
+                                S3C2443_UCON_RXERR_IRQEN)
+
+#define S5PC100_ULCON_DEFAULT  S3C2410_LCON_CS8
+
+#define S5PC100_UFCON_DEFAULT  (S3C2410_UFCON_FIFOMODE |       \
+                                S3C2440_UFCON_RXTRIG8 |        \
+                                S3C2440_UFCON_TXTRIG16)
 
 static struct s3c2410_uartcfg smdkc100_uartcfgs[] __initdata = {
        [0] = {
                .hwport      = 0,
                .flags       = 0,
-               .ucon        = 0x3c5,
-               .ulcon       = 0x03,
-               .ufcon       = 0x51,
+               .ucon        = S5PC100_UCON_DEFAULT,
+               .ulcon       = S5PC100_ULCON_DEFAULT,
+               .ufcon       = S5PC100_UFCON_DEFAULT,
        },
        [1] = {
                .hwport      = 1,
                .flags       = 0,
-               .ucon        = 0x3c5,
-               .ulcon       = 0x03,
-               .ufcon       = 0x51,
+               .ucon        = S5PC100_UCON_DEFAULT,
+               .ulcon       = S5PC100_ULCON_DEFAULT,
+               .ufcon       = S5PC100_UFCON_DEFAULT,
        },
        [2] = {
                .hwport      = 2,
                .flags       = 0,
-               .ucon        = 0x3c5,
-               .ulcon       = 0x03,
-               .ufcon       = 0x51,
+               .ucon        = S5PC100_UCON_DEFAULT,
+               .ulcon       = S5PC100_ULCON_DEFAULT,
+               .ufcon       = S5PC100_UFCON_DEFAULT,
        },
        [3] = {
                .hwport      = 3,
                .flags       = 0,
-               .ucon        = 0x3c5,
-               .ulcon       = 0x03,
-               .ufcon       = 0x51,
+               .ucon        = S5PC100_UCON_DEFAULT,
+               .ulcon       = S5PC100_ULCON_DEFAULT,
+               .ufcon       = S5PC100_UFCON_DEFAULT,
        },
 };
 
@@ -118,8 +128,7 @@ static struct platform_device smdkc100_lcd_powerdev = {
 static struct s3c_fb_pd_win smdkc100_fb_win0 = {
        /* this is to ensure we use win0 */
        .win_mode       = {
-               .refresh        = 70,
-               .pixclock       = (8+13+3+800)*(7+5+1+480),
+               .pixclock = 1000000000000ULL / ((8+13+3+800)*(7+5+1+480)*80),
                .left_margin    = 8,
                .right_margin   = 13,
                .upper_margin   = 7,
@@ -140,8 +149,6 @@ static struct s3c_fb_platdata smdkc100_lcd_pdata __initdata = {
        .setup_gpio     = s5pc100_fb_gpio_setup_24bpp,
 };
 
-static struct map_desc smdkc100_iodesc[] = {};
-
 static struct platform_device *smdkc100_devices[] __initdata = {
        &s3c_device_i2c0,
        &s3c_device_i2c1,
@@ -150,11 +157,13 @@ static struct platform_device *smdkc100_devices[] __initdata = {
        &s3c_device_hsmmc1,
        &s3c_device_hsmmc2,
        &smdkc100_lcd_powerdev,
+       &s5pc100_device_iis0,
+       &s5pc100_device_ac97,
 };
 
 static void __init smdkc100_map_io(void)
 {
-       s5pc1xx_init_io(smdkc100_iodesc, ARRAY_SIZE(smdkc100_iodesc));
+       s5p_init_io(NULL, 0, S5P_VA_CHIPID);
        s3c24xx_init_clocks(12000000);
        s3c24xx_init_uarts(smdkc100_uartcfgs, ARRAY_SIZE(smdkc100_uartcfgs));
 }
@@ -178,10 +187,9 @@ static void __init smdkc100_machine_init(void)
 
 MACHINE_START(SMDKC100, "SMDKC100")
        /* Maintainer: Byungho Min <bhmin@samsung.com> */
-       .phys_io        = S5PC100_PA_UART & 0xfff00000,
-       .io_pg_offst    = (((u32)S5PC1XX_VA_UART) >> 18) & 0xfffc,
-       .boot_params    = S5PC100_PA_SDRAM + 0x100,
-
+       .phys_io        = S3C_PA_UART & 0xfff00000,
+       .io_pg_offst    = (((u32)S3C_VA_UART) >> 18) & 0xfffc,
+       .boot_params    = S5P_PA_SDRAM + 0x100,
        .init_irq       = s5pc100_init_irq,
        .map_io         = smdkc100_map_io,
        .init_machine   = smdkc100_machine_init,
similarity index 95%
rename from arch/arm/plat-s5pc1xx/setup-sdhci-gpio.c
rename to arch/arm/mach-s5pc100/setup-sdhci-gpio.c
index 185c8941e6447d527b0be8ed772651dc7bd657c3..7769c760c9ef525eeec0ff7dd35a5403c31b7587 100644 (file)
@@ -1,8 +1,8 @@
-/* linux/arch/arm/plat-s5pc1xx/setup-sdhci-gpio.c
+/* linux/arch/arm/plat-s5pc100/setup-sdhci-gpio.c
  *
  * Copyright 2009 Samsung Eletronics
  *
- * S5PC1XX - Helper functions for setting up SDHCI device(s) GPIO (HSMMC)
+ * S5PC100 - Helper functions for setting up SDHCI device(s) GPIO (HSMMC)
  *
  * 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
index 7601c28e240b9e32aa2a5c2550a93a37a539f6d1..0761eac9aaea62ba93f7ded2088b2f183c925664 100644 (file)
@@ -13,18 +13,68 @@ config CPU_S5PV210
        bool
        select PLAT_S5P
        select S3C_PL330_DMA
+       select S5P_EXT_INT
        help
          Enable S5PV210 CPU support
 
-choice
-       prompt "Select machine type"
-       depends on ARCH_S5PV210
-       default MACH_SMDKV210
+config S5PV210_SETUP_I2C1
+       bool
+       help
+         Common setup code for i2c bus 1.
+
+config S5PV210_SETUP_I2C2
+       bool
+       help
+         Common setup code for i2c bus 2.
+
+config S5PV210_SETUP_FB_24BPP
+       bool
+       help
+          Common setup code for S5PV210 with an 24bpp RGB display helper.
+
+config S5PV210_SETUP_SDHCI
+        bool
+        select S5PV210_SETUP_SDHCI_GPIO
+        help
+          Internal helper functions for S5PV210 based SDHCI systems
+
+config S5PV210_SETUP_SDHCI_GPIO
+       bool
+       help
+         Common setup code for SDHCI gpio.
+
+# machine support
+
+config MACH_AQUILA
+       bool "Samsung Aquila"
+       select CPU_S5PV210
+       select ARCH_SPARSEMEM_ENABLE
+       select S5PV210_SETUP_FB_24BPP
+       select S3C_DEV_FB
+       help
+         Machine support for the Samsung Aquila target based on S5PC110 SoC
+
+config MACH_GONI
+       bool "GONI"
+       select CPU_S5PV210
+       select ARCH_SPARSEMEM_ENABLE
+       help
+         Machine support for Samsung GONI board
+         S5PC110(MCP) is one of package option of S5PV210
+
+config S5PC110_DEV_ONENAND
+       bool
+       help
+         Compile in platform device definition for OneNAND1 controller
 
 config MACH_SMDKV210
        bool "SMDKV210"
        select CPU_S5PV210
        select ARCH_SPARSEMEM_ENABLE
+       select SAMSUNG_DEV_ADC
+       select SAMSUNG_DEV_TS
+       select S3C_DEV_WDT
+       select HAVE_S3C2410_WATCHDOG
        help
          Machine support for Samsung SMDKV210
 
@@ -32,10 +82,10 @@ config MACH_SMDKC110
        bool "SMDKC110"
        select CPU_S5PV210
        select ARCH_SPARSEMEM_ENABLE
+       select S3C_DEV_WDT
+       select HAVE_S3C2410_WATCHDOG
        help
          Machine support for Samsung SMDKC110
          S5PC110(MCP) is one of package option of S5PV210
 
-endchoice
-
 endif
index 99827813d293afc96b545aac1b6cffcf5f43524b..30be9a6a462092c2120188241ed39122794f0a78 100644 (file)
@@ -17,9 +17,19 @@ obj-$(CONFIG_CPU_S5PV210)    += setup-i2c0.o
 
 # machine support
 
+obj-$(CONFIG_MACH_AQUILA)      += mach-aquila.o
 obj-$(CONFIG_MACH_SMDKV210)    += mach-smdkv210.o
 obj-$(CONFIG_MACH_SMDKC110)    += mach-smdkc110.o
+obj-$(CONFIG_MACH_GONI)                += mach-goni.o
 
 # device support
 
 obj-y                          += dev-audio.o
+obj-$(CONFIG_S3C64XX_DEV_SPI)  += dev-spi.o
+obj-$(CONFIG_S5PC110_DEV_ONENAND) += dev-onenand.o
+
+obj-$(CONFIG_S5PV210_SETUP_FB_24BPP)   += setup-fb-24bpp.o
+obj-$(CONFIG_S5PV210_SETUP_I2C1)       += setup-i2c1.o
+obj-$(CONFIG_S5PV210_SETUP_I2C2)       += setup-i2c2.o
+obj-$(CONFIG_S5PV210_SETUP_SDHCI)       += setup-sdhci.o
+obj-$(CONFIG_S5PV210_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o
index 2b776eb5d150367dea5a20ffae96c6a6c516e354..411a4a9cbfc79df156338febc880dbbb1b18737a 100644 (file)
@@ -32,6 +32,8 @@
 #include <plat/devs.h>
 #include <plat/clock.h>
 #include <plat/s5pv210.h>
+#include <plat/iic-core.h>
+#include <plat/sdhci.h>
 
 /* Initial IO mappings */
 
@@ -74,7 +76,21 @@ static void s5pv210_idle(void)
 
 void __init s5pv210_map_io(void)
 {
+#ifdef CONFIG_S3C_DEV_ADC
+       s3c_device_adc.name     = "s3c64xx-adc";
+#endif
+
        iotable_init(s5pv210_iodesc, ARRAY_SIZE(s5pv210_iodesc));
+
+       /* initialise device information early */
+       s5pv210_default_sdhci0();
+       s5pv210_default_sdhci1();
+       s5pv210_default_sdhci2();
+
+       /* the i2c devices are directly compatible with s3c2440 */
+       s3c_i2c0_setname("s3c2440-i2c");
+       s3c_i2c1_setname("s3c2440-i2c");
+       s3c_i2c2_setname("s3c2440-i2c");
 }
 
 void __init s5pv210_init_clocks(int xtal)
diff --git a/arch/arm/mach-s5pv210/dev-onenand.c b/arch/arm/mach-s5pv210/dev-onenand.c
new file mode 100644 (file)
index 0000000..34997b7
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * linux/arch/arm/mach-s5pv210/dev-onenand.c
+ *
+ *  Copyright (c) 2008-2010 Samsung Electronics
+ *  Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * S5PC110 series device definition for OneNAND devices
+ *
+ * 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/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/onenand.h>
+
+#include <mach/irqs.h>
+#include <mach/map.h>
+
+static struct resource s5pc110_onenand_resources[] = {
+       [0] = {
+               .start  = S5PC110_PA_ONENAND,
+               .end    = S5PC110_PA_ONENAND + SZ_128K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = S5PC110_PA_ONENAND_DMA,
+               .end    = S5PC110_PA_ONENAND_DMA + SZ_2K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+struct platform_device s5pc110_device_onenand = {
+       .name           = "s5pc110-onenand",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(s5pc110_onenand_resources),
+       .resource       = s5pc110_onenand_resources,
+};
+
+void s5pc110_onenand_set_platdata(struct onenand_platform_data *pdata)
+{
+       struct onenand_platform_data *pd;
+
+       pd = kmemdup(pdata, sizeof(struct onenand_platform_data), GFP_KERNEL);
+       if (!pd)
+               printk(KERN_ERR "%s: no memory for platform data\n", __func__);
+       s5pc110_device_onenand.dev.platform_data = pd;
+}
diff --git a/arch/arm/mach-s5pv210/dev-spi.c b/arch/arm/mach-s5pv210/dev-spi.c
new file mode 100644 (file)
index 0000000..337a62b
--- /dev/null
@@ -0,0 +1,178 @@
+/* linux/arch/arm/mach-s5pv210/dev-spi.c
+ *
+ * Copyright (C) 2010 Samsung Electronics Co. Ltd.
+ *     Jaswinder Singh <jassi.brar@samsung.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/platform_device.h>
+#include <linux/dma-mapping.h>
+
+#include <mach/dma.h>
+#include <mach/map.h>
+#include <mach/irqs.h>
+#include <mach/gpio.h>
+#include <mach/spi-clocks.h>
+
+#include <plat/s3c64xx-spi.h>
+#include <plat/gpio-cfg.h>
+
+static char *spi_src_clks[] = {
+       [S5PV210_SPI_SRCCLK_PCLK] = "pclk",
+       [S5PV210_SPI_SRCCLK_SCLK] = "sclk_spi",
+};
+
+/* SPI Controller platform_devices */
+
+/* Since we emulate multi-cs capability, we do not touch the CS.
+ * The emulated CS is toggled by board specific mechanism, as it can
+ * be either some immediate GPIO or some signal out of some other
+ * chip in between ... or some yet another way.
+ * We simply do not assume anything about CS.
+ */
+static int s5pv210_spi_cfg_gpio(struct platform_device *pdev)
+{
+       switch (pdev->id) {
+       case 0:
+               s3c_gpio_cfgpin(S5PV210_GPB(0), S3C_GPIO_SFN(2));
+               s3c_gpio_cfgpin(S5PV210_GPB(1), S3C_GPIO_SFN(2));
+               s3c_gpio_cfgpin(S5PV210_GPB(2), S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(S5PV210_GPB(0), S3C_GPIO_PULL_UP);
+               s3c_gpio_setpull(S5PV210_GPB(1), S3C_GPIO_PULL_UP);
+               s3c_gpio_setpull(S5PV210_GPB(2), S3C_GPIO_PULL_UP);
+               break;
+
+       case 1:
+               s3c_gpio_cfgpin(S5PV210_GPB(4), S3C_GPIO_SFN(2));
+               s3c_gpio_cfgpin(S5PV210_GPB(5), S3C_GPIO_SFN(2));
+               s3c_gpio_cfgpin(S5PV210_GPB(6), S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(S5PV210_GPB(4), S3C_GPIO_PULL_UP);
+               s3c_gpio_setpull(S5PV210_GPB(5), S3C_GPIO_PULL_UP);
+               s3c_gpio_setpull(S5PV210_GPB(6), S3C_GPIO_PULL_UP);
+               break;
+
+       default:
+               dev_err(&pdev->dev, "Invalid SPI Controller number!");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static struct resource s5pv210_spi0_resource[] = {
+       [0] = {
+               .start = S5PV210_PA_SPI0,
+               .end   = S5PV210_PA_SPI0 + 0x100 - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = DMACH_SPI0_TX,
+               .end   = DMACH_SPI0_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = DMACH_SPI0_RX,
+               .end   = DMACH_SPI0_RX,
+               .flags = IORESOURCE_DMA,
+       },
+       [3] = {
+               .start = IRQ_SPI0,
+               .end   = IRQ_SPI0,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct s3c64xx_spi_info s5pv210_spi0_pdata = {
+       .cfg_gpio = s5pv210_spi_cfg_gpio,
+       .fifo_lvl_mask = 0x1ff,
+       .rx_lvl_offset = 15,
+       .high_speed = 1,
+};
+
+static u64 spi_dmamask = DMA_BIT_MASK(32);
+
+struct platform_device s5pv210_device_spi0 = {
+       .name             = "s3c64xx-spi",
+       .id               = 0,
+       .num_resources    = ARRAY_SIZE(s5pv210_spi0_resource),
+       .resource         = s5pv210_spi0_resource,
+       .dev = {
+               .dma_mask               = &spi_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+               .platform_data = &s5pv210_spi0_pdata,
+       },
+};
+
+static struct resource s5pv210_spi1_resource[] = {
+       [0] = {
+               .start = S5PV210_PA_SPI1,
+               .end   = S5PV210_PA_SPI1 + 0x100 - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = DMACH_SPI1_TX,
+               .end   = DMACH_SPI1_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = DMACH_SPI1_RX,
+               .end   = DMACH_SPI1_RX,
+               .flags = IORESOURCE_DMA,
+       },
+       [3] = {
+               .start = IRQ_SPI1,
+               .end   = IRQ_SPI1,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct s3c64xx_spi_info s5pv210_spi1_pdata = {
+       .cfg_gpio = s5pv210_spi_cfg_gpio,
+       .fifo_lvl_mask = 0x7f,
+       .rx_lvl_offset = 15,
+       .high_speed = 1,
+};
+
+struct platform_device s5pv210_device_spi1 = {
+       .name             = "s3c64xx-spi",
+       .id               = 1,
+       .num_resources    = ARRAY_SIZE(s5pv210_spi1_resource),
+       .resource         = s5pv210_spi1_resource,
+       .dev = {
+               .dma_mask               = &spi_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+               .platform_data = &s5pv210_spi1_pdata,
+       },
+};
+
+void __init s5pv210_spi_set_info(int cntrlr, int src_clk_nr, int num_cs)
+{
+       struct s3c64xx_spi_info *pd;
+
+       /* Reject invalid configuration */
+       if (!num_cs || src_clk_nr < 0
+                       || src_clk_nr > S5PV210_SPI_SRCCLK_SCLK) {
+               printk(KERN_ERR "%s: Invalid SPI configuration\n", __func__);
+               return;
+       }
+
+       switch (cntrlr) {
+       case 0:
+               pd = &s5pv210_spi0_pdata;
+               break;
+       case 1:
+               pd = &s5pv210_spi1_pdata;
+               break;
+       default:
+               printk(KERN_ERR "%s: Invalid SPI controller(%d)\n",
+                                                       __func__, cntrlr);
+               return;
+       }
+
+       pd->num_cs = num_cs;
+       pd->src_clk_nr = src_clk_nr;
+       pd->src_clk_name = spi_src_clks[src_clk_nr];
+}
index 62c5175ef291485b67612d301e3f40a89dc66f3e..96895378ea27dd54dd3ae9b9ae87e21e0944ff3b 100644 (file)
 
 /* VIC0: System, DMA, Timer */
 
-#define IRQ_EINT0              S5P_IRQ_VIC0(0)
-#define IRQ_EINT1              S5P_IRQ_VIC0(1)
-#define IRQ_EINT2              S5P_IRQ_VIC0(2)
-#define IRQ_EINT3              S5P_IRQ_VIC0(3)
-#define IRQ_EINT4              S5P_IRQ_VIC0(4)
-#define IRQ_EINT5              S5P_IRQ_VIC0(5)
-#define IRQ_EINT6              S5P_IRQ_VIC0(6)
-#define IRQ_EINT7              S5P_IRQ_VIC0(7)
-#define IRQ_EINT8              S5P_IRQ_VIC0(8)
-#define IRQ_EINT9              S5P_IRQ_VIC0(9)
-#define IRQ_EINT10             S5P_IRQ_VIC0(10)
-#define IRQ_EINT11             S5P_IRQ_VIC0(11)
-#define IRQ_EINT12             S5P_IRQ_VIC0(12)
-#define IRQ_EINT13             S5P_IRQ_VIC0(13)
-#define IRQ_EINT14             S5P_IRQ_VIC0(14)
-#define IRQ_EINT15             S5P_IRQ_VIC0(15)
 #define IRQ_EINT16_31          S5P_IRQ_VIC0(16)
 #define IRQ_BATF               S5P_IRQ_VIC0(17)
 #define IRQ_MDMA               S5P_IRQ_VIC0(18)
 #define IRQ_MDNIE3             S5P_IRQ_VIC3(8)
 #define IRQ_VIC_END            S5P_IRQ_VIC3(31)
 
-#define S5P_IRQ_EINT_BASE      (IRQ_VIC_END + 1)
-
-#define S5P_EINT(x)            ((x) + S5P_IRQ_EINT_BASE)
-#define IRQ_EINT(x)            S5P_EINT(x)
+#define S5P_EINT_BASE1         (S5P_IRQ_VIC0(0))
+#define S5P_EINT_BASE2         (IRQ_VIC_END + 1)
 
 /* Set the default NR_IRQS */
+#define NR_IRQS                        (IRQ_EINT(31) + 1)
 
-#define NR_IRQS                (IRQ_EINT(31) + 1)
+/* Compatibility */
+#define IRQ_LCD_FIFO           IRQ_LCD0
+#define IRQ_LCD_VSYNC          IRQ_LCD1
+#define IRQ_LCD_SYSTEM         IRQ_LCD2
 
 #endif /* ASM_ARCH_IRQS_H */
index 5adcb9f26e449ef76504b10244cbd3570fb710dc..34eb168ec95038d946bc3e3bed0bec9c7353e60f 100644 (file)
@@ -16,6 +16,9 @@
 #include <plat/map-base.h>
 #include <plat/map-s5p.h>
 
+#define S5PC110_PA_ONENAND     (0xB0000000)
+#define S5PC110_PA_ONENAND_DMA (0xB0600000)
+
 #define S5PV210_PA_CHIPID      (0xE0000000)
 #define S5P_PA_CHIPID          S5PV210_PA_CHIPID
 
 #define S5PV210_PA_GPIO                (0xE0200000)
 #define S5P_PA_GPIO            S5PV210_PA_GPIO
 
+/* SPI */
+#define S5PV210_PA_SPI0                0xE1300000
+#define S5PV210_PA_SPI1                0xE1400000
+
 #define S5PV210_PA_IIC0                (0xE1800000)
+#define S5PV210_PA_IIC1                (0xFAB00000)
+#define S5PV210_PA_IIC2                (0xE1A00000)
 
 #define S5PV210_PA_TIMER       (0xE2500000)
 #define S5P_PA_TIMER           S5PV210_PA_TIMER
 
 #define S5PV210_PA_SYSTIMER    (0xE2600000)
 
+#define S5PV210_PA_WATCHDOG    (0xE2700000)
+
 #define S5PV210_PA_UART                (0xE2900000)
 
 #define S5P_PA_UART0           (S5PV210_PA_UART + 0x0)
 #define S5PV210_PA_PDMA0       0xE0900000
 #define S5PV210_PA_PDMA1       0xE0A00000
 
+#define S5PV210_PA_FB          (0xF8000000)
+
+#define S5PV210_PA_HSMMC(x)    (0xEB000000 + ((x) * 0x100000))
+
 #define S5PV210_PA_VIC0                (0xF2000000)
 #define S5P_PA_VIC0            S5PV210_PA_VIC0
 
 /* AC97 */
 #define S5PV210_PA_AC97                0xE2200000
 
+#define S5PV210_PA_ADC         (0xE1700000)
+
 /* compatibiltiy defines. */
 #define S3C_PA_UART            S5PV210_PA_UART
+#define S3C_PA_HSMMC0          S5PV210_PA_HSMMC(0)
+#define S3C_PA_HSMMC1          S5PV210_PA_HSMMC(1)
+#define S3C_PA_HSMMC2          S5PV210_PA_HSMMC(2)
 #define S3C_PA_IIC             S5PV210_PA_IIC0
+#define S3C_PA_IIC1            S5PV210_PA_IIC1
+#define S3C_PA_IIC2            S5PV210_PA_IIC2
+#define S3C_PA_FB              S5PV210_PA_FB
+#define S3C_PA_WDT             S5PV210_PA_WATCHDOG
+
+#define SAMSUNG_PA_ADC         S5PV210_PA_ADC
 
 #endif /* __ASM_ARCH_MAP_H */
index e56e0e4673ed49afc102f09ffdf7ee5b0c7bf74c..2a25ab40c863d3e41a1a14ede697a4647bc7c652 100644 (file)
 
 #define S5P_RST_STAT           S5P_CLKREG(0xA000)
 #define S5P_OSC_CON            S5P_CLKREG(0x8000)
+#define S5P_MDNIE_SEL          S5P_CLKREG(0x7008)
 #define S5P_MIPI_PHY_CON0      S5P_CLKREG(0x7200)
 #define S5P_MIPI_PHY_CON1      S5P_CLKREG(0x7204)
 #define S5P_MIPI_CONTROL       S5P_CLKREG(0xE814)
diff --git a/arch/arm/mach-s5pv210/include/mach/regs-fb.h b/arch/arm/mach-s5pv210/include/mach/regs-fb.h
new file mode 100644 (file)
index 0000000..60d9929
--- /dev/null
@@ -0,0 +1,21 @@
+/* 
+ * Copyright 2010 Ben Dooks <ben-linux@fluff.org>
+ *
+ * Dummy framebuffer to allow build for the moment.
+ * 
+ * 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 __ASM_ARCH_MACH_REGS_FB_H
+#define __ASM_ARCH_MACH_REGS_FB_H __FILE__
+
+#include <plat/regs-fb-v4.h>
+
+static inline unsigned int s3c_fb_pal_reg(unsigned int window, int reg)
+{
+       return 0x2400 + (window * 256 *4 ) + reg;
+}
+
+#endif /* __ASM_ARCH_MACH_REGS_FB_H */
diff --git a/arch/arm/mach-s5pv210/include/mach/regs-gpio.h b/arch/arm/mach-s5pv210/include/mach/regs-gpio.h
new file mode 100644 (file)
index 0000000..49e029b
--- /dev/null
@@ -0,0 +1,48 @@
+/* linux/arch/arm/mach-s5pv210/include/mach/regs-gpio.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * S5PV210 - GPIO (including EINT) register definitions
+ *
+ * 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 __ASM_ARCH_REGS_GPIO_H
+#define __ASM_ARCH_REGS_GPIO_H __FILE__
+
+#include <mach/map.h>
+
+#define S5PV210_EINT30CON              (S5P_VA_GPIO + 0xE00)
+#define S5P_EINT_CON(x)                        (S5PV210_EINT30CON + ((x) * 0x4))
+
+#define S5PV210_EINT30FLTCON0          (S5P_VA_GPIO + 0xE80)
+#define S5P_EINT_FLTCON(x)             (S5PV210_EINT30FLTCON0 + ((x) * 0x4))
+
+#define S5PV210_EINT30MASK             (S5P_VA_GPIO + 0xF00)
+#define S5P_EINT_MASK(x)               (S5PV210_EINT30MASK + ((x) * 0x4))
+
+#define S5PV210_EINT30PEND             (S5P_VA_GPIO + 0xF40)
+#define S5P_EINT_PEND(x)               (S5PV210_EINT30PEND + ((x) * 0x4))
+
+#define EINT_REG_NR(x)                 (EINT_OFFSET(x) >> 3)
+
+#define eint_irq_to_bit(irq)           (1 << (EINT_OFFSET(irq) & 0x7))
+
+/* values for S5P_EXTINT0 */
+#define S5P_EXTINT_LOWLEV              (0x00)
+#define S5P_EXTINT_HILEV               (0x01)
+#define S5P_EXTINT_FALLEDGE            (0x02)
+#define S5P_EXTINT_RISEEDGE            (0x03)
+#define S5P_EXTINT_BOTHEDGE            (0x04)
+
+#define EINT_MODE              S3C_GPIO_SFN(0xf)
+
+#define EINT_GPIO_0(x)         S5PV210_GPH0(x)
+#define EINT_GPIO_1(x)         S5PV210_GPH1(x)
+#define EINT_GPIO_2(x)         S5PV210_GPH2(x)
+#define EINT_GPIO_3(x)         S5PV210_GPH3(x)
+
+#endif /* __ASM_ARCH_REGS_GPIO_H */
diff --git a/arch/arm/mach-s5pv210/include/mach/spi-clocks.h b/arch/arm/mach-s5pv210/include/mach/spi-clocks.h
new file mode 100644 (file)
index 0000000..02acded
--- /dev/null
@@ -0,0 +1,17 @@
+/* linux/arch/arm/mach-s5pv210/include/mach/spi-clocks.h
+ *
+ * Copyright (C) 2010 Samsung Electronics Co. Ltd.
+ *     Jaswinder Singh <jassi.brar@samsung.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 __S5PV210_PLAT_SPI_CLKS_H
+#define __S5PV210_PLAT_SPI_CLKS_H __FILE__
+
+#define S5PV210_SPI_SRCCLK_PCLK                0
+#define S5PV210_SPI_SRCCLK_SCLK                1
+
+#endif /* __S5PV210_PLAT_SPI_CLKS_H */
diff --git a/arch/arm/mach-s5pv210/mach-aquila.c b/arch/arm/mach-s5pv210/mach-aquila.c
new file mode 100644 (file)
index 0000000..10bc76e
--- /dev/null
@@ -0,0 +1,149 @@
+/* linux/arch/arm/mach-s5pv210/mach-aquila.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.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/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/fb.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+#include <mach/regs-fb.h>
+
+#include <plat/regs-serial.h>
+#include <plat/s5pv210.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/fb.h>
+
+/* Following are default values for UCON, ULCON and UFCON UART registers */
+#define S5PV210_UCON_DEFAULT   (S3C2410_UCON_TXILEVEL |        \
+                                S3C2410_UCON_RXILEVEL |        \
+                                S3C2410_UCON_TXIRQMODE |       \
+                                S3C2410_UCON_RXIRQMODE |       \
+                                S3C2410_UCON_RXFIFO_TOI |      \
+                                S3C2443_UCON_RXERR_IRQEN)
+
+#define S5PV210_ULCON_DEFAULT  S3C2410_LCON_CS8
+
+#define S5PV210_UFCON_DEFAULT  (S3C2410_UFCON_FIFOMODE |       \
+                                S5PV210_UFCON_TXTRIG4 |        \
+                                S5PV210_UFCON_RXTRIG4)
+
+static struct s3c2410_uartcfg smdkv210_uartcfgs[] __initdata = {
+       [0] = {
+               .hwport         = 0,
+               .flags          = 0,
+               .ucon           = S5PV210_UCON_DEFAULT,
+               .ulcon          = S5PV210_ULCON_DEFAULT,
+               .ufcon          = S5PV210_UFCON_DEFAULT,
+       },
+       [1] = {
+               .hwport         = 1,
+               .flags          = 0,
+               .ucon           = S5PV210_UCON_DEFAULT,
+               .ulcon          = S5PV210_ULCON_DEFAULT,
+               .ufcon          = S5PV210_UFCON_DEFAULT,
+       },
+       [2] = {
+               .hwport         = 2,
+               .flags          = 0,
+               .ucon           = S5PV210_UCON_DEFAULT,
+               .ulcon          = S5PV210_ULCON_DEFAULT,
+               .ufcon          = S5PV210_UFCON_DEFAULT,
+       },
+       [3] = {
+               .hwport         = 3,
+               .flags          = 0,
+               .ucon           = S5PV210_UCON_DEFAULT,
+               .ulcon          = S5PV210_ULCON_DEFAULT,
+               .ufcon          = S5PV210_UFCON_DEFAULT,
+       },
+};
+
+/* Frame Buffer */
+static struct s3c_fb_pd_win aquila_fb_win0 = {
+       .win_mode = {
+               .pixclock = 1000000000000ULL / ((16+16+2+480)*(28+3+2+800)*60),
+               .left_margin = 16,
+               .right_margin = 16,
+               .upper_margin = 3,
+               .lower_margin = 28,
+               .hsync_len = 2,
+               .vsync_len = 2,
+               .xres = 480,
+               .yres = 800,
+       },
+       .max_bpp = 32,
+       .default_bpp = 16,
+};
+
+static struct s3c_fb_pd_win aquila_fb_win1 = {
+       .win_mode = {
+               .pixclock = 1000000000000ULL / ((16+16+2+480)*(28+3+2+800)*60),
+               .left_margin = 16,
+               .right_margin = 16,
+               .upper_margin = 3,
+               .lower_margin = 28,
+               .hsync_len = 2,
+               .vsync_len = 2,
+               .xres = 480,
+               .yres = 800,
+       },
+       .max_bpp = 32,
+       .default_bpp = 16,
+};
+
+static struct s3c_fb_platdata aquila_lcd_pdata __initdata = {
+       .win[0]         = &aquila_fb_win0,
+       .win[1]         = &aquila_fb_win1,
+       .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
+       .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC |
+                         VIDCON1_INV_VCLK | VIDCON1_INV_VDEN,
+       .setup_gpio     = s5pv210_fb_gpio_setup_24bpp,
+};
+
+static struct platform_device *aquila_devices[] __initdata = {
+       &s3c_device_fb,
+};
+
+static void __init aquila_map_io(void)
+{
+       s5p_init_io(NULL, 0, S5P_VA_CHIPID);
+       s3c24xx_init_clocks(24000000);
+       s3c24xx_init_uarts(smdkv210_uartcfgs, ARRAY_SIZE(smdkv210_uartcfgs));
+}
+
+static void __init aquila_machine_init(void)
+{
+       /* FB */
+       s3c_fb_set_platdata(&aquila_lcd_pdata);
+
+       platform_add_devices(aquila_devices, ARRAY_SIZE(aquila_devices));
+}
+
+MACHINE_START(AQUILA, "Aquila")
+       /* Maintainers:
+          Marek Szyprowski <m.szyprowski@samsung.com>
+          Kyungmin Park <kyungmin.park@samsung.com> */
+       .phys_io        = S3C_PA_UART & 0xfff00000,
+       .io_pg_offst    = (((u32)S3C_VA_UART) >> 18) & 0xfffc,
+       .boot_params    = S5P_PA_SDRAM + 0x100,
+       .init_irq       = s5pv210_init_irq,
+       .map_io         = aquila_map_io,
+       .init_machine   = aquila_machine_init,
+       .timer          = &s3c24xx_timer,
+MACHINE_END
diff --git a/arch/arm/mach-s5pv210/mach-goni.c b/arch/arm/mach-s5pv210/mach-goni.c
new file mode 100644 (file)
index 0000000..4863b13
--- /dev/null
@@ -0,0 +1,98 @@
+/* linux/arch/arm/mach-s5pv210/mach-goni.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.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/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+
+#include <plat/regs-serial.h>
+#include <plat/s5pv210.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+
+/* Following are default values for UCON, ULCON and UFCON UART registers */
+#define S5PV210_UCON_DEFAULT   (S3C2410_UCON_TXILEVEL |        \
+                                S3C2410_UCON_RXILEVEL |        \
+                                S3C2410_UCON_TXIRQMODE |       \
+                                S3C2410_UCON_RXIRQMODE |       \
+                                S3C2410_UCON_RXFIFO_TOI |      \
+                                S3C2443_UCON_RXERR_IRQEN)
+
+#define S5PV210_ULCON_DEFAULT  S3C2410_LCON_CS8
+
+#define S5PV210_UFCON_DEFAULT  (S3C2410_UFCON_FIFOMODE |       \
+                                S5PV210_UFCON_TXTRIG4 |        \
+                                S5PV210_UFCON_RXTRIG4)
+
+static struct s3c2410_uartcfg goni_uartcfgs[] __initdata = {
+       [0] = {
+               .hwport         = 0,
+               .flags          = 0,
+               .ucon           = S5PV210_UCON_DEFAULT,
+               .ulcon          = S5PV210_ULCON_DEFAULT,
+               .ufcon          = S5PV210_UFCON_DEFAULT,
+       },
+       [1] = {
+               .hwport         = 1,
+               .flags          = 0,
+               .ucon           = S5PV210_UCON_DEFAULT,
+               .ulcon          = S5PV210_ULCON_DEFAULT,
+               .ufcon          = S5PV210_UFCON_DEFAULT,
+       },
+       [2] = {
+               .hwport         = 2,
+               .flags          = 0,
+               .ucon           = S5PV210_UCON_DEFAULT,
+               .ulcon          = S5PV210_ULCON_DEFAULT,
+               .ufcon          = S5PV210_UFCON_DEFAULT,
+       },
+       [3] = {
+               .hwport         = 3,
+               .flags          = 0,
+               .ucon           = S5PV210_UCON_DEFAULT,
+               .ulcon          = S5PV210_ULCON_DEFAULT,
+               .ufcon          = S5PV210_UFCON_DEFAULT,
+       },
+};
+
+static struct platform_device *goni_devices[] __initdata = {
+};
+
+static void __init goni_map_io(void)
+{
+       s5p_init_io(NULL, 0, S5P_VA_CHIPID);
+       s3c24xx_init_clocks(24000000);
+       s3c24xx_init_uarts(goni_uartcfgs, ARRAY_SIZE(goni_uartcfgs));
+}
+
+static void __init goni_machine_init(void)
+{
+       platform_add_devices(goni_devices, ARRAY_SIZE(goni_devices));
+}
+
+MACHINE_START(GONI, "GONI")
+       /* Maintainers: Kyungmin Park <kyungmin.park@samsung.com> */
+       .phys_io        = S3C_PA_UART & 0xfff00000,
+       .io_pg_offst    = (((u32)S3C_VA_UART) >> 18) & 0xfffc,
+       .boot_params    = S5P_PA_SDRAM + 0x100,
+       .init_irq       = s5pv210_init_irq,
+       .map_io         = goni_map_io,
+       .init_machine   = goni_machine_init,
+       .timer          = &s3c24xx_timer,
+MACHINE_END
index 6f9fd3274e2e3196d18a213a40c43f89a768a989..4c8903c6d1044af2488a4d58421d64b7194b3c0e 100644 (file)
@@ -74,6 +74,7 @@ static struct s3c2410_uartcfg smdkv210_uartcfgs[] __initdata = {
 static struct platform_device *smdkc110_devices[] __initdata = {
        &s5pv210_device_iis0,
        &s5pv210_device_ac97,
+       &s3c_device_wdt,
 };
 
 static void __init smdkc110_map_io(void)
index 3c29e18528a5f3df6067e33b39b8506829f5fa56..0d462794804066afb6d705ca47c3005681bc7410 100644 (file)
@@ -25,6 +25,8 @@
 #include <plat/s5pv210.h>
 #include <plat/devs.h>
 #include <plat/cpu.h>
+#include <plat/adc.h>
+#include <plat/ts.h>
 
 /* Following are default values for UCON, ULCON and UFCON UART registers */
 #define S5PV210_UCON_DEFAULT   (S3C2410_UCON_TXILEVEL |        \
@@ -74,6 +76,15 @@ static struct s3c2410_uartcfg smdkv210_uartcfgs[] __initdata = {
 static struct platform_device *smdkv210_devices[] __initdata = {
        &s5pv210_device_iis0,
        &s5pv210_device_ac97,
+       &s3c_device_adc,
+       &s3c_device_ts,
+       &s3c_device_wdt,
+};
+
+static struct s3c2410_ts_mach_info s3c_ts_platform __initdata = {
+       .delay                  = 10000,
+       .presc                  = 49,
+       .oversampling_shift     = 2,
 };
 
 static void __init smdkv210_map_io(void)
@@ -85,6 +96,7 @@ static void __init smdkv210_map_io(void)
 
 static void __init smdkv210_machine_init(void)
 {
+       s3c24xx_ts_set_platdata(&s3c_ts_platform);
        platform_add_devices(smdkv210_devices, ARRAY_SIZE(smdkv210_devices));
 }
 
diff --git a/arch/arm/mach-s5pv210/setup-fb-24bpp.c b/arch/arm/mach-s5pv210/setup-fb-24bpp.c
new file mode 100644 (file)
index 0000000..a50cbac
--- /dev/null
@@ -0,0 +1,62 @@
+/* linux/arch/arm/plat-s5pv210/setup-fb-24bpp.c
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * Base s5pv210 setup information for 24bpp LCD framebuffer
+ *
+ * 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/kernel.h>
+#include <linux/types.h>
+#include <linux/fb.h>
+
+#include <mach/regs-fb.h>
+#include <mach/gpio.h>
+#include <mach/map.h>
+#include <plat/fb.h>
+#include <mach/regs-clock.h>
+#include <plat/gpio-cfg.h>
+
+void s5pv210_fb_gpio_setup_24bpp(void)
+{
+       unsigned int gpio = 0;
+
+       for (gpio = S5PV210_GPF0(0); gpio <= S5PV210_GPF0(7); gpio++) {
+               s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+               s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
+       }
+
+       for (gpio = S5PV210_GPF1(0); gpio <= S5PV210_GPF1(7); gpio++) {
+               s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+               s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
+       }
+
+       for (gpio = S5PV210_GPF2(0); gpio <= S5PV210_GPF2(7); gpio++) {
+               s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+               s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
+       }
+
+       for (gpio = S5PV210_GPF3(0); gpio <= S5PV210_GPF3(3); gpio++) {
+               s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+               s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
+       }
+
+       /* Set DISPLAY_CONTROL register for Display path selection.
+        *
+        * ouput   |   RGB   |   I80   |   ITU
+        * -----------------------------------
+        *  00     |   MIE   |  FIMD   |  FIMD
+        *  01     | MDNIE   | MDNIE   |  FIMD
+        *  10     |  FIMD   |  FIMD   |  FIMD
+        *  11     |  FIMD   |  FIMD   |  FIMD
+        */
+       writel(0x2, S5P_MDNIE_SEL);
+}
index 9ec6845840e561e108b6f7dfe635be00d0029643..c718253c70b8e2d6016dd24d0a8fa7f495efb467 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/mach-s5pv210/setup-i2c0.c
  *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
  *             http://www.samsung.com/
  *
  * I2C0 GPIO configuration.
 
 struct platform_device; /* don't need the contents */
 
+#include <mach/gpio.h>
 #include <plat/iic.h>
+#include <plat/gpio-cfg.h>
 
 void s3c_i2c0_cfg_gpio(struct platform_device *dev)
 {
-       /* Will be populated later */
+       s3c_gpio_cfgpin(S5PV210_GPD1(0), S3C_GPIO_SFN(2));
+       s3c_gpio_setpull(S5PV210_GPD1(0), S3C_GPIO_PULL_UP);
+       s3c_gpio_cfgpin(S5PV210_GPD1(1), S3C_GPIO_SFN(2));
+       s3c_gpio_setpull(S5PV210_GPD1(1), S3C_GPIO_PULL_UP);
 }
diff --git a/arch/arm/mach-s5pv210/setup-i2c1.c b/arch/arm/mach-s5pv210/setup-i2c1.c
new file mode 100644 (file)
index 0000000..45e0e6e
--- /dev/null
@@ -0,0 +1,30 @@
+/* linux/arch/arm/mach-s5pv210/setup-i2c1.c
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * I2C1 GPIO configuration.
+ *
+ * Based on plat-s3c64xx/setup-i2c1.c
+ *
+ * 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/kernel.h>
+#include <linux/types.h>
+
+struct platform_device; /* don't need the contents */
+
+#include <mach/gpio.h>
+#include <plat/iic.h>
+#include <plat/gpio-cfg.h>
+
+void s3c_i2c1_cfg_gpio(struct platform_device *dev)
+{
+       s3c_gpio_cfgpin(S5PV210_GPD1(2), S3C_GPIO_SFN(2));
+       s3c_gpio_setpull(S5PV210_GPD1(2), S3C_GPIO_PULL_UP);
+       s3c_gpio_cfgpin(S5PV210_GPD1(3), S3C_GPIO_SFN(2));
+       s3c_gpio_setpull(S5PV210_GPD1(3), S3C_GPIO_PULL_UP);
+}
diff --git a/arch/arm/mach-s5pv210/setup-i2c2.c b/arch/arm/mach-s5pv210/setup-i2c2.c
new file mode 100644 (file)
index 0000000..b11b4bf
--- /dev/null
@@ -0,0 +1,30 @@
+/* linux/arch/arm/mach-s5pv210/setup-i2c2.c
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * I2C2 GPIO configuration.
+ *
+ * Based on plat-s3c64xx/setup-i2c0.c
+ *
+ * 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/kernel.h>
+#include <linux/types.h>
+
+struct platform_device; /* don't need the contents */
+
+#include <mach/gpio.h>
+#include <plat/iic.h>
+#include <plat/gpio-cfg.h>
+
+void s3c_i2c2_cfg_gpio(struct platform_device *dev)
+{
+       s3c_gpio_cfgpin(S5PV210_GPD1(4), S3C_GPIO_SFN(2));
+       s3c_gpio_setpull(S5PV210_GPD1(4), S3C_GPIO_PULL_UP);
+       s3c_gpio_cfgpin(S5PV210_GPD1(5), S3C_GPIO_SFN(2));
+       s3c_gpio_setpull(S5PV210_GPD1(5), S3C_GPIO_PULL_UP);
+}
diff --git a/arch/arm/mach-s5pv210/setup-sdhci-gpio.c b/arch/arm/mach-s5pv210/setup-sdhci-gpio.c
new file mode 100644 (file)
index 0000000..fe7d86d
--- /dev/null
@@ -0,0 +1,104 @@
+/* linux/arch/arm/plat-s5pc1xx/setup-sdhci-gpio.c
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * S5PV210 - Helper functions for setting up SDHCI device(s) GPIO (HSMMC)
+ *
+ * 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/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+
+#include <mach/gpio.h>
+#include <plat/gpio-cfg.h>
+#include <plat/regs-sdhci.h>
+
+void s5pv210_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width)
+{
+       unsigned int gpio;
+
+       /* Set all the necessary GPG0/GPG1 pins to special-function 2 */
+       for (gpio = S5PV210_GPG0(0); gpio < S5PV210_GPG0(2); gpio++) {
+               s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+       }
+       switch (width) {
+       case 8:
+               /* GPG1[3:6] special-funtion 3 */
+               for (gpio = S5PV210_GPG1(3); gpio <= S5PV210_GPG1(6); gpio++) {
+                       s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3));
+                       s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+               }
+       case 4:
+               /* GPG0[3:6] special-funtion 2 */
+               for (gpio = S5PV210_GPG0(3); gpio <= S5PV210_GPG0(6); gpio++) {
+                       s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+                       s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+               }
+       default:
+               break;
+       }
+
+       s3c_gpio_setpull(S5PV210_GPG0(2), S3C_GPIO_PULL_UP);
+       s3c_gpio_cfgpin(S5PV210_GPG0(2), S3C_GPIO_SFN(2));
+}
+
+void s5pv210_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width)
+{
+       unsigned int gpio;
+
+       /* Set all the necessary GPG1[0:1] pins to special-function 2 */
+       for (gpio = S5PV210_GPG1(0); gpio < S5PV210_GPG1(2); gpio++) {
+               s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+       }
+
+       /* Data pin GPG1[3:6] to special-function 2 */
+       for (gpio = S5PV210_GPG1(3); gpio <= S5PV210_GPG1(6); gpio++) {
+               s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+       }
+
+       s3c_gpio_setpull(S5PV210_GPG1(2), S3C_GPIO_PULL_UP);
+       s3c_gpio_cfgpin(S5PV210_GPG1(2), S3C_GPIO_SFN(2));
+}
+
+void s5pv210_setup_sdhci2_cfg_gpio(struct platform_device *dev, int width)
+{
+       unsigned int gpio;
+
+       /* Set all the necessary GPG2[0:1] pins to special-function 2 */
+       for (gpio = S5PV210_GPG2(0); gpio < S5PV210_GPG2(2); gpio++) {
+               s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+       }
+
+       switch (width) {
+       case 8:
+               /* Data pin GPG3[3:6] to special-function 3 */
+               for (gpio = S5PV210_GPG3(3); gpio <= S5PV210_GPG3(6); gpio++) {
+                       s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3));
+                       s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+               }
+       case 4:
+               /* Data pin GPG2[3:6] to special-function 2 */
+               for (gpio = S5PV210_GPG2(3); gpio <= S5PV210_GPG2(6); gpio++) {
+                       s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+                       s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+               }
+       default:
+               break;
+       }
+
+       s3c_gpio_setpull(S5PV210_GPG2(2), S3C_GPIO_PULL_UP);
+       s3c_gpio_cfgpin(S5PV210_GPG2(2), S3C_GPIO_SFN(2));
+}
diff --git a/arch/arm/mach-s5pv210/setup-sdhci.c b/arch/arm/mach-s5pv210/setup-sdhci.c
new file mode 100644 (file)
index 0000000..51815ec
--- /dev/null
@@ -0,0 +1,63 @@
+/* linux/arch/arm/mach-s5pv210/setup-sdhci.c
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * S5PV210 - Helper functions for settign up SDHCI device(s) (HSMMC)
+ *
+ * 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/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+
+#include <plat/regs-sdhci.h>
+#include <plat/sdhci.h>
+
+/* clock sources for the mmc bus clock, order as for the ctrl2[5..4] */
+
+char *s5pv210_hsmmc_clksrcs[4] = {
+       [0] = "hsmmc",          /* HCLK */
+       [1] = "hsmmc",          /* HCLK */
+       [2] = "sclk_mmc",       /* mmc_bus */
+       /*[4] = reserved */
+};
+
+void s5pv210_setup_sdhci_cfg_card(struct platform_device *dev,
+                                   void __iomem *r,
+                                   struct mmc_ios *ios,
+                                   struct mmc_card *card)
+{
+       u32 ctrl2, ctrl3;
+
+       /* don't need to alter anything acording to card-type */
+
+       writel(S3C64XX_SDHCI_CONTROL4_DRIVE_9mA, r + S3C64XX_SDHCI_CONTROL4);
+
+       ctrl2 = readl(r + S3C_SDHCI_CONTROL2);
+       ctrl2 &= S3C_SDHCI_CTRL2_SELBASECLK_MASK;
+       ctrl2 |= (S3C64XX_SDHCI_CTRL2_ENSTAASYNCCLR |
+                 S3C64XX_SDHCI_CTRL2_ENCMDCNFMSK |
+                 S3C_SDHCI_CTRL2_ENFBCLKRX |
+                 S3C_SDHCI_CTRL2_DFCNT_NONE |
+                 S3C_SDHCI_CTRL2_ENCLKOUTHOLD);
+
+       if (ios->clock < 25 * 1000000)
+               ctrl3 = (S3C_SDHCI_CTRL3_FCSEL3 |
+                        S3C_SDHCI_CTRL3_FCSEL2 |
+                        S3C_SDHCI_CTRL3_FCSEL1 |
+                        S3C_SDHCI_CTRL3_FCSEL0);
+       else
+               ctrl3 = (S3C_SDHCI_CTRL3_FCSEL1 | S3C_SDHCI_CTRL3_FCSEL0);
+
+       writel(ctrl2, r + S3C_SDHCI_CONTROL2);
+       writel(ctrl3, r + S3C_SDHCI_CONTROL3);
+}
index 4cf7c565aaedf80cd93d508c7bcf4926d152e052..bbfe197fb4d6274c19734a94ba2d9e7b8ddd0978 100644 (file)
@@ -2,7 +2,7 @@
  * linux/arch/arm/mach-sa1100/leds.c
  *
  * SA1100 LEDs dispatcher
- * 
+ *
  * Copyright (C) 2001 Nicolas Pitre
  */
 #include <linux/compiler.h>
@@ -18,10 +18,10 @@ sa1100_leds_init(void)
 {
        if (machine_is_assabet())
                leds_event = assabet_leds_event;
-       if (machine_is_consus())
-               leds_event = consus_leds_event;
+       if (machine_is_consus())
+               leds_event = consus_leds_event;
        if (machine_is_badge4())
-               leds_event = badge4_leds_event;
+               leds_event = badge4_leds_event;
        if (machine_is_brutus())
                leds_event = brutus_leds_event;
        if (machine_is_cerf())
index 37a7112d4117ee1e0e75b9ae6e58ea72d82c8baf..89d175ce74d2c3626b838770d250c802f937d4b5 100644 (file)
 static int __init shark_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 {
        if (dev->bus->number == 0)
-               if (dev->devfn == 0) return 255;
-               else return 11;
-       else return 255;
+               if (dev->devfn == 0)
+                       return 255;
+               else
+                       return 11;
+       else
+               return 255;
 }
 
 extern void __init via82c505_preinit(void);
 
 static struct hw_pci shark_pci __initdata = {
        .setup          = via82c505_setup,
-       .swizzle        = pci_std_swizzle,
+       .swizzle        = pci_std_swizzle,
        .map_irq        = shark_map_irq,
        .nr_controllers = 1,
        .scan           = via82c505_scan_bus,
index b67e571d4bf7956813bef9bef7f1d9adb30f29da..baf6bcc3169c6f0f9ff817ca374e0dcd05eee0b9 100644 (file)
@@ -13,7 +13,6 @@
 
 #include <linux/types.h>
 #include <linux/amba/pl061.h>
-#include <linux/types.h>
 #include <linux/ptrace.h>
 #include <linux/io.h>
 #include <asm/hardware/vic.h>
index e2958eb567f9f1e5a2047f0dc4aebd7327adaba3..b2eda4dc1c34ea7172a773899275c18bbfab5dd4 100644 (file)
@@ -423,6 +423,33 @@ void  nuc900_fb_set_platdata(struct nuc900fb_mach_info *pd)
 }
 #endif
 
+/* AUDIO controller*/
+static u64 nuc900_device_audio_dmamask = -1;
+static struct resource nuc900_ac97_resource[] = {
+       [0] = {
+               .start = W90X900_PA_ACTL,
+               .end   = W90X900_PA_ACTL + W90X900_SZ_ACTL - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_ACTL,
+               .end   = IRQ_ACTL,
+               .flags = IORESOURCE_IRQ,
+       }
+
+};
+
+struct platform_device nuc900_device_audio = {
+       .name           = "nuc900-audio",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(nuc900_ac97_resource),
+       .resource       = nuc900_ac97_resource,
+       .dev              = {
+               .dma_mask               = &nuc900_device_audio_dmamask,
+               .coherent_dma_mask      = -1,
+       }
+};
+
 /*Here should be your evb resourse,such as LCD*/
 
 static struct platform_device *nuc900_public_dev[] __initdata = {
@@ -434,6 +461,7 @@ static struct platform_device *nuc900_public_dev[] __initdata = {
        &nuc900_device_emc,
        &nuc900_device_spi,
        &nuc900_device_wdt,
+       &nuc900_device_audio,
 };
 
 /* Provide adding specific CPU platform devices API */
diff --git a/arch/arm/mach-w90x900/include/mach/mfp.h b/arch/arm/mach-w90x900/include/mach/mfp.h
new file mode 100644 (file)
index 0000000..94c0e71
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * arch/arm/mach-w90x900/include/mach/mfp.h
+ *
+ * Copyright (c) 2010 Nuvoton technology corporation.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * Based on arch/arm/mach-s3c2410/include/mach/map.h
+ *
+ * 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 __ASM_ARCH_MFP_H
+#define __ASM_ARCH_MFP_H
+
+extern void mfp_set_groupf(struct device *dev);
+extern void mfp_set_groupc(struct device *dev);
+extern void mfp_set_groupi(struct device *dev);
+extern void mfp_set_groupg(struct device *dev);
+
+#endif /* __ASM_ARCH_MFP_H */
index a47dc9a708ee0a29aaa4c62009f0344c07c9e93b..fb7fb627b1a564ca920fdb747080988f3fb75551 100644 (file)
 
 #define GPIOG0TO1      (0x03 << 14)
 #define GPIOG2TO3      (0x03 << 16)
+#define GPIOG22TO23    (0x03 << 22)
+
 #define ENSPI          (0x0a << 14)
 #define ENI2C0         (0x01 << 14)
 #define ENI2C1         (0x01 << 16)
+#define ENAC97         (0x02 << 22)
 
 static DEFINE_MUTEX(mfp_mutex);
 
@@ -146,6 +149,9 @@ void mfp_set_groupg(struct device *dev)
        } else if (strcmp(dev_id, "nuc900-i2c1") == 0) {
                mfpen &= ~(GPIOG2TO3);
                mfpen |= ENI2C1;/*enable i2c1*/
+       } else if (strcmp(dev_id, "nuc900-audio") == 0) {
+               mfpen &= ~(GPIOG22TO23);
+               mfpen |= ENAC97;/*enable AC97*/
        } else {
                mfpen &= ~(GPIOG0TO1 | GPIOG2TO3);/*GPIOG[3:0]*/
        }
index 06a90dcfc60a6f0cc0b88d5a02bfefdbfeb8610a..37c8157e116e8aa54dc8cdf4ffddf1e4f8bda0f3 100644 (file)
@@ -91,7 +91,11 @@ ENTRY(v7_flush_kern_cache_all)
  THUMB(        stmfd   sp!, {r4-r7, r9-r11, lr}        )
        bl      v7_flush_dcache_all
        mov     r0, #0
+#ifdef CONFIG_SMP
+       mcr     p15, 0, r0, c7, c1, 0           @ invalidate I-cache inner shareable
+#else
        mcr     p15, 0, r0, c7, c5, 0           @ I+BTB cache invalidate
+#endif
  ARM(  ldmfd   sp!, {r4-r5, r7, r9-r11, lr}    )
  THUMB(        ldmfd   sp!, {r4-r7, r9-r11, lr}        )
        mov     pc, lr
index eeb5a7c5ff0974b24fc51cb65b32bd131b9dd7f5..fa8028b1e1cf3a6f7dbfa2af346e3b1897a9033b 100644 (file)
@@ -72,7 +72,7 @@
 1998-11-23  Scott Bambrough  <scottb@netwinder.org>
 
        * README.FPE - fix typo in description of lfm/sfm instructions
-       * NOTES - Added file to describe known bugs/problems 
+       * NOTES - Added file to describe known bugs/problems
        * fpmodule.c - Changed version number to 0.94
 
 1998-11-20  Scott Bambrough  <scottb@netwinder.org>
index 859b300d89fde4f9aa8498483a29691059129408..bd425dc13b616b69d868d7520d3fe6e79bf445dc 100644 (file)
@@ -30,7 +30,7 @@ one byte.
        EXCEPTION TRAP ENABLE BYTE
        SYSTEM CONTROL BYTE
        CUMULATIVE EXCEPTION FLAGS BYTE
-       
+
 The FPCR is a 32 bit register consisting of bit flags.
 */
 
index cb0b638744824344f26672b854b56e86ddf00e2d..2a8646173c2f57b3270bfde937095efb606e3135 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
+ * Copyright (C) 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
 #define MX35_H1_TLL_BIT                (1 << 5)
 #define MX35_H1_USBTE_BIT      (1 << 4)
 
-int mxc_set_usbcontrol(int port, unsigned int flags)
+#define MXC_OTG_OFFSET         0
+#define MXC_H1_OFFSET          0x200
+
+/* USB_CTRL */
+#define MXC_OTG_UCTRL_OWIE_BIT         (1 << 27)       /* OTG wakeup intr enable */
+#define MXC_OTG_UCTRL_OPM_BIT          (1 << 24)       /* OTG power mask */
+#define MXC_H1_UCTRL_H1UIE_BIT         (1 << 12)       /* Host1 ULPI interrupt enable */
+#define MXC_H1_UCTRL_H1WIE_BIT         (1 << 11)       /* HOST1 wakeup intr enable */
+#define MXC_H1_UCTRL_H1PM_BIT          (1 <<  8)               /* HOST1 power mask */
+
+/* USB_PHY_CTRL_FUNC */
+#define MXC_OTG_PHYCTRL_OC_DIS_BIT     (1 << 8)        /* OTG Disable Overcurrent Event */
+#define MXC_H1_OC_DIS_BIT                      (1 << 5)        /* UH1 Disable Overcurrent Event */
+
+#define MXC_USBCMD_OFFSET                      0x140
+
+/* USBCMD */
+#define MXC_UCMD_ITC_NO_THRESHOLD_MASK (~(0xff << 16)) /* Interrupt Threshold Control */
+
+int mxc_initialize_usb_hw(int port, unsigned int flags)
 {
        unsigned int v;
 #ifdef CONFIG_ARCH_MX3
@@ -186,9 +206,85 @@ int mxc_set_usbcontrol(int port, unsigned int flags)
                return 0;
        }
 #endif /* CONFIG_MACH_MX27 */
+#ifdef CONFIG_ARCH_MX51
+       if (cpu_is_mx51()) {
+               void __iomem *usb_base;
+               u32 usbotg_base;
+               u32 usbother_base;
+               int ret = 0;
+
+               usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K);
+
+               switch (port) {
+               case 0: /* OTG port */
+                       usbotg_base = usb_base + MXC_OTG_OFFSET;
+                       break;
+               case 1: /* Host 1 port */
+                       usbotg_base = usb_base + MXC_H1_OFFSET;
+                       break;
+               default:
+                       printk(KERN_ERR"%s no such port %d\n", __func__, port);
+                       ret = -ENOENT;
+                       goto error;
+               }
+               usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET;
+
+               switch (port) {
+               case 0: /*OTG port */
+                       if (flags & MXC_EHCI_INTERNAL_PHY) {
+                               v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET);
+
+                               if (flags & MXC_EHCI_POWER_PINS_ENABLED)
+                                       v |= (MXC_OTG_PHYCTRL_OC_DIS_BIT | MXC_OTG_UCTRL_OPM_BIT); /* OC/USBPWR is not used */
+                               else
+                                       v &= ~(MXC_OTG_PHYCTRL_OC_DIS_BIT | MXC_OTG_UCTRL_OPM_BIT); /* OC/USBPWR is used */
+                               __raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET);
+
+                               v = __raw_readl(usbother_base + MXC_USBCTRL_OFFSET);
+                               if (flags & MXC_EHCI_WAKEUP_ENABLED)
+                                       v |= MXC_OTG_UCTRL_OWIE_BIT;/* OTG wakeup enable */
+                               else
+                                       v &= ~MXC_OTG_UCTRL_OWIE_BIT;/* OTG wakeup disable */
+                               __raw_writel(v, usbother_base + MXC_USBCTRL_OFFSET);
+                       }
+                       break;
+               case 1: /* Host 1 */
+                       /*Host ULPI */
+                       v = __raw_readl(usbother_base + MXC_USBCTRL_OFFSET);
+                       if (flags & MXC_EHCI_WAKEUP_ENABLED)
+                               v &= ~(MXC_H1_UCTRL_H1WIE_BIT | MXC_H1_UCTRL_H1UIE_BIT);/* HOST1 wakeup/ULPI intr disable */
+                       else
+                               v &= ~(MXC_H1_UCTRL_H1WIE_BIT | MXC_H1_UCTRL_H1UIE_BIT);/* HOST1 wakeup/ULPI intr disable */
+
+                       if (flags & MXC_EHCI_POWER_PINS_ENABLED)
+                               v &= ~MXC_H1_UCTRL_H1PM_BIT; /* HOST1 power mask used*/
+                       else
+                               v |= MXC_H1_UCTRL_H1PM_BIT; /* HOST1 power mask used*/
+                       __raw_writel(v, usbother_base + MXC_USBCTRL_OFFSET);
+
+                       v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET);
+                       if (flags & MXC_EHCI_POWER_PINS_ENABLED)
+                               v &= ~MXC_H1_OC_DIS_BIT; /* OC is used */
+                       else
+                               v |= MXC_H1_OC_DIS_BIT; /* OC is not used */
+                       __raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET);
+
+                       v = __raw_readl(usbotg_base + MXC_USBCMD_OFFSET);
+                       if (flags & MXC_EHCI_ITC_NO_THRESHOLD)
+                               /* Interrupt Threshold Control:Immediate (no threshold) */
+                               v &= MXC_UCMD_ITC_NO_THRESHOLD_MASK;
+                       __raw_writel(v, usbotg_base + MXC_USBCMD_OFFSET);
+                       break;
+               }
+
+error:
+               iounmap(usb_base);
+               return ret;
+       }
+#endif
        printk(KERN_WARNING
                "%s() unable to setup USBCONTROL for this CPU\n", __func__);
        return -EINVAL;
 }
-EXPORT_SYMBOL(mxc_set_usbcontrol);
+EXPORT_SYMBOL(mxc_initialize_usb_hw);
 
index 70b23893f0943630f1f515ba8ee7bd2542c7152c..71437c61cfd70f65e1aafd73095faf3718e3e8e3 100644 (file)
@@ -3,7 +3,7 @@
  * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
  *
  * Based on code from Freescale,
- * Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2004-2010 Freescale Semiconductor, Inc. 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
@@ -38,7 +38,6 @@ static int gpio_table_size;
 #define GPIO_ICR2      (cpu_is_mx1_mx2() ? 0x2C : 0x10)
 #define GPIO_IMR       (cpu_is_mx1_mx2() ? 0x30 : 0x14)
 #define GPIO_ISR       (cpu_is_mx1_mx2() ? 0x34 : 0x18)
-#define GPIO_ISR       (cpu_is_mx1_mx2() ? 0x34 : 0x18)
 
 #define GPIO_INT_LOW_LEV       (cpu_is_mx1_mx2() ? 0x3 : 0x0)
 #define GPIO_INT_HIGH_LEV      (cpu_is_mx1_mx2() ? 0x2 : 0x1)
@@ -289,7 +288,7 @@ int __init mxc_gpio_init(struct mxc_gpio_port *port, int cnt)
                /* its a serious configuration bug when it fails */
                BUG_ON( gpiochip_add(&port[i].chip) < 0 );
 
-               if (cpu_is_mx1() || cpu_is_mx3() || cpu_is_mx25()) {
+               if (cpu_is_mx1() || cpu_is_mx3() || cpu_is_mx25() || cpu_is_mx51()) {
                        /* setup one handler for each entry */
                        set_irq_chained_handler(port[i].irq, mx3_gpio_irq_handler);
                        set_irq_data(port[i].irq, &port[i]);
index fc5fec9b55f0d650c83034fba25ba981738b7921..36ff3cedee1a1d3cd3d7ffbc1c32ab185ed1cdcf 100644 (file)
@@ -26,6 +26,7 @@ enum mx31moboard_boards {
        MX31DEVBOARD    = 1,
        MX31MARXBOT     = 2,
        MX31SMARTBOT    = 3,
+       MX31EYEBOT      = 4,
 };
 
 /*
@@ -35,7 +36,7 @@ enum mx31moboard_boards {
 
 extern void mx31moboard_devboard_init(void);
 extern void mx31moboard_marxbot_init(void);
-extern void mx31moboard_smartbot_init(void);
+extern void mx31moboard_smartbot_init(int board);
 
 #endif
 
index e51465d7b2248ef4ae330c2152589504f12b607a..cbaed295a2bfdf699728d2bdb69ed5443165c9db 100644 (file)
@@ -719,6 +719,23 @@ enum iomux_pins {
 #define MX31_PIN_SRXD5__SRXD5          IOMUX_MODE(MX31_PIN_SRXD5, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_SCK5__SCK5            IOMUX_MODE(MX31_PIN_SCK5, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_SFS5__SFS5            IOMUX_MODE(MX31_PIN_SFS5, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_KEY_ROW0_KEY_ROW0     IOMUX_MODE(MX31_PIN_KEY_ROW0, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_KEY_ROW1_KEY_ROW1     IOMUX_MODE(MX31_PIN_KEY_ROW1, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_KEY_ROW2_KEY_ROW2     IOMUX_MODE(MX31_PIN_KEY_ROW2, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_KEY_ROW3_KEY_ROW3     IOMUX_MODE(MX31_PIN_KEY_ROW3, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_KEY_ROW4_KEY_ROW4     IOMUX_MODE(MX31_PIN_KEY_ROW4, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_KEY_ROW5_KEY_ROW5     IOMUX_MODE(MX31_PIN_KEY_ROW5, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_KEY_ROW6_KEY_ROW6     IOMUX_MODE(MX31_PIN_KEY_ROW6, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_KEY_ROW7_KEY_ROW7     IOMUX_MODE(MX31_PIN_KEY_ROW7, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_KEY_COL0_KEY_COL0     IOMUX_MODE(MX31_PIN_KEY_COL0, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_KEY_COL1_KEY_COL1     IOMUX_MODE(MX31_PIN_KEY_COL1, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_KEY_COL2_KEY_COL2     IOMUX_MODE(MX31_PIN_KEY_COL2, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_KEY_COL3_KEY_COL3     IOMUX_MODE(MX31_PIN_KEY_COL3, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_KEY_COL4_KEY_COL4     IOMUX_MODE(MX31_PIN_KEY_COL4, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_KEY_COL5_KEY_COL5     IOMUX_MODE(MX31_PIN_KEY_COL5, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_KEY_COL6_KEY_COL6     IOMUX_MODE(MX31_PIN_KEY_COL6, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_KEY_COL7_KEY_COL7     IOMUX_MODE(MX31_PIN_KEY_COL7, IOMUX_CONFIG_FUNC)
+
 
 /*
  * XXX: The SS0, SS1, SS2, SS3 lines of spi3 are multiplexed with cspi2_ss0,
index b4f975e6a665696f2d4fa96c8e8fe6ddefb7875b..ab0f95d953d02539ab76e69973056814a79ffcd4 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2009-2010 Amit Kucheria <amit.kucheria@canonical.com>
+ * Copyright (C) 2010 Freescale Semiconductor, Inc.
  *
  * The code contained herein is licensed under the GNU General Public
  * License. You may obtain a copy of the GNU General Public License
@@ -37,6 +38,11 @@ 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_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)
+#define MX51_GPIO_PAD_CTRL             (PAD_CTL_DSE_HIGH | PAD_CTL_PKE | \
+                               PAD_CTL_SRE_FAST)
 
 /*
  * The naming convention for the pad modes is MX51_PAD_<padname>__<padmode>
@@ -57,6 +63,7 @@ typedef enum iomux_config {
 #define MX51_PAD_GPIO_2_3__EIM_D19     IOMUX_PAD(0x3fc, 0x068, 1, 0x0,   0, NO_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)
 #define MX51_PAD_GPIO_2_6__EIM_D22     IOMUX_PAD(0x408, 0x074, 1, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_GPIO_2_7__EIM_D23     IOMUX_PAD(0x40c, 0x078, 1, 0x0,   0, NO_PAD_CTRL)
 
@@ -208,18 +215,19 @@ typedef enum iomux_config {
 #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_GPIO_1_25__USBH1_CLK  IOMUX_PAD(0x678, 0x278, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_26__USBH1_DIR  IOMUX_PAD(0x67C, 0x27C, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_27__USBH1_STP  IOMUX_PAD(0x680, 0x280, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_28__USBH1_NXT  IOMUX_PAD(0x684, 0x284, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_11__USBH1_DATA0        IOMUX_PAD(0x688, 0x288, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_12__USBH1_DATA1        IOMUX_PAD(0x68C, 0x28C, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_13__USBH1_DATA2        IOMUX_PAD(0x690, 0x290, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_14__USBH1_DATA3        IOMUX_PAD(0x694, 0x294, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_15__USBH1_DATA4        IOMUX_PAD(0x698, 0x298, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_16__USBH1_DATA5        IOMUX_PAD(0x69C, 0x29C, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_17__USBH1_DATA6        IOMUX_PAD(0x6A0, 0x2A0, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_18__USBH1_DATA7        IOMUX_PAD(0x6A4, 0x2A4, 2, 0x0, 0, NO_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)
+#define MX51_PAD_USBH1_STP__GPIO_1_27  IOMUX_PAD(0x680, 0x280, IOMUX_CONFIG_GPIO, 0x0, 0, MX51_USBH1_PAD_CTRL)
+#define MX51_PAD_USBH1_NXT__USBH1_NXT  IOMUX_PAD(0x684, 0x284, IOMUX_CONFIG_ALT0, 0x0, 0, MX51_USBH1_PAD_CTRL)
+#define MX51_PAD_USBH1_DATA0__USBH1_DATA0      IOMUX_PAD(0x688, 0x288, IOMUX_CONFIG_ALT0, 0x0, 0, MX51_USBH1_PAD_CTRL)
+#define MX51_PAD_USBH1_DATA1__USBH1_DATA1      IOMUX_PAD(0x68C, 0x28C, IOMUX_CONFIG_ALT0, 0x0, 0, MX51_USBH1_PAD_CTRL)
+#define MX51_PAD_USBH1_DATA2__USBH1_DATA2      IOMUX_PAD(0x690, 0x290, IOMUX_CONFIG_ALT0, 0x0, 0, MX51_USBH1_PAD_CTRL)
+#define MX51_PAD_USBH1_DATA3__USBH1_DATA3      IOMUX_PAD(0x694, 0x294, IOMUX_CONFIG_ALT0, 0x0, 0, MX51_USBH1_PAD_CTRL)
+#define MX51_PAD_USBH1_DATA4__USBH1_DATA4      IOMUX_PAD(0x698, 0x298, IOMUX_CONFIG_ALT0, 0x0, 0, MX51_USBH1_PAD_CTRL)
+#define MX51_PAD_USBH1_DATA5__USBH1_DATA5      IOMUX_PAD(0x69C, 0x29C, IOMUX_CONFIG_ALT0, 0x0, 0, MX51_USBH1_PAD_CTRL)
+#define MX51_PAD_USBH1_DATA6__USBH1_DATA6      IOMUX_PAD(0x6A0, 0x2A0, IOMUX_CONFIG_ALT0, 0x0, 0, MX51_USBH1_PAD_CTRL)
+#define MX51_PAD_USBH1_DATA7__USBH1_DATA7      IOMUX_PAD(0x6A4, 0x2A4, IOMUX_CONFIG_ALT0, 0x0, 0, MX51_USBH1_PAD_CTRL)
 #define MX51_PAD_GPIO_3_0__DI1_PIN11   IOMUX_PAD(0x6A8, 0x2A8, 4, 0x0, 0, NO_PAD_CTRL)
 #define MX51_PAD_GPIO_3_1__DI1_PIN12   IOMUX_PAD(0x6AC, 0x2AC, 4, 0x0, 0, NO_PAD_CTRL)
 #define MX51_PAD_GPIO_3_2__DI1_PIN13   IOMUX_PAD(0x6B0, 0x2B0, 4, 0x0, 0, NO_PAD_CTRL)
@@ -299,7 +307,7 @@ typedef enum iomux_config {
 #define MX51_PAD_GPIO_1_4__GPIO1_4     IOMUX_PAD(0x804, 0x3D8, 0, 0x0, 0, NO_PAD_CTRL)
 #define MX51_PAD_GPIO_1_5__GPIO1_5     IOMUX_PAD(0x808, 0x3DC, 0, 0x0, 0, NO_PAD_CTRL)
 #define MX51_PAD_GPIO_1_6__GPIO1_6     IOMUX_PAD(0x80C, 0x3E0, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_7__GPIO1_7     IOMUX_PAD(0x810, 0x3E4, 0, 0x0, 0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO_1_7__GPIO1_7     IOMUX_PAD(0x810, 0x3E4, 0, 0x0, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_GPIO_1_8__GPIO1_8     IOMUX_PAD(0x814, 0x3E8, 0, 0x0, 1, \
                                                (PAD_CTL_SRE_SLOW | PAD_CTL_DSE_MED | PAD_CTL_PUS_100K_UP |  PAD_CTL_HYS))
 #define MX51_PAD_GPIO_1_9__GPIO1_9     IOMUX_PAD(0x818, 0x3EC, 0, 0x0, 0, NO_PAD_CTRL)
index 4b9b8368c0c08d6d0e8d31a04638997760ec2c59..7fc5f9946199ef66f0353fbd83b78101cee469eb 100644 (file)
 #define MXC_EHCI_INTERNAL_PHY          (1 << 7)
 #define MXC_EHCI_IPPUE_DOWN            (1 << 8)
 #define MXC_EHCI_IPPUE_UP              (1 << 9)
+#define MXC_EHCI_WAKEUP_ENABLED        (1 << 10)
+#define MXC_EHCI_ITC_NO_THRESHOLD      (1 << 11)
+
+#define MXC_USBCTRL_OFFSET             0
+#define MXC_USB_PHY_CTR_FUNC_OFFSET    0x8
+#define MXC_USB_PHY_CTR_FUNC2_OFFSET   0xc
+
+#define MX5_USBOTHER_REGS_OFFSET       0x800
+
+/* USB_PHY_CTRL_FUNC2*/
+#define MX5_USB_UTMI_PHYCTRL1_PLLDIV_MASK              0x3
+#define MX5_USB_UTMI_PHYCTRL1_PLLDIV_SHIFT             0
 
 struct mxc_usbh_platform_data {
        int (*init)(struct platform_device *pdev);
@@ -35,7 +47,7 @@ struct mxc_usbh_platform_data {
        struct otg_transceiver  *otg;
 };
 
-int mxc_set_usbcontrol(int port, unsigned int flags);
+int mxc_initialize_usb_hw(int port, unsigned int flags);
 
 #endif /* __INCLUDE_ASM_ARCH_MXC_EHCI_H */
 
index c1ce51abdba612b31a1dd8760f62ce22c2e23d8f..f9a1b059a76cde1926f50758200c046f27685e7d 100644 (file)
 #define MX2_TSTAT_COMP         (1 << 0)
 
 /* MX31, MX35, MX25, MXC91231, MX5 */
-#define MX3_TCTL_WAITEN                (1 << 3) /* Wait enable mode */
-#define MX3_TCTL_CLK_IPG       (1 << 6)
-#define MX3_TCTL_FRR           (1 << 9)
-#define MX3_IR                 0x0c
-#define MX3_TSTAT              0x08
-#define MX3_TSTAT_OF1          (1 << 0)
-#define MX3_TCN                        0x24
-#define MX3_TCMP               0x10
+#define V2_TCTL_WAITEN         (1 << 3) /* Wait enable mode */
+#define V2_TCTL_CLK_IPG                (1 << 6)
+#define V2_TCTL_FRR            (1 << 9)
+#define V2_IR                  0x0c
+#define V2_TSTAT               0x08
+#define V2_TSTAT_OF1           (1 << 0)
+#define V2_TCN                 0x24
+#define V2_TCMP                        0x10
 
 #define timer_is_v1()  (cpu_is_mx1() || cpu_is_mx21() || cpu_is_mx27())
 #define timer_is_v2()  (!timer_is_v1())
@@ -76,7 +76,7 @@ static inline void gpt_irq_disable(void)
        unsigned int tmp;
 
        if (timer_is_v2())
-               __raw_writel(0, timer_base + MX3_IR);
+               __raw_writel(0, timer_base + V2_IR);
        else {
                tmp = __raw_readl(timer_base + MXC_TCTL);
                __raw_writel(tmp & ~MX1_2_TCTL_IRQEN, timer_base + MXC_TCTL);
@@ -86,7 +86,7 @@ static inline void gpt_irq_disable(void)
 static inline void gpt_irq_enable(void)
 {
        if (timer_is_v2())
-               __raw_writel(1<<0, timer_base + MX3_IR);
+               __raw_writel(1<<0, timer_base + V2_IR);
        else {
                __raw_writel(__raw_readl(timer_base + MXC_TCTL) | MX1_2_TCTL_IRQEN,
                        timer_base + MXC_TCTL);
@@ -102,7 +102,7 @@ static void gpt_irq_acknowledge(void)
                        __raw_writel(MX2_TSTAT_CAPT | MX2_TSTAT_COMP,
                                timer_base + MX1_2_TSTAT);
        } else if (timer_is_v2())
-               __raw_writel(MX3_TSTAT_OF1, timer_base + MX3_TSTAT);
+               __raw_writel(V2_TSTAT_OF1, timer_base + V2_TSTAT);
 }
 
 static cycle_t mx1_2_get_cycles(struct clocksource *cs)
@@ -110,9 +110,9 @@ static cycle_t mx1_2_get_cycles(struct clocksource *cs)
        return __raw_readl(timer_base + MX1_2_TCN);
 }
 
-static cycle_t mx3_get_cycles(struct clocksource *cs)
+static cycle_t v2_get_cycles(struct clocksource *cs)
 {
-       return __raw_readl(timer_base + MX3_TCN);
+       return __raw_readl(timer_base + V2_TCN);
 }
 
 static struct clocksource clocksource_mxc = {
@@ -129,7 +129,7 @@ static int __init mxc_clocksource_init(struct clk *timer_clk)
        unsigned int c = clk_get_rate(timer_clk);
 
        if (timer_is_v2())
-               clocksource_mxc.read = mx3_get_cycles;
+               clocksource_mxc.read = v2_get_cycles;
 
        clocksource_mxc.mult = clocksource_hz2mult(c,
                                        clocksource_mxc.shift);
@@ -153,16 +153,16 @@ static int mx1_2_set_next_event(unsigned long evt,
                                -ETIME : 0;
 }
 
-static int mx3_set_next_event(unsigned long evt,
+static int v2_set_next_event(unsigned long evt,
                              struct clock_event_device *unused)
 {
        unsigned long tcmp;
 
-       tcmp = __raw_readl(timer_base + MX3_TCN) + evt;
+       tcmp = __raw_readl(timer_base + V2_TCN) + evt;
 
-       __raw_writel(tcmp, timer_base + MX3_TCMP);
+       __raw_writel(tcmp, timer_base + V2_TCMP);
 
-       return (int)(tcmp - __raw_readl(timer_base + MX3_TCN)) < 0 ?
+       return (int)(tcmp - __raw_readl(timer_base + V2_TCN)) < 0 ?
                                -ETIME : 0;
 }
 
@@ -192,8 +192,8 @@ static void mxc_set_mode(enum clock_event_mode mode,
        if (mode != clockevent_mode) {
                /* Set event time into far-far future */
                if (timer_is_v2())
-                       __raw_writel(__raw_readl(timer_base + MX3_TCN) - 3,
-                                       timer_base + MX3_TCMP);
+                       __raw_writel(__raw_readl(timer_base + V2_TCN) - 3,
+                                       timer_base + V2_TCMP);
                else
                        __raw_writel(__raw_readl(timer_base + MX1_2_TCN) - 3,
                                        timer_base + MX1_2_TCMP);
@@ -245,7 +245,7 @@ static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id)
        uint32_t tstat;
 
        if (timer_is_v2())
-               tstat = __raw_readl(timer_base + MX3_TSTAT);
+               tstat = __raw_readl(timer_base + V2_TSTAT);
        else
                tstat = __raw_readl(timer_base + MX1_2_TSTAT);
 
@@ -276,7 +276,7 @@ static int __init mxc_clockevent_init(struct clk *timer_clk)
        unsigned int c = clk_get_rate(timer_clk);
 
        if (timer_is_v2())
-               clockevent_mxc.set_next_event = mx3_set_next_event;
+               clockevent_mxc.set_next_event = v2_set_next_event;
 
        clockevent_mxc.mult = div_sc(c, NSEC_PER_SEC,
                                        clockevent_mxc.shift);
@@ -308,7 +308,7 @@ void __init mxc_timer_init(struct clk *timer_clk, void __iomem *base, int irq)
        __raw_writel(0, timer_base + MXC_TPRER); /* see datasheet note */
 
        if (timer_is_v2())
-               tctl_val = MX3_TCTL_CLK_IPG | MX3_TCTL_FRR | MX3_TCTL_WAITEN | MXC_TCTL_TEN;
+               tctl_val = V2_TCTL_CLK_IPG | V2_TCTL_FRR | V2_TCTL_WAITEN | MXC_TCTL_TEN;
        else
                tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 | MXC_TCTL_TEN;
 
index afa6709db0b347c0010671c7f5a189d4086fb809..9b86d2a60d43789a22d644105981815169123dd7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C)2004-2010 Freescale Semiconductor, Inc. All Rights Reserved.
  *
  * The code contained herein is licensed under the GNU General Public
  * License. You may obtain a copy of the GNU General Public License
@@ -19,6 +19,7 @@
 #include <asm/mach/irq.h>
 
 #include <mach/hardware.h>
+#include <mach/common.h>
 
 /*
  *****************************************
@@ -144,6 +145,7 @@ void __init tzic_init_irq(void __iomem *irqbase)
                set_irq_handler(i, handle_level_irq);
                set_irq_flags(i, IRQF_VALID);
        }
+       mxc_register_gpios();
 
        pr_info("TrustZone Interrupt Controller (TZIC) initialized\n");
 }
index dc2ac42d63195f0dbe6c3b7acd964eef117e9661..393e9219a5b68afe61f6416c3fac531cc188cefc 100644 (file)
@@ -624,79 +624,58 @@ do {      \
        __raw_writel(l, base + reg); \
 } while(0)
 
-void omap_set_gpio_debounce(int gpio, int enable)
+/**
+ * _set_gpio_debounce - low level gpio debounce time
+ * @bank: the gpio bank we're acting upon
+ * @gpio: the gpio number on this @gpio
+ * @debounce: debounce time to use
+ *
+ * OMAP's debounce time is in 31us steps so we need
+ * to convert and round up to the closest unit.
+ */
+static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio,
+               unsigned debounce)
 {
-       struct gpio_bank *bank;
-       void __iomem *reg;
-       unsigned long flags;
-       u32 val, l = 1 << get_gpio_index(gpio);
+       void __iomem            *reg = bank->base;
+       u32                     val;
+       u32                     l;
+
+       if (debounce < 32)
+               debounce = 0x01;
+       else if (debounce > 7936)
+               debounce = 0xff;
+       else
+               debounce = (debounce / 0x1f) - 1;
 
-       if (cpu_class_is_omap1())
-               return;
+       l = 1 << get_gpio_index(gpio);
 
-       bank = get_gpio_bank(gpio);
-       reg = bank->base;
+       if (cpu_is_omap44xx())
+               reg += OMAP4_GPIO_DEBOUNCINGTIME;
+       else
+               reg += OMAP24XX_GPIO_DEBOUNCE_VAL;
+
+       __raw_writel(debounce, reg);
 
+       reg = bank->base;
        if (cpu_is_omap44xx())
                reg += OMAP4_GPIO_DEBOUNCENABLE;
        else
                reg += OMAP24XX_GPIO_DEBOUNCE_EN;
 
-       if (!(bank->mod_usage & l)) {
-               printk(KERN_ERR "GPIO %d not requested\n", gpio);
-               return;
-       }
-
-       spin_lock_irqsave(&bank->lock, flags);
        val = __raw_readl(reg);
 
-       if (enable && !(val & l))
+       if (debounce) {
                val |= l;
-       else if (!enable && (val & l))
-               val &= ~l;
-       else
-               goto done;
-
-       if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
-               bank->dbck_enable_mask = val;
-               if (enable)
+               if (cpu_is_omap34xx() || cpu_is_omap44xx())
                        clk_enable(bank->dbck);
-               else
+       } else {
+               val &= ~l;
+               if (cpu_is_omap34xx() || cpu_is_omap44xx())
                        clk_disable(bank->dbck);
        }
 
        __raw_writel(val, reg);
-done:
-       spin_unlock_irqrestore(&bank->lock, flags);
 }
-EXPORT_SYMBOL(omap_set_gpio_debounce);
-
-void omap_set_gpio_debounce_time(int gpio, int enc_time)
-{
-       struct gpio_bank *bank;
-       void __iomem *reg;
-
-       if (cpu_class_is_omap1())
-               return;
-
-       bank = get_gpio_bank(gpio);
-       reg = bank->base;
-
-       if (!bank->mod_usage) {
-               printk(KERN_ERR "GPIO not requested\n");
-               return;
-       }
-
-       enc_time &= 0xff;
-
-       if (cpu_is_omap44xx())
-               reg += OMAP4_GPIO_DEBOUNCINGTIME;
-       else
-               reg += OMAP24XX_GPIO_DEBOUNCE_VAL;
-
-       __raw_writel(enc_time, reg);
-}
-EXPORT_SYMBOL(omap_set_gpio_debounce_time);
 
 #ifdef CONFIG_ARCH_OMAP2PLUS
 static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio,
@@ -1656,6 +1635,20 @@ static int gpio_output(struct gpio_chip *chip, unsigned offset, int value)
        return 0;
 }
 
+static int gpio_debounce(struct gpio_chip *chip, unsigned offset,
+               unsigned debounce)
+{
+       struct gpio_bank *bank;
+       unsigned long flags;
+
+       bank = container_of(chip, struct gpio_bank, chip);
+       spin_lock_irqsave(&bank->lock, flags);
+       _set_gpio_debounce(bank, offset, debounce);
+       spin_unlock_irqrestore(&bank->lock, flags);
+
+       return 0;
+}
+
 static void gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
        struct gpio_bank *bank;
@@ -1909,6 +1902,7 @@ static int __init _omap_gpio_init(void)
                bank->chip.direction_input = gpio_input;
                bank->chip.get = gpio_get;
                bank->chip.direction_output = gpio_output;
+               bank->chip.set_debounce = gpio_debounce;
                bank->chip.set = gpio_set;
                bank->chip.to_irq = gpio_2irq;
                if (bank_is_mpuio(bank)) {
index 58583732b29a30a2eee8076e3960602b2b3263c9..452e18438b41b21546e5ae52c7b0b25e74078032 100644 (file)
@@ -234,32 +234,6 @@ void __init s3c24xx_udc_set_platdata(struct s3c2410_udc_mach_info *pd)
        }
 }
 
-
-/* Watchdog */
-
-static struct resource s3c_wdt_resource[] = {
-       [0] = {
-               .start = S3C24XX_PA_WATCHDOG,
-               .end   = S3C24XX_PA_WATCHDOG + S3C24XX_SZ_WATCHDOG - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start = IRQ_WDT,
-               .end   = IRQ_WDT,
-               .flags = IORESOURCE_IRQ,
-       }
-
-};
-
-struct platform_device s3c_device_wdt = {
-       .name             = "s3c2410-wdt",
-       .id               = -1,
-       .num_resources    = ARRAY_SIZE(s3c_wdt_resource),
-       .resource         = s3c_wdt_resource,
-};
-
-EXPORT_SYMBOL(s3c_device_wdt);
-
 /* IIS */
 
 static struct resource s3c_iis_resource[] = {
index 92bd75607b436f5ede6f38a72989ba952a42d619..11d6a1bbd90d4e34bb68fbca4cd2c05fd5d562ba 100644 (file)
@@ -7,7 +7,7 @@
 
 config PLAT_S5P
        bool
-       depends on (ARCH_S5P6440 || ARCH_S5P6442 || ARCH_S5PV210)
+       depends on (ARCH_S5P6440 || ARCH_S5P6442 || ARCH_S5PC100 || ARCH_S5PV210)
        default y
        select ARM_VIC
        select NO_IOPORT
@@ -24,3 +24,9 @@ config PLAT_S5P
        select SAMSUNG_IRQ_UART
        help
          Base platform code for Samsung's S5P series SoC.
+
+config S5P_EXT_INT
+       bool
+       help
+         Use the external interrupts (other than GPIO interrupts.)
+         Note: Do not choose this for S5P6440.
index 0ec09a9c36bd6d8e5e4c9af2ed7185318b6c12be..39c242bb9d58682d90e58c10b1d5dc8b4d307480 100644 (file)
@@ -16,3 +16,5 @@ obj-y                         += dev-uart.o
 obj-y                          += cpu.o
 obj-y                          += clock.o
 obj-y                          += irq.o
+obj-$(CONFIG_S5P_EXT_INT)      += irq-eint.o
+
index 24a931fd8d3b5583709d6456a447c5f41ec92df1..b5e255265f20de4085bac619341f8bb9c1c40fd7 100644 (file)
@@ -148,6 +148,7 @@ static struct clk *s5p_clks[] __initdata = {
        &clk_fout_vpll,
        &clk_arm,
        &clk_vpll,
+       &clk_xusbxti,
 };
 
 void __init s5p_register_clocks(unsigned long xtal_freq)
index f92e5de3a75597372e32e4ec87f627360afc1177..75cb8c37ca2cf437a79244729d99b5121a0bd7af 100644 (file)
 #include <plat/cpu.h>
 #include <plat/s5p6440.h>
 #include <plat/s5p6442.h>
+#include <plat/s5pc100.h>
 #include <plat/s5pv210.h>
 
 /* table of supported CPUs */
 
 static const char name_s5p6440[] = "S5P6440";
 static const char name_s5p6442[] = "S5P6442";
+static const char name_s5pc100[] = "S5PC100";
 static const char name_s5pv210[] = "S5PV210/S5PC110";
 
 static struct cpu_table cpu_ids[] __initdata = {
@@ -44,6 +46,14 @@ static struct cpu_table cpu_ids[] __initdata = {
                .init_uarts     = s5p6442_init_uarts,
                .init           = s5p6442_init,
                .name           = name_s5p6442,
+       }, {
+               .idcode         = 0x43100000,
+               .idmask         = 0xfffff000,
+               .map_io         = s5pc100_map_io,
+               .init_clocks    = s5pc100_init_clocks,
+               .init_uarts     = s5pc100_init_uarts,
+               .init           = s5pc100_init,
+               .name           = name_s5pc100,
        }, {
                .idcode         = 0x43110000,
                .idmask         = 0xfffff000,
index 9ff3d718be39f1b15b30b8c60361cbd8215f7699..3fb3a3a1746505fc376e20a13cdfe153842db8cb 100644 (file)
 #define IRQ_TIMER3             S5P_TIMER_IRQ(3)
 #define IRQ_TIMER4             S5P_TIMER_IRQ(4)
 
+#define IRQ_EINT(x)            ((x) < 16 ? ((x) + S5P_EINT_BASE1) \
+                                       : ((x) - 16 + S5P_EINT_BASE2))
+
+#define EINT_OFFSET(irq)       ((irq) < S5P_EINT_BASE2 ? \
+                                               ((irq) - S5P_EINT_BASE1) : \
+                                               ((irq) + 16 - S5P_EINT_BASE2))
+
 #endif /* __ASM_PLAT_S5P_IRQS_H */
diff --git a/arch/arm/plat-s5p/include/plat/s5pc100.h b/arch/arm/plat-s5p/include/plat/s5pc100.h
new file mode 100644 (file)
index 0000000..5f6099d
--- /dev/null
@@ -0,0 +1,33 @@
+/* arch/arm/plat-s5p/include/plat/s5pc100.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * Header file for s5pc100 cpu support
+ *
+ * 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.
+*/
+
+/* Common init code for S5PC100 related SoCs */
+
+extern void s5pc100_common_init_uarts(struct s3c2410_uartcfg *cfg, int no);
+extern void s5pc100_register_clocks(void);
+extern void s5pc100_setup_clocks(void);
+
+#ifdef CONFIG_CPU_S5PC100
+
+extern  int s5pc100_init(void);
+extern void s5pc100_init_irq(void);
+extern void s5pc100_map_io(void);
+extern void s5pc100_init_clocks(int xtal);
+
+#define s5pc100_init_uarts s5pc100_common_init_uarts
+
+#else
+#define s5pc100_init_clocks NULL
+#define s5pc100_init_uarts NULL
+#define s5pc100_map_io NULL
+#define s5pc100_init NULL
+#endif
diff --git a/arch/arm/plat-s5p/irq-eint.c b/arch/arm/plat-s5p/irq-eint.c
new file mode 100644 (file)
index 0000000..e56c807
--- /dev/null
@@ -0,0 +1,218 @@
+/* linux/arch/arm/plat-s5p/irq-eint.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * S5P - IRQ EINT support
+ *
+ * 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/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/sysdev.h>
+#include <linux/gpio.h>
+
+#include <asm/hardware/vic.h>
+
+#include <plat/regs-irqtype.h>
+
+#include <mach/map.h>
+#include <plat/cpu.h>
+#include <plat/pm.h>
+
+#include <plat/gpio-cfg.h>
+#include <mach/regs-gpio.h>
+
+static inline void s5p_irq_eint_mask(unsigned int irq)
+{
+       u32 mask;
+
+       mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(irq)));
+       mask |= eint_irq_to_bit(irq);
+       __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(irq)));
+}
+
+static void s5p_irq_eint_unmask(unsigned int irq)
+{
+       u32 mask;
+
+       mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(irq)));
+       mask &= ~(eint_irq_to_bit(irq));
+       __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(irq)));
+}
+
+static inline void s5p_irq_eint_ack(unsigned int irq)
+{
+       __raw_writel(eint_irq_to_bit(irq), S5P_EINT_PEND(EINT_REG_NR(irq)));
+}
+
+static void s5p_irq_eint_maskack(unsigned int irq)
+{
+       /* compiler should in-line these */
+       s5p_irq_eint_mask(irq);
+       s5p_irq_eint_ack(irq);
+}
+
+static int s5p_irq_eint_set_type(unsigned int irq, unsigned int type)
+{
+       int offs = EINT_OFFSET(irq);
+       int shift;
+       u32 ctrl, mask;
+       u32 newvalue = 0;
+
+       switch (type) {
+       case IRQ_TYPE_EDGE_RISING:
+               newvalue = S5P_EXTINT_RISEEDGE;
+               break;
+
+       case IRQ_TYPE_EDGE_FALLING:
+               newvalue = S5P_EXTINT_RISEEDGE;
+               break;
+
+       case IRQ_TYPE_EDGE_BOTH:
+               newvalue = S5P_EXTINT_BOTHEDGE;
+               break;
+
+       case IRQ_TYPE_LEVEL_LOW:
+               newvalue = S5P_EXTINT_LOWLEV;
+               break;
+
+       case IRQ_TYPE_LEVEL_HIGH:
+               newvalue = S5P_EXTINT_HILEV;
+               break;
+
+       default:
+               printk(KERN_ERR "No such irq type %d", type);
+               return -EINVAL;
+       }
+
+       shift = (offs & 0x7) * 4;
+       mask = 0x7 << shift;
+
+       ctrl = __raw_readl(S5P_EINT_CON(EINT_REG_NR(irq)));
+       ctrl &= ~mask;
+       ctrl |= newvalue << shift;
+       __raw_writel(ctrl, S5P_EINT_CON(EINT_REG_NR(irq)));
+
+       if ((0 <= offs) && (offs < 8))
+               s3c_gpio_cfgpin(EINT_GPIO_0(offs & 0x7), EINT_MODE);
+
+       else if ((8 <= offs) && (offs < 16))
+               s3c_gpio_cfgpin(EINT_GPIO_1(offs & 0x7), EINT_MODE);
+
+       else if ((16 <= offs) && (offs < 24))
+               s3c_gpio_cfgpin(EINT_GPIO_2(offs & 0x7), EINT_MODE);
+
+       else if ((24 <= offs) && (offs < 32))
+               s3c_gpio_cfgpin(EINT_GPIO_3(offs & 0x7), EINT_MODE);
+
+       else
+               printk(KERN_ERR "No such irq number %d", offs);
+
+       return 0;
+}
+
+static struct irq_chip s5p_irq_eint = {
+       .name           = "s5p-eint",
+       .mask           = s5p_irq_eint_mask,
+       .unmask         = s5p_irq_eint_unmask,
+       .mask_ack       = s5p_irq_eint_maskack,
+       .ack            = s5p_irq_eint_ack,
+       .set_type       = s5p_irq_eint_set_type,
+#ifdef CONFIG_PM
+       .set_wake       = s3c_irqext_wake,
+#endif
+};
+
+/* s5p_irq_demux_eint
+ *
+ * This function demuxes the IRQ from the group0 external interrupts,
+ * from EINTs 16 to 31. It is designed to be inlined into the specific
+ * handler s5p_irq_demux_eintX_Y.
+ *
+ * Each EINT pend/mask registers handle eight of them.
+ */
+static inline void s5p_irq_demux_eint(unsigned int start)
+{
+       u32 status = __raw_readl(S5P_EINT_PEND(EINT_REG_NR(start)));
+       u32 mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(start)));
+       unsigned int irq;
+
+       status &= ~mask;
+       status &= 0xff;
+
+       while (status) {
+               irq = fls(status) - 1;
+               generic_handle_irq(irq + start);
+               status &= ~(1 << irq);
+       }
+}
+
+static void s5p_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
+{
+       s5p_irq_demux_eint(IRQ_EINT(16));
+       s5p_irq_demux_eint(IRQ_EINT(24));
+}
+
+static inline void s5p_irq_vic_eint_mask(unsigned int irq)
+{
+       void __iomem *base = get_irq_chip_data(irq);
+
+       s5p_irq_eint_mask(irq);
+       writel(1 << EINT_OFFSET(irq), base + VIC_INT_ENABLE_CLEAR);
+}
+
+static void s5p_irq_vic_eint_unmask(unsigned int irq)
+{
+       void __iomem *base = get_irq_chip_data(irq);
+
+       s5p_irq_eint_unmask(irq);
+       writel(1 << EINT_OFFSET(irq), base + VIC_INT_ENABLE);
+}
+
+static inline void s5p_irq_vic_eint_ack(unsigned int irq)
+{
+       __raw_writel(eint_irq_to_bit(irq), S5P_EINT_PEND(EINT_REG_NR(irq)));
+}
+
+static void s5p_irq_vic_eint_maskack(unsigned int irq)
+{
+       s5p_irq_vic_eint_mask(irq);
+       s5p_irq_vic_eint_ack(irq);
+}
+
+static struct irq_chip s5p_irq_vic_eint = {
+       .name           = "s5p_vic_eint",
+       .mask           = s5p_irq_vic_eint_mask,
+       .unmask         = s5p_irq_vic_eint_unmask,
+       .mask_ack       = s5p_irq_vic_eint_maskack,
+       .ack            = s5p_irq_vic_eint_ack,
+       .set_type       = s5p_irq_eint_set_type,
+#ifdef CONFIG_PM
+       .set_wake       = s3c_irqext_wake,
+#endif
+};
+
+int __init s5p_init_irq_eint(void)
+{
+       int irq;
+
+       for (irq = IRQ_EINT(0); irq <= IRQ_EINT(15); irq++)
+               set_irq_chip(irq, &s5p_irq_vic_eint);
+
+       for (irq = IRQ_EINT(16); irq <= IRQ_EINT(31); irq++) {
+               set_irq_chip(irq, &s5p_irq_eint);
+               set_irq_handler(irq, handle_level_irq);
+               set_irq_flags(irq, IRQF_VALID);
+       }
+
+       set_irq_chained_handler(IRQ_EINT16_31, s5p_irq_demux_eint16_31);
+       return 0;
+}
+
+arch_initcall(s5p_init_irq_eint);
diff --git a/arch/arm/plat-s5pc1xx/Kconfig b/arch/arm/plat-s5pc1xx/Kconfig
deleted file mode 100644 (file)
index c7bd2bb..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-# Copyright 2009 Samsung Electronics Co.
-#      Byungho Min <bhmin@samsung.com>
-#
-# Licensed under GPLv2
-
-config PLAT_S5PC1XX
-       bool
-       depends on ARCH_S5PC1XX
-       default y
-       select PLAT_S3C
-       select ARM_VIC
-       select NO_IOPORT
-       select ARCH_REQUIRE_GPIOLIB
-       select SAMSUNG_CLKSRC
-       select SAMSUNG_IRQ_UART
-       select SAMSUNG_IRQ_VIC_TIMER
-       select S3C_GPIO_TRACK
-       select S3C_GPIO_PULL_UPDOWN
-       select S5P_GPIO_DRVSTR
-       select S3C_GPIO_CFG_S3C24XX
-       select S3C_GPIO_CFG_S3C64XX
-       select SAMSUNG_GPIOLIB_4BIT
-       help
-         Base platform code for any Samsung S5PC1XX device
-
-if PLAT_S5PC1XX
-
-# Configuration options shared by all S3C64XX implementations
-
-config CPU_S5PC100_INIT
-       bool
-       help
-         Common initialisation code for the S5PC1XX
-
-config CPU_S5PC100_CLOCK
-       bool
-       help
-         Common clock support code for the S5PC1XX
-
-# platform specific device setup
-
-config S5PC1XX_SETUP_SDHCI_GPIO
-       bool
-       help
-         Common setup code for SDHCI gpio.
-
-endif
diff --git a/arch/arm/plat-s5pc1xx/Makefile b/arch/arm/plat-s5pc1xx/Makefile
deleted file mode 100644 (file)
index 9ce6409..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-# arch/arm/plat-s5pc1xx/Makefile
-#
-# Copyright 2009 Samsung Electronics Co.
-#
-# Licensed under GPLv2
-
-obj-y                          :=
-obj-m                          :=
-obj-n                          := dummy.o
-obj-                           :=
-
-# Core files
-
-obj-y                          += dev-uart.o
-obj-y                          += cpu.o
-obj-y                          += irq.o
-obj-y                          += clock.o
-
-# CPU support
-
-obj-$(CONFIG_CPU_S5PC100_INIT) += s5pc100-init.o
-obj-$(CONFIG_CPU_S5PC100_CLOCK)        += s5pc100-clock.o
-
-# Device setup
-
-obj-$(CONFIG_S5PC1XX_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o
diff --git a/arch/arm/plat-s5pc1xx/clock.c b/arch/arm/plat-s5pc1xx/clock.c
deleted file mode 100644 (file)
index 387f231..0000000
+++ /dev/null
@@ -1,709 +0,0 @@
-/* linux/arch/arm/plat-s5pc1xx/clock.c
- *
- * Copyright 2009 Samsung Electronics Co.
- *
- * S5PC1XX Base clock support
- *
- * Based on plat-s3c64xx/clock.c
- *
- * 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/init.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <mach/map.h>
-
-#include <plat/regs-clock.h>
-#include <plat/devs.h>
-#include <plat/clock.h>
-
-struct clk clk_27m = {
-       .name           = "clk_27m",
-       .id             = -1,
-       .rate           = 27000000,
-};
-
-static int clk_48m_ctrl(struct clk *clk, int enable)
-{
-       unsigned long flags;
-       u32 val;
-
-       /* can't rely on clock lock, this register has other usages */
-       local_irq_save(flags);
-
-       val = __raw_readl(S5PC100_CLKSRC1);
-       if (enable)
-               val |= S5PC100_CLKSRC1_CLK48M_MASK;
-       else
-               val &= ~S5PC100_CLKSRC1_CLK48M_MASK;
-
-       __raw_writel(val, S5PC100_CLKSRC1);
-       local_irq_restore(flags);
-
-       return 0;
-}
-
-struct clk clk_48m = {
-       .name           = "clk_48m",
-       .id             = -1,
-       .rate           = 48000000,
-       .enable         = clk_48m_ctrl,
-};
-
-struct clk clk_54m = {
-       .name           = "clk_54m",
-       .id             = -1,
-       .rate           = 54000000,
-};
-
-struct clk clk_hd0 = {
-       .name           = "hclkd0",
-       .id             = -1,
-       .rate           = 0,
-       .parent         = NULL,
-       .ctrlbit        = 0,
-       .ops            = &clk_ops_def_setrate,
-};
-
-struct clk clk_pd0 = {
-       .name           = "pclkd0",
-       .id             = -1,
-       .rate           = 0,
-       .parent         = NULL,
-       .ctrlbit        = 0,
-       .ops            = &clk_ops_def_setrate,
-};
-
-static int s5pc1xx_clk_gate(void __iomem *reg, struct clk *clk, int enable)
-{
-       unsigned int ctrlbit = clk->ctrlbit;
-       u32 con;
-
-       con = __raw_readl(reg);
-       if (enable)
-               con |= ctrlbit;
-       else
-               con &= ~ctrlbit;
-       __raw_writel(con, reg);
-
-       return 0;
-}
-
-static int s5pc100_clk_d00_ctrl(struct clk *clk, int enable)
-{
-       return s5pc1xx_clk_gate(S5PC100_CLKGATE_D00, clk, enable);
-}
-
-static int s5pc100_clk_d01_ctrl(struct clk *clk, int enable)
-{
-       return s5pc1xx_clk_gate(S5PC100_CLKGATE_D01, clk, enable);
-}
-
-static int s5pc100_clk_d02_ctrl(struct clk *clk, int enable)
-{
-       return s5pc1xx_clk_gate(S5PC100_CLKGATE_D02, clk, enable);
-}
-
-static int s5pc100_clk_d10_ctrl(struct clk *clk, int enable)
-{
-       return s5pc1xx_clk_gate(S5PC100_CLKGATE_D10, clk, enable);
-}
-
-static int s5pc100_clk_d11_ctrl(struct clk *clk, int enable)
-{
-       return s5pc1xx_clk_gate(S5PC100_CLKGATE_D11, clk, enable);
-}
-
-static int s5pc100_clk_d12_ctrl(struct clk *clk, int enable)
-{
-       return s5pc1xx_clk_gate(S5PC100_CLKGATE_D12, clk, enable);
-}
-
-static int s5pc100_clk_d13_ctrl(struct clk *clk, int enable)
-{
-       return s5pc1xx_clk_gate(S5PC100_CLKGATE_D13, clk, enable);
-}
-
-static int s5pc100_clk_d14_ctrl(struct clk *clk, int enable)
-{
-       return s5pc1xx_clk_gate(S5PC100_CLKGATE_D14, clk, enable);
-}
-
-static int s5pc100_clk_d15_ctrl(struct clk *clk, int enable)
-{
-       return s5pc1xx_clk_gate(S5PC100_CLKGATE_D15, clk, enable);
-}
-
-static int s5pc100_clk_d20_ctrl(struct clk *clk, int enable)
-{
-       return s5pc1xx_clk_gate(S5PC100_CLKGATE_D20, clk, enable);
-}
-
-int s5pc100_sclk0_ctrl(struct clk *clk, int enable)
-{
-       return s5pc1xx_clk_gate(S5PC100_SCLKGATE0, clk, enable);
-}
-
-int s5pc100_sclk1_ctrl(struct clk *clk, int enable)
-{
-       return s5pc1xx_clk_gate(S5PC100_SCLKGATE1, clk, enable);
-}
-
-static struct clk s5pc100_init_clocks_disable[] = {
-       {
-               .name           = "dsi",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d11_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D11_DSI,
-       }, {
-               .name           = "csi",
-               .id             = -1,
-               .parent         = &clk_h,
-               .enable         = s5pc100_clk_d11_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D11_CSI,
-       }, {
-               .name           = "ccan",
-               .id             = 0,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d14_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D14_CCAN0,
-       }, {
-               .name           = "ccan",
-               .id             = 1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d14_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D14_CCAN1,
-       }, {
-               .name           = "keypad",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d15_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D15_KEYIF,
-       }, {
-               .name           = "hclkd2",
-               .id             = -1,
-               .parent         = NULL,
-               .enable         = s5pc100_clk_d20_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D20_HCLKD2,
-       }, {
-               .name           = "iis-d2",
-               .id             = -1,
-               .parent         = NULL,
-               .enable         = s5pc100_clk_d20_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D20_I2SD2,
-       },
-};
-
-static struct clk s5pc100_init_clocks[] = {
-       /* System1 (D0_0) devices */
-       {
-               .name           = "intc",
-               .id             = -1,
-               .parent         = &clk_hd0,
-               .enable         = s5pc100_clk_d00_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D00_INTC,
-       }, {
-               .name           = "tzic",
-               .id             = -1,
-               .parent         = &clk_hd0,
-               .enable         = s5pc100_clk_d00_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D00_TZIC,
-       }, {
-               .name           = "cf-ata",
-               .id             = -1,
-               .parent         = &clk_hd0,
-               .enable         = s5pc100_clk_d00_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D00_CFCON,
-       }, {
-               .name           = "mdma",
-               .id             = -1,
-               .parent         = &clk_hd0,
-               .enable         = s5pc100_clk_d00_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D00_MDMA,
-       }, {
-               .name           = "g2d",
-               .id             = -1,
-               .parent         = &clk_hd0,
-               .enable         = s5pc100_clk_d00_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D00_G2D,
-       }, {
-               .name           = "secss",
-               .id             = -1,
-               .parent         = &clk_hd0,
-               .enable         = s5pc100_clk_d00_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D00_SECSS,
-       }, {
-               .name           = "cssys",
-               .id             = -1,
-               .parent         = &clk_hd0,
-               .enable         = s5pc100_clk_d00_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D00_CSSYS,
-       },
-
-       /* Memory (D0_1) devices */
-       {
-               .name           = "dmc",
-               .id             = -1,
-               .parent         = &clk_hd0,
-               .enable         = s5pc100_clk_d01_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D01_DMC,
-       }, {
-               .name           = "sromc",
-               .id             = -1,
-               .parent         = &clk_hd0,
-               .enable         = s5pc100_clk_d01_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D01_SROMC,
-       }, {
-               .name           = "onenand",
-               .id             = -1,
-               .parent         = &clk_hd0,
-               .enable         = s5pc100_clk_d01_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D01_ONENAND,
-       }, {
-               .name           = "nand",
-               .id             = -1,
-               .parent         = &clk_hd0,
-               .enable         = s5pc100_clk_d01_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D01_NFCON,
-       }, {
-               .name           = "intmem",
-               .id             = -1,
-               .parent         = &clk_hd0,
-               .enable         = s5pc100_clk_d01_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D01_INTMEM,
-       }, {
-               .name           = "ebi",
-               .id             = -1,
-               .parent         = &clk_hd0,
-               .enable         = s5pc100_clk_d01_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D01_EBI,
-       },
-
-       /* System2 (D0_2) devices */
-       {
-               .name           = "seckey",
-               .id             = -1,
-               .parent         = &clk_pd0,
-               .enable         = s5pc100_clk_d02_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D02_SECKEY,
-       }, {
-               .name           = "sdm",
-               .id             = -1,
-               .parent         = &clk_hd0,
-               .enable         = s5pc100_clk_d02_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D02_SDM,
-       },
-
-       /* File (D1_0) devices */
-       {
-               .name           = "pdma",
-               .id             = 0,
-               .parent         = &clk_h,
-               .enable         = s5pc100_clk_d10_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D10_PDMA0,
-       }, {
-               .name           = "pdma",
-               .id             = 1,
-               .parent         = &clk_h,
-               .enable         = s5pc100_clk_d10_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D10_PDMA1,
-       }, {
-               .name           = "usb-host",
-               .id             = -1,
-               .parent         = &clk_h,
-               .enable         = s5pc100_clk_d10_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D10_USBHOST,
-       }, {
-               .name           = "otg",
-               .id             = -1,
-               .parent         = &clk_h,
-               .enable         = s5pc100_clk_d10_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D10_USBOTG,
-       }, {
-               .name           = "modem",
-               .id             = -1,
-               .parent         = &clk_h,
-               .enable         = s5pc100_clk_d10_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D10_MODEMIF,
-       }, {
-               .name           = "hsmmc",
-               .id             = 0,
-               .parent         = &clk_48m,
-               .enable         = s5pc100_clk_d10_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D10_HSMMC0,
-       }, {
-               .name           = "hsmmc",
-               .id             = 1,
-               .parent         = &clk_48m,
-               .enable         = s5pc100_clk_d10_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D10_HSMMC1,
-       }, {
-               .name           = "hsmmc",
-               .id             = 2,
-               .parent         = &clk_48m,
-               .enable         = s5pc100_clk_d10_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D10_HSMMC2,
-       },
-
-       /* Multimedia1 (D1_1) devices */
-       {
-               .name           = "lcd",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d11_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D11_LCD,
-       }, {
-               .name           = "rotator",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d11_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D11_ROTATOR,
-       }, {
-               .name           = "fimc",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d11_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D11_FIMC0,
-       }, {
-               .name           = "fimc",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d11_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D11_FIMC1,
-       }, {
-               .name           = "fimc",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d11_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D11_FIMC2,
-       }, {
-               .name           = "jpeg",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d11_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D11_JPEG,
-       }, {
-               .name           = "g3d",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d11_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D11_G3D,
-       },
-
-       /* Multimedia2 (D1_2) devices */
-       {
-               .name           = "tv",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d12_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D12_TV,
-       }, {
-               .name           = "vp",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d12_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D12_VP,
-       }, {
-               .name           = "mixer",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d12_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D12_MIXER,
-       }, {
-               .name           = "hdmi",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d12_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D12_HDMI,
-       }, {
-               .name           = "mfc",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d12_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D12_MFC,
-       },
-
-       /* System (D1_3) devices */
-       {
-               .name           = "chipid",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d13_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D13_CHIPID,
-       }, {
-               .name           = "gpio",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d13_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D13_GPIO,
-       }, {
-               .name           = "apc",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d13_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D13_APC,
-       }, {
-               .name           = "iec",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d13_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D13_IEC,
-       }, {
-               .name           = "timers",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d13_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D13_PWM,
-       }, {
-               .name           = "systimer",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d13_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D13_SYSTIMER,
-       }, {
-               .name           = "watchdog",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d13_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D13_WDT,
-       }, {
-               .name           = "rtc",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d13_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D13_RTC,
-       },
-
-       /* Connectivity (D1_4) devices */
-       {
-               .name           = "uart",
-               .id             = 0,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d14_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D14_UART0,
-       }, {
-               .name           = "uart",
-               .id             = 1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d14_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D14_UART1,
-       }, {
-               .name           = "uart",
-               .id             = 2,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d14_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D14_UART2,
-       }, {
-               .name           = "uart",
-               .id             = 3,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d14_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D14_UART3,
-       }, {
-               .name           = "i2c",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d14_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D14_IIC,
-       }, {
-               .name           = "hdmi-i2c",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d14_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D14_HDMI_IIC,
-       }, {
-               .name           = "spi",
-               .id             = 0,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d14_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D14_SPI0,
-       }, {
-               .name           = "spi",
-               .id             = 1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d14_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D14_SPI1,
-       }, {
-               .name           = "spi",
-               .id             = 2,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d14_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D14_SPI2,
-       }, {
-               .name           = "irda",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d14_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D14_IRDA,
-       }, {
-               .name           = "hsitx",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d14_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D14_HSITX,
-       }, {
-               .name           = "hsirx",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d14_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D14_HSIRX,
-       },
-
-       /* Audio (D1_5) devices */
-       {
-               .name           = "iis",
-               .id             = 0,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d15_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D15_IIS0,
-       }, {
-               .name           = "iis",
-               .id             = 1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d15_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D15_IIS1,
-       }, {
-               .name           = "iis",
-               .id             = 2,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d15_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D15_IIS2,
-       }, {
-               .name           = "ac97",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d15_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D15_AC97,
-       }, {
-               .name           = "pcm",
-               .id             = 0,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d15_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D15_PCM0,
-       }, {
-               .name           = "pcm",
-               .id             = 1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d15_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D15_PCM1,
-       }, {
-               .name           = "spdif",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d15_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D15_SPDIF,
-       }, {
-               .name           = "adc",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d15_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D15_TSADC,
-       }, {
-               .name           = "cg",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s5pc100_clk_d15_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_D15_CG,
-       },
-
-       /* Audio (D2_0) devices: all disabled */
-
-       /* Special Clocks 0 */
-       {
-               .name           = "sclk_hpm",
-               .id             = -1,
-               .parent         = NULL,
-               .enable         = s5pc100_sclk0_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_SCLK0_HPM,
-       }, {
-               .name           = "sclk_onenand",
-               .id             = -1,
-               .parent         = NULL,
-               .enable         = s5pc100_sclk0_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_SCLK0_ONENAND,
-       }, {
-               .name           = "spi_48",
-               .id             = 0,
-               .parent         = &clk_48m,
-               .enable         = s5pc100_sclk0_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_SCLK0_SPI0_48,
-       }, {
-               .name           = "spi_48",
-               .id             = 1,
-               .parent         = &clk_48m,
-               .enable         = s5pc100_sclk0_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_SCLK0_SPI1_48,
-       }, {
-               .name           = "spi_48",
-               .id             = 2,
-               .parent         = &clk_48m,
-               .enable         = s5pc100_sclk0_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_SCLK0_SPI2_48,
-       }, {
-               .name           = "mmc_48",
-               .id             = 0,
-               .parent         = &clk_48m,
-               .enable         = s5pc100_sclk0_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_SCLK0_MMC0_48,
-       }, {
-               .name           = "mmc_48",
-               .id             = 1,
-               .parent         = &clk_48m,
-               .enable         = s5pc100_sclk0_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_SCLK0_MMC1_48,
-       }, {
-               .name           = "mmc_48",
-               .id             = 2,
-               .parent         = &clk_48m,
-               .enable         = s5pc100_sclk0_ctrl,
-               .ctrlbit        = S5PC100_CLKGATE_SCLK0_MMC2_48,
-       },
-       /* Special Clocks 1 */
-};
-
-static struct clk *clks[] __initdata = {
-       &clk_ext,
-       &clk_epll,
-       &clk_pd0,
-       &clk_hd0,
-       &clk_27m,
-       &clk_48m,
-       &clk_54m,
-};
-
-void __init s5pc1xx_register_clocks(void)
-{
-       struct clk *clkp;
-       int ret;
-       int ptr;
-       int size;
-
-       s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
-
-       s3c_register_clocks(s5pc100_init_clocks,
-                           ARRAY_SIZE(s5pc100_init_clocks));
-
-       clkp = s5pc100_init_clocks_disable;
-       size = ARRAY_SIZE(s5pc100_init_clocks_disable);
-
-       for (ptr = 0; ptr < size; ptr++, clkp++) {
-               ret = s3c24xx_register_clock(clkp);
-               if (ret < 0) {
-                       printk(KERN_ERR "Failed to register clock %s (%d)\n",
-                              clkp->name, ret);
-               }
-
-               (clkp->enable)(clkp, 0);
-       }
-
-       s3c_pwmclk_init();
-}
diff --git a/arch/arm/plat-s5pc1xx/cpu.c b/arch/arm/plat-s5pc1xx/cpu.c
deleted file mode 100644 (file)
index 02baeaa..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/* linux/arch/arm/plat-s5pc1xx/cpu.c
- *
- * Copyright 2009 Samsung Electronics Co.
- *     Byungho Min <bhmin@samsung.com>
- *
- * S5PC1XX CPU Support
- *
- * Based on plat-s3c64xx/cpu.c
- *
- * 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/init.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <mach/map.h>
-
-#include <asm/mach/map.h>
-
-#include <plat/regs-serial.h>
-
-#include <plat/cpu.h>
-#include <plat/devs.h>
-#include <plat/clock.h>
-
-#include <plat/s5pc100.h>
-
-/* table of supported CPUs */
-
-static const char name_s5pc100[] = "S5PC100";
-
-static struct cpu_table cpu_ids[] __initdata = {
-       {
-               .idcode         = 0x43100000,
-               .idmask         = 0xfffff000,
-               .map_io         = s5pc100_map_io,
-               .init_clocks    = s5pc100_init_clocks,
-               .init_uarts     = s5pc100_init_uarts,
-               .init           = s5pc100_init,
-               .name           = name_s5pc100,
-       },
-};
-/* minimal IO mapping */
-
-/* see notes on uart map in arch/arm/mach-s5pc100/include/mach/debug-macro.S */
-#define UART_OFFS (S3C_PA_UART & 0xffff)
-
-static struct map_desc s5pc1xx_iodesc[] __initdata = {
-       {
-               .virtual        = (unsigned long)S5PC1XX_VA_CLK_OTHER,
-               .pfn            = __phys_to_pfn(S5PC1XX_PA_CLK_OTHER),
-               .length         = SZ_4K,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = (unsigned long)S5PC1XX_VA_GPIO,
-               .pfn            = __phys_to_pfn(S5PC100_PA_GPIO),
-               .length         = SZ_4K,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = (unsigned long)S5PC1XX_VA_CHIPID,
-               .pfn            = __phys_to_pfn(S5PC1XX_PA_CHIPID),
-               .length         = SZ_16,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = (unsigned long)S5PC1XX_VA_CLK,
-               .pfn            = __phys_to_pfn(S5PC1XX_PA_CLK),
-               .length         = SZ_4K,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = (unsigned long)S5PC1XX_VA_PWR,
-               .pfn            = __phys_to_pfn(S5PC1XX_PA_PWR),
-               .length         = SZ_4K,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = (unsigned long)(S5PC1XX_VA_UART),
-               .pfn            = __phys_to_pfn(S5PC1XX_PA_UART),
-               .length         = SZ_4K,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = (unsigned long)S5PC1XX_VA_VIC(0),
-               .pfn            = __phys_to_pfn(S5PC1XX_PA_VIC(0)),
-               .length         = SZ_4K,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = (unsigned long)S5PC1XX_VA_VIC(1),
-               .pfn            = __phys_to_pfn(S5PC1XX_PA_VIC(1)),
-               .length         = SZ_4K,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = (unsigned long)S5PC1XX_VA_VIC(2),
-               .pfn            = __phys_to_pfn(S5PC1XX_PA_VIC(2)),
-               .length         = SZ_4K,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = (unsigned long)S5PC1XX_VA_TIMER,
-               .pfn            = __phys_to_pfn(S5PC1XX_PA_TIMER),
-               .length         = SZ_256,
-               .type           = MT_DEVICE,
-       },
-};
-
-/* read cpu identification code */
-
-void __init s5pc1xx_init_io(struct map_desc *mach_desc, int size)
-{
-       unsigned long idcode;
-
-       /* initialise the io descriptors we need for initialisation */
-       iotable_init(s5pc1xx_iodesc, ARRAY_SIZE(s5pc1xx_iodesc));
-       iotable_init(mach_desc, size);
-
-       idcode = __raw_readl(S5PC1XX_VA_CHIPID);
-       s3c_init_cpu(idcode, cpu_ids, ARRAY_SIZE(cpu_ids));
-}
diff --git a/arch/arm/plat-s5pc1xx/dev-uart.c b/arch/arm/plat-s5pc1xx/dev-uart.c
deleted file mode 100644 (file)
index 586c95c..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/* linux/arch/arm/plat-s5pc1xx/dev-uart.c
- *
- * Copyright 2009 Samsung Electronics Co.
- *     Byungho Min <bhmin@samsung.com>
- *
- * Based on plat-s3c64xx/dev-uart.c
- *
- * 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/kernel.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/platform_device.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/irq.h>
-#include <mach/hardware.h>
-#include <mach/map.h>
-
-#include <plat/devs.h>
-
-/* Serial port registrations */
-
-/* 64xx uarts are closer together */
-
-static struct resource s5pc1xx_uart0_resource[] = {
-       [0] = {
-               .start  = S3C_PA_UART0,
-               .end    = S3C_PA_UART0 + 0x100,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = IRQ_S3CUART_RX0,
-               .end    = IRQ_S3CUART_RX0,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               .start  = IRQ_S3CUART_TX0,
-               .end    = IRQ_S3CUART_TX0,
-               .flags  = IORESOURCE_IRQ,
-
-       },
-       [3] = {
-               .start  = IRQ_S3CUART_ERR0,
-               .end    = IRQ_S3CUART_ERR0,
-               .flags  = IORESOURCE_IRQ,
-       }
-};
-
-static struct resource s5pc1xx_uart1_resource[] = {
-       [0] = {
-               .start = S3C_PA_UART1,
-               .end   = S3C_PA_UART1 + 0x100,
-               .flags = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = IRQ_S3CUART_RX1,
-               .end    = IRQ_S3CUART_RX1,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               .start  = IRQ_S3CUART_TX1,
-               .end    = IRQ_S3CUART_TX1,
-               .flags  = IORESOURCE_IRQ,
-
-       },
-       [3] = {
-               .start  = IRQ_S3CUART_ERR1,
-               .end    = IRQ_S3CUART_ERR1,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct resource s5pc1xx_uart2_resource[] = {
-       [0] = {
-               .start = S3C_PA_UART2,
-               .end   = S3C_PA_UART2 + 0x100,
-               .flags = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = IRQ_S3CUART_RX2,
-               .end    = IRQ_S3CUART_RX2,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               .start  = IRQ_S3CUART_TX2,
-               .end    = IRQ_S3CUART_TX2,
-               .flags  = IORESOURCE_IRQ,
-
-       },
-       [3] = {
-               .start  = IRQ_S3CUART_ERR2,
-               .end    = IRQ_S3CUART_ERR2,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct resource s5pc1xx_uart3_resource[] = {
-       [0] = {
-               .start = S3C_PA_UART3,
-               .end   = S3C_PA_UART3 + 0x100,
-               .flags = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = IRQ_S3CUART_RX3,
-               .end    = IRQ_S3CUART_RX3,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               .start  = IRQ_S3CUART_TX3,
-               .end    = IRQ_S3CUART_TX3,
-               .flags  = IORESOURCE_IRQ,
-
-       },
-       [3] = {
-               .start  = IRQ_S3CUART_ERR3,
-               .end    = IRQ_S3CUART_ERR3,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-
-struct s3c24xx_uart_resources s5pc1xx_uart_resources[] __initdata = {
-       [0] = {
-               .resources      = s5pc1xx_uart0_resource,
-               .nr_resources   = ARRAY_SIZE(s5pc1xx_uart0_resource),
-       },
-       [1] = {
-               .resources      = s5pc1xx_uart1_resource,
-               .nr_resources   = ARRAY_SIZE(s5pc1xx_uart1_resource),
-       },
-       [2] = {
-               .resources      = s5pc1xx_uart2_resource,
-               .nr_resources   = ARRAY_SIZE(s5pc1xx_uart2_resource),
-       },
-       [3] = {
-               .resources      = s5pc1xx_uart3_resource,
-               .nr_resources   = ARRAY_SIZE(s5pc1xx_uart3_resource),
-       },
-};
diff --git a/arch/arm/plat-s5pc1xx/include/plat/gpio-ext.h b/arch/arm/plat-s5pc1xx/include/plat/gpio-ext.h
deleted file mode 100644 (file)
index 33ad267..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/* linux/arch/arm/plat-s5pc1xx/include/plat/gpio-eint.h
- *
- * Copyright 2009 Samsung Electronics Co.
- *
- * External Interrupt (GPH0 ~ GPH3) control register definitions
- *
- * 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.
-*/
-
-#define S5PC1XX_WKUP_INT_CON0_7                (S5PC1XX_EINT_BASE + 0x0)
-#define S5PC1XX_WKUP_INT_CON8_15       (S5PC1XX_EINT_BASE + 0x4)
-#define S5PC1XX_WKUP_INT_CON16_23      (S5PC1XX_EINT_BASE + 0x8)
-#define S5PC1XX_WKUP_INT_CON24_31      (S5PC1XX_EINT_BASE + 0xC)
-#define S5PC1XX_WKUP_INT_CON(x)                (S5PC1XX_WKUP_INT_CON0_7 + (x * 0x4))
-
-#define S5PC1XX_WKUP_INT_FLTCON0_3     (S5PC1XX_EINT_BASE + 0x80)
-#define S5PC1XX_WKUP_INT_FLTCON4_7     (S5PC1XX_EINT_BASE + 0x84)
-#define S5PC1XX_WKUP_INT_FLTCON8_11    (S5PC1XX_EINT_BASE + 0x88)
-#define S5PC1XX_WKUP_INT_FLTCON12_15   (S5PC1XX_EINT_BASE + 0x8C)
-#define S5PC1XX_WKUP_INT_FLTCON16_19   (S5PC1XX_EINT_BASE + 0x90)
-#define S5PC1XX_WKUP_INT_FLTCON20_23   (S5PC1XX_EINT_BASE + 0x94)
-#define S5PC1XX_WKUP_INT_FLTCON24_27   (S5PC1XX_EINT_BASE + 0x98)
-#define S5PC1XX_WKUP_INT_FLTCON28_31   (S5PC1XX_EINT_BASE + 0x9C)
-#define S5PC1XX_WKUP_INT_FLTCON(x)     (S5PC1XX_WKUP_INT_FLTCON0_3 + (x * 0x4))
-
-#define S5PC1XX_WKUP_INT_MASK0_7       (S5PC1XX_EINT_BASE + 0x100)
-#define S5PC1XX_WKUP_INT_MASK8_15      (S5PC1XX_EINT_BASE + 0x104)
-#define S5PC1XX_WKUP_INT_MASK16_23     (S5PC1XX_EINT_BASE + 0x108)
-#define S5PC1XX_WKUP_INT_MASK24_31     (S5PC1XX_EINT_BASE + 0x10C)
-#define S5PC1XX_WKUP_INT_MASK(x)       (S5PC1XX_WKUP_INT_MASK0_7 + (x * 0x4))
-
-#define S5PC1XX_WKUP_INT_PEND0_7       (S5PC1XX_EINT_BASE + 0x140)
-#define S5PC1XX_WKUP_INT_PEND8_15      (S5PC1XX_EINT_BASE + 0x144)
-#define S5PC1XX_WKUP_INT_PEND16_23     (S5PC1XX_EINT_BASE + 0x148)
-#define S5PC1XX_WKUP_INT_PEND24_31     (S5PC1XX_EINT_BASE + 0x14C)
-#define S5PC1XX_WKUP_INT_PEND(x)       (S5PC1XX_WKUP_INT_PEND0_7 + (x * 0x4))
-
-#define S5PC1XX_WKUP_INT_LOWLEV                (0x00)
-#define S5PC1XX_WKUP_INT_HILEV         (0x01)
-#define S5PC1XX_WKUP_INT_FALLEDGE      (0x02)
-#define S5PC1XX_WKUP_INT_RISEEDGE      (0x03)
-#define S5PC1XX_WKUP_INT_BOTHEDGE      (0x04)
diff --git a/arch/arm/plat-s5pc1xx/include/plat/irqs.h b/arch/arm/plat-s5pc1xx/include/plat/irqs.h
deleted file mode 100644 (file)
index 409c804..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-/* linux/arch/arm/plat-s5pc1xx/include/plat/irqs.h
- *
- * Copyright 2009 Samsung Electronics Co.
- *      Byungho Min <bhmin@samsung.com>
- *
- * S5PC1XX - Common IRQ support
- *
- * Based on plat-s3c64xx/include/plat/irqs.h
- */
-
-#ifndef __ASM_PLAT_S5PC1XX_IRQS_H
-#define __ASM_PLAT_S5PC1XX_IRQS_H __FILE__
-
-/* we keep the first set of CPU IRQs out of the range of
- * the ISA space, so that the PC104 has them to itself
- * and we don't end up having to do horrible things to the
- * standard ISA drivers....
- *
- * note, since we're using the VICs, our start must be a
- * mulitple of 32 to allow the common code to work
- */
-
-#define S3C_IRQ_OFFSET         (32)
-
-#define S3C_IRQ(x)             ((x) + S3C_IRQ_OFFSET)
-
-#define S3C_VIC0_BASE          S3C_IRQ(0)
-#define S3C_VIC1_BASE          S3C_IRQ(32)
-#define S3C_VIC2_BASE          S3C_IRQ(64)
-
-/* UART interrupts, each UART has 4 intterupts per channel so
- * use the space between the ISA and S3C main interrupts. Note, these
- * are not in the same order as the S3C24XX series! */
-
-#define IRQ_S3CUART_BASE0      (16)
-#define IRQ_S3CUART_BASE1      (20)
-#define IRQ_S3CUART_BASE2      (24)
-#define IRQ_S3CUART_BASE3      (28)
-
-#define UART_IRQ_RXD           (0)
-#define UART_IRQ_ERR           (1)
-#define UART_IRQ_TXD           (2)
-#define UART_IRQ_MODEM         (3)
-
-#define IRQ_S3CUART_RX0                (IRQ_S3CUART_BASE0 + UART_IRQ_RXD)
-#define IRQ_S3CUART_TX0                (IRQ_S3CUART_BASE0 + UART_IRQ_TXD)
-#define IRQ_S3CUART_ERR0       (IRQ_S3CUART_BASE0 + UART_IRQ_ERR)
-
-#define IRQ_S3CUART_RX1                (IRQ_S3CUART_BASE1 + UART_IRQ_RXD)
-#define IRQ_S3CUART_TX1                (IRQ_S3CUART_BASE1 + UART_IRQ_TXD)
-#define IRQ_S3CUART_ERR1       (IRQ_S3CUART_BASE1 + UART_IRQ_ERR)
-
-#define IRQ_S3CUART_RX2                (IRQ_S3CUART_BASE2 + UART_IRQ_RXD)
-#define IRQ_S3CUART_TX2                (IRQ_S3CUART_BASE2 + UART_IRQ_TXD)
-#define IRQ_S3CUART_ERR2       (IRQ_S3CUART_BASE2 + UART_IRQ_ERR)
-
-#define IRQ_S3CUART_RX3                (IRQ_S3CUART_BASE3 + UART_IRQ_RXD)
-#define IRQ_S3CUART_TX3                (IRQ_S3CUART_BASE3 + UART_IRQ_TXD)
-#define IRQ_S3CUART_ERR3       (IRQ_S3CUART_BASE3 + UART_IRQ_ERR)
-
-/* VIC based IRQs */
-
-#define S5PC1XX_IRQ_VIC0(x)    (S3C_VIC0_BASE + (x))
-#define S5PC1XX_IRQ_VIC1(x)    (S3C_VIC1_BASE + (x))
-#define S5PC1XX_IRQ_VIC2(x)    (S3C_VIC2_BASE + (x))
-
-/*
- * VIC0: system, DMA, timer
- */
-#define IRQ_EINT0              S5PC1XX_IRQ_VIC0(0)
-#define IRQ_EINT1              S5PC1XX_IRQ_VIC0(1)
-#define IRQ_EINT2              S5PC1XX_IRQ_VIC0(2)
-#define IRQ_EINT3              S5PC1XX_IRQ_VIC0(3)
-#define IRQ_EINT4              S5PC1XX_IRQ_VIC0(4)
-#define IRQ_EINT5              S5PC1XX_IRQ_VIC0(5)
-#define IRQ_EINT6              S5PC1XX_IRQ_VIC0(6)
-#define IRQ_EINT7              S5PC1XX_IRQ_VIC0(7)
-#define IRQ_EINT8              S5PC1XX_IRQ_VIC0(8)
-#define IRQ_EINT9              S5PC1XX_IRQ_VIC0(9)
-#define IRQ_EINT10             S5PC1XX_IRQ_VIC0(10)
-#define IRQ_EINT11             S5PC1XX_IRQ_VIC0(11)
-#define IRQ_EINT12             S5PC1XX_IRQ_VIC0(12)
-#define IRQ_EINT13             S5PC1XX_IRQ_VIC0(13)
-#define IRQ_EINT14             S5PC1XX_IRQ_VIC0(14)
-#define IRQ_EINT15             S5PC1XX_IRQ_VIC0(15)
-#define IRQ_EINT16_31          S5PC1XX_IRQ_VIC0(16)
-#define IRQ_BATF               S5PC1XX_IRQ_VIC0(17)
-#define IRQ_MDMA               S5PC1XX_IRQ_VIC0(18)
-#define IRQ_PDMA0              S5PC1XX_IRQ_VIC0(19)
-#define IRQ_PDMA1              S5PC1XX_IRQ_VIC0(20)
-#define IRQ_TIMER0_VIC         S5PC1XX_IRQ_VIC0(21)
-#define IRQ_TIMER1_VIC         S5PC1XX_IRQ_VIC0(22)
-#define IRQ_TIMER2_VIC         S5PC1XX_IRQ_VIC0(23)
-#define IRQ_TIMER3_VIC         S5PC1XX_IRQ_VIC0(24)
-#define IRQ_TIMER4_VIC         S5PC1XX_IRQ_VIC0(25)
-#define IRQ_SYSTIMER           S5PC1XX_IRQ_VIC0(26)
-#define IRQ_WDT                        S5PC1XX_IRQ_VIC0(27)
-#define IRQ_RTC_ALARM          S5PC1XX_IRQ_VIC0(28)
-#define IRQ_RTC_TIC            S5PC1XX_IRQ_VIC0(29)
-#define IRQ_GPIOINT            S5PC1XX_IRQ_VIC0(30)
-
-/*
- * VIC1: ARM, power, memory, connectivity
- */
-#define IRQ_CORTEX0            S5PC1XX_IRQ_VIC1(0)
-#define IRQ_CORTEX1            S5PC1XX_IRQ_VIC1(1)
-#define IRQ_CORTEX2            S5PC1XX_IRQ_VIC1(2)
-#define IRQ_CORTEX3            S5PC1XX_IRQ_VIC1(3)
-#define IRQ_CORTEX4            S5PC1XX_IRQ_VIC1(4)
-#define IRQ_IEMAPC             S5PC1XX_IRQ_VIC1(5)
-#define IRQ_IEMIEC             S5PC1XX_IRQ_VIC1(6)
-#define IRQ_ONENAND            S5PC1XX_IRQ_VIC1(7)
-#define IRQ_NFC                        S5PC1XX_IRQ_VIC1(8)
-#define IRQ_CFC                        S5PC1XX_IRQ_VIC1(9)
-#define IRQ_UART0              S5PC1XX_IRQ_VIC1(10)
-#define IRQ_UART1              S5PC1XX_IRQ_VIC1(11)
-#define IRQ_UART2              S5PC1XX_IRQ_VIC1(12)
-#define IRQ_UART3              S5PC1XX_IRQ_VIC1(13)
-#define IRQ_IIC                        S5PC1XX_IRQ_VIC1(14)
-#define IRQ_SPI0               S5PC1XX_IRQ_VIC1(15)
-#define IRQ_SPI1               S5PC1XX_IRQ_VIC1(16)
-#define IRQ_SPI2               S5PC1XX_IRQ_VIC1(17)
-#define IRQ_IRDA               S5PC1XX_IRQ_VIC1(18)
-#define IRQ_CAN0               S5PC1XX_IRQ_VIC1(19)
-#define IRQ_CAN1               S5PC1XX_IRQ_VIC1(20)
-#define IRQ_HSIRX              S5PC1XX_IRQ_VIC1(21)
-#define IRQ_HSITX              S5PC1XX_IRQ_VIC1(22)
-#define IRQ_UHOST              S5PC1XX_IRQ_VIC1(23)
-#define IRQ_OTG                        S5PC1XX_IRQ_VIC1(24)
-#define IRQ_MSM                        S5PC1XX_IRQ_VIC1(25)
-#define IRQ_HSMMC0             S5PC1XX_IRQ_VIC1(26)
-#define IRQ_HSMMC1             S5PC1XX_IRQ_VIC1(27)
-#define IRQ_HSMMC2             S5PC1XX_IRQ_VIC1(28)
-#define IRQ_MIPICSI            S5PC1XX_IRQ_VIC1(29)
-#define IRQ_MIPIDSI            S5PC1XX_IRQ_VIC1(30)
-
-/*
- * VIC2: multimedia, audio, security
- */
-#define IRQ_LCD0               S5PC1XX_IRQ_VIC2(0)
-#define IRQ_LCD1               S5PC1XX_IRQ_VIC2(1)
-#define IRQ_LCD2               S5PC1XX_IRQ_VIC2(2)
-#define IRQ_LCD3               S5PC1XX_IRQ_VIC2(3)
-#define IRQ_ROTATOR            S5PC1XX_IRQ_VIC2(4)
-#define IRQ_FIMC0              S5PC1XX_IRQ_VIC2(5)
-#define IRQ_FIMC1              S5PC1XX_IRQ_VIC2(6)
-#define IRQ_FIMC2              S5PC1XX_IRQ_VIC2(7)
-#define IRQ_JPEG               S5PC1XX_IRQ_VIC2(8)
-#define IRQ_2D                 S5PC1XX_IRQ_VIC2(9)
-#define IRQ_3D                 S5PC1XX_IRQ_VIC2(10)
-#define IRQ_MIXER              S5PC1XX_IRQ_VIC2(11)
-#define IRQ_HDMI               S5PC1XX_IRQ_VIC2(12)
-#define IRQ_IIC1               S5PC1XX_IRQ_VIC2(13)
-#define IRQ_MFC                        S5PC1XX_IRQ_VIC2(14)
-#define IRQ_TVENC              S5PC1XX_IRQ_VIC2(15)
-#define IRQ_I2S0               S5PC1XX_IRQ_VIC2(16)
-#define IRQ_I2S1               S5PC1XX_IRQ_VIC2(17)
-#define IRQ_I2S2               S5PC1XX_IRQ_VIC2(18)
-#define IRQ_AC97               S5PC1XX_IRQ_VIC2(19)
-#define IRQ_PCM0               S5PC1XX_IRQ_VIC2(20)
-#define IRQ_PCM1               S5PC1XX_IRQ_VIC2(21)
-#define IRQ_SPDIF              S5PC1XX_IRQ_VIC2(22)
-#define IRQ_ADC                        S5PC1XX_IRQ_VIC2(23)
-#define IRQ_PENDN              S5PC1XX_IRQ_VIC2(24)
-#define IRQ_TC                 IRQ_PENDN
-#define IRQ_KEYPAD             S5PC1XX_IRQ_VIC2(25)
-#define IRQ_CG                 S5PC1XX_IRQ_VIC2(26)
-#define IRQ_SEC                        S5PC1XX_IRQ_VIC2(27)
-#define IRQ_SECRX              S5PC1XX_IRQ_VIC2(28)
-#define IRQ_SECTX              S5PC1XX_IRQ_VIC2(29)
-#define IRQ_SDMIRQ             S5PC1XX_IRQ_VIC2(30)
-#define IRQ_SDMFIQ             S5PC1XX_IRQ_VIC2(31)
-
-#define IRQ_TIMER(x)           (IRQ_SDMFIQ + 1 + (x))
-#define IRQ_TIMER0             IRQ_TIMER(0)
-#define IRQ_TIMER1             IRQ_TIMER(1)
-#define IRQ_TIMER2             IRQ_TIMER(2)
-#define IRQ_TIMER3             IRQ_TIMER(3)
-#define IRQ_TIMER4             IRQ_TIMER(4)
-
-/* External interrupt */
-#define S3C_IRQ_EINT_BASE      (IRQ_SDMFIQ + 6)
-
-#define S3C_EINT(x)            (S3C_IRQ_EINT_BASE + (x - 16))
-#define IRQ_EINT(x)            (x < 16 ? IRQ_EINT0 + x : S3C_EINT(x))
-#define IRQ_EINT_BIT(x)                (x < IRQ_EINT16_31 ? x - IRQ_EINT0 : x - S3C_EINT(0))
-
-/* GPIO interrupt */
-#define S3C_IRQ_GPIO_BASE      (IRQ_EINT(31) + 1)
-#define S3C_IRQ_GPIO(x)                (S3C_IRQ_GPIO_BASE + (x))
-
-/*
- * Until MP04 Groups -> 40 (exactly 39) Groups * 8 ~= 320 GPIOs
- */
-#define NR_IRQS                        (S3C_IRQ_GPIO(320) + 1)
-
-#endif /* __ASM_PLAT_S5PC1XX_IRQS_H */
-
diff --git a/arch/arm/plat-s5pc1xx/include/plat/pll.h b/arch/arm/plat-s5pc1xx/include/plat/pll.h
deleted file mode 100644 (file)
index 21afef1..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/* arch/arm/plat-s5pc1xx/include/plat/pll.h
- *
- * Copyright 2009 Samsung Electronics Co.
- *     Byungho Min <bhmin@samsung.com>
- *
- * S5PC1XX PLL code
- *
- * Based on plat-s3c64xx/include/plat/pll.h
- *
- * 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.
-*/
-
-#define S5P_PLL_MDIV_MASK      ((1 << (25-16+1)) - 1)
-#define S5P_PLL_PDIV_MASK      ((1 << (13-8+1)) - 1)
-#define S5P_PLL_SDIV_MASK      ((1 << (2-0+1)) - 1)
-#define S5P_PLL_MDIV_SHIFT     (16)
-#define S5P_PLL_PDIV_SHIFT     (8)
-#define S5P_PLL_SDIV_SHIFT     (0)
-
-#include <asm/div64.h>
-
-static inline unsigned long s5pc1xx_get_pll(unsigned long baseclk,
-                                           u32 pllcon)
-{
-       u32 mdiv, pdiv, sdiv;
-       u64 fvco = baseclk;
-
-       mdiv = (pllcon >> S5P_PLL_MDIV_SHIFT) & S5P_PLL_MDIV_MASK;
-       pdiv = (pllcon >> S5P_PLL_PDIV_SHIFT) & S5P_PLL_PDIV_MASK;
-       sdiv = (pllcon >> S5P_PLL_SDIV_SHIFT) & S5P_PLL_SDIV_MASK;
-
-       fvco *= mdiv;
-       do_div(fvco, (pdiv << sdiv));
-
-       return (unsigned long)fvco;
-}
diff --git a/arch/arm/plat-s5pc1xx/include/plat/regs-clock.h b/arch/arm/plat-s5pc1xx/include/plat/regs-clock.h
deleted file mode 100644 (file)
index 24dec4e..0000000
+++ /dev/null
@@ -1,252 +0,0 @@
-/* arch/arm/plat-s5pc1xx/include/plat/regs-clock.h
- *
- * Copyright 2009 Samsung Electronics Co.
- *     Byungho Min <bhmin@samsung.com>
- *
- * S5PC1XX clock register definitions
- *
- * 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 __PLAT_REGS_CLOCK_H
-#define __PLAT_REGS_CLOCK_H __FILE__
-
-#define S5PC100_CLKREG(x)              (S5PC1XX_VA_CLK + (x))
-#define S5PC100_CLKREG_OTHER(x)                (S5PC1XX_VA_CLK_OTHER + (x))
-
-/* s5pc100 register for clock */
-#define S5PC100_APLL_LOCK              S5PC100_CLKREG(0x00)
-#define S5PC100_MPLL_LOCK              S5PC100_CLKREG(0x04)
-#define S5PC100_EPLL_LOCK              S5PC100_CLKREG(0x08)
-#define S5PC100_HPLL_LOCK              S5PC100_CLKREG(0x0C)
-
-#define S5PC100_APLL_CON               S5PC100_CLKREG(0x100)
-#define S5PC100_MPLL_CON               S5PC100_CLKREG(0x104)
-#define S5PC100_EPLL_CON               S5PC100_CLKREG(0x108)
-#define S5PC100_HPLL_CON               S5PC100_CLKREG(0x10C)
-
-#define S5PC100_CLKSRC0                        S5PC100_CLKREG(0x200)
-#define S5PC100_CLKSRC1                        S5PC100_CLKREG(0x204)
-#define S5PC100_CLKSRC2                        S5PC100_CLKREG(0x208)
-#define S5PC100_CLKSRC3                        S5PC100_CLKREG(0x20C)
-
-#define S5PC100_CLKDIV0                        S5PC100_CLKREG(0x300)
-#define S5PC100_CLKDIV1                        S5PC100_CLKREG(0x304)
-#define S5PC100_CLKDIV2                        S5PC100_CLKREG(0x308)
-#define S5PC100_CLKDIV3                        S5PC100_CLKREG(0x30C)
-#define S5PC100_CLKDIV4                        S5PC100_CLKREG(0x310)
-
-#define S5PC100_CLK_OUT                        S5PC100_CLKREG(0x400)
-
-#define S5PC100_CLKGATE_D00            S5PC100_CLKREG(0x500)
-#define S5PC100_CLKGATE_D01            S5PC100_CLKREG(0x504)
-#define S5PC100_CLKGATE_D02            S5PC100_CLKREG(0x508)
-
-#define S5PC100_CLKGATE_D10            S5PC100_CLKREG(0x520)
-#define S5PC100_CLKGATE_D11            S5PC100_CLKREG(0x524)
-#define S5PC100_CLKGATE_D12            S5PC100_CLKREG(0x528)
-#define S5PC100_CLKGATE_D13            S5PC100_CLKREG(0x52C)
-#define S5PC100_CLKGATE_D14            S5PC100_CLKREG(0x530)
-#define S5PC100_CLKGATE_D15            S5PC100_CLKREG(0x534)
-
-#define S5PC100_CLKGATE_D20            S5PC100_CLKREG(0x540)
-
-#define S5PC100_SCLKGATE0              S5PC100_CLKREG(0x560)
-#define S5PC100_SCLKGATE1              S5PC100_CLKREG(0x564)
-
-/* EPLL_CON */
-#define S5PC100_EPLL_EN                        (1<<31)
-#define S5PC100_EPLL_MASK              0xffffffff
-#define S5PC100_EPLLVAL(_m, _p, _s)    ((_m) << 16 | ((_p) << 8) | ((_s)))
-
-/* CLKSRC0..CLKSRC3 -> mostly removed due to clksrc updates */
-#define S5PC100_CLKSRC1_CLK48M_MASK    (0x1<<24)
-#define S5PC100_CLKSRC1_CLK48M_SHIFT   (24)
-
-/* CLKDIV0 */
-#define S5PC100_CLKDIV0_APLL_MASK              (0x1<<0)
-#define S5PC100_CLKDIV0_APLL_SHIFT             (0)
-#define S5PC100_CLKDIV0_ARM_MASK               (0x7<<4)
-#define S5PC100_CLKDIV0_ARM_SHIFT              (4)
-#define S5PC100_CLKDIV0_D0_MASK                (0x7<<8)
-#define S5PC100_CLKDIV0_D0_SHIFT               (8)
-#define S5PC100_CLKDIV0_PCLKD0_MASK            (0x7<<12)
-#define S5PC100_CLKDIV0_PCLKD0_SHIFT   (12)
-#define S5PC100_CLKDIV0_SECSS_MASK             (0x7<<16)
-#define S5PC100_CLKDIV0_SECSS_SHIFT            (16)
-
-/* CLKDIV1 (OneNAND clock only used in one place, removed) */
-#define S5PC100_CLKDIV1_APLL2_MASK             (0x7<<0)
-#define S5PC100_CLKDIV1_APLL2_SHIFT            (0)
-#define S5PC100_CLKDIV1_MPLL_MASK              (0x3<<4)
-#define S5PC100_CLKDIV1_MPLL_SHIFT             (4)
-#define S5PC100_CLKDIV1_MPLL2_MASK             (0x1<<8)
-#define S5PC100_CLKDIV1_MPLL2_SHIFT            (8)
-#define S5PC100_CLKDIV1_D1_MASK                (0x7<<12)
-#define S5PC100_CLKDIV1_D1_SHIFT               (12)
-#define S5PC100_CLKDIV1_PCLKD1_MASK            (0x7<<16)
-#define S5PC100_CLKDIV1_PCLKD1_SHIFT   (16)
-#define S5PC100_CLKDIV1_CAM_MASK               (0x1F<<24)
-#define S5PC100_CLKDIV1_CAM_SHIFT              (24)
-
-/* CLKDIV2 => removed in clksrc update */
-/* CLKDIV3 => removed in clksrc update, or not needed */
-/* CLKDIV4 => removed in clksrc update, or not needed */
-
-/* HCLKD0/PCLKD0 Clock Gate 0 Registers */
-#define S5PC100_CLKGATE_D00_INTC               (1<<0)
-#define S5PC100_CLKGATE_D00_TZIC               (1<<1)
-#define S5PC100_CLKGATE_D00_CFCON              (1<<2)
-#define S5PC100_CLKGATE_D00_MDMA               (1<<3)
-#define S5PC100_CLKGATE_D00_G2D                (1<<4)
-#define S5PC100_CLKGATE_D00_SECSS              (1<<5)
-#define S5PC100_CLKGATE_D00_CSSYS              (1<<6)
-
-/* HCLKD0/PCLKD0 Clock Gate 1 Registers */
-#define S5PC100_CLKGATE_D01_DMC                (1<<0)
-#define S5PC100_CLKGATE_D01_SROMC              (1<<1)
-#define S5PC100_CLKGATE_D01_ONENAND            (1<<2)
-#define S5PC100_CLKGATE_D01_NFCON              (1<<3)
-#define S5PC100_CLKGATE_D01_INTMEM             (1<<4)
-#define S5PC100_CLKGATE_D01_EBI                (1<<5)
-
-/* PCLKD0 Clock Gate 2 Registers */
-#define S5PC100_CLKGATE_D02_SECKEY             (1<<1)
-#define S5PC100_CLKGATE_D02_SDM                (1<<2)
-
-/* HCLKD1/PCLKD1 Clock Gate 0 Registers */
-#define S5PC100_CLKGATE_D10_PDMA0              (1<<0)
-#define S5PC100_CLKGATE_D10_PDMA1              (1<<1)
-#define S5PC100_CLKGATE_D10_USBHOST            (1<<2)
-#define S5PC100_CLKGATE_D10_USBOTG             (1<<3)
-#define S5PC100_CLKGATE_D10_MODEMIF            (1<<4)
-#define S5PC100_CLKGATE_D10_HSMMC0             (1<<5)
-#define S5PC100_CLKGATE_D10_HSMMC1             (1<<6)
-#define S5PC100_CLKGATE_D10_HSMMC2             (1<<7)
-
-/* HCLKD1/PCLKD1 Clock Gate 1 Registers */
-#define S5PC100_CLKGATE_D11_LCD                (1<<0)
-#define S5PC100_CLKGATE_D11_ROTATOR            (1<<1)
-#define S5PC100_CLKGATE_D11_FIMC0              (1<<2)
-#define S5PC100_CLKGATE_D11_FIMC1              (1<<3)
-#define S5PC100_CLKGATE_D11_FIMC2              (1<<4)
-#define S5PC100_CLKGATE_D11_JPEG               (1<<5)
-#define S5PC100_CLKGATE_D11_DSI                (1<<6)
-#define S5PC100_CLKGATE_D11_CSI                (1<<7)
-#define S5PC100_CLKGATE_D11_G3D                (1<<8)
-
-/* HCLKD1/PCLKD1 Clock Gate 2 Registers */
-#define S5PC100_CLKGATE_D12_TV         (1<<0)
-#define S5PC100_CLKGATE_D12_VP         (1<<1)
-#define S5PC100_CLKGATE_D12_MIXER              (1<<2)
-#define S5PC100_CLKGATE_D12_HDMI               (1<<3)
-#define S5PC100_CLKGATE_D12_MFC                (1<<4)
-
-/* HCLKD1/PCLKD1 Clock Gate 3 Registers */
-#define S5PC100_CLKGATE_D13_CHIPID             (1<<0)
-#define S5PC100_CLKGATE_D13_GPIO               (1<<1)
-#define S5PC100_CLKGATE_D13_APC                (1<<2)
-#define S5PC100_CLKGATE_D13_IEC                (1<<3)
-#define S5PC100_CLKGATE_D13_PWM                (1<<6)
-#define S5PC100_CLKGATE_D13_SYSTIMER   (1<<7)
-#define S5PC100_CLKGATE_D13_WDT                (1<<8)
-#define S5PC100_CLKGATE_D13_RTC                (1<<9)
-
-/* HCLKD1/PCLKD1 Clock Gate 4 Registers */
-#define S5PC100_CLKGATE_D14_UART0              (1<<0)
-#define S5PC100_CLKGATE_D14_UART1              (1<<1)
-#define S5PC100_CLKGATE_D14_UART2              (1<<2)
-#define S5PC100_CLKGATE_D14_UART3              (1<<3)
-#define S5PC100_CLKGATE_D14_IIC                (1<<4)
-#define S5PC100_CLKGATE_D14_HDMI_IIC   (1<<5)
-#define S5PC100_CLKGATE_D14_SPI0               (1<<6)
-#define S5PC100_CLKGATE_D14_SPI1               (1<<7)
-#define S5PC100_CLKGATE_D14_SPI2               (1<<8)
-#define S5PC100_CLKGATE_D14_IRDA               (1<<9)
-#define S5PC100_CLKGATE_D14_CCAN0              (1<<10)
-#define S5PC100_CLKGATE_D14_CCAN1              (1<<11)
-#define S5PC100_CLKGATE_D14_HSITX              (1<<12)
-#define S5PC100_CLKGATE_D14_HSIRX              (1<<13)
-
-/* HCLKD1/PCLKD1 Clock Gate 5 Registers */
-#define S5PC100_CLKGATE_D15_IIS0               (1<<0)
-#define S5PC100_CLKGATE_D15_IIS1               (1<<1)
-#define S5PC100_CLKGATE_D15_IIS2               (1<<2)
-#define S5PC100_CLKGATE_D15_AC97               (1<<3)
-#define S5PC100_CLKGATE_D15_PCM0               (1<<4)
-#define S5PC100_CLKGATE_D15_PCM1               (1<<5)
-#define S5PC100_CLKGATE_D15_SPDIF              (1<<6)
-#define S5PC100_CLKGATE_D15_TSADC              (1<<7)
-#define S5PC100_CLKGATE_D15_KEYIF              (1<<8)
-#define S5PC100_CLKGATE_D15_CG         (1<<9)
-
-/* HCLKD2 Clock Gate 0 Registers */
-#define S5PC100_CLKGATE_D20_HCLKD2             (1<<0)
-#define S5PC100_CLKGATE_D20_I2SD2              (1<<1)
-
-/* Special Clock Gate 0 Registers */
-#define        S5PC100_CLKGATE_SCLK0_HPM               (1<<0)
-#define        S5PC100_CLKGATE_SCLK0_PWI               (1<<1)
-#define        S5PC100_CLKGATE_SCLK0_ONENAND   (1<<2)
-#define        S5PC100_CLKGATE_SCLK0_UART              (1<<3)
-#define        S5PC100_CLKGATE_SCLK0_SPI0              (1<<4)
-#define        S5PC100_CLKGATE_SCLK0_SPI1              (1<<5)
-#define        S5PC100_CLKGATE_SCLK0_SPI2              (1<<6)
-#define        S5PC100_CLKGATE_SCLK0_SPI0_48   (1<<7)
-#define        S5PC100_CLKGATE_SCLK0_SPI1_48   (1<<8)
-#define        S5PC100_CLKGATE_SCLK0_SPI2_48   (1<<9)
-#define        S5PC100_CLKGATE_SCLK0_IRDA              (1<<10)
-#define        S5PC100_CLKGATE_SCLK0_USBHOST   (1<<11)
-#define        S5PC100_CLKGATE_SCLK0_MMC0              (1<<12)
-#define        S5PC100_CLKGATE_SCLK0_MMC1              (1<<13)
-#define        S5PC100_CLKGATE_SCLK0_MMC2              (1<<14)
-#define        S5PC100_CLKGATE_SCLK0_MMC0_48   (1<<15)
-#define        S5PC100_CLKGATE_SCLK0_MMC1_48   (1<<16)
-#define        S5PC100_CLKGATE_SCLK0_MMC2_48   (1<<17)
-
-/* Special Clock Gate 1 Registers */
-#define        S5PC100_CLKGATE_SCLK1_LCD               (1<<0)
-#define        S5PC100_CLKGATE_SCLK1_FIMC0             (1<<1)
-#define        S5PC100_CLKGATE_SCLK1_FIMC1             (1<<2)
-#define        S5PC100_CLKGATE_SCLK1_FIMC2             (1<<3)
-#define        S5PC100_CLKGATE_SCLK1_TV54              (1<<4)
-#define        S5PC100_CLKGATE_SCLK1_VDAC54    (1<<5)
-#define        S5PC100_CLKGATE_SCLK1_MIXER             (1<<6)
-#define        S5PC100_CLKGATE_SCLK1_HDMI              (1<<7)
-#define        S5PC100_CLKGATE_SCLK1_AUDIO0    (1<<8)
-#define        S5PC100_CLKGATE_SCLK1_AUDIO1    (1<<9)
-#define        S5PC100_CLKGATE_SCLK1_AUDIO2    (1<<10)
-#define        S5PC100_CLKGATE_SCLK1_SPDIF             (1<<11)
-#define        S5PC100_CLKGATE_SCLK1_CAM               (1<<12)
-
-#define S5PC100_SWRESET                S5PC100_CLKREG_OTHER(0x000)
-#define S5PC100_OND_SWRESET    S5PC100_CLKREG_OTHER(0x008)
-#define S5PC100_GEN_CTRL       S5PC100_CLKREG_OTHER(0x100)
-#define S5PC100_GEN_STATUS     S5PC100_CLKREG_OTHER(0x104)
-#define S5PC100_MEM_SYS_CFG    S5PC100_CLKREG_OTHER(0x200)
-#define S5PC100_CAM_MUX_SEL    S5PC100_CLKREG_OTHER(0x300)
-#define S5PC100_MIXER_OUT_SEL  S5PC100_CLKREG_OTHER(0x304)
-#define S5PC100_LPMP_MODE_SEL  S5PC100_CLKREG_OTHER(0x308)
-#define S5PC100_MIPI_PHY_CON0  S5PC100_CLKREG_OTHER(0x400)
-#define S5PC100_MIPI_PHY_CON1  S5PC100_CLKREG_OTHER(0x414)
-#define S5PC100_HDMI_PHY_CON0  S5PC100_CLKREG_OTHER(0x420)
-
-#define S5PC100_SWRESET_RESETVAL       0xc100
-#define S5PC100_OTHER_SYS_INT  24
-#define S5PC100_OTHER_STA_TYPE 23
-#define STA_TYPE_EXPON         0
-#define STA_TYPE_SFR           1
-
-#define S5PC100_SLEEP_CFG_OSC_EN       0
-
-/* OTHERS Resgister */
-#define S5PC100_OTHERS_USB_SIG_MASK    (1 << 16)
-#define S5PC100_OTHERS_MIPI_DPHY_EN            (1 << 28)
-
-/* MIPI D-PHY Control Register 0 */
-#define S5PC100_MIPI_PHY_CON0_M_RESETN (1 << 1)
-#define S5PC100_MIPI_PHY_CON0_S_RESETN (1 << 0)
-
-#endif /* _PLAT_REGS_CLOCK_H */
diff --git a/arch/arm/plat-s5pc1xx/include/plat/regs-power.h b/arch/arm/plat-s5pc1xx/include/plat/regs-power.h
deleted file mode 100644 (file)
index 02ffa49..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/* arch/arm/plat-s5pc1xx/include/plat/regs-clock.h
- *
- * Copyright 2009 Samsung Electronics Co.
- *     Jongse Won <jongse.won@samsung.com>
- *
- * S5PC1XX clock register definitions
- *
- * 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 __ASM_ARM_REGS_PWR
-#define __ASM_ARM_REGS_PWR __FILE__
-
-#define S5PC1XX_PWRREG(x)                      (S5PC1XX_VA_PWR + (x))
-
-/* s5pc100 (0xE0108000) register for power management */
-#define S5PC100_PWR_CFG                                S5PC1XX_PWRREG(0x0)
-#define S5PC100_EINT_WAKEUP_MASK               S5PC1XX_PWRREG(0x4)
-#define S5PC100_NORMAL_CFG                     S5PC1XX_PWRREG(0x10)
-#define S5PC100_STOP_CFG                       S5PC1XX_PWRREG(0x14)
-#define S5PC100_SLEEP_CFG                      S5PC1XX_PWRREG(0x18)
-#define S5PC100_STOP_MEM_CFG                   S5PC1XX_PWRREG(0x1C)
-#define S5PC100_OSC_FREQ                       S5PC1XX_PWRREG(0x100)
-#define S5PC100_OSC_STABLE                     S5PC1XX_PWRREG(0x104)
-#define S5PC100_PWR_STABLE                     S5PC1XX_PWRREG(0x108)
-#define S5PC100_MTC_STABLE                     S5PC1XX_PWRREG(0x110)
-#define S5PC100_CLAMP_STABLE                   S5PC1XX_PWRREG(0x114)
-#define S5PC100_OTHERS                         S5PC1XX_PWRREG(0x200)
-#define S5PC100_RST_STAT                       S5PC1XX_PWRREG(0x300)
-#define S5PC100_WAKEUP_STAT                    S5PC1XX_PWRREG(0x304)
-#define S5PC100_BLK_PWR_STAT                   S5PC1XX_PWRREG(0x308)
-#define S5PC100_INFORM0                                S5PC1XX_PWRREG(0x400)
-#define S5PC100_INFORM1                                S5PC1XX_PWRREG(0x404)
-#define S5PC100_INFORM2                                S5PC1XX_PWRREG(0x408)
-#define S5PC100_INFORM3                                S5PC1XX_PWRREG(0x40C)
-#define S5PC100_INFORM4                                S5PC1XX_PWRREG(0x410)
-#define S5PC100_INFORM5                                S5PC1XX_PWRREG(0x414)
-#define S5PC100_INFORM6                                S5PC1XX_PWRREG(0x418)
-#define S5PC100_INFORM7                                S5PC1XX_PWRREG(0x41C)
-#define S5PC100_DCGIDX_MAP0                    S5PC1XX_PWRREG(0x500)
-#define S5PC100_DCGIDX_MAP1                    S5PC1XX_PWRREG(0x504)
-#define S5PC100_DCGIDX_MAP2                    S5PC1XX_PWRREG(0x508)
-#define S5PC100_DCGPERF_MAP0                   S5PC1XX_PWRREG(0x50C)
-#define S5PC100_DCGPERF_MAP1                   S5PC1XX_PWRREG(0x510)
-#define S5PC100_DVCIDX_MAP                     S5PC1XX_PWRREG(0x514)
-#define S5PC100_FREQ_CPU                       S5PC1XX_PWRREG(0x518)
-#define S5PC100_FREQ_DPM                       S5PC1XX_PWRREG(0x51C)
-#define S5PC100_DVSEMCLK_EN                    S5PC1XX_PWRREG(0x520)
-#define S5PC100_APLL_CON_L8                    S5PC1XX_PWRREG(0x600)
-#define S5PC100_APLL_CON_L7                    S5PC1XX_PWRREG(0x604)
-#define S5PC100_APLL_CON_L6                    S5PC1XX_PWRREG(0x608)
-#define S5PC100_APLL_CON_L5                    S5PC1XX_PWRREG(0x60C)
-#define S5PC100_APLL_CON_L4                    S5PC1XX_PWRREG(0x610)
-#define S5PC100_APLL_CON_L3                    S5PC1XX_PWRREG(0x614)
-#define S5PC100_APLL_CON_L2                    S5PC1XX_PWRREG(0x618)
-#define S5PC100_APLL_CON_L1                    S5PC1XX_PWRREG(0x61C)
-#define S5PC100_IEM_CONTROL                    S5PC1XX_PWRREG(0x620)
-#define S5PC100_CLKDIV_IEM_L8                  S5PC1XX_PWRREG(0x700)
-#define S5PC100_CLKDIV_IEM_L7                  S5PC1XX_PWRREG(0x704)
-#define S5PC100_CLKDIV_IEM_L6                  S5PC1XX_PWRREG(0x708)
-#define S5PC100_CLKDIV_IEM_L5                  S5PC1XX_PWRREG(0x70C)
-#define S5PC100_CLKDIV_IEM_L4                  S5PC1XX_PWRREG(0x710)
-#define S5PC100_CLKDIV_IEM_L3                  S5PC1XX_PWRREG(0x714)
-#define S5PC100_CLKDIV_IEM_L2                  S5PC1XX_PWRREG(0x718)
-#define S5PC100_CLKDIV_IEM_L1                  S5PC1XX_PWRREG(0x71C)
-#define S5PC100_IEM_HPMCLK_DIV                 S5PC1XX_PWRREG(0x724)
-
-/* PWR_CFG */
-#define S5PC100_PWRCFG_CFG_DEEP_IDLE           (1 << 31)
-#define S5PC100_PWRCFG_CFG_WFI_MASK            (3 << 5)
-#define S5PC100_PWRCFG_CFG_WFI_IDLE            (0 << 5)
-#define S5PC100_PWRCFG_CFG_WFI_DEEP_IDLE       (1 << 5)
-#define S5PC100_PWRCFG_CFG_WFI_STOP            (2 << 5)
-#define S5PC100_PWRCFG_CFG_WFI_SLEEP           (3 << 5)
-
-/* SLEEP_CFG */
-#define S5PC100_SLEEP_OSC_EN_SLEEP             (1 << 0)
-
-/* OTHERS */
-#define S5PC100_PMU_INT_DISABLE                        (1 << 24)
-
-#endif /* __ASM_ARM_REGS_PWR */
diff --git a/arch/arm/plat-s5pc1xx/include/plat/s5pc100.h b/arch/arm/plat-s5pc1xx/include/plat/s5pc100.h
deleted file mode 100644 (file)
index 2531f34..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/* arch/arm/plat-s5pc1xx/include/plat/s5pc100.h
- *
- * Copyright 2009 Samsung Electronics Co.
- *     Byungho Min <bhmin@samsung.com>
- *
- * Header file for s5pc100 cpu support
- *
- * Based on plat-s3c64xx/include/plat/s3c6400.h
- *
- * 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.
-*/
-
-/* Common init code for S5PC100 related SoCs */
-extern  int s5pc100_init(void);
-extern void s5pc100_map_io(void);
-extern void s5pc100_init_clocks(int xtal);
-extern  int s5pc100_register_baseclocks(unsigned long xtal);
-extern void s5pc100_init_irq(void);
-extern void s5pc100_init_io(struct map_desc *mach_desc, int size);
-extern void s5pc100_common_init_uarts(struct s3c2410_uartcfg *cfg, int no);
-extern void s5pc100_register_clocks(void);
-extern void s5pc100_setup_clocks(void);
-extern struct sysdev_class s5pc100_sysclass;
-
-#define s5pc100_init_uarts s5pc100_common_init_uarts
-
-/* Some day, belows will be moved to plat-s5pc/include/plat/cpu.h */
-extern void s5pc1xx_init_irq(u32 *vic_valid, int num);
-extern void s5pc1xx_init_io(struct map_desc *mach_desc, int size);
-
-/* Some day, belows will be moved to plat-s5pc/include/plat/clock.h */
-extern struct clk clk_hpll;
-extern struct clk clk_hd0;
-extern struct clk clk_pd0;
-extern struct clk clk_54m;
-extern void s5pc1xx_register_clocks(void);
-extern int s5pc100_sclk0_ctrl(struct clk *clk, int enable);
-extern int s5pc100_sclk1_ctrl(struct clk *clk, int enable);
-
-/* Some day, belows will be moved to plat-s5pc/include/plat/devs.h */
-extern struct s3c24xx_uart_resources s5pc1xx_uart_resources[];
-extern struct platform_device s3c_device_g2d;
-extern struct platform_device s3c_device_g3d;
-extern struct platform_device s3c_device_vpp;
-extern struct platform_device s3c_device_tvenc;
-extern struct platform_device s3c_device_tvscaler;
-extern struct platform_device s3c_device_rotator;
-extern struct platform_device s3c_device_jpeg;
-extern struct platform_device s3c_device_onenand;
-extern struct platform_device s3c_device_usb_otghcd;
-extern struct platform_device s3c_device_keypad;
-extern struct platform_device s3c_device_ts;
-extern struct platform_device s3c_device_g3d;
-extern struct platform_device s3c_device_smc911x;
-extern struct platform_device s3c_device_fimc0;
-extern struct platform_device s3c_device_fimc1;
-extern struct platform_device s3c_device_mfc;
-extern struct platform_device s3c_device_ac97;
-extern struct platform_device s3c_device_fimc0;
-extern struct platform_device s3c_device_fimc1;
-extern struct platform_device s3c_device_fimc2;
-
diff --git a/arch/arm/plat-s5pc1xx/irq-eint.c b/arch/arm/plat-s5pc1xx/irq-eint.c
deleted file mode 100644 (file)
index 373122f..0000000
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * linux/arch/arm/plat-s5pc1xx/irq-eint.c
- *
- *  Copyright 2009 Samsung Electronics Co.
- *  Byungho Min <bhmin@samsung.com>
- *  Kyungin Park <kyungmin.park@samsung.com>
- *
- * Based on plat-s3c64xx/irq-eint.c
- *
- * S5PC1XX - Interrupt handling for IRQ_EINT(x)
- *
- * 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/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-#include <linux/sysdev.h>
-#include <linux/pm.h>
-#include <linux/gpio.h>
-
-#include <asm/hardware/vic.h>
-
-#include <mach/map.h>
-
-#include <plat/gpio-cfg.h>
-#include <plat/gpio-ext.h>
-#include <plat/pm.h>
-#include <plat/regs-gpio.h>
-#include <plat/regs-irqtype.h>
-
-/*
- * bank is a group of external interrupt
- * bank0 means EINT0 ... EINT7
- * bank1 means EINT8 ... EINT15
- * bank2 means EINT16 ... EINT23
- * bank3 means EINT24 ... EINT31
- */
-
-static inline int s3c_get_eint(unsigned int irq)
-{
-       int real;
-
-       if (irq < IRQ_EINT16_31)
-               real = (irq - IRQ_EINT0);
-       else
-               real = (irq - S3C_IRQ_EINT_BASE) + IRQ_EINT16_31 - IRQ_EINT0;
-
-       return real;
-}
-
-static inline int s3c_get_bank(unsigned int irq)
-{
-       return s3c_get_eint(irq) >> 3;
-}
-
-static inline int s3c_eint_to_bit(unsigned int irq)
-{
-       int real, bit;
-
-       real = s3c_get_eint(irq);
-       bit = 1 << (real & (8 - 1));
-
-       return bit;
-}
-
-static inline void s3c_irq_eint_mask(unsigned int irq)
-{
-       u32 mask;
-       u32 bank = s3c_get_bank(irq);
-
-       mask = __raw_readl(S5PC1XX_WKUP_INT_MASK(bank));
-       mask |= s3c_eint_to_bit(irq);
-       __raw_writel(mask, S5PC1XX_WKUP_INT_MASK(bank));
-}
-
-static void s3c_irq_eint_unmask(unsigned int irq)
-{
-       u32 mask;
-       u32 bank = s3c_get_bank(irq);
-
-       mask = __raw_readl(S5PC1XX_WKUP_INT_MASK(bank));
-       mask &= ~(s3c_eint_to_bit(irq));
-       __raw_writel(mask, S5PC1XX_WKUP_INT_MASK(bank));
-}
-
-static inline void s3c_irq_eint_ack(unsigned int irq)
-{
-       u32 bank = s3c_get_bank(irq);
-
-       __raw_writel(s3c_eint_to_bit(irq), S5PC1XX_WKUP_INT_PEND(bank));
-}
-
-static void s3c_irq_eint_maskack(unsigned int irq)
-{
-       /* compiler should in-line these */
-       s3c_irq_eint_mask(irq);
-       s3c_irq_eint_ack(irq);
-}
-
-static int s3c_irq_eint_set_type(unsigned int irq, unsigned int type)
-{
-       u32 bank = s3c_get_bank(irq);
-       int real = s3c_get_eint(irq);
-       int gpio, shift, sfn;
-       u32 ctrl, con = 0;
-
-       switch (type) {
-       case IRQ_TYPE_NONE:
-               printk(KERN_WARNING "No edge setting!\n");
-               break;
-
-       case IRQ_TYPE_EDGE_RISING:
-               con = S5PC1XX_WKUP_INT_RISEEDGE;
-               break;
-
-       case IRQ_TYPE_EDGE_FALLING:
-               con = S5PC1XX_WKUP_INT_FALLEDGE;
-               break;
-
-       case IRQ_TYPE_EDGE_BOTH:
-               con = S5PC1XX_WKUP_INT_BOTHEDGE;
-               break;
-
-       case IRQ_TYPE_LEVEL_LOW:
-               con = S5PC1XX_WKUP_INT_LOWLEV;
-               break;
-
-       case IRQ_TYPE_LEVEL_HIGH:
-               con = S5PC1XX_WKUP_INT_HILEV;
-               break;
-
-       default:
-               printk(KERN_ERR "No such irq type %d", type);
-               return -EINVAL;
-       }
-
-       gpio = real & (8 - 1);
-       shift = gpio << 2;
-
-       ctrl = __raw_readl(S5PC1XX_WKUP_INT_CON(bank));
-       ctrl &= ~(0x7 << shift);
-       ctrl |= con << shift;
-       __raw_writel(ctrl, S5PC1XX_WKUP_INT_CON(bank));
-
-       switch (real) {
-       case 0 ... 7:
-                       gpio = S5PC100_GPH0(gpio);
-               break;
-       case 8 ... 15:
-                       gpio = S5PC100_GPH1(gpio);
-               break;
-       case 16 ... 23:
-                       gpio = S5PC100_GPH2(gpio);
-               break;
-       case 24 ... 31:
-                       gpio = S5PC100_GPH3(gpio);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       sfn = S3C_GPIO_SFN(0x2);
-       s3c_gpio_cfgpin(gpio, sfn);
-
-       return 0;
-}
-
-static struct irq_chip s3c_irq_eint = {
-       .name           = "EINT",
-       .mask           = s3c_irq_eint_mask,
-       .unmask         = s3c_irq_eint_unmask,
-       .mask_ack       = s3c_irq_eint_maskack,
-       .ack            = s3c_irq_eint_ack,
-       .set_type       = s3c_irq_eint_set_type,
-       .set_wake       = s3c_irqext_wake,
-};
-
-/* s3c_irq_demux_eint
- *
- * This function demuxes the IRQ from external interrupts,
- * from IRQ_EINT(16) to IRQ_EINT(31). It is designed to be inlined into
- * the specific handlers s3c_irq_demux_eintX_Y.
- */
-static inline void s3c_irq_demux_eint(unsigned int start, unsigned int end)
-{
-       u32 status = __raw_readl(S5PC1XX_WKUP_INT_PEND((start >> 3)));
-       u32 mask = __raw_readl(S5PC1XX_WKUP_INT_MASK((start >> 3)));
-       unsigned int irq;
-
-       status &= ~mask;
-       status &= (1 << (end - start + 1)) - 1;
-
-       for (irq = IRQ_EINT(start); irq <= IRQ_EINT(end); irq++) {
-               if (status & 1)
-                       generic_handle_irq(irq);
-
-               status >>= 1;
-       }
-}
-
-static void s3c_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
-{
-       s3c_irq_demux_eint(16, 23);
-       s3c_irq_demux_eint(24, 31);
-}
-
-/*
- * Handle EINT0 ... EINT15 at VIC directly
- */
-static void s3c_irq_vic_eint_mask(unsigned int irq)
-{
-       void __iomem *base = get_irq_chip_data(irq);
-       unsigned int real;
-
-       s3c_irq_eint_mask(irq);
-       real = s3c_get_eint(irq);
-       writel(1 << real, base + VIC_INT_ENABLE_CLEAR);
-}
-
-static void s3c_irq_vic_eint_unmask(unsigned int irq)
-{
-       void __iomem *base = get_irq_chip_data(irq);
-       unsigned int real;
-
-       s3c_irq_eint_unmask(irq);
-       real = s3c_get_eint(irq);
-       writel(1 << real, base + VIC_INT_ENABLE);
-}
-
-static inline void s3c_irq_vic_eint_ack(unsigned int irq)
-{
-       u32 bit;
-       u32 bank = s3c_get_bank(irq);
-
-       bit = s3c_eint_to_bit(irq);
-       __raw_writel(bit, S5PC1XX_WKUP_INT_PEND(bank));
-}
-
-static void s3c_irq_vic_eint_maskack(unsigned int irq)
-{
-       /* compiler should in-line these */
-       s3c_irq_vic_eint_mask(irq);
-       s3c_irq_vic_eint_ack(irq);
-}
-
-static struct irq_chip s3c_irq_vic_eint = {
-       .name           = "EINT",
-       .mask           = s3c_irq_vic_eint_mask,
-       .unmask         = s3c_irq_vic_eint_unmask,
-       .mask_ack       = s3c_irq_vic_eint_maskack,
-       .ack            = s3c_irq_vic_eint_ack,
-       .set_type       = s3c_irq_eint_set_type,
-       .set_wake       = s3c_irqext_wake,
-};
-
-static int __init s5pc1xx_init_irq_eint(void)
-{
-       int irq;
-
-       for (irq = IRQ_EINT0; irq <= IRQ_EINT15; irq++) {
-               set_irq_chip(irq, &s3c_irq_vic_eint);
-               set_irq_handler(irq, handle_level_irq);
-               set_irq_flags(irq, IRQF_VALID);
-       }
-
-       for (irq = IRQ_EINT(16); irq <= IRQ_EINT(31); irq++) {
-               set_irq_chip(irq, &s3c_irq_eint);
-               set_irq_handler(irq, handle_level_irq);
-               set_irq_flags(irq, IRQF_VALID);
-       }
-
-       set_irq_chained_handler(IRQ_EINT16_31, s3c_irq_demux_eint16_31);
-
-       return 0;
-}
-
-arch_initcall(s5pc1xx_init_irq_eint);
diff --git a/arch/arm/plat-s5pc1xx/irq.c b/arch/arm/plat-s5pc1xx/irq.c
deleted file mode 100644 (file)
index bfc5248..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/* arch/arm/plat-s5pc1xx/irq.c
- *
- * Copyright 2009 Samsung Electronics Co.
- *      Byungho Min <bhmin@samsung.com>
- *
- * S5PC1XX - Interrupt handling
- *
- * Based on plat-s3c64xx/irq.c
- *
- * 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/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-
-#include <asm/hardware/vic.h>
-
-#include <mach/map.h>
-#include <plat/irq-vic-timer.h>
-#include <plat/irq-uart.h>
-#include <plat/cpu.h>
-
-/* Note, we make use of the fact that the parent IRQs, IRQ_UART[0..3]
- * are consecutive when looking up the interrupt in the demux routines.
- */
-static struct s3c_uart_irq uart_irqs[] = {
-       [0] = {
-               .regs           = (void *)S3C_VA_UART0,
-               .base_irq       = IRQ_S3CUART_BASE0,
-               .parent_irq     = IRQ_UART0,
-       },
-       [1] = {
-               .regs           = (void *)S3C_VA_UART1,
-               .base_irq       = IRQ_S3CUART_BASE1,
-               .parent_irq     = IRQ_UART1,
-       },
-       [2] = {
-               .regs           = (void *)S3C_VA_UART2,
-               .base_irq       = IRQ_S3CUART_BASE2,
-               .parent_irq     = IRQ_UART2,
-       },
-       [3] = {
-               .regs           = (void *)S3C_VA_UART3,
-               .base_irq       = IRQ_S3CUART_BASE3,
-               .parent_irq     = IRQ_UART3,
-       },
-};
-
-void __init s5pc1xx_init_irq(u32 *vic_valid, int num)
-{
-       int i;
-
-       printk(KERN_DEBUG "%s: initialising interrupts\n", __func__);
-
-       /* initialise the pair of VICs */
-       for (i = 0; i < num; i++)
-               vic_init((void *)S5PC1XX_VA_VIC(i), S3C_IRQ(i * S3C_IRQ_OFFSET),
-                               vic_valid[i], 0);
-
-       /* add the timer sub-irqs */
-
-       s3c_init_vic_timer_irq(IRQ_TIMER0_VIC, IRQ_TIMER0);
-       s3c_init_vic_timer_irq(IRQ_TIMER1_VIC, IRQ_TIMER1);
-       s3c_init_vic_timer_irq(IRQ_TIMER2_VIC, IRQ_TIMER2);
-       s3c_init_vic_timer_irq(IRQ_TIMER3_VIC, IRQ_TIMER3);
-       s3c_init_vic_timer_irq(IRQ_TIMER4_VIC, IRQ_TIMER4);
-
-       s3c_init_uart_irqs(uart_irqs, ARRAY_SIZE(uart_irqs));
-}
-
-
diff --git a/arch/arm/plat-s5pc1xx/s5pc100-clock.c b/arch/arm/plat-s5pc1xx/s5pc100-clock.c
deleted file mode 100644 (file)
index 2bf6c57..0000000
+++ /dev/null
@@ -1,876 +0,0 @@
-/* linux/arch/arm/plat-s5pc1xx/s5pc100-clock.c
- *
- * Copyright 2009 Samsung Electronics, Co.
- *     Byungho Min <bhmin@samsung.com>
- *
- * S5PC100 based common clock support
- *
- * Based on plat-s3c64xx/s3c6400-clock.c
- *
- * 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/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/sysdev.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <mach/map.h>
-
-#include <plat/cpu-freq.h>
-
-#include <plat/regs-clock.h>
-#include <plat/clock.h>
-#include <plat/clock-clksrc.h>
-#include <plat/cpu.h>
-#include <plat/pll.h>
-#include <plat/devs.h>
-#include <plat/s5pc100.h>
-
-/* fin_apll, fin_mpll and fin_epll are all the same clock, which we call
- * ext_xtal_mux for want of an actual name from the manual.
-*/
-
-static struct clk clk_ext_xtal_mux = {
-       .name           = "ext_xtal",
-       .id             = -1,
-};
-
-#define clk_fin_apll clk_ext_xtal_mux
-#define clk_fin_mpll clk_ext_xtal_mux
-#define clk_fin_epll clk_ext_xtal_mux
-#define clk_fin_hpll clk_ext_xtal_mux
-
-#define clk_fout_mpll  clk_mpll
-#define clk_vclk_54m   clk_54m
-
-/* APLL */
-static struct clk clk_fout_apll = {
-       .name           = "fout_apll",
-       .id             = -1,
-       .rate           = 27000000,
-};
-
-static struct clk *clk_src_apll_list[] = {
-       [0] = &clk_fin_apll,
-       [1] = &clk_fout_apll,
-};
-
-static struct clksrc_sources clk_src_apll = {
-       .sources        = clk_src_apll_list,
-       .nr_sources     = ARRAY_SIZE(clk_src_apll_list),
-};
-
-static struct clksrc_clk clk_mout_apll = {
-       .clk    = {
-               .name           = "mout_apll",
-               .id             = -1,
-       },
-       .sources        = &clk_src_apll,
-       .reg_src = { .reg = S5PC100_CLKSRC0, .shift = 0, .size = 1, },
-};
-
-static unsigned long s5pc100_clk_dout_apll_get_rate(struct clk *clk)
-{
-       unsigned long rate = clk_get_rate(clk->parent);
-       unsigned int ratio;
-
-       ratio = __raw_readl(S5PC100_CLKDIV0) & S5PC100_CLKDIV0_APLL_MASK;
-       ratio >>= S5PC100_CLKDIV0_APLL_SHIFT;
-
-       return rate / (ratio + 1);
-}
-
-static struct clk clk_dout_apll = {
-       .name           = "dout_apll",
-       .id             = -1,
-       .parent         = &clk_mout_apll.clk,
-       .ops            = &(struct clk_ops) {
-               .get_rate       = s5pc100_clk_dout_apll_get_rate,
-       },
-};
-
-static unsigned long s5pc100_clk_arm_get_rate(struct clk *clk)
-{
-       unsigned long rate = clk_get_rate(clk->parent);
-       unsigned int ratio;
-
-       ratio = __raw_readl(S5PC100_CLKDIV0) & S5PC100_CLKDIV0_ARM_MASK;
-       ratio >>= S5PC100_CLKDIV0_ARM_SHIFT;
-
-       return rate / (ratio + 1);
-}
-
-static unsigned long s5pc100_clk_arm_round_rate(struct clk *clk,
-                                               unsigned long rate)
-{
-       unsigned long parent = clk_get_rate(clk->parent);
-       u32 div;
-
-       if (parent < rate)
-               return rate;
-
-       div = (parent / rate) - 1;
-       if (div > S5PC100_CLKDIV0_ARM_MASK)
-               div = S5PC100_CLKDIV0_ARM_MASK;
-
-       return parent / (div + 1);
-}
-
-static int s5pc100_clk_arm_set_rate(struct clk *clk, unsigned long rate)
-{
-       unsigned long parent = clk_get_rate(clk->parent);
-       u32 div;
-       u32 val;
-
-       if (rate < parent / (S5PC100_CLKDIV0_ARM_MASK + 1))
-               return -EINVAL;
-
-       rate = clk_round_rate(clk, rate);
-       div = clk_get_rate(clk->parent) / rate;
-
-       val = __raw_readl(S5PC100_CLKDIV0);
-       val &= S5PC100_CLKDIV0_ARM_MASK;
-       val |= (div - 1);
-       __raw_writel(val, S5PC100_CLKDIV0);
-
-       return 0;
-}
-
-static struct clk clk_arm = {
-       .name           = "armclk",
-       .id             = -1,
-       .parent         = &clk_dout_apll,
-       .ops            = &(struct clk_ops) {
-               .get_rate       = s5pc100_clk_arm_get_rate,
-               .set_rate       = s5pc100_clk_arm_set_rate,
-               .round_rate     = s5pc100_clk_arm_round_rate,
-       },
-};
-
-static unsigned long s5pc100_clk_dout_d0_bus_get_rate(struct clk *clk)
-{
-       unsigned long rate = clk_get_rate(clk->parent);
-       unsigned int ratio;
-
-       ratio = __raw_readl(S5PC100_CLKDIV0) & S5PC100_CLKDIV0_D0_MASK;
-       ratio >>= S5PC100_CLKDIV0_D0_SHIFT;
-
-       return rate / (ratio + 1);
-}
-
-static struct clk clk_dout_d0_bus = {
-       .name           = "dout_d0_bus",
-       .id             = -1,
-       .parent         = &clk_arm,
-       .ops            = &(struct clk_ops) {
-               .get_rate       = s5pc100_clk_dout_d0_bus_get_rate,
-       },
-};
-
-static unsigned long s5pc100_clk_dout_pclkd0_get_rate(struct clk *clk)
-{
-       unsigned long rate = clk_get_rate(clk->parent);
-       unsigned int ratio;
-
-       ratio = __raw_readl(S5PC100_CLKDIV0) & S5PC100_CLKDIV0_PCLKD0_MASK;
-       ratio >>= S5PC100_CLKDIV0_PCLKD0_SHIFT;
-
-       return rate / (ratio + 1);
-}
-
-static struct clk clk_dout_pclkd0 = {
-       .name           = "dout_pclkd0",
-       .id             = -1,
-       .parent         = &clk_dout_d0_bus,
-       .ops            = &(struct clk_ops) {
-               .get_rate       = s5pc100_clk_dout_pclkd0_get_rate,
-       },
-};
-
-static unsigned long s5pc100_clk_dout_apll2_get_rate(struct clk *clk)
-{
-       unsigned long rate = clk_get_rate(clk->parent);
-       unsigned int ratio;
-
-       ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_APLL2_MASK;
-       ratio >>= S5PC100_CLKDIV1_APLL2_SHIFT;
-
-       return rate / (ratio + 1);
-}
-
-static struct clk clk_dout_apll2 = {
-       .name           = "dout_apll2",
-       .id             = -1,
-       .parent         = &clk_mout_apll.clk,
-       .ops            = &(struct clk_ops) {
-               .get_rate       = s5pc100_clk_dout_apll2_get_rate,
-       },
-};
-
-/* MPLL */
-static struct clk *clk_src_mpll_list[] = {
-       [0] = &clk_fin_mpll,
-       [1] = &clk_fout_mpll,
-};
-
-static struct clksrc_sources clk_src_mpll = {
-       .sources        = clk_src_mpll_list,
-       .nr_sources     = ARRAY_SIZE(clk_src_mpll_list),
-};
-
-static struct clksrc_clk clk_mout_mpll = {
-       .clk = {
-               .name           = "mout_mpll",
-               .id             = -1,
-       },
-       .sources        = &clk_src_mpll,
-       .reg_src = { .reg = S5PC100_CLKSRC0, .shift = 4, .size = 1, },
-};
-
-static struct clk *clkset_am_list[] = {
-       [0] = &clk_mout_mpll.clk,
-       [1] = &clk_dout_apll2,
-};
-
-static struct clksrc_sources clk_src_am = {
-       .sources        = clkset_am_list,
-       .nr_sources     = ARRAY_SIZE(clkset_am_list),
-};
-
-static struct clksrc_clk clk_mout_am = {
-       .clk = {
-               .name           = "mout_am",
-               .id             = -1,
-       },
-       .sources        = &clk_src_am,
-       .reg_src = { .reg = S5PC100_CLKSRC0, .shift = 16, .size = 1, },
-};
-
-static unsigned long s5pc100_clk_dout_d1_bus_get_rate(struct clk *clk)
-{
-       unsigned long rate = clk_get_rate(clk->parent);
-       unsigned int ratio;
-
-       printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
-
-       ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_D1_MASK;
-       ratio >>= S5PC100_CLKDIV1_D1_SHIFT;
-
-       return rate / (ratio + 1);
-}
-
-static struct clk clk_dout_d1_bus = {
-       .name           = "dout_d1_bus",
-       .id             = -1,
-       .parent         = &clk_mout_am.clk,
-       .ops            = &(struct clk_ops) {
-               .get_rate       = s5pc100_clk_dout_d1_bus_get_rate,
-       },
-};
-
-static struct clk *clkset_onenand_list[] = {
-       [0] = &clk_dout_d0_bus,
-       [1] = &clk_dout_d1_bus,
-};
-
-static struct clksrc_sources clk_src_onenand = {
-       .sources        = clkset_onenand_list,
-       .nr_sources     = ARRAY_SIZE(clkset_onenand_list),
-};
-
-static struct clksrc_clk clk_mout_onenand = {
-       .clk = {
-               .name           = "mout_onenand",
-               .id             = -1,
-       },
-       .sources        = &clk_src_onenand,
-       .reg_src = { .reg = S5PC100_CLKSRC0, .shift = 24, .size = 1, },
-};
-
-static unsigned long s5pc100_clk_dout_pclkd1_get_rate(struct clk *clk)
-{
-       unsigned long rate = clk_get_rate(clk->parent);
-       unsigned int ratio;
-
-       printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
-
-       ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_PCLKD1_MASK;
-       ratio >>= S5PC100_CLKDIV1_PCLKD1_SHIFT;
-
-       return rate / (ratio + 1);
-}
-
-static struct clk clk_dout_pclkd1 = {
-       .name           = "dout_pclkd1",
-       .id             = -1,
-       .parent         = &clk_dout_d1_bus,
-       .ops            = &(struct clk_ops) {
-               .get_rate       = s5pc100_clk_dout_pclkd1_get_rate,
-       },
-};
-
-static unsigned long s5pc100_clk_dout_mpll2_get_rate(struct clk *clk)
-{
-       unsigned long rate = clk_get_rate(clk->parent);
-       unsigned int ratio;
-
-       printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
-
-       ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_MPLL2_MASK;
-       ratio >>= S5PC100_CLKDIV1_MPLL2_SHIFT;
-
-       return rate / (ratio + 1);
-}
-
-static struct clk clk_dout_mpll2 = {
-       .name           = "dout_mpll2",
-       .id             = -1,
-       .parent         = &clk_mout_am.clk,
-       .ops            = &(struct clk_ops) {
-               .get_rate       = s5pc100_clk_dout_mpll2_get_rate,
-       },
-};
-
-static unsigned long s5pc100_clk_dout_cam_get_rate(struct clk *clk)
-{
-       unsigned long rate = clk_get_rate(clk->parent);
-       unsigned int ratio;
-
-       printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
-
-       ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_CAM_MASK;
-       ratio >>= S5PC100_CLKDIV1_CAM_SHIFT;
-
-       return rate / (ratio + 1);
-}
-
-static struct clk clk_dout_cam = {
-       .name           = "dout_cam",
-       .id             = -1,
-       .parent         = &clk_dout_mpll2,
-       .ops            = &(struct clk_ops) {
-               .get_rate       = s5pc100_clk_dout_cam_get_rate,
-       },
-};
-
-static unsigned long s5pc100_clk_dout_mpll_get_rate(struct clk *clk)
-{
-       unsigned long rate = clk_get_rate(clk->parent);
-       unsigned int ratio;
-
-       printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
-
-       ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_MPLL_MASK;
-       ratio >>= S5PC100_CLKDIV1_MPLL_SHIFT;
-
-       return rate / (ratio + 1);
-}
-
-static struct clk clk_dout_mpll = {
-       .name           = "dout_mpll",
-       .id             = -1,
-       .parent         = &clk_mout_am.clk,
-       .ops            = &(struct clk_ops) {
-               .get_rate       = s5pc100_clk_dout_mpll_get_rate,
-       },
-};
-
-/* EPLL */
-static struct clk clk_fout_epll = {
-       .name           = "fout_epll",
-       .id             = -1,
-};
-
-static struct clk *clk_src_epll_list[] = {
-       [0] = &clk_fin_epll,
-       [1] = &clk_fout_epll,
-};
-
-static struct clksrc_sources clk_src_epll = {
-       .sources        = clk_src_epll_list,
-       .nr_sources     = ARRAY_SIZE(clk_src_epll_list),
-};
-
-static struct clksrc_clk clk_mout_epll = {
-       .clk    = {
-               .name           = "mout_epll",
-               .id             = -1,
-       },
-       .sources = &clk_src_epll,
-       .reg_src = { .reg = S5PC100_CLKSRC0, .shift = 8, .size = 1, },
-};
-
-/* HPLL */
-static struct clk clk_fout_hpll = {
-       .name           = "fout_hpll",
-       .id             = -1,
-};
-
-static struct clk *clk_src_hpll_list[] = {
-       [0] = &clk_27m,
-       [1] = &clk_fout_hpll,
-};
-
-static struct clksrc_sources clk_src_hpll = {
-       .sources        = clk_src_hpll_list,
-       .nr_sources     = ARRAY_SIZE(clk_src_hpll_list),
-};
-
-static struct clksrc_clk clk_mout_hpll = {
-       .clk    = {
-               .name           = "mout_hpll",
-               .id             = -1,
-       },
-       .sources = &clk_src_hpll,
-       .reg_src = { .reg = S5PC100_CLKSRC0, .shift = 12, .size = 1, },
-};
-
-/* Peripherals */
-/*
- * The peripheral clocks are all controlled via clocksource followed
- * by an optional divider and gate stage. We currently roll this into
- * one clock which hides the intermediate clock from the mux.
- *
- * Note, the JPEG clock can only be an even divider...
- *
- * The scaler and LCD clocks depend on the S5PC100 version, and also
- * have a common parent divisor so are not included here.
- */
-
-static struct clk clk_iis_cd0 = {
-       .name           = "iis_cdclk0",
-       .id             = -1,
-};
-
-static struct clk clk_iis_cd1 = {
-       .name           = "iis_cdclk1",
-       .id             = -1,
-};
-
-static struct clk clk_iis_cd2 = {
-       .name           = "iis_cdclk2",
-       .id             = -1,
-};
-
-static struct clk clk_pcm_cd0 = {
-       .name           = "pcm_cdclk0",
-       .id             = -1,
-};
-
-static struct clk clk_pcm_cd1 = {
-       .name           = "pcm_cdclk1",
-       .id             = -1,
-};
-
-static struct clk *clkset_audio0_list[] = {
-       &clk_mout_epll.clk,
-       &clk_dout_mpll,
-       &clk_fin_epll,
-       &clk_iis_cd0,
-       &clk_pcm_cd0,
-       &clk_mout_hpll.clk,
-};
-
-static struct clksrc_sources clkset_audio0 = {
-       .sources        = clkset_audio0_list,
-       .nr_sources     = ARRAY_SIZE(clkset_audio0_list),
-};
-
-static struct clk *clkset_spi_list[] = {
-       &clk_mout_epll.clk,
-       &clk_dout_mpll2,
-       &clk_fin_epll,
-       &clk_mout_hpll.clk,
-};
-
-static struct clksrc_sources clkset_spi = {
-       .sources        = clkset_spi_list,
-       .nr_sources     = ARRAY_SIZE(clkset_spi_list),
-};
-
-static struct clk *clkset_uart_list[] = {
-       &clk_mout_epll.clk,
-       &clk_dout_mpll,
-};
-
-static struct clksrc_sources clkset_uart = {
-       .sources        = clkset_uart_list,
-       .nr_sources     = ARRAY_SIZE(clkset_uart_list),
-};
-
-static struct clk *clkset_audio1_list[] = {
-       &clk_mout_epll.clk,
-       &clk_dout_mpll,
-       &clk_fin_epll,
-       &clk_iis_cd1,
-       &clk_pcm_cd1,
-       &clk_mout_hpll.clk,
-};
-
-static struct clksrc_sources clkset_audio1 = {
-       .sources        = clkset_audio1_list,
-       .nr_sources     = ARRAY_SIZE(clkset_audio1_list),
-};
-
-static struct clk *clkset_audio2_list[] = {
-       &clk_mout_epll.clk,
-       &clk_dout_mpll,
-       &clk_fin_epll,
-       &clk_iis_cd2,
-       &clk_mout_hpll.clk,
-};
-
-static struct clksrc_sources clkset_audio2 = {
-       .sources        = clkset_audio2_list,
-       .nr_sources     = ARRAY_SIZE(clkset_audio2_list),
-};
-
-static struct clksrc_clk clksrc_audio[] = {
-       {
-               .clk    = {
-                       .name           = "audio-bus",
-                       .id             = 0,
-                       .ctrlbit        = S5PC100_CLKGATE_SCLK1_AUDIO0,
-                       .enable         = s5pc100_sclk1_ctrl,
-               },
-               .sources = &clkset_audio0,
-               .reg_div = { .reg = S5PC100_CLKDIV4, .shift = 12, .size = 4, },
-               .reg_src = { .reg = S5PC100_CLKSRC3, .shift = 12, .size = 3, },
-       }, {
-               .clk    = {
-                       .name           = "audio-bus",
-                       .id             = 1,
-                       .ctrlbit        = S5PC100_CLKGATE_SCLK1_AUDIO1,
-                       .enable         = s5pc100_sclk1_ctrl,
-               },
-               .sources = &clkset_audio1,
-               .reg_div = { .reg = S5PC100_CLKDIV4, .shift = 16, .size = 4, },
-               .reg_src = { .reg = S5PC100_CLKSRC3, .shift = 16, .size = 3, },
-       }, {
-               .clk    = {
-                       .name           = "audio-bus",
-                       .id             = 2,
-                       .ctrlbit        = S5PC100_CLKGATE_SCLK1_AUDIO2,
-                       .enable         = s5pc100_sclk1_ctrl,
-               },
-               .sources = &clkset_audio2,
-               .reg_div = { .reg = S5PC100_CLKDIV4, .shift = 20, .size = 4, },
-               .reg_src = { .reg = S5PC100_CLKSRC3, .shift = 20, .size = 3, },
-       },
-};
-
-static struct clk *clkset_spdif_list[] = {
-       &clksrc_audio[0].clk,
-       &clksrc_audio[1].clk,
-       &clksrc_audio[2].clk,
-};
-
-static struct clksrc_sources clkset_spdif = {
-       .sources        = clkset_spdif_list,
-       .nr_sources     = ARRAY_SIZE(clkset_spdif_list),
-};
-
-static struct clk *clkset_lcd_fimc_list[] = {
-       &clk_mout_epll.clk,
-       &clk_dout_mpll,
-       &clk_mout_hpll.clk,
-       &clk_vclk_54m,
-};
-
-static struct clksrc_sources clkset_lcd_fimc = {
-       .sources        = clkset_lcd_fimc_list,
-       .nr_sources     = ARRAY_SIZE(clkset_lcd_fimc_list),
-};
-
-static struct clk *clkset_mmc_list[] = {
-       &clk_mout_epll.clk,
-       &clk_dout_mpll,
-       &clk_fin_epll,
-       &clk_mout_hpll.clk ,
-};
-
-static struct clksrc_sources clkset_mmc = {
-       .sources        = clkset_mmc_list,
-       .nr_sources     = ARRAY_SIZE(clkset_mmc_list),
-};
-
-static struct clk *clkset_usbhost_list[] = {
-       &clk_mout_epll.clk,
-       &clk_dout_mpll,
-       &clk_mout_hpll.clk,
-       &clk_48m,
-};
-
-static struct clksrc_sources clkset_usbhost = {
-       .sources        = clkset_usbhost_list,
-       .nr_sources     = ARRAY_SIZE(clkset_usbhost_list),
-};
-
-static struct clksrc_clk clksrc_clks[] = {
-       {
-               .clk    = {
-                       .name           = "spi_bus",
-                       .id             = 0,
-                       .ctrlbit        = S5PC100_CLKGATE_SCLK0_SPI0,
-                       .enable         = s5pc100_sclk0_ctrl,
-
-               },
-               .sources = &clkset_spi,
-               .reg_div = { .reg = S5PC100_CLKDIV2, .shift = 4, .size = 4, },
-               .reg_src = { .reg = S5PC100_CLKSRC1, .shift = 4, .size = 2, },
-       }, {
-               .clk    = {
-                       .name           = "spi_bus",
-                       .id             = 1,
-                       .ctrlbit        = S5PC100_CLKGATE_SCLK0_SPI1,
-                       .enable         = s5pc100_sclk0_ctrl,
-               },
-               .sources = &clkset_spi,
-               .reg_div = { .reg = S5PC100_CLKDIV2, .shift = 8, .size = 4, },
-               .reg_src = { .reg = S5PC100_CLKSRC1, .shift = 8, .size = 2, },
-       }, {
-               .clk    = {
-                       .name           = "spi_bus",
-                       .id             = 2,
-                       .ctrlbit        = S5PC100_CLKGATE_SCLK0_SPI2,
-                       .enable         = s5pc100_sclk0_ctrl,
-               },
-               .sources = &clkset_spi,
-               .reg_div = { .reg = S5PC100_CLKDIV2, .shift = 12, .size = 4, },
-               .reg_src = { .reg = S5PC100_CLKSRC1, .shift = 12, .size = 2, },
-       }, {
-               .clk    = {
-                       .name           = "uclk1",
-                       .id             = -1,
-                       .ctrlbit        = S5PC100_CLKGATE_SCLK0_UART,
-                       .enable         = s5pc100_sclk0_ctrl,
-               },
-               .sources = &clkset_uart,
-               .reg_div = { .reg = S5PC100_CLKDIV2, .shift = 0, .size = 3, },
-               .reg_src = { .reg = S5PC100_CLKSRC1, .shift = 0, .size = 1, },
-       }, {
-               .clk    = {
-                       .name           = "spdif",
-                       .id             = -1,
-               },
-               .sources        = &clkset_spdif,
-               .reg_src = { .reg = S5PC100_CLKSRC3, .shift = 24, .size = 2, },
-       }, {
-               .clk    = {
-                       .name           = "lcd",
-                       .id             = -1,
-                       .ctrlbit        = S5PC100_CLKGATE_SCLK1_LCD,
-                       .enable         = s5pc100_sclk1_ctrl,
-               },
-               .sources = &clkset_lcd_fimc,
-               .reg_div = { .reg = S5PC100_CLKDIV3, .shift = 12, .size = 4, },
-               .reg_src = { .reg = S5PC100_CLKSRC2, .shift = 12, .size = 2, },
-       }, {
-               .clk    = {
-                       .name           = "fimc",
-                       .id             = 0,
-                       .ctrlbit        = S5PC100_CLKGATE_SCLK1_FIMC0,
-                       .enable         = s5pc100_sclk1_ctrl,
-               },
-               .sources = &clkset_lcd_fimc,
-               .reg_div = { .reg = S5PC100_CLKDIV3, .shift = 16, .size = 4, },
-               .reg_src = { .reg = S5PC100_CLKSRC2, .shift = 16, .size = 2, },
-       }, {
-               .clk    = {
-                       .name           = "fimc",
-                       .id             = 1,
-                       .ctrlbit        = S5PC100_CLKGATE_SCLK1_FIMC1,
-                       .enable         = s5pc100_sclk1_ctrl,
-               },
-               .sources        = &clkset_lcd_fimc,
-               .reg_div = { .reg = S5PC100_CLKDIV3, .shift = 20, .size = 4, },
-               .reg_src = { .reg = S5PC100_CLKSRC2, .shift = 20, .size = 2, },
-       }, {
-               .clk    = {
-                       .name           = "fimc",
-                       .id             = 2,
-                       .ctrlbit        = S5PC100_CLKGATE_SCLK1_FIMC2,
-                       .enable         = s5pc100_sclk1_ctrl,
-               },
-               .sources = &clkset_lcd_fimc,
-               .reg_div = { .reg = S5PC100_CLKDIV3, .shift = 24, .size = 4, },
-               .reg_src = { .reg = S5PC100_CLKSRC2, .shift = 24, .size = 2, },
-       }, {
-               .clk    = {
-                       .name           = "mmc_bus",
-                       .id             = 0,
-                       .ctrlbit        = S5PC100_CLKGATE_SCLK0_MMC0,
-                       .enable         = s5pc100_sclk0_ctrl,
-               },
-               .sources = &clkset_mmc,
-               .reg_div = { .reg = S5PC100_CLKDIV3, .shift = 0, .size = 4, },
-               .reg_src = { .reg = S5PC100_CLKSRC2, .shift = 0, .size = 2, },
-       }, {
-               .clk    = {
-                       .name           = "mmc_bus",
-                       .id             = 1,
-                       .ctrlbit        = S5PC100_CLKGATE_SCLK0_MMC1,
-                       .enable         = s5pc100_sclk0_ctrl,
-               },
-               .sources = &clkset_mmc,
-               .reg_div = { .reg = S5PC100_CLKDIV3, .shift = 4, .size = 4, },
-               .reg_src = { .reg = S5PC100_CLKSRC2, .shift = 4, .size = 2, },
-       }, {
-               .clk    = {
-                       .name           = "mmc_bus",
-                       .id             = 2,
-                       .ctrlbit        = S5PC100_CLKGATE_SCLK0_MMC2,
-                       .enable         = s5pc100_sclk0_ctrl,
-               },
-               .sources        = &clkset_mmc,
-               .reg_div = { .reg = S5PC100_CLKDIV3, .shift = 8, .size = 4, },
-               .reg_src = { .reg = S5PC100_CLKSRC2, .shift = 8, .size = 2, },
-       }, {
-               .clk    = {
-                       .name           = "usbhost",
-                       .id             = -1,
-                       .ctrlbit        = S5PC100_CLKGATE_SCLK0_USBHOST,
-                       .enable         = s5pc100_sclk0_ctrl,
-               },
-               .sources = &clkset_usbhost,
-               .reg_div = { .reg = S5PC100_CLKDIV2, .shift = 20, .size = 4, },
-               .reg_src = { .reg = S5PC100_CLKSRC1, .shift = 20, .size = 2, },
-       }
-};
-
-/* Clock initialisation code */
-
-static struct clksrc_clk *init_parents[] = {
-       &clk_mout_apll,
-       &clk_mout_mpll,
-       &clk_mout_am,
-       &clk_mout_onenand,
-       &clk_mout_epll,
-       &clk_mout_hpll,
-};
-
-#define GET_DIV(clk, field) ((((clk) & field##_MASK) >> field##_SHIFT) + 1)
-
-void __init_or_cpufreq s5pc100_setup_clocks(void)
-{
-       struct clk *xtal_clk;
-       unsigned long xtal;
-       unsigned long armclk;
-       unsigned long hclkd0;
-       unsigned long hclk;
-       unsigned long pclkd0;
-       unsigned long pclk;
-       unsigned long apll, mpll, epll, hpll;
-       unsigned int ptr;
-       u32 clkdiv0, clkdiv1;
-
-       printk(KERN_DEBUG "%s: registering clocks\n", __func__);
-
-       clkdiv0 = __raw_readl(S5PC100_CLKDIV0);
-       clkdiv1 = __raw_readl(S5PC100_CLKDIV1);
-
-       printk(KERN_DEBUG "%s: clkdiv0 = %08x, clkdiv1 = %08x\n", __func__, clkdiv0, clkdiv1);
-
-       xtal_clk = clk_get(NULL, "xtal");
-       BUG_ON(IS_ERR(xtal_clk));
-
-       xtal = clk_get_rate(xtal_clk);
-       clk_put(xtal_clk);
-
-       printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal);
-
-       apll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_APLL_CON));
-       mpll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_MPLL_CON));
-       epll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_EPLL_CON));
-       hpll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_HPLL_CON));
-
-       printk(KERN_INFO "S5PC100: Apll=%ld.%03ld Mhz, Mpll=%ld.%03ld Mhz"
-               ", Epll=%ld.%03ld Mhz, Hpll=%ld.%03ld Mhz\n",
-               print_mhz(apll), print_mhz(mpll),
-               print_mhz(epll), print_mhz(hpll));
-
-       armclk = apll / GET_DIV(clkdiv0, S5PC100_CLKDIV0_APLL);
-       armclk = armclk / GET_DIV(clkdiv0, S5PC100_CLKDIV0_ARM);
-       hclkd0 = armclk / GET_DIV(clkdiv0, S5PC100_CLKDIV0_D0);
-       pclkd0 = hclkd0 / GET_DIV(clkdiv0, S5PC100_CLKDIV0_PCLKD0);
-       hclk = mpll / GET_DIV(clkdiv1, S5PC100_CLKDIV1_D1);
-       pclk = hclk / GET_DIV(clkdiv1, S5PC100_CLKDIV1_PCLKD1);
-
-       printk(KERN_INFO "S5PC100: ARMCLK=%ld.%03ld MHz, HCLKD0=%ld.%03ld MHz,"
-               " PCLKD0=%ld.%03ld MHz\n, HCLK=%ld.%03ld MHz,"
-               " PCLK=%ld.%03ld MHz\n",
-               print_mhz(armclk), print_mhz(hclkd0),
-               print_mhz(pclkd0), print_mhz(hclk), print_mhz(pclk));
-
-       clk_fout_apll.rate = apll;
-       clk_fout_mpll.rate = mpll;
-       clk_fout_epll.rate = epll;
-       clk_fout_hpll.rate = hpll;
-
-       clk_h.rate = hclk;
-       clk_p.rate = pclk;
-       clk_f.rate = armclk;
-
-       for (ptr = 0; ptr < ARRAY_SIZE(init_parents); ptr++)
-               s3c_set_clksrc(init_parents[ptr], true);
-
-       for (ptr = 0; ptr < ARRAY_SIZE(clksrc_audio); ptr++)
-               s3c_set_clksrc(clksrc_audio + ptr, true);
-
-       for (ptr = 0; ptr < ARRAY_SIZE(clksrc_clks); ptr++)
-               s3c_set_clksrc(clksrc_clks + ptr, true);
-}
-
-static struct clk *clks[] __initdata = {
-       &clk_ext_xtal_mux,
-       &clk_dout_apll,
-       &clk_dout_d0_bus,
-       &clk_dout_pclkd0,
-       &clk_dout_apll2,
-       &clk_mout_apll.clk,
-       &clk_mout_mpll.clk,
-       &clk_mout_epll.clk,
-       &clk_mout_hpll.clk,
-       &clk_mout_am.clk,
-       &clk_dout_d1_bus,
-       &clk_mout_onenand.clk,
-       &clk_dout_pclkd1,
-       &clk_dout_mpll2,
-       &clk_dout_cam,
-       &clk_dout_mpll,
-       &clk_fout_epll,
-       &clk_iis_cd0,
-       &clk_iis_cd1,
-       &clk_iis_cd2,
-       &clk_pcm_cd0,
-       &clk_pcm_cd1,
-       &clk_arm,
-};
-
-void __init s5pc100_register_clocks(void)
-{
-       struct clk *clkp;
-       int ret;
-       int ptr;
-
-       for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
-               clkp = clks[ptr];
-               ret = s3c24xx_register_clock(clkp);
-               if (ret < 0) {
-                       printk(KERN_ERR "Failed to register clock %s (%d)\n",
-                              clkp->name, ret);
-               }
-       }
-
-       s3c_register_clksrc(clksrc_audio, ARRAY_SIZE(clksrc_audio));
-       s3c_register_clksrc(clksrc_clks, ARRAY_SIZE(clksrc_clks));
-}
index 229919e9744c8ee3f2cf0b570c48247946f0d6bb..2753fb3e4f7339be6563d5bc3ed2009806560c7c 100644 (file)
@@ -6,7 +6,7 @@
 
 config PLAT_SAMSUNG
        bool
-       depends on ARCH_S3C2410 || ARCH_S3C24A0 || ARCH_S3C64XX || ARCH_S5PC1XX
+       depends on ARCH_S3C2410 || ARCH_S3C24A0 || ARCH_S3C64XX
        select NO_IOPORT
        default y
        help
@@ -170,6 +170,11 @@ config S3C_DEV_I2C1
        help
          Compile in platform device definitions for I2C channel 1
 
+config S3C_DEV_I2C2
+       bool
+       help
+         Compile in platform device definitions for I2C channel 2
+
 config S3C_DEV_FB
        bool
        help
@@ -185,11 +190,22 @@ config S3C_DEV_USB_HSOTG
        help
          Compile in platform device definition for USB high-speed OtG
 
+config S3C_DEV_WDT
+       bool
+       default y if ARCH_S3C2410
+       help
+         Complie in platform device definition for Watchdog Timer
+
 config S3C_DEV_NAND
        bool
        help
          Compile in platform device definition for NAND controller
 
+config S3C_DEV_ONENAND
+       bool
+       help
+         Compile in platform device definition for OneNAND controller
+
 config S3C_DEV_RTC
        bool
        help
@@ -269,4 +285,12 @@ config SAMSUNG_PM_CHECK_CHUNKSIZE
 
          See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt>
 
+config SAMSUNG_WAKEMASK
+       bool
+       depends on PM
+       help
+         Compile support for wakeup-mask controls found on the S3C6400
+         and above. This code allows a set of interrupt to wakeup-mask
+         mappings. See <plat/wakeup-mask.h>
+
 endif
index 48288499a3b9f8a3a2fceb5be1d5047f88fcd7c1..b1d82cc5e716cc87fd75440eed3f117f0b5b4fb9 100644 (file)
@@ -36,11 +36,14 @@ obj-$(CONFIG_S3C_DEV_HSMMC2)        += dev-hsmmc2.o
 obj-$(CONFIG_S3C_DEV_HWMON)    += dev-hwmon.o
 obj-y                          += dev-i2c0.o
 obj-$(CONFIG_S3C_DEV_I2C1)     += dev-i2c1.o
+obj-$(CONFIG_S3C_DEV_I2C2)     += dev-i2c2.o
 obj-$(CONFIG_S3C_DEV_FB)       += dev-fb.o
 obj-y                          += dev-uart.o
 obj-$(CONFIG_S3C_DEV_USB_HOST) += dev-usb.o
 obj-$(CONFIG_S3C_DEV_USB_HSOTG)        += dev-usb-hsotg.o
+obj-$(CONFIG_S3C_DEV_WDT)      += dev-wdt.o
 obj-$(CONFIG_S3C_DEV_NAND)     += dev-nand.o
+obj-$(CONFIG_S3C_DEV_ONENAND)  += dev-onenand.o
 obj-$(CONFIG_S3C_DEV_RTC)      += dev-rtc.o
 
 obj-$(CONFIG_SAMSUNG_DEV_ADC)  += dev-adc.o
@@ -58,6 +61,8 @@ obj-$(CONFIG_PM)              += pm.o
 obj-$(CONFIG_PM)               += pm-gpio.o
 obj-$(CONFIG_SAMSUNG_PM_CHECK) += pm-check.o
 
+obj-$(CONFIG_SAMSUNG_WAKEMASK) += wakeup-mask.o
+
 # PWM support
 
 obj-$(CONFIG_HAVE_PWM)         += pwm.o
index 210030d5cfe13e3761e99f19732ab9a3b97a893c..04d9521ddc9f0e652d62453a99bbb19fa877c7fa 100644 (file)
@@ -66,6 +66,7 @@ struct adc_device {
        struct s3c_adc_client   *cur;
        struct s3c_adc_client   *ts_pend;
        void __iomem            *regs;
+       spinlock_t               lock;
 
        unsigned int             prescale;
 
@@ -74,7 +75,7 @@ struct adc_device {
 
 static struct adc_device *adc_dev;
 
-static LIST_HEAD(adc_pending);
+static LIST_HEAD(adc_pending); /* protected by adc_device.lock */
 
 #define adc_dbg(_adc, msg...) dev_dbg(&(_adc)->pdev->dev, msg)
 
@@ -145,7 +146,7 @@ int s3c_adc_start(struct s3c_adc_client *client,
        if (client->is_ts && adc->ts_pend)
                return -EAGAIN;
 
-       local_irq_save(flags);
+       spin_lock_irqsave(&adc->lock, flags);
 
        client->channel = channel;
        client->nr_samples = nr_samples;
@@ -157,7 +158,8 @@ int s3c_adc_start(struct s3c_adc_client *client,
 
        if (!adc->cur)
                s3c_adc_try(adc);
-       local_irq_restore(flags);
+
+       spin_unlock_irqrestore(&adc->lock, flags);
 
        return 0;
 }
@@ -237,6 +239,10 @@ EXPORT_SYMBOL_GPL(s3c_adc_register);
 
 void s3c_adc_release(struct s3c_adc_client *client)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&adc_dev->lock, flags);
+
        /* We should really check that nothing is in progress. */
        if (adc_dev->cur == client)
                adc_dev->cur = NULL;
@@ -255,6 +261,8 @@ void s3c_adc_release(struct s3c_adc_client *client)
 
        if (adc_dev->cur == NULL)
                s3c_adc_try(adc_dev);
+
+       spin_unlock_irqrestore(&adc_dev->lock, flags);
        kfree(client);
 }
 EXPORT_SYMBOL_GPL(s3c_adc_release);
@@ -264,7 +272,6 @@ static irqreturn_t s3c_adc_irq(int irq, void *pw)
        struct adc_device *adc = pw;
        struct s3c_adc_client *client = adc->cur;
        enum s3c_cpu_type cpu = platform_get_device_id(adc->pdev)->driver_data;
-       unsigned long flags;
        unsigned data0, data1;
 
        if (!client) {
@@ -296,12 +303,12 @@ static irqreturn_t s3c_adc_irq(int irq, void *pw)
                client->select_cb(client, 1);
                s3c_adc_convert(adc);
        } else {
-               local_irq_save(flags);
+               spin_lock(&adc->lock);
                (client->select_cb)(client, 0);
                adc->cur = NULL;
 
                s3c_adc_try(adc);
-               local_irq_restore(flags);
+               spin_unlock(&adc->lock);
        }
 
 exit:
@@ -326,6 +333,8 @@ static int s3c_adc_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
+       spin_lock_init(&adc->lock);
+
        adc->pdev = pdev;
        adc->prescale = S3C2410_ADCCON_PRSCVL(49);
 
@@ -407,13 +416,17 @@ static int __devexit s3c_adc_remove(struct platform_device *pdev)
 static int s3c_adc_suspend(struct platform_device *pdev, pm_message_t state)
 {
        struct adc_device *adc = platform_get_drvdata(pdev);
+       unsigned long flags;
        u32 con;
 
+       spin_lock_irqsave(&adc->lock, flags);
+
        con = readl(adc->regs + S3C2410_ADCCON);
        con |= S3C2410_ADCCON_STDBM;
        writel(con, adc->regs + S3C2410_ADCCON);
 
        disable_irq(adc->irq);
+       spin_unlock_irqrestore(&adc->lock, flags);
        clk_disable(adc->clk);
 
        return 0;
@@ -422,6 +435,7 @@ static int s3c_adc_suspend(struct platform_device *pdev, pm_message_t state)
 static int s3c_adc_resume(struct platform_device *pdev)
 {
        struct adc_device *adc = platform_get_drvdata(pdev);
+       unsigned long flags;
 
        clk_enable(adc->clk);
        enable_irq(adc->irq);
diff --git a/arch/arm/plat-samsung/dev-i2c2.c b/arch/arm/plat-samsung/dev-i2c2.c
new file mode 100644 (file)
index 0000000..07036de
--- /dev/null
@@ -0,0 +1,70 @@
+/* linux/arch/arm/plat-s3c/dev-i2c2.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * S3C series device definition for i2c device 2
+ *
+ * Based on plat-samsung/dev-i2c0.c
+ *
+ * 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/gfp.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+
+#include <mach/irqs.h>
+#include <mach/map.h>
+
+#include <plat/regs-iic.h>
+#include <plat/iic.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+
+static struct resource s3c_i2c_resource[] = {
+       [0] = {
+               .start = S3C_PA_IIC2,
+               .end   = S3C_PA_IIC2 + SZ_4K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_CAN0,
+               .end   = IRQ_CAN0,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device s3c_device_i2c2 = {
+       .name             = "s3c2410-i2c",
+       .id               = 2,
+       .num_resources    = ARRAY_SIZE(s3c_i2c_resource),
+       .resource         = s3c_i2c_resource,
+};
+
+static struct s3c2410_platform_i2c default_i2c_data2 __initdata = {
+       .flags          = 0,
+       .bus_num        = 2,
+       .slave_addr     = 0x10,
+       .frequency      = 100*1000,
+       .sda_delay      = 100,
+};
+
+void __init s3c_i2c2_set_platdata(struct s3c2410_platform_i2c *pd)
+{
+       struct s3c2410_platform_i2c *npd;
+
+       if (!pd)
+               pd = &default_i2c_data2;
+
+       npd = kmemdup(pd, sizeof(struct s3c2410_platform_i2c), GFP_KERNEL);
+       if (!npd)
+               printk(KERN_ERR "%s: no memory for platform data\n", __func__);
+       else if (!npd->cfg_gpio)
+               npd->cfg_gpio = s3c_i2c2_cfg_gpio;
+
+       s3c_device_i2c2.dev.platform_data = npd;
+}
diff --git a/arch/arm/plat-samsung/dev-onenand.c b/arch/arm/plat-samsung/dev-onenand.c
new file mode 100644 (file)
index 0000000..45ec732
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * linux/arch/arm/plat-samsung/dev-onenand.c
+ *
+ *  Copyright (c) 2008-2010 Samsung Electronics
+ *  Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * S3C64XX/S5PC100 series device definition for OneNAND devices
+ *
+ * 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/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/onenand.h>
+
+#include <mach/irqs.h>
+#include <mach/map.h>
+
+static struct resource s3c_onenand_resources[] = {
+       [0] = {
+               .start  = S3C_PA_ONENAND,
+               .end    = S3C_PA_ONENAND + 0x400 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = S3C_PA_ONENAND_BUF,
+               .end    = S3C_PA_ONENAND_BUF + S3C_SZ_ONENAND_BUF - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [2] = {
+               .start  = IRQ_ONENAND,
+               .end    = IRQ_ONENAND,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device s3c_device_onenand = {
+       .name           = "samsung-onenand",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(s3c_onenand_resources),
+       .resource       = s3c_onenand_resources,
+};
+
+void s3c_onenand_set_platdata(struct onenand_platform_data *pdata)
+{
+       struct onenand_platform_data *pd;
+
+       pd = kmemdup(pdata, sizeof(struct onenand_platform_data), GFP_KERNEL);
+       if (!pd)
+               printk(KERN_ERR "%s: no memory for platform data\n", __func__);
+       s3c_device_onenand.dev.platform_data = pd;
+}
diff --git a/arch/arm/plat-samsung/dev-wdt.c b/arch/arm/plat-samsung/dev-wdt.c
new file mode 100644 (file)
index 0000000..5efca87
--- /dev/null
@@ -0,0 +1,40 @@
+/* linux/arch/arm/plat-samsung/dev-wdt.c
+ *
+ * Copyright (c) 2004 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C series device definition for the watchdog timer
+ *
+ * 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/kernel.h>
+#include <linux/platform_device.h>
+
+#include <mach/irqs.h>
+#include <mach/map.h>
+
+#include <plat/devs.h>
+
+static struct resource s3c_wdt_resource[] = {
+       [0] = {
+               .start  = S3C_PA_WDT,
+               .end    = S3C_PA_WDT + SZ_1M - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = IRQ_WDT,
+               .end    = IRQ_WDT,
+               .flags  = IORESOURCE_IRQ,
+       }
+};
+
+struct platform_device s3c_device_wdt = {
+       .name           = "s3c2410-wdt",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(s3c_wdt_resource),
+       .resource       = s3c_wdt_resource,
+};
+EXPORT_SYMBOL(s3c_device_wdt);
index ef69e56b28854e508d007cb14b92dc5bbf05022b..e6144e4b91189fa9596bc2c73a335d1b252d0d6d 100644 (file)
@@ -45,6 +45,7 @@ extern struct platform_device s3c_device_lcd;
 extern struct platform_device s3c_device_wdt;
 extern struct platform_device s3c_device_i2c0;
 extern struct platform_device s3c_device_i2c1;
+extern struct platform_device s3c_device_i2c2;
 extern struct platform_device s3c_device_rtc;
 extern struct platform_device s3c_device_adc;
 extern struct platform_device s3c_device_sdi;
@@ -57,9 +58,20 @@ extern struct platform_device s3c_device_hsmmc2;
 extern struct platform_device s3c_device_spi0;
 extern struct platform_device s3c_device_spi1;
 
+extern struct platform_device s5pc100_device_spi0;
+extern struct platform_device s5pc100_device_spi1;
+extern struct platform_device s5pc100_device_spi2;
+extern struct platform_device s5pv210_device_spi0;
+extern struct platform_device s5pv210_device_spi1;
+extern struct platform_device s5p6440_device_spi0;
+extern struct platform_device s5p6440_device_spi1;
+
 extern struct platform_device s3c_device_hwmon;
 
 extern struct platform_device s3c_device_nand;
+extern struct platform_device s3c_device_onenand;
+extern struct platform_device s3c64xx_device_onenand1;
+extern struct platform_device s5pc110_device_onenand;
 
 extern struct platform_device s3c_device_usbgadget;
 extern struct platform_device s3c_device_usb_hsotg;
@@ -76,10 +88,18 @@ extern struct platform_device s5p6442_device_pcm0;
 extern struct platform_device s5p6442_device_pcm1;
 extern struct platform_device s5p6442_device_iis0;
 extern struct platform_device s5p6442_device_iis1;
+extern struct platform_device s5p6442_device_spi;
 
 extern struct platform_device s5p6440_device_pcm;
 extern struct platform_device s5p6440_device_iis;
 
+extern struct platform_device s5pc100_device_ac97;
+extern struct platform_device s5pc100_device_pcm0;
+extern struct platform_device s5pc100_device_pcm1;
+extern struct platform_device s5pc100_device_iis0;
+extern struct platform_device s5pc100_device_iis1;
+extern struct platform_device s5pc100_device_iis2;
+
 /* s3c2440 specific devices */
 
 #ifdef CONFIG_CPU_S3C2440
index 1f85649d8c18a46bb48b40d22e2e20032c728aef..27d3b497b55b65bbee3df10e1c6ab5f5814832ab 100644 (file)
@@ -84,4 +84,11 @@ extern void s3c64xx_fb_gpio_setup_24bpp(void);
  */
 extern void s5pc100_fb_gpio_setup_24bpp(void);
 
+/**
+ * s5pv210_fb_gpio_setup_24bpp() - S5PV210/S5PC110 setup function for 24bpp LCD
+ *
+ * Initialise the GPIO for an 24bpp LCD display on the RGB interface.
+ */
+extern void s5pv210_fb_gpio_setup_24bpp(void);
+
 #endif /* __PLAT_S3C_FB_H */
index 34efdd2b032c718e94777a9286a8f0c4f41dd4d3..db4112c6f2becd7371fc86428c5ca4b50a07bbdd 100644 (file)
@@ -43,6 +43,11 @@ struct s3c_gpio_chip;
  * layouts. Provide an point to vector control routine and provide any
  * per-bank configuration information that other systems such as the
  * external interrupt code will need.
+ *
+ * @sa s3c_gpio_cfgpin
+ * @sa s3c_gpio_getcfg
+ * @sa s3c_gpio_setpull
+ * @sa s3c_gpio_getpull
  */
 struct s3c_gpio_cfg {
        unsigned int    cfg_eint;
@@ -70,11 +75,25 @@ struct s3c_gpio_cfg {
 /**
  * s3c_gpio_cfgpin() - Change the GPIO function of a pin.
  * @pin pin The pin number to configure.
- * @pin to The configuration for the pin's function.
+ * @to to The configuration for the pin's function.
  *
  * Configure which function is actually connected to the external
  * pin, such as an gpio input, output or some form of special function
  * connected to an internal peripheral block.
+ *
+ * The @to parameter can be one of the generic S3C_GPIO_INPUT, S3C_GPIO_OUTPUT
+ * or S3C_GPIO_SFN() to indicate one of the possible values that the helper
+ * will then generate the correct bit mask and shift for the configuration.
+ *
+ * If a bank of GPIOs all needs to be set to special-function 2, then
+ * the following code will work:
+ *
+ *     for (gpio = start; gpio < end; gpio++)
+ *             s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+ *
+ * The @to parameter can also be a specific value already shifted to the
+ * correct position in the control register, although these are discouraged
+ * in newer kernels and are only being kept for compatibility.
  */
 extern int s3c_gpio_cfgpin(unsigned int pin, unsigned int to);
 
@@ -108,6 +127,8 @@ extern unsigned s3c_gpio_getcfg(unsigned int pin);
  * This function sets the state of the pull-{up,down} resistor for the
  * specified pin. It will return 0 if successfull, or a negative error
  * code if the pin cannot support the requested pull setting.
+ *
+ * @pull is one of S3C_GPIO_PULL_NONE, S3C_GPIO_PULL_DOWN or S3C_GPIO_PULL_UP.
 */
 extern int s3c_gpio_setpull(unsigned int pin, s3c_gpio_pull_t pull);
 
index 36397ca2096224033b9ed15fabc464b18fa2ee7d..f182669b8e8eec1f478e0b3e9649fb2c8629e2ae 100644 (file)
@@ -32,4 +32,11 @@ static inline void s3c_i2c1_setname(char *name)
 #endif
 }
 
+static inline void s3c_i2c2_setname(char *name)
+{
+#ifdef CONFIG_S3C_DEV_I2C2
+       s3c_device_i2c2.name = name;
+#endif
+}
+
 #endif /* __ASM_ARCH_IIC_H */
index 3083df00dee609dfd5651dfdea9e7125ee7651d1..133308bf595dcf775cf29626164e33ae02dedc25 100644 (file)
@@ -54,9 +54,11 @@ struct s3c2410_platform_i2c {
  */
 extern void s3c_i2c0_set_platdata(struct s3c2410_platform_i2c *i2c);
 extern void s3c_i2c1_set_platdata(struct s3c2410_platform_i2c *i2c);
+extern void s3c_i2c2_set_platdata(struct s3c2410_platform_i2c *i2c);
 
 /* defined by architecture to configure gpio */
 extern void s3c_i2c0_cfg_gpio(struct platform_device *dev);
 extern void s3c_i2c1_cfg_gpio(struct platform_device *dev);
+extern void s3c_i2c2_cfg_gpio(struct platform_device *dev);
 
 #endif /* __ASM_ARCH_IIC_H */
diff --git a/arch/arm/plat-samsung/include/plat/onenand-core.h b/arch/arm/plat-samsung/include/plat/onenand-core.h
new file mode 100644 (file)
index 0000000..7701cb7
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * linux/arch/arm/plat-samsung/onenand-core.h
+ *
+ *  Copyright (c) 2010 Samsung Electronics
+ *  Kyungmin Park <kyungmin.park@samsung.com>
+ *  Marek Szyprowski <m.szyprowski@samsung.com>
+ *
+ * Samsung OneNAD Controller core functions
+ *
+ * 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 __ASM_ARCH_ONENAND_CORE_H
+#define __ASM_ARCH_ONENAND_CORE_H __FILE__
+
+/* These functions are only for use with the core support code, such as
+ * the cpu specific initialisation code
+ */
+
+/* re-define device name depending on support. */
+static inline void s3c_onenand_setname(char *name)
+{
+#ifdef CONFIG_S3C_DEV_ONENAND
+       s3c_device_onenand.name = name;
+#endif
+}
+
+static inline void s3c64xx_onenand1_setname(char *name)
+{
+#ifdef CONFIG_S3C64XX_DEV_ONENAND1
+       s3c64xx_device_onenand1.name = name;
+#endif
+}
+
+#endif /* __ASM_ARCH_ONENAND_CORE_H */
diff --git a/arch/arm/plat-samsung/include/plat/regs-onenand.h b/arch/arm/plat-samsung/include/plat/regs-onenand.h
new file mode 100644 (file)
index 0000000..930ea8b
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * linux/arch/arm/plat-s3c/include/plat/regs-onenand.h
+ *
+ *  Copyright (C) 2008-2010 Samsung Electronics
+ *  Kyungmin Park <kyungmin.park@samsung.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 __SAMSUNG_ONENAND_H__
+#define __SAMSUNG_ONENAND_H__
+
+#include <mach/hardware.h>
+
+/*
+ * OneNAND Controller
+ */
+#define MEM_CFG_OFFSET         0x0000
+#define BURST_LEN_OFFSET       0x0010
+#define MEM_RESET_OFFSET       0x0020
+#define INT_ERR_STAT_OFFSET    0x0030
+#define INT_ERR_MASK_OFFSET    0x0040
+#define INT_ERR_ACK_OFFSET     0x0050
+#define ECC_ERR_STAT_OFFSET    0x0060
+#define MANUFACT_ID_OFFSET     0x0070
+#define DEVICE_ID_OFFSET       0x0080
+#define DATA_BUF_SIZE_OFFSET   0x0090
+#define BOOT_BUF_SIZE_OFFSET   0x00A0
+#define BUF_AMOUNT_OFFSET      0x00B0
+#define TECH_OFFSET            0x00C0
+#define FBA_WIDTH_OFFSET       0x00D0
+#define FPA_WIDTH_OFFSET       0x00E0
+#define FSA_WIDTH_OFFSET       0x00F0
+#define TRANS_SPARE_OFFSET     0x0140
+#define DBS_DFS_WIDTH_OFFSET   0x0160
+#define INT_PIN_ENABLE_OFFSET  0x01A0
+#define ACC_CLOCK_OFFSET       0x01C0
+#define FLASH_VER_ID_OFFSET    0x01F0
+#define FLASH_AUX_CNTRL_OFFSET 0x0300          /* s3c64xx only */
+
+#define ONENAND_MEM_RESET_HOT  0x3
+#define ONENAND_MEM_RESET_COLD 0x2
+#define ONENAND_MEM_RESET_WARM 0x1
+
+#define CACHE_OP_ERR           (1 << 13)
+#define RST_CMP                        (1 << 12)
+#define RDY_ACT                        (1 << 11)
+#define INT_ACT                        (1 << 10)
+#define UNSUP_CMD              (1 << 9)
+#define LOCKED_BLK             (1 << 8)
+#define BLK_RW_CMP             (1 << 7)
+#define ERS_CMP                        (1 << 6)
+#define PGM_CMP                        (1 << 5)
+#define LOAD_CMP               (1 << 4)
+#define ERS_FAIL               (1 << 3)
+#define PGM_FAIL               (1 << 2)
+#define INT_TO                 (1 << 1)
+#define LD_FAIL_ECC_ERR                (1 << 0)
+
+#define TSRF                   (1 << 0)
+
+#endif
index d5837cf8e402751493f51f3889302891df4556a5..65c190d142ddc24708da631eac324d87e95f375a 100644 (file)
 #define S3C2410_RTCCON_CLKSEL (1<<1)
 #define S3C2410_RTCCON_CNTSEL (1<<2)
 #define S3C2410_RTCCON_CLKRST (1<<3)
+#define S3C64XX_RTCCON_TICEN  (1<<8)
+
+#define S3C64XX_RTCCON_TICMSK (0xF<<7)
+#define S3C64XX_RTCCON_TICSHT (7)
 
 #define S3C2410_TICNT        S3C2410_RTCREG(0x44)
 #define S3C2410_TICNT_ENABLE  (1<<7)
index d1772414931569f05a41616bb055b6df1d81797f..e5aba8f95b791355f8d01a77347482053099933d 100644 (file)
@@ -63,5 +63,9 @@ struct s3c64xx_spi_info {
  * has some chips attached to it.
  */
 extern void s3c64xx_spi_set_info(int cntrlr, int src_clk_nr, int num_cs);
+extern void s5pc100_spi_set_info(int cntrlr, int src_clk_nr, int num_cs);
+extern void s5pv210_spi_set_info(int cntrlr, int src_clk_nr, int num_cs);
+extern void s5p6440_spi_set_info(int cntrlr, int src_clk_nr, int num_cs);
+extern void s5p6442_spi_set_info(int cntrlr, int src_clk_nr, int num_cs);
 
 #endif /* __S3C64XX_PLAT_SPI_H */
index 7d07cd7aa4f202a44bc8047bf11255c91eebb81f..13f9fb20900a13c61c927b7ed36fb0d63310c783 100644 (file)
@@ -75,6 +75,9 @@ extern void s5pc100_setup_sdhci0_cfg_gpio(struct platform_device *, int w);
 extern void s5pc100_setup_sdhci1_cfg_gpio(struct platform_device *, int w);
 extern void s5pc100_setup_sdhci2_cfg_gpio(struct platform_device *, int w);
 extern void s3c64xx_setup_sdhci2_cfg_gpio(struct platform_device *, int w);
+extern void s5pv210_setup_sdhci0_cfg_gpio(struct platform_device *, int w);
+extern void s5pv210_setup_sdhci1_cfg_gpio(struct platform_device *, int w);
+extern void s5pv210_setup_sdhci2_cfg_gpio(struct platform_device *, int w);
 
 /* S3C6400 SDHCI setup */
 
@@ -218,4 +221,56 @@ static inline void s5pc100_default_sdhci1(void) { }
 static inline void s5pc100_default_sdhci2(void) { }
 #endif /* CONFIG_S5PC100_SETUP_SDHCI */
 
+
+/* S5PC110 SDHCI setup */
+#ifdef CONFIG_S5PV210_SETUP_SDHCI
+extern char *s5pv210_hsmmc_clksrcs[4];
+
+extern void s5pv210_setup_sdhci_cfg_card(struct platform_device *dev,
+                                          void __iomem *r,
+                                          struct mmc_ios *ios,
+                                          struct mmc_card *card);
+
+#ifdef CONFIG_S3C_DEV_HSMMC
+static inline void s5pv210_default_sdhci0(void)
+{
+       s3c_hsmmc0_def_platdata.clocks = s5pv210_hsmmc_clksrcs;
+       s3c_hsmmc0_def_platdata.cfg_gpio = s5pv210_setup_sdhci0_cfg_gpio;
+       s3c_hsmmc0_def_platdata.cfg_card = s5pv210_setup_sdhci_cfg_card;
+}
+#else
+static inline void s5pc100_default_sdhci0(void) { }
+#endif /* CONFIG_S3C_DEV_HSMMC */
+
+#ifdef CONFIG_S3C_DEV_HSMMC1
+static inline void s5pv210_default_sdhci1(void)
+{
+       s3c_hsmmc1_def_platdata.clocks = s5pv210_hsmmc_clksrcs;
+       s3c_hsmmc1_def_platdata.cfg_gpio = s5pv210_setup_sdhci1_cfg_gpio;
+       s3c_hsmmc1_def_platdata.cfg_card = s5pv210_setup_sdhci_cfg_card;
+}
+#else
+static inline void s5pv210_default_sdhci1(void) { }
+#endif /* CONFIG_S3C_DEV_HSMMC1 */
+
+#ifdef CONFIG_S3C_DEV_HSMMC2
+static inline void s5pv210_default_sdhci2(void)
+{
+       s3c_hsmmc2_def_platdata.clocks = s5pv210_hsmmc_clksrcs;
+       s3c_hsmmc2_def_platdata.cfg_gpio = s5pv210_setup_sdhci2_cfg_gpio;
+       s3c_hsmmc2_def_platdata.cfg_card = s5pv210_setup_sdhci_cfg_card;
+}
+#else
+static inline void s5pv210_default_sdhci2(void) { }
+#endif /* CONFIG_S3C_DEV_HSMMC2 */
+
+#else
+static inline void s5pv210_default_sdhci0(void) { }
+static inline void s5pv210_default_sdhci1(void) { }
+static inline void s5pv210_default_sdhci2(void) { }
+#endif /* CONFIG_S5PC100_SETUP_SDHCI */
+
+
+
+
 #endif /* __PLAT_S3C_SDHCI_H */
diff --git a/arch/arm/plat-samsung/include/plat/wakeup-mask.h b/arch/arm/plat-samsung/include/plat/wakeup-mask.h
new file mode 100644 (file)
index 0000000..43e4acd
--- /dev/null
@@ -0,0 +1,44 @@
+/* arch/arm/plat-samsung/include/plat/wakeup-mask.h
+ *
+ * Copyright 2010 Ben Dooks <ben-linux@fluff.org>
+ *
+ * Support for wakeup mask interrupts on newer SoCs
+ *
+ * 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 __PLAT_WAKEUP_MASK_H
+#define __PLAT_WAKEUP_MASK_H __file__
+
+/* if no irq yet defined, but still want to mask */
+#define NO_WAKEUP_IRQ (0x90000000)
+
+/**
+ * struct samsung_wakeup_mask - wakeup mask information
+ * @irq: The interrupt associated with this wakeup.
+ * @bit: The bit, as a (1 << bitno) controlling this source.
+ */ 
+struct samsung_wakeup_mask {
+       unsigned int    irq;
+       u32             bit;
+};
+
+/**
+ * samsung_sync_wakemask - sync wakeup mask information for pm
+ * @reg: The register that is used.
+ * @masks: The list of masks to use.
+ * @nr_masks: The number of entries pointed to buy @masks.
+ *
+ * Synchronise the wakeup mask information at suspend time from the list
+ * of interrupts and control bits in @masks. We do this at suspend time
+ * as overriding the relevant irq chips is harder and the register is only
+ * required to be correct before we enter sleep.
+ */
+extern void samsung_sync_wakemask(void __iomem *reg,
+                                 struct samsung_wakeup_mask *masks,
+                                 int nr_masks);
+
+#endif /* __PLAT_WAKEUP_MASK_H */
index d50ab9d2af53ff9083122f61097d69114757ae60..7df03f87fbfabfd68c681afc25e6f78d8974f0ed 100644 (file)
@@ -331,8 +331,10 @@ void s3c_pm_save_gpios(void)
 
        for (gpio_nr = 0; gpio_nr < S3C_GPIO_END;) {
                ourchip = s3c_gpiolib_getchip(gpio_nr);
-               if (!ourchip)
+               if (!ourchip) {
+                       gpio_nr++;
                        continue;
+               }
 
                s3c_pm_save_gpio(ourchip);
 
@@ -369,8 +371,10 @@ void s3c_pm_restore_gpios(void)
 
        for (gpio_nr = 0; gpio_nr < S3C_GPIO_END;) {
                ourchip = s3c_gpiolib_getchip(gpio_nr);
-               if (!ourchip)
+               if (!ourchip) {
+                       gpio_nr++;
                        continue;
+               }
 
                s3c_pm_resume_gpio(ourchip);
 
diff --git a/arch/arm/plat-samsung/wakeup-mask.c b/arch/arm/plat-samsung/wakeup-mask.c
new file mode 100644 (file)
index 0000000..2e09b6a
--- /dev/null
@@ -0,0 +1,47 @@
+/* arch/arm/plat-samsung/wakeup-mask.c
+ *
+ * Copyright 2010 Ben Dooks <ben-linux@fluff.org>
+ *
+ * Support for wakeup mask interrupts on newer SoCs
+ *
+ * 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/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/sysdev.h>
+#include <linux/types.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <plat/wakeup-mask.h>
+#include <plat/pm.h>
+
+void samsung_sync_wakemask(void __iomem *reg,
+                          struct samsung_wakeup_mask *mask, int nr_mask)
+{
+       struct irq_desc *desc;
+       u32 val;
+
+       val = __raw_readl(reg);
+
+       for (; nr_mask > 0; nr_mask--, mask++) {
+               if (mask->irq == NO_WAKEUP_IRQ) {
+                       val |= mask->bit;
+                       continue;
+               }
+
+               desc = irq_to_desc(mask->irq);
+
+               /* bit of a liberty to read this directly from irq_desc. */
+               if (desc->wake_depth > 0)
+                       val &= ~mask->bit;
+               else
+                       val |= mask->bit;
+       }
+
+       printk(KERN_INFO "wakemask %08x => %08x\n", __raw_readl(reg), val);
+       __raw_writel(val, reg);
+}
index 377320e3bd1741b19d7c5acdc2ad2de78502ae6a..06394e5ead6c51543c71ea16793cd6cad371589d 100644 (file)
@@ -1,25 +1,7 @@
 #ifndef __ASM_AVR32_SCATTERLIST_H
 #define __ASM_AVR32_SCATTERLIST_H
 
-#include <asm/types.h>
-
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-   unsigned long       sg_magic;
-#endif
-    unsigned long      page_link;
-    unsigned int       offset;
-    dma_addr_t         dma_address;
-    unsigned int       length;
-};
-
-/* These macros should be used after a pci_map_sg call has been done
- * to get bus addresses of each of the SG entries and their lengths.
- * You should only work with the number of sg entries pci_map_sg
- * returns.
- */
-#define sg_dma_address(sg)     ((sg)->dma_address)
-#define sg_dma_len(sg)         ((sg)->length)
+#include <asm-generic/scatterlist.h>
 
 #define ISA_DMA_THRESHOLD (0xffffffff)
 
index c078849df7f9712349e0e5c1f721d977953f8e3f..f66294b4f9d29d31fbec1075aabf3483be352309 100644 (file)
@@ -348,7 +348,7 @@ config MEM_MT48LC16M16A2TG_75
 
 config MEM_MT48LC32M8A2_75
        bool
-       depends on (BFIN537_STAMP || PNAV10 || BFIN538_EZKIT)
+       depends on (BFIN518F_EZBRD || BFIN537_STAMP || PNAV10 || BFIN538_EZKIT)
        default y
 
 config MEM_MT48LC8M32B2B5_7
@@ -361,11 +361,6 @@ config MEM_MT48LC32M16A2TG_75
        depends on (BFIN527_EZKIT || BFIN527_EZKIT_V2 || BFIN532_IP0X || BLACKSTAMP)
        default y
 
-config MEM_MT48LC32M8A2_75
-       bool
-       depends on (BFIN518F_EZBRD)
-       default y
-
 config MEM_MT48H32M16LFCJ_75
        bool
        depends on (BFIN526_EZBRD)
@@ -791,6 +786,34 @@ config MEMCPY_L1
          If enabled, the memcpy function is linked
          into L1 instruction memory. (less latency)
 
+config STRCMP_L1
+       bool "locate strcmp function in L1 Memory"
+       default y
+       help
+         If enabled, the strcmp function is linked
+         into L1 instruction memory (less latency).
+
+config STRNCMP_L1
+       bool "locate strncmp function in L1 Memory"
+       default y
+       help
+         If enabled, the strncmp function is linked
+         into L1 instruction memory (less latency).
+
+config STRCPY_L1
+       bool "locate strcpy function in L1 Memory"
+       default y
+       help
+         If enabled, the strcpy function is linked
+         into L1 instruction memory (less latency).
+
+config STRNCPY_L1
+       bool "locate strncpy function in L1 Memory"
+       default y
+       help
+         If enabled, the strncpy function is linked
+         into L1 instruction memory (less latency).
+
 config SYS_BFIN_SPINLOCK_L1
        bool "Locate sys_bfin_spinlock function in L1 Memory"
        default y
@@ -1187,32 +1210,6 @@ config  PM_BFIN_SLEEP
          If unsure, select "Sleep Deeper".
 endchoice
 
-config PM_WAKEUP_BY_GPIO
-       bool "Allow Wakeup from Standby by GPIO"
-       depends on PM && !BF54x
-
-config PM_WAKEUP_GPIO_NUMBER
-       int "GPIO number"
-       range 0 47
-       depends on PM_WAKEUP_BY_GPIO
-       default 2
-
-choice
-       prompt "GPIO Polarity"
-       depends on PM_WAKEUP_BY_GPIO
-       default PM_WAKEUP_GPIO_POLAR_H
-config  PM_WAKEUP_GPIO_POLAR_H
-       bool "Active High"
-config  PM_WAKEUP_GPIO_POLAR_L
-       bool "Active Low"
-config  PM_WAKEUP_GPIO_POLAR_EDGE_F
-       bool "Falling EDGE"
-config  PM_WAKEUP_GPIO_POLAR_EDGE_R
-       bool "Rising EDGE"
-config  PM_WAKEUP_GPIO_POLAR_EDGE_B
-       bool "Both EDGE"
-endchoice
-
 comment "Possible Suspend Mem / Hibernate Wake-Up Sources"
        depends on PM
 
index aec89a5280b2249ef8890c14ddd96918de36838b..d1825cb247685dacb6175f58829bec48edb6c03f 100644 (file)
@@ -238,7 +238,7 @@ config EARLY_PRINTK
 config NMI_WATCHDOG
        bool "Enable NMI watchdog to help debugging lockup on SMP"
        default n
-       depends on (SMP && !BFIN_SCRATCH_REG_RETN)
+       depends on SMP
        help
          If any CPU in the system does not execute the period local timer
          interrupt for more than 5 seconds, then the NMI handler dumps debug
@@ -264,4 +264,13 @@ config BFIN_ISRAM_SELF_TEST
        help
          Run some self tests of the isram driver code at boot.
 
+config BFIN_PSEUDODBG_INSNS
+       bool "Support pseudo debug instructions"
+       default n
+       help
+         This option allows the kernel to emulate some pseudo instructions which
+         allow simulator test cases to be run under Linux with no changes.
+
+         Most people should say N here.
+
 endmenu
index e6485c305ea6e53266412712216136ec126cac4b..121cc04d877d891c1e4594a9ade1795abf5991e4 100644 (file)
@@ -39,9 +39,15 @@ extern unsigned long sclk_to_usecs(unsigned long sclk);
 extern unsigned long usecs_to_sclk(unsigned long usecs);
 
 struct pt_regs;
+#if defined(CONFIG_DEBUG_VERBOSE)
 extern void dump_bfin_process(struct pt_regs *regs);
 extern void dump_bfin_mem(struct pt_regs *regs);
 extern void dump_bfin_trace_buffer(void);
+#else
+#define dump_bfin_process(regs)
+#define dump_bfin_mem(regs)
+#define dump_bfin_trace_buffer()
+#endif
 
 /* init functions only */
 extern int init_arch_irq(void);
index 75f6dc336d46d4b13e04a42bf8facb44ea79a49f..8d9b1eba89c48ad57a1437c0e19716082266cc69 100644 (file)
@@ -9,7 +9,12 @@
 
 #ifdef CONFIG_BUG
 
-#define BFIN_BUG_OPCODE        0xefcd
+/*
+ * This can be any undefined 16-bit opcode, meaning
+ * ((opcode & 0xc000) != 0xc000)
+ * Anything from 0x0001 to 0x000A (inclusive) will work
+ */
+#define BFIN_BUG_OPCODE        0x0001
 
 #ifdef CONFIG_DEBUG_BUGVERBOSE
 
index 8542bc31f63cae7445482a4a46b41d797f06acfd..93f6c634fdf4cbfdb5399e6327baef82096cf390 100644 (file)
@@ -15,6 +15,8 @@
 #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
 #define SMP_CACHE_BYTES        L1_CACHE_BYTES
 
+#define ARCH_KMALLOC_MINALIGN  L1_CACHE_BYTES
+
 #ifdef CONFIG_SMP
 #define __cacheline_aligned
 #else
index 91bd2d7b9d5541fdb56271e94f1d9dcd68054be8..01b19d0cf50974be13f804e6175f9f814d1e136b 100644 (file)
@@ -167,23 +167,23 @@ int bfin_special_gpio_request(unsigned gpio, const char *label);
 #endif
 
 #ifdef CONFIG_PM
+int bfin_pm_standby_ctrl(unsigned ctrl);
 
-unsigned int bfin_pm_standby_setup(void);
-void bfin_pm_standby_restore(void);
+static inline int bfin_pm_standby_setup(void)
+{
+       return bfin_pm_standby_ctrl(1);
+}
+
+static inline void bfin_pm_standby_restore(void)
+{
+       bfin_pm_standby_ctrl(0);
+}
 
 void bfin_gpio_pm_hibernate_restore(void);
 void bfin_gpio_pm_hibernate_suspend(void);
 
 #ifndef CONFIG_BF54x
-#define PM_WAKE_RISING 0x1
-#define PM_WAKE_FALLING        0x2
-#define PM_WAKE_HIGH   0x4
-#define PM_WAKE_LOW    0x8
-#define PM_WAKE_BOTH_EDGES     (PM_WAKE_RISING | PM_WAKE_FALLING)
-#define PM_WAKE_IGNORE 0xF0
-
-int gpio_pm_wakeup_request(unsigned gpio, unsigned char type);
-void gpio_pm_wakeup_free(unsigned gpio);
+int gpio_pm_wakeup_ctrl(unsigned gpio, unsigned ctrl);
 
 struct gpio_port_s {
        unsigned short data;
index 821c699c22387c2a607170a128cb2a962866360a..dcca3e6d6e808b1423654315912de2f00eedab2e 100644 (file)
@@ -80,7 +80,8 @@ PTE_BIT_FUNC(mkyoung, |= _PAGE_ACCESSED);
  * ZERO_PAGE is a global shared page that is always zero: used
  * for zero-mapped memory areas etc..
  */
-#define ZERO_PAGE(vaddr)       (virt_to_page(0))
+#define ZERO_PAGE(vaddr)       virt_to_page(empty_zero_page)
+extern char empty_zero_page[];
 
 extern unsigned int kobjsize(const void *objp);
 
diff --git a/arch/blackfin/include/asm/pseudo_instructions.h b/arch/blackfin/include/asm/pseudo_instructions.h
new file mode 100644 (file)
index 0000000..b00adfa
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * header file for pseudo instructions
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _BLACKFIN_PSEUDO_
+#define _BLACKFIN_PSEUDO_
+
+#include <linux/types.h>
+#include <asm/ptrace.h>
+
+extern bool execute_pseudodbg_assert(struct pt_regs *fp, unsigned int opcode);
+extern bool execute_pseudodbg(struct pt_regs *fp, unsigned int opcode);
+
+#endif
index 04f448711cd09eb1755875b87bfe2db353aff15f..64d41d34ab0b84cafce79f11bcddfa812d8682ff 100644 (file)
@@ -1,27 +1,7 @@
 #ifndef _BLACKFIN_SCATTERLIST_H
 #define _BLACKFIN_SCATTERLIST_H
 
-#include <linux/mm.h>
-
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-       unsigned long sg_magic;
-#endif
-       unsigned long page_link;
-       unsigned int offset;
-       dma_addr_t dma_address;
-       unsigned int length;
-};
-
-/*
- * These macros should be used after a pci_map_sg call has been done
- * to get bus addresses of each of the SG entries and their lengths.
- * You should only work with the number of sg entries pci_map_sg
- * returns, or alternatively stop on the first sg_dma_len(sg) which
- * is 0.
- */
-#define sg_dma_address(sg)      ((sg)->dma_address)
-#define sg_dma_len(sg)          ((sg)->length)
+#include <asm-generic/scatterlist.h>
 
 #define ISA_DMA_THRESHOLD      (0xffffffff)
 
index d7f0ccb418c347e5d9bb7e15f2c0a131d9c1d5b7..423c099aa988f6749e7c4a55479c4141b52ef818 100644 (file)
 #ifdef __KERNEL__              /* only set these up for kernel code */
 
 #define __HAVE_ARCH_STRCPY
-extern inline char *strcpy(char *dest, const char *src)
-{
-       char *xdest = dest;
-       char temp = 0;
-
-       __asm__ __volatile__ (
-               "1:"
-               "%2 = B [%1++] (Z);"
-               "B [%0++] = %2;"
-               "CC = %2;"
-               "if cc jump 1b (bp);"
-               : "+&a" (dest), "+&a" (src), "=&d" (temp)
-               :
-               : "memory", "CC");
-
-       return xdest;
-}
+extern char *strcpy(char *dest, const char *src);
 
 #define __HAVE_ARCH_STRNCPY
-extern inline char *strncpy(char *dest, const char *src, size_t n)
-{
-       char *xdest = dest;
-       char temp = 0;
-
-       if (n == 0)
-               return xdest;
-
-       __asm__ __volatile__ (
-               "1:"
-               "%3 = B [%1++] (Z);"
-               "B [%0++] = %3;"
-               "CC = %3;"
-               "if ! cc jump 2f;"
-               "%2 += -1;"
-               "CC = %2 == 0;"
-               "if ! cc jump 1b (bp);"
-               "jump 4f;"
-               "2:"
-               /* if src is shorter than n, we need to null pad bytes now */
-               "%3 = 0;"
-               "3:"
-               "%2 += -1;"
-               "CC = %2 == 0;"
-               "if cc jump 4f;"
-               "B [%0++] = %3;"
-               "jump 3b;"
-               "4:"
-               : "+&a" (dest), "+&a" (src), "+&da" (n), "=&d" (temp)
-               :
-               : "memory", "CC");
-
-       return xdest;
-}
+extern char *strncpy(char *dest, const char *src, size_t n);
 
 #define __HAVE_ARCH_STRCMP
-extern inline int strcmp(const char *cs, const char *ct)
-{
-       /* need to use int's here so the char's in the assembly don't get
-        * sign extended incorrectly when we don't want them to be
-        */
-       int __res1, __res2;
-
-       __asm__ __volatile__ (
-               "1:"
-               "%2 = B[%0++] (Z);"      /* get *cs */
-               "%3 = B[%1++] (Z);"      /* get *ct */
-               "CC = %2 == %3;"         /* compare a byte */
-               "if ! cc jump 2f;"       /* not equal, break out */
-               "CC = %2;"               /* at end of cs? */
-               "if cc jump 1b (bp);"    /* no, keep going */
-               "jump.s 3f;"             /* strings are equal */
-               "2:"
-               "%2 = %2 - %3;"          /* *cs - *ct */
-               "3:"
-               : "+&a" (cs), "+&a" (ct), "=&d" (__res1), "=&d" (__res2)
-               :
-               : "memory", "CC");
-
-       return __res1;
-}
+extern int strcmp(const char *cs, const char *ct);
 
 #define __HAVE_ARCH_STRNCMP
-extern inline int strncmp(const char *cs, const char *ct, size_t count)
-{
-       /* need to use int's here so the char's in the assembly don't get
-        * sign extended incorrectly when we don't want them to be
-        */
-       int __res1, __res2;
-
-       if (!count)
-               return 0;
-
-       __asm__ __volatile__ (
-               "1:"
-               "%3 = B[%0++] (Z);"      /* get *cs */
-               "%4 = B[%1++] (Z);"      /* get *ct */
-               "CC = %3 == %4;"         /* compare a byte */
-               "if ! cc jump 3f;"       /* not equal, break out */
-               "CC = %3;"               /* at end of cs? */
-               "if ! cc jump 4f;"       /* yes, all done */
-               "%2 += -1;"              /* no, adjust count */
-               "CC = %2 == 0;"
-               "if ! cc jump 1b;"       /* more to do, keep going */
-               "2:"
-               "%3 = 0;"                /* strings are equal */
-               "jump.s 4f;"
-               "3:"
-               "%3 = %3 - %4;"          /* *cs - *ct */
-               "4:"
-               : "+&a" (cs), "+&a" (ct), "+&da" (count), "=&d" (__res1), "=&d" (__res2)
-               :
-               : "memory", "CC");
-
-       return __res1;
-}
+extern int strncmp(const char *cs, const char *ct, size_t count);
 
 #define __HAVE_ARCH_MEMSET
 extern void *memset(void *s, int c, size_t count);
index f1a06c006ed0260f91c32db07720a74d727a1c33..7c368682c0a3b13f7d85da165bc3aa7e0bc52ee1 100644 (file)
@@ -1 +1,2 @@
 #include <asm-generic/tlbflush.h>
+#define flush_tlb_kernel_range(s, e) do { } while (0)
index dc0aa55ae773420fb426733e0b437d089580a692..33589a29b8d87641b208dd6c7d3c7c7f129592f7 100644 (file)
 #ifndef __ASSEMBLY__
 extern unsigned long trace_buff_offset;
 extern unsigned long software_trace_buff[];
+#if defined(CONFIG_DEBUG_VERBOSE)
+extern void decode_address(char *buf, unsigned long address);
+extern bool get_instruction(unsigned int *val, unsigned short *address);
+#else
+static inline void decode_address(char *buf, unsigned long address) { }
+static inline bool get_instruction(unsigned int *val, unsigned short *address) { return false; }
+#endif
 
 /* Trace Macros for C files */
 
index 346a421f1562fad53d66485d3d8d7ea2b51935ff..30d0d1f01dc7f0c017245ae75c5ba2693d335e87 100644 (file)
@@ -7,7 +7,8 @@ extra-y := init_task.o vmlinux.lds
 obj-y := \
        entry.o process.o bfin_ksyms.o ptrace.o setup.o signal.o \
        sys_bfin.o traps.o irqchip.o dma-mapping.o flat.o \
-       fixed_code.o reboot.o bfin_gpio.o bfin_dma_5xx.o
+       fixed_code.o reboot.o bfin_gpio.o bfin_dma_5xx.o \
+       exception.o dumpstack.o
 
 ifeq ($(CONFIG_GENERIC_CLOCKEVENTS),y)
     obj-y += time-ts.o
@@ -29,6 +30,8 @@ obj-$(CONFIG_NMI_WATCHDOG)           += nmi.o
 obj-$(CONFIG_EARLY_PRINTK)           += early_printk.o
 obj-$(CONFIG_EARLY_PRINTK)           += shadow_console.o
 obj-$(CONFIG_STACKTRACE)             += stacktrace.o
+obj-$(CONFIG_DEBUG_VERBOSE)          += trace.o
+obj-$(CONFIG_BFIN_PSEUDODBG_INSNS)   += pseudodbg.o
 
 # the kgdb test puts code into L2 and without linker
 # relaxation, we need to force long calls to/from it
index e35e20f00d9b3c864ec2a568afc86947f2a5681d..42833ee2b308ba546b323823a6bc2d37e94481ba 100644 (file)
@@ -475,9 +475,7 @@ GET_GPIO_P(maskb)
 
 
 #ifdef CONFIG_PM
-
 static unsigned short wakeup_map[GPIO_BANK_NUM];
-static unsigned char wakeup_flags_map[MAX_BLACKFIN_GPIOS];
 
 static const unsigned int sic_iwr_irqs[] = {
 #if defined(BF533_FAMILY)
@@ -514,112 +512,26 @@ static const unsigned int sic_iwr_irqs[] = {
 *************************************************************
 * MODIFICATION HISTORY :
 **************************************************************/
-int gpio_pm_wakeup_request(unsigned gpio, unsigned char type)
-{
-       unsigned long flags;
-
-       if ((check_gpio(gpio) < 0) || !type)
-               return -EINVAL;
-
-       local_irq_save_hw(flags);
-       wakeup_map[gpio_bank(gpio)] |= gpio_bit(gpio);
-       wakeup_flags_map[gpio] = type;
-       local_irq_restore_hw(flags);
-
-       return 0;
-}
-EXPORT_SYMBOL(gpio_pm_wakeup_request);
-
-void gpio_pm_wakeup_free(unsigned gpio)
+int gpio_pm_wakeup_ctrl(unsigned gpio, unsigned ctrl)
 {
        unsigned long flags;
 
        if (check_gpio(gpio) < 0)
-               return;
+               return -EINVAL;
 
        local_irq_save_hw(flags);
-
-       wakeup_map[gpio_bank(gpio)] &= ~gpio_bit(gpio);
-
-       local_irq_restore_hw(flags);
-}
-EXPORT_SYMBOL(gpio_pm_wakeup_free);
-
-static int bfin_gpio_wakeup_type(unsigned gpio, unsigned char type)
-{
-       port_setup(gpio, GPIO_USAGE);
-       set_gpio_dir(gpio, 0);
-       set_gpio_inen(gpio, 1);
-
-       if (type & (PM_WAKE_RISING | PM_WAKE_FALLING))
-               set_gpio_edge(gpio, 1);
-        else
-               set_gpio_edge(gpio, 0);
-
-       if ((type & (PM_WAKE_BOTH_EDGES)) == (PM_WAKE_BOTH_EDGES))
-               set_gpio_both(gpio, 1);
+       if (ctrl)
+               wakeup_map[gpio_bank(gpio)] |= gpio_bit(gpio);
        else
-               set_gpio_both(gpio, 0);
-
-       if ((type & (PM_WAKE_FALLING | PM_WAKE_LOW)))
-               set_gpio_polar(gpio, 1);
-       else
-               set_gpio_polar(gpio, 0);
+               wakeup_map[gpio_bank(gpio)] &= ~gpio_bit(gpio);
 
-       SSYNC();
-
-       return 0;
-}
-
-u32 bfin_pm_standby_setup(void)
-{
-       u16 bank, mask, i, gpio;
-
-       for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) {
-               mask = wakeup_map[gpio_bank(i)];
-               bank = gpio_bank(i);
-
-               gpio_bank_saved[bank].maskb = gpio_array[bank]->maskb;
-               gpio_array[bank]->maskb = 0;
-
-               if (mask) {
-#if defined(CONFIG_BF52x) || defined(BF537_FAMILY) || defined(CONFIG_BF51x)
-                       gpio_bank_saved[bank].fer   = *port_fer[bank];
-#endif
-                       gpio_bank_saved[bank].inen  = gpio_array[bank]->inen;
-                       gpio_bank_saved[bank].polar = gpio_array[bank]->polar;
-                       gpio_bank_saved[bank].dir   = gpio_array[bank]->dir;
-                       gpio_bank_saved[bank].edge  = gpio_array[bank]->edge;
-                       gpio_bank_saved[bank].both  = gpio_array[bank]->both;
-                       gpio_bank_saved[bank].reserved =
-                                               reserved_gpio_map[bank];
-
-                       gpio = i;
-
-                       while (mask) {
-                               if ((mask & 1) && (wakeup_flags_map[gpio] !=
-                                       PM_WAKE_IGNORE)) {
-                                       reserved_gpio_map[gpio_bank(gpio)] |=
-                                                       gpio_bit(gpio);
-                                       bfin_gpio_wakeup_type(gpio,
-                                               wakeup_flags_map[gpio]);
-                                       set_gpio_data(gpio, 0); /*Clear*/
-                               }
-                               gpio++;
-                               mask >>= 1;
-                       }
-
-                       bfin_internal_set_wake(sic_iwr_irqs[bank], 1);
-                       gpio_array[bank]->maskb_set = wakeup_map[gpio_bank(i)];
-               }
-       }
-
-       AWA_DUMMY_READ(maskb_set);
+       set_gpio_maskb(gpio, ctrl);
+       local_irq_restore_hw(flags);
 
        return 0;
 }
 
-void bfin_pm_standby_restore(void)
+int bfin_pm_standby_ctrl(unsigned ctrl)
 {
        u16 bank, mask, i;
 
@@ -627,24 +539,10 @@ void bfin_pm_standby_restore(void)
                mask = wakeup_map[gpio_bank(i)];
                bank = gpio_bank(i);
 
-               if (mask) {
-#if defined(CONFIG_BF52x) || defined(BF537_FAMILY) || defined(CONFIG_BF51x)
-                       *port_fer[bank]         = gpio_bank_saved[bank].fer;
-#endif
-                       gpio_array[bank]->inen  = gpio_bank_saved[bank].inen;
-                       gpio_array[bank]->dir   = gpio_bank_saved[bank].dir;
-                       gpio_array[bank]->polar = gpio_bank_saved[bank].polar;
-                       gpio_array[bank]->edge  = gpio_bank_saved[bank].edge;
-                       gpio_array[bank]->both  = gpio_bank_saved[bank].both;
-
-                       reserved_gpio_map[bank] =
-                                       gpio_bank_saved[bank].reserved;
-                       bfin_internal_set_wake(sic_iwr_irqs[bank], 0);
-               }
-
-               gpio_array[bank]->maskb = gpio_bank_saved[bank].maskb;
+               if (mask)
+                       bfin_internal_set_wake(sic_iwr_irqs[bank], ctrl);
        }
-       AWA_DUMMY_READ(maskb);
+       return 0;
 }
 
 void bfin_gpio_pm_hibernate_suspend(void)
@@ -708,16 +606,11 @@ void bfin_gpio_pm_hibernate_restore(void)
 #else /* CONFIG_BF54x */
 #ifdef CONFIG_PM
 
-u32 bfin_pm_standby_setup(void)
+int bfin_pm_standby_ctrl(unsigned ctrl)
 {
        return 0;
 }
 
-void bfin_pm_standby_restore(void)
-{
-
-}
-
 void bfin_gpio_pm_hibernate_suspend(void)
 {
        int i, bank;
index ed8392c117eaa1d32d0e0623dc12788c4702095b..2c264b51566afa2d7ca45b8ad129fcc8384e89c0 100644 (file)
@@ -32,6 +32,18 @@ EXPORT_SYMBOL(memcmp);
 EXPORT_SYMBOL(memmove);
 EXPORT_SYMBOL(memchr);
 
+/*
+ * Because string functions are both inline and exported functions and
+ * folder arch/blackfin/lib is configured as a library path in Makefile,
+ * symbols exported in folder lib  is not linked into built-in.o but
+ * inlined only. In order to export string symbols to kernel module
+ * properly, they should be exported here.
+ */
+EXPORT_SYMBOL(strcpy);
+EXPORT_SYMBOL(strncpy);
+EXPORT_SYMBOL(strcmp);
+EXPORT_SYMBOL(strncmp);
+
 /*
  * libgcc functions - functions that are used internally by the
  * compiler...  (prototypes are not correct though, but that
diff --git a/arch/blackfin/kernel/dumpstack.c b/arch/blackfin/kernel/dumpstack.c
new file mode 100644 (file)
index 0000000..5cfbaa2
--- /dev/null
@@ -0,0 +1,174 @@
+/* Provide basic stack dumping functions
+ *
+ * Copyright 2004-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later
+ */
+
+#include <linux/kernel.h>
+#include <linux/thread_info.h>
+#include <linux/mm.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <asm/trace.h>
+
+/*
+ * Checks to see if the address pointed to is either a
+ * 16-bit CALL instruction, or a 32-bit CALL instruction
+ */
+static bool is_bfin_call(unsigned short *addr)
+{
+       unsigned int opcode;
+
+       if (!get_instruction(&opcode, addr))
+               return false;
+
+       if ((opcode >= 0x0060 && opcode <= 0x0067) ||
+           (opcode >= 0x0070 && opcode <= 0x0077) ||
+           (opcode >= 0xE3000000 && opcode <= 0xE3FFFFFF))
+               return true;
+
+       return false;
+
+}
+
+void show_stack(struct task_struct *task, unsigned long *stack)
+{
+#ifdef CONFIG_PRINTK
+       unsigned int *addr, *endstack, *fp = 0, *frame;
+       unsigned short *ins_addr;
+       char buf[150];
+       unsigned int i, j, ret_addr, frame_no = 0;
+
+       /*
+        * If we have been passed a specific stack, use that one otherwise
+        *    if we have been passed a task structure, use that, otherwise
+        *    use the stack of where the variable "stack" exists
+        */
+
+       if (stack == NULL) {
+               if (task) {
+                       /* We know this is a kernel stack, so this is the start/end */
+                       stack = (unsigned long *)task->thread.ksp;
+                       endstack = (unsigned int *)(((unsigned int)(stack) & ~(THREAD_SIZE - 1)) + THREAD_SIZE);
+               } else {
+                       /* print out the existing stack info */
+                       stack = (unsigned long *)&stack;
+                       endstack = (unsigned int *)PAGE_ALIGN((unsigned int)stack);
+               }
+       } else
+               endstack = (unsigned int *)PAGE_ALIGN((unsigned int)stack);
+
+       printk(KERN_NOTICE "Stack info:\n");
+       decode_address(buf, (unsigned int)stack);
+       printk(KERN_NOTICE " SP: [0x%p] %s\n", stack, buf);
+
+       if (!access_ok(VERIFY_READ, stack, (unsigned int)endstack - (unsigned int)stack)) {
+               printk(KERN_NOTICE "Invalid stack pointer\n");
+               return;
+       }
+
+       /* First thing is to look for a frame pointer */
+       for (addr = (unsigned int *)((unsigned int)stack & ~0xF); addr < endstack; addr++) {
+               if (*addr & 0x1)
+                       continue;
+               ins_addr = (unsigned short *)*addr;
+               ins_addr--;
+               if (is_bfin_call(ins_addr))
+                       fp = addr - 1;
+
+               if (fp) {
+                       /* Let's check to see if it is a frame pointer */
+                       while (fp >= (addr - 1) && fp < endstack
+                              && fp && ((unsigned int) fp & 0x3) == 0)
+                               fp = (unsigned int *)*fp;
+                       if (fp == 0 || fp == endstack) {
+                               fp = addr - 1;
+                               break;
+                       }
+                       fp = 0;
+               }
+       }
+       if (fp) {
+               frame = fp;
+               printk(KERN_NOTICE " FP: (0x%p)\n", fp);
+       } else
+               frame = 0;
+
+       /*
+        * Now that we think we know where things are, we
+        * walk the stack again, this time printing things out
+        * incase there is no frame pointer, we still look for
+        * valid return addresses
+        */
+
+       /* First time print out data, next time, print out symbols */
+       for (j = 0; j <= 1; j++) {
+               if (j)
+                       printk(KERN_NOTICE "Return addresses in stack:\n");
+               else
+                       printk(KERN_NOTICE " Memory from 0x%08lx to %p", ((long unsigned int)stack & ~0xF), endstack);
+
+               fp = frame;
+               frame_no = 0;
+
+               for (addr = (unsigned int *)((unsigned int)stack & ~0xF), i = 0;
+                    addr < endstack; addr++, i++) {
+
+                       ret_addr = 0;
+                       if (!j && i % 8 == 0)
+                               printk(KERN_NOTICE "%p:", addr);
+
+                       /* if it is an odd address, or zero, just skip it */
+                       if (*addr & 0x1 || !*addr)
+                               goto print;
+
+                       ins_addr = (unsigned short *)*addr;
+
+                       /* Go back one instruction, and see if it is a CALL */
+                       ins_addr--;
+                       ret_addr = is_bfin_call(ins_addr);
+ print:
+                       if (!j && stack == (unsigned long *)addr)
+                               printk("[%08x]", *addr);
+                       else if (ret_addr)
+                               if (j) {
+                                       decode_address(buf, (unsigned int)*addr);
+                                       if (frame == addr) {
+                                               printk(KERN_NOTICE "   frame %2i : %s\n", frame_no, buf);
+                                               continue;
+                                       }
+                                       printk(KERN_NOTICE "    address : %s\n", buf);
+                               } else
+                                       printk("<%08x>", *addr);
+                       else if (fp == addr) {
+                               if (j)
+                                       frame = addr+1;
+                               else
+                                       printk("(%08x)", *addr);
+
+                               fp = (unsigned int *)*addr;
+                               frame_no++;
+
+                       } else if (!j)
+                               printk(" %08x ", *addr);
+               }
+               if (!j)
+                       printk("\n");
+       }
+#endif
+}
+EXPORT_SYMBOL(show_stack);
+
+void dump_stack(void)
+{
+       unsigned long stack;
+#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
+       int tflags;
+#endif
+       trace_buffer_save(tflags);
+       dump_bfin_trace_buffer();
+       show_stack(current, &stack);
+       trace_buffer_restore(tflags);
+}
+EXPORT_SYMBOL(dump_stack);
diff --git a/arch/blackfin/kernel/exception.c b/arch/blackfin/kernel/exception.c
new file mode 100644 (file)
index 0000000..9208b5f
--- /dev/null
@@ -0,0 +1,45 @@
+/* Basic functions for adding/removing custom exception handlers
+ *
+ * Copyright 2004-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later
+ */
+
+#include <linux/module.h>
+#include <asm/irq_handler.h>
+
+int bfin_request_exception(unsigned int exception, void (*handler)(void))
+{
+       void (*curr_handler)(void);
+
+       if (exception > 0x3F)
+               return -EINVAL;
+
+       curr_handler = ex_table[exception];
+
+       if (curr_handler != ex_replaceable)
+               return -EBUSY;
+
+       ex_table[exception] = handler;
+
+       return 0;
+}
+EXPORT_SYMBOL(bfin_request_exception);
+
+int bfin_free_exception(unsigned int exception, void (*handler)(void))
+{
+       void (*curr_handler)(void);
+
+       if (exception > 0x3F)
+               return -EINVAL;
+
+       curr_handler = ex_table[exception];
+
+       if (curr_handler != handler)
+               return -EBUSY;
+
+       ex_table[exception] = ex_replaceable;
+
+       return 0;
+}
+EXPORT_SYMBOL(bfin_free_exception);
index 7367aea4ae59ff3cb7af0f9e3b8b18e5f1467aea..08bc44ea688313976e6d54b6cbb679e395271159 100644 (file)
@@ -66,7 +66,7 @@ void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
        gdb_regs[BFIN_RETN] = regs->retn;
        gdb_regs[BFIN_RETE] = regs->rete;
        gdb_regs[BFIN_PC] = regs->pc;
-       gdb_regs[BFIN_CC] = 0;
+       gdb_regs[BFIN_CC] = (regs->astat >> 5) & 1;
        gdb_regs[BFIN_EXTRA1] = 0;
        gdb_regs[BFIN_EXTRA2] = 0;
        gdb_regs[BFIN_EXTRA3] = 0;
diff --git a/arch/blackfin/kernel/pseudodbg.c b/arch/blackfin/kernel/pseudodbg.c
new file mode 100644 (file)
index 0000000..db85bc9
--- /dev/null
@@ -0,0 +1,191 @@
+/* The fake debug assert instructions
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/ptrace.h>
+
+const char * const greg_names[] = {
+       "R0",    "R1",      "R2",     "R3",    "R4",    "R5",    "R6",     "R7",
+       "P0",    "P1",      "P2",     "P3",    "P4",    "P5",    "SP",     "FP",
+       "I0",    "I1",      "I2",     "I3",    "M0",    "M1",    "M2",     "M3",
+       "B0",    "B1",      "B2",     "B3",    "L0",    "L1",    "L2",     "L3",
+       "A0.X",  "A0.W",    "A1.X",   "A1.W",  "<res>", "<res>", "ASTAT",  "RETS",
+       "<res>", "<res>",   "<res>",  "<res>", "<res>", "<res>", "<res>",  "<res>",
+       "LC0",   "LT0",     "LB0",    "LC1",   "LT1",   "LB1",   "CYCLES", "CYCLES2",
+       "USP",   "SEQSTAT", "SYSCFG", "RETI",  "RETX",  "RETN",  "RETE",   "EMUDAT",
+};
+
+static const char *get_allreg_name(int grp, int reg)
+{
+       return greg_names[(grp << 3) | reg];
+}
+
+/*
+ * Unfortunately, the pt_regs structure is not laid out the same way as the
+ * hardware register file, so we need to do some fix ups.
+ *
+ * CYCLES is not stored in the pt_regs structure - so, we just read it from
+ * the hardware.
+ *
+ * Don't support:
+ *  - All reserved registers
+ *  - All in group 7 are (supervisors only)
+ */
+
+static bool fix_up_reg(struct pt_regs *fp, long *value, int grp, int reg)
+{
+       long *val = &fp->r0;
+       unsigned long tmp;
+
+       /* Only do Dregs and Pregs for now */
+       if (grp == 5 ||
+          (grp == 4 && (reg == 4 || reg == 5)) ||
+          (grp == 7))
+               return false;
+
+       if (grp == 0 || (grp == 1 && reg < 6))
+               val -= (reg + 8 * grp);
+       else if (grp == 1 && reg == 6)
+               val = &fp->usp;
+       else if (grp == 1 && reg == 7)
+               val = &fp->fp;
+       else if (grp == 2) {
+               val = &fp->i0;
+               val -= reg;
+       } else if (grp == 3 && reg >= 4) {
+               val = &fp->l0;
+               val -= (reg - 4);
+       } else if (grp == 3 && reg < 4) {
+               val = &fp->b0;
+               val -= reg;
+       } else if (grp == 4 && reg < 4) {
+               val = &fp->a0x;
+               val -= reg;
+       } else if (grp == 4 && reg == 6)
+               val = &fp->astat;
+       else if (grp == 4 && reg == 7)
+               val = &fp->rets;
+       else if (grp == 6 && reg < 6) {
+               val = &fp->lc0;
+               val -= reg;
+       } else if (grp == 6 && reg == 6) {
+               __asm__ __volatile__("%0 = cycles;\n" : "=d"(tmp));
+               val = &tmp;
+       } else if (grp == 6 && reg == 7) {
+               __asm__ __volatile__("%0 = cycles2;\n" : "=d"(tmp));
+               val = &tmp;
+       }
+
+       *value = *val;
+       return true;
+
+}
+
+#define PseudoDbg_Assert_opcode         0xf0000000
+#define PseudoDbg_Assert_expected_bits  0
+#define PseudoDbg_Assert_expected_mask  0xffff
+#define PseudoDbg_Assert_regtest_bits   16
+#define PseudoDbg_Assert_regtest_mask   0x7
+#define PseudoDbg_Assert_grp_bits       19
+#define PseudoDbg_Assert_grp_mask       0x7
+#define PseudoDbg_Assert_dbgop_bits     22
+#define PseudoDbg_Assert_dbgop_mask     0x3
+#define PseudoDbg_Assert_dontcare_bits  24
+#define PseudoDbg_Assert_dontcare_mask  0x7
+#define PseudoDbg_Assert_code_bits      27
+#define PseudoDbg_Assert_code_mask      0x1f
+
+/*
+ * DBGA - debug assert
+ */
+bool execute_pseudodbg_assert(struct pt_regs *fp, unsigned int opcode)
+{
+       int expected = ((opcode >> PseudoDbg_Assert_expected_bits) & PseudoDbg_Assert_expected_mask);
+       int dbgop    = ((opcode >> (PseudoDbg_Assert_dbgop_bits)) & PseudoDbg_Assert_dbgop_mask);
+       int grp      = ((opcode >> (PseudoDbg_Assert_grp_bits)) & PseudoDbg_Assert_grp_mask);
+       int regtest  = ((opcode >> (PseudoDbg_Assert_regtest_bits)) & PseudoDbg_Assert_regtest_mask);
+       long value;
+
+       if ((opcode & 0xFF000000) != PseudoDbg_Assert_opcode)
+               return false;
+
+       if (!fix_up_reg(fp, &value, grp, regtest))
+               return false;
+
+       if (dbgop == 0 || dbgop == 2) {
+               /* DBGA ( regs_lo , uimm16 ) */
+               /* DBGAL ( regs , uimm16 ) */
+               if (expected != (value & 0xFFFF)) {
+                       pr_notice("DBGA (%s.L,0x%x) failure, got 0x%x\n",
+                               get_allreg_name(grp, regtest),
+                               expected, (unsigned int)(value & 0xFFFF));
+                       return false;
+               }
+
+       } else if (dbgop == 1 || dbgop == 3) {
+               /* DBGA ( regs_hi , uimm16 ) */
+               /* DBGAH ( regs , uimm16 ) */
+               if (expected != ((value >> 16) & 0xFFFF)) {
+                       pr_notice("DBGA (%s.H,0x%x) failure, got 0x%x\n",
+                               get_allreg_name(grp, regtest),
+                               expected, (unsigned int)((value >> 16) & 0xFFFF));
+                       return false;
+               }
+       }
+
+       fp->pc += 4;
+       return true;
+}
+
+#define PseudoDbg_opcode        0xf8000000
+#define PseudoDbg_reg_bits      0
+#define PseudoDbg_reg_mask      0x7
+#define PseudoDbg_grp_bits      3
+#define PseudoDbg_grp_mask      0x7
+#define PseudoDbg_fn_bits       6
+#define PseudoDbg_fn_mask       0x3
+#define PseudoDbg_code_bits     8
+#define PseudoDbg_code_mask     0xff
+
+/*
+ * DBG - debug (dump a register value out)
+ */
+bool execute_pseudodbg(struct pt_regs *fp, unsigned int opcode)
+{
+       int grp, fn, reg;
+       long value, value1;
+
+       if ((opcode & 0xFF000000) != PseudoDbg_opcode)
+               return false;
+
+       opcode >>= 16;
+       grp = ((opcode >> PseudoDbg_grp_bits) & PseudoDbg_reg_mask);
+       fn  = ((opcode >> PseudoDbg_fn_bits)  & PseudoDbg_fn_mask);
+       reg = ((opcode >> PseudoDbg_reg_bits) & PseudoDbg_reg_mask);
+
+       if (fn == 3 && (reg == 0 || reg == 1)) {
+               if (!fix_up_reg(fp, &value, 4, 2 * reg))
+                       return false;
+               if (!fix_up_reg(fp, &value1, 4, 2 * reg + 1))
+                       return false;
+
+               pr_notice("DBG A%i = %02lx%08lx\n", reg, value & 0xFF, value1);
+               fp->pc += 2;
+               return true;
+
+       } else if (fn == 0) {
+               if (!fix_up_reg(fp, &value, grp, reg))
+                       return false;
+
+               pr_notice("DBG %s = %08lx\n", get_allreg_name(grp, reg), value);
+               fp->pc += 2;
+               return true;
+       }
+
+       return false;
+}
index 43eb969405d1657bd0aba85b2528e9d28296bd55..6ec77685df526899c6998fe3030513714d42d5a8 100644 (file)
@@ -292,28 +292,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                        break;
                }
 
-#ifdef CONFIG_BINFMT_ELF_FDPIC
-       case PTRACE_GETFDPIC: {
-               unsigned long tmp = 0;
-
-               switch (addr) {
-               case_PTRACE_GETFDPIC_EXEC:
-               case PTRACE_GETFDPIC_EXEC:
-                       tmp = child->mm->context.exec_fdpic_loadmap;
-                       break;
-               case_PTRACE_GETFDPIC_INTERP:
-               case PTRACE_GETFDPIC_INTERP:
-                       tmp = child->mm->context.interp_fdpic_loadmap;
-                       break;
-               default:
-                       break;
-               }
-
-               ret = put_user(tmp, datap);
-               break;
-       }
-#endif
-
                /* when I and D space are separate, this will have to be fixed. */
        case PTRACE_POKEDATA:
                pr_debug("ptrace: PTRACE_PEEKDATA\n");
@@ -357,8 +335,14 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
        case PTRACE_PEEKUSR:
                switch (addr) {
 #ifdef CONFIG_BINFMT_ELF_FDPIC /* backwards compat */
-               case PT_FDPIC_EXEC:   goto case_PTRACE_GETFDPIC_EXEC;
-               case PT_FDPIC_INTERP: goto case_PTRACE_GETFDPIC_INTERP;
+               case PT_FDPIC_EXEC:
+                       request = PTRACE_GETFDPIC;
+                       addr = PTRACE_GETFDPIC_EXEC;
+                       goto case_default;
+               case PT_FDPIC_INTERP:
+                       request = PTRACE_GETFDPIC;
+                       addr = PTRACE_GETFDPIC_INTERP;
+                       goto case_default;
 #endif
                default:
                        ret = get_reg(child, addr, datap);
@@ -385,6 +369,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                                             0, sizeof(struct pt_regs),
                                             (const void __user *)data);
 
+       case_default:
        default:
                ret = ptrace_request(child, request, addr, data);
                break;
index 8e2efceb364b8752b48ae63c97451ee0ee58a629..d37a397f43f5eacab8517c6c83fd2cf50e1905da 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2004-2009 Analog Devices Inc.
+ * Copyright 2004-2010 Analog Devices Inc.
  *
  * Licensed under the GPL-2 or later.
  */
@@ -925,7 +925,7 @@ void __init setup_arch(char **cmdline_p)
        else if (_bfin_swrst & RESET_SOFTWARE)
                printk(KERN_NOTICE "Reset caused by Software reset\n");
 
-       printk(KERN_INFO "Blackfin support (C) 2004-2009 Analog Devices, Inc.\n");
+       printk(KERN_INFO "Blackfin support (C) 2004-2010 Analog Devices, Inc.\n");
        if (bfin_compiled_revid() == 0xffff)
                printk(KERN_INFO "Compiled for ADSP-%s Rev any, running on 0.%d\n", CPU, bfin_revid());
        else if (bfin_compiled_revid() == -1)
index 2e7f8e10bf87109083f43f73411327ae5223f724..bdc1e2f0da32383420a46ef6c1e3fe93a805c0ea 100644 (file)
@@ -47,3 +47,26 @@ unsigned long get_fb_unmapped_area(struct file *filp, unsigned long orig_addr,
 }
 EXPORT_SYMBOL(get_fb_unmapped_area);
 #endif
+
+/* Needed for legacy userspace atomic emulation */
+static DEFINE_SPINLOCK(bfin_spinlock_lock);
+
+#ifdef CONFIG_SYS_BFIN_SPINLOCK_L1
+__attribute__((l1_text))
+#endif
+asmlinkage int sys_bfin_spinlock(int *p)
+{
+       int ret, tmp = 0;
+
+       spin_lock(&bfin_spinlock_lock); /* This would also hold kernel preemption. */
+       ret = get_user(tmp, p);
+       if (likely(ret == 0)) {
+               if (unlikely(tmp))
+                       ret = 1;
+               else
+                       put_user(1, p);
+       }
+       spin_unlock(&bfin_spinlock_lock);
+
+       return ret;
+}
diff --git a/arch/blackfin/kernel/trace.c b/arch/blackfin/kernel/trace.c
new file mode 100644 (file)
index 0000000..59fcdf6
--- /dev/null
@@ -0,0 +1,981 @@
+/* provide some functions which dump the trace buffer, in a nice way for people
+ * to read it, and understand what is going on
+ *
+ * Copyright 2004-2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later
+ */
+
+#include <linux/kernel.h>
+#include <linux/hardirq.h>
+#include <linux/thread_info.h>
+#include <linux/mm.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/kallsyms.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <asm/dma.h>
+#include <asm/trace.h>
+#include <asm/fixed_code.h>
+#include <asm/traps.h>
+#include <asm/irq_handler.h>
+
+void decode_address(char *buf, unsigned long address)
+{
+       struct task_struct *p;
+       struct mm_struct *mm;
+       unsigned long flags, offset;
+       unsigned char in_atomic = (bfin_read_IPEND() & 0x10) || in_atomic();
+       struct rb_node *n;
+
+#ifdef CONFIG_KALLSYMS
+       unsigned long symsize;
+       const char *symname;
+       char *modname;
+       char *delim = ":";
+       char namebuf[128];
+#endif
+
+       buf += sprintf(buf, "<0x%08lx> ", address);
+
+#ifdef CONFIG_KALLSYMS
+       /* look up the address and see if we are in kernel space */
+       symname = kallsyms_lookup(address, &symsize, &offset, &modname, namebuf);
+
+       if (symname) {
+               /* yeah! kernel space! */
+               if (!modname)
+                       modname = delim = "";
+               sprintf(buf, "{ %s%s%s%s + 0x%lx }",
+                       delim, modname, delim, symname,
+                       (unsigned long)offset);
+               return;
+       }
+#endif
+
+       if (address >= FIXED_CODE_START && address < FIXED_CODE_END) {
+               /* Problem in fixed code section? */
+               strcat(buf, "/* Maybe fixed code section */");
+               return;
+
+       } else if (address < CONFIG_BOOT_LOAD) {
+               /* Problem somewhere before the kernel start address */
+               strcat(buf, "/* Maybe null pointer? */");
+               return;
+
+       } else if (address >= COREMMR_BASE) {
+               strcat(buf, "/* core mmrs */");
+               return;
+
+       } else if (address >= SYSMMR_BASE) {
+               strcat(buf, "/* system mmrs */");
+               return;
+
+       } else if (address >= L1_ROM_START && address < L1_ROM_START + L1_ROM_LENGTH) {
+               strcat(buf, "/* on-chip L1 ROM */");
+               return;
+
+       } else if (address >= L1_SCRATCH_START && address < L1_SCRATCH_START + L1_SCRATCH_LENGTH) {
+               strcat(buf, "/* on-chip scratchpad */");
+               return;
+
+       } else if (address >= physical_mem_end && address < ASYNC_BANK0_BASE) {
+               strcat(buf, "/* unconnected memory */");
+               return;
+
+       } else if (address >= ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE && address < BOOT_ROM_START) {
+               strcat(buf, "/* reserved memory */");
+               return;
+
+       } else if (address >= L1_DATA_A_START && address < L1_DATA_A_START + L1_DATA_A_LENGTH) {
+               strcat(buf, "/* on-chip Data Bank A */");
+               return;
+
+       } else if (address >= L1_DATA_B_START && address < L1_DATA_B_START + L1_DATA_B_LENGTH) {
+               strcat(buf, "/* on-chip Data Bank B */");
+               return;
+       }
+
+       /*
+        * Don't walk any of the vmas if we are oopsing, it has been known
+        * to cause problems - corrupt vmas (kernel crashes) cause double faults
+        */
+       if (oops_in_progress) {
+               strcat(buf, "/* kernel dynamic memory (maybe user-space) */");
+               return;
+       }
+
+       /* looks like we're off in user-land, so let's walk all the
+        * mappings of all our processes and see if we can't be a whee
+        * bit more specific
+        */
+       write_lock_irqsave(&tasklist_lock, flags);
+       for_each_process(p) {
+               mm = (in_atomic ? p->mm : get_task_mm(p));
+               if (!mm)
+                       continue;
+
+               if (!down_read_trylock(&mm->mmap_sem)) {
+                       if (!in_atomic)
+                               mmput(mm);
+                       continue;
+               }
+
+               for (n = rb_first(&mm->mm_rb); n; n = rb_next(n)) {
+                       struct vm_area_struct *vma;
+
+                       vma = rb_entry(n, struct vm_area_struct, vm_rb);
+
+                       if (address >= vma->vm_start && address < vma->vm_end) {
+                               char _tmpbuf[256];
+                               char *name = p->comm;
+                               struct file *file = vma->vm_file;
+
+                               if (file) {
+                                       char *d_name = d_path(&file->f_path, _tmpbuf,
+                                                     sizeof(_tmpbuf));
+                                       if (!IS_ERR(d_name))
+                                               name = d_name;
+                               }
+
+                               /* FLAT does not have its text aligned to the start of
+                                * the map while FDPIC ELF does ...
+                                */
+
+                               /* before we can check flat/fdpic, we need to
+                                * make sure current is valid
+                                */
+                               if ((unsigned long)current >= FIXED_CODE_START &&
+                                   !((unsigned long)current & 0x3)) {
+                                       if (current->mm &&
+                                           (address > current->mm->start_code) &&
+                                           (address < current->mm->end_code))
+                                               offset = address - current->mm->start_code;
+                                       else
+                                               offset = (address - vma->vm_start) +
+                                                        (vma->vm_pgoff << PAGE_SHIFT);
+
+                                       sprintf(buf, "[ %s + 0x%lx ]", name, offset);
+                               } else
+                                       sprintf(buf, "[ %s vma:0x%lx-0x%lx]",
+                                               name, vma->vm_start, vma->vm_end);
+
+                               up_read(&mm->mmap_sem);
+                               if (!in_atomic)
+                                       mmput(mm);
+
+                               if (buf[0] == '\0')
+                                       sprintf(buf, "[ %s ] dynamic memory", name);
+
+                               goto done;
+                       }
+               }
+
+               up_read(&mm->mmap_sem);
+               if (!in_atomic)
+                       mmput(mm);
+       }
+
+       /*
+        * we were unable to find this address anywhere,
+        * or some MMs were skipped because they were in use.
+        */
+       sprintf(buf, "/* kernel dynamic memory */");
+
+done:
+       write_unlock_irqrestore(&tasklist_lock, flags);
+}
+
+#define EXPAND_LEN ((1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN) * 256 - 1)
+
+/*
+ * Similar to get_user, do some address checking, then dereference
+ * Return true on success, false on bad address
+ */
+bool get_mem16(unsigned short *val, unsigned short *address)
+{
+       unsigned long addr = (unsigned long)address;
+
+       /* Check for odd addresses */
+       if (addr & 0x1)
+               return false;
+
+       switch (bfin_mem_access_type(addr, 2)) {
+       case BFIN_MEM_ACCESS_CORE:
+       case BFIN_MEM_ACCESS_CORE_ONLY:
+               *val = *address;
+               return true;
+       case BFIN_MEM_ACCESS_DMA:
+               dma_memcpy(val, address, 2);
+               return true;
+       case BFIN_MEM_ACCESS_ITEST:
+               isram_memcpy(val, address, 2);
+               return true;
+       default: /* invalid access */
+               return false;
+       }
+}
+
+bool get_instruction(unsigned int *val, unsigned short *address)
+{
+       unsigned long addr = (unsigned long)address;
+       unsigned short opcode0, opcode1;
+
+       /* Check for odd addresses */
+       if (addr & 0x1)
+               return false;
+
+       /* MMR region will never have instructions */
+       if (addr >= SYSMMR_BASE)
+               return false;
+
+       /* Scratchpad will never have instructions */
+       if (addr >= L1_SCRATCH_START && addr < L1_SCRATCH_START + L1_SCRATCH_LENGTH)
+               return false;
+
+       /* Data banks will never have instructions */
+       if (addr >= BOOT_ROM_START + BOOT_ROM_LENGTH && addr < L1_CODE_START)
+               return false;
+
+       if (!get_mem16(&opcode0, address))
+               return false;
+
+       /* was this a 32-bit instruction? If so, get the next 16 bits */
+       if ((opcode0 & 0xc000) == 0xc000) {
+               if (!get_mem16(&opcode1, address + 1))
+                       return false;
+               *val = (opcode0 << 16) + opcode1;
+       } else
+               *val = opcode0;
+
+       return true;
+}
+
+#if defined(CONFIG_DEBUG_BFIN_HWTRACE_ON)
+/*
+ * decode the instruction if we are printing out the trace, as it
+ * makes things easier to follow, without running it through objdump
+ * Decode the change of flow, and the common load/store instructions
+ * which are the main cause for faults, and discontinuities in the trace
+ * buffer.
+ */
+
+#define ProgCtrl_opcode         0x0000
+#define ProgCtrl_poprnd_bits    0
+#define ProgCtrl_poprnd_mask    0xf
+#define ProgCtrl_prgfunc_bits   4
+#define ProgCtrl_prgfunc_mask   0xf
+#define ProgCtrl_code_bits      8
+#define ProgCtrl_code_mask      0xff
+
+static void decode_ProgCtrl_0(unsigned int opcode)
+{
+       int poprnd  = ((opcode >> ProgCtrl_poprnd_bits) & ProgCtrl_poprnd_mask);
+       int prgfunc = ((opcode >> ProgCtrl_prgfunc_bits) & ProgCtrl_prgfunc_mask);
+
+       if (prgfunc == 0 && poprnd == 0)
+               pr_cont("NOP");
+       else if (prgfunc == 1 && poprnd == 0)
+               pr_cont("RTS");
+       else if (prgfunc == 1 && poprnd == 1)
+               pr_cont("RTI");
+       else if (prgfunc == 1 && poprnd == 2)
+               pr_cont("RTX");
+       else if (prgfunc == 1 && poprnd == 3)
+               pr_cont("RTN");
+       else if (prgfunc == 1 && poprnd == 4)
+               pr_cont("RTE");
+       else if (prgfunc == 2 && poprnd == 0)
+               pr_cont("IDLE");
+       else if (prgfunc == 2 && poprnd == 3)
+               pr_cont("CSYNC");
+       else if (prgfunc == 2 && poprnd == 4)
+               pr_cont("SSYNC");
+       else if (prgfunc == 2 && poprnd == 5)
+               pr_cont("EMUEXCPT");
+       else if (prgfunc == 3)
+               pr_cont("CLI R%i", poprnd);
+       else if (prgfunc == 4)
+               pr_cont("STI R%i", poprnd);
+       else if (prgfunc == 5)
+               pr_cont("JUMP (P%i)", poprnd);
+       else if (prgfunc == 6)
+               pr_cont("CALL (P%i)", poprnd);
+       else if (prgfunc == 7)
+               pr_cont("CALL (PC + P%i)", poprnd);
+       else if (prgfunc == 8)
+               pr_cont("JUMP (PC + P%i", poprnd);
+       else if (prgfunc == 9)
+               pr_cont("RAISE %i", poprnd);
+       else if (prgfunc == 10)
+               pr_cont("EXCPT %i", poprnd);
+       else
+               pr_cont("0x%04x", opcode);
+
+}
+
+#define BRCC_opcode             0x1000
+#define BRCC_offset_bits        0
+#define BRCC_offset_mask        0x3ff
+#define BRCC_B_bits             10
+#define BRCC_B_mask             0x1
+#define BRCC_T_bits             11
+#define BRCC_T_mask             0x1
+#define BRCC_code_bits          12
+#define BRCC_code_mask          0xf
+
+static void decode_BRCC_0(unsigned int opcode)
+{
+       int B = ((opcode >> BRCC_B_bits) & BRCC_B_mask);
+       int T = ((opcode >> BRCC_T_bits) & BRCC_T_mask);
+
+       pr_cont("IF %sCC JUMP pcrel %s", T ? "" : "!", B ? "(BP)" : "");
+}
+
+#define CALLa_opcode    0xe2000000
+#define CALLa_addr_bits 0
+#define CALLa_addr_mask 0xffffff
+#define CALLa_S_bits    24
+#define CALLa_S_mask    0x1
+#define CALLa_code_bits 25
+#define CALLa_code_mask 0x7f
+
+static void decode_CALLa_0(unsigned int opcode)
+{
+       int S   = ((opcode >> (CALLa_S_bits - 16)) & CALLa_S_mask);
+
+       if (S)
+               pr_cont("CALL pcrel");
+       else
+               pr_cont("JUMP.L");
+}
+
+#define LoopSetup_opcode                0xe0800000
+#define LoopSetup_eoffset_bits          0
+#define LoopSetup_eoffset_mask          0x3ff
+#define LoopSetup_dontcare_bits         10
+#define LoopSetup_dontcare_mask         0x3
+#define LoopSetup_reg_bits              12
+#define LoopSetup_reg_mask              0xf
+#define LoopSetup_soffset_bits          16
+#define LoopSetup_soffset_mask          0xf
+#define LoopSetup_c_bits                20
+#define LoopSetup_c_mask                0x1
+#define LoopSetup_rop_bits              21
+#define LoopSetup_rop_mask              0x3
+#define LoopSetup_code_bits             23
+#define LoopSetup_code_mask             0x1ff
+
+static void decode_LoopSetup_0(unsigned int opcode)
+{
+       int c   = ((opcode >> LoopSetup_c_bits)   & LoopSetup_c_mask);
+       int reg = ((opcode >> LoopSetup_reg_bits) & LoopSetup_reg_mask);
+       int rop = ((opcode >> LoopSetup_rop_bits) & LoopSetup_rop_mask);
+
+       pr_cont("LSETUP <> LC%i", c);
+       if ((rop & 1) == 1)
+               pr_cont("= P%i", reg);
+       if ((rop & 2) == 2)
+               pr_cont(" >> 0x1");
+}
+
+#define DspLDST_opcode          0x9c00
+#define DspLDST_reg_bits        0
+#define DspLDST_reg_mask        0x7
+#define DspLDST_i_bits          3
+#define DspLDST_i_mask          0x3
+#define DspLDST_m_bits          5
+#define DspLDST_m_mask          0x3
+#define DspLDST_aop_bits        7
+#define DspLDST_aop_mask        0x3
+#define DspLDST_W_bits          9
+#define DspLDST_W_mask          0x1
+#define DspLDST_code_bits       10
+#define DspLDST_code_mask       0x3f
+
+static void decode_dspLDST_0(unsigned int opcode)
+{
+       int i   = ((opcode >> DspLDST_i_bits) & DspLDST_i_mask);
+       int m   = ((opcode >> DspLDST_m_bits) & DspLDST_m_mask);
+       int W   = ((opcode >> DspLDST_W_bits) & DspLDST_W_mask);
+       int aop = ((opcode >> DspLDST_aop_bits) & DspLDST_aop_mask);
+       int reg = ((opcode >> DspLDST_reg_bits) & DspLDST_reg_mask);
+
+       if (W == 0) {
+               pr_cont("R%i", reg);
+               switch (m) {
+               case 0:
+                       pr_cont(" = ");
+                       break;
+               case 1:
+                       pr_cont(".L = ");
+                       break;
+               case 2:
+                       pr_cont(".W = ");
+                       break;
+               }
+       }
+
+       pr_cont("[ I%i", i);
+
+       switch (aop) {
+       case 0:
+               pr_cont("++ ]");
+               break;
+       case 1:
+               pr_cont("-- ]");
+               break;
+       }
+
+       if (W == 1) {
+               pr_cont(" = R%i", reg);
+               switch (m) {
+               case 1:
+                       pr_cont(".L = ");
+                       break;
+               case 2:
+                       pr_cont(".W = ");
+                       break;
+               }
+       }
+}
+
+#define LDST_opcode             0x9000
+#define LDST_reg_bits           0
+#define LDST_reg_mask           0x7
+#define LDST_ptr_bits           3
+#define LDST_ptr_mask           0x7
+#define LDST_Z_bits             6
+#define LDST_Z_mask             0x1
+#define LDST_aop_bits           7
+#define LDST_aop_mask           0x3
+#define LDST_W_bits             9
+#define LDST_W_mask             0x1
+#define LDST_sz_bits            10
+#define LDST_sz_mask            0x3
+#define LDST_code_bits          12
+#define LDST_code_mask          0xf
+
+static void decode_LDST_0(unsigned int opcode)
+{
+       int Z   = ((opcode >> LDST_Z_bits) & LDST_Z_mask);
+       int W   = ((opcode >> LDST_W_bits) & LDST_W_mask);
+       int sz  = ((opcode >> LDST_sz_bits) & LDST_sz_mask);
+       int aop = ((opcode >> LDST_aop_bits) & LDST_aop_mask);
+       int reg = ((opcode >> LDST_reg_bits) & LDST_reg_mask);
+       int ptr = ((opcode >> LDST_ptr_bits) & LDST_ptr_mask);
+
+       if (W == 0)
+               pr_cont("%s%i = ", (sz == 0 && Z == 1) ? "P" : "R", reg);
+
+       switch (sz) {
+       case 1:
+               pr_cont("W");
+               break;
+       case 2:
+               pr_cont("B");
+               break;
+       }
+
+       pr_cont("[P%i", ptr);
+
+       switch (aop) {
+       case 0:
+               pr_cont("++");
+               break;
+       case 1:
+               pr_cont("--");
+               break;
+       }
+       pr_cont("]");
+
+       if (W == 1)
+               pr_cont(" = %s%i ", (sz == 0 && Z == 1) ? "P" : "R", reg);
+
+       if (sz) {
+               if (Z)
+                       pr_cont(" (X)");
+               else
+                       pr_cont(" (Z)");
+       }
+}
+
+#define LDSTii_opcode           0xa000
+#define LDSTii_reg_bit          0
+#define LDSTii_reg_mask         0x7
+#define LDSTii_ptr_bit          3
+#define LDSTii_ptr_mask         0x7
+#define LDSTii_offset_bit       6
+#define LDSTii_offset_mask      0xf
+#define LDSTii_op_bit           10
+#define LDSTii_op_mask          0x3
+#define LDSTii_W_bit            12
+#define LDSTii_W_mask           0x1
+#define LDSTii_code_bit         13
+#define LDSTii_code_mask        0x7
+
+static void decode_LDSTii_0(unsigned int opcode)
+{
+       int reg = ((opcode >> LDSTii_reg_bit) & LDSTii_reg_mask);
+       int ptr = ((opcode >> LDSTii_ptr_bit) & LDSTii_ptr_mask);
+       int offset = ((opcode >> LDSTii_offset_bit) & LDSTii_offset_mask);
+       int op = ((opcode >> LDSTii_op_bit) & LDSTii_op_mask);
+       int W = ((opcode >> LDSTii_W_bit) & LDSTii_W_mask);
+
+       if (W == 0) {
+               pr_cont("%s%i = %s[P%i + %i]", op == 3 ? "R" : "P", reg,
+                       op == 1 || op == 2 ? "" : "W", ptr, offset);
+               if (op == 2)
+                       pr_cont("(Z)");
+               if (op == 3)
+                       pr_cont("(X)");
+       } else {
+               pr_cont("%s[P%i + %i] = %s%i", op == 0 ? "" : "W", ptr,
+                       offset, op == 3 ? "P" : "R", reg);
+       }
+}
+
+#define LDSTidxI_opcode         0xe4000000
+#define LDSTidxI_offset_bits    0
+#define LDSTidxI_offset_mask    0xffff
+#define LDSTidxI_reg_bits       16
+#define LDSTidxI_reg_mask       0x7
+#define LDSTidxI_ptr_bits       19
+#define LDSTidxI_ptr_mask       0x7
+#define LDSTidxI_sz_bits        22
+#define LDSTidxI_sz_mask        0x3
+#define LDSTidxI_Z_bits         24
+#define LDSTidxI_Z_mask         0x1
+#define LDSTidxI_W_bits         25
+#define LDSTidxI_W_mask         0x1
+#define LDSTidxI_code_bits      26
+#define LDSTidxI_code_mask      0x3f
+
+static void decode_LDSTidxI_0(unsigned int opcode)
+{
+       int Z      = ((opcode >> LDSTidxI_Z_bits)      & LDSTidxI_Z_mask);
+       int W      = ((opcode >> LDSTidxI_W_bits)      & LDSTidxI_W_mask);
+       int sz     = ((opcode >> LDSTidxI_sz_bits)     & LDSTidxI_sz_mask);
+       int reg    = ((opcode >> LDSTidxI_reg_bits)    & LDSTidxI_reg_mask);
+       int ptr    = ((opcode >> LDSTidxI_ptr_bits)    & LDSTidxI_ptr_mask);
+       int offset = ((opcode >> LDSTidxI_offset_bits) & LDSTidxI_offset_mask);
+
+       if (W == 0)
+               pr_cont("%s%i = ", sz == 0 && Z == 1 ? "P" : "R", reg);
+
+       if (sz == 1)
+               pr_cont("W");
+       if (sz == 2)
+               pr_cont("B");
+
+       pr_cont("[P%i + %s0x%x]", ptr, offset & 0x20 ? "-" : "",
+               (offset & 0x1f) << 2);
+
+       if (W == 0 && sz != 0) {
+               if (Z)
+                       pr_cont("(X)");
+               else
+                       pr_cont("(Z)");
+       }
+
+       if (W == 1)
+               pr_cont("= %s%i", (sz == 0 && Z == 1) ? "P" : "R", reg);
+
+}
+
+static void decode_opcode(unsigned int opcode)
+{
+#ifdef CONFIG_BUG
+       if (opcode == BFIN_BUG_OPCODE)
+               pr_cont("BUG");
+       else
+#endif
+       if ((opcode & 0xffffff00) == ProgCtrl_opcode)
+               decode_ProgCtrl_0(opcode);
+       else if ((opcode & 0xfffff000) == BRCC_opcode)
+               decode_BRCC_0(opcode);
+       else if ((opcode & 0xfffff000) == 0x2000)
+               pr_cont("JUMP.S");
+       else if ((opcode & 0xfe000000) == CALLa_opcode)
+               decode_CALLa_0(opcode);
+       else if ((opcode & 0xff8000C0) == LoopSetup_opcode)
+               decode_LoopSetup_0(opcode);
+       else if ((opcode & 0xfffffc00) == DspLDST_opcode)
+               decode_dspLDST_0(opcode);
+       else if ((opcode & 0xfffff000) == LDST_opcode)
+               decode_LDST_0(opcode);
+       else if ((opcode & 0xffffe000) == LDSTii_opcode)
+               decode_LDSTii_0(opcode);
+       else if ((opcode & 0xfc000000) == LDSTidxI_opcode)
+               decode_LDSTidxI_0(opcode);
+       else if (opcode & 0xffff0000)
+               pr_cont("0x%08x", opcode);
+       else
+               pr_cont("0x%04x", opcode);
+}
+
+#define BIT_MULTI_INS 0x08000000
+static void decode_instruction(unsigned short *address)
+{
+       unsigned int opcode;
+
+       if (!get_instruction(&opcode, address))
+               return;
+
+       decode_opcode(opcode);
+
+       /* If things are a 32-bit instruction, it has the possibility of being
+        * a multi-issue instruction (a 32-bit, and 2 16 bit instrucitions)
+        * This test collidates with the unlink instruction, so disallow that
+        */
+       if ((opcode & 0xc0000000) == 0xc0000000 &&
+           (opcode & BIT_MULTI_INS) &&
+           (opcode & 0xe8000000) != 0xe8000000) {
+               pr_cont(" || ");
+               if (!get_instruction(&opcode, address + 2))
+                       return;
+               decode_opcode(opcode);
+               pr_cont(" || ");
+               if (!get_instruction(&opcode, address + 3))
+                       return;
+               decode_opcode(opcode);
+       }
+}
+#endif
+
+void dump_bfin_trace_buffer(void)
+{
+#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
+       int tflags, i = 0, fault = 0;
+       char buf[150];
+       unsigned short *addr;
+       unsigned int cpu = raw_smp_processor_id();
+#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND
+       int j, index;
+#endif
+
+       trace_buffer_save(tflags);
+
+       pr_notice("Hardware Trace:\n");
+
+#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND
+       pr_notice("WARNING: Expanded trace turned on - can not trace exceptions\n");
+#endif
+
+       if (likely(bfin_read_TBUFSTAT() & TBUFCNT)) {
+               for (; bfin_read_TBUFSTAT() & TBUFCNT; i++) {
+                       addr = (unsigned short *)bfin_read_TBUF();
+                       decode_address(buf, (unsigned long)addr);
+                       pr_notice("%4i Target : %s\n", i, buf);
+                       /* Normally, the faulting instruction doesn't go into
+                        * the trace buffer, (since it doesn't commit), so
+                        * we print out the fault address here
+                        */
+                       if (!fault && addr == ((unsigned short *)evt_ivhw)) {
+                               addr = (unsigned short *)bfin_read_TBUF();
+                               decode_address(buf, (unsigned long)addr);
+                               pr_notice("      FAULT : %s ", buf);
+                               decode_instruction(addr);
+                               pr_cont("\n");
+                               fault = 1;
+                               continue;
+                       }
+                       if (!fault && addr == (unsigned short *)trap &&
+                               (cpu_pda[cpu].seqstat & SEQSTAT_EXCAUSE) > VEC_EXCPT15) {
+                               decode_address(buf, cpu_pda[cpu].icplb_fault_addr);
+                               pr_notice("      FAULT : %s ", buf);
+                               decode_instruction((unsigned short *)cpu_pda[cpu].icplb_fault_addr);
+                               pr_cont("\n");
+                               fault = 1;
+                       }
+                       addr = (unsigned short *)bfin_read_TBUF();
+                       decode_address(buf, (unsigned long)addr);
+                       pr_notice("     Source : %s ", buf);
+                       decode_instruction(addr);
+                       pr_cont("\n");
+               }
+       }
+
+#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND
+       if (trace_buff_offset)
+               index = trace_buff_offset / 4;
+       else
+               index = EXPAND_LEN;
+
+       j = (1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN) * 128;
+       while (j) {
+               decode_address(buf, software_trace_buff[index]);
+               pr_notice("%4i Target : %s\n", i, buf);
+               index -= 1;
+               if (index < 0)
+                       index = EXPAND_LEN;
+               decode_address(buf, software_trace_buff[index]);
+               pr_notice("     Source : %s ", buf);
+               decode_instruction((unsigned short *)software_trace_buff[index]);
+               pr_cont("\n");
+               index -= 1;
+               if (index < 0)
+                       index = EXPAND_LEN;
+               j--;
+               i++;
+       }
+#endif
+
+       trace_buffer_restore(tflags);
+#endif
+}
+EXPORT_SYMBOL(dump_bfin_trace_buffer);
+
+void dump_bfin_process(struct pt_regs *fp)
+{
+       /* We should be able to look at fp->ipend, but we don't push it on the
+        * stack all the time, so do this until we fix that */
+       unsigned int context = bfin_read_IPEND();
+
+       if (oops_in_progress)
+               pr_emerg("Kernel OOPS in progress\n");
+
+       if (context & 0x0020 && (fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR)
+               pr_notice("HW Error context\n");
+       else if (context & 0x0020)
+               pr_notice("Deferred Exception context\n");
+       else if (context & 0x3FC0)
+               pr_notice("Interrupt context\n");
+       else if (context & 0x4000)
+               pr_notice("Deferred Interrupt context\n");
+       else if (context & 0x8000)
+               pr_notice("Kernel process context\n");
+
+       /* Because we are crashing, and pointers could be bad, we check things
+        * pretty closely before we use them
+        */
+       if ((unsigned long)current >= FIXED_CODE_START &&
+           !((unsigned long)current & 0x3) && current->pid) {
+               pr_notice("CURRENT PROCESS:\n");
+               if (current->comm >= (char *)FIXED_CODE_START)
+                       pr_notice("COMM=%s PID=%d",
+                               current->comm, current->pid);
+               else
+                       pr_notice("COMM= invalid");
+
+               pr_cont("  CPU=%d\n", current_thread_info()->cpu);
+               if (!((unsigned long)current->mm & 0x3) &&
+                       (unsigned long)current->mm >= FIXED_CODE_START) {
+                       pr_notice("TEXT = 0x%p-0x%p        DATA = 0x%p-0x%p\n",
+                               (void *)current->mm->start_code,
+                               (void *)current->mm->end_code,
+                               (void *)current->mm->start_data,
+                               (void *)current->mm->end_data);
+                       pr_notice(" BSS = 0x%p-0x%p  USER-STACK = 0x%p\n\n",
+                               (void *)current->mm->end_data,
+                               (void *)current->mm->brk,
+                               (void *)current->mm->start_stack);
+               } else
+                       pr_notice("invalid mm\n");
+       } else
+               pr_notice("No Valid process in current context\n");
+}
+
+void dump_bfin_mem(struct pt_regs *fp)
+{
+       unsigned short *addr, *erraddr, val = 0, err = 0;
+       char sti = 0, buf[6];
+
+       erraddr = (void *)fp->pc;
+
+       pr_notice("return address: [0x%p]; contents of:", erraddr);
+
+       for (addr = (unsigned short *)((unsigned long)erraddr & ~0xF) - 0x10;
+            addr < (unsigned short *)((unsigned long)erraddr & ~0xF) + 0x10;
+            addr++) {
+               if (!((unsigned long)addr & 0xF))
+                       pr_notice("0x%p: ", addr);
+
+               if (!get_mem16(&val, addr)) {
+                               val = 0;
+                               sprintf(buf, "????");
+               } else
+                       sprintf(buf, "%04x", val);
+
+               if (addr == erraddr) {
+                       pr_cont("[%s]", buf);
+                       err = val;
+               } else
+                       pr_cont(" %s ", buf);
+
+               /* Do any previous instructions turn on interrupts? */
+               if (addr <= erraddr &&                          /* in the past */
+                   ((val >= 0x0040 && val <= 0x0047) ||        /* STI instruction */
+                     val == 0x017b))                           /* [SP++] = RETI */
+                       sti = 1;
+       }
+
+       pr_cont("\n");
+
+       /* Hardware error interrupts can be deferred */
+       if (unlikely(sti && (fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR &&
+           oops_in_progress)){
+               pr_notice("Looks like this was a deferred error - sorry\n");
+#ifndef CONFIG_DEBUG_HWERR
+               pr_notice("The remaining message may be meaningless\n");
+               pr_notice("You should enable CONFIG_DEBUG_HWERR to get a better idea where it came from\n");
+#else
+               /* If we are handling only one peripheral interrupt
+                * and current mm and pid are valid, and the last error
+                * was in that user space process's text area
+                * print it out - because that is where the problem exists
+                */
+               if ((!(((fp)->ipend & ~0x30) & (((fp)->ipend & ~0x30) - 1))) &&
+                    (current->pid && current->mm)) {
+                       /* And the last RETI points to the current userspace context */
+                       if ((fp + 1)->pc >= current->mm->start_code &&
+                           (fp + 1)->pc <= current->mm->end_code) {
+                               pr_notice("It might be better to look around here :\n");
+                               pr_notice("-------------------------------------------\n");
+                               show_regs(fp + 1);
+                               pr_notice("-------------------------------------------\n");
+                       }
+               }
+#endif
+       }
+}
+
+void show_regs(struct pt_regs *fp)
+{
+       char buf[150];
+       struct irqaction *action;
+       unsigned int i;
+       unsigned long flags = 0;
+       unsigned int cpu = raw_smp_processor_id();
+       unsigned char in_atomic = (bfin_read_IPEND() & 0x10) || in_atomic();
+
+       pr_notice("\n");
+       if (CPUID != bfin_cpuid())
+               pr_notice("Compiled for cpu family 0x%04x (Rev %d), "
+                       "but running on:0x%04x (Rev %d)\n",
+                       CPUID, bfin_compiled_revid(), bfin_cpuid(), bfin_revid());
+
+       pr_notice("ADSP-%s-0.%d",
+               CPU, bfin_compiled_revid());
+
+       if (bfin_compiled_revid() !=  bfin_revid())
+               pr_cont("(Detected 0.%d)", bfin_revid());
+
+       pr_cont(" %lu(MHz CCLK) %lu(MHz SCLK) (%s)\n",
+               get_cclk()/1000000, get_sclk()/1000000,
+#ifdef CONFIG_MPU
+               "mpu on"
+#else
+               "mpu off"
+#endif
+               );
+
+       pr_notice("%s", linux_banner);
+
+       pr_notice("\nSEQUENCER STATUS:\t\t%s\n", print_tainted());
+       pr_notice(" SEQSTAT: %08lx  IPEND: %04lx  IMASK: %04lx  SYSCFG: %04lx\n",
+               (long)fp->seqstat, fp->ipend, cpu_pda[raw_smp_processor_id()].ex_imask, fp->syscfg);
+       if (fp->ipend & EVT_IRPTEN)
+               pr_notice("  Global Interrupts Disabled (IPEND[4])\n");
+       if (!(cpu_pda[raw_smp_processor_id()].ex_imask & (EVT_IVG13 | EVT_IVG12 | EVT_IVG11 |
+                       EVT_IVG10 | EVT_IVG9 | EVT_IVG8 | EVT_IVG7 | EVT_IVTMR)))
+               pr_notice("  Peripheral interrupts masked off\n");
+       if (!(cpu_pda[raw_smp_processor_id()].ex_imask & (EVT_IVG15 | EVT_IVG14)))
+               pr_notice("  Kernel interrupts masked off\n");
+       if ((fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR) {
+               pr_notice("  HWERRCAUSE: 0x%lx\n",
+                       (fp->seqstat & SEQSTAT_HWERRCAUSE) >> 14);
+#ifdef EBIU_ERRMST
+               /* If the error was from the EBIU, print it out */
+               if (bfin_read_EBIU_ERRMST() & CORE_ERROR) {
+                       pr_notice("  EBIU Error Reason  : 0x%04x\n",
+                               bfin_read_EBIU_ERRMST());
+                       pr_notice("  EBIU Error Address : 0x%08x\n",
+                               bfin_read_EBIU_ERRADD());
+               }
+#endif
+       }
+       pr_notice("  EXCAUSE   : 0x%lx\n",
+               fp->seqstat & SEQSTAT_EXCAUSE);
+       for (i = 2; i <= 15 ; i++) {
+               if (fp->ipend & (1 << i)) {
+                       if (i != 4) {
+                               decode_address(buf, bfin_read32(EVT0 + 4*i));
+                               pr_notice("  physical IVG%i asserted : %s\n", i, buf);
+                       } else
+                               pr_notice("  interrupts disabled\n");
+               }
+       }
+
+       /* if no interrupts are going off, don't print this out */
+       if (fp->ipend & ~0x3F) {
+               for (i = 0; i < (NR_IRQS - 1); i++) {
+                       if (!in_atomic)
+                               raw_spin_lock_irqsave(&irq_desc[i].lock, flags);
+
+                       action = irq_desc[i].action;
+                       if (!action)
+                               goto unlock;
+
+                       decode_address(buf, (unsigned int)action->handler);
+                       pr_notice("  logical irq %3d mapped  : %s", i, buf);
+                       for (action = action->next; action; action = action->next) {
+                               decode_address(buf, (unsigned int)action->handler);
+                               pr_cont(", %s", buf);
+                       }
+                       pr_cont("\n");
+unlock:
+                       if (!in_atomic)
+                               raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags);
+               }
+       }
+
+       decode_address(buf, fp->rete);
+       pr_notice(" RETE: %s\n", buf);
+       decode_address(buf, fp->retn);
+       pr_notice(" RETN: %s\n", buf);
+       decode_address(buf, fp->retx);
+       pr_notice(" RETX: %s\n", buf);
+       decode_address(buf, fp->rets);
+       pr_notice(" RETS: %s\n", buf);
+       decode_address(buf, fp->pc);
+       pr_notice(" PC  : %s\n", buf);
+
+       if (((long)fp->seqstat &  SEQSTAT_EXCAUSE) &&
+           (((long)fp->seqstat & SEQSTAT_EXCAUSE) != VEC_HWERR)) {
+               decode_address(buf, cpu_pda[cpu].dcplb_fault_addr);
+               pr_notice("DCPLB_FAULT_ADDR: %s\n", buf);
+               decode_address(buf, cpu_pda[cpu].icplb_fault_addr);
+               pr_notice("ICPLB_FAULT_ADDR: %s\n", buf);
+       }
+
+       pr_notice("PROCESSOR STATE:\n");
+       pr_notice(" R0 : %08lx    R1 : %08lx    R2 : %08lx    R3 : %08lx\n",
+               fp->r0, fp->r1, fp->r2, fp->r3);
+       pr_notice(" R4 : %08lx    R5 : %08lx    R6 : %08lx    R7 : %08lx\n",
+               fp->r4, fp->r5, fp->r6, fp->r7);
+       pr_notice(" P0 : %08lx    P1 : %08lx    P2 : %08lx    P3 : %08lx\n",
+               fp->p0, fp->p1, fp->p2, fp->p3);
+       pr_notice(" P4 : %08lx    P5 : %08lx    FP : %08lx    SP : %08lx\n",
+               fp->p4, fp->p5, fp->fp, (long)fp);
+       pr_notice(" LB0: %08lx    LT0: %08lx    LC0: %08lx\n",
+               fp->lb0, fp->lt0, fp->lc0);
+       pr_notice(" LB1: %08lx    LT1: %08lx    LC1: %08lx\n",
+               fp->lb1, fp->lt1, fp->lc1);
+       pr_notice(" B0 : %08lx    L0 : %08lx    M0 : %08lx    I0 : %08lx\n",
+               fp->b0, fp->l0, fp->m0, fp->i0);
+       pr_notice(" B1 : %08lx    L1 : %08lx    M1 : %08lx    I1 : %08lx\n",
+               fp->b1, fp->l1, fp->m1, fp->i1);
+       pr_notice(" B2 : %08lx    L2 : %08lx    M2 : %08lx    I2 : %08lx\n",
+               fp->b2, fp->l2, fp->m2, fp->i2);
+       pr_notice(" B3 : %08lx    L3 : %08lx    M3 : %08lx    I3 : %08lx\n",
+               fp->b3, fp->l3, fp->m3, fp->i3);
+       pr_notice("A0.w: %08lx   A0.x: %08lx   A1.w: %08lx   A1.x: %08lx\n",
+               fp->a0w, fp->a0x, fp->a1w, fp->a1x);
+
+       pr_notice("USP : %08lx  ASTAT: %08lx\n",
+               rdusp(), fp->astat);
+
+       pr_notice("\n");
+}
index ba70c4bc2699e7a288b36a591930106b23d84d32..59c1df75e4de9519d61070142b62f3b1eb90ef5a 100644 (file)
@@ -1,25 +1,22 @@
 /*
- * Copyright 2004-2009 Analog Devices Inc.
+ * Main exception handling logic.
+ *
+ * Copyright 2004-2010 Analog Devices Inc.
  *
  * Licensed under the GPL-2 or later
  */
 
 #include <linux/bug.h>
 #include <linux/uaccess.h>
-#include <linux/interrupt.h>
 #include <linux/module.h>
-#include <linux/kallsyms.h>
-#include <linux/fs.h>
-#include <linux/rbtree.h>
 #include <asm/traps.h>
-#include <asm/cacheflush.h>
 #include <asm/cplb.h>
-#include <asm/dma.h>
 #include <asm/blackfin.h>
 #include <asm/irq_handler.h>
 #include <linux/irq.h>
 #include <asm/trace.h>
 #include <asm/fixed_code.h>
+#include <asm/pseudo_instructions.h>
 
 #ifdef CONFIG_KGDB
 # include <linux/kgdb.h>
@@ -62,194 +59,6 @@ void __init trap_init(void)
        CSYNC();
 }
 
-static void decode_address(char *buf, unsigned long address)
-{
-#ifdef CONFIG_DEBUG_VERBOSE
-       struct task_struct *p;
-       struct mm_struct *mm;
-       unsigned long flags, offset;
-       unsigned char in_atomic = (bfin_read_IPEND() & 0x10) || in_atomic();
-       struct rb_node *n;
-
-#ifdef CONFIG_KALLSYMS
-       unsigned long symsize;
-       const char *symname;
-       char *modname;
-       char *delim = ":";
-       char namebuf[128];
-#endif
-
-       buf += sprintf(buf, "<0x%08lx> ", address);
-
-#ifdef CONFIG_KALLSYMS
-       /* look up the address and see if we are in kernel space */
-       symname = kallsyms_lookup(address, &symsize, &offset, &modname, namebuf);
-
-       if (symname) {
-               /* yeah! kernel space! */
-               if (!modname)
-                       modname = delim = "";
-               sprintf(buf, "{ %s%s%s%s + 0x%lx }",
-                       delim, modname, delim, symname,
-                       (unsigned long)offset);
-               return;
-       }
-#endif
-
-       if (address >= FIXED_CODE_START && address < FIXED_CODE_END) {
-               /* Problem in fixed code section? */
-               strcat(buf, "/* Maybe fixed code section */");
-               return;
-
-       } else if (address < CONFIG_BOOT_LOAD) {
-               /* Problem somewhere before the kernel start address */
-               strcat(buf, "/* Maybe null pointer? */");
-               return;
-
-       } else if (address >= COREMMR_BASE) {
-               strcat(buf, "/* core mmrs */");
-               return;
-
-       } else if (address >= SYSMMR_BASE) {
-               strcat(buf, "/* system mmrs */");
-               return;
-
-       } else if (address >= L1_ROM_START && address < L1_ROM_START + L1_ROM_LENGTH) {
-               strcat(buf, "/* on-chip L1 ROM */");
-               return;
-       }
-
-       /*
-        * Don't walk any of the vmas if we are oopsing, it has been known
-        * to cause problems - corrupt vmas (kernel crashes) cause double faults
-        */
-       if (oops_in_progress) {
-               strcat(buf, "/* kernel dynamic memory (maybe user-space) */");
-               return;
-       }
-
-       /* looks like we're off in user-land, so let's walk all the
-        * mappings of all our processes and see if we can't be a whee
-        * bit more specific
-        */
-       write_lock_irqsave(&tasklist_lock, flags);
-       for_each_process(p) {
-               mm = (in_atomic ? p->mm : get_task_mm(p));
-               if (!mm)
-                       continue;
-
-               if (!down_read_trylock(&mm->mmap_sem)) {
-                       if (!in_atomic)
-                               mmput(mm);
-                       continue;
-               }
-
-               for (n = rb_first(&mm->mm_rb); n; n = rb_next(n)) {
-                       struct vm_area_struct *vma;
-
-                       vma = rb_entry(n, struct vm_area_struct, vm_rb);
-
-                       if (address >= vma->vm_start && address < vma->vm_end) {
-                               char _tmpbuf[256];
-                               char *name = p->comm;
-                               struct file *file = vma->vm_file;
-
-                               if (file) {
-                                       char *d_name = d_path(&file->f_path, _tmpbuf,
-                                                     sizeof(_tmpbuf));
-                                       if (!IS_ERR(d_name))
-                                               name = d_name;
-                               }
-
-                               /* FLAT does not have its text aligned to the start of
-                                * the map while FDPIC ELF does ...
-                                */
-
-                               /* before we can check flat/fdpic, we need to
-                                * make sure current is valid
-                                */
-                               if ((unsigned long)current >= FIXED_CODE_START &&
-                                   !((unsigned long)current & 0x3)) {
-                                       if (current->mm &&
-                                           (address > current->mm->start_code) &&
-                                           (address < current->mm->end_code))
-                                               offset = address - current->mm->start_code;
-                                       else
-                                               offset = (address - vma->vm_start) +
-                                                        (vma->vm_pgoff << PAGE_SHIFT);
-
-                                       sprintf(buf, "[ %s + 0x%lx ]", name, offset);
-                               } else
-                                       sprintf(buf, "[ %s vma:0x%lx-0x%lx]",
-                                               name, vma->vm_start, vma->vm_end);
-
-                               up_read(&mm->mmap_sem);
-                               if (!in_atomic)
-                                       mmput(mm);
-
-                               if (buf[0] == '\0')
-                                       sprintf(buf, "[ %s ] dynamic memory", name);
-
-                               goto done;
-                       }
-               }
-
-               up_read(&mm->mmap_sem);
-               if (!in_atomic)
-                       mmput(mm);
-       }
-
-       /*
-        * we were unable to find this address anywhere,
-        * or some MMs were skipped because they were in use.
-        */
-       sprintf(buf, "/* kernel dynamic memory */");
-
-done:
-       write_unlock_irqrestore(&tasklist_lock, flags);
-#else
-       sprintf(buf, " ");
-#endif
-}
-
-asmlinkage void double_fault_c(struct pt_regs *fp)
-{
-#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
-       int j;
-       trace_buffer_save(j);
-#endif
-
-       console_verbose();
-       oops_in_progress = 1;
-#ifdef CONFIG_DEBUG_VERBOSE
-       printk(KERN_EMERG "Double Fault\n");
-#ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT
-       if (((long)fp->seqstat &  SEQSTAT_EXCAUSE) == VEC_UNCOV) {
-               unsigned int cpu = raw_smp_processor_id();
-               char buf[150];
-               decode_address(buf, cpu_pda[cpu].retx_doublefault);
-               printk(KERN_EMERG "While handling exception (EXCAUSE = 0x%x) at %s:\n",
-                       (unsigned int)cpu_pda[cpu].seqstat_doublefault & SEQSTAT_EXCAUSE, buf);
-               decode_address(buf, cpu_pda[cpu].dcplb_doublefault_addr);
-               printk(KERN_NOTICE "   DCPLB_FAULT_ADDR: %s\n", buf);
-               decode_address(buf, cpu_pda[cpu].icplb_doublefault_addr);
-               printk(KERN_NOTICE "   ICPLB_FAULT_ADDR: %s\n", buf);
-
-               decode_address(buf, fp->retx);
-               printk(KERN_NOTICE "The instruction at %s caused a double exception\n", buf);
-       } else
-#endif
-       {
-               dump_bfin_process(fp);
-               dump_bfin_mem(fp);
-               show_regs(fp);
-               dump_bfin_trace_buffer();
-       }
-#endif
-       panic("Double Fault - unrecoverable event");
-
-}
-
 static int kernel_mode_regs(struct pt_regs *regs)
 {
        return regs->ipend & 0xffc0;
@@ -259,6 +68,9 @@ asmlinkage notrace void trap_c(struct pt_regs *fp)
 {
 #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
        int j;
+#endif
+#ifdef CONFIG_BFIN_PSEUDODBG_INSNS
+       int opcode;
 #endif
        unsigned int cpu = raw_smp_processor_id();
        const char *strerror = NULL;
@@ -391,6 +203,19 @@ asmlinkage notrace void trap_c(struct pt_regs *fp)
                                panic("BUG()");
                        }
                }
+#endif
+#ifdef CONFIG_BFIN_PSEUDODBG_INSNS
+               /*
+                * Support for the fake instructions, if the instruction fails,
+                * then just execute a illegal opcode failure (like normal).
+                * Don't support these instructions inside the kernel
+                */
+               if (!kernel_mode_regs(fp) && get_instruction(&opcode, (unsigned short *)fp->pc)) {
+                       if (execute_pseudodbg_assert(fp, opcode))
+                               goto traps_done;
+                       if (execute_pseudodbg(fp, opcode))
+                               goto traps_done;
+               }
 #endif
                info.si_code = ILL_ILLOPC;
                sig = SIGILL;
@@ -672,659 +497,44 @@ asmlinkage notrace void trap_c(struct pt_regs *fp)
        trace_buffer_restore(j);
 }
 
-/* Typical exception handling routines */
-
-#define EXPAND_LEN ((1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN) * 256 - 1)
-
-/*
- * Similar to get_user, do some address checking, then dereference
- * Return true on success, false on bad address
- */
-static bool get_instruction(unsigned short *val, unsigned short *address)
-{
-       unsigned long addr = (unsigned long)address;
-
-       /* Check for odd addresses */
-       if (addr & 0x1)
-               return false;
-
-       /* MMR region will never have instructions */
-       if (addr >= SYSMMR_BASE)
-               return false;
-
-       switch (bfin_mem_access_type(addr, 2)) {
-               case BFIN_MEM_ACCESS_CORE:
-               case BFIN_MEM_ACCESS_CORE_ONLY:
-                       *val = *address;
-                       return true;
-               case BFIN_MEM_ACCESS_DMA:
-                       dma_memcpy(val, address, 2);
-                       return true;
-               case BFIN_MEM_ACCESS_ITEST:
-                       isram_memcpy(val, address, 2);
-                       return true;
-               default: /* invalid access */
-                       return false;
-       }
-}
-
-/*
- * decode the instruction if we are printing out the trace, as it
- * makes things easier to follow, without running it through objdump
- * These are the normal instructions which cause change of flow, which
- * would be at the source of the trace buffer
- */
-#if defined(CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_BFIN_HWTRACE_ON)
-static void decode_instruction(unsigned short *address)
-{
-       unsigned short opcode;
-
-       if (get_instruction(&opcode, address)) {
-               if (opcode == 0x0010)
-                       verbose_printk("RTS");
-               else if (opcode == 0x0011)
-                       verbose_printk("RTI");
-               else if (opcode == 0x0012)
-                       verbose_printk("RTX");
-               else if (opcode == 0x0013)
-                       verbose_printk("RTN");
-               else if (opcode == 0x0014)
-                       verbose_printk("RTE");
-               else if (opcode == 0x0025)
-                       verbose_printk("EMUEXCPT");
-               else if (opcode >= 0x0040 && opcode <= 0x0047)
-                       verbose_printk("STI R%i", opcode & 7);
-               else if (opcode >= 0x0050 && opcode <= 0x0057)
-                       verbose_printk("JUMP (P%i)", opcode & 7);
-               else if (opcode >= 0x0060 && opcode <= 0x0067)
-                       verbose_printk("CALL (P%i)", opcode & 7);
-               else if (opcode >= 0x0070 && opcode <= 0x0077)
-                       verbose_printk("CALL (PC+P%i)", opcode & 7);
-               else if (opcode >= 0x0080 && opcode <= 0x0087)
-                       verbose_printk("JUMP (PC+P%i)", opcode & 7);
-               else if (opcode >= 0x0090 && opcode <= 0x009F)
-                       verbose_printk("RAISE 0x%x", opcode & 0xF);
-               else if (opcode >= 0x00A0 && opcode <= 0x00AF)
-                       verbose_printk("EXCPT 0x%x", opcode & 0xF);
-               else if ((opcode >= 0x1000 && opcode <= 0x13FF) || (opcode >= 0x1800 && opcode <= 0x1BFF))
-                       verbose_printk("IF !CC JUMP");
-               else if ((opcode >= 0x1400 && opcode <= 0x17ff) || (opcode >= 0x1c00 && opcode <= 0x1fff))
-                       verbose_printk("IF CC JUMP");
-               else if (opcode >= 0x2000 && opcode <= 0x2fff)
-                       verbose_printk("JUMP.S");
-               else if (opcode >= 0xe080 && opcode <= 0xe0ff)
-                       verbose_printk("LSETUP");
-               else if (opcode >= 0xe200 && opcode <= 0xe2ff)
-                       verbose_printk("JUMP.L");
-               else if (opcode >= 0xe300 && opcode <= 0xe3ff)
-                       verbose_printk("CALL pcrel");
-               else
-                       verbose_printk("0x%04x", opcode);
-       }
-
-}
-#endif
-
-void dump_bfin_trace_buffer(void)
-{
-#ifdef CONFIG_DEBUG_VERBOSE
-#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
-       int tflags, i = 0;
-       char buf[150];
-       unsigned short *addr;
-#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND
-       int j, index;
-#endif
-
-       trace_buffer_save(tflags);
-
-       printk(KERN_NOTICE "Hardware Trace:\n");
-
-#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND
-       printk(KERN_NOTICE "WARNING: Expanded trace turned on - can not trace exceptions\n");
-#endif
-
-       if (likely(bfin_read_TBUFSTAT() & TBUFCNT)) {
-               for (; bfin_read_TBUFSTAT() & TBUFCNT; i++) {
-                       decode_address(buf, (unsigned long)bfin_read_TBUF());
-                       printk(KERN_NOTICE "%4i Target : %s\n", i, buf);
-                       addr = (unsigned short *)bfin_read_TBUF();
-                       decode_address(buf, (unsigned long)addr);
-                       printk(KERN_NOTICE "     Source : %s ", buf);
-                       decode_instruction(addr);
-                       printk("\n");
-               }
-       }
-
-#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND
-       if (trace_buff_offset)
-               index = trace_buff_offset / 4;
-       else
-               index = EXPAND_LEN;
-
-       j = (1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN) * 128;
-       while (j) {
-               decode_address(buf, software_trace_buff[index]);
-               printk(KERN_NOTICE "%4i Target : %s\n", i, buf);
-               index -= 1;
-               if (index < 0 )
-                       index = EXPAND_LEN;
-               decode_address(buf, software_trace_buff[index]);
-               printk(KERN_NOTICE "     Source : %s ", buf);
-               decode_instruction((unsigned short *)software_trace_buff[index]);
-               printk("\n");
-               index -= 1;
-               if (index < 0)
-                       index = EXPAND_LEN;
-               j--;
-               i++;
-       }
-#endif
-
-       trace_buffer_restore(tflags);
-#endif
-#endif
-}
-EXPORT_SYMBOL(dump_bfin_trace_buffer);
-
-#ifdef CONFIG_BUG
-int is_valid_bugaddr(unsigned long addr)
-{
-       unsigned short opcode;
-
-       if (!get_instruction(&opcode, (unsigned short *)addr))
-               return 0;
-
-       return opcode == BFIN_BUG_OPCODE;
-}
-#endif
-
-/*
- * Checks to see if the address pointed to is either a
- * 16-bit CALL instruction, or a 32-bit CALL instruction
- */
-static bool is_bfin_call(unsigned short *addr)
-{
-       unsigned short opcode = 0, *ins_addr;
-       ins_addr = (unsigned short *)addr;
-
-       if (!get_instruction(&opcode, ins_addr))
-               return false;
-
-       if ((opcode >= 0x0060 && opcode <= 0x0067) ||
-           (opcode >= 0x0070 && opcode <= 0x0077))
-               return true;
-
-       ins_addr--;
-       if (!get_instruction(&opcode, ins_addr))
-               return false;
-
-       if (opcode >= 0xE300 && opcode <= 0xE3FF)
-               return true;
-
-       return false;
-
-}
-
-void show_stack(struct task_struct *task, unsigned long *stack)
-{
-#ifdef CONFIG_PRINTK
-       unsigned int *addr, *endstack, *fp = 0, *frame;
-       unsigned short *ins_addr;
-       char buf[150];
-       unsigned int i, j, ret_addr, frame_no = 0;
-
-       /*
-        * If we have been passed a specific stack, use that one otherwise
-        *    if we have been passed a task structure, use that, otherwise
-        *    use the stack of where the variable "stack" exists
-        */
-
-       if (stack == NULL) {
-               if (task) {
-                       /* We know this is a kernel stack, so this is the start/end */
-                       stack = (unsigned long *)task->thread.ksp;
-                       endstack = (unsigned int *)(((unsigned int)(stack) & ~(THREAD_SIZE - 1)) + THREAD_SIZE);
-               } else {
-                       /* print out the existing stack info */
-                       stack = (unsigned long *)&stack;
-                       endstack = (unsigned int *)PAGE_ALIGN((unsigned int)stack);
-               }
-       } else
-               endstack = (unsigned int *)PAGE_ALIGN((unsigned int)stack);
-
-       printk(KERN_NOTICE "Stack info:\n");
-       decode_address(buf, (unsigned int)stack);
-       printk(KERN_NOTICE " SP: [0x%p] %s\n", stack, buf);
-
-       if (!access_ok(VERIFY_READ, stack, (unsigned int)endstack - (unsigned int)stack)) {
-               printk(KERN_NOTICE "Invalid stack pointer\n");
-               return;
-       }
-
-       /* First thing is to look for a frame pointer */
-       for (addr = (unsigned int *)((unsigned int)stack & ~0xF); addr < endstack; addr++) {
-               if (*addr & 0x1)
-                       continue;
-               ins_addr = (unsigned short *)*addr;
-               ins_addr--;
-               if (is_bfin_call(ins_addr))
-                       fp = addr - 1;
-
-               if (fp) {
-                       /* Let's check to see if it is a frame pointer */
-                       while (fp >= (addr - 1) && fp < endstack
-                              && fp && ((unsigned int) fp & 0x3) == 0)
-                               fp = (unsigned int *)*fp;
-                       if (fp == 0 || fp == endstack) {
-                               fp = addr - 1;
-                               break;
-                       }
-                       fp = 0;
-               }
-       }
-       if (fp) {
-               frame = fp;
-               printk(KERN_NOTICE " FP: (0x%p)\n", fp);
-       } else
-               frame = 0;
-
-       /*
-        * Now that we think we know where things are, we
-        * walk the stack again, this time printing things out
-        * incase there is no frame pointer, we still look for
-        * valid return addresses
-        */
-
-       /* First time print out data, next time, print out symbols */
-       for (j = 0; j <= 1; j++) {
-               if (j)
-                       printk(KERN_NOTICE "Return addresses in stack:\n");
-               else
-                       printk(KERN_NOTICE " Memory from 0x%08lx to %p", ((long unsigned int)stack & ~0xF), endstack);
-
-               fp = frame;
-               frame_no = 0;
-
-               for (addr = (unsigned int *)((unsigned int)stack & ~0xF), i = 0;
-                    addr < endstack; addr++, i++) {
-
-                       ret_addr = 0;
-                       if (!j && i % 8 == 0)
-                               printk(KERN_NOTICE "%p:",addr);
-
-                       /* if it is an odd address, or zero, just skip it */
-                       if (*addr & 0x1 || !*addr)
-                               goto print;
-
-                       ins_addr = (unsigned short *)*addr;
-
-                       /* Go back one instruction, and see if it is a CALL */
-                       ins_addr--;
-                       ret_addr = is_bfin_call(ins_addr);
- print:
-                       if (!j && stack == (unsigned long *)addr)
-                               printk("[%08x]", *addr);
-                       else if (ret_addr)
-                               if (j) {
-                                       decode_address(buf, (unsigned int)*addr);
-                                       if (frame == addr) {
-                                               printk(KERN_NOTICE "   frame %2i : %s\n", frame_no, buf);
-                                               continue;
-                                       }
-                                       printk(KERN_NOTICE "    address : %s\n", buf);
-                               } else
-                                       printk("<%08x>", *addr);
-                       else if (fp == addr) {
-                               if (j)
-                                       frame = addr+1;
-                               else
-                                       printk("(%08x)", *addr);
-
-                               fp = (unsigned int *)*addr;
-                               frame_no++;
-
-                       } else if (!j)
-                               printk(" %08x ", *addr);
-               }
-               if (!j)
-                       printk("\n");
-       }
-#endif
-}
-EXPORT_SYMBOL(show_stack);
-
-void dump_stack(void)
+asmlinkage void double_fault_c(struct pt_regs *fp)
 {
-       unsigned long stack;
 #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
-       int tflags;
+       int j;
+       trace_buffer_save(j);
 #endif
-       trace_buffer_save(tflags);
-       dump_bfin_trace_buffer();
-       show_stack(current, &stack);
-       trace_buffer_restore(tflags);
-}
-EXPORT_SYMBOL(dump_stack);
 
-void dump_bfin_process(struct pt_regs *fp)
-{
+       console_verbose();
+       oops_in_progress = 1;
 #ifdef CONFIG_DEBUG_VERBOSE
-       /* We should be able to look at fp->ipend, but we don't push it on the
-        * stack all the time, so do this until we fix that */
-       unsigned int context = bfin_read_IPEND();
-
-       if (oops_in_progress)
-               verbose_printk(KERN_EMERG "Kernel OOPS in progress\n");
-
-       if (context & 0x0020 && (fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR)
-               verbose_printk(KERN_NOTICE "HW Error context\n");
-       else if (context & 0x0020)
-               verbose_printk(KERN_NOTICE "Deferred Exception context\n");
-       else if (context & 0x3FC0)
-               verbose_printk(KERN_NOTICE "Interrupt context\n");
-       else if (context & 0x4000)
-               verbose_printk(KERN_NOTICE "Deferred Interrupt context\n");
-       else if (context & 0x8000)
-               verbose_printk(KERN_NOTICE "Kernel process context\n");
-
-       /* Because we are crashing, and pointers could be bad, we check things
-        * pretty closely before we use them
-        */
-       if ((unsigned long)current >= FIXED_CODE_START &&
-           !((unsigned long)current & 0x3) && current->pid) {
-               verbose_printk(KERN_NOTICE "CURRENT PROCESS:\n");
-               if (current->comm >= (char *)FIXED_CODE_START)
-                       verbose_printk(KERN_NOTICE "COMM=%s PID=%d",
-                               current->comm, current->pid);
-               else
-                       verbose_printk(KERN_NOTICE "COMM= invalid");
+       printk(KERN_EMERG "Double Fault\n");
+#ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT
+       if (((long)fp->seqstat &  SEQSTAT_EXCAUSE) == VEC_UNCOV) {
+               unsigned int cpu = raw_smp_processor_id();
+               char buf[150];
+               decode_address(buf, cpu_pda[cpu].retx_doublefault);
+               printk(KERN_EMERG "While handling exception (EXCAUSE = 0x%x) at %s:\n",
+                       (unsigned int)cpu_pda[cpu].seqstat_doublefault & SEQSTAT_EXCAUSE, buf);
+               decode_address(buf, cpu_pda[cpu].dcplb_doublefault_addr);
+               printk(KERN_NOTICE "   DCPLB_FAULT_ADDR: %s\n", buf);
+               decode_address(buf, cpu_pda[cpu].icplb_doublefault_addr);
+               printk(KERN_NOTICE "   ICPLB_FAULT_ADDR: %s\n", buf);
 
-               printk(KERN_CONT " CPU=%d\n", current_thread_info()->cpu);
-               if (!((unsigned long)current->mm & 0x3) && (unsigned long)current->mm >= FIXED_CODE_START)
-                       verbose_printk(KERN_NOTICE
-                               "TEXT = 0x%p-0x%p        DATA = 0x%p-0x%p\n"
-                               " BSS = 0x%p-0x%p  USER-STACK = 0x%p\n\n",
-                               (void *)current->mm->start_code,
-                               (void *)current->mm->end_code,
-                               (void *)current->mm->start_data,
-                               (void *)current->mm->end_data,
-                               (void *)current->mm->end_data,
-                               (void *)current->mm->brk,
-                               (void *)current->mm->start_stack);
-               else
-                       verbose_printk(KERN_NOTICE "invalid mm\n");
+               decode_address(buf, fp->retx);
+               printk(KERN_NOTICE "The instruction at %s caused a double exception\n", buf);
        } else
-               verbose_printk(KERN_NOTICE
-                              "No Valid process in current context\n");
-#endif
-}
-
-void dump_bfin_mem(struct pt_regs *fp)
-{
-#ifdef CONFIG_DEBUG_VERBOSE
-       unsigned short *addr, *erraddr, val = 0, err = 0;
-       char sti = 0, buf[6];
-
-       erraddr = (void *)fp->pc;
-
-       verbose_printk(KERN_NOTICE "return address: [0x%p]; contents of:", erraddr);
-
-       for (addr = (unsigned short *)((unsigned long)erraddr & ~0xF) - 0x10;
-            addr < (unsigned short *)((unsigned long)erraddr & ~0xF) + 0x10;
-            addr++) {
-               if (!((unsigned long)addr & 0xF))
-                       verbose_printk(KERN_NOTICE "0x%p: ", addr);
-
-               if (!get_instruction(&val, addr)) {
-                               val = 0;
-                               sprintf(buf, "????");
-               } else
-                       sprintf(buf, "%04x", val);
-
-               if (addr == erraddr) {
-                       verbose_printk("[%s]", buf);
-                       err = val;
-               } else
-                       verbose_printk(" %s ", buf);
-
-               /* Do any previous instructions turn on interrupts? */
-               if (addr <= erraddr &&                          /* in the past */
-                   ((val >= 0x0040 && val <= 0x0047) ||        /* STI instruction */
-                     val == 0x017b))                           /* [SP++] = RETI */
-                       sti = 1;
-       }
-
-       verbose_printk("\n");
-
-       /* Hardware error interrupts can be deferred */
-       if (unlikely(sti && (fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR &&
-           oops_in_progress)){
-               verbose_printk(KERN_NOTICE "Looks like this was a deferred error - sorry\n");
-#ifndef CONFIG_DEBUG_HWERR
-               verbose_printk(KERN_NOTICE
-"The remaining message may be meaningless\n"
-"You should enable CONFIG_DEBUG_HWERR to get a better idea where it came from\n");
-#else
-               /* If we are handling only one peripheral interrupt
-                * and current mm and pid are valid, and the last error
-                * was in that user space process's text area
-                * print it out - because that is where the problem exists
-                */
-               if ((!(((fp)->ipend & ~0x30) & (((fp)->ipend & ~0x30) - 1))) &&
-                    (current->pid && current->mm)) {
-                       /* And the last RETI points to the current userspace context */
-                       if ((fp + 1)->pc >= current->mm->start_code &&
-                           (fp + 1)->pc <= current->mm->end_code) {
-                               verbose_printk(KERN_NOTICE "It might be better to look around here :\n");
-                               verbose_printk(KERN_NOTICE "-------------------------------------------\n");
-                               show_regs(fp + 1);
-                               verbose_printk(KERN_NOTICE "-------------------------------------------\n");
-                       }
-               }
-#endif
-       }
-#endif
-}
-
-void show_regs(struct pt_regs *fp)
-{
-#ifdef CONFIG_DEBUG_VERBOSE
-       char buf [150];
-       struct irqaction *action;
-       unsigned int i;
-       unsigned long flags = 0;
-       unsigned int cpu = raw_smp_processor_id();
-       unsigned char in_atomic = (bfin_read_IPEND() & 0x10) || in_atomic();
-
-       verbose_printk(KERN_NOTICE "\n");
-       if (CPUID != bfin_cpuid())
-               verbose_printk(KERN_NOTICE "Compiled for cpu family 0x%04x (Rev %d), "
-                       "but running on:0x%04x (Rev %d)\n",
-                       CPUID, bfin_compiled_revid(), bfin_cpuid(), bfin_revid());
-
-       verbose_printk(KERN_NOTICE "ADSP-%s-0.%d",
-               CPU, bfin_compiled_revid());
-
-       if (bfin_compiled_revid() !=  bfin_revid())
-               verbose_printk("(Detected 0.%d)", bfin_revid());
-
-       verbose_printk(" %lu(MHz CCLK) %lu(MHz SCLK) (%s)\n",
-               get_cclk()/1000000, get_sclk()/1000000,
-#ifdef CONFIG_MPU
-               "mpu on"
-#else
-               "mpu off"
-#endif
-               );
-
-       verbose_printk(KERN_NOTICE "%s", linux_banner);
-
-       verbose_printk(KERN_NOTICE "\nSEQUENCER STATUS:\t\t%s\n", print_tainted());
-       verbose_printk(KERN_NOTICE " SEQSTAT: %08lx  IPEND: %04lx  IMASK: %04lx  SYSCFG: %04lx\n",
-               (long)fp->seqstat, fp->ipend, cpu_pda[raw_smp_processor_id()].ex_imask, fp->syscfg);
-       if (fp->ipend & EVT_IRPTEN)
-               verbose_printk(KERN_NOTICE "  Global Interrupts Disabled (IPEND[4])\n");
-       if (!(cpu_pda[raw_smp_processor_id()].ex_imask & (EVT_IVG13 | EVT_IVG12 | EVT_IVG11 |
-                       EVT_IVG10 | EVT_IVG9 | EVT_IVG8 | EVT_IVG7 | EVT_IVTMR)))
-               verbose_printk(KERN_NOTICE "  Peripheral interrupts masked off\n");
-       if (!(cpu_pda[raw_smp_processor_id()].ex_imask & (EVT_IVG15 | EVT_IVG14)))
-               verbose_printk(KERN_NOTICE "  Kernel interrupts masked off\n");
-       if ((fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR) {
-               verbose_printk(KERN_NOTICE "  HWERRCAUSE: 0x%lx\n",
-                       (fp->seqstat & SEQSTAT_HWERRCAUSE) >> 14);
-#ifdef EBIU_ERRMST
-               /* If the error was from the EBIU, print it out */
-               if (bfin_read_EBIU_ERRMST() & CORE_ERROR) {
-                       verbose_printk(KERN_NOTICE "  EBIU Error Reason  : 0x%04x\n",
-                               bfin_read_EBIU_ERRMST());
-                       verbose_printk(KERN_NOTICE "  EBIU Error Address : 0x%08x\n",
-                               bfin_read_EBIU_ERRADD());
-               }
 #endif
+       {
+               dump_bfin_process(fp);
+               dump_bfin_mem(fp);
+               show_regs(fp);
+               dump_bfin_trace_buffer();
        }
-       verbose_printk(KERN_NOTICE "  EXCAUSE   : 0x%lx\n",
-               fp->seqstat & SEQSTAT_EXCAUSE);
-       for (i = 2; i <= 15 ; i++) {
-               if (fp->ipend & (1 << i)) {
-                       if (i != 4) {
-                               decode_address(buf, bfin_read32(EVT0 + 4*i));
-                               verbose_printk(KERN_NOTICE "  physical IVG%i asserted : %s\n", i, buf);
-                       } else
-                               verbose_printk(KERN_NOTICE "  interrupts disabled\n");
-               }
-       }
-
-       /* if no interrupts are going off, don't print this out */
-       if (fp->ipend & ~0x3F) {
-               for (i = 0; i < (NR_IRQS - 1); i++) {
-                       if (!in_atomic)
-                               raw_spin_lock_irqsave(&irq_desc[i].lock, flags);
-
-                       action = irq_desc[i].action;
-                       if (!action)
-                               goto unlock;
-
-                       decode_address(buf, (unsigned int)action->handler);
-                       verbose_printk(KERN_NOTICE "  logical irq %3d mapped  : %s", i, buf);
-                       for (action = action->next; action; action = action->next) {
-                               decode_address(buf, (unsigned int)action->handler);
-                               verbose_printk(", %s", buf);
-                       }
-                       verbose_printk("\n");
-unlock:
-                       if (!in_atomic)
-                               raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags);
-               }
-       }
-
-       decode_address(buf, fp->rete);
-       verbose_printk(KERN_NOTICE " RETE: %s\n", buf);
-       decode_address(buf, fp->retn);
-       verbose_printk(KERN_NOTICE " RETN: %s\n", buf);
-       decode_address(buf, fp->retx);
-       verbose_printk(KERN_NOTICE " RETX: %s\n", buf);
-       decode_address(buf, fp->rets);
-       verbose_printk(KERN_NOTICE " RETS: %s\n", buf);
-       decode_address(buf, fp->pc);
-       verbose_printk(KERN_NOTICE " PC  : %s\n", buf);
-
-       if (((long)fp->seqstat &  SEQSTAT_EXCAUSE) &&
-           (((long)fp->seqstat & SEQSTAT_EXCAUSE) != VEC_HWERR)) {
-               decode_address(buf, cpu_pda[cpu].dcplb_fault_addr);
-               verbose_printk(KERN_NOTICE "DCPLB_FAULT_ADDR: %s\n", buf);
-               decode_address(buf, cpu_pda[cpu].icplb_fault_addr);
-               verbose_printk(KERN_NOTICE "ICPLB_FAULT_ADDR: %s\n", buf);
-       }
-
-       verbose_printk(KERN_NOTICE "PROCESSOR STATE:\n");
-       verbose_printk(KERN_NOTICE " R0 : %08lx    R1 : %08lx    R2 : %08lx    R3 : %08lx\n",
-               fp->r0, fp->r1, fp->r2, fp->r3);
-       verbose_printk(KERN_NOTICE " R4 : %08lx    R5 : %08lx    R6 : %08lx    R7 : %08lx\n",
-               fp->r4, fp->r5, fp->r6, fp->r7);
-       verbose_printk(KERN_NOTICE " P0 : %08lx    P1 : %08lx    P2 : %08lx    P3 : %08lx\n",
-               fp->p0, fp->p1, fp->p2, fp->p3);
-       verbose_printk(KERN_NOTICE " P4 : %08lx    P5 : %08lx    FP : %08lx    SP : %08lx\n",
-               fp->p4, fp->p5, fp->fp, (long)fp);
-       verbose_printk(KERN_NOTICE " LB0: %08lx    LT0: %08lx    LC0: %08lx\n",
-               fp->lb0, fp->lt0, fp->lc0);
-       verbose_printk(KERN_NOTICE " LB1: %08lx    LT1: %08lx    LC1: %08lx\n",
-               fp->lb1, fp->lt1, fp->lc1);
-       verbose_printk(KERN_NOTICE " B0 : %08lx    L0 : %08lx    M0 : %08lx    I0 : %08lx\n",
-               fp->b0, fp->l0, fp->m0, fp->i0);
-       verbose_printk(KERN_NOTICE " B1 : %08lx    L1 : %08lx    M1 : %08lx    I1 : %08lx\n",
-               fp->b1, fp->l1, fp->m1, fp->i1);
-       verbose_printk(KERN_NOTICE " B2 : %08lx    L2 : %08lx    M2 : %08lx    I2 : %08lx\n",
-               fp->b2, fp->l2, fp->m2, fp->i2);
-       verbose_printk(KERN_NOTICE " B3 : %08lx    L3 : %08lx    M3 : %08lx    I3 : %08lx\n",
-               fp->b3, fp->l3, fp->m3, fp->i3);
-       verbose_printk(KERN_NOTICE "A0.w: %08lx   A0.x: %08lx   A1.w: %08lx   A1.x: %08lx\n",
-               fp->a0w, fp->a0x, fp->a1w, fp->a1x);
-
-       verbose_printk(KERN_NOTICE "USP : %08lx  ASTAT: %08lx\n",
-               rdusp(), fp->astat);
-
-       verbose_printk(KERN_NOTICE "\n");
 #endif
-}
-
-#ifdef CONFIG_SYS_BFIN_SPINLOCK_L1
-asmlinkage int sys_bfin_spinlock(int *spinlock)__attribute__((l1_text));
-#endif
-
-static DEFINE_SPINLOCK(bfin_spinlock_lock);
-
-asmlinkage int sys_bfin_spinlock(int *p)
-{
-       int ret, tmp = 0;
-
-       spin_lock(&bfin_spinlock_lock); /* This would also hold kernel preemption. */
-       ret = get_user(tmp, p);
-       if (likely(ret == 0)) {
-               if (unlikely(tmp))
-                       ret = 1;
-               else
-                       put_user(1, p);
-       }
-       spin_unlock(&bfin_spinlock_lock);
-       return ret;
-}
-
-int bfin_request_exception(unsigned int exception, void (*handler)(void))
-{
-       void (*curr_handler)(void);
-
-       if (exception > 0x3F)
-               return -EINVAL;
-
-       curr_handler = ex_table[exception];
-
-       if (curr_handler != ex_replaceable)
-               return -EBUSY;
-
-       ex_table[exception] = handler;
+       panic("Double Fault - unrecoverable event");
 
-       return 0;
 }
-EXPORT_SYMBOL(bfin_request_exception);
-
-int bfin_free_exception(unsigned int exception, void (*handler)(void))
-{
-       void (*curr_handler)(void);
-
-       if (exception > 0x3F)
-               return -EINVAL;
-
-       curr_handler = ex_table[exception];
 
-       if (curr_handler != handler)
-               return -EBUSY;
-
-       ex_table[exception] = ex_replaceable;
-
-       return 0;
-}
-EXPORT_SYMBOL(bfin_free_exception);
 
 void panic_cplb_error(int cplb_panic, struct pt_regs *fp)
 {
@@ -1349,3 +559,23 @@ void panic_cplb_error(int cplb_panic, struct pt_regs *fp)
        dump_stack();
        panic("Unrecoverable event");
 }
+
+#ifdef CONFIG_BUG
+int is_valid_bugaddr(unsigned long addr)
+{
+       unsigned int opcode;
+
+       if (!get_instruction(&opcode, (unsigned short *)addr))
+               return 0;
+
+       return opcode == BFIN_BUG_OPCODE;
+}
+#endif
+
+/* stub this out */
+#ifndef CONFIG_DEBUG_VERBOSE
+void show_regs(struct pt_regs *fp)
+{
+
+}
+#endif
index c30d99b109694bcee489a51acc808288a38f7b2b..eab1bef3f5bf37100c07a5d2de9868e2bc352004 100644 (file)
@@ -20,6 +20,7 @@
  * R1 = filler byte
  * R2 = count
  * Favours word aligned data.
+ * The strncpy assumes that I0 and I1 are not used in this function
  */
 
 ENTRY(_memset)
diff --git a/arch/blackfin/lib/strcmp.S b/arch/blackfin/lib/strcmp.S
new file mode 100644 (file)
index 0000000..d7c1d15
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2005-2010 Analog Devices Inc.
+ *
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
+ */
+
+#include <linux/linkage.h>
+
+/* void *strcmp(char *s1, const char *s2);
+ * R0 = address (s1)
+ * R1 = address (s2)
+ *
+ * Returns an integer less than, equal to, or greater than zero if s1
+ *  (or the first n  bytes thereof) is found, respectively, to be less
+ *  than, to match, or be greater than s2.
+ */
+
+#ifdef CONFIG_STRCMP_L1
+.section .l1.text
+#else
+.text
+#endif
+
+.align 2
+
+ENTRY(_strcmp)
+       P0 = R0 ;       /* s1 */
+       P1 = R1 ;       /* s2 */
+
+1:
+       R0 = B[P0++] (Z);      /* get *s1 */
+       R1 = B[P1++] (Z);      /* get *s2 */
+       CC = R0 == R1;         /* compare a byte */
+       if ! cc jump 2f;       /* not equal, break out */
+       CC = R0;               /* at end of s1? */
+       if cc jump 1b (bp);    /* no, keep going */
+       jump.s 3f;             /* strings are equal */
+2:
+       R0 = R0 - R1;          /* *s1 - *s2 */
+3:
+       RTS;
+
+ENDPROC(_strcmp)
diff --git a/arch/blackfin/lib/strcmp.c b/arch/blackfin/lib/strcmp.c
deleted file mode 100644 (file)
index fde39a1..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Provide symbol in case str func is not inlined.
- *
- * Copyright (c) 2006-2007 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#define strcmp __inline_strcmp
-#include <asm/string.h>
-#undef strcmp
-
-#include <linux/module.h>
-
-int strcmp(const char *dest, const char *src)
-{
-       return __inline_strcmp(dest, src);
-}
-EXPORT_SYMBOL(strcmp);
diff --git a/arch/blackfin/lib/strcpy.S b/arch/blackfin/lib/strcpy.S
new file mode 100644 (file)
index 0000000..a6a0c63
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2005-2010 Analog Devices Inc.
+ *
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
+ */
+
+#include <linux/linkage.h>
+
+/* void *strcpy(char *dest, const char *src);
+ * R0 = address (dest)
+ * R1 = address (src)
+ *
+ * Returns a pointer to the destination string dest
+ */
+
+#ifdef CONFIG_STRCPY_L1
+.section .l1.text
+#else
+.text
+#endif
+
+.align 2
+
+ENTRY(_strcpy)
+       P0 = R0 ;       /* dst*/
+       P1 = R1 ;       /* src*/
+
+1:
+       R1 = B [P1++] (Z);
+       B [P0++] = R1;
+       CC = R1;
+       if cc jump 1b (bp);
+       RTS;
+
+ENDPROC(_strcpy)
diff --git a/arch/blackfin/lib/strcpy.c b/arch/blackfin/lib/strcpy.c
deleted file mode 100644 (file)
index 2a8836b..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Provide symbol in case str func is not inlined.
- *
- * Copyright (c) 2006-2007 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#define strcpy __inline_strcpy
-#include <asm/string.h>
-#undef strcpy
-
-#include <linux/module.h>
-
-char *strcpy(char *dest, const char *src)
-{
-       return __inline_strcpy(dest, src);
-}
-EXPORT_SYMBOL(strcpy);
diff --git a/arch/blackfin/lib/strncmp.S b/arch/blackfin/lib/strncmp.S
new file mode 100644 (file)
index 0000000..6da37c3
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2005-2010 Analog Devices Inc.
+ *
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
+ */
+
+#include <linux/linkage.h>
+
+/* void *strncpy(char *s1, const char *s2, size_t n);
+ * R0 = address (dest)
+ * R1 = address (src)
+ * R2 = size (n)
+ * Returns a pointer to the destination string dest
+ */
+
+#ifdef CONFIG_STRNCMP_L1
+.section .l1.text
+#else
+.text
+#endif
+
+.align 2
+
+ENTRY(_strncmp)
+       CC = R2 == 0;
+       if CC JUMP 5f;
+
+       P0 = R0 ;       /* s1 */
+       P1 = R1 ;       /* s2 */
+1:
+       R0 = B[P0++] (Z);      /* get *s1 */
+       R1 = B[P1++] (Z);      /* get *s2 */
+       CC = R0 == R1;         /* compare a byte */
+       if ! cc jump 3f;       /* not equal, break out */
+       CC = R0;               /* at end of s1? */
+       if ! cc jump 4f;       /* yes, all done */
+       R2 += -1;              /* no, adjust count */
+       CC = R2 == 0;
+       if ! cc jump 1b (bp);  /* more to do, keep going */
+2:
+       R0 = 0;                /* strings are equal */
+       jump.s 4f;
+3:
+       R0 = R0 - R1;          /* *s1 - *s2 */
+4:
+       RTS;
+
+5:
+       R0 = 0;
+       RTS;
+
+ENDPROC(_strncmp)
diff --git a/arch/blackfin/lib/strncmp.c b/arch/blackfin/lib/strncmp.c
deleted file mode 100644 (file)
index 46518b1..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Provide symbol in case str func is not inlined.
- *
- * Copyright (c) 2006-2007 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#define strncmp __inline_strncmp
-#include <asm/string.h>
-#include <linux/module.h>
-#undef strncmp
-
-int strncmp(const char *cs, const char *ct, size_t count)
-{
-       return __inline_strncmp(cs, ct, count);
-}
-EXPORT_SYMBOL(strncmp);
diff --git a/arch/blackfin/lib/strncpy.S b/arch/blackfin/lib/strncpy.S
new file mode 100644 (file)
index 0000000..f3931d5
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2005-2010 Analog Devices Inc.
+ *
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
+ */
+
+#include <linux/linkage.h>
+#include <asm/context.S>
+
+/* void *strncpy(char *dest, const char *src, size_t n);
+ * R0 = address (dest)
+ * R1 = address (src)
+ * R2 = size
+ * Returns a pointer (R0) to the destination string dest
+ *  we do this by not changing R0
+ */
+
+#ifdef CONFIG_STRNCPY_L1
+.section .l1.text
+#else
+.text
+#endif
+
+.align 2
+
+ENTRY(_strncpy)
+       CC = R2 == 0;
+       if CC JUMP 4f;
+
+       P2 = R2 ;       /* size */
+       P0 = R0 ;       /* dst*/
+       P1 = R1 ;       /* src*/
+
+       LSETUP (1f, 2f) LC0 = P2;
+1:
+       R1 = B [P1++] (Z);
+       B [P0++] = R1;
+       CC = R1 == 0;
+2:
+       if CC jump 3f;
+
+       RTS;
+
+       /* if src is shorter than n, we need to null pad bytes in dest
+        * but, we can get here when the last byte is zero, and we don't
+        * want to copy an extra byte at the end, so we need to check
+        */
+3:
+       R2 = LC0;
+       CC = R2
+       if ! CC jump 6f;
+
+       /* if the required null padded portion is small, do it here, rather than
+        * handling the overhead of memset (which is OK when things are big).
+        */
+       R3 = 0x20;
+       CC = R2 < R3;
+       IF CC jump 4f;
+
+       R2 += -1;
+
+       /* Set things up for memset
+        * R0 = address
+        * R1 = filler byte (this case it's zero, set above)
+        * R2 = count (set above)
+        */
+
+       I1 = R0;
+       R0 = RETS;
+       I0 = R0;
+       R0 = P0;
+       pseudo_long_call _memset, p0;
+       R0 = I0;
+       RETS = R0;
+       R0 = I1;
+       RTS;
+
+4:
+       LSETUP(5f, 5f) LC0;
+5:
+       B [P0++] = R1;
+6:
+       RTS;
+
+ENDPROC(_strncpy)
diff --git a/arch/blackfin/lib/strncpy.c b/arch/blackfin/lib/strncpy.c
deleted file mode 100644 (file)
index ea1dc6b..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Provide symbol in case str func is not inlined.
- *
- * Copyright (c) 2006-2007 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#define strncpy __inline_strncpy
-#include <asm/string.h>
-#undef strncpy
-
-#include <linux/module.h>
-
-char *strncpy(char *dest, const char *src, size_t n)
-{
-       return __inline_strncpy(dest, src, n);
-}
-EXPORT_SYMBOL(strncpy);
index ebe76d1e874aabbb183bf6fe43dd948c1360431b..f392af641657d78f5be0294cc162c4c294c4f5d2 100644 (file)
@@ -98,6 +98,10 @@ static struct musb_hdrc_config musb_config = {
        .num_eps        = 8,
        .dma_channels   = 8,
        .gpio_vrsel     = GPIO_PF11,
+       /* Some custom boards need to be active low, just set it to "0"
+        * if it is the case.
+        */
+       .gpio_vrsel_active      = 1,
 };
 
 static struct musb_hdrc_platform_data musb_plat = {
index 55069af4f67dd88b69230c659e67c8b821713de0..606eb36b9d6ea2ce31d9d9082d0c8de9ac5512d4 100644 (file)
@@ -62,6 +62,10 @@ static struct musb_hdrc_config musb_config = {
        .num_eps        = 8,
        .dma_channels   = 8,
        .gpio_vrsel     = GPIO_PG13,
+       /* Some custom boards need to be active low, just set it to "0"
+        * if it is the case.
+        */
+       .gpio_vrsel_active      = 1,
 };
 
 static struct musb_hdrc_platform_data musb_plat = {
index 923383386aa18cee70cd86efb4db19fe5017e8a1..a05c967a24cfc22046fde2709da087a6c30bfef1 100644 (file)
@@ -102,6 +102,10 @@ static struct musb_hdrc_config musb_config = {
        .num_eps        = 8,
        .dma_channels   = 8,
        .gpio_vrsel     = GPIO_PG13,
+       /* Some custom boards need to be active low, just set it to "0"
+        * if it is the case.
+        */
+       .gpio_vrsel_active      = 1,
 };
 
 static struct musb_hdrc_platform_data musb_plat = {
index c489d602c59013036d1bb0b546fd208d6773091a..05d45994480eaf8b2dae60ae59aeb439b2ebb05b 100644 (file)
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/reboot.h>
+#include <asm/portmux.h>
 #include <linux/spi/ad7877.h>
 
 /*
  * Name the Board for the /proc/cpuinfo
  */
-char *bfin_board_name = "CamSig Minotaur BF537";
+const char bfin_board_name[] = "CamSig Minotaur BF537";
 
 #if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
 static struct resource bfin_pcmcia_cf_resources[] = {
index 066d5c261f47e3a34def90192dadc06c582de7ed..cf396ea40092a010344554f469a418160b37a1e0 100644 (file)
 #define        RCV_HALF        0x0004  /*              Receive FIFO Has 1 Byte To Read                 */
 #define        RCV_FULL        0x000C  /*              Receive FIFO Full (2 Bytes To Read)             */
 
-/* ************  CONTROLLER AREA NETWORK (CAN) MASKS  ***************/
-/* CAN_CONTROL Masks                                                                                           */
-#define        SRS                     0x0001  /* Software Reset                                               */
-#define        DNM                     0x0002  /* Device Net Mode                                              */
-#define        ABO                     0x0004  /* Auto-Bus On Enable                                   */
-#define        TXPRIO          0x0008  /* TX Priority (Priority/Mailbox*)              */
-#define        WBA                     0x0010  /* Wake-Up On CAN Bus Activity Enable   */
-#define        SMR                     0x0020  /* Sleep Mode Request                                   */
-#define        CSR                     0x0040  /* CAN Suspend Mode Request                             */
-#define        CCR                     0x0080  /* CAN Configuration Mode Request               */
-
-/* CAN_STATUS Masks                                                                                            */
-#define        WT                      0x0001  /* TX Warning Flag                                      */
-#define        WR                      0x0002  /* RX Warning Flag                                      */
-#define        EP                      0x0004  /* Error Passive Mode                           */
-#define        EBO                     0x0008  /* Error Bus Off Mode                           */
-#define        SMA                     0x0020  /* Sleep Mode Acknowledge                       */
-#define        CSA                     0x0040  /* Suspend Mode Acknowledge                     */
-#define        CCA                     0x0080  /* Configuration Mode Acknowledge       */
-#define        MBPTR           0x1F00  /* Mailbox Pointer                                      */
-#define        TRM                     0x4000  /* Transmit Mode                                        */
-#define        REC                     0x8000  /* Receive Mode                                         */
-
-/* CAN_CLOCK Masks                                                                     */
-#define        BRP                     0x03FF  /* Bit-Rate Pre-Scaler  */
-
-/* CAN_TIMING Masks                                                                                    */
-#define        TSEG1           0x000F  /* Time Segment 1                               */
-#define        TSEG2           0x0070  /* Time Segment 2                               */
-#define        SAM                     0x0080  /* Sampling                                             */
-#define        SJW                     0x0300  /* Synchronization Jump Width   */
-
-/* CAN_DEBUG Masks                                                                                     */
-#define        DEC                     0x0001  /* Disable CAN Error Counters   */
-#define        DRI                     0x0002  /* Disable CAN RX Input                 */
-#define        DTO                     0x0004  /* Disable CAN TX Output                */
-#define        DIL                     0x0008  /* Disable CAN Internal Loop    */
-#define        MAA                     0x0010  /* Mode Auto-Acknowledge Enable */
-#define        MRB                     0x0020  /* Mode Read Back Enable                */
-#define        CDE                     0x8000  /* CAN Debug Enable                             */
-
-/* CAN_CEC Masks                                                                               */
-#define        RXECNT          0x00FF  /* Receive Error Counter        */
-#define        TXECNT          0xFF00  /* Transmit Error Counter       */
-
-/* CAN_INTR Masks                                                                                      */
-#define        MBRIRQ  0x0001  /* Mailbox Receive Interrupt    */
-#define        MBRIF           MBRIRQ  /* legacy */
-#define        MBTIRQ  0x0002  /* Mailbox Transmit Interrupt   */
-#define        MBTIF           MBTIRQ  /* legacy */
-#define        GIRQ            0x0004  /* Global Interrupt                             */
-#define        SMACK           0x0008  /* Sleep Mode Acknowledge               */
-#define        CANTX           0x0040  /* CAN TX Bus Value                             */
-#define        CANRX           0x0080  /* CAN RX Bus Value                             */
-
-/* CAN_MBxx_ID1 and CAN_MBxx_ID0 Masks                                                                         */
-#define DFC                    0xFFFF  /* Data Filtering Code (If Enabled) (ID0)               */
-#define        EXTID_LO        0xFFFF  /* Lower 16 Bits of Extended Identifier (ID0)   */
-#define        EXTID_HI        0x0003  /* Upper 2 Bits of Extended Identifier (ID1)    */
-#define        BASEID          0x1FFC  /* Base Identifier                                                              */
-#define        IDE                     0x2000  /* Identifier Extension                                                 */
-#define        RTR                     0x4000  /* Remote Frame Transmission Request                    */
-#define        AME                     0x8000  /* Acceptance Mask Enable                                               */
-
-/* CAN_MBxx_TIMESTAMP Masks                                    */
-#define TSV                    0xFFFF  /* Timestamp    */
-
-/* CAN_MBxx_LENGTH Masks                                               */
-#define DLC                    0x000F  /* Data Length Code     */
-
-/* CAN_AMxxH and CAN_AMxxL Masks                                                                                               */
-#define DFM                    0xFFFF  /* Data Field Mask (If Enabled) (CAN_AMxxL)                     */
-#define        EXTID_LO        0xFFFF  /* Lower 16 Bits of Extended Identifier (CAN_AMxxL)     */
-#define        EXTID_HI        0x0003  /* Upper 2 Bits of Extended Identifier (CAN_AMxxH)      */
-#define        BASEID          0x1FFC  /* Base Identifier                                                                      */
-#define        AMIDE           0x2000  /* Acceptance Mask ID Extension Enable                          */
-#define        FMD                     0x4000  /* Full Mask Data Field Enable                                          */
-#define        FDF                     0x8000  /* Filter On Data Field Enable                                          */
-
-/* CAN_MC1 Masks                                                                       */
-#define        MC0                     0x0001  /* Enable Mailbox 0             */
-#define        MC1                     0x0002  /* Enable Mailbox 1             */
-#define        MC2                     0x0004  /* Enable Mailbox 2             */
-#define        MC3                     0x0008  /* Enable Mailbox 3             */
-#define        MC4                     0x0010  /* Enable Mailbox 4             */
-#define        MC5                     0x0020  /* Enable Mailbox 5             */
-#define        MC6                     0x0040  /* Enable Mailbox 6             */
-#define        MC7                     0x0080  /* Enable Mailbox 7             */
-#define        MC8                     0x0100  /* Enable Mailbox 8             */
-#define        MC9                     0x0200  /* Enable Mailbox 9             */
-#define        MC10            0x0400  /* Enable Mailbox 10    */
-#define        MC11            0x0800  /* Enable Mailbox 11    */
-#define        MC12            0x1000  /* Enable Mailbox 12    */
-#define        MC13            0x2000  /* Enable Mailbox 13    */
-#define        MC14            0x4000  /* Enable Mailbox 14    */
-#define        MC15            0x8000  /* Enable Mailbox 15    */
-
-/* CAN_MC2 Masks                                                                       */
-#define        MC16            0x0001  /* Enable Mailbox 16    */
-#define        MC17            0x0002  /* Enable Mailbox 17    */
-#define        MC18            0x0004  /* Enable Mailbox 18    */
-#define        MC19            0x0008  /* Enable Mailbox 19    */
-#define        MC20            0x0010  /* Enable Mailbox 20    */
-#define        MC21            0x0020  /* Enable Mailbox 21    */
-#define        MC22            0x0040  /* Enable Mailbox 22    */
-#define        MC23            0x0080  /* Enable Mailbox 23    */
-#define        MC24            0x0100  /* Enable Mailbox 24    */
-#define        MC25            0x0200  /* Enable Mailbox 25    */
-#define        MC26            0x0400  /* Enable Mailbox 26    */
-#define        MC27            0x0800  /* Enable Mailbox 27    */
-#define        MC28            0x1000  /* Enable Mailbox 28    */
-#define        MC29            0x2000  /* Enable Mailbox 29    */
-#define        MC30            0x4000  /* Enable Mailbox 30    */
-#define        MC31            0x8000  /* Enable Mailbox 31    */
-
-/* CAN_MD1 Masks                                                                                               */
-#define        MD0                     0x0001  /* Enable Mailbox 0 For Receive         */
-#define        MD1                     0x0002  /* Enable Mailbox 1 For Receive         */
-#define        MD2                     0x0004  /* Enable Mailbox 2 For Receive         */
-#define        MD3                     0x0008  /* Enable Mailbox 3 For Receive         */
-#define        MD4                     0x0010  /* Enable Mailbox 4 For Receive         */
-#define        MD5                     0x0020  /* Enable Mailbox 5 For Receive         */
-#define        MD6                     0x0040  /* Enable Mailbox 6 For Receive         */
-#define        MD7                     0x0080  /* Enable Mailbox 7 For Receive         */
-#define        MD8                     0x0100  /* Enable Mailbox 8 For Receive         */
-#define        MD9                     0x0200  /* Enable Mailbox 9 For Receive         */
-#define        MD10            0x0400  /* Enable Mailbox 10 For Receive        */
-#define        MD11            0x0800  /* Enable Mailbox 11 For Receive        */
-#define        MD12            0x1000  /* Enable Mailbox 12 For Receive        */
-#define        MD13            0x2000  /* Enable Mailbox 13 For Receive        */
-#define        MD14            0x4000  /* Enable Mailbox 14 For Receive        */
-#define        MD15            0x8000  /* Enable Mailbox 15 For Receive        */
-
-/* CAN_MD2 Masks                                                                                               */
-#define        MD16            0x0001  /* Enable Mailbox 16 For Receive        */
-#define        MD17            0x0002  /* Enable Mailbox 17 For Receive        */
-#define        MD18            0x0004  /* Enable Mailbox 18 For Receive        */
-#define        MD19            0x0008  /* Enable Mailbox 19 For Receive        */
-#define        MD20            0x0010  /* Enable Mailbox 20 For Receive        */
-#define        MD21            0x0020  /* Enable Mailbox 21 For Receive        */
-#define        MD22            0x0040  /* Enable Mailbox 22 For Receive        */
-#define        MD23            0x0080  /* Enable Mailbox 23 For Receive        */
-#define        MD24            0x0100  /* Enable Mailbox 24 For Receive        */
-#define        MD25            0x0200  /* Enable Mailbox 25 For Receive        */
-#define        MD26            0x0400  /* Enable Mailbox 26 For Receive        */
-#define        MD27            0x0800  /* Enable Mailbox 27 For Receive        */
-#define        MD28            0x1000  /* Enable Mailbox 28 For Receive        */
-#define        MD29            0x2000  /* Enable Mailbox 29 For Receive        */
-#define        MD30            0x4000  /* Enable Mailbox 30 For Receive        */
-#define        MD31            0x8000  /* Enable Mailbox 31 For Receive        */
-
-/* CAN_RMP1 Masks                                                                                              */
-#define        RMP0            0x0001  /* RX Message Pending In Mailbox 0      */
-#define        RMP1            0x0002  /* RX Message Pending In Mailbox 1      */
-#define        RMP2            0x0004  /* RX Message Pending In Mailbox 2      */
-#define        RMP3            0x0008  /* RX Message Pending In Mailbox 3      */
-#define        RMP4            0x0010  /* RX Message Pending In Mailbox 4      */
-#define        RMP5            0x0020  /* RX Message Pending In Mailbox 5      */
-#define        RMP6            0x0040  /* RX Message Pending In Mailbox 6      */
-#define        RMP7            0x0080  /* RX Message Pending In Mailbox 7      */
-#define        RMP8            0x0100  /* RX Message Pending In Mailbox 8      */
-#define        RMP9            0x0200  /* RX Message Pending In Mailbox 9      */
-#define        RMP10           0x0400  /* RX Message Pending In Mailbox 10     */
-#define        RMP11           0x0800  /* RX Message Pending In Mailbox 11     */
-#define        RMP12           0x1000  /* RX Message Pending In Mailbox 12     */
-#define        RMP13           0x2000  /* RX Message Pending In Mailbox 13     */
-#define        RMP14           0x4000  /* RX Message Pending In Mailbox 14     */
-#define        RMP15           0x8000  /* RX Message Pending In Mailbox 15     */
-
-/* CAN_RMP2 Masks                                                                                              */
-#define        RMP16           0x0001  /* RX Message Pending In Mailbox 16     */
-#define        RMP17           0x0002  /* RX Message Pending In Mailbox 17     */
-#define        RMP18           0x0004  /* RX Message Pending In Mailbox 18     */
-#define        RMP19           0x0008  /* RX Message Pending In Mailbox 19     */
-#define        RMP20           0x0010  /* RX Message Pending In Mailbox 20     */
-#define        RMP21           0x0020  /* RX Message Pending In Mailbox 21     */
-#define        RMP22           0x0040  /* RX Message Pending In Mailbox 22     */
-#define        RMP23           0x0080  /* RX Message Pending In Mailbox 23     */
-#define        RMP24           0x0100  /* RX Message Pending In Mailbox 24     */
-#define        RMP25           0x0200  /* RX Message Pending In Mailbox 25     */
-#define        RMP26           0x0400  /* RX Message Pending In Mailbox 26     */
-#define        RMP27           0x0800  /* RX Message Pending In Mailbox 27     */
-#define        RMP28           0x1000  /* RX Message Pending In Mailbox 28     */
-#define        RMP29           0x2000  /* RX Message Pending In Mailbox 29     */
-#define        RMP30           0x4000  /* RX Message Pending In Mailbox 30     */
-#define        RMP31           0x8000  /* RX Message Pending In Mailbox 31     */
-
-/* CAN_RML1 Masks                                                                                              */
-#define        RML0            0x0001  /* RX Message Lost In Mailbox 0         */
-#define        RML1            0x0002  /* RX Message Lost In Mailbox 1         */
-#define        RML2            0x0004  /* RX Message Lost In Mailbox 2         */
-#define        RML3            0x0008  /* RX Message Lost In Mailbox 3         */
-#define        RML4            0x0010  /* RX Message Lost In Mailbox 4         */
-#define        RML5            0x0020  /* RX Message Lost In Mailbox 5         */
-#define        RML6            0x0040  /* RX Message Lost In Mailbox 6         */
-#define        RML7            0x0080  /* RX Message Lost In Mailbox 7         */
-#define        RML8            0x0100  /* RX Message Lost In Mailbox 8         */
-#define        RML9            0x0200  /* RX Message Lost In Mailbox 9         */
-#define        RML10           0x0400  /* RX Message Lost In Mailbox 10        */
-#define        RML11           0x0800  /* RX Message Lost In Mailbox 11        */
-#define        RML12           0x1000  /* RX Message Lost In Mailbox 12        */
-#define        RML13           0x2000  /* RX Message Lost In Mailbox 13        */
-#define        RML14           0x4000  /* RX Message Lost In Mailbox 14        */
-#define        RML15           0x8000  /* RX Message Lost In Mailbox 15        */
-
-/* CAN_RML2 Masks                                                                                              */
-#define        RML16           0x0001  /* RX Message Lost In Mailbox 16        */
-#define        RML17           0x0002  /* RX Message Lost In Mailbox 17        */
-#define        RML18           0x0004  /* RX Message Lost In Mailbox 18        */
-#define        RML19           0x0008  /* RX Message Lost In Mailbox 19        */
-#define        RML20           0x0010  /* RX Message Lost In Mailbox 20        */
-#define        RML21           0x0020  /* RX Message Lost In Mailbox 21        */
-#define        RML22           0x0040  /* RX Message Lost In Mailbox 22        */
-#define        RML23           0x0080  /* RX Message Lost In Mailbox 23        */
-#define        RML24           0x0100  /* RX Message Lost In Mailbox 24        */
-#define        RML25           0x0200  /* RX Message Lost In Mailbox 25        */
-#define        RML26           0x0400  /* RX Message Lost In Mailbox 26        */
-#define        RML27           0x0800  /* RX Message Lost In Mailbox 27        */
-#define        RML28           0x1000  /* RX Message Lost In Mailbox 28        */
-#define        RML29           0x2000  /* RX Message Lost In Mailbox 29        */
-#define        RML30           0x4000  /* RX Message Lost In Mailbox 30        */
-#define        RML31           0x8000  /* RX Message Lost In Mailbox 31        */
-
-/* CAN_OPSS1 Masks                                                                                                                                                             */
-#define        OPSS0           0x0001  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 0       */
-#define        OPSS1           0x0002  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 1       */
-#define        OPSS2           0x0004  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 2       */
-#define        OPSS3           0x0008  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 3       */
-#define        OPSS4           0x0010  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 4       */
-#define        OPSS5           0x0020  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 5       */
-#define        OPSS6           0x0040  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 6       */
-#define        OPSS7           0x0080  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 7       */
-#define        OPSS8           0x0100  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 8       */
-#define        OPSS9           0x0200  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 9       */
-#define        OPSS10          0x0400  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 10      */
-#define        OPSS11          0x0800  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 11      */
-#define        OPSS12          0x1000  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 12      */
-#define        OPSS13          0x2000  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 13      */
-#define        OPSS14          0x4000  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 14      */
-#define        OPSS15          0x8000  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 15      */
-
-/* CAN_OPSS2 Masks                                                                                                                                                             */
-#define        OPSS16          0x0001  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 16      */
-#define        OPSS17          0x0002  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 17      */
-#define        OPSS18          0x0004  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 18      */
-#define        OPSS19          0x0008  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 19      */
-#define        OPSS20          0x0010  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 20      */
-#define        OPSS21          0x0020  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 21      */
-#define        OPSS22          0x0040  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 22      */
-#define        OPSS23          0x0080  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 23      */
-#define        OPSS24          0x0100  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 24      */
-#define        OPSS25          0x0200  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 25      */
-#define        OPSS26          0x0400  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 26      */
-#define        OPSS27          0x0800  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 27      */
-#define        OPSS28          0x1000  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 28      */
-#define        OPSS29          0x2000  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 29      */
-#define        OPSS30          0x4000  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 30      */
-#define        OPSS31          0x8000  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 31      */
-
-/* CAN_TRR1 Masks                                                                                                              */
-#define        TRR0            0x0001  /* Deny But Don't Lock Access To Mailbox 0      */
-#define        TRR1            0x0002  /* Deny But Don't Lock Access To Mailbox 1      */
-#define        TRR2            0x0004  /* Deny But Don't Lock Access To Mailbox 2      */
-#define        TRR3            0x0008  /* Deny But Don't Lock Access To Mailbox 3      */
-#define        TRR4            0x0010  /* Deny But Don't Lock Access To Mailbox 4      */
-#define        TRR5            0x0020  /* Deny But Don't Lock Access To Mailbox 5      */
-#define        TRR6            0x0040  /* Deny But Don't Lock Access To Mailbox 6      */
-#define        TRR7            0x0080  /* Deny But Don't Lock Access To Mailbox 7      */
-#define        TRR8            0x0100  /* Deny But Don't Lock Access To Mailbox 8      */
-#define        TRR9            0x0200  /* Deny But Don't Lock Access To Mailbox 9      */
-#define        TRR10           0x0400  /* Deny But Don't Lock Access To Mailbox 10     */
-#define        TRR11           0x0800  /* Deny But Don't Lock Access To Mailbox 11     */
-#define        TRR12           0x1000  /* Deny But Don't Lock Access To Mailbox 12     */
-#define        TRR13           0x2000  /* Deny But Don't Lock Access To Mailbox 13     */
-#define        TRR14           0x4000  /* Deny But Don't Lock Access To Mailbox 14     */
-#define        TRR15           0x8000  /* Deny But Don't Lock Access To Mailbox 15     */
-
-/* CAN_TRR2 Masks                                                                                                              */
-#define        TRR16           0x0001  /* Deny But Don't Lock Access To Mailbox 16     */
-#define        TRR17           0x0002  /* Deny But Don't Lock Access To Mailbox 17     */
-#define        TRR18           0x0004  /* Deny But Don't Lock Access To Mailbox 18     */
-#define        TRR19           0x0008  /* Deny But Don't Lock Access To Mailbox 19     */
-#define        TRR20           0x0010  /* Deny But Don't Lock Access To Mailbox 20     */
-#define        TRR21           0x0020  /* Deny But Don't Lock Access To Mailbox 21     */
-#define        TRR22           0x0040  /* Deny But Don't Lock Access To Mailbox 22     */
-#define        TRR23           0x0080  /* Deny But Don't Lock Access To Mailbox 23     */
-#define        TRR24           0x0100  /* Deny But Don't Lock Access To Mailbox 24     */
-#define        TRR25           0x0200  /* Deny But Don't Lock Access To Mailbox 25     */
-#define        TRR26           0x0400  /* Deny But Don't Lock Access To Mailbox 26     */
-#define        TRR27           0x0800  /* Deny But Don't Lock Access To Mailbox 27     */
-#define        TRR28           0x1000  /* Deny But Don't Lock Access To Mailbox 28     */
-#define        TRR29           0x2000  /* Deny But Don't Lock Access To Mailbox 29     */
-#define        TRR30           0x4000  /* Deny But Don't Lock Access To Mailbox 30     */
-#define        TRR31           0x8000  /* Deny But Don't Lock Access To Mailbox 31     */
-
-/* CAN_TRS1 Masks                                                                                                      */
-#define        TRS0            0x0001  /* Remote Frame Request For Mailbox 0   */
-#define        TRS1            0x0002  /* Remote Frame Request For Mailbox 1   */
-#define        TRS2            0x0004  /* Remote Frame Request For Mailbox 2   */
-#define        TRS3            0x0008  /* Remote Frame Request For Mailbox 3   */
-#define        TRS4            0x0010  /* Remote Frame Request For Mailbox 4   */
-#define        TRS5            0x0020  /* Remote Frame Request For Mailbox 5   */
-#define        TRS6            0x0040  /* Remote Frame Request For Mailbox 6   */
-#define        TRS7            0x0080  /* Remote Frame Request For Mailbox 7   */
-#define        TRS8            0x0100  /* Remote Frame Request For Mailbox 8   */
-#define        TRS9            0x0200  /* Remote Frame Request For Mailbox 9   */
-#define        TRS10           0x0400  /* Remote Frame Request For Mailbox 10  */
-#define        TRS11           0x0800  /* Remote Frame Request For Mailbox 11  */
-#define        TRS12           0x1000  /* Remote Frame Request For Mailbox 12  */
-#define        TRS13           0x2000  /* Remote Frame Request For Mailbox 13  */
-#define        TRS14           0x4000  /* Remote Frame Request For Mailbox 14  */
-#define        TRS15           0x8000  /* Remote Frame Request For Mailbox 15  */
-
-/* CAN_TRS2 Masks                                                                                                      */
-#define        TRS16           0x0001  /* Remote Frame Request For Mailbox 16  */
-#define        TRS17           0x0002  /* Remote Frame Request For Mailbox 17  */
-#define        TRS18           0x0004  /* Remote Frame Request For Mailbox 18  */
-#define        TRS19           0x0008  /* Remote Frame Request For Mailbox 19  */
-#define        TRS20           0x0010  /* Remote Frame Request For Mailbox 20  */
-#define        TRS21           0x0020  /* Remote Frame Request For Mailbox 21  */
-#define        TRS22           0x0040  /* Remote Frame Request For Mailbox 22  */
-#define        TRS23           0x0080  /* Remote Frame Request For Mailbox 23  */
-#define        TRS24           0x0100  /* Remote Frame Request For Mailbox 24  */
-#define        TRS25           0x0200  /* Remote Frame Request For Mailbox 25  */
-#define        TRS26           0x0400  /* Remote Frame Request For Mailbox 26  */
-#define        TRS27           0x0800  /* Remote Frame Request For Mailbox 27  */
-#define        TRS28           0x1000  /* Remote Frame Request For Mailbox 28  */
-#define        TRS29           0x2000  /* Remote Frame Request For Mailbox 29  */
-#define        TRS30           0x4000  /* Remote Frame Request For Mailbox 30  */
-#define        TRS31           0x8000  /* Remote Frame Request For Mailbox 31  */
-
-/* CAN_AA1 Masks                                                                                               */
-#define        AA0                     0x0001  /* Aborted Message In Mailbox 0         */
-#define        AA1                     0x0002  /* Aborted Message In Mailbox 1         */
-#define        AA2                     0x0004  /* Aborted Message In Mailbox 2         */
-#define        AA3                     0x0008  /* Aborted Message In Mailbox 3         */
-#define        AA4                     0x0010  /* Aborted Message In Mailbox 4         */
-#define        AA5                     0x0020  /* Aborted Message In Mailbox 5         */
-#define        AA6                     0x0040  /* Aborted Message In Mailbox 6         */
-#define        AA7                     0x0080  /* Aborted Message In Mailbox 7         */
-#define        AA8                     0x0100  /* Aborted Message In Mailbox 8         */
-#define        AA9                     0x0200  /* Aborted Message In Mailbox 9         */
-#define        AA10            0x0400  /* Aborted Message In Mailbox 10        */
-#define        AA11            0x0800  /* Aborted Message In Mailbox 11        */
-#define        AA12            0x1000  /* Aborted Message In Mailbox 12        */
-#define        AA13            0x2000  /* Aborted Message In Mailbox 13        */
-#define        AA14            0x4000  /* Aborted Message In Mailbox 14        */
-#define        AA15            0x8000  /* Aborted Message In Mailbox 15        */
-
-/* CAN_AA2 Masks                                                                                               */
-#define        AA16            0x0001  /* Aborted Message In Mailbox 16        */
-#define        AA17            0x0002  /* Aborted Message In Mailbox 17        */
-#define        AA18            0x0004  /* Aborted Message In Mailbox 18        */
-#define        AA19            0x0008  /* Aborted Message In Mailbox 19        */
-#define        AA20            0x0010  /* Aborted Message In Mailbox 20        */
-#define        AA21            0x0020  /* Aborted Message In Mailbox 21        */
-#define        AA22            0x0040  /* Aborted Message In Mailbox 22        */
-#define        AA23            0x0080  /* Aborted Message In Mailbox 23        */
-#define        AA24            0x0100  /* Aborted Message In Mailbox 24        */
-#define        AA25            0x0200  /* Aborted Message In Mailbox 25        */
-#define        AA26            0x0400  /* Aborted Message In Mailbox 26        */
-#define        AA27            0x0800  /* Aborted Message In Mailbox 27        */
-#define        AA28            0x1000  /* Aborted Message In Mailbox 28        */
-#define        AA29            0x2000  /* Aborted Message In Mailbox 29        */
-#define        AA30            0x4000  /* Aborted Message In Mailbox 30        */
-#define        AA31            0x8000  /* Aborted Message In Mailbox 31        */
-
-/* CAN_TA1 Masks                                                                                                       */
-#define        TA0                     0x0001  /* Transmit Successful From Mailbox 0   */
-#define        TA1                     0x0002  /* Transmit Successful From Mailbox 1   */
-#define        TA2                     0x0004  /* Transmit Successful From Mailbox 2   */
-#define        TA3                     0x0008  /* Transmit Successful From Mailbox 3   */
-#define        TA4                     0x0010  /* Transmit Successful From Mailbox 4   */
-#define        TA5                     0x0020  /* Transmit Successful From Mailbox 5   */
-#define        TA6                     0x0040  /* Transmit Successful From Mailbox 6   */
-#define        TA7                     0x0080  /* Transmit Successful From Mailbox 7   */
-#define        TA8                     0x0100  /* Transmit Successful From Mailbox 8   */
-#define        TA9                     0x0200  /* Transmit Successful From Mailbox 9   */
-#define        TA10            0x0400  /* Transmit Successful From Mailbox 10  */
-#define        TA11            0x0800  /* Transmit Successful From Mailbox 11  */
-#define        TA12            0x1000  /* Transmit Successful From Mailbox 12  */
-#define        TA13            0x2000  /* Transmit Successful From Mailbox 13  */
-#define        TA14            0x4000  /* Transmit Successful From Mailbox 14  */
-#define        TA15            0x8000  /* Transmit Successful From Mailbox 15  */
-
-/* CAN_TA2 Masks                                                                                                       */
-#define        TA16            0x0001  /* Transmit Successful From Mailbox 16  */
-#define        TA17            0x0002  /* Transmit Successful From Mailbox 17  */
-#define        TA18            0x0004  /* Transmit Successful From Mailbox 18  */
-#define        TA19            0x0008  /* Transmit Successful From Mailbox 19  */
-#define        TA20            0x0010  /* Transmit Successful From Mailbox 20  */
-#define        TA21            0x0020  /* Transmit Successful From Mailbox 21  */
-#define        TA22            0x0040  /* Transmit Successful From Mailbox 22  */
-#define        TA23            0x0080  /* Transmit Successful From Mailbox 23  */
-#define        TA24            0x0100  /* Transmit Successful From Mailbox 24  */
-#define        TA25            0x0200  /* Transmit Successful From Mailbox 25  */
-#define        TA26            0x0400  /* Transmit Successful From Mailbox 26  */
-#define        TA27            0x0800  /* Transmit Successful From Mailbox 27  */
-#define        TA28            0x1000  /* Transmit Successful From Mailbox 28  */
-#define        TA29            0x2000  /* Transmit Successful From Mailbox 29  */
-#define        TA30            0x4000  /* Transmit Successful From Mailbox 30  */
-#define        TA31            0x8000  /* Transmit Successful From Mailbox 31  */
-
-/* CAN_MBTD Masks                                                                                              */
-#define TDPTR          0x001F  /* Mailbox To Temporarily Disable       */
-#define        TDA                     0x0040  /* Temporary Disable Acknowledge        */
-#define        TDR                     0x0080  /* Temporary Disable Request            */
-
-/* CAN_RFH1 Masks                                                                                                                                              */
-#define        RFH0            0x0001  /* Enable Automatic Remote Frame Handling For Mailbox 0         */
-#define        RFH1            0x0002  /* Enable Automatic Remote Frame Handling For Mailbox 1         */
-#define        RFH2            0x0004  /* Enable Automatic Remote Frame Handling For Mailbox 2         */
-#define        RFH3            0x0008  /* Enable Automatic Remote Frame Handling For Mailbox 3         */
-#define        RFH4            0x0010  /* Enable Automatic Remote Frame Handling For Mailbox 4         */
-#define        RFH5            0x0020  /* Enable Automatic Remote Frame Handling For Mailbox 5         */
-#define        RFH6            0x0040  /* Enable Automatic Remote Frame Handling For Mailbox 6         */
-#define        RFH7            0x0080  /* Enable Automatic Remote Frame Handling For Mailbox 7         */
-#define        RFH8            0x0100  /* Enable Automatic Remote Frame Handling For Mailbox 8         */
-#define        RFH9            0x0200  /* Enable Automatic Remote Frame Handling For Mailbox 9         */
-#define        RFH10           0x0400  /* Enable Automatic Remote Frame Handling For Mailbox 10        */
-#define        RFH11           0x0800  /* Enable Automatic Remote Frame Handling For Mailbox 11        */
-#define        RFH12           0x1000  /* Enable Automatic Remote Frame Handling For Mailbox 12        */
-#define        RFH13           0x2000  /* Enable Automatic Remote Frame Handling For Mailbox 13        */
-#define        RFH14           0x4000  /* Enable Automatic Remote Frame Handling For Mailbox 14        */
-#define        RFH15           0x8000  /* Enable Automatic Remote Frame Handling For Mailbox 15        */
-
-/* CAN_RFH2 Masks                                                                                                                                              */
-#define        RFH16           0x0001  /* Enable Automatic Remote Frame Handling For Mailbox 16        */
-#define        RFH17           0x0002  /* Enable Automatic Remote Frame Handling For Mailbox 17        */
-#define        RFH18           0x0004  /* Enable Automatic Remote Frame Handling For Mailbox 18        */
-#define        RFH19           0x0008  /* Enable Automatic Remote Frame Handling For Mailbox 19        */
-#define        RFH20           0x0010  /* Enable Automatic Remote Frame Handling For Mailbox 20        */
-#define        RFH21           0x0020  /* Enable Automatic Remote Frame Handling For Mailbox 21        */
-#define        RFH22           0x0040  /* Enable Automatic Remote Frame Handling For Mailbox 22        */
-#define        RFH23           0x0080  /* Enable Automatic Remote Frame Handling For Mailbox 23        */
-#define        RFH24           0x0100  /* Enable Automatic Remote Frame Handling For Mailbox 24        */
-#define        RFH25           0x0200  /* Enable Automatic Remote Frame Handling For Mailbox 25        */
-#define        RFH26           0x0400  /* Enable Automatic Remote Frame Handling For Mailbox 26        */
-#define        RFH27           0x0800  /* Enable Automatic Remote Frame Handling For Mailbox 27        */
-#define        RFH28           0x1000  /* Enable Automatic Remote Frame Handling For Mailbox 28        */
-#define        RFH29           0x2000  /* Enable Automatic Remote Frame Handling For Mailbox 29        */
-#define        RFH30           0x4000  /* Enable Automatic Remote Frame Handling For Mailbox 30        */
-#define        RFH31           0x8000  /* Enable Automatic Remote Frame Handling For Mailbox 31        */
-
-/* CAN_MBTIF1 Masks                                                                                                    */
-#define        MBTIF0          0x0001  /* TX Interrupt Active In Mailbox 0             */
-#define        MBTIF1          0x0002  /* TX Interrupt Active In Mailbox 1             */
-#define        MBTIF2          0x0004  /* TX Interrupt Active In Mailbox 2             */
-#define        MBTIF3          0x0008  /* TX Interrupt Active In Mailbox 3             */
-#define        MBTIF4          0x0010  /* TX Interrupt Active In Mailbox 4             */
-#define        MBTIF5          0x0020  /* TX Interrupt Active In Mailbox 5             */
-#define        MBTIF6          0x0040  /* TX Interrupt Active In Mailbox 6             */
-#define        MBTIF7          0x0080  /* TX Interrupt Active In Mailbox 7             */
-#define        MBTIF8          0x0100  /* TX Interrupt Active In Mailbox 8             */
-#define        MBTIF9          0x0200  /* TX Interrupt Active In Mailbox 9             */
-#define        MBTIF10         0x0400  /* TX Interrupt Active In Mailbox 10    */
-#define        MBTIF11         0x0800  /* TX Interrupt Active In Mailbox 11    */
-#define        MBTIF12         0x1000  /* TX Interrupt Active In Mailbox 12    */
-#define        MBTIF13         0x2000  /* TX Interrupt Active In Mailbox 13    */
-#define        MBTIF14         0x4000  /* TX Interrupt Active In Mailbox 14    */
-#define        MBTIF15         0x8000  /* TX Interrupt Active In Mailbox 15    */
-
-/* CAN_MBTIF2 Masks                                                                                                    */
-#define        MBTIF16         0x0001  /* TX Interrupt Active In Mailbox 16    */
-#define        MBTIF17         0x0002  /* TX Interrupt Active In Mailbox 17    */
-#define        MBTIF18         0x0004  /* TX Interrupt Active In Mailbox 18    */
-#define        MBTIF19         0x0008  /* TX Interrupt Active In Mailbox 19    */
-#define        MBTIF20         0x0010  /* TX Interrupt Active In Mailbox 20    */
-#define        MBTIF21         0x0020  /* TX Interrupt Active In Mailbox 21    */
-#define        MBTIF22         0x0040  /* TX Interrupt Active In Mailbox 22    */
-#define        MBTIF23         0x0080  /* TX Interrupt Active In Mailbox 23    */
-#define        MBTIF24         0x0100  /* TX Interrupt Active In Mailbox 24    */
-#define        MBTIF25         0x0200  /* TX Interrupt Active In Mailbox 25    */
-#define        MBTIF26         0x0400  /* TX Interrupt Active In Mailbox 26    */
-#define        MBTIF27         0x0800  /* TX Interrupt Active In Mailbox 27    */
-#define        MBTIF28         0x1000  /* TX Interrupt Active In Mailbox 28    */
-#define        MBTIF29         0x2000  /* TX Interrupt Active In Mailbox 29    */
-#define        MBTIF30         0x4000  /* TX Interrupt Active In Mailbox 30    */
-#define        MBTIF31         0x8000  /* TX Interrupt Active In Mailbox 31    */
-
-/* CAN_MBRIF1 Masks                                                                                                    */
-#define        MBRIF0          0x0001  /* RX Interrupt Active In Mailbox 0             */
-#define        MBRIF1          0x0002  /* RX Interrupt Active In Mailbox 1             */
-#define        MBRIF2          0x0004  /* RX Interrupt Active In Mailbox 2             */
-#define        MBRIF3          0x0008  /* RX Interrupt Active In Mailbox 3             */
-#define        MBRIF4          0x0010  /* RX Interrupt Active In Mailbox 4             */
-#define        MBRIF5          0x0020  /* RX Interrupt Active In Mailbox 5             */
-#define        MBRIF6          0x0040  /* RX Interrupt Active In Mailbox 6             */
-#define        MBRIF7          0x0080  /* RX Interrupt Active In Mailbox 7             */
-#define        MBRIF8          0x0100  /* RX Interrupt Active In Mailbox 8             */
-#define        MBRIF9          0x0200  /* RX Interrupt Active In Mailbox 9             */
-#define        MBRIF10         0x0400  /* RX Interrupt Active In Mailbox 10    */
-#define        MBRIF11         0x0800  /* RX Interrupt Active In Mailbox 11    */
-#define        MBRIF12         0x1000  /* RX Interrupt Active In Mailbox 12    */
-#define        MBRIF13         0x2000  /* RX Interrupt Active In Mailbox 13    */
-#define        MBRIF14         0x4000  /* RX Interrupt Active In Mailbox 14    */
-#define        MBRIF15         0x8000  /* RX Interrupt Active In Mailbox 15    */
-
-/* CAN_MBRIF2 Masks                                                                                                    */
-#define        MBRIF16         0x0001  /* RX Interrupt Active In Mailbox 16    */
-#define        MBRIF17         0x0002  /* RX Interrupt Active In Mailbox 17    */
-#define        MBRIF18         0x0004  /* RX Interrupt Active In Mailbox 18    */
-#define        MBRIF19         0x0008  /* RX Interrupt Active In Mailbox 19    */
-#define        MBRIF20         0x0010  /* RX Interrupt Active In Mailbox 20    */
-#define        MBRIF21         0x0020  /* RX Interrupt Active In Mailbox 21    */
-#define        MBRIF22         0x0040  /* RX Interrupt Active In Mailbox 22    */
-#define        MBRIF23         0x0080  /* RX Interrupt Active In Mailbox 23    */
-#define        MBRIF24         0x0100  /* RX Interrupt Active In Mailbox 24    */
-#define        MBRIF25         0x0200  /* RX Interrupt Active In Mailbox 25    */
-#define        MBRIF26         0x0400  /* RX Interrupt Active In Mailbox 26    */
-#define        MBRIF27         0x0800  /* RX Interrupt Active In Mailbox 27    */
-#define        MBRIF28         0x1000  /* RX Interrupt Active In Mailbox 28    */
-#define        MBRIF29         0x2000  /* RX Interrupt Active In Mailbox 29    */
-#define        MBRIF30         0x4000  /* RX Interrupt Active In Mailbox 30    */
-#define        MBRIF31         0x8000  /* RX Interrupt Active In Mailbox 31    */
-
-/* CAN_MBIM1 Masks                                                                                             */
-#define        MBIM0           0x0001  /* Enable Interrupt For Mailbox 0       */
-#define        MBIM1           0x0002  /* Enable Interrupt For Mailbox 1       */
-#define        MBIM2           0x0004  /* Enable Interrupt For Mailbox 2       */
-#define        MBIM3           0x0008  /* Enable Interrupt For Mailbox 3       */
-#define        MBIM4           0x0010  /* Enable Interrupt For Mailbox 4       */
-#define        MBIM5           0x0020  /* Enable Interrupt For Mailbox 5       */
-#define        MBIM6           0x0040  /* Enable Interrupt For Mailbox 6       */
-#define        MBIM7           0x0080  /* Enable Interrupt For Mailbox 7       */
-#define        MBIM8           0x0100  /* Enable Interrupt For Mailbox 8       */
-#define        MBIM9           0x0200  /* Enable Interrupt For Mailbox 9       */
-#define        MBIM10          0x0400  /* Enable Interrupt For Mailbox 10      */
-#define        MBIM11          0x0800  /* Enable Interrupt For Mailbox 11      */
-#define        MBIM12          0x1000  /* Enable Interrupt For Mailbox 12      */
-#define        MBIM13          0x2000  /* Enable Interrupt For Mailbox 13      */
-#define        MBIM14          0x4000  /* Enable Interrupt For Mailbox 14      */
-#define        MBIM15          0x8000  /* Enable Interrupt For Mailbox 15      */
-
-/* CAN_MBIM2 Masks                                                                                             */
-#define        MBIM16          0x0001  /* Enable Interrupt For Mailbox 16      */
-#define        MBIM17          0x0002  /* Enable Interrupt For Mailbox 17      */
-#define        MBIM18          0x0004  /* Enable Interrupt For Mailbox 18      */
-#define        MBIM19          0x0008  /* Enable Interrupt For Mailbox 19      */
-#define        MBIM20          0x0010  /* Enable Interrupt For Mailbox 20      */
-#define        MBIM21          0x0020  /* Enable Interrupt For Mailbox 21      */
-#define        MBIM22          0x0040  /* Enable Interrupt For Mailbox 22      */
-#define        MBIM23          0x0080  /* Enable Interrupt For Mailbox 23      */
-#define        MBIM24          0x0100  /* Enable Interrupt For Mailbox 24      */
-#define        MBIM25          0x0200  /* Enable Interrupt For Mailbox 25      */
-#define        MBIM26          0x0400  /* Enable Interrupt For Mailbox 26      */
-#define        MBIM27          0x0800  /* Enable Interrupt For Mailbox 27      */
-#define        MBIM28          0x1000  /* Enable Interrupt For Mailbox 28      */
-#define        MBIM29          0x2000  /* Enable Interrupt For Mailbox 29      */
-#define        MBIM30          0x4000  /* Enable Interrupt For Mailbox 30      */
-#define        MBIM31          0x8000  /* Enable Interrupt For Mailbox 31      */
-
-/* CAN_GIM Masks                                                                                                                               */
-#define        EWTIM           0x0001  /* Enable TX Error Count Interrupt                                      */
-#define        EWRIM           0x0002  /* Enable RX Error Count Interrupt                                      */
-#define        EPIM            0x0004  /* Enable Error-Passive Mode Interrupt                          */
-#define        BOIM            0x0008  /* Enable Bus Off Interrupt                                                     */
-#define        WUIM            0x0010  /* Enable Wake-Up Interrupt                                                     */
-#define        UIAIM           0x0020  /* Enable Access To Unimplemented Address Interrupt     */
-#define        AAIM            0x0040  /* Enable Abort Acknowledge Interrupt                           */
-#define        RMLIM           0x0080  /* Enable RX Message Lost Interrupt                                     */
-#define        UCEIM           0x0100  /* Enable Universal Counter Overflow Interrupt          */
-#define        EXTIM           0x0200  /* Enable External Trigger Output Interrupt                     */
-#define        ADIM            0x0400  /* Enable Access Denied Interrupt                                       */
-
-/* CAN_GIS Masks                                                                                                                       */
-#define        EWTIS           0x0001  /* TX Error Count IRQ Status                                    */
-#define        EWRIS           0x0002  /* RX Error Count IRQ Status                                    */
-#define        EPIS            0x0004  /* Error-Passive Mode IRQ Status                                */
-#define        BOIS            0x0008  /* Bus Off IRQ Status                                                   */
-#define        WUIS            0x0010  /* Wake-Up IRQ Status                                                   */
-#define        UIAIS           0x0020  /* Access To Unimplemented Address IRQ Status   */
-#define        AAIS            0x0040  /* Abort Acknowledge IRQ Status                                 */
-#define        RMLIS           0x0080  /* RX Message Lost IRQ Status                                   */
-#define        UCEIS           0x0100  /* Universal Counter Overflow IRQ Status                */
-#define        EXTIS           0x0200  /* External Trigger Output IRQ Status                   */
-#define        ADIS            0x0400  /* Access Denied IRQ Status                                             */
-
-/* CAN_GIF Masks                                                                                                                       */
-#define        EWTIF           0x0001  /* TX Error Count IRQ Flag                                              */
-#define        EWRIF           0x0002  /* RX Error Count IRQ Flag                                              */
-#define        EPIF            0x0004  /* Error-Passive Mode IRQ Flag                                  */
-#define        BOIF            0x0008  /* Bus Off IRQ Flag                                                             */
-#define        WUIF            0x0010  /* Wake-Up IRQ Flag                                                             */
-#define        UIAIF           0x0020  /* Access To Unimplemented Address IRQ Flag             */
-#define        AAIF            0x0040  /* Abort Acknowledge IRQ Flag                                   */
-#define        RMLIF           0x0080  /* RX Message Lost IRQ Flag                                             */
-#define        UCEIF           0x0100  /* Universal Counter Overflow IRQ Flag                  */
-#define        EXTIF           0x0200  /* External Trigger Output IRQ Flag                             */
-#define        ADIF            0x0400  /* Access Denied IRQ Flag                                               */
-
-/* CAN_UCCNF Masks                                                                                                                     */
-#define        UCCNF           0x000F  /* Universal Counter Mode                                               */
-#define UC_STAMP       0x0001  /*              Timestamp Mode                                                  */
-#define UC_WDOG                0x0002  /*              Watchdog Mode                                                   */
-#define UC_AUTOTX      0x0003  /*              Auto-Transmit Mode                                              */
-#define UC_ERROR       0x0006  /*              CAN Error Frame Count                                   */
-#define UC_OVER                0x0007  /*              CAN Overload Frame Count                                */
-#define UC_LOST                0x0008  /*              Arbitration Lost During TX Count                */
-#define UC_AA          0x0009  /*              TX Abort Count                                                  */
-#define UC_TA          0x000A  /*              TX Successful Count                                             */
-#define UC_REJECT      0x000B  /*              RX Message Rejected Count                               */
-#define UC_RML         0x000C  /*              RX Message Lost Count                                   */
-#define UC_RX          0x000D  /*              Total Successful RX Messages Count              */
-#define UC_RMP         0x000E  /*              Successful RX W/Matching ID Count               */
-#define UC_ALL         0x000F  /*              Correct Message On CAN Bus Line Count   */
-#define        UCRC            0x0020  /* Universal Counter Reload/Clear                               */
-#define        UCCT            0x0040  /* Universal Counter CAN Trigger                                */
-#define        UCE                     0x0080  /* Universal Counter Enable                                             */
-
-/* CAN_ESR Masks                                                                               */
-#define        ACKE            0x0004  /* Acknowledge Error            */
-#define        SER                     0x0008  /* Stuff Error                          */
-#define        CRCE            0x0010  /* CRC Error                            */
-#define        SA0                     0x0020  /* Stuck At Dominant Error      */
-#define        BEF                     0x0040  /* Bit Error Flag                       */
-#define        FER                     0x0080  /* Form Error Flag                      */
-
-/* CAN_EWR Masks                                                                                               */
-#define        EWLREC          0x00FF  /* RX Error Count Limit (For EWRIS)     */
-#define        EWLTEC          0xFF00  /* TX Error Count Limit (For EWTIS)     */
-
 /*  *******************  PIN CONTROL REGISTER MASKS  ************************/
 /* PORT_MUX Masks                                                                                                                      */
 #define        PJSE                    0x0001  /* Port J SPI/SPORT Enable                      */
index 789a4f226f7b2c8b0b75eb763e12b693830978c9..1a6d617c5fcf8680597f0b5b4143be15b5590201 100644 (file)
@@ -74,7 +74,7 @@
 
 #define IRQ_PPI_ERROR       42 /*PPI Error Interrupt */
 #define IRQ_CAN_ERROR       43 /*CAN Error Interrupt */
-#define IRQ_MAC_ERROR       44 /*PPI Error Interrupt */
+#define IRQ_MAC_ERROR       44 /*MAC Status/Error Interrupt */
 #define IRQ_SPORT0_ERROR    45 /*SPORT0 Error Interrupt */
 #define IRQ_SPORT1_ERROR    46 /*SPORT1 Error Interrupt */
 #define IRQ_SPI_ERROR       47 /*SPI Error Interrupt */
index fac563e6f62f7adbe357cab7d501d1c6fc276ac9..d7061d9f2a832cd2c0936edf06db800d03a62637 100644 (file)
 #define        RCV_HALF        0x0004          /*              Receive FIFO Has 1 Byte To Read */
 #define        RCV_FULL        0x000C          /*              Receive FIFO Full (2 Bytes To Read) */
 
-
-/* ************         CONTROLLER AREA NETWORK (CAN) MASKS  ***************/
-/* CAN_CONTROL Masks                                    */
-#define        SRS                     0x0001  /* Software Reset */
-#define        DNM                     0x0002  /* Device Net Mode */
-#define        ABO                     0x0004  /* Auto-Bus On Enable */
-#define        WBA                     0x0010  /* Wake-Up On CAN Bus Activity Enable */
-#define        SMR                     0x0020  /* Sleep Mode Request */
-#define        CSR                     0x0040  /* CAN Suspend Mode Request */
-#define        CCR                     0x0080  /* CAN Configuration Mode Request */
-
-/* CAN_STATUS Masks                                     */
-#define        WT                      0x0001  /* TX Warning Flag */
-#define        WR                      0x0002  /* RX Warning Flag */
-#define        EP                      0x0004  /* Error Passive Mode */
-#define        EBO                     0x0008  /* Error Bus Off Mode */
-#define        CSA                     0x0040  /* Suspend Mode Acknowledge */
-#define        CCA                     0x0080  /* Configuration Mode Acknowledge */
-#define        MBPTR           0x1F00  /* Mailbox Pointer */
-#define        TRM                     0x4000  /* Transmit Mode */
-#define        REC                     0x8000  /* Receive Mode */
-
-/* CAN_CLOCK Masks              */
-#define        BRP                     0x03FF  /* Bit-Rate Pre-Scaler */
-
-/* CAN_TIMING Masks                             */
-#define        TSEG1           0x000F  /* Time Segment 1 */
-#define        TSEG2           0x0070  /* Time Segment 2 */
-#define        SAM                     0x0080  /* Sampling */
-#define        SJW                     0x0300  /* Synchronization Jump Width */
-
-/* CAN_DEBUG Masks                              */
-#define        DEC                     0x0001  /* Disable CAN Error Counters */
-#define        DRI                     0x0002  /* Disable CAN RX Input */
-#define        DTO                     0x0004  /* Disable CAN TX Output */
-#define        DIL                     0x0008  /* Disable CAN Internal Loop */
-#define        MAA                     0x0010  /* Mode Auto-Acknowledge Enable */
-#define        MRB                     0x0020  /* Mode Read Back Enable */
-#define        CDE                     0x8000  /* CAN Debug Enable */
-
-/* CAN_CEC Masks                        */
-#define        RXECNT          0x00FF  /* Receive Error Counter */
-#define        TXECNT          0xFF00  /* Transmit Error Counter */
-
-/* CAN_INTR Masks                               */
-#define        MBRIRQ  0x0001  /* Mailbox Receive Interrupt */
-#define        MBRIF           MBRIRQ  /* legacy */
-#define        MBTIRQ  0x0002  /* Mailbox Transmit Interrupt */
-#define        MBTIF           MBTIRQ  /* legacy */
-#define        GIRQ            0x0004  /* Global Interrupt */
-#define        SMACK           0x0008  /* Sleep Mode Acknowledge */
-#define        CANTX           0x0040  /* CAN TX Bus Value */
-#define        CANRX           0x0080  /* CAN RX Bus Value */
-
-/* CAN_MBxx_ID1        and CAN_MBxx_ID0 Masks                   */
-#define        DFC                     0xFFFF  /* Data Filtering Code (If Enabled) (ID0) */
-#define        EXTID_LO        0xFFFF  /* Lower 16 Bits of Extended Identifier (ID0) */
-#define        EXTID_HI        0x0003  /* Upper 2 Bits of Extended Identifier (ID1) */
-#define        BASEID          0x1FFC  /* Base Identifier       */
-#define        IDE                     0x2000  /* Identifier Extension */
-#define        RTR                     0x4000  /* Remote Frame Transmission Request */
-#define        AME                     0x8000  /* Acceptance Mask Enable */
-
-/* CAN_MBxx_TIMESTAMP Masks */
-#define        TSV                     0xFFFF  /* Timestamp */
-
-/* CAN_MBxx_LENGTH Masks */
-#define        DLC                     0x000F  /* Data Length Code */
-
-/* CAN_AMxxH and CAN_AMxxL Masks                                        */
-#define        DFM                     0xFFFF  /* Data Field Mask (If Enabled) (CAN_AMxxL) */
-#define        EXTID_LO        0xFFFF  /* Lower 16 Bits of Extended Identifier (CAN_AMxxL) */
-#define        EXTID_HI        0x0003  /* Upper 2 Bits of Extended Identifier (CAN_AMxxH) */
-#define        BASEID          0x1FFC  /* Base Identifier               */
-#define        AMIDE           0x2000  /* Acceptance Mask ID Extension Enable */
-#define        FMD                     0x4000  /* Full Mask Data Field Enable */
-#define        FDF                     0x8000  /* Filter On Data Field Enable */
-
-/* CAN_MC1 Masks                */
-#define        MC0                     0x0001  /* Enable Mailbox 0 */
-#define        MC1                     0x0002  /* Enable Mailbox 1 */
-#define        MC2                     0x0004  /* Enable Mailbox 2 */
-#define        MC3                     0x0008  /* Enable Mailbox 3 */
-#define        MC4                     0x0010  /* Enable Mailbox 4 */
-#define        MC5                     0x0020  /* Enable Mailbox 5 */
-#define        MC6                     0x0040  /* Enable Mailbox 6 */
-#define        MC7                     0x0080  /* Enable Mailbox 7 */
-#define        MC8                     0x0100  /* Enable Mailbox 8 */
-#define        MC9                     0x0200  /* Enable Mailbox 9 */
-#define        MC10            0x0400  /* Enable Mailbox 10 */
-#define        MC11            0x0800  /* Enable Mailbox 11 */
-#define        MC12            0x1000  /* Enable Mailbox 12 */
-#define        MC13            0x2000  /* Enable Mailbox 13 */
-#define        MC14            0x4000  /* Enable Mailbox 14 */
-#define        MC15            0x8000  /* Enable Mailbox 15 */
-
-/* CAN_MC2 Masks                */
-#define        MC16            0x0001  /* Enable Mailbox 16 */
-#define        MC17            0x0002  /* Enable Mailbox 17 */
-#define        MC18            0x0004  /* Enable Mailbox 18 */
-#define        MC19            0x0008  /* Enable Mailbox 19 */
-#define        MC20            0x0010  /* Enable Mailbox 20 */
-#define        MC21            0x0020  /* Enable Mailbox 21 */
-#define        MC22            0x0040  /* Enable Mailbox 22 */
-#define        MC23            0x0080  /* Enable Mailbox 23 */
-#define        MC24            0x0100  /* Enable Mailbox 24 */
-#define        MC25            0x0200  /* Enable Mailbox 25 */
-#define        MC26            0x0400  /* Enable Mailbox 26 */
-#define        MC27            0x0800  /* Enable Mailbox 27 */
-#define        MC28            0x1000  /* Enable Mailbox 28 */
-#define        MC29            0x2000  /* Enable Mailbox 29 */
-#define        MC30            0x4000  /* Enable Mailbox 30 */
-#define        MC31            0x8000  /* Enable Mailbox 31 */
-
-/* CAN_MD1 Masks                                        */
-#define        MD0                     0x0001  /* Enable Mailbox 0 For Receive */
-#define        MD1                     0x0002  /* Enable Mailbox 1 For Receive */
-#define        MD2                     0x0004  /* Enable Mailbox 2 For Receive */
-#define        MD3                     0x0008  /* Enable Mailbox 3 For Receive */
-#define        MD4                     0x0010  /* Enable Mailbox 4 For Receive */
-#define        MD5                     0x0020  /* Enable Mailbox 5 For Receive */
-#define        MD6                     0x0040  /* Enable Mailbox 6 For Receive */
-#define        MD7                     0x0080  /* Enable Mailbox 7 For Receive */
-#define        MD8                     0x0100  /* Enable Mailbox 8 For Receive */
-#define        MD9                     0x0200  /* Enable Mailbox 9 For Receive */
-#define        MD10            0x0400  /* Enable Mailbox 10 For Receive */
-#define        MD11            0x0800  /* Enable Mailbox 11 For Receive */
-#define        MD12            0x1000  /* Enable Mailbox 12 For Receive */
-#define        MD13            0x2000  /* Enable Mailbox 13 For Receive */
-#define        MD14            0x4000  /* Enable Mailbox 14 For Receive */
-#define        MD15            0x8000  /* Enable Mailbox 15 For Receive */
-
-/* CAN_MD2 Masks                                        */
-#define        MD16            0x0001  /* Enable Mailbox 16 For Receive */
-#define        MD17            0x0002  /* Enable Mailbox 17 For Receive */
-#define        MD18            0x0004  /* Enable Mailbox 18 For Receive */
-#define        MD19            0x0008  /* Enable Mailbox 19 For Receive */
-#define        MD20            0x0010  /* Enable Mailbox 20 For Receive */
-#define        MD21            0x0020  /* Enable Mailbox 21 For Receive */
-#define        MD22            0x0040  /* Enable Mailbox 22 For Receive */
-#define        MD23            0x0080  /* Enable Mailbox 23 For Receive */
-#define        MD24            0x0100  /* Enable Mailbox 24 For Receive */
-#define        MD25            0x0200  /* Enable Mailbox 25 For Receive */
-#define        MD26            0x0400  /* Enable Mailbox 26 For Receive */
-#define        MD27            0x0800  /* Enable Mailbox 27 For Receive */
-#define        MD28            0x1000  /* Enable Mailbox 28 For Receive */
-#define        MD29            0x2000  /* Enable Mailbox 29 For Receive */
-#define        MD30            0x4000  /* Enable Mailbox 30 For Receive */
-#define        MD31            0x8000  /* Enable Mailbox 31 For Receive */
-
-/* CAN_RMP1 Masks                                       */
-#define        RMP0            0x0001  /* RX Message Pending In Mailbox 0 */
-#define        RMP1            0x0002  /* RX Message Pending In Mailbox 1 */
-#define        RMP2            0x0004  /* RX Message Pending In Mailbox 2 */
-#define        RMP3            0x0008  /* RX Message Pending In Mailbox 3 */
-#define        RMP4            0x0010  /* RX Message Pending In Mailbox 4 */
-#define        RMP5            0x0020  /* RX Message Pending In Mailbox 5 */
-#define        RMP6            0x0040  /* RX Message Pending In Mailbox 6 */
-#define        RMP7            0x0080  /* RX Message Pending In Mailbox 7 */
-#define        RMP8            0x0100  /* RX Message Pending In Mailbox 8 */
-#define        RMP9            0x0200  /* RX Message Pending In Mailbox 9 */
-#define        RMP10           0x0400  /* RX Message Pending In Mailbox 10 */
-#define        RMP11           0x0800  /* RX Message Pending In Mailbox 11 */
-#define        RMP12           0x1000  /* RX Message Pending In Mailbox 12 */
-#define        RMP13           0x2000  /* RX Message Pending In Mailbox 13 */
-#define        RMP14           0x4000  /* RX Message Pending In Mailbox 14 */
-#define        RMP15           0x8000  /* RX Message Pending In Mailbox 15 */
-
-/* CAN_RMP2 Masks                                       */
-#define        RMP16           0x0001  /* RX Message Pending In Mailbox 16 */
-#define        RMP17           0x0002  /* RX Message Pending In Mailbox 17 */
-#define        RMP18           0x0004  /* RX Message Pending In Mailbox 18 */
-#define        RMP19           0x0008  /* RX Message Pending In Mailbox 19 */
-#define        RMP20           0x0010  /* RX Message Pending In Mailbox 20 */
-#define        RMP21           0x0020  /* RX Message Pending In Mailbox 21 */
-#define        RMP22           0x0040  /* RX Message Pending In Mailbox 22 */
-#define        RMP23           0x0080  /* RX Message Pending In Mailbox 23 */
-#define        RMP24           0x0100  /* RX Message Pending In Mailbox 24 */
-#define        RMP25           0x0200  /* RX Message Pending In Mailbox 25 */
-#define        RMP26           0x0400  /* RX Message Pending In Mailbox 26 */
-#define        RMP27           0x0800  /* RX Message Pending In Mailbox 27 */
-#define        RMP28           0x1000  /* RX Message Pending In Mailbox 28 */
-#define        RMP29           0x2000  /* RX Message Pending In Mailbox 29 */
-#define        RMP30           0x4000  /* RX Message Pending In Mailbox 30 */
-#define        RMP31           0x8000  /* RX Message Pending In Mailbox 31 */
-
-/* CAN_RML1 Masks                                       */
-#define        RML0            0x0001  /* RX Message Lost In Mailbox 0 */
-#define        RML1            0x0002  /* RX Message Lost In Mailbox 1 */
-#define        RML2            0x0004  /* RX Message Lost In Mailbox 2 */
-#define        RML3            0x0008  /* RX Message Lost In Mailbox 3 */
-#define        RML4            0x0010  /* RX Message Lost In Mailbox 4 */
-#define        RML5            0x0020  /* RX Message Lost In Mailbox 5 */
-#define        RML6            0x0040  /* RX Message Lost In Mailbox 6 */
-#define        RML7            0x0080  /* RX Message Lost In Mailbox 7 */
-#define        RML8            0x0100  /* RX Message Lost In Mailbox 8 */
-#define        RML9            0x0200  /* RX Message Lost In Mailbox 9 */
-#define        RML10           0x0400  /* RX Message Lost In Mailbox 10 */
-#define        RML11           0x0800  /* RX Message Lost In Mailbox 11 */
-#define        RML12           0x1000  /* RX Message Lost In Mailbox 12 */
-#define        RML13           0x2000  /* RX Message Lost In Mailbox 13 */
-#define        RML14           0x4000  /* RX Message Lost In Mailbox 14 */
-#define        RML15           0x8000  /* RX Message Lost In Mailbox 15 */
-
-/* CAN_RML2 Masks                                       */
-#define        RML16           0x0001  /* RX Message Lost In Mailbox 16 */
-#define        RML17           0x0002  /* RX Message Lost In Mailbox 17 */
-#define        RML18           0x0004  /* RX Message Lost In Mailbox 18 */
-#define        RML19           0x0008  /* RX Message Lost In Mailbox 19 */
-#define        RML20           0x0010  /* RX Message Lost In Mailbox 20 */
-#define        RML21           0x0020  /* RX Message Lost In Mailbox 21 */
-#define        RML22           0x0040  /* RX Message Lost In Mailbox 22 */
-#define        RML23           0x0080  /* RX Message Lost In Mailbox 23 */
-#define        RML24           0x0100  /* RX Message Lost In Mailbox 24 */
-#define        RML25           0x0200  /* RX Message Lost In Mailbox 25 */
-#define        RML26           0x0400  /* RX Message Lost In Mailbox 26 */
-#define        RML27           0x0800  /* RX Message Lost In Mailbox 27 */
-#define        RML28           0x1000  /* RX Message Lost In Mailbox 28 */
-#define        RML29           0x2000  /* RX Message Lost In Mailbox 29 */
-#define        RML30           0x4000  /* RX Message Lost In Mailbox 30 */
-#define        RML31           0x8000  /* RX Message Lost In Mailbox 31 */
-
-/* CAN_OPSS1 Masks                                                                                                      */
-#define        OPSS0           0x0001  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 0 */
-#define        OPSS1           0x0002  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 1 */
-#define        OPSS2           0x0004  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 2 */
-#define        OPSS3           0x0008  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 3 */
-#define        OPSS4           0x0010  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 4 */
-#define        OPSS5           0x0020  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 5 */
-#define        OPSS6           0x0040  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 6 */
-#define        OPSS7           0x0080  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 7 */
-#define        OPSS8           0x0100  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 8 */
-#define        OPSS9           0x0200  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 9 */
-#define        OPSS10          0x0400  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 10 */
-#define        OPSS11          0x0800  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 11 */
-#define        OPSS12          0x1000  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 12 */
-#define        OPSS13          0x2000  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 13 */
-#define        OPSS14          0x4000  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 14 */
-#define        OPSS15          0x8000  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 15 */
-
-/* CAN_OPSS2 Masks                                                                                                      */
-#define        OPSS16          0x0001  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 16 */
-#define        OPSS17          0x0002  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 17 */
-#define        OPSS18          0x0004  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 18 */
-#define        OPSS19          0x0008  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 19 */
-#define        OPSS20          0x0010  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 20 */
-#define        OPSS21          0x0020  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 21 */
-#define        OPSS22          0x0040  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 22 */
-#define        OPSS23          0x0080  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 23 */
-#define        OPSS24          0x0100  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 24 */
-#define        OPSS25          0x0200  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 25 */
-#define        OPSS26          0x0400  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 26 */
-#define        OPSS27          0x0800  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 27 */
-#define        OPSS28          0x1000  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 28 */
-#define        OPSS29          0x2000  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 29 */
-#define        OPSS30          0x4000  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 30 */
-#define        OPSS31          0x8000  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 31 */
-
-/* CAN_TRR1 Masks                                                       */
-#define        TRR0            0x0001  /* Deny But Don't Lock Access To Mailbox 0 */
-#define        TRR1            0x0002  /* Deny But Don't Lock Access To Mailbox 1 */
-#define        TRR2            0x0004  /* Deny But Don't Lock Access To Mailbox 2 */
-#define        TRR3            0x0008  /* Deny But Don't Lock Access To Mailbox 3 */
-#define        TRR4            0x0010  /* Deny But Don't Lock Access To Mailbox 4 */
-#define        TRR5            0x0020  /* Deny But Don't Lock Access To Mailbox 5 */
-#define        TRR6            0x0040  /* Deny But Don't Lock Access To Mailbox 6 */
-#define        TRR7            0x0080  /* Deny But Don't Lock Access To Mailbox 7 */
-#define        TRR8            0x0100  /* Deny But Don't Lock Access To Mailbox 8 */
-#define        TRR9            0x0200  /* Deny But Don't Lock Access To Mailbox 9 */
-#define        TRR10           0x0400  /* Deny But Don't Lock Access To Mailbox 10 */
-#define        TRR11           0x0800  /* Deny But Don't Lock Access To Mailbox 11 */
-#define        TRR12           0x1000  /* Deny But Don't Lock Access To Mailbox 12 */
-#define        TRR13           0x2000  /* Deny But Don't Lock Access To Mailbox 13 */
-#define        TRR14           0x4000  /* Deny But Don't Lock Access To Mailbox 14 */
-#define        TRR15           0x8000  /* Deny But Don't Lock Access To Mailbox 15 */
-
-/* CAN_TRR2 Masks                                                       */
-#define        TRR16           0x0001  /* Deny But Don't Lock Access To Mailbox 16 */
-#define        TRR17           0x0002  /* Deny But Don't Lock Access To Mailbox 17 */
-#define        TRR18           0x0004  /* Deny But Don't Lock Access To Mailbox 18 */
-#define        TRR19           0x0008  /* Deny But Don't Lock Access To Mailbox 19 */
-#define        TRR20           0x0010  /* Deny But Don't Lock Access To Mailbox 20 */
-#define        TRR21           0x0020  /* Deny But Don't Lock Access To Mailbox 21 */
-#define        TRR22           0x0040  /* Deny But Don't Lock Access To Mailbox 22 */
-#define        TRR23           0x0080  /* Deny But Don't Lock Access To Mailbox 23 */
-#define        TRR24           0x0100  /* Deny But Don't Lock Access To Mailbox 24 */
-#define        TRR25           0x0200  /* Deny But Don't Lock Access To Mailbox 25 */
-#define        TRR26           0x0400  /* Deny But Don't Lock Access To Mailbox 26 */
-#define        TRR27           0x0800  /* Deny But Don't Lock Access To Mailbox 27 */
-#define        TRR28           0x1000  /* Deny But Don't Lock Access To Mailbox 28 */
-#define        TRR29           0x2000  /* Deny But Don't Lock Access To Mailbox 29 */
-#define        TRR30           0x4000  /* Deny But Don't Lock Access To Mailbox 30 */
-#define        TRR31           0x8000  /* Deny But Don't Lock Access To Mailbox 31 */
-
-/* CAN_TRS1 Masks                                               */
-#define        TRS0            0x0001  /* Remote Frame Request For Mailbox 0 */
-#define        TRS1            0x0002  /* Remote Frame Request For Mailbox 1 */
-#define        TRS2            0x0004  /* Remote Frame Request For Mailbox 2 */
-#define        TRS3            0x0008  /* Remote Frame Request For Mailbox 3 */
-#define        TRS4            0x0010  /* Remote Frame Request For Mailbox 4 */
-#define        TRS5            0x0020  /* Remote Frame Request For Mailbox 5 */
-#define        TRS6            0x0040  /* Remote Frame Request For Mailbox 6 */
-#define        TRS7            0x0080  /* Remote Frame Request For Mailbox 7 */
-#define        TRS8            0x0100  /* Remote Frame Request For Mailbox 8 */
-#define        TRS9            0x0200  /* Remote Frame Request For Mailbox 9 */
-#define        TRS10           0x0400  /* Remote Frame Request For Mailbox 10 */
-#define        TRS11           0x0800  /* Remote Frame Request For Mailbox 11 */
-#define        TRS12           0x1000  /* Remote Frame Request For Mailbox 12 */
-#define        TRS13           0x2000  /* Remote Frame Request For Mailbox 13 */
-#define        TRS14           0x4000  /* Remote Frame Request For Mailbox 14 */
-#define        TRS15           0x8000  /* Remote Frame Request For Mailbox 15 */
-
-/* CAN_TRS2 Masks                                               */
-#define        TRS16           0x0001  /* Remote Frame Request For Mailbox 16 */
-#define        TRS17           0x0002  /* Remote Frame Request For Mailbox 17 */
-#define        TRS18           0x0004  /* Remote Frame Request For Mailbox 18 */
-#define        TRS19           0x0008  /* Remote Frame Request For Mailbox 19 */
-#define        TRS20           0x0010  /* Remote Frame Request For Mailbox 20 */
-#define        TRS21           0x0020  /* Remote Frame Request For Mailbox 21 */
-#define        TRS22           0x0040  /* Remote Frame Request For Mailbox 22 */
-#define        TRS23           0x0080  /* Remote Frame Request For Mailbox 23 */
-#define        TRS24           0x0100  /* Remote Frame Request For Mailbox 24 */
-#define        TRS25           0x0200  /* Remote Frame Request For Mailbox 25 */
-#define        TRS26           0x0400  /* Remote Frame Request For Mailbox 26 */
-#define        TRS27           0x0800  /* Remote Frame Request For Mailbox 27 */
-#define        TRS28           0x1000  /* Remote Frame Request For Mailbox 28 */
-#define        TRS29           0x2000  /* Remote Frame Request For Mailbox 29 */
-#define        TRS30           0x4000  /* Remote Frame Request For Mailbox 30 */
-#define        TRS31           0x8000  /* Remote Frame Request For Mailbox 31 */
-
-/* CAN_AA1 Masks                                        */
-#define        AA0                     0x0001  /* Aborted Message In Mailbox 0 */
-#define        AA1                     0x0002  /* Aborted Message In Mailbox 1 */
-#define        AA2                     0x0004  /* Aborted Message In Mailbox 2 */
-#define        AA3                     0x0008  /* Aborted Message In Mailbox 3 */
-#define        AA4                     0x0010  /* Aborted Message In Mailbox 4 */
-#define        AA5                     0x0020  /* Aborted Message In Mailbox 5 */
-#define        AA6                     0x0040  /* Aborted Message In Mailbox 6 */
-#define        AA7                     0x0080  /* Aborted Message In Mailbox 7 */
-#define        AA8                     0x0100  /* Aborted Message In Mailbox 8 */
-#define        AA9                     0x0200  /* Aborted Message In Mailbox 9 */
-#define        AA10            0x0400  /* Aborted Message In Mailbox 10 */
-#define        AA11            0x0800  /* Aborted Message In Mailbox 11 */
-#define        AA12            0x1000  /* Aborted Message In Mailbox 12 */
-#define        AA13            0x2000  /* Aborted Message In Mailbox 13 */
-#define        AA14            0x4000  /* Aborted Message In Mailbox 14 */
-#define        AA15            0x8000  /* Aborted Message In Mailbox 15 */
-
-/* CAN_AA2 Masks                                        */
-#define        AA16            0x0001  /* Aborted Message In Mailbox 16 */
-#define        AA17            0x0002  /* Aborted Message In Mailbox 17 */
-#define        AA18            0x0004  /* Aborted Message In Mailbox 18 */
-#define        AA19            0x0008  /* Aborted Message In Mailbox 19 */
-#define        AA20            0x0010  /* Aborted Message In Mailbox 20 */
-#define        AA21            0x0020  /* Aborted Message In Mailbox 21 */
-#define        AA22            0x0040  /* Aborted Message In Mailbox 22 */
-#define        AA23            0x0080  /* Aborted Message In Mailbox 23 */
-#define        AA24            0x0100  /* Aborted Message In Mailbox 24 */
-#define        AA25            0x0200  /* Aborted Message In Mailbox 25 */
-#define        AA26            0x0400  /* Aborted Message In Mailbox 26 */
-#define        AA27            0x0800  /* Aborted Message In Mailbox 27 */
-#define        AA28            0x1000  /* Aborted Message In Mailbox 28 */
-#define        AA29            0x2000  /* Aborted Message In Mailbox 29 */
-#define        AA30            0x4000  /* Aborted Message In Mailbox 30 */
-#define        AA31            0x8000  /* Aborted Message In Mailbox 31 */
-
-/* CAN_TA1 Masks                                                */
-#define        TA0                     0x0001  /* Transmit Successful From Mailbox 0 */
-#define        TA1                     0x0002  /* Transmit Successful From Mailbox 1 */
-#define        TA2                     0x0004  /* Transmit Successful From Mailbox 2 */
-#define        TA3                     0x0008  /* Transmit Successful From Mailbox 3 */
-#define        TA4                     0x0010  /* Transmit Successful From Mailbox 4 */
-#define        TA5                     0x0020  /* Transmit Successful From Mailbox 5 */
-#define        TA6                     0x0040  /* Transmit Successful From Mailbox 6 */
-#define        TA7                     0x0080  /* Transmit Successful From Mailbox 7 */
-#define        TA8                     0x0100  /* Transmit Successful From Mailbox 8 */
-#define        TA9                     0x0200  /* Transmit Successful From Mailbox 9 */
-#define        TA10            0x0400  /* Transmit Successful From Mailbox 10 */
-#define        TA11            0x0800  /* Transmit Successful From Mailbox 11 */
-#define        TA12            0x1000  /* Transmit Successful From Mailbox 12 */
-#define        TA13            0x2000  /* Transmit Successful From Mailbox 13 */
-#define        TA14            0x4000  /* Transmit Successful From Mailbox 14 */
-#define        TA15            0x8000  /* Transmit Successful From Mailbox 15 */
-
-/* CAN_TA2 Masks                                                */
-#define        TA16            0x0001  /* Transmit Successful From Mailbox 16 */
-#define        TA17            0x0002  /* Transmit Successful From Mailbox 17 */
-#define        TA18            0x0004  /* Transmit Successful From Mailbox 18 */
-#define        TA19            0x0008  /* Transmit Successful From Mailbox 19 */
-#define        TA20            0x0010  /* Transmit Successful From Mailbox 20 */
-#define        TA21            0x0020  /* Transmit Successful From Mailbox 21 */
-#define        TA22            0x0040  /* Transmit Successful From Mailbox 22 */
-#define        TA23            0x0080  /* Transmit Successful From Mailbox 23 */
-#define        TA24            0x0100  /* Transmit Successful From Mailbox 24 */
-#define        TA25            0x0200  /* Transmit Successful From Mailbox 25 */
-#define        TA26            0x0400  /* Transmit Successful From Mailbox 26 */
-#define        TA27            0x0800  /* Transmit Successful From Mailbox 27 */
-#define        TA28            0x1000  /* Transmit Successful From Mailbox 28 */
-#define        TA29            0x2000  /* Transmit Successful From Mailbox 29 */
-#define        TA30            0x4000  /* Transmit Successful From Mailbox 30 */
-#define        TA31            0x8000  /* Transmit Successful From Mailbox 31 */
-
-/* CAN_MBTD Masks                                       */
-#define        TDPTR           0x001F  /* Mailbox To Temporarily Disable */
-#define        TDA                     0x0040  /* Temporary Disable Acknowledge */
-#define        TDR                     0x0080  /* Temporary Disable Request */
-
-/* CAN_RFH1 Masks                                                                                       */
-#define        RFH0            0x0001  /* Enable Automatic Remote Frame Handling For Mailbox 0 */
-#define        RFH1            0x0002  /* Enable Automatic Remote Frame Handling For Mailbox 1 */
-#define        RFH2            0x0004  /* Enable Automatic Remote Frame Handling For Mailbox 2 */
-#define        RFH3            0x0008  /* Enable Automatic Remote Frame Handling For Mailbox 3 */
-#define        RFH4            0x0010  /* Enable Automatic Remote Frame Handling For Mailbox 4 */
-#define        RFH5            0x0020  /* Enable Automatic Remote Frame Handling For Mailbox 5 */
-#define        RFH6            0x0040  /* Enable Automatic Remote Frame Handling For Mailbox 6 */
-#define        RFH7            0x0080  /* Enable Automatic Remote Frame Handling For Mailbox 7 */
-#define        RFH8            0x0100  /* Enable Automatic Remote Frame Handling For Mailbox 8 */
-#define        RFH9            0x0200  /* Enable Automatic Remote Frame Handling For Mailbox 9 */
-#define        RFH10           0x0400  /* Enable Automatic Remote Frame Handling For Mailbox 10 */
-#define        RFH11           0x0800  /* Enable Automatic Remote Frame Handling For Mailbox 11 */
-#define        RFH12           0x1000  /* Enable Automatic Remote Frame Handling For Mailbox 12 */
-#define        RFH13           0x2000  /* Enable Automatic Remote Frame Handling For Mailbox 13 */
-#define        RFH14           0x4000  /* Enable Automatic Remote Frame Handling For Mailbox 14 */
-#define        RFH15           0x8000  /* Enable Automatic Remote Frame Handling For Mailbox 15 */
-
-/* CAN_RFH2 Masks                                                                                       */
-#define        RFH16           0x0001  /* Enable Automatic Remote Frame Handling For Mailbox 16 */
-#define        RFH17           0x0002  /* Enable Automatic Remote Frame Handling For Mailbox 17 */
-#define        RFH18           0x0004  /* Enable Automatic Remote Frame Handling For Mailbox 18 */
-#define        RFH19           0x0008  /* Enable Automatic Remote Frame Handling For Mailbox 19 */
-#define        RFH20           0x0010  /* Enable Automatic Remote Frame Handling For Mailbox 20 */
-#define        RFH21           0x0020  /* Enable Automatic Remote Frame Handling For Mailbox 21 */
-#define        RFH22           0x0040  /* Enable Automatic Remote Frame Handling For Mailbox 22 */
-#define        RFH23           0x0080  /* Enable Automatic Remote Frame Handling For Mailbox 23 */
-#define        RFH24           0x0100  /* Enable Automatic Remote Frame Handling For Mailbox 24 */
-#define        RFH25           0x0200  /* Enable Automatic Remote Frame Handling For Mailbox 25 */
-#define        RFH26           0x0400  /* Enable Automatic Remote Frame Handling For Mailbox 26 */
-#define        RFH27           0x0800  /* Enable Automatic Remote Frame Handling For Mailbox 27 */
-#define        RFH28           0x1000  /* Enable Automatic Remote Frame Handling For Mailbox 28 */
-#define        RFH29           0x2000  /* Enable Automatic Remote Frame Handling For Mailbox 29 */
-#define        RFH30           0x4000  /* Enable Automatic Remote Frame Handling For Mailbox 30 */
-#define        RFH31           0x8000  /* Enable Automatic Remote Frame Handling For Mailbox 31 */
-
-/* CAN_MBTIF1 Masks                                             */
-#define        MBTIF0          0x0001  /* TX Interrupt Active In Mailbox 0 */
-#define        MBTIF1          0x0002  /* TX Interrupt Active In Mailbox 1 */
-#define        MBTIF2          0x0004  /* TX Interrupt Active In Mailbox 2 */
-#define        MBTIF3          0x0008  /* TX Interrupt Active In Mailbox 3 */
-#define        MBTIF4          0x0010  /* TX Interrupt Active In Mailbox 4 */
-#define        MBTIF5          0x0020  /* TX Interrupt Active In Mailbox 5 */
-#define        MBTIF6          0x0040  /* TX Interrupt Active In Mailbox 6 */
-#define        MBTIF7          0x0080  /* TX Interrupt Active In Mailbox 7 */
-#define        MBTIF8          0x0100  /* TX Interrupt Active In Mailbox 8 */
-#define        MBTIF9          0x0200  /* TX Interrupt Active In Mailbox 9 */
-#define        MBTIF10         0x0400  /* TX Interrupt Active In Mailbox 10 */
-#define        MBTIF11         0x0800  /* TX Interrupt Active In Mailbox 11 */
-#define        MBTIF12         0x1000  /* TX Interrupt Active In Mailbox 12 */
-#define        MBTIF13         0x2000  /* TX Interrupt Active In Mailbox 13 */
-#define        MBTIF14         0x4000  /* TX Interrupt Active In Mailbox 14 */
-#define        MBTIF15         0x8000  /* TX Interrupt Active In Mailbox 15 */
-
-/* CAN_MBTIF2 Masks                                             */
-#define        MBTIF16         0x0001  /* TX Interrupt Active In Mailbox 16 */
-#define        MBTIF17         0x0002  /* TX Interrupt Active In Mailbox 17 */
-#define        MBTIF18         0x0004  /* TX Interrupt Active In Mailbox 18 */
-#define        MBTIF19         0x0008  /* TX Interrupt Active In Mailbox 19 */
-#define        MBTIF20         0x0010  /* TX Interrupt Active In Mailbox 20 */
-#define        MBTIF21         0x0020  /* TX Interrupt Active In Mailbox 21 */
-#define        MBTIF22         0x0040  /* TX Interrupt Active In Mailbox 22 */
-#define        MBTIF23         0x0080  /* TX Interrupt Active In Mailbox 23 */
-#define        MBTIF24         0x0100  /* TX Interrupt Active In Mailbox 24 */
-#define        MBTIF25         0x0200  /* TX Interrupt Active In Mailbox 25 */
-#define        MBTIF26         0x0400  /* TX Interrupt Active In Mailbox 26 */
-#define        MBTIF27         0x0800  /* TX Interrupt Active In Mailbox 27 */
-#define        MBTIF28         0x1000  /* TX Interrupt Active In Mailbox 28 */
-#define        MBTIF29         0x2000  /* TX Interrupt Active In Mailbox 29 */
-#define        MBTIF30         0x4000  /* TX Interrupt Active In Mailbox 30 */
-#define        MBTIF31         0x8000  /* TX Interrupt Active In Mailbox 31 */
-
-/* CAN_MBRIF1 Masks                                             */
-#define        MBRIF0          0x0001  /* RX Interrupt Active In Mailbox 0 */
-#define        MBRIF1          0x0002  /* RX Interrupt Active In Mailbox 1 */
-#define        MBRIF2          0x0004  /* RX Interrupt Active In Mailbox 2 */
-#define        MBRIF3          0x0008  /* RX Interrupt Active In Mailbox 3 */
-#define        MBRIF4          0x0010  /* RX Interrupt Active In Mailbox 4 */
-#define        MBRIF5          0x0020  /* RX Interrupt Active In Mailbox 5 */
-#define        MBRIF6          0x0040  /* RX Interrupt Active In Mailbox 6 */
-#define        MBRIF7          0x0080  /* RX Interrupt Active In Mailbox 7 */
-#define        MBRIF8          0x0100  /* RX Interrupt Active In Mailbox 8 */
-#define        MBRIF9          0x0200  /* RX Interrupt Active In Mailbox 9 */
-#define        MBRIF10         0x0400  /* RX Interrupt Active In Mailbox 10 */
-#define        MBRIF11         0x0800  /* RX Interrupt Active In Mailbox 11 */
-#define        MBRIF12         0x1000  /* RX Interrupt Active In Mailbox 12 */
-#define        MBRIF13         0x2000  /* RX Interrupt Active In Mailbox 13 */
-#define        MBRIF14         0x4000  /* RX Interrupt Active In Mailbox 14 */
-#define        MBRIF15         0x8000  /* RX Interrupt Active In Mailbox 15 */
-
-/* CAN_MBRIF2 Masks                                             */
-#define        MBRIF16         0x0001  /* RX Interrupt Active In Mailbox 16 */
-#define        MBRIF17         0x0002  /* RX Interrupt Active In Mailbox 17 */
-#define        MBRIF18         0x0004  /* RX Interrupt Active In Mailbox 18 */
-#define        MBRIF19         0x0008  /* RX Interrupt Active In Mailbox 19 */
-#define        MBRIF20         0x0010  /* RX Interrupt Active In Mailbox 20 */
-#define        MBRIF21         0x0020  /* RX Interrupt Active In Mailbox 21 */
-#define        MBRIF22         0x0040  /* RX Interrupt Active In Mailbox 22 */
-#define        MBRIF23         0x0080  /* RX Interrupt Active In Mailbox 23 */
-#define        MBRIF24         0x0100  /* RX Interrupt Active In Mailbox 24 */
-#define        MBRIF25         0x0200  /* RX Interrupt Active In Mailbox 25 */
-#define        MBRIF26         0x0400  /* RX Interrupt Active In Mailbox 26 */
-#define        MBRIF27         0x0800  /* RX Interrupt Active In Mailbox 27 */
-#define        MBRIF28         0x1000  /* RX Interrupt Active In Mailbox 28 */
-#define        MBRIF29         0x2000  /* RX Interrupt Active In Mailbox 29 */
-#define        MBRIF30         0x4000  /* RX Interrupt Active In Mailbox 30 */
-#define        MBRIF31         0x8000  /* RX Interrupt Active In Mailbox 31 */
-
-/* CAN_MBIM1 Masks                                      */
-#define        MBIM0           0x0001  /* Enable Interrupt For Mailbox 0 */
-#define        MBIM1           0x0002  /* Enable Interrupt For Mailbox 1 */
-#define        MBIM2           0x0004  /* Enable Interrupt For Mailbox 2 */
-#define        MBIM3           0x0008  /* Enable Interrupt For Mailbox 3 */
-#define        MBIM4           0x0010  /* Enable Interrupt For Mailbox 4 */
-#define        MBIM5           0x0020  /* Enable Interrupt For Mailbox 5 */
-#define        MBIM6           0x0040  /* Enable Interrupt For Mailbox 6 */
-#define        MBIM7           0x0080  /* Enable Interrupt For Mailbox 7 */
-#define        MBIM8           0x0100  /* Enable Interrupt For Mailbox 8 */
-#define        MBIM9           0x0200  /* Enable Interrupt For Mailbox 9 */
-#define        MBIM10          0x0400  /* Enable Interrupt For Mailbox 10 */
-#define        MBIM11          0x0800  /* Enable Interrupt For Mailbox 11 */
-#define        MBIM12          0x1000  /* Enable Interrupt For Mailbox 12 */
-#define        MBIM13          0x2000  /* Enable Interrupt For Mailbox 13 */
-#define        MBIM14          0x4000  /* Enable Interrupt For Mailbox 14 */
-#define        MBIM15          0x8000  /* Enable Interrupt For Mailbox 15 */
-
-/* CAN_MBIM2 Masks                                      */
-#define        MBIM16          0x0001  /* Enable Interrupt For Mailbox 16 */
-#define        MBIM17          0x0002  /* Enable Interrupt For Mailbox 17 */
-#define        MBIM18          0x0004  /* Enable Interrupt For Mailbox 18 */
-#define        MBIM19          0x0008  /* Enable Interrupt For Mailbox 19 */
-#define        MBIM20          0x0010  /* Enable Interrupt For Mailbox 20 */
-#define        MBIM21          0x0020  /* Enable Interrupt For Mailbox 21 */
-#define        MBIM22          0x0040  /* Enable Interrupt For Mailbox 22 */
-#define        MBIM23          0x0080  /* Enable Interrupt For Mailbox 23 */
-#define        MBIM24          0x0100  /* Enable Interrupt For Mailbox 24 */
-#define        MBIM25          0x0200  /* Enable Interrupt For Mailbox 25 */
-#define        MBIM26          0x0400  /* Enable Interrupt For Mailbox 26 */
-#define        MBIM27          0x0800  /* Enable Interrupt For Mailbox 27 */
-#define        MBIM28          0x1000  /* Enable Interrupt For Mailbox 28 */
-#define        MBIM29          0x2000  /* Enable Interrupt For Mailbox 29 */
-#define        MBIM30          0x4000  /* Enable Interrupt For Mailbox 30 */
-#define        MBIM31          0x8000  /* Enable Interrupt For Mailbox 31 */
-
-/* CAN_GIM Masks                                                                        */
-#define        EWTIM           0x0001  /* Enable TX Error Count Interrupt */
-#define        EWRIM           0x0002  /* Enable RX Error Count Interrupt */
-#define        EPIM            0x0004  /* Enable Error-Passive Mode Interrupt */
-#define        BOIM            0x0008  /* Enable Bus Off Interrupt */
-#define        WUIM            0x0010  /* Enable Wake-Up Interrupt */
-#define        UIAIM           0x0020  /* Enable Access To Unimplemented Address Interrupt */
-#define        AAIM            0x0040  /* Enable Abort Acknowledge Interrupt */
-#define        RMLIM           0x0080  /* Enable RX Message Lost Interrupt */
-#define        UCEIM           0x0100  /* Enable Universal Counter Overflow Interrupt */
-#define        EXTIM           0x0200  /* Enable External Trigger Output Interrupt */
-#define        ADIM            0x0400  /* Enable Access Denied Interrupt */
-
-/* CAN_GIS Masks                                                                */
-#define        EWTIS           0x0001  /* TX Error Count IRQ Status */
-#define        EWRIS           0x0002  /* RX Error Count IRQ Status */
-#define        EPIS            0x0004  /* Error-Passive Mode IRQ Status */
-#define        BOIS            0x0008  /* Bus Off IRQ Status */
-#define        WUIS            0x0010  /* Wake-Up IRQ Status */
-#define        UIAIS           0x0020  /* Access To Unimplemented Address IRQ Status */
-#define        AAIS            0x0040  /* Abort Acknowledge IRQ Status */
-#define        RMLIS           0x0080  /* RX Message Lost IRQ Status */
-#define        UCEIS           0x0100  /* Universal Counter Overflow IRQ Status */
-#define        EXTIS           0x0200  /* External Trigger Output IRQ Status */
-#define        ADIS            0x0400  /* Access Denied IRQ Status */
-
-/* CAN_GIF Masks                                                                */
-#define        EWTIF           0x0001  /* TX Error Count IRQ Flag */
-#define        EWRIF           0x0002  /* RX Error Count IRQ Flag */
-#define        EPIF            0x0004  /* Error-Passive Mode IRQ Flag */
-#define        BOIF            0x0008  /* Bus Off IRQ Flag      */
-#define        WUIF            0x0010  /* Wake-Up IRQ Flag      */
-#define        UIAIF           0x0020  /* Access To Unimplemented Address IRQ Flag */
-#define        AAIF            0x0040  /* Abort Acknowledge IRQ Flag */
-#define        RMLIF           0x0080  /* RX Message Lost IRQ Flag */
-#define        UCEIF           0x0100  /* Universal Counter Overflow IRQ Flag */
-#define        EXTIF           0x0200  /* External Trigger Output IRQ Flag */
-#define        ADIF            0x0400  /* Access Denied IRQ Flag */
-
-/* CAN_UCCNF Masks                                                              */
-#define        UCCNF           0x000F  /* Universal Counter Mode */
-#define        UC_STAMP        0x0001  /*              Timestamp Mode */
-#define        UC_WDOG         0x0002  /*              Watchdog Mode */
-#define        UC_AUTOTX       0x0003  /*              Auto-Transmit Mode */
-#define        UC_ERROR        0x0006  /*              CAN Error Frame Count */
-#define        UC_OVER         0x0007  /*              CAN Overload Frame Count */
-#define        UC_LOST         0x0008  /*              Arbitration Lost During TX Count */
-#define        UC_AA           0x0009  /*              TX Abort Count */
-#define        UC_TA           0x000A  /*              TX Successful Count */
-#define        UC_REJECT       0x000B  /*              RX Message Rejected Count */
-#define        UC_RML          0x000C  /*              RX Message Lost Count */
-#define        UC_RX           0x000D  /*              Total Successful RX Messages Count */
-#define        UC_RMP          0x000E  /*              Successful RX W/Matching ID Count */
-#define        UC_ALL          0x000F  /*              Correct Message On CAN Bus Line Count */
-#define        UCRC            0x0020  /* Universal Counter Reload/Clear */
-#define        UCCT            0x0040  /* Universal Counter CAN Trigger */
-#define        UCE                     0x0080  /* Universal Counter Enable */
-
-/* CAN_ESR Masks                        */
-#define        ACKE            0x0004  /* Acknowledge Error */
-#define        SER                     0x0008  /* Stuff Error */
-#define        CRCE            0x0010  /* CRC Error */
-#define        SA0                     0x0020  /* Stuck At Dominant Error */
-#define        BEF                     0x0040  /* Bit Error Flag */
-#define        FER                     0x0080  /* Form Error Flag */
-
-/* CAN_EWR Masks                                        */
-#define        EWLREC          0x00FF  /* RX Error Count Limit (For EWRIS) */
-#define        EWLTEC          0xFF00  /* TX Error Count Limit (For EWTIS) */
-
 #endif /* _DEF_BF539_H */
index f60c333fec667ea8c88f0023659e8d2ae9dcab8e..dbb6b1d83f6dc7a2d0dc1861f23d0856a1170bd0 100644 (file)
@@ -498,6 +498,10 @@ static struct musb_hdrc_config musb_config = {
        .num_eps        = 8,
        .dma_channels   = 8,
        .gpio_vrsel     = GPIO_PH6,
+       /* Some custom boards need to be active low, just set it to "0"
+        * if it is the case.
+        */
+       .gpio_vrsel_active      = 1,
 };
 
 static struct musb_hdrc_platform_data musb_plat = {
index 06919db00a7419df563e40a00ac65ca5220caa7c..6fcfb9187c357bcf1b69f5ae821fec5386f6dc6b 100644 (file)
@@ -603,6 +603,10 @@ static struct musb_hdrc_config musb_config = {
        .num_eps        = 8,
        .dma_channels   = 8,
        .gpio_vrsel     = GPIO_PE7,
+       /* Some custom boards need to be active low, just set it to "0"
+        * if it is the case.
+        */
+       .gpio_vrsel_active      = 1,
 };
 
 static struct musb_hdrc_platform_data musb_plat = {
index ab04d137fd8bc585fb86c099709c938d6e26491e..0ed06c2366fe9ca744db5dd51393e4c573d733c3 100644 (file)
 
 #define                    ECCCNT  0x3ff      /* Transfer Count */
 
-/* Bit masks for CAN0_CONTROL */
-
-#define                       SRS  0x1        /* Software Reset */
-#define                       DNM  0x2        /* DeviceNet Mode */
-#define                       ABO  0x4        /* Auto Bus On */
-#define                       WBA  0x10       /* Wakeup On CAN Bus Activity */
-#define                       SMR  0x20       /* Sleep Mode Request */
-#define                       CSR  0x40       /* CAN Suspend Mode Request */
-#define                       CCR  0x80       /* CAN Configuration Mode Request */
-
-/* Bit masks for CAN0_STATUS */
-
-#define                        WT  0x1        /* CAN Transmit Warning Flag */
-#define                        WR  0x2        /* CAN Receive Warning Flag */
-#define                        EP  0x4        /* CAN Error Passive Mode */
-#define                       EBO  0x8        /* CAN Error Bus Off Mode */
-#define                       CSA  0x40       /* CAN Suspend Mode Acknowledge */
-#define                       CCA  0x80       /* CAN Configuration Mode Acknowledge */
-#define                     MBPTR  0x1f00     /* Mailbox Pointer */
-#define                       TRM  0x4000     /* Transmit Mode Status */
-#define                       REC  0x8000     /* Receive Mode Status */
-
-/* Bit masks for CAN0_DEBUG */
-
-#define                       DEC  0x1        /* Disable Transmit/Receive Error Counters */
-#define                       DRI  0x2        /* Disable CANRX Input Pin */
-#define                       DTO  0x4        /* Disable CANTX Output Pin */
-#define                       DIL  0x8        /* Disable Internal Loop */
-#define                       MAA  0x10       /* Mode Auto-Acknowledge */
-#define                       MRB  0x20       /* Mode Read Back */
-#define                       CDE  0x8000     /* CAN Debug Mode Enable */
-
-/* Bit masks for CAN0_CLOCK */
-
-#define                       BRP  0x3ff      /* CAN Bit Rate Prescaler */
-
-/* Bit masks for CAN0_TIMING */
-
-#define                       SJW  0x300      /* Synchronization Jump Width */
-#define                       SAM  0x80       /* Sampling */
-#define                     TSEG2  0x70       /* Time Segment 2 */
-#define                     TSEG1  0xf        /* Time Segment 1 */
-
-/* Bit masks for CAN0_INTR */
-
-#define                     CANRX  0x80       /* Serial Input From Transceiver */
-#define                     CANTX  0x40       /* Serial Output To Transceiver */
-#define                     SMACK  0x8        /* Sleep Mode Acknowledge */
-#define                      GIRQ  0x4        /* Global Interrupt Request Status */
-#define                    MBTIRQ  0x2        /* Mailbox Transmit Interrupt Request */
-#define                    MBRIRQ  0x1        /* Mailbox Receive Interrupt Request */
-
-/* Bit masks for CAN0_GIM */
-
-#define                     EWTIM  0x1        /* Error Warning Transmit Interrupt Mask */
-#define                     EWRIM  0x2        /* Error Warning Receive Interrupt Mask */
-#define                      EPIM  0x4        /* Error Passive Interrupt Mask */
-#define                      BOIM  0x8        /* Bus Off Interrupt Mask */
-#define                      WUIM  0x10       /* Wakeup Interrupt Mask */
-#define                     UIAIM  0x20       /* Unimplemented Address Interrupt Mask */
-#define                      AAIM  0x40       /* Abort Acknowledge Interrupt Mask */
-#define                     RMLIM  0x80       /* Receive Message Lost Interrupt Mask */
-#define                     UCEIM  0x100      /* Universal Counter Exceeded Interrupt Mask */
-#define                      ADIM  0x400      /* Access Denied Interrupt Mask */
-
-/* Bit masks for CAN0_GIS */
-
-#define                     EWTIS  0x1        /* Error Warning Transmit Interrupt Status */
-#define                     EWRIS  0x2        /* Error Warning Receive Interrupt Status */
-#define                      EPIS  0x4        /* Error Passive Interrupt Status */
-#define                      BOIS  0x8        /* Bus Off Interrupt Status */
-#define                      WUIS  0x10       /* Wakeup Interrupt Status */
-#define                     UIAIS  0x20       /* Unimplemented Address Interrupt Status */
-#define                      AAIS  0x40       /* Abort Acknowledge Interrupt Status */
-#define                     RMLIS  0x80       /* Receive Message Lost Interrupt Status */
-#define                     UCEIS  0x100      /* Universal Counter Exceeded Interrupt Status */
-#define                      ADIS  0x400      /* Access Denied Interrupt Status */
-
-/* Bit masks for CAN0_GIF */
-
-#define                     EWTIF  0x1        /* Error Warning Transmit Interrupt Flag */
-#define                     EWRIF  0x2        /* Error Warning Receive Interrupt Flag */
-#define                      EPIF  0x4        /* Error Passive Interrupt Flag */
-#define                      BOIF  0x8        /* Bus Off Interrupt Flag */
-#define                      WUIF  0x10       /* Wakeup Interrupt Flag */
-#define                     UIAIF  0x20       /* Unimplemented Address Interrupt Flag */
-#define                      AAIF  0x40       /* Abort Acknowledge Interrupt Flag */
-#define                     RMLIF  0x80       /* Receive Message Lost Interrupt Flag */
-#define                     UCEIF  0x100      /* Universal Counter Exceeded Interrupt Flag */
-#define                      ADIF  0x400      /* Access Denied Interrupt Flag */
-
-/* Bit masks for CAN0_MBTD */
-
-#define                       TDR  0x80       /* Temporary Disable Request */
-#define                       TDA  0x40       /* Temporary Disable Acknowledge */
-#define                     TDPTR  0x1f       /* Temporary Disable Pointer */
-
-/* Bit masks for CAN0_UCCNF */
-
-#define                     UCCNF  0xf        /* Universal Counter Configuration */
-#define                      UCRC  0x20       /* Universal Counter Reload/Clear */
-#define                      UCCT  0x40       /* Universal Counter CAN Trigger */
-#define                       UCE  0x80       /* Universal Counter Enable */
-
-/* Bit masks for CAN0_CEC */
-
-#define                    RXECNT  0xff       /* Receive Error Counter */
-#define                    TXECNT  0xff00     /* Transmit Error Counter */
-
-/* Bit masks for CAN0_ESR */
-
-#define                       FER  0x80       /* Form Error */
-#define                       BEF  0x40       /* Bit Error Flag */
-#define                       SA0  0x20       /* Stuck At Dominant */
-#define                      CRCE  0x10       /* CRC Error */
-#define                       SER  0x8        /* Stuff Bit Error */
-#define                      ACKE  0x4        /* Acknowledge Error */
-
-/* Bit masks for CAN0_EWR */
-
-#define                    EWLTEC  0xff00     /* Transmit Error Warning Limit */
-#define                    EWLREC  0xff       /* Receive Error Warning Limit */
-
-/* Bit masks for CAN0_AMxx_H */
-
-#define                       FDF  0x8000     /* Filter On Data Field */
-#define                       FMD  0x4000     /* Full Mask Data */
-#define                     AMIDE  0x2000     /* Acceptance Mask Identifier Extension */
-#define                    BASEID  0x1ffc     /* Base Identifier */
-#define                  EXTID_HI  0x3        /* Extended Identifier High Bits */
-
-/* Bit masks for CAN0_AMxx_L */
-
-#define                  EXTID_LO  0xffff     /* Extended Identifier Low Bits */
-#define                       DFM  0xffff     /* Data Field Mask */
-
-/* Bit masks for CAN0_MBxx_ID1 */
-
-#define                       AME  0x8000     /* Acceptance Mask Enable */
-#define                       RTR  0x4000     /* Remote Transmission Request */
-#define                       IDE  0x2000     /* Identifier Extension */
-#define                    BASEID  0x1ffc     /* Base Identifier */
-#define                  EXTID_HI  0x3        /* Extended Identifier High Bits */
-
-/* Bit masks for CAN0_MBxx_ID0 */
-
-#define                  EXTID_LO  0xffff     /* Extended Identifier Low Bits */
-#define                       DFM  0xffff     /* Data Field Mask */
-
-/* Bit masks for CAN0_MBxx_TIMESTAMP */
-
-#define                       TSV  0xffff     /* Time Stamp Value */
-
-/* Bit masks for CAN0_MBxx_LENGTH */
-
-#define                       DLC  0xf        /* Data Length Code */
-
-/* Bit masks for CAN0_MBxx_DATA3 */
-
-#define                 CAN_BYTE0  0xff00     /* Data Field Byte 0 */
-#define                 CAN_BYTE1  0xff       /* Data Field Byte 1 */
-
-/* Bit masks for CAN0_MBxx_DATA2 */
-
-#define                 CAN_BYTE2  0xff00     /* Data Field Byte 2 */
-#define                 CAN_BYTE3  0xff       /* Data Field Byte 3 */
-
-/* Bit masks for CAN0_MBxx_DATA1 */
-
-#define                 CAN_BYTE4  0xff00     /* Data Field Byte 4 */
-#define                 CAN_BYTE5  0xff       /* Data Field Byte 5 */
-
-/* Bit masks for CAN0_MBxx_DATA0 */
-
-#define                 CAN_BYTE6  0xff00     /* Data Field Byte 6 */
-#define                 CAN_BYTE7  0xff       /* Data Field Byte 7 */
-
-/* Bit masks for CAN0_MC1 */
-
-#define                       MC0  0x1        /* Mailbox 0 Enable */
-#define                       MC1  0x2        /* Mailbox 1 Enable */
-#define                       MC2  0x4        /* Mailbox 2 Enable */
-#define                       MC3  0x8        /* Mailbox 3 Enable */
-#define                       MC4  0x10       /* Mailbox 4 Enable */
-#define                       MC5  0x20       /* Mailbox 5 Enable */
-#define                       MC6  0x40       /* Mailbox 6 Enable */
-#define                       MC7  0x80       /* Mailbox 7 Enable */
-#define                       MC8  0x100      /* Mailbox 8 Enable */
-#define                       MC9  0x200      /* Mailbox 9 Enable */
-#define                      MC10  0x400      /* Mailbox 10 Enable */
-#define                      MC11  0x800      /* Mailbox 11 Enable */
-#define                      MC12  0x1000     /* Mailbox 12 Enable */
-#define                      MC13  0x2000     /* Mailbox 13 Enable */
-#define                      MC14  0x4000     /* Mailbox 14 Enable */
-#define                      MC15  0x8000     /* Mailbox 15 Enable */
-
-/* Bit masks for CAN0_MC2 */
-
-#define                      MC16  0x1        /* Mailbox 16 Enable */
-#define                      MC17  0x2        /* Mailbox 17 Enable */
-#define                      MC18  0x4        /* Mailbox 18 Enable */
-#define                      MC19  0x8        /* Mailbox 19 Enable */
-#define                      MC20  0x10       /* Mailbox 20 Enable */
-#define                      MC21  0x20       /* Mailbox 21 Enable */
-#define                      MC22  0x40       /* Mailbox 22 Enable */
-#define                      MC23  0x80       /* Mailbox 23 Enable */
-#define                      MC24  0x100      /* Mailbox 24 Enable */
-#define                      MC25  0x200      /* Mailbox 25 Enable */
-#define                      MC26  0x400      /* Mailbox 26 Enable */
-#define                      MC27  0x800      /* Mailbox 27 Enable */
-#define                      MC28  0x1000     /* Mailbox 28 Enable */
-#define                      MC29  0x2000     /* Mailbox 29 Enable */
-#define                      MC30  0x4000     /* Mailbox 30 Enable */
-#define                      MC31  0x8000     /* Mailbox 31 Enable */
-
-/* Bit masks for CAN0_MD1 */
-
-#define                       MD0  0x1        /* Mailbox 0 Receive Enable */
-#define                       MD1  0x2        /* Mailbox 1 Receive Enable */
-#define                       MD2  0x4        /* Mailbox 2 Receive Enable */
-#define                       MD3  0x8        /* Mailbox 3 Receive Enable */
-#define                       MD4  0x10       /* Mailbox 4 Receive Enable */
-#define                       MD5  0x20       /* Mailbox 5 Receive Enable */
-#define                       MD6  0x40       /* Mailbox 6 Receive Enable */
-#define                       MD7  0x80       /* Mailbox 7 Receive Enable */
-#define                       MD8  0x100      /* Mailbox 8 Receive Enable */
-#define                       MD9  0x200      /* Mailbox 9 Receive Enable */
-#define                      MD10  0x400      /* Mailbox 10 Receive Enable */
-#define                      MD11  0x800      /* Mailbox 11 Receive Enable */
-#define                      MD12  0x1000     /* Mailbox 12 Receive Enable */
-#define                      MD13  0x2000     /* Mailbox 13 Receive Enable */
-#define                      MD14  0x4000     /* Mailbox 14 Receive Enable */
-#define                      MD15  0x8000     /* Mailbox 15 Receive Enable */
-
-/* Bit masks for CAN0_MD2 */
-
-#define                      MD16  0x1        /* Mailbox 16 Receive Enable */
-#define                      MD17  0x2        /* Mailbox 17 Receive Enable */
-#define                      MD18  0x4        /* Mailbox 18 Receive Enable */
-#define                      MD19  0x8        /* Mailbox 19 Receive Enable */
-#define                      MD20  0x10       /* Mailbox 20 Receive Enable */
-#define                      MD21  0x20       /* Mailbox 21 Receive Enable */
-#define                      MD22  0x40       /* Mailbox 22 Receive Enable */
-#define                      MD23  0x80       /* Mailbox 23 Receive Enable */
-#define                      MD24  0x100      /* Mailbox 24 Receive Enable */
-#define                      MD25  0x200      /* Mailbox 25 Receive Enable */
-#define                      MD26  0x400      /* Mailbox 26 Receive Enable */
-#define                      MD27  0x800      /* Mailbox 27 Receive Enable */
-#define                      MD28  0x1000     /* Mailbox 28 Receive Enable */
-#define                      MD29  0x2000     /* Mailbox 29 Receive Enable */
-#define                      MD30  0x4000     /* Mailbox 30 Receive Enable */
-#define                      MD31  0x8000     /* Mailbox 31 Receive Enable */
-
-/* Bit masks for CAN0_RMP1 */
-
-#define                      RMP0  0x1        /* Mailbox 0 Receive Message Pending */
-#define                      RMP1  0x2        /* Mailbox 1 Receive Message Pending */
-#define                      RMP2  0x4        /* Mailbox 2 Receive Message Pending */
-#define                      RMP3  0x8        /* Mailbox 3 Receive Message Pending */
-#define                      RMP4  0x10       /* Mailbox 4 Receive Message Pending */
-#define                      RMP5  0x20       /* Mailbox 5 Receive Message Pending */
-#define                      RMP6  0x40       /* Mailbox 6 Receive Message Pending */
-#define                      RMP7  0x80       /* Mailbox 7 Receive Message Pending */
-#define                      RMP8  0x100      /* Mailbox 8 Receive Message Pending */
-#define                      RMP9  0x200      /* Mailbox 9 Receive Message Pending */
-#define                     RMP10  0x400      /* Mailbox 10 Receive Message Pending */
-#define                     RMP11  0x800      /* Mailbox 11 Receive Message Pending */
-#define                     RMP12  0x1000     /* Mailbox 12 Receive Message Pending */
-#define                     RMP13  0x2000     /* Mailbox 13 Receive Message Pending */
-#define                     RMP14  0x4000     /* Mailbox 14 Receive Message Pending */
-#define                     RMP15  0x8000     /* Mailbox 15 Receive Message Pending */
-
-/* Bit masks for CAN0_RMP2 */
-
-#define                     RMP16  0x1        /* Mailbox 16 Receive Message Pending */
-#define                     RMP17  0x2        /* Mailbox 17 Receive Message Pending */
-#define                     RMP18  0x4        /* Mailbox 18 Receive Message Pending */
-#define                     RMP19  0x8        /* Mailbox 19 Receive Message Pending */
-#define                     RMP20  0x10       /* Mailbox 20 Receive Message Pending */
-#define                     RMP21  0x20       /* Mailbox 21 Receive Message Pending */
-#define                     RMP22  0x40       /* Mailbox 22 Receive Message Pending */
-#define                     RMP23  0x80       /* Mailbox 23 Receive Message Pending */
-#define                     RMP24  0x100      /* Mailbox 24 Receive Message Pending */
-#define                     RMP25  0x200      /* Mailbox 25 Receive Message Pending */
-#define                     RMP26  0x400      /* Mailbox 26 Receive Message Pending */
-#define                     RMP27  0x800      /* Mailbox 27 Receive Message Pending */
-#define                     RMP28  0x1000     /* Mailbox 28 Receive Message Pending */
-#define                     RMP29  0x2000     /* Mailbox 29 Receive Message Pending */
-#define                     RMP30  0x4000     /* Mailbox 30 Receive Message Pending */
-#define                     RMP31  0x8000     /* Mailbox 31 Receive Message Pending */
-
-/* Bit masks for CAN0_RML1 */
-
-#define                      RML0  0x1        /* Mailbox 0 Receive Message Lost */
-#define                      RML1  0x2        /* Mailbox 1 Receive Message Lost */
-#define                      RML2  0x4        /* Mailbox 2 Receive Message Lost */
-#define                      RML3  0x8        /* Mailbox 3 Receive Message Lost */
-#define                      RML4  0x10       /* Mailbox 4 Receive Message Lost */
-#define                      RML5  0x20       /* Mailbox 5 Receive Message Lost */
-#define                      RML6  0x40       /* Mailbox 6 Receive Message Lost */
-#define                      RML7  0x80       /* Mailbox 7 Receive Message Lost */
-#define                      RML8  0x100      /* Mailbox 8 Receive Message Lost */
-#define                      RML9  0x200      /* Mailbox 9 Receive Message Lost */
-#define                     RML10  0x400      /* Mailbox 10 Receive Message Lost */
-#define                     RML11  0x800      /* Mailbox 11 Receive Message Lost */
-#define                     RML12  0x1000     /* Mailbox 12 Receive Message Lost */
-#define                     RML13  0x2000     /* Mailbox 13 Receive Message Lost */
-#define                     RML14  0x4000     /* Mailbox 14 Receive Message Lost */
-#define                     RML15  0x8000     /* Mailbox 15 Receive Message Lost */
-
-/* Bit masks for CAN0_RML2 */
-
-#define                     RML16  0x1        /* Mailbox 16 Receive Message Lost */
-#define                     RML17  0x2        /* Mailbox 17 Receive Message Lost */
-#define                     RML18  0x4        /* Mailbox 18 Receive Message Lost */
-#define                     RML19  0x8        /* Mailbox 19 Receive Message Lost */
-#define                     RML20  0x10       /* Mailbox 20 Receive Message Lost */
-#define                     RML21  0x20       /* Mailbox 21 Receive Message Lost */
-#define                     RML22  0x40       /* Mailbox 22 Receive Message Lost */
-#define                     RML23  0x80       /* Mailbox 23 Receive Message Lost */
-#define                     RML24  0x100      /* Mailbox 24 Receive Message Lost */
-#define                     RML25  0x200      /* Mailbox 25 Receive Message Lost */
-#define                     RML26  0x400      /* Mailbox 26 Receive Message Lost */
-#define                     RML27  0x800      /* Mailbox 27 Receive Message Lost */
-#define                     RML28  0x1000     /* Mailbox 28 Receive Message Lost */
-#define                     RML29  0x2000     /* Mailbox 29 Receive Message Lost */
-#define                     RML30  0x4000     /* Mailbox 30 Receive Message Lost */
-#define                     RML31  0x8000     /* Mailbox 31 Receive Message Lost */
-
-/* Bit masks for CAN0_OPSS1 */
-
-#define                     OPSS0  0x1        /* Mailbox 0 Overwrite Protection/Single-Shot Transmission Enable */
-#define                     OPSS1  0x2        /* Mailbox 1 Overwrite Protection/Single-Shot Transmission Enable */
-#define                     OPSS2  0x4        /* Mailbox 2 Overwrite Protection/Single-Shot Transmission Enable */
-#define                     OPSS3  0x8        /* Mailbox 3 Overwrite Protection/Single-Shot Transmission Enable */
-#define                     OPSS4  0x10       /* Mailbox 4 Overwrite Protection/Single-Shot Transmission Enable */
-#define                     OPSS5  0x20       /* Mailbox 5 Overwrite Protection/Single-Shot Transmission Enable */
-#define                     OPSS6  0x40       /* Mailbox 6 Overwrite Protection/Single-Shot Transmission Enable */
-#define                     OPSS7  0x80       /* Mailbox 7 Overwrite Protection/Single-Shot Transmission Enable */
-#define                     OPSS8  0x100      /* Mailbox 8 Overwrite Protection/Single-Shot Transmission Enable */
-#define                     OPSS9  0x200      /* Mailbox 9 Overwrite Protection/Single-Shot Transmission Enable */
-#define                    OPSS10  0x400      /* Mailbox 10 Overwrite Protection/Single-Shot Transmission Enable */
-#define                    OPSS11  0x800      /* Mailbox 11 Overwrite Protection/Single-Shot Transmission Enable */
-#define                    OPSS12  0x1000     /* Mailbox 12 Overwrite Protection/Single-Shot Transmission Enable */
-#define                    OPSS13  0x2000     /* Mailbox 13 Overwrite Protection/Single-Shot Transmission Enable */
-#define                    OPSS14  0x4000     /* Mailbox 14 Overwrite Protection/Single-Shot Transmission Enable */
-#define                    OPSS15  0x8000     /* Mailbox 15 Overwrite Protection/Single-Shot Transmission Enable */
-
-/* Bit masks for CAN0_OPSS2 */
-
-#define                    OPSS16  0x1        /* Mailbox 16 Overwrite Protection/Single-Shot Transmission Enable */
-#define                    OPSS17  0x2        /* Mailbox 17 Overwrite Protection/Single-Shot Transmission Enable */
-#define                    OPSS18  0x4        /* Mailbox 18 Overwrite Protection/Single-Shot Transmission Enable */
-#define                    OPSS19  0x8        /* Mailbox 19 Overwrite Protection/Single-Shot Transmission Enable */
-#define                    OPSS20  0x10       /* Mailbox 20 Overwrite Protection/Single-Shot Transmission Enable */
-#define                    OPSS21  0x20       /* Mailbox 21 Overwrite Protection/Single-Shot Transmission Enable */
-#define                    OPSS22  0x40       /* Mailbox 22 Overwrite Protection/Single-Shot Transmission Enable */
-#define                    OPSS23  0x80       /* Mailbox 23 Overwrite Protection/Single-Shot Transmission Enable */
-#define                    OPSS24  0x100      /* Mailbox 24 Overwrite Protection/Single-Shot Transmission Enable */
-#define                    OPSS25  0x200      /* Mailbox 25 Overwrite Protection/Single-Shot Transmission Enable */
-#define                    OPSS26  0x400      /* Mailbox 26 Overwrite Protection/Single-Shot Transmission Enable */
-#define                    OPSS27  0x800      /* Mailbox 27 Overwrite Protection/Single-Shot Transmission Enable */
-#define                    OPSS28  0x1000     /* Mailbox 28 Overwrite Protection/Single-Shot Transmission Enable */
-#define                    OPSS29  0x2000     /* Mailbox 29 Overwrite Protection/Single-Shot Transmission Enable */
-#define                    OPSS30  0x4000     /* Mailbox 30 Overwrite Protection/Single-Shot Transmission Enable */
-#define                    OPSS31  0x8000     /* Mailbox 31 Overwrite Protection/Single-Shot Transmission Enable */
-
-/* Bit masks for CAN0_TRS1 */
-
-#define                      TRS0  0x1        /* Mailbox 0 Transmit Request Set */
-#define                      TRS1  0x2        /* Mailbox 1 Transmit Request Set */
-#define                      TRS2  0x4        /* Mailbox 2 Transmit Request Set */
-#define                      TRS3  0x8        /* Mailbox 3 Transmit Request Set */
-#define                      TRS4  0x10       /* Mailbox 4 Transmit Request Set */
-#define                      TRS5  0x20       /* Mailbox 5 Transmit Request Set */
-#define                      TRS6  0x40       /* Mailbox 6 Transmit Request Set */
-#define                      TRS7  0x80       /* Mailbox 7 Transmit Request Set */
-#define                      TRS8  0x100      /* Mailbox 8 Transmit Request Set */
-#define                      TRS9  0x200      /* Mailbox 9 Transmit Request Set */
-#define                     TRS10  0x400      /* Mailbox 10 Transmit Request Set */
-#define                     TRS11  0x800      /* Mailbox 11 Transmit Request Set */
-#define                     TRS12  0x1000     /* Mailbox 12 Transmit Request Set */
-#define                     TRS13  0x2000     /* Mailbox 13 Transmit Request Set */
-#define                     TRS14  0x4000     /* Mailbox 14 Transmit Request Set */
-#define                     TRS15  0x8000     /* Mailbox 15 Transmit Request Set */
-
-/* Bit masks for CAN0_TRS2 */
-
-#define                     TRS16  0x1        /* Mailbox 16 Transmit Request Set */
-#define                     TRS17  0x2        /* Mailbox 17 Transmit Request Set */
-#define                     TRS18  0x4        /* Mailbox 18 Transmit Request Set */
-#define                     TRS19  0x8        /* Mailbox 19 Transmit Request Set */
-#define                     TRS20  0x10       /* Mailbox 20 Transmit Request Set */
-#define                     TRS21  0x20       /* Mailbox 21 Transmit Request Set */
-#define                     TRS22  0x40       /* Mailbox 22 Transmit Request Set */
-#define                     TRS23  0x80       /* Mailbox 23 Transmit Request Set */
-#define                     TRS24  0x100      /* Mailbox 24 Transmit Request Set */
-#define                     TRS25  0x200      /* Mailbox 25 Transmit Request Set */
-#define                     TRS26  0x400      /* Mailbox 26 Transmit Request Set */
-#define                     TRS27  0x800      /* Mailbox 27 Transmit Request Set */
-#define                     TRS28  0x1000     /* Mailbox 28 Transmit Request Set */
-#define                     TRS29  0x2000     /* Mailbox 29 Transmit Request Set */
-#define                     TRS30  0x4000     /* Mailbox 30 Transmit Request Set */
-#define                     TRS31  0x8000     /* Mailbox 31 Transmit Request Set */
-
-/* Bit masks for CAN0_TRR1 */
-
-#define                      TRR0  0x1        /* Mailbox 0 Transmit Request Reset */
-#define                      TRR1  0x2        /* Mailbox 1 Transmit Request Reset */
-#define                      TRR2  0x4        /* Mailbox 2 Transmit Request Reset */
-#define                      TRR3  0x8        /* Mailbox 3 Transmit Request Reset */
-#define                      TRR4  0x10       /* Mailbox 4 Transmit Request Reset */
-#define                      TRR5  0x20       /* Mailbox 5 Transmit Request Reset */
-#define                      TRR6  0x40       /* Mailbox 6 Transmit Request Reset */
-#define                      TRR7  0x80       /* Mailbox 7 Transmit Request Reset */
-#define                      TRR8  0x100      /* Mailbox 8 Transmit Request Reset */
-#define                      TRR9  0x200      /* Mailbox 9 Transmit Request Reset */
-#define                     TRR10  0x400      /* Mailbox 10 Transmit Request Reset */
-#define                     TRR11  0x800      /* Mailbox 11 Transmit Request Reset */
-#define                     TRR12  0x1000     /* Mailbox 12 Transmit Request Reset */
-#define                     TRR13  0x2000     /* Mailbox 13 Transmit Request Reset */
-#define                     TRR14  0x4000     /* Mailbox 14 Transmit Request Reset */
-#define                     TRR15  0x8000     /* Mailbox 15 Transmit Request Reset */
-
-/* Bit masks for CAN0_TRR2 */
-
-#define                     TRR16  0x1        /* Mailbox 16 Transmit Request Reset */
-#define                     TRR17  0x2        /* Mailbox 17 Transmit Request Reset */
-#define                     TRR18  0x4        /* Mailbox 18 Transmit Request Reset */
-#define                     TRR19  0x8        /* Mailbox 19 Transmit Request Reset */
-#define                     TRR20  0x10       /* Mailbox 20 Transmit Request Reset */
-#define                     TRR21  0x20       /* Mailbox 21 Transmit Request Reset */
-#define                     TRR22  0x40       /* Mailbox 22 Transmit Request Reset */
-#define                     TRR23  0x80       /* Mailbox 23 Transmit Request Reset */
-#define                     TRR24  0x100      /* Mailbox 24 Transmit Request Reset */
-#define                     TRR25  0x200      /* Mailbox 25 Transmit Request Reset */
-#define                     TRR26  0x400      /* Mailbox 26 Transmit Request Reset */
-#define                     TRR27  0x800      /* Mailbox 27 Transmit Request Reset */
-#define                     TRR28  0x1000     /* Mailbox 28 Transmit Request Reset */
-#define                     TRR29  0x2000     /* Mailbox 29 Transmit Request Reset */
-#define                     TRR30  0x4000     /* Mailbox 30 Transmit Request Reset */
-#define                     TRR31  0x8000     /* Mailbox 31 Transmit Request Reset */
-
-/* Bit masks for CAN0_AA1 */
-
-#define                       AA0  0x1        /* Mailbox 0 Abort Acknowledge */
-#define                       AA1  0x2        /* Mailbox 1 Abort Acknowledge */
-#define                       AA2  0x4        /* Mailbox 2 Abort Acknowledge */
-#define                       AA3  0x8        /* Mailbox 3 Abort Acknowledge */
-#define                       AA4  0x10       /* Mailbox 4 Abort Acknowledge */
-#define                       AA5  0x20       /* Mailbox 5 Abort Acknowledge */
-#define                       AA6  0x40       /* Mailbox 6 Abort Acknowledge */
-#define                       AA7  0x80       /* Mailbox 7 Abort Acknowledge */
-#define                       AA8  0x100      /* Mailbox 8 Abort Acknowledge */
-#define                       AA9  0x200      /* Mailbox 9 Abort Acknowledge */
-#define                      AA10  0x400      /* Mailbox 10 Abort Acknowledge */
-#define                      AA11  0x800      /* Mailbox 11 Abort Acknowledge */
-#define                      AA12  0x1000     /* Mailbox 12 Abort Acknowledge */
-#define                      AA13  0x2000     /* Mailbox 13 Abort Acknowledge */
-#define                      AA14  0x4000     /* Mailbox 14 Abort Acknowledge */
-#define                      AA15  0x8000     /* Mailbox 15 Abort Acknowledge */
-
-/* Bit masks for CAN0_AA2 */
-
-#define                      AA16  0x1        /* Mailbox 16 Abort Acknowledge */
-#define                      AA17  0x2        /* Mailbox 17 Abort Acknowledge */
-#define                      AA18  0x4        /* Mailbox 18 Abort Acknowledge */
-#define                      AA19  0x8        /* Mailbox 19 Abort Acknowledge */
-#define                      AA20  0x10       /* Mailbox 20 Abort Acknowledge */
-#define                      AA21  0x20       /* Mailbox 21 Abort Acknowledge */
-#define                      AA22  0x40       /* Mailbox 22 Abort Acknowledge */
-#define                      AA23  0x80       /* Mailbox 23 Abort Acknowledge */
-#define                      AA24  0x100      /* Mailbox 24 Abort Acknowledge */
-#define                      AA25  0x200      /* Mailbox 25 Abort Acknowledge */
-#define                      AA26  0x400      /* Mailbox 26 Abort Acknowledge */
-#define                      AA27  0x800      /* Mailbox 27 Abort Acknowledge */
-#define                      AA28  0x1000     /* Mailbox 28 Abort Acknowledge */
-#define                      AA29  0x2000     /* Mailbox 29 Abort Acknowledge */
-#define                      AA30  0x4000     /* Mailbox 30 Abort Acknowledge */
-#define                      AA31  0x8000     /* Mailbox 31 Abort Acknowledge */
-
-/* Bit masks for CAN0_TA1 */
-
-#define                       TA0  0x1        /* Mailbox 0 Transmit Acknowledge */
-#define                       TA1  0x2        /* Mailbox 1 Transmit Acknowledge */
-#define                       TA2  0x4        /* Mailbox 2 Transmit Acknowledge */
-#define                       TA3  0x8        /* Mailbox 3 Transmit Acknowledge */
-#define                       TA4  0x10       /* Mailbox 4 Transmit Acknowledge */
-#define                       TA5  0x20       /* Mailbox 5 Transmit Acknowledge */
-#define                       TA6  0x40       /* Mailbox 6 Transmit Acknowledge */
-#define                       TA7  0x80       /* Mailbox 7 Transmit Acknowledge */
-#define                       TA8  0x100      /* Mailbox 8 Transmit Acknowledge */
-#define                       TA9  0x200      /* Mailbox 9 Transmit Acknowledge */
-#define                      TA10  0x400      /* Mailbox 10 Transmit Acknowledge */
-#define                      TA11  0x800      /* Mailbox 11 Transmit Acknowledge */
-#define                      TA12  0x1000     /* Mailbox 12 Transmit Acknowledge */
-#define                      TA13  0x2000     /* Mailbox 13 Transmit Acknowledge */
-#define                      TA14  0x4000     /* Mailbox 14 Transmit Acknowledge */
-#define                      TA15  0x8000     /* Mailbox 15 Transmit Acknowledge */
-
-/* Bit masks for CAN0_TA2 */
-
-#define                      TA16  0x1        /* Mailbox 16 Transmit Acknowledge */
-#define                      TA17  0x2        /* Mailbox 17 Transmit Acknowledge */
-#define                      TA18  0x4        /* Mailbox 18 Transmit Acknowledge */
-#define                      TA19  0x8        /* Mailbox 19 Transmit Acknowledge */
-#define                      TA20  0x10       /* Mailbox 20 Transmit Acknowledge */
-#define                      TA21  0x20       /* Mailbox 21 Transmit Acknowledge */
-#define                      TA22  0x40       /* Mailbox 22 Transmit Acknowledge */
-#define                      TA23  0x80       /* Mailbox 23 Transmit Acknowledge */
-#define                      TA24  0x100      /* Mailbox 24 Transmit Acknowledge */
-#define                      TA25  0x200      /* Mailbox 25 Transmit Acknowledge */
-#define                      TA26  0x400      /* Mailbox 26 Transmit Acknowledge */
-#define                      TA27  0x800      /* Mailbox 27 Transmit Acknowledge */
-#define                      TA28  0x1000     /* Mailbox 28 Transmit Acknowledge */
-#define                      TA29  0x2000     /* Mailbox 29 Transmit Acknowledge */
-#define                      TA30  0x4000     /* Mailbox 30 Transmit Acknowledge */
-#define                      TA31  0x8000     /* Mailbox 31 Transmit Acknowledge */
-
-/* Bit masks for CAN0_RFH1 */
-
-#define                      RFH0  0x1        /* Mailbox 0 Remote Frame Handling Enable */
-#define                      RFH1  0x2        /* Mailbox 1 Remote Frame Handling Enable */
-#define                      RFH2  0x4        /* Mailbox 2 Remote Frame Handling Enable */
-#define                      RFH3  0x8        /* Mailbox 3 Remote Frame Handling Enable */
-#define                      RFH4  0x10       /* Mailbox 4 Remote Frame Handling Enable */
-#define                      RFH5  0x20       /* Mailbox 5 Remote Frame Handling Enable */
-#define                      RFH6  0x40       /* Mailbox 6 Remote Frame Handling Enable */
-#define                      RFH7  0x80       /* Mailbox 7 Remote Frame Handling Enable */
-#define                      RFH8  0x100      /* Mailbox 8 Remote Frame Handling Enable */
-#define                      RFH9  0x200      /* Mailbox 9 Remote Frame Handling Enable */
-#define                     RFH10  0x400      /* Mailbox 10 Remote Frame Handling Enable */
-#define                     RFH11  0x800      /* Mailbox 11 Remote Frame Handling Enable */
-#define                     RFH12  0x1000     /* Mailbox 12 Remote Frame Handling Enable */
-#define                     RFH13  0x2000     /* Mailbox 13 Remote Frame Handling Enable */
-#define                     RFH14  0x4000     /* Mailbox 14 Remote Frame Handling Enable */
-#define                     RFH15  0x8000     /* Mailbox 15 Remote Frame Handling Enable */
-
-/* Bit masks for CAN0_RFH2 */
-
-#define                     RFH16  0x1        /* Mailbox 16 Remote Frame Handling Enable */
-#define                     RFH17  0x2        /* Mailbox 17 Remote Frame Handling Enable */
-#define                     RFH18  0x4        /* Mailbox 18 Remote Frame Handling Enable */
-#define                     RFH19  0x8        /* Mailbox 19 Remote Frame Handling Enable */
-#define                     RFH20  0x10       /* Mailbox 20 Remote Frame Handling Enable */
-#define                     RFH21  0x20       /* Mailbox 21 Remote Frame Handling Enable */
-#define                     RFH22  0x40       /* Mailbox 22 Remote Frame Handling Enable */
-#define                     RFH23  0x80       /* Mailbox 23 Remote Frame Handling Enable */
-#define                     RFH24  0x100      /* Mailbox 24 Remote Frame Handling Enable */
-#define                     RFH25  0x200      /* Mailbox 25 Remote Frame Handling Enable */
-#define                     RFH26  0x400      /* Mailbox 26 Remote Frame Handling Enable */
-#define                     RFH27  0x800      /* Mailbox 27 Remote Frame Handling Enable */
-#define                     RFH28  0x1000     /* Mailbox 28 Remote Frame Handling Enable */
-#define                     RFH29  0x2000     /* Mailbox 29 Remote Frame Handling Enable */
-#define                     RFH30  0x4000     /* Mailbox 30 Remote Frame Handling Enable */
-#define                     RFH31  0x8000     /* Mailbox 31 Remote Frame Handling Enable */
-
-/* Bit masks for CAN0_MBIM1 */
-
-#define                     MBIM0  0x1        /* Mailbox 0 Mailbox Interrupt Mask */
-#define                     MBIM1  0x2        /* Mailbox 1 Mailbox Interrupt Mask */
-#define                     MBIM2  0x4        /* Mailbox 2 Mailbox Interrupt Mask */
-#define                     MBIM3  0x8        /* Mailbox 3 Mailbox Interrupt Mask */
-#define                     MBIM4  0x10       /* Mailbox 4 Mailbox Interrupt Mask */
-#define                     MBIM5  0x20       /* Mailbox 5 Mailbox Interrupt Mask */
-#define                     MBIM6  0x40       /* Mailbox 6 Mailbox Interrupt Mask */
-#define                     MBIM7  0x80       /* Mailbox 7 Mailbox Interrupt Mask */
-#define                     MBIM8  0x100      /* Mailbox 8 Mailbox Interrupt Mask */
-#define                     MBIM9  0x200      /* Mailbox 9 Mailbox Interrupt Mask */
-#define                    MBIM10  0x400      /* Mailbox 10 Mailbox Interrupt Mask */
-#define                    MBIM11  0x800      /* Mailbox 11 Mailbox Interrupt Mask */
-#define                    MBIM12  0x1000     /* Mailbox 12 Mailbox Interrupt Mask */
-#define                    MBIM13  0x2000     /* Mailbox 13 Mailbox Interrupt Mask */
-#define                    MBIM14  0x4000     /* Mailbox 14 Mailbox Interrupt Mask */
-#define                    MBIM15  0x8000     /* Mailbox 15 Mailbox Interrupt Mask */
-
-/* Bit masks for CAN0_MBIM2 */
-
-#define                    MBIM16  0x1        /* Mailbox 16 Mailbox Interrupt Mask */
-#define                    MBIM17  0x2        /* Mailbox 17 Mailbox Interrupt Mask */
-#define                    MBIM18  0x4        /* Mailbox 18 Mailbox Interrupt Mask */
-#define                    MBIM19  0x8        /* Mailbox 19 Mailbox Interrupt Mask */
-#define                    MBIM20  0x10       /* Mailbox 20 Mailbox Interrupt Mask */
-#define                    MBIM21  0x20       /* Mailbox 21 Mailbox Interrupt Mask */
-#define                    MBIM22  0x40       /* Mailbox 22 Mailbox Interrupt Mask */
-#define                    MBIM23  0x80       /* Mailbox 23 Mailbox Interrupt Mask */
-#define                    MBIM24  0x100      /* Mailbox 24 Mailbox Interrupt Mask */
-#define                    MBIM25  0x200      /* Mailbox 25 Mailbox Interrupt Mask */
-#define                    MBIM26  0x400      /* Mailbox 26 Mailbox Interrupt Mask */
-#define                    MBIM27  0x800      /* Mailbox 27 Mailbox Interrupt Mask */
-#define                    MBIM28  0x1000     /* Mailbox 28 Mailbox Interrupt Mask */
-#define                    MBIM29  0x2000     /* Mailbox 29 Mailbox Interrupt Mask */
-#define                    MBIM30  0x4000     /* Mailbox 30 Mailbox Interrupt Mask */
-#define                    MBIM31  0x8000     /* Mailbox 31 Mailbox Interrupt Mask */
-
-/* Bit masks for CAN0_MBTIF1 */
-
-#define                    MBTIF0  0x1        /* Mailbox 0 Mailbox Transmit Interrupt Flag */
-#define                    MBTIF1  0x2        /* Mailbox 1 Mailbox Transmit Interrupt Flag */
-#define                    MBTIF2  0x4        /* Mailbox 2 Mailbox Transmit Interrupt Flag */
-#define                    MBTIF3  0x8        /* Mailbox 3 Mailbox Transmit Interrupt Flag */
-#define                    MBTIF4  0x10       /* Mailbox 4 Mailbox Transmit Interrupt Flag */
-#define                    MBTIF5  0x20       /* Mailbox 5 Mailbox Transmit Interrupt Flag */
-#define                    MBTIF6  0x40       /* Mailbox 6 Mailbox Transmit Interrupt Flag */
-#define                    MBTIF7  0x80       /* Mailbox 7 Mailbox Transmit Interrupt Flag */
-#define                    MBTIF8  0x100      /* Mailbox 8 Mailbox Transmit Interrupt Flag */
-#define                    MBTIF9  0x200      /* Mailbox 9 Mailbox Transmit Interrupt Flag */
-#define                   MBTIF10  0x400      /* Mailbox 10 Mailbox Transmit Interrupt Flag */
-#define                   MBTIF11  0x800      /* Mailbox 11 Mailbox Transmit Interrupt Flag */
-#define                   MBTIF12  0x1000     /* Mailbox 12 Mailbox Transmit Interrupt Flag */
-#define                   MBTIF13  0x2000     /* Mailbox 13 Mailbox Transmit Interrupt Flag */
-#define                   MBTIF14  0x4000     /* Mailbox 14 Mailbox Transmit Interrupt Flag */
-#define                   MBTIF15  0x8000     /* Mailbox 15 Mailbox Transmit Interrupt Flag */
-
-/* Bit masks for CAN0_MBTIF2 */
-
-#define                   MBTIF16  0x1        /* Mailbox 16 Mailbox Transmit Interrupt Flag */
-#define                   MBTIF17  0x2        /* Mailbox 17 Mailbox Transmit Interrupt Flag */
-#define                   MBTIF18  0x4        /* Mailbox 18 Mailbox Transmit Interrupt Flag */
-#define                   MBTIF19  0x8        /* Mailbox 19 Mailbox Transmit Interrupt Flag */
-#define                   MBTIF20  0x10       /* Mailbox 20 Mailbox Transmit Interrupt Flag */
-#define                   MBTIF21  0x20       /* Mailbox 21 Mailbox Transmit Interrupt Flag */
-#define                   MBTIF22  0x40       /* Mailbox 22 Mailbox Transmit Interrupt Flag */
-#define                   MBTIF23  0x80       /* Mailbox 23 Mailbox Transmit Interrupt Flag */
-#define                   MBTIF24  0x100      /* Mailbox 24 Mailbox Transmit Interrupt Flag */
-#define                   MBTIF25  0x200      /* Mailbox 25 Mailbox Transmit Interrupt Flag */
-#define                   MBTIF26  0x400      /* Mailbox 26 Mailbox Transmit Interrupt Flag */
-#define                   MBTIF27  0x800      /* Mailbox 27 Mailbox Transmit Interrupt Flag */
-#define                   MBTIF28  0x1000     /* Mailbox 28 Mailbox Transmit Interrupt Flag */
-#define                   MBTIF29  0x2000     /* Mailbox 29 Mailbox Transmit Interrupt Flag */
-#define                   MBTIF30  0x4000     /* Mailbox 30 Mailbox Transmit Interrupt Flag */
-#define                   MBTIF31  0x8000     /* Mailbox 31 Mailbox Transmit Interrupt Flag */
-
-/* Bit masks for CAN0_MBRIF1 */
-
-#define                    MBRIF0  0x1        /* Mailbox 0 Mailbox Receive Interrupt Flag */
-#define                    MBRIF1  0x2        /* Mailbox 1 Mailbox Receive Interrupt Flag */
-#define                    MBRIF2  0x4        /* Mailbox 2 Mailbox Receive Interrupt Flag */
-#define                    MBRIF3  0x8        /* Mailbox 3 Mailbox Receive Interrupt Flag */
-#define                    MBRIF4  0x10       /* Mailbox 4 Mailbox Receive Interrupt Flag */
-#define                    MBRIF5  0x20       /* Mailbox 5 Mailbox Receive Interrupt Flag */
-#define                    MBRIF6  0x40       /* Mailbox 6 Mailbox Receive Interrupt Flag */
-#define                    MBRIF7  0x80       /* Mailbox 7 Mailbox Receive Interrupt Flag */
-#define                    MBRIF8  0x100      /* Mailbox 8 Mailbox Receive Interrupt Flag */
-#define                    MBRIF9  0x200      /* Mailbox 9 Mailbox Receive Interrupt Flag */
-#define                   MBRIF10  0x400      /* Mailbox 10 Mailbox Receive Interrupt Flag */
-#define                   MBRIF11  0x800      /* Mailbox 11 Mailbox Receive Interrupt Flag */
-#define                   MBRIF12  0x1000     /* Mailbox 12 Mailbox Receive Interrupt Flag */
-#define                   MBRIF13  0x2000     /* Mailbox 13 Mailbox Receive Interrupt Flag */
-#define                   MBRIF14  0x4000     /* Mailbox 14 Mailbox Receive Interrupt Flag */
-#define                   MBRIF15  0x8000     /* Mailbox 15 Mailbox Receive Interrupt Flag */
-
-/* Bit masks for CAN0_MBRIF2 */
-
-#define                   MBRIF16  0x1        /* Mailbox 16 Mailbox Receive Interrupt Flag */
-#define                   MBRIF17  0x2        /* Mailbox 17 Mailbox Receive Interrupt Flag */
-#define                   MBRIF18  0x4        /* Mailbox 18 Mailbox Receive Interrupt Flag */
-#define                   MBRIF19  0x8        /* Mailbox 19 Mailbox Receive Interrupt Flag */
-#define                   MBRIF20  0x10       /* Mailbox 20 Mailbox Receive Interrupt Flag */
-#define                   MBRIF21  0x20       /* Mailbox 21 Mailbox Receive Interrupt Flag */
-#define                   MBRIF22  0x40       /* Mailbox 22 Mailbox Receive Interrupt Flag */
-#define                   MBRIF23  0x80       /* Mailbox 23 Mailbox Receive Interrupt Flag */
-#define                   MBRIF24  0x100      /* Mailbox 24 Mailbox Receive Interrupt Flag */
-#define                   MBRIF25  0x200      /* Mailbox 25 Mailbox Receive Interrupt Flag */
-#define                   MBRIF26  0x400      /* Mailbox 26 Mailbox Receive Interrupt Flag */
-#define                   MBRIF27  0x800      /* Mailbox 27 Mailbox Receive Interrupt Flag */
-#define                   MBRIF28  0x1000     /* Mailbox 28 Mailbox Receive Interrupt Flag */
-#define                   MBRIF29  0x2000     /* Mailbox 29 Mailbox Receive Interrupt Flag */
-#define                   MBRIF30  0x4000     /* Mailbox 30 Mailbox Receive Interrupt Flag */
-#define                   MBRIF31  0x8000     /* Mailbox 31 Mailbox Receive Interrupt Flag */
-
 /* Bit masks for EPPIx_STATUS */
 
 #define                 CFIFO_ERR  0x1        /* Chroma FIFO Error */
index 5163e2c383c5201a2c59e5cab514660640d86bd6..bfcfa86db2b57ae5c13164d2ca78aefa12af0da6 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/spi/flash.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
+#include <linux/jiffies.h>
 #include <linux/i2c-pca-platform.h>
 #include <linux/delay.h>
 #include <linux/io.h>
@@ -112,7 +113,7 @@ static struct resource bfin_i2c_pca_resources[] = {
 struct i2c_pca9564_pf_platform_data pca9564_platform_data = {
        .gpio = -1,
        .i2c_clock_speed = 330000,
-       .timeout = 10000
+       .timeout = HZ,
 };
 
 /* PCA9564 I2C Bus driver */
index 7ad8878bfa1815110a53220a1d96ab2c53df0476..1c8c4c7245c3868eb9cfcc62b783bac6a7c90755 100644 (file)
@@ -92,26 +92,29 @@ static void __init search_IAR(void)
 {
        unsigned ivg, irq_pos = 0;
        for (ivg = 0; ivg <= IVG13 - IVG7; ivg++) {
-               int irqn;
+               int irqN;
 
                ivg7_13[ivg].istop = ivg7_13[ivg].ifirst = &ivg_table[irq_pos];
 
-               for (irqn = 0; irqn < NR_PERI_INTS; irqn++) {
-                       int iar_shift = (irqn & 7) * 4;
-                               if (ivg == (0xf &
-#if defined(CONFIG_BF52x) || defined(CONFIG_BF538) \
-       || defined(CONFIG_BF539) || defined(CONFIG_BF51x)
-                            bfin_read32((unsigned long *)SIC_IAR0 +
-                                        ((irqn % 32) >> 3) + ((irqn / 32) *
-                                        ((SIC_IAR4 - SIC_IAR0) / 4))) >> iar_shift)) {
+               for (irqN = 0; irqN < NR_PERI_INTS; irqN += 4) {
+                       int irqn;
+                       u32 iar = bfin_read32((unsigned long *)SIC_IAR0 +
+#if defined(CONFIG_BF51x) || defined(CONFIG_BF52x) || \
+       defined(CONFIG_BF538) || defined(CONFIG_BF539)
+                               ((irqN % 32) >> 3) + ((irqN / 32) * ((SIC_IAR4 - SIC_IAR0) / 4))
 #else
-                            bfin_read32((unsigned long *)SIC_IAR0 +
-                                        (irqn >> 3)) >> iar_shift)) {
+                               (irqN >> 3)
 #endif
-                               ivg_table[irq_pos].irqno = IVG7 + irqn;
-                               ivg_table[irq_pos].isrflag = 1 << (irqn % 32);
-                               ivg7_13[ivg].istop++;
-                               irq_pos++;
+                               );
+
+                       for (irqn = irqN; irqn < irqN + 4; ++irqn) {
+                               int iar_shift = (irqn & 7) * 4;
+                               if (ivg == (0xf & (iar >> iar_shift))) {
+                                       ivg_table[irq_pos].irqno = IVG7 + irqn;
+                                       ivg_table[irq_pos].isrflag = 1 << (irqn % 32);
+                                       ivg7_13[ivg].istop++;
+                                       irq_pos++;
+                               }
                        }
                }
        }
@@ -662,14 +665,7 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
 #ifdef CONFIG_PM
 int bfin_gpio_set_wake(unsigned int irq, unsigned int state)
 {
-       unsigned gpio = irq_to_gpio(irq);
-
-       if (state)
-               gpio_pm_wakeup_request(gpio, PM_WAKE_IGNORE);
-       else
-               gpio_pm_wakeup_free(gpio);
-
-       return 0;
+       return gpio_pm_wakeup_ctrl(irq_to_gpio(irq), state);
 }
 #endif
 
index c1f1ccc846f067ade4556eb3c2e98db523a27a50..ea7f95f6bb4c92b4cd779a3c158bce85c9694361 100644 (file)
 #include <asm/dma.h>
 #include <asm/dpmc.h>
 
-#ifdef CONFIG_PM_WAKEUP_GPIO_POLAR_H
-#define WAKEUP_TYPE    PM_WAKE_HIGH
-#endif
-
-#ifdef CONFIG_PM_WAKEUP_GPIO_POLAR_L
-#define WAKEUP_TYPE    PM_WAKE_LOW
-#endif
-
-#ifdef CONFIG_PM_WAKEUP_GPIO_POLAR_EDGE_F
-#define WAKEUP_TYPE    PM_WAKE_FALLING
-#endif
-
-#ifdef CONFIG_PM_WAKEUP_GPIO_POLAR_EDGE_R
-#define WAKEUP_TYPE    PM_WAKE_RISING
-#endif
-
-#ifdef CONFIG_PM_WAKEUP_GPIO_POLAR_EDGE_B
-#define WAKEUP_TYPE    PM_WAKE_BOTH_EDGES
-#endif
-
 
 void bfin_pm_suspend_standby_enter(void)
 {
        unsigned long flags;
 
-#ifdef CONFIG_PM_WAKEUP_BY_GPIO
-       gpio_pm_wakeup_request(CONFIG_PM_WAKEUP_GPIO_NUMBER, WAKEUP_TYPE);
-#endif
-
        local_irq_save_hw(flags);
        bfin_pm_standby_setup();
 
index 7cecbaf0358ab03e0a42e5492475d7a241f31fd3..a17107a700d50cce38a1f581ba0e9b6c5a413c77 100644 (file)
@@ -170,8 +170,8 @@ static irqreturn_t ipi_handler(int irq, void *dev_instance)
                        kfree(msg);
                        break;
                default:
-                       printk(KERN_CRIT "CPU%u: Unknown IPI message \
-                       0x%lx\n", cpu, msg->type);
+                       printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%lx\n",
+                              cpu, msg->type);
                        kfree(msg);
                        break;
                }
index 355b87aa6b9322da7c1e5074e0eb5170fe6d5de3..bb4e8fff4b556f14751e9502d407b6c3398679bf 100644 (file)
 #include "blackfin_sram.h"
 
 /*
- * BAD_PAGE is the page that is used for page faults when linux
- * is out-of-memory. Older versions of linux just did a
- * do_exit(), but using this instead means there is less risk
- * for a process dying in kernel mode, possibly leaving a inode
- * unused etc..
- *
- * BAD_PAGETABLE is the accompanying page-table: it is initialized
- * to point to BAD_PAGE entries.
- *
- * ZERO_PAGE is a special page that is used for zero-initialized
- * data and COW.
+ * ZERO_PAGE is a special page that is used for zero-initialized data and COW.
+ * Let the bss do its zero-init magic so we don't have to do it ourselves.
  */
-static unsigned long empty_bad_page_table;
-
-static unsigned long empty_bad_page;
-
-static unsigned long empty_zero_page;
+char empty_zero_page[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE)));
+EXPORT_SYMBOL(empty_zero_page);
 
 #ifndef CONFIG_EXCEPTION_L1_SCRATCH
 #if defined CONFIG_SYSCALL_TAB_L1
@@ -52,40 +40,26 @@ EXPORT_SYMBOL(cpu_pda);
 void __init paging_init(void)
 {
        /*
-        * make sure start_mem is page aligned,  otherwise bootmem and
-        * page_alloc get different views og the world
+        * make sure start_mem is page aligned, otherwise bootmem and
+        * page_alloc get different views of the world
         */
        unsigned long end_mem = memory_end & PAGE_MASK;
 
-       pr_debug("start_mem is %#lx   virtual_end is %#lx\n", PAGE_ALIGN(memory_start), end_mem);
-
-       /*
-        * initialize the bad page table and bad page to point
-        * to a couple of allocated pages
-        */
-       empty_bad_page_table = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
-       empty_bad_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
-       empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
-       memset((void *)empty_zero_page, 0, PAGE_SIZE);
+       unsigned long zones_size[MAX_NR_ZONES] = {
+               [0] = 0,
+               [ZONE_DMA] = (end_mem - PAGE_OFFSET) >> PAGE_SHIFT,
+               [ZONE_NORMAL] = 0,
+#ifdef CONFIG_HIGHMEM
+               [ZONE_HIGHMEM] = 0,
+#endif
+       };
 
-       /*
-        * Set up SFC/DFC registers (user data space)
-        */
+       /* Set up SFC/DFC registers (user data space) */
        set_fs(KERNEL_DS);
 
-       pr_debug("free_area_init -> start_mem is %#lx   virtual_end is %#lx\n",
+       pr_debug("free_area_init -> start_mem is %#lx virtual_end is %#lx\n",
                PAGE_ALIGN(memory_start), end_mem);
-
-       {
-               unsigned long zones_size[MAX_NR_ZONES] = { 0, };
-
-               zones_size[ZONE_DMA] = (end_mem - PAGE_OFFSET) >> PAGE_SHIFT;
-               zones_size[ZONE_NORMAL] = 0;
-#ifdef CONFIG_HIGHMEM
-               zones_size[ZONE_HIGHMEM] = 0;
-#endif
-               free_area_init(zones_size);
-       }
+       free_area_init(zones_size);
 }
 
 asmlinkage void __init init_pda(void)
index 39b058564f62400db2b00af74127d13cd0d83fd4..7e2e674ed4440a6a0e333f0ddca5f29837394e13 100644 (file)
@@ -43,13 +43,12 @@ static DEFINE_SPINLOCK(dtest_lock);
 /* Takes a void pointer */
 #define IADDR2DTEST(x) \
        ({ unsigned long __addr = (unsigned long)(x); \
-               (__addr & 0x47F8)        | /* address bits 14 & 10:3 */ \
-               (__addr & 0x8000) << 23  | /* Bank A/B               */ \
-               (__addr & 0x0800) << 15  | /* address bit  11        */ \
-               (__addr & 0x3000) <<  4  | /* address bits 13:12     */ \
-               (__addr & 0x8000) <<  8  | /* address bit  15        */ \
-               (0x1000000)              | /* instruction access = 1 */ \
-               (0x4);                     /* data array = 1         */ \
+               ((__addr & (1 << 11)) << (26 - 11)) | /* addr bit 11 (Way0/Way1)   */ \
+               (1 << 24)                           | /* instruction access = 1    */ \
+               ((__addr & (1 << 15)) << (23 - 15)) | /* addr bit 15 (Data Bank)   */ \
+               ((__addr & (3 << 12)) << (16 - 12)) | /* addr bits 13:12 (Subbank) */ \
+               (__addr & 0x47F8)                   | /* addr bits 14 & 10:3       */ \
+               (1 << 2);                             /* data array = 1            */ \
        })
 
 /* Takes a pointer, and returns the offset (in bits) which things should be shifted */
@@ -196,7 +195,7 @@ EXPORT_SYMBOL(isram_memcpy);
 
 #ifdef CONFIG_BFIN_ISRAM_SELF_TEST
 
-#define TEST_LEN 0x100
+static int test_len = 0x20000;
 
 static __init void hex_dump(unsigned char *buf, int len)
 {
@@ -212,15 +211,15 @@ static __init int isram_read_test(char *sdram, void *l1inst)
        pr_info("INFO: running isram_read tests\n");
 
        /* setup some different data to play with */
-       for (i = 0; i < TEST_LEN; ++i)
-               sdram[i] = i;
-       dma_memcpy(l1inst, sdram, TEST_LEN);
+       for (i = 0; i < test_len; ++i)
+               sdram[i] = i % 255;
+       dma_memcpy(l1inst, sdram, test_len);
 
        /* make sure we can read the L1 inst */
-       for (i = 0; i < TEST_LEN; i += sizeof(uint64_t)) {
+       for (i = 0; i < test_len; i += sizeof(uint64_t)) {
                data1 = isram_read(l1inst + i);
                memcpy(&data2, sdram + i, sizeof(data2));
-               if (memcmp(&data1, &data2, sizeof(uint64_t))) {
+               if (data1 != data2) {
                        pr_err("FAIL: isram_read(%p) returned %#llx but wanted %#llx\n",
                                l1inst + i, data1, data2);
                        ++ret;
@@ -238,25 +237,25 @@ static __init int isram_write_test(char *sdram, void *l1inst)
        pr_info("INFO: running isram_write tests\n");
 
        /* setup some different data to play with */
-       memset(sdram, 0, TEST_LEN * 2);
-       dma_memcpy(l1inst, sdram, TEST_LEN);
-       for (i = 0; i < TEST_LEN; ++i)
-               sdram[i] = i;
+       memset(sdram, 0, test_len * 2);
+       dma_memcpy(l1inst, sdram, test_len);
+       for (i = 0; i < test_len; ++i)
+               sdram[i] = i % 255;
 
        /* make sure we can write the L1 inst */
-       for (i = 0; i < TEST_LEN; i += sizeof(uint64_t)) {
+       for (i = 0; i < test_len; i += sizeof(uint64_t)) {
                memcpy(&data1, sdram + i, sizeof(data1));
                isram_write(l1inst + i, data1);
                data2 = isram_read(l1inst + i);
-               if (memcmp(&data1, &data2, sizeof(uint64_t))) {
+               if (data1 != data2) {
                        pr_err("FAIL: isram_write(%p, %#llx) != %#llx\n",
                                l1inst + i, data1, data2);
                        ++ret;
                }
        }
 
-       dma_memcpy(sdram + TEST_LEN, l1inst, TEST_LEN);
-       if (memcmp(sdram, sdram + TEST_LEN, TEST_LEN)) {
+       dma_memcpy(sdram + test_len, l1inst, test_len);
+       if (memcmp(sdram, sdram + test_len, test_len)) {
                pr_err("FAIL: isram_write() did not work properly\n");
                ++ret;
        }
@@ -268,12 +267,12 @@ static __init int
 _isram_memcpy_test(char pattern, void *sdram, void *l1inst, const char *smemcpy,
                    void *(*fmemcpy)(void *, const void *, size_t))
 {
-       memset(sdram, pattern, TEST_LEN);
-       fmemcpy(l1inst, sdram, TEST_LEN);
-       fmemcpy(sdram + TEST_LEN, l1inst, TEST_LEN);
-       if (memcmp(sdram, sdram + TEST_LEN, TEST_LEN)) {
+       memset(sdram, pattern, test_len);
+       fmemcpy(l1inst, sdram, test_len);
+       fmemcpy(sdram + test_len, l1inst, test_len);
+       if (memcmp(sdram, sdram + test_len, test_len)) {
                pr_err("FAIL: %s(%p <=> %p, %#x) failed (data is %#x)\n",
-                       smemcpy, l1inst, sdram, TEST_LEN, pattern);
+                       smemcpy, l1inst, sdram, test_len, pattern);
                return 1;
        }
        return 0;
@@ -292,12 +291,13 @@ static __init int isram_memcpy_test(char *sdram, void *l1inst)
        /* check read of small, unaligned, and hardware 64bit limits */
        pr_info("INFO: running isram_memcpy (read) tests\n");
 
-       for (i = 0; i < TEST_LEN; ++i)
-               sdram[i] = i;
-       dma_memcpy(l1inst, sdram, TEST_LEN);
+       /* setup some different data to play with */
+       for (i = 0; i < test_len; ++i)
+               sdram[i] = i % 255;
+       dma_memcpy(l1inst, sdram, test_len);
 
        thisret = 0;
-       for (i = 0; i < TEST_LEN - 32; ++i) {
+       for (i = 0; i < test_len - 32; ++i) {
                unsigned char cmp[32];
                for (j = 1; j <= 32; ++j) {
                        memset(cmp, 0, sizeof(cmp));
@@ -310,7 +310,7 @@ static __init int isram_memcpy_test(char *sdram, void *l1inst)
                                pr_cont("\n");
                                if (++thisret > 20) {
                                        pr_err("FAIL: skipping remaining series\n");
-                                       i = TEST_LEN;
+                                       i = test_len;
                                        break;
                                }
                        }
@@ -321,11 +321,11 @@ static __init int isram_memcpy_test(char *sdram, void *l1inst)
        /* check write of small, unaligned, and hardware 64bit limits */
        pr_info("INFO: running isram_memcpy (write) tests\n");
 
-       memset(sdram + TEST_LEN, 0, TEST_LEN);
-       dma_memcpy(l1inst, sdram + TEST_LEN, TEST_LEN);
+       memset(sdram + test_len, 0, test_len);
+       dma_memcpy(l1inst, sdram + test_len, test_len);
 
        thisret = 0;
-       for (i = 0; i < TEST_LEN - 32; ++i) {
+       for (i = 0; i < test_len - 32; ++i) {
                unsigned char cmp[32];
                for (j = 1; j <= 32; ++j) {
                        isram_memcpy(l1inst + i, sdram + i, j);
@@ -338,7 +338,7 @@ static __init int isram_memcpy_test(char *sdram, void *l1inst)
                                pr_cont("\n");
                                if (++thisret > 20) {
                                        pr_err("FAIL: skipping remaining series\n");
-                                       i = TEST_LEN;
+                                       i = test_len;
                                        break;
                                }
                        }
@@ -355,22 +355,30 @@ static __init int isram_test_init(void)
        char *sdram;
        void *l1inst;
 
-       sdram = kmalloc(TEST_LEN * 2, GFP_KERNEL);
-       if (!sdram) {
-               pr_warning("SKIP: could not allocate sdram\n");
-               return 0;
+       /* Try to test as much of L1SRAM as possible */
+       while (test_len) {
+               test_len >>= 1;
+               l1inst = l1_inst_sram_alloc(test_len);
+               if (l1inst)
+                       break;
        }
-
-       l1inst = l1_inst_sram_alloc(TEST_LEN);
        if (!l1inst) {
-               kfree(sdram);
                pr_warning("SKIP: could not allocate L1 inst\n");
                return 0;
        }
+       pr_info("INFO: testing %#x bytes (%p - %p)\n",
+               test_len, l1inst, l1inst + test_len);
+
+       sdram = kmalloc(test_len * 2, GFP_KERNEL);
+       if (!sdram) {
+               sram_free(l1inst);
+               pr_warning("SKIP: could not allocate sdram\n");
+               return 0;
+       }
 
        /* sanity check initial L1 inst state */
        ret = 1;
-       pr_info("INFO: running initial dma_memcpy checks\n");
+       pr_info("INFO: running initial dma_memcpy checks %p\n", sdram);
        if (_isram_memcpy_test(0xa, sdram, l1inst, dma_memcpy))
                goto abort;
        if (_isram_memcpy_test(0x5, sdram, l1inst, dma_memcpy))
index 49b2ff2c8b74bee191df47682bcbae227b5beac6..627e04b5ba9a8979be2149ecff27e52f6bb05458 100644 (file)
@@ -256,7 +256,8 @@ static void *_sram_alloc(size_t size, struct sram_piece *pfree_head,
                plast->next = pslot->next;
                pavail = pslot;
        } else {
-               pavail = kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
+               /* use atomic so our L1 allocator can be used atomically */
+               pavail = kmem_cache_alloc(sram_piece_cache, GFP_ATOMIC);
 
                if (!pavail)
                        return NULL;
index 1f2ae909d3e65a8ec8f1d957b04064042841caf5..c3405507a3d1f0dc846483f110dc4e9afea57af7 100644 (file)
@@ -73,8 +73,7 @@ struct eeprom_type
   int adapt_state; /* 1 = To high , 0 = Even, -1 = To low */
   
   /* this one is to keep the read/write operations atomic */
-  wait_queue_head_t wait_q;
-  volatile int busy;
+  struct mutex lock;
   int retry_cnt_addr; /* Used to keep track of number of retries for
                          adaptive timing adjustments */
   int retry_cnt_read;
@@ -115,8 +114,7 @@ const struct file_operations eeprom_fops =
 
 int __init eeprom_init(void)
 {
-  init_waitqueue_head(&eeprom.wait_q);
-  eeprom.busy = 0;
+  mutex_init(&eeprom.lock);
 
 #ifdef CONFIG_ETRAX_I2C_EEPROM_PROBE
 #define EETEXT "Found"
@@ -439,10 +437,7 @@ static loff_t eeprom_lseek(struct file * file, loff_t offset, int orig)
 
 static int eeprom_read_buf(loff_t addr, char * buf, int count)
 {
-  struct file f;
-
-  f.f_pos = addr;
-  return eeprom_read(&f, buf, count, &addr);
+  return eeprom_read(NULL, buf, count, &addr);
 }
 
 
@@ -452,7 +447,7 @@ static int eeprom_read_buf(loff_t addr, char * buf, int count)
 static ssize_t eeprom_read(struct file * file, char * buf, size_t count, loff_t *off)
 {
   int read=0;
-  unsigned long p = file->f_pos;
+  unsigned long p = *off;
 
   unsigned char page;
 
@@ -461,12 +456,9 @@ static ssize_t eeprom_read(struct file * file, char * buf, size_t count, loff_t
     return -EFAULT;
   }
   
-  wait_event_interruptible(eeprom.wait_q, !eeprom.busy);
-  if (signal_pending(current))
+  if (mutex_lock_interruptible(&eeprom.lock))
     return -EINTR;
 
-  eeprom.busy++;
-
   page = (unsigned char) (p >> 8);
   
   if(!eeprom_address(p))
@@ -476,8 +468,7 @@ static ssize_t eeprom_read(struct file * file, char * buf, size_t count, loff_t
     i2c_stop();
     
     /* don't forget to wake them up */
-    eeprom.busy--;
-    wake_up_interruptible(&eeprom.wait_q);  
+    mutex_unlock(&eeprom.lock);
     return -EFAULT;
   }
 
@@ -501,11 +492,10 @@ static ssize_t eeprom_read(struct file * file, char * buf, size_t count, loff_t
   
   if(read > 0)
   {
-    file->f_pos += read;
+    *off += read;
   }
 
-  eeprom.busy--;
-  wake_up_interruptible(&eeprom.wait_q);
+  mutex_unlock(&eeprom.lock);
   return read;
 }
 
@@ -513,11 +503,7 @@ static ssize_t eeprom_read(struct file * file, char * buf, size_t count, loff_t
 
 static int eeprom_write_buf(loff_t addr, const char * buf, int count)
 {
-  struct file f;
-
-  f.f_pos = addr;
-  
-  return eeprom_write(&f, buf, count, &addr);
+  return eeprom_write(NULL, buf, count, &addr);
 }
 
 
@@ -534,16 +520,14 @@ static ssize_t eeprom_write(struct file * file, const char * buf, size_t count,
     return -EFAULT;
   }
 
-  wait_event_interruptible(eeprom.wait_q, !eeprom.busy);
   /* bail out if we get interrupted */
-  if (signal_pending(current))
+  if (mutex_lock_interruptible(&eeprom.lock))
     return -EINTR;
-  eeprom.busy++;
   for(i = 0; (i < EEPROM_RETRIES) && (restart > 0); i++)
   {
     restart = 0;
     written = 0;
-    p = file->f_pos;
+    p = *off;
    
     
     while( (written < count) && (p < eeprom.size))
@@ -556,8 +540,7 @@ static ssize_t eeprom_write(struct file * file, const char * buf, size_t count,
         i2c_stop();
         
         /* don't forget to wake them up */
-        eeprom.busy--;
-        wake_up_interruptible(&eeprom.wait_q);
+        mutex_unlock(&eeprom.lock);
         return -EFAULT;
       }
 #ifdef EEPROM_ADAPTIVE_TIMING      
@@ -669,12 +652,11 @@ static ssize_t eeprom_write(struct file * file, const char * buf, size_t count,
     } /* while */
   } /* for  */
 
-  eeprom.busy--;
-  wake_up_interruptible(&eeprom.wait_q);
-  if (written == 0 && file->f_pos >= eeprom.size){
+  mutex_unlock(&eeprom.lock);
+  if (written == 0 && p >= eeprom.size){
     return -ENOSPC;
   }
-  file->f_pos += written;
+  *off = p;
   return written;
 }
 
index faff53ad1f96cd56327caf8c182ad70c81fc161f..249a7842ff5f906280fba7b1fa0a5affdeccee1d 100644 (file)
@@ -1,22 +1,7 @@
 #ifndef __ASM_CRIS_SCATTERLIST_H
 #define __ASM_CRIS_SCATTERLIST_H
 
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-       unsigned long sg_magic;
-#endif
-       char *  address;    /* Location data is to be transferred to */
-       unsigned int length;
-
-       /* The following is i386 highmem junk - not used by us */
-       unsigned long page_link;
-       unsigned int offset;/* for highmem, page offset */
-
-};
-
-#define sg_dma_address(sg)     ((sg)->address)
-#define sg_dma_len(sg)         ((sg)->length)
-/* i386 junk */
+#include <asm-generic/scatterlist.h>
 
 #define ISA_DMA_THRESHOLD (0x1fffffff)
 
index 2da716407ff29d73de0598f287ed3730142e3fe7..e6bedd0cd9a58984f1a9ef3f9f59ef5d4ebc652a 100644 (file)
@@ -12,6 +12,7 @@
 #ifndef __ASM_GDB_STUB_H
 #define __ASM_GDB_STUB_H
 
+#undef GDBSTUB_DEBUG_IO
 #undef GDBSTUB_DEBUG_PROTOCOL
 
 #include <asm/ptrace.h>
@@ -108,6 +109,12 @@ extern void gdbstub_printk(const char *fmt, ...);
 extern void debug_to_serial(const char *p, int n);
 extern void console_set_baud(unsigned baud);
 
+#ifdef GDBSTUB_DEBUG_IO
+#define gdbstub_io(FMT,...) gdbstub_printk(FMT, ##__VA_ARGS__)
+#else
+#define gdbstub_io(FMT,...) ({ 0; })
+#endif
+
 #ifdef GDBSTUB_DEBUG_PROTOCOL
 #define gdbstub_proto(FMT,...) gdbstub_printk(FMT,##__VA_ARGS__)
 #else
index 2947764fc0e042b997b71078246701c19cef5e46..ccae981876fa659863e910634302ef53c8f67a5a 100644 (file)
@@ -35,8 +35,8 @@
  * the slab must be aligned such that load- and store-double instructions don't
  * fault if used
  */
-#define        ARCH_KMALLOC_MINALIGN           8
-#define        ARCH_SLAB_MINALIGN              8
+#define        ARCH_KMALLOC_MINALIGN           L1_CACHE_BYTES
+#define        ARCH_SLAB_MINALIGN              L1_CACHE_BYTES
 
 /*****************************************************************************/
 /*
index 4bca8a28546c2474e6300d041e117186175dc0ea..1614bfd7e3a4bb8902509ea7eb04fd7e31020710 100644 (file)
@@ -1,45 +1,7 @@
 #ifndef _ASM_SCATTERLIST_H
 #define _ASM_SCATTERLIST_H
 
-#include <asm/types.h>
-
-/*
- * Drivers must set either ->address or (preferred) page and ->offset
- * to indicate where data must be transferred to/from.
- *
- * Using page is recommended since it handles highmem data as well as
- * low mem. ->address is restricted to data which has a virtual mapping, and
- * it will go away in the future. Updating to page can be automated very
- * easily -- something like
- *
- * sg->address = some_ptr;
- *
- * can be rewritten as
- *
- * sg_set_buf(sg, some_ptr, length);
- *
- * and that's it. There's no excuse for not highmem enabling YOUR driver. /jens
- */
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-       unsigned long   sg_magic;
-#endif
-       unsigned long   page_link;
-       unsigned int    offset;         /* for highmem, page offset */
-
-       dma_addr_t      dma_address;
-       unsigned int    length;
-};
-
-/*
- * These macros should be used after a pci_map_sg call has been done
- * to get bus addresses of each of the SG entries and their lengths.
- * You should only work with the number of sg entries pci_map_sg
- * returns, or alternatively stop on the first sg_dma_len(sg) which
- * is 0.
- */
-#define sg_dma_address(sg)     ((sg)->dma_address)
-#define sg_dma_len(sg)         ((sg)->length)
+#include <asm-generic/scatterlist.h>
 
 #define ISA_DMA_THRESHOLD (0xffffffffUL)
 
index c997bccb9221de081e682deb916bf1c0a8e61ee5..2ca641d199f81b7eef23159bd82edf4ed1259ca3 100644 (file)
@@ -171,11 +171,11 @@ int gdbstub_rx_char(unsigned char *_ch, int nonblock)
                return -EINTR;
        }
        else if (st & (UART_LSR_FE|UART_LSR_OE|UART_LSR_PE)) {
-               gdbstub_proto("### GDB Rx Error (st=%02x) ###\n",st);
+               gdbstub_io("### GDB Rx Error (st=%02x) ###\n",st);
                return -EIO;
        }
        else {
-               gdbstub_proto("### GDB Rx %02x (st=%02x) ###\n",ch,st);
+               gdbstub_io("### GDB Rx %02x (st=%02x) ###\n",ch,st);
                *_ch = ch & 0x7f;
                return 0;
        }
index 7ca8a6b19ac97c3d74d1f6bbab44d23b45697fd9..84d103c33c9c4356220725a853405ccf15ab8870 100644 (file)
@@ -1344,6 +1344,44 @@ void gdbstub_get_mmu_state(void)
 
 } /* end gdbstub_get_mmu_state() */
 
+/*
+ * handle general query commands of the form 'qXXXXX'
+ */
+static void gdbstub_handle_query(void)
+{
+       if (strcmp(input_buffer, "qAttached") == 0) {
+               /* return current thread ID */
+               sprintf(output_buffer, "1");
+               return;
+       }
+
+       if (strcmp(input_buffer, "qC") == 0) {
+               /* return current thread ID */
+               sprintf(output_buffer, "QC 0");
+               return;
+       }
+
+       if (strcmp(input_buffer, "qOffsets") == 0) {
+               /* return relocation offset of text and data segments */
+               sprintf(output_buffer, "Text=0;Data=0;Bss=0");
+               return;
+       }
+
+       if (strcmp(input_buffer, "qSymbol::") == 0) {
+               sprintf(output_buffer, "OK");
+               return;
+       }
+
+       if (strcmp(input_buffer, "qSupported") == 0) {
+               /* query of supported features */
+               sprintf(output_buffer, "PacketSize=%u;ReverseContinue-;ReverseStep-",
+                       sizeof(input_buffer));
+               return;
+       }
+
+       gdbstub_strcpy(output_buffer,"E01");
+}
+
 /*****************************************************************************/
 /*
  * handle event interception and GDB remote protocol processing
@@ -1840,6 +1878,10 @@ void gdbstub(int sigval)
                case 'k' :
                        goto done;      /* just continue */
 
+                       /* detach */
+               case 'D':
+                       gdbstub_strcpy(output_buffer, "OK");
+                       break;
 
                        /* reset the whole machine (FIXME: system dependent) */
                case 'r':
@@ -1852,6 +1894,14 @@ void gdbstub(int sigval)
                        __debug_status.dcr |= DCR_SE;
                        goto done;
 
+                       /* extended command */
+               case 'v':
+                       if (strcmp(input_buffer, "vCont?") == 0) {
+                               output_buffer[0] = 0;
+                               break;
+                       }
+                       goto unsupported_cmd;
+
                        /* set baud rate (bBB) */
                case 'b':
                        ptr = &input_buffer[1];
@@ -1923,8 +1973,19 @@ void gdbstub(int sigval)
                        gdbstub_strcpy(output_buffer,"OK");
                        break;
 
+                       /* Thread-setting packet */
+               case 'H':
+                       gdbstub_strcpy(output_buffer, "OK");
+                       break;
+
+               case 'q':
+                       gdbstub_handle_query();
+                       break;
+
                default:
+               unsupported_cmd:
                        gdbstub_proto("### GDB Unsupported Cmd '%s'\n",input_buffer);
+                       gdbstub_strcpy(output_buffer,"E01");
                        break;
                }
 
index 60eeed3694c0764d2d0b9d7d3a0c2cffe14b9a89..fac028936a041aab80f80506901e643787caaf3b 100644 (file)
@@ -344,26 +344,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                                             0, sizeof(child->thread.user->f),
                                             (const void __user *)data);
 
-       case PTRACE_GETFDPIC:
-               tmp = 0;
-               switch (addr) {
-               case PTRACE_GETFDPIC_EXEC:
-                       tmp = child->mm->context.exec_fdpic_loadmap;
-                       break;
-               case PTRACE_GETFDPIC_INTERP:
-                       tmp = child->mm->context.interp_fdpic_loadmap;
-                       break;
-               default:
-                       break;
-               }
-
-               ret = 0;
-               if (put_user(tmp, (unsigned long *) data)) {
-                       ret = -EFAULT;
-                       break;
-               }
-               break;
-
        default:
                ret = ptrace_request(child, request, addr, data);
                break;
index 71abd1510a59d5e453b5a4567c237a32a1f18a44..6c155d69da297b9f7d9b0dcab63814ccf095fd8e 100644 (file)
@@ -46,8 +46,9 @@ static void frv_change_dcache_mode(unsigned long newmode)
 /*
  * handle requests to dynamically switch the write caching mode delivered by /proc
  */
-static int procctl_frv_cachemode(ctl_table *table, int write, struct file *filp,
-                                void __user *buffer, size_t *lenp, loff_t *ppos)
+static int procctl_frv_cachemode(ctl_table *table, int write,
+                                void __user *buffer, size_t *lenp,
+                                loff_t *ppos)
 {
        unsigned long hsr0;
        char buff[8];
@@ -84,7 +85,7 @@ static int procctl_frv_cachemode(ctl_table *table, int write, struct file *filp,
        }
 
        /* read the state */
-       if (filp->f_pos > 0) {
+       if (*ppos > 0) {
                *lenp = 0;
                return 0;
        }
@@ -110,7 +111,7 @@ static int procctl_frv_cachemode(ctl_table *table, int write, struct file *filp,
                return -EFAULT;
 
        *lenp = len;
-       filp->f_pos = len;
+       *ppos = len;
        return 0;
 
 } /* end procctl_frv_cachemode() */
@@ -120,8 +121,9 @@ static int procctl_frv_cachemode(ctl_table *table, int write, struct file *filp,
  * permit the mm_struct the nominated process is using have its MMU context ID pinned
  */
 #ifdef CONFIG_MMU
-static int procctl_frv_pin_cxnr(ctl_table *table, int write, struct file *filp,
-                               void __user *buffer, size_t *lenp, loff_t *ppos)
+static int procctl_frv_pin_cxnr(ctl_table *table, int write,
+                               void __user *buffer, size_t *lenp,
+                               loff_t *ppos)
 {
        pid_t pid;
        char buff[16], *p;
@@ -150,7 +152,7 @@ static int procctl_frv_pin_cxnr(ctl_table *table, int write, struct file *filp,
        }
 
        /* read the currently pinned CXN */
-       if (filp->f_pos > 0) {
+       if (*ppos > 0) {
                *lenp = 0;
                return 0;
        }
@@ -163,7 +165,7 @@ static int procctl_frv_pin_cxnr(ctl_table *table, int write, struct file *filp,
                return -EFAULT;
 
        *lenp = len;
-       filp->f_pos = len;
+       *ppos = len;
        return 0;
 
 } /* end procctl_frv_pin_cxnr() */
index d3ecdd87ac90b0ca8642d6d38886f6afc14a56fe..de08a4a2cc1c4f76cb9c403d5b33a04b04f242b0 100644 (file)
@@ -1,17 +1,7 @@
 #ifndef _H8300_SCATTERLIST_H
 #define _H8300_SCATTERLIST_H
 
-#include <asm/types.h>
-
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-       unsigned long   sg_magic;
-#endif
-       unsigned long   page_link;
-       unsigned int    offset;
-       dma_addr_t      dma_address;
-       unsigned int    length;
-};
+#include <asm-generic/scatterlist.h>
 
 #define ISA_DMA_THRESHOLD      (0xffffffff)
 
index 9676100b83ee02563047459766d81ba59d701beb..95610820041ea33bf76f9097fcab9d2312a475ea 100644 (file)
@@ -56,6 +56,9 @@ config MMU
 config NEED_DMA_MAP_STATE
        def_bool y
 
+config NEED_SG_DMA_LENGTH
+       def_bool y
+
 config SWIOTLB
        bool
 
@@ -495,6 +498,14 @@ config HAVE_ARCH_NODEDATA_EXTENSION
        def_bool y
        depends on NUMA
 
+config USE_PERCPU_NUMA_NODE_ID
+       def_bool y
+       depends on NUMA
+
+config HAVE_MEMORYLESS_NODES
+       def_bool y
+       depends on NUMA
+
 config ARCH_PROC_KCORE_TEXT
        def_bool y
        depends on PROC_KCORE
index 21adbd7f90f86cf588e10638e1cf93091f2b5388..837dc82a013eb7f93b792bf0d4c713ce1939ba81 100644 (file)
@@ -94,7 +94,6 @@ ia64_acpi_release_global_lock (unsigned int *lock)
 #define acpi_noirq 0   /* ACPI always enabled on IA64 */
 #define acpi_pci_disabled 0 /* ACPI PCI always enabled on IA64 */
 #define acpi_strict 1  /* no ACPI spec workarounds on IA64 */
-#define acpi_ht 0      /* no HT-only mode on IA64 */
 #endif
 #define acpi_processor_cstate_check(x) (x) /* no idle limits on IA64 :) */
 static inline void disable_acpi(void) { }
index d8e98961dec77e42be573f1778b6d69a542c21a2..f299a4fb25c86e08fb516fcb1fa22e6df8bab1e1 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _ASM_IA64_SCATTERLIST_H
 #define _ASM_IA64_SCATTERLIST_H
 
+#include <asm-generic/scatterlist.h>
 /*
  * It used to be that ISA_DMA_THRESHOLD had something to do with the
  * DMA-limits of ISA-devices.  Nowadays, its only remaining use (apart
@@ -10,7 +11,6 @@
  * that's 4GB - 1.
  */
 #define ISA_DMA_THRESHOLD      0xffffffff
-
-#include <asm-generic/scatterlist.h>
+#define ARCH_HAS_SG_CHAIN
 
 #endif /* _ASM_IA64_SCATTERLIST_H */
index d323071d0f915e95ad60d6c45974a4e9788aedae..09f646753d1aa2203c2b0942f2294ae0e11d6e67 100644 (file)
  */
 #define RECLAIM_DISTANCE 15
 
-/*
- * Returns the number of the node containing CPU 'cpu'
- */
-#define cpu_to_node(cpu) (int)(cpu_to_node_map[cpu])
-
 /*
  * Returns a bitmask of CPUs on Node 'node'.
  */
index 3095654f9ab394839b9ae52509b5ec786c9f7837..d9485d952ed0a8c26fe8677b09e5ba249a5f9c25 100644 (file)
@@ -31,8 +31,6 @@ struct dma_map_ops swiotlb_dma_ops = {
        .unmap_sg = swiotlb_unmap_sg_attrs,
        .sync_single_for_cpu = swiotlb_sync_single_for_cpu,
        .sync_single_for_device = swiotlb_sync_single_for_device,
-       .sync_single_range_for_cpu = swiotlb_sync_single_range_for_cpu,
-       .sync_single_range_for_device = swiotlb_sync_single_range_for_device,
        .sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
        .sync_sg_for_device = swiotlb_sync_sg_for_device,
        .dma_supported = swiotlb_dma_supported,
index 0dec7f702448a07b6fc520342969411423d6445a..7c7909f9bc938b1bda4f1ece171ebd962aec2cfd 100644 (file)
@@ -638,7 +638,7 @@ ptrace_attach_sync_user_rbs (struct task_struct *child)
         */
 
        read_lock(&tasklist_lock);
-       if (child->signal) {
+       if (child->sighand) {
                spin_lock_irq(&child->sighand->siglock);
                if (child->state == TASK_STOPPED &&
                    !test_and_set_tsk_thread_flag(child, TIF_RESTORE_RSE)) {
@@ -662,7 +662,7 @@ ptrace_attach_sync_user_rbs (struct task_struct *child)
         * job control stop, so that SIGCONT can be used to wake it up.
         */
        read_lock(&tasklist_lock);
-       if (child->signal) {
+       if (child->sighand) {
                spin_lock_irq(&child->sighand->siglock);
                if (child->state == TASK_TRACED &&
                    (child->signal->flags & SIGNAL_STOP_STOPPED)) {
index e5230b2ff2c5e4dbc7d74d84c4142d0634e92a63..6a1380e90f874b54573d880e72c9c46b88661fe7 100644 (file)
@@ -390,6 +390,14 @@ smp_callin (void)
 
        fix_b0_for_bsp();
 
+#ifdef CONFIG_NUMA
+       /*
+        * numa_node_id() works after this.
+        */
+       set_numa_node(cpu_to_node_map[cpuid]);
+       set_numa_mem(local_memory_node(cpu_to_node_map[cpuid]));
+#endif
+
        ipi_call_lock_irq();
        spin_lock(&vector_lock);
        /* Setup the per cpu irq handling data structures */
@@ -632,6 +640,9 @@ void __devinit smp_prepare_boot_cpu(void)
 {
        cpu_set(smp_processor_id(), cpu_online_map);
        cpu_set(smp_processor_id(), cpu_callin_map);
+#ifdef CONFIG_NUMA
+       set_numa_node(cpu_to_node_map[smp_processor_id()]);
+#endif
        per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
        paravirt_post_smp_prepare_boot_cpu();
 }
index 7f3c0a2e60cdb32178f757534f670ab74f3b19a6..d5f4e9161201f648dbaf90ec96c300ec63d6536b 100644 (file)
@@ -979,11 +979,13 @@ long kvm_arch_vm_ioctl(struct file *filp,
                r = -EFAULT;
                if (copy_from_user(&irq_event, argp, sizeof irq_event))
                        goto out;
+               r = -ENXIO;
                if (irqchip_in_kernel(kvm)) {
                        __s32 status;
                        status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
                                    irq_event.irq, irq_event.level);
                        if (ioctl == KVM_IRQ_LINE_STATUS) {
+                               r = -EFAULT;
                                irq_event.status = status;
                                if (copy_to_user(argp, &irq_event,
                                                        sizeof irq_event))
@@ -1379,7 +1381,7 @@ static void kvm_release_vm_pages(struct kvm *kvm)
        int i, j;
        unsigned long base_gfn;
 
-       slots = rcu_dereference(kvm->memslots);
+       slots = kvm_memslots(kvm);
        for (i = 0; i < slots->nmemslots; i++) {
                memslot = &slots->memslots[i];
                base_gfn = memslot->base_gfn;
@@ -1535,8 +1537,10 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
                        goto out;
 
                if (copy_to_user(user_stack, stack,
-                                sizeof(struct kvm_ia64_vcpu_stack)))
+                                sizeof(struct kvm_ia64_vcpu_stack))) {
+                       r = -EFAULT;
                        goto out;
+               }
 
                break;
        }
index 7a62f75778c535f7421fc16ec4525407e3686e9b..f0b9cac824145709c570a3994b2dceaf089b32e3 100644 (file)
@@ -51,7 +51,7 @@ static int __init  kvm_vmm_init(void)
        vmm_fpswa_interface = fpswa_interface;
 
        /*Register vmm data to kvm side*/
-       return kvm_init(&vmm_info, 1024, THIS_MODULE);
+       return kvm_init(&vmm_info, 1024, 0, THIS_MODULE);
 }
 
 static void __exit kvm_vmm_exit(void)
index 3efea7d0a351c5159d5e843406e744fe0948a33d..2437718bd6b16c27027f1d2bba3060fd45bf8862 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/init.h>
 #include <linux/bootmem.h>
 #include <linux/module.h>
+#include <linux/random.h>
 #include <asm/mmzone.h>
 #include <asm/numa.h>
 
@@ -50,6 +51,22 @@ paddr_to_nid(unsigned long paddr)
        return (i < num_node_memblks) ? node_memblk[i].nid : (num_node_memblks ? -1 : 0);
 }
 
+/*
+ * Return the bit number of a random bit set in the nodemask.
+ *   (returns -1 if nodemask is empty)
+ */
+int __node_random(const nodemask_t *maskp)
+{
+       int w, bit = -1;
+
+       w = nodes_weight(*maskp);
+       if (w)
+               bit = bitmap_ord_to_pos(maskp->bits,
+                       get_random_int() % w, MAX_NUMNODES);
+       return bit;
+}
+EXPORT_SYMBOL(__node_random);
+
 #if defined(CONFIG_SPARSEMEM) && defined(CONFIG_NUMA)
 /*
  * Because of holes evaluate on section limits.
index 64aff520b899d59ef84a4c94032eb9cc13f7f3fa..aa2533ae7e9e37f4d14f9b53ed1cd67e7e0f28af 100644 (file)
@@ -335,8 +335,11 @@ pcibios_setup_root_windows(struct pci_bus *bus, struct pci_controller *ctrl)
 }
 
 struct pci_bus * __devinit
-pci_acpi_scan_root(struct acpi_device *device, int domain, int bus)
+pci_acpi_scan_root(struct acpi_pci_root *root)
 {
+       struct acpi_device *device = root->device;
+       int domain = root->segment;
+       int bus = root->secondary.start;
        struct pci_controller *controller;
        unsigned int windows = 0;
        struct pci_bus *pbus;
index f6c1c5fd075d6c0305334a5de54631e6c63e006e..fa1eceed0d23addfffb6674061a7ca6504317446 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/miscdevice.h>
 #include <linux/utsname.h>
 #include <linux/cpumask.h>
-#include <linux/smp_lock.h>
 #include <linux/nodemask.h>
 #include <linux/smp.h>
 #include <linux/mutex.h>
@@ -682,8 +681,7 @@ static int sn_hwperf_map_err(int hwperf_err)
 /*
  * ioctl for "sn_hwperf" misc device
  */
-static int
-sn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, unsigned long arg)
+static long sn_hwperf_ioctl(struct file *fp, u32 op, unsigned long arg)
 {
        struct sn_hwperf_ioctl_args a;
        struct cpuinfo_ia64 *cdata;
@@ -699,8 +697,6 @@ sn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, unsigned long arg)
        int i;
        int j;
 
-       unlock_kernel();
-
        /* only user requests are allowed here */
        if ((op & SN_HWPERF_OP_MASK) < 10) {
                r = -EINVAL;
@@ -859,12 +855,11 @@ sn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, unsigned long arg)
 error:
        vfree(p);
 
-       lock_kernel();
        return r;
 }
 
 static const struct file_operations sn_hwperf_fops = {
-       .ioctl = sn_hwperf_ioctl,
+       .unlocked_ioctl = sn_hwperf_ioctl,
 };
 
 static struct miscdevice sn_hwperf_dev = {
index 1ed372c73d0bd9ef05f143289ccecc77cbc3ada5..aeeddd8dac17b7feb6726e73ff3b7c61ce193ba1 100644 (file)
@@ -1,20 +1,7 @@
 #ifndef _ASM_M32R_SCATTERLIST_H
 #define _ASM_M32R_SCATTERLIST_H
 
-#include <asm/types.h>
-
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-    unsigned long sg_magic;
-#endif
-    char *  address;    /* Location data is to be transferred to, NULL for
-                         * highmem page */
-    unsigned long page_link;
-    unsigned int offset;/* for highmem, page offset */
-
-    dma_addr_t dma_address;
-    unsigned int length;
-};
+#include <asm-generic/scatterlist.h>
 
 #define ISA_DMA_THRESHOLD (0x1fffffff)
 
index b5da298ba61df539b07bcadd8ef979d465215d5d..2e3737b92ffca3e36d0005317feee1d38dee526e 100644 (file)
@@ -7,6 +7,7 @@ config M68K
        default y
        select HAVE_AOUT
        select HAVE_IDE
+       select GENERIC_ATOMIC64
 
 config MMU
        bool
index d2cc35d985328f7a240ad85216fc9123820be008..b1577f741fa8c46789c4324662dcb87f6a6369ce 100644 (file)
@@ -97,10 +97,6 @@ static void amiga_get_model(char *model);
 static void amiga_get_hardware_list(struct seq_file *m);
 /* amiga specific timer functions */
 static unsigned long amiga_gettimeoffset(void);
-static int a3000_hwclk(int, struct rtc_time *);
-static int a2000_hwclk(int, struct rtc_time *);
-static int amiga_set_clock_mmss(unsigned long);
-static unsigned int amiga_get_ss(void);
 extern void amiga_mksound(unsigned int count, unsigned int ticks);
 static void amiga_reset(void);
 extern void amiga_init_sound(void);
@@ -138,10 +134,6 @@ static struct {
        }
 };
 
-static struct resource rtc_resource = {
-       .start = 0x00dc0000, .end = 0x00dcffff
-};
-
 static struct resource ram_resource[NUM_MEMINFO];
 
 
@@ -387,15 +379,6 @@ void __init config_amiga(void)
        mach_get_model       = amiga_get_model;
        mach_get_hardware_list = amiga_get_hardware_list;
        mach_gettimeoffset   = amiga_gettimeoffset;
-       if (AMIGAHW_PRESENT(A3000_CLK)) {
-               mach_hwclk         = a3000_hwclk;
-               rtc_resource.name = "A3000 RTC";
-               request_resource(&iomem_resource, &rtc_resource);
-       } else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ {
-               mach_hwclk         = a2000_hwclk;
-               rtc_resource.name = "A2000 RTC";
-               request_resource(&iomem_resource, &rtc_resource);
-       }
 
        /*
         * default MAX_DMA=0xffffffff on all machines. If we don't do so, the SCSI
@@ -404,8 +387,6 @@ void __init config_amiga(void)
         */
        mach_max_dma_address = 0xffffffff;
 
-       mach_set_clock_mmss  = amiga_set_clock_mmss;
-       mach_get_ss          = amiga_get_ss;
        mach_reset           = amiga_reset;
 #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE)
        mach_beep            = amiga_mksound;
@@ -530,161 +511,6 @@ static unsigned long amiga_gettimeoffset(void)
        return ticks + offset;
 }
 
-static int a3000_hwclk(int op, struct rtc_time *t)
-{
-       tod_3000.cntrl1 = TOD3000_CNTRL1_HOLD;
-
-       if (!op) { /* read */
-               t->tm_sec  = tod_3000.second1 * 10 + tod_3000.second2;
-               t->tm_min  = tod_3000.minute1 * 10 + tod_3000.minute2;
-               t->tm_hour = tod_3000.hour1   * 10 + tod_3000.hour2;
-               t->tm_mday = tod_3000.day1    * 10 + tod_3000.day2;
-               t->tm_wday = tod_3000.weekday;
-               t->tm_mon  = tod_3000.month1  * 10 + tod_3000.month2 - 1;
-               t->tm_year = tod_3000.year1   * 10 + tod_3000.year2;
-               if (t->tm_year <= 69)
-                       t->tm_year += 100;
-       } else {
-               tod_3000.second1 = t->tm_sec / 10;
-               tod_3000.second2 = t->tm_sec % 10;
-               tod_3000.minute1 = t->tm_min / 10;
-               tod_3000.minute2 = t->tm_min % 10;
-               tod_3000.hour1   = t->tm_hour / 10;
-               tod_3000.hour2   = t->tm_hour % 10;
-               tod_3000.day1    = t->tm_mday / 10;
-               tod_3000.day2    = t->tm_mday % 10;
-               if (t->tm_wday != -1)
-                       tod_3000.weekday = t->tm_wday;
-               tod_3000.month1  = (t->tm_mon + 1) / 10;
-               tod_3000.month2  = (t->tm_mon + 1) % 10;
-               if (t->tm_year >= 100)
-                       t->tm_year -= 100;
-               tod_3000.year1   = t->tm_year / 10;
-               tod_3000.year2   = t->tm_year % 10;
-       }
-
-       tod_3000.cntrl1 = TOD3000_CNTRL1_FREE;
-
-       return 0;
-}
-
-static int a2000_hwclk(int op, struct rtc_time *t)
-{
-       int cnt = 5;
-
-       tod_2000.cntrl1 = TOD2000_CNTRL1_HOLD;
-
-       while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt) {
-               tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
-               udelay(70);
-               tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
-               --cnt;
-       }
-
-       if (!cnt)
-               printk(KERN_INFO "hwclk: timed out waiting for RTC (0x%x)\n",
-                       tod_2000.cntrl1);
-
-       if (!op) { /* read */
-               t->tm_sec  = tod_2000.second1     * 10 + tod_2000.second2;
-               t->tm_min  = tod_2000.minute1     * 10 + tod_2000.minute2;
-               t->tm_hour = (tod_2000.hour1 & 3) * 10 + tod_2000.hour2;
-               t->tm_mday = tod_2000.day1        * 10 + tod_2000.day2;
-               t->tm_wday = tod_2000.weekday;
-               t->tm_mon  = tod_2000.month1      * 10 + tod_2000.month2 - 1;
-               t->tm_year = tod_2000.year1       * 10 + tod_2000.year2;
-               if (t->tm_year <= 69)
-                       t->tm_year += 100;
-
-               if (!(tod_2000.cntrl3 & TOD2000_CNTRL3_24HMODE)) {
-                       if (!(tod_2000.hour1 & TOD2000_HOUR1_PM) && t->tm_hour == 12)
-                               t->tm_hour = 0;
-                       else if ((tod_2000.hour1 & TOD2000_HOUR1_PM) && t->tm_hour != 12)
-                               t->tm_hour += 12;
-               }
-       } else {
-               tod_2000.second1 = t->tm_sec / 10;
-               tod_2000.second2 = t->tm_sec % 10;
-               tod_2000.minute1 = t->tm_min / 10;
-               tod_2000.minute2 = t->tm_min % 10;
-               if (tod_2000.cntrl3 & TOD2000_CNTRL3_24HMODE)
-                       tod_2000.hour1 = t->tm_hour / 10;
-               else if (t->tm_hour >= 12)
-                       tod_2000.hour1 = TOD2000_HOUR1_PM +
-                               (t->tm_hour - 12) / 10;
-               else
-                       tod_2000.hour1 = t->tm_hour / 10;
-               tod_2000.hour2   = t->tm_hour % 10;
-               tod_2000.day1    = t->tm_mday / 10;
-               tod_2000.day2    = t->tm_mday % 10;
-               if (t->tm_wday != -1)
-                       tod_2000.weekday = t->tm_wday;
-               tod_2000.month1  = (t->tm_mon + 1) / 10;
-               tod_2000.month2  = (t->tm_mon + 1) % 10;
-               if (t->tm_year >= 100)
-                       t->tm_year -= 100;
-               tod_2000.year1   = t->tm_year / 10;
-               tod_2000.year2   = t->tm_year % 10;
-       }
-
-       tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
-
-       return 0;
-}
-
-static int amiga_set_clock_mmss(unsigned long nowtime)
-{
-       short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
-
-       if (AMIGAHW_PRESENT(A3000_CLK)) {
-               tod_3000.cntrl1 = TOD3000_CNTRL1_HOLD;
-
-               tod_3000.second1 = real_seconds / 10;
-               tod_3000.second2 = real_seconds % 10;
-               tod_3000.minute1 = real_minutes / 10;
-               tod_3000.minute2 = real_minutes % 10;
-
-               tod_3000.cntrl1 = TOD3000_CNTRL1_FREE;
-       } else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ {
-               int cnt = 5;
-
-               tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
-
-               while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt) {
-                       tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
-                       udelay(70);
-                       tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
-                       --cnt;
-               }
-
-               if (!cnt)
-                       printk(KERN_INFO "set_clock_mmss: timed out waiting for RTC (0x%x)\n", tod_2000.cntrl1);
-
-               tod_2000.second1 = real_seconds / 10;
-               tod_2000.second2 = real_seconds % 10;
-               tod_2000.minute1 = real_minutes / 10;
-               tod_2000.minute2 = real_minutes % 10;
-
-               tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
-       }
-
-       return 0;
-}
-
-static unsigned int amiga_get_ss(void)
-{
-       unsigned int s;
-
-       if (AMIGAHW_PRESENT(A3000_CLK)) {
-               tod_3000.cntrl1 = TOD3000_CNTRL1_HOLD;
-               s = tod_3000.second1 * 10 + tod_3000.second2;
-               tod_3000.cntrl1 = TOD3000_CNTRL1_FREE;
-       } else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ {
-               s = tod_2000.second1 * 10 + tod_2000.second2;
-       }
-       return s;
-}
-
 static NORET_TYPE void amiga_reset(void)
     ATTRIB_NORET;
 
index 38f18bf14737cbff063eb3cb5d3767d13575dec7..7fd8b41723ea4b4b4e4f763c1aebf8cd3ce6a44a 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/zorro.h>
 
 #include <asm/amigahw.h>
+#include <asm/amigayle.h>
 
 
 #ifdef CONFIG_ZORRO
@@ -55,11 +56,77 @@ static int __init amiga_init_bus(void)
 
 subsys_initcall(amiga_init_bus);
 
-#endif /* CONFIG_ZORRO */
+
+static int z_dev_present(zorro_id id)
+{
+       unsigned int i;
+
+       for (i = 0; i < zorro_num_autocon; i++)
+               if (zorro_autocon[i].rom.er_Manufacturer == ZORRO_MANUF(id) &&
+                   zorro_autocon[i].rom.er_Product == ZORRO_PROD(id))
+                       return 1;
+
+       return 0;
+}
+
+#else /* !CONFIG_ZORRO */
+
+static inline int z_dev_present(zorro_id id) { return 0; }
+
+#endif /* !CONFIG_ZORRO */
+
+
+static const struct resource a3000_scsi_resource __initconst = {
+       .start  = 0xdd0000,
+       .end    = 0xdd00ff,
+       .flags  = IORESOURCE_MEM,
+};
+
+
+static const struct resource a4000t_scsi_resource __initconst = {
+       .start  = 0xdd0000,
+       .end    = 0xdd0fff,
+       .flags  = IORESOURCE_MEM,
+};
+
+
+static const struct resource a1200_ide_resource __initconst = {
+       .start  = 0xda0000,
+       .end    = 0xda1fff,
+       .flags  = IORESOURCE_MEM,
+};
+
+static const struct gayle_ide_platform_data a1200_ide_pdata __initconst = {
+       .base           = 0xda0000,
+       .irqport        = 0xda9000,
+       .explicit_ack   = 1,
+};
+
+
+static const struct resource a4000_ide_resource __initconst = {
+       .start  = 0xdd2000,
+       .end    = 0xdd3fff,
+       .flags  = IORESOURCE_MEM,
+};
+
+static const struct gayle_ide_platform_data a4000_ide_pdata __initconst = {
+       .base           = 0xdd2020,
+       .irqport        = 0xdd3020,
+       .explicit_ack   = 0,
+};
+
+
+static const struct resource amiga_rtc_resource __initconst = {
+       .start  = 0x00dc0000,
+       .end    = 0x00dcffff,
+       .flags  = IORESOURCE_MEM,
+};
 
 
 static int __init amiga_init_devices(void)
 {
+       struct platform_device *pdev;
+
        if (!MACH_IS_AMIGA)
                return -ENODEV;
 
@@ -77,6 +144,53 @@ static int __init amiga_init_devices(void)
        if (AMIGAHW_PRESENT(AMI_FLOPPY))
                platform_device_register_simple("amiga-floppy", -1, NULL, 0);
 
+       if (AMIGAHW_PRESENT(A3000_SCSI))
+               platform_device_register_simple("amiga-a3000-scsi", -1,
+                                               &a3000_scsi_resource, 1);
+
+       if (AMIGAHW_PRESENT(A4000_SCSI))
+               platform_device_register_simple("amiga-a4000t-scsi", -1,
+                                               &a4000t_scsi_resource, 1);
+
+       if (AMIGAHW_PRESENT(A1200_IDE) ||
+           z_dev_present(ZORRO_PROD_MTEC_VIPER_MK_V_E_MATRIX_530_SCSI_IDE)) {
+               pdev = platform_device_register_simple("amiga-gayle-ide", -1,
+                                                      &a1200_ide_resource, 1);
+               platform_device_add_data(pdev, &a1200_ide_pdata,
+                                        sizeof(a1200_ide_pdata));
+       }
+
+       if (AMIGAHW_PRESENT(A4000_IDE)) {
+               pdev = platform_device_register_simple("amiga-gayle-ide", -1,
+                                                      &a4000_ide_resource, 1);
+               platform_device_add_data(pdev, &a4000_ide_pdata,
+                                        sizeof(a4000_ide_pdata));
+       }
+
+
+       /* other I/O hardware */
+       if (AMIGAHW_PRESENT(AMI_KEYBOARD))
+               platform_device_register_simple("amiga-keyboard", -1, NULL, 0);
+
+       if (AMIGAHW_PRESENT(AMI_MOUSE))
+               platform_device_register_simple("amiga-mouse", -1, NULL, 0);
+
+       if (AMIGAHW_PRESENT(AMI_SERIAL))
+               platform_device_register_simple("amiga-serial", -1, NULL, 0);
+
+       if (AMIGAHW_PRESENT(AMI_PARALLEL))
+               platform_device_register_simple("amiga-parallel", -1, NULL, 0);
+
+
+       /* real time clocks */
+       if (AMIGAHW_PRESENT(A2000_CLK))
+               platform_device_register_simple("rtc-msm6242", -1,
+                                               &amiga_rtc_resource, 1);
+
+       if (AMIGAHW_PRESENT(A3000_CLK))
+               platform_device_register_simple("rtc-rp5c01", -1,
+                                               &amiga_rtc_resource, 1);
+
        return 0;
 }
 
index bb5a6aa329f3e840ae9ae4fe9acc3a6749789f42..a01453d9c231ba9b0da87050b7322aeab91ce83c 100644 (file)
@@ -104,4 +104,10 @@ struct GAYLE {
 #define GAYLE_CFG_250NS                0x00
 #define GAYLE_CFG_720NS                0x0c
 
+struct gayle_ide_platform_data {
+       unsigned long base;
+       unsigned long irqport;
+       int explicit_ack;       /* A1200 IDE needs explicit ack */
+};
+
 #endif /* asm-m68k/amigayle.h */
index 8d29145ebb27b66b6402c0c04367032c15d1e35c..eab36dcacf6c427241b64e969343f23649ccd11a 100644 (file)
@@ -3,3 +3,5 @@
 #else
 #include "atomic_mm.h"
 #endif
+
+#include <asm-generic/atomic64.h>
index fed3fd30de7e468797a85ff5945119c436f92fce..ecafbe1718c3cccee4a0441efaca9670b0548c59 100644 (file)
@@ -8,4 +8,6 @@
 #define        L1_CACHE_SHIFT  4
 #define        L1_CACHE_BYTES  (1<< L1_CACHE_SHIFT)
 
+#define ARCH_KMALLOC_MINALIGN  L1_CACHE_BYTES
+
 #endif
index ed2b69b96805b50cafc1c8d09e9b07c51f23d77d..db824a4b136ea5a8bf39f4da57b2cdc068e6d97b 100644 (file)
 
 #define MCF_GPIO_PAR_UART                   (0xA4036)
 #define MCF_GPIO_PAR_FECI2C                 (0xA4033)
+#define MCF_GPIO_PAR_QSPI                   (0xA4034)
 #define MCF_GPIO_PAR_FEC                    (0xA4038)
 
 #define MCF_GPIO_PAR_UART_PAR_URXD0         (0x0001)
index a34894cf8e6f3ec02ea35fd3098c39c5084675c8..e8d06b24a48ea4e65478d9ef043a9cfcf1eb83d6 100644 (file)
 #define MCFGPIO_IRQ_MAX                        8
 #define MCFGPIO_IRQ_VECBASE            MCFINT_VECBASE
 
+/*
+ * Pin Assignment
+*/
+#define        MCFGPIO_PAR_QSPI        (MCF_IPSBAR + 0x10004A)
+#define        MCFGPIO_PAR_TIMER       (MCF_IPSBAR + 0x10004C)
 /****************************************************************************/
 #endif /* m523xsim_h */
index 14bce877ed8853e6744e90c6e9665e256d7b938d..79b7b402f3c984a48eda4aedb65f20995e672a50 100644 (file)
 #define        MCFSIM_DMA1ICR          MCFSIM_ICR7     /* DMA 1 ICR */
 #define        MCFSIM_DMA2ICR          MCFSIM_ICR8     /* DMA 2 ICR */
 #define        MCFSIM_DMA3ICR          MCFSIM_ICR9     /* DMA 3 ICR */
+#define        MCFSIM_QSPIICR          MCFSIM_ICR10    /* QSPI ICR */
 
 /*
  *     Define system peripheral IRQ usage.
  */
+#define        MCF_IRQ_QSPI            28              /* QSPI, Level 4 */
 #define        MCF_IRQ_TIMER           30              /* Timer0, Level 6 */
 #define        MCF_IRQ_PROFILER        31              /* Timer1, Level 7 */
 
index 453356d72d80a4a1dad0608603e8bf3fd585695a..1feb46f108ce79bdbf5561f29a084ae87ed53107 100644 (file)
@@ -31,6 +31,7 @@
 #define        MCFINT_UART0            13              /* Interrupt number for UART0 */
 #define        MCFINT_UART1            14              /* Interrupt number for UART1 */
 #define        MCFINT_UART2            15              /* Interrupt number for UART2 */
+#define        MCFINT_QSPI             18              /* Interrupt number for QSPI */
 #define        MCFINT_PIT1             36              /* Interrupt number for PIT1 */
 
 /*
 #define MCFGPIO_PIN_MAX                        100
 #define MCFGPIO_IRQ_MAX                        8
 #define MCFGPIO_IRQ_VECBASE            MCFINT_VECBASE
+
+#define MCFGPIO_PAR_QSPI       (MCF_IPSBAR + 0x10004A)
+#define MCFGPIO_PAR_TIMER      (MCF_IPSBAR + 0x10004C)
 #endif
 
 #ifdef CONFIG_M5275
 #define MCFGPIO_PIN_MAX                        148
 #define MCFGPIO_IRQ_MAX                        8
 #define MCFGPIO_IRQ_VECBASE            MCFINT_VECBASE
+
+#define MCFGPIO_PAR_QSPI       (MCF_IPSBAR + 0x10007E)
 #endif
 
 /*
 #define MCFEPORT_EPPDR         (MCF_IPSBAR + 0x130005)
 
 
+
 /*
  *     GPIO pins setups to enable the UARTs.
  */
index e2ad1f42b65709e762621c06e53420c7e839e571..891cbedad97269ad99fa0cf4e885a42b0610491a 100644 (file)
@@ -29,6 +29,7 @@
 
 #define        MCFINT_VECBASE          64              /* Vector base number */
 #define        MCFINT_UART0            13              /* Interrupt number for UART0 */
+#define        MCFINT_QSPI             18              /* Interrupt number for QSPI */
 #define        MCFINT_PIT1             55              /* Interrupt number for PIT1 */
 
 /*
 #define MCF5282_I2C_I2SR_RXAK   (0x01)  // received acknowledge
 
 
-
-/*********************************************************************
-*
-* Queued Serial Peripheral Interface (QSPI) Module
-*
-*********************************************************************/
-/* Derek - 21 Feb 2005 */
-/* change to the format used in I2C */
-/* Read/Write access macros for general use */
-#define MCF5282_QSPI_QMR        MCF_IPSBAR + 0x0340
-#define MCF5282_QSPI_QDLYR      MCF_IPSBAR + 0x0344
-#define MCF5282_QSPI_QWR        MCF_IPSBAR + 0x0348
-#define MCF5282_QSPI_QIR        MCF_IPSBAR + 0x034C
-#define MCF5282_QSPI_QAR        MCF_IPSBAR + 0x0350
-#define MCF5282_QSPI_QDR        MCF_IPSBAR + 0x0354
-#define MCF5282_QSPI_QCR        MCF_IPSBAR + 0x0354
-
-/* Bit level definitions and macros */
-#define MCF5282_QSPI_QMR_MSTR                           (0x8000)
-#define MCF5282_QSPI_QMR_DOHIE                          (0x4000)
-#define MCF5282_QSPI_QMR_BITS_16                        (0x0000)
-#define MCF5282_QSPI_QMR_BITS_8                         (0x2000)
-#define MCF5282_QSPI_QMR_BITS_9                         (0x2400)
-#define MCF5282_QSPI_QMR_BITS_10                        (0x2800)
-#define MCF5282_QSPI_QMR_BITS_11                        (0x2C00)
-#define MCF5282_QSPI_QMR_BITS_12                        (0x3000)
-#define MCF5282_QSPI_QMR_BITS_13                        (0x3400)
-#define MCF5282_QSPI_QMR_BITS_14                        (0x3800)
-#define MCF5282_QSPI_QMR_BITS_15                        (0x3C00)
-#define MCF5282_QSPI_QMR_CPOL                           (0x0200)
-#define MCF5282_QSPI_QMR_CPHA                           (0x0100)
-#define MCF5282_QSPI_QMR_BAUD(x)                        (((x)&0x00FF))
-
-#define MCF5282_QSPI_QDLYR_SPE                          (0x80)
-#define MCF5282_QSPI_QDLYR_QCD(x)                       (((x)&0x007F)<<8)
-#define MCF5282_QSPI_QDLYR_DTL(x)                       (((x)&0x00FF))
-
-#define MCF5282_QSPI_QWR_HALT                           (0x8000)
-#define MCF5282_QSPI_QWR_WREN                           (0x4000)
-#define MCF5282_QSPI_QWR_WRTO                           (0x2000)
-#define MCF5282_QSPI_QWR_CSIV                           (0x1000)
-#define MCF5282_QSPI_QWR_ENDQP(x)                       (((x)&0x000F)<<8)
-#define MCF5282_QSPI_QWR_CPTQP(x)                       (((x)&0x000F)<<4)
-#define MCF5282_QSPI_QWR_NEWQP(x)                       (((x)&0x000F))
-
-#define MCF5282_QSPI_QIR_WCEFB                          (0x8000)
-#define MCF5282_QSPI_QIR_ABRTB                          (0x4000)
-#define MCF5282_QSPI_QIR_ABRTL                          (0x1000)
-#define MCF5282_QSPI_QIR_WCEFE                          (0x0800)
-#define MCF5282_QSPI_QIR_ABRTE                          (0x0400)
-#define MCF5282_QSPI_QIR_SPIFE                          (0x0100)
-#define MCF5282_QSPI_QIR_WCEF                           (0x0008)
-#define MCF5282_QSPI_QIR_ABRT                           (0x0004)
-#define MCF5282_QSPI_QIR_SPIF                           (0x0001)
-
-#define MCF5282_QSPI_QAR_ADDR(x)                        (((x)&0x003F))
-
-#define MCF5282_QSPI_QDR_COMMAND(x)                     (((x)&0xFF00))
-#define MCF5282_QSPI_QCR_DATA(x)                        (((x)&0x00FF)<<8)
-#define MCF5282_QSPI_QCR_CONT                           (0x8000)
-#define MCF5282_QSPI_QCR_BITSE                          (0x4000)
-#define MCF5282_QSPI_QCR_DT                             (0x2000)
-#define MCF5282_QSPI_QCR_DSCK                           (0x1000)
-#define MCF5282_QSPI_QCR_CS                             (((x)&0x000F)<<8)
-
-/****************************************************************************/
 #endif /* m528xsim_h */
index 36bf15aec9aebcfc6da77bc3f2f83e2907a5a805..c4bf1c81e3cfa5255901fa2c9c2b817d2173e968 100644 (file)
@@ -17,6 +17,7 @@
 #define MCFINT_UART0        26          /* Interrupt number for UART0 */
 #define MCFINT_UART1        27          /* Interrupt number for UART1 */
 #define MCFINT_UART2        28          /* Interrupt number for UART2 */
+#define MCFINT_QSPI         31          /* Interrupt number for QSPI */
 
 #define MCF_WTM_WCR    MCF_REG16(0xFC098000)
 
diff --git a/arch/m68k/include/asm/mcfqspi.h b/arch/m68k/include/asm/mcfqspi.h
new file mode 100644 (file)
index 0000000..39d90d5
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Definitions for Freescale Coldfire QSPI module
+ *
+ * Copyright 2010 Steven King <sfking@fdwdc.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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+*/
+
+#ifndef mcfqspi_h
+#define mcfqspi_h
+
+#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x)
+#define        MCFQSPI_IOBASE          (MCF_IPSBAR + 0x340)
+#elif defined(CONFIG_M5249)
+#define MCFQSPI_IOBASE         (MCF_MBAR + 0x300)
+#elif defined(CONFIG_M520x) || defined(CONFIG_M532x)
+#define MCFQSPI_IOBASE         0xFC058000
+#endif
+#define MCFQSPI_IOSIZE         0x40
+
+/**
+ * struct mcfqspi_cs_control - chip select control for the coldfire qspi driver
+ * @setup: setup the control; allocate gpio's, etc. May be NULL.
+ * @teardown: finish with the control; free gpio's, etc. May be NULL.
+ * @select: output the signals to select the device.  Can not be NULL.
+ * @deselect: output the signals to deselect the device. Can not be NULL.
+ *
+ * The QSPI module has 4 hardware chip selects.  We don't use them.  Instead
+ * platforms are required to supply a mcfqspi_cs_control as a part of the
+ * platform data for each QSPI master controller.  Only the select and
+ * deselect functions are required.
+*/
+struct mcfqspi_cs_control {
+       int     (*setup)(struct mcfqspi_cs_control *);
+       void    (*teardown)(struct mcfqspi_cs_control *);
+       void    (*select)(struct mcfqspi_cs_control *, u8, bool);
+       void    (*deselect)(struct mcfqspi_cs_control *, u8, bool);
+};
+
+/**
+ * struct mcfqspi_platform_data - platform data for the coldfire qspi driver
+ * @bus_num: board specific identifier for this qspi driver.
+ * @num_chipselects: number of chip selects supported by this qspi driver.
+ * @cs_control: platform dependent chip select control.
+*/
+struct mcfqspi_platform_data {
+       s16     bus_num;
+       u16     num_chipselect;
+       struct mcfqspi_cs_control *cs_control;
+};
+
+#endif /* mcfqspi_h */
diff --git a/arch/m68k/include/asm/mcfsmc.h b/arch/m68k/include/asm/mcfsmc.h
deleted file mode 100644 (file)
index 527bea5..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-/****************************************************************************/
-
-/*
- *     mcfsmc.h -- SMC ethernet support for ColdFire environments.
- *
- *     (C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com)
- *     (C) Copyright 2000, Lineo Inc. (www.lineo.com) 
- */
-
-/****************************************************************************/
-#ifndef        mcfsmc_h
-#define        mcfsmc_h
-/****************************************************************************/
-
-/*
- *     None of the current ColdFire targets that use the SMC91x111
- *     allow 8 bit accesses. So this code is 16bit access only.
- */
-
-
-#undef outb
-#undef inb
-#undef outw
-#undef outwd
-#undef inw     
-#undef outl
-#undef inl
-
-#undef outsb
-#undef outsw
-#undef outsl
-#undef insb
-#undef insw
-#undef insl
-
-/*
- *     Re-defines for ColdFire environment... The SMC part is
- *     mapped into memory space, so remap the PC-style in/out
- *     routines to handle that.
- */
-#define        outb    smc_outb
-#define        inb     smc_inb
-#define        outw    smc_outw
-#define        outwd   smc_outwd
-#define        inw     smc_inw
-#define        outl    smc_outl
-#define        inl     smc_inl
-
-#define        outsb   smc_outsb
-#define        outsw   smc_outsw
-#define        outsl   smc_outsl
-#define        insb    smc_insb
-#define        insw    smc_insw
-#define        insl    smc_insl
-
-
-static inline int smc_inb(unsigned int addr)
-{
-       register unsigned short w;
-       w = *((volatile unsigned short *) (addr & ~0x1));
-       return(((addr & 0x1) ? w : (w >> 8)) & 0xff);
-}
-
-static inline void smc_outw(unsigned int val, unsigned int addr)
-{
-       *((volatile unsigned short *) addr) = (val << 8) | (val >> 8);
-}
-
-static inline int smc_inw(unsigned int addr)
-{
-       register unsigned short w;
-       w = *((volatile unsigned short *) addr);
-       return(((w << 8) | (w >> 8)) & 0xffff);
-}
-
-static inline void smc_outl(unsigned long val, unsigned int addr)
-{
-       *((volatile unsigned long *) addr) = 
-               ((val << 8) & 0xff000000) | ((val >> 8) & 0x00ff0000) |
-               ((val << 8) & 0x0000ff00) | ((val >> 8) & 0x000000ff);
-}
-
-static inline void smc_outwd(unsigned int val, unsigned int addr)
-{
-       *((volatile unsigned short *) addr) = val;
-}
-
-
-/*
- *     The rep* functions are used to feed the data port with
- *     raw data. So we do not byte swap them when copying.
- */
-
-static inline void smc_insb(unsigned int addr, void *vbuf, int unsigned long len)
-{
-       volatile unsigned short *rp;
-       unsigned short          *buf, *ebuf;
-
-       buf = (unsigned short *) vbuf;
-       rp = (volatile unsigned short *) addr;
-
-       /* Copy as words for as long as possible */
-       for (ebuf = buf + (len >> 1); (buf < ebuf); )
-               *buf++ = *rp;
-
-       /* Lastly, handle left over byte */
-       if (len & 0x1)
-               *((unsigned char *) buf) = (*rp >> 8) & 0xff;
-}
-
-static inline void smc_insw(unsigned int addr, void *vbuf, unsigned long len)
-{
-       volatile unsigned short *rp;
-       unsigned short          *buf, *ebuf;
-
-       buf = (unsigned short *) vbuf;
-       rp = (volatile unsigned short *) addr;
-       for (ebuf = buf + len; (buf < ebuf); )
-               *buf++ = *rp;
-}
-
-static inline void smc_insl(unsigned int addr, void *vbuf, unsigned long len)
-{
-       volatile unsigned long  *rp;
-       unsigned long           *buf, *ebuf;
-
-       buf = (unsigned long *) vbuf;
-       rp = (volatile unsigned long *) addr;
-       for (ebuf = buf + len; (buf < ebuf); )
-               *buf++ = *rp;
-}
-
-static inline void smc_outsw(unsigned int addr, const void *vbuf, unsigned long len)
-{
-       volatile unsigned short *rp;
-       unsigned short          *buf, *ebuf;
-
-       buf = (unsigned short *) vbuf;
-       rp = (volatile unsigned short *) addr;
-       for (ebuf = buf + len; (buf < ebuf); )
-               *rp = *buf++;
-}
-
-static inline void smc_outsl(unsigned int addr, void *vbuf, unsigned long len)
-{
-       volatile unsigned long  *rp;
-       unsigned long           *buf, *ebuf;
-
-       buf = (unsigned long *) vbuf;
-       rp = (volatile unsigned long *) addr;
-       for (ebuf = buf + len; (buf < ebuf); )
-               *rp = *buf++;
-}
-
-
-#ifdef CONFIG_NETtel
-/*
- *     Re-map the address space of at least one of the SMC ethernet
- *     parts. Both parts power up decoding the same address, so we
- *     need to move one of them first, before doing enything else.
- *
- *     We also increase the number of wait states for this part by one.
- */
-
-void smc_remap(unsigned int ioaddr)
-{
-       static int              once = 0;
-       extern unsigned short   ppdata;
-       if (once++ == 0) {
-               *((volatile unsigned short *)MCFSIM_PADDR) = 0x00ec;
-               ppdata |= 0x0080;
-               *((volatile unsigned short *)MCFSIM_PADAT) = ppdata;
-               outw(0x0001, ioaddr + BANK_SELECT);
-               outw(0x0001, ioaddr + BANK_SELECT);
-               outw(0x0067, ioaddr + BASE);
-
-               ppdata &= ~0x0080;
-               *((volatile unsigned short *)MCFSIM_PADAT) = ppdata;
-       }
-       
-       *((volatile unsigned short *)(MCF_MBAR+MCFSIM_CSCR3)) = 0x1180;
-}
-
-#endif
-
-/****************************************************************************/
-#endif /* mcfsmc_h */
index cbd3d4751dd2998bb8732652b2bb66d9bd9a4b1d..7a6a7590cc02cd584d28fd9e2a98d9d1b8b30797 100644 (file)
@@ -44,11 +44,15 @@ static inline void wrusp(unsigned long usp)
  * User space process size: 3.75GB. This is hardcoded into a few places,
  * so don't change it unless you know what you are doing.
  */
+#ifdef CONFIG_MMU
 #ifndef CONFIG_SUN3
 #define TASK_SIZE      (0xF0000000UL)
 #else
 #define TASK_SIZE      (0x0E000000UL)
 #endif
+#else
+#define TASK_SIZE      (0xFFFFFFFFUL)
+#endif
 
 #ifdef __KERNEL__
 #define STACK_TOP      TASK_SIZE
index e27ad902b1cff9bb26792f3fe99ee96a45fa8bc5..175da06c6b9549c27bb87ccd11a06f9d0a4a4b13 100644 (file)
@@ -1,23 +1,9 @@
 #ifndef _M68K_SCATTERLIST_H
 #define _M68K_SCATTERLIST_H
 
-#include <linux/types.h>
-
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-       unsigned long sg_magic;
-#endif
-       unsigned long page_link;
-       unsigned int offset;
-       unsigned int length;
-
-       dma_addr_t dma_address; /* A place to hang host-specific addresses at. */
-};
+#include <asm-generic/scatterlist.h>
 
 /* This is bogus and should go away. */
 #define ISA_DMA_THRESHOLD (0x00ffffff)
 
-#define sg_dma_address(sg)     ((sg)->dma_address)
-#define sg_dma_len(sg)         ((sg)->length)
-
 #endif /* !(_M68K_SCATTERLIST_H) */
index 064f5913db1a7c2122dd902c01f558b0484ab4cf..efeb6033fc1701621b418c4af5bd5046bd7bacaf 100644 (file)
@@ -566,7 +566,7 @@ config RAMBASE
          processor address space.
 
 config RAMSIZE
-       hex "Size of RAM (in bytes)"
+       hex "Size of RAM (in bytes), or 0 for automatic"
        default "0x400000"
        help
          Define the size of the system RAM. If you select 0 then the
index 6f6673cb58290c31d1bc215e0e312a70d88a3f8f..bc05cf74d9c0609f3a57ff9405a58400a427feea 100644 (file)
@@ -2,7 +2,7 @@
  *  linux/arch/m68knommu/mm/fault.c
  *
  *  Copyright (C) 1998  D. Jeff Dionne <jeff@lineo.ca>,
- *  Copyright (C) 2000  Lineo, Inc.  (www.lineo.com) 
+ *  Copyright (C) 2000  Lineo, Inc.  (www.lineo.com)
  *
  *  Based on:
  *
@@ -36,7 +36,7 @@ asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
                              unsigned long error_code)
 {
 #ifdef DEBUG
-       printk (KERN_DEBUG "regs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld\n",
+       printk(KERN_DEBUG "regs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld\n",
                regs->sr, regs->pc, address, error_code);
 #endif
 
@@ -44,11 +44,11 @@ asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
         * Oops. The kernel tried to access some bad page. We'll have to
         * terminate things with extreme prejudice.
         */
-       if ((unsigned long) address < PAGE_SIZE) {
+       if ((unsigned long) address < PAGE_SIZE)
                printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
-       else
+       else
                printk(KERN_ALERT "Unable to handle kernel access");
-       printk(KERN_ALERT " at virtual address %08lx\n",address);
+       printk(KERN_ALERT " at virtual address %08lx\n", address);
        die_if_kernel("Oops", regs, error_code);
        do_exit(SIGKILL);
 
index 92614de42cd349b6656c6f557f82cc1263fb17d5..71d2ba474c63373a8b65301d862463d62d85ad48 100644 (file)
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/spi/spi.h>
+#include <linux/gpio.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfuart.h>
+#include <asm/mcfqspi.h>
 
 /***************************************************************************/
 
@@ -74,9 +77,152 @@ static struct platform_device m520x_fec = {
        .resource               = m520x_fec_resources,
 };
 
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+static struct resource m520x_qspi_resources[] = {
+       {
+               .start          = MCFQSPI_IOBASE,
+               .end            = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = MCFINT_VECBASE + MCFINT_QSPI,
+               .end            = MCFINT_VECBASE + MCFINT_QSPI,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+#define MCFQSPI_CS0    62
+#define MCFQSPI_CS1    63
+#define MCFQSPI_CS2    44
+
+static int m520x_cs_setup(struct mcfqspi_cs_control *cs_control)
+{
+       int status;
+
+       status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
+               goto fail0;
+       }
+       status = gpio_direction_output(MCFQSPI_CS0, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
+               goto fail1;
+       }
+
+       status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
+               goto fail1;
+       }
+       status = gpio_direction_output(MCFQSPI_CS1, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
+               goto fail2;
+       }
+
+       status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
+               goto fail2;
+       }
+       status = gpio_direction_output(MCFQSPI_CS2, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
+               goto fail3;
+       }
+
+       return 0;
+
+fail3:
+       gpio_free(MCFQSPI_CS2);
+fail2:
+       gpio_free(MCFQSPI_CS1);
+fail1:
+       gpio_free(MCFQSPI_CS0);
+fail0:
+       return status;
+}
+
+static void m520x_cs_teardown(struct mcfqspi_cs_control *cs_control)
+{
+       gpio_free(MCFQSPI_CS2);
+       gpio_free(MCFQSPI_CS1);
+       gpio_free(MCFQSPI_CS0);
+}
+
+static void m520x_cs_select(struct mcfqspi_cs_control *cs_control,
+                           u8 chip_select, bool cs_high)
+{
+       switch (chip_select) {
+       case 0:
+               gpio_set_value(MCFQSPI_CS0, cs_high);
+               break;
+       case 1:
+               gpio_set_value(MCFQSPI_CS1, cs_high);
+               break;
+       case 2:
+               gpio_set_value(MCFQSPI_CS2, cs_high);
+               break;
+       }
+}
+
+static void m520x_cs_deselect(struct mcfqspi_cs_control *cs_control,
+                             u8 chip_select, bool cs_high)
+{
+       switch (chip_select) {
+       case 0:
+               gpio_set_value(MCFQSPI_CS0, !cs_high);
+               break;
+       case 1:
+               gpio_set_value(MCFQSPI_CS1, !cs_high);
+               break;
+       case 2:
+               gpio_set_value(MCFQSPI_CS2, !cs_high);
+               break;
+       }
+}
+
+static struct mcfqspi_cs_control m520x_cs_control = {
+       .setup                  = m520x_cs_setup,
+       .teardown               = m520x_cs_teardown,
+       .select                 = m520x_cs_select,
+       .deselect               = m520x_cs_deselect,
+};
+
+static struct mcfqspi_platform_data m520x_qspi_data = {
+       .bus_num                = 0,
+       .num_chipselect         = 3,
+       .cs_control             = &m520x_cs_control,
+};
+
+static struct platform_device m520x_qspi = {
+       .name                   = "mcfqspi",
+       .id                     = 0,
+       .num_resources          = ARRAY_SIZE(m520x_qspi_resources),
+       .resource               = m520x_qspi_resources,
+       .dev.platform_data      = &m520x_qspi_data,
+};
+
+static void __init m520x_qspi_init(void)
+{
+       u16 par;
+       /* setup Port QS for QSPI with gpio CS control */
+       writeb(0x3f, MCF_IPSBAR + MCF_GPIO_PAR_QSPI);
+       /* make U1CTS and U2RTS gpio for cs_control */
+       par = readw(MCF_IPSBAR + MCF_GPIO_PAR_UART);
+       par &= 0x00ff;
+       writew(par, MCF_IPSBAR + MCF_GPIO_PAR_UART);
+}
+#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */
+
+
 static struct platform_device *m520x_devices[] __initdata = {
        &m520x_uart,
        &m520x_fec,
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+       &m520x_qspi,
+#endif
 };
 
 /***************************************************************************/
@@ -147,6 +293,9 @@ void __init config_BSP(char *commandp, int size)
        mach_reset = m520x_cpu_reset;
        m520x_uarts_init();
        m520x_fec_init();
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+       m520x_qspi_init();
+#endif
 }
 
 /***************************************************************************/
index 6ba84f2aa397cc639eff61ea38acb9f0e1be903b..8980f6d7715a5a5990e08bcd23e55e673d308993 100644 (file)
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/spi/spi.h>
+#include <linux/gpio.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfuart.h>
+#include <asm/mcfqspi.h>
 
 /***************************************************************************/
 
@@ -75,9 +78,173 @@ static struct platform_device m523x_fec = {
        .resource               = m523x_fec_resources,
 };
 
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+static struct resource m523x_qspi_resources[] = {
+       {
+               .start          = MCFQSPI_IOBASE,
+               .end            = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = MCFINT_VECBASE + MCFINT_QSPI,
+               .end            = MCFINT_VECBASE + MCFINT_QSPI,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+#define MCFQSPI_CS0    91
+#define MCFQSPI_CS1    92
+#define MCFQSPI_CS2    103
+#define MCFQSPI_CS3    99
+
+static int m523x_cs_setup(struct mcfqspi_cs_control *cs_control)
+{
+       int status;
+
+       status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
+               goto fail0;
+       }
+       status = gpio_direction_output(MCFQSPI_CS0, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
+               goto fail1;
+       }
+
+       status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
+               goto fail1;
+       }
+       status = gpio_direction_output(MCFQSPI_CS1, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
+               goto fail2;
+       }
+
+       status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
+               goto fail2;
+       }
+       status = gpio_direction_output(MCFQSPI_CS2, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
+               goto fail3;
+       }
+
+       status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS3 failed\n");
+               goto fail3;
+       }
+       status = gpio_direction_output(MCFQSPI_CS3, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n");
+               goto fail4;
+       }
+
+       return 0;
+
+fail4:
+       gpio_free(MCFQSPI_CS3);
+fail3:
+       gpio_free(MCFQSPI_CS2);
+fail2:
+       gpio_free(MCFQSPI_CS1);
+fail1:
+       gpio_free(MCFQSPI_CS0);
+fail0:
+       return status;
+}
+
+static void m523x_cs_teardown(struct mcfqspi_cs_control *cs_control)
+{
+       gpio_free(MCFQSPI_CS3);
+       gpio_free(MCFQSPI_CS2);
+       gpio_free(MCFQSPI_CS1);
+       gpio_free(MCFQSPI_CS0);
+}
+
+static void m523x_cs_select(struct mcfqspi_cs_control *cs_control,
+                           u8 chip_select, bool cs_high)
+{
+       switch (chip_select) {
+       case 0:
+               gpio_set_value(MCFQSPI_CS0, cs_high);
+               break;
+       case 1:
+               gpio_set_value(MCFQSPI_CS1, cs_high);
+               break;
+       case 2:
+               gpio_set_value(MCFQSPI_CS2, cs_high);
+               break;
+       case 3:
+               gpio_set_value(MCFQSPI_CS3, cs_high);
+               break;
+       }
+}
+
+static void m523x_cs_deselect(struct mcfqspi_cs_control *cs_control,
+                             u8 chip_select, bool cs_high)
+{
+       switch (chip_select) {
+       case 0:
+               gpio_set_value(MCFQSPI_CS0, !cs_high);
+               break;
+       case 1:
+               gpio_set_value(MCFQSPI_CS1, !cs_high);
+               break;
+       case 2:
+               gpio_set_value(MCFQSPI_CS2, !cs_high);
+               break;
+       case 3:
+               gpio_set_value(MCFQSPI_CS3, !cs_high);
+               break;
+       }
+}
+
+static struct mcfqspi_cs_control m523x_cs_control = {
+       .setup                  = m523x_cs_setup,
+       .teardown               = m523x_cs_teardown,
+       .select                 = m523x_cs_select,
+       .deselect               = m523x_cs_deselect,
+};
+
+static struct mcfqspi_platform_data m523x_qspi_data = {
+       .bus_num                = 0,
+       .num_chipselect         = 4,
+       .cs_control             = &m523x_cs_control,
+};
+
+static struct platform_device m523x_qspi = {
+       .name                   = "mcfqspi",
+       .id                     = 0,
+       .num_resources          = ARRAY_SIZE(m523x_qspi_resources),
+       .resource               = m523x_qspi_resources,
+       .dev.platform_data      = &m523x_qspi_data,
+};
+
+static void __init m523x_qspi_init(void)
+{
+       u16 par;
+
+       /* setup QSPS pins for QSPI with gpio CS control */
+       writeb(0x1f, MCFGPIO_PAR_QSPI);
+       /* and CS2 & CS3 as gpio */
+       par = readw(MCFGPIO_PAR_TIMER);
+       par &= 0x3f3f;
+       writew(par, MCFGPIO_PAR_TIMER);
+}
+#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */
+
 static struct platform_device *m523x_devices[] __initdata = {
        &m523x_uart,
        &m523x_fec,
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+       &m523x_qspi,
+#endif
 };
 
 /***************************************************************************/
@@ -114,6 +281,9 @@ void __init config_BSP(char *commandp, int size)
 static int __init init_BSP(void)
 {
        m523x_fec_init();
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+       m523x_qspi_init();
+#endif
        platform_add_devices(m523x_devices, ARRAY_SIZE(m523x_devices));
        return 0;
 }
index 646f5ba462fcb6675293f7c55a8ee6efb6e31fbf..ceb31e5744a6f0c63dbe9429612a5d0d8847c44a 100644 (file)
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/spi/spi.h>
+#include <linux/gpio.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfuart.h>
+#include <asm/mcfqspi.h>
 
 /***************************************************************************/
 
@@ -37,8 +40,196 @@ static struct platform_device m5249_uart = {
        .dev.platform_data      = m5249_uart_platform,
 };
 
+#ifdef CONFIG_M5249C3
+
+static struct resource m5249_smc91x_resources[] = {
+       {
+               .start          = 0xe0000300,
+               .end            = 0xe0000300 + 0x100,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = MCFINTC2_GPIOIRQ6,
+               .end            = MCFINTC2_GPIOIRQ6,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device m5249_smc91x = {
+       .name                   = "smc91x",
+       .id                     = 0,
+       .num_resources          = ARRAY_SIZE(m5249_smc91x_resources),
+       .resource               = m5249_smc91x_resources,
+};
+
+#endif /* CONFIG_M5249C3 */
+
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+static struct resource m5249_qspi_resources[] = {
+       {
+               .start          = MCFQSPI_IOBASE,
+               .end            = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = MCF_IRQ_QSPI,
+               .end            = MCF_IRQ_QSPI,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+#define MCFQSPI_CS0    29
+#define MCFQSPI_CS1    24
+#define MCFQSPI_CS2    21
+#define MCFQSPI_CS3    22
+
+static int m5249_cs_setup(struct mcfqspi_cs_control *cs_control)
+{
+       int status;
+
+       status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
+               goto fail0;
+       }
+       status = gpio_direction_output(MCFQSPI_CS0, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
+               goto fail1;
+       }
+
+       status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
+               goto fail1;
+       }
+       status = gpio_direction_output(MCFQSPI_CS1, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
+               goto fail2;
+       }
+
+       status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
+               goto fail2;
+       }
+       status = gpio_direction_output(MCFQSPI_CS2, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
+               goto fail3;
+       }
+
+       status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS3 failed\n");
+               goto fail3;
+       }
+       status = gpio_direction_output(MCFQSPI_CS3, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n");
+               goto fail4;
+       }
+
+       return 0;
+
+fail4:
+       gpio_free(MCFQSPI_CS3);
+fail3:
+       gpio_free(MCFQSPI_CS2);
+fail2:
+       gpio_free(MCFQSPI_CS1);
+fail1:
+       gpio_free(MCFQSPI_CS0);
+fail0:
+       return status;
+}
+
+static void m5249_cs_teardown(struct mcfqspi_cs_control *cs_control)
+{
+       gpio_free(MCFQSPI_CS3);
+       gpio_free(MCFQSPI_CS2);
+       gpio_free(MCFQSPI_CS1);
+       gpio_free(MCFQSPI_CS0);
+}
+
+static void m5249_cs_select(struct mcfqspi_cs_control *cs_control,
+                           u8 chip_select, bool cs_high)
+{
+       switch (chip_select) {
+       case 0:
+               gpio_set_value(MCFQSPI_CS0, cs_high);
+               break;
+       case 1:
+               gpio_set_value(MCFQSPI_CS1, cs_high);
+               break;
+       case 2:
+               gpio_set_value(MCFQSPI_CS2, cs_high);
+               break;
+       case 3:
+               gpio_set_value(MCFQSPI_CS3, cs_high);
+               break;
+       }
+}
+
+static void m5249_cs_deselect(struct mcfqspi_cs_control *cs_control,
+                             u8 chip_select, bool cs_high)
+{
+       switch (chip_select) {
+       case 0:
+               gpio_set_value(MCFQSPI_CS0, !cs_high);
+               break;
+       case 1:
+               gpio_set_value(MCFQSPI_CS1, !cs_high);
+               break;
+       case 2:
+               gpio_set_value(MCFQSPI_CS2, !cs_high);
+               break;
+       case 3:
+               gpio_set_value(MCFQSPI_CS3, !cs_high);
+               break;
+       }
+}
+
+static struct mcfqspi_cs_control m5249_cs_control = {
+       .setup                  = m5249_cs_setup,
+       .teardown               = m5249_cs_teardown,
+       .select                 = m5249_cs_select,
+       .deselect               = m5249_cs_deselect,
+};
+
+static struct mcfqspi_platform_data m5249_qspi_data = {
+       .bus_num                = 0,
+       .num_chipselect         = 4,
+       .cs_control             = &m5249_cs_control,
+};
+
+static struct platform_device m5249_qspi = {
+       .name                   = "mcfqspi",
+       .id                     = 0,
+       .num_resources          = ARRAY_SIZE(m5249_qspi_resources),
+       .resource               = m5249_qspi_resources,
+       .dev.platform_data      = &m5249_qspi_data,
+};
+
+static void __init m5249_qspi_init(void)
+{
+       /* QSPI irq setup */
+       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL4 | MCFSIM_ICR_PRI0,
+              MCF_MBAR + MCFSIM_QSPIICR);
+       mcf_mapirq2imr(MCF_IRQ_QSPI, MCFINTC_QSPI);
+}
+#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */
+
+
 static struct platform_device *m5249_devices[] __initdata = {
        &m5249_uart,
+#ifdef CONFIG_M5249C3
+       &m5249_smc91x,
+#endif
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+       &m5249_qspi,
+#endif
 };
 
 /***************************************************************************/
@@ -67,6 +258,24 @@ static void __init m5249_uarts_init(void)
 
 /***************************************************************************/
 
+#ifdef CONFIG_M5249C3
+
+static void __init m5249_smc91x_init(void)
+{
+       u32  gpio;
+
+       /* Set the GPIO line as interrupt source for smc91x device */
+       gpio = readl(MCF_MBAR2 + MCFSIM2_GPIOINTENABLE);
+       writel(gpio | 0x40, MCF_MBAR2 + MCFSIM2_GPIOINTENABLE);
+
+       gpio = readl(MCF_MBAR2 + MCFSIM2_INTLEVEL5);
+       writel(gpio | 0x04000000, MCF_MBAR2 + MCFSIM2_INTLEVEL5);
+}
+
+#endif /* CONFIG_M5249C3 */
+
+/***************************************************************************/
+
 static void __init m5249_timers_init(void)
 {
        /* Timer1 is always used as system timer */
@@ -100,6 +309,12 @@ void __init config_BSP(char *commandp, int size)
        mach_reset = m5249_cpu_reset;
        m5249_timers_init();
        m5249_uarts_init();
+#ifdef CONFIG_M5249C3
+       m5249_smc91x_init();
+#endif
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+       m5249_qspi_init();
+#endif
 }
 
 /***************************************************************************/
index fa51be172830a856fade06999c65d08276e5e8e6..3d9c35c98b98ff2e28014a26dd616c312dff6754 100644 (file)
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/spi/spi.h>
+#include <linux/gpio.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfuart.h>
+#include <asm/mcfqspi.h>
 
 /***************************************************************************/
 
@@ -106,12 +109,188 @@ static struct platform_device m527x_fec[] = {
        },
 };
 
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+static struct resource m527x_qspi_resources[] = {
+       {
+               .start          = MCFQSPI_IOBASE,
+               .end            = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = MCFINT_VECBASE + MCFINT_QSPI,
+               .end            = MCFINT_VECBASE + MCFINT_QSPI,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+#if defined(CONFIG_M5271)
+#define MCFQSPI_CS0    91
+#define MCFQSPI_CS1    92
+#define MCFQSPI_CS2    99
+#define MCFQSPI_CS3    103
+#elif defined(CONFIG_M5275)
+#define MCFQSPI_CS0    59
+#define MCFQSPI_CS1    60
+#define MCFQSPI_CS2    61
+#define MCFQSPI_CS3    62
+#endif
+
+static int m527x_cs_setup(struct mcfqspi_cs_control *cs_control)
+{
+       int status;
+
+       status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
+               goto fail0;
+       }
+       status = gpio_direction_output(MCFQSPI_CS0, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
+               goto fail1;
+       }
+
+       status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
+               goto fail1;
+       }
+       status = gpio_direction_output(MCFQSPI_CS1, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
+               goto fail2;
+       }
+
+       status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
+               goto fail2;
+       }
+       status = gpio_direction_output(MCFQSPI_CS2, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
+               goto fail3;
+       }
+
+       status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS3 failed\n");
+               goto fail3;
+       }
+       status = gpio_direction_output(MCFQSPI_CS3, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n");
+               goto fail4;
+       }
+
+       return 0;
+
+fail4:
+       gpio_free(MCFQSPI_CS3);
+fail3:
+       gpio_free(MCFQSPI_CS2);
+fail2:
+       gpio_free(MCFQSPI_CS1);
+fail1:
+       gpio_free(MCFQSPI_CS0);
+fail0:
+       return status;
+}
+
+static void m527x_cs_teardown(struct mcfqspi_cs_control *cs_control)
+{
+       gpio_free(MCFQSPI_CS3);
+       gpio_free(MCFQSPI_CS2);
+       gpio_free(MCFQSPI_CS1);
+       gpio_free(MCFQSPI_CS0);
+}
+
+static void m527x_cs_select(struct mcfqspi_cs_control *cs_control,
+                           u8 chip_select, bool cs_high)
+{
+       switch (chip_select) {
+       case 0:
+               gpio_set_value(MCFQSPI_CS0, cs_high);
+               break;
+       case 1:
+               gpio_set_value(MCFQSPI_CS1, cs_high);
+               break;
+       case 2:
+               gpio_set_value(MCFQSPI_CS2, cs_high);
+               break;
+       case 3:
+               gpio_set_value(MCFQSPI_CS3, cs_high);
+               break;
+       }
+}
+
+static void m527x_cs_deselect(struct mcfqspi_cs_control *cs_control,
+                             u8 chip_select, bool cs_high)
+{
+       switch (chip_select) {
+       case 0:
+               gpio_set_value(MCFQSPI_CS0, !cs_high);
+               break;
+       case 1:
+               gpio_set_value(MCFQSPI_CS1, !cs_high);
+               break;
+       case 2:
+               gpio_set_value(MCFQSPI_CS2, !cs_high);
+               break;
+       case 3:
+               gpio_set_value(MCFQSPI_CS3, !cs_high);
+               break;
+       }
+}
+
+static struct mcfqspi_cs_control m527x_cs_control = {
+       .setup                  = m527x_cs_setup,
+       .teardown               = m527x_cs_teardown,
+       .select                 = m527x_cs_select,
+       .deselect               = m527x_cs_deselect,
+};
+
+static struct mcfqspi_platform_data m527x_qspi_data = {
+       .bus_num                = 0,
+       .num_chipselect         = 4,
+       .cs_control             = &m527x_cs_control,
+};
+
+static struct platform_device m527x_qspi = {
+       .name                   = "mcfqspi",
+       .id                     = 0,
+       .num_resources          = ARRAY_SIZE(m527x_qspi_resources),
+       .resource               = m527x_qspi_resources,
+       .dev.platform_data      = &m527x_qspi_data,
+};
+
+static void __init m527x_qspi_init(void)
+{
+#if defined(CONFIG_M5271)
+       u16 par;
+
+       /* setup QSPS pins for QSPI with gpio CS control */
+       writeb(0x1f, MCFGPIO_PAR_QSPI);
+       /* and CS2 & CS3 as gpio */
+       par = readw(MCFGPIO_PAR_TIMER);
+       par &= 0x3f3f;
+       writew(par, MCFGPIO_PAR_TIMER);
+#elif defined(CONFIG_M5275)
+       /* setup QSPS pins for QSPI with gpio CS control */
+       writew(0x003e, MCFGPIO_PAR_QSPI);
+#endif
+}
+#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */
+
 static struct platform_device *m527x_devices[] __initdata = {
        &m527x_uart,
        &m527x_fec[0],
 #ifdef CONFIG_FEC2
        &m527x_fec[1],
 #endif
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+       &m527x_qspi,
+#endif
 };
 
 /***************************************************************************/
@@ -187,6 +366,9 @@ void __init config_BSP(char *commandp, int size)
        mach_reset = m527x_cpu_reset;
        m527x_uarts_init();
        m527x_fec_init();
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+       m527x_qspi_init();
+#endif
 }
 
 /***************************************************************************/
index 6e608d1836f1e5e69a5d8e9be2dc25add5301986..76b743343bfa46d4967fab7af6d1caf406cf6da2 100644 (file)
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <linux/spi/spi.h>
+#include <linux/gpio.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfuart.h>
+#include <asm/mcfqspi.h>
 
 /***************************************************************************/
 
@@ -76,10 +79,141 @@ static struct platform_device m528x_fec = {
        .resource               = m528x_fec_resources,
 };
 
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+static struct resource m528x_qspi_resources[] = {
+       {
+               .start          = MCFQSPI_IOBASE,
+               .end            = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = MCFINT_VECBASE + MCFINT_QSPI,
+               .end            = MCFINT_VECBASE + MCFINT_QSPI,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+#define MCFQSPI_CS0    147
+#define MCFQSPI_CS1    148
+#define MCFQSPI_CS2    149
+#define MCFQSPI_CS3    150
+
+static int m528x_cs_setup(struct mcfqspi_cs_control *cs_control)
+{
+       int status;
+
+       status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
+               goto fail0;
+       }
+       status = gpio_direction_output(MCFQSPI_CS0, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
+               goto fail1;
+       }
+
+       status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
+               goto fail1;
+       }
+       status = gpio_direction_output(MCFQSPI_CS1, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
+               goto fail2;
+       }
+
+       status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
+               goto fail2;
+       }
+       status = gpio_direction_output(MCFQSPI_CS2, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
+               goto fail3;
+       }
+
+       status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS3 failed\n");
+               goto fail3;
+       }
+       status = gpio_direction_output(MCFQSPI_CS3, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n");
+               goto fail4;
+       }
+
+       return 0;
+
+fail4:
+       gpio_free(MCFQSPI_CS3);
+fail3:
+       gpio_free(MCFQSPI_CS2);
+fail2:
+       gpio_free(MCFQSPI_CS1);
+fail1:
+       gpio_free(MCFQSPI_CS0);
+fail0:
+       return status;
+}
+
+static void m528x_cs_teardown(struct mcfqspi_cs_control *cs_control)
+{
+       gpio_free(MCFQSPI_CS3);
+       gpio_free(MCFQSPI_CS2);
+       gpio_free(MCFQSPI_CS1);
+       gpio_free(MCFQSPI_CS0);
+}
+
+static void m528x_cs_select(struct mcfqspi_cs_control *cs_control,
+                           u8 chip_select, bool cs_high)
+{
+       gpio_set_value(MCFQSPI_CS0 + chip_select, cs_high);
+}
+
+static void m528x_cs_deselect(struct mcfqspi_cs_control *cs_control,
+                             u8 chip_select, bool cs_high)
+{
+       gpio_set_value(MCFQSPI_CS0 + chip_select, !cs_high);
+}
+
+static struct mcfqspi_cs_control m528x_cs_control = {
+       .setup                  = m528x_cs_setup,
+       .teardown               = m528x_cs_teardown,
+       .select                 = m528x_cs_select,
+       .deselect               = m528x_cs_deselect,
+};
+
+static struct mcfqspi_platform_data m528x_qspi_data = {
+       .bus_num                = 0,
+       .num_chipselect         = 4,
+       .cs_control             = &m528x_cs_control,
+};
+
+static struct platform_device m528x_qspi = {
+       .name                   = "mcfqspi",
+       .id                     = 0,
+       .num_resources          = ARRAY_SIZE(m528x_qspi_resources),
+       .resource               = m528x_qspi_resources,
+       .dev.platform_data      = &m528x_qspi_data,
+};
+
+static void __init m528x_qspi_init(void)
+{
+       /* setup Port QS for QSPI with gpio CS control */
+       __raw_writeb(0x07, MCFGPIO_PQSPAR);
+}
+#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */
 
 static struct platform_device *m528x_devices[] __initdata = {
        &m528x_uart,
        &m528x_fec,
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+       &m528x_qspi,
+#endif
 };
 
 /***************************************************************************/
@@ -174,6 +308,9 @@ static int __init init_BSP(void)
        mach_reset = m528x_cpu_reset;
        m528x_uarts_init();
        m528x_fec_init();
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+       m528x_qspi_init();
+#endif
        platform_add_devices(m528x_devices, ARRAY_SIZE(m528x_devices));
        return 0;
 }
index 667db6598451e64ff9a2d0035e2d75b84c69ec2f..6de52697682829562a94bfd4577dc40b7e55e390 100644 (file)
@@ -14,5 +14,7 @@
 
 asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
 
-obj-y  += config.o gpio.o
+obj-y                  += config.o gpio.o
+obj-$(CONFIG_NETtel)   += nettel.o
+obj-$(CONFIG_CLEOPATRA)        += nettel.o
 
diff --git a/arch/m68knommu/platform/5307/nettel.c b/arch/m68knommu/platform/5307/nettel.c
new file mode 100644 (file)
index 0000000..e925ea4
--- /dev/null
@@ -0,0 +1,153 @@
+/***************************************************************************/
+
+/*
+ *     nettel.c -- startup code support for the NETtel boards
+ *
+ *     Copyright (C) 2009, Greg Ungerer (gerg@snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/nettel.h>
+
+/***************************************************************************/
+
+/*
+ * Define the IO and interrupt resources of the 2 SMC9196 interfaces.
+ */
+#define        NETTEL_SMC0_ADDR        0x30600300
+#define        NETTEL_SMC0_IRQ         29
+
+#define        NETTEL_SMC1_ADDR        0x30600000
+#define        NETTEL_SMC1_IRQ         27
+
+/*
+ * We need some access into the SMC9196 registers. Define those registers
+ * we will need here (including the smc91x.h doesn't seem to give us these
+ * in a simple form).
+ */
+#define        SMC91xx_BANKSELECT      14
+#define        SMC91xx_BASEADDR        2
+#define        SMC91xx_BASEMAC         4
+
+/***************************************************************************/
+
+static struct resource nettel_smc91x_0_resources[] = {
+       {
+               .start          = NETTEL_SMC0_ADDR,
+               .end            = NETTEL_SMC0_ADDR + 0x20,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = NETTEL_SMC0_IRQ,
+               .end            = NETTEL_SMC0_IRQ,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource nettel_smc91x_1_resources[] = {
+       {
+               .start          = NETTEL_SMC1_ADDR,
+               .end            = NETTEL_SMC1_ADDR + 0x20,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = NETTEL_SMC1_IRQ,
+               .end            = NETTEL_SMC1_IRQ,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device nettel_smc91x[] = {
+       {
+               .name                   = "smc91x",
+               .id                     = 0,
+               .num_resources          = ARRAY_SIZE(nettel_smc91x_0_resources),
+               .resource               = nettel_smc91x_0_resources,
+       },
+       {
+               .name                   = "smc91x",
+               .id                     = 1,
+               .num_resources          = ARRAY_SIZE(nettel_smc91x_1_resources),
+               .resource               = nettel_smc91x_1_resources,
+       },
+};
+
+static struct platform_device *nettel_devices[] __initdata = {
+       &nettel_smc91x[0],
+       &nettel_smc91x[1],
+};
+
+/***************************************************************************/
+
+static u8 nettel_macdefault[] __initdata = {
+       0x00, 0xd0, 0xcf, 0x00, 0x00, 0x01,
+};
+
+/*
+ * Set flash contained MAC address into SMC9196 core. Make sure the flash
+ * MAC address is sane, and not an empty flash. If no good use the Moreton
+ * Bay default MAC address instead.
+ */
+
+static void __init nettel_smc91x_setmac(unsigned int ioaddr, unsigned int flashaddr)
+{
+       u16 *macp;
+
+       macp = (u16 *) flashaddr;
+       if ((macp[0] == 0xffff) && (macp[1] == 0xffff) && (macp[2] == 0xffff))
+               macp = (u16 *) &nettel_macdefault[0];
+
+       writew(1, NETTEL_SMC0_ADDR + SMC91xx_BANKSELECT);
+       writew(macp[0], ioaddr + SMC91xx_BASEMAC);
+       writew(macp[1], ioaddr + SMC91xx_BASEMAC + 2);
+       writew(macp[2], ioaddr + SMC91xx_BASEMAC + 4);
+}
+
+/***************************************************************************/
+
+/*
+ * Re-map the address space of at least one of the SMC ethernet
+ * parts. Both parts power up decoding the same address, so we
+ * need to move one of them first, before doing anything else.
+ */
+
+static void __init nettel_smc91x_init(void)
+{
+       writew(0x00ec, MCF_MBAR + MCFSIM_PADDR);
+       mcf_setppdata(0, 0x0080);
+       writew(1, NETTEL_SMC0_ADDR + SMC91xx_BANKSELECT);
+       writew(0x0067, NETTEL_SMC0_ADDR + SMC91xx_BASEADDR);
+       mcf_setppdata(0x0080, 0);
+
+       /* Set correct chip select timing for SMC9196 accesses */
+       writew(0x1180, MCF_MBAR + MCFSIM_CSCR3);
+
+       /* Set the SMC interrupts to be auto-vectored */
+       mcf_autovector(NETTEL_SMC0_IRQ);
+       mcf_autovector(NETTEL_SMC1_IRQ);
+
+       /* Set MAC addresses from flash for both interfaces */
+       nettel_smc91x_setmac(NETTEL_SMC0_ADDR, 0xf0006000);
+       nettel_smc91x_setmac(NETTEL_SMC1_ADDR, 0xf0006006);
+}
+
+/***************************************************************************/
+
+static int __init init_nettel(void)
+{
+       nettel_smc91x_init();
+       platform_add_devices(nettel_devices, ARRAY_SIZE(nettel_devices));
+       return 0;
+}
+
+arch_initcall(init_nettel);
+
+/***************************************************************************/
index d632948e64e53602d3714197852f441d3288cf78..ca51323f957b4ec86bf7e5be18080475d089677b 100644 (file)
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/spi/spi.h>
+#include <linux/gpio.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfuart.h>
 #include <asm/mcfdma.h>
 #include <asm/mcfwdebug.h>
+#include <asm/mcfqspi.h>
 
 /***************************************************************************/
 
@@ -82,9 +85,127 @@ static struct platform_device m532x_fec = {
        .resource               = m532x_fec_resources,
 };
 
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+static struct resource m532x_qspi_resources[] = {
+       {
+               .start          = MCFQSPI_IOBASE,
+               .end            = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = MCFINT_VECBASE + MCFINT_QSPI,
+               .end            = MCFINT_VECBASE + MCFINT_QSPI,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+#define MCFQSPI_CS0    84
+#define MCFQSPI_CS1    85
+#define MCFQSPI_CS2    86
+
+static int m532x_cs_setup(struct mcfqspi_cs_control *cs_control)
+{
+       int status;
+
+       status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
+               goto fail0;
+       }
+       status = gpio_direction_output(MCFQSPI_CS0, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
+               goto fail1;
+       }
+
+       status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
+               goto fail1;
+       }
+       status = gpio_direction_output(MCFQSPI_CS1, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
+               goto fail2;
+       }
+
+       status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
+               goto fail2;
+       }
+       status = gpio_direction_output(MCFQSPI_CS2, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
+               goto fail3;
+       }
+
+       return 0;
+
+fail3:
+       gpio_free(MCFQSPI_CS2);
+fail2:
+       gpio_free(MCFQSPI_CS1);
+fail1:
+       gpio_free(MCFQSPI_CS0);
+fail0:
+       return status;
+}
+
+static void m532x_cs_teardown(struct mcfqspi_cs_control *cs_control)
+{
+       gpio_free(MCFQSPI_CS2);
+       gpio_free(MCFQSPI_CS1);
+       gpio_free(MCFQSPI_CS0);
+}
+
+static void m532x_cs_select(struct mcfqspi_cs_control *cs_control,
+                           u8 chip_select, bool cs_high)
+{
+       gpio_set_value(MCFQSPI_CS0 + chip_select, cs_high);
+}
+
+static void m532x_cs_deselect(struct mcfqspi_cs_control *cs_control,
+                             u8 chip_select, bool cs_high)
+{
+       gpio_set_value(MCFQSPI_CS0 + chip_select, !cs_high);
+}
+
+static struct mcfqspi_cs_control m532x_cs_control = {
+       .setup                  = m532x_cs_setup,
+       .teardown               = m532x_cs_teardown,
+       .select                 = m532x_cs_select,
+       .deselect               = m532x_cs_deselect,
+};
+
+static struct mcfqspi_platform_data m532x_qspi_data = {
+       .bus_num                = 0,
+       .num_chipselect         = 3,
+       .cs_control             = &m532x_cs_control,
+};
+
+static struct platform_device m532x_qspi = {
+       .name                   = "mcfqspi",
+       .id                     = 0,
+       .num_resources          = ARRAY_SIZE(m532x_qspi_resources),
+       .resource               = m532x_qspi_resources,
+       .dev.platform_data      = &m532x_qspi_data,
+};
+
+static void __init m532x_qspi_init(void)
+{
+       /* setup QSPS pins for QSPI with gpio CS control */
+       writew(0x01f0, MCF_GPIO_PAR_QSPI);
+}
+#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */
+
+
 static struct platform_device *m532x_devices[] __initdata = {
        &m532x_uart,
        &m532x_fec,
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+       &m532x_qspi,
+#endif
 };
 
 /***************************************************************************/
@@ -158,6 +279,9 @@ static int __init init_BSP(void)
 {
        m532x_uarts_init();
        m532x_fec_init();
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+       m532x_qspi_init();
+#endif
        platform_add_devices(m532x_devices, ARRAY_SIZE(m532x_devices));
        return 0;
 }
index 6acb8d294cb625362e8d586947f32bcf6e3afee2..f27e688c404e48c60cf2eb29e1f56d8ee7a2ab10 100644 (file)
@@ -110,7 +110,7 @@ void m360_cpm_reset()
        /*      pte = find_pte(&init_mm, host_page_addr); */
        /*      pte_val(*pte) |= _PAGE_NO_CACHE; */
        /*      flush_tlb_page(current->mm->mmap, host_buffer); */
-       
+
        /* Tell everyone where the comm processor resides.
        */
 /*     cpmp = (cpm360_t *)commproc; */
@@ -191,7 +191,7 @@ cpm_interrupt(int irq, void * dev, struct pt_regs * regs)
         */
        ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cisr |= (1 << vec);
 #endif
-       
+
 }
 
 /* The CPM can generate the error interrupt when there is a race condition
index 402b46e630f6d5acb6490b92a047264ce17ec802..123b2fe72d01f93a82076a87548e1050bead7d07 100644 (file)
 struct device_node;
 
 struct dev_archdata {
-       /* Optional pointer to an OF device node */
-       struct device_node      *of_node;
-
        /* DMA operations on that device */
        struct dma_map_ops      *dma_ops;
        void                    *dma_data;
 };
 
 struct pdev_archdata {
+       u64 dma_mask;
 };
 
-static inline void dev_archdata_set_node(struct dev_archdata *ad,
-                                        struct device_node *np)
-{
-       ad->of_node = np;
-}
-
-static inline struct device_node *
-dev_archdata_get_node(const struct dev_archdata *ad)
-{
-       return ad->of_node;
-}
-
 #endif /* _ASM_MICROBLAZE_DEVICE_H */
 
 
index ba917cfaefe6c4e6027ac46d12970f1168e08e35..73cb98040982434f87c4761616186b3c004bd51d 100644 (file)
@@ -21,9 +21,8 @@
  * probed using OF properties.
  */
 struct of_device {
-       struct device_node      *node; /* to be obsoleted */
-       u64                     dma_mask; /* DMA mask */
        struct device           dev; /* Generic device interface */
+       struct pdev_archdata    archdata;
 };
 
 extern ssize_t of_device_get_modalias(struct of_device *ofdev,
index 35d786fe93ae0dcba7e1cf434606e9e61d1b05c2..dc4a8900cc8087dd6b315e484ada573bb1f7ef1d 100644 (file)
@@ -1 +1,3 @@
 #include <asm-generic/scatterlist.h>
+
+#define ISA_DMA_THRESHOLD      (~0UL)
index 9a0f7632c47c92ed471250d4858731531e7bd381..b372787886ed5b5df23beeb663e4ea9067d9b7b1 100644 (file)
@@ -12,7 +12,7 @@
 void of_device_make_bus_id(struct of_device *dev)
 {
        static atomic_t bus_no_reg_magic;
-       struct device_node *node = dev->node;
+       struct device_node *node = dev->dev.of_node;
        const u32 *reg;
        u64 addr;
        int magic;
@@ -49,11 +49,10 @@ struct of_device *of_device_alloc(struct device_node *np,
        if (!dev)
                return NULL;
 
-       dev->node = of_node_get(np);
-       dev->dev.dma_mask = &dev->dma_mask;
+       dev->dev.of_node = of_node_get(np);
+       dev->dev.dma_mask = &dev->archdata.dma_mask;
        dev->dev.parent = parent;
        dev->dev.release = of_release_dev;
-       dev->dev.archdata.of_node = np;
 
        if (bus_id)
                dev_set_name(&dev->dev, bus_id);
@@ -75,17 +74,17 @@ int of_device_uevent(struct device *dev, struct kobj_uevent_env *env)
 
        ofdev = to_of_device(dev);
 
-       if (add_uevent_var(env, "OF_NAME=%s", ofdev->node->name))
+       if (add_uevent_var(env, "OF_NAME=%s", ofdev->dev.of_node->name))
                return -ENOMEM;
 
-       if (add_uevent_var(env, "OF_TYPE=%s", ofdev->node->type))
+       if (add_uevent_var(env, "OF_TYPE=%s", ofdev->dev.of_node->type))
                return -ENOMEM;
 
        /* Since the compatible field can contain pretty much anything
         * it's not really legal to split it out with commas. We split it
         * up using a number of environment variables instead. */
 
-       compat = of_get_property(ofdev->node, "compatible", &cplen);
+       compat = of_get_property(ofdev->dev.of_node, "compatible", &cplen);
        while (compat && *compat && cplen > 0) {
                if (add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat))
                        return -ENOMEM;
index 0dc755286d38e44b8ff209d05d4d7c2a1c9d1b9a..ccf6f4257f4b83b24893818ad393b251f3f7b5e7 100644 (file)
@@ -47,7 +47,7 @@ struct of_device *of_platform_device_create(struct device_node *np,
        if (!dev)
                return NULL;
 
-       dev->dma_mask = 0xffffffffUL;
+       dev->archdata.dma_mask = 0xffffffffUL;
        dev->dev.bus = &of_platform_bus_type;
 
        /* We do not fill the DMA ops for platform devices by default.
@@ -166,7 +166,7 @@ EXPORT_SYMBOL(of_platform_bus_probe);
 
 static int of_dev_node_match(struct device *dev, void *data)
 {
-       return to_of_device(dev)->node == data;
+       return to_of_device(dev)->dev.of_node == data;
 }
 
 struct of_device *of_find_device_by_node(struct device_node *np)
@@ -184,7 +184,7 @@ EXPORT_SYMBOL(of_find_device_by_node);
 static int of_dev_phandle_match(struct device *dev, void *data)
 {
        phandle *ph = data;
-       return to_of_device(dev)->node->phandle == *ph;
+       return to_of_device(dev)->dev.of_node->phandle == *ph;
 }
 
 struct of_device *of_find_device_by_phandle(phandle ph)
index 83d69fe17c9f1404e481e2d2cbb22985f0be2cf5..9af65e79be36d3d8398d96a063836af90c506842 100644 (file)
@@ -1,27 +1,7 @@
 #ifndef __ASM_SCATTERLIST_H
 #define __ASM_SCATTERLIST_H
 
-#include <asm/types.h>
-
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-       unsigned long   sg_magic;
-#endif
-       unsigned long   page_link;
-       unsigned int    offset;
-       dma_addr_t      dma_address;
-       unsigned int    length;
-};
-
-/*
- * These macros should be used after a pci_map_sg call has been done
- * to get bus addresses of each of the SG entries and their lengths.
- * You should only work with the number of sg entries pci_map_sg
- * returns, or alternatively stop on the first sg_dma_len(sg) which
- * is 0.
- */
-#define sg_dma_address(sg)     ((sg)->dma_address)
-#define sg_dma_len(sg)         ((sg)->length)
+#include <asm-generic/scatterlist.h>
 
 #define ISA_DMA_THRESHOLD (0x00ffffffUL)
 
index e41222d6c2fd1a5d3a97a20482c09ff10b652eba..f0cc1f84a72f180c5492987327b855b36bf46561 100644 (file)
@@ -1,157 +1 @@
-/* MN10300 Atomic counter operations
- *
- * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public Licence
- * as published by the Free Software Foundation; either version
- * 2 of the Licence, or (at your option) any later version.
- */
-#ifndef _ASM_ATOMIC_H
-#define _ASM_ATOMIC_H
-
-#ifdef CONFIG_SMP
-#error not SMP safe
-#endif
-
-/*
- * Atomic operations that C can't guarantee us.  Useful for
- * resource counting etc..
- */
-
-#define ATOMIC_INIT(i) { (i) }
-
-#ifdef __KERNEL__
-
-/**
- * atomic_read - read atomic variable
- * @v: pointer of type atomic_t
- *
- * Atomically reads the value of @v.  Note that the guaranteed
- * useful range of an atomic_t is only 24 bits.
- */
-#define atomic_read(v) (*(volatile int *)&(v)->counter)
-
-/**
- * atomic_set - set atomic variable
- * @v: pointer of type atomic_t
- * @i: required value
- *
- * Atomically sets the value of @v to @i.  Note that the guaranteed
- * useful range of an atomic_t is only 24 bits.
- */
-#define atomic_set(v, i) (((v)->counter) = (i))
-
-#include <asm/system.h>
-
-/**
- * atomic_add_return - add integer to atomic variable
- * @i: integer value to add
- * @v: pointer of type atomic_t
- *
- * Atomically adds @i to @v and returns the result
- * Note that the guaranteed useful range of an atomic_t is only 24 bits.
- */
-static inline int atomic_add_return(int i, atomic_t *v)
-{
-       unsigned long flags;
-       int temp;
-
-       local_irq_save(flags);
-       temp = v->counter;
-       temp += i;
-       v->counter = temp;
-       local_irq_restore(flags);
-
-       return temp;
-}
-
-/**
- * atomic_sub_return - subtract integer from atomic variable
- * @i: integer value to subtract
- * @v: pointer of type atomic_t
- *
- * Atomically subtracts @i from @v and returns the result
- * Note that the guaranteed useful range of an atomic_t is only 24 bits.
- */
-static inline int atomic_sub_return(int i, atomic_t *v)
-{
-       unsigned long flags;
-       int temp;
-
-       local_irq_save(flags);
-       temp = v->counter;
-       temp -= i;
-       v->counter = temp;
-       local_irq_restore(flags);
-
-       return temp;
-}
-
-static inline int atomic_add_negative(int i, atomic_t *v)
-{
-       return atomic_add_return(i, v) < 0;
-}
-
-static inline void atomic_add(int i, atomic_t *v)
-{
-       atomic_add_return(i, v);
-}
-
-static inline void atomic_sub(int i, atomic_t *v)
-{
-       atomic_sub_return(i, v);
-}
-
-static inline void atomic_inc(atomic_t *v)
-{
-       atomic_add_return(1, v);
-}
-
-static inline void atomic_dec(atomic_t *v)
-{
-       atomic_sub_return(1, v);
-}
-
-#define atomic_dec_return(v)           atomic_sub_return(1, (v))
-#define atomic_inc_return(v)           atomic_add_return(1, (v))
-
-#define atomic_sub_and_test(i, v)      (atomic_sub_return((i), (v)) == 0)
-#define atomic_dec_and_test(v)         (atomic_sub_return(1, (v)) == 0)
-#define atomic_inc_and_test(v)         (atomic_add_return(1, (v)) == 0)
-
-#define atomic_add_unless(v, a, u)                             \
-({                                                             \
-       int c, old;                                             \
-       c = atomic_read(v);                                     \
-       while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
-               c = old;                                        \
-       c != (u);                                               \
-})
-
-#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
-
-static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
-{
-       unsigned long flags;
-
-       mask = ~mask;
-       local_irq_save(flags);
-       *addr &= mask;
-       local_irq_restore(flags);
-}
-
-#define atomic_xchg(ptr, v)            (xchg(&(ptr)->counter, (v)))
-#define atomic_cmpxchg(v, old, new)    (cmpxchg(&((v)->counter), (old), (new)))
-
-/* Atomic operations are already serializing on MN10300??? */
-#define smp_mb__before_atomic_dec()    barrier()
-#define smp_mb__after_atomic_dec()     barrier()
-#define smp_mb__before_atomic_inc()    barrier()
-#define smp_mb__after_atomic_inc()     barrier()
-
-#include <asm-generic/atomic-long.h>
-
-#endif /* __KERNEL__ */
-#endif /* _ASM_ATOMIC_H */
+#include <asm-generic/atomic.h>
index e03cfa2e997e7299e1215a3a8c25a516d19d6751..6e2fe28dde4e7d68f260871c9377b96f30e8e644 100644 (file)
@@ -21,6 +21,8 @@
 #define L1_CACHE_DISPARITY     L1_CACHE_NENTRIES * L1_CACHE_BYTES
 #endif
 
+#define ARCH_KMALLOC_MINALIGN  L1_CACHE_BYTES
+
 /* data cache purge registers
  * - read from the register to unconditionally purge that cache line
  * - write address & 0xffffff00 to conditionally purge that cache line
index 67535901b9ffaf34e2ac366017313bf6dbd44da8..7bd00b9e030d427083567d9a223856cfee7d2e18 100644 (file)
 #ifndef _ASM_SCATTERLIST_H
 #define _ASM_SCATTERLIST_H
 
-#include <asm/types.h>
-
-/*
- * Drivers must set either ->address or (preferred) page and ->offset
- * to indicate where data must be transferred to/from.
- *
- * Using page is recommended since it handles highmem data as well as
- * low mem. ->address is restricted to data which has a virtual mapping, and
- * it will go away in the future. Updating to page can be automated very
- * easily -- something like
- *
- * sg->address = some_ptr;
- *
- * can be rewritten as
- *
- * sg_set_page(virt_to_page(some_ptr));
- * sg->offset = (unsigned long) some_ptr & ~PAGE_MASK;
- *
- * and that's it. There's no excuse for not highmem enabling YOUR driver. /jens
- */
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-       unsigned long   sg_magic;
-#endif
-       unsigned long   page_link;
-       unsigned int    offset;         /* for highmem, page offset */
-       dma_addr_t      dma_address;
-       unsigned int    length;
-};
+#include <asm-generic/scatterlist.h>
 
 #define ISA_DMA_THRESHOLD (0x00ffffff)
 
-/*
- * These macros should be used after a pci_map_sg call has been done
- * to get bus addresses of each of the SG entries and their lengths.
- * You should only work with the number of sg entries pci_map_sg
- * returns.
- */
-#define sg_dma_address(sg)     ((sg)->dma_address)
-#define sg_dma_len(sg)         ((sg)->length)
-
 #endif /* _ASM_SCATTERLIST_H */
index 9c4da3d63bfb9056ca6adf42da80575adb1f6b40..05a366a5c4d5c28431d3910aa69d993e7372e737 100644 (file)
@@ -98,6 +98,9 @@ config STACKTRACE_SUPPORT
 config NEED_DMA_MAP_STATE
        def_bool y
 
+config NEED_SG_DMA_LENGTH
+       def_bool y
+
 config ISA_DMA_API
        bool
 
index 75e46c557a16901d03f93cb83d2b3838e7793172..72cfdb0cfdd157485e2acd4a27de5c7788b483c1 100644 (file)
@@ -44,7 +44,7 @@
 #endif
 
 #ifdef CONFIG_DEBUG_BUGVERBOSE
-#define __WARN()                                                       \
+#define __WARN_TAINT(taint)                                            \
        do {                                                            \
                asm volatile("\n"                                       \
                             "1:\t" PARISC_BUG_BREAK_ASM "\n"           \
                             "\t.org 2b+%c3\n"                          \
                             "\t.popsection"                            \
                             : : "i" (__FILE__), "i" (__LINE__),        \
-                            "i" (BUGFLAG_WARNING),                     \
+                            "i" (BUGFLAG_TAINT(taint)),                \
                             "i" (sizeof(struct bug_entry)) );          \
        } while(0)
 #else
-#define __WARN()                                                       \
+#define __WARN_TAINT(taint)                                            \
        do {                                                            \
                asm volatile("\n"                                       \
                             "1:\t" PARISC_BUG_BREAK_ASM "\n"           \
@@ -67,7 +67,7 @@
                             "\t.short %c0\n"                           \
                             "\t.org 2b+%c1\n"                          \
                             "\t.popsection"                            \
-                            : : "i" (BUGFLAG_WARNING),                 \
+                            : : "i" (BUGFLAG_TAINT(taint)),            \
                             "i" (sizeof(struct bug_entry)) );          \
        } while(0)
 #endif
index 477277739da5f8bd895b8bd814fd59c733dfc962..4556d820128a435abf969933c0b25e67a9f57600 100644 (file)
@@ -2,6 +2,7 @@
 #define _PARISC_CACHEFLUSH_H
 
 #include <linux/mm.h>
+#include <linux/uaccess.h>
 
 /* The usual comment is "Caches aren't brain-dead on the <architecture>".
  * Unfortunately, that doesn't apply to PA-RISC. */
@@ -125,11 +126,20 @@ static inline void *kmap(struct page *page)
 
 #define kunmap(page)                   kunmap_parisc(page_address(page))
 
-#define kmap_atomic(page, idx)         page_address(page)
+static inline void *kmap_atomic(struct page *page, enum km_type idx)
+{
+       pagefault_disable();
+       return page_address(page);
+}
 
-#define kunmap_atomic(addr, idx)       kunmap_parisc(addr)
+static inline void kunmap_atomic(void *addr, enum km_type idx)
+{
+       kunmap_parisc(addr);
+       pagefault_enable();
+}
 
-#define kmap_atomic_pfn(pfn, idx)      page_address(pfn_to_page(pfn))
+#define kmap_atomic_prot(page, idx, prot)      kmap_atomic(page, idx)
+#define kmap_atomic_pfn(pfn, idx)      kmap_atomic(pfn_to_page(pfn), (idx))
 #define kmap_atomic_to_page(ptr)       virt_to_page(ptr)
 #endif
 
index 62269b31ebf4a89d404ec157cd653cba848de2f7..2c3b79b54b28ba4899233970ef377002039912b9 100644 (file)
@@ -3,25 +3,9 @@
 
 #include <asm/page.h>
 #include <asm/types.h>
-
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-       unsigned long sg_magic;
-#endif
-       unsigned long page_link;
-       unsigned int offset;
-
-       unsigned int length;
-
-       /* an IOVA can be 64-bits on some PA-Risc platforms. */
-       dma_addr_t iova;        /* I/O Virtual Address */
-       __u32      iova_length; /* bytes mapped */
-};
-
-#define sg_virt_addr(sg) ((unsigned long)sg_virt(sg))
-#define sg_dma_address(sg) ((sg)->iova)
-#define sg_dma_len(sg)     ((sg)->iova_length)
+#include <asm-generic/scatterlist.h>
 
 #define ISA_DMA_THRESHOLD (~0UL)
+#define sg_virt_addr(sg) ((unsigned long)sg_virt(sg))
 
 #endif /* _ASM_PARISC_SCATTERLIST_H */
index ec787b411e9a12ac73cf07342ffbf05ef52d7959..dcd55103a4bb7ff433433c1bcdadc466376de52e 100644 (file)
 #else
 #define FRAME_SIZE     64
 #endif
+#define FRAME_ALIGN    64
 
-#define align(x,y) (((x)+FRAME_SIZE+(y)-1) - (((x)+(y)-1)%(y)))
+/* Add FRAME_SIZE to the size x and align it to y. All definitions
+ * that use align_frame will include space for a frame.
+ */
+#define align_frame(x,y) (((x)+FRAME_SIZE+(y)-1) - (((x)+(y)-1)%(y)))
 
 int main(void)
 {
@@ -146,7 +150,8 @@ int main(void)
        DEFINE(TASK_PT_IOR, offsetof(struct task_struct, thread.regs.ior));
        BLANK();
        DEFINE(TASK_SZ, sizeof(struct task_struct));
-       DEFINE(TASK_SZ_ALGN, align(sizeof(struct task_struct), 64));
+       /* TASK_SZ_ALGN includes space for a stack frame. */
+       DEFINE(TASK_SZ_ALGN, align_frame(sizeof(struct task_struct), FRAME_ALIGN));
        BLANK();
        DEFINE(PT_PSW, offsetof(struct pt_regs, gr[ 0]));
        DEFINE(PT_GR1, offsetof(struct pt_regs, gr[ 1]));
@@ -233,7 +238,8 @@ int main(void)
        DEFINE(PT_ISR, offsetof(struct pt_regs, isr));
        DEFINE(PT_IOR, offsetof(struct pt_regs, ior));
        DEFINE(PT_SIZE, sizeof(struct pt_regs));
-       DEFINE(PT_SZ_ALGN, align(sizeof(struct pt_regs), 64));
+       /* PT_SZ_ALGN includes space for a stack frame. */
+       DEFINE(PT_SZ_ALGN, align_frame(sizeof(struct pt_regs), FRAME_ALIGN));
        BLANK();
        DEFINE(TI_TASK, offsetof(struct thread_info, task));
        DEFINE(TI_EXEC_DOMAIN, offsetof(struct thread_info, exec_domain));
@@ -242,7 +248,8 @@ int main(void)
        DEFINE(TI_SEGMENT, offsetof(struct thread_info, addr_limit));
        DEFINE(TI_PRE_COUNT, offsetof(struct thread_info, preempt_count));
        DEFINE(THREAD_SZ, sizeof(struct thread_info));
-       DEFINE(THREAD_SZ_ALGN, align(sizeof(struct thread_info), 64));
+       /* THREAD_SZ_ALGN includes space for a stack frame. */
+       DEFINE(THREAD_SZ_ALGN, align_frame(sizeof(struct thread_info), FRAME_ALIGN));
        BLANK();
        DEFINE(ICACHE_BASE, offsetof(struct pdc_cache_info, ic_base));
        DEFINE(ICACHE_STRIDE, offsetof(struct pdc_cache_info, ic_stride));
index 3a44f7f704fad67792fa0cc6325060adb6db933c..6337adef30f64f158086d6ff322dd20ed7ec6361 100644 (file)
        .align          32
        .endm
 
-       /* The following are simple 32 vs 64 bit instruction
-        * abstractions for the macros */
-       .macro          EXTR    reg1,start,length,reg2
-#ifdef CONFIG_64BIT
-       extrd,u         \reg1,32+(\start),\length,\reg2
-#else
-       extrw,u         \reg1,\start,\length,\reg2
-#endif
-       .endm
-
-       .macro          DEP     reg1,start,length,reg2
-#ifdef CONFIG_64BIT
-       depd            \reg1,32+(\start),\length,\reg2
-#else
-       depw            \reg1,\start,\length,\reg2
-#endif
-       .endm
-
-       .macro          DEPI    val,start,length,reg
-#ifdef CONFIG_64BIT
-       depdi           \val,32+(\start),\length,\reg
-#else
-       depwi           \val,\start,\length,\reg
-#endif
-       .endm
-
        /* In LP64, the space contains part of the upper 32 bits of the
         * fault.  We have to extract this and place it in the va,
         * zeroing the corresponding bits in the space register */
         */
        .macro          L2_ptep pmd,pte,index,va,fault
 #if PT_NLEVELS == 3
-       EXTR            \va,31-ASM_PMD_SHIFT,ASM_BITS_PER_PMD,\index
+       extru           \va,31-ASM_PMD_SHIFT,ASM_BITS_PER_PMD,\index
 #else
-       EXTR            \va,31-ASM_PGDIR_SHIFT,ASM_BITS_PER_PGD,\index
+       extru           \va,31-ASM_PGDIR_SHIFT,ASM_BITS_PER_PGD,\index
 #endif
-       DEP             %r0,31,PAGE_SHIFT,\pmd  /* clear offset */
+       dep             %r0,31,PAGE_SHIFT,\pmd  /* clear offset */
        copy            %r0,\pte
        ldw,s           \index(\pmd),\pmd
        bb,>=,n         \pmd,_PxD_PRESENT_BIT,\fault
-       DEP             %r0,31,PxD_FLAG_SHIFT,\pmd /* clear flags */
+       dep             %r0,31,PxD_FLAG_SHIFT,\pmd /* clear flags */
        copy            \pmd,%r9
        SHLREG          %r9,PxD_VALUE_SHIFT,\pmd
-       EXTR            \va,31-PAGE_SHIFT,ASM_BITS_PER_PTE,\index
-       DEP             %r0,31,PAGE_SHIFT,\pmd  /* clear offset */
+       extru           \va,31-PAGE_SHIFT,ASM_BITS_PER_PTE,\index
+       dep             %r0,31,PAGE_SHIFT,\pmd  /* clear offset */
        shladd          \index,BITS_PER_PTE_ENTRY,\pmd,\pmd
        LDREG           %r0(\pmd),\pte          /* pmd is now pte */
        bb,>=,n         \pte,_PAGE_PRESENT_BIT,\fault
        depdi           0,31,32,\tmp
 #endif
        copy            \va,\tmp1
-       DEPI            0,31,23,\tmp1
+       depi            0,31,23,\tmp1
        cmpb,COND(<>),n \tmp,\tmp1,\fault
        ldi             (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),\prot
        depd,z          \prot,8,7,\prot
@@ -997,13 +971,6 @@ intr_restore:
 
        rfi
        nop
-       nop
-       nop
-       nop
-       nop
-       nop
-       nop
-       nop
 
 #ifndef CONFIG_PREEMPT
 # define intr_do_preempt       intr_restore
@@ -2076,9 +2043,10 @@ syscall_restore:
        LDREG   TASK_PT_GR31(%r1),%r31     /* restore syscall rp */
 
        /* NOTE: We use rsm/ssm pair to make this operation atomic */
+       LDREG   TASK_PT_GR30(%r1),%r1              /* Get user sp */
        rsm     PSW_SM_I, %r0
-       LDREG   TASK_PT_GR30(%r1),%r30             /* restore user sp */
-       mfsp    %sr3,%r1                           /* Get users space id */
+       copy    %r1,%r30                           /* Restore user sp */
+       mfsp    %sr3,%r1                           /* Get user space id */
        mtsp    %r1,%sr7                           /* Restore sr7 */
        ssm     PSW_SM_I, %r0
 
index f5f96021caa0deedec2257af361dc95ba0307ea5..68e75ce838d6dd05d4101ba0dd7e707896e0612b 100644 (file)
@@ -47,18 +47,17 @@ ENTRY(linux_gateway_page)
        KILL_INSN
        .endr
 
-       /* ADDRESS 0xb0 to 0xb4, lws uses 1 insns for entry */
+       /* ADDRESS 0xb0 to 0xb8, lws uses two insns for entry */
        /* Light-weight-syscall entry must always be located at 0xb0 */
        /* WARNING: Keep this number updated with table size changes */
 #define __NR_lws_entries (2)
 
 lws_entry:
-       /* Unconditional branch to lws_start, located on the 
-          same gateway page */
-       b,n     lws_start
+       gate    lws_start, %r0          /* increase privilege */
+       depi    3, 31, 2, %r31          /* Ensure we return into user mode. */
 
-       /* Fill from 0xb4 to 0xe0 */
-       .rept 11
+       /* Fill from 0xb8 to 0xe0 */
+       .rept 10
        KILL_INSN
        .endr
 
@@ -423,9 +422,6 @@ tracesys_sigexit:
 
        *********************************************************/
 lws_start:
-       /* Gate and ensure we return to userspace */
-       gate    .+8, %r0
-       depi    3, 31, 2, %r31  /* Ensure we return to userspace */
 
 #ifdef CONFIG_64BIT
        /* FIXME: If we are a 64-bit kernel just
@@ -442,7 +438,7 @@ lws_start:
 #endif 
 
         /* Is the lws entry number valid? */
-       comiclr,>>=     __NR_lws_entries, %r20, %r0
+       comiclr,>>      __NR_lws_entries, %r20, %r0
        b,n     lws_exit_nosys
 
        /* WARNING: Trashing sr2 and sr3 */
@@ -473,7 +469,7 @@ lws_exit:
        /* now reset the lowest bit of sp if it was set */
        xor     %r30,%r1,%r30
 #endif
-       be,n    0(%sr3, %r31)
+       be,n    0(%sr7, %r31)
 
 
        
@@ -529,7 +525,6 @@ lws_compare_and_swap32:
 #endif
 
 lws_compare_and_swap:
-#ifdef CONFIG_SMP
        /* Load start of lock table */
        ldil    L%lws_lock_start, %r20
        ldo     R%lws_lock_start(%r20), %r28
@@ -572,8 +567,6 @@ cas_wouldblock:
        ldo     2(%r0), %r28                            /* 2nd case */
        b       lws_exit                                /* Contended... */
        ldo     -EAGAIN(%r0), %r21                      /* Spin in userspace */
-#endif
-/* CONFIG_SMP */
 
        /*
                prev = *addr;
@@ -601,13 +594,11 @@ cas_action:
 1:     ldw     0(%sr3,%r26), %r28
        sub,<>  %r28, %r25, %r0
 2:     stw     %r24, 0(%sr3,%r26)
-#ifdef CONFIG_SMP
        /* Free lock */
        stw     %r20, 0(%sr2,%r20)
-# if ENABLE_LWS_DEBUG
+#if ENABLE_LWS_DEBUG
        /* Clear thread register indicator */
        stw     %r0, 4(%sr2,%r20)
-# endif
 #endif
        /* Return to userspace, set no error */
        b       lws_exit
@@ -615,12 +606,10 @@ cas_action:
 
 3:             
        /* Error occured on load or store */
-#ifdef CONFIG_SMP
        /* Free lock */
        stw     %r20, 0(%sr2,%r20)
-# if ENABLE_LWS_DEBUG
+#if ENABLE_LWS_DEBUG
        stw     %r0, 4(%sr2,%r20)
-# endif
 #endif
        b       lws_exit
        ldo     -EFAULT(%r0),%r21       /* set errno */
@@ -672,7 +661,6 @@ ENTRY(sys_call_table64)
 END(sys_call_table64)
 #endif
 
-#ifdef CONFIG_SMP
        /*
                All light-weight-syscall atomic operations 
                will use this set of locks 
@@ -694,8 +682,6 @@ ENTRY(lws_lock_start)
        .endr
 END(lws_lock_start)
        .previous
-#endif
-/* CONFIG_SMP for lws_lock_start */
 
 .end
 
index 3ca1c61492182d3321c2fe7d2cf00d003ff5a8a5..27a7492ddb0d66f7762e94dea40ff3f3ac1fcd85 100644 (file)
@@ -342,6 +342,7 @@ decode_fpu(unsigned int Fpu_register[], unsigned int trap_counts[])
                return SIGNALCODE(SIGFPE, FPE_FLTINV);
          case DIVISIONBYZEROEXCEPTION:
                update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
+               Clear_excp_register(exception_index);
                return SIGNALCODE(SIGFPE, FPE_FLTDIV);
          case INEXACTEXCEPTION:
                update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
index c6afbfc957703f800610a96f0caa8008f53e598e..18162ce4261ef63eae30818c2eb5ffa4608ba728 100644 (file)
@@ -264,8 +264,7 @@ no_context:
 
   out_of_memory:
        up_read(&mm->mmap_sem);
-       printk(KERN_CRIT "VM: killing process %s\n", current->comm);
-       if (user_mode(regs))
-               do_group_exit(SIGKILL);
-       goto no_context;
+       if (!user_mode(regs))
+               goto no_context;
+       pagefault_out_of_memory();
 }
index c4c4549c22bbe8a3ce06149429096d0c87207c73..66a315e06dce88691322901a7ab7c6d38c702f4b 100644 (file)
@@ -663,6 +663,9 @@ config ZONE_DMA
 config NEED_DMA_MAP_STATE
        def_bool (PPC64 || NOT_COHERENT_CACHE)
 
+config NEED_SG_DMA_LENGTH
+       def_bool y
+
 config GENERIC_ISA_DMA
        bool
        depends on PPC64 || POWER4 || 6xx && !CPM2
index a9b91ed3d4b9e17ae8494e17ba498d19aa43a89c..2048a6aeea9140dc88a0cbb218c2b2c301ca5a1e 100644 (file)
@@ -21,6 +21,7 @@
 /* operations for longs and pointers */
 #define PPC_LL         stringify_in_c(ld)
 #define PPC_STL                stringify_in_c(std)
+#define PPC_STLU       stringify_in_c(stdu)
 #define PPC_LCMPI      stringify_in_c(cmpdi)
 #define PPC_LONG       stringify_in_c(.llong)
 #define PPC_LONG_ALIGN stringify_in_c(.balign 8)
@@ -44,6 +45,7 @@
 /* operations for longs and pointers */
 #define PPC_LL         stringify_in_c(lwz)
 #define PPC_STL                stringify_in_c(stw)
+#define PPC_STLU       stringify_in_c(stwu)
 #define PPC_LCMPI      stringify_in_c(cmpwi)
 #define PPC_LONG       stringify_in_c(.long)
 #define PPC_LONG_ALIGN stringify_in_c(.balign 4)
index 2c15212e1700d5418802f1ccf6f85a142e2251d8..065c590c991d2c5ddbb64c2a99d8bfc0967313da 100644 (file)
        }                                                       \
 } while (0)
 
-#define __WARN() do {                                          \
+#define __WARN_TAINT(taint) do {                               \
        __asm__ __volatile__(                                   \
                "1:     twi 31,0,0\n"                           \
                _EMIT_BUG_ENTRY                                 \
                : : "i" (__FILE__), "i" (__LINE__),             \
-                 "i" (BUGFLAG_WARNING),                        \
+                 "i" (BUGFLAG_TAINT(taint)),                   \
                  "i" (sizeof(struct bug_entry)));              \
 } while (0)
 
                "1:     "PPC_TLNEI"     %4,0\n"                 \
                _EMIT_BUG_ENTRY                                 \
                : : "i" (__FILE__), "i" (__LINE__),             \
-                 "i" (BUGFLAG_WARNING),                        \
+                 "i" (BUGFLAG_TAINT(TAINT_WARN)),              \
                  "i" (sizeof(struct bug_entry)),               \
                  "r" (__ret_warn_on));                         \
        }                                                       \
index 6d94d27ed850a7110627f943398e65b885665075..a3954e4fcbe2edbc5466e8d2ff4bffb16ca57312 100644 (file)
@@ -10,9 +10,6 @@ struct dma_map_ops;
 struct device_node;
 
 struct dev_archdata {
-       /* Optional pointer to an OF device node */
-       struct device_node      *of_node;
-
        /* DMA operations on that device */
        struct dma_map_ops      *dma_ops;
 
@@ -30,19 +27,8 @@ struct dev_archdata {
 #endif
 };
 
-static inline void dev_archdata_set_node(struct dev_archdata *ad,
-                                        struct device_node *np)
-{
-       ad->of_node = np;
-}
-
-static inline struct device_node *
-dev_archdata_get_node(const struct dev_archdata *ad)
-{
-       return ad->of_node;
-}
-
 struct pdev_archdata {
+       u64 dma_mask;
 };
 
 #endif /* _ASM_POWERPC_DEVICE_H */
index 81f3b0b5601ecf8c113d1c457e68463ad3f94fa6..6c5547d82bbe7dc5283dec2fc6ddf437fe2e76e0 100644 (file)
@@ -77,4 +77,14 @@ struct kvm_debug_exit_arch {
 struct kvm_guest_debug_arch {
 };
 
+#define KVM_REG_MASK           0x001f
+#define KVM_REG_EXT_MASK       0xffe0
+#define KVM_REG_GPR            0x0000
+#define KVM_REG_FPR            0x0020
+#define KVM_REG_QPR            0x0040
+#define KVM_REG_FQPR           0x0060
+
+#define KVM_INTERRUPT_SET      -1U
+#define KVM_INTERRUPT_UNSET    -2U
+
 #endif /* __LINUX_KVM_POWERPC_H */
index aadf2dd6f84e15c919c9020e9271c3e8f7427a35..c5ea4cda34b329fa3f6bac605e95ad114105c09d 100644 (file)
@@ -88,6 +88,8 @@
 
 #define BOOK3S_HFLAG_DCBZ32                    0x1
 #define BOOK3S_HFLAG_SLB                       0x2
+#define BOOK3S_HFLAG_PAIRED_SINGLE             0x4
+#define BOOK3S_HFLAG_NATIVE_PS                 0x8
 
 #define RESUME_FLAG_NV          (1<<0)  /* Reload guest nonvolatile state? */
 #define RESUME_FLAG_HOST        (1<<1)  /* Resume host? */
index db7db0a96967ad8dc4c2eb2a5c2438d878187e73..6f74d93725a0f3327e4d3c6088828113b62079f4 100644 (file)
 
 #include <linux/types.h>
 #include <linux/kvm_host.h>
-#include <asm/kvm_book3s_64_asm.h>
+#include <asm/kvm_book3s_asm.h>
 
 struct kvmppc_slb {
        u64 esid;
        u64 vsid;
        u64 orige;
        u64 origv;
-       bool valid;
-       bool Ks;
-       bool Kp;
-       bool nx;
-       bool large    /* PTEs are 16MB */
-       bool tb;        /* 1TB segment */
-       bool class;
+       bool valid      : 1;
+       bool Ks         : 1;
+       bool Kp         : 1;
+       bool nx         : 1;
+       bool large      : 1;    /* PTEs are 16MB */
+       bool tb         : 1;    /* 1TB segment */
+       bool class      : 1;
 };
 
 struct kvmppc_sr {
        u32 raw;
        u32 vsid;
-       bool Ks;
-       bool Kp;
-       bool nx;
+       bool Ks         : 1;
+       bool Kp         : 1;
+       bool nx         : 1;
+       bool valid      : 1;
 };
 
 struct kvmppc_bat {
        u64 raw;
        u32 bepi;
        u32 bepi_mask;
-       bool vs;
-       bool vp;
        u32 brpn;
        u8 wimg;
        u8 pp;
+       bool vs         : 1;
+       bool vp         : 1;
 };
 
 struct kvmppc_sid_map {
        u64 guest_vsid;
        u64 guest_esid;
        u64 host_vsid;
-       bool valid;
+       bool valid      : 1;
 };
 
 #define SID_MAP_BITS    9
@@ -70,7 +71,7 @@ struct kvmppc_sid_map {
 
 struct kvmppc_vcpu_book3s {
        struct kvm_vcpu vcpu;
-       struct kvmppc_book3s_shadow_vcpu shadow_vcpu;
+       struct kvmppc_book3s_shadow_vcpu *shadow_vcpu;
        struct kvmppc_sid_map sid_map[SID_MAP_NUM];
        struct kvmppc_slb slb[64];
        struct {
@@ -82,9 +83,10 @@ struct kvmppc_vcpu_book3s {
        struct kvmppc_bat ibat[8];
        struct kvmppc_bat dbat[8];
        u64 hid[6];
+       u64 gqr[8];
        int slb_nr;
+       u32 dsisr;
        u64 sdr1;
-       u64 dsisr;
        u64 hior;
        u64 msr_mask;
        u64 vsid_first;
@@ -98,15 +100,15 @@ struct kvmppc_vcpu_book3s {
 #define CONTEXT_GUEST          1
 #define CONTEXT_GUEST_END      2
 
-#define VSID_REAL      0xfffffffffff00000
-#define VSID_REAL_DR   0xffffffffffe00000
-#define VSID_REAL_IR   0xffffffffffd00000
-#define VSID_BAT       0xffffffffffc00000
-#define VSID_PR                0x8000000000000000
+#define VSID_REAL      0x1fffffffffc00000ULL
+#define VSID_BAT       0x1fffffffffb00000ULL
+#define VSID_REAL_DR   0x2000000000000000ULL
+#define VSID_REAL_IR   0x4000000000000000ULL
+#define VSID_PR                0x8000000000000000ULL
 
-extern void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, u64 ea, u64 ea_mask);
+extern void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong ea, ulong ea_mask);
 extern void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 vp, u64 vp_mask);
-extern void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, u64 pa_start, u64 pa_end);
+extern void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end);
 extern void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 new_msr);
 extern void kvmppc_mmu_book3s_64_init(struct kvm_vcpu *vcpu);
 extern void kvmppc_mmu_book3s_32_init(struct kvm_vcpu *vcpu);
@@ -114,11 +116,13 @@ extern int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte);
 extern int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr);
 extern void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu);
 extern struct kvmppc_pte *kvmppc_mmu_find_pte(struct kvm_vcpu *vcpu, u64 ea, bool data);
-extern int kvmppc_ld(struct kvm_vcpu *vcpu, ulong eaddr, int size, void *ptr, bool data);
-extern int kvmppc_st(struct kvm_vcpu *vcpu, ulong eaddr, int size, void *ptr);
+extern int kvmppc_ld(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr, bool data);
+extern int kvmppc_st(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr, bool data);
 extern void kvmppc_book3s_queue_irqprio(struct kvm_vcpu *vcpu, unsigned int vec);
 extern void kvmppc_set_bat(struct kvm_vcpu *vcpu, struct kvmppc_bat *bat,
                           bool upper, u32 val);
+extern void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr);
+extern int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu);
 
 extern u32 kvmppc_trampoline_lowmem;
 extern u32 kvmppc_trampoline_enter;
@@ -126,6 +130,8 @@ extern void kvmppc_rmcall(ulong srr0, ulong srr1);
 extern void kvmppc_load_up_fpu(void);
 extern void kvmppc_load_up_altivec(void);
 extern void kvmppc_load_up_vsx(void);
+extern u32 kvmppc_alignment_dsisr(struct kvm_vcpu *vcpu, unsigned int inst);
+extern ulong kvmppc_alignment_dar(struct kvm_vcpu *vcpu, unsigned int inst);
 
 static inline struct kvmppc_vcpu_book3s *to_book3s(struct kvm_vcpu *vcpu)
 {
@@ -140,7 +146,108 @@ static inline ulong dsisr(void)
 }
 
 extern void kvm_return_point(void);
+static inline struct kvmppc_book3s_shadow_vcpu *to_svcpu(struct kvm_vcpu *vcpu);
+
+static inline void kvmppc_set_gpr(struct kvm_vcpu *vcpu, int num, ulong val)
+{
+       if ( num < 14 ) {
+               to_svcpu(vcpu)->gpr[num] = val;
+               to_book3s(vcpu)->shadow_vcpu->gpr[num] = val;
+       } else
+               vcpu->arch.gpr[num] = val;
+}
+
+static inline ulong kvmppc_get_gpr(struct kvm_vcpu *vcpu, int num)
+{
+       if ( num < 14 )
+               return to_svcpu(vcpu)->gpr[num];
+       else
+               return vcpu->arch.gpr[num];
+}
+
+static inline void kvmppc_set_cr(struct kvm_vcpu *vcpu, u32 val)
+{
+       to_svcpu(vcpu)->cr = val;
+       to_book3s(vcpu)->shadow_vcpu->cr = val;
+}
+
+static inline u32 kvmppc_get_cr(struct kvm_vcpu *vcpu)
+{
+       return to_svcpu(vcpu)->cr;
+}
+
+static inline void kvmppc_set_xer(struct kvm_vcpu *vcpu, u32 val)
+{
+       to_svcpu(vcpu)->xer = val;
+       to_book3s(vcpu)->shadow_vcpu->xer = val;
+}
+
+static inline u32 kvmppc_get_xer(struct kvm_vcpu *vcpu)
+{
+       return to_svcpu(vcpu)->xer;
+}
+
+static inline void kvmppc_set_ctr(struct kvm_vcpu *vcpu, ulong val)
+{
+       to_svcpu(vcpu)->ctr = val;
+}
+
+static inline ulong kvmppc_get_ctr(struct kvm_vcpu *vcpu)
+{
+       return to_svcpu(vcpu)->ctr;
+}
+
+static inline void kvmppc_set_lr(struct kvm_vcpu *vcpu, ulong val)
+{
+       to_svcpu(vcpu)->lr = val;
+}
+
+static inline ulong kvmppc_get_lr(struct kvm_vcpu *vcpu)
+{
+       return to_svcpu(vcpu)->lr;
+}
+
+static inline void kvmppc_set_pc(struct kvm_vcpu *vcpu, ulong val)
+{
+       to_svcpu(vcpu)->pc = val;
+}
+
+static inline ulong kvmppc_get_pc(struct kvm_vcpu *vcpu)
+{
+       return to_svcpu(vcpu)->pc;
+}
+
+static inline u32 kvmppc_get_last_inst(struct kvm_vcpu *vcpu)
+{
+       ulong pc = kvmppc_get_pc(vcpu);
+       struct kvmppc_book3s_shadow_vcpu *svcpu = to_svcpu(vcpu);
+
+       /* Load the instruction manually if it failed to do so in the
+        * exit path */
+       if (svcpu->last_inst == KVM_INST_FETCH_FAILED)
+               kvmppc_ld(vcpu, &pc, sizeof(u32), &svcpu->last_inst, false);
+
+       return svcpu->last_inst;
+}
+
+static inline ulong kvmppc_get_fault_dar(struct kvm_vcpu *vcpu)
+{
+       return to_svcpu(vcpu)->fault_dar;
+}
+
+/* Magic register values loaded into r3 and r4 before the 'sc' assembly
+ * instruction for the OSI hypercalls */
+#define OSI_SC_MAGIC_R3                        0x113724FA
+#define OSI_SC_MAGIC_R4                        0x77810F9B
 
 #define INS_DCBZ                       0x7c0007ec
 
+/* Also add subarch specific defines */
+
+#ifdef CONFIG_PPC_BOOK3S_32
+#include <asm/kvm_book3s_32.h>
+#else
+#include <asm/kvm_book3s_64.h>
+#endif
+
 #endif /* __ASM_KVM_BOOK3S_H__ */
diff --git a/arch/powerpc/include/asm/kvm_book3s_32.h b/arch/powerpc/include/asm/kvm_book3s_32.h
new file mode 100644 (file)
index 0000000..de604db
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright SUSE Linux Products GmbH 2010
+ *
+ * Authors: Alexander Graf <agraf@suse.de>
+ */
+
+#ifndef __ASM_KVM_BOOK3S_32_H__
+#define __ASM_KVM_BOOK3S_32_H__
+
+static inline struct kvmppc_book3s_shadow_vcpu *to_svcpu(struct kvm_vcpu *vcpu)
+{
+       return to_book3s(vcpu)->shadow_vcpu;
+}
+
+#define PTE_SIZE       12
+#define VSID_ALL       0
+#define SR_INVALID     0x00000001      /* VSID 1 should always be unused */
+#define SR_KP          0x20000000
+#define PTE_V          0x80000000
+#define PTE_SEC                0x00000040
+#define PTE_M          0x00000010
+#define PTE_R          0x00000100
+#define PTE_C          0x00000080
+
+#define SID_SHIFT      28
+#define ESID_MASK      0xf0000000
+#define VSID_MASK      0x00fffffff0000000ULL
+
+#endif /* __ASM_KVM_BOOK3S_32_H__ */
diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h
new file mode 100644 (file)
index 0000000..4cadd61
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright SUSE Linux Products GmbH 2010
+ *
+ * Authors: Alexander Graf <agraf@suse.de>
+ */
+
+#ifndef __ASM_KVM_BOOK3S_64_H__
+#define __ASM_KVM_BOOK3S_64_H__
+
+static inline struct kvmppc_book3s_shadow_vcpu *to_svcpu(struct kvm_vcpu *vcpu)
+{
+       return &get_paca()->shadow_vcpu;
+}
+
+#endif /* __ASM_KVM_BOOK3S_64_H__ */
similarity index 82%
rename from arch/powerpc/include/asm/kvm_book3s_64_asm.h
rename to arch/powerpc/include/asm/kvm_book3s_asm.h
index 183461b484076e25fd5ca714cce4426b82b0e1e6..36fdb3aff30ba938a4288b774e087af456d60313 100644 (file)
@@ -22,7 +22,7 @@
 
 #ifdef __ASSEMBLY__
 
-#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
+#ifdef CONFIG_KVM_BOOK3S_HANDLER
 
 #include <asm/kvm_asm.h>
 
@@ -55,7 +55,7 @@ kvmppc_resume_\intno:
 .macro DO_KVM intno
 .endm
 
-#endif /* CONFIG_KVM_BOOK3S_64_HANDLER */
+#endif /* CONFIG_KVM_BOOK3S_HANDLER */
 
 #else  /*__ASSEMBLY__ */
 
@@ -63,12 +63,33 @@ struct kvmppc_book3s_shadow_vcpu {
        ulong gpr[14];
        u32 cr;
        u32 xer;
+
+       u32 fault_dsisr;
+       u32 last_inst;
+       ulong ctr;
+       ulong lr;
+       ulong pc;
+       ulong shadow_srr1;
+       ulong fault_dar;
+
        ulong host_r1;
        ulong host_r2;
        ulong handler;
        ulong scratch0;
        ulong scratch1;
        ulong vmhandler;
+       u8 in_guest;
+
+#ifdef CONFIG_PPC_BOOK3S_32
+       u32     sr[16];                 /* Guest SRs */
+#endif
+#ifdef CONFIG_PPC_BOOK3S_64
+       u8 slb_max;                     /* highest used guest slb entry */
+       struct  {
+               u64     esid;
+               u64     vsid;
+       } slb[64];                      /* guest SLB */
+#endif
 };
 
 #endif /*__ASSEMBLY__ */
diff --git a/arch/powerpc/include/asm/kvm_booke.h b/arch/powerpc/include/asm/kvm_booke.h
new file mode 100644 (file)
index 0000000..9c9ba3d
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright SUSE Linux Products GmbH 2010
+ *
+ * Authors: Alexander Graf <agraf@suse.de>
+ */
+
+#ifndef __ASM_KVM_BOOKE_H__
+#define __ASM_KVM_BOOKE_H__
+
+#include <linux/types.h>
+#include <linux/kvm_host.h>
+
+static inline void kvmppc_set_gpr(struct kvm_vcpu *vcpu, int num, ulong val)
+{
+       vcpu->arch.gpr[num] = val;
+}
+
+static inline ulong kvmppc_get_gpr(struct kvm_vcpu *vcpu, int num)
+{
+       return vcpu->arch.gpr[num];
+}
+
+static inline void kvmppc_set_cr(struct kvm_vcpu *vcpu, u32 val)
+{
+       vcpu->arch.cr = val;
+}
+
+static inline u32 kvmppc_get_cr(struct kvm_vcpu *vcpu)
+{
+       return vcpu->arch.cr;
+}
+
+static inline void kvmppc_set_xer(struct kvm_vcpu *vcpu, u32 val)
+{
+       vcpu->arch.xer = val;
+}
+
+static inline u32 kvmppc_get_xer(struct kvm_vcpu *vcpu)
+{
+       return vcpu->arch.xer;
+}
+
+static inline u32 kvmppc_get_last_inst(struct kvm_vcpu *vcpu)
+{
+       return vcpu->arch.last_inst;
+}
+
+static inline void kvmppc_set_ctr(struct kvm_vcpu *vcpu, ulong val)
+{
+       vcpu->arch.ctr = val;
+}
+
+static inline ulong kvmppc_get_ctr(struct kvm_vcpu *vcpu)
+{
+       return vcpu->arch.ctr;
+}
+
+static inline void kvmppc_set_lr(struct kvm_vcpu *vcpu, ulong val)
+{
+       vcpu->arch.lr = val;
+}
+
+static inline ulong kvmppc_get_lr(struct kvm_vcpu *vcpu)
+{
+       return vcpu->arch.lr;
+}
+
+static inline void kvmppc_set_pc(struct kvm_vcpu *vcpu, ulong val)
+{
+       vcpu->arch.pc = val;
+}
+
+static inline ulong kvmppc_get_pc(struct kvm_vcpu *vcpu)
+{
+       return vcpu->arch.pc;
+}
+
+static inline ulong kvmppc_get_fault_dar(struct kvm_vcpu *vcpu)
+{
+       return vcpu->arch.fault_dear;
+}
+
+#endif /* __ASM_KVM_BOOKE_H__ */
diff --git a/arch/powerpc/include/asm/kvm_fpu.h b/arch/powerpc/include/asm/kvm_fpu.h
new file mode 100644 (file)
index 0000000..94f05de
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright Novell Inc. 2010
+ *
+ * Authors: Alexander Graf <agraf@suse.de>
+ */
+
+#ifndef __ASM_KVM_FPU_H__
+#define __ASM_KVM_FPU_H__
+
+#include <linux/types.h>
+
+extern void fps_fres(struct thread_struct *t, u32 *dst, u32 *src1);
+extern void fps_frsqrte(struct thread_struct *t, u32 *dst, u32 *src1);
+extern void fps_fsqrts(struct thread_struct *t, u32 *dst, u32 *src1);
+
+extern void fps_fadds(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2);
+extern void fps_fdivs(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2);
+extern void fps_fmuls(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2);
+extern void fps_fsubs(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2);
+
+extern void fps_fmadds(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2,
+                      u32 *src3);
+extern void fps_fmsubs(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2,
+                      u32 *src3);
+extern void fps_fnmadds(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2,
+                       u32 *src3);
+extern void fps_fnmsubs(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2,
+                       u32 *src3);
+extern void fps_fsel(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2,
+                    u32 *src3);
+
+#define FPD_ONE_IN(name) extern void fpd_ ## name(u64 *fpscr, u32 *cr, \
+                               u64 *dst, u64 *src1);
+#define FPD_TWO_IN(name) extern void fpd_ ## name(u64 *fpscr, u32 *cr, \
+                               u64 *dst, u64 *src1, u64 *src2);
+#define FPD_THREE_IN(name) extern void fpd_ ## name(u64 *fpscr, u32 *cr, \
+                               u64 *dst, u64 *src1, u64 *src2, u64 *src3);
+
+extern void fpd_fcmpu(u64 *fpscr, u32 *cr, u64 *src1, u64 *src2);
+extern void fpd_fcmpo(u64 *fpscr, u32 *cr, u64 *src1, u64 *src2);
+
+FPD_ONE_IN(fsqrts)
+FPD_ONE_IN(frsqrtes)
+FPD_ONE_IN(fres)
+FPD_ONE_IN(frsp)
+FPD_ONE_IN(fctiw)
+FPD_ONE_IN(fctiwz)
+FPD_ONE_IN(fsqrt)
+FPD_ONE_IN(fre)
+FPD_ONE_IN(frsqrte)
+FPD_ONE_IN(fneg)
+FPD_ONE_IN(fabs)
+FPD_TWO_IN(fadds)
+FPD_TWO_IN(fsubs)
+FPD_TWO_IN(fdivs)
+FPD_TWO_IN(fmuls)
+FPD_TWO_IN(fcpsgn)
+FPD_TWO_IN(fdiv)
+FPD_TWO_IN(fadd)
+FPD_TWO_IN(fmul)
+FPD_TWO_IN(fsub)
+FPD_THREE_IN(fmsubs)
+FPD_THREE_IN(fmadds)
+FPD_THREE_IN(fnmsubs)
+FPD_THREE_IN(fnmadds)
+FPD_THREE_IN(fsel)
+FPD_THREE_IN(fmsub)
+FPD_THREE_IN(fmadd)
+FPD_THREE_IN(fnmsub)
+FPD_THREE_IN(fnmadd)
+
+#endif
index 5e5bae7e152fe4a084eef9f61cf72abfe728e399..0c9ad869decd36cb95988d61a10fe993c8bc3b1c 100644 (file)
@@ -66,7 +66,7 @@ struct kvm_vcpu_stat {
        u32 dec_exits;
        u32 ext_intr_exits;
        u32 halt_wakeup;
-#ifdef CONFIG_PPC64
+#ifdef CONFIG_PPC_BOOK3S
        u32 pf_storage;
        u32 pf_instruc;
        u32 sp_storage;
@@ -124,12 +124,12 @@ struct kvm_arch {
 };
 
 struct kvmppc_pte {
-       u64 eaddr;
+       ulong eaddr;
        u64 vpage;
-       u64 raddr;
-       bool may_read;
-       bool may_write;
-       bool may_execute;
+       ulong raddr;
+       bool may_read           : 1;
+       bool may_write          : 1;
+       bool may_execute        : 1;
 };
 
 struct kvmppc_mmu {
@@ -145,7 +145,7 @@ struct kvmppc_mmu {
        int  (*xlate)(struct kvm_vcpu *vcpu, gva_t eaddr, struct kvmppc_pte *pte, bool data);
        void (*reset_msr)(struct kvm_vcpu *vcpu);
        void (*tlbie)(struct kvm_vcpu *vcpu, ulong addr, bool large);
-       int  (*esid_to_vsid)(struct kvm_vcpu *vcpu, u64 esid, u64 *vsid);
+       int  (*esid_to_vsid)(struct kvm_vcpu *vcpu, ulong esid, u64 *vsid);
        u64  (*ea_to_vp)(struct kvm_vcpu *vcpu, gva_t eaddr, bool data);
        bool (*is_dcbz32)(struct kvm_vcpu *vcpu);
 };
@@ -160,7 +160,7 @@ struct hpte_cache {
 struct kvm_vcpu_arch {
        ulong host_stack;
        u32 host_pid;
-#ifdef CONFIG_PPC64
+#ifdef CONFIG_PPC_BOOK3S
        ulong host_msr;
        ulong host_r2;
        void *host_retip;
@@ -175,7 +175,7 @@ struct kvm_vcpu_arch {
        ulong gpr[32];
 
        u64 fpr[32];
-       u32 fpscr;
+       u64 fpscr;
 
 #ifdef CONFIG_ALTIVEC
        vector128 vr[32];
@@ -186,19 +186,23 @@ struct kvm_vcpu_arch {
        u64 vsr[32];
 #endif
 
+#ifdef CONFIG_PPC_BOOK3S
+       /* For Gekko paired singles */
+       u32 qpr[32];
+#endif
+
+#ifdef CONFIG_BOOKE
        ulong pc;
        ulong ctr;
        ulong lr;
 
-#ifdef CONFIG_BOOKE
        ulong xer;
        u32 cr;
 #endif
 
        ulong msr;
-#ifdef CONFIG_PPC64
+#ifdef CONFIG_PPC_BOOK3S
        ulong shadow_msr;
-       ulong shadow_srr1;
        ulong hflags;
        ulong guest_owned_ext;
 #endif
@@ -253,20 +257,22 @@ struct kvm_vcpu_arch {
        struct dentry *debugfs_exit_timing;
 #endif
 
+#ifdef CONFIG_BOOKE
        u32 last_inst;
-#ifdef CONFIG_PPC64
-       ulong fault_dsisr;
-#endif
        ulong fault_dear;
        ulong fault_esr;
        ulong queued_dear;
        ulong queued_esr;
+#endif
        gpa_t paddr_accessed;
 
        u8 io_gpr; /* GPR used as IO source/target */
        u8 mmio_is_bigendian;
+       u8 mmio_sign_extend;
        u8 dcr_needed;
        u8 dcr_is_write;
+       u8 osi_needed;
+       u8 osi_enabled;
 
        u32 cpr0_cfgaddr; /* holds the last set cpr0_cfgaddr */
 
@@ -275,7 +281,7 @@ struct kvm_vcpu_arch {
        u64 dec_jiffies;
        unsigned long pending_exceptions;
 
-#ifdef CONFIG_PPC64
+#ifdef CONFIG_PPC_BOOK3S
        struct hpte_cache hpte_cache[HPTEG_CACHE_NUM];
        int hpte_cache_offset;
 #endif
index e2642829e4350b5d9c0f62a17c11b03a06f75c58..18d139ec2d223555960b703637173ffe6dddab13 100644 (file)
@@ -30,6 +30,8 @@
 #include <linux/kvm_host.h>
 #ifdef CONFIG_PPC_BOOK3S
 #include <asm/kvm_book3s.h>
+#else
+#include <asm/kvm_booke.h>
 #endif
 
 enum emulation_result {
@@ -37,6 +39,7 @@ enum emulation_result {
        EMULATE_DO_MMIO,      /* kvm_run filled with MMIO request */
        EMULATE_DO_DCR,       /* kvm_run filled with DCR request */
        EMULATE_FAIL,         /* can't emulate this instruction */
+       EMULATE_AGAIN,        /* something went wrong. go again */
 };
 
 extern int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu);
@@ -48,8 +51,11 @@ extern void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu);
 extern int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
                               unsigned int rt, unsigned int bytes,
                               int is_bigendian);
+extern int kvmppc_handle_loads(struct kvm_run *run, struct kvm_vcpu *vcpu,
+                               unsigned int rt, unsigned int bytes,
+                               int is_bigendian);
 extern int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
-                               u32 val, unsigned int bytes, int is_bigendian);
+                               u64 val, unsigned int bytes, int is_bigendian);
 
 extern int kvmppc_emulate_instruction(struct kvm_run *run,
                                       struct kvm_vcpu *vcpu);
@@ -63,6 +69,7 @@ extern void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gpa_t gpaddr,
 extern void kvmppc_mmu_priv_switch(struct kvm_vcpu *vcpu, int usermode);
 extern void kvmppc_mmu_switch_pid(struct kvm_vcpu *vcpu, u32 pid);
 extern void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu);
+extern int kvmppc_mmu_init(struct kvm_vcpu *vcpu);
 extern int kvmppc_mmu_dtlb_index(struct kvm_vcpu *vcpu, gva_t eaddr);
 extern int kvmppc_mmu_itlb_index(struct kvm_vcpu *vcpu, gva_t eaddr);
 extern gpa_t kvmppc_mmu_xlate(struct kvm_vcpu *vcpu, unsigned int gtlb_index,
@@ -88,6 +95,8 @@ extern void kvmppc_core_queue_dec(struct kvm_vcpu *vcpu);
 extern void kvmppc_core_dequeue_dec(struct kvm_vcpu *vcpu);
 extern void kvmppc_core_queue_external(struct kvm_vcpu *vcpu,
                                        struct kvm_interrupt *irq);
+extern void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu,
+                                         struct kvm_interrupt *irq);
 
 extern int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
                                   unsigned int op, int *advance);
@@ -99,81 +108,37 @@ extern void kvmppc_booke_exit(void);
 
 extern void kvmppc_core_destroy_mmu(struct kvm_vcpu *vcpu);
 
-#ifdef CONFIG_PPC_BOOK3S
-
-/* We assume we're always acting on the current vcpu */
-
-static inline void kvmppc_set_gpr(struct kvm_vcpu *vcpu, int num, ulong val)
-{
-       if ( num < 14 ) {
-               get_paca()->shadow_vcpu.gpr[num] = val;
-               to_book3s(vcpu)->shadow_vcpu.gpr[num] = val;
-       } else
-               vcpu->arch.gpr[num] = val;
-}
-
-static inline ulong kvmppc_get_gpr(struct kvm_vcpu *vcpu, int num)
-{
-       if ( num < 14 )
-               return get_paca()->shadow_vcpu.gpr[num];
-       else
-               return vcpu->arch.gpr[num];
-}
-
-static inline void kvmppc_set_cr(struct kvm_vcpu *vcpu, u32 val)
-{
-       get_paca()->shadow_vcpu.cr = val;
-       to_book3s(vcpu)->shadow_vcpu.cr = val;
-}
-
-static inline u32 kvmppc_get_cr(struct kvm_vcpu *vcpu)
-{
-       return get_paca()->shadow_vcpu.cr;
-}
-
-static inline void kvmppc_set_xer(struct kvm_vcpu *vcpu, u32 val)
-{
-       get_paca()->shadow_vcpu.xer = val;
-       to_book3s(vcpu)->shadow_vcpu.xer = val;
-}
-
-static inline u32 kvmppc_get_xer(struct kvm_vcpu *vcpu)
+/*
+ * Cuts out inst bits with ordering according to spec.
+ * That means the leftmost bit is zero. All given bits are included.
+ */
+static inline u32 kvmppc_get_field(u64 inst, int msb, int lsb)
 {
-       return get_paca()->shadow_vcpu.xer;
-}
+       u32 r;
+       u32 mask;
 
-#else
+       BUG_ON(msb > lsb);
 
-static inline void kvmppc_set_gpr(struct kvm_vcpu *vcpu, int num, ulong val)
-{
-       vcpu->arch.gpr[num] = val;
-}
+       mask = (1 << (lsb - msb + 1)) - 1;
+       r = (inst >> (63 - lsb)) & mask;
 
-static inline ulong kvmppc_get_gpr(struct kvm_vcpu *vcpu, int num)
-{
-       return vcpu->arch.gpr[num];
+       return r;
 }
 
-static inline void kvmppc_set_cr(struct kvm_vcpu *vcpu, u32 val)
+/*
+ * Replaces inst bits with ordering according to spec.
+ */
+static inline u32 kvmppc_set_field(u64 inst, int msb, int lsb, int value)
 {
-       vcpu->arch.cr = val;
-}
+       u32 r;
+       u32 mask;
 
-static inline u32 kvmppc_get_cr(struct kvm_vcpu *vcpu)
-{
-       return vcpu->arch.cr;
-}
+       BUG_ON(msb > lsb);
 
-static inline void kvmppc_set_xer(struct kvm_vcpu *vcpu, u32 val)
-{
-       vcpu->arch.xer = val;
-}
+       mask = ((1 << (lsb - msb + 1)) - 1) << (63 - lsb);
+       r = (inst & ~mask) | ((value << (63 - lsb)) & mask);
 
-static inline u32 kvmppc_get_xer(struct kvm_vcpu *vcpu)
-{
-       return vcpu->arch.xer;
+       return r;
 }
 
-#endif
-
 #endif /* __POWERPC_KVM_PPC_H__ */
index a062c57696d080b99ae231a70a443ee075e443fc..19a661b4cb98205f6304c3c449062e6ca20e3c94 100644 (file)
@@ -108,7 +108,7 @@ static inline void* macio_get_drvdata(struct macio_dev *dev)
 
 static inline struct device_node *macio_get_of_node(struct macio_dev *mdev)
 {
-       return mdev->ofdev.node;
+       return mdev->ofdev.dev.of_node;
 }
 
 #ifdef CONFIG_PCI
index 26383e0778aaaa143ad3aa793753204d5f8d7ca9..81fb41289d6cb071474c5df484a4ca81b963d1db 100644 (file)
@@ -27,6 +27,8 @@ extern int __init_new_context(void);
 extern void __destroy_context(int context_id);
 static inline void mmu_context_init(void) { }
 #else
+extern unsigned long __init_new_context(void);
+extern void __destroy_context(unsigned long context_id);
 extern void mmu_context_init(void);
 #endif
 
index 42561f4f032d0250e3bad6b0727cf7a4e123dad0..ecc4fc69ac13c973eca8bd9b4aeef9153f6c2cf0 100644 (file)
@@ -248,6 +248,7 @@ struct mpc52xx_psc_fifo {
        u16             tflwfptr;       /* PSC + 0x9e */
 };
 
+#define MPC512x_PSC_FIFO_EOF           0x100
 #define MPC512x_PSC_FIFO_RESET_SLICE   0x80
 #define MPC512x_PSC_FIFO_ENABLE_SLICE  0x01
 #define MPC512x_PSC_FIFO_ENABLE_DMA    0x04
index a64debf177dca8efcbe7534333f81a5b2d3d26d5..444e97e2982ea54cef41240b2ff2ea85ee1db761 100644 (file)
@@ -12,9 +12,8 @@
  */
 struct of_device
 {
-       struct device_node      *node;          /* to be obsoleted */
-       u64                     dma_mask;       /* DMA mask */
        struct device           dev;            /* Generic device interface */
+       struct pdev_archdata    archdata;
 };
 
 extern struct of_device *of_device_alloc(struct device_node *np,
index 971dfa4815f02fa8e02ac604c0e1e869b7b05234..8ce7963ad41d32075e3a11950ee3b5a5160c623c 100644 (file)
@@ -23,7 +23,7 @@
 #include <asm/page.h>
 #include <asm/exception-64e.h>
 #ifdef CONFIG_KVM_BOOK3S_64_HANDLER
-#include <asm/kvm_book3s_64_asm.h>
+#include <asm/kvm_book3s_asm.h>
 #endif
 
 register struct paca_struct *local_paca asm("r13");
@@ -137,15 +137,9 @@ struct paca_struct {
        u64 startpurr;                  /* PURR/TB value snapshot */
        u64 startspurr;                 /* SPURR value snapshot */
 
-#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
-       struct  {
-               u64     esid;
-               u64     vsid;
-       } kvm_slb[64];                  /* guest SLB */
+#ifdef CONFIG_KVM_BOOK3S_HANDLER
        /* We use this to store guest state in */
        struct kvmppc_book3s_shadow_vcpu shadow_vcpu;
-       u8 kvm_slb_max;                 /* highest used guest slb entry */
-       u8 kvm_in_guest;                /* are we inside the guest? */
 #endif
 };
 
index 221ba62404644d598ae2e9a6d20db6a3322656d0..7492fe8ad6e400e43f80faf6da0c62c6226d8db2 100644 (file)
@@ -229,6 +229,9 @@ struct thread_struct {
        unsigned long   spefscr;        /* SPE & eFP status */
        int             used_spe;       /* set if process has used spe */
 #endif /* CONFIG_SPE */
+#ifdef CONFIG_KVM_BOOK3S_32_HANDLER
+       void*           kvm_shadow_vcpu; /* KVM internal data */
+#endif /* CONFIG_KVM_BOOK3S_32_HANDLER */
 };
 
 #define ARCH_MIN_TASKALIGN 16
index b68f025924a861106b7fe01e1ee6ec391775b149..d62fdf4e504bcd54fc2aff2f6e567858bf6c4b69 100644 (file)
 #define HID1_ABE       (1<<10)         /* 7450 Address Broadcast Enable */
 #define HID1_PS                (1<<16)         /* 750FX PLL selection */
 #define SPRN_HID2      0x3F8           /* Hardware Implementation Register 2 */
+#define SPRN_HID2_GEKKO        0x398           /* Gekko HID2 Register */
 #define SPRN_IABR      0x3F2   /* Instruction Address Breakpoint Register */
 #define SPRN_IABR2     0x3FA           /* 83xx */
 #define SPRN_IBCR      0x135           /* 83xx Insn Breakpoint Control Reg */
 #define SPRN_HID4      0x3F4           /* 970 HID4 */
+#define SPRN_HID4_GEKKO        0x3F3           /* Gekko HID4 */
 #define SPRN_HID5      0x3F6           /* 970 HID5 */
 #define SPRN_HID6      0x3F9   /* BE HID 6 */
 #define   HID6_LB      (0x0F<<12) /* Concurrent Large Page Modes */
 #define SPRN_VRSAVE    0x100   /* Vector Register Save Register */
 #define SPRN_XER       0x001   /* Fixed Point Exception Register */
 
+#define SPRN_MMCR0_GEKKO 0x3B8 /* Gekko Monitor Mode Control Register 0 */
+#define SPRN_MMCR1_GEKKO 0x3BC /* Gekko Monitor Mode Control Register 1 */
+#define SPRN_PMC1_GEKKO  0x3B9 /* Gekko Performance Monitor Control 1 */
+#define SPRN_PMC2_GEKKO  0x3BA /* Gekko Performance Monitor Control 2 */
+#define SPRN_PMC3_GEKKO  0x3BD /* Gekko Performance Monitor Control 3 */
+#define SPRN_PMC4_GEKKO  0x3BE /* Gekko Performance Monitor Control 4 */
+#define SPRN_WPAR_GEKKO  0x399 /* Gekko Write Pipe Address Register */
+
 #define SPRN_SCOMC     0x114   /* SCOM Access Control */
 #define SPRN_SCOMD     0x115   /* SCOM Access DATA */
 
index 912bf597870f700188e907c7f424557108a86624..34cc78fd0ef4281d423faf3022f36f59bf7884a2 100644 (file)
@@ -9,38 +9,12 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-#ifdef __KERNEL__
-#include <linux/types.h>
 #include <asm/dma.h>
-
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-       unsigned long sg_magic;
-#endif
-       unsigned long page_link;
-       unsigned int offset;
-       unsigned int length;
-
-       /* For TCE or SWIOTLB support */
-       dma_addr_t dma_address;
-       u32 dma_length;
-};
-
-/*
- * These macros should be used after a dma_map_sg call has been done
- * to get bus addresses of each of the SG entries and their lengths.
- * You should only work with the number of sg entries pci_map_sg
- * returns, or alternatively stop on the first sg_dma_len(sg) which
- * is 0.
- */
-#define sg_dma_address(sg)     ((sg)->dma_address)
-#define sg_dma_len(sg)         ((sg)->dma_length)
+#include <asm-generic/scatterlist.h>
 
 #ifdef __powerpc64__
 #define ISA_DMA_THRESHOLD      (~0UL)
 #endif
-
 #define ARCH_HAS_SG_CHAIN
 
-#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_SCATTERLIST_H */
index 28a686fb269c057de4a4ddf0e6b24dbf908abe82..496cc5b3984f534866d57e3c0d2a9c7f8eb25503 100644 (file)
@@ -50,6 +50,9 @@
 #endif
 #ifdef CONFIG_KVM
 #include <linux/kvm_host.h>
+#ifndef CONFIG_BOOKE
+#include <asm/kvm_book3s.h>
+#endif
 #endif
 
 #ifdef CONFIG_PPC32
@@ -105,6 +108,9 @@ int main(void)
        DEFINE(THREAD_USED_SPE, offsetof(struct thread_struct, used_spe));
 #endif /* CONFIG_SPE */
 #endif /* CONFIG_PPC64 */
+#ifdef CONFIG_KVM_BOOK3S_32_HANDLER
+       DEFINE(THREAD_KVM_SVCPU, offsetof(struct thread_struct, kvm_shadow_vcpu));
+#endif
 
        DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
        DEFINE(TI_LOCAL_FLAGS, offsetof(struct thread_info, local_flags));
@@ -191,33 +197,9 @@ int main(void)
        DEFINE(PACA_DATA_OFFSET, offsetof(struct paca_struct, data_offset));
        DEFINE(PACA_TRAP_SAVE, offsetof(struct paca_struct, trap_save));
 #ifdef CONFIG_KVM_BOOK3S_64_HANDLER
-       DEFINE(PACA_KVM_IN_GUEST, offsetof(struct paca_struct, kvm_in_guest));
-       DEFINE(PACA_KVM_SLB, offsetof(struct paca_struct, kvm_slb));
-       DEFINE(PACA_KVM_SLB_MAX, offsetof(struct paca_struct, kvm_slb_max));
-       DEFINE(PACA_KVM_CR, offsetof(struct paca_struct, shadow_vcpu.cr));
-       DEFINE(PACA_KVM_XER, offsetof(struct paca_struct, shadow_vcpu.xer));
-       DEFINE(PACA_KVM_R0, offsetof(struct paca_struct, shadow_vcpu.gpr[0]));
-       DEFINE(PACA_KVM_R1, offsetof(struct paca_struct, shadow_vcpu.gpr[1]));
-       DEFINE(PACA_KVM_R2, offsetof(struct paca_struct, shadow_vcpu.gpr[2]));
-       DEFINE(PACA_KVM_R3, offsetof(struct paca_struct, shadow_vcpu.gpr[3]));
-       DEFINE(PACA_KVM_R4, offsetof(struct paca_struct, shadow_vcpu.gpr[4]));
-       DEFINE(PACA_KVM_R5, offsetof(struct paca_struct, shadow_vcpu.gpr[5]));
-       DEFINE(PACA_KVM_R6, offsetof(struct paca_struct, shadow_vcpu.gpr[6]));
-       DEFINE(PACA_KVM_R7, offsetof(struct paca_struct, shadow_vcpu.gpr[7]));
-       DEFINE(PACA_KVM_R8, offsetof(struct paca_struct, shadow_vcpu.gpr[8]));
-       DEFINE(PACA_KVM_R9, offsetof(struct paca_struct, shadow_vcpu.gpr[9]));
-       DEFINE(PACA_KVM_R10, offsetof(struct paca_struct, shadow_vcpu.gpr[10]));
-       DEFINE(PACA_KVM_R11, offsetof(struct paca_struct, shadow_vcpu.gpr[11]));
-       DEFINE(PACA_KVM_R12, offsetof(struct paca_struct, shadow_vcpu.gpr[12]));
-       DEFINE(PACA_KVM_R13, offsetof(struct paca_struct, shadow_vcpu.gpr[13]));
-       DEFINE(PACA_KVM_HOST_R1, offsetof(struct paca_struct, shadow_vcpu.host_r1));
-       DEFINE(PACA_KVM_HOST_R2, offsetof(struct paca_struct, shadow_vcpu.host_r2));
-       DEFINE(PACA_KVM_VMHANDLER, offsetof(struct paca_struct,
-                                           shadow_vcpu.vmhandler));
-       DEFINE(PACA_KVM_SCRATCH0, offsetof(struct paca_struct,
-                                          shadow_vcpu.scratch0));
-       DEFINE(PACA_KVM_SCRATCH1, offsetof(struct paca_struct,
-                                          shadow_vcpu.scratch1));
+       DEFINE(PACA_KVM_SVCPU, offsetof(struct paca_struct, shadow_vcpu));
+       DEFINE(SVCPU_SLB, offsetof(struct kvmppc_book3s_shadow_vcpu, slb));
+       DEFINE(SVCPU_SLB_MAX, offsetof(struct kvmppc_book3s_shadow_vcpu, slb_max));
 #endif
 #endif /* CONFIG_PPC64 */
 
@@ -228,8 +210,8 @@ int main(void)
        /* Interrupt register frame */
        DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
        DEFINE(INT_FRAME_SIZE, STACK_INT_FRAME_SIZE);
-#ifdef CONFIG_PPC64
        DEFINE(SWITCH_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs));
+#ifdef CONFIG_PPC64
        /* Create extra stack space for SRR0 and SRR1 when calling prom/rtas. */
        DEFINE(PROM_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16);
        DEFINE(RTAS_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16);
@@ -412,9 +394,6 @@ int main(void)
        DEFINE(VCPU_HOST_STACK, offsetof(struct kvm_vcpu, arch.host_stack));
        DEFINE(VCPU_HOST_PID, offsetof(struct kvm_vcpu, arch.host_pid));
        DEFINE(VCPU_GPRS, offsetof(struct kvm_vcpu, arch.gpr));
-       DEFINE(VCPU_LR, offsetof(struct kvm_vcpu, arch.lr));
-       DEFINE(VCPU_CTR, offsetof(struct kvm_vcpu, arch.ctr));
-       DEFINE(VCPU_PC, offsetof(struct kvm_vcpu, arch.pc));
        DEFINE(VCPU_MSR, offsetof(struct kvm_vcpu, arch.msr));
        DEFINE(VCPU_SPRG4, offsetof(struct kvm_vcpu, arch.sprg4));
        DEFINE(VCPU_SPRG5, offsetof(struct kvm_vcpu, arch.sprg5));
@@ -422,27 +401,68 @@ int main(void)
        DEFINE(VCPU_SPRG7, offsetof(struct kvm_vcpu, arch.sprg7));
        DEFINE(VCPU_SHADOW_PID, offsetof(struct kvm_vcpu, arch.shadow_pid));
 
-       DEFINE(VCPU_LAST_INST, offsetof(struct kvm_vcpu, arch.last_inst));
-       DEFINE(VCPU_FAULT_DEAR, offsetof(struct kvm_vcpu, arch.fault_dear));
-       DEFINE(VCPU_FAULT_ESR, offsetof(struct kvm_vcpu, arch.fault_esr));
-
-       /* book3s_64 */
-#ifdef CONFIG_PPC64
-       DEFINE(VCPU_FAULT_DSISR, offsetof(struct kvm_vcpu, arch.fault_dsisr));
+       /* book3s */
+#ifdef CONFIG_PPC_BOOK3S
        DEFINE(VCPU_HOST_RETIP, offsetof(struct kvm_vcpu, arch.host_retip));
-       DEFINE(VCPU_HOST_R2, offsetof(struct kvm_vcpu, arch.host_r2));
        DEFINE(VCPU_HOST_MSR, offsetof(struct kvm_vcpu, arch.host_msr));
        DEFINE(VCPU_SHADOW_MSR, offsetof(struct kvm_vcpu, arch.shadow_msr));
-       DEFINE(VCPU_SHADOW_SRR1, offsetof(struct kvm_vcpu, arch.shadow_srr1));
        DEFINE(VCPU_TRAMPOLINE_LOWMEM, offsetof(struct kvm_vcpu, arch.trampoline_lowmem));
        DEFINE(VCPU_TRAMPOLINE_ENTER, offsetof(struct kvm_vcpu, arch.trampoline_enter));
        DEFINE(VCPU_HIGHMEM_HANDLER, offsetof(struct kvm_vcpu, arch.highmem_handler));
        DEFINE(VCPU_RMCALL, offsetof(struct kvm_vcpu, arch.rmcall));
        DEFINE(VCPU_HFLAGS, offsetof(struct kvm_vcpu, arch.hflags));
+       DEFINE(VCPU_SVCPU, offsetof(struct kvmppc_vcpu_book3s, shadow_vcpu) -
+                          offsetof(struct kvmppc_vcpu_book3s, vcpu));
+       DEFINE(SVCPU_CR, offsetof(struct kvmppc_book3s_shadow_vcpu, cr));
+       DEFINE(SVCPU_XER, offsetof(struct kvmppc_book3s_shadow_vcpu, xer));
+       DEFINE(SVCPU_CTR, offsetof(struct kvmppc_book3s_shadow_vcpu, ctr));
+       DEFINE(SVCPU_LR, offsetof(struct kvmppc_book3s_shadow_vcpu, lr));
+       DEFINE(SVCPU_PC, offsetof(struct kvmppc_book3s_shadow_vcpu, pc));
+       DEFINE(SVCPU_R0, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[0]));
+       DEFINE(SVCPU_R1, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[1]));
+       DEFINE(SVCPU_R2, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[2]));
+       DEFINE(SVCPU_R3, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[3]));
+       DEFINE(SVCPU_R4, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[4]));
+       DEFINE(SVCPU_R5, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[5]));
+       DEFINE(SVCPU_R6, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[6]));
+       DEFINE(SVCPU_R7, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[7]));
+       DEFINE(SVCPU_R8, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[8]));
+       DEFINE(SVCPU_R9, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[9]));
+       DEFINE(SVCPU_R10, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[10]));
+       DEFINE(SVCPU_R11, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[11]));
+       DEFINE(SVCPU_R12, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[12]));
+       DEFINE(SVCPU_R13, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[13]));
+       DEFINE(SVCPU_HOST_R1, offsetof(struct kvmppc_book3s_shadow_vcpu, host_r1));
+       DEFINE(SVCPU_HOST_R2, offsetof(struct kvmppc_book3s_shadow_vcpu, host_r2));
+       DEFINE(SVCPU_VMHANDLER, offsetof(struct kvmppc_book3s_shadow_vcpu,
+                                        vmhandler));
+       DEFINE(SVCPU_SCRATCH0, offsetof(struct kvmppc_book3s_shadow_vcpu,
+                                       scratch0));
+       DEFINE(SVCPU_SCRATCH1, offsetof(struct kvmppc_book3s_shadow_vcpu,
+                                       scratch1));
+       DEFINE(SVCPU_IN_GUEST, offsetof(struct kvmppc_book3s_shadow_vcpu,
+                                       in_guest));
+       DEFINE(SVCPU_FAULT_DSISR, offsetof(struct kvmppc_book3s_shadow_vcpu,
+                                          fault_dsisr));
+       DEFINE(SVCPU_FAULT_DAR, offsetof(struct kvmppc_book3s_shadow_vcpu,
+                                        fault_dar));
+       DEFINE(SVCPU_LAST_INST, offsetof(struct kvmppc_book3s_shadow_vcpu,
+                                        last_inst));
+       DEFINE(SVCPU_SHADOW_SRR1, offsetof(struct kvmppc_book3s_shadow_vcpu,
+                                          shadow_srr1));
+#ifdef CONFIG_PPC_BOOK3S_32
+       DEFINE(SVCPU_SR, offsetof(struct kvmppc_book3s_shadow_vcpu, sr));
+#endif
 #else
        DEFINE(VCPU_CR, offsetof(struct kvm_vcpu, arch.cr));
        DEFINE(VCPU_XER, offsetof(struct kvm_vcpu, arch.xer));
-#endif /* CONFIG_PPC64 */
+       DEFINE(VCPU_LR, offsetof(struct kvm_vcpu, arch.lr));
+       DEFINE(VCPU_CTR, offsetof(struct kvm_vcpu, arch.ctr));
+       DEFINE(VCPU_PC, offsetof(struct kvm_vcpu, arch.pc));
+       DEFINE(VCPU_LAST_INST, offsetof(struct kvm_vcpu, arch.last_inst));
+       DEFINE(VCPU_FAULT_DEAR, offsetof(struct kvm_vcpu, arch.fault_dear));
+       DEFINE(VCPU_FAULT_ESR, offsetof(struct kvm_vcpu, arch.fault_esr));
+#endif /* CONFIG_PPC_BOOK3S */
 #endif
 #ifdef CONFIG_44x
        DEFINE(PGD_T_LOG2, PGD_T_LOG2);
index 4ff4da2c238bcd8585775cb4f2cb1432b89330c4..e7fe218b86978e52b2ff50f9d34c6efbd4b64790 100644 (file)
@@ -39,8 +39,8 @@ struct dma_map_ops swiotlb_dma_ops = {
        .dma_supported = swiotlb_dma_supported,
        .map_page = swiotlb_map_page,
        .unmap_page = swiotlb_unmap_page,
-       .sync_single_range_for_cpu = swiotlb_sync_single_range_for_cpu,
-       .sync_single_range_for_device = swiotlb_sync_single_range_for_device,
+       .sync_single_for_cpu = swiotlb_sync_single_for_cpu,
+       .sync_single_for_device = swiotlb_sync_single_for_device,
        .sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
        .sync_sg_for_device = swiotlb_sync_sg_for_device,
        .mapping_error = swiotlb_dma_mapping_error,
index 6c1df5757cd6e1a260a96557f5d9f7ea1f807f94..8d1de6f31d5a6befad3d93715d4ddf338b027b55 100644 (file)
@@ -127,11 +127,11 @@ static inline void dma_direct_sync_sg(struct device *dev,
                __dma_sync_page(sg_page(sg), sg->offset, sg->length, direction);
 }
 
-static inline void dma_direct_sync_single_range(struct device *dev,
-               dma_addr_t dma_handle, unsigned long offset, size_t size,
-               enum dma_data_direction direction)
+static inline void dma_direct_sync_single(struct device *dev,
+                                         dma_addr_t dma_handle, size_t size,
+                                         enum dma_data_direction direction)
 {
-       __dma_sync(bus_to_virt(dma_handle+offset), size, direction);
+       __dma_sync(bus_to_virt(dma_handle), size, direction);
 }
 #endif
 
@@ -144,8 +144,8 @@ struct dma_map_ops dma_direct_ops = {
        .map_page       = dma_direct_map_page,
        .unmap_page     = dma_direct_unmap_page,
 #ifdef CONFIG_NOT_COHERENT_CACHE
-       .sync_single_range_for_cpu      = dma_direct_sync_single_range,
-       .sync_single_range_for_device   = dma_direct_sync_single_range,
+       .sync_single_for_cpu            = dma_direct_sync_single,
+       .sync_single_for_device         = dma_direct_sync_single,
        .sync_sg_for_cpu                = dma_direct_sync_sg,
        .sync_sg_for_device             = dma_direct_sync_sg,
 #endif
index e025e89fe93e2632a2a485c1d52e4edaf12be3fe..98c4b29a56f4587c10ba5cbf39aebb1d3b2253ff 100644 (file)
@@ -33,6 +33,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/ptrace.h>
 #include <asm/bug.h>
+#include <asm/kvm_book3s_asm.h>
 
 /* 601 only have IBAT; cr0.eq is set on 601 when using this macro */
 #define LOAD_BAT(n, reg, RA, RB)       \
@@ -303,6 +304,7 @@ __secondary_hold_acknowledge:
  */
 #define EXCEPTION(n, label, hdlr, xfer)                \
        . = n;                                  \
+       DO_KVM n;                               \
 label:                                         \
        EXCEPTION_PROLOG;                       \
        addi    r3,r1,STACK_FRAME_OVERHEAD;     \
@@ -358,6 +360,7 @@ i##n:                                                               \
  *     -- paulus.
  */
        . = 0x200
+       DO_KVM  0x200
        mtspr   SPRN_SPRG_SCRATCH0,r10
        mtspr   SPRN_SPRG_SCRATCH1,r11
        mfcr    r10
@@ -381,6 +384,7 @@ i##n:                                                               \
 
 /* Data access exception. */
        . = 0x300
+       DO_KVM  0x300
 DataAccess:
        EXCEPTION_PROLOG
        mfspr   r10,SPRN_DSISR
@@ -397,6 +401,7 @@ DataAccess:
 
 /* Instruction access exception. */
        . = 0x400
+       DO_KVM  0x400
 InstructionAccess:
        EXCEPTION_PROLOG
        andis.  r0,r9,0x4000            /* no pte found? */
@@ -413,6 +418,7 @@ InstructionAccess:
 
 /* Alignment exception */
        . = 0x600
+       DO_KVM  0x600
 Alignment:
        EXCEPTION_PROLOG
        mfspr   r4,SPRN_DAR
@@ -427,6 +433,7 @@ Alignment:
 
 /* Floating-point unavailable */
        . = 0x800
+       DO_KVM  0x800
 FPUnavailable:
 BEGIN_FTR_SECTION
 /*
@@ -450,6 +457,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_FPU_UNAVAILABLE)
 
 /* System call */
        . = 0xc00
+       DO_KVM  0xc00
 SystemCall:
        EXCEPTION_PROLOG
        EXC_XFER_EE_LITE(0xc00, DoSyscall)
@@ -467,9 +475,11 @@ SystemCall:
  * by executing an altivec instruction.
  */
        . = 0xf00
+       DO_KVM  0xf00
        b       PerformanceMonitor
 
        . = 0xf20
+       DO_KVM  0xf20
        b       AltiVecUnavailable
 
 /*
@@ -882,6 +892,10 @@ __secondary_start:
        RFI
 #endif /* CONFIG_SMP */
 
+#ifdef CONFIG_KVM_BOOK3S_HANDLER
+#include "../kvm/book3s_rmhandlers.S"
+#endif
+
 /*
  * Those generic dummy functions are kept for CPUs not
  * included in CONFIG_6xx
index bed9a29ee383a067ba6e2a37a1b74385e746ad13..844a44b6447254889a10c35c2acf877981a4f16e 100644 (file)
@@ -37,7 +37,7 @@
 #include <asm/firmware.h>
 #include <asm/page_64.h>
 #include <asm/irqflags.h>
-#include <asm/kvm_book3s_64_asm.h>
+#include <asm/kvm_book3s_asm.h>
 
 /* The physical memory is layed out such that the secondary processor
  * spin code sits at 0x0000...0x00ff. On server, the vectors follow
@@ -169,7 +169,7 @@ exception_marker:
 /* KVM trampoline code needs to be close to the interrupt handlers */
 
 #ifdef CONFIG_KVM_BOOK3S_64_HANDLER
-#include "../kvm/book3s_64_rmhandlers.S"
+#include "../kvm/book3s_rmhandlers.S"
 #endif
 
 _GLOBAL(generic_secondary_thread_init)
index 71cf280da1847f3255a71d0bb9b9cf439b5852f8..21266abfbda64cb0a11fd2a10aa8f1af47c574a1 100644 (file)
@@ -140,14 +140,14 @@ static struct dma_map_ops ibmebus_dma_ops = {
 
 static int ibmebus_match_path(struct device *dev, void *data)
 {
-       struct device_node *dn = to_of_device(dev)->node;
+       struct device_node *dn = to_of_device(dev)->dev.of_node;
        return (dn->full_name &&
                (strcasecmp((char *)data, dn->full_name) == 0));
 }
 
 static int ibmebus_match_node(struct device *dev, void *data)
 {
-       return to_of_device(dev)->node == data;
+       return to_of_device(dev)->dev.of_node == data;
 }
 
 static int ibmebus_create_device(struct device_node *dn)
@@ -202,7 +202,7 @@ static int ibmebus_create_devices(const struct of_device_id *matches)
 int ibmebus_register_driver(struct of_platform_driver *drv)
 {
        /* If the driver uses devices that ibmebus doesn't know, add them */
-       ibmebus_create_devices(drv->match_table);
+       ibmebus_create_devices(drv->driver.of_match_table);
 
        return of_register_driver(drv, &ibmebus_bus_type);
 }
index a359cb08e9006168a60ba87b9e34df0c02256d51..df78e0236a02b808fe9c863f8721d92c164c0f97 100644 (file)
@@ -13,7 +13,7 @@
 static void of_device_make_bus_id(struct of_device *dev)
 {
        static atomic_t bus_no_reg_magic;
-       struct device_node *node = dev->node;
+       struct device_node *node = dev->dev.of_node;
        const u32 *reg;
        u64 addr;
        int magic;
@@ -69,11 +69,10 @@ struct of_device *of_device_alloc(struct device_node *np,
        if (!dev)
                return NULL;
 
-       dev->node = of_node_get(np);
-       dev->dev.dma_mask = &dev->dma_mask;
+       dev->dev.of_node = of_node_get(np);
+       dev->dev.dma_mask = &dev->archdata.dma_mask;
        dev->dev.parent = parent;
        dev->dev.release = of_release_dev;
-       dev->dev.archdata.of_node = np;
 
        if (bus_id)
                dev_set_name(&dev->dev, "%s", bus_id);
@@ -95,17 +94,17 @@ int of_device_uevent(struct device *dev, struct kobj_uevent_env *env)
 
        ofdev = to_of_device(dev);
 
-       if (add_uevent_var(env, "OF_NAME=%s", ofdev->node->name))
+       if (add_uevent_var(env, "OF_NAME=%s", ofdev->dev.of_node->name))
                return -ENOMEM;
 
-       if (add_uevent_var(env, "OF_TYPE=%s", ofdev->node->type))
+       if (add_uevent_var(env, "OF_TYPE=%s", ofdev->dev.of_node->type))
                return -ENOMEM;
 
         /* Since the compatible field can contain pretty much anything
          * it's not really legal to split it out with commas. We split it
          * up using a number of environment variables instead. */
 
-       compat = of_get_property(ofdev->node, "compatible", &cplen);
+       compat = of_get_property(ofdev->dev.of_node, "compatible", &cplen);
        while (compat && *compat && cplen > 0) {
                if (add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat))
                        return -ENOMEM;
index 6c1dfc3ff8bc16903d976e73a242c6268eadb3d3..487a98851ba6f04f24fd50d200f712ba29df46ac 100644 (file)
@@ -74,7 +74,7 @@ struct of_device* of_platform_device_create(struct device_node *np,
        if (!dev)
                return NULL;
 
-       dev->dma_mask = 0xffffffffUL;
+       dev->archdata.dma_mask = 0xffffffffUL;
        dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
 
        dev->dev.bus = &of_platform_bus_type;
@@ -195,7 +195,7 @@ EXPORT_SYMBOL(of_platform_bus_probe);
 
 static int of_dev_node_match(struct device *dev, void *data)
 {
-       return to_of_device(dev)->node == data;
+       return to_of_device(dev)->dev.of_node == data;
 }
 
 struct of_device *of_find_device_by_node(struct device_node *np)
@@ -213,7 +213,7 @@ EXPORT_SYMBOL(of_find_device_by_node);
 static int of_dev_phandle_match(struct device *dev, void *data)
 {
        phandle *ph = data;
-       return to_of_device(dev)->node->phandle == *ph;
+       return to_of_device(dev)->dev.of_node->phandle == *ph;
 }
 
 struct of_device *of_find_device_by_phandle(phandle ph)
@@ -246,10 +246,10 @@ static int __devinit of_pci_phb_probe(struct of_device *dev,
        if (ppc_md.pci_setup_phb == NULL)
                return -ENODEV;
 
-       printk(KERN_INFO "Setting up PCI bus %s\n", dev->node->full_name);
+       pr_info("Setting up PCI bus %s\n", dev->dev.of_node->full_name);
 
        /* Alloc and setup PHB data structure */
-       phb = pcibios_alloc_controller(dev->node);
+       phb = pcibios_alloc_controller(dev->dev.of_node);
        if (!phb)
                return -ENODEV;
 
@@ -263,19 +263,19 @@ static int __devinit of_pci_phb_probe(struct of_device *dev,
        }
 
        /* Process "ranges" property */
-       pci_process_bridge_OF_ranges(phb, dev->node, 0);
+       pci_process_bridge_OF_ranges(phb, dev->dev.of_node, 0);
 
        /* Init pci_dn data structures */
        pci_devs_phb_init_dynamic(phb);
 
        /* Register devices with EEH */
 #ifdef CONFIG_EEH
-       if (dev->node->child)
-               eeh_add_device_tree_early(dev->node);
+       if (dev->dev.of_node->child)
+               eeh_add_device_tree_early(dev->dev.of_node);
 #endif /* CONFIG_EEH */
 
        /* Scan the bus */
-       pcibios_scan_phb(phb, dev->node);
+       pcibios_scan_phb(phb, dev->dev.of_node);
        if (phb->bus == NULL)
                return -ENXIO;
 
@@ -306,10 +306,11 @@ static struct of_device_id of_pci_phb_ids[] = {
 };
 
 static struct of_platform_driver of_pci_phb_driver = {
-       .match_table = of_pci_phb_ids,
        .probe = of_pci_phb_probe,
        .driver = {
                .name = "of-pci",
+               .owner = THIS_MODULE,
+               .of_match_table = of_pci_phb_ids,
        },
 };
 
index 0c0567e58409ae006ae4f077d4a54e2a29fb81d4..6646005dffb102b8b57172442aa8a71c5ed85a82 100644 (file)
@@ -1097,8 +1097,8 @@ void __devinit pcibios_setup_bus_devices(struct pci_bus *bus)
                if (dev->is_added)
                        continue;
 
-               /* Setup OF node pointer in archdata */
-               sd->of_node = pci_device_to_OF_node(dev);
+               /* Setup OF node pointer in the device */
+               dev->dev.of_node = pci_device_to_OF_node(dev);
 
                /* Fixup NUMA node as it may not be setup yet by the generic
                 * code and is needed by the DMA init
index ab3e392ac63c41fda474ce4857660bbd38e459bd..bc9f39d2598bcf7df0e26c95eaa2f5054e005ca9 100644 (file)
@@ -101,6 +101,10 @@ EXPORT_SYMBOL(pci_dram_offset);
 EXPORT_SYMBOL(start_thread);
 EXPORT_SYMBOL(kernel_thread);
 
+#ifndef CONFIG_BOOKE
+EXPORT_SYMBOL_GPL(cvt_df);
+EXPORT_SYMBOL_GPL(cvt_fd);
+#endif
 EXPORT_SYMBOL(giveup_fpu);
 #ifdef CONFIG_ALTIVEC
 EXPORT_SYMBOL(giveup_altivec);
index 9ce7b62dc3a4f07e76daa301b2df12f52f524a05..00b9436f76525c501ecd8bcfab1abef5911a42d4 100644 (file)
@@ -707,7 +707,7 @@ static int vio_cmo_bus_probe(struct vio_dev *viodev)
         * Check to see that device has a DMA window and configure
         * entitlement for the device.
         */
-       if (of_get_property(viodev->dev.archdata.of_node,
+       if (of_get_property(viodev->dev.of_node,
                            "ibm,my-dma-window", NULL)) {
                /* Check that the driver is CMO enabled and get desired DMA */
                if (!viodrv->get_desired_dma) {
@@ -1054,7 +1054,7 @@ static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev)
        if (firmware_has_feature(FW_FEATURE_ISERIES))
                return vio_build_iommu_table_iseries(dev);
 
-       dma_window = of_get_property(dev->dev.archdata.of_node,
+       dma_window = of_get_property(dev->dev.of_node,
                                  "ibm,my-dma-window", NULL);
        if (!dma_window)
                return NULL;
@@ -1063,7 +1063,7 @@ static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev)
        if (tbl == NULL)
                return NULL;
 
-       of_parse_dma_window(dev->dev.archdata.of_node, dma_window,
+       of_parse_dma_window(dev->dev.of_node, dma_window,
                            &tbl->it_index, &offset, &size);
 
        /* TCE table size - measured in tce entries */
@@ -1091,7 +1091,7 @@ static const struct vio_device_id *vio_match_device(
 {
        while (ids->type[0] != '\0') {
                if ((strncmp(dev->type, ids->type, strlen(ids->type)) == 0) &&
-                   of_device_is_compatible(dev->dev.archdata.of_node,
+                   of_device_is_compatible(dev->dev.of_node,
                                         ids->compat))
                        return ids;
                ids++;
@@ -1184,7 +1184,7 @@ EXPORT_SYMBOL(vio_unregister_driver);
 static void __devinit vio_dev_release(struct device *dev)
 {
        /* XXX should free TCE table */
-       of_node_put(dev->archdata.of_node);
+       of_node_put(dev->of_node);
        kfree(to_vio_dev(dev));
 }
 
@@ -1235,7 +1235,7 @@ struct vio_dev *vio_register_device_node(struct device_node *of_node)
                if (unit_address != NULL)
                        viodev->unit_address = *unit_address;
        }
-       viodev->dev.archdata.of_node = of_node_get(of_node);
+       viodev->dev.of_node = of_node_get(of_node);
 
        if (firmware_has_feature(FW_FEATURE_CMO))
                vio_cmo_set_dma_ops(viodev);
@@ -1320,7 +1320,7 @@ static ssize_t name_show(struct device *dev,
 static ssize_t devspec_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       struct device_node *of_node = dev->archdata.of_node;
+       struct device_node *of_node = dev->of_node;
 
        return sprintf(buf, "%s\n", of_node ? of_node->full_name : "none");
 }
@@ -1332,7 +1332,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
        struct device_node *dn;
        const char *cp;
 
-       dn = dev->archdata.of_node;
+       dn = dev->of_node;
        if (!dn)
                return -ENODEV;
        cp = of_get_property(dn, "compatible", NULL);
@@ -1370,7 +1370,7 @@ static int vio_hotplug(struct device *dev, struct kobj_uevent_env *env)
        struct device_node *dn;
        const char *cp;
 
-       dn = dev->archdata.of_node;
+       dn = dev->of_node;
        if (!dn)
                return -ENODEV;
        cp = of_get_property(dn, "compatible", NULL);
@@ -1402,7 +1402,7 @@ static struct bus_type vio_bus_type = {
 */
 const void *vio_get_attribute(struct vio_dev *vdev, char *which, int *length)
 {
-       return of_get_property(vdev->dev.archdata.of_node, which, length);
+       return of_get_property(vdev->dev.of_node, which, length);
 }
 EXPORT_SYMBOL(vio_get_attribute);
 
index 689a57c2ac8009f3d62a51cb9d94dc90a333d4e3..73c0a3f64ed1e9587b5776ae3c198af94edc9a97 100644 (file)
@@ -147,7 +147,7 @@ static int __init kvmppc_44x_init(void)
        if (r)
                return r;
 
-       return kvm_init(NULL, sizeof(struct kvmppc_vcpu_44x), THIS_MODULE);
+       return kvm_init(NULL, sizeof(struct kvmppc_vcpu_44x), 0, THIS_MODULE);
 }
 
 static void __exit kvmppc_44x_exit(void)
index 60624cc9f4d4067a2c891e862a83b7c1a83f2de0..b7baff78f90ca174fd24c66675cdffe0250cb702 100644 (file)
@@ -22,12 +22,34 @@ config KVM
        select ANON_INODES
        select KVM_MMIO
 
+config KVM_BOOK3S_HANDLER
+       bool
+
+config KVM_BOOK3S_32_HANDLER
+       bool
+       select KVM_BOOK3S_HANDLER
+
 config KVM_BOOK3S_64_HANDLER
        bool
+       select KVM_BOOK3S_HANDLER
+
+config KVM_BOOK3S_32
+       tristate "KVM support for PowerPC book3s_32 processors"
+       depends on EXPERIMENTAL && PPC_BOOK3S_32 && !SMP && !PTE_64BIT
+       select KVM
+       select KVM_BOOK3S_32_HANDLER
+       ---help---
+         Support running unmodified book3s_32 guest kernels
+         in virtual machines on book3s_32 host processors.
+
+         This module provides access to the hardware capabilities through
+         a character device node named /dev/kvm.
+
+         If unsure, say N.
 
 config KVM_BOOK3S_64
        tristate "KVM support for PowerPC book3s_64 processors"
-       depends on EXPERIMENTAL && PPC64
+       depends on EXPERIMENTAL && PPC_BOOK3S_64
        select KVM
        select KVM_BOOK3S_64_HANDLER
        ---help---
index 56484d6523777582f3a44e84850ead22cb237d52..ff436066bf776f4677d7f853ab158631f753ea4f 100644 (file)
@@ -14,7 +14,7 @@ CFLAGS_emulate.o  := -I.
 
 common-objs-y += powerpc.o emulate.o
 obj-$(CONFIG_KVM_EXIT_TIMING) += timing.o
-obj-$(CONFIG_KVM_BOOK3S_64_HANDLER) += book3s_64_exports.o
+obj-$(CONFIG_KVM_BOOK3S_HANDLER) += book3s_exports.o
 
 AFLAGS_booke_interrupts.o := -I$(obj)
 
@@ -40,17 +40,31 @@ kvm-objs-$(CONFIG_KVM_E500) := $(kvm-e500-objs)
 
 kvm-book3s_64-objs := \
        $(common-objs-y) \
+       fpu.o \
+       book3s_paired_singles.o \
        book3s.o \
-       book3s_64_emulate.o \
-       book3s_64_interrupts.o \
+       book3s_emulate.o \
+       book3s_interrupts.o \
        book3s_64_mmu_host.o \
        book3s_64_mmu.o \
        book3s_32_mmu.o
 kvm-objs-$(CONFIG_KVM_BOOK3S_64) := $(kvm-book3s_64-objs)
 
+kvm-book3s_32-objs := \
+       $(common-objs-y) \
+       fpu.o \
+       book3s_paired_singles.o \
+       book3s.o \
+       book3s_emulate.o \
+       book3s_interrupts.o \
+       book3s_32_mmu_host.o \
+       book3s_32_mmu.o
+kvm-objs-$(CONFIG_KVM_BOOK3S_32) := $(kvm-book3s_32-objs)
+
 kvm-objs := $(kvm-objs-m) $(kvm-objs-y)
 
 obj-$(CONFIG_KVM_440) += kvm.o
 obj-$(CONFIG_KVM_E500) += kvm.o
 obj-$(CONFIG_KVM_BOOK3S_64) += kvm.o
+obj-$(CONFIG_KVM_BOOK3S_32) += kvm.o
 
index 604af29b71ed28ac8d641ab977496a2638cdeb19..b998abf1a63d13f8f05132037560b8e466d3b955 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/kvm_host.h>
 #include <linux/err.h>
+#include <linux/slab.h>
 
 #include <asm/reg.h>
 #include <asm/cputable.h>
@@ -29,6 +30,7 @@
 #include <linux/gfp.h>
 #include <linux/sched.h>
 #include <linux/vmalloc.h>
+#include <linux/highmem.h>
 
 #define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU
 
 /* #define EXIT_DEBUG_SIMPLE */
 /* #define DEBUG_EXT */
 
-static void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr);
+static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr,
+                            ulong msr);
+
+/* Some compatibility defines */
+#ifdef CONFIG_PPC_BOOK3S_32
+#define MSR_USER32 MSR_USER
+#define MSR_USER64 MSR_USER
+#define HW_PAGE_SIZE PAGE_SIZE
+#endif
 
 struct kvm_stats_debugfs_item debugfs_entries[] = {
        { "exits",       VCPU_STAT(sum_exits) },
@@ -69,18 +79,26 @@ void kvmppc_core_load_guest_debugstate(struct kvm_vcpu *vcpu)
 
 void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
-       memcpy(get_paca()->kvm_slb, to_book3s(vcpu)->slb_shadow, sizeof(get_paca()->kvm_slb));
-       memcpy(&get_paca()->shadow_vcpu, &to_book3s(vcpu)->shadow_vcpu,
+#ifdef CONFIG_PPC_BOOK3S_64
+       memcpy(to_svcpu(vcpu)->slb, to_book3s(vcpu)->slb_shadow, sizeof(to_svcpu(vcpu)->slb));
+       memcpy(&get_paca()->shadow_vcpu, to_book3s(vcpu)->shadow_vcpu,
               sizeof(get_paca()->shadow_vcpu));
-       get_paca()->kvm_slb_max = to_book3s(vcpu)->slb_shadow_max;
+       to_svcpu(vcpu)->slb_max = to_book3s(vcpu)->slb_shadow_max;
+#endif
+
+#ifdef CONFIG_PPC_BOOK3S_32
+       current->thread.kvm_shadow_vcpu = to_book3s(vcpu)->shadow_vcpu;
+#endif
 }
 
 void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu)
 {
-       memcpy(to_book3s(vcpu)->slb_shadow, get_paca()->kvm_slb, sizeof(get_paca()->kvm_slb));
-       memcpy(&to_book3s(vcpu)->shadow_vcpu, &get_paca()->shadow_vcpu,
+#ifdef CONFIG_PPC_BOOK3S_64
+       memcpy(to_book3s(vcpu)->slb_shadow, to_svcpu(vcpu)->slb, sizeof(to_svcpu(vcpu)->slb));
+       memcpy(to_book3s(vcpu)->shadow_vcpu, &get_paca()->shadow_vcpu,
               sizeof(get_paca()->shadow_vcpu));
-       to_book3s(vcpu)->slb_shadow_max = get_paca()->kvm_slb_max;
+       to_book3s(vcpu)->slb_shadow_max = to_svcpu(vcpu)->slb_max;
+#endif
 
        kvmppc_giveup_ext(vcpu, MSR_FP);
        kvmppc_giveup_ext(vcpu, MSR_VEC);
@@ -131,18 +149,22 @@ void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 msr)
                }
        }
 
-       if (((vcpu->arch.msr & (MSR_IR|MSR_DR)) != (old_msr & (MSR_IR|MSR_DR))) ||
-           (vcpu->arch.msr & MSR_PR) != (old_msr & MSR_PR)) {
+       if ((vcpu->arch.msr & (MSR_PR|MSR_IR|MSR_DR)) !=
+                  (old_msr & (MSR_PR|MSR_IR|MSR_DR))) {
                kvmppc_mmu_flush_segments(vcpu);
-               kvmppc_mmu_map_segment(vcpu, vcpu->arch.pc);
+               kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu));
        }
+
+       /* Preload FPU if it's enabled */
+       if (vcpu->arch.msr & MSR_FP)
+               kvmppc_handle_ext(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, MSR_FP);
 }
 
 void kvmppc_inject_interrupt(struct kvm_vcpu *vcpu, int vec, u64 flags)
 {
-       vcpu->arch.srr0 = vcpu->arch.pc;
+       vcpu->arch.srr0 = kvmppc_get_pc(vcpu);
        vcpu->arch.srr1 = vcpu->arch.msr | flags;
-       vcpu->arch.pc = to_book3s(vcpu)->hior + vec;
+       kvmppc_set_pc(vcpu, to_book3s(vcpu)->hior + vec);
        vcpu->arch.mmu.reset_msr(vcpu);
 }
 
@@ -218,6 +240,12 @@ void kvmppc_core_queue_external(struct kvm_vcpu *vcpu,
        kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL);
 }
 
+void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu,
+                                  struct kvm_interrupt *irq)
+{
+       kvmppc_book3s_dequeue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL);
+}
+
 int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
 {
        int deliver = 1;
@@ -302,7 +330,7 @@ void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu)
                printk(KERN_EMERG "KVM: Check pending: %lx\n", vcpu->arch.pending_exceptions);
 #endif
        priority = __ffs(*pending);
-       while (priority <= (sizeof(unsigned int) * 8)) {
+       while (priority < BOOK3S_IRQPRIO_MAX) {
                if (kvmppc_book3s_irqprio_deliver(vcpu, priority) &&
                    (priority != BOOK3S_IRQPRIO_DECREMENTER)) {
                        /* DEC interrupts get cleared by mtdec */
@@ -318,13 +346,18 @@ void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu)
 
 void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr)
 {
+       u32 host_pvr;
+
        vcpu->arch.hflags &= ~BOOK3S_HFLAG_SLB;
        vcpu->arch.pvr = pvr;
+#ifdef CONFIG_PPC_BOOK3S_64
        if ((pvr >= 0x330000) && (pvr < 0x70330000)) {
                kvmppc_mmu_book3s_64_init(vcpu);
                to_book3s(vcpu)->hior = 0xfff00000;
                to_book3s(vcpu)->msr_mask = 0xffffffffffffffffULL;
-       } else {
+       } else
+#endif
+       {
                kvmppc_mmu_book3s_32_init(vcpu);
                to_book3s(vcpu)->hior = 0;
                to_book3s(vcpu)->msr_mask = 0xffffffffULL;
@@ -337,6 +370,32 @@ void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr)
            !strcmp(cur_cpu_spec->platform, "ppc970"))
                vcpu->arch.hflags |= BOOK3S_HFLAG_DCBZ32;
 
+       /* Cell performs badly if MSR_FEx are set. So let's hope nobody
+          really needs them in a VM on Cell and force disable them. */
+       if (!strcmp(cur_cpu_spec->platform, "ppc-cell-be"))
+               to_book3s(vcpu)->msr_mask &= ~(MSR_FE0 | MSR_FE1);
+
+#ifdef CONFIG_PPC_BOOK3S_32
+       /* 32 bit Book3S always has 32 byte dcbz */
+       vcpu->arch.hflags |= BOOK3S_HFLAG_DCBZ32;
+#endif
+
+       /* On some CPUs we can execute paired single operations natively */
+       asm ( "mfpvr %0" : "=r"(host_pvr));
+       switch (host_pvr) {
+       case 0x00080200:        /* lonestar 2.0 */
+       case 0x00088202:        /* lonestar 2.2 */
+       case 0x70000100:        /* gekko 1.0 */
+       case 0x00080100:        /* gekko 2.0 */
+       case 0x00083203:        /* gekko 2.3a */
+       case 0x00083213:        /* gekko 2.3b */
+       case 0x00083204:        /* gekko 2.4 */
+       case 0x00083214:        /* gekko 2.4e (8SE) - retail HW2 */
+       case 0x00087200:        /* broadway */
+               vcpu->arch.hflags |= BOOK3S_HFLAG_NATIVE_PS;
+               /* Enable HID2.PSE - in case we need it later */
+               mtspr(SPRN_HID2_GEKKO, mfspr(SPRN_HID2_GEKKO) | (1 << 29));
+       }
 }
 
 /* Book3s_32 CPUs always have 32 bytes cache line size, which Linux assumes. To
@@ -350,34 +409,29 @@ void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr)
  */
 static void kvmppc_patch_dcbz(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte)
 {
-       bool touched = false;
-       hva_t hpage;
+       struct page *hpage;
+       u64 hpage_offset;
        u32 *page;
        int i;
 
-       hpage = gfn_to_hva(vcpu->kvm, pte->raddr >> PAGE_SHIFT);
-       if (kvm_is_error_hva(hpage))
+       hpage = gfn_to_page(vcpu->kvm, pte->raddr >> PAGE_SHIFT);
+       if (is_error_page(hpage))
                return;
 
-       hpage |= pte->raddr & ~PAGE_MASK;
-       hpage &= ~0xFFFULL;
-
-       page = vmalloc(HW_PAGE_SIZE);
-
-       if (copy_from_user(page, (void __user *)hpage, HW_PAGE_SIZE))
-               goto out;
+       hpage_offset = pte->raddr & ~PAGE_MASK;
+       hpage_offset &= ~0xFFFULL;
+       hpage_offset /= 4;
 
-       for (i=0; i < HW_PAGE_SIZE / 4; i++)
-               if ((page[i] & 0xff0007ff) == INS_DCBZ) {
-                       page[i] &= 0xfffffff7; // reserved instruction, so we trap
-                       touched = true;
-               }
+       get_page(hpage);
+       page = kmap_atomic(hpage, KM_USER0);
 
-       if (touched)
-               copy_to_user((void __user *)hpage, page, HW_PAGE_SIZE);
+       /* patch dcbz into reserved instruction, so we trap */
+       for (i=hpage_offset; i < hpage_offset + (HW_PAGE_SIZE / 4); i++)
+               if ((page[i] & 0xff0007ff) == INS_DCBZ)
+                       page[i] &= 0xfffffff7;
 
-out:
-       vfree(page);
+       kunmap_atomic(page, KM_USER0);
+       put_page(hpage);
 }
 
 static int kvmppc_xlate(struct kvm_vcpu *vcpu, ulong eaddr, bool data,
@@ -391,15 +445,7 @@ static int kvmppc_xlate(struct kvm_vcpu *vcpu, ulong eaddr, bool data,
        } else {
                pte->eaddr = eaddr;
                pte->raddr = eaddr & 0xffffffff;
-               pte->vpage = eaddr >> 12;
-               switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
-               case 0:
-                       pte->vpage |= VSID_REAL;
-               case MSR_DR:
-                       pte->vpage |= VSID_REAL_DR;
-               case MSR_IR:
-                       pte->vpage |= VSID_REAL_IR;
-               }
+               pte->vpage = VSID_REAL | eaddr >> 12;
                pte->may_read = true;
                pte->may_write = true;
                pte->may_execute = true;
@@ -434,55 +480,55 @@ err:
        return kvmppc_bad_hva();
 }
 
-int kvmppc_st(struct kvm_vcpu *vcpu, ulong eaddr, int size, void *ptr)
+int kvmppc_st(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr,
+             bool data)
 {
        struct kvmppc_pte pte;
-       hva_t hva = eaddr;
 
        vcpu->stat.st++;
 
-       if (kvmppc_xlate(vcpu, eaddr, false, &pte))
-               goto err;
+       if (kvmppc_xlate(vcpu, *eaddr, data, &pte))
+               return -ENOENT;
 
-       hva = kvmppc_pte_to_hva(vcpu, &pte, false);
-       if (kvm_is_error_hva(hva))
-               goto err;
+       *eaddr = pte.raddr;
 
-       if (copy_to_user((void __user *)hva, ptr, size)) {
-               printk(KERN_INFO "kvmppc_st at 0x%lx failed\n", hva);
-               goto err;
-       }
+       if (!pte.may_write)
+               return -EPERM;
 
-       return 0;
+       if (kvm_write_guest(vcpu->kvm, pte.raddr, ptr, size))
+               return EMULATE_DO_MMIO;
 
-err:
-       return -ENOENT;
+       return EMULATE_DONE;
 }
 
-int kvmppc_ld(struct kvm_vcpu *vcpu, ulong eaddr, int size, void *ptr,
+int kvmppc_ld(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr,
                      bool data)
 {
        struct kvmppc_pte pte;
-       hva_t hva = eaddr;
+       hva_t hva = *eaddr;
 
        vcpu->stat.ld++;
 
-       if (kvmppc_xlate(vcpu, eaddr, data, &pte))
-               goto err;
+       if (kvmppc_xlate(vcpu, *eaddr, data, &pte))
+               goto nopte;
+
+       *eaddr = pte.raddr;
 
        hva = kvmppc_pte_to_hva(vcpu, &pte, true);
        if (kvm_is_error_hva(hva))
-               goto err;
+               goto mmio;
 
        if (copy_from_user(ptr, (void __user *)hva, size)) {
                printk(KERN_INFO "kvmppc_ld at 0x%lx failed\n", hva);
-               goto err;
+               goto mmio;
        }
 
-       return 0;
+       return EMULATE_DONE;
 
-err:
+nopte:
        return -ENOENT;
+mmio:
+       return EMULATE_DO_MMIO;
 }
 
 static int kvmppc_visible_gfn(struct kvm_vcpu *vcpu, gfn_t gfn)
@@ -499,12 +545,11 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
        int page_found = 0;
        struct kvmppc_pte pte;
        bool is_mmio = false;
+       bool dr = (vcpu->arch.msr & MSR_DR) ? true : false;
+       bool ir = (vcpu->arch.msr & MSR_IR) ? true : false;
+       u64 vsid;
 
-       if ( vec == BOOK3S_INTERRUPT_DATA_STORAGE ) {
-               relocated = (vcpu->arch.msr & MSR_DR);
-       } else {
-               relocated = (vcpu->arch.msr & MSR_IR);
-       }
+       relocated = data ? dr : ir;
 
        /* Resolve real address if translation turned on */
        if (relocated) {
@@ -516,14 +561,25 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
                pte.raddr = eaddr & 0xffffffff;
                pte.eaddr = eaddr;
                pte.vpage = eaddr >> 12;
-               switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
-               case 0:
-                       pte.vpage |= VSID_REAL;
-               case MSR_DR:
-                       pte.vpage |= VSID_REAL_DR;
-               case MSR_IR:
-                       pte.vpage |= VSID_REAL_IR;
-               }
+       }
+
+       switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
+       case 0:
+               pte.vpage |= ((u64)VSID_REAL << (SID_SHIFT - 12));
+               break;
+       case MSR_DR:
+       case MSR_IR:
+               vcpu->arch.mmu.esid_to_vsid(vcpu, eaddr >> SID_SHIFT, &vsid);
+
+               if ((vcpu->arch.msr & (MSR_DR|MSR_IR)) == MSR_DR)
+                       pte.vpage |= ((u64)VSID_REAL_DR << (SID_SHIFT - 12));
+               else
+                       pte.vpage |= ((u64)VSID_REAL_IR << (SID_SHIFT - 12));
+               pte.vpage |= vsid;
+
+               if (vsid == -1)
+                       page_found = -EINVAL;
+               break;
        }
 
        if (vcpu->arch.mmu.is_dcbz32(vcpu) &&
@@ -538,20 +594,20 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
 
        if (page_found == -ENOENT) {
                /* Page not found in guest PTE entries */
-               vcpu->arch.dear = vcpu->arch.fault_dear;
-               to_book3s(vcpu)->dsisr = vcpu->arch.fault_dsisr;
-               vcpu->arch.msr |= (vcpu->arch.shadow_srr1 & 0x00000000f8000000ULL);
+               vcpu->arch.dear = kvmppc_get_fault_dar(vcpu);
+               to_book3s(vcpu)->dsisr = to_svcpu(vcpu)->fault_dsisr;
+               vcpu->arch.msr |= (to_svcpu(vcpu)->shadow_srr1 & 0x00000000f8000000ULL);
                kvmppc_book3s_queue_irqprio(vcpu, vec);
        } else if (page_found == -EPERM) {
                /* Storage protection */
-               vcpu->arch.dear = vcpu->arch.fault_dear;
-               to_book3s(vcpu)->dsisr = vcpu->arch.fault_dsisr & ~DSISR_NOHPTE;
+               vcpu->arch.dear = kvmppc_get_fault_dar(vcpu);
+               to_book3s(vcpu)->dsisr = to_svcpu(vcpu)->fault_dsisr & ~DSISR_NOHPTE;
                to_book3s(vcpu)->dsisr |= DSISR_PROTFAULT;
-               vcpu->arch.msr |= (vcpu->arch.shadow_srr1 & 0x00000000f8000000ULL);
+               vcpu->arch.msr |= (to_svcpu(vcpu)->shadow_srr1 & 0x00000000f8000000ULL);
                kvmppc_book3s_queue_irqprio(vcpu, vec);
        } else if (page_found == -EINVAL) {
                /* Page not found in guest SLB */
-               vcpu->arch.dear = vcpu->arch.fault_dear;
+               vcpu->arch.dear = kvmppc_get_fault_dar(vcpu);
                kvmppc_book3s_queue_irqprio(vcpu, vec + 0x80);
        } else if (!is_mmio &&
                   kvmppc_visible_gfn(vcpu, pte.raddr >> PAGE_SHIFT)) {
@@ -583,11 +639,13 @@ static inline int get_fpr_index(int i)
 }
 
 /* Give up external provider (FPU, Altivec, VSX) */
-static void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr)
+void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr)
 {
        struct thread_struct *t = &current->thread;
        u64 *vcpu_fpr = vcpu->arch.fpr;
+#ifdef CONFIG_VSX
        u64 *vcpu_vsx = vcpu->arch.vsr;
+#endif
        u64 *thread_fpr = (u64*)t->fpr;
        int i;
 
@@ -629,21 +687,65 @@ static void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr)
        kvmppc_recalc_shadow_msr(vcpu);
 }
 
+static int kvmppc_read_inst(struct kvm_vcpu *vcpu)
+{
+       ulong srr0 = kvmppc_get_pc(vcpu);
+       u32 last_inst = kvmppc_get_last_inst(vcpu);
+       int ret;
+
+       ret = kvmppc_ld(vcpu, &srr0, sizeof(u32), &last_inst, false);
+       if (ret == -ENOENT) {
+               vcpu->arch.msr = kvmppc_set_field(vcpu->arch.msr, 33, 33, 1);
+               vcpu->arch.msr = kvmppc_set_field(vcpu->arch.msr, 34, 36, 0);
+               vcpu->arch.msr = kvmppc_set_field(vcpu->arch.msr, 42, 47, 0);
+               kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_INST_STORAGE);
+               return EMULATE_AGAIN;
+       }
+
+       return EMULATE_DONE;
+}
+
+static int kvmppc_check_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr)
+{
+
+       /* Need to do paired single emulation? */
+       if (!(vcpu->arch.hflags & BOOK3S_HFLAG_PAIRED_SINGLE))
+               return EMULATE_DONE;
+
+       /* Read out the instruction */
+       if (kvmppc_read_inst(vcpu) == EMULATE_DONE)
+               /* Need to emulate */
+               return EMULATE_FAIL;
+
+       return EMULATE_AGAIN;
+}
+
 /* Handle external providers (FPU, Altivec, VSX) */
 static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr,
                             ulong msr)
 {
        struct thread_struct *t = &current->thread;
        u64 *vcpu_fpr = vcpu->arch.fpr;
+#ifdef CONFIG_VSX
        u64 *vcpu_vsx = vcpu->arch.vsr;
+#endif
        u64 *thread_fpr = (u64*)t->fpr;
        int i;
 
+       /* When we have paired singles, we emulate in software */
+       if (vcpu->arch.hflags & BOOK3S_HFLAG_PAIRED_SINGLE)
+               return RESUME_GUEST;
+
        if (!(vcpu->arch.msr & msr)) {
                kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
                return RESUME_GUEST;
        }
 
+       /* We already own the ext */
+       if (vcpu->arch.guest_owned_ext & msr) {
+               return RESUME_GUEST;
+       }
+
 #ifdef DEBUG_EXT
        printk(KERN_INFO "Loading up ext 0x%lx\n", msr);
 #endif
@@ -696,21 +798,33 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
        run->ready_for_interrupt_injection = 1;
 #ifdef EXIT_DEBUG
        printk(KERN_EMERG "exit_nr=0x%x | pc=0x%lx | dar=0x%lx | dec=0x%x | msr=0x%lx\n",
-               exit_nr, vcpu->arch.pc, vcpu->arch.fault_dear,
-               kvmppc_get_dec(vcpu), vcpu->arch.msr);
+               exit_nr, kvmppc_get_pc(vcpu), kvmppc_get_fault_dar(vcpu),
+               kvmppc_get_dec(vcpu), to_svcpu(vcpu)->shadow_srr1);
 #elif defined (EXIT_DEBUG_SIMPLE)
        if ((exit_nr != 0x900) && (exit_nr != 0x500))
                printk(KERN_EMERG "exit_nr=0x%x | pc=0x%lx | dar=0x%lx | msr=0x%lx\n",
-                       exit_nr, vcpu->arch.pc, vcpu->arch.fault_dear,
+                       exit_nr, kvmppc_get_pc(vcpu), kvmppc_get_fault_dar(vcpu),
                        vcpu->arch.msr);
 #endif
        kvm_resched(vcpu);
        switch (exit_nr) {
        case BOOK3S_INTERRUPT_INST_STORAGE:
                vcpu->stat.pf_instruc++;
+
+#ifdef CONFIG_PPC_BOOK3S_32
+               /* We set segments as unused segments when invalidating them. So
+                * treat the respective fault as segment fault. */
+               if (to_svcpu(vcpu)->sr[kvmppc_get_pc(vcpu) >> SID_SHIFT]
+                   == SR_INVALID) {
+                       kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu));
+                       r = RESUME_GUEST;
+                       break;
+               }
+#endif
+
                /* only care about PTEG not found errors, but leave NX alone */
-               if (vcpu->arch.shadow_srr1 & 0x40000000) {
-                       r = kvmppc_handle_pagefault(run, vcpu, vcpu->arch.pc, exit_nr);
+               if (to_svcpu(vcpu)->shadow_srr1 & 0x40000000) {
+                       r = kvmppc_handle_pagefault(run, vcpu, kvmppc_get_pc(vcpu), exit_nr);
                        vcpu->stat.sp_instruc++;
                } else if (vcpu->arch.mmu.is_dcbz32(vcpu) &&
                          (!(vcpu->arch.hflags & BOOK3S_HFLAG_DCBZ32))) {
@@ -719,37 +833,52 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
                         *     so we can't use the NX bit inside the guest. Let's cross our fingers,
                         *     that no guest that needs the dcbz hack does NX.
                         */
-                       kvmppc_mmu_pte_flush(vcpu, vcpu->arch.pc, ~0xFFFULL);
+                       kvmppc_mmu_pte_flush(vcpu, kvmppc_get_pc(vcpu), ~0xFFFUL);
+                       r = RESUME_GUEST;
                } else {
-                       vcpu->arch.msr |= vcpu->arch.shadow_srr1 & 0x58000000;
+                       vcpu->arch.msr |= to_svcpu(vcpu)->shadow_srr1 & 0x58000000;
                        kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
-                       kvmppc_mmu_pte_flush(vcpu, vcpu->arch.pc, ~0xFFFULL);
+                       kvmppc_mmu_pte_flush(vcpu, kvmppc_get_pc(vcpu), ~0xFFFUL);
                        r = RESUME_GUEST;
                }
                break;
        case BOOK3S_INTERRUPT_DATA_STORAGE:
+       {
+               ulong dar = kvmppc_get_fault_dar(vcpu);
                vcpu->stat.pf_storage++;
+
+#ifdef CONFIG_PPC_BOOK3S_32
+               /* We set segments as unused segments when invalidating them. So
+                * treat the respective fault as segment fault. */
+               if ((to_svcpu(vcpu)->sr[dar >> SID_SHIFT]) == SR_INVALID) {
+                       kvmppc_mmu_map_segment(vcpu, dar);
+                       r = RESUME_GUEST;
+                       break;
+               }
+#endif
+
                /* The only case we need to handle is missing shadow PTEs */
-               if (vcpu->arch.fault_dsisr & DSISR_NOHPTE) {
-                       r = kvmppc_handle_pagefault(run, vcpu, vcpu->arch.fault_dear, exit_nr);
+               if (to_svcpu(vcpu)->fault_dsisr & DSISR_NOHPTE) {
+                       r = kvmppc_handle_pagefault(run, vcpu, dar, exit_nr);
                } else {
-                       vcpu->arch.dear = vcpu->arch.fault_dear;
-                       to_book3s(vcpu)->dsisr = vcpu->arch.fault_dsisr;
+                       vcpu->arch.dear = dar;
+                       to_book3s(vcpu)->dsisr = to_svcpu(vcpu)->fault_dsisr;
                        kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
-                       kvmppc_mmu_pte_flush(vcpu, vcpu->arch.dear, ~0xFFFULL);
+                       kvmppc_mmu_pte_flush(vcpu, vcpu->arch.dear, ~0xFFFUL);
                        r = RESUME_GUEST;
                }
                break;
+       }
        case BOOK3S_INTERRUPT_DATA_SEGMENT:
-               if (kvmppc_mmu_map_segment(vcpu, vcpu->arch.fault_dear) < 0) {
-                       vcpu->arch.dear = vcpu->arch.fault_dear;
+               if (kvmppc_mmu_map_segment(vcpu, kvmppc_get_fault_dar(vcpu)) < 0) {
+                       vcpu->arch.dear = kvmppc_get_fault_dar(vcpu);
                        kvmppc_book3s_queue_irqprio(vcpu,
                                BOOK3S_INTERRUPT_DATA_SEGMENT);
                }
                r = RESUME_GUEST;
                break;
        case BOOK3S_INTERRUPT_INST_SEGMENT:
-               if (kvmppc_mmu_map_segment(vcpu, vcpu->arch.pc) < 0) {
+               if (kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu)) < 0) {
                        kvmppc_book3s_queue_irqprio(vcpu,
                                BOOK3S_INTERRUPT_INST_SEGMENT);
                }
@@ -764,18 +893,22 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
                vcpu->stat.ext_intr_exits++;
                r = RESUME_GUEST;
                break;
+       case BOOK3S_INTERRUPT_PERFMON:
+               r = RESUME_GUEST;
+               break;
        case BOOK3S_INTERRUPT_PROGRAM:
        {
                enum emulation_result er;
                ulong flags;
 
-               flags = vcpu->arch.shadow_srr1 & 0x1f0000ull;
+program_interrupt:
+               flags = to_svcpu(vcpu)->shadow_srr1 & 0x1f0000ull;
 
                if (vcpu->arch.msr & MSR_PR) {
 #ifdef EXIT_DEBUG
-                       printk(KERN_INFO "Userspace triggered 0x700 exception at 0x%lx (0x%x)\n", vcpu->arch.pc, vcpu->arch.last_inst);
+                       printk(KERN_INFO "Userspace triggered 0x700 exception at 0x%lx (0x%x)\n", kvmppc_get_pc(vcpu), kvmppc_get_last_inst(vcpu));
 #endif
-                       if ((vcpu->arch.last_inst & 0xff0007ff) !=
+                       if ((kvmppc_get_last_inst(vcpu) & 0xff0007ff) !=
                            (INS_DCBZ & 0xfffffff7)) {
                                kvmppc_core_queue_program(vcpu, flags);
                                r = RESUME_GUEST;
@@ -789,33 +922,80 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
                case EMULATE_DONE:
                        r = RESUME_GUEST_NV;
                        break;
+               case EMULATE_AGAIN:
+                       r = RESUME_GUEST;
+                       break;
                case EMULATE_FAIL:
                        printk(KERN_CRIT "%s: emulation at %lx failed (%08x)\n",
-                              __func__, vcpu->arch.pc, vcpu->arch.last_inst);
+                              __func__, kvmppc_get_pc(vcpu), kvmppc_get_last_inst(vcpu));
                        kvmppc_core_queue_program(vcpu, flags);
                        r = RESUME_GUEST;
                        break;
+               case EMULATE_DO_MMIO:
+                       run->exit_reason = KVM_EXIT_MMIO;
+                       r = RESUME_HOST_NV;
+                       break;
                default:
                        BUG();
                }
                break;
        }
        case BOOK3S_INTERRUPT_SYSCALL:
-#ifdef EXIT_DEBUG
-               printk(KERN_INFO "Syscall Nr %d\n", (int)kvmppc_get_gpr(vcpu, 0));
-#endif
-               vcpu->stat.syscall_exits++;
-               kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
-               r = RESUME_GUEST;
+               // XXX make user settable
+               if (vcpu->arch.osi_enabled &&
+                   (((u32)kvmppc_get_gpr(vcpu, 3)) == OSI_SC_MAGIC_R3) &&
+                   (((u32)kvmppc_get_gpr(vcpu, 4)) == OSI_SC_MAGIC_R4)) {
+                       u64 *gprs = run->osi.gprs;
+                       int i;
+
+                       run->exit_reason = KVM_EXIT_OSI;
+                       for (i = 0; i < 32; i++)
+                               gprs[i] = kvmppc_get_gpr(vcpu, i);
+                       vcpu->arch.osi_needed = 1;
+                       r = RESUME_HOST_NV;
+
+               } else {
+                       vcpu->stat.syscall_exits++;
+                       kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
+                       r = RESUME_GUEST;
+               }
                break;
        case BOOK3S_INTERRUPT_FP_UNAVAIL:
-               r = kvmppc_handle_ext(vcpu, exit_nr, MSR_FP);
-               break;
        case BOOK3S_INTERRUPT_ALTIVEC:
-               r = kvmppc_handle_ext(vcpu, exit_nr, MSR_VEC);
-               break;
        case BOOK3S_INTERRUPT_VSX:
-               r = kvmppc_handle_ext(vcpu, exit_nr, MSR_VSX);
+       {
+               int ext_msr = 0;
+
+               switch (exit_nr) {
+               case BOOK3S_INTERRUPT_FP_UNAVAIL: ext_msr = MSR_FP;  break;
+               case BOOK3S_INTERRUPT_ALTIVEC:    ext_msr = MSR_VEC; break;
+               case BOOK3S_INTERRUPT_VSX:        ext_msr = MSR_VSX; break;
+               }
+
+               switch (kvmppc_check_ext(vcpu, exit_nr)) {
+               case EMULATE_DONE:
+                       /* everything ok - let's enable the ext */
+                       r = kvmppc_handle_ext(vcpu, exit_nr, ext_msr);
+                       break;
+               case EMULATE_FAIL:
+                       /* we need to emulate this instruction */
+                       goto program_interrupt;
+                       break;
+               default:
+                       /* nothing to worry about - go again */
+                       break;
+               }
+               break;
+       }
+       case BOOK3S_INTERRUPT_ALIGNMENT:
+               if (kvmppc_read_inst(vcpu) == EMULATE_DONE) {
+                       to_book3s(vcpu)->dsisr = kvmppc_alignment_dsisr(vcpu,
+                               kvmppc_get_last_inst(vcpu));
+                       vcpu->arch.dear = kvmppc_alignment_dar(vcpu,
+                               kvmppc_get_last_inst(vcpu));
+                       kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
+               }
+               r = RESUME_GUEST;
                break;
        case BOOK3S_INTERRUPT_MACHINE_CHECK:
        case BOOK3S_INTERRUPT_TRACE:
@@ -825,7 +1005,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
        default:
                /* Ugh - bork here! What did we get? */
                printk(KERN_EMERG "exit_nr=0x%x | pc=0x%lx | msr=0x%lx\n",
-                       exit_nr, vcpu->arch.pc, vcpu->arch.shadow_srr1);
+                       exit_nr, kvmppc_get_pc(vcpu), to_svcpu(vcpu)->shadow_srr1);
                r = RESUME_HOST;
                BUG();
                break;
@@ -852,7 +1032,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
        }
 
 #ifdef EXIT_DEBUG
-       printk(KERN_EMERG "KVM exit: vcpu=0x%p pc=0x%lx r=0x%x\n", vcpu, vcpu->arch.pc, r);
+       printk(KERN_EMERG "KVM exit: vcpu=0x%p pc=0x%lx r=0x%x\n", vcpu, kvmppc_get_pc(vcpu), r);
 #endif
 
        return r;
@@ -867,10 +1047,12 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 {
        int i;
 
-       regs->pc = vcpu->arch.pc;
+       vcpu_load(vcpu);
+
+       regs->pc = kvmppc_get_pc(vcpu);
        regs->cr = kvmppc_get_cr(vcpu);
-       regs->ctr = vcpu->arch.ctr;
-       regs->lr = vcpu->arch.lr;
+       regs->ctr = kvmppc_get_ctr(vcpu);
+       regs->lr = kvmppc_get_lr(vcpu);
        regs->xer = kvmppc_get_xer(vcpu);
        regs->msr = vcpu->arch.msr;
        regs->srr0 = vcpu->arch.srr0;
@@ -887,6 +1069,8 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
        for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
                regs->gpr[i] = kvmppc_get_gpr(vcpu, i);
 
+       vcpu_put(vcpu);
+
        return 0;
 }
 
@@ -894,10 +1078,12 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 {
        int i;
 
-       vcpu->arch.pc = regs->pc;
+       vcpu_load(vcpu);
+
+       kvmppc_set_pc(vcpu, regs->pc);
        kvmppc_set_cr(vcpu, regs->cr);
-       vcpu->arch.ctr = regs->ctr;
-       vcpu->arch.lr = regs->lr;
+       kvmppc_set_ctr(vcpu, regs->ctr);
+       kvmppc_set_lr(vcpu, regs->lr);
        kvmppc_set_xer(vcpu, regs->xer);
        kvmppc_set_msr(vcpu, regs->msr);
        vcpu->arch.srr0 = regs->srr0;
@@ -913,6 +1099,8 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
        for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
                kvmppc_set_gpr(vcpu, i, regs->gpr[i]);
 
+       vcpu_put(vcpu);
+
        return 0;
 }
 
@@ -922,6 +1110,8 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
        struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
        int i;
 
+       vcpu_load(vcpu);
+
        sregs->pvr = vcpu->arch.pvr;
 
        sregs->u.s.sdr1 = to_book3s(vcpu)->sdr1;
@@ -940,6 +1130,9 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
                        sregs->u.s.ppc32.dbat[i] = vcpu3s->dbat[i].raw;
                }
        }
+
+       vcpu_put(vcpu);
+
        return 0;
 }
 
@@ -949,6 +1142,8 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
        struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
        int i;
 
+       vcpu_load(vcpu);
+
        kvmppc_set_pvr(vcpu, sregs->pvr);
 
        vcpu3s->sdr1 = sregs->u.s.sdr1;
@@ -975,6 +1170,9 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
 
        /* Flush the MMU after messing with the segments */
        kvmppc_mmu_pte_flush(vcpu, 0, 0);
+
+       vcpu_put(vcpu);
+
        return 0;
 }
 
@@ -1042,24 +1240,33 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
 {
        struct kvmppc_vcpu_book3s *vcpu_book3s;
        struct kvm_vcpu *vcpu;
-       int err;
+       int err = -ENOMEM;
 
-       vcpu_book3s = (struct kvmppc_vcpu_book3s *)__get_free_pages( GFP_KERNEL | __GFP_ZERO,
-                       get_order(sizeof(struct kvmppc_vcpu_book3s)));
-       if (!vcpu_book3s) {
-               err = -ENOMEM;
+       vcpu_book3s = vmalloc(sizeof(struct kvmppc_vcpu_book3s));
+       if (!vcpu_book3s)
                goto out;
-       }
+
+       memset(vcpu_book3s, 0, sizeof(struct kvmppc_vcpu_book3s));
+
+       vcpu_book3s->shadow_vcpu = (struct kvmppc_book3s_shadow_vcpu *)
+               kzalloc(sizeof(*vcpu_book3s->shadow_vcpu), GFP_KERNEL);
+       if (!vcpu_book3s->shadow_vcpu)
+               goto free_vcpu;
 
        vcpu = &vcpu_book3s->vcpu;
        err = kvm_vcpu_init(vcpu, kvm, id);
        if (err)
-               goto free_vcpu;
+               goto free_shadow_vcpu;
 
        vcpu->arch.host_retip = kvm_return_point;
        vcpu->arch.host_msr = mfmsr();
+#ifdef CONFIG_PPC_BOOK3S_64
        /* default to book3s_64 (970fx) */
        vcpu->arch.pvr = 0x3C0301;
+#else
+       /* default to book3s_32 (750) */
+       vcpu->arch.pvr = 0x84202;
+#endif
        kvmppc_set_pvr(vcpu, vcpu->arch.pvr);
        vcpu_book3s->slb_nr = 64;
 
@@ -1067,23 +1274,24 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
        vcpu->arch.trampoline_lowmem = kvmppc_trampoline_lowmem;
        vcpu->arch.trampoline_enter = kvmppc_trampoline_enter;
        vcpu->arch.highmem_handler = (ulong)kvmppc_handler_highmem;
+#ifdef CONFIG_PPC_BOOK3S_64
        vcpu->arch.rmcall = *(ulong*)kvmppc_rmcall;
+#else
+       vcpu->arch.rmcall = (ulong)kvmppc_rmcall;
+#endif
 
        vcpu->arch.shadow_msr = MSR_USER64;
 
-       err = __init_new_context();
+       err = kvmppc_mmu_init(vcpu);
        if (err < 0)
-               goto free_vcpu;
-       vcpu_book3s->context_id = err;
-
-       vcpu_book3s->vsid_max = ((vcpu_book3s->context_id + 1) << USER_ESID_BITS) - 1;
-       vcpu_book3s->vsid_first = vcpu_book3s->context_id << USER_ESID_BITS;
-       vcpu_book3s->vsid_next = vcpu_book3s->vsid_first;
+               goto free_shadow_vcpu;
 
        return vcpu;
 
+free_shadow_vcpu:
+       kfree(vcpu_book3s->shadow_vcpu);
 free_vcpu:
-       free_pages((long)vcpu_book3s, get_order(sizeof(struct kvmppc_vcpu_book3s)));
+       vfree(vcpu_book3s);
 out:
        return ERR_PTR(err);
 }
@@ -1092,9 +1300,9 @@ void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu)
 {
        struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
 
-       __destroy_context(vcpu_book3s->context_id);
        kvm_vcpu_uninit(vcpu);
-       free_pages((long)vcpu_book3s, get_order(sizeof(struct kvmppc_vcpu_book3s)));
+       kfree(vcpu_book3s->shadow_vcpu);
+       vfree(vcpu_book3s);
 }
 
 extern int __kvmppc_vcpu_entry(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu);
@@ -1102,8 +1310,12 @@ int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 {
        int ret;
        struct thread_struct ext_bkp;
+#ifdef CONFIG_ALTIVEC
        bool save_vec = current->thread.used_vr;
+#endif
+#ifdef CONFIG_VSX
        bool save_vsx = current->thread.used_vsr;
+#endif
        ulong ext_msr;
 
        /* No need to go into the guest when all we do is going out */
@@ -1144,6 +1356,10 @@ int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
        /* XXX we get called with irq disabled - change that! */
        local_irq_enable();
 
+       /* Preload FPU if it's enabled */
+       if (vcpu->arch.msr & MSR_FP)
+               kvmppc_handle_ext(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, MSR_FP);
+
        ret = __kvmppc_vcpu_entry(kvm_run, vcpu);
 
        local_irq_disable();
@@ -1179,7 +1395,8 @@ int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 
 static int kvmppc_book3s_init(void)
 {
-       return kvm_init(NULL, sizeof(struct kvmppc_vcpu_book3s), THIS_MODULE);
+       return kvm_init(NULL, sizeof(struct kvmppc_vcpu_book3s), 0,
+                       THIS_MODULE);
 }
 
 static void kvmppc_book3s_exit(void)
index faf99f20d993a89666f7fb2995c40c175be94ca7..0b10503c8a4aac4dfce46c7bf50c4fa017aa0db3 100644 (file)
@@ -37,7 +37,7 @@
 #define dprintk(X...) do { } while(0)
 #endif
 
-#ifdef DEBUG_PTE
+#ifdef DEBUG_MMU_PTE
 #define dprintk_pte(X...) printk(KERN_INFO X)
 #else
 #define dprintk_pte(X...) do { } while(0)
@@ -45,6 +45,9 @@
 
 #define PTEG_FLAG_ACCESSED     0x00000100
 #define PTEG_FLAG_DIRTY                0x00000080
+#ifndef SID_SHIFT
+#define SID_SHIFT              28
+#endif
 
 static inline bool check_debug_ip(struct kvm_vcpu *vcpu)
 {
@@ -57,6 +60,8 @@ static inline bool check_debug_ip(struct kvm_vcpu *vcpu)
 
 static int kvmppc_mmu_book3s_32_xlate_bat(struct kvm_vcpu *vcpu, gva_t eaddr,
                                          struct kvmppc_pte *pte, bool data);
+static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
+                                            u64 *vsid);
 
 static struct kvmppc_sr *find_sr(struct kvmppc_vcpu_book3s *vcpu_book3s, gva_t eaddr)
 {
@@ -66,13 +71,14 @@ static struct kvmppc_sr *find_sr(struct kvmppc_vcpu_book3s *vcpu_book3s, gva_t e
 static u64 kvmppc_mmu_book3s_32_ea_to_vp(struct kvm_vcpu *vcpu, gva_t eaddr,
                                         bool data)
 {
-       struct kvmppc_sr *sre = find_sr(to_book3s(vcpu), eaddr);
+       u64 vsid;
        struct kvmppc_pte pte;
 
        if (!kvmppc_mmu_book3s_32_xlate_bat(vcpu, eaddr, &pte, data))
                return pte.vpage;
 
-       return (((u64)eaddr >> 12) & 0xffff) | (((u64)sre->vsid) << 16);
+       kvmppc_mmu_book3s_32_esid_to_vsid(vcpu, eaddr >> SID_SHIFT, &vsid);
+       return (((u64)eaddr >> 12) & 0xffff) | (vsid << 16);
 }
 
 static void kvmppc_mmu_book3s_32_reset_msr(struct kvm_vcpu *vcpu)
@@ -142,8 +148,13 @@ static int kvmppc_mmu_book3s_32_xlate_bat(struct kvm_vcpu *vcpu, gva_t eaddr,
                                    bat->bepi_mask);
                }
                if ((eaddr & bat->bepi_mask) == bat->bepi) {
+                       u64 vsid;
+                       kvmppc_mmu_book3s_32_esid_to_vsid(vcpu,
+                               eaddr >> SID_SHIFT, &vsid);
+                       vsid <<= 16;
+                       pte->vpage = (((u64)eaddr >> 12) & 0xffff) | vsid;
+
                        pte->raddr = bat->brpn | (eaddr & ~bat->bepi_mask);
-                       pte->vpage = (eaddr >> 12) | VSID_BAT;
                        pte->may_read = bat->pp;
                        pte->may_write = bat->pp > 1;
                        pte->may_execute = true;
@@ -172,7 +183,7 @@ static int kvmppc_mmu_book3s_32_xlate_pte(struct kvm_vcpu *vcpu, gva_t eaddr,
        struct kvmppc_sr *sre;
        hva_t ptegp;
        u32 pteg[16];
-       u64 ptem = 0;
+       u32 ptem = 0;
        int i;
        int found = 0;
 
@@ -302,6 +313,7 @@ static void kvmppc_mmu_book3s_32_mtsrin(struct kvm_vcpu *vcpu, u32 srnum,
        /* And then put in the new SR */
        sre->raw = value;
        sre->vsid = (value & 0x0fffffff);
+       sre->valid = (value & 0x80000000) ? false : true;
        sre->Ks = (value & 0x40000000) ? true : false;
        sre->Kp = (value & 0x20000000) ? true : false;
        sre->nx = (value & 0x10000000) ? true : false;
@@ -312,36 +324,48 @@ static void kvmppc_mmu_book3s_32_mtsrin(struct kvm_vcpu *vcpu, u32 srnum,
 
 static void kvmppc_mmu_book3s_32_tlbie(struct kvm_vcpu *vcpu, ulong ea, bool large)
 {
-       kvmppc_mmu_pte_flush(vcpu, ea, ~0xFFFULL);
+       kvmppc_mmu_pte_flush(vcpu, ea, 0x0FFFF000);
 }
 
-static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, u64 esid,
+static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
                                             u64 *vsid)
 {
+       ulong ea = esid << SID_SHIFT;
+       struct kvmppc_sr *sr;
+       u64 gvsid = esid;
+
+       if (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
+               sr = find_sr(to_book3s(vcpu), ea);
+               if (sr->valid)
+                       gvsid = sr->vsid;
+       }
+
        /* In case we only have one of MSR_IR or MSR_DR set, let's put
           that in the real-mode context (and hope RM doesn't access
           high memory) */
        switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
        case 0:
-               *vsid = (VSID_REAL >> 16) | esid;
+               *vsid = VSID_REAL | esid;
                break;
        case MSR_IR:
-               *vsid = (VSID_REAL_IR >> 16) | esid;
+               *vsid = VSID_REAL_IR | gvsid;
                break;
        case MSR_DR:
-               *vsid = (VSID_REAL_DR >> 16) | esid;
+               *vsid = VSID_REAL_DR | gvsid;
                break;
        case MSR_DR|MSR_IR:
-       {
-               ulong ea;
-               ea = esid << SID_SHIFT;
-               *vsid = find_sr(to_book3s(vcpu), ea)->vsid;
+               if (!sr->valid)
+                       return -1;
+
+               *vsid = sr->vsid;
                break;
-       }
        default:
                BUG();
        }
 
+       if (vcpu->arch.msr & MSR_PR)
+               *vsid |= VSID_PR;
+
        return 0;
 }
 
diff --git a/arch/powerpc/kvm/book3s_32_mmu_host.c b/arch/powerpc/kvm/book3s_32_mmu_host.c
new file mode 100644 (file)
index 0000000..0bb6600
--- /dev/null
@@ -0,0 +1,483 @@
+/*
+ * Copyright (C) 2010 SUSE Linux Products GmbH. All rights reserved.
+ *
+ * Authors:
+ *     Alexander Graf <agraf@suse.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.
+ *
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/kvm_host.h>
+
+#include <asm/kvm_ppc.h>
+#include <asm/kvm_book3s.h>
+#include <asm/mmu-hash32.h>
+#include <asm/machdep.h>
+#include <asm/mmu_context.h>
+#include <asm/hw_irq.h>
+
+/* #define DEBUG_MMU */
+/* #define DEBUG_SR */
+
+#ifdef DEBUG_MMU
+#define dprintk_mmu(a, ...) printk(KERN_INFO a, __VA_ARGS__)
+#else
+#define dprintk_mmu(a, ...) do { } while(0)
+#endif
+
+#ifdef DEBUG_SR
+#define dprintk_sr(a, ...) printk(KERN_INFO a, __VA_ARGS__)
+#else
+#define dprintk_sr(a, ...) do { } while(0)
+#endif
+
+#if PAGE_SHIFT != 12
+#error Unknown page size
+#endif
+
+#ifdef CONFIG_SMP
+#error XXX need to grab mmu_hash_lock
+#endif
+
+#ifdef CONFIG_PTE_64BIT
+#error Only 32 bit pages are supported for now
+#endif
+
+static ulong htab;
+static u32 htabmask;
+
+static void invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
+{
+       volatile u32 *pteg;
+
+       dprintk_mmu("KVM: Flushing SPTE: 0x%llx (0x%llx) -> 0x%llx\n",
+                   pte->pte.eaddr, pte->pte.vpage, pte->host_va);
+
+       pteg = (u32*)pte->slot;
+
+       pteg[0] = 0;
+       asm volatile ("sync");
+       asm volatile ("tlbie %0" : : "r" (pte->pte.eaddr) : "memory");
+       asm volatile ("sync");
+       asm volatile ("tlbsync");
+
+       pte->host_va = 0;
+
+       if (pte->pte.may_write)
+               kvm_release_pfn_dirty(pte->pfn);
+       else
+               kvm_release_pfn_clean(pte->pfn);
+}
+
+void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask)
+{
+       int i;
+
+       dprintk_mmu("KVM: Flushing %d Shadow PTEs: 0x%x & 0x%x\n",
+                   vcpu->arch.hpte_cache_offset, guest_ea, ea_mask);
+       BUG_ON(vcpu->arch.hpte_cache_offset > HPTEG_CACHE_NUM);
+
+       guest_ea &= ea_mask;
+       for (i = 0; i < vcpu->arch.hpte_cache_offset; i++) {
+               struct hpte_cache *pte;
+
+               pte = &vcpu->arch.hpte_cache[i];
+               if (!pte->host_va)
+                       continue;
+
+               if ((pte->pte.eaddr & ea_mask) == guest_ea) {
+                       invalidate_pte(vcpu, pte);
+               }
+       }
+
+       /* Doing a complete flush -> start from scratch */
+       if (!ea_mask)
+               vcpu->arch.hpte_cache_offset = 0;
+}
+
+void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 guest_vp, u64 vp_mask)
+{
+       int i;
+
+       dprintk_mmu("KVM: Flushing %d Shadow vPTEs: 0x%llx & 0x%llx\n",
+                   vcpu->arch.hpte_cache_offset, guest_vp, vp_mask);
+       BUG_ON(vcpu->arch.hpte_cache_offset > HPTEG_CACHE_NUM);
+
+       guest_vp &= vp_mask;
+       for (i = 0; i < vcpu->arch.hpte_cache_offset; i++) {
+               struct hpte_cache *pte;
+
+               pte = &vcpu->arch.hpte_cache[i];
+               if (!pte->host_va)
+                       continue;
+
+               if ((pte->pte.vpage & vp_mask) == guest_vp) {
+                       invalidate_pte(vcpu, pte);
+               }
+       }
+}
+
+void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end)
+{
+       int i;
+
+       dprintk_mmu("KVM: Flushing %d Shadow pPTEs: 0x%llx & 0x%llx\n",
+                   vcpu->arch.hpte_cache_offset, pa_start, pa_end);
+       BUG_ON(vcpu->arch.hpte_cache_offset > HPTEG_CACHE_NUM);
+
+       for (i = 0; i < vcpu->arch.hpte_cache_offset; i++) {
+               struct hpte_cache *pte;
+
+               pte = &vcpu->arch.hpte_cache[i];
+               if (!pte->host_va)
+                       continue;
+
+               if ((pte->pte.raddr >= pa_start) &&
+                   (pte->pte.raddr < pa_end)) {
+                       invalidate_pte(vcpu, pte);
+               }
+       }
+}
+
+struct kvmppc_pte *kvmppc_mmu_find_pte(struct kvm_vcpu *vcpu, u64 ea, bool data)
+{
+       int i;
+       u64 guest_vp;
+
+       guest_vp = vcpu->arch.mmu.ea_to_vp(vcpu, ea, false);
+       for (i=0; i<vcpu->arch.hpte_cache_offset; i++) {
+               struct hpte_cache *pte;
+
+               pte = &vcpu->arch.hpte_cache[i];
+               if (!pte->host_va)
+                       continue;
+
+               if (pte->pte.vpage == guest_vp)
+                       return &pte->pte;
+       }
+
+       return NULL;
+}
+
+static int kvmppc_mmu_hpte_cache_next(struct kvm_vcpu *vcpu)
+{
+       if (vcpu->arch.hpte_cache_offset == HPTEG_CACHE_NUM)
+               kvmppc_mmu_pte_flush(vcpu, 0, 0);
+
+       return vcpu->arch.hpte_cache_offset++;
+}
+
+/* We keep 512 gvsid->hvsid entries, mapping the guest ones to the array using
+ * a hash, so we don't waste cycles on looping */
+static u16 kvmppc_sid_hash(struct kvm_vcpu *vcpu, u64 gvsid)
+{
+       return (u16)(((gvsid >> (SID_MAP_BITS * 7)) & SID_MAP_MASK) ^
+                    ((gvsid >> (SID_MAP_BITS * 6)) & SID_MAP_MASK) ^
+                    ((gvsid >> (SID_MAP_BITS * 5)) & SID_MAP_MASK) ^
+                    ((gvsid >> (SID_MAP_BITS * 4)) & SID_MAP_MASK) ^
+                    ((gvsid >> (SID_MAP_BITS * 3)) & SID_MAP_MASK) ^
+                    ((gvsid >> (SID_MAP_BITS * 2)) & SID_MAP_MASK) ^
+                    ((gvsid >> (SID_MAP_BITS * 1)) & SID_MAP_MASK) ^
+                    ((gvsid >> (SID_MAP_BITS * 0)) & SID_MAP_MASK));
+}
+
+
+static struct kvmppc_sid_map *find_sid_vsid(struct kvm_vcpu *vcpu, u64 gvsid)
+{
+       struct kvmppc_sid_map *map;
+       u16 sid_map_mask;
+
+       if (vcpu->arch.msr & MSR_PR)
+               gvsid |= VSID_PR;
+
+       sid_map_mask = kvmppc_sid_hash(vcpu, gvsid);
+       map = &to_book3s(vcpu)->sid_map[sid_map_mask];
+       if (map->guest_vsid == gvsid) {
+               dprintk_sr("SR: Searching 0x%llx -> 0x%llx\n",
+                           gvsid, map->host_vsid);
+               return map;
+       }
+
+       map = &to_book3s(vcpu)->sid_map[SID_MAP_MASK - sid_map_mask];
+       if (map->guest_vsid == gvsid) {
+               dprintk_sr("SR: Searching 0x%llx -> 0x%llx\n",
+                           gvsid, map->host_vsid);
+               return map;
+       }
+
+       dprintk_sr("SR: Searching 0x%llx -> not found\n", gvsid);
+       return NULL;
+}
+
+static u32 *kvmppc_mmu_get_pteg(struct kvm_vcpu *vcpu, u32 vsid, u32 eaddr,
+                               bool primary)
+{
+       u32 page, hash;
+       ulong pteg = htab;
+
+       page = (eaddr & ~ESID_MASK) >> 12;
+
+       hash = ((vsid ^ page) << 6);
+       if (!primary)
+               hash = ~hash;
+
+       hash &= htabmask;
+
+       pteg |= hash;
+
+       dprintk_mmu("htab: %lx | hash: %x | htabmask: %x | pteg: %lx\n",
+               htab, hash, htabmask, pteg);
+
+       return (u32*)pteg;
+}
+
+extern char etext[];
+
+int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte)
+{
+       pfn_t hpaddr;
+       u64 va;
+       u64 vsid;
+       struct kvmppc_sid_map *map;
+       volatile u32 *pteg;
+       u32 eaddr = orig_pte->eaddr;
+       u32 pteg0, pteg1;
+       register int rr = 0;
+       bool primary = false;
+       bool evict = false;
+       int hpte_id;
+       struct hpte_cache *pte;
+
+       /* Get host physical address for gpa */
+       hpaddr = gfn_to_pfn(vcpu->kvm, orig_pte->raddr >> PAGE_SHIFT);
+       if (kvm_is_error_hva(hpaddr)) {
+               printk(KERN_INFO "Couldn't get guest page for gfn %lx!\n",
+                                orig_pte->eaddr);
+               return -EINVAL;
+       }
+       hpaddr <<= PAGE_SHIFT;
+
+       /* and write the mapping ea -> hpa into the pt */
+       vcpu->arch.mmu.esid_to_vsid(vcpu, orig_pte->eaddr >> SID_SHIFT, &vsid);
+       map = find_sid_vsid(vcpu, vsid);
+       if (!map) {
+               kvmppc_mmu_map_segment(vcpu, eaddr);
+               map = find_sid_vsid(vcpu, vsid);
+       }
+       BUG_ON(!map);
+
+       vsid = map->host_vsid;
+       va = (vsid << SID_SHIFT) | (eaddr & ~ESID_MASK);
+
+next_pteg:
+       if (rr == 16) {
+               primary = !primary;
+               evict = true;
+               rr = 0;
+       }
+
+       pteg = kvmppc_mmu_get_pteg(vcpu, vsid, eaddr, primary);
+
+       /* not evicting yet */
+       if (!evict && (pteg[rr] & PTE_V)) {
+               rr += 2;
+               goto next_pteg;
+       }
+
+       dprintk_mmu("KVM: old PTEG: %p (%d)\n", pteg, rr);
+       dprintk_mmu("KVM:   %08x - %08x\n", pteg[0], pteg[1]);
+       dprintk_mmu("KVM:   %08x - %08x\n", pteg[2], pteg[3]);
+       dprintk_mmu("KVM:   %08x - %08x\n", pteg[4], pteg[5]);
+       dprintk_mmu("KVM:   %08x - %08x\n", pteg[6], pteg[7]);
+       dprintk_mmu("KVM:   %08x - %08x\n", pteg[8], pteg[9]);
+       dprintk_mmu("KVM:   %08x - %08x\n", pteg[10], pteg[11]);
+       dprintk_mmu("KVM:   %08x - %08x\n", pteg[12], pteg[13]);
+       dprintk_mmu("KVM:   %08x - %08x\n", pteg[14], pteg[15]);
+
+       pteg0 = ((eaddr & 0x0fffffff) >> 22) | (vsid << 7) | PTE_V |
+               (primary ? 0 : PTE_SEC);
+       pteg1 = hpaddr | PTE_M | PTE_R | PTE_C;
+
+       if (orig_pte->may_write) {
+               pteg1 |= PP_RWRW;
+               mark_page_dirty(vcpu->kvm, orig_pte->raddr >> PAGE_SHIFT);
+       } else {
+               pteg1 |= PP_RWRX;
+       }
+
+       local_irq_disable();
+
+       if (pteg[rr]) {
+               pteg[rr] = 0;
+               asm volatile ("sync");
+       }
+       pteg[rr + 1] = pteg1;
+       pteg[rr] = pteg0;
+       asm volatile ("sync");
+
+       local_irq_enable();
+
+       dprintk_mmu("KVM: new PTEG: %p\n", pteg);
+       dprintk_mmu("KVM:   %08x - %08x\n", pteg[0], pteg[1]);
+       dprintk_mmu("KVM:   %08x - %08x\n", pteg[2], pteg[3]);
+       dprintk_mmu("KVM:   %08x - %08x\n", pteg[4], pteg[5]);
+       dprintk_mmu("KVM:   %08x - %08x\n", pteg[6], pteg[7]);
+       dprintk_mmu("KVM:   %08x - %08x\n", pteg[8], pteg[9]);
+       dprintk_mmu("KVM:   %08x - %08x\n", pteg[10], pteg[11]);
+       dprintk_mmu("KVM:   %08x - %08x\n", pteg[12], pteg[13]);
+       dprintk_mmu("KVM:   %08x - %08x\n", pteg[14], pteg[15]);
+
+
+       /* Now tell our Shadow PTE code about the new page */
+
+       hpte_id = kvmppc_mmu_hpte_cache_next(vcpu);
+       pte = &vcpu->arch.hpte_cache[hpte_id];
+
+       dprintk_mmu("KVM: %c%c Map 0x%llx: [%lx] 0x%llx (0x%llx) -> %lx\n",
+                   orig_pte->may_write ? 'w' : '-',
+                   orig_pte->may_execute ? 'x' : '-',
+                   orig_pte->eaddr, (ulong)pteg, va,
+                   orig_pte->vpage, hpaddr);
+
+       pte->slot = (ulong)&pteg[rr];
+       pte->host_va = va;
+       pte->pte = *orig_pte;
+       pte->pfn = hpaddr >> PAGE_SHIFT;
+
+       return 0;
+}
+
+static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid)
+{
+       struct kvmppc_sid_map *map;
+       struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
+       u16 sid_map_mask;
+       static int backwards_map = 0;
+
+       if (vcpu->arch.msr & MSR_PR)
+               gvsid |= VSID_PR;
+
+       /* We might get collisions that trap in preceding order, so let's
+          map them differently */
+
+       sid_map_mask = kvmppc_sid_hash(vcpu, gvsid);
+       if (backwards_map)
+               sid_map_mask = SID_MAP_MASK - sid_map_mask;
+
+       map = &to_book3s(vcpu)->sid_map[sid_map_mask];
+
+       /* Make sure we're taking the other map next time */
+       backwards_map = !backwards_map;
+
+       /* Uh-oh ... out of mappings. Let's flush! */
+       if (vcpu_book3s->vsid_next >= vcpu_book3s->vsid_max) {
+               vcpu_book3s->vsid_next = vcpu_book3s->vsid_first;
+               memset(vcpu_book3s->sid_map, 0,
+                      sizeof(struct kvmppc_sid_map) * SID_MAP_NUM);
+               kvmppc_mmu_pte_flush(vcpu, 0, 0);
+               kvmppc_mmu_flush_segments(vcpu);
+       }
+       map->host_vsid = vcpu_book3s->vsid_next;
+
+       /* Would have to be 111 to be completely aligned with the rest of
+          Linux, but that is just way too little space! */
+       vcpu_book3s->vsid_next+=1;
+
+       map->guest_vsid = gvsid;
+       map->valid = true;
+
+       return map;
+}
+
+int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr)
+{
+       u32 esid = eaddr >> SID_SHIFT;
+       u64 gvsid;
+       u32 sr;
+       struct kvmppc_sid_map *map;
+       struct kvmppc_book3s_shadow_vcpu *svcpu = to_svcpu(vcpu);
+
+       if (vcpu->arch.mmu.esid_to_vsid(vcpu, esid, &gvsid)) {
+               /* Invalidate an entry */
+               svcpu->sr[esid] = SR_INVALID;
+               return -ENOENT;
+       }
+
+       map = find_sid_vsid(vcpu, gvsid);
+       if (!map)
+               map = create_sid_map(vcpu, gvsid);
+
+       map->guest_esid = esid;
+       sr = map->host_vsid | SR_KP;
+       svcpu->sr[esid] = sr;
+
+       dprintk_sr("MMU: mtsr %d, 0x%x\n", esid, sr);
+
+       return 0;
+}
+
+void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu)
+{
+       int i;
+       struct kvmppc_book3s_shadow_vcpu *svcpu = to_svcpu(vcpu);
+
+       dprintk_sr("MMU: flushing all segments (%d)\n", ARRAY_SIZE(svcpu->sr));
+       for (i = 0; i < ARRAY_SIZE(svcpu->sr); i++)
+               svcpu->sr[i] = SR_INVALID;
+}
+
+void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu)
+{
+       kvmppc_mmu_pte_flush(vcpu, 0, 0);
+       preempt_disable();
+       __destroy_context(to_book3s(vcpu)->context_id);
+       preempt_enable();
+}
+
+/* From mm/mmu_context_hash32.c */
+#define CTX_TO_VSID(ctx) (((ctx) * (897 * 16)) & 0xffffff)
+
+int kvmppc_mmu_init(struct kvm_vcpu *vcpu)
+{
+       struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
+       int err;
+       ulong sdr1;
+
+       err = __init_new_context();
+       if (err < 0)
+               return -1;
+       vcpu3s->context_id = err;
+
+       vcpu3s->vsid_max = CTX_TO_VSID(vcpu3s->context_id + 1) - 1;
+       vcpu3s->vsid_first = CTX_TO_VSID(vcpu3s->context_id);
+
+#if 0 /* XXX still doesn't guarantee uniqueness */
+       /* We could collide with the Linux vsid space because the vsid
+        * wraps around at 24 bits. We're safe if we do our own space
+        * though, so let's always set the highest bit. */
+
+       vcpu3s->vsid_max |= 0x00800000;
+       vcpu3s->vsid_first |= 0x00800000;
+#endif
+       BUG_ON(vcpu3s->vsid_max < vcpu3s->vsid_first);
+
+       vcpu3s->vsid_next = vcpu3s->vsid_first;
+
+       /* Remember where the HTAB is */
+       asm ( "mfsdr1 %0" : "=r"(sdr1) );
+       htabmask = ((sdr1 & 0x1FF) << 16) | 0xFFC0;
+       htab = (ulong)__va(sdr1 & 0xffff0000);
+
+       return 0;
+}
diff --git a/arch/powerpc/kvm/book3s_32_sr.S b/arch/powerpc/kvm/book3s_32_sr.S
new file mode 100644 (file)
index 0000000..3608471
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright SUSE Linux Products GmbH 2009
+ *
+ * Authors: Alexander Graf <agraf@suse.de>
+ */
+
+/******************************************************************************
+ *                                                                            *
+ *                               Entry code                                   *
+ *                                                                            *
+ *****************************************************************************/
+
+.macro LOAD_GUEST_SEGMENTS
+
+       /* Required state:
+        *
+        * MSR = ~IR|DR
+        * R1 = host R1
+        * R2 = host R2
+        * R3 = shadow vcpu
+        * all other volatile GPRS = free
+        * SVCPU[CR]  = guest CR
+        * SVCPU[XER] = guest XER
+        * SVCPU[CTR] = guest CTR
+        * SVCPU[LR]  = guest LR
+        */
+
+#define XCHG_SR(n)     lwz     r9, (SVCPU_SR+(n*4))(r3);  \
+                       mtsr    n, r9
+
+       XCHG_SR(0)
+       XCHG_SR(1)
+       XCHG_SR(2)
+       XCHG_SR(3)
+       XCHG_SR(4)
+       XCHG_SR(5)
+       XCHG_SR(6)
+       XCHG_SR(7)
+       XCHG_SR(8)
+       XCHG_SR(9)
+       XCHG_SR(10)
+       XCHG_SR(11)
+       XCHG_SR(12)
+       XCHG_SR(13)
+       XCHG_SR(14)
+       XCHG_SR(15)
+
+       /* Clear BATs. */
+
+#define KVM_KILL_BAT(n, reg)           \
+        mtspr   SPRN_IBAT##n##U,reg;   \
+        mtspr   SPRN_IBAT##n##L,reg;   \
+        mtspr   SPRN_DBAT##n##U,reg;   \
+        mtspr   SPRN_DBAT##n##L,reg;   \
+
+        li     r9, 0
+       KVM_KILL_BAT(0, r9)
+       KVM_KILL_BAT(1, r9)
+       KVM_KILL_BAT(2, r9)
+       KVM_KILL_BAT(3, r9)
+
+.endm
+
+/******************************************************************************
+ *                                                                            *
+ *                               Exit code                                    *
+ *                                                                            *
+ *****************************************************************************/
+
+.macro LOAD_HOST_SEGMENTS
+
+       /* Register usage at this point:
+        *
+        * R1         = host R1
+        * R2         = host R2
+        * R12        = exit handler id
+        * R13        = shadow vcpu - SHADOW_VCPU_OFF
+        * SVCPU.*    = guest *
+        * SVCPU[CR]  = guest CR
+        * SVCPU[XER] = guest XER
+        * SVCPU[CTR] = guest CTR
+        * SVCPU[LR]  = guest LR
+        *
+        */
+
+       /* Restore BATs */
+
+       /* We only overwrite the upper part, so we only restoree
+          the upper part. */
+#define KVM_LOAD_BAT(n, reg, RA, RB)   \
+       lwz     RA,(n*16)+0(reg);       \
+       lwz     RB,(n*16)+4(reg);       \
+       mtspr   SPRN_IBAT##n##U,RA;     \
+       mtspr   SPRN_IBAT##n##L,RB;     \
+       lwz     RA,(n*16)+8(reg);       \
+       lwz     RB,(n*16)+12(reg);      \
+       mtspr   SPRN_DBAT##n##U,RA;     \
+       mtspr   SPRN_DBAT##n##L,RB;     \
+
+       lis     r9, BATS@ha
+       addi    r9, r9, BATS@l
+       tophys(r9, r9)
+       KVM_LOAD_BAT(0, r9, r10, r11)
+       KVM_LOAD_BAT(1, r9, r10, r11)
+       KVM_LOAD_BAT(2, r9, r10, r11)
+       KVM_LOAD_BAT(3, r9, r10, r11)
+
+       /* Restore Segment Registers */
+
+       /* 0xc - 0xf */
+
+        li      r0, 4
+        mtctr   r0
+       LOAD_REG_IMMEDIATE(r3, 0x20000000 | (0x111 * 0xc))
+        lis     r4, 0xc000
+3:      mtsrin  r3, r4
+        addi    r3, r3, 0x111     /* increment VSID */
+        addis   r4, r4, 0x1000    /* address of next segment */
+        bdnz    3b
+
+       /* 0x0 - 0xb */
+
+       /* 'current->mm' needs to be in r4 */
+       tophys(r4, r2)
+       lwz     r4, MM(r4)
+       tophys(r4, r4)
+       /* This only clobbers r0, r3, r4 and r5 */
+       bl      switch_mmu_context
+
+.endm
index 512dcff77554aa6d76bd3b432b2b1aa0cdb7cd93..4025ea26b3c1df7c8f27dd38e1ddddc1087b38ed 100644 (file)
@@ -232,7 +232,7 @@ do_second:
                        }
 
                        dprintk("KVM MMU: Translated 0x%lx [0x%llx] -> 0x%llx "
-                               "-> 0x%llx\n",
+                               "-> 0x%lx\n",
                                eaddr, avpn, gpte->vpage, gpte->raddr);
                        found = true;
                        break;
@@ -383,7 +383,7 @@ static void kvmppc_mmu_book3s_64_slbia(struct kvm_vcpu *vcpu)
 
        if (vcpu->arch.msr & MSR_IR) {
                kvmppc_mmu_flush_segments(vcpu);
-               kvmppc_mmu_map_segment(vcpu, vcpu->arch.pc);
+               kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu));
        }
 }
 
@@ -439,37 +439,43 @@ static void kvmppc_mmu_book3s_64_tlbie(struct kvm_vcpu *vcpu, ulong va,
        kvmppc_mmu_pte_vflush(vcpu, va >> 12, mask);
 }
 
-static int kvmppc_mmu_book3s_64_esid_to_vsid(struct kvm_vcpu *vcpu, u64 esid,
+static int kvmppc_mmu_book3s_64_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
                                             u64 *vsid)
 {
+       ulong ea = esid << SID_SHIFT;
+       struct kvmppc_slb *slb;
+       u64 gvsid = esid;
+
+       if (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
+               slb = kvmppc_mmu_book3s_64_find_slbe(to_book3s(vcpu), ea);
+               if (slb)
+                       gvsid = slb->vsid;
+       }
+
        switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
        case 0:
-               *vsid = (VSID_REAL >> 16) | esid;
+               *vsid = VSID_REAL | esid;
                break;
        case MSR_IR:
-               *vsid = (VSID_REAL_IR >> 16) | esid;
+               *vsid = VSID_REAL_IR | gvsid;
                break;
        case MSR_DR:
-               *vsid = (VSID_REAL_DR >> 16) | esid;
+               *vsid = VSID_REAL_DR | gvsid;
                break;
        case MSR_DR|MSR_IR:
-       {
-               ulong ea;
-               struct kvmppc_slb *slb;
-               ea = esid << SID_SHIFT;
-               slb = kvmppc_mmu_book3s_64_find_slbe(to_book3s(vcpu), ea);
-               if (slb)
-                       *vsid = slb->vsid;
-               else
+               if (!slb)
                        return -ENOENT;
 
+               *vsid = gvsid;
                break;
-       }
        default:
                BUG();
                break;
        }
 
+       if (vcpu->arch.msr & MSR_PR)
+               *vsid |= VSID_PR;
+
        return 0;
 }
 
index f2899b297ffdc79181e82cfdc333261ec67df0c6..e4b5744977f6a4ad89c2a20653cef70b1286bbfb 100644 (file)
 
 static void invalidate_pte(struct hpte_cache *pte)
 {
-       dprintk_mmu("KVM: Flushing SPT %d: 0x%llx (0x%llx) -> 0x%llx\n",
-                   i, pte->pte.eaddr, pte->pte.vpage, pte->host_va);
+       dprintk_mmu("KVM: Flushing SPT: 0x%lx (0x%llx) -> 0x%llx\n",
+                   pte->pte.eaddr, pte->pte.vpage, pte->host_va);
 
        ppc_md.hpte_invalidate(pte->slot, pte->host_va,
                               MMU_PAGE_4K, MMU_SEGSIZE_256M,
                               false);
        pte->host_va = 0;
-       kvm_release_pfn_dirty(pte->pfn);
+
+       if (pte->pte.may_write)
+               kvm_release_pfn_dirty(pte->pfn);
+       else
+               kvm_release_pfn_clean(pte->pfn);
 }
 
-void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, u64 guest_ea, u64 ea_mask)
+void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask)
 {
        int i;
 
-       dprintk_mmu("KVM: Flushing %d Shadow PTEs: 0x%llx & 0x%llx\n",
+       dprintk_mmu("KVM: Flushing %d Shadow PTEs: 0x%lx & 0x%lx\n",
                    vcpu->arch.hpte_cache_offset, guest_ea, ea_mask);
        BUG_ON(vcpu->arch.hpte_cache_offset > HPTEG_CACHE_NUM);
 
@@ -106,12 +110,12 @@ void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 guest_vp, u64 vp_mask)
        }
 }
 
-void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, u64 pa_start, u64 pa_end)
+void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end)
 {
        int i;
 
-       dprintk_mmu("KVM: Flushing %d Shadow pPTEs: 0x%llx & 0x%llx\n",
-                   vcpu->arch.hpte_cache_offset, guest_pa, pa_mask);
+       dprintk_mmu("KVM: Flushing %d Shadow pPTEs: 0x%lx & 0x%lx\n",
+                   vcpu->arch.hpte_cache_offset, pa_start, pa_end);
        BUG_ON(vcpu->arch.hpte_cache_offset > HPTEG_CACHE_NUM);
 
        for (i = 0; i < vcpu->arch.hpte_cache_offset; i++) {
@@ -182,7 +186,7 @@ static struct kvmppc_sid_map *find_sid_vsid(struct kvm_vcpu *vcpu, u64 gvsid)
        sid_map_mask = kvmppc_sid_hash(vcpu, gvsid);
        map = &to_book3s(vcpu)->sid_map[sid_map_mask];
        if (map->guest_vsid == gvsid) {
-               dprintk_slb("SLB: Searching 0x%llx -> 0x%llx\n",
+               dprintk_slb("SLB: Searching: 0x%llx -> 0x%llx\n",
                            gvsid, map->host_vsid);
                return map;
        }
@@ -194,7 +198,8 @@ static struct kvmppc_sid_map *find_sid_vsid(struct kvm_vcpu *vcpu, u64 gvsid)
                return map;
        }
 
-       dprintk_slb("SLB: Searching 0x%llx -> not found\n", gvsid);
+       dprintk_slb("SLB: Searching %d/%d: 0x%llx -> not found\n",
+                   sid_map_mask, SID_MAP_MASK - sid_map_mask, gvsid);
        return NULL;
 }
 
@@ -212,7 +217,7 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte)
        /* Get host physical address for gpa */
        hpaddr = gfn_to_pfn(vcpu->kvm, orig_pte->raddr >> PAGE_SHIFT);
        if (kvm_is_error_hva(hpaddr)) {
-               printk(KERN_INFO "Couldn't get guest page for gfn %llx!\n", orig_pte->eaddr);
+               printk(KERN_INFO "Couldn't get guest page for gfn %lx!\n", orig_pte->eaddr);
                return -EINVAL;
        }
        hpaddr <<= PAGE_SHIFT;
@@ -227,10 +232,16 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte)
        vcpu->arch.mmu.esid_to_vsid(vcpu, orig_pte->eaddr >> SID_SHIFT, &vsid);
        map = find_sid_vsid(vcpu, vsid);
        if (!map) {
-               kvmppc_mmu_map_segment(vcpu, orig_pte->eaddr);
+               ret = kvmppc_mmu_map_segment(vcpu, orig_pte->eaddr);
+               WARN_ON(ret < 0);
                map = find_sid_vsid(vcpu, vsid);
        }
-       BUG_ON(!map);
+       if (!map) {
+               printk(KERN_ERR "KVM: Segment map for 0x%llx (0x%lx) failed\n",
+                               vsid, orig_pte->eaddr);
+               WARN_ON(true);
+               return -EINVAL;
+       }
 
        vsid = map->host_vsid;
        va = hpt_va(orig_pte->eaddr, vsid, MMU_SEGSIZE_256M);
@@ -257,26 +268,26 @@ map_again:
 
        if (ret < 0) {
                /* If we couldn't map a primary PTE, try a secondary */
-#ifdef USE_SECONDARY
                hash = ~hash;
+               vflags ^= HPTE_V_SECONDARY;
                attempt++;
-               if (attempt % 2)
-                       vflags = HPTE_V_SECONDARY;
-               else
-                       vflags = 0;
-#else
-               attempt = 2;
-#endif
                goto map_again;
        } else {
                int hpte_id = kvmppc_mmu_hpte_cache_next(vcpu);
                struct hpte_cache *pte = &vcpu->arch.hpte_cache[hpte_id];
 
-               dprintk_mmu("KVM: %c%c Map 0x%llx: [%lx] 0x%lx (0x%llx) -> %lx\n",
+               dprintk_mmu("KVM: %c%c Map 0x%lx: [%lx] 0x%lx (0x%llx) -> %lx\n",
                            ((rflags & HPTE_R_PP) == 3) ? '-' : 'w',
                            (rflags & HPTE_R_N) ? '-' : 'x',
                            orig_pte->eaddr, hpteg, va, orig_pte->vpage, hpaddr);
 
+               /* The ppc_md code may give us a secondary entry even though we
+                  asked for a primary. Fix up. */
+               if ((ret & _PTEIDX_SECONDARY) && !(vflags & HPTE_V_SECONDARY)) {
+                       hash = ~hash;
+                       hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP);
+               }
+
                pte->slot = hpteg + (ret & 7);
                pte->host_va = va;
                pte->pte = *orig_pte;
@@ -321,6 +332,9 @@ static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid)
        map->guest_vsid = gvsid;
        map->valid = true;
 
+       dprintk_slb("SLB: New mapping at %d: 0x%llx -> 0x%llx\n",
+                   sid_map_mask, gvsid, map->host_vsid);
+
        return map;
 }
 
@@ -331,14 +345,14 @@ static int kvmppc_mmu_next_segment(struct kvm_vcpu *vcpu, ulong esid)
        int found_inval = -1;
        int r;
 
-       if (!get_paca()->kvm_slb_max)
-               get_paca()->kvm_slb_max = 1;
+       if (!to_svcpu(vcpu)->slb_max)
+               to_svcpu(vcpu)->slb_max = 1;
 
        /* Are we overwriting? */
-       for (i = 1; i < get_paca()->kvm_slb_max; i++) {
-               if (!(get_paca()->kvm_slb[i].esid & SLB_ESID_V))
+       for (i = 1; i < to_svcpu(vcpu)->slb_max; i++) {
+               if (!(to_svcpu(vcpu)->slb[i].esid & SLB_ESID_V))
                        found_inval = i;
-               else if ((get_paca()->kvm_slb[i].esid & ESID_MASK) == esid)
+               else if ((to_svcpu(vcpu)->slb[i].esid & ESID_MASK) == esid)
                        return i;
        }
 
@@ -352,11 +366,11 @@ static int kvmppc_mmu_next_segment(struct kvm_vcpu *vcpu, ulong esid)
                max_slb_size = mmu_slb_size;
 
        /* Overflowing -> purge */
-       if ((get_paca()->kvm_slb_max) == max_slb_size)
+       if ((to_svcpu(vcpu)->slb_max) == max_slb_size)
                kvmppc_mmu_flush_segments(vcpu);
 
-       r = get_paca()->kvm_slb_max;
-       get_paca()->kvm_slb_max++;
+       r = to_svcpu(vcpu)->slb_max;
+       to_svcpu(vcpu)->slb_max++;
 
        return r;
 }
@@ -374,7 +388,7 @@ int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr)
 
        if (vcpu->arch.mmu.esid_to_vsid(vcpu, esid, &gvsid)) {
                /* Invalidate an entry */
-               get_paca()->kvm_slb[slb_index].esid = 0;
+               to_svcpu(vcpu)->slb[slb_index].esid = 0;
                return -ENOENT;
        }
 
@@ -388,8 +402,8 @@ int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr)
        slb_vsid &= ~SLB_VSID_KP;
        slb_esid |= slb_index;
 
-       get_paca()->kvm_slb[slb_index].esid = slb_esid;
-       get_paca()->kvm_slb[slb_index].vsid = slb_vsid;
+       to_svcpu(vcpu)->slb[slb_index].esid = slb_esid;
+       to_svcpu(vcpu)->slb[slb_index].vsid = slb_vsid;
 
        dprintk_slb("slbmte %#llx, %#llx\n", slb_vsid, slb_esid);
 
@@ -398,11 +412,29 @@ int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr)
 
 void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu)
 {
-       get_paca()->kvm_slb_max = 1;
-       get_paca()->kvm_slb[0].esid = 0;
+       to_svcpu(vcpu)->slb_max = 1;
+       to_svcpu(vcpu)->slb[0].esid = 0;
 }
 
 void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu)
 {
        kvmppc_mmu_pte_flush(vcpu, 0, 0);
+       __destroy_context(to_book3s(vcpu)->context_id);
+}
+
+int kvmppc_mmu_init(struct kvm_vcpu *vcpu)
+{
+       struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
+       int err;
+
+       err = __init_new_context();
+       if (err < 0)
+               return -1;
+       vcpu3s->context_id = err;
+
+       vcpu3s->vsid_max = ((vcpu3s->context_id + 1) << USER_ESID_BITS) - 1;
+       vcpu3s->vsid_first = vcpu3s->context_id << USER_ESID_BITS;
+       vcpu3s->vsid_next = vcpu3s->vsid_first;
+
+       return 0;
 }
index 35b762722187ca884bd950bcbb894c4dfae09b32..04e7d3bbfe8bb8d36144a5ab7af95d4bb503d007 100644 (file)
@@ -44,8 +44,7 @@ slb_exit_skip_ ## num:
  *                                                                            *
  *****************************************************************************/
 
-.global kvmppc_handler_trampoline_enter
-kvmppc_handler_trampoline_enter:
+.macro LOAD_GUEST_SEGMENTS
 
        /* Required state:
         *
@@ -53,20 +52,14 @@ kvmppc_handler_trampoline_enter:
         * R13 = PACA
         * R1 = host R1
         * R2 = host R2
-        * R9 = guest IP
-        * R10 = guest MSR
-        * all other GPRS = free
-        * PACA[KVM_CR] = guest CR
-        * PACA[KVM_XER] = guest XER
+        * R3 = shadow vcpu
+        * all other volatile GPRS = free
+        * SVCPU[CR]  = guest CR
+        * SVCPU[XER] = guest XER
+        * SVCPU[CTR] = guest CTR
+        * SVCPU[LR]  = guest LR
         */
 
-       mtsrr0  r9
-       mtsrr1  r10
-
-       /* Activate guest mode, so faults get handled by KVM */
-       li      r11, KVM_GUEST_MODE_GUEST
-       stb     r11, PACA_KVM_IN_GUEST(r13)
-
        /* Remove LPAR shadow entries */
 
 #if SLB_NUM_BOLTED == 3
@@ -101,14 +94,14 @@ kvmppc_handler_trampoline_enter:
 
        /* Fill SLB with our shadow */
 
-       lbz     r12, PACA_KVM_SLB_MAX(r13)
+       lbz     r12, SVCPU_SLB_MAX(r3)
        mulli   r12, r12, 16
-       addi    r12, r12, PACA_KVM_SLB
-       add     r12, r12, r13
+       addi    r12, r12, SVCPU_SLB
+       add     r12, r12, r3
 
        /* for (r11 = kvm_slb; r11 < kvm_slb + kvm_slb_size; r11+=slb_entry) */
-       li      r11, PACA_KVM_SLB
-       add     r11, r11, r13
+       li      r11, SVCPU_SLB
+       add     r11, r11, r3
 
 slb_loop_enter:
 
@@ -127,34 +120,7 @@ slb_loop_enter_skip:
 
 slb_do_enter:
 
-       /* Enter guest */
-
-       ld      r0, (PACA_KVM_R0)(r13)
-       ld      r1, (PACA_KVM_R1)(r13)
-       ld      r2, (PACA_KVM_R2)(r13)
-       ld      r3, (PACA_KVM_R3)(r13)
-       ld      r4, (PACA_KVM_R4)(r13)
-       ld      r5, (PACA_KVM_R5)(r13)
-       ld      r6, (PACA_KVM_R6)(r13)
-       ld      r7, (PACA_KVM_R7)(r13)
-       ld      r8, (PACA_KVM_R8)(r13)
-       ld      r9, (PACA_KVM_R9)(r13)
-       ld      r10, (PACA_KVM_R10)(r13)
-       ld      r12, (PACA_KVM_R12)(r13)
-
-       lwz     r11, (PACA_KVM_CR)(r13)
-       mtcr    r11
-
-       ld      r11, (PACA_KVM_XER)(r13)
-       mtxer   r11
-
-       ld      r11, (PACA_KVM_R11)(r13)
-       ld      r13, (PACA_KVM_R13)(r13)
-
-       RFI
-kvmppc_handler_trampoline_enter_end:
-
-
+.endm
 
 /******************************************************************************
  *                                                                            *
@@ -162,99 +128,22 @@ kvmppc_handler_trampoline_enter_end:
  *                                                                            *
  *****************************************************************************/
 
-.global kvmppc_handler_trampoline_exit
-kvmppc_handler_trampoline_exit:
+.macro LOAD_HOST_SEGMENTS
 
        /* Register usage at this point:
         *
-        * SPRG_SCRATCH0     = guest R13
-        * R12               = exit handler id
-        * R13               = PACA
-        * PACA.KVM.SCRATCH0 = guest R12
-        * PACA.KVM.SCRATCH1 = guest CR
+        * R1         = host R1
+        * R2         = host R2
+        * R12        = exit handler id
+        * R13        = shadow vcpu - SHADOW_VCPU_OFF [=PACA on PPC64]
+        * SVCPU.*    = guest *
+        * SVCPU[CR]  = guest CR
+        * SVCPU[XER] = guest XER
+        * SVCPU[CTR] = guest CTR
+        * SVCPU[LR]  = guest LR
         *
         */
 
-       /* Save registers */
-
-       std     r0, PACA_KVM_R0(r13)
-       std     r1, PACA_KVM_R1(r13)
-       std     r2, PACA_KVM_R2(r13)
-       std     r3, PACA_KVM_R3(r13)
-       std     r4, PACA_KVM_R4(r13)
-       std     r5, PACA_KVM_R5(r13)
-       std     r6, PACA_KVM_R6(r13)
-       std     r7, PACA_KVM_R7(r13)
-       std     r8, PACA_KVM_R8(r13)
-       std     r9, PACA_KVM_R9(r13)
-       std     r10, PACA_KVM_R10(r13)
-       std     r11, PACA_KVM_R11(r13)
-
-       /* Restore R1/R2 so we can handle faults */
-       ld      r1, PACA_KVM_HOST_R1(r13)
-       ld      r2, PACA_KVM_HOST_R2(r13)
-
-       /* Save guest PC and MSR in GPRs */
-       mfsrr0  r3
-       mfsrr1  r4
-
-       /* Get scratch'ed off registers */
-       mfspr   r9, SPRN_SPRG_SCRATCH0
-       std     r9, PACA_KVM_R13(r13)
-
-       ld      r8, PACA_KVM_SCRATCH0(r13)
-       std     r8, PACA_KVM_R12(r13)
-
-       lwz     r7, PACA_KVM_SCRATCH1(r13)
-       stw     r7, PACA_KVM_CR(r13)
-
-       /* Save more register state  */
-
-       mfxer   r6
-       stw     r6, PACA_KVM_XER(r13)
-
-       mfdar   r5
-       mfdsisr r6
-
-       /*
-        * In order for us to easily get the last instruction,
-        * we got the #vmexit at, we exploit the fact that the
-        * virtual layout is still the same here, so we can just
-        * ld from the guest's PC address
-        */
-
-       /* We only load the last instruction when it's safe */
-       cmpwi   r12, BOOK3S_INTERRUPT_DATA_STORAGE
-       beq     ld_last_inst
-       cmpwi   r12, BOOK3S_INTERRUPT_PROGRAM
-       beq     ld_last_inst
-
-       b       no_ld_last_inst
-
-ld_last_inst:
-       /* Save off the guest instruction we're at */
-
-       /* Set guest mode to 'jump over instruction' so if lwz faults
-        * we'll just continue at the next IP. */
-       li      r9, KVM_GUEST_MODE_SKIP
-       stb     r9, PACA_KVM_IN_GUEST(r13)
-
-       /*    1) enable paging for data */
-       mfmsr   r9
-       ori     r11, r9, MSR_DR                 /* Enable paging for data */
-       mtmsr   r11
-       /*    2) fetch the instruction */
-       li      r0, KVM_INST_FETCH_FAILED       /* In case lwz faults */
-       lwz     r0, 0(r3)
-       /*    3) disable paging again */
-       mtmsr   r9
-
-no_ld_last_inst:
-
-       /* Unset guest mode */
-       li      r9, KVM_GUEST_MODE_NONE
-       stb     r9, PACA_KVM_IN_GUEST(r13)
-
        /* Restore bolted entries from the shadow and fix it along the way */
 
        /* We don't store anything in entry 0, so we don't need to take care of it */
@@ -275,28 +164,4 @@ no_ld_last_inst:
 
 slb_do_exit:
 
-       /* Register usage at this point:
-        *
-        * R0         = guest last inst
-        * R1         = host R1
-        * R2         = host R2
-        * R3         = guest PC
-        * R4         = guest MSR
-        * R5         = guest DAR
-        * R6         = guest DSISR
-        * R12        = exit handler id
-        * R13        = PACA
-        * PACA.KVM.* = guest *
-        *
-        */
-
-       /* RFI into the highmem handler */
-       mfmsr   r7
-       ori     r7, r7, MSR_IR|MSR_DR|MSR_RI    /* Enable paging */
-       mtsrr1  r7
-       ld      r8, PACA_KVM_VMHANDLER(r13)     /* Highmem handler address */
-       mtsrr0  r8
-
-       RFI
-kvmppc_handler_trampoline_exit_end:
-
+.endm
similarity index 58%
rename from arch/powerpc/kvm/book3s_64_emulate.c
rename to arch/powerpc/kvm/book3s_emulate.c
index 2b0ee7e040c90d7870851ae46d564b1e17451ad7..c85f906038ce8d4441a841721d046e7de3611c8f 100644 (file)
 #define OP_31_XOP_MFMSR                83
 #define OP_31_XOP_MTMSR                146
 #define OP_31_XOP_MTMSRD       178
+#define OP_31_XOP_MTSR         210
 #define OP_31_XOP_MTSRIN       242
 #define OP_31_XOP_TLBIEL       274
 #define OP_31_XOP_TLBIE                306
 #define OP_31_XOP_SLBMTE       402
 #define OP_31_XOP_SLBIE                434
 #define OP_31_XOP_SLBIA                498
+#define OP_31_XOP_MFSR         595
 #define OP_31_XOP_MFSRIN       659
+#define OP_31_XOP_DCBA         758
 #define OP_31_XOP_SLBMFEV      851
 #define OP_31_XOP_EIOIO                854
 #define OP_31_XOP_SLBMFEE      915
 /* DCBZ is actually 1014, but we patch it to 1010 so we get a trap */
 #define OP_31_XOP_DCBZ         1010
 
+#define OP_LFS                 48
+#define OP_LFD                 50
+#define OP_STFS                        52
+#define OP_STFD                        54
+
+#define SPRN_GQR0              912
+#define SPRN_GQR1              913
+#define SPRN_GQR2              914
+#define SPRN_GQR3              915
+#define SPRN_GQR4              916
+#define SPRN_GQR5              917
+#define SPRN_GQR6              918
+#define SPRN_GQR7              919
+
+/* Book3S_32 defines mfsrin(v) - but that messes up our abstract
+ * function pointers, so let's just disable the define. */
+#undef mfsrin
+
 int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
                            unsigned int inst, int *advance)
 {
@@ -52,7 +73,7 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
                switch (get_xop(inst)) {
                case OP_19_XOP_RFID:
                case OP_19_XOP_RFI:
-                       vcpu->arch.pc = vcpu->arch.srr0;
+                       kvmppc_set_pc(vcpu, vcpu->arch.srr0);
                        kvmppc_set_msr(vcpu, vcpu->arch.srr1);
                        *advance = 0;
                        break;
@@ -80,6 +101,18 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
                case OP_31_XOP_MTMSR:
                        kvmppc_set_msr(vcpu, kvmppc_get_gpr(vcpu, get_rs(inst)));
                        break;
+               case OP_31_XOP_MFSR:
+               {
+                       int srnum;
+
+                       srnum = kvmppc_get_field(inst, 12 + 32, 15 + 32);
+                       if (vcpu->arch.mmu.mfsrin) {
+                               u32 sr;
+                               sr = vcpu->arch.mmu.mfsrin(vcpu, srnum);
+                               kvmppc_set_gpr(vcpu, get_rt(inst), sr);
+                       }
+                       break;
+               }
                case OP_31_XOP_MFSRIN:
                {
                        int srnum;
@@ -92,6 +125,11 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
                        }
                        break;
                }
+               case OP_31_XOP_MTSR:
+                       vcpu->arch.mmu.mtsrin(vcpu,
+                               (inst >> 16) & 0xf,
+                               kvmppc_get_gpr(vcpu, get_rs(inst)));
+                       break;
                case OP_31_XOP_MTSRIN:
                        vcpu->arch.mmu.mtsrin(vcpu,
                                (kvmppc_get_gpr(vcpu, get_rb(inst)) >> 28) & 0xf,
@@ -150,12 +188,17 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
                                kvmppc_set_gpr(vcpu, get_rt(inst), t);
                        }
                        break;
+               case OP_31_XOP_DCBA:
+                       /* Gets treated as NOP */
+                       break;
                case OP_31_XOP_DCBZ:
                {
                        ulong rb = kvmppc_get_gpr(vcpu, get_rb(inst));
                        ulong ra = 0;
-                       ulong addr;
+                       ulong addr, vaddr;
                        u32 zeros[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+                       u32 dsisr;
+                       int r;
 
                        if (get_ra(inst))
                                ra = kvmppc_get_gpr(vcpu, get_ra(inst));
@@ -163,15 +206,25 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
                        addr = (ra + rb) & ~31ULL;
                        if (!(vcpu->arch.msr & MSR_SF))
                                addr &= 0xffffffff;
+                       vaddr = addr;
+
+                       r = kvmppc_st(vcpu, &addr, 32, zeros, true);
+                       if ((r == -ENOENT) || (r == -EPERM)) {
+                               *advance = 0;
+                               vcpu->arch.dear = vaddr;
+                               to_svcpu(vcpu)->fault_dar = vaddr;
+
+                               dsisr = DSISR_ISSTORE;
+                               if (r == -ENOENT)
+                                       dsisr |= DSISR_NOHPTE;
+                               else if (r == -EPERM)
+                                       dsisr |= DSISR_PROTFAULT;
+
+                               to_book3s(vcpu)->dsisr = dsisr;
+                               to_svcpu(vcpu)->fault_dsisr = dsisr;
 
-                       if (kvmppc_st(vcpu, addr, 32, zeros)) {
-                               vcpu->arch.dear = addr;
-                               vcpu->arch.fault_dear = addr;
-                               to_book3s(vcpu)->dsisr = DSISR_PROTFAULT |
-                                                     DSISR_ISSTORE;
                                kvmppc_book3s_queue_irqprio(vcpu,
                                        BOOK3S_INTERRUPT_DATA_STORAGE);
-                               kvmppc_mmu_pte_flush(vcpu, addr, ~0xFFFULL);
                        }
 
                        break;
@@ -184,6 +237,9 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
                emulated = EMULATE_FAIL;
        }
 
+       if (emulated == EMULATE_FAIL)
+               emulated = kvmppc_emulate_paired_single(run, vcpu);
+
        return emulated;
 }
 
@@ -207,6 +263,34 @@ void kvmppc_set_bat(struct kvm_vcpu *vcpu, struct kvmppc_bat *bat, bool upper,
        }
 }
 
+static u32 kvmppc_read_bat(struct kvm_vcpu *vcpu, int sprn)
+{
+       struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
+       struct kvmppc_bat *bat;
+
+       switch (sprn) {
+       case SPRN_IBAT0U ... SPRN_IBAT3L:
+               bat = &vcpu_book3s->ibat[(sprn - SPRN_IBAT0U) / 2];
+               break;
+       case SPRN_IBAT4U ... SPRN_IBAT7L:
+               bat = &vcpu_book3s->ibat[4 + ((sprn - SPRN_IBAT4U) / 2)];
+               break;
+       case SPRN_DBAT0U ... SPRN_DBAT3L:
+               bat = &vcpu_book3s->dbat[(sprn - SPRN_DBAT0U) / 2];
+               break;
+       case SPRN_DBAT4U ... SPRN_DBAT7L:
+               bat = &vcpu_book3s->dbat[4 + ((sprn - SPRN_DBAT4U) / 2)];
+               break;
+       default:
+               BUG();
+       }
+
+       if (sprn % 2)
+               return bat->raw >> 32;
+       else
+               return bat->raw;
+}
+
 static void kvmppc_write_bat(struct kvm_vcpu *vcpu, int sprn, u32 val)
 {
        struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
@@ -217,13 +301,13 @@ static void kvmppc_write_bat(struct kvm_vcpu *vcpu, int sprn, u32 val)
                bat = &vcpu_book3s->ibat[(sprn - SPRN_IBAT0U) / 2];
                break;
        case SPRN_IBAT4U ... SPRN_IBAT7L:
-               bat = &vcpu_book3s->ibat[(sprn - SPRN_IBAT4U) / 2];
+               bat = &vcpu_book3s->ibat[4 + ((sprn - SPRN_IBAT4U) / 2)];
                break;
        case SPRN_DBAT0U ... SPRN_DBAT3L:
                bat = &vcpu_book3s->dbat[(sprn - SPRN_DBAT0U) / 2];
                break;
        case SPRN_DBAT4U ... SPRN_DBAT7L:
-               bat = &vcpu_book3s->dbat[(sprn - SPRN_DBAT4U) / 2];
+               bat = &vcpu_book3s->dbat[4 + ((sprn - SPRN_DBAT4U) / 2)];
                break;
        default:
                BUG();
@@ -258,6 +342,7 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
                /* BAT writes happen so rarely that we're ok to flush
                 * everything here */
                kvmppc_mmu_pte_flush(vcpu, 0, 0);
+               kvmppc_mmu_flush_segments(vcpu);
                break;
        case SPRN_HID0:
                to_book3s(vcpu)->hid[0] = spr_val;
@@ -268,7 +353,32 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
        case SPRN_HID2:
                to_book3s(vcpu)->hid[2] = spr_val;
                break;
+       case SPRN_HID2_GEKKO:
+               to_book3s(vcpu)->hid[2] = spr_val;
+               /* HID2.PSE controls paired single on gekko */
+               switch (vcpu->arch.pvr) {
+               case 0x00080200:        /* lonestar 2.0 */
+               case 0x00088202:        /* lonestar 2.2 */
+               case 0x70000100:        /* gekko 1.0 */
+               case 0x00080100:        /* gekko 2.0 */
+               case 0x00083203:        /* gekko 2.3a */
+               case 0x00083213:        /* gekko 2.3b */
+               case 0x00083204:        /* gekko 2.4 */
+               case 0x00083214:        /* gekko 2.4e (8SE) - retail HW2 */
+               case 0x00087200:        /* broadway */
+                       if (vcpu->arch.hflags & BOOK3S_HFLAG_NATIVE_PS) {
+                               /* Native paired singles */
+                       } else if (spr_val & (1 << 29)) { /* HID2.PSE */
+                               vcpu->arch.hflags |= BOOK3S_HFLAG_PAIRED_SINGLE;
+                               kvmppc_giveup_ext(vcpu, MSR_FP);
+                       } else {
+                               vcpu->arch.hflags &= ~BOOK3S_HFLAG_PAIRED_SINGLE;
+                       }
+                       break;
+               }
+               break;
        case SPRN_HID4:
+       case SPRN_HID4_GEKKO:
                to_book3s(vcpu)->hid[4] = spr_val;
                break;
        case SPRN_HID5:
@@ -278,12 +388,30 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
                    (mfmsr() & MSR_HV))
                        vcpu->arch.hflags |= BOOK3S_HFLAG_DCBZ32;
                break;
+       case SPRN_GQR0:
+       case SPRN_GQR1:
+       case SPRN_GQR2:
+       case SPRN_GQR3:
+       case SPRN_GQR4:
+       case SPRN_GQR5:
+       case SPRN_GQR6:
+       case SPRN_GQR7:
+               to_book3s(vcpu)->gqr[sprn - SPRN_GQR0] = spr_val;
+               break;
        case SPRN_ICTC:
        case SPRN_THRM1:
        case SPRN_THRM2:
        case SPRN_THRM3:
        case SPRN_CTRLF:
        case SPRN_CTRLT:
+       case SPRN_L2CR:
+       case SPRN_MMCR0_GEKKO:
+       case SPRN_MMCR1_GEKKO:
+       case SPRN_PMC1_GEKKO:
+       case SPRN_PMC2_GEKKO:
+       case SPRN_PMC3_GEKKO:
+       case SPRN_PMC4_GEKKO:
+       case SPRN_WPAR_GEKKO:
                break;
        default:
                printk(KERN_INFO "KVM: invalid SPR write: %d\n", sprn);
@@ -301,6 +429,12 @@ int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
        int emulated = EMULATE_DONE;
 
        switch (sprn) {
+       case SPRN_IBAT0U ... SPRN_IBAT3L:
+       case SPRN_IBAT4U ... SPRN_IBAT7L:
+       case SPRN_DBAT0U ... SPRN_DBAT3L:
+       case SPRN_DBAT4U ... SPRN_DBAT7L:
+               kvmppc_set_gpr(vcpu, rt, kvmppc_read_bat(vcpu, sprn));
+               break;
        case SPRN_SDR1:
                kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->sdr1);
                break;
@@ -320,19 +454,40 @@ int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
                kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->hid[1]);
                break;
        case SPRN_HID2:
+       case SPRN_HID2_GEKKO:
                kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->hid[2]);
                break;
        case SPRN_HID4:
+       case SPRN_HID4_GEKKO:
                kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->hid[4]);
                break;
        case SPRN_HID5:
                kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->hid[5]);
                break;
+       case SPRN_GQR0:
+       case SPRN_GQR1:
+       case SPRN_GQR2:
+       case SPRN_GQR3:
+       case SPRN_GQR4:
+       case SPRN_GQR5:
+       case SPRN_GQR6:
+       case SPRN_GQR7:
+               kvmppc_set_gpr(vcpu, rt,
+                              to_book3s(vcpu)->gqr[sprn - SPRN_GQR0]);
+               break;
        case SPRN_THRM1:
        case SPRN_THRM2:
        case SPRN_THRM3:
        case SPRN_CTRLF:
        case SPRN_CTRLT:
+       case SPRN_L2CR:
+       case SPRN_MMCR0_GEKKO:
+       case SPRN_MMCR1_GEKKO:
+       case SPRN_PMC1_GEKKO:
+       case SPRN_PMC2_GEKKO:
+       case SPRN_PMC3_GEKKO:
+       case SPRN_PMC4_GEKKO:
+       case SPRN_WPAR_GEKKO:
                kvmppc_set_gpr(vcpu, rt, 0);
                break;
        default:
@@ -346,3 +501,73 @@ int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
        return emulated;
 }
 
+u32 kvmppc_alignment_dsisr(struct kvm_vcpu *vcpu, unsigned int inst)
+{
+       u32 dsisr = 0;
+
+       /*
+        * This is what the spec says about DSISR bits (not mentioned = 0):
+        *
+        * 12:13                [DS]    Set to bits 30:31
+        * 15:16                [X]     Set to bits 29:30
+        * 17                   [X]     Set to bit 25
+        *                      [D/DS]  Set to bit 5
+        * 18:21                [X]     Set to bits 21:24
+        *                      [D/DS]  Set to bits 1:4
+        * 22:26                        Set to bits 6:10 (RT/RS/FRT/FRS)
+        * 27:31                        Set to bits 11:15 (RA)
+        */
+
+       switch (get_op(inst)) {
+       /* D-form */
+       case OP_LFS:
+       case OP_LFD:
+       case OP_STFD:
+       case OP_STFS:
+               dsisr |= (inst >> 12) & 0x4000; /* bit 17 */
+               dsisr |= (inst >> 17) & 0x3c00; /* bits 18:21 */
+               break;
+       /* X-form */
+       case 31:
+               dsisr |= (inst << 14) & 0x18000; /* bits 15:16 */
+               dsisr |= (inst << 8)  & 0x04000; /* bit 17 */
+               dsisr |= (inst << 3)  & 0x03c00; /* bits 18:21 */
+               break;
+       default:
+               printk(KERN_INFO "KVM: Unaligned instruction 0x%x\n", inst);
+               break;
+       }
+
+       dsisr |= (inst >> 16) & 0x03ff; /* bits 22:31 */
+
+       return dsisr;
+}
+
+ulong kvmppc_alignment_dar(struct kvm_vcpu *vcpu, unsigned int inst)
+{
+       ulong dar = 0;
+       ulong ra;
+
+       switch (get_op(inst)) {
+       case OP_LFS:
+       case OP_LFD:
+       case OP_STFD:
+       case OP_STFS:
+               ra = get_ra(inst);
+               if (ra)
+                       dar = kvmppc_get_gpr(vcpu, ra);
+               dar += (s32)((s16)inst);
+               break;
+       case 31:
+               ra = get_ra(inst);
+               if (ra)
+                       dar = kvmppc_get_gpr(vcpu, ra);
+               dar += kvmppc_get_gpr(vcpu, get_rb(inst));
+               break;
+       default:
+               printk(KERN_INFO "KVM: Unaligned instruction 0x%x\n", inst);
+               break;
+       }
+
+       return dar;
+}
similarity index 62%
rename from arch/powerpc/kvm/book3s_64_interrupts.S
rename to arch/powerpc/kvm/book3s_interrupts.S
index c1584d0cbce82d3ca9f3dd0565d6d5adacbfc3c7..2f0bc928b08a0ff8499dd75052e2a61a7d19a330 100644 (file)
 #include <asm/asm-offsets.h>
 #include <asm/exception-64s.h>
 
-#define KVMPPC_HANDLE_EXIT .kvmppc_handle_exit
-#define ULONG_SIZE 8
-#define VCPU_GPR(n)     (VCPU_GPRS + (n * ULONG_SIZE))
+#if defined(CONFIG_PPC_BOOK3S_64)
 
-.macro DISABLE_INTERRUPTS
-       mfmsr   r0
-       rldicl  r0,r0,48,1
-       rotldi  r0,r0,16
-       mtmsrd  r0,1
-.endm
+#define ULONG_SIZE             8
+#define FUNC(name)             GLUE(.,name)
 
+#define GET_SHADOW_VCPU(reg)    \
+        addi    reg, r13, PACA_KVM_SVCPU
+
+#define DISABLE_INTERRUPTS     \
+       mfmsr   r0;             \
+       rldicl  r0,r0,48,1;     \
+       rotldi  r0,r0,16;       \
+       mtmsrd  r0,1;           \
+
+#elif defined(CONFIG_PPC_BOOK3S_32)
+
+#define ULONG_SIZE              4
+#define FUNC(name)             name
+
+#define GET_SHADOW_VCPU(reg)    \
+        lwz     reg, (THREAD + THREAD_KVM_SVCPU)(r2)
+
+#define DISABLE_INTERRUPTS     \
+       mfmsr   r0;             \
+       rlwinm  r0,r0,0,17,15;  \
+       mtmsr   r0;             \
+
+#endif /* CONFIG_PPC_BOOK3S_XX */
+
+
+#define VCPU_GPR(n)            (VCPU_GPRS + (n * ULONG_SIZE))
 #define VCPU_LOAD_NVGPRS(vcpu) \
-       ld      r14, VCPU_GPR(r14)(vcpu); \
-       ld      r15, VCPU_GPR(r15)(vcpu); \
-       ld      r16, VCPU_GPR(r16)(vcpu); \
-       ld      r17, VCPU_GPR(r17)(vcpu); \
-       ld      r18, VCPU_GPR(r18)(vcpu); \
-       ld      r19, VCPU_GPR(r19)(vcpu); \
-       ld      r20, VCPU_GPR(r20)(vcpu); \
-       ld      r21, VCPU_GPR(r21)(vcpu); \
-       ld      r22, VCPU_GPR(r22)(vcpu); \
-       ld      r23, VCPU_GPR(r23)(vcpu); \
-       ld      r24, VCPU_GPR(r24)(vcpu); \
-       ld      r25, VCPU_GPR(r25)(vcpu); \
-       ld      r26, VCPU_GPR(r26)(vcpu); \
-       ld      r27, VCPU_GPR(r27)(vcpu); \
-       ld      r28, VCPU_GPR(r28)(vcpu); \
-       ld      r29, VCPU_GPR(r29)(vcpu); \
-       ld      r30, VCPU_GPR(r30)(vcpu); \
-       ld      r31, VCPU_GPR(r31)(vcpu); \
+       PPC_LL  r14, VCPU_GPR(r14)(vcpu); \
+       PPC_LL  r15, VCPU_GPR(r15)(vcpu); \
+       PPC_LL  r16, VCPU_GPR(r16)(vcpu); \
+       PPC_LL  r17, VCPU_GPR(r17)(vcpu); \
+       PPC_LL  r18, VCPU_GPR(r18)(vcpu); \
+       PPC_LL  r19, VCPU_GPR(r19)(vcpu); \
+       PPC_LL  r20, VCPU_GPR(r20)(vcpu); \
+       PPC_LL  r21, VCPU_GPR(r21)(vcpu); \
+       PPC_LL  r22, VCPU_GPR(r22)(vcpu); \
+       PPC_LL  r23, VCPU_GPR(r23)(vcpu); \
+       PPC_LL  r24, VCPU_GPR(r24)(vcpu); \
+       PPC_LL  r25, VCPU_GPR(r25)(vcpu); \
+       PPC_LL  r26, VCPU_GPR(r26)(vcpu); \
+       PPC_LL  r27, VCPU_GPR(r27)(vcpu); \
+       PPC_LL  r28, VCPU_GPR(r28)(vcpu); \
+       PPC_LL  r29, VCPU_GPR(r29)(vcpu); \
+       PPC_LL  r30, VCPU_GPR(r30)(vcpu); \
+       PPC_LL  r31, VCPU_GPR(r31)(vcpu); \
 
 /*****************************************************************************
  *                                                                           *
@@ -69,11 +89,11 @@ _GLOBAL(__kvmppc_vcpu_entry)
 
 kvm_start_entry:
        /* Write correct stack frame */
-       mflr    r0
-       std     r0,16(r1)
+       mflr    r0
+       PPC_STL r0,PPC_LR_STKOFF(r1)
 
        /* Save host state to the stack */
-       stdu    r1, -SWITCH_FRAME_SIZE(r1)
+       PPC_STLU r1, -SWITCH_FRAME_SIZE(r1)
 
        /* Save r3 (kvm_run) and r4 (vcpu) */
        SAVE_2GPRS(3, r1)
@@ -82,33 +102,28 @@ kvm_start_entry:
        SAVE_NVGPRS(r1)
 
        /* Save LR */
-       std     r0, _LINK(r1)
+       PPC_STL r0, _LINK(r1)
 
        /* Load non-volatile guest state from the vcpu */
        VCPU_LOAD_NVGPRS(r4)
 
+       GET_SHADOW_VCPU(r5)
+
        /* Save R1/R2 in the PACA */
-       std     r1, PACA_KVM_HOST_R1(r13)
-       std     r2, PACA_KVM_HOST_R2(r13)
+       PPC_STL r1, SVCPU_HOST_R1(r5)
+       PPC_STL r2, SVCPU_HOST_R2(r5)
 
        /* XXX swap in/out on load? */
-       ld      r3, VCPU_HIGHMEM_HANDLER(r4)
-       std     r3, PACA_KVM_VMHANDLER(r13)
+       PPC_LL  r3, VCPU_HIGHMEM_HANDLER(r4)
+       PPC_STL r3, SVCPU_VMHANDLER(r5)
 
 kvm_start_lightweight:
 
-       ld      r9, VCPU_PC(r4)                 /* r9 = vcpu->arch.pc */
-       ld      r10, VCPU_SHADOW_MSR(r4)        /* r10 = vcpu->arch.shadow_msr */
-
-       /* Load some guest state in the respective registers */
-       ld      r5, VCPU_CTR(r4)        /* r5 = vcpu->arch.ctr */
-                                       /* will be swapped in by rmcall */
-
-       ld      r3, VCPU_LR(r4)         /* r3 = vcpu->arch.lr */
-       mtlr    r3                      /* LR = r3 */
+       PPC_LL  r10, VCPU_SHADOW_MSR(r4)        /* r10 = vcpu->arch.shadow_msr */
 
        DISABLE_INTERRUPTS
 
+#ifdef CONFIG_PPC_BOOK3S_64
        /* Some guests may need to have dcbz set to 32 byte length.
         *
         * Usually we ensure that by patching the guest's instructions
@@ -118,7 +133,7 @@ kvm_start_lightweight:
         * because that's a lot faster.
         */
 
-       ld      r3, VCPU_HFLAGS(r4)
+       PPC_LL  r3, VCPU_HFLAGS(r4)
        rldicl. r3, r3, 0, 63           /* CR = ((r3 & 1) == 0) */
        beq     no_dcbz32_on
 
@@ -128,13 +143,15 @@ kvm_start_lightweight:
 
 no_dcbz32_on:
 
-       ld      r6, VCPU_RMCALL(r4)
+#endif /* CONFIG_PPC_BOOK3S_64 */
+
+       PPC_LL  r6, VCPU_RMCALL(r4)
        mtctr   r6
 
-       ld      r3, VCPU_TRAMPOLINE_ENTER(r4)
+       PPC_LL  r3, VCPU_TRAMPOLINE_ENTER(r4)
        LOAD_REG_IMMEDIATE(r4, MSR_KERNEL & ~(MSR_IR | MSR_DR))
 
-       /* Jump to SLB patching handlder and into our guest */
+       /* Jump to segment patching handler and into our guest */
        bctr
 
 /*
@@ -149,31 +166,20 @@ kvmppc_handler_highmem:
        /*
         * Register usage at this point:
         *
-        * R0         = guest last inst
-        * R1         = host R1
-        * R2         = host R2
-        * R3         = guest PC
-        * R4         = guest MSR
-        * R5         = guest DAR
-        * R6         = guest DSISR
-        * R13        = PACA
-        * PACA.KVM.* = guest *
+        * R1       = host R1
+        * R2       = host R2
+        * R12      = exit handler id
+        * R13      = PACA
+        * SVCPU.*  = guest *
         *
         */
 
        /* R7 = vcpu */
-       ld      r7, GPR4(r1)
+       PPC_LL  r7, GPR4(r1)
 
-       /* Now save the guest state */
+#ifdef CONFIG_PPC_BOOK3S_64
 
-       stw     r0, VCPU_LAST_INST(r7)
-
-       std     r3, VCPU_PC(r7)
-       std     r4, VCPU_SHADOW_SRR1(r7)
-       std     r5, VCPU_FAULT_DEAR(r7)
-       std     r6, VCPU_FAULT_DSISR(r7)
-
-       ld      r5, VCPU_HFLAGS(r7)
+       PPC_LL  r5, VCPU_HFLAGS(r7)
        rldicl. r5, r5, 0, 63           /* CR = ((r5 & 1) == 0) */
        beq     no_dcbz32_off
 
@@ -184,35 +190,29 @@ kvmppc_handler_highmem:
 
 no_dcbz32_off:
 
-       std     r14, VCPU_GPR(r14)(r7)
-       std     r15, VCPU_GPR(r15)(r7)
-       std     r16, VCPU_GPR(r16)(r7)
-       std     r17, VCPU_GPR(r17)(r7)
-       std     r18, VCPU_GPR(r18)(r7)
-       std     r19, VCPU_GPR(r19)(r7)
-       std     r20, VCPU_GPR(r20)(r7)
-       std     r21, VCPU_GPR(r21)(r7)
-       std     r22, VCPU_GPR(r22)(r7)
-       std     r23, VCPU_GPR(r23)(r7)
-       std     r24, VCPU_GPR(r24)(r7)
-       std     r25, VCPU_GPR(r25)(r7)
-       std     r26, VCPU_GPR(r26)(r7)
-       std     r27, VCPU_GPR(r27)(r7)
-       std     r28, VCPU_GPR(r28)(r7)
-       std     r29, VCPU_GPR(r29)(r7)
-       std     r30, VCPU_GPR(r30)(r7)
-       std     r31, VCPU_GPR(r31)(r7)
-
-       /* Save guest CTR */
-       mfctr   r5
-       std     r5, VCPU_CTR(r7)
-
-       /* Save guest LR */
-       mflr    r5
-       std     r5, VCPU_LR(r7)
+#endif /* CONFIG_PPC_BOOK3S_64 */
+
+       PPC_STL r14, VCPU_GPR(r14)(r7)
+       PPC_STL r15, VCPU_GPR(r15)(r7)
+       PPC_STL r16, VCPU_GPR(r16)(r7)
+       PPC_STL r17, VCPU_GPR(r17)(r7)
+       PPC_STL r18, VCPU_GPR(r18)(r7)
+       PPC_STL r19, VCPU_GPR(r19)(r7)
+       PPC_STL r20, VCPU_GPR(r20)(r7)
+       PPC_STL r21, VCPU_GPR(r21)(r7)
+       PPC_STL r22, VCPU_GPR(r22)(r7)
+       PPC_STL r23, VCPU_GPR(r23)(r7)
+       PPC_STL r24, VCPU_GPR(r24)(r7)
+       PPC_STL r25, VCPU_GPR(r25)(r7)
+       PPC_STL r26, VCPU_GPR(r26)(r7)
+       PPC_STL r27, VCPU_GPR(r27)(r7)
+       PPC_STL r28, VCPU_GPR(r28)(r7)
+       PPC_STL r29, VCPU_GPR(r29)(r7)
+       PPC_STL r30, VCPU_GPR(r30)(r7)
+       PPC_STL r31, VCPU_GPR(r31)(r7)
 
        /* Restore host msr -> SRR1 */
-       ld      r6, VCPU_HOST_MSR(r7)
+       PPC_LL  r6, VCPU_HOST_MSR(r7)
 
        /*
         * For some interrupts, we need to call the real Linux
@@ -228,9 +228,12 @@ no_dcbz32_off:
        beq     call_linux_handler
        cmpwi   r12, BOOK3S_INTERRUPT_DECREMENTER
        beq     call_linux_handler
+       cmpwi   r12, BOOK3S_INTERRUPT_PERFMON
+       beq     call_linux_handler
 
        /* Back to EE=1 */
        mtmsr   r6
+       sync
        b       kvm_return_point
 
 call_linux_handler:
@@ -249,14 +252,14 @@ call_linux_handler:
         */
 
        /* Restore host IP -> SRR0 */
-       ld      r5, VCPU_HOST_RETIP(r7)
+       PPC_LL  r5, VCPU_HOST_RETIP(r7)
 
        /* XXX Better move to a safe function?
         *     What if we get an HTAB flush in between mtsrr0 and mtsrr1? */
 
        mtlr    r12
 
-       ld      r4, VCPU_TRAMPOLINE_LOWMEM(r7)
+       PPC_LL  r4, VCPU_TRAMPOLINE_LOWMEM(r7)
        mtsrr0  r4
        LOAD_REG_IMMEDIATE(r3, MSR_KERNEL & ~(MSR_IR | MSR_DR))
        mtsrr1  r3
@@ -274,7 +277,7 @@ kvm_return_point:
 
        /* Restore r3 (kvm_run) and r4 (vcpu) */
        REST_2GPRS(3, r1)
-       bl      KVMPPC_HANDLE_EXIT
+       bl      FUNC(kvmppc_handle_exit)
 
        /* If RESUME_GUEST, get back in the loop */
        cmpwi   r3, RESUME_GUEST
@@ -285,7 +288,7 @@ kvm_return_point:
 
 kvm_exit_loop:
 
-       ld      r4, _LINK(r1)
+       PPC_LL  r4, _LINK(r1)
        mtlr    r4
 
        /* Restore non-volatile host registers (r14 - r31) */
@@ -296,8 +299,8 @@ kvm_exit_loop:
 
 kvm_loop_heavyweight:
 
-       ld      r4, _LINK(r1)
-       std     r4, (16 + SWITCH_FRAME_SIZE)(r1)
+       PPC_LL  r4, _LINK(r1)
+       PPC_STL r4, (PPC_LR_STKOFF + SWITCH_FRAME_SIZE)(r1)
 
        /* Load vcpu and cpu_run */
        REST_2GPRS(3, r1)
@@ -315,4 +318,3 @@ kvm_loop_lightweight:
 
        /* Jump back into the beginning of this function */
        b       kvm_start_lightweight
-
diff --git a/arch/powerpc/kvm/book3s_paired_singles.c b/arch/powerpc/kvm/book3s_paired_singles.c
new file mode 100644 (file)
index 0000000..a9f66ab
--- /dev/null
@@ -0,0 +1,1289 @@
+/*
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright Novell Inc 2010
+ *
+ * Authors: Alexander Graf <agraf@suse.de>
+ */
+
+#include <asm/kvm.h>
+#include <asm/kvm_ppc.h>
+#include <asm/disassemble.h>
+#include <asm/kvm_book3s.h>
+#include <asm/kvm_fpu.h>
+#include <asm/reg.h>
+#include <asm/cacheflush.h>
+#include <linux/vmalloc.h>
+
+/* #define DEBUG */
+
+#ifdef DEBUG
+#define dprintk printk
+#else
+#define dprintk(...) do { } while(0);
+#endif
+
+#define OP_LFS                 48
+#define OP_LFSU                        49
+#define OP_LFD                 50
+#define OP_LFDU                        51
+#define OP_STFS                        52
+#define OP_STFSU               53
+#define OP_STFD                        54
+#define OP_STFDU               55
+#define OP_PSQ_L               56
+#define OP_PSQ_LU              57
+#define OP_PSQ_ST              60
+#define OP_PSQ_STU             61
+
+#define OP_31_LFSX             535
+#define OP_31_LFSUX            567
+#define OP_31_LFDX             599
+#define OP_31_LFDUX            631
+#define OP_31_STFSX            663
+#define OP_31_STFSUX           695
+#define OP_31_STFX             727
+#define OP_31_STFUX            759
+#define OP_31_LWIZX            887
+#define OP_31_STFIWX           983
+
+#define OP_59_FADDS            21
+#define OP_59_FSUBS            20
+#define OP_59_FSQRTS           22
+#define OP_59_FDIVS            18
+#define OP_59_FRES             24
+#define OP_59_FMULS            25
+#define OP_59_FRSQRTES         26
+#define OP_59_FMSUBS           28
+#define OP_59_FMADDS           29
+#define OP_59_FNMSUBS          30
+#define OP_59_FNMADDS          31
+
+#define OP_63_FCMPU            0
+#define OP_63_FCPSGN           8
+#define OP_63_FRSP             12
+#define OP_63_FCTIW            14
+#define OP_63_FCTIWZ           15
+#define OP_63_FDIV             18
+#define OP_63_FADD             21
+#define OP_63_FSQRT            22
+#define OP_63_FSEL             23
+#define OP_63_FRE              24
+#define OP_63_FMUL             25
+#define OP_63_FRSQRTE          26
+#define OP_63_FMSUB            28
+#define OP_63_FMADD            29
+#define OP_63_FNMSUB           30
+#define OP_63_FNMADD           31
+#define OP_63_FCMPO            32
+#define OP_63_MTFSB1           38 // XXX
+#define OP_63_FSUB             20
+#define OP_63_FNEG             40
+#define OP_63_MCRFS            64
+#define OP_63_MTFSB0           70
+#define OP_63_FMR              72
+#define OP_63_MTFSFI           134
+#define OP_63_FABS             264
+#define OP_63_MFFS             583
+#define OP_63_MTFSF            711
+
+#define OP_4X_PS_CMPU0         0
+#define OP_4X_PSQ_LX           6
+#define OP_4XW_PSQ_STX         7
+#define OP_4A_PS_SUM0          10
+#define OP_4A_PS_SUM1          11
+#define OP_4A_PS_MULS0         12
+#define OP_4A_PS_MULS1         13
+#define OP_4A_PS_MADDS0                14
+#define OP_4A_PS_MADDS1                15
+#define OP_4A_PS_DIV           18
+#define OP_4A_PS_SUB           20
+#define OP_4A_PS_ADD           21
+#define OP_4A_PS_SEL           23
+#define OP_4A_PS_RES           24
+#define OP_4A_PS_MUL           25
+#define OP_4A_PS_RSQRTE                26
+#define OP_4A_PS_MSUB          28
+#define OP_4A_PS_MADD          29
+#define OP_4A_PS_NMSUB         30
+#define OP_4A_PS_NMADD         31
+#define OP_4X_PS_CMPO0         32
+#define OP_4X_PSQ_LUX          38
+#define OP_4XW_PSQ_STUX                39
+#define OP_4X_PS_NEG           40
+#define OP_4X_PS_CMPU1         64
+#define OP_4X_PS_MR            72
+#define OP_4X_PS_CMPO1         96
+#define OP_4X_PS_NABS          136
+#define OP_4X_PS_ABS           264
+#define OP_4X_PS_MERGE00       528
+#define OP_4X_PS_MERGE01       560
+#define OP_4X_PS_MERGE10       592
+#define OP_4X_PS_MERGE11       624
+
+#define SCALAR_NONE            0
+#define SCALAR_HIGH            (1 << 0)
+#define SCALAR_LOW             (1 << 1)
+#define SCALAR_NO_PS0          (1 << 2)
+#define SCALAR_NO_PS1          (1 << 3)
+
+#define GQR_ST_TYPE_MASK       0x00000007
+#define GQR_ST_TYPE_SHIFT      0
+#define GQR_ST_SCALE_MASK      0x00003f00
+#define GQR_ST_SCALE_SHIFT     8
+#define GQR_LD_TYPE_MASK       0x00070000
+#define GQR_LD_TYPE_SHIFT      16
+#define GQR_LD_SCALE_MASK      0x3f000000
+#define GQR_LD_SCALE_SHIFT     24
+
+#define GQR_QUANTIZE_FLOAT     0
+#define GQR_QUANTIZE_U8                4
+#define GQR_QUANTIZE_U16       5
+#define GQR_QUANTIZE_S8                6
+#define GQR_QUANTIZE_S16       7
+
+#define FPU_LS_SINGLE          0
+#define FPU_LS_DOUBLE          1
+#define FPU_LS_SINGLE_LOW      2
+
+static inline void kvmppc_sync_qpr(struct kvm_vcpu *vcpu, int rt)
+{
+       struct thread_struct t;
+
+       t.fpscr.val = vcpu->arch.fpscr;
+       cvt_df((double*)&vcpu->arch.fpr[rt], (float*)&vcpu->arch.qpr[rt], &t);
+}
+
+static void kvmppc_inject_pf(struct kvm_vcpu *vcpu, ulong eaddr, bool is_store)
+{
+       u64 dsisr;
+
+       vcpu->arch.msr = kvmppc_set_field(vcpu->arch.msr, 33, 36, 0);
+       vcpu->arch.msr = kvmppc_set_field(vcpu->arch.msr, 42, 47, 0);
+       vcpu->arch.dear = eaddr;
+       /* Page Fault */
+       dsisr = kvmppc_set_field(0, 33, 33, 1);
+       if (is_store)
+               to_book3s(vcpu)->dsisr = kvmppc_set_field(dsisr, 38, 38, 1);
+       kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_DATA_STORAGE);
+}
+
+static int kvmppc_emulate_fpr_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
+                                  int rs, ulong addr, int ls_type)
+{
+       int emulated = EMULATE_FAIL;
+       struct thread_struct t;
+       int r;
+       char tmp[8];
+       int len = sizeof(u32);
+
+       if (ls_type == FPU_LS_DOUBLE)
+               len = sizeof(u64);
+
+       t.fpscr.val = vcpu->arch.fpscr;
+
+       /* read from memory */
+       r = kvmppc_ld(vcpu, &addr, len, tmp, true);
+       vcpu->arch.paddr_accessed = addr;
+
+       if (r < 0) {
+               kvmppc_inject_pf(vcpu, addr, false);
+               goto done_load;
+       } else if (r == EMULATE_DO_MMIO) {
+               emulated = kvmppc_handle_load(run, vcpu, KVM_REG_FPR | rs, len, 1);
+               goto done_load;
+       }
+
+       emulated = EMULATE_DONE;
+
+       /* put in registers */
+       switch (ls_type) {
+       case FPU_LS_SINGLE:
+               cvt_fd((float*)tmp, (double*)&vcpu->arch.fpr[rs], &t);
+               vcpu->arch.qpr[rs] = *((u32*)tmp);
+               break;
+       case FPU_LS_DOUBLE:
+               vcpu->arch.fpr[rs] = *((u64*)tmp);
+               break;
+       }
+
+       dprintk(KERN_INFO "KVM: FPR_LD [0x%llx] at 0x%lx (%d)\n", *(u64*)tmp,
+                         addr, len);
+
+done_load:
+       return emulated;
+}
+
+static int kvmppc_emulate_fpr_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
+                                   int rs, ulong addr, int ls_type)
+{
+       int emulated = EMULATE_FAIL;
+       struct thread_struct t;
+       int r;
+       char tmp[8];
+       u64 val;
+       int len;
+
+       t.fpscr.val = vcpu->arch.fpscr;
+
+       switch (ls_type) {
+       case FPU_LS_SINGLE:
+               cvt_df((double*)&vcpu->arch.fpr[rs], (float*)tmp, &t);
+               val = *((u32*)tmp);
+               len = sizeof(u32);
+               break;
+       case FPU_LS_SINGLE_LOW:
+               *((u32*)tmp) = vcpu->arch.fpr[rs];
+               val = vcpu->arch.fpr[rs] & 0xffffffff;
+               len = sizeof(u32);
+               break;
+       case FPU_LS_DOUBLE:
+               *((u64*)tmp) = vcpu->arch.fpr[rs];
+               val = vcpu->arch.fpr[rs];
+               len = sizeof(u64);
+               break;
+       default:
+               val = 0;
+               len = 0;
+       }
+
+       r = kvmppc_st(vcpu, &addr, len, tmp, true);
+       vcpu->arch.paddr_accessed = addr;
+       if (r < 0) {
+               kvmppc_inject_pf(vcpu, addr, true);
+       } else if (r == EMULATE_DO_MMIO) {
+               emulated = kvmppc_handle_store(run, vcpu, val, len, 1);
+       } else {
+               emulated = EMULATE_DONE;
+       }
+
+       dprintk(KERN_INFO "KVM: FPR_ST [0x%llx] at 0x%lx (%d)\n",
+                         val, addr, len);
+
+       return emulated;
+}
+
+static int kvmppc_emulate_psq_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
+                                  int rs, ulong addr, bool w, int i)
+{
+       int emulated = EMULATE_FAIL;
+       struct thread_struct t;
+       int r;
+       float one = 1.0;
+       u32 tmp[2];
+
+       t.fpscr.val = vcpu->arch.fpscr;
+
+       /* read from memory */
+       if (w) {
+               r = kvmppc_ld(vcpu, &addr, sizeof(u32), tmp, true);
+               memcpy(&tmp[1], &one, sizeof(u32));
+       } else {
+               r = kvmppc_ld(vcpu, &addr, sizeof(u32) * 2, tmp, true);
+       }
+       vcpu->arch.paddr_accessed = addr;
+       if (r < 0) {
+               kvmppc_inject_pf(vcpu, addr, false);
+               goto done_load;
+       } else if ((r == EMULATE_DO_MMIO) && w) {
+               emulated = kvmppc_handle_load(run, vcpu, KVM_REG_FPR | rs, 4, 1);
+               vcpu->arch.qpr[rs] = tmp[1];
+               goto done_load;
+       } else if (r == EMULATE_DO_MMIO) {
+               emulated = kvmppc_handle_load(run, vcpu, KVM_REG_FQPR | rs, 8, 1);
+               goto done_load;
+       }
+
+       emulated = EMULATE_DONE;
+
+       /* put in registers */
+       cvt_fd((float*)&tmp[0], (double*)&vcpu->arch.fpr[rs], &t);
+       vcpu->arch.qpr[rs] = tmp[1];
+
+       dprintk(KERN_INFO "KVM: PSQ_LD [0x%x, 0x%x] at 0x%lx (%d)\n", tmp[0],
+                         tmp[1], addr, w ? 4 : 8);
+
+done_load:
+       return emulated;
+}
+
+static int kvmppc_emulate_psq_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
+                                   int rs, ulong addr, bool w, int i)
+{
+       int emulated = EMULATE_FAIL;
+       struct thread_struct t;
+       int r;
+       u32 tmp[2];
+       int len = w ? sizeof(u32) : sizeof(u64);
+
+       t.fpscr.val = vcpu->arch.fpscr;
+
+       cvt_df((double*)&vcpu->arch.fpr[rs], (float*)&tmp[0], &t);
+       tmp[1] = vcpu->arch.qpr[rs];
+
+       r = kvmppc_st(vcpu, &addr, len, tmp, true);
+       vcpu->arch.paddr_accessed = addr;
+       if (r < 0) {
+               kvmppc_inject_pf(vcpu, addr, true);
+       } else if ((r == EMULATE_DO_MMIO) && w) {
+               emulated = kvmppc_handle_store(run, vcpu, tmp[0], 4, 1);
+       } else if (r == EMULATE_DO_MMIO) {
+               u64 val = ((u64)tmp[0] << 32) | tmp[1];
+               emulated = kvmppc_handle_store(run, vcpu, val, 8, 1);
+       } else {
+               emulated = EMULATE_DONE;
+       }
+
+       dprintk(KERN_INFO "KVM: PSQ_ST [0x%x, 0x%x] at 0x%lx (%d)\n",
+                         tmp[0], tmp[1], addr, len);
+
+       return emulated;
+}
+
+/*
+ * Cuts out inst bits with ordering according to spec.
+ * That means the leftmost bit is zero. All given bits are included.
+ */
+static inline u32 inst_get_field(u32 inst, int msb, int lsb)
+{
+       return kvmppc_get_field(inst, msb + 32, lsb + 32);
+}
+
+/*
+ * Replaces inst bits with ordering according to spec.
+ */
+static inline u32 inst_set_field(u32 inst, int msb, int lsb, int value)
+{
+       return kvmppc_set_field(inst, msb + 32, lsb + 32, value);
+}
+
+bool kvmppc_inst_is_paired_single(struct kvm_vcpu *vcpu, u32 inst)
+{
+       if (!(vcpu->arch.hflags & BOOK3S_HFLAG_PAIRED_SINGLE))
+               return false;
+
+       switch (get_op(inst)) {
+       case OP_PSQ_L:
+       case OP_PSQ_LU:
+       case OP_PSQ_ST:
+       case OP_PSQ_STU:
+       case OP_LFS:
+       case OP_LFSU:
+       case OP_LFD:
+       case OP_LFDU:
+       case OP_STFS:
+       case OP_STFSU:
+       case OP_STFD:
+       case OP_STFDU:
+               return true;
+       case 4:
+               /* X form */
+               switch (inst_get_field(inst, 21, 30)) {
+               case OP_4X_PS_CMPU0:
+               case OP_4X_PSQ_LX:
+               case OP_4X_PS_CMPO0:
+               case OP_4X_PSQ_LUX:
+               case OP_4X_PS_NEG:
+               case OP_4X_PS_CMPU1:
+               case OP_4X_PS_MR:
+               case OP_4X_PS_CMPO1:
+               case OP_4X_PS_NABS:
+               case OP_4X_PS_ABS:
+               case OP_4X_PS_MERGE00:
+               case OP_4X_PS_MERGE01:
+               case OP_4X_PS_MERGE10:
+               case OP_4X_PS_MERGE11:
+                       return true;
+               }
+               /* XW form */
+               switch (inst_get_field(inst, 25, 30)) {
+               case OP_4XW_PSQ_STX:
+               case OP_4XW_PSQ_STUX:
+                       return true;
+               }
+               /* A form */
+               switch (inst_get_field(inst, 26, 30)) {
+               case OP_4A_PS_SUM1:
+               case OP_4A_PS_SUM0:
+               case OP_4A_PS_MULS0:
+               case OP_4A_PS_MULS1:
+               case OP_4A_PS_MADDS0:
+               case OP_4A_PS_MADDS1:
+               case OP_4A_PS_DIV:
+               case OP_4A_PS_SUB:
+               case OP_4A_PS_ADD:
+               case OP_4A_PS_SEL:
+               case OP_4A_PS_RES:
+               case OP_4A_PS_MUL:
+               case OP_4A_PS_RSQRTE:
+               case OP_4A_PS_MSUB:
+               case OP_4A_PS_MADD:
+               case OP_4A_PS_NMSUB:
+               case OP_4A_PS_NMADD:
+                       return true;
+               }
+               break;
+       case 59:
+               switch (inst_get_field(inst, 21, 30)) {
+               case OP_59_FADDS:
+               case OP_59_FSUBS:
+               case OP_59_FDIVS:
+               case OP_59_FRES:
+               case OP_59_FRSQRTES:
+                       return true;
+               }
+               switch (inst_get_field(inst, 26, 30)) {
+               case OP_59_FMULS:
+               case OP_59_FMSUBS:
+               case OP_59_FMADDS:
+               case OP_59_FNMSUBS:
+               case OP_59_FNMADDS:
+                       return true;
+               }
+               break;
+       case 63:
+               switch (inst_get_field(inst, 21, 30)) {
+               case OP_63_MTFSB0:
+               case OP_63_MTFSB1:
+               case OP_63_MTFSF:
+               case OP_63_MTFSFI:
+               case OP_63_MCRFS:
+               case OP_63_MFFS:
+               case OP_63_FCMPU:
+               case OP_63_FCMPO:
+               case OP_63_FNEG:
+               case OP_63_FMR:
+               case OP_63_FABS:
+               case OP_63_FRSP:
+               case OP_63_FDIV:
+               case OP_63_FADD:
+               case OP_63_FSUB:
+               case OP_63_FCTIW:
+               case OP_63_FCTIWZ:
+               case OP_63_FRSQRTE:
+               case OP_63_FCPSGN:
+                       return true;
+               }
+               switch (inst_get_field(inst, 26, 30)) {
+               case OP_63_FMUL:
+               case OP_63_FSEL:
+               case OP_63_FMSUB:
+               case OP_63_FMADD:
+               case OP_63_FNMSUB:
+               case OP_63_FNMADD:
+                       return true;
+               }
+               break;
+       case 31:
+               switch (inst_get_field(inst, 21, 30)) {
+               case OP_31_LFSX:
+               case OP_31_LFSUX:
+               case OP_31_LFDX:
+               case OP_31_LFDUX:
+               case OP_31_STFSX:
+               case OP_31_STFSUX:
+               case OP_31_STFX:
+               case OP_31_STFUX:
+               case OP_31_STFIWX:
+                       return true;
+               }
+               break;
+       }
+
+       return false;
+}
+
+static int get_d_signext(u32 inst)
+{
+       int d = inst & 0x8ff;
+
+       if (d & 0x800)
+               return -(d & 0x7ff);
+
+       return (d & 0x7ff);
+}
+
+static int kvmppc_ps_three_in(struct kvm_vcpu *vcpu, bool rc,
+                                     int reg_out, int reg_in1, int reg_in2,
+                                     int reg_in3, int scalar,
+                                     void (*func)(struct thread_struct *t,
+                                                u32 *dst, u32 *src1,
+                                                u32 *src2, u32 *src3))
+{
+       u32 *qpr = vcpu->arch.qpr;
+       u64 *fpr = vcpu->arch.fpr;
+       u32 ps0_out;
+       u32 ps0_in1, ps0_in2, ps0_in3;
+       u32 ps1_in1, ps1_in2, ps1_in3;
+       struct thread_struct t;
+       t.fpscr.val = vcpu->arch.fpscr;
+
+       /* RC */
+       WARN_ON(rc);
+
+       /* PS0 */
+       cvt_df((double*)&fpr[reg_in1], (float*)&ps0_in1, &t);
+       cvt_df((double*)&fpr[reg_in2], (float*)&ps0_in2, &t);
+       cvt_df((double*)&fpr[reg_in3], (float*)&ps0_in3, &t);
+
+       if (scalar & SCALAR_LOW)
+               ps0_in2 = qpr[reg_in2];
+
+       func(&t, &ps0_out, &ps0_in1, &ps0_in2, &ps0_in3);
+
+       dprintk(KERN_INFO "PS3 ps0 -> f(0x%x, 0x%x, 0x%x) = 0x%x\n",
+                         ps0_in1, ps0_in2, ps0_in3, ps0_out);
+
+       if (!(scalar & SCALAR_NO_PS0))
+               cvt_fd((float*)&ps0_out, (double*)&fpr[reg_out], &t);
+
+       /* PS1 */
+       ps1_in1 = qpr[reg_in1];
+       ps1_in2 = qpr[reg_in2];
+       ps1_in3 = qpr[reg_in3];
+
+       if (scalar & SCALAR_HIGH)
+               ps1_in2 = ps0_in2;
+
+       if (!(scalar & SCALAR_NO_PS1))
+               func(&t, &qpr[reg_out], &ps1_in1, &ps1_in2, &ps1_in3);
+
+       dprintk(KERN_INFO "PS3 ps1 -> f(0x%x, 0x%x, 0x%x) = 0x%x\n",
+                         ps1_in1, ps1_in2, ps1_in3, qpr[reg_out]);
+
+       return EMULATE_DONE;
+}
+
+static int kvmppc_ps_two_in(struct kvm_vcpu *vcpu, bool rc,
+                                   int reg_out, int reg_in1, int reg_in2,
+                                   int scalar,
+                                   void (*func)(struct thread_struct *t,
+                                                u32 *dst, u32 *src1,
+                                                u32 *src2))
+{
+       u32 *qpr = vcpu->arch.qpr;
+       u64 *fpr = vcpu->arch.fpr;
+       u32 ps0_out;
+       u32 ps0_in1, ps0_in2;
+       u32 ps1_out;
+       u32 ps1_in1, ps1_in2;
+       struct thread_struct t;
+       t.fpscr.val = vcpu->arch.fpscr;
+
+       /* RC */
+       WARN_ON(rc);
+
+       /* PS0 */
+       cvt_df((double*)&fpr[reg_in1], (float*)&ps0_in1, &t);
+
+       if (scalar & SCALAR_LOW)
+               ps0_in2 = qpr[reg_in2];
+       else
+               cvt_df((double*)&fpr[reg_in2], (float*)&ps0_in2, &t);
+
+       func(&t, &ps0_out, &ps0_in1, &ps0_in2);
+
+       if (!(scalar & SCALAR_NO_PS0)) {
+               dprintk(KERN_INFO "PS2 ps0 -> f(0x%x, 0x%x) = 0x%x\n",
+                                 ps0_in1, ps0_in2, ps0_out);
+
+               cvt_fd((float*)&ps0_out, (double*)&fpr[reg_out], &t);
+       }
+
+       /* PS1 */
+       ps1_in1 = qpr[reg_in1];
+       ps1_in2 = qpr[reg_in2];
+
+       if (scalar & SCALAR_HIGH)
+               ps1_in2 = ps0_in2;
+
+       func(&t, &ps1_out, &ps1_in1, &ps1_in2);
+
+       if (!(scalar & SCALAR_NO_PS1)) {
+               qpr[reg_out] = ps1_out;
+
+               dprintk(KERN_INFO "PS2 ps1 -> f(0x%x, 0x%x) = 0x%x\n",
+                                 ps1_in1, ps1_in2, qpr[reg_out]);
+       }
+
+       return EMULATE_DONE;
+}
+
+static int kvmppc_ps_one_in(struct kvm_vcpu *vcpu, bool rc,
+                                   int reg_out, int reg_in,
+                                   void (*func)(struct thread_struct *t,
+                                                u32 *dst, u32 *src1))
+{
+       u32 *qpr = vcpu->arch.qpr;
+       u64 *fpr = vcpu->arch.fpr;
+       u32 ps0_out, ps0_in;
+       u32 ps1_in;
+       struct thread_struct t;
+       t.fpscr.val = vcpu->arch.fpscr;
+
+       /* RC */
+       WARN_ON(rc);
+
+       /* PS0 */
+       cvt_df((double*)&fpr[reg_in], (float*)&ps0_in, &t);
+       func(&t, &ps0_out, &ps0_in);
+
+       dprintk(KERN_INFO "PS1 ps0 -> f(0x%x) = 0x%x\n",
+                         ps0_in, ps0_out);
+
+       cvt_fd((float*)&ps0_out, (double*)&fpr[reg_out], &t);
+
+       /* PS1 */
+       ps1_in = qpr[reg_in];
+       func(&t, &qpr[reg_out], &ps1_in);
+
+       dprintk(KERN_INFO "PS1 ps1 -> f(0x%x) = 0x%x\n",
+                         ps1_in, qpr[reg_out]);
+
+       return EMULATE_DONE;
+}
+
+int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu)
+{
+       u32 inst = kvmppc_get_last_inst(vcpu);
+       enum emulation_result emulated = EMULATE_DONE;
+
+       int ax_rd = inst_get_field(inst, 6, 10);
+       int ax_ra = inst_get_field(inst, 11, 15);
+       int ax_rb = inst_get_field(inst, 16, 20);
+       int ax_rc = inst_get_field(inst, 21, 25);
+       short full_d = inst_get_field(inst, 16, 31);
+
+       u64 *fpr_d = &vcpu->arch.fpr[ax_rd];
+       u64 *fpr_a = &vcpu->arch.fpr[ax_ra];
+       u64 *fpr_b = &vcpu->arch.fpr[ax_rb];
+       u64 *fpr_c = &vcpu->arch.fpr[ax_rc];
+
+       bool rcomp = (inst & 1) ? true : false;
+       u32 cr = kvmppc_get_cr(vcpu);
+       struct thread_struct t;
+#ifdef DEBUG
+       int i;
+#endif
+
+       t.fpscr.val = vcpu->arch.fpscr;
+
+       if (!kvmppc_inst_is_paired_single(vcpu, inst))
+               return EMULATE_FAIL;
+
+       if (!(vcpu->arch.msr & MSR_FP)) {
+               kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL);
+               return EMULATE_AGAIN;
+       }
+
+       kvmppc_giveup_ext(vcpu, MSR_FP);
+       preempt_disable();
+       enable_kernel_fp();
+       /* Do we need to clear FE0 / FE1 here? Don't think so. */
+
+#ifdef DEBUG
+       for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++) {
+               u32 f;
+               cvt_df((double*)&vcpu->arch.fpr[i], (float*)&f, &t);
+               dprintk(KERN_INFO "FPR[%d] = 0x%x / 0x%llx    QPR[%d] = 0x%x\n",
+                       i, f, vcpu->arch.fpr[i], i, vcpu->arch.qpr[i]);
+       }
+#endif
+
+       switch (get_op(inst)) {
+       case OP_PSQ_L:
+       {
+               ulong addr = ax_ra ? kvmppc_get_gpr(vcpu, ax_ra) : 0;
+               bool w = inst_get_field(inst, 16, 16) ? true : false;
+               int i = inst_get_field(inst, 17, 19);
+
+               addr += get_d_signext(inst);
+               emulated = kvmppc_emulate_psq_load(run, vcpu, ax_rd, addr, w, i);
+               break;
+       }
+       case OP_PSQ_LU:
+       {
+               ulong addr = kvmppc_get_gpr(vcpu, ax_ra);
+               bool w = inst_get_field(inst, 16, 16) ? true : false;
+               int i = inst_get_field(inst, 17, 19);
+
+               addr += get_d_signext(inst);
+               emulated = kvmppc_emulate_psq_load(run, vcpu, ax_rd, addr, w, i);
+
+               if (emulated == EMULATE_DONE)
+                       kvmppc_set_gpr(vcpu, ax_ra, addr);
+               break;
+       }
+       case OP_PSQ_ST:
+       {
+               ulong addr = ax_ra ? kvmppc_get_gpr(vcpu, ax_ra) : 0;
+               bool w = inst_get_field(inst, 16, 16) ? true : false;
+               int i = inst_get_field(inst, 17, 19);
+
+               addr += get_d_signext(inst);
+               emulated = kvmppc_emulate_psq_store(run, vcpu, ax_rd, addr, w, i);
+               break;
+       }
+       case OP_PSQ_STU:
+       {
+               ulong addr = kvmppc_get_gpr(vcpu, ax_ra);
+               bool w = inst_get_field(inst, 16, 16) ? true : false;
+               int i = inst_get_field(inst, 17, 19);
+
+               addr += get_d_signext(inst);
+               emulated = kvmppc_emulate_psq_store(run, vcpu, ax_rd, addr, w, i);
+
+               if (emulated == EMULATE_DONE)
+                       kvmppc_set_gpr(vcpu, ax_ra, addr);
+               break;
+       }
+       case 4:
+               /* X form */
+               switch (inst_get_field(inst, 21, 30)) {
+               case OP_4X_PS_CMPU0:
+                       /* XXX */
+                       emulated = EMULATE_FAIL;
+                       break;
+               case OP_4X_PSQ_LX:
+               {
+                       ulong addr = ax_ra ? kvmppc_get_gpr(vcpu, ax_ra) : 0;
+                       bool w = inst_get_field(inst, 21, 21) ? true : false;
+                       int i = inst_get_field(inst, 22, 24);
+
+                       addr += kvmppc_get_gpr(vcpu, ax_rb);
+                       emulated = kvmppc_emulate_psq_load(run, vcpu, ax_rd, addr, w, i);
+                       break;
+               }
+               case OP_4X_PS_CMPO0:
+                       /* XXX */
+                       emulated = EMULATE_FAIL;
+                       break;
+               case OP_4X_PSQ_LUX:
+               {
+                       ulong addr = kvmppc_get_gpr(vcpu, ax_ra);
+                       bool w = inst_get_field(inst, 21, 21) ? true : false;
+                       int i = inst_get_field(inst, 22, 24);
+
+                       addr += kvmppc_get_gpr(vcpu, ax_rb);
+                       emulated = kvmppc_emulate_psq_load(run, vcpu, ax_rd, addr, w, i);
+
+                       if (emulated == EMULATE_DONE)
+                               kvmppc_set_gpr(vcpu, ax_ra, addr);
+                       break;
+               }
+               case OP_4X_PS_NEG:
+                       vcpu->arch.fpr[ax_rd] = vcpu->arch.fpr[ax_rb];
+                       vcpu->arch.fpr[ax_rd] ^= 0x8000000000000000ULL;
+                       vcpu->arch.qpr[ax_rd] = vcpu->arch.qpr[ax_rb];
+                       vcpu->arch.qpr[ax_rd] ^= 0x80000000;
+                       break;
+               case OP_4X_PS_CMPU1:
+                       /* XXX */
+                       emulated = EMULATE_FAIL;
+                       break;
+               case OP_4X_PS_MR:
+                       WARN_ON(rcomp);
+                       vcpu->arch.fpr[ax_rd] = vcpu->arch.fpr[ax_rb];
+                       vcpu->arch.qpr[ax_rd] = vcpu->arch.qpr[ax_rb];
+                       break;
+               case OP_4X_PS_CMPO1:
+                       /* XXX */
+                       emulated = EMULATE_FAIL;
+                       break;
+               case OP_4X_PS_NABS:
+                       WARN_ON(rcomp);
+                       vcpu->arch.fpr[ax_rd] = vcpu->arch.fpr[ax_rb];
+                       vcpu->arch.fpr[ax_rd] |= 0x8000000000000000ULL;
+                       vcpu->arch.qpr[ax_rd] = vcpu->arch.qpr[ax_rb];
+                       vcpu->arch.qpr[ax_rd] |= 0x80000000;
+                       break;
+               case OP_4X_PS_ABS:
+                       WARN_ON(rcomp);
+                       vcpu->arch.fpr[ax_rd] = vcpu->arch.fpr[ax_rb];
+                       vcpu->arch.fpr[ax_rd] &= ~0x8000000000000000ULL;
+                       vcpu->arch.qpr[ax_rd] = vcpu->arch.qpr[ax_rb];
+                       vcpu->arch.qpr[ax_rd] &= ~0x80000000;
+                       break;
+               case OP_4X_PS_MERGE00:
+                       WARN_ON(rcomp);
+                       vcpu->arch.fpr[ax_rd] = vcpu->arch.fpr[ax_ra];
+                       /* vcpu->arch.qpr[ax_rd] = vcpu->arch.fpr[ax_rb]; */
+                       cvt_df((double*)&vcpu->arch.fpr[ax_rb],
+                              (float*)&vcpu->arch.qpr[ax_rd], &t);
+                       break;
+               case OP_4X_PS_MERGE01:
+                       WARN_ON(rcomp);
+                       vcpu->arch.fpr[ax_rd] = vcpu->arch.fpr[ax_ra];
+                       vcpu->arch.qpr[ax_rd] = vcpu->arch.qpr[ax_rb];
+                       break;
+               case OP_4X_PS_MERGE10:
+                       WARN_ON(rcomp);
+                       /* vcpu->arch.fpr[ax_rd] = vcpu->arch.qpr[ax_ra]; */
+                       cvt_fd((float*)&vcpu->arch.qpr[ax_ra],
+                              (double*)&vcpu->arch.fpr[ax_rd], &t);
+                       /* vcpu->arch.qpr[ax_rd] = vcpu->arch.fpr[ax_rb]; */
+                       cvt_df((double*)&vcpu->arch.fpr[ax_rb],
+                              (float*)&vcpu->arch.qpr[ax_rd], &t);
+                       break;
+               case OP_4X_PS_MERGE11:
+                       WARN_ON(rcomp);
+                       /* vcpu->arch.fpr[ax_rd] = vcpu->arch.qpr[ax_ra]; */
+                       cvt_fd((float*)&vcpu->arch.qpr[ax_ra],
+                              (double*)&vcpu->arch.fpr[ax_rd], &t);
+                       vcpu->arch.qpr[ax_rd] = vcpu->arch.qpr[ax_rb];
+                       break;
+               }
+               /* XW form */
+               switch (inst_get_field(inst, 25, 30)) {
+               case OP_4XW_PSQ_STX:
+               {
+                       ulong addr = ax_ra ? kvmppc_get_gpr(vcpu, ax_ra) : 0;
+                       bool w = inst_get_field(inst, 21, 21) ? true : false;
+                       int i = inst_get_field(inst, 22, 24);
+
+                       addr += kvmppc_get_gpr(vcpu, ax_rb);
+                       emulated = kvmppc_emulate_psq_store(run, vcpu, ax_rd, addr, w, i);
+                       break;
+               }
+               case OP_4XW_PSQ_STUX:
+               {
+                       ulong addr = kvmppc_get_gpr(vcpu, ax_ra);
+                       bool w = inst_get_field(inst, 21, 21) ? true : false;
+                       int i = inst_get_field(inst, 22, 24);
+
+                       addr += kvmppc_get_gpr(vcpu, ax_rb);
+                       emulated = kvmppc_emulate_psq_store(run, vcpu, ax_rd, addr, w, i);
+
+                       if (emulated == EMULATE_DONE)
+                               kvmppc_set_gpr(vcpu, ax_ra, addr);
+                       break;
+               }
+               }
+               /* A form */
+               switch (inst_get_field(inst, 26, 30)) {
+               case OP_4A_PS_SUM1:
+                       emulated = kvmppc_ps_two_in(vcpu, rcomp, ax_rd,
+                                       ax_rb, ax_ra, SCALAR_NO_PS0 | SCALAR_HIGH, fps_fadds);
+                       vcpu->arch.fpr[ax_rd] = vcpu->arch.fpr[ax_rc];
+                       break;
+               case OP_4A_PS_SUM0:
+                       emulated = kvmppc_ps_two_in(vcpu, rcomp, ax_rd,
+                                       ax_ra, ax_rb, SCALAR_NO_PS1 | SCALAR_LOW, fps_fadds);
+                       vcpu->arch.qpr[ax_rd] = vcpu->arch.qpr[ax_rc];
+                       break;
+               case OP_4A_PS_MULS0:
+                       emulated = kvmppc_ps_two_in(vcpu, rcomp, ax_rd,
+                                       ax_ra, ax_rc, SCALAR_HIGH, fps_fmuls);
+                       break;
+               case OP_4A_PS_MULS1:
+                       emulated = kvmppc_ps_two_in(vcpu, rcomp, ax_rd,
+                                       ax_ra, ax_rc, SCALAR_LOW, fps_fmuls);
+                       break;
+               case OP_4A_PS_MADDS0:
+                       emulated = kvmppc_ps_three_in(vcpu, rcomp, ax_rd,
+                                       ax_ra, ax_rc, ax_rb, SCALAR_HIGH, fps_fmadds);
+                       break;
+               case OP_4A_PS_MADDS1:
+                       emulated = kvmppc_ps_three_in(vcpu, rcomp, ax_rd,
+                                       ax_ra, ax_rc, ax_rb, SCALAR_LOW, fps_fmadds);
+                       break;
+               case OP_4A_PS_DIV:
+                       emulated = kvmppc_ps_two_in(vcpu, rcomp, ax_rd,
+                                       ax_ra, ax_rb, SCALAR_NONE, fps_fdivs);
+                       break;
+               case OP_4A_PS_SUB:
+                       emulated = kvmppc_ps_two_in(vcpu, rcomp, ax_rd,
+                                       ax_ra, ax_rb, SCALAR_NONE, fps_fsubs);
+                       break;
+               case OP_4A_PS_ADD:
+                       emulated = kvmppc_ps_two_in(vcpu, rcomp, ax_rd,
+                                       ax_ra, ax_rb, SCALAR_NONE, fps_fadds);
+                       break;
+               case OP_4A_PS_SEL:
+                       emulated = kvmppc_ps_three_in(vcpu, rcomp, ax_rd,
+                                       ax_ra, ax_rc, ax_rb, SCALAR_NONE, fps_fsel);
+                       break;
+               case OP_4A_PS_RES:
+                       emulated = kvmppc_ps_one_in(vcpu, rcomp, ax_rd,
+                                       ax_rb, fps_fres);
+                       break;
+               case OP_4A_PS_MUL:
+                       emulated = kvmppc_ps_two_in(vcpu, rcomp, ax_rd,
+                                       ax_ra, ax_rc, SCALAR_NONE, fps_fmuls);
+                       break;
+               case OP_4A_PS_RSQRTE:
+                       emulated = kvmppc_ps_one_in(vcpu, rcomp, ax_rd,
+                                       ax_rb, fps_frsqrte);
+                       break;
+               case OP_4A_PS_MSUB:
+                       emulated = kvmppc_ps_three_in(vcpu, rcomp, ax_rd,
+                                       ax_ra, ax_rc, ax_rb, SCALAR_NONE, fps_fmsubs);
+                       break;
+               case OP_4A_PS_MADD:
+                       emulated = kvmppc_ps_three_in(vcpu, rcomp, ax_rd,
+                                       ax_ra, ax_rc, ax_rb, SCALAR_NONE, fps_fmadds);
+                       break;
+               case OP_4A_PS_NMSUB:
+                       emulated = kvmppc_ps_three_in(vcpu, rcomp, ax_rd,
+                                       ax_ra, ax_rc, ax_rb, SCALAR_NONE, fps_fnmsubs);
+                       break;
+               case OP_4A_PS_NMADD:
+                       emulated = kvmppc_ps_three_in(vcpu, rcomp, ax_rd,
+                                       ax_ra, ax_rc, ax_rb, SCALAR_NONE, fps_fnmadds);
+                       break;
+               }
+               break;
+
+       /* Real FPU operations */
+
+       case OP_LFS:
+       {
+               ulong addr = (ax_ra ? kvmppc_get_gpr(vcpu, ax_ra) : 0) + full_d;
+
+               emulated = kvmppc_emulate_fpr_load(run, vcpu, ax_rd, addr,
+                                                  FPU_LS_SINGLE);
+               break;
+       }
+       case OP_LFSU:
+       {
+               ulong addr = kvmppc_get_gpr(vcpu, ax_ra) + full_d;
+
+               emulated = kvmppc_emulate_fpr_load(run, vcpu, ax_rd, addr,
+                                                  FPU_LS_SINGLE);
+
+               if (emulated == EMULATE_DONE)
+                       kvmppc_set_gpr(vcpu, ax_ra, addr);
+               break;
+       }
+       case OP_LFD:
+       {
+               ulong addr = (ax_ra ? kvmppc_get_gpr(vcpu, ax_ra) : 0) + full_d;
+
+               emulated = kvmppc_emulate_fpr_load(run, vcpu, ax_rd, addr,
+                                                  FPU_LS_DOUBLE);
+               break;
+       }
+       case OP_LFDU:
+       {
+               ulong addr = kvmppc_get_gpr(vcpu, ax_ra) + full_d;
+
+               emulated = kvmppc_emulate_fpr_load(run, vcpu, ax_rd, addr,
+                                                  FPU_LS_DOUBLE);
+
+               if (emulated == EMULATE_DONE)
+                       kvmppc_set_gpr(vcpu, ax_ra, addr);
+               break;
+       }
+       case OP_STFS:
+       {
+               ulong addr = (ax_ra ? kvmppc_get_gpr(vcpu, ax_ra) : 0) + full_d;
+
+               emulated = kvmppc_emulate_fpr_store(run, vcpu, ax_rd, addr,
+                                                   FPU_LS_SINGLE);
+               break;
+       }
+       case OP_STFSU:
+       {
+               ulong addr = kvmppc_get_gpr(vcpu, ax_ra) + full_d;
+
+               emulated = kvmppc_emulate_fpr_store(run, vcpu, ax_rd, addr,
+                                                   FPU_LS_SINGLE);
+
+               if (emulated == EMULATE_DONE)
+                       kvmppc_set_gpr(vcpu, ax_ra, addr);
+               break;
+       }
+       case OP_STFD:
+       {
+               ulong addr = (ax_ra ? kvmppc_get_gpr(vcpu, ax_ra) : 0) + full_d;
+
+               emulated = kvmppc_emulate_fpr_store(run, vcpu, ax_rd, addr,
+                                                   FPU_LS_DOUBLE);
+               break;
+       }
+       case OP_STFDU:
+       {
+               ulong addr = kvmppc_get_gpr(vcpu, ax_ra) + full_d;
+
+               emulated = kvmppc_emulate_fpr_store(run, vcpu, ax_rd, addr,
+                                                   FPU_LS_DOUBLE);
+
+               if (emulated == EMULATE_DONE)
+                       kvmppc_set_gpr(vcpu, ax_ra, addr);
+               break;
+       }
+       case 31:
+               switch (inst_get_field(inst, 21, 30)) {
+               case OP_31_LFSX:
+               {
+                       ulong addr = ax_ra ? kvmppc_get_gpr(vcpu, ax_ra) : 0;
+
+                       addr += kvmppc_get_gpr(vcpu, ax_rb);
+                       emulated = kvmppc_emulate_fpr_load(run, vcpu, ax_rd,
+                                                          addr, FPU_LS_SINGLE);
+                       break;
+               }
+               case OP_31_LFSUX:
+               {
+                       ulong addr = kvmppc_get_gpr(vcpu, ax_ra) +
+                                    kvmppc_get_gpr(vcpu, ax_rb);
+
+                       emulated = kvmppc_emulate_fpr_load(run, vcpu, ax_rd,
+                                                          addr, FPU_LS_SINGLE);
+
+                       if (emulated == EMULATE_DONE)
+                               kvmppc_set_gpr(vcpu, ax_ra, addr);
+                       break;
+               }
+               case OP_31_LFDX:
+               {
+                       ulong addr = (ax_ra ? kvmppc_get_gpr(vcpu, ax_ra) : 0) +
+                                    kvmppc_get_gpr(vcpu, ax_rb);
+
+                       emulated = kvmppc_emulate_fpr_load(run, vcpu, ax_rd,
+                                                          addr, FPU_LS_DOUBLE);
+                       break;
+               }
+               case OP_31_LFDUX:
+               {
+                       ulong addr = kvmppc_get_gpr(vcpu, ax_ra) +
+                                    kvmppc_get_gpr(vcpu, ax_rb);
+
+                       emulated = kvmppc_emulate_fpr_load(run, vcpu, ax_rd,
+                                                          addr, FPU_LS_DOUBLE);
+
+                       if (emulated == EMULATE_DONE)
+                               kvmppc_set_gpr(vcpu, ax_ra, addr);
+                       break;
+               }
+               case OP_31_STFSX:
+               {
+                       ulong addr = (ax_ra ? kvmppc_get_gpr(vcpu, ax_ra) : 0) +
+                                    kvmppc_get_gpr(vcpu, ax_rb);
+
+                       emulated = kvmppc_emulate_fpr_store(run, vcpu, ax_rd,
+                                                           addr, FPU_LS_SINGLE);
+                       break;
+               }
+               case OP_31_STFSUX:
+               {
+                       ulong addr = kvmppc_get_gpr(vcpu, ax_ra) +
+                                    kvmppc_get_gpr(vcpu, ax_rb);
+
+                       emulated = kvmppc_emulate_fpr_store(run, vcpu, ax_rd,
+                                                           addr, FPU_LS_SINGLE);
+
+                       if (emulated == EMULATE_DONE)
+                               kvmppc_set_gpr(vcpu, ax_ra, addr);
+                       break;
+               }
+               case OP_31_STFX:
+               {
+                       ulong addr = (ax_ra ? kvmppc_get_gpr(vcpu, ax_ra) : 0) +
+                                    kvmppc_get_gpr(vcpu, ax_rb);
+
+                       emulated = kvmppc_emulate_fpr_store(run, vcpu, ax_rd,
+                                                           addr, FPU_LS_DOUBLE);
+                       break;
+               }
+               case OP_31_STFUX:
+               {
+                       ulong addr = kvmppc_get_gpr(vcpu, ax_ra) +
+                                    kvmppc_get_gpr(vcpu, ax_rb);
+
+                       emulated = kvmppc_emulate_fpr_store(run, vcpu, ax_rd,
+                                                           addr, FPU_LS_DOUBLE);
+
+                       if (emulated == EMULATE_DONE)
+                               kvmppc_set_gpr(vcpu, ax_ra, addr);
+                       break;
+               }
+               case OP_31_STFIWX:
+               {
+                       ulong addr = (ax_ra ? kvmppc_get_gpr(vcpu, ax_ra) : 0) +
+                                    kvmppc_get_gpr(vcpu, ax_rb);
+
+                       emulated = kvmppc_emulate_fpr_store(run, vcpu, ax_rd,
+                                                           addr,
+                                                           FPU_LS_SINGLE_LOW);
+                       break;
+               }
+                       break;
+               }
+               break;
+       case 59:
+               switch (inst_get_field(inst, 21, 30)) {
+               case OP_59_FADDS:
+                       fpd_fadds(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_b);
+                       kvmppc_sync_qpr(vcpu, ax_rd);
+                       break;
+               case OP_59_FSUBS:
+                       fpd_fsubs(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_b);
+                       kvmppc_sync_qpr(vcpu, ax_rd);
+                       break;
+               case OP_59_FDIVS:
+                       fpd_fdivs(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_b);
+                       kvmppc_sync_qpr(vcpu, ax_rd);
+                       break;
+               case OP_59_FRES:
+                       fpd_fres(&vcpu->arch.fpscr, &cr, fpr_d, fpr_b);
+                       kvmppc_sync_qpr(vcpu, ax_rd);
+                       break;
+               case OP_59_FRSQRTES:
+                       fpd_frsqrtes(&vcpu->arch.fpscr, &cr, fpr_d, fpr_b);
+                       kvmppc_sync_qpr(vcpu, ax_rd);
+                       break;
+               }
+               switch (inst_get_field(inst, 26, 30)) {
+               case OP_59_FMULS:
+                       fpd_fmuls(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c);
+                       kvmppc_sync_qpr(vcpu, ax_rd);
+                       break;
+               case OP_59_FMSUBS:
+                       fpd_fmsubs(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
+                       kvmppc_sync_qpr(vcpu, ax_rd);
+                       break;
+               case OP_59_FMADDS:
+                       fpd_fmadds(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
+                       kvmppc_sync_qpr(vcpu, ax_rd);
+                       break;
+               case OP_59_FNMSUBS:
+                       fpd_fnmsubs(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
+                       kvmppc_sync_qpr(vcpu, ax_rd);
+                       break;
+               case OP_59_FNMADDS:
+                       fpd_fnmadds(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
+                       kvmppc_sync_qpr(vcpu, ax_rd);
+                       break;
+               }
+               break;
+       case 63:
+               switch (inst_get_field(inst, 21, 30)) {
+               case OP_63_MTFSB0:
+               case OP_63_MTFSB1:
+               case OP_63_MCRFS:
+               case OP_63_MTFSFI:
+                       /* XXX need to implement */
+                       break;
+               case OP_63_MFFS:
+                       /* XXX missing CR */
+                       *fpr_d = vcpu->arch.fpscr;
+                       break;
+               case OP_63_MTFSF:
+                       /* XXX missing fm bits */
+                       /* XXX missing CR */
+                       vcpu->arch.fpscr = *fpr_b;
+                       break;
+               case OP_63_FCMPU:
+               {
+                       u32 tmp_cr;
+                       u32 cr0_mask = 0xf0000000;
+                       u32 cr_shift = inst_get_field(inst, 6, 8) * 4;
+
+                       fpd_fcmpu(&vcpu->arch.fpscr, &tmp_cr, fpr_a, fpr_b);
+                       cr &= ~(cr0_mask >> cr_shift);
+                       cr |= (cr & cr0_mask) >> cr_shift;
+                       break;
+               }
+               case OP_63_FCMPO:
+               {
+                       u32 tmp_cr;
+                       u32 cr0_mask = 0xf0000000;
+                       u32 cr_shift = inst_get_field(inst, 6, 8) * 4;
+
+                       fpd_fcmpo(&vcpu->arch.fpscr, &tmp_cr, fpr_a, fpr_b);
+                       cr &= ~(cr0_mask >> cr_shift);
+                       cr |= (cr & cr0_mask) >> cr_shift;
+                       break;
+               }
+               case OP_63_FNEG:
+                       fpd_fneg(&vcpu->arch.fpscr, &cr, fpr_d, fpr_b);
+                       break;
+               case OP_63_FMR:
+                       *fpr_d = *fpr_b;
+                       break;
+               case OP_63_FABS:
+                       fpd_fabs(&vcpu->arch.fpscr, &cr, fpr_d, fpr_b);
+                       break;
+               case OP_63_FCPSGN:
+                       fpd_fcpsgn(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_b);
+                       break;
+               case OP_63_FDIV:
+                       fpd_fdiv(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_b);
+                       break;
+               case OP_63_FADD:
+                       fpd_fadd(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_b);
+                       break;
+               case OP_63_FSUB:
+                       fpd_fsub(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_b);
+                       break;
+               case OP_63_FCTIW:
+                       fpd_fctiw(&vcpu->arch.fpscr, &cr, fpr_d, fpr_b);
+                       break;
+               case OP_63_FCTIWZ:
+                       fpd_fctiwz(&vcpu->arch.fpscr, &cr, fpr_d, fpr_b);
+                       break;
+               case OP_63_FRSP:
+                       fpd_frsp(&vcpu->arch.fpscr, &cr, fpr_d, fpr_b);
+                       kvmppc_sync_qpr(vcpu, ax_rd);
+                       break;
+               case OP_63_FRSQRTE:
+               {
+                       double one = 1.0f;
+
+                       /* fD = sqrt(fB) */
+                       fpd_fsqrt(&vcpu->arch.fpscr, &cr, fpr_d, fpr_b);
+                       /* fD = 1.0f / fD */
+                       fpd_fdiv(&vcpu->arch.fpscr, &cr, fpr_d, (u64*)&one, fpr_d);
+                       break;
+               }
+               }
+               switch (inst_get_field(inst, 26, 30)) {
+               case OP_63_FMUL:
+                       fpd_fmul(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c);
+                       break;
+               case OP_63_FSEL:
+                       fpd_fsel(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
+                       break;
+               case OP_63_FMSUB:
+                       fpd_fmsub(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
+                       break;
+               case OP_63_FMADD:
+                       fpd_fmadd(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
+                       break;
+               case OP_63_FNMSUB:
+                       fpd_fnmsub(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
+                       break;
+               case OP_63_FNMADD:
+                       fpd_fnmadd(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
+                       break;
+               }
+               break;
+       }
+
+#ifdef DEBUG
+       for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++) {
+               u32 f;
+               cvt_df((double*)&vcpu->arch.fpr[i], (float*)&f, &t);
+               dprintk(KERN_INFO "FPR[%d] = 0x%x\n", i, f);
+       }
+#endif
+
+       if (rcomp)
+               kvmppc_set_cr(vcpu, cr);
+
+       preempt_enable();
+
+       return emulated;
+}
similarity index 62%
rename from arch/powerpc/kvm/book3s_64_rmhandlers.S
rename to arch/powerpc/kvm/book3s_rmhandlers.S
index c83c60ad96c58a791b01913e481a2316a81882a4..506d5c316c966b2d30f265818827286ee61c69e1 100644 (file)
 #include <asm/reg.h>
 #include <asm/page.h>
 #include <asm/asm-offsets.h>
+
+#ifdef CONFIG_PPC_BOOK3S_64
 #include <asm/exception-64s.h>
+#endif
 
 /*****************************************************************************
  *                                                                           *
  *                                                                           *
  ****************************************************************************/
 
+#if defined(CONFIG_PPC_BOOK3S_64)
+
+#define LOAD_SHADOW_VCPU(reg)                          \
+       mfspr   reg, SPRN_SPRG_PACA
+
+#define SHADOW_VCPU_OFF                PACA_KVM_SVCPU
+#define MSR_NOIRQ              MSR_KERNEL & ~(MSR_IR | MSR_DR)
+#define FUNC(name)             GLUE(.,name)
+
+#elif defined(CONFIG_PPC_BOOK3S_32)
+
+#define LOAD_SHADOW_VCPU(reg)                                          \
+       mfspr   reg, SPRN_SPRG_THREAD;                                  \
+       lwz     reg, THREAD_KVM_SVCPU(reg);                             \
+       /* PPC32 can have a NULL pointer - let's check for that */      \
+       mtspr   SPRN_SPRG_SCRATCH1, r12;        /* Save r12 */          \
+       mfcr    r12;                                                    \
+       cmpwi   reg, 0;                                                 \
+       bne     1f;                                                     \
+       mfspr   reg, SPRN_SPRG_SCRATCH0;                                \
+       mtcr    r12;                                                    \
+       mfspr   r12, SPRN_SPRG_SCRATCH1;                                \
+       b       kvmppc_resume_\intno;                                   \
+1:;                                                                    \
+       mtcr    r12;                                                    \
+       mfspr   r12, SPRN_SPRG_SCRATCH1;                                \
+       tophys(reg, reg)
+
+#define SHADOW_VCPU_OFF                0
+#define MSR_NOIRQ              MSR_KERNEL
+#define FUNC(name)             name
+
+#endif
 
 .macro INTERRUPT_TRAMPOLINE intno
 
@@ -42,19 +78,19 @@ kvmppc_trampoline_\intno:
         * First thing to do is to find out if we're coming
         * from a KVM guest or a Linux process.
         *
-        * To distinguish, we check a magic byte in the PACA
+        * To distinguish, we check a magic byte in the PACA/current
         */
-       mfspr   r13, SPRN_SPRG_PACA             /* r13 = PACA */
-       std     r12, PACA_KVM_SCRATCH0(r13)
+       LOAD_SHADOW_VCPU(r13)
+       PPC_STL r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH0)(r13)
        mfcr    r12
-       stw     r12, PACA_KVM_SCRATCH1(r13)
-       lbz     r12, PACA_KVM_IN_GUEST(r13)
+       stw     r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH1)(r13)
+       lbz     r12, (SHADOW_VCPU_OFF + SVCPU_IN_GUEST)(r13)
        cmpwi   r12, KVM_GUEST_MODE_NONE
        bne     ..kvmppc_handler_hasmagic_\intno
        /* No KVM guest? Then jump back to the Linux handler! */
-       lwz     r12, PACA_KVM_SCRATCH1(r13)
+       lwz     r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH1)(r13)
        mtcr    r12
-       ld      r12, PACA_KVM_SCRATCH0(r13)
+       PPC_LL  r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH0)(r13)
        mfspr   r13, SPRN_SPRG_SCRATCH0         /* r13 = original r13 */
        b       kvmppc_resume_\intno            /* Get back original handler */
 
@@ -76,9 +112,7 @@ kvmppc_trampoline_\intno:
 INTERRUPT_TRAMPOLINE   BOOK3S_INTERRUPT_SYSTEM_RESET
 INTERRUPT_TRAMPOLINE   BOOK3S_INTERRUPT_MACHINE_CHECK
 INTERRUPT_TRAMPOLINE   BOOK3S_INTERRUPT_DATA_STORAGE
-INTERRUPT_TRAMPOLINE   BOOK3S_INTERRUPT_DATA_SEGMENT
 INTERRUPT_TRAMPOLINE   BOOK3S_INTERRUPT_INST_STORAGE
-INTERRUPT_TRAMPOLINE   BOOK3S_INTERRUPT_INST_SEGMENT
 INTERRUPT_TRAMPOLINE   BOOK3S_INTERRUPT_EXTERNAL
 INTERRUPT_TRAMPOLINE   BOOK3S_INTERRUPT_ALIGNMENT
 INTERRUPT_TRAMPOLINE   BOOK3S_INTERRUPT_PROGRAM
@@ -88,7 +122,14 @@ INTERRUPT_TRAMPOLINE        BOOK3S_INTERRUPT_SYSCALL
 INTERRUPT_TRAMPOLINE   BOOK3S_INTERRUPT_TRACE
 INTERRUPT_TRAMPOLINE   BOOK3S_INTERRUPT_PERFMON
 INTERRUPT_TRAMPOLINE   BOOK3S_INTERRUPT_ALTIVEC
+
+/* Those are only available on 64 bit machines */
+
+#ifdef CONFIG_PPC_BOOK3S_64
+INTERRUPT_TRAMPOLINE   BOOK3S_INTERRUPT_DATA_SEGMENT
+INTERRUPT_TRAMPOLINE   BOOK3S_INTERRUPT_INST_SEGMENT
 INTERRUPT_TRAMPOLINE   BOOK3S_INTERRUPT_VSX
+#endif
 
 /*
  * Bring us back to the faulting code, but skip the
@@ -99,11 +140,11 @@ INTERRUPT_TRAMPOLINE       BOOK3S_INTERRUPT_VSX
  *
  * Input Registers:
  *
- * R12               = free
- * R13               = PACA
- * PACA.KVM.SCRATCH0 = guest R12
- * PACA.KVM.SCRATCH1 = guest CR
- * SPRG_SCRATCH0     = guest R13
+ * R12            = free
+ * R13            = Shadow VCPU (PACA)
+ * SVCPU.SCRATCH0 = guest R12
+ * SVCPU.SCRATCH1 = guest CR
+ * SPRG_SCRATCH0  = guest R13
  *
  */
 kvmppc_handler_skip_ins:
@@ -114,9 +155,9 @@ kvmppc_handler_skip_ins:
        mtsrr0  r12
 
        /* Clean up all state */
-       lwz     r12, PACA_KVM_SCRATCH1(r13)
+       lwz     r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH1)(r13)
        mtcr    r12
-       ld      r12, PACA_KVM_SCRATCH0(r13)
+       PPC_LL  r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH0)(r13)
        mfspr   r13, SPRN_SPRG_SCRATCH0
 
        /* And get back into the code */
@@ -147,41 +188,48 @@ kvmppc_handler_lowmem_trampoline_end:
  *
  * R3 = function
  * R4 = MSR
- * R5 = CTR
+ * R5 = scratch register
  *
  */
 _GLOBAL(kvmppc_rmcall)
-       mtmsr   r4              /* Disable relocation, so mtsrr
+       LOAD_REG_IMMEDIATE(r5, MSR_NOIRQ)
+       mtmsr   r5              /* Disable relocation and interrupts, so mtsrr
                                   doesn't get interrupted */
-       mtctr   r5
+       sync
        mtsrr0  r3
        mtsrr1  r4
        RFI
 
+#if defined(CONFIG_PPC_BOOK3S_32)
+#define STACK_LR       INT_FRAME_SIZE+4
+#elif defined(CONFIG_PPC_BOOK3S_64)
+#define STACK_LR       _LINK
+#endif
+
 /*
  * Activate current's external feature (FPU/Altivec/VSX)
  */
-#define define_load_up(what)                           \
-                                                       \
-_GLOBAL(kvmppc_load_up_ ## what);                      \
-       subi    r1, r1, INT_FRAME_SIZE;                 \
-       mflr    r3;                                     \
-       std     r3, _LINK(r1);                          \
-       mfmsr   r4;                                     \
-       std     r31, GPR3(r1);                          \
-       mr      r31, r4;                                \
-       li      r5, MSR_DR;                             \
-       oris    r5, r5, MSR_EE@h;                       \
-       andc    r4, r4, r5;                             \
-       mtmsr   r4;                                     \
-                                                       \
-       bl      .load_up_ ## what;                      \
-                                                       \
-       mtmsr   r31;                                    \
-       ld      r3, _LINK(r1);                          \
-       ld      r31, GPR3(r1);                          \
-       addi    r1, r1, INT_FRAME_SIZE;                 \
-       mtlr    r3;                                     \
+#define define_load_up(what)                                   \
+                                                               \
+_GLOBAL(kvmppc_load_up_ ## what);                              \
+       PPC_STLU r1, -INT_FRAME_SIZE(r1);                       \
+       mflr    r3;                                             \
+       PPC_STL r3, STACK_LR(r1);                               \
+       PPC_STL r20, _NIP(r1);                                  \
+       mfmsr   r20;                                            \
+       LOAD_REG_IMMEDIATE(r3, MSR_DR|MSR_EE);                  \
+       andc    r3,r20,r3;              /* Disable DR,EE */     \
+       mtmsr   r3;                                             \
+       sync;                                                   \
+                                                               \
+       bl      FUNC(load_up_ ## what);                         \
+                                                               \
+       mtmsr   r20;                    /* Enable DR,EE */      \
+       sync;                                                   \
+       PPC_LL  r3, STACK_LR(r1);                               \
+       PPC_LL  r20, _NIP(r1);                                  \
+       mtlr    r3;                                             \
+       addi    r1, r1, INT_FRAME_SIZE;                         \
        blr
 
 define_load_up(fpu)
@@ -194,11 +242,10 @@ define_load_up(vsx)
 
 .global kvmppc_trampoline_lowmem
 kvmppc_trampoline_lowmem:
-       .long kvmppc_handler_lowmem_trampoline - _stext
+       .long kvmppc_handler_lowmem_trampoline - CONFIG_KERNEL_START
 
 .global kvmppc_trampoline_enter
 kvmppc_trampoline_enter:
-       .long kvmppc_handler_trampoline_enter - _stext
-
-#include "book3s_64_slb.S"
+       .long kvmppc_handler_trampoline_enter - CONFIG_KERNEL_START
 
+#include "book3s_segment.S"
diff --git a/arch/powerpc/kvm/book3s_segment.S b/arch/powerpc/kvm/book3s_segment.S
new file mode 100644 (file)
index 0000000..7c52ed0
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright SUSE Linux Products GmbH 2010
+ *
+ * Authors: Alexander Graf <agraf@suse.de>
+ */
+
+/* Real mode helpers */
+
+#if defined(CONFIG_PPC_BOOK3S_64)
+
+#define GET_SHADOW_VCPU(reg)    \
+       addi    reg, r13, PACA_KVM_SVCPU
+
+#elif defined(CONFIG_PPC_BOOK3S_32)
+
+#define GET_SHADOW_VCPU(reg)                           \
+       tophys(reg, r2);                        \
+       lwz     reg, (THREAD + THREAD_KVM_SVCPU)(reg);  \
+       tophys(reg, reg)
+
+#endif
+
+/* Disable for nested KVM */
+#define USE_QUICK_LAST_INST
+
+
+/* Get helper functions for subarch specific functionality */
+
+#if defined(CONFIG_PPC_BOOK3S_64)
+#include "book3s_64_slb.S"
+#elif defined(CONFIG_PPC_BOOK3S_32)
+#include "book3s_32_sr.S"
+#endif
+
+/******************************************************************************
+ *                                                                            *
+ *                               Entry code                                   *
+ *                                                                            *
+ *****************************************************************************/
+
+.global kvmppc_handler_trampoline_enter
+kvmppc_handler_trampoline_enter:
+
+       /* Required state:
+        *
+        * MSR = ~IR|DR
+        * R13 = PACA
+        * R1 = host R1
+        * R2 = host R2
+        * R10 = guest MSR
+        * all other volatile GPRS = free
+        * SVCPU[CR] = guest CR
+        * SVCPU[XER] = guest XER
+        * SVCPU[CTR] = guest CTR
+        * SVCPU[LR] = guest LR
+        */
+
+       /* r3 = shadow vcpu */
+       GET_SHADOW_VCPU(r3)
+
+       /* Move SRR0 and SRR1 into the respective regs */
+       PPC_LL  r9, SVCPU_PC(r3)
+       mtsrr0  r9
+       mtsrr1  r10
+
+       /* Activate guest mode, so faults get handled by KVM */
+       li      r11, KVM_GUEST_MODE_GUEST
+       stb     r11, SVCPU_IN_GUEST(r3)
+
+       /* Switch to guest segment. This is subarch specific. */
+       LOAD_GUEST_SEGMENTS
+
+       /* Enter guest */
+
+       PPC_LL  r4, (SVCPU_CTR)(r3)
+       PPC_LL  r5, (SVCPU_LR)(r3)
+       lwz     r6, (SVCPU_CR)(r3)
+       lwz     r7, (SVCPU_XER)(r3)
+
+       mtctr   r4
+       mtlr    r5
+       mtcr    r6
+       mtxer   r7
+
+       PPC_LL  r0, (SVCPU_R0)(r3)
+       PPC_LL  r1, (SVCPU_R1)(r3)
+       PPC_LL  r2, (SVCPU_R2)(r3)
+       PPC_LL  r4, (SVCPU_R4)(r3)
+       PPC_LL  r5, (SVCPU_R5)(r3)
+       PPC_LL  r6, (SVCPU_R6)(r3)
+       PPC_LL  r7, (SVCPU_R7)(r3)
+       PPC_LL  r8, (SVCPU_R8)(r3)
+       PPC_LL  r9, (SVCPU_R9)(r3)
+       PPC_LL  r10, (SVCPU_R10)(r3)
+       PPC_LL  r11, (SVCPU_R11)(r3)
+       PPC_LL  r12, (SVCPU_R12)(r3)
+       PPC_LL  r13, (SVCPU_R13)(r3)
+
+       PPC_LL  r3, (SVCPU_R3)(r3)
+
+       RFI
+kvmppc_handler_trampoline_enter_end:
+
+
+
+/******************************************************************************
+ *                                                                            *
+ *                               Exit code                                    *
+ *                                                                            *
+ *****************************************************************************/
+
+.global kvmppc_handler_trampoline_exit
+kvmppc_handler_trampoline_exit:
+
+       /* Register usage at this point:
+        *
+        * SPRG_SCRATCH0  = guest R13
+        * R12            = exit handler id
+        * R13            = shadow vcpu - SHADOW_VCPU_OFF [=PACA on PPC64]
+        * SVCPU.SCRATCH0 = guest R12
+        * SVCPU.SCRATCH1 = guest CR
+        *
+        */
+
+       /* Save registers */
+
+       PPC_STL r0, (SHADOW_VCPU_OFF + SVCPU_R0)(r13)
+       PPC_STL r1, (SHADOW_VCPU_OFF + SVCPU_R1)(r13)
+       PPC_STL r2, (SHADOW_VCPU_OFF + SVCPU_R2)(r13)
+       PPC_STL r3, (SHADOW_VCPU_OFF + SVCPU_R3)(r13)
+       PPC_STL r4, (SHADOW_VCPU_OFF + SVCPU_R4)(r13)
+       PPC_STL r5, (SHADOW_VCPU_OFF + SVCPU_R5)(r13)
+       PPC_STL r6, (SHADOW_VCPU_OFF + SVCPU_R6)(r13)
+       PPC_STL r7, (SHADOW_VCPU_OFF + SVCPU_R7)(r13)
+       PPC_STL r8, (SHADOW_VCPU_OFF + SVCPU_R8)(r13)
+       PPC_STL r9, (SHADOW_VCPU_OFF + SVCPU_R9)(r13)
+       PPC_STL r10, (SHADOW_VCPU_OFF + SVCPU_R10)(r13)
+       PPC_STL r11, (SHADOW_VCPU_OFF + SVCPU_R11)(r13)
+
+       /* Restore R1/R2 so we can handle faults */
+       PPC_LL  r1, (SHADOW_VCPU_OFF + SVCPU_HOST_R1)(r13)
+       PPC_LL  r2, (SHADOW_VCPU_OFF + SVCPU_HOST_R2)(r13)
+
+       /* Save guest PC and MSR */
+       mfsrr0  r3
+       mfsrr1  r4
+
+       PPC_STL r3, (SHADOW_VCPU_OFF + SVCPU_PC)(r13)
+       PPC_STL r4, (SHADOW_VCPU_OFF + SVCPU_SHADOW_SRR1)(r13)
+
+       /* Get scratch'ed off registers */
+       mfspr   r9, SPRN_SPRG_SCRATCH0
+       PPC_LL  r8, (SHADOW_VCPU_OFF + SVCPU_SCRATCH0)(r13)
+       lwz     r7, (SHADOW_VCPU_OFF + SVCPU_SCRATCH1)(r13)
+
+       PPC_STL r9, (SHADOW_VCPU_OFF + SVCPU_R13)(r13)
+       PPC_STL r8, (SHADOW_VCPU_OFF + SVCPU_R12)(r13)
+       stw     r7, (SHADOW_VCPU_OFF + SVCPU_CR)(r13)
+
+       /* Save more register state  */
+
+       mfxer   r5
+       mfdar   r6
+       mfdsisr r7
+       mfctr   r8
+       mflr    r9
+
+       stw     r5, (SHADOW_VCPU_OFF + SVCPU_XER)(r13)
+       PPC_STL r6, (SHADOW_VCPU_OFF + SVCPU_FAULT_DAR)(r13)
+       stw     r7, (SHADOW_VCPU_OFF + SVCPU_FAULT_DSISR)(r13)
+       PPC_STL r8, (SHADOW_VCPU_OFF + SVCPU_CTR)(r13)
+       PPC_STL r9, (SHADOW_VCPU_OFF + SVCPU_LR)(r13)
+
+       /*
+        * In order for us to easily get the last instruction,
+        * we got the #vmexit at, we exploit the fact that the
+        * virtual layout is still the same here, so we can just
+        * ld from the guest's PC address
+        */
+
+       /* We only load the last instruction when it's safe */
+       cmpwi   r12, BOOK3S_INTERRUPT_DATA_STORAGE
+       beq     ld_last_inst
+       cmpwi   r12, BOOK3S_INTERRUPT_PROGRAM
+       beq     ld_last_inst
+       cmpwi   r12, BOOK3S_INTERRUPT_ALIGNMENT
+       beq-    ld_last_inst
+
+       b       no_ld_last_inst
+
+ld_last_inst:
+       /* Save off the guest instruction we're at */
+
+       /* In case lwz faults */
+       li      r0, KVM_INST_FETCH_FAILED
+
+#ifdef USE_QUICK_LAST_INST
+
+       /* Set guest mode to 'jump over instruction' so if lwz faults
+        * we'll just continue at the next IP. */
+       li      r9, KVM_GUEST_MODE_SKIP
+       stb     r9, (SHADOW_VCPU_OFF + SVCPU_IN_GUEST)(r13)
+
+       /*    1) enable paging for data */
+       mfmsr   r9
+       ori     r11, r9, MSR_DR                 /* Enable paging for data */
+       mtmsr   r11
+       sync
+       /*    2) fetch the instruction */
+       lwz     r0, 0(r3)
+       /*    3) disable paging again */
+       mtmsr   r9
+       sync
+
+#endif
+       stw     r0, (SHADOW_VCPU_OFF + SVCPU_LAST_INST)(r13)
+
+no_ld_last_inst:
+
+       /* Unset guest mode */
+       li      r9, KVM_GUEST_MODE_NONE
+       stb     r9, (SHADOW_VCPU_OFF + SVCPU_IN_GUEST)(r13)
+
+       /* Switch back to host MMU */
+       LOAD_HOST_SEGMENTS
+
+       /* Register usage at this point:
+        *
+        * R1       = host R1
+        * R2       = host R2
+        * R12      = exit handler id
+        * R13      = shadow vcpu - SHADOW_VCPU_OFF [=PACA on PPC64]
+        * SVCPU.*  = guest *
+        *
+        */
+
+       /* RFI into the highmem handler */
+       mfmsr   r7
+       ori     r7, r7, MSR_IR|MSR_DR|MSR_RI|MSR_ME     /* Enable paging */
+       mtsrr1  r7
+       /* Load highmem handler address */
+       PPC_LL  r8, (SHADOW_VCPU_OFF + SVCPU_VMHANDLER)(r13)
+       mtsrr0  r8
+
+       RFI
+kvmppc_handler_trampoline_exit_end:
index 2a3a1953d4bd76a66ef49feb2882609b2847118e..a33ab8cc2ccc09a805a1b9991d2e9245de652a5a 100644 (file)
@@ -133,6 +133,12 @@ void kvmppc_core_queue_external(struct kvm_vcpu *vcpu,
        kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_EXTERNAL);
 }
 
+void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu,
+                                  struct kvm_interrupt *irq)
+{
+       clear_bit(BOOKE_IRQPRIO_EXTERNAL, &vcpu->arch.pending_exceptions);
+}
+
 /* Deliver the interrupt of the corresponding priority, if possible. */
 static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
                                         unsigned int priority)
@@ -479,6 +485,8 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 {
        int i;
 
+       vcpu_load(vcpu);
+
        regs->pc = vcpu->arch.pc;
        regs->cr = kvmppc_get_cr(vcpu);
        regs->ctr = vcpu->arch.ctr;
@@ -499,6 +507,8 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
        for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
                regs->gpr[i] = kvmppc_get_gpr(vcpu, i);
 
+       vcpu_put(vcpu);
+
        return 0;
 }
 
@@ -506,6 +516,8 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 {
        int i;
 
+       vcpu_load(vcpu);
+
        vcpu->arch.pc = regs->pc;
        kvmppc_set_cr(vcpu, regs->cr);
        vcpu->arch.ctr = regs->ctr;
@@ -525,6 +537,8 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
        for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
                kvmppc_set_gpr(vcpu, i, regs->gpr[i]);
 
+       vcpu_put(vcpu);
+
        return 0;
 }
 
@@ -553,7 +567,12 @@ int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
 int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
                                   struct kvm_translation *tr)
 {
-       return kvmppc_core_vcpu_translate(vcpu, tr);
+       int r;
+
+       vcpu_load(vcpu);
+       r = kvmppc_core_vcpu_translate(vcpu, tr);
+       vcpu_put(vcpu);
+       return r;
 }
 
 int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
index 669a5c5fc7d725db4f9d8ae6bddc47bce21eb475..bc2b4004eb265a70ea4b082693e0b9eb9cf49e3f 100644 (file)
@@ -161,7 +161,7 @@ static int __init kvmppc_e500_init(void)
        flush_icache_range(kvmppc_booke_handlers,
                        kvmppc_booke_handlers + max_ivor + kvmppc_handler_len);
 
-       return kvm_init(NULL, sizeof(struct kvmppc_vcpu_e500), THIS_MODULE);
+       return kvm_init(NULL, sizeof(struct kvmppc_vcpu_e500), 0, THIS_MODULE);
 }
 
 static void __init kvmppc_e500_exit(void)
index cb72a65f4eccc01bcac5a431a090df8f36a9a374..4568ec386c2aa858afe0a6024adfb476cac18c33 100644 (file)
 #define OP_31_XOP_LBZX      87
 #define OP_31_XOP_STWX      151
 #define OP_31_XOP_STBX      215
+#define OP_31_XOP_LBZUX     119
 #define OP_31_XOP_STBUX     247
 #define OP_31_XOP_LHZX      279
 #define OP_31_XOP_LHZUX     311
 #define OP_31_XOP_MFSPR     339
+#define OP_31_XOP_LHAX      343
 #define OP_31_XOP_STHX      407
 #define OP_31_XOP_STHUX     439
 #define OP_31_XOP_MTSPR     467
 #define OP_STBU 39
 #define OP_LHZ  40
 #define OP_LHZU 41
+#define OP_LHA  42
+#define OP_LHAU 43
 #define OP_STH  44
 #define OP_STHU 45
 
-#ifdef CONFIG_PPC64
+#ifdef CONFIG_PPC_BOOK3S
 static int kvmppc_dec_enabled(struct kvm_vcpu *vcpu)
 {
        return 1;
@@ -82,7 +86,7 @@ void kvmppc_emulate_dec(struct kvm_vcpu *vcpu)
        unsigned long dec_nsec;
 
        pr_debug("mtDEC: %x\n", vcpu->arch.dec);
-#ifdef CONFIG_PPC64
+#ifdef CONFIG_PPC_BOOK3S
        /* mtdec lowers the interrupt line when positive. */
        kvmppc_core_dequeue_dec(vcpu);
 
@@ -128,7 +132,7 @@ void kvmppc_emulate_dec(struct kvm_vcpu *vcpu)
  * from opcode tables in the future. */
 int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
 {
-       u32 inst = vcpu->arch.last_inst;
+       u32 inst = kvmppc_get_last_inst(vcpu);
        u32 ea;
        int ra;
        int rb;
@@ -143,13 +147,9 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
 
        pr_debug(KERN_INFO "Emulating opcode %d / %d\n", get_op(inst), get_xop(inst));
 
-       /* Try again next time */
-       if (inst == KVM_INST_FETCH_FAILED)
-               return EMULATE_DONE;
-
        switch (get_op(inst)) {
        case OP_TRAP:
-#ifdef CONFIG_PPC64
+#ifdef CONFIG_PPC_BOOK3S
        case OP_TRAP_64:
                kvmppc_core_queue_program(vcpu, SRR1_PROGTRAP);
 #else
@@ -171,6 +171,19 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
                        emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1);
                        break;
 
+               case OP_31_XOP_LBZUX:
+                       rt = get_rt(inst);
+                       ra = get_ra(inst);
+                       rb = get_rb(inst);
+
+                       ea = kvmppc_get_gpr(vcpu, rb);
+                       if (ra)
+                               ea += kvmppc_get_gpr(vcpu, ra);
+
+                       emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1);
+                       kvmppc_set_gpr(vcpu, ra, ea);
+                       break;
+
                case OP_31_XOP_STWX:
                        rs = get_rs(inst);
                        emulated = kvmppc_handle_store(run, vcpu,
@@ -200,6 +213,11 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
                        kvmppc_set_gpr(vcpu, rs, ea);
                        break;
 
+               case OP_31_XOP_LHAX:
+                       rt = get_rt(inst);
+                       emulated = kvmppc_handle_loads(run, vcpu, rt, 2, 1);
+                       break;
+
                case OP_31_XOP_LHZX:
                        rt = get_rt(inst);
                        emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1);
@@ -450,6 +468,18 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
                kvmppc_set_gpr(vcpu, ra, vcpu->arch.paddr_accessed);
                break;
 
+       case OP_LHA:
+               rt = get_rt(inst);
+               emulated = kvmppc_handle_loads(run, vcpu, rt, 2, 1);
+               break;
+
+       case OP_LHAU:
+               ra = get_ra(inst);
+               rt = get_rt(inst);
+               emulated = kvmppc_handle_loads(run, vcpu, rt, 2, 1);
+               kvmppc_set_gpr(vcpu, ra, vcpu->arch.paddr_accessed);
+               break;
+
        case OP_STH:
                rs = get_rs(inst);
                emulated = kvmppc_handle_store(run, vcpu,
@@ -472,7 +502,9 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
 
        if (emulated == EMULATE_FAIL) {
                emulated = kvmppc_core_emulate_op(run, vcpu, inst, &advance);
-               if (emulated == EMULATE_FAIL) {
+               if (emulated == EMULATE_AGAIN) {
+                       advance = 0;
+               } else if (emulated == EMULATE_FAIL) {
                        advance = 0;
                        printk(KERN_ERR "Couldn't emulate instruction 0x%08x "
                               "(op %d xop %d)\n", inst, get_op(inst), get_xop(inst));
@@ -480,10 +512,11 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
                }
        }
 
-       trace_kvm_ppc_instr(inst, vcpu->arch.pc, emulated);
+       trace_kvm_ppc_instr(inst, kvmppc_get_pc(vcpu), emulated);
 
+       /* Advance past emulated instruction. */
        if (advance)
-               vcpu->arch.pc += 4; /* Advance past emulated instruction. */
+               kvmppc_set_pc(vcpu, kvmppc_get_pc(vcpu) + 4);
 
        return emulated;
 }
diff --git a/arch/powerpc/kvm/fpu.S b/arch/powerpc/kvm/fpu.S
new file mode 100644 (file)
index 0000000..2b340a3
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ *  FPU helper code to use FPU operations from inside the kernel
+ *
+ *    Copyright (C) 2010 Alexander Graf (agraf@suse.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 <asm/reg.h>
+#include <asm/page.h>
+#include <asm/mmu.h>
+#include <asm/pgtable.h>
+#include <asm/cputable.h>
+#include <asm/cache.h>
+#include <asm/thread_info.h>
+#include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
+
+/* Instructions operating on single parameters */
+
+/*
+ * Single operation with one input operand
+ *
+ * R3 = (double*)&fpscr
+ * R4 = (short*)&result
+ * R5 = (short*)&param1
+ */
+#define FPS_ONE_IN(name)                                       \
+_GLOBAL(fps_ ## name);                                                 \
+       lfd     0,0(r3);                /* load up fpscr value */       \
+       MTFSF_L(0);                                                     \
+       lfs     0,0(r5);                                                \
+                                                                       \
+       name    0,0;                                                    \
+                                                                       \
+       stfs    0,0(r4);                                                \
+       mffs    0;                                                      \
+       stfd    0,0(r3);        /* save new fpscr value */      \
+       blr
+
+/*
+ * Single operation with two input operands
+ *
+ * R3 = (double*)&fpscr
+ * R4 = (short*)&result
+ * R5 = (short*)&param1
+ * R6 = (short*)&param2
+ */
+#define FPS_TWO_IN(name)                                       \
+_GLOBAL(fps_ ## name);                                                 \
+       lfd     0,0(r3);                /* load up fpscr value */       \
+       MTFSF_L(0);                                                     \
+       lfs     0,0(r5);                                                \
+       lfs     1,0(r6);                                                \
+                                                                       \
+       name    0,0,1;                                                  \
+                                                                       \
+       stfs    0,0(r4);                                                \
+       mffs    0;                                                      \
+       stfd    0,0(r3);                /* save new fpscr value */      \
+       blr
+
+/*
+ * Single operation with three input operands
+ *
+ * R3 = (double*)&fpscr
+ * R4 = (short*)&result
+ * R5 = (short*)&param1
+ * R6 = (short*)&param2
+ * R7 = (short*)&param3
+ */
+#define FPS_THREE_IN(name)                                     \
+_GLOBAL(fps_ ## name);                                                 \
+       lfd     0,0(r3);                /* load up fpscr value */       \
+       MTFSF_L(0);                                                     \
+       lfs     0,0(r5);                                                \
+       lfs     1,0(r6);                                                \
+       lfs     2,0(r7);                                                \
+                                                                       \
+       name    0,0,1,2;                                                \
+                                                                       \
+       stfs    0,0(r4);                                                \
+       mffs    0;                                                      \
+       stfd    0,0(r3);                /* save new fpscr value */      \
+       blr
+
+FPS_ONE_IN(fres)
+FPS_ONE_IN(frsqrte)
+FPS_ONE_IN(fsqrts)
+FPS_TWO_IN(fadds)
+FPS_TWO_IN(fdivs)
+FPS_TWO_IN(fmuls)
+FPS_TWO_IN(fsubs)
+FPS_THREE_IN(fmadds)
+FPS_THREE_IN(fmsubs)
+FPS_THREE_IN(fnmadds)
+FPS_THREE_IN(fnmsubs)
+FPS_THREE_IN(fsel)
+
+
+/* Instructions operating on double parameters */
+
+/*
+ * Beginning of double instruction processing
+ *
+ * R3 = (double*)&fpscr
+ * R4 = (u32*)&cr
+ * R5 = (double*)&result
+ * R6 = (double*)&param1
+ * R7 = (double*)&param2 [load_two]
+ * R8 = (double*)&param3 [load_three]
+ * LR = instruction call function
+ */
+fpd_load_three:
+       lfd     2,0(r8)                 /* load param3 */
+fpd_load_two:
+       lfd     1,0(r7)                 /* load param2 */
+fpd_load_one:
+       lfd     0,0(r6)                 /* load param1 */
+fpd_load_none:
+       lfd     3,0(r3)                 /* load up fpscr value */
+       MTFSF_L(3)
+       lwz     r6, 0(r4)               /* load cr */
+       mtcr    r6
+       blr
+
+/*
+ * End of double instruction processing
+ *
+ * R3 = (double*)&fpscr
+ * R4 = (u32*)&cr
+ * R5 = (double*)&result
+ * LR = caller of instruction call function
+ */
+fpd_return:
+       mfcr    r6
+       stfd    0,0(r5)                 /* save result */
+       mffs    0
+       stfd    0,0(r3)                 /* save new fpscr value */
+       stw     r6,0(r4)                /* save new cr value */
+       blr
+
+/*
+ * Double operation with no input operand
+ *
+ * R3 = (double*)&fpscr
+ * R4 = (u32*)&cr
+ * R5 = (double*)&result
+ */
+#define FPD_NONE_IN(name)                                              \
+_GLOBAL(fpd_ ## name);                                                 \
+       mflr    r12;                                                    \
+       bl      fpd_load_none;                                          \
+       mtlr    r12;                                                    \
+                                                                       \
+       name.   0;                      /* call instruction */          \
+       b       fpd_return
+
+/*
+ * Double operation with one input operand
+ *
+ * R3 = (double*)&fpscr
+ * R4 = (u32*)&cr
+ * R5 = (double*)&result
+ * R6 = (double*)&param1
+ */
+#define FPD_ONE_IN(name)                                               \
+_GLOBAL(fpd_ ## name);                                                 \
+       mflr    r12;                                                    \
+       bl      fpd_load_one;                                           \
+       mtlr    r12;                                                    \
+                                                                       \
+       name.   0,0;                    /* call instruction */          \
+       b       fpd_return
+
+/*
+ * Double operation with two input operands
+ *
+ * R3 = (double*)&fpscr
+ * R4 = (u32*)&cr
+ * R5 = (double*)&result
+ * R6 = (double*)&param1
+ * R7 = (double*)&param2
+ * R8 = (double*)&param3
+ */
+#define FPD_TWO_IN(name)                                               \
+_GLOBAL(fpd_ ## name);                                                 \
+       mflr    r12;                                                    \
+       bl      fpd_load_two;                                           \
+       mtlr    r12;                                                    \
+                                                                       \
+       name.   0,0,1;                  /* call instruction */          \
+       b       fpd_return
+
+/*
+ * CR Double operation with two input operands
+ *
+ * R3 = (double*)&fpscr
+ * R4 = (u32*)&cr
+ * R5 = (double*)&param1
+ * R6 = (double*)&param2
+ * R7 = (double*)&param3
+ */
+#define FPD_TWO_IN_CR(name)                                            \
+_GLOBAL(fpd_ ## name);                                                 \
+       lfd     1,0(r6);                /* load param2 */               \
+       lfd     0,0(r5);                /* load param1 */               \
+       lfd     3,0(r3);                /* load up fpscr value */       \
+       MTFSF_L(3);                                                     \
+       lwz     r6, 0(r4);              /* load cr */                   \
+       mtcr    r6;                                                     \
+                                                                       \
+       name    0,0,1;                  /* call instruction */          \
+       mfcr    r6;                                                     \
+       mffs    0;                                                      \
+       stfd    0,0(r3);                /* save new fpscr value */      \
+       stw     r6,0(r4);               /* save new cr value */         \
+       blr
+
+/*
+ * Double operation with three input operands
+ *
+ * R3 = (double*)&fpscr
+ * R4 = (u32*)&cr
+ * R5 = (double*)&result
+ * R6 = (double*)&param1
+ * R7 = (double*)&param2
+ * R8 = (double*)&param3
+ */
+#define FPD_THREE_IN(name)                                             \
+_GLOBAL(fpd_ ## name);                                                 \
+       mflr    r12;                                                    \
+       bl      fpd_load_three;                                         \
+       mtlr    r12;                                                    \
+                                                                       \
+       name.   0,0,1,2;                /* call instruction */          \
+       b       fpd_return
+
+FPD_ONE_IN(fsqrts)
+FPD_ONE_IN(frsqrtes)
+FPD_ONE_IN(fres)
+FPD_ONE_IN(frsp)
+FPD_ONE_IN(fctiw)
+FPD_ONE_IN(fctiwz)
+FPD_ONE_IN(fsqrt)
+FPD_ONE_IN(fre)
+FPD_ONE_IN(frsqrte)
+FPD_ONE_IN(fneg)
+FPD_ONE_IN(fabs)
+FPD_TWO_IN(fadds)
+FPD_TWO_IN(fsubs)
+FPD_TWO_IN(fdivs)
+FPD_TWO_IN(fmuls)
+FPD_TWO_IN_CR(fcmpu)
+FPD_TWO_IN(fcpsgn)
+FPD_TWO_IN(fdiv)
+FPD_TWO_IN(fadd)
+FPD_TWO_IN(fmul)
+FPD_TWO_IN_CR(fcmpo)
+FPD_TWO_IN(fsub)
+FPD_THREE_IN(fmsubs)
+FPD_THREE_IN(fmadds)
+FPD_THREE_IN(fnmsubs)
+FPD_THREE_IN(fnmadds)
+FPD_THREE_IN(fsel)
+FPD_THREE_IN(fmsub)
+FPD_THREE_IN(fmadd)
+FPD_THREE_IN(fnmsub)
+FPD_THREE_IN(fnmadd)
index 297fcd2ff7d01a0d9dddf473b1cc4e4415fccf4b..9b8683f39e0533576440892bed1ba16577dd6421 100644 (file)
@@ -70,7 +70,7 @@ int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu)
        case EMULATE_FAIL:
                /* XXX Deliver Program interrupt to guest. */
                printk(KERN_EMERG "%s: emulation failed (%08x)\n", __func__,
-                      vcpu->arch.last_inst);
+                      kvmppc_get_last_inst(vcpu));
                r = RESUME_HOST;
                break;
        default:
@@ -148,6 +148,10 @@ int kvm_dev_ioctl_check_extension(long ext)
 
        switch (ext) {
        case KVM_CAP_PPC_SEGSTATE:
+       case KVM_CAP_PPC_PAIRED_SINGLES:
+       case KVM_CAP_PPC_UNSET_IRQ:
+       case KVM_CAP_ENABLE_CAP:
+       case KVM_CAP_PPC_OSI:
                r = 1;
                break;
        case KVM_CAP_COALESCED_MMIO:
@@ -193,12 +197,17 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id)
 {
        struct kvm_vcpu *vcpu;
        vcpu = kvmppc_core_vcpu_create(kvm, id);
-       kvmppc_create_vcpu_debugfs(vcpu, id);
+       if (!IS_ERR(vcpu))
+               kvmppc_create_vcpu_debugfs(vcpu, id);
        return vcpu;
 }
 
 void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
 {
+       /* Make sure we're not using the vcpu anymore */
+       hrtimer_cancel(&vcpu->arch.dec_timer);
+       tasklet_kill(&vcpu->arch.tasklet);
+
        kvmppc_remove_vcpu_debugfs(vcpu);
        kvmppc_core_vcpu_free(vcpu);
 }
@@ -278,7 +287,7 @@ static void kvmppc_complete_dcr_load(struct kvm_vcpu *vcpu,
 static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu,
                                       struct kvm_run *run)
 {
-       ulong gpr;
+       u64 gpr;
 
        if (run->mmio.len > sizeof(gpr)) {
                printk(KERN_ERR "bad MMIO length: %d\n", run->mmio.len);
@@ -287,6 +296,7 @@ static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu,
 
        if (vcpu->arch.mmio_is_bigendian) {
                switch (run->mmio.len) {
+               case 8: gpr = *(u64 *)run->mmio.data; break;
                case 4: gpr = *(u32 *)run->mmio.data; break;
                case 2: gpr = *(u16 *)run->mmio.data; break;
                case 1: gpr = *(u8 *)run->mmio.data; break;
@@ -300,7 +310,43 @@ static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu,
                }
        }
 
+       if (vcpu->arch.mmio_sign_extend) {
+               switch (run->mmio.len) {
+#ifdef CONFIG_PPC64
+               case 4:
+                       gpr = (s64)(s32)gpr;
+                       break;
+#endif
+               case 2:
+                       gpr = (s64)(s16)gpr;
+                       break;
+               case 1:
+                       gpr = (s64)(s8)gpr;
+                       break;
+               }
+       }
+
        kvmppc_set_gpr(vcpu, vcpu->arch.io_gpr, gpr);
+
+       switch (vcpu->arch.io_gpr & KVM_REG_EXT_MASK) {
+       case KVM_REG_GPR:
+               kvmppc_set_gpr(vcpu, vcpu->arch.io_gpr, gpr);
+               break;
+       case KVM_REG_FPR:
+               vcpu->arch.fpr[vcpu->arch.io_gpr & KVM_REG_MASK] = gpr;
+               break;
+#ifdef CONFIG_PPC_BOOK3S
+       case KVM_REG_QPR:
+               vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_REG_MASK] = gpr;
+               break;
+       case KVM_REG_FQPR:
+               vcpu->arch.fpr[vcpu->arch.io_gpr & KVM_REG_MASK] = gpr;
+               vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_REG_MASK] = gpr;
+               break;
+#endif
+       default:
+               BUG();
+       }
 }
 
 int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
@@ -319,12 +365,25 @@ int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
        vcpu->arch.mmio_is_bigendian = is_bigendian;
        vcpu->mmio_needed = 1;
        vcpu->mmio_is_write = 0;
+       vcpu->arch.mmio_sign_extend = 0;
 
        return EMULATE_DO_MMIO;
 }
 
+/* Same as above, but sign extends */
+int kvmppc_handle_loads(struct kvm_run *run, struct kvm_vcpu *vcpu,
+                        unsigned int rt, unsigned int bytes, int is_bigendian)
+{
+       int r;
+
+       r = kvmppc_handle_load(run, vcpu, rt, bytes, is_bigendian);
+       vcpu->arch.mmio_sign_extend = 1;
+
+       return r;
+}
+
 int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
-                        u32 val, unsigned int bytes, int is_bigendian)
+                        u64 val, unsigned int bytes, int is_bigendian)
 {
        void *data = run->mmio.data;
 
@@ -342,6 +401,7 @@ int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
        /* Store the value at the lowest bytes in 'data'. */
        if (is_bigendian) {
                switch (bytes) {
+               case 8: *(u64 *)data = val; break;
                case 4: *(u32 *)data = val; break;
                case 2: *(u16 *)data = val; break;
                case 1: *(u8  *)data = val; break;
@@ -376,6 +436,13 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
                if (!vcpu->arch.dcr_is_write)
                        kvmppc_complete_dcr_load(vcpu, run);
                vcpu->arch.dcr_needed = 0;
+       } else if (vcpu->arch.osi_needed) {
+               u64 *gprs = run->osi.gprs;
+               int i;
+
+               for (i = 0; i < 32; i++)
+                       kvmppc_set_gpr(vcpu, i, gprs[i]);
+               vcpu->arch.osi_needed = 0;
        }
 
        kvmppc_core_deliver_interrupts(vcpu);
@@ -396,7 +463,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 
 int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq)
 {
-       kvmppc_core_queue_external(vcpu, irq);
+       if (irq->irq == KVM_INTERRUPT_UNSET)
+               kvmppc_core_dequeue_external(vcpu, irq);
+       else
+               kvmppc_core_queue_external(vcpu, irq);
 
        if (waitqueue_active(&vcpu->wq)) {
                wake_up_interruptible(&vcpu->wq);
@@ -406,6 +476,27 @@ int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq)
        return 0;
 }
 
+static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
+                                    struct kvm_enable_cap *cap)
+{
+       int r;
+
+       if (cap->flags)
+               return -EINVAL;
+
+       switch (cap->cap) {
+       case KVM_CAP_PPC_OSI:
+               r = 0;
+               vcpu->arch.osi_enabled = true;
+               break;
+       default:
+               r = -EINVAL;
+               break;
+       }
+
+       return r;
+}
+
 int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
                                     struct kvm_mp_state *mp_state)
 {
@@ -434,6 +525,15 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
                r = kvm_vcpu_ioctl_interrupt(vcpu, &irq);
                break;
        }
+       case KVM_ENABLE_CAP:
+       {
+               struct kvm_enable_cap cap;
+               r = -EFAULT;
+               if (copy_from_user(&cap, argp, sizeof(cap)))
+                       goto out;
+               r = kvm_vcpu_ioctl_enable_cap(vcpu, &cap);
+               break;
+       }
        default:
                r = -EINVAL;
        }
index 0dfba2bf7f3189e0fd93c3168ad769a4968a6522..d0ee554e86e47c77d5084a7ac6d4f640e5cf763c 100644 (file)
 static unsigned long next_mmu_context;
 static unsigned long context_map[LAST_CONTEXT / BITS_PER_LONG + 1];
 
-
-/*
- * Set up the context for a new address space.
- */
-int init_new_context(struct task_struct *t, struct mm_struct *mm)
+unsigned long __init_new_context(void)
 {
        unsigned long ctx = next_mmu_context;
 
@@ -74,11 +70,30 @@ int init_new_context(struct task_struct *t, struct mm_struct *mm)
                        ctx = 0;
        }
        next_mmu_context = (ctx + 1) & LAST_CONTEXT;
-       mm->context.id = ctx;
+
+       return ctx;
+}
+EXPORT_SYMBOL_GPL(__init_new_context);
+
+/*
+ * Set up the context for a new address space.
+ */
+int init_new_context(struct task_struct *t, struct mm_struct *mm)
+{
+       mm->context.id = __init_new_context();
 
        return 0;
 }
 
+/*
+ * Free a context ID. Make sure to call this with preempt disabled!
+ */
+void __destroy_context(unsigned long ctx)
+{
+       clear_bit(ctx, context_map);
+}
+EXPORT_SYMBOL_GPL(__destroy_context);
+
 /*
  * We're finished using the context for an address space.
  */
@@ -86,7 +101,7 @@ void destroy_context(struct mm_struct *mm)
 {
        preempt_disable();
        if (mm->context.id != NO_CONTEXT) {
-               clear_bit(mm->context.id, context_map);
+               __destroy_context(mm->context.id);
                mm->context.id = NO_CONTEXT;
        }
        preempt_enable();
index b7f518a60f031d0e5beec01144f8a0d45650b63e..707e572b7c4037e901aae3667613eb01f395d757 100644 (file)
@@ -22,6 +22,7 @@
 #include <asm/prom.h>
 #include <asm/time.h>
 #include <asm/mpc5121.h>
+#include <asm/mpc52xx_psc.h>
 
 #include "mpc512x.h"
 
@@ -95,9 +96,86 @@ void __init mpc512x_declare_of_platform_devices(void)
        }
 }
 
+#define DEFAULT_FIFO_SIZE 16
+
+static unsigned int __init get_fifo_size(struct device_node *np,
+                                        char *prop_name)
+{
+       const unsigned int *fp;
+
+       fp = of_get_property(np, prop_name, NULL);
+       if (fp)
+               return *fp;
+
+       pr_warning("no %s property in %s node, defaulting to %d\n",
+                  prop_name, np->full_name, DEFAULT_FIFO_SIZE);
+
+       return DEFAULT_FIFO_SIZE;
+}
+
+#define FIFOC(_base) ((struct mpc512x_psc_fifo __iomem *) \
+                   ((u32)(_base) + sizeof(struct mpc52xx_psc)))
+
+/* Init PSC FIFO space for TX and RX slices */
+void __init mpc512x_psc_fifo_init(void)
+{
+       struct device_node *np;
+       void __iomem *psc;
+       unsigned int tx_fifo_size;
+       unsigned int rx_fifo_size;
+       int fifobase = 0; /* current fifo address in 32 bit words */
+
+       for_each_compatible_node(np, NULL, "fsl,mpc5121-psc") {
+               tx_fifo_size = get_fifo_size(np, "fsl,tx-fifo-size");
+               rx_fifo_size = get_fifo_size(np, "fsl,rx-fifo-size");
+
+               /* size in register is in 4 byte units */
+               tx_fifo_size /= 4;
+               rx_fifo_size /= 4;
+               if (!tx_fifo_size)
+                       tx_fifo_size = 1;
+               if (!rx_fifo_size)
+                       rx_fifo_size = 1;
+
+               psc = of_iomap(np, 0);
+               if (!psc) {
+                       pr_err("%s: Can't map %s device\n",
+                               __func__, np->full_name);
+                       continue;
+               }
+
+               /* FIFO space is 4KiB, check if requested size is available */
+               if ((fifobase + tx_fifo_size + rx_fifo_size) > 0x1000) {
+                       pr_err("%s: no fifo space available for %s\n",
+                               __func__, np->full_name);
+                       iounmap(psc);
+                       /*
+                        * chances are that another device requests less
+                        * fifo space, so we continue.
+                        */
+                       continue;
+               }
+
+               /* set tx and rx fifo size registers */
+               out_be32(&FIFOC(psc)->txsz, (fifobase << 16) | tx_fifo_size);
+               fifobase += tx_fifo_size;
+               out_be32(&FIFOC(psc)->rxsz, (fifobase << 16) | rx_fifo_size);
+               fifobase += rx_fifo_size;
+
+               /* reset and enable the slices */
+               out_be32(&FIFOC(psc)->txcmd, 0x80);
+               out_be32(&FIFOC(psc)->txcmd, 0x01);
+               out_be32(&FIFOC(psc)->rxcmd, 0x80);
+               out_be32(&FIFOC(psc)->rxcmd, 0x01);
+
+               iounmap(psc);
+       }
+}
+
 void __init mpc512x_init(void)
 {
        mpc512x_declare_of_platform_devices();
        mpc5121_clk_init();
        mpc512x_restart_init();
+       mpc512x_psc_fifo_init();
 }
index fda7c2a18282613e8847f577bd425f8aa4367537..ca5305a5bd61d8021c50dbb452db5adc376b4a0b 100644 (file)
@@ -168,7 +168,7 @@ static int __devinit mpc52xx_wkup_gpiochip_probe(struct of_device *ofdev,
        ofchip->gc.get              = mpc52xx_wkup_gpio_get;
        ofchip->gc.set              = mpc52xx_wkup_gpio_set;
 
-       ret = of_mm_gpiochip_add(ofdev->node, &chip->mmchip);
+       ret = of_mm_gpiochip_add(ofdev->dev.of_node, &chip->mmchip);
        if (ret)
                return ret;
 
@@ -193,8 +193,11 @@ static const struct of_device_id mpc52xx_wkup_gpiochip_match[] = {
 };
 
 static struct of_platform_driver mpc52xx_wkup_gpiochip_driver = {
-       .name = "gpio_wkup",
-       .match_table = mpc52xx_wkup_gpiochip_match,
+       .driver = {
+               .name = "gpio_wkup",
+               .owner = THIS_MODULE,
+               .of_match_table = mpc52xx_wkup_gpiochip_match,
+       },
        .probe = mpc52xx_wkup_gpiochip_probe,
        .remove = mpc52xx_gpiochip_remove,
 };
@@ -329,7 +332,7 @@ static int __devinit mpc52xx_simple_gpiochip_probe(struct of_device *ofdev,
        ofchip->gc.get              = mpc52xx_simple_gpio_get;
        ofchip->gc.set              = mpc52xx_simple_gpio_set;
 
-       ret = of_mm_gpiochip_add(ofdev->node, &chip->mmchip);
+       ret = of_mm_gpiochip_add(ofdev->dev.of_node, &chip->mmchip);
        if (ret)
                return ret;
 
@@ -349,8 +352,11 @@ static const struct of_device_id mpc52xx_simple_gpiochip_match[] = {
 };
 
 static struct of_platform_driver mpc52xx_simple_gpiochip_driver = {
-       .name = "gpio",
-       .match_table = mpc52xx_simple_gpiochip_match,
+       .driver = {
+               .name = "gpio",
+               .owner = THIS_MODULE,
+               .of_match_table = mpc52xx_simple_gpiochip_match,
+       },
        .probe = mpc52xx_simple_gpiochip_probe,
        .remove = mpc52xx_gpiochip_remove,
 };
index a60ee39d3b783d09ab67f2d3d3280af9bfdaf34d..46c93578cbf048230dc24fcd906a113872eb3bfb 100644 (file)
@@ -734,8 +734,8 @@ static int __devinit mpc52xx_gpt_probe(struct of_device *ofdev,
 
        spin_lock_init(&gpt->lock);
        gpt->dev = &ofdev->dev;
-       gpt->ipb_freq = mpc5xxx_get_bus_frequency(ofdev->node);
-       gpt->regs = of_iomap(ofdev->node, 0);
+       gpt->ipb_freq = mpc5xxx_get_bus_frequency(ofdev->dev.of_node);
+       gpt->regs = of_iomap(ofdev->dev.of_node, 0);
        if (!gpt->regs) {
                kfree(gpt);
                return -ENOMEM;
@@ -743,21 +743,21 @@ static int __devinit mpc52xx_gpt_probe(struct of_device *ofdev,
 
        dev_set_drvdata(&ofdev->dev, gpt);
 
-       mpc52xx_gpt_gpio_setup(gpt, ofdev->node);
-       mpc52xx_gpt_irq_setup(gpt, ofdev->node);
+       mpc52xx_gpt_gpio_setup(gpt, ofdev->dev.of_node);
+       mpc52xx_gpt_irq_setup(gpt, ofdev->dev.of_node);
 
        mutex_lock(&mpc52xx_gpt_list_mutex);
        list_add(&gpt->list, &mpc52xx_gpt_list);
        mutex_unlock(&mpc52xx_gpt_list_mutex);
 
        /* check if this device could be a watchdog */
-       if (of_get_property(ofdev->node, "fsl,has-wdt", NULL) ||
-           of_get_property(ofdev->node, "has-wdt", NULL)) {
+       if (of_get_property(ofdev->dev.of_node, "fsl,has-wdt", NULL) ||
+           of_get_property(ofdev->dev.of_node, "has-wdt", NULL)) {
                const u32 *on_boot_wdt;
 
                gpt->wdt_mode = MPC52xx_GPT_CAN_WDT;
-               on_boot_wdt = of_get_property(ofdev->node, "fsl,wdt-on-boot",
-                                             NULL);
+               on_boot_wdt = of_get_property(ofdev->dev.of_node,
+                                             "fsl,wdt-on-boot", NULL);
                if (on_boot_wdt) {
                        dev_info(gpt->dev, "used as watchdog\n");
                        gpt->wdt_mode |= MPC52xx_GPT_IS_WDT;
@@ -784,8 +784,11 @@ static const struct of_device_id mpc52xx_gpt_match[] = {
 };
 
 static struct of_platform_driver mpc52xx_gpt_driver = {
-       .name = "mpc52xx-gpt",
-       .match_table = mpc52xx_gpt_match,
+       .driver = {
+               .name = "mpc52xx-gpt",
+               .owner = THIS_MODULE,
+               .of_match_table = mpc52xx_gpt_match,
+       },
        .probe = mpc52xx_gpt_probe,
        .remove = mpc52xx_gpt_remove,
 };
index d4f8be307cd5b3aef4adc4b360dbfbf08190a442..e86aec644501b26ff767379dfdc30a07df745e28 100644 (file)
@@ -445,14 +445,14 @@ mpc52xx_lpbfifo_probe(struct of_device *op, const struct of_device_id *match)
        if (lpbfifo.dev != NULL)
                return -ENOSPC;
 
-       lpbfifo.irq = irq_of_parse_and_map(op->node, 0);
+       lpbfifo.irq = irq_of_parse_and_map(op->dev.of_node, 0);
        if (!lpbfifo.irq)
                return -ENODEV;
 
-       if (of_address_to_resource(op->node, 0, &res))
+       if (of_address_to_resource(op->dev.of_node, 0, &res))
                return -ENODEV;
        lpbfifo.regs_phys = res.start;
-       lpbfifo.regs = of_iomap(op->node, 0);
+       lpbfifo.regs = of_iomap(op->dev.of_node, 0);
        if (!lpbfifo.regs)
                return -ENOMEM;
 
@@ -537,9 +537,11 @@ static struct of_device_id mpc52xx_lpbfifo_match[] __devinitconst = {
 };
 
 static struct of_platform_driver mpc52xx_lpbfifo_driver = {
-       .owner = THIS_MODULE,
-       .name = "mpc52xx-lpbfifo",
-       .match_table = mpc52xx_lpbfifo_match,
+       .driver = {
+               .name = "mpc52xx-lpbfifo",
+               .owner = THIS_MODULE,
+               .of_match_table = mpc52xx_lpbfifo_match,
+       },
        .probe = mpc52xx_lpbfifo_probe,
        .remove = __devexit_p(mpc52xx_lpbfifo_remove),
 };
index f21555d3395ae7ab3b5d4c69d600b84fd1a039bc..9f2e52b36f91673c4787c650bb1fe8b31ae3a09f 100644 (file)
@@ -119,12 +119,12 @@ static int __devinit ep8248e_mdio_probe(struct of_device *ofdev,
        struct device_node *node;
        int ret;
 
-       node = of_get_parent(ofdev->node);
+       node = of_get_parent(ofdev->dev.of_node);
        of_node_put(node);
        if (node != ep8248e_bcsr_node)
                return -ENODEV;
 
-       ret = of_address_to_resource(ofdev->node, 0, &res);
+       ret = of_address_to_resource(ofdev->dev.of_node, 0, &res);
        if (ret)
                return ret;
 
@@ -142,7 +142,7 @@ static int __devinit ep8248e_mdio_probe(struct of_device *ofdev,
        bus->parent = &ofdev->dev;
        snprintf(bus->id, MII_BUS_ID_SIZE, "%x", res.start);
 
-       ret = of_mdiobus_register(bus, ofdev->node);
+       ret = of_mdiobus_register(bus, ofdev->dev.of_node);
        if (ret)
                goto err_free_irq;
 
@@ -170,8 +170,9 @@ static const struct of_device_id ep8248e_mdio_match[] = {
 static struct of_platform_driver ep8248e_mdio_driver = {
        .driver = {
                .name = "ep8248e-mdio-bitbang",
+               .owner = THIS_MODULE,
+               .of_match_table = ep8248e_mdio_match,
        },
-       .match_table = ep8248e_mdio_match,
        .probe = ep8248e_mdio_probe,
        .remove = ep8248e_mdio_remove,
 };
index 43805348b81ee90be3577f9dfd8a08693363cb60..ebe6c353720972f992936da851bff121b651e9f2 100644 (file)
@@ -321,7 +321,7 @@ static struct platform_suspend_ops mpc83xx_suspend_ops = {
 static int pmc_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 pmc_type *type = match->data;
        int ret = 0;
@@ -423,8 +423,11 @@ static struct of_device_id pmc_match[] = {
 };
 
 static struct of_platform_driver pmc_driver = {
-       .name = "mpc83xx-pmc",
-       .match_table = pmc_match,
+       .driver = {
+               .name = "mpc83xx-pmc",
+               .owner = THIS_MODULE,
+               .of_match_table = pmc_match,
+       },
        .probe = pmc_probe,
        .remove = pmc_remove
 };
index 8efe48192f3f50a0748978641fbad80ca050258c..6257e5378615eeab7c687d7375490a48169c8cc6 100644 (file)
@@ -345,7 +345,7 @@ static int axon_msi_shutdown(struct of_device *device)
 static int axon_msi_probe(struct of_device *device,
                          const struct of_device_id *device_id)
 {
-       struct device_node *dn = device->node;
+       struct device_node *dn = device->dev.of_node;
        struct axon_msic *msic;
        unsigned int virq;
        int dcr_base, dcr_len;
@@ -447,11 +447,12 @@ static const struct of_device_id axon_msi_device_id[] = {
 };
 
 static struct of_platform_driver axon_msi_driver = {
-       .match_table    = axon_msi_device_id,
        .probe          = axon_msi_probe,
        .shutdown       = axon_msi_shutdown,
-       .driver         = {
-               .name   = "axon-msi"
+       .driver = {
+               .name = "axon-msi",
+               .owner = THIS_MODULE,
+               .of_match_table = axon_msi_device_id,
        },
 };
 
index e3ec4976fae7a554c405ce7823d34b09bfbf37c5..22667a09d40eee6276eff723a8e4523e2b2e5bd2 100644 (file)
@@ -545,7 +545,6 @@ static struct iommu_table *cell_get_iommu_table(struct device *dev)
 {
        struct iommu_window *window;
        struct cbe_iommu *iommu;
-       struct dev_archdata *archdata = &dev->archdata;
 
        /* Current implementation uses the first window available in that
         * node's iommu. We -might- do something smarter later though it may
@@ -554,7 +553,7 @@ static struct iommu_table *cell_get_iommu_table(struct device *dev)
        iommu = cell_iommu_for_node(dev_to_node(dev));
        if (iommu == NULL || list_empty(&iommu->windows)) {
                printk(KERN_ERR "iommu: missing iommu for %s (node %d)\n",
-                      archdata->of_node ? archdata->of_node->full_name : "?",
+                      dev->of_node ? dev->of_node->full_name : "?",
                       dev_to_node(dev));
                return NULL;
        }
@@ -897,7 +896,7 @@ static u64 cell_iommu_get_fixed_address(struct device *dev)
        const u32 *ranges = NULL;
        int i, len, best, naddr, nsize, pna, range_size;
 
-       np = of_node_get(dev->archdata.of_node);
+       np = of_node_get(dev->of_node);
        while (1) {
                naddr = of_n_addr_cells(np);
                nsize = of_n_size_cells(np);
index 5c2808252516500b9d8871dfea5c5e78f67f4268..1a40da92154c99cab1568cf80d743eca5fab4d2c 100644 (file)
@@ -1849,8 +1849,7 @@ out:
        return ret;
 }
 
-static int spufs_mfc_fsync(struct file *file, struct dentry *dentry,
-                          int datasync)
+static int spufs_mfc_fsync(struct file *file, int datasync)
 {
        return spufs_mfc_flush(file, NULL);
 }
index fc1b1c42b1dce10ff94a8491b788d7a51862350d..e5e5f823d6870fece5c4a4ba3c918597ca3f9c0b 100644 (file)
@@ -251,7 +251,7 @@ const struct file_operations spufs_context_fops = {
        .llseek         = dcache_dir_lseek,
        .read           = generic_read_dir,
        .readdir        = dcache_readdir,
-       .fsync          = simple_sync_file,
+       .fsync          = noop_fsync,
 };
 EXPORT_SYMBOL_GPL(spufs_context_fops);
 
index 0f881f64583e97f9436b48c6156d643db7ddead1..627ee089e75d4bde3b04b3d9ab1ee48d54c931d0 100644 (file)
@@ -220,7 +220,7 @@ static int __devinit gpio_mdio_probe(struct of_device *ofdev,
                                     const struct of_device_id *match)
 {
        struct device *dev = &ofdev->dev;
-       struct device_node *np = ofdev->node;
+       struct device_node *np = ofdev->dev.of_node;
        struct mii_bus *new_bus;
        struct gpio_priv *priv;
        const unsigned int *prop;
@@ -301,11 +301,12 @@ MODULE_DEVICE_TABLE(of, gpio_mdio_match);
 
 static struct of_platform_driver gpio_mdio_driver =
 {
-       .match_table    = gpio_mdio_match,
        .probe          = gpio_mdio_probe,
        .remove         = gpio_mdio_remove,
-       .driver         = {
-               .name   = "gpio-mdio-bitbang",
+       .driver = {
+               .name = "gpio-mdio-bitbang",
+               .owner = THIS_MODULE,
+               .of_match_table = gpio_mdio_match,
        },
 };
 
index ac6fdd9732912848dd3cc3ee8d606e9ff8c6a894..f372ec1691a3d79450e6cf64f6f7d72b38e8f590 100644 (file)
@@ -360,10 +360,10 @@ static int pcmcia_notify(struct notifier_block *nb, unsigned long action,
        /* We know electra_cf devices will always have of_node set, since
         * electra_cf is an of_platform driver.
         */
-       if (!parent->archdata.of_node)
+       if (!parent->of_node)
                return 0;
 
-       if (!of_device_is_compatible(parent->archdata.of_node, "electra-cf"))
+       if (!of_device_is_compatible(parent->of_node, "electra-cf"))
                return 0;
 
        /* We use the direct ops for localbus */
index 6d09f5e3e7e49c77bd286dcc22366b4daf53c4b8..23083c397528408e182b2e2cd8be6d5078aafdab 100644 (file)
@@ -766,7 +766,7 @@ int ps3_system_bus_device_register(struct ps3_system_bus_device *dev)
                BUG();
        };
 
-       dev->core.archdata.of_node = NULL;
+       dev->core.of_node = NULL;
        set_dev_node(&dev->core, 0);
 
        pr_debug("%s:%d add %s\n", __func__, __LINE__, dev_name(&dev->core));
index 1fefae76e295de282e696d480c1ffb66846480e2..e19ff021e7111508580b5f6746d43d93e275fbf7 100644 (file)
@@ -102,7 +102,7 @@ static const struct file_operations hcall_inst_seq_fops = {
 #define CPU_NAME_BUF_SIZE      32
 
 
-static void probe_hcall_entry(unsigned long opcode, unsigned long *args)
+static void probe_hcall_entry(void *ignored, unsigned long opcode, unsigned long *args)
 {
        struct hcall_stats *h;
 
@@ -114,7 +114,7 @@ static void probe_hcall_entry(unsigned long opcode, unsigned long *args)
        h->purr_start = mfspr(SPRN_PURR);
 }
 
-static void probe_hcall_exit(unsigned long opcode, unsigned long retval,
+static void probe_hcall_exit(void *ignored, unsigned long opcode, unsigned long retval,
                             unsigned long *retbuf)
 {
        struct hcall_stats *h;
@@ -140,11 +140,11 @@ static int __init hcall_inst_init(void)
        if (!firmware_has_feature(FW_FEATURE_LPAR))
                return 0;
 
-       if (register_trace_hcall_entry(probe_hcall_entry))
+       if (register_trace_hcall_entry(probe_hcall_entry, NULL))
                return -EINVAL;
 
-       if (register_trace_hcall_exit(probe_hcall_exit)) {
-               unregister_trace_hcall_entry(probe_hcall_entry);
+       if (register_trace_hcall_exit(probe_hcall_exit, NULL)) {
+               unregister_trace_hcall_entry(probe_hcall_entry, NULL);
                return -EINVAL;
        }
 
index 1a0000a4b6d62636d93babf7b495000413aa000a..d26182d42cbfb5a712fb6803dfdf056f560e0c33 100644 (file)
@@ -468,7 +468,7 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev)
 
        pr_debug("pci_dma_dev_setup_pSeries: %s\n", pci_name(dev));
 
-       dn = dev->dev.archdata.of_node;
+       dn = dev->dev.of_node;
 
        /* If we're the direct child of a root bus, then we need to allocate
         * an iommu table ourselves. The bus setup code should have setup
index 88f4ae787832a270053673b4f0ceb7e5fe1b62cf..402d2212162f6bddc0a79506112448d6f6714461 100644 (file)
@@ -185,7 +185,7 @@ axon_ram_probe(struct of_device *device, const struct of_device_id *device_id)
        axon_ram_bank_id++;
 
        dev_info(&device->dev, "Found memory controller on %s\n",
-                       device->node->full_name);
+                       device->dev.of_node->full_name);
 
        bank = kzalloc(sizeof(struct axon_ram_bank), GFP_KERNEL);
        if (bank == NULL) {
@@ -198,7 +198,7 @@ axon_ram_probe(struct of_device *device, const struct of_device_id *device_id)
 
        bank->device = device;
 
-       if (of_address_to_resource(device->node, 0, &resource) != 0) {
+       if (of_address_to_resource(device->dev.of_node, 0, &resource) != 0) {
                dev_err(&device->dev, "Cannot access device tree\n");
                rc = -EFAULT;
                goto failed;
@@ -253,7 +253,7 @@ axon_ram_probe(struct of_device *device, const struct of_device_id *device_id)
        blk_queue_logical_block_size(bank->disk->queue, AXON_RAM_SECTOR_SIZE);
        add_disk(bank->disk);
 
-       bank->irq_id = irq_of_parse_and_map(device->node, 0);
+       bank->irq_id = irq_of_parse_and_map(device->dev.of_node, 0);
        if (bank->irq_id == NO_IRQ) {
                dev_err(&device->dev, "Cannot access ECC interrupt ID\n");
                rc = -EFAULT;
@@ -327,12 +327,12 @@ static struct of_device_id axon_ram_device_id[] = {
 };
 
 static struct of_platform_driver axon_ram_driver = {
-       .match_table    = axon_ram_device_id,
        .probe          = axon_ram_probe,
        .remove         = axon_ram_remove,
-       .driver         = {
-               .owner  = THIS_MODULE,
-               .name   = AXON_RAM_MODULE_NAME,
+       .driver = {
+               .name = AXON_RAM_MODULE_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = axon_ram_device_id,
        },
 };
 
index 378ebd9aac18567af6b249c34138e71698a52dd0..a7c5c470af147f73edb4a7448879b20fabf522cc 100644 (file)
@@ -377,7 +377,7 @@ mpc52xx_bcom_probe(struct of_device *op, const struct of_device_id *match)
        printk(KERN_INFO "DMA: MPC52xx BestComm driver\n");
 
        /* Get the bestcomm node */
-       of_node_get(op->node);
+       of_node_get(op->dev.of_node);
 
        /* Prepare SRAM */
        ofn_sram = of_find_matching_node(NULL, mpc52xx_sram_ids);
@@ -406,10 +406,10 @@ mpc52xx_bcom_probe(struct of_device *op, const struct of_device_id *match)
        }
 
        /* Save the node */
-       bcom_eng->ofnode = op->node;
+       bcom_eng->ofnode = op->dev.of_node;
 
        /* Get, reserve & map io */
-       if (of_address_to_resource(op->node, 0, &res_bcom)) {
+       if (of_address_to_resource(op->dev.of_node, 0, &res_bcom)) {
                printk(KERN_ERR DRIVER_NAME ": "
                        "Can't get resource\n");
                rv = -EINVAL;
@@ -453,7 +453,7 @@ error_sramclean:
        kfree(bcom_eng);
        bcom_sram_cleanup();
 error_ofput:
-       of_node_put(op->node);
+       of_node_put(op->dev.of_node);
 
        printk(KERN_ERR "DMA: MPC52xx BestComm init failed !\n");
 
@@ -494,14 +494,12 @@ MODULE_DEVICE_TABLE(of, mpc52xx_bcom_of_match);
 
 
 static struct of_platform_driver mpc52xx_bcom_of_platform_driver = {
-       .owner          = THIS_MODULE,
-       .name           = DRIVER_NAME,
-       .match_table    = mpc52xx_bcom_of_match,
        .probe          = mpc52xx_bcom_probe,
        .remove         = mpc52xx_bcom_remove,
-       .driver         = {
-               .name   = DRIVER_NAME,
-               .owner  = THIS_MODULE,
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = mpc52xx_bcom_of_match,
        },
 };
 
index 3482e3fd89c04e99a0205f1fbc82ad7d28313f3e..a7be144f5874335da103e0af4c33b3b3d1e1f3fe 100644 (file)
@@ -249,7 +249,7 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev,
                goto error_out;
        }
 
-       msi->irqhost = irq_alloc_host(dev->node, IRQ_HOST_MAP_LINEAR,
+       msi->irqhost = irq_alloc_host(dev->dev.of_node, IRQ_HOST_MAP_LINEAR,
                                      NR_MSI_IRQS, &fsl_msi_host_ops, 0);
 
        if (msi->irqhost == NULL) {
@@ -259,10 +259,10 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev,
        }
 
        /* Get the MSI reg base */
-       err = of_address_to_resource(dev->node, 0, &res);
+       err = of_address_to_resource(dev->dev.of_node, 0, &res);
        if (err) {
                dev_err(&dev->dev, "%s resource error!\n",
-                               dev->node->full_name);
+                               dev->dev.of_node->full_name);
                goto error_out;
        }
 
@@ -285,16 +285,16 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev,
                goto error_out;
        }
 
-       p = of_get_property(dev->node, "interrupts", &count);
+       p = of_get_property(dev->dev.of_node, "interrupts", &count);
        if (!p) {
                dev_err(&dev->dev, "no interrupts property found on %s\n",
-                               dev->node->full_name);
+                               dev->dev.of_node->full_name);
                err = -ENODEV;
                goto error_out;
        }
        if (count % 8 != 0) {
                dev_err(&dev->dev, "Malformed interrupts property on %s\n",
-                               dev->node->full_name);
+                               dev->dev.of_node->full_name);
                err = -EINVAL;
                goto error_out;
        }
@@ -303,7 +303,7 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev,
        for (i = 0; i < count / 2; i++) {
                if (i > NR_MSI_REG)
                        break;
-               virt_msir = irq_of_parse_and_map(dev->node, 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);
                        set_irq_chained_handler(virt_msir, fsl_msi_cascade);
@@ -345,8 +345,11 @@ static const struct of_device_id fsl_of_msi_ids[] = {
 };
 
 static struct of_platform_driver fsl_of_msi_driver = {
-       .name = "fsl-msi",
-       .match_table = fsl_of_msi_ids,
+       .driver = {
+               .name = "fsl-msi",
+               .owner = THIS_MODULE,
+               .of_match_table = fsl_of_msi_ids,
+       },
        .probe = fsl_of_msi_probe,
 };
 
index a7635a993dca545c144c3183201337f89997eaa1..9082eb921ad995f7caac8752d00f9dc91cf48381 100644 (file)
@@ -60,7 +60,7 @@ static struct platform_suspend_ops pmc_suspend_ops = {
 
 static int pmc_probe(struct of_device *ofdev, const struct of_device_id *id)
 {
-       pmc_regs = of_iomap(ofdev->node, 0);
+       pmc_regs = of_iomap(ofdev->dev.of_node, 0);
        if (!pmc_regs)
                return -ENOMEM;
 
@@ -76,8 +76,11 @@ static const struct of_device_id pmc_ids[] = {
 };
 
 static struct of_platform_driver pmc_driver = {
-       .driver.name = "fsl-pmc",
-       .match_table = pmc_ids,
+       .driver = {
+               .name = "fsl-pmc",
+               .owner = THIS_MODULE,
+               .of_match_table = pmc_ids,
+       },
        .probe = pmc_probe,
 };
 
index 71fba88f50db86e5946593fe0f8407ffc078974b..cd37e49e70349d05cc82c48e83b0bd6a42faa9ce 100644 (file)
@@ -1,6 +1,15 @@
 /*
  * Freescale MPC85xx/MPC86xx RapidIO support
  *
+ * Copyright 2009 Sysgo AG
+ * Thomas Moll <thomas.moll@sysgo.com>
+ * - fixed maintenance access routines, check for aligned access
+ *
+ * Copyright 2009 Integrated Device Technology, Inc.
+ * Alex Bounine <alexandre.bounine@idt.com>
+ * - Added Port-Write message handling
+ * - Added Machine Check exception handling
+ *
  * Copyright (C) 2007, 2008 Freescale Semiconductor, Inc.
  * Zhang Wei <wei.zhang@freescale.com>
  *
 #include <linux/of_platform.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/kfifo.h>
 
 #include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/uaccess.h>
+
+#undef DEBUG_PW        /* Port-Write debugging */
 
 /* RapidIO definition irq, which read from OF-tree */
 #define IRQ_RIO_BELL(m)                (((struct rio_priv *)(m->priv))->bellirq)
 #define IRQ_RIO_TX(m)          (((struct rio_priv *)(m->priv))->txirq)
 #define IRQ_RIO_RX(m)          (((struct rio_priv *)(m->priv))->rxirq)
+#define IRQ_RIO_PW(m)          (((struct rio_priv *)(m->priv))->pwirq)
 
 #define RIO_ATMU_REGS_OFFSET   0x10c00
 #define RIO_P_MSG_REGS_OFFSET  0x11000
 #define RIO_S_MSG_REGS_OFFSET  0x13000
 #define RIO_ESCSR              0x158
 #define RIO_CCSR               0x15c
+#define RIO_LTLEDCSR           0x0608
+#define  RIO_LTLEDCSR_IER      0x80000000
+#define  RIO_LTLEDCSR_PRT      0x01000000
+#define RIO_LTLEECSR           0x060c
+#define RIO_EPWISR             0x10010
 #define RIO_ISR_AACR           0x10120
 #define RIO_ISR_AACR_AA                0x1     /* Accept All ID */
 #define RIO_MAINT_WIN_SIZE     0x400000
 #define RIO_MSG_ISR_QFI                0x00000010
 #define RIO_MSG_ISR_DIQI       0x00000001
 
+#define RIO_IPWMR_SEN          0x00100000
+#define RIO_IPWMR_QFIE         0x00000100
+#define RIO_IPWMR_EIE          0x00000020
+#define RIO_IPWMR_CQ           0x00000002
+#define RIO_IPWMR_PWE          0x00000001
+
+#define RIO_IPWSR_QF           0x00100000
+#define RIO_IPWSR_TE           0x00000080
+#define RIO_IPWSR_QFI          0x00000010
+#define RIO_IPWSR_PWD          0x00000008
+#define RIO_IPWSR_PWB          0x00000004
+
 #define RIO_MSG_DESC_SIZE      32
 #define RIO_MSG_BUFFER_SIZE    4096
 #define RIO_MIN_TX_RING_SIZE   2
@@ -121,7 +153,7 @@ struct rio_msg_regs {
        u32 pad10[26];
        u32 pwmr;
        u32 pwsr;
-       u32 pad11;
+       u32 epwqbar;
        u32 pwqbar;
 };
 
@@ -160,6 +192,14 @@ struct rio_msg_rx_ring {
        void *dev_id;
 };
 
+struct rio_port_write_msg {
+       void *virt;
+       dma_addr_t phys;
+       u32 msg_count;
+       u32 err_count;
+       u32 discard_count;
+};
+
 struct rio_priv {
        struct device *dev;
        void __iomem *regs_win;
@@ -172,11 +212,64 @@ struct rio_priv {
        struct rio_dbell_ring dbell_ring;
        struct rio_msg_tx_ring msg_tx_ring;
        struct rio_msg_rx_ring msg_rx_ring;
+       struct rio_port_write_msg port_write_msg;
        int bellirq;
        int txirq;
        int rxirq;
+       int pwirq;
+       struct work_struct pw_work;
+       struct kfifo pw_fifo;
+       spinlock_t pw_fifo_lock;
 };
 
+#define __fsl_read_rio_config(x, addr, err, op)                \
+       __asm__ __volatile__(                           \
+               "1:     "op" %1,0(%2)\n"                \
+               "       eieio\n"                        \
+               "2:\n"                                  \
+               ".section .fixup,\"ax\"\n"              \
+               "3:     li %1,-1\n"                     \
+               "       li %0,%3\n"                     \
+               "       b 2b\n"                         \
+               ".section __ex_table,\"a\"\n"           \
+               "       .align 2\n"                     \
+               "       .long 1b,3b\n"                  \
+               ".text"                                 \
+               : "=r" (err), "=r" (x)                  \
+               : "b" (addr), "i" (-EFAULT), "0" (err))
+
+static void __iomem *rio_regs_win;
+
+static int (*saved_mcheck_exception)(struct pt_regs *regs);
+
+static int fsl_rio_mcheck_exception(struct pt_regs *regs)
+{
+       const struct exception_table_entry *entry = NULL;
+       unsigned long reason = (mfspr(SPRN_MCSR) & MCSR_MASK);
+
+       if (reason & MCSR_BUS_RBERR) {
+               reason = in_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR));
+               if (reason & (RIO_LTLEDCSR_IER | RIO_LTLEDCSR_PRT)) {
+                       /* Check if we are prepared to handle this fault */
+                       entry = search_exception_tables(regs->nip);
+                       if (entry) {
+                               pr_debug("RIO: %s - MC Exception handled\n",
+                                        __func__);
+                               out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR),
+                                        0);
+                               regs->msr |= MSR_RI;
+                               regs->nip = entry->fixup;
+                               return 1;
+                       }
+               }
+       }
+
+       if (saved_mcheck_exception)
+               return saved_mcheck_exception(regs);
+       else
+               return cur_cpu_spec->machine_check(regs);
+}
+
 /**
  * fsl_rio_doorbell_send - Send a MPC85xx doorbell message
  * @mport: RapidIO master port info
@@ -277,27 +370,44 @@ fsl_rio_config_read(struct rio_mport *mport, int index, u16 destid,
 {
        struct rio_priv *priv = mport->priv;
        u8 *data;
+       u32 rval, err = 0;
 
        pr_debug
            ("fsl_rio_config_read: index %d destid %d hopcount %d offset %8.8x len %d\n",
             index, destid, hopcount, offset, len);
+
+       /* 16MB maintenance window possible */
+       /* allow only aligned access to maintenance registers */
+       if (offset > (0x1000000 - len) || !IS_ALIGNED(offset, len))
+               return -EINVAL;
+
        out_be32(&priv->maint_atmu_regs->rowtar,
-                (destid << 22) | (hopcount << 12) | ((offset & ~0x3) >> 9));
+                (destid << 22) | (hopcount << 12) | (offset >> 12));
+       out_be32(&priv->maint_atmu_regs->rowtear,  (destid >> 10));
 
-       data = (u8 *) priv->maint_win + offset;
+       data = (u8 *) priv->maint_win + (offset & (RIO_MAINT_WIN_SIZE - 1));
        switch (len) {
        case 1:
-               *val = in_8((u8 *) data);
+               __fsl_read_rio_config(rval, data, err, "lbz");
                break;
        case 2:
-               *val = in_be16((u16 *) data);
+               __fsl_read_rio_config(rval, data, err, "lhz");
                break;
-       default:
-               *val = in_be32((u32 *) data);
+       case 4:
+               __fsl_read_rio_config(rval, data, err, "lwz");
                break;
+       default:
+               return -EINVAL;
        }
 
-       return 0;
+       if (err) {
+               pr_debug("RIO: cfg_read error %d for %x:%x:%x\n",
+                        err, destid, hopcount, offset);
+       }
+
+       *val = rval;
+
+       return err;
 }
 
 /**
@@ -322,10 +432,17 @@ fsl_rio_config_write(struct rio_mport *mport, int index, u16 destid,
        pr_debug
            ("fsl_rio_config_write: index %d destid %d hopcount %d offset %8.8x len %d val %8.8x\n",
             index, destid, hopcount, offset, len, val);
+
+       /* 16MB maintenance windows possible */
+       /* allow only aligned access to maintenance registers */
+       if (offset > (0x1000000 - len) || !IS_ALIGNED(offset, len))
+               return -EINVAL;
+
        out_be32(&priv->maint_atmu_regs->rowtar,
-                (destid << 22) | (hopcount << 12) | ((offset & ~0x3) >> 9));
+                (destid << 22) | (hopcount << 12) | (offset >> 12));
+       out_be32(&priv->maint_atmu_regs->rowtear,  (destid >> 10));
 
-       data = (u8 *) priv->maint_win + offset;
+       data = (u8 *) priv->maint_win + (offset & (RIO_MAINT_WIN_SIZE - 1));
        switch (len) {
        case 1:
                out_8((u8 *) data, val);
@@ -333,9 +450,11 @@ fsl_rio_config_write(struct rio_mport *mport, int index, u16 destid,
        case 2:
                out_be16((u16 *) data, val);
                break;
-       default:
+       case 4:
                out_be32((u32 *) data, val);
                break;
+       default:
+               return -EINVAL;
        }
 
        return 0;
@@ -930,6 +1049,223 @@ static int fsl_rio_doorbell_init(struct rio_mport *mport)
        return rc;
 }
 
+/**
+ * fsl_rio_port_write_handler - MPC85xx port write interrupt handler
+ * @irq: Linux interrupt number
+ * @dev_instance: Pointer to interrupt-specific data
+ *
+ * Handles port write interrupts. Parses a list of registered
+ * port write event handlers and executes a matching event handler.
+ */
+static irqreturn_t
+fsl_rio_port_write_handler(int irq, void *dev_instance)
+{
+       u32 ipwmr, ipwsr;
+       struct rio_mport *port = (struct rio_mport *)dev_instance;
+       struct rio_priv *priv = port->priv;
+       u32 epwisr, tmp;
+
+       ipwmr = in_be32(&priv->msg_regs->pwmr);
+       ipwsr = in_be32(&priv->msg_regs->pwsr);
+
+       epwisr = in_be32(priv->regs_win + RIO_EPWISR);
+       if (epwisr & 0x80000000) {
+               tmp = in_be32(priv->regs_win + RIO_LTLEDCSR);
+               pr_info("RIO_LTLEDCSR = 0x%x\n", tmp);
+               out_be32(priv->regs_win + RIO_LTLEDCSR, 0);
+       }
+
+       if (!(epwisr & 0x00000001))
+               return IRQ_HANDLED;
+
+#ifdef DEBUG_PW
+       pr_debug("PW Int->IPWMR: 0x%08x IPWSR: 0x%08x (", ipwmr, ipwsr);
+       if (ipwsr & RIO_IPWSR_QF)
+               pr_debug(" QF");
+       if (ipwsr & RIO_IPWSR_TE)
+               pr_debug(" TE");
+       if (ipwsr & RIO_IPWSR_QFI)
+               pr_debug(" QFI");
+       if (ipwsr & RIO_IPWSR_PWD)
+               pr_debug(" PWD");
+       if (ipwsr & RIO_IPWSR_PWB)
+               pr_debug(" PWB");
+       pr_debug(" )\n");
+#endif
+       out_be32(&priv->msg_regs->pwsr,
+                ipwsr & (RIO_IPWSR_TE | RIO_IPWSR_QFI | RIO_IPWSR_PWD));
+
+       if ((ipwmr & RIO_IPWMR_EIE) && (ipwsr & RIO_IPWSR_TE)) {
+               priv->port_write_msg.err_count++;
+               pr_info("RIO: Port-Write Transaction Err (%d)\n",
+                        priv->port_write_msg.err_count);
+       }
+       if (ipwsr & RIO_IPWSR_PWD) {
+               priv->port_write_msg.discard_count++;
+               pr_info("RIO: Port Discarded Port-Write Msg(s) (%d)\n",
+                        priv->port_write_msg.discard_count);
+       }
+
+       /* Schedule deferred processing if PW was received */
+       if (ipwsr & RIO_IPWSR_QFI) {
+               /* Save PW message (if there is room in FIFO),
+                * otherwise discard it.
+                */
+               if (kfifo_avail(&priv->pw_fifo) >= RIO_PW_MSG_SIZE) {
+                       priv->port_write_msg.msg_count++;
+                       kfifo_in(&priv->pw_fifo, priv->port_write_msg.virt,
+                                RIO_PW_MSG_SIZE);
+               } else {
+                       priv->port_write_msg.discard_count++;
+                       pr_info("RIO: ISR Discarded Port-Write Msg(s) (%d)\n",
+                                priv->port_write_msg.discard_count);
+               }
+               schedule_work(&priv->pw_work);
+       }
+
+       /* Issue Clear Queue command. This allows another
+        * port-write to be received.
+        */
+       out_be32(&priv->msg_regs->pwmr, ipwmr | RIO_IPWMR_CQ);
+
+       return IRQ_HANDLED;
+}
+
+static void fsl_pw_dpc(struct work_struct *work)
+{
+       struct rio_priv *priv = container_of(work, struct rio_priv, pw_work);
+       unsigned long flags;
+       u32 msg_buffer[RIO_PW_MSG_SIZE/sizeof(u32)];
+
+       /*
+        * Process port-write messages
+        */
+       spin_lock_irqsave(&priv->pw_fifo_lock, flags);
+       while (kfifo_out(&priv->pw_fifo, (unsigned char *)msg_buffer,
+                        RIO_PW_MSG_SIZE)) {
+               /* Process one message */
+               spin_unlock_irqrestore(&priv->pw_fifo_lock, flags);
+#ifdef DEBUG_PW
+               {
+               u32 i;
+               pr_debug("%s : Port-Write Message:", __func__);
+               for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32); i++) {
+                       if ((i%4) == 0)
+                               pr_debug("\n0x%02x: 0x%08x", i*4,
+                                        msg_buffer[i]);
+                       else
+                               pr_debug(" 0x%08x", msg_buffer[i]);
+               }
+               pr_debug("\n");
+               }
+#endif
+               /* Pass the port-write message to RIO core for processing */
+               rio_inb_pwrite_handler((union rio_pw_msg *)msg_buffer);
+               spin_lock_irqsave(&priv->pw_fifo_lock, flags);
+       }
+       spin_unlock_irqrestore(&priv->pw_fifo_lock, flags);
+}
+
+/**
+ * fsl_rio_pw_enable - enable/disable port-write interface init
+ * @mport: Master port implementing the port write unit
+ * @enable:    1=enable; 0=disable port-write message handling
+ */
+static int fsl_rio_pw_enable(struct rio_mport *mport, int enable)
+{
+       struct rio_priv *priv = mport->priv;
+       u32 rval;
+
+       rval = in_be32(&priv->msg_regs->pwmr);
+
+       if (enable)
+               rval |= RIO_IPWMR_PWE;
+       else
+               rval &= ~RIO_IPWMR_PWE;
+
+       out_be32(&priv->msg_regs->pwmr, rval);
+
+       return 0;
+}
+
+/**
+ * fsl_rio_port_write_init - MPC85xx port write interface init
+ * @mport: Master port implementing the port write unit
+ *
+ * Initializes port write unit hardware and DMA buffer
+ * ring. Called from fsl_rio_setup(). Returns %0 on success
+ * or %-ENOMEM on failure.
+ */
+static int fsl_rio_port_write_init(struct rio_mport *mport)
+{
+       struct rio_priv *priv = mport->priv;
+       int rc = 0;
+
+       /* Following configurations require a disabled port write controller */
+       out_be32(&priv->msg_regs->pwmr,
+                in_be32(&priv->msg_regs->pwmr) & ~RIO_IPWMR_PWE);
+
+       /* Initialize port write */
+       priv->port_write_msg.virt = dma_alloc_coherent(priv->dev,
+                                       RIO_PW_MSG_SIZE,
+                                       &priv->port_write_msg.phys, GFP_KERNEL);
+       if (!priv->port_write_msg.virt) {
+               pr_err("RIO: unable allocate port write queue\n");
+               return -ENOMEM;
+       }
+
+       priv->port_write_msg.err_count = 0;
+       priv->port_write_msg.discard_count = 0;
+
+       /* Point dequeue/enqueue pointers at first entry */
+       out_be32(&priv->msg_regs->epwqbar, 0);
+       out_be32(&priv->msg_regs->pwqbar, (u32) priv->port_write_msg.phys);
+
+       pr_debug("EIPWQBAR: 0x%08x IPWQBAR: 0x%08x\n",
+                in_be32(&priv->msg_regs->epwqbar),
+                in_be32(&priv->msg_regs->pwqbar));
+
+       /* Clear interrupt status IPWSR */
+       out_be32(&priv->msg_regs->pwsr,
+                (RIO_IPWSR_TE | RIO_IPWSR_QFI | RIO_IPWSR_PWD));
+
+       /* Configure port write contoller for snooping enable all reporting,
+          clear queue full */
+       out_be32(&priv->msg_regs->pwmr,
+                RIO_IPWMR_SEN | RIO_IPWMR_QFIE | RIO_IPWMR_EIE | RIO_IPWMR_CQ);
+
+
+       /* Hook up port-write handler */
+       rc = request_irq(IRQ_RIO_PW(mport), fsl_rio_port_write_handler, 0,
+                        "port-write", (void *)mport);
+       if (rc < 0) {
+               pr_err("MPC85xx RIO: unable to request inbound doorbell irq");
+               goto err_out;
+       }
+
+       INIT_WORK(&priv->pw_work, fsl_pw_dpc);
+       spin_lock_init(&priv->pw_fifo_lock);
+       if (kfifo_alloc(&priv->pw_fifo, RIO_PW_MSG_SIZE * 32, GFP_KERNEL)) {
+               pr_err("FIFO allocation failed\n");
+               rc = -ENOMEM;
+               goto err_out_irq;
+       }
+
+       pr_debug("IPWMR: 0x%08x IPWSR: 0x%08x\n",
+                in_be32(&priv->msg_regs->pwmr),
+                in_be32(&priv->msg_regs->pwsr));
+
+       return rc;
+
+err_out_irq:
+       free_irq(IRQ_RIO_PW(mport), (void *)mport);
+err_out:
+       dma_free_coherent(priv->dev, RIO_PW_MSG_SIZE,
+                         priv->port_write_msg.virt,
+                         priv->port_write_msg.phys);
+       return rc;
+}
+
 static char *cmdline = NULL;
 
 static int fsl_rio_get_hdid(int index)
@@ -1015,41 +1351,41 @@ int fsl_rio_setup(struct of_device *dev)
        u64 law_start, law_size;
        int paw, aw, sw;
 
-       if (!dev->node) {
+       if (!dev->dev.of_node) {
                dev_err(&dev->dev, "Device OF-Node is NULL");
                return -EFAULT;
        }
 
-       rc = of_address_to_resource(dev->node, 0, &regs);
+       rc = of_address_to_resource(dev->dev.of_node, 0, &regs);
        if (rc) {
                dev_err(&dev->dev, "Can't get %s property 'reg'\n",
-                               dev->node->full_name);
+                               dev->dev.of_node->full_name);
                return -EFAULT;
        }
-       dev_info(&dev->dev, "Of-device full name %s\n", dev->node->full_name);
+       dev_info(&dev->dev, "Of-device full name %s\n", dev->dev.of_node->full_name);
        dev_info(&dev->dev, "Regs: %pR\n", &regs);
 
-       dt_range = of_get_property(dev->node, "ranges", &rlen);
+       dt_range = of_get_property(dev->dev.of_node, "ranges", &rlen);
        if (!dt_range) {
                dev_err(&dev->dev, "Can't get %s property 'ranges'\n",
-                               dev->node->full_name);
+                               dev->dev.of_node->full_name);
                return -EFAULT;
        }
 
        /* Get node address wide */
-       cell = of_get_property(dev->node, "#address-cells", NULL);
+       cell = of_get_property(dev->dev.of_node, "#address-cells", NULL);
        if (cell)
                aw = *cell;
        else
-               aw = of_n_addr_cells(dev->node);
+               aw = of_n_addr_cells(dev->dev.of_node);
        /* Get node size wide */
-       cell = of_get_property(dev->node, "#size-cells", NULL);
+       cell = of_get_property(dev->dev.of_node, "#size-cells", NULL);
        if (cell)
                sw = *cell;
        else
-               sw = of_n_size_cells(dev->node);
+               sw = of_n_size_cells(dev->dev.of_node);
        /* Get parent address wide wide */
-       paw = of_n_addr_cells(dev->node);
+       paw = of_n_addr_cells(dev->dev.of_node);
 
        law_start = of_read_number(dt_range + aw, paw);
        law_size = of_read_number(dt_range + aw + paw, sw);
@@ -1057,7 +1393,7 @@ int fsl_rio_setup(struct of_device *dev)
        dev_info(&dev->dev, "LAW start 0x%016llx, size 0x%016llx.\n",
                        law_start, law_size);
 
-       ops = kmalloc(sizeof(struct rio_ops), GFP_KERNEL);
+       ops = kzalloc(sizeof(struct rio_ops), GFP_KERNEL);
        if (!ops) {
                rc = -ENOMEM;
                goto err_ops;
@@ -1067,6 +1403,7 @@ int fsl_rio_setup(struct of_device *dev)
        ops->cread = fsl_rio_config_read;
        ops->cwrite = fsl_rio_config_write;
        ops->dsend = fsl_rio_doorbell_send;
+       ops->pwenable = fsl_rio_pw_enable;
 
        port = kzalloc(sizeof(struct rio_mport), GFP_KERNEL);
        if (!port) {
@@ -1089,11 +1426,12 @@ int fsl_rio_setup(struct of_device *dev)
        port->iores.flags = IORESOURCE_MEM;
        port->iores.name = "rio_io_win";
 
-       priv->bellirq = irq_of_parse_and_map(dev->node, 2);
-       priv->txirq = irq_of_parse_and_map(dev->node, 3);
-       priv->rxirq = irq_of_parse_and_map(dev->node, 4);
-       dev_info(&dev->dev, "bellirq: %d, txirq: %d, rxirq %d\n", priv->bellirq,
-                               priv->txirq, priv->rxirq);
+       priv->pwirq   = irq_of_parse_and_map(dev->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);
+       dev_info(&dev->dev, "pwirq: %d, bellirq: %d, txirq: %d, rxirq %d\n",
+                priv->pwirq, priv->bellirq, priv->txirq, priv->rxirq);
 
        rio_init_dbell_res(&port->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff);
        rio_init_mbox_res(&port->riores[RIO_INB_MBOX_RESOURCE], 0, 0);
@@ -1109,6 +1447,7 @@ int fsl_rio_setup(struct of_device *dev)
        rio_register_mport(port);
 
        priv->regs_win = ioremap(regs.start, regs.end - regs.start + 1);
+       rio_regs_win = priv->regs_win;
 
        /* Probe the master port phy type */
        ccsr = in_be32(priv->regs_win + RIO_CCSR);
@@ -1166,7 +1505,8 @@ int fsl_rio_setup(struct of_device *dev)
 
        /* Configure maintenance transaction window */
        out_be32(&priv->maint_atmu_regs->rowbar, law_start >> 12);
-       out_be32(&priv->maint_atmu_regs->rowar, 0x80077015);    /* 4M */
+       out_be32(&priv->maint_atmu_regs->rowar,
+                0x80077000 | (ilog2(RIO_MAINT_WIN_SIZE) - 1));
 
        priv->maint_win = ioremap(law_start, RIO_MAINT_WIN_SIZE);
 
@@ -1175,6 +1515,12 @@ int fsl_rio_setup(struct of_device *dev)
                        (law_start + RIO_MAINT_WIN_SIZE) >> 12);
        out_be32(&priv->dbell_atmu_regs->rowar, 0x8004200b);    /* 4k */
        fsl_rio_doorbell_init(port);
+       fsl_rio_port_write_init(port);
+
+       saved_mcheck_exception = ppc_md.machine_check_exception;
+       ppc_md.machine_check_exception = fsl_rio_mcheck_exception;
+       /* Ensure that RFXE is set */
+       mtspr(SPRN_HID1, (mfspr(SPRN_HID1) | 0x20000));
 
        return 0;
 err:
@@ -1195,7 +1541,7 @@ static int __devinit fsl_of_rio_rpn_probe(struct of_device *dev,
 {
        int rc;
        printk(KERN_INFO "Setting up RapidIO peer-to-peer network %s\n",
-                       dev->node->full_name);
+                       dev->dev.of_node->full_name);
 
        rc = fsl_rio_setup(dev);
        if (rc)
@@ -1215,8 +1561,11 @@ static const struct of_device_id fsl_of_rio_rpn_ids[] = {
 };
 
 static struct of_platform_driver fsl_of_rio_rpn_driver = {
-       .name = "fsl-of-rio",
-       .match_table = fsl_of_rio_rpn_ids,
+       .driver = {
+               .name = "fsl-of-rio",
+               .owner = THIS_MODULE,
+               .of_match_table = fsl_of_rio_rpn_ids,
+       },
        .probe = fsl_of_rio_rpn_probe,
 };
 
index 652652db4ce283f11cee235d689268d0dcfce36d..d07137a07d7509b0e6cf082f5de6e421922f2091 100644 (file)
@@ -124,7 +124,7 @@ static void pmi_notify_handlers(struct work_struct *work)
 static int pmi_of_probe(struct of_device *dev,
                        const struct of_device_id *match)
 {
-       struct device_node *np = dev->node;
+       struct device_node *np = dev->dev.of_node;
        int rc;
 
        if (data) {
@@ -206,11 +206,12 @@ static int pmi_of_remove(struct of_device *dev)
 }
 
 static struct of_platform_driver pmi_of_platform_driver = {
-       .match_table    = pmi_match,
        .probe          = pmi_of_probe,
        .remove         = pmi_of_remove,
-       .driver         = {
-               .name   = "pmi",
+       .driver = {
+               .name = "pmi",
+               .owner = THIS_MODULE,
+               .of_match_table = pmi_match,
        },
 };
 
index 149393c02c3f117b0f2f9d7e2387b5c83fffcdcf..093e0ae1a9418fc0830be5c6bee35041c774d198 100644 (file)
@@ -669,8 +669,11 @@ static const struct of_device_id qe_ids[] = {
 };
 
 static struct of_platform_driver qe_driver = {
-       .driver.name = "fsl-qe",
-       .match_table = qe_ids,
+       .driver = {
+               .name = "fsl-qe",
+               .owner = THIS_MODULE,
+               .of_match_table = qe_ids,
+       },
        .probe = qe_probe,
        .resume = qe_resume,
 };
index 79d0ca0868200462357e04ece79837647441cae3..bee1c0f794cf0262b00032493c0b79426d1730e9 100644 (file)
@@ -102,6 +102,7 @@ config S390
        select HAVE_KERNEL_GZIP
        select HAVE_KERNEL_BZIP2
        select HAVE_KERNEL_LZMA
+       select HAVE_KERNEL_LZO
        select ARCH_INLINE_SPIN_TRYLOCK
        select ARCH_INLINE_SPIN_TRYLOCK_BH
        select ARCH_INLINE_SPIN_LOCK
@@ -479,13 +480,6 @@ config CMM
          Everybody who wants to run Linux under VM should select this
          option.
 
-config CMM_PROC
-       bool "/proc interface to cooperative memory management"
-       depends on CMM
-       help
-         Select this option to enable the /proc interface to the
-         cooperative memory management.
-
 config CMM_IUCV
        bool "IUCV special message interface to cooperative memory management"
        depends on CMM && (SMSGIUCV=y || CMM=SMSGIUCV)
index 6e4a67ad07e1adc5b00c78c6a36f3bf2bf2029eb..1c999f726a582ca4704da2e81929d67fdd4a9bef 100644 (file)
@@ -7,7 +7,7 @@
 BITS := $(if $(CONFIG_64BIT),64,31)
 
 targets        := vmlinux.lds vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 \
-          vmlinux.bin.lzma misc.o piggy.o sizes.h head$(BITS).o
+          vmlinux.bin.lzma vmlinux.bin.lzo misc.o piggy.o sizes.h head$(BITS).o
 
 KBUILD_CFLAGS := -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2
 KBUILD_CFLAGS += $(cflags-y)
@@ -47,6 +47,7 @@ vmlinux.bin.all-y := $(obj)/vmlinux.bin
 suffix-$(CONFIG_KERNEL_GZIP)  := gz
 suffix-$(CONFIG_KERNEL_BZIP2) := bz2
 suffix-$(CONFIG_KERNEL_LZMA)  := lzma
+suffix-$(CONFIG_KERNEL_LZO)  := lzo
 
 $(obj)/vmlinux.bin.gz: $(vmlinux.bin.all-y)
        $(call if_changed,gzip)
@@ -54,6 +55,8 @@ $(obj)/vmlinux.bin.bz2: $(vmlinux.bin.all-y)
        $(call if_changed,bzip2)
 $(obj)/vmlinux.bin.lzma: $(vmlinux.bin.all-y)
        $(call if_changed,lzma)
+$(obj)/vmlinux.bin.lzo: $(vmlinux.bin.all-y)
+       $(call if_changed,lzo)
 
 LDFLAGS_piggy.o := -r --format binary --oformat $(LD_BFD) -T
 $(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.$(suffix-y)
index 14e0479d3888eb8d5178fd0f0f4c851dc37ebdf4..0851eb1e919e8dfbf4d7deab9e29ddce9acd8274 100644 (file)
@@ -50,6 +50,10 @@ static unsigned long free_mem_end_ptr;
 #include "../../../../lib/decompress_unlzma.c"
 #endif
 
+#ifdef CONFIG_KERNEL_LZO
+#include "../../../../lib/decompress_unlzo.c"
+#endif
+
 extern _sclp_print_early(const char *);
 
 int puts(const char *s)
index 451bfbb9db3dbac8830ace5d850ae98ee75ad341..76daea117181e9df886da524ebfb4147f54ff84a 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <linux/compiler.h>
 #include <linux/types.h>
+#include <asm/system.h>
 
 #define ATOMIC_INIT(i)  { (i) }
 
@@ -274,6 +275,7 @@ static inline void atomic64_clear_mask(unsigned long long mask, atomic64_t *v)
 static inline int atomic64_add_unless(atomic64_t *v, long long a, long long u)
 {
        long long c, old;
+
        c = atomic64_read(v);
        for (;;) {
                if (unlikely(c == u))
@@ -286,6 +288,23 @@ static inline int atomic64_add_unless(atomic64_t *v, long long a, long long u)
        return c != u;
 }
 
+static inline long long atomic64_dec_if_positive(atomic64_t *v)
+{
+       long long c, old, dec;
+
+       c = atomic64_read(v);
+       for (;;) {
+               dec = c - 1;
+               if (unlikely(dec < 0))
+                       break;
+               old = atomic64_cmpxchg((v), c, dec);
+               if (likely(old == c))
+                       break;
+               c = old;
+       }
+       return dec;
+}
+
 #define atomic64_add(_i, _v)           atomic64_add_return(_i, _v)
 #define atomic64_add_negative(_i, _v)  (atomic64_add_return(_i, _v) < 0)
 #define atomic64_inc(_v)               atomic64_add_return(1, _v)
index 9beeb9db9b23a7695adaf435755d1b1ae5bd37af..bf90d1fd97a59cbd4141f8180be49e7b0cc265f7 100644 (file)
        unreachable();                                  \
 } while (0)
 
-#define __WARN() do {                                  \
-       __EMIT_BUG(BUGFLAG_WARNING);                    \
+#define __WARN_TAINT(taint) do {                       \
+       __EMIT_BUG(BUGFLAG_TAINT(taint));               \
 } while (0)
 
 #define WARN_ON(x) ({                                  \
        int __ret_warn_on = !!(x);                      \
        if (__builtin_constant_p(__ret_warn_on)) {      \
                if (__ret_warn_on)                      \
-                       __EMIT_BUG(BUGFLAG_WARNING);    \
+                       __WARN();                       \
        } else {                                        \
                if (unlikely(__ret_warn_on))            \
-                       __EMIT_BUG(BUGFLAG_WARNING);    \
+                       __WARN();                       \
        }                                               \
        unlikely(__ret_warn_on);                        \
 })
index f4bd346a52d3567e6a7b33885308b28e787cac2f..1c0030f9b890b7ff29c95c10db807d8ab4d92778 100644 (file)
@@ -91,6 +91,14 @@ struct ccw_device {
        void (*handler) (struct ccw_device *, unsigned long, struct irb *);
 };
 
+/*
+ * Possible CIO actions triggered by the unit check handler.
+ */
+enum uc_todo {
+       UC_TODO_RETRY,
+       UC_TODO_RETRY_ON_NEW_PATH,
+       UC_TODO_STOP
+};
 
 /**
  * struct ccw driver - device driver for channel attached devices
@@ -107,6 +115,7 @@ struct ccw_device {
  * @freeze: callback for freezing during hibernation snapshotting
  * @thaw: undo work done in @freeze
  * @restore: callback for restoring after hibernation
+ * @uc_handler: callback for unit check handler
  * @driver: embedded device driver structure
  * @name: device driver name
  */
@@ -124,6 +133,7 @@ struct ccw_driver {
        int (*freeze)(struct ccw_device *);
        int (*thaw) (struct ccw_device *);
        int (*restore)(struct ccw_device *);
+       enum uc_todo (*uc_handler) (struct ccw_device *, struct irb *);
        struct device_driver driver;
        char *name;
 };
index 35d786fe93ae0dcba7e1cf434606e9e61d1b05c2..be44d94cba549d386e1b6a3abaed0d88b8628336 100644 (file)
@@ -1 +1,3 @@
+#define ISA_DMA_THRESHOLD      (~0UL)
+
 #include <asm-generic/scatterlist.h>
index d9b490a2716e16624f0b1c1e2b45205815ae74cf..5232278d79adc289cae995a78d51fd04c90b096f 100644 (file)
@@ -132,8 +132,6 @@ int main(void)
        DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock));
        DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags));
        DEFINE(__LC_FTRACE_FUNC, offsetof(struct _lowcore, ftrace_func));
-       DEFINE(__LC_SIE_HOOK, offsetof(struct _lowcore, sie_hook));
-       DEFINE(__LC_CMF_HPP, offsetof(struct _lowcore, cmf_hpp));
        DEFINE(__LC_IRB, offsetof(struct _lowcore, irb));
        DEFINE(__LC_CPU_TIMER_SAVE_AREA, offsetof(struct _lowcore, cpu_timer_save_area));
        DEFINE(__LC_CLOCK_COMP_SAVE_AREA, offsetof(struct _lowcore, clock_comp_save_area));
@@ -154,6 +152,8 @@ int main(void)
        DEFINE(__LC_FP_CREG_SAVE_AREA, offsetof(struct _lowcore, fpt_creg_save_area));
        DEFINE(__LC_LAST_BREAK, offsetof(struct _lowcore, breaking_event_addr));
        DEFINE(__LC_VDSO_PER_CPU, offsetof(struct _lowcore, vdso_per_cpu_data));
+       DEFINE(__LC_SIE_HOOK, offsetof(struct _lowcore, sie_hook));
+       DEFINE(__LC_CMF_HPP, offsetof(struct _lowcore, cmf_hpp));
 #endif /* CONFIG_32BIT */
        return 0;
 }
index 178d92536d903864999f18b8ece299d4c0a8446a..e7192e1cb6785b24db347b2bbe2c22a469bdeb7d 100644 (file)
@@ -65,7 +65,7 @@ _TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \
        ltgr    %r3,%r3
        jz      0f
        basr    %r14,%r3
-       0:
+0:
 #endif
        .endm
 
index 3d34eef5a2c3a03987479a28df28e4a415e3c2f0..2a3d2bf6f083070678f4c777b4cea0db00b9ff74 100644 (file)
@@ -63,6 +63,8 @@ int __kprobes is_prohibited_opcode(kprobe_opcode_t *instruction)
        case 0x0b:      /* bsm   */
        case 0x83:      /* diag  */
        case 0x44:      /* ex    */
+       case 0xac:      /* stnsm */
+       case 0xad:      /* stosm */
                return -EINVAL;
        }
        switch (*(__u16 *) instruction) {
@@ -72,6 +74,7 @@ int __kprobes is_prohibited_opcode(kprobe_opcode_t *instruction)
        case 0xb258:    /* bsg   */
        case 0xb218:    /* pc    */
        case 0xb228:    /* pt    */
+       case 0xb98d:    /* epsw  */
                return -EINVAL;
        }
        return 0;
index 7d893248d26507bce1dcc0a2df02f6479a823052..c8e8e1354e1dd403d6bcbb56e5c0d6f8ac3a0b33 100644 (file)
@@ -401,7 +401,6 @@ setup_lowcore(void)
        lc->io_new_psw.mask = psw_kernel_bits;
        lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler;
        lc->clock_comparator = -1ULL;
-       lc->cmf_hpp = -1ULL;
        lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE;
        lc->async_stack = (unsigned long)
                __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE;
@@ -418,6 +417,7 @@ setup_lowcore(void)
                __ctl_set_bit(14, 29);
        }
 #else
+       lc->cmf_hpp = -1ULL;
        lc->vdso_per_cpu_data = (unsigned long) &lc->paste[0];
 #endif
        lc->sync_enter_timer = S390_lowcore.sync_enter_timer;
index e4d98de83dd8393586118ec7ee760d4907385c05..541053ed234ea1c0cd8a893de5bf16c9c30d9022 100644 (file)
@@ -944,21 +944,21 @@ static int __cpuinit smp_cpu_notify(struct notifier_block *self,
        struct cpu *c = &per_cpu(cpu_devices, cpu);
        struct sys_device *s = &c->sysdev;
        struct s390_idle_data *idle;
+       int err = 0;
 
        switch (action) {
        case CPU_ONLINE:
        case CPU_ONLINE_FROZEN:
                idle = &per_cpu(s390_idle, cpu);
                memset(idle, 0, sizeof(struct s390_idle_data));
-               if (sysfs_create_group(&s->kobj, &cpu_online_attr_group))
-                       return NOTIFY_BAD;
+               err = sysfs_create_group(&s->kobj, &cpu_online_attr_group);
                break;
        case CPU_DEAD:
        case CPU_DEAD_FROZEN:
                sysfs_remove_group(&s->kobj, &cpu_online_attr_group);
                break;
        }
-       return NOTIFY_OK;
+       return notifier_from_errno(err);
 }
 
 static struct notifier_block __cpuinitdata smp_cpu_nb = {
index 2f4b687cc7fa094f943daf925bd07c27204c717a..a7251580891cfef25483e683460d58f498eb65b6 100644 (file)
@@ -33,17 +33,6 @@ config KVM
 
          If unsure, say N.
 
-config KVM_AWARE_CMF
-       depends on KVM
-       bool "KVM aware sampling"
-       ---help---
-         This option enhances the sampling data from the CPU Measurement
-         Facility with additional information, that allows to distinguish
-         guest(s) and host when using the kernel based virtual machine
-         functionality.
-
-         If unsure, say N.
-
 # OK, it's a little counter-intuitive to do this, but it puts it neatly under
 # the virtualization menu.
 source drivers/vhost/Kconfig
index 49292869a5cdbeb18cb2a3a17e46a25f68d21b55..8093e6f47f49735d978f19ff4ea40db7ab797313 100644 (file)
@@ -341,11 +341,13 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
 
        rc = kvm_vcpu_init(vcpu, kvm, id);
        if (rc)
-               goto out_free_cpu;
+               goto out_free_sie_block;
        VM_EVENT(kvm, 3, "create cpu %d at %p, sie block at %p", id, vcpu,
                 vcpu->arch.sie_block);
 
        return vcpu;
+out_free_sie_block:
+       free_page((unsigned long)(vcpu->arch.sie_block));
 out_free_cpu:
        kfree(vcpu);
 out_nomem:
@@ -750,7 +752,7 @@ gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
 static int __init kvm_s390_init(void)
 {
        int ret;
-       ret = kvm_init(NULL, sizeof(struct kvm_vcpu), THIS_MODULE);
+       ret = kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE);
        if (ret)
                return ret;
 
index 60f09ab3672c9d26453395f70addbb45f6a77d6c..cfa9d1777457894ab96679cfe571084e24ba790f 100644 (file)
@@ -72,7 +72,7 @@ static inline void kvm_s390_vcpu_set_mem(struct kvm_vcpu *vcpu)
        struct kvm_memslots *memslots;
 
        idx = srcu_read_lock(&vcpu->kvm->srcu);
-       memslots = rcu_dereference(vcpu->kvm->memslots);
+       memslots = kvm_memslots(vcpu->kvm);
 
        mem = &memslots->memslots[0];
 
index 31646bd0e469a6db61f2386de29a2da0bb2b0e0f..7e9d30d567b0ab21265b669f1f343018d10de080 100644 (file)
@@ -32,12 +32,10 @@ SPI_PSW  = STACK_FRAME_OVERHEAD + __PT_PSW
 
 
        .macro SPP newpp
-#ifdef CONFIG_KVM_AWARE_CMF
        tm      __LC_MACHINE_FLAGS+6,0x20       # MACHINE_FLAG_SPP
        jz      0f
        .insn   s,0xb2800000,\newpp
-       0:
-#endif
+0:
        .endm
 
 sie_irq_handler:
index f87b34731e1d9e377de37c30adfcbc50dec18477..eb6a2ef5f82e88cdf5621f197dfb2864133df325 100644 (file)
@@ -1,11 +1,9 @@
 /*
- *  arch/s390/mm/cmm.c
+ *  Collaborative memory management interface.
  *
- *  S390 version
- *    Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *    Copyright IBM Corp 2003,2010
+ *    Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>,
  *
- *  Collaborative memory management interface.
  */
 
 #include <linux/errno.h>
@@ -20,9 +18,9 @@
 #include <linux/kthread.h>
 #include <linux/oom.h>
 #include <linux/suspend.h>
+#include <linux/uaccess.h>
 
 #include <asm/pgalloc.h>
-#include <asm/uaccess.h>
 #include <asm/diag.h>
 
 static char *sender = "VMRMSVM";
@@ -53,14 +51,14 @@ static struct cmm_page_array *cmm_timed_page_list;
 static DEFINE_SPINLOCK(cmm_lock);
 
 static struct task_struct *cmm_thread_ptr;
-static wait_queue_head_t cmm_thread_wait;
-static struct timer_list cmm_timer;
+static DECLARE_WAIT_QUEUE_HEAD(cmm_thread_wait);
+static DEFINE_TIMER(cmm_timer, NULL, 0, 0);
 
 static void cmm_timer_fn(unsigned long);
 static void cmm_set_timer(void);
 
-static long
-cmm_alloc_pages(long nr, long *counter, struct cmm_page_array **list)
+static long cmm_alloc_pages(long nr, long *counter,
+                           struct cmm_page_array **list)
 {
        struct cmm_page_array *pa, *npa;
        unsigned long addr;
@@ -99,8 +97,7 @@ cmm_alloc_pages(long nr, long *counter, struct cmm_page_array **list)
        return nr;
 }
 
-static long
-cmm_free_pages(long nr, long *counter, struct cmm_page_array **list)
+static long cmm_free_pages(long nr, long *counter, struct cmm_page_array **list)
 {
        struct cmm_page_array *pa;
        unsigned long addr;
@@ -140,11 +137,10 @@ static int cmm_oom_notify(struct notifier_block *self,
 }
 
 static struct notifier_block cmm_oom_nb = {
-       .notifier_call = cmm_oom_notify
+       .notifier_call = cmm_oom_notify,
 };
 
-static int
-cmm_thread(void *dummy)
+static int cmm_thread(void *dummy)
 {
        int rc;
 
@@ -170,7 +166,7 @@ cmm_thread(void *dummy)
                                cmm_timed_pages_target = cmm_timed_pages;
                } else if (cmm_timed_pages_target < cmm_timed_pages) {
                        cmm_free_pages(1, &cmm_timed_pages,
-                                      &cmm_timed_page_list);
+                                      &cmm_timed_page_list);
                }
                if (cmm_timed_pages > 0 && !timer_pending(&cmm_timer))
                        cmm_set_timer();
@@ -178,14 +174,12 @@ cmm_thread(void *dummy)
        return 0;
 }
 
-static void
-cmm_kick_thread(void)
+static void cmm_kick_thread(void)
 {
        wake_up(&cmm_thread_wait);
 }
 
-static void
-cmm_set_timer(void)
+static void cmm_set_timer(void)
 {
        if (cmm_timed_pages_target <= 0 || cmm_timeout_seconds <= 0) {
                if (timer_pending(&cmm_timer))
@@ -202,8 +196,7 @@ cmm_set_timer(void)
        add_timer(&cmm_timer);
 }
 
-static void
-cmm_timer_fn(unsigned long ignored)
+static void cmm_timer_fn(unsigned long ignored)
 {
        long nr;
 
@@ -216,57 +209,49 @@ cmm_timer_fn(unsigned long ignored)
        cmm_set_timer();
 }
 
-void
-cmm_set_pages(long nr)
+static void cmm_set_pages(long nr)
 {
        cmm_pages_target = nr;
        cmm_kick_thread();
 }
 
-long
-cmm_get_pages(void)
+static long cmm_get_pages(void)
 {
        return cmm_pages;
 }
 
-void
-cmm_add_timed_pages(long nr)
+static void cmm_add_timed_pages(long nr)
 {
        cmm_timed_pages_target += nr;
        cmm_kick_thread();
 }
 
-long
-cmm_get_timed_pages(void)
+static long cmm_get_timed_pages(void)
 {
        return cmm_timed_pages;
 }
 
-void
-cmm_set_timeout(long nr, long seconds)
+static void cmm_set_timeout(long nr, long seconds)
 {
        cmm_timeout_pages = nr;
        cmm_timeout_seconds = seconds;
        cmm_set_timer();
 }
 
-static int
-cmm_skip_blanks(char *cp, char **endp)
+static int cmm_skip_blanks(char *cp, char **endp)
 {
        char *str;
 
-       for (str = cp; *str == ' ' || *str == '\t'; str++);
+       for (str = cp; *str == ' ' || *str == '\t'; str++)
+               ;
        *endp = str;
        return str != cp;
 }
 
-#ifdef CONFIG_CMM_PROC
-
 static struct ctl_table cmm_table[];
 
-static int
-cmm_pages_handler(ctl_table *ctl, int write,
-                 void __user *buffer, size_t *lenp, loff_t *ppos)
+static int cmm_pages_handler(ctl_table *ctl, int write, void __user *buffer,
+                            size_t *lenp, loff_t *ppos)
 {
        char buf[16], *p;
        long nr;
@@ -305,9 +290,8 @@ cmm_pages_handler(ctl_table *ctl, int write,
        return 0;
 }
 
-static int
-cmm_timeout_handler(ctl_table *ctl, int write,
-                   void __user *buffer, size_t *lenp, loff_t *ppos)
+static int cmm_timeout_handler(ctl_table *ctl, int write,  void __user *buffer,
+                              size_t *lenp, loff_t *ppos)
 {
        char buf[64], *p;
        long nr, seconds;
@@ -370,12 +354,10 @@ static struct ctl_table cmm_dir_table[] = {
        },
        { }
 };
-#endif
 
 #ifdef CONFIG_CMM_IUCV
 #define SMSG_PREFIX "CMM"
-static void
-cmm_smsg_target(const char *from, char *msg)
+static void cmm_smsg_target(const char *from, char *msg)
 {
        long nr, seconds;
 
@@ -445,16 +427,13 @@ static struct notifier_block cmm_power_notifier = {
        .notifier_call = cmm_power_event,
 };
 
-static int
-cmm_init (void)
+static int cmm_init(void)
 {
        int rc = -ENOMEM;
 
-#ifdef CONFIG_CMM_PROC
        cmm_sysctl_header = register_sysctl_table(cmm_dir_table);
        if (!cmm_sysctl_header)
                goto out_sysctl;
-#endif
 #ifdef CONFIG_CMM_IUCV
        rc = smsg_register_callback(SMSG_PREFIX, cmm_smsg_target);
        if (rc < 0)
@@ -466,8 +445,6 @@ cmm_init (void)
        rc = register_pm_notifier(&cmm_power_notifier);
        if (rc)
                goto out_pm;
-       init_waitqueue_head(&cmm_thread_wait);
-       init_timer(&cmm_timer);
        cmm_thread_ptr = kthread_run(cmm_thread, NULL, "cmmthread");
        rc = IS_ERR(cmm_thread_ptr) ? PTR_ERR(cmm_thread_ptr) : 0;
        if (rc)
@@ -483,36 +460,26 @@ out_oom_notify:
        smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target);
 out_smsg:
 #endif
-#ifdef CONFIG_CMM_PROC
        unregister_sysctl_table(cmm_sysctl_header);
 out_sysctl:
-#endif
+       del_timer_sync(&cmm_timer);
        return rc;
 }
+module_init(cmm_init);
 
-static void
-cmm_exit(void)
+static void cmm_exit(void)
 {
-       kthread_stop(cmm_thread_ptr);
-       unregister_pm_notifier(&cmm_power_notifier);
-       unregister_oom_notifier(&cmm_oom_nb);
-       cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list);
-       cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list);
-#ifdef CONFIG_CMM_PROC
        unregister_sysctl_table(cmm_sysctl_header);
-#endif
 #ifdef CONFIG_CMM_IUCV
        smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target);
 #endif
+       unregister_pm_notifier(&cmm_power_notifier);
+       unregister_oom_notifier(&cmm_oom_nb);
+       kthread_stop(cmm_thread_ptr);
+       del_timer_sync(&cmm_timer);
+       cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list);
+       cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list);
 }
-
-module_init(cmm_init);
 module_exit(cmm_exit);
 
-EXPORT_SYMBOL(cmm_set_pages);
-EXPORT_SYMBOL(cmm_get_pages);
-EXPORT_SYMBOL(cmm_add_timed_pages);
-EXPORT_SYMBOL(cmm_get_timed_pages);
-EXPORT_SYMBOL(cmm_set_timeout);
-
 MODULE_LICENSE("GPL");
index 9f533b8362c788170bfb451a02b40bbe9771829f..4fa1a665821557a0af3f25912bc679df36254917 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _ASM_SCORE_SCATTERLIST_H
 #define _ASM_SCORE_SCATTERLIST_H
 
+#define ISA_DMA_THRESHOLD      (~0UL)
+
 #include <asm-generic/scatterlist.h>
 
 #endif /* _ASM_SCORE_SCATTERLIST_H */
index 0e318c905eea984d57824526f50be505be82ddbd..c5ee4ce60b576d0e5155e940f9230a29cc622639 100644 (file)
@@ -186,6 +186,9 @@ config DMA_NONCOHERENT
 config NEED_DMA_MAP_STATE
        def_bool DMA_NONCOHERENT
 
+config NEED_SG_DMA_LENGTH
+       def_bool y
+
 source "init/Kconfig"
 
 source "kernel/Kconfig.freezer"
index 62123885a6fa6b0c790fda1bda57ea1d3a025029..49714258732e57ff0be5da2f458f37f356f19ca5 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
+#include <linux/mfd/sh_mobile_sdhi.h>
 #include <linux/mtd/physmap.h>
 #include <linux/gpio.h>
 #include <linux/interrupt.h>
@@ -442,7 +443,9 @@ static void sdhi0_set_pwr(struct platform_device *pdev, int state)
 }
 
 static struct sh_mobile_sdhi_info sdhi0_info = {
-       .set_pwr = sdhi0_set_pwr,
+       .dma_slave_tx   = SHDMA_SLAVE_SDHI0_TX,
+       .dma_slave_rx   = SHDMA_SLAVE_SDHI0_RX,
+       .set_pwr        = sdhi0_set_pwr,
 };
 
 static struct resource sdhi0_resources[] = {
@@ -478,7 +481,9 @@ static void sdhi1_set_pwr(struct platform_device *pdev, int state)
 }
 
 static struct sh_mobile_sdhi_info sdhi1_info = {
-       .set_pwr = sdhi1_set_pwr,
+       .dma_slave_tx   = SHDMA_SLAVE_SDHI1_TX,
+       .dma_slave_rx   = SHDMA_SLAVE_SDHI1_RX,
+       .set_pwr        = sdhi1_set_pwr,
 };
 
 static struct resource sdhi1_resources[] = {
@@ -769,6 +774,51 @@ static struct platform_device irda_device = {
        .resource       = irda_resources,
 };
 
+#include <media/ak881x.h>
+#include <media/sh_vou.h>
+
+struct ak881x_pdata ak881x_pdata = {
+       .flags = AK881X_IF_MODE_SLAVE,
+};
+
+static struct i2c_board_info ak8813 = {
+       I2C_BOARD_INFO("ak8813", 0x20),
+       .platform_data = &ak881x_pdata,
+};
+
+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,
+       .i2c_adap       = 0,
+       .module_name    = "ak881x",
+};
+
+static struct resource sh_vou_resources[] = {
+       [0] = {
+               .start  = 0xfe960000,
+               .end    = 0xfe962043,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 55,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device vou_device = {
+       .name           = "sh-vou",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(sh_vou_resources),
+       .resource       = sh_vou_resources,
+       .dev            = {
+               .platform_data  = &sh_vou_pdata,
+       },
+       .archdata       = {
+               .hwblk_id       = HWBLK_VOU,
+       },
+};
+
 static struct platform_device *ecovec_devices[] __initdata = {
        &heartbeat_device,
        &nor_flash_device,
@@ -790,6 +840,7 @@ static struct platform_device *ecovec_devices[] __initdata = {
        &camera_devices[2],
        &fsi_device,
        &irda_device,
+       &vou_device,
 };
 
 #ifdef CONFIG_I2C
@@ -1179,6 +1230,38 @@ static int __init arch_setup(void)
        i2c_register_board_info(1, i2c1_devices,
                                ARRAY_SIZE(i2c1_devices));
 
+       /* VOU */
+       gpio_request(GPIO_FN_DV_D15, NULL);
+       gpio_request(GPIO_FN_DV_D14, NULL);
+       gpio_request(GPIO_FN_DV_D13, NULL);
+       gpio_request(GPIO_FN_DV_D12, NULL);
+       gpio_request(GPIO_FN_DV_D11, NULL);
+       gpio_request(GPIO_FN_DV_D10, NULL);
+       gpio_request(GPIO_FN_DV_D9, NULL);
+       gpio_request(GPIO_FN_DV_D8, NULL);
+       gpio_request(GPIO_FN_DV_CLKI, NULL);
+       gpio_request(GPIO_FN_DV_CLK, NULL);
+       gpio_request(GPIO_FN_DV_VSYNC, NULL);
+       gpio_request(GPIO_FN_DV_HSYNC, NULL);
+
+       /* AK8813 power / reset sequence */
+       gpio_request(GPIO_PTG4, NULL);
+       gpio_request(GPIO_PTU3, NULL);
+       /* Reset */
+       gpio_direction_output(GPIO_PTG4, 0);
+       /* Power down */
+       gpio_direction_output(GPIO_PTU3, 1);
+
+       udelay(10);
+
+       /* Power up, reset */
+       gpio_set_value(GPIO_PTU3, 0);
+
+       udelay(10);
+
+       /* Remove reset */
+       gpio_set_value(GPIO_PTG4, 1);
+
        return platform_add_devices(ecovec_devices,
                                    ARRAY_SIZE(ecovec_devices));
 }
index b2cd0ed8664efff8697fb54c4702384cc211f0d9..68994a163f6c7eeaa6b1d60892c9ddd8d85efffb 100644 (file)
@@ -10,6 +10,8 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
+#include <linux/mfd/sh_mobile_sdhi.h>
+#include <linux/mfd/tmio.h>
 #include <linux/mtd/physmap.h>
 #include <linux/mtd/onenand.h>
 #include <linux/delay.h>
@@ -356,10 +358,19 @@ static struct resource kfr2r09_sh_sdhi0_resources[] = {
        },
 };
 
+static struct sh_mobile_sdhi_info sh7724_sdhi0_data = {
+       .dma_slave_tx   = SHDMA_SLAVE_SDHI0_TX,
+       .dma_slave_rx   = SHDMA_SLAVE_SDHI0_RX,
+       .tmio_flags     = TMIO_MMC_WRPROTECT_DISABLE,
+};
+
 static struct platform_device kfr2r09_sh_sdhi0_device = {
        .name           = "sh_mobile_sdhi",
        .num_resources  = ARRAY_SIZE(kfr2r09_sh_sdhi0_resources),
        .resource       = kfr2r09_sh_sdhi0_resources,
+       .dev = {
+               .platform_data  = &sh7724_sdhi0_data,
+       },
        .archdata = {
                .hwblk_id = HWBLK_SDHI0,
        },
index 7da0fc94a01efc34aecf31b4909e98f9532faf13..87185de2044698724cb50b66e3770eb1359b2bf6 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/interrupt.h>
 #include <linux/input.h>
 #include <linux/input/sh_keysc.h>
+#include <linux/mfd/sh_mobile_sdhi.h>
 #include <linux/mtd/physmap.h>
 #include <linux/mtd/nand.h>
 #include <linux/i2c.h>
@@ -402,10 +403,18 @@ static struct resource sdhi_cn9_resources[] = {
        },
 };
 
+static struct sh_mobile_sdhi_info sh7724_sdhi_data = {
+       .dma_slave_tx   = SHDMA_SLAVE_SDHI0_TX,
+       .dma_slave_rx   = SHDMA_SLAVE_SDHI0_RX,
+};
+
 static struct platform_device sdhi_cn9_device = {
        .name           = "sh_mobile_sdhi",
        .num_resources  = ARRAY_SIZE(sdhi_cn9_resources),
        .resource       = sdhi_cn9_resources,
+       .dev = {
+               .platform_data  = &sh7724_sdhi_data,
+       },
        .archdata = {
                .hwblk_id = HWBLK_SDHI,
        },
index e74ae7b0d8bf35cecbcb0fbe985c8e60a9e8dffb..f9b82546c2df9c1fc2216011244ba6edf67da1ee 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/device.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
+#include <linux/mfd/sh_mobile_sdhi.h>
 #include <linux/mtd/physmap.h>
 #include <linux/delay.h>
 #include <linux/smc91x.h>
@@ -462,11 +463,19 @@ static struct resource sdhi0_cn7_resources[] = {
        },
 };
 
+static struct sh_mobile_sdhi_info sh7724_sdhi0_data = {
+       .dma_slave_tx   = SHDMA_SLAVE_SDHI0_TX,
+       .dma_slave_rx   = SHDMA_SLAVE_SDHI0_RX,
+};
+
 static struct platform_device sdhi0_cn7_device = {
        .name           = "sh_mobile_sdhi",
        .id             = 0,
        .num_resources  = ARRAY_SIZE(sdhi0_cn7_resources),
        .resource       = sdhi0_cn7_resources,
+       .dev = {
+               .platform_data  = &sh7724_sdhi0_data,
+       },
        .archdata = {
                .hwblk_id = HWBLK_SDHI0,
        },
@@ -485,11 +494,19 @@ static struct resource sdhi1_cn8_resources[] = {
        },
 };
 
+static struct sh_mobile_sdhi_info sh7724_sdhi1_data = {
+       .dma_slave_tx   = SHDMA_SLAVE_SDHI1_TX,
+       .dma_slave_rx   = SHDMA_SLAVE_SDHI1_RX,
+};
+
 static struct platform_device sdhi1_cn8_device = {
        .name           = "sh_mobile_sdhi",
        .id             = 1,
        .num_resources  = ARRAY_SIZE(sdhi1_cn8_resources),
        .resource       = sdhi1_cn8_resources,
+       .dev = {
+               .platform_data  = &sh7724_sdhi1_data,
+       },
        .archdata = {
                .hwblk_id = HWBLK_SDHI1,
        },
@@ -515,6 +532,52 @@ static struct platform_device irda_device = {
        .resource       = irda_resources,
 };
 
+#include <media/ak881x.h>
+#include <media/sh_vou.h>
+
+struct ak881x_pdata ak881x_pdata = {
+       .flags = AK881X_IF_MODE_SLAVE,
+};
+
+static struct i2c_board_info ak8813 = {
+       /* With open J18 jumper address is 0x21 */
+       I2C_BOARD_INFO("ak8813", 0x20),
+       .platform_data = &ak881x_pdata,
+};
+
+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,
+       .i2c_adap       = 0,
+       .module_name    = "ak881x",
+};
+
+static struct resource sh_vou_resources[] = {
+       [0] = {
+               .start  = 0xfe960000,
+               .end    = 0xfe962043,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 55,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device vou_device = {
+       .name           = "sh-vou",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(sh_vou_resources),
+       .resource       = sh_vou_resources,
+       .dev            = {
+               .platform_data  = &sh_vou_pdata,
+       },
+       .archdata       = {
+               .hwblk_id       = HWBLK_VOU,
+       },
+};
+
 static struct platform_device *ms7724se_devices[] __initdata = {
        &heartbeat_device,
        &smc91x_eth_device,
@@ -530,6 +593,7 @@ static struct platform_device *ms7724se_devices[] __initdata = {
        &sdhi0_cn7_device,
        &sdhi1_cn8_device,
        &irda_device,
+       &vou_device,
 };
 
 /* I2C device */
@@ -614,6 +678,7 @@ static int __init devices_setup(void)
 {
        u16 sw = __raw_readw(SW4140); /* select camera, monitor */
        struct clk *clk;
+       u16 fpga_out;
 
        /* register board specific self-refresh code */
        sh_mobile_register_self_refresh(SUSP_SH_STANDBY | SUSP_SH_SF |
@@ -623,14 +688,26 @@ static int __init devices_setup(void)
                                        &ms7724se_sdram_leave_start,
                                        &ms7724se_sdram_leave_end);
        /* Reset Release */
-       __raw_writew(__raw_readw(FPGA_OUT) &
-                 ~((1 << 1)  | /* LAN */
-                   (1 << 6)  | /* VIDEO DAC */
-                   (1 << 7)  | /* AK4643 */
-                   (1 << 8)  | /* IrDA */
-                   (1 << 12) | /* USB0 */
-                   (1 << 14)), /* RMII */
-                 FPGA_OUT);
+       fpga_out = __raw_readw(FPGA_OUT);
+       /* bit4: NTSC_PDN, bit5: NTSC_RESET */
+       fpga_out &= ~((1 << 1)  | /* LAN */
+                     (1 << 4)  | /* AK8813 PDN */
+                     (1 << 5)  | /* AK8813 RESET */
+                     (1 << 6)  | /* VIDEO DAC */
+                     (1 << 7)  | /* AK4643 */
+                     (1 << 8)  | /* IrDA */
+                     (1 << 12) | /* USB0 */
+                     (1 << 14)); /* RMII */
+       __raw_writew(fpga_out | (1 << 4), FPGA_OUT);
+
+       udelay(10);
+
+       /* AK8813 RESET */
+       __raw_writew(fpga_out | (1 << 5), FPGA_OUT);
+
+       udelay(10);
+
+       __raw_writew(fpga_out, FPGA_OUT);
 
        /* turn on USB clocks, use external clock */
        __raw_writew((__raw_readw(PORT_MSELCRB) & ~0xc000) | 0x8000, PORT_MSELCRB);
@@ -862,6 +939,20 @@ static int __init devices_setup(void)
                lcdc_info.ch[0].flags          = LCDC_FLAGS_DWPOL;
        }
 
+       /* VOU */
+       gpio_request(GPIO_FN_DV_D15, NULL);
+       gpio_request(GPIO_FN_DV_D14, NULL);
+       gpio_request(GPIO_FN_DV_D13, NULL);
+       gpio_request(GPIO_FN_DV_D12, NULL);
+       gpio_request(GPIO_FN_DV_D11, NULL);
+       gpio_request(GPIO_FN_DV_D10, NULL);
+       gpio_request(GPIO_FN_DV_D9, NULL);
+       gpio_request(GPIO_FN_DV_D8, NULL);
+       gpio_request(GPIO_FN_DV_CLKI, NULL);
+       gpio_request(GPIO_FN_DV_CLK, NULL);
+       gpio_request(GPIO_FN_DV_VSYNC, NULL);
+       gpio_request(GPIO_FN_DV_HSYNC, NULL);
+
        return platform_add_devices(ms7724se_devices,
                                    ARRAY_SIZE(ms7724se_devices));
 }
index e9af616b21600ffa7154ab1a4b671a6384fafd68..71f39c71b04b08a94c77882944e4f0567fb7d5f7 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.34-rc5
-# Tue May 18 17:22:09 2010
+# Linux kernel version: 2.6.34
+# Mon May 24 08:33:02 2010
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
@@ -76,7 +76,7 @@ CONFIG_RCU_FANOUT=32
 # CONFIG_TREE_RCU_TRACE is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=14
+CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_CGROUPS is not set
 # CONFIG_SYSFS_DEPRECATED_V2 is not set
 # CONFIG_RELAY is not set
@@ -111,18 +111,17 @@ CONFIG_PERF_USE_VMALLOC=y
 #
 CONFIG_PERF_EVENTS=y
 CONFIG_PERF_COUNTERS=y
+# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
 CONFIG_VM_EVENT_COUNTERS=y
 CONFIG_PCI_QUIRKS=y
-CONFIG_COMPAT_BRK=y
+# CONFIG_COMPAT_BRK is not set
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
 CONFIG_PROFILING=y
-CONFIG_TRACEPOINTS=y
-CONFIG_OPROFILE=y
+# CONFIG_OPROFILE is not set
 CONFIG_HAVE_OPROFILE=y
-CONFIG_KPROBES=y
-CONFIG_KRETPROBES=y
+# CONFIG_KPROBES is not set
 CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
@@ -130,6 +129,7 @@ CONFIG_HAVE_DMA_ATTRS=y
 CONFIG_HAVE_CLK=y
 CONFIG_HAVE_DMA_API_DEBUG=y
 CONFIG_HAVE_HW_BREAKPOINT=y
+CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y
 
 #
 # GCOV-based kernel profiling
@@ -243,8 +243,9 @@ CONFIG_PAGE_OFFSET=0x80000000
 CONFIG_FORCE_MAX_ZONEORDER=11
 CONFIG_MEMORY_START=0x40000000
 CONFIG_MEMORY_SIZE=0x20000000
-CONFIG_29BIT=y
-# CONFIG_PMB is not set
+# CONFIG_29BIT is not set
+CONFIG_32BIT=y
+CONFIG_PMB=y
 CONFIG_X2TLB=y
 CONFIG_VSYSCALL=y
 # CONFIG_NUMA is not set
@@ -262,9 +263,9 @@ CONFIG_PAGE_SIZE_4KB=y
 # CONFIG_PAGE_SIZE_8KB is not set
 # CONFIG_PAGE_SIZE_16KB is not set
 # CONFIG_PAGE_SIZE_64KB is not set
-CONFIG_HUGETLB_PAGE_SIZE_64K=y
+# CONFIG_HUGETLB_PAGE_SIZE_64K is not set
 # CONFIG_HUGETLB_PAGE_SIZE_256K is not set
-# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
+CONFIG_HUGETLB_PAGE_SIZE_1MB=y
 # CONFIG_HUGETLB_PAGE_SIZE_4MB is not set
 # CONFIG_HUGETLB_PAGE_SIZE_64MB is not set
 # CONFIG_HUGETLB_PAGE_SIZE_512MB is not set
@@ -276,7 +277,7 @@ CONFIG_SPARSEMEM=y
 CONFIG_HAVE_MEMORY_PRESENT=y
 CONFIG_SPARSEMEM_STATIC=y
 # CONFIG_MEMORY_HOTPLUG is not set
-CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_SPLIT_PTLOCK_CPUS=999999
 CONFIG_MIGRATION=y
 # CONFIG_PHYS_ADDR_T_64BIT is not set
 CONFIG_ZONE_DMA_FLAG=0
@@ -298,7 +299,7 @@ CONFIG_CPU_LITTLE_ENDIAN=y
 # CONFIG_CPU_BIG_ENDIAN is not set
 CONFIG_SH_FPU=y
 CONFIG_SH_STORE_QUEUES=y
-# CONFIG_SPECULATIVE_EXECUTION is not set
+CONFIG_SPECULATIVE_EXECUTION=y
 CONFIG_CPU_HAS_INTEVT=y
 CONFIG_CPU_HAS_SR_RB=y
 CONFIG_CPU_HAS_FPU=y
@@ -308,7 +309,7 @@ CONFIG_CPU_HAS_FPU=y
 #
 # CONFIG_SH_HIGHLANDER is not set
 CONFIG_SH_SH7785LCR=y
-CONFIG_SH_SH7785LCR_29BIT_PHYSMAPS=y
+# CONFIG_SH_SH7785LCR_PT is not set
 
 #
 # Timer and clock configuration
@@ -371,7 +372,7 @@ CONFIG_SECCOMP=y
 # CONFIG_PREEMPT_VOLUNTARY is not set
 CONFIG_PREEMPT=y
 CONFIG_GUSA=y
-# CONFIG_INTC_USERIMASK is not set
+CONFIG_INTC_USERIMASK=y
 
 #
 # Boot options
@@ -389,6 +390,7 @@ CONFIG_PCI=y
 CONFIG_PCI_DOMAINS=y
 # CONFIG_PCIEPORTBUS is not set
 # CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_PCI_DEBUG=y
 # CONFIG_PCI_STUB is not set
 # CONFIG_PCI_IOV is not set
 # CONFIG_PCCARD is not set
@@ -465,6 +467,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
@@ -485,8 +488,6 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # Network testing
 #
 # CONFIG_NET_PKTGEN is not set
-# CONFIG_NET_TCPPROBE is not set
-# CONFIG_NET_DROP_MONITOR is not set
 # CONFIG_HAMRADIO is not set
 # CONFIG_CAN is not set
 # CONFIG_IRDA is not set
@@ -499,10 +500,19 @@ CONFIG_WIRELESS=y
 #
 # 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
 #
@@ -514,7 +524,11 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_DEVTMPFS is not set
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
+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=y
@@ -537,6 +551,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
 
 #
@@ -668,7 +683,9 @@ CONFIG_ATA=y
 CONFIG_ATA_VERBOSE_ERROR=y
 CONFIG_SATA_PMP=y
 # CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_AHCI_PLATFORM is not set
 # CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_INIC162X is not set
 CONFIG_ATA_SFF=y
 # CONFIG_SATA_SVW is not set
 # CONFIG_ATA_PIIX is not set
@@ -683,7 +700,6 @@ CONFIG_SATA_SIL=y
 # 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
@@ -753,8 +769,36 @@ CONFIG_NETDEVICES=y
 # CONFIG_TUN is not set
 # CONFIG_VETH is not set
 # CONFIG_ARCNET is not set
-# CONFIG_NET_ETHERNET is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
+# CONFIG_AX88796 is not set
+# CONFIG_STNIC is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+CONFIG_NET_VENDOR_3COM=y
+CONFIG_VORTEX=y
+# CONFIG_TYPHOON is not set
+# CONFIG_SMC91X is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMC911X is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 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 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_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_NETDEV_1000=y
 # CONFIG_ACENIC is not set
 # CONFIG_DL2K is not set
@@ -836,6 +880,7 @@ CONFIG_INPUT_KEYBOARD=y
 CONFIG_KEYBOARD_ATKBD=y
 # CONFIG_QT2160 is not set
 # CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_TCA6416 is not set
 # CONFIG_KEYBOARD_MAX7359 is not set
 # CONFIG_KEYBOARD_NEWTON is not set
 # CONFIG_KEYBOARD_OPENCORES is not set
@@ -884,6 +929,7 @@ CONFIG_HW_CONSOLE=y
 CONFIG_VT_HW_CONSOLE_BINDING=y
 # CONFIG_DEVKMEM is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_N_GSM is not set
 # CONFIG_NOZOMI is not set
 
 #
@@ -901,6 +947,8 @@ CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 # CONFIG_SERIAL_JSM is not set
 # 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=y
 # CONFIG_LEGACY_PTYS is not set
@@ -1071,7 +1119,7 @@ CONFIG_FB_CFB_IMAGEBLIT=y
 # 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_KYRO=y
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_VT8623 is not set
@@ -1097,15 +1145,15 @@ CONFIG_FB_SM501=y
 #
 CONFIG_DUMMY_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
-# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
 # 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 is not set
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
 CONFIG_LOGO_SUPERH_MONO=y
 CONFIG_LOGO_SUPERH_VGA16=y
 CONFIG_LOGO_SUPERH_CLUT224=y
@@ -1129,15 +1177,18 @@ CONFIG_SND_SEQ_HRTIMER_DEFAULT=y
 CONFIG_SND_DYNAMIC_MINORS=y
 # CONFIG_SND_SUPPORT_OLD_API is not set
 # CONFIG_SND_VERBOSE_PROCFS is not set
-# CONFIG_SND_VERBOSE_PRINTK is not set
-# CONFIG_SND_DEBUG is not set
+CONFIG_SND_VERBOSE_PRINTK=y
+CONFIG_SND_DEBUG=y
+CONFIG_SND_DEBUG_VERBOSE=y
+CONFIG_SND_VMASTER=y
 CONFIG_SND_RAWMIDI_SEQ=y
 CONFIG_SND_OPL3_LIB_SEQ=y
 # CONFIG_SND_OPL4_LIB_SEQ is not set
 # CONFIG_SND_SBAWE_SEQ is not set
-# CONFIG_SND_EMU10K1_SEQ is not set
+CONFIG_SND_EMU10K1_SEQ=y
 CONFIG_SND_MPU401_UART=y
 CONFIG_SND_OPL3_LIB=y
+CONFIG_SND_AC97_CODEC=y
 # CONFIG_SND_DRIVERS is not set
 CONFIG_SND_PCI=y
 # CONFIG_SND_AD1889 is not set
@@ -1172,7 +1223,7 @@ CONFIG_SND_CMIPCI=y
 # CONFIG_SND_INDIGODJ is not set
 # CONFIG_SND_INDIGOIOX is not set
 # CONFIG_SND_INDIGODJX is not set
-# CONFIG_SND_EMU10K1 is not set
+CONFIG_SND_EMU10K1=y
 # CONFIG_SND_EMU10K1X is not set
 # CONFIG_SND_ENS1370 is not set
 # CONFIG_SND_ENS1371 is not set
@@ -1211,6 +1262,7 @@ CONFIG_SND_USB=y
 # CONFIG_SND_USB_CAIAQ is not set
 # CONFIG_SND_SOC 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
@@ -1226,44 +1278,42 @@ CONFIG_USB_HID=y
 # Special HID drivers
 #
 # CONFIG_HID_3M_PCT is not set
-CONFIG_HID_A4TECH=m
-CONFIG_HID_APPLE=m
-CONFIG_HID_BELKIN=m
-CONFIG_HID_CHERRY=m
-CONFIG_HID_CHICONY=m
-CONFIG_HID_CYPRESS=m
-CONFIG_HID_DRAGONRISE=m
-# CONFIG_DRAGONRISE_FF is not set
-CONFIG_HID_EZKEY=m
-CONFIG_HID_KYE=m
-CONFIG_HID_GYRATION=m
-CONFIG_HID_TWINHAN=m
-CONFIG_HID_KENSINGTON=m
-CONFIG_HID_LOGITECH=m
-# CONFIG_LOGITECH_FF is not set
-# CONFIG_LOGIRUMBLEPAD2_FF is not set
-# CONFIG_LOGIG940_FF is not set
-CONFIG_HID_MICROSOFT=m
+# 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=m
-CONFIG_HID_NTRIG=m
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
 # CONFIG_HID_ORTEK is not set
-CONFIG_HID_PANTHERLORD=m
-# CONFIG_PANTHERLORD_FF is not set
-CONFIG_HID_PETALYNX=m
+# 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_SAMSUNG=m
-CONFIG_HID_SONY=m
+# 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=m
-CONFIG_HID_GREENASIA=m
-# CONFIG_GREENASIA_FF is not set
-CONFIG_HID_SMARTJOYPLUS=m
-# CONFIG_SMARTJOYPLUS_FF is not set
-CONFIG_HID_TOPSEED=m
+# 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=m
-# CONFIG_ZEROPLUS_FF 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=y
@@ -1276,9 +1326,8 @@ CONFIG_USB=y
 # Miscellaneous USB options
 #
 # CONFIG_USB_DEVICEFS is not set
-CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DEVICE_CLASS is not set
 # CONFIG_USB_DYNAMIC_MINORS is not set
-# CONFIG_USB_OTG is not set
 # CONFIG_USB_OTG_WHITELIST is not set
 # CONFIG_USB_OTG_BLACKLIST_HUB is not set
 # CONFIG_USB_MON is not set
@@ -1290,9 +1339,7 @@ CONFIG_USB_DEVICE_CLASS=y
 #
 # CONFIG_USB_C67X00_HCD is not set
 # CONFIG_USB_XHCI_HCD is not set
-CONFIG_USB_EHCI_HCD=m
-# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
-# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_EHCI_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
@@ -1361,7 +1408,6 @@ CONFIG_USB_STORAGE=y
 # 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
@@ -1464,6 +1510,7 @@ CONFIG_DMADEVICES=y
 #
 # DMA Devices
 #
+# CONFIG_TIMB_DMA is not set
 # CONFIG_AUXDISPLAY is not set
 CONFIG_UIO=m
 # CONFIG_UIO_CIF is not set
@@ -1473,10 +1520,6 @@ CONFIG_UIO=m
 # CONFIG_UIO_SERCOS3 is not set
 # CONFIG_UIO_PCI_GENERIC is not set
 # CONFIG_UIO_NETX is not set
-
-#
-# TI VLYNQ
-#
 # CONFIG_STAGING is not set
 
 #
@@ -1653,63 +1696,75 @@ CONFIG_MAGIC_SYSRQ=y
 # CONFIG_UNUSED_SYMBOLS is not set
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
-# CONFIG_DEBUG_KERNEL 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=y
-CONFIG_TRACE_IRQFLAGS=y
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=400
+# CONFIG_DEBUG_KMEMLEAK_TEST is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+# 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_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# 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_FRAME_POINTER=y
+# 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_LKDTM is not set
+# CONFIG_FAULT_INJECTION is not set
 CONFIG_LATENCYTOP=y
 CONFIG_SYSCTL_SYSCALL_CHECK=y
-CONFIG_NOP_TRACER=y
-CONFIG_HAVE_FTRACE_NMI_ENTER=y
+# CONFIG_PAGE_POISONING is not set
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
 CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
 CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
-CONFIG_TRACER_MAX_TRACE=y
-CONFIG_RING_BUFFER=y
-CONFIG_FTRACE_NMI_ENTER=y
-CONFIG_EVENT_TRACING=y
-CONFIG_CONTEXT_SWITCH_TRACER=y
-CONFIG_RING_BUFFER_ALLOW_SWAP=y
-CONFIG_TRACING=y
-CONFIG_GENERIC_TRACER=y
 CONFIG_TRACING_SUPPORT=y
-CONFIG_FTRACE=y
-CONFIG_FUNCTION_TRACER=y
-CONFIG_FUNCTION_GRAPH_TRACER=y
-CONFIG_IRQSOFF_TRACER=y
-# CONFIG_PREEMPT_TRACER is not set
-CONFIG_SCHED_TRACER=y
-# CONFIG_FTRACE_SYSCALLS 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_KSYM_TRACER is not set
-CONFIG_STACK_TRACER=y
-CONFIG_KMEMTRACE=y
-CONFIG_WORKQUEUE_TRACER=y
-# CONFIG_BLK_DEV_IO_TRACE is not set
-CONFIG_DYNAMIC_FTRACE=y
-# CONFIG_FUNCTION_PROFILER is not set
-CONFIG_FTRACE_MCOUNT_RECORD=y
-# CONFIG_FTRACE_STARTUP_TEST is not set
-# CONFIG_RING_BUFFER_BENCHMARK is not set
+# CONFIG_FTRACE is not set
 # CONFIG_DYNAMIC_DEBUG is not set
 # CONFIG_DMA_API_DEBUG is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
 # CONFIG_SH_STANDARD_BIOS is not set
-CONFIG_DWARF_UNWINDER=y
-CONFIG_MCOUNT=y
+# CONFIG_STACK_DEBUG is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_4KSTACKS is not set
+CONFIG_DUMP_CODE=y
+# CONFIG_DWARF_UNWINDER is not set
+# CONFIG_SH_NO_BSS_INIT is not set
 
 #
 # Security options
@@ -1820,7 +1875,7 @@ CONFIG_CRYPTO_DES=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 # CONFIG_CRYPTO_HW is not set
 # CONFIG_VIRTUALIZATION is not set
-CONFIG_BINARY_PRINTF=y
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
index d02c01b3e6b9fd899e2d09a5518f12beefa44c76..6323f864d1116ab2038074b7efa5d8282e5f0449 100644 (file)
@@ -48,7 +48,7 @@ do {                                                  \
                   "i" (sizeof(struct bug_entry)));     \
 } while (0)
 
-#define __WARN()                                       \
+#define __WARN_TAINT(taint)                            \
 do {                                                   \
        __asm__ __volatile__ (                          \
                "1:\t.short %O0\n"                      \
@@ -57,7 +57,7 @@ do {                                                  \
                 : "n" (TRAPA_BUG_OPCODE),              \
                   "i" (__FILE__),                      \
                   "i" (__LINE__),                      \
-                  "i" (BUGFLAG_WARNING),               \
+                  "i" (BUGFLAG_TAINT(taint)),          \
                   "i" (sizeof(struct bug_entry)));     \
 } while (0)
 
diff --git a/arch/sh/include/asm/dmaengine.h b/arch/sh/include/asm/dmaengine.h
deleted file mode 100644 (file)
index 2a02b61..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Header for the new SH dmaengine driver
- *
- * 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 ASM_DMAENGINE_H
-#define ASM_DMAENGINE_H
-
-#include <linux/sh_dma.h>
-
-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_SIUA_TX,
-       SHDMA_SLAVE_SIUA_RX,
-       SHDMA_SLAVE_SIUB_TX,
-       SHDMA_SLAVE_SIUB_RX,
-};
-
-#endif
index e8d4142baf59f9377ca55ab3ad85ef42039b3003..1d95c78808d13cfaab77145d91921f76517aa205 100644 (file)
@@ -11,8 +11,6 @@
 #ifndef ASM_SIU_H
 #define ASM_SIU_H
 
-#include <asm/dmaengine.h>
-
 struct device;
 
 struct siu_platform {
index 48560407cbe1c92acff99ff7fb858a4f5b1172a8..7a5b8a331b4aa55f6d7141486fd6153491c4a4a6 100644 (file)
@@ -235,4 +235,19 @@ enum {
        HWBLK_NR,
 };
 
+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_SIUA_TX,
+       SHDMA_SLAVE_SIUA_RX,
+       SHDMA_SLAVE_SIUB_TX,
+       SHDMA_SLAVE_SIUB_RX,
+       SHDMA_SLAVE_SDHI0_TX,
+       SHDMA_SLAVE_SDHI0_RX,
+};
+
 #endif /* __ASM_SH7722_H__ */
index 0cd1f71a11168e52d1d4fa51e324a26a95eb2793..fbbf550cc529c10d3ebbb8aa010de963d3a842fc 100644 (file)
@@ -283,4 +283,23 @@ enum {
        HWBLK_NR,
 };
 
+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_SDHI0_TX,
+       SHDMA_SLAVE_SDHI0_RX,
+       SHDMA_SLAVE_SDHI1_TX,
+       SHDMA_SLAVE_SDHI1_RX,
+};
+
 #endif /* __ASM_SH7724_H__ */
index 105a6d41b569acaf84f1130b3c812defba5ae4f1..597c9fbe49c6d88e45a248c424400422e949188f 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/kernel.h>
 #include <linux/clk.h>
 #include <linux/io.h>
-#include <linux/clk.h>
 #include <asm/clkdev.h>
 #include <asm/clock.h>
 #include <asm/freq.h>
index 24c6167a718187c0f21148f13e37fa8672253196..156ccc9600155f159c7f84baed82990e16ed6292 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/usb/m66592.h>
 
 #include <asm/clock.h>
-#include <asm/dmaengine.h>
 #include <asm/mmzone.h>
 #include <asm/siu.h>
 
@@ -75,6 +74,16 @@ static const struct sh_dmae_slave_config sh7722_dmae_slaves[] = {
                .addr           = 0xa454c094,
                .chcr           = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_32BIT),
                .mid_rid        = 0xb6,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SDHI0_TX,
+               .addr           = 0x04ce0030,
+               .chcr           = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_16BIT),
+               .mid_rid        = 0xc1,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SDHI0_RX,
+               .addr           = 0x04ce0030,
+               .chcr           = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_16BIT),
+               .mid_rid        = 0xc2,
        },
 };
 
index 89fe16d20fdb5149119264625a86aec201d4177a..79c556e5626213b16f44051242c8f93ac7389904 100644 (file)
 #include <linux/mm.h>
 #include <linux/serial_sci.h>
 #include <linux/uio_driver.h>
+#include <linux/sh_dma.h>
 #include <linux/sh_timer.h>
 #include <linux/io.h>
 #include <linux/notifier.h>
 
 #include <asm/suspend.h>
 #include <asm/clock.h>
-#include <asm/dmaengine.h>
 #include <asm/mmzone.h>
 
 #include <cpu/dma-register.h>
 #include <cpu/sh7724.h>
 
 /* DMA */
+static const struct sh_dmae_slave_config sh7724_dmae_slaves[] = {
+       {
+               .slave_id       = SHDMA_SLAVE_SCIF0_TX,
+               .addr           = 0xffe0000c,
+               .chcr           = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+               .mid_rid        = 0x21,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF0_RX,
+               .addr           = 0xffe00014,
+               .chcr           = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+               .mid_rid        = 0x22,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF1_TX,
+               .addr           = 0xffe1000c,
+               .chcr           = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+               .mid_rid        = 0x25,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF1_RX,
+               .addr           = 0xffe10014,
+               .chcr           = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+               .mid_rid        = 0x26,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF2_TX,
+               .addr           = 0xffe2000c,
+               .chcr           = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+               .mid_rid        = 0x29,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF2_RX,
+               .addr           = 0xffe20014,
+               .chcr           = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+               .mid_rid        = 0x2a,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF3_TX,
+               .addr           = 0xa4e30020,
+               .chcr           = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+               .mid_rid        = 0x2d,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF3_RX,
+               .addr           = 0xa4e30024,
+               .chcr           = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+               .mid_rid        = 0x2e,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF4_TX,
+               .addr           = 0xa4e40020,
+               .chcr           = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+               .mid_rid        = 0x31,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF4_RX,
+               .addr           = 0xa4e40024,
+               .chcr           = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+               .mid_rid        = 0x32,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF5_TX,
+               .addr           = 0xa4e50020,
+               .chcr           = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+               .mid_rid        = 0x35,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF5_RX,
+               .addr           = 0xa4e50024,
+               .chcr           = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+               .mid_rid        = 0x36,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SDHI0_TX,
+               .addr           = 0x04ce0030,
+               .chcr           = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_16BIT),
+               .mid_rid        = 0xc1,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SDHI0_RX,
+               .addr           = 0x04ce0030,
+               .chcr           = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_16BIT),
+               .mid_rid        = 0xc2,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SDHI1_TX,
+               .addr           = 0x04cf0030,
+               .chcr           = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_16BIT),
+               .mid_rid        = 0xc9,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SDHI1_RX,
+               .addr           = 0x04cf0030,
+               .chcr           = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_16BIT),
+               .mid_rid        = 0xca,
+       },
+};
+
 static const struct sh_dmae_channel sh7724_dmae_channels[] = {
        {
                .offset = 0,
@@ -62,6 +146,8 @@ static const struct sh_dmae_channel sh7724_dmae_channels[] = {
 static const unsigned int ts_shift[] = TS_SHIFT;
 
 static struct sh_dmae_pdata dma_platform_data = {
+       .slave          = sh7724_dmae_slaves,
+       .slave_num      = ARRAY_SIZE(sh7724_dmae_slaves),
        .channel        = sh7724_dmae_channels,
        .channel_num    = ARRAY_SIZE(sh7724_dmae_channels),
        .ts_low_shift   = CHCR_TS_LOW_SHIFT,
index b12f537e4dde39077f6e4e16bbe59a17e0ac0693..0f414864f76b2e42a49bd26705834b550fca02b5 100644 (file)
 #include <linux/serial.h>
 #include <linux/io.h>
 #include <linux/serial_sci.h>
+#include <linux/sh_dma.h>
 #include <linux/sh_timer.h>
 
-#include <asm/dmaengine.h>
-
 #include <cpu/dma-register.h>
 
 static struct plat_sci_port scif0_platform_data = {
index f3e3ea0ce050061e6920d0bcfb81862b79f1ec76..c9a572bc6dc84c78f00f61ceb7bf342378e17697 100644 (file)
@@ -13,9 +13,9 @@
 #include <linux/serial_sci.h>
 #include <linux/io.h>
 #include <linux/mm.h>
+#include <linux/sh_dma.h>
 #include <linux/sh_timer.h>
 
-#include <asm/dmaengine.h>
 #include <asm/mmzone.h>
 
 #include <cpu/dma-register.h>
index 81657091da4636774bfd7f5b06e482e9150b31d9..8797723231ea0dde8429778274fa4c7cc7670ad4 100644 (file)
 #include <linux/mm.h>
 #include <linux/dma-mapping.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_dma.h>
 #include <linux/sh_intc.h>
 #include <cpu/dma-register.h>
 #include <asm/mmzone.h>
-#include <asm/dmaengine.h>
 
 static struct plat_sci_port scif0_platform_data = {
        .mapbase        = 0xffea0000,
index 5ec1d1818691e5968609e58087e0502f49eb7475..886d7d83ace38912aa4966da50159d43686b0fde 100644 (file)
@@ -845,8 +845,10 @@ static int dwarf_parse_cie(void *entry, void *p, unsigned long len,
        rb_link_node(&cie->node, parent, rb_node);
        rb_insert_color(&cie->node, &cie_root);
 
+#ifdef CONFIG_MODULES
        if (mod != NULL)
                list_add_tail(&cie->link, &mod->arch.cie_list);
+#endif
 
        spin_unlock_irqrestore(&dwarf_cie_lock, flags);
 
@@ -935,8 +937,10 @@ static int dwarf_parse_fde(void *entry, u32 entry_type,
        rb_link_node(&fde->node, parent, rb_node);
        rb_insert_color(&fde->node, &fde_root);
 
+#ifdef CONFIG_MODULES
        if (mod != NULL)
                list_add_tail(&fde->link, &mod->arch.fde_list);
+#endif
 
        spin_unlock_irqrestore(&dwarf_fde_lock, flags);
 
index d4104ce9fe53c8a01fc354c41e0d57c5359a1d68..6c4bbba2a67573e2d1a72d2362bc28b4af4e2428 100644 (file)
@@ -435,29 +435,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                                             REGSET_DSP,
                                             0, sizeof(struct pt_dspregs),
                                             (const void __user *)data);
-#endif
-#ifdef CONFIG_BINFMT_ELF_FDPIC
-       case PTRACE_GETFDPIC: {
-               unsigned long tmp = 0;
-
-               switch (addr) {
-               case PTRACE_GETFDPIC_EXEC:
-                       tmp = child->mm->context.exec_fdpic_loadmap;
-                       break;
-               case PTRACE_GETFDPIC_INTERP:
-                       tmp = child->mm->context.interp_fdpic_loadmap;
-                       break;
-               default:
-                       break;
-               }
-
-               ret = 0;
-               if (put_user(tmp, datap)) {
-                       ret = -EFAULT;
-                       break;
-               }
-               break;
-       }
 #endif
        default:
                ret = ptrace_request(child, request, addr, data);
index f8ab296047b3a0122dcc5636277b0d2881b07e56..1bcc13f05962e3f66ecefebf0c3adedb670bb456 100644 (file)
@@ -35,7 +35,7 @@ ENTRY(strlen)
        mov.b   @r4+,r1
        tst     r1,r1
        bt      8f
-       add     #1,r2   
+       add     #1,r2
 
 1:
        mov     #0,r3
index d6781ce687e24cfeec3e8c9b61939f4b2a3831b8..6f1470baa314e8787213efedb78e0a3f9d6f9e56 100644 (file)
@@ -133,6 +133,9 @@ config ZONE_DMA
 config NEED_DMA_MAP_STATE
        def_bool y
 
+config NEED_SG_DMA_LENGTH
+       def_bool y
+
 config GENERIC_ISA_DMA
        bool
        default y if SPARC32
index f3b85b6b0b764796407f2e2a026a5a45163561e2..d4c45214741252d7327daf0ba0f50c10dcef6f5f 100644 (file)
@@ -13,25 +13,10 @@ struct dev_archdata {
        void                    *iommu;
        void                    *stc;
        void                    *host_controller;
-
-       struct device_node      *prom_node;
        struct of_device        *op;
-
        int                     numa_node;
 };
 
-static inline void dev_archdata_set_node(struct dev_archdata *ad,
-                                        struct device_node *np)
-{
-       ad->prom_node = np;
-}
-
-static inline struct device_node *
-dev_archdata_get_node(const struct dev_archdata *ad)
-{
-       return ad->prom_node;
-}
-
 struct pdev_archdata {
 };
 
index b83e447296553d08b9fd04541e70c024dc6276a2..e834880be2040944783d7b0e31be1158ed788d4c 100644 (file)
@@ -18,7 +18,7 @@ static inline int fb_is_primary_device(struct fb_info *info)
        struct device *dev = info->device;
        struct device_node *node;
 
-       node = dev->archdata.prom_node;
+       node = dev->of_node;
        if (node &&
            node == of_console_device)
                return 1;
index 36439d67ad7111cadbc4cc3810e9577932211094..8fac3ab22f36f6ebde89a140ce08e4fd5d107099 100644 (file)
@@ -589,7 +589,7 @@ static unsigned long __init sun_floppy_init(void)
                if (!op)
                        return 0;
 
-               state_prop = of_get_property(op->node, "status", NULL);
+               state_prop = of_get_property(op->dev.of_node, "status", NULL);
                if (state_prop && !strncmp(state_prop, "disabled", 8))
                        return 0;
 
@@ -716,7 +716,7 @@ static unsigned long __init sun_floppy_init(void)
 
                return sun_floppy_types[0];
        }
-       prop = of_get_property(op->node, "status", NULL);
+       prop = of_get_property(op->dev.of_node, "status", NULL);
        if (prop && !strncmp(state, "disabled", 8))
                return 0;
 
index a5d9811f9697734863510a8b1c7336d228ac45ab..f320246a05863ddfd05d9e107e1aa85f12f24880 100644 (file)
@@ -14,7 +14,6 @@
  */
 struct of_device
 {
-       struct device_node              *node;
        struct device                   dev;
        struct resource                 resource[PROMREG_MAX];
        unsigned int                    irqs[PROMINTR_MAX];
index ff9ead640c4aa090f33de6f9576766b6d639e6d8..c333b8d0949bf199b9a88a8b406ff644ca69c74e 100644 (file)
@@ -113,7 +113,7 @@ static int __devinit ecpp_probe(struct of_device *op, const struct of_device_id
        struct parport *p;
        int slot, err;
 
-       parent = op->node->parent;
+       parent = op->dev.of_node->parent;
        if (!strcmp(parent->name, "dma")) {
                p = parport_pc_probe_port(base, base + 0x400,
                                          op->irqs[0], PARPORT_DMA_NOFIFO,
@@ -232,8 +232,11 @@ static const struct of_device_id ecpp_match[] = {
 };
 
 static struct of_platform_driver ecpp_driver = {
-       .name                   = "ecpp",
-       .match_table            = ecpp_match,
+       .driver = {
+               .name = "ecpp",
+               .owner = THIS_MODULE,
+               .of_match_table = ecpp_match,
+       },
        .probe                  = ecpp_probe,
        .remove                 = __devexit_p(ecpp_remove),
 };
index d1120257b0330cd25f6d6db0cac22ef700917c29..433e45f05fd4c1f593cf66df60b448668aed665e 100644 (file)
@@ -1,8 +1,9 @@
 #ifndef _SPARC_SCATTERLIST_H
 #define _SPARC_SCATTERLIST_H
 
-#define sg_dma_len(sg)         ((sg)->dma_length)
-
 #include <asm-generic/scatterlist.h>
 
+#define ISA_DMA_THRESHOLD      (~0UL)
+#define ARCH_HAS_SG_CHAIN
+
 #endif /* !(_SPARC_SCATTERLIST_H) */
index 71ec90b9e3167d890f9a25bf28b451c2e703c9f8..b27476caa1333d4fbc2a85b380c4eb3c392c4c97 100644 (file)
@@ -174,8 +174,11 @@ static struct of_device_id __initdata apc_match[] = {
 MODULE_DEVICE_TABLE(of, apc_match);
 
 static struct of_platform_driver apc_driver = {
-       .name           = "apc",
-       .match_table    = apc_match,
+       .driver = {
+               .name = "apc",
+               .owner = THIS_MODULE,
+               .of_match_table = apc_match,
+       },
        .probe          = apc_probe,
 };
 
index 9f52db2d441cb035a5e497fe5e2d94c916f9dc0e..ddc84128b3c2e4c9be06129f1aecc04f196a3dab 100644 (file)
@@ -104,7 +104,7 @@ MODULE_DEVICE_TABLE(of, auxio_match);
 
 static int __devinit auxio_probe(struct of_device *dev, const struct of_device_id *match)
 {
-       struct device_node *dp = dev->node;
+       struct device_node *dp = dev->dev.of_node;
        unsigned long size;
 
        if (!strcmp(dp->parent->name, "ebus")) {
@@ -132,10 +132,11 @@ static int __devinit auxio_probe(struct of_device *dev, const struct of_device_i
 }
 
 static struct of_platform_driver auxio_driver = {
-       .match_table    = auxio_match,
        .probe          = auxio_probe,
-       .driver         = {
-               .name   = "auxio",
+       .driver = {
+               .name = "auxio",
+               .owner = THIS_MODULE,
+               .of_match_table = auxio_match,
        },
 };
 
index 415c86d5a8dac990c011309bde3d89afe9a307c7..434335f65823ec944626a9cbe0b9bbccb28bfd86 100644 (file)
@@ -149,10 +149,11 @@ static struct of_device_id __initdata clock_board_match[] = {
 };
 
 static struct of_platform_driver clock_board_driver = {
-       .match_table    = clock_board_match,
        .probe          = clock_board_probe,
-       .driver         = {
-               .name   = "clock_board",
+       .driver = {
+               .name = "clock_board",
+               .owner = THIS_MODULE,
+               .of_match_table = clock_board_match,
        },
 };
 
@@ -168,7 +169,7 @@ static int __devinit fhc_probe(struct of_device *op,
                goto out;
        }
 
-       if (!strcmp(op->node->parent->name, "central"))
+       if (!strcmp(op->dev.of_node->parent->name, "central"))
                p->central = true;
 
        p->pregs = of_ioremap(&op->resource[0], 0,
@@ -183,7 +184,7 @@ static int __devinit fhc_probe(struct of_device *op,
                reg = upa_readl(p->pregs + FHC_PREGS_BSR);
                p->board_num = ((reg >> 16) & 1) | ((reg >> 12) & 0x0e);
        } else {
-               p->board_num = of_getintprop_default(op->node, "board#", -1);
+               p->board_num = of_getintprop_default(op->dev.of_node, "board#", -1);
                if (p->board_num == -1) {
                        printk(KERN_ERR "fhc: No board# property\n");
                        goto out_unmap_pregs;
@@ -254,10 +255,11 @@ static struct of_device_id __initdata fhc_match[] = {
 };
 
 static struct of_platform_driver fhc_driver = {
-       .match_table    = fhc_match,
        .probe          = fhc_probe,
-       .driver         = {
-               .name   = "fhc",
+       .driver = {
+               .name = "fhc",
+               .owner = THIS_MODULE,
+               .of_match_table = fhc_match,
        },
 };
 
index e1a9598e2a4db8b0c0cc36aca1c7ac5addb1dbc5..870cb65b3f216e38b81fc6932afe145067f6aec9 100644 (file)
@@ -425,7 +425,7 @@ static int __devinit jbusmc_probe(struct of_device *op,
        INIT_LIST_HEAD(&p->list);
 
        err = -ENODEV;
-       prop = of_get_property(op->node, "portid", &len);
+       prop = of_get_property(op->dev.of_node, "portid", &len);
        if (!prop || len != 4) {
                printk(KERN_ERR PFX "Cannot find portid.\n");
                goto out_free;
@@ -433,7 +433,7 @@ static int __devinit jbusmc_probe(struct of_device *op,
 
        p->portid = *prop;
 
-       prop = of_get_property(op->node, "memory-control-register-1", &len);
+       prop = of_get_property(op->dev.of_node, "memory-control-register-1", &len);
        if (!prop || len != 8) {
                printk(KERN_ERR PFX "Cannot get memory control register 1.\n");
                goto out_free;
@@ -449,7 +449,7 @@ static int __devinit jbusmc_probe(struct of_device *op,
        }
 
        err = -ENODEV;
-       ml = of_get_property(op->node, "memory-layout", &p->layout_len);
+       ml = of_get_property(op->dev.of_node, "memory-layout", &p->layout_len);
        if (!ml) {
                printk(KERN_ERR PFX "Cannot get memory layout property.\n");
                goto out_iounmap;
@@ -466,7 +466,7 @@ static int __devinit jbusmc_probe(struct of_device *op,
        mc_list_add(&p->list);
 
        printk(KERN_INFO PFX "UltraSPARC-IIIi memory controller at %s\n",
-              op->node->full_name);
+              op->dev.of_node->full_name);
 
        dev_set_drvdata(&op->dev, p);
 
@@ -693,7 +693,7 @@ static void chmc_fetch_decode_regs(struct chmc *p)
 static int __devinit chmc_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;
        unsigned long ver;
        const void *pval;
        int len, portid;
@@ -811,8 +811,11 @@ static const struct of_device_id us3mc_match[] = {
 MODULE_DEVICE_TABLE(of, us3mc_match);
 
 static struct of_platform_driver us3mc_driver = {
-       .name           = "us3mc",
-       .match_table    = us3mc_match,
+       .driver = {
+               .name = "us3mc",
+               .owner = THIS_MODULE,
+               .of_match_table = us3mc_match,
+       },
        .probe          = us3mc_probe,
        .remove         = __devexit_p(us3mc_remove),
 };
index 84e5386714cdbe0f3397d6d6eddc52f8c841ddcc..703e4aa9bc38420fde79f7a7fdbc6b9bb60045b6 100644 (file)
@@ -290,7 +290,7 @@ static void *sbus_alloc_coherent(struct device *dev, size_t len,
        if (mmu_map_dma_area(dev, dma_addrp, va, res->start, len_total) != 0)
                goto err_noiommu;
 
-       res->name = op->node->name;
+       res->name = op->dev.of_node->name;
 
        return (void *)(unsigned long)res->start;
 
index da527b33ebc708ad2693d9932bbae97f671e2d88..47e63f1e719c7a2d9e4d4e757b1bf0a07e16d308 100644 (file)
@@ -254,10 +254,10 @@ static void __init build_device_resources(struct of_device *op,
                return;
 
        p_op = to_of_device(parent);
-       bus = of_match_bus(p_op->node);
-       bus->count_cells(op->node, &na, &ns);
+       bus = of_match_bus(p_op->dev.of_node);
+       bus->count_cells(op->dev.of_node, &na, &ns);
 
-       preg = of_get_property(op->node, bus->addr_prop_name, &num_reg);
+       preg = of_get_property(op->dev.of_node, bus->addr_prop_name, &num_reg);
        if (!preg || num_reg == 0)
                return;
 
@@ -271,8 +271,8 @@ static void __init build_device_resources(struct of_device *op,
                struct resource *r = &op->resource[index];
                u32 addr[OF_MAX_ADDR_CELLS];
                const u32 *reg = (preg + (index * ((na + ns) * 4)));
-               struct device_node *dp = op->node;
-               struct device_node *pp = p_op->node;
+               struct device_node *dp = op->dev.of_node;
+               struct device_node *pp = p_op->dev.of_node;
                struct of_bus *pbus, *dbus;
                u64 size, result = OF_BAD_ADDR;
                unsigned long flags;
@@ -321,7 +321,7 @@ static void __init build_device_resources(struct of_device *op,
 
                if (of_resource_verbose)
                        printk("%s reg[%d] -> %llx\n",
-                              op->node->full_name, index,
+                              op->dev.of_node->full_name, index,
                               result);
 
                if (result != OF_BAD_ADDR) {
@@ -329,7 +329,7 @@ static void __init build_device_resources(struct of_device *op,
                        r->end = result + size - 1;
                        r->flags = flags | ((result >> 32ULL) & 0xffUL);
                }
-               r->name = op->node->name;
+               r->name = op->dev.of_node->name;
        }
 }
 
@@ -345,10 +345,9 @@ static struct of_device * __init scan_one_device(struct device_node *dp,
                return NULL;
 
        sd = &op->dev.archdata;
-       sd->prom_node = dp;
        sd->op = op;
 
-       op->node = dp;
+       op->dev.of_node = dp;
 
        op->clock_freq = of_getintprop_default(dp, "clock-frequency",
                                               (25*1000*1000));
index b3d4cb5d21b333c54fee00998491644397eb92d1..1dae8079f7287a7d52631bb589899c93f3c146d0 100644 (file)
@@ -323,10 +323,10 @@ static void __init build_device_resources(struct of_device *op,
                return;
 
        p_op = to_of_device(parent);
-       bus = of_match_bus(p_op->node);
-       bus->count_cells(op->node, &na, &ns);
+       bus = of_match_bus(p_op->dev.of_node);
+       bus->count_cells(op->dev.of_node, &na, &ns);
 
-       preg = of_get_property(op->node, bus->addr_prop_name, &num_reg);
+       preg = of_get_property(op->dev.of_node, bus->addr_prop_name, &num_reg);
        if (!preg || num_reg == 0)
                return;
 
@@ -340,7 +340,7 @@ static void __init build_device_resources(struct of_device *op,
        if (num_reg > PROMREG_MAX) {
                printk(KERN_WARNING "%s: Too many regs (%d), "
                       "limiting to %d.\n",
-                      op->node->full_name, num_reg, PROMREG_MAX);
+                      op->dev.of_node->full_name, num_reg, PROMREG_MAX);
                num_reg = PROMREG_MAX;
        }
 
@@ -348,8 +348,8 @@ static void __init build_device_resources(struct of_device *op,
                struct resource *r = &op->resource[index];
                u32 addr[OF_MAX_ADDR_CELLS];
                const u32 *reg = (preg + (index * ((na + ns) * 4)));
-               struct device_node *dp = op->node;
-               struct device_node *pp = p_op->node;
+               struct device_node *dp = op->dev.of_node;
+               struct device_node *pp = p_op->dev.of_node;
                struct of_bus *pbus, *dbus;
                u64 size, result = OF_BAD_ADDR;
                unsigned long flags;
@@ -397,7 +397,7 @@ static void __init build_device_resources(struct of_device *op,
 
                if (of_resource_verbose)
                        printk("%s reg[%d] -> %llx\n",
-                              op->node->full_name, index,
+                              op->dev.of_node->full_name, index,
                               result);
 
                if (result != OF_BAD_ADDR) {
@@ -408,7 +408,7 @@ static void __init build_device_resources(struct of_device *op,
                        r->end = result + size - 1;
                        r->flags = flags;
                }
-               r->name = op->node->name;
+               r->name = op->dev.of_node->name;
        }
 }
 
@@ -530,7 +530,7 @@ static unsigned int __init build_one_device_irq(struct of_device *op,
                                                struct device *parent,
                                                unsigned int irq)
 {
-       struct device_node *dp = op->node;
+       struct device_node *dp = op->dev.of_node;
        struct device_node *pp, *ip;
        unsigned int orig_irq = irq;
        int nid;
@@ -575,7 +575,7 @@ static unsigned int __init build_one_device_irq(struct of_device *op,
 
                        if (of_irq_verbose)
                                printk("%s: Apply [%s:%x] imap --> [%s:%x]\n",
-                                      op->node->full_name,
+                                      op->dev.of_node->full_name,
                                       pp->full_name, this_orig_irq,
                                       (iret ? iret->full_name : "NULL"), irq);
 
@@ -594,7 +594,7 @@ static unsigned int __init build_one_device_irq(struct of_device *op,
                                if (of_irq_verbose)
                                        printk("%s: PCI swizzle [%s] "
                                               "%x --> %x\n",
-                                              op->node->full_name,
+                                              op->dev.of_node->full_name,
                                               pp->full_name, this_orig_irq,
                                               irq);
 
@@ -611,11 +611,11 @@ static unsigned int __init build_one_device_irq(struct of_device *op,
        if (!ip)
                return orig_irq;
 
-       irq = ip->irq_trans->irq_build(op->node, irq,
+       irq = ip->irq_trans->irq_build(op->dev.of_node, irq,
                                       ip->irq_trans->data);
        if (of_irq_verbose)
                printk("%s: Apply IRQ trans [%s] %x --> %x\n",
-                      op->node->full_name, ip->full_name, orig_irq, irq);
+                     op->dev.of_node->full_name, ip->full_name, orig_irq, irq);
 
 out:
        nid = of_node_to_nid(dp);
@@ -640,10 +640,9 @@ static struct of_device * __init scan_one_device(struct device_node *dp,
                return NULL;
 
        sd = &op->dev.archdata;
-       sd->prom_node = dp;
        sd->op = op;
 
-       op->node = dp;
+       op->dev.of_node = dp;
 
        op->clock_freq = of_getintprop_default(dp, "clock-frequency",
                                               (25*1000*1000));
index 0247e68210b3417eba430ae12ef98facbf0ab76d..10c6c36a6e7565a7716cb98c7107f089e232f3fa 100644 (file)
@@ -16,7 +16,7 @@ static int node_match(struct device *dev, void *data)
        struct of_device *op = to_of_device(dev);
        struct device_node *dp = data;
 
-       return (op->node == dp);
+       return (op->dev.of_node == dp);
 }
 
 struct of_device *of_find_device_by_node(struct device_node *dp)
@@ -48,7 +48,7 @@ EXPORT_SYMBOL(irq_of_parse_and_map);
 void of_propagate_archdata(struct of_device *bus)
 {
        struct dev_archdata *bus_sd = &bus->dev.archdata;
-       struct device_node *bus_dp = bus->node;
+       struct device_node *bus_dp = bus->dev.of_node;
        struct device_node *dp;
 
        for (dp = bus_dp->child; dp; dp = dp->sibling) {
index 5ac539a5930f5401239d81f2e1bfff217472a60e..8a8363adb8bd1ac68c1ad49e6afba66dc7b43ae5 100644 (file)
@@ -261,7 +261,6 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
        sd->iommu = pbm->iommu;
        sd->stc = &pbm->stc;
        sd->host_controller = pbm;
-       sd->prom_node = node;
        sd->op = op = of_find_device_by_node(node);
        sd->numa_node = pbm->numa_node;
 
@@ -285,6 +284,7 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
        dev->sysdata = node;
        dev->dev.parent = bus->bridge;
        dev->dev.bus = &pci_bus_type;
+       dev->dev.of_node = node;
        dev->devfn = devfn;
        dev->multifunction = 0;         /* maybe a lie? */
        set_pcie_port_type(dev);
@@ -653,7 +653,7 @@ show_pciobppath_attr(struct device * dev, struct device_attribute * attr, char *
        struct device_node *dp;
 
        pdev = to_pci_dev(dev);
-       dp = pdev->dev.archdata.prom_node;
+       dp = pdev->dev.of_node;
 
        return snprintf (buf, PAGE_SIZE, "%s\n", dp->full_name);
 }
@@ -683,7 +683,7 @@ static void __devinit pci_bus_register_of_sysfs(struct pci_bus *bus)
 struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm,
                                            struct device *parent)
 {
-       struct device_node *node = pbm->op->node;
+       struct device_node *node = pbm->op->dev.of_node;
        struct pci_bus *bus;
 
        printk("PCI: Scanning PBM %s\n", node->full_name);
@@ -1022,7 +1022,7 @@ void arch_teardown_msi_irq(unsigned int virt_irq)
 
 struct device_node *pci_device_to_OF_node(struct pci_dev *pdev)
 {
-       return pdev->dev.archdata.prom_node;
+       return pdev->dev.of_node;
 }
 EXPORT_SYMBOL(pci_device_to_OF_node);
 
@@ -1151,15 +1151,13 @@ static int __init of_pci_slot_init(void)
                struct device_node *node;
 
                if (pbus->self) {
-                       struct dev_archdata *sd = pbus->self->sysdata;
-
                        /* PCI->PCI bridge */
-                       node = sd->prom_node;
+                       node = pbus->self->dev.of_node;
                } else {
                        struct pci_pbm_info *pbm = pbus->sysdata;
 
                        /* Host PCI controller */
-                       node = pbm->op->node;
+                       node = pbm->op->dev.of_node;
                }
 
                pci_bus_slot_names(node, pbus);
index 8a000583b5cf62ef887d419f54528a8080350e6b..6c7a33af3ba625f83c589d025b2aed149f0d5d16 100644 (file)
@@ -314,12 +314,12 @@ struct pci_ops sun4v_pci_ops = {
 
 void pci_get_pbm_props(struct pci_pbm_info *pbm)
 {
-       const u32 *val = of_get_property(pbm->op->node, "bus-range", NULL);
+       const u32 *val = of_get_property(pbm->op->dev.of_node, "bus-range", NULL);
 
        pbm->pci_first_busno = val[0];
        pbm->pci_last_busno = val[1];
 
-       val = of_get_property(pbm->op->node, "ino-bitmap", NULL);
+       val = of_get_property(pbm->op->dev.of_node, "ino-bitmap", NULL);
        if (val) {
                pbm->ino_bitmap = (((u64)val[1] << 32UL) |
                                   ((u64)val[0] <<  0UL));
@@ -365,7 +365,8 @@ static void pci_register_legacy_regions(struct resource *io_res,
 
 static void pci_register_iommu_region(struct pci_pbm_info *pbm)
 {
-       const u32 *vdma = of_get_property(pbm->op->node, "virtual-dma", NULL);
+       const u32 *vdma = of_get_property(pbm->op->dev.of_node, "virtual-dma",
+                                         NULL);
 
        if (vdma) {
                struct resource *rp = kzalloc(sizeof(*rp), GFP_KERNEL);
@@ -394,7 +395,7 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm)
        int num_pbm_ranges;
 
        saw_mem = saw_io = 0;
-       pbm_ranges = of_get_property(pbm->op->node, "ranges", &i);
+       pbm_ranges = of_get_property(pbm->op->dev.of_node, "ranges", &i);
        if (!pbm_ranges) {
                prom_printf("PCI: Fatal error, missing PBM ranges property "
                            " for %s\n",
index d53f45bc7dda269b3b488c7117da530c8b1c701f..51cfa09e392ab13f67862c11460e856235b6b9dc 100644 (file)
@@ -413,7 +413,7 @@ static int __devinit pci_fire_pbm_init(struct pci_pbm_info *pbm,
                                       struct of_device *op, u32 portid)
 {
        const struct linux_prom64_registers *regs;
-       struct device_node *dp = op->node;
+       struct device_node *dp = op->dev.of_node;
        int err;
 
        pbm->numa_node = -1;
@@ -458,7 +458,7 @@ static int __devinit pci_fire_pbm_init(struct pci_pbm_info *pbm,
 static int __devinit fire_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 pci_pbm_info *pbm;
        struct iommu *iommu;
        u32 portid;
@@ -508,8 +508,11 @@ static struct of_device_id __initdata fire_match[] = {
 };
 
 static struct of_platform_driver fire_driver = {
-       .name           = DRIVER_NAME,
-       .match_table    = fire_match,
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = fire_match,
+       },
        .probe          = fire_probe,
 };
 
index e0ef847219c3b0f11b3330d15b57a4858549567d..548b8ca9c2106d7b7fa88d602db86a125a2a283e 100644 (file)
@@ -324,7 +324,7 @@ void sparc64_pbm_msi_init(struct pci_pbm_info *pbm,
        const u32 *val;
        int len;
 
-       val = of_get_property(pbm->op->node, "#msi-eqs", &len);
+       val = of_get_property(pbm->op->dev.of_node, "#msi-eqs", &len);
        if (!val || len != 4)
                goto no_msi;
        pbm->msiq_num = *val;
@@ -347,16 +347,16 @@ void sparc64_pbm_msi_init(struct pci_pbm_info *pbm,
                        u32 msi64_len;
                } *arng;
 
-               val = of_get_property(pbm->op->node, "msi-eq-size", &len);
+               val = of_get_property(pbm->op->dev.of_node, "msi-eq-size", &len);
                if (!val || len != 4)
                        goto no_msi;
 
                pbm->msiq_ent_count = *val;
 
-               mqp = of_get_property(pbm->op->node,
+               mqp = of_get_property(pbm->op->dev.of_node,
                                      "msi-eq-to-devino", &len);
                if (!mqp)
-                       mqp = of_get_property(pbm->op->node,
+                       mqp = of_get_property(pbm->op->dev.of_node,
                                              "msi-eq-devino", &len);
                if (!mqp || len != sizeof(struct msiq_prop))
                        goto no_msi;
@@ -364,27 +364,27 @@ void sparc64_pbm_msi_init(struct pci_pbm_info *pbm,
                pbm->msiq_first = mqp->first_msiq;
                pbm->msiq_first_devino = mqp->first_devino;
 
-               val = of_get_property(pbm->op->node, "#msi", &len);
+               val = of_get_property(pbm->op->dev.of_node, "#msi", &len);
                if (!val || len != 4)
                        goto no_msi;
                pbm->msi_num = *val;
 
-               mrng = of_get_property(pbm->op->node, "msi-ranges", &len);
+               mrng = of_get_property(pbm->op->dev.of_node, "msi-ranges", &len);
                if (!mrng || len != sizeof(struct msi_range_prop))
                        goto no_msi;
                pbm->msi_first = mrng->first_msi;
 
-               val = of_get_property(pbm->op->node, "msi-data-mask", &len);
+               val = of_get_property(pbm->op->dev.of_node, "msi-data-mask", &len);
                if (!val || len != 4)
                        goto no_msi;
                pbm->msi_data_mask = *val;
 
-               val = of_get_property(pbm->op->node, "msix-data-width", &len);
+               val = of_get_property(pbm->op->dev.of_node, "msix-data-width", &len);
                if (!val || len != 4)
                        goto no_msi;
                pbm->msix_data_width = *val;
 
-               arng = of_get_property(pbm->op->node, "msi-address-ranges",
+               arng = of_get_property(pbm->op->dev.of_node, "msi-address-ranges",
                                       &len);
                if (!arng || len != sizeof(struct addr_range_prop))
                        goto no_msi;
index 142b9d6984a8d9886b7c25433e75de59205689f0..558a70512824252d00e7e8c61396bc10b266c7a2 100644 (file)
@@ -285,7 +285,7 @@ static irqreturn_t psycho_ce_intr(int irq, void *dev_id)
 #define  PSYCHO_ECCCTRL_CE      0x2000000000000000UL /* Enable CE INterrupts */
 static void psycho_register_error_handlers(struct pci_pbm_info *pbm)
 {
-       struct of_device *op = of_find_device_by_node(pbm->op->node);
+       struct of_device *op = of_find_device_by_node(pbm->op->dev.of_node);
        unsigned long base = pbm->controller_regs;
        u64 tmp;
        int err;
@@ -507,7 +507,7 @@ static int __devinit psycho_probe(struct of_device *op,
                                  const struct of_device_id *match)
 {
        const struct linux_prom64_registers *pr_regs;
-       struct device_node *dp = op->node;
+       struct device_node *dp = op->dev.of_node;
        struct pci_pbm_info *pbm;
        struct iommu *iommu;
        int is_pbm_a, err;
@@ -602,8 +602,11 @@ static struct of_device_id __initdata psycho_match[] = {
 };
 
 static struct of_platform_driver psycho_driver = {
-       .name           = DRIVER_NAME,
-       .match_table    = psycho_match,
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = psycho_match,
+       },
        .probe          = psycho_probe,
 };
 
index ba6fbeba3e2cf7e2e5c5f34afdcbabd6d1c60a36..6dad8e3b750666c433926d9a9d6963a42cc99de5 100644 (file)
@@ -310,7 +310,7 @@ static irqreturn_t sabre_ce_intr(int irq, void *dev_id)
 
 static void sabre_register_error_handlers(struct pci_pbm_info *pbm)
 {
-       struct device_node *dp = pbm->op->node;
+       struct device_node *dp = pbm->op->dev.of_node;
        struct of_device *op;
        unsigned long base = pbm->controller_regs;
        u64 tmp;
@@ -456,7 +456,7 @@ static int __devinit sabre_probe(struct of_device *op,
                                 const struct of_device_id *match)
 {
        const struct linux_prom64_registers *pr_regs;
-       struct device_node *dp = op->node;
+       struct device_node *dp = op->dev.of_node;
        struct pci_pbm_info *pbm;
        u32 upa_portid, dma_mask;
        struct iommu *iommu;
@@ -596,8 +596,11 @@ static struct of_device_id __initdata sabre_match[] = {
 };
 
 static struct of_platform_driver sabre_driver = {
-       .name           = DRIVER_NAME,
-       .match_table    = sabre_match,
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = sabre_match,
+       },
        .probe          = sabre_probe,
 };
 
index 2b5cdde77af774942113f53f4eb66dec00659ee2..97a1ae2e1c02ebee8bbcdd221254f80bb46b15b4 100644 (file)
@@ -844,7 +844,7 @@ static int pbm_routes_this_ino(struct pci_pbm_info *pbm, u32 ino)
  */
 static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
 {
-       struct of_device *op = of_find_device_by_node(pbm->op->node);
+       struct of_device *op = of_find_device_by_node(pbm->op->dev.of_node);
        u64 tmp, err_mask, err_no_mask;
        int err;
 
@@ -939,7 +939,7 @@ static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
 
 static void schizo_register_error_handlers(struct pci_pbm_info *pbm)
 {
-       struct of_device *op = of_find_device_by_node(pbm->op->node);
+       struct of_device *op = of_find_device_by_node(pbm->op->dev.of_node);
        u64 tmp, err_mask, err_no_mask;
        int err;
 
@@ -1068,7 +1068,7 @@ static void __devinit schizo_scan_bus(struct pci_pbm_info *pbm,
 {
        pbm_config_busmastering(pbm);
        pbm->is_66mhz_capable =
-               (of_find_property(pbm->op->node, "66mhz-capable", NULL)
+               (of_find_property(pbm->op->dev.of_node, "66mhz-capable", NULL)
                 != NULL);
 
        pbm->pci_bus = pci_scan_one_pbm(pbm, parent);
@@ -1138,7 +1138,7 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
        u32 dma_mask;
        u64 control;
 
-       vdma = of_get_property(pbm->op->node, "virtual-dma", NULL);
+       vdma = of_get_property(pbm->op->dev.of_node, "virtual-dma", NULL);
        if (!vdma)
                vdma = vdma_default;
 
@@ -1268,7 +1268,7 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
            pbm->chip_version >= 0x2)
                tmp |= 0x3UL << SCHIZO_PCICTRL_PTO_SHIFT;
 
-       if (!of_find_property(pbm->op->node, "no-bus-parking", NULL))
+       if (!of_find_property(pbm->op->dev.of_node, "no-bus-parking", NULL))
                tmp |= SCHIZO_PCICTRL_PARK;
        else
                tmp &= ~SCHIZO_PCICTRL_PARK;
@@ -1311,7 +1311,7 @@ static int __devinit schizo_pbm_init(struct pci_pbm_info *pbm,
                                     int chip_type)
 {
        const struct linux_prom64_registers *regs;
-       struct device_node *dp = op->node;
+       struct device_node *dp = op->dev.of_node;
        const char *chipset_name;
        int is_pbm_a, err;
 
@@ -1415,7 +1415,7 @@ static struct pci_pbm_info * __devinit schizo_find_sibling(u32 portid,
 
 static int __devinit __schizo_init(struct of_device *op, unsigned long chip_type)
 {
-       struct device_node *dp = op->node;
+       struct device_node *dp = op->dev.of_node;
        struct pci_pbm_info *pbm;
        struct iommu *iommu;
        u32 portid;
@@ -1491,8 +1491,11 @@ static struct of_device_id __initdata schizo_match[] = {
 };
 
 static struct of_platform_driver schizo_driver = {
-       .name           = DRIVER_NAME,
-       .match_table    = schizo_match,
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = schizo_match,
+       },
        .probe          = schizo_probe,
 };
 
index 23c33ff9c31e3414f68a6316706443efb19f80c3..a24af6f7e17f12b125f16d716690e02b663b5f88 100644 (file)
@@ -540,7 +540,7 @@ static void __devinit pci_sun4v_scan_bus(struct pci_pbm_info *pbm,
        struct property *prop;
        struct device_node *dp;
 
-       dp = pbm->op->node;
+       dp = pbm->op->dev.of_node;
        prop = of_find_property(dp, "66mhz-capable", NULL);
        pbm->is_66mhz_capable = (prop != NULL);
        pbm->pci_bus = pci_scan_one_pbm(pbm, parent);
@@ -584,7 +584,7 @@ static int __devinit pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
        u32 dma_mask, dma_offset;
        const u32 *vdma;
 
-       vdma = of_get_property(pbm->op->node, "virtual-dma", NULL);
+       vdma = of_get_property(pbm->op->dev.of_node, "virtual-dma", NULL);
        if (!vdma)
                vdma = vdma_default;
 
@@ -881,7 +881,7 @@ static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
 static int __devinit pci_sun4v_pbm_init(struct pci_pbm_info *pbm,
                                        struct of_device *op, u32 devhandle)
 {
-       struct device_node *dp = op->node;
+       struct device_node *dp = op->dev.of_node;
        int err;
 
        pbm->numa_node = of_node_to_nid(dp);
@@ -929,7 +929,7 @@ static int __devinit pci_sun4v_probe(struct of_device *op,
        u32 devhandle;
        int i, err;
 
-       dp = op->node;
+       dp = op->dev.of_node;
 
        if (!hvapi_negotiated++) {
                err = sun4v_hvapi_register(HV_GRP_PCI,
@@ -1009,8 +1009,11 @@ static struct of_device_id __initdata pci_sun4v_match[] = {
 };
 
 static struct of_platform_driver pci_sun4v_driver = {
-       .name           = DRIVER_NAME,
-       .match_table    = pci_sun4v_match,
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = pci_sun4v_match,
+       },
        .probe          = pci_sun4v_probe,
 };
 
index 34ce49f80eac53185dfe32b951bb10e91224b4e2..0ec92c8861dd3a68fe0465b71ccf8007ad6e40a7 100644 (file)
@@ -92,6 +92,8 @@ struct cpu_hw_events {
 
        /* Enabled/disable state.  */
        int                     enabled;
+
+       unsigned int            group_flag;
 };
 DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = { .enabled = 1, };
 
@@ -981,53 +983,6 @@ static int collect_events(struct perf_event *group, int max_count,
        return n;
 }
 
-static void event_sched_in(struct perf_event *event)
-{
-       event->state = PERF_EVENT_STATE_ACTIVE;
-       event->oncpu = smp_processor_id();
-       event->tstamp_running += event->ctx->time - event->tstamp_stopped;
-       if (is_software_event(event))
-               event->pmu->enable(event);
-}
-
-int hw_perf_group_sched_in(struct perf_event *group_leader,
-                          struct perf_cpu_context *cpuctx,
-                          struct perf_event_context *ctx)
-{
-       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
-       struct perf_event *sub;
-       int n0, n;
-
-       if (!sparc_pmu)
-               return 0;
-
-       n0 = cpuc->n_events;
-       n = collect_events(group_leader, perf_max_events - n0,
-                          &cpuc->event[n0], &cpuc->events[n0],
-                          &cpuc->current_idx[n0]);
-       if (n < 0)
-               return -EAGAIN;
-       if (check_excludes(cpuc->event, n0, n))
-               return -EINVAL;
-       if (sparc_check_constraints(cpuc->event, cpuc->events, n + n0))
-               return -EAGAIN;
-       cpuc->n_events = n0 + n;
-       cpuc->n_added += n;
-
-       cpuctx->active_oncpu += n;
-       n = 1;
-       event_sched_in(group_leader);
-       list_for_each_entry(sub, &group_leader->sibling_list, group_entry) {
-               if (sub->state != PERF_EVENT_STATE_OFF) {
-                       event_sched_in(sub);
-                       n++;
-               }
-       }
-       ctx->nr_active += n;
-
-       return 1;
-}
-
 static int sparc_pmu_enable(struct perf_event *event)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
@@ -1045,11 +1000,20 @@ static int sparc_pmu_enable(struct perf_event *event)
        cpuc->events[n0] = event->hw.event_base;
        cpuc->current_idx[n0] = PIC_NO_INDEX;
 
+       /*
+        * If group events scheduling transaction was started,
+        * skip the schedulability test here, it will be peformed
+        * at commit time(->commit_txn) as a whole
+        */
+       if (cpuc->group_flag & PERF_EVENT_TXN_STARTED)
+               goto nocheck;
+
        if (check_excludes(cpuc->event, n0, 1))
                goto out;
        if (sparc_check_constraints(cpuc->event, cpuc->events, n0 + 1))
                goto out;
 
+nocheck:
        cpuc->n_events++;
        cpuc->n_added++;
 
@@ -1129,11 +1093,61 @@ static int __hw_perf_event_init(struct perf_event *event)
        return 0;
 }
 
+/*
+ * Start group events scheduling transaction
+ * Set the flag to make pmu::enable() not perform the
+ * schedulability test, it will be performed at commit time
+ */
+static void sparc_pmu_start_txn(const struct pmu *pmu)
+{
+       struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+
+       cpuhw->group_flag |= PERF_EVENT_TXN_STARTED;
+}
+
+/*
+ * Stop group events scheduling transaction
+ * Clear the flag and pmu::enable() will perform the
+ * schedulability test.
+ */
+static void sparc_pmu_cancel_txn(const struct pmu *pmu)
+{
+       struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+
+       cpuhw->group_flag &= ~PERF_EVENT_TXN_STARTED;
+}
+
+/*
+ * Commit group events scheduling transaction
+ * Perform the group schedulability test as a whole
+ * Return 0 if success
+ */
+static int sparc_pmu_commit_txn(const struct pmu *pmu)
+{
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+       int n;
+
+       if (!sparc_pmu)
+               return -EINVAL;
+
+       cpuc = &__get_cpu_var(cpu_hw_events);
+       n = cpuc->n_events;
+       if (check_excludes(cpuc->event, 0, n))
+               return -EINVAL;
+       if (sparc_check_constraints(cpuc->event, cpuc->events, n))
+               return -EAGAIN;
+
+       return 0;
+}
+
 static const struct pmu pmu = {
        .enable         = sparc_pmu_enable,
        .disable        = sparc_pmu_disable,
        .read           = sparc_pmu_read,
        .unthrottle     = sparc_pmu_unthrottle,
+       .start_txn      = sparc_pmu_start_txn,
+       .cancel_txn     = sparc_pmu_cancel_txn,
+       .commit_txn     = sparc_pmu_commit_txn,
 };
 
 const struct pmu *hw_perf_event_init(struct perf_event *event)
index 5e4563d86f191d39c2cf6ab386f233a13a877585..9589d8b9b0c17eb59f5d0d2d1b66a94ac3fd655e 100644 (file)
@@ -79,8 +79,11 @@ static struct of_device_id __initdata pmc_match[] = {
 MODULE_DEVICE_TABLE(of, pmc_match);
 
 static struct of_platform_driver pmc_driver = {
-       .name           = "pmc",
-       .match_table    = pmc_match,
+       .driver = {
+               .name = "pmc",
+               .owner = THIS_MODULE,
+               .of_match_table = pmc_match,
+       },
        .probe          = pmc_probe,
 };
 
index e2a045c235a10b9d3861e48b7af2e2acab7b50e1..168d4cb63f5b34e110f021769adb1f199bee9a1e 100644 (file)
@@ -41,9 +41,9 @@ static int __devinit power_probe(struct of_device *op, const struct of_device_id
        power_reg = of_ioremap(res, 0, 0x4, "power");
 
        printk(KERN_INFO "%s: Control reg at %llx\n",
-              op->node->name, res->start);
+              op->dev.of_node->name, res->start);
 
-       if (has_button_interrupt(irq, op->node)) {
+       if (has_button_interrupt(irq, op->dev.of_node)) {
                if (request_irq(irq,
                                power_handler, 0, "power", NULL) < 0)
                        printk(KERN_ERR "power: Cannot setup IRQ handler.\n");
@@ -60,10 +60,11 @@ static struct of_device_id __initdata power_match[] = {
 };
 
 static struct of_platform_driver power_driver = {
-       .match_table    = power_match,
        .probe          = power_probe,
-       .driver         = {
-               .name   = "power",
+       .driver = {
+               .name = "power",
+               .owner = THIS_MODULE,
+               .of_match_table = power_match,
        },
 };
 
index 8f1478475421586adedf59895adfdbd8a2ae04b1..3f34ac853931c816d7e004d57d44d7663f859524 100644 (file)
@@ -450,7 +450,7 @@ int psycho_iommu_init(struct pci_pbm_info *pbm, int tsbsize,
 void psycho_pbm_init_common(struct pci_pbm_info *pbm, struct of_device *op,
                            const char *chip_name, int chip_type)
 {
-       struct device_node *dp = op->node;
+       struct device_node *dp = op->dev.of_node;
 
        pbm->name = dp->full_name;
        pbm->numa_node = -1;
index 406e0872504e814ae8b4086c58a371f2b45f10d5..cfeaf04b9cdf4204cfc5d21f1d8d84bfddb0367d 100644 (file)
@@ -63,10 +63,10 @@ void sbus_set_sbus64(struct device *dev, int bursts)
        int slot;
        u64 val;
 
-       regs = of_get_property(op->node, "reg", NULL);
+       regs = of_get_property(op->dev.of_node, "reg", NULL);
        if (!regs) {
                printk(KERN_ERR "sbus_set_sbus64: Cannot find regs for %s\n",
-                      op->node->full_name);
+                      op->dev.of_node->full_name);
                return;
        }
        slot = regs->which_io;
@@ -287,7 +287,7 @@ static irqreturn_t sysio_ue_handler(int irq, void *dev_id)
                 SYSIO_UEAFSR_SPIO | SYSIO_UEAFSR_SDRD | SYSIO_UEAFSR_SDWR);
        upa_writeq(error_bits, afsr_reg);
 
-       portid = of_getintprop_default(op->node, "portid", -1);
+       portid = of_getintprop_default(op->dev.of_node, "portid", -1);
 
        /* Log the error. */
        printk("SYSIO[%x]: Uncorrectable ECC Error, primary error type[%s]\n",
@@ -361,7 +361,7 @@ static irqreturn_t sysio_ce_handler(int irq, void *dev_id)
                 SYSIO_CEAFSR_SPIO | SYSIO_CEAFSR_SDRD | SYSIO_CEAFSR_SDWR);
        upa_writeq(error_bits, afsr_reg);
 
-       portid = of_getintprop_default(op->node, "portid", -1);
+       portid = of_getintprop_default(op->dev.of_node, "portid", -1);
 
        printk("SYSIO[%x]: Correctable ECC Error, primary error type[%s]\n",
               portid,
@@ -439,7 +439,7 @@ static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id)
                 SYSIO_SBAFSR_SLE | SYSIO_SBAFSR_STO | SYSIO_SBAFSR_SBERR);
        upa_writeq(error_bits, afsr_reg);
 
-       portid = of_getintprop_default(op->node, "portid", -1);
+       portid = of_getintprop_default(op->dev.of_node, "portid", -1);
 
        /* Log the error. */
        printk("SYSIO[%x]: SBUS Error, primary error type[%s] read(%d)\n",
@@ -496,7 +496,7 @@ static void __init sysio_register_error_handlers(struct of_device *op)
        u64 control;
        int portid;
 
-       portid = of_getintprop_default(op->node, "portid", -1);
+       portid = of_getintprop_default(op->dev.of_node, "portid", -1);
 
        irq = sbus_build_irq(op, SYSIO_UE_INO);
        if (request_irq(irq, sysio_ue_handler, 0,
@@ -537,7 +537,7 @@ static void __init sysio_register_error_handlers(struct of_device *op)
 static void __init sbus_iommu_init(struct of_device *op)
 {
        const struct linux_prom64_registers *pr;
-       struct device_node *dp = op->node;
+       struct device_node *dp = op->dev.of_node;
        struct iommu *iommu;
        struct strbuf *strbuf;
        unsigned long regs, reg_base;
@@ -589,7 +589,7 @@ static void __init sbus_iommu_init(struct of_device *op)
         */
        iommu->write_complete_reg = regs + 0x2000UL;
 
-       portid = of_getintprop_default(op->node, "portid", -1);
+       portid = of_getintprop_default(op->dev.of_node, "portid", -1);
        printk(KERN_INFO "SYSIO: UPA portID %x, at %016lx\n",
               portid, regs);
 
index 4453003032b57a8a6cab91f87eb03eabd8c26e67..e404b063be2cbc1d141c899c2e91f1ad79463989 100644 (file)
@@ -144,7 +144,7 @@ static struct platform_device m48t59_rtc = {
 
 static int __devinit clock_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;
        const char *model = of_get_property(dp, "model", NULL);
 
        if (!model)
@@ -177,10 +177,11 @@ static struct of_device_id __initdata clock_match[] = {
 };
 
 static struct of_platform_driver clock_driver = {
-       .match_table    = clock_match,
        .probe          = clock_probe,
-       .driver         = {
-               .name   = "rtc",
+       .driver = {
+               .name = "rtc",
+               .owner = THIS_MODULE,
+               .of_match_table = clock_match,
        },
 };
 
index c7bbe6cf7b85a3d76c86bbe06ddbccef4e573ad5..21e9fcae0668cdb7994ca856b428fa4a7a74b6e1 100644 (file)
@@ -424,7 +424,7 @@ static int __devinit rtc_probe(struct of_device *op, const struct of_device_id *
        struct resource *r;
 
        printk(KERN_INFO "%s: RTC regs at 0x%llx\n",
-              op->node->full_name, op->resource[0].start);
+              op->dev.of_node->full_name, op->resource[0].start);
 
        /* The CMOS RTC driver only accepts IORESOURCE_IO, so cons
         * up a fake resource so that the probe works for all cases.
@@ -463,10 +463,11 @@ static struct of_device_id __initdata rtc_match[] = {
 };
 
 static struct of_platform_driver rtc_driver = {
-       .match_table    = rtc_match,
        .probe          = rtc_probe,
-       .driver         = {
-               .name   = "rtc",
+       .driver = {
+               .name = "rtc",
+               .owner = THIS_MODULE,
+               .of_match_table = rtc_match,
        },
 };
 
@@ -480,7 +481,7 @@ static int __devinit bq4802_probe(struct of_device *op, const struct of_device_i
 {
 
        printk(KERN_INFO "%s: BQ4802 regs at 0x%llx\n",
-              op->node->full_name, op->resource[0].start);
+              op->dev.of_node->full_name, op->resource[0].start);
 
        rtc_bq4802_device.resource = &op->resource[0];
        return platform_device_register(&rtc_bq4802_device);
@@ -495,10 +496,11 @@ static struct of_device_id __initdata bq4802_match[] = {
 };
 
 static struct of_platform_driver bq4802_driver = {
-       .match_table    = bq4802_match,
        .probe          = bq4802_probe,
-       .driver         = {
-               .name   = "bq4802",
+       .driver = {
+               .name = "bq4802",
+               .owner = THIS_MODULE,
+               .of_match_table = bq4802_match,
        },
 };
 
@@ -534,7 +536,7 @@ static struct platform_device m48t59_rtc = {
 
 static int __devinit mostek_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;
 
        /* On an Enterprise system there can be multiple mostek clocks.
         * We should only match the one that is on the central FHC bus.
@@ -558,10 +560,11 @@ static struct of_device_id __initdata mostek_match[] = {
 };
 
 static struct of_platform_driver mostek_driver = {
-       .match_table    = mostek_match,
        .probe          = mostek_probe,
-       .driver         = {
-               .name   = "mostek",
+       .driver = {
+               .name = "mostek",
+               .owner = THIS_MODULE,
+               .of_match_table = mostek_match,
        },
 };
 
index d332503fa1beae1f54a53fbbb62356ea2113cfb1..cfcac1ff4cf20276d19ee8fb137dfc84a6cf8abb 100644 (file)
@@ -124,8 +124,8 @@ static ssize_t harddog_write(struct file *file, const char __user *data, size_t
        return 0;
 }
 
-static int harddog_ioctl(struct inode *inode, struct file *file,
-                        unsigned int cmd, unsigned long arg)
+static int harddog_ioctl_unlocked(struct file *file,
+                                 unsigned int cmd, unsigned long arg)
 {
        void __user *argp= (void __user *)arg;
        static struct watchdog_info ident = {
@@ -148,10 +148,22 @@ static int harddog_ioctl(struct inode *inode, struct file *file,
        }
 }
 
+static long harddog_ioctl(struct file *file,
+                         unsigned int cmd, unsigned long arg)
+{
+       long ret;
+
+       lock_kernel();
+       ret = harddog_ioctl_unlocked(file, cmd, arg);
+       unlock_kernel();
+
+       return ret;
+}
+
 static const struct file_operations harddog_fops = {
        .owner          = THIS_MODULE,
        .write          = harddog_write,
-       .ioctl          = harddog_ioctl,
+       .unlocked_ioctl = harddog_ioctl,
        .open           = harddog_open,
        .release        = harddog_release,
 };
index 368219cc2366d666ca92e0ac38497f111d888501..ae42695c3597991b338bff62bd19aa22bb194790 100644 (file)
@@ -136,7 +136,7 @@ static unsigned int hostaudio_poll(struct file *file,
        return mask;
 }
 
-static int hostaudio_ioctl(struct inode *inode, struct file *file,
+static long hostaudio_ioctl(struct file *file,
                           unsigned int cmd, unsigned long arg)
 {
        struct hostaudio_state *state = file->private_data;
@@ -223,7 +223,7 @@ static int hostaudio_release(struct inode *inode, struct file *file)
 
 /* /dev/mixer file operations */
 
-static int hostmixer_ioctl_mixdev(struct inode *inode, struct file *file,
+static long hostmixer_ioctl_mixdev(struct file *file,
                                  unsigned int cmd, unsigned long arg)
 {
        struct hostmixer_state *state = file->private_data;
@@ -289,7 +289,7 @@ static const struct file_operations hostaudio_fops = {
        .read           = hostaudio_read,
        .write          = hostaudio_write,
        .poll           = hostaudio_poll,
-       .ioctl          = hostaudio_ioctl,
+       .unlocked_ioctl = hostaudio_ioctl,
        .mmap           = NULL,
        .open           = hostaudio_open,
        .release        = hostaudio_release,
@@ -298,7 +298,7 @@ static const struct file_operations hostaudio_fops = {
 static const struct file_operations hostmixer_fops = {
        .owner          = THIS_MODULE,
        .llseek         = no_llseek,
-       .ioctl          = hostmixer_ioctl_mixdev,
+       .unlocked_ioctl = hostmixer_ioctl_mixdev,
        .open           = hostmixer_open_mixdev,
        .release        = hostmixer_release,
 };
index d22f9e5c0eac5f483da649cfb7da2201c8888458..7158393b67933371250f029ef0ce7ea1e1c705dc 100644 (file)
@@ -46,8 +46,7 @@ static ssize_t mmapper_write(struct file *file, const char __user *buf,
        return count;
 }
 
-static int mmapper_ioctl(struct inode *inode, struct file *file,
-                        unsigned int cmd, unsigned long arg)
+static long mmapper_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        return -ENOIOCTLCMD;
 }
@@ -90,7 +89,7 @@ static const struct file_operations mmapper_fops = {
        .owner          = THIS_MODULE,
        .read           = mmapper_read,
        .write          = mmapper_write,
-       .ioctl          = mmapper_ioctl,
+       .unlocked_ioctl = mmapper_ioctl,
        .mmap           = mmapper_mmap,
        .open           = mmapper_open,
        .release        = mmapper_release,
index a2d3a5fbeeda02a7456fc21a843a70a15d9b1c14..dcb0593b4a66348a204a44fee3366c5da0848ad1 100644 (file)
@@ -109,6 +109,9 @@ config SBUS
 config NEED_DMA_MAP_STATE
        def_bool (X86_64 || DMAR || DMA_API_DEBUG)
 
+config NEED_SG_DMA_LENGTH
+       def_bool y
+
 config GENERIC_ISA_DMA
        def_bool y
 
@@ -1703,6 +1706,10 @@ config HAVE_ARCH_EARLY_PFN_TO_NID
        def_bool X86_64
        depends on NUMA
 
+config USE_PERCPU_NUMA_NODE_ID
+       def_bool X86_64
+       depends on NUMA
+
 menu "Power management and ACPI options"
 
 config ARCH_HIBERNATION_HEADER
@@ -1923,6 +1930,14 @@ config PCI_MMCONFIG
        bool "Support mmconfig PCI config space access"
        depends on X86_64 && PCI && ACPI
 
+config PCI_CNB20LE_QUIRK
+       bool "Read CNB20LE Host Bridge Windows"
+       depends on PCI
+       help
+         Read the PCI windows out of the CNB20LE host bridge. This allows
+         PCI hotplug to work on systems with the CNB20LE chipset which do
+         not have ACPI.
+
 config DMAR
        bool "Support for DMA Remapping Devices (EXPERIMENTAL)"
        depends on PCI_MSI && ACPI && EXPERIMENTAL
index 56f462cf22d2fc75cb6c8616697813ada52d53e9..aa2c39d968fc7a9235d4f3009d38ddf566a33154 100644 (file)
@@ -85,7 +85,6 @@ extern int acpi_ioapic;
 extern int acpi_noirq;
 extern int acpi_strict;
 extern int acpi_disabled;
-extern int acpi_ht;
 extern int acpi_pci_disabled;
 extern int acpi_skip_timer_override;
 extern int acpi_use_timer_override;
@@ -97,7 +96,6 @@ void acpi_pic_sci_set_trigger(unsigned int, u16);
 static inline void disable_acpi(void)
 {
        acpi_disabled = 1;
-       acpi_ht = 0;
        acpi_pci_disabled = 1;
        acpi_noirq = 1;
 }
index dca9c545f44e6be7105f85c3a5f17ac16020d9fa..468145914389942273f2d68c5b9d57b48bf84a8e 100644 (file)
@@ -332,6 +332,7 @@ static __always_inline __pure bool __static_cpu_has(u8 bit)
 #endif
 }
 
+#if __GNUC__ >= 4
 #define static_cpu_has(bit)                                    \
 (                                                              \
        __builtin_constant_p(boot_cpu_has(bit)) ?               \
@@ -340,6 +341,12 @@ static __always_inline __pure bool __static_cpu_has(u8 bit)
                __static_cpu_has(bit) :                         \
                boot_cpu_has(bit)                               \
 )
+#else
+/*
+ * gcc 3.x is too stupid to do the static test; fall back to dynamic.
+ */
+#define static_cpu_has(bit) boot_cpu_has(bit)
+#endif
 
 #endif /* defined(__KERNEL__) && !defined(__ASSEMBLY__) */
 
diff --git a/arch/x86/include/asm/intel_scu_ipc.h b/arch/x86/include/asm/intel_scu_ipc.h
new file mode 100644 (file)
index 0000000..4470c9a
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef _ASM_X86_INTEL_SCU_IPC_H_
+#define  _ASM_X86_INTEL_SCU_IPC_H_
+
+/* Read single register */
+int intel_scu_ipc_ioread8(u16 addr, u8 *data);
+
+/* Read two sequential registers */
+int intel_scu_ipc_ioread16(u16 addr, u16 *data);
+
+/* Read four sequential registers */
+int intel_scu_ipc_ioread32(u16 addr, u32 *data);
+
+/* Read a vector */
+int intel_scu_ipc_readv(u16 *addr, u8 *data, int len);
+
+/* Write single register */
+int intel_scu_ipc_iowrite8(u16 addr, u8 data);
+
+/* Write two sequential registers */
+int intel_scu_ipc_iowrite16(u16 addr, u16 data);
+
+/* Write four sequential registers */
+int intel_scu_ipc_iowrite32(u16 addr, u32 data);
+
+/* Write a vector */
+int intel_scu_ipc_writev(u16 *addr, u8 *data, int len);
+
+/* Update single register based on the mask */
+int intel_scu_ipc_update_register(u16 addr, u8 data, u8 mask);
+
+/*
+ * Indirect register read
+ * Can be used when SCCB(System Controller Configuration Block) register
+ * HRIM(Honor Restricted IPC Messages) is set (bit 23)
+ */
+int intel_scu_ipc_register_read(u32 addr, u32 *data);
+
+/*
+ * Indirect register write
+ * Can be used when SCCB(System Controller Configuration Block) register
+ * HRIM(Honor Restricted IPC Messages) is set (bit 23)
+ */
+int intel_scu_ipc_register_write(u32 addr, u32 data);
+
+/* Issue commands to the SCU with or without data */
+int intel_scu_ipc_simple_command(int cmd, int sub);
+int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,
+                                                       u32 *out, int outlen);
+/* I2C control api */
+int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data);
+
+/* Update FW version */
+int intel_scu_ipc_fw_update(u8 *buffer, u32 length);
+
+#endif
index f46b79f6c16c873a337013fa8a18e18f85c4ee22..ff90055c7f0bfe9b38f901496877c4c6c31008c1 100644 (file)
@@ -21,6 +21,7 @@
 #define __KVM_HAVE_PIT_STATE2
 #define __KVM_HAVE_XEN_HVM
 #define __KVM_HAVE_VCPU_EVENTS
+#define __KVM_HAVE_DEBUGREGS
 
 /* Architectural interrupt line count. */
 #define KVM_NR_INTERRUPTS 256
@@ -257,6 +258,11 @@ struct kvm_reinject_control {
 /* When set in flags, include corresponding fields on KVM_SET_VCPU_EVENTS */
 #define KVM_VCPUEVENT_VALID_NMI_PENDING        0x00000001
 #define KVM_VCPUEVENT_VALID_SIPI_VECTOR        0x00000002
+#define KVM_VCPUEVENT_VALID_SHADOW     0x00000004
+
+/* Interrupt shadow states */
+#define KVM_X86_SHADOW_INT_MOV_SS      0x01
+#define KVM_X86_SHADOW_INT_STI         0x02
 
 /* for KVM_GET/SET_VCPU_EVENTS */
 struct kvm_vcpu_events {
@@ -271,7 +277,7 @@ struct kvm_vcpu_events {
                __u8 injected;
                __u8 nr;
                __u8 soft;
-               __u8 pad;
+               __u8 shadow;
        } interrupt;
        struct {
                __u8 injected;
@@ -284,4 +290,13 @@ struct kvm_vcpu_events {
        __u32 reserved[10];
 };
 
+/* for KVM_GET/SET_DEBUGREGS */
+struct kvm_debugregs {
+       __u64 db[4];
+       __u64 dr6;
+       __u64 dr7;
+       __u64 flags;
+       __u64 reserved[9];
+};
+
 #endif /* _ASM_X86_KVM_H */
index 7a6f54fa13ba426d4cca30862cc38e5e8e4a53cc..0b2729bf207055ce1621bd8a92872f5b9909694b 100644 (file)
@@ -11,6 +11,8 @@
 #ifndef _ASM_X86_KVM_X86_EMULATE_H
 #define _ASM_X86_KVM_X86_EMULATE_H
 
+#include <asm/desc_defs.h>
+
 struct x86_emulate_ctxt;
 
 /*
@@ -62,6 +64,15 @@ struct x86_emulate_ops {
        int (*read_std)(unsigned long addr, void *val,
                        unsigned int bytes, struct kvm_vcpu *vcpu, u32 *error);
 
+       /*
+        * write_std: Write bytes of standard (non-emulated/special) memory.
+        *            Used for descriptor writing.
+        *  @addr:  [IN ] Linear address to which to write.
+        *  @val:   [OUT] Value write to memory, zero-extended to 'u_long'.
+        *  @bytes: [IN ] Number of bytes to write to memory.
+        */
+       int (*write_std)(unsigned long addr, void *val,
+                        unsigned int bytes, struct kvm_vcpu *vcpu, u32 *error);
        /*
         * fetch: Read bytes of standard (non-emulated/special) memory.
         *        Used for instruction fetch.
@@ -109,6 +120,23 @@ struct x86_emulate_ops {
                                unsigned int bytes,
                                struct kvm_vcpu *vcpu);
 
+       int (*pio_in_emulated)(int size, unsigned short port, void *val,
+                              unsigned int count, struct kvm_vcpu *vcpu);
+
+       int (*pio_out_emulated)(int size, unsigned short port, const void *val,
+                               unsigned int count, struct kvm_vcpu *vcpu);
+
+       bool (*get_cached_descriptor)(struct desc_struct *desc,
+                                     int seg, struct kvm_vcpu *vcpu);
+       void (*set_cached_descriptor)(struct desc_struct *desc,
+                                     int seg, struct kvm_vcpu *vcpu);
+       u16 (*get_segment_selector)(int seg, struct kvm_vcpu *vcpu);
+       void (*set_segment_selector)(u16 sel, int seg, struct kvm_vcpu *vcpu);
+       void (*get_gdt)(struct desc_ptr *dt, struct kvm_vcpu *vcpu);
+       ulong (*get_cr)(int cr, struct kvm_vcpu *vcpu);
+       void (*set_cr)(int cr, ulong val, struct kvm_vcpu *vcpu);
+       int (*cpl)(struct kvm_vcpu *vcpu);
+       void (*set_rflags)(struct kvm_vcpu *vcpu, unsigned long rflags);
 };
 
 /* Type, address-of, and value of an instruction's operand. */
@@ -124,6 +152,12 @@ struct fetch_cache {
        unsigned long end;
 };
 
+struct read_cache {
+       u8 data[1024];
+       unsigned long pos;
+       unsigned long end;
+};
+
 struct decode_cache {
        u8 twobyte;
        u8 b;
@@ -139,7 +173,7 @@ struct decode_cache {
        u8 seg_override;
        unsigned int d;
        unsigned long regs[NR_VCPU_REGS];
-       unsigned long eip, eip_orig;
+       unsigned long eip;
        /* modrm */
        u8 modrm;
        u8 modrm_mod;
@@ -151,16 +185,15 @@ struct decode_cache {
        void *modrm_ptr;
        unsigned long modrm_val;
        struct fetch_cache fetch;
+       struct read_cache io_read;
 };
 
-#define X86_SHADOW_INT_MOV_SS  1
-#define X86_SHADOW_INT_STI     2
-
 struct x86_emulate_ctxt {
        /* Register state before/after emulation. */
        struct kvm_vcpu *vcpu;
 
        unsigned long eflags;
+       unsigned long eip; /* eip before instruction emulation */
        /* Emulated execution mode, represented by an X86EMUL_MODE value. */
        int mode;
        u32 cs_base;
@@ -168,6 +201,7 @@ struct x86_emulate_ctxt {
        /* interruptibility state, as a result of execution of STI or MOV SS */
        int interruptibility;
 
+       bool restart; /* restart string instruction after writeback */
        /* decode cache */
        struct decode_cache decode;
 };
@@ -194,5 +228,9 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt,
                    struct x86_emulate_ops *ops);
 int x86_emulate_insn(struct x86_emulate_ctxt *ctxt,
                     struct x86_emulate_ops *ops);
+int emulator_task_switch(struct x86_emulate_ctxt *ctxt,
+                        struct x86_emulate_ops *ops,
+                        u16 tss_selector, int reason,
+                        bool has_error_code, u32 error_code);
 
 #endif /* _ASM_X86_KVM_X86_EMULATE_H */
index 06d9e79ca37dccad56acb3050ee837c8156ff414..76f5483cffecb884b1054b90312bec176253d3b7 100644 (file)
@@ -171,15 +171,15 @@ struct kvm_pte_chain {
 union kvm_mmu_page_role {
        unsigned word;
        struct {
-               unsigned glevels:4;
                unsigned level:4;
+               unsigned cr4_pae:1;
                unsigned quadrant:2;
                unsigned pad_for_nice_hex_output:6;
                unsigned direct:1;
                unsigned access:3;
                unsigned invalid:1;
-               unsigned cr4_pge:1;
                unsigned nxe:1;
+               unsigned cr0_wp:1;
        };
 };
 
@@ -187,8 +187,6 @@ struct kvm_mmu_page {
        struct list_head link;
        struct hlist_node hash_link;
 
-       struct list_head oos_link;
-
        /*
         * The following two entries are used to key the shadow page in the
         * hash table.
@@ -204,9 +202,9 @@ struct kvm_mmu_page {
         * in this shadow page.
         */
        DECLARE_BITMAP(slot_bitmap, KVM_MEMORY_SLOTS + KVM_PRIVATE_MEM_SLOTS);
-       int multimapped;         /* More than one parent_pte? */
-       int root_count;          /* Currently serving as active root */
+       bool multimapped;         /* More than one parent_pte? */
        bool unsync;
+       int root_count;          /* Currently serving as active root */
        unsigned int unsync_children;
        union {
                u64 *parent_pte;               /* !multimapped */
@@ -224,14 +222,9 @@ struct kvm_pv_mmu_op_buffer {
 
 struct kvm_pio_request {
        unsigned long count;
-       int cur_count;
-       gva_t guest_gva;
        int in;
        int port;
        int size;
-       int string;
-       int down;
-       int rep;
 };
 
 /*
@@ -320,6 +313,7 @@ struct kvm_vcpu_arch {
        struct kvm_queued_exception {
                bool pending;
                bool has_error_code;
+               bool reinject;
                u8 nr;
                u32 error_code;
        } exception;
@@ -362,8 +356,8 @@ struct kvm_vcpu_arch {
        u64 *mce_banks;
 
        /* used for guest single stepping over the given code position */
-       u16 singlestep_cs;
        unsigned long singlestep_rip;
+
        /* fields used by HYPER-V emulation */
        u64 hv_vapic;
 };
@@ -389,6 +383,7 @@ struct kvm_arch {
        unsigned int n_free_mmu_pages;
        unsigned int n_requested_mmu_pages;
        unsigned int n_alloc_mmu_pages;
+       atomic_t invlpg_counter;
        struct hlist_head mmu_page_hash[KVM_NUM_MMU_PAGES];
        /*
         * Hash table of struct kvm_mmu_page.
@@ -461,11 +456,6 @@ struct kvm_vcpu_stat {
        u32 nmi_injections;
 };
 
-struct descriptor_table {
-       u16 limit;
-       unsigned long base;
-} __attribute__((packed));
-
 struct kvm_x86_ops {
        int (*cpu_has_kvm_support)(void);          /* __init */
        int (*disabled_by_bios)(void);             /* __init */
@@ -503,12 +493,11 @@ struct kvm_x86_ops {
        void (*set_cr3)(struct kvm_vcpu *vcpu, unsigned long cr3);
        void (*set_cr4)(struct kvm_vcpu *vcpu, unsigned long cr4);
        void (*set_efer)(struct kvm_vcpu *vcpu, u64 efer);
-       void (*get_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
-       void (*set_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
-       void (*get_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
-       void (*set_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
-       int (*get_dr)(struct kvm_vcpu *vcpu, int dr, unsigned long *dest);
-       int (*set_dr)(struct kvm_vcpu *vcpu, int dr, unsigned long value);
+       void (*get_idt)(struct kvm_vcpu *vcpu, struct desc_ptr *dt);
+       void (*set_idt)(struct kvm_vcpu *vcpu, struct desc_ptr *dt);
+       void (*get_gdt)(struct kvm_vcpu *vcpu, struct desc_ptr *dt);
+       void (*set_gdt)(struct kvm_vcpu *vcpu, struct desc_ptr *dt);
+       void (*set_dr7)(struct kvm_vcpu *vcpu, unsigned long value);
        void (*cache_reg)(struct kvm_vcpu *vcpu, enum kvm_reg reg);
        unsigned long (*get_rflags)(struct kvm_vcpu *vcpu);
        void (*set_rflags)(struct kvm_vcpu *vcpu, unsigned long rflags);
@@ -527,7 +516,8 @@ struct kvm_x86_ops {
        void (*set_irq)(struct kvm_vcpu *vcpu);
        void (*set_nmi)(struct kvm_vcpu *vcpu);
        void (*queue_exception)(struct kvm_vcpu *vcpu, unsigned nr,
-                               bool has_error_code, u32 error_code);
+                               bool has_error_code, u32 error_code,
+                               bool reinject);
        int (*interrupt_allowed)(struct kvm_vcpu *vcpu);
        int (*nmi_allowed)(struct kvm_vcpu *vcpu);
        bool (*get_nmi_mask)(struct kvm_vcpu *vcpu);
@@ -541,6 +531,8 @@ struct kvm_x86_ops {
        int (*get_lpage_level)(void);
        bool (*rdtscp_supported)(void);
 
+       void (*set_supported_cpuid)(u32 func, struct kvm_cpuid_entry2 *entry);
+
        const struct trace_print_flags *exit_reasons_str;
 };
 
@@ -587,23 +579,14 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
 void kvm_report_emulation_failure(struct kvm_vcpu *cvpu, const char *context);
 void realmode_lgdt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
 void realmode_lidt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
-void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
-                  unsigned long *rflags);
 
-unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr);
-void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long value,
-                    unsigned long *rflags);
 void kvm_enable_efer_bits(u64);
 int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *data);
 int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
 
 struct x86_emulate_ctxt;
 
-int kvm_emulate_pio(struct kvm_vcpu *vcpu, int in,
-                    int size, unsigned port);
-int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, int in,
-                          int size, unsigned long count, int down,
-                           gva_t address, int rep, unsigned port);
+int kvm_fast_pio_out(struct kvm_vcpu *vcpu, int size, unsigned short port);
 void kvm_emulate_cpuid(struct kvm_vcpu *vcpu);
 int kvm_emulate_halt(struct kvm_vcpu *vcpu);
 int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address);
@@ -616,12 +599,15 @@ int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr,
 void kvm_get_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg);
 int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, int seg);
 
-int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason);
+int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason,
+                   bool has_error_code, u32 error_code);
 
 void kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
 void kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3);
 void kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4);
 void kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8);
+int kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val);
+int kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val);
 unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu);
 void kvm_lmsw(struct kvm_vcpu *vcpu, unsigned long msw);
 void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l);
@@ -634,6 +620,8 @@ void kvm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags);
 
 void kvm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr);
 void kvm_queue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code);
+void kvm_requeue_exception(struct kvm_vcpu *vcpu, unsigned nr);
+void kvm_requeue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code);
 void kvm_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long cr2,
                           u32 error_code);
 bool kvm_require_cpl(struct kvm_vcpu *vcpu, int required_cpl);
@@ -649,8 +637,6 @@ int emulator_write_emulated(unsigned long addr,
                            unsigned int bytes,
                            struct kvm_vcpu *vcpu);
 
-unsigned long segment_base(u16 selector);
-
 void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu);
 void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
                       const u8 *new, int bytes,
@@ -675,7 +661,6 @@ void kvm_mmu_invlpg(struct kvm_vcpu *vcpu, gva_t gva);
 void kvm_enable_tdp(void);
 void kvm_disable_tdp(void);
 
-int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3);
 int complete_pio(struct kvm_vcpu *vcpu);
 bool kvm_check_iopl(struct kvm_vcpu *vcpu);
 
@@ -724,23 +709,6 @@ static inline void kvm_load_ldt(u16 sel)
        asm("lldt %0" : : "rm"(sel));
 }
 
-static inline void kvm_get_idt(struct descriptor_table *table)
-{
-       asm("sidt %0" : "=m"(*table));
-}
-
-static inline void kvm_get_gdt(struct descriptor_table *table)
-{
-       asm("sgdt %0" : "=m"(*table));
-}
-
-static inline unsigned long kvm_read_tr_base(void)
-{
-       u16 tr;
-       asm("str %0" : "=g"(tr));
-       return segment_base(tr);
-}
-
 #ifdef CONFIG_X86_64
 static inline unsigned long read_msr(unsigned long msr)
 {
@@ -826,4 +794,6 @@ int kvm_cpu_get_interrupt(struct kvm_vcpu *v);
 void kvm_define_shared_msr(unsigned index, u32 msr);
 void kvm_set_shared_msr(unsigned index, u64 val, u64 mask);
 
+bool kvm_is_linear_rip(struct kvm_vcpu *vcpu, unsigned long linear_rip);
+
 #endif /* _ASM_X86_KVM_HOST_H */
index ffae1420e7d76d0b549360cec1b3b93071bc867a..05eba5e9a8e8e59372ddc615e630a8a21f155f37 100644 (file)
 #define KVM_FEATURE_CLOCKSOURCE                0
 #define KVM_FEATURE_NOP_IO_DELAY       1
 #define KVM_FEATURE_MMU_OP             2
+/* This indicates that the new set of kvmclock msrs
+ * are available. The use of 0x11 and 0x12 is deprecated
+ */
+#define KVM_FEATURE_CLOCKSOURCE2        3
+
+/* The last 8 bits are used to indicate how to interpret the flags field
+ * in pvclock structure. If no bits are set, all flags are ignored.
+ */
+#define KVM_FEATURE_CLOCKSOURCE_STABLE_BIT     24
 
 #define MSR_KVM_WALL_CLOCK  0x11
 #define MSR_KVM_SYSTEM_TIME 0x12
 
+/* Custom MSRs falls in the range 0x4b564d00-0x4b564dff */
+#define MSR_KVM_WALL_CLOCK_NEW  0x4b564d00
+#define MSR_KVM_SYSTEM_TIME_NEW 0x4b564d01
+
 #define KVM_MAX_MMU_OP_BATCH           32
 
 /* Operations for KVM_HC_MMU_OP */
index 6c3fdd631ed3df7652ed0ad261377006297b7f5f..f32a4301c4d4559157e1ac72f79a239025ccc1e0 100644 (file)
@@ -225,5 +225,13 @@ extern void mcheck_intel_therm_init(void);
 static inline void mcheck_intel_therm_init(void) { }
 #endif
 
+/*
+ * Used by APEI to report memory error via /dev/mcelog
+ */
+
+struct cper_sec_mem_err;
+extern void apei_mce_report_mem_error(int corrected,
+                                     struct cper_sec_mem_err *mem_err);
+
 #endif /* __KERNEL__ */
 #endif /* _ASM_X86_MCE_H */
index bc473acfa7f97ea52e9800a4afc038d543e84ce2..b49d8ca228f6ffe743e19d0423c676e62b1d29df 100644 (file)
 #define MSR_IA32_EBL_CR_POWERON                0x0000002a
 #define MSR_IA32_FEATURE_CONTROL        0x0000003a
 
-#define FEATURE_CONTROL_LOCKED         (1<<0)
-#define FEATURE_CONTROL_VMXON_ENABLED  (1<<2)
+#define FEATURE_CONTROL_LOCKED                         (1<<0)
+#define FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX       (1<<1)
+#define FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX      (1<<2)
 
 #define MSR_IA32_APICBASE              0x0000001b
 #define MSR_IA32_APICBASE_BSP          (1<<8)
 
 #define MSR_IA32_MISC_ENABLE           0x000001a0
 
+#define MSR_IA32_TEMPERATURE_TARGET    0x000001a2
+
 /* MISC_ENABLE bits: architectural */
 #define MSR_IA32_MISC_ENABLE_FAST_STRING       (1ULL << 0)
 #define MSR_IA32_MISC_ENABLE_TCC               (1ULL << 1)
index 1a0422348d6d3f5aae451824c14f65fc0631bfc2..8d8797eae5d704e238d764b4b4d1e7254c2ecc62 100644 (file)
@@ -83,7 +83,7 @@ struct irq_routing_table {
 
 extern unsigned int pcibios_irq_mask;
 
-extern spinlock_t pci_config_lock;
+extern raw_spinlock_t pci_config_lock;
 
 extern int (*pcibios_enable_irq)(struct pci_dev *dev);
 extern void (*pcibios_disable_irq)(struct pci_dev *dev);
index b05400a542ff6d60ea4e82bea72d05d416c0efc6..64a8ebff06fcef47dc36301e038ea2d63acad27b 100644 (file)
@@ -89,7 +89,8 @@
        P4_CCCR_ENABLE)
 
 /* HT mask */
-#define P4_CCCR_MASK_HT        (P4_CCCR_MASK | P4_CCCR_THREAD_ANY)
+#define P4_CCCR_MASK_HT                                \
+       (P4_CCCR_MASK | P4_CCCR_OVF_PMI_T1 | P4_CCCR_THREAD_ANY)
 
 #define P4_GEN_ESCR_EMASK(class, name, bit)    \
        class##__##name = ((1 << bit) << P4_ESCR_EVENTMASK_SHIFT)
index 6d93508f262602eba40417dda7a0357d1ff47cb6..35f2d1948adad8bebad28a5dc06b328454dc6ace 100644 (file)
@@ -29,7 +29,8 @@ struct pvclock_vcpu_time_info {
        u64   system_time;
        u32   tsc_to_system_mul;
        s8    tsc_shift;
-       u8    pad[3];
+       u8    flags;
+       u8    pad[2];
 } __attribute__((__packed__)); /* 32 bytes */
 
 struct pvclock_wall_clock {
@@ -38,5 +39,6 @@ struct pvclock_wall_clock {
        u32   nsec;
 } __attribute__((__packed__));
 
+#define PVCLOCK_TSC_STABLE_BIT (1 << 0)
 #endif /* __ASSEMBLY__ */
 #endif /* _ASM_X86_PVCLOCK_ABI_H */
index 53235fd5f8ce67cf4f085c092e611fa19fa04684..cd02f324aa6b39c8ba1d149b7646f356043fa77c 100644 (file)
@@ -6,6 +6,7 @@
 
 /* some helper functions for xen and kvm pv clock sources */
 cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src);
+void pvclock_set_flags(u8 flags);
 unsigned long pvclock_tsc_khz(struct pvclock_vcpu_time_info *src);
 void pvclock_read_wallclock(struct pvclock_wall_clock *wall,
                            struct pvclock_vcpu_time_info *vcpu,
index 75af592677ec0fd76af2101309eff68eedf1fb23..fb0b1874396f5fd172c1c61e0adae1da37be2e46 100644 (file)
@@ -1,8 +1,9 @@
 #ifndef _ASM_X86_SCATTERLIST_H
 #define _ASM_X86_SCATTERLIST_H
 
-#define ISA_DMA_THRESHOLD (0x00ffffff)
-
 #include <asm-generic/scatterlist.h>
 
+#define ISA_DMA_THRESHOLD (0x00ffffff)
+#define ARCH_HAS_SG_CHAIN
+
 #endif /* _ASM_X86_SCATTERLIST_H */
index 38638cd2fa4c87997dec931e0bcdd4f49f6fb28a..0e831059ac5ae83de16a740e087b105f376ae3cd 100644 (file)
@@ -81,7 +81,9 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
        u32 event_inj_err;
        u64 nested_cr3;
        u64 lbr_ctl;
-       u8 reserved_5[832];
+       u64 reserved_5;
+       u64 next_rip;
+       u8 reserved_6[816];
 };
 
 
@@ -115,6 +117,10 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
 #define SVM_IOIO_SIZE_MASK (7 << SVM_IOIO_SIZE_SHIFT)
 #define SVM_IOIO_ASIZE_MASK (7 << SVM_IOIO_ASIZE_SHIFT)
 
+#define SVM_VM_CR_VALID_MASK   0x001fULL
+#define SVM_VM_CR_SVM_LOCK_MASK 0x0008ULL
+#define SVM_VM_CR_SVM_DIS_MASK  0x0010ULL
+
 struct __attribute__ ((__packed__)) vmcb_seg {
        u16 selector;
        u16 attrib;
@@ -238,6 +244,7 @@ struct __attribute__ ((__packed__)) vmcb {
 
 #define SVM_EXITINFOSHIFT_TS_REASON_IRET 36
 #define SVM_EXITINFOSHIFT_TS_REASON_JMP 38
+#define SVM_EXITINFOSHIFT_TS_HAS_ERROR_CODE 44
 
 #define        SVM_EXIT_READ_CR0       0x000
 #define        SVM_EXIT_READ_CR3       0x003
index 62ba9400cc43302ba943ac44dcd6659bc4ea3ffd..f0b6e5dbc5a03b97f821cb71a6d4b95c2bc51b77 100644 (file)
@@ -239,8 +239,8 @@ static inline struct thread_info *current_thread_info(void)
 #define TS_USEDFPU             0x0001  /* FPU was used by this task
                                           this quantum (SMP) */
 #define TS_COMPAT              0x0002  /* 32bit syscall active (64BIT)*/
-#define TS_POLLING             0x0004  /* true if in idle loop
-                                          and not sleeping */
+#define TS_POLLING             0x0004  /* idle task polling need_resched,
+                                          skip sending interrupt */
 #define TS_RESTORE_SIGMASK     0x0008  /* restore signal mask in do_signal() */
 
 #define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING)
index c5087d7965871c5d9ec8e93d96c7fc4a8c5b3469..21899cc31e52110242dc6f041c08048701ecee32 100644 (file)
 extern int cpu_to_node_map[];
 
 /* Returns the number of the node containing CPU 'cpu' */
-static inline int cpu_to_node(int cpu)
+static inline int __cpu_to_node(int cpu)
 {
        return cpu_to_node_map[cpu];
 }
-#define early_cpu_to_node(cpu) cpu_to_node(cpu)
+#define early_cpu_to_node __cpu_to_node
+#define cpu_to_node __cpu_to_node
 
 #else /* CONFIG_X86_64 */
 
 /* Mappings between logical cpu number and node number */
 DECLARE_EARLY_PER_CPU(int, x86_cpu_to_node_map);
 
-/* Returns the number of the current Node. */
-DECLARE_PER_CPU(int, node_number);
-#define numa_node_id()         percpu_read(node_number)
-
 #ifdef CONFIG_DEBUG_PER_CPU_MAPS
-extern int cpu_to_node(int cpu);
+/*
+ * override generic percpu implementation of cpu_to_node
+ */
+extern int __cpu_to_node(int cpu);
+#define cpu_to_node __cpu_to_node
+
 extern int early_cpu_to_node(int cpu);
 
 #else  /* !CONFIG_DEBUG_PER_CPU_MAPS */
 
-/* Returns the number of the node containing CPU 'cpu' */
-static inline int cpu_to_node(int cpu)
-{
-       return per_cpu(x86_cpu_to_node_map, cpu);
-}
-
 /* Same function but used if called before per_cpu areas are setup */
 static inline int early_cpu_to_node(int cpu)
 {
@@ -170,6 +166,10 @@ static inline int numa_node_id(void)
 {
        return 0;
 }
+/*
+ * indicate override:
+ */
+#define numa_node_id numa_node_id
 
 static inline int early_cpu_to_node(int cpu)
 {
index fb9a080740ecf48970e9648c85caac34bfaf09c6..9e6779f7cf2d12461ddbb2164f101ae8a3c15674 100644 (file)
@@ -25,6 +25,8 @@
  *
  */
 
+#include <linux/types.h>
+
 /*
  * Definitions of Primary Processor-Based VM-Execution Controls.
  */
@@ -120,6 +122,8 @@ enum vmcs_field {
        GUEST_IA32_DEBUGCTL_HIGH        = 0x00002803,
        GUEST_IA32_PAT                  = 0x00002804,
        GUEST_IA32_PAT_HIGH             = 0x00002805,
+       GUEST_IA32_EFER                 = 0x00002806,
+       GUEST_IA32_EFER_HIGH            = 0x00002807,
        GUEST_PDPTR0                    = 0x0000280a,
        GUEST_PDPTR0_HIGH               = 0x0000280b,
        GUEST_PDPTR1                    = 0x0000280c,
@@ -130,6 +134,8 @@ enum vmcs_field {
        GUEST_PDPTR3_HIGH               = 0x00002811,
        HOST_IA32_PAT                   = 0x00002c00,
        HOST_IA32_PAT_HIGH              = 0x00002c01,
+       HOST_IA32_EFER                  = 0x00002c02,
+       HOST_IA32_EFER_HIGH             = 0x00002c03,
        PIN_BASED_VM_EXEC_CONTROL       = 0x00004000,
        CPU_BASED_VM_EXEC_CONTROL       = 0x00004002,
        EXCEPTION_BITMAP                = 0x00004004,
@@ -394,6 +400,10 @@ enum vmcs_field {
 #define ASM_VMX_INVEPT           ".byte 0x66, 0x0f, 0x38, 0x80, 0x08"
 #define ASM_VMX_INVVPID                  ".byte 0x66, 0x0f, 0x38, 0x81, 0x08"
 
-
+struct vmx_msr_entry {
+       u32 index;
+       u32 reserved;
+       u64 value;
+} __aligned(16);
 
 #endif
index 488be461a3805104746e5a38a819f2691bb97c09..60cc4058ed5feb9c05dcf7917593c099d21df4df 100644 (file)
@@ -63,7 +63,6 @@ EXPORT_SYMBOL(acpi_disabled);
 int acpi_noirq;                                /* skip ACPI IRQ initialization */
 int acpi_pci_disabled;         /* skip ACPI PCI scan and IRQ initialization */
 EXPORT_SYMBOL(acpi_pci_disabled);
-int acpi_ht __initdata = 1;    /* enable HT */
 
 int acpi_lapic;
 int acpi_ioapic;
@@ -1501,9 +1500,8 @@ void __init acpi_boot_table_init(void)
 
        /*
         * If acpi_disabled, bail out
-        * One exception: acpi=ht continues far enough to enumerate LAPICs
         */
-       if (acpi_disabled && !acpi_ht)
+       if (acpi_disabled)
                return; 
 
        /*
@@ -1534,9 +1532,8 @@ int __init early_acpi_boot_init(void)
 {
        /*
         * If acpi_disabled, bail out
-        * One exception: acpi=ht continues far enough to enumerate LAPICs
         */
-       if (acpi_disabled && !acpi_ht)
+       if (acpi_disabled)
                return 1;
 
        /*
@@ -1554,9 +1551,8 @@ int __init acpi_boot_init(void)
 
        /*
         * If acpi_disabled, bail out
-        * One exception: acpi=ht continues far enough to enumerate LAPICs
         */
-       if (acpi_disabled && !acpi_ht)
+       if (acpi_disabled)
                return 1;
 
        acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf);
@@ -1591,21 +1587,12 @@ static int __init parse_acpi(char *arg)
        /* acpi=force to over-ride black-list */
        else if (strcmp(arg, "force") == 0) {
                acpi_force = 1;
-               acpi_ht = 1;
                acpi_disabled = 0;
        }
        /* acpi=strict disables out-of-spec workarounds */
        else if (strcmp(arg, "strict") == 0) {
                acpi_strict = 1;
        }
-       /* Limit ACPI just to boot-time to enable HT */
-       else if (strcmp(arg, "ht") == 0) {
-               if (!acpi_force) {
-                       printk(KERN_WARNING "acpi=ht will be removed in Linux-2.6.35\n");
-                       disable_acpi();
-               }
-               acpi_ht = 1;
-       }
        /* acpi=rsdt use RSDT instead of XSDT */
        else if (strcmp(arg, "rsdt") == 0) {
                acpi_rsdt_forced = 1;
index f9961034e55793b1619edac03f2e34ed57ef7798..82e508677b91116ec8428e434ae164a8390084bf 100644 (file)
@@ -162,8 +162,6 @@ static int __init acpi_sleep_setup(char *str)
 #endif
                if (strncmp(str, "old_ordering", 12) == 0)
                        acpi_old_suspend_ordering();
-               if (strncmp(str, "sci_force_enable", 16) == 0)
-                       acpi_set_sci_en_on_resume();
                str = strchr(str, ',');
                if (str != NULL)
                        str += strspn(str, ", \t");
index e5a4a1e016180c0a5aea127d550ae2389600de73..c02cc692985c13b902f1a9c914535170f9670d01 100644 (file)
@@ -51,6 +51,7 @@
 #include <asm/smp.h>
 #include <asm/mce.h>
 #include <asm/kvm_para.h>
+#include <asm/tsc.h>
 
 unsigned int num_processors;
 
@@ -1151,8 +1152,13 @@ static void __cpuinit lapic_setup_esr(void)
  */
 void __cpuinit setup_local_APIC(void)
 {
-       unsigned int value;
-       int i, j;
+       unsigned int value, queued;
+       int i, j, acked = 0;
+       unsigned long long tsc = 0, ntsc;
+       long long max_loops = cpu_khz;
+
+       if (cpu_has_tsc)
+               rdtscll(tsc);
 
        if (disable_apic) {
                arch_disable_smp_support();
@@ -1204,13 +1210,32 @@ void __cpuinit setup_local_APIC(void)
         * the interrupt. Hence a vector might get locked. It was noticed
         * for timer irq (vector 0x31). Issue an extra EOI to clear ISR.
         */
-       for (i = APIC_ISR_NR - 1; i >= 0; i--) {
-               value = apic_read(APIC_ISR + i*0x10);
-               for (j = 31; j >= 0; j--) {
-                       if (value & (1<<j))
-                               ack_APIC_irq();
+       do {
+               queued = 0;
+               for (i = APIC_ISR_NR - 1; i >= 0; i--)
+                       queued |= apic_read(APIC_IRR + i*0x10);
+
+               for (i = APIC_ISR_NR - 1; i >= 0; i--) {
+                       value = apic_read(APIC_ISR + i*0x10);
+                       for (j = 31; j >= 0; j--) {
+                               if (value & (1<<j)) {
+                                       ack_APIC_irq();
+                                       acked++;
+                               }
+                       }
                }
-       }
+               if (acked > 256) {
+                       printk(KERN_ERR "LAPIC pending interrupts after %d EOI\n",
+                              acked);
+                       break;
+               }
+               if (cpu_has_tsc) {
+                       rdtscll(ntsc);
+                       max_loops = (cpu_khz << 10) - (ntsc - tsc);
+               } else
+                       max_loops--;
+       } while (queued && max_loops > 0);
+       WARN_ON(max_loops <= 0);
 
        /*
         * Now that we are all set up, enable the APIC
index cc83a002786e0bb16163afd17ffba909f88abe14..68e4a6f2211e2e8ea52015e5c4a8861f4f5269d9 100644 (file)
@@ -1121,9 +1121,9 @@ void __cpuinit cpu_init(void)
        oist = &per_cpu(orig_ist, cpu);
 
 #ifdef CONFIG_NUMA
-       if (cpu != 0 && percpu_read(node_number) == 0 &&
-           cpu_to_node(cpu) != NUMA_NO_NODE)
-               percpu_write(node_number, cpu_to_node(cpu));
+       if (cpu != 0 && percpu_read(numa_node) == 0 &&
+           early_cpu_to_node(cpu) != NUMA_NO_NODE)
+               set_numa_node(early_cpu_to_node(cpu));
 #endif
 
        me = current;
index 6f3dc8fbbfdc77fe49a070bffcc685b3af102ce8..7ec2123838e6f70f5af02e6e5804143bcc29090c 100644 (file)
@@ -1497,8 +1497,8 @@ static struct cpufreq_driver cpufreq_amd64_driver = {
  * simply keep the boost-disable flag in sync with the current global
  * state.
  */
-static int __cpuinit cpb_notify(struct notifier_block *nb, unsigned long action,
-                               void *hcpu)
+static int cpb_notify(struct notifier_block *nb, unsigned long action,
+                     void *hcpu)
 {
        unsigned cpu = (long)hcpu;
        u32 lo, hi;
@@ -1528,7 +1528,7 @@ static int __cpuinit cpb_notify(struct notifier_block *nb, unsigned long action,
        return NOTIFY_OK;
 }
 
-static struct notifier_block __cpuinitdata cpb_nb = {
+static struct notifier_block cpb_nb = {
        .notifier_call          = cpb_notify,
 };
 
index 4ac6d48fe11bc66eb2d8283e83438b0947e5ae92..bb34b03af25252ddb2298e80121f9955a6ae6192 100644 (file)
@@ -7,3 +7,5 @@ obj-$(CONFIG_X86_MCE_THRESHOLD) += threshold.o
 obj-$(CONFIG_X86_MCE_INJECT)   += mce-inject.o
 
 obj-$(CONFIG_X86_THERMAL_VECTOR) += therm_throt.o
+
+obj-$(CONFIG_ACPI_APEI)                += mce-apei.o
diff --git a/arch/x86/kernel/cpu/mcheck/mce-apei.c b/arch/x86/kernel/cpu/mcheck/mce-apei.c
new file mode 100644 (file)
index 0000000..745b54f
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Bridge between MCE and APEI
+ *
+ * On some machine, corrected memory errors are reported via APEI
+ * generic hardware error source (GHES) instead of corrected Machine
+ * Check. These corrected memory errors can be reported to user space
+ * through /dev/mcelog via faking a corrected Machine Check, so that
+ * the error memory page can be offlined by /sbin/mcelog if the error
+ * count for one page is beyond the threshold.
+ *
+ * For fatal MCE, save MCE record into persistent storage via ERST, so
+ * that the MCE record can be logged after reboot via ERST.
+ *
+ * Copyright 2010 Intel Corp.
+ *   Author: Huang Ying <ying.huang@intel.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/acpi.h>
+#include <linux/cper.h>
+#include <acpi/apei.h>
+#include <asm/mce.h>
+
+#include "mce-internal.h"
+
+void apei_mce_report_mem_error(int corrected, struct cper_sec_mem_err *mem_err)
+{
+       struct mce m;
+
+       /* Only corrected MC is reported */
+       if (!corrected)
+               return;
+
+       mce_setup(&m);
+       m.bank = 1;
+       /* Fake a memory read corrected error with unknown channel */
+       m.status = MCI_STATUS_VAL | MCI_STATUS_EN | MCI_STATUS_ADDRV | 0x9f;
+       m.addr = mem_err->physical_addr;
+       mce_log(&m);
+       mce_notify_irq();
+}
+EXPORT_SYMBOL_GPL(apei_mce_report_mem_error);
+
+#define CPER_CREATOR_MCE                                               \
+       UUID_LE(0x75a574e3, 0x5052, 0x4b29, 0x8a, 0x8e, 0xbe, 0x2c,     \
+               0x64, 0x90, 0xb8, 0x9d)
+#define CPER_SECTION_TYPE_MCE                                          \
+       UUID_LE(0xfe08ffbe, 0x95e4, 0x4be7, 0xbc, 0x73, 0x40, 0x96,     \
+               0x04, 0x4a, 0x38, 0xfc)
+
+/*
+ * CPER specification (in UEFI specification 2.3 appendix N) requires
+ * byte-packed.
+ */
+struct cper_mce_record {
+       struct cper_record_header hdr;
+       struct cper_section_descriptor sec_hdr;
+       struct mce mce;
+} __packed;
+
+int apei_write_mce(struct mce *m)
+{
+       struct cper_mce_record rcd;
+
+       memset(&rcd, 0, sizeof(rcd));
+       memcpy(rcd.hdr.signature, CPER_SIG_RECORD, CPER_SIG_SIZE);
+       rcd.hdr.revision = CPER_RECORD_REV;
+       rcd.hdr.signature_end = CPER_SIG_END;
+       rcd.hdr.section_count = 1;
+       rcd.hdr.error_severity = CPER_SER_FATAL;
+       /* timestamp, platform_id, partition_id are all invalid */
+       rcd.hdr.validation_bits = 0;
+       rcd.hdr.record_length = sizeof(rcd);
+       rcd.hdr.creator_id = CPER_CREATOR_MCE;
+       rcd.hdr.notification_type = CPER_NOTIFY_MCE;
+       rcd.hdr.record_id = cper_next_record_id();
+       rcd.hdr.flags = CPER_HW_ERROR_FLAGS_PREVERR;
+
+       rcd.sec_hdr.section_offset = (void *)&rcd.mce - (void *)&rcd;
+       rcd.sec_hdr.section_length = sizeof(rcd.mce);
+       rcd.sec_hdr.revision = CPER_SEC_REV;
+       /* fru_id and fru_text is invalid */
+       rcd.sec_hdr.validation_bits = 0;
+       rcd.sec_hdr.flags = CPER_SEC_PRIMARY;
+       rcd.sec_hdr.section_type = CPER_SECTION_TYPE_MCE;
+       rcd.sec_hdr.section_severity = CPER_SER_FATAL;
+
+       memcpy(&rcd.mce, m, sizeof(*m));
+
+       return erst_write(&rcd.hdr);
+}
+
+ssize_t apei_read_mce(struct mce *m, u64 *record_id)
+{
+       struct cper_mce_record rcd;
+       ssize_t len;
+
+       len = erst_read_next(&rcd.hdr, sizeof(rcd));
+       if (len <= 0)
+               return len;
+       /* Can not skip other records in storage via ERST unless clear them */
+       else if (len != sizeof(rcd) ||
+                uuid_le_cmp(rcd.hdr.creator_id, CPER_CREATOR_MCE)) {
+               if (printk_ratelimit())
+                       pr_warning(
+                       "MCE-APEI: Can not skip the unknown record in ERST");
+               return -EIO;
+       }
+
+       memcpy(m, &rcd.mce, sizeof(*m));
+       *record_id = rcd.hdr.record_id;
+
+       return sizeof(*m);
+}
+
+/* Check whether there is record in ERST */
+int apei_check_mce(void)
+{
+       return erst_get_record_count();
+}
+
+int apei_clear_mce(u64 record_id)
+{
+       return erst_clear(record_id);
+}
index 32996f9fab670be274b925e7ec3a4bd52e8650c3..fefcc69ee8b5a937bdcce8f551b4d3ce585db585 100644 (file)
@@ -28,3 +28,26 @@ extern int mce_ser;
 
 extern struct mce_bank *mce_banks;
 
+#ifdef CONFIG_ACPI_APEI
+int apei_write_mce(struct mce *m);
+ssize_t apei_read_mce(struct mce *m, u64 *record_id);
+int apei_check_mce(void);
+int apei_clear_mce(u64 record_id);
+#else
+static inline int apei_write_mce(struct mce *m)
+{
+       return -EINVAL;
+}
+static inline ssize_t apei_read_mce(struct mce *m, u64 *record_id)
+{
+       return 0;
+}
+static inline int apei_check_mce(void)
+{
+       return 0;
+}
+static inline int apei_clear_mce(u64 record_id)
+{
+       return -EINVAL;
+}
+#endif
index 7a355ddcc64b98707fef017c084937b82219aa89..707165dbc20343310147dcd483605b7bfde456f0 100644 (file)
@@ -264,7 +264,7 @@ static void wait_for_panic(void)
 
 static void mce_panic(char *msg, struct mce *final, char *exp)
 {
-       int i;
+       int i, apei_err = 0;
 
        if (!fake_panic) {
                /*
@@ -287,8 +287,11 @@ static void mce_panic(char *msg, struct mce *final, char *exp)
                struct mce *m = &mcelog.entry[i];
                if (!(m->status & MCI_STATUS_VAL))
                        continue;
-               if (!(m->status & MCI_STATUS_UC))
+               if (!(m->status & MCI_STATUS_UC)) {
                        print_mce(m);
+                       if (!apei_err)
+                               apei_err = apei_write_mce(m);
+               }
        }
        /* Now print uncorrected but with the final one last */
        for (i = 0; i < MCE_LOG_LEN; i++) {
@@ -297,11 +300,17 @@ static void mce_panic(char *msg, struct mce *final, char *exp)
                        continue;
                if (!(m->status & MCI_STATUS_UC))
                        continue;
-               if (!final || memcmp(m, final, sizeof(struct mce)))
+               if (!final || memcmp(m, final, sizeof(struct mce))) {
                        print_mce(m);
+                       if (!apei_err)
+                               apei_err = apei_write_mce(m);
+               }
        }
-       if (final)
+       if (final) {
                print_mce(final);
+               if (!apei_err)
+                       apei_err = apei_write_mce(final);
+       }
        if (cpu_missing)
                printk(KERN_EMERG "Some CPUs didn't answer in synchronization\n");
        print_mce_tail();
@@ -1493,6 +1502,43 @@ static void collect_tscs(void *data)
        rdtscll(cpu_tsc[smp_processor_id()]);
 }
 
+static int mce_apei_read_done;
+
+/* Collect MCE record of previous boot in persistent storage via APEI ERST. */
+static int __mce_read_apei(char __user **ubuf, size_t usize)
+{
+       int rc;
+       u64 record_id;
+       struct mce m;
+
+       if (usize < sizeof(struct mce))
+               return -EINVAL;
+
+       rc = apei_read_mce(&m, &record_id);
+       /* Error or no more MCE record */
+       if (rc <= 0) {
+               mce_apei_read_done = 1;
+               return rc;
+       }
+       rc = -EFAULT;
+       if (copy_to_user(*ubuf, &m, sizeof(struct mce)))
+               return rc;
+       /*
+        * In fact, we should have cleared the record after that has
+        * been flushed to the disk or sent to network in
+        * /sbin/mcelog, but we have no interface to support that now,
+        * so just clear it to avoid duplication.
+        */
+       rc = apei_clear_mce(record_id);
+       if (rc) {
+               mce_apei_read_done = 1;
+               return rc;
+       }
+       *ubuf += sizeof(struct mce);
+
+       return 0;
+}
+
 static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize,
                        loff_t *off)
 {
@@ -1506,15 +1552,19 @@ static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize,
                return -ENOMEM;
 
        mutex_lock(&mce_read_mutex);
+
+       if (!mce_apei_read_done) {
+               err = __mce_read_apei(&buf, usize);
+               if (err || buf != ubuf)
+                       goto out;
+       }
+
        next = rcu_dereference_check_mce(mcelog.next);
 
        /* Only supports full reads right now */
-       if (*off != 0 || usize < MCE_LOG_LEN*sizeof(struct mce)) {
-               mutex_unlock(&mce_read_mutex);
-               kfree(cpu_tsc);
-
-               return -EINVAL;
-       }
+       err = -EINVAL;
+       if (*off != 0 || usize < MCE_LOG_LEN*sizeof(struct mce))
+               goto out;
 
        err = 0;
        prev = 0;
@@ -1562,10 +1612,15 @@ timeout:
                        memset(&mcelog.entry[i], 0, sizeof(struct mce));
                }
        }
+
+       if (err)
+               err = -EFAULT;
+
+out:
        mutex_unlock(&mce_read_mutex);
        kfree(cpu_tsc);
 
-       return err ? -EFAULT : buf - ubuf;
+       return err ? err : buf - ubuf;
 }
 
 static unsigned int mce_poll(struct file *file, poll_table *wait)
@@ -1573,6 +1628,8 @@ static unsigned int mce_poll(struct file *file, poll_table *wait)
        poll_wait(file, &mce_wait, wait);
        if (rcu_dereference_check_mce(mcelog.next))
                return POLLIN | POLLRDNORM;
+       if (!mce_apei_read_done && apei_check_mce())
+               return POLLIN | POLLRDNORM;
        return 0;
 }
 
index 81c499eceb21d88f62499a86cb9b0034d8519858..e1a0a3bf9716722671325212dceb559db2a47bf3 100644 (file)
@@ -190,7 +190,7 @@ thermal_throttle_cpu_callback(struct notifier_block *nfb,
                mutex_unlock(&therm_cpu_lock);
                break;
        }
-       return err ? NOTIFY_BAD : NOTIFY_OK;
+       return notifier_from_errno(err);
 }
 
 static struct notifier_block thermal_throttle_cpu_notifier __cpuinitdata =
index fd4db0db3708917ce471190eb7647a64074dc910..c77586061bcbc7642d2f7662f487f4432d2e3ff0 100644 (file)
@@ -1717,7 +1717,11 @@ void perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int ski
         */
        regs->bp = rewind_frame_pointer(skip + 1);
        regs->cs = __KERNEL_CS;
-       local_save_flags(regs->flags);
+       /*
+        * We abuse bit 3 to pass exact information, see perf_misc_flags
+        * and the comment with PERF_EFLAGS_EXACT.
+        */
+       regs->flags = 0;
 }
 
 unsigned long perf_instruction_pointer(struct pt_regs *regs)
index 424fc8de68e4f27391281a2514e11454370ec6c6..ae85d69644d182f31c9711eba6c5ddb21862bcec 100644 (file)
@@ -465,15 +465,21 @@ out:
        return rc;
 }
 
-static inline void p4_pmu_clear_cccr_ovf(struct hw_perf_event *hwc)
+static inline int p4_pmu_clear_cccr_ovf(struct hw_perf_event *hwc)
 {
-       unsigned long dummy;
+       int overflow = 0;
+       u32 low, high;
 
-       rdmsrl(hwc->config_base + hwc->idx, dummy);
-       if (dummy & P4_CCCR_OVF) {
+       rdmsr(hwc->config_base + hwc->idx, low, high);
+
+       /* we need to check high bit for unflagged overflows */
+       if ((low & P4_CCCR_OVF) || !(high & (1 << 31))) {
+               overflow = 1;
                (void)checking_wrmsrl(hwc->config_base + hwc->idx,
-                       ((u64)dummy) & ~P4_CCCR_OVF);
+                       ((u64)low) & ~P4_CCCR_OVF);
        }
+
+       return overflow;
 }
 
 static inline void p4_pmu_disable_event(struct perf_event *event)
@@ -584,21 +590,15 @@ static int p4_pmu_handle_irq(struct pt_regs *regs)
 
                WARN_ON_ONCE(hwc->idx != idx);
 
-               /*
-                * FIXME: Redundant call, actually not needed
-                * but just to check if we're screwed
-                */
-               p4_pmu_clear_cccr_ovf(hwc);
+               /* it might be unflagged overflow */
+               handled = p4_pmu_clear_cccr_ovf(hwc);
 
                val = x86_perf_event_update(event);
-               if (val & (1ULL << (x86_pmu.cntval_bits - 1)))
+               if (!handled && (val & (1ULL << (x86_pmu.cntval_bits - 1))))
                        continue;
 
-               /*
-                * event overflow
-                */
-               handled         = 1;
-               data.period     = event->hw.last_period;
+               /* event overflow for sure */
+               data.period = event->hw.last_period;
 
                if (!x86_perf_event_set_period(event))
                        continue;
@@ -670,7 +670,7 @@ static void p4_pmu_swap_config_ts(struct hw_perf_event *hwc, int cpu)
 
 /*
  * ESCR address hashing is tricky, ESCRs are not sequential
- * in memory but all starts from MSR_P4_BSU_ESCR0 (0x03e0) and
+ * in memory but all starts from MSR_P4_BSU_ESCR0 (0x03a0) and
  * the metric between any ESCRs is laid in range [0xa0,0xe1]
  *
  * so we make ~70% filled hashtable
@@ -735,8 +735,9 @@ static int p4_get_escr_idx(unsigned int addr)
 {
        unsigned int idx = P4_ESCR_MSR_IDX(addr);
 
-       if (unlikely(idx >= P4_ESCR_MSR_TABLE_SIZE ||
-                       !p4_escr_table[idx])) {
+       if (unlikely(idx >= P4_ESCR_MSR_TABLE_SIZE      ||
+                       !p4_escr_table[idx]             ||
+                       p4_escr_table[idx] != addr)) {
                WARN_ONCE(1, "P4 PMU: Wrong address passed: %x\n", addr);
                return -1;
        }
@@ -762,7 +763,7 @@ static int p4_pmu_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign
 {
        unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
        unsigned long escr_mask[BITS_TO_LONGS(P4_ESCR_MSR_TABLE_SIZE)];
-       int cpu = raw_smp_processor_id();
+       int cpu = smp_processor_id();
        struct hw_perf_event *hwc;
        struct p4_event_bind *bind;
        unsigned int i, thread, num;
index 8b862d5900fe4a29b6bc100770e371db41ee0d91..1b7b31ab7d86536ecde1d68034cf882216ac32a6 100644 (file)
@@ -170,7 +170,7 @@ static int __cpuinit cpuid_class_cpu_callback(struct notifier_block *nfb,
                cpuid_device_destroy(cpu);
                break;
        }
-       return err ? NOTIFY_BAD : NOTIFY_OK;
+       return notifier_from_errno(err);
 }
 
 static struct notifier_block __refdata cpuid_class_cpu_notifier =
index feaeb0d3aa4f984e2e9afac7a62d9de3acfe6f57..eb9b76c716c2277d147f2a3b4ad12456ec57dfb6 100644 (file)
@@ -29,6 +29,8 @@
 #define KVM_SCALE 22
 
 static int kvmclock = 1;
+static int msr_kvm_system_time = MSR_KVM_SYSTEM_TIME;
+static int msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK;
 
 static int parse_no_kvmclock(char *arg)
 {
@@ -54,7 +56,8 @@ static unsigned long kvm_get_wallclock(void)
 
        low = (int)__pa_symbol(&wall_clock);
        high = ((u64)__pa_symbol(&wall_clock) >> 32);
-       native_write_msr(MSR_KVM_WALL_CLOCK, low, high);
+
+       native_write_msr(msr_kvm_wall_clock, low, high);
 
        vcpu_time = &get_cpu_var(hv_clock);
        pvclock_read_wallclock(&wall_clock, vcpu_time, &ts);
@@ -130,7 +133,8 @@ static int kvm_register_clock(char *txt)
        high = ((u64)__pa(&per_cpu(hv_clock, cpu)) >> 32);
        printk(KERN_INFO "kvm-clock: cpu %d, msr %x:%x, %s\n",
               cpu, high, low, txt);
-       return native_write_msr_safe(MSR_KVM_SYSTEM_TIME, low, high);
+
+       return native_write_msr_safe(msr_kvm_system_time, low, high);
 }
 
 #ifdef CONFIG_X86_LOCAL_APIC
@@ -165,14 +169,14 @@ static void __init kvm_smp_prepare_boot_cpu(void)
 #ifdef CONFIG_KEXEC
 static void kvm_crash_shutdown(struct pt_regs *regs)
 {
-       native_write_msr_safe(MSR_KVM_SYSTEM_TIME, 0, 0);
+       native_write_msr(msr_kvm_system_time, 0, 0);
        native_machine_crash_shutdown(regs);
 }
 #endif
 
 static void kvm_shutdown(void)
 {
-       native_write_msr_safe(MSR_KVM_SYSTEM_TIME, 0, 0);
+       native_write_msr(msr_kvm_system_time, 0, 0);
        native_machine_shutdown();
 }
 
@@ -181,27 +185,37 @@ void __init kvmclock_init(void)
        if (!kvm_para_available())
                return;
 
-       if (kvmclock && kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE)) {
-               if (kvm_register_clock("boot clock"))
-                       return;
-               pv_time_ops.sched_clock = kvm_clock_read;
-               x86_platform.calibrate_tsc = kvm_get_tsc_khz;
-               x86_platform.get_wallclock = kvm_get_wallclock;
-               x86_platform.set_wallclock = kvm_set_wallclock;
+       if (kvmclock && kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE2)) {
+               msr_kvm_system_time = MSR_KVM_SYSTEM_TIME_NEW;
+               msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK_NEW;
+       } else if (!(kvmclock && kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE)))
+               return;
+
+       printk(KERN_INFO "kvm-clock: Using msrs %x and %x",
+               msr_kvm_system_time, msr_kvm_wall_clock);
+
+       if (kvm_register_clock("boot clock"))
+               return;
+       pv_time_ops.sched_clock = kvm_clock_read;
+       x86_platform.calibrate_tsc = kvm_get_tsc_khz;
+       x86_platform.get_wallclock = kvm_get_wallclock;
+       x86_platform.set_wallclock = kvm_set_wallclock;
 #ifdef CONFIG_X86_LOCAL_APIC
-               x86_cpuinit.setup_percpu_clockev =
-                       kvm_setup_secondary_clock;
+       x86_cpuinit.setup_percpu_clockev =
+               kvm_setup_secondary_clock;
 #endif
 #ifdef CONFIG_SMP
-               smp_ops.smp_prepare_boot_cpu = kvm_smp_prepare_boot_cpu;
+       smp_ops.smp_prepare_boot_cpu = kvm_smp_prepare_boot_cpu;
 #endif
-               machine_ops.shutdown  = kvm_shutdown;
+       machine_ops.shutdown  = kvm_shutdown;
 #ifdef CONFIG_KEXEC
-               machine_ops.crash_shutdown  = kvm_crash_shutdown;
+       machine_ops.crash_shutdown  = kvm_crash_shutdown;
 #endif
-               kvm_get_preset_lpj();
-               clocksource_register(&kvm_clock);
-               pv_info.paravirt_enabled = 1;
-               pv_info.name = "KVM";
-       }
+       kvm_get_preset_lpj();
+       clocksource_register(&kvm_clock);
+       pv_info.paravirt_enabled = 1;
+       pv_info.name = "KVM";
+
+       if (kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE_STABLE_BIT))
+               pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT);
 }
index 2cd8c544e41a22a224c8f29f3f517e609c60536e..fa6551d36c102105c8654c7d4f60f82e65990822 100644 (file)
@@ -260,6 +260,7 @@ static void microcode_dev_exit(void)
 }
 
 MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
+MODULE_ALIAS("devname:cpu/microcode");
 #else
 #define microcode_dev_init()   0
 #define microcode_dev_exit()   do { } while (0)
index 4d4468e9f47cbc7ba182ea92c78ec989c0a8b555..7bf2dc4c8f701de8965fc1e124126863c7384552 100644 (file)
@@ -230,7 +230,7 @@ static int __cpuinit msr_class_cpu_callback(struct notifier_block *nfb,
                msr_device_destroy(cpu);
                break;
        }
-       return err ? NOTIFY_BAD : NOTIFY_OK;
+       return notifier_from_errno(err);
 }
 
 static struct notifier_block __refdata msr_class_cpu_notifier = {
index 7d2829dde20e8cbbf538ea6fcf39384510a65426..a5bc528d43282a344936922328d2b5bf59b187ae 100644 (file)
@@ -31,8 +31,6 @@ static struct dma_map_ops swiotlb_dma_ops = {
        .free_coherent = swiotlb_free_coherent,
        .sync_single_for_cpu = swiotlb_sync_single_for_cpu,
        .sync_single_for_device = swiotlb_sync_single_for_device,
-       .sync_single_range_for_cpu = swiotlb_sync_single_range_for_cpu,
-       .sync_single_range_for_device = swiotlb_sync_single_range_for_device,
        .sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
        .sync_sg_for_device = swiotlb_sync_sg_for_device,
        .map_sg = swiotlb_map_sg_attrs,
index 03801f2f761fc312ba80353425c1cc7243a0105f..239427ca02af05f8671aacaf9820aa298e94bff1 100644 (file)
@@ -31,8 +31,16 @@ struct pvclock_shadow_time {
        u32 tsc_to_nsec_mul;
        int tsc_shift;
        u32 version;
+       u8  flags;
 };
 
+static u8 valid_flags __read_mostly = 0;
+
+void pvclock_set_flags(u8 flags)
+{
+       valid_flags = flags;
+}
+
 /*
  * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
  * yielding a 64-bit result.
@@ -91,6 +99,7 @@ static unsigned pvclock_get_time_values(struct pvclock_shadow_time *dst,
                dst->system_timestamp  = src->system_time;
                dst->tsc_to_nsec_mul   = src->tsc_to_system_mul;
                dst->tsc_shift         = src->tsc_shift;
+               dst->flags             = src->flags;
                rmb();          /* test version after fetching data */
        } while ((src->version & 1) || (dst->version != src->version));
 
@@ -109,11 +118,14 @@ unsigned long pvclock_tsc_khz(struct pvclock_vcpu_time_info *src)
        return pv_tsc_khz;
 }
 
+static atomic64_t last_value = ATOMIC64_INIT(0);
+
 cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src)
 {
        struct pvclock_shadow_time shadow;
        unsigned version;
        cycle_t ret, offset;
+       u64 last;
 
        do {
                version = pvclock_get_time_values(&shadow, src);
@@ -123,6 +135,31 @@ cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src)
                barrier();
        } while (version != src->version);
 
+       if ((valid_flags & PVCLOCK_TSC_STABLE_BIT) &&
+               (shadow.flags & PVCLOCK_TSC_STABLE_BIT))
+               return ret;
+
+       /*
+        * Assumption here is that last_value, a global accumulator, always goes
+        * forward. If we are less than that, we should not be much smaller.
+        * We assume there is an error marging we're inside, and then the correction
+        * does not sacrifice accuracy.
+        *
+        * For reads: global may have changed between test and return,
+        * but this means someone else updated poked the clock at a later time.
+        * We just need to make sure we are not seeing a backwards event.
+        *
+        * For updates: last_value = ret is not enough, since two vcpus could be
+        * updating at the same time, and one of them could be slightly behind,
+        * making the assumption that last_value always go forward fail to hold.
+        */
+       last = atomic64_read(&last_value);
+       do {
+               if (ret < last)
+                       return last;
+               last = atomic64_cmpxchg(&last_value, last, ret);
+       } while (unlikely(last != ret));
+
        return ret;
 }
 
index e8029896309af8cadb39b2445568d8c3ddc410ae..b4ae4acbd031061d022a0c3e2873b7fd346a9263 100644 (file)
@@ -676,6 +676,17 @@ static struct dmi_system_id __initdata bad_bios_dmi_table[] = {
                        DMI_MATCH(DMI_BOARD_NAME, "DG45FC"),
                },
        },
+       /*
+        * The Dell Inspiron Mini 1012 has DMI_BIOS_VENDOR = "Dell Inc.", so
+        * match on the product name.
+        */
+       {
+               .callback = dmi_low_memory_corruption,
+               .ident = "Phoenix BIOS",
+               .matches = {
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1012"),
+               },
+       },
 #endif
        {}
 };
index ef6370b00e70ce50ab73ed6b6ad5a1db48b749ab..a867940a6dfc4dfb31ac1f28a54ccb98d11aff46 100644 (file)
@@ -265,10 +265,10 @@ void __init setup_per_cpu_areas(void)
 
 #if defined(CONFIG_X86_64) && defined(CONFIG_NUMA)
        /*
-        * make sure boot cpu node_number is right, when boot cpu is on the
+        * make sure boot cpu numa_node is right, when boot cpu is on the
         * node that doesn't have mem installed
         */
-       per_cpu(node_number, boot_cpu_id) = cpu_to_node(boot_cpu_id);
+       set_cpu_numa_node(boot_cpu_id, early_cpu_to_node(boot_cpu_id));
 #endif
 
        /* Setup node to cpumask map */
index 763d815e27a005159ca5b52c68df4f43010b9832..37462f1ddba54d1ad3af14a682efb1e71dc6df96 100644 (file)
@@ -1215,9 +1215,17 @@ __init void prefill_possible_map(void)
        if (!num_processors)
                num_processors = 1;
 
-       if (setup_possible_cpus == -1)
-               possible = num_processors + disabled_cpus;
-       else
+       i = setup_max_cpus ?: 1;
+       if (setup_possible_cpus == -1) {
+               possible = num_processors;
+#ifdef CONFIG_HOTPLUG_CPU
+               if (setup_max_cpus)
+                       possible += disabled_cpus;
+#else
+               if (possible > i)
+                       possible = i;
+#endif
+       } else
                possible = setup_possible_cpus;
 
        total_cpus = max_t(int, possible, num_processors + disabled_cpus);
@@ -1230,11 +1238,23 @@ __init void prefill_possible_map(void)
                possible = nr_cpu_ids;
        }
 
+#ifdef CONFIG_HOTPLUG_CPU
+       if (!setup_max_cpus)
+#endif
+       if (possible > i) {
+               printk(KERN_WARNING
+                       "%d Processors exceeds max_cpus limit of %u\n",
+                       possible, setup_max_cpus);
+               possible = i;
+       }
+
        printk(KERN_INFO "SMP: Allowing %d CPUs, %d hotplug CPUs\n",
                possible, max_t(int, possible - num_processors, 0));
 
        for (i = 0; i < possible; i++)
                set_cpu_possible(i, true);
+       for (; i < NR_CPUS; i++)
+               set_cpu_possible(i, false);
 
        nr_cpu_ids = possible;
 }
index cc2c60474fd06562a31269c3eeb10eae18b9847d..c2f1b26141e2c4ab3888315b4754cbf1a324be40 100644 (file)
@@ -46,6 +46,7 @@
 
 /* Global pointer to shared data; NULL means no measured launch. */
 struct tboot *tboot __read_mostly;
+EXPORT_SYMBOL(tboot);
 
 /* timeout for APs (in secs) to enter wait-for-SIPI state during shutdown */
 #define AP_WAIT_TIMEOUT                1
index 4dade6ac08276537b07824ab7c23224d93946905..5ac0bb465ed67fd725881ccacfeb22e44597f4cf 100644 (file)
@@ -33,6 +33,7 @@
 #include <asm/kvm_emulate.h>
 
 #include "x86.h"
+#include "tss.h"
 
 /*
  * Opcode effective-address decode tables.
@@ -50,6 +51,8 @@
 #define DstReg      (2<<1)     /* Register operand. */
 #define DstMem      (3<<1)     /* Memory operand. */
 #define DstAcc      (4<<1)      /* Destination Accumulator */
+#define DstDI       (5<<1)     /* Destination is in ES:(E)DI */
+#define DstMem64    (6<<1)     /* 64bit memory operand */
 #define DstMask     (7<<1)
 /* Source operand type. */
 #define SrcNone     (0<<4)     /* No source operand. */
@@ -63,6 +66,7 @@
 #define SrcOne      (7<<4)     /* Implied '1' */
 #define SrcImmUByte (8<<4)      /* 8-bit unsigned immediate operand. */
 #define SrcImmU     (9<<4)      /* Immediate operand, unsigned */
+#define SrcSI       (0xa<<4)   /* Source is in the DS:RSI */
 #define SrcMask     (0xf<<4)
 /* Generic ModRM decode. */
 #define ModRM       (1<<8)
@@ -85,6 +89,9 @@
 #define Src2ImmByte (2<<29)
 #define Src2One     (3<<29)
 #define Src2Imm16   (4<<29)
+#define Src2Mem16   (5<<29) /* Used for Ep encoding. First argument has to be
+                              in memory and second argument is located
+                              immediately after the first one in memory. */
 #define Src2Mask    (7<<29)
 
 enum {
@@ -147,8 +154,8 @@ static u32 opcode_table[256] = {
        0, 0, 0, 0,
        /* 0x68 - 0x6F */
        SrcImm | Mov | Stack, 0, SrcImmByte | Mov | Stack, 0,
-       SrcNone  | ByteOp  | ImplicitOps, SrcNone  | ImplicitOps, /* insb, insw/insd */
-       SrcNone  | ByteOp  | ImplicitOps, SrcNone  | ImplicitOps, /* outsb, outsw/outsd */
+       DstDI | ByteOp | Mov | String, DstDI | Mov | String, /* insb, insw/insd */
+       SrcSI | ByteOp | ImplicitOps | String, SrcSI | ImplicitOps | String, /* outsb, outsw/outsd */
        /* 0x70 - 0x77 */
        SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte,
        SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte,
@@ -173,12 +180,12 @@ static u32 opcode_table[256] = {
        /* 0xA0 - 0xA7 */
        ByteOp | DstReg | SrcMem | Mov | MemAbs, DstReg | SrcMem | Mov | MemAbs,
        ByteOp | DstMem | SrcReg | Mov | MemAbs, DstMem | SrcReg | Mov | MemAbs,
-       ByteOp | ImplicitOps | Mov | String, ImplicitOps | Mov | String,
-       ByteOp | ImplicitOps | String, ImplicitOps | String,
+       ByteOp | SrcSI | DstDI | Mov | String, SrcSI | DstDI | Mov | String,
+       ByteOp | SrcSI | DstDI | String, SrcSI | DstDI | String,
        /* 0xA8 - 0xAF */
-       0, 0, ByteOp | ImplicitOps | Mov | String, ImplicitOps | Mov | String,
-       ByteOp | ImplicitOps | Mov | String, ImplicitOps | Mov | String,
-       ByteOp | ImplicitOps | String, ImplicitOps | String,
+       0, 0, ByteOp | DstDI | Mov | String, DstDI | Mov | String,
+       ByteOp | SrcSI | DstAcc | Mov | String, SrcSI | DstAcc | Mov | String,
+       ByteOp | DstDI | String, DstDI | String,
        /* 0xB0 - 0xB7 */
        ByteOp | DstReg | SrcImm | Mov, ByteOp | DstReg | SrcImm | Mov,
        ByteOp | DstReg | SrcImm | Mov, ByteOp | DstReg | SrcImm | Mov,
@@ -204,13 +211,13 @@ static u32 opcode_table[256] = {
        0, 0, 0, 0, 0, 0, 0, 0,
        /* 0xE0 - 0xE7 */
        0, 0, 0, 0,
-       ByteOp | SrcImmUByte, SrcImmUByte,
-       ByteOp | SrcImmUByte, SrcImmUByte,
+       ByteOp | SrcImmUByte | DstAcc, SrcImmUByte | DstAcc,
+       ByteOp | SrcImmUByte | DstAcc, SrcImmUByte | DstAcc,
        /* 0xE8 - 0xEF */
        SrcImm | Stack, SrcImm | ImplicitOps,
        SrcImmU | Src2Imm16 | No64, SrcImmByte | ImplicitOps,
-       SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps,
-       SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps,
+       SrcNone | ByteOp | DstAcc, SrcNone | DstAcc,
+       SrcNone | ByteOp | DstAcc, SrcNone | DstAcc,
        /* 0xF0 - 0xF7 */
        0, 0, 0, 0,
        ImplicitOps | Priv, ImplicitOps, Group | Group3_Byte, Group | Group3,
@@ -343,7 +350,8 @@ static u32 group_table[] = {
        [Group5*8] =
        DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM,
        SrcMem | ModRM | Stack, 0,
-       SrcMem | ModRM | Stack, 0, SrcMem | ModRM | Stack, 0,
+       SrcMem | ModRM | Stack, SrcMem | ModRM | Src2Mem16 | ImplicitOps,
+       SrcMem | ModRM | Stack, 0,
        [Group7*8] =
        0, 0, ModRM | SrcMem | Priv, ModRM | SrcMem | Priv,
        SrcNone | ModRM | DstMem | Mov, 0,
@@ -353,14 +361,14 @@ static u32 group_table[] = {
        DstMem | SrcImmByte | ModRM, DstMem | SrcImmByte | ModRM | Lock,
        DstMem | SrcImmByte | ModRM | Lock, DstMem | SrcImmByte | ModRM | Lock,
        [Group9*8] =
-       0, ImplicitOps | ModRM | Lock, 0, 0, 0, 0, 0, 0,
+       0, DstMem64 | ModRM | Lock, 0, 0, 0, 0, 0, 0,
 };
 
 static u32 group2_table[] = {
        [Group7*8] =
-       SrcNone | ModRM | Priv, 0, 0, SrcNone | ModRM,
+       SrcNone | ModRM | Priv, 0, 0, SrcNone | ModRM | Priv,
        SrcNone | ModRM | DstMem | Mov, 0,
-       SrcMem16 | ModRM | Mov, 0,
+       SrcMem16 | ModRM | Mov | Priv, 0,
        [Group9*8] =
        0, 0, 0, 0, 0, 0, 0, 0,
 };
@@ -562,7 +570,7 @@ static u32 group2_table[] = {
 #define insn_fetch(_type, _size, _eip)                                  \
 ({     unsigned long _x;                                               \
        rc = do_insn_fetch(ctxt, ops, (_eip), &_x, (_size));            \
-       if (rc != 0)                                                    \
+       if (rc != X86EMUL_CONTINUE)                                     \
                goto done;                                              \
        (_eip) += (_size);                                              \
        (_type)_x;                                                      \
@@ -638,40 +646,40 @@ static unsigned long ss_base(struct x86_emulate_ctxt *ctxt)
 
 static int do_fetch_insn_byte(struct x86_emulate_ctxt *ctxt,
                              struct x86_emulate_ops *ops,
-                             unsigned long linear, u8 *dest)
+                             unsigned long eip, u8 *dest)
 {
        struct fetch_cache *fc = &ctxt->decode.fetch;
        int rc;
-       int size;
+       int size, cur_size;
 
-       if (linear < fc->start || linear >= fc->end) {
-               size = min(15UL, PAGE_SIZE - offset_in_page(linear));
-               rc = ops->fetch(linear, fc->data, size, ctxt->vcpu, NULL);
-               if (rc)
+       if (eip == fc->end) {
+               cur_size = fc->end - fc->start;
+               size = min(15UL - cur_size, PAGE_SIZE - offset_in_page(eip));
+               rc = ops->fetch(ctxt->cs_base + eip, fc->data + cur_size,
+                               size, ctxt->vcpu, NULL);
+               if (rc != X86EMUL_CONTINUE)
                        return rc;
-               fc->start = linear;
-               fc->end = linear + size;
+               fc->end += size;
        }
-       *dest = fc->data[linear - fc->start];
-       return 0;
+       *dest = fc->data[eip - fc->start];
+       return X86EMUL_CONTINUE;
 }
 
 static int do_insn_fetch(struct x86_emulate_ctxt *ctxt,
                         struct x86_emulate_ops *ops,
                         unsigned long eip, void *dest, unsigned size)
 {
-       int rc = 0;
+       int rc;
 
        /* x86 instructions are limited to 15 bytes. */
-       if (eip + size - ctxt->decode.eip_orig > 15)
+       if (eip + size - ctxt->eip > 15)
                return X86EMUL_UNHANDLEABLE;
-       eip += ctxt->cs_base;
        while (size--) {
                rc = do_fetch_insn_byte(ctxt, ops, eip++, dest++);
-               if (rc)
+               if (rc != X86EMUL_CONTINUE)
                        return rc;
        }
-       return 0;
+       return X86EMUL_CONTINUE;
 }
 
 /*
@@ -702,7 +710,7 @@ static int read_descriptor(struct x86_emulate_ctxt *ctxt,
        *address = 0;
        rc = ops->read_std((unsigned long)ptr, (unsigned long *)size, 2,
                           ctxt->vcpu, NULL);
-       if (rc)
+       if (rc != X86EMUL_CONTINUE)
                return rc;
        rc = ops->read_std((unsigned long)ptr + 2, address, op_bytes,
                           ctxt->vcpu, NULL);
@@ -782,7 +790,7 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt,
        struct decode_cache *c = &ctxt->decode;
        u8 sib;
        int index_reg = 0, base_reg = 0, scale;
-       int rc = 0;
+       int rc = X86EMUL_CONTINUE;
 
        if (c->rex_prefix) {
                c->modrm_reg = (c->rex_prefix & 4) << 1;        /* REX.R */
@@ -895,7 +903,7 @@ static int decode_abs(struct x86_emulate_ctxt *ctxt,
                      struct x86_emulate_ops *ops)
 {
        struct decode_cache *c = &ctxt->decode;
-       int rc = 0;
+       int rc = X86EMUL_CONTINUE;
 
        switch (c->ad_bytes) {
        case 2:
@@ -916,14 +924,18 @@ int
 x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
 {
        struct decode_cache *c = &ctxt->decode;
-       int rc = 0;
+       int rc = X86EMUL_CONTINUE;
        int mode = ctxt->mode;
        int def_op_bytes, def_ad_bytes, group;
 
-       /* Shadow copy of register state. Committed on successful emulation. */
 
+       /* we cannot decode insn before we complete previous rep insn */
+       WARN_ON(ctxt->restart);
+
+       /* Shadow copy of register state. Committed on successful emulation. */
        memset(c, 0, sizeof(struct decode_cache));
-       c->eip = c->eip_orig = kvm_rip_read(ctxt->vcpu);
+       c->eip = ctxt->eip;
+       c->fetch.start = c->fetch.end = c->eip;
        ctxt->cs_base = seg_base(ctxt, VCPU_SREG_CS);
        memcpy(c->regs, ctxt->vcpu->arch.regs, sizeof c->regs);
 
@@ -1015,11 +1027,6 @@ done_prefixes:
                }
        }
 
-       if (mode == X86EMUL_MODE_PROT64 && (c->d & No64)) {
-               kvm_report_emulation_failure(ctxt->vcpu, "invalid x86/64 instruction");
-               return -1;
-       }
-
        if (c->d & Group) {
                group = c->d & GroupMask;
                c->modrm = insn_fetch(u8, 1, c->eip);
@@ -1046,7 +1053,7 @@ done_prefixes:
                rc = decode_modrm(ctxt, ops);
        else if (c->d & MemAbs)
                rc = decode_abs(ctxt, ops);
-       if (rc)
+       if (rc != X86EMUL_CONTINUE)
                goto done;
 
        if (!c->has_seg_override)
@@ -1057,6 +1064,10 @@ done_prefixes:
 
        if (c->ad_bytes != 8)
                c->modrm_ea = (u32)c->modrm_ea;
+
+       if (c->rip_relative)
+               c->modrm_ea += c->eip;
+
        /*
         * Decode and fetch the source operand: register, memory
         * or immediate.
@@ -1091,6 +1102,8 @@ done_prefixes:
                        break;
                }
                c->src.type = OP_MEM;
+               c->src.ptr = (unsigned long *)c->modrm_ea;
+               c->src.val = 0;
                break;
        case SrcImm:
        case SrcImmU:
@@ -1139,6 +1152,14 @@ done_prefixes:
                c->src.bytes = 1;
                c->src.val = 1;
                break;
+       case SrcSI:
+               c->src.type = OP_MEM;
+               c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
+               c->src.ptr = (unsigned long *)
+                       register_address(c,  seg_override_base(ctxt, c),
+                                        c->regs[VCPU_REGS_RSI]);
+               c->src.val = 0;
+               break;
        }
 
        /*
@@ -1168,6 +1189,12 @@ done_prefixes:
                c->src2.bytes = 1;
                c->src2.val = 1;
                break;
+       case Src2Mem16:
+               c->src2.type = OP_MEM;
+               c->src2.bytes = 2;
+               c->src2.ptr = (unsigned long *)(c->modrm_ea + c->src.bytes);
+               c->src2.val = 0;
+               break;
        }
 
        /* Decode and fetch the destination operand: register or memory. */
@@ -1180,6 +1207,7 @@ done_prefixes:
                         c->twobyte && (c->b == 0xb6 || c->b == 0xb7));
                break;
        case DstMem:
+       case DstMem64:
                if ((c->d & ModRM) && c->modrm_mod == 3) {
                        c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
                        c->dst.type = OP_REG;
@@ -1188,12 +1216,24 @@ done_prefixes:
                        break;
                }
                c->dst.type = OP_MEM;
+               c->dst.ptr = (unsigned long *)c->modrm_ea;
+               if ((c->d & DstMask) == DstMem64)
+                       c->dst.bytes = 8;
+               else
+                       c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
+               c->dst.val = 0;
+               if (c->d & BitOp) {
+                       unsigned long mask = ~(c->dst.bytes * 8 - 1);
+
+                       c->dst.ptr = (void *)c->dst.ptr +
+                                                  (c->src.val & mask) / 8;
+               }
                break;
        case DstAcc:
                c->dst.type = OP_REG;
-               c->dst.bytes = c->op_bytes;
+               c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
                c->dst.ptr = &c->regs[VCPU_REGS_RAX];
-               switch (c->op_bytes) {
+               switch (c->dst.bytes) {
                        case 1:
                                c->dst.val = *(u8 *)c->dst.ptr;
                                break;
@@ -1203,18 +1243,248 @@ done_prefixes:
                        case 4:
                                c->dst.val = *(u32 *)c->dst.ptr;
                                break;
+                       case 8:
+                               c->dst.val = *(u64 *)c->dst.ptr;
+                               break;
                }
                c->dst.orig_val = c->dst.val;
                break;
+       case DstDI:
+               c->dst.type = OP_MEM;
+               c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
+               c->dst.ptr = (unsigned long *)
+                       register_address(c, es_base(ctxt),
+                                        c->regs[VCPU_REGS_RDI]);
+               c->dst.val = 0;
+               break;
        }
 
-       if (c->rip_relative)
-               c->modrm_ea += c->eip;
-
 done:
        return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
 }
 
+static int pio_in_emulated(struct x86_emulate_ctxt *ctxt,
+                          struct x86_emulate_ops *ops,
+                          unsigned int size, unsigned short port,
+                          void *dest)
+{
+       struct read_cache *rc = &ctxt->decode.io_read;
+
+       if (rc->pos == rc->end) { /* refill pio read ahead */
+               struct decode_cache *c = &ctxt->decode;
+               unsigned int in_page, n;
+               unsigned int count = c->rep_prefix ?
+                       address_mask(c, c->regs[VCPU_REGS_RCX]) : 1;
+               in_page = (ctxt->eflags & EFLG_DF) ?
+                       offset_in_page(c->regs[VCPU_REGS_RDI]) :
+                       PAGE_SIZE - offset_in_page(c->regs[VCPU_REGS_RDI]);
+               n = min(min(in_page, (unsigned int)sizeof(rc->data)) / size,
+                       count);
+               if (n == 0)
+                       n = 1;
+               rc->pos = rc->end = 0;
+               if (!ops->pio_in_emulated(size, port, rc->data, n, ctxt->vcpu))
+                       return 0;
+               rc->end = n * size;
+       }
+
+       memcpy(dest, rc->data + rc->pos, size);
+       rc->pos += size;
+       return 1;
+}
+
+static u32 desc_limit_scaled(struct desc_struct *desc)
+{
+       u32 limit = get_desc_limit(desc);
+
+       return desc->g ? (limit << 12) | 0xfff : limit;
+}
+
+static void get_descriptor_table_ptr(struct x86_emulate_ctxt *ctxt,
+                                    struct x86_emulate_ops *ops,
+                                    u16 selector, struct desc_ptr *dt)
+{
+       if (selector & 1 << 2) {
+               struct desc_struct desc;
+               memset (dt, 0, sizeof *dt);
+               if (!ops->get_cached_descriptor(&desc, VCPU_SREG_LDTR, ctxt->vcpu))
+                       return;
+
+               dt->size = desc_limit_scaled(&desc); /* what if limit > 65535? */
+               dt->address = get_desc_base(&desc);
+       } else
+               ops->get_gdt(dt, ctxt->vcpu);
+}
+
+/* allowed just for 8 bytes segments */
+static int read_segment_descriptor(struct x86_emulate_ctxt *ctxt,
+                                  struct x86_emulate_ops *ops,
+                                  u16 selector, struct desc_struct *desc)
+{
+       struct desc_ptr dt;
+       u16 index = selector >> 3;
+       int ret;
+       u32 err;
+       ulong addr;
+
+       get_descriptor_table_ptr(ctxt, ops, selector, &dt);
+
+       if (dt.size < index * 8 + 7) {
+               kvm_inject_gp(ctxt->vcpu, selector & 0xfffc);
+               return X86EMUL_PROPAGATE_FAULT;
+       }
+       addr = dt.address + index * 8;
+       ret = ops->read_std(addr, desc, sizeof *desc, ctxt->vcpu,  &err);
+       if (ret == X86EMUL_PROPAGATE_FAULT)
+               kvm_inject_page_fault(ctxt->vcpu, addr, err);
+
+       return ret;
+}
+
+/* allowed just for 8 bytes segments */
+static int write_segment_descriptor(struct x86_emulate_ctxt *ctxt,
+                                   struct x86_emulate_ops *ops,
+                                   u16 selector, struct desc_struct *desc)
+{
+       struct desc_ptr dt;
+       u16 index = selector >> 3;
+       u32 err;
+       ulong addr;
+       int ret;
+
+       get_descriptor_table_ptr(ctxt, ops, selector, &dt);
+
+       if (dt.size < index * 8 + 7) {
+               kvm_inject_gp(ctxt->vcpu, selector & 0xfffc);
+               return X86EMUL_PROPAGATE_FAULT;
+       }
+
+       addr = dt.address + index * 8;
+       ret = ops->write_std(addr, desc, sizeof *desc, ctxt->vcpu, &err);
+       if (ret == X86EMUL_PROPAGATE_FAULT)
+               kvm_inject_page_fault(ctxt->vcpu, addr, err);
+
+       return ret;
+}
+
+static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
+                                  struct x86_emulate_ops *ops,
+                                  u16 selector, int seg)
+{
+       struct desc_struct seg_desc;
+       u8 dpl, rpl, cpl;
+       unsigned err_vec = GP_VECTOR;
+       u32 err_code = 0;
+       bool null_selector = !(selector & ~0x3); /* 0000-0003 are null */
+       int ret;
+
+       memset(&seg_desc, 0, sizeof seg_desc);
+
+       if ((seg <= VCPU_SREG_GS && ctxt->mode == X86EMUL_MODE_VM86)
+           || ctxt->mode == X86EMUL_MODE_REAL) {
+               /* set real mode segment descriptor */
+               set_desc_base(&seg_desc, selector << 4);
+               set_desc_limit(&seg_desc, 0xffff);
+               seg_desc.type = 3;
+               seg_desc.p = 1;
+               seg_desc.s = 1;
+               goto load;
+       }
+
+       /* NULL selector is not valid for TR, CS and SS */
+       if ((seg == VCPU_SREG_CS || seg == VCPU_SREG_SS || seg == VCPU_SREG_TR)
+           && null_selector)
+               goto exception;
+
+       /* TR should be in GDT only */
+       if (seg == VCPU_SREG_TR && (selector & (1 << 2)))
+               goto exception;
+
+       if (null_selector) /* for NULL selector skip all following checks */
+               goto load;
+
+       ret = read_segment_descriptor(ctxt, ops, selector, &seg_desc);
+       if (ret != X86EMUL_CONTINUE)
+               return ret;
+
+       err_code = selector & 0xfffc;
+       err_vec = GP_VECTOR;
+
+       /* can't load system descriptor into segment selecor */
+       if (seg <= VCPU_SREG_GS && !seg_desc.s)
+               goto exception;
+
+       if (!seg_desc.p) {
+               err_vec = (seg == VCPU_SREG_SS) ? SS_VECTOR : NP_VECTOR;
+               goto exception;
+       }
+
+       rpl = selector & 3;
+       dpl = seg_desc.dpl;
+       cpl = ops->cpl(ctxt->vcpu);
+
+       switch (seg) {
+       case VCPU_SREG_SS:
+               /*
+                * segment is not a writable data segment or segment
+                * selector's RPL != CPL or segment selector's RPL != CPL
+                */
+               if (rpl != cpl || (seg_desc.type & 0xa) != 0x2 || dpl != cpl)
+                       goto exception;
+               break;
+       case VCPU_SREG_CS:
+               if (!(seg_desc.type & 8))
+                       goto exception;
+
+               if (seg_desc.type & 4) {
+                       /* conforming */
+                       if (dpl > cpl)
+                               goto exception;
+               } else {
+                       /* nonconforming */
+                       if (rpl > cpl || dpl != cpl)
+                               goto exception;
+               }
+               /* CS(RPL) <- CPL */
+               selector = (selector & 0xfffc) | cpl;
+               break;
+       case VCPU_SREG_TR:
+               if (seg_desc.s || (seg_desc.type != 1 && seg_desc.type != 9))
+                       goto exception;
+               break;
+       case VCPU_SREG_LDTR:
+               if (seg_desc.s || seg_desc.type != 2)
+                       goto exception;
+               break;
+       default: /*  DS, ES, FS, or GS */
+               /*
+                * segment is not a data or readable code segment or
+                * ((segment is a data or nonconforming code segment)
+                * and (both RPL and CPL > DPL))
+                */
+               if ((seg_desc.type & 0xa) == 0x8 ||
+                   (((seg_desc.type & 0xc) != 0xc) &&
+                    (rpl > dpl && cpl > dpl)))
+                       goto exception;
+               break;
+       }
+
+       if (seg_desc.s) {
+               /* mark segment as accessed */
+               seg_desc.type |= 1;
+               ret = write_segment_descriptor(ctxt, ops, selector, &seg_desc);
+               if (ret != X86EMUL_CONTINUE)
+                       return ret;
+       }
+load:
+       ops->set_segment_selector(selector, seg, ctxt->vcpu);
+       ops->set_cached_descriptor(&seg_desc, seg, ctxt->vcpu);
+       return X86EMUL_CONTINUE;
+exception:
+       kvm_queue_exception_e(ctxt->vcpu, err_vec, err_code);
+       return X86EMUL_PROPAGATE_FAULT;
+}
+
 static inline void emulate_push(struct x86_emulate_ctxt *ctxt)
 {
        struct decode_cache *c = &ctxt->decode;
@@ -1251,7 +1521,7 @@ static int emulate_popf(struct x86_emulate_ctxt *ctxt,
        int rc;
        unsigned long val, change_mask;
        int iopl = (ctxt->eflags & X86_EFLAGS_IOPL) >> IOPL_SHIFT;
-       int cpl = kvm_x86_ops->get_cpl(ctxt->vcpu);
+       int cpl = ops->cpl(ctxt->vcpu);
 
        rc = emulate_pop(ctxt, ops, &val, len);
        if (rc != X86EMUL_CONTINUE)
@@ -1306,10 +1576,10 @@ static int emulate_pop_sreg(struct x86_emulate_ctxt *ctxt,
        int rc;
 
        rc = emulate_pop(ctxt, ops, &selector, c->op_bytes);
-       if (rc != 0)
+       if (rc != X86EMUL_CONTINUE)
                return rc;
 
-       rc = kvm_load_segment_descriptor(ctxt->vcpu, (u16)selector, seg);
+       rc = load_segment_descriptor(ctxt, ops, (u16)selector, seg);
        return rc;
 }
 
@@ -1332,7 +1602,7 @@ static int emulate_popa(struct x86_emulate_ctxt *ctxt,
                        struct x86_emulate_ops *ops)
 {
        struct decode_cache *c = &ctxt->decode;
-       int rc = 0;
+       int rc = X86EMUL_CONTINUE;
        int reg = VCPU_REGS_RDI;
 
        while (reg >= VCPU_REGS_RAX) {
@@ -1343,7 +1613,7 @@ static int emulate_popa(struct x86_emulate_ctxt *ctxt,
                }
 
                rc = emulate_pop(ctxt, ops, &c->regs[reg], c->op_bytes);
-               if (rc != 0)
+               if (rc != X86EMUL_CONTINUE)
                        break;
                --reg;
        }
@@ -1354,12 +1624,8 @@ static inline int emulate_grp1a(struct x86_emulate_ctxt *ctxt,
                                struct x86_emulate_ops *ops)
 {
        struct decode_cache *c = &ctxt->decode;
-       int rc;
 
-       rc = emulate_pop(ctxt, ops, &c->dst.val, c->dst.bytes);
-       if (rc != 0)
-               return rc;
-       return 0;
+       return emulate_pop(ctxt, ops, &c->dst.val, c->dst.bytes);
 }
 
 static inline void emulate_grp2(struct x86_emulate_ctxt *ctxt)
@@ -1395,7 +1661,6 @@ static inline int emulate_grp3(struct x86_emulate_ctxt *ctxt,
                               struct x86_emulate_ops *ops)
 {
        struct decode_cache *c = &ctxt->decode;
-       int rc = 0;
 
        switch (c->modrm_reg) {
        case 0 ... 1:   /* test */
@@ -1408,11 +1673,9 @@ static inline int emulate_grp3(struct x86_emulate_ctxt *ctxt,
                emulate_1op("neg", c->dst, ctxt->eflags);
                break;
        default:
-               DPRINTF("Cannot emulate %02x\n", c->b);
-               rc = X86EMUL_UNHANDLEABLE;
-               break;
+               return 0;
        }
-       return rc;
+       return 1;
 }
 
 static inline int emulate_grp45(struct x86_emulate_ctxt *ctxt,
@@ -1442,20 +1705,14 @@ static inline int emulate_grp45(struct x86_emulate_ctxt *ctxt,
                emulate_push(ctxt);
                break;
        }
-       return 0;
+       return X86EMUL_CONTINUE;
 }
 
 static inline int emulate_grp9(struct x86_emulate_ctxt *ctxt,
-                              struct x86_emulate_ops *ops,
-                              unsigned long memop)
+                              struct x86_emulate_ops *ops)
 {
        struct decode_cache *c = &ctxt->decode;
-       u64 old, new;
-       int rc;
-
-       rc = ops->read_emulated(memop, &old, 8, ctxt->vcpu);
-       if (rc != X86EMUL_CONTINUE)
-               return rc;
+       u64 old = c->dst.orig_val;
 
        if (((u32) (old >> 0) != (u32) c->regs[VCPU_REGS_RAX]) ||
            ((u32) (old >> 32) != (u32) c->regs[VCPU_REGS_RDX])) {
@@ -1463,17 +1720,13 @@ static inline int emulate_grp9(struct x86_emulate_ctxt *ctxt,
                c->regs[VCPU_REGS_RAX] = (u32) (old >> 0);
                c->regs[VCPU_REGS_RDX] = (u32) (old >> 32);
                ctxt->eflags &= ~EFLG_ZF;
-
        } else {
-               new = ((u64)c->regs[VCPU_REGS_RCX] << 32) |
+               c->dst.val = ((u64)c->regs[VCPU_REGS_RCX] << 32) |
                       (u32) c->regs[VCPU_REGS_RBX];
 
-               rc = ops->cmpxchg_emulated(memop, &old, &new, 8, ctxt->vcpu);
-               if (rc != X86EMUL_CONTINUE)
-                       return rc;
                ctxt->eflags |= EFLG_ZF;
        }
-       return 0;
+       return X86EMUL_CONTINUE;
 }
 
 static int emulate_ret_far(struct x86_emulate_ctxt *ctxt,
@@ -1484,14 +1737,14 @@ static int emulate_ret_far(struct x86_emulate_ctxt *ctxt,
        unsigned long cs;
 
        rc = emulate_pop(ctxt, ops, &c->eip, c->op_bytes);
-       if (rc)
+       if (rc != X86EMUL_CONTINUE)
                return rc;
        if (c->op_bytes == 4)
                c->eip = (u32)c->eip;
        rc = emulate_pop(ctxt, ops, &cs, c->op_bytes);
-       if (rc)
+       if (rc != X86EMUL_CONTINUE)
                return rc;
-       rc = kvm_load_segment_descriptor(ctxt->vcpu, (u16)cs, VCPU_SREG_CS);
+       rc = load_segment_descriptor(ctxt, ops, (u16)cs, VCPU_SREG_CS);
        return rc;
 }
 
@@ -1544,7 +1797,7 @@ static inline int writeback(struct x86_emulate_ctxt *ctxt,
        default:
                break;
        }
-       return 0;
+       return X86EMUL_CONTINUE;
 }
 
 static void toggle_interruptibility(struct x86_emulate_ctxt *ctxt, u32 mask)
@@ -1598,8 +1851,11 @@ emulate_syscall(struct x86_emulate_ctxt *ctxt)
        u64 msr_data;
 
        /* syscall is not available in real mode */
-       if (ctxt->mode == X86EMUL_MODE_REAL || ctxt->mode == X86EMUL_MODE_VM86)
-               return X86EMUL_UNHANDLEABLE;
+       if (ctxt->mode == X86EMUL_MODE_REAL ||
+           ctxt->mode == X86EMUL_MODE_VM86) {
+               kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+               return X86EMUL_PROPAGATE_FAULT;
+       }
 
        setup_syscalls_segments(ctxt, &cs, &ss);
 
@@ -1649,14 +1905,16 @@ emulate_sysenter(struct x86_emulate_ctxt *ctxt)
        /* inject #GP if in real mode */
        if (ctxt->mode == X86EMUL_MODE_REAL) {
                kvm_inject_gp(ctxt->vcpu, 0);
-               return X86EMUL_UNHANDLEABLE;
+               return X86EMUL_PROPAGATE_FAULT;
        }
 
        /* XXX sysenter/sysexit have not been tested in 64bit mode.
        * Therefore, we inject an #UD.
        */
-       if (ctxt->mode == X86EMUL_MODE_PROT64)
-               return X86EMUL_UNHANDLEABLE;
+       if (ctxt->mode == X86EMUL_MODE_PROT64) {
+               kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+               return X86EMUL_PROPAGATE_FAULT;
+       }
 
        setup_syscalls_segments(ctxt, &cs, &ss);
 
@@ -1711,7 +1969,7 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt)
        if (ctxt->mode == X86EMUL_MODE_REAL ||
            ctxt->mode == X86EMUL_MODE_VM86) {
                kvm_inject_gp(ctxt->vcpu, 0);
-               return X86EMUL_UNHANDLEABLE;
+               return X86EMUL_PROPAGATE_FAULT;
        }
 
        setup_syscalls_segments(ctxt, &cs, &ss);
@@ -1756,7 +2014,8 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt)
        return X86EMUL_CONTINUE;
 }
 
-static bool emulator_bad_iopl(struct x86_emulate_ctxt *ctxt)
+static bool emulator_bad_iopl(struct x86_emulate_ctxt *ctxt,
+                             struct x86_emulate_ops *ops)
 {
        int iopl;
        if (ctxt->mode == X86EMUL_MODE_REAL)
@@ -1764,7 +2023,7 @@ static bool emulator_bad_iopl(struct x86_emulate_ctxt *ctxt)
        if (ctxt->mode == X86EMUL_MODE_VM86)
                return true;
        iopl = (ctxt->eflags & X86_EFLAGS_IOPL) >> IOPL_SHIFT;
-       return kvm_x86_ops->get_cpl(ctxt->vcpu) > iopl;
+       return ops->cpl(ctxt->vcpu) > iopl;
 }
 
 static bool emulator_io_port_access_allowed(struct x86_emulate_ctxt *ctxt,
@@ -1801,22 +2060,419 @@ static bool emulator_io_permited(struct x86_emulate_ctxt *ctxt,
                                 struct x86_emulate_ops *ops,
                                 u16 port, u16 len)
 {
-       if (emulator_bad_iopl(ctxt))
+       if (emulator_bad_iopl(ctxt, ops))
                if (!emulator_io_port_access_allowed(ctxt, ops, port, len))
                        return false;
        return true;
 }
 
+static u32 get_cached_descriptor_base(struct x86_emulate_ctxt *ctxt,
+                                     struct x86_emulate_ops *ops,
+                                     int seg)
+{
+       struct desc_struct desc;
+       if (ops->get_cached_descriptor(&desc, seg, ctxt->vcpu))
+               return get_desc_base(&desc);
+       else
+               return ~0;
+}
+
+static void save_state_to_tss16(struct x86_emulate_ctxt *ctxt,
+                               struct x86_emulate_ops *ops,
+                               struct tss_segment_16 *tss)
+{
+       struct decode_cache *c = &ctxt->decode;
+
+       tss->ip = c->eip;
+       tss->flag = ctxt->eflags;
+       tss->ax = c->regs[VCPU_REGS_RAX];
+       tss->cx = c->regs[VCPU_REGS_RCX];
+       tss->dx = c->regs[VCPU_REGS_RDX];
+       tss->bx = c->regs[VCPU_REGS_RBX];
+       tss->sp = c->regs[VCPU_REGS_RSP];
+       tss->bp = c->regs[VCPU_REGS_RBP];
+       tss->si = c->regs[VCPU_REGS_RSI];
+       tss->di = c->regs[VCPU_REGS_RDI];
+
+       tss->es = ops->get_segment_selector(VCPU_SREG_ES, ctxt->vcpu);
+       tss->cs = ops->get_segment_selector(VCPU_SREG_CS, ctxt->vcpu);
+       tss->ss = ops->get_segment_selector(VCPU_SREG_SS, ctxt->vcpu);
+       tss->ds = ops->get_segment_selector(VCPU_SREG_DS, ctxt->vcpu);
+       tss->ldt = ops->get_segment_selector(VCPU_SREG_LDTR, ctxt->vcpu);
+}
+
+static int load_state_from_tss16(struct x86_emulate_ctxt *ctxt,
+                                struct x86_emulate_ops *ops,
+                                struct tss_segment_16 *tss)
+{
+       struct decode_cache *c = &ctxt->decode;
+       int ret;
+
+       c->eip = tss->ip;
+       ctxt->eflags = tss->flag | 2;
+       c->regs[VCPU_REGS_RAX] = tss->ax;
+       c->regs[VCPU_REGS_RCX] = tss->cx;
+       c->regs[VCPU_REGS_RDX] = tss->dx;
+       c->regs[VCPU_REGS_RBX] = tss->bx;
+       c->regs[VCPU_REGS_RSP] = tss->sp;
+       c->regs[VCPU_REGS_RBP] = tss->bp;
+       c->regs[VCPU_REGS_RSI] = tss->si;
+       c->regs[VCPU_REGS_RDI] = tss->di;
+
+       /*
+        * SDM says that segment selectors are loaded before segment
+        * descriptors
+        */
+       ops->set_segment_selector(tss->ldt, VCPU_SREG_LDTR, ctxt->vcpu);
+       ops->set_segment_selector(tss->es, VCPU_SREG_ES, ctxt->vcpu);
+       ops->set_segment_selector(tss->cs, VCPU_SREG_CS, ctxt->vcpu);
+       ops->set_segment_selector(tss->ss, VCPU_SREG_SS, ctxt->vcpu);
+       ops->set_segment_selector(tss->ds, VCPU_SREG_DS, ctxt->vcpu);
+
+       /*
+        * Now load segment descriptors. If fault happenes at this stage
+        * it is handled in a context of new task
+        */
+       ret = load_segment_descriptor(ctxt, ops, tss->ldt, VCPU_SREG_LDTR);
+       if (ret != X86EMUL_CONTINUE)
+               return ret;
+       ret = load_segment_descriptor(ctxt, ops, tss->es, VCPU_SREG_ES);
+       if (ret != X86EMUL_CONTINUE)
+               return ret;
+       ret = load_segment_descriptor(ctxt, ops, tss->cs, VCPU_SREG_CS);
+       if (ret != X86EMUL_CONTINUE)
+               return ret;
+       ret = load_segment_descriptor(ctxt, ops, tss->ss, VCPU_SREG_SS);
+       if (ret != X86EMUL_CONTINUE)
+               return ret;
+       ret = load_segment_descriptor(ctxt, ops, tss->ds, VCPU_SREG_DS);
+       if (ret != X86EMUL_CONTINUE)
+               return ret;
+
+       return X86EMUL_CONTINUE;
+}
+
+static int task_switch_16(struct x86_emulate_ctxt *ctxt,
+                         struct x86_emulate_ops *ops,
+                         u16 tss_selector, u16 old_tss_sel,
+                         ulong old_tss_base, struct desc_struct *new_desc)
+{
+       struct tss_segment_16 tss_seg;
+       int ret;
+       u32 err, new_tss_base = get_desc_base(new_desc);
+
+       ret = ops->read_std(old_tss_base, &tss_seg, sizeof tss_seg, ctxt->vcpu,
+                           &err);
+       if (ret == X86EMUL_PROPAGATE_FAULT) {
+               /* FIXME: need to provide precise fault address */
+               kvm_inject_page_fault(ctxt->vcpu, old_tss_base, err);
+               return ret;
+       }
+
+       save_state_to_tss16(ctxt, ops, &tss_seg);
+
+       ret = ops->write_std(old_tss_base, &tss_seg, sizeof tss_seg, ctxt->vcpu,
+                            &err);
+       if (ret == X86EMUL_PROPAGATE_FAULT) {
+               /* FIXME: need to provide precise fault address */
+               kvm_inject_page_fault(ctxt->vcpu, old_tss_base, err);
+               return ret;
+       }
+
+       ret = ops->read_std(new_tss_base, &tss_seg, sizeof tss_seg, ctxt->vcpu,
+                           &err);
+       if (ret == X86EMUL_PROPAGATE_FAULT) {
+               /* FIXME: need to provide precise fault address */
+               kvm_inject_page_fault(ctxt->vcpu, new_tss_base, err);
+               return ret;
+       }
+
+       if (old_tss_sel != 0xffff) {
+               tss_seg.prev_task_link = old_tss_sel;
+
+               ret = ops->write_std(new_tss_base,
+                                    &tss_seg.prev_task_link,
+                                    sizeof tss_seg.prev_task_link,
+                                    ctxt->vcpu, &err);
+               if (ret == X86EMUL_PROPAGATE_FAULT) {
+                       /* FIXME: need to provide precise fault address */
+                       kvm_inject_page_fault(ctxt->vcpu, new_tss_base, err);
+                       return ret;
+               }
+       }
+
+       return load_state_from_tss16(ctxt, ops, &tss_seg);
+}
+
+static void save_state_to_tss32(struct x86_emulate_ctxt *ctxt,
+                               struct x86_emulate_ops *ops,
+                               struct tss_segment_32 *tss)
+{
+       struct decode_cache *c = &ctxt->decode;
+
+       tss->cr3 = ops->get_cr(3, ctxt->vcpu);
+       tss->eip = c->eip;
+       tss->eflags = ctxt->eflags;
+       tss->eax = c->regs[VCPU_REGS_RAX];
+       tss->ecx = c->regs[VCPU_REGS_RCX];
+       tss->edx = c->regs[VCPU_REGS_RDX];
+       tss->ebx = c->regs[VCPU_REGS_RBX];
+       tss->esp = c->regs[VCPU_REGS_RSP];
+       tss->ebp = c->regs[VCPU_REGS_RBP];
+       tss->esi = c->regs[VCPU_REGS_RSI];
+       tss->edi = c->regs[VCPU_REGS_RDI];
+
+       tss->es = ops->get_segment_selector(VCPU_SREG_ES, ctxt->vcpu);
+       tss->cs = ops->get_segment_selector(VCPU_SREG_CS, ctxt->vcpu);
+       tss->ss = ops->get_segment_selector(VCPU_SREG_SS, ctxt->vcpu);
+       tss->ds = ops->get_segment_selector(VCPU_SREG_DS, ctxt->vcpu);
+       tss->fs = ops->get_segment_selector(VCPU_SREG_FS, ctxt->vcpu);
+       tss->gs = ops->get_segment_selector(VCPU_SREG_GS, ctxt->vcpu);
+       tss->ldt_selector = ops->get_segment_selector(VCPU_SREG_LDTR, ctxt->vcpu);
+}
+
+static int load_state_from_tss32(struct x86_emulate_ctxt *ctxt,
+                                struct x86_emulate_ops *ops,
+                                struct tss_segment_32 *tss)
+{
+       struct decode_cache *c = &ctxt->decode;
+       int ret;
+
+       ops->set_cr(3, tss->cr3, ctxt->vcpu);
+       c->eip = tss->eip;
+       ctxt->eflags = tss->eflags | 2;
+       c->regs[VCPU_REGS_RAX] = tss->eax;
+       c->regs[VCPU_REGS_RCX] = tss->ecx;
+       c->regs[VCPU_REGS_RDX] = tss->edx;
+       c->regs[VCPU_REGS_RBX] = tss->ebx;
+       c->regs[VCPU_REGS_RSP] = tss->esp;
+       c->regs[VCPU_REGS_RBP] = tss->ebp;
+       c->regs[VCPU_REGS_RSI] = tss->esi;
+       c->regs[VCPU_REGS_RDI] = tss->edi;
+
+       /*
+        * SDM says that segment selectors are loaded before segment
+        * descriptors
+        */
+       ops->set_segment_selector(tss->ldt_selector, VCPU_SREG_LDTR, ctxt->vcpu);
+       ops->set_segment_selector(tss->es, VCPU_SREG_ES, ctxt->vcpu);
+       ops->set_segment_selector(tss->cs, VCPU_SREG_CS, ctxt->vcpu);
+       ops->set_segment_selector(tss->ss, VCPU_SREG_SS, ctxt->vcpu);
+       ops->set_segment_selector(tss->ds, VCPU_SREG_DS, ctxt->vcpu);
+       ops->set_segment_selector(tss->fs, VCPU_SREG_FS, ctxt->vcpu);
+       ops->set_segment_selector(tss->gs, VCPU_SREG_GS, ctxt->vcpu);
+
+       /*
+        * Now load segment descriptors. If fault happenes at this stage
+        * it is handled in a context of new task
+        */
+       ret = load_segment_descriptor(ctxt, ops, tss->ldt_selector, VCPU_SREG_LDTR);
+       if (ret != X86EMUL_CONTINUE)
+               return ret;
+       ret = load_segment_descriptor(ctxt, ops, tss->es, VCPU_SREG_ES);
+       if (ret != X86EMUL_CONTINUE)
+               return ret;
+       ret = load_segment_descriptor(ctxt, ops, tss->cs, VCPU_SREG_CS);
+       if (ret != X86EMUL_CONTINUE)
+               return ret;
+       ret = load_segment_descriptor(ctxt, ops, tss->ss, VCPU_SREG_SS);
+       if (ret != X86EMUL_CONTINUE)
+               return ret;
+       ret = load_segment_descriptor(ctxt, ops, tss->ds, VCPU_SREG_DS);
+       if (ret != X86EMUL_CONTINUE)
+               return ret;
+       ret = load_segment_descriptor(ctxt, ops, tss->fs, VCPU_SREG_FS);
+       if (ret != X86EMUL_CONTINUE)
+               return ret;
+       ret = load_segment_descriptor(ctxt, ops, tss->gs, VCPU_SREG_GS);
+       if (ret != X86EMUL_CONTINUE)
+               return ret;
+
+       return X86EMUL_CONTINUE;
+}
+
+static int task_switch_32(struct x86_emulate_ctxt *ctxt,
+                         struct x86_emulate_ops *ops,
+                         u16 tss_selector, u16 old_tss_sel,
+                         ulong old_tss_base, struct desc_struct *new_desc)
+{
+       struct tss_segment_32 tss_seg;
+       int ret;
+       u32 err, new_tss_base = get_desc_base(new_desc);
+
+       ret = ops->read_std(old_tss_base, &tss_seg, sizeof tss_seg, ctxt->vcpu,
+                           &err);
+       if (ret == X86EMUL_PROPAGATE_FAULT) {
+               /* FIXME: need to provide precise fault address */
+               kvm_inject_page_fault(ctxt->vcpu, old_tss_base, err);
+               return ret;
+       }
+
+       save_state_to_tss32(ctxt, ops, &tss_seg);
+
+       ret = ops->write_std(old_tss_base, &tss_seg, sizeof tss_seg, ctxt->vcpu,
+                            &err);
+       if (ret == X86EMUL_PROPAGATE_FAULT) {
+               /* FIXME: need to provide precise fault address */
+               kvm_inject_page_fault(ctxt->vcpu, old_tss_base, err);
+               return ret;
+       }
+
+       ret = ops->read_std(new_tss_base, &tss_seg, sizeof tss_seg, ctxt->vcpu,
+                           &err);
+       if (ret == X86EMUL_PROPAGATE_FAULT) {
+               /* FIXME: need to provide precise fault address */
+               kvm_inject_page_fault(ctxt->vcpu, new_tss_base, err);
+               return ret;
+       }
+
+       if (old_tss_sel != 0xffff) {
+               tss_seg.prev_task_link = old_tss_sel;
+
+               ret = ops->write_std(new_tss_base,
+                                    &tss_seg.prev_task_link,
+                                    sizeof tss_seg.prev_task_link,
+                                    ctxt->vcpu, &err);
+               if (ret == X86EMUL_PROPAGATE_FAULT) {
+                       /* FIXME: need to provide precise fault address */
+                       kvm_inject_page_fault(ctxt->vcpu, new_tss_base, err);
+                       return ret;
+               }
+       }
+
+       return load_state_from_tss32(ctxt, ops, &tss_seg);
+}
+
+static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt,
+                                  struct x86_emulate_ops *ops,
+                                  u16 tss_selector, int reason,
+                                  bool has_error_code, u32 error_code)
+{
+       struct desc_struct curr_tss_desc, next_tss_desc;
+       int ret;
+       u16 old_tss_sel = ops->get_segment_selector(VCPU_SREG_TR, ctxt->vcpu);
+       ulong old_tss_base =
+               get_cached_descriptor_base(ctxt, ops, VCPU_SREG_TR);
+       u32 desc_limit;
+
+       /* FIXME: old_tss_base == ~0 ? */
+
+       ret = read_segment_descriptor(ctxt, ops, tss_selector, &next_tss_desc);
+       if (ret != X86EMUL_CONTINUE)
+               return ret;
+       ret = read_segment_descriptor(ctxt, ops, old_tss_sel, &curr_tss_desc);
+       if (ret != X86EMUL_CONTINUE)
+               return ret;
+
+       /* FIXME: check that next_tss_desc is tss */
+
+       if (reason != TASK_SWITCH_IRET) {
+               if ((tss_selector & 3) > next_tss_desc.dpl ||
+                   ops->cpl(ctxt->vcpu) > next_tss_desc.dpl) {
+                       kvm_inject_gp(ctxt->vcpu, 0);
+                       return X86EMUL_PROPAGATE_FAULT;
+               }
+       }
+
+       desc_limit = desc_limit_scaled(&next_tss_desc);
+       if (!next_tss_desc.p ||
+           ((desc_limit < 0x67 && (next_tss_desc.type & 8)) ||
+            desc_limit < 0x2b)) {
+               kvm_queue_exception_e(ctxt->vcpu, TS_VECTOR,
+                                     tss_selector & 0xfffc);
+               return X86EMUL_PROPAGATE_FAULT;
+       }
+
+       if (reason == TASK_SWITCH_IRET || reason == TASK_SWITCH_JMP) {
+               curr_tss_desc.type &= ~(1 << 1); /* clear busy flag */
+               write_segment_descriptor(ctxt, ops, old_tss_sel,
+                                        &curr_tss_desc);
+       }
+
+       if (reason == TASK_SWITCH_IRET)
+               ctxt->eflags = ctxt->eflags & ~X86_EFLAGS_NT;
+
+       /* set back link to prev task only if NT bit is set in eflags
+          note that old_tss_sel is not used afetr this point */
+       if (reason != TASK_SWITCH_CALL && reason != TASK_SWITCH_GATE)
+               old_tss_sel = 0xffff;
+
+       if (next_tss_desc.type & 8)
+               ret = task_switch_32(ctxt, ops, tss_selector, old_tss_sel,
+                                    old_tss_base, &next_tss_desc);
+       else
+               ret = task_switch_16(ctxt, ops, tss_selector, old_tss_sel,
+                                    old_tss_base, &next_tss_desc);
+       if (ret != X86EMUL_CONTINUE)
+               return ret;
+
+       if (reason == TASK_SWITCH_CALL || reason == TASK_SWITCH_GATE)
+               ctxt->eflags = ctxt->eflags | X86_EFLAGS_NT;
+
+       if (reason != TASK_SWITCH_IRET) {
+               next_tss_desc.type |= (1 << 1); /* set busy flag */
+               write_segment_descriptor(ctxt, ops, tss_selector,
+                                        &next_tss_desc);
+       }
+
+       ops->set_cr(0,  ops->get_cr(0, ctxt->vcpu) | X86_CR0_TS, ctxt->vcpu);
+       ops->set_cached_descriptor(&next_tss_desc, VCPU_SREG_TR, ctxt->vcpu);
+       ops->set_segment_selector(tss_selector, VCPU_SREG_TR, ctxt->vcpu);
+
+       if (has_error_code) {
+               struct decode_cache *c = &ctxt->decode;
+
+               c->op_bytes = c->ad_bytes = (next_tss_desc.type & 8) ? 4 : 2;
+               c->lock_prefix = 0;
+               c->src.val = (unsigned long) error_code;
+               emulate_push(ctxt);
+       }
+
+       return ret;
+}
+
+int emulator_task_switch(struct x86_emulate_ctxt *ctxt,
+                        struct x86_emulate_ops *ops,
+                        u16 tss_selector, int reason,
+                        bool has_error_code, u32 error_code)
+{
+       struct decode_cache *c = &ctxt->decode;
+       int rc;
+
+       memset(c, 0, sizeof(struct decode_cache));
+       c->eip = ctxt->eip;
+       memcpy(c->regs, ctxt->vcpu->arch.regs, sizeof c->regs);
+       c->dst.type = OP_NONE;
+
+       rc = emulator_do_task_switch(ctxt, ops, tss_selector, reason,
+                                    has_error_code, error_code);
+
+       if (rc == X86EMUL_CONTINUE) {
+               memcpy(ctxt->vcpu->arch.regs, c->regs, sizeof c->regs);
+               kvm_rip_write(ctxt->vcpu, c->eip);
+               rc = writeback(ctxt, ops);
+       }
+
+       return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
+}
+
+static void string_addr_inc(struct x86_emulate_ctxt *ctxt, unsigned long base,
+                           int reg, struct operand *op)
+{
+       struct decode_cache *c = &ctxt->decode;
+       int df = (ctxt->eflags & EFLG_DF) ? -1 : 1;
+
+       register_address_increment(c, &c->regs[reg], df * op->bytes);
+       op->ptr = (unsigned long *)register_address(c,  base, c->regs[reg]);
+}
+
 int
 x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
 {
-       unsigned long memop = 0;
        u64 msr_data;
-       unsigned long saved_eip = 0;
        struct decode_cache *c = &ctxt->decode;
-       unsigned int port;
-       int io_dir_in;
-       int rc = 0;
+       int rc = X86EMUL_CONTINUE;
+       int saved_dst_type = c->dst.type;
 
        ctxt->interruptibility = 0;
 
@@ -1826,26 +2482,30 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
         */
 
        memcpy(c->regs, ctxt->vcpu->arch.regs, sizeof c->regs);
-       saved_eip = c->eip;
+
+       if (ctxt->mode == X86EMUL_MODE_PROT64 && (c->d & No64)) {
+               kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+               goto done;
+       }
 
        /* LOCK prefix is allowed only with some instructions */
-       if (c->lock_prefix && !(c->d & Lock)) {
+       if (c->lock_prefix && (!(c->d & Lock) || c->dst.type != OP_MEM)) {
                kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
                goto done;
        }
 
        /* Privileged instruction can be executed only in CPL=0 */
-       if ((c->d & Priv) && kvm_x86_ops->get_cpl(ctxt->vcpu)) {
+       if ((c->d & Priv) && ops->cpl(ctxt->vcpu)) {
                kvm_inject_gp(ctxt->vcpu, 0);
                goto done;
        }
 
-       if (((c->d & ModRM) && (c->modrm_mod != 3)) || (c->d & MemAbs))
-               memop = c->modrm_ea;
-
        if (c->rep_prefix && (c->d & String)) {
+               ctxt->restart = true;
                /* All REP prefixes have the same first termination condition */
-               if (c->regs[VCPU_REGS_RCX] == 0) {
+               if (address_mask(c, c->regs[VCPU_REGS_RCX]) == 0) {
+               string_done:
+                       ctxt->restart = false;
                        kvm_rip_write(ctxt->vcpu, c->eip);
                        goto done;
                }
@@ -1857,25 +2517,18 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
                 *      - if REPNE/REPNZ and ZF = 1 then done
                 */
                if ((c->b == 0xa6) || (c->b == 0xa7) ||
-                               (c->b == 0xae) || (c->b == 0xaf)) {
+                   (c->b == 0xae) || (c->b == 0xaf)) {
                        if ((c->rep_prefix == REPE_PREFIX) &&
-                               ((ctxt->eflags & EFLG_ZF) == 0)) {
-                                       kvm_rip_write(ctxt->vcpu, c->eip);
-                                       goto done;
-                       }
+                           ((ctxt->eflags & EFLG_ZF) == 0))
+                               goto string_done;
                        if ((c->rep_prefix == REPNE_PREFIX) &&
-                               ((ctxt->eflags & EFLG_ZF) == EFLG_ZF)) {
-                               kvm_rip_write(ctxt->vcpu, c->eip);
-                               goto done;
-                       }
+                           ((ctxt->eflags & EFLG_ZF) == EFLG_ZF))
+                               goto string_done;
                }
-               c->regs[VCPU_REGS_RCX]--;
-               c->eip = kvm_rip_read(ctxt->vcpu);
+               c->eip = ctxt->eip;
        }
 
        if (c->src.type == OP_MEM) {
-               c->src.ptr = (unsigned long *)memop;
-               c->src.val = 0;
                rc = ops->read_emulated((unsigned long)c->src.ptr,
                                        &c->src.val,
                                        c->src.bytes,
@@ -1885,29 +2538,25 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
                c->src.orig_val = c->src.val;
        }
 
+       if (c->src2.type == OP_MEM) {
+               rc = ops->read_emulated((unsigned long)c->src2.ptr,
+                                       &c->src2.val,
+                                       c->src2.bytes,
+                                       ctxt->vcpu);
+               if (rc != X86EMUL_CONTINUE)
+                       goto done;
+       }
+
        if ((c->d & DstMask) == ImplicitOps)
                goto special_insn;
 
 
-       if (c->dst.type == OP_MEM) {
-               c->dst.ptr = (unsigned long *)memop;
-               c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
-               c->dst.val = 0;
-               if (c->d & BitOp) {
-                       unsigned long mask = ~(c->dst.bytes * 8 - 1);
-
-                       c->dst.ptr = (void *)c->dst.ptr +
-                                                  (c->src.val & mask) / 8;
-               }
-               if (!(c->d & Mov)) {
-                       /* optimisation - avoid slow emulated read */
-                       rc = ops->read_emulated((unsigned long)c->dst.ptr,
-                                               &c->dst.val,
-                                               c->dst.bytes,
-                                               ctxt->vcpu);
-                       if (rc != X86EMUL_CONTINUE)
-                               goto done;
-               }
+       if ((c->dst.type == OP_MEM) && !(c->d & Mov)) {
+               /* optimisation - avoid slow emulated read if Mov */
+               rc = ops->read_emulated((unsigned long)c->dst.ptr, &c->dst.val,
+                                       c->dst.bytes, ctxt->vcpu);
+               if (rc != X86EMUL_CONTINUE)
+                       goto done;
        }
        c->dst.orig_val = c->dst.val;
 
@@ -1926,7 +2575,7 @@ special_insn:
                break;
        case 0x07:              /* pop es */
                rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_ES);
-               if (rc != 0)
+               if (rc != X86EMUL_CONTINUE)
                        goto done;
                break;
        case 0x08 ... 0x0d:
@@ -1945,7 +2594,7 @@ special_insn:
                break;
        case 0x17:              /* pop ss */
                rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_SS);
-               if (rc != 0)
+               if (rc != X86EMUL_CONTINUE)
                        goto done;
                break;
        case 0x18 ... 0x1d:
@@ -1957,7 +2606,7 @@ special_insn:
                break;
        case 0x1f:              /* pop ds */
                rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_DS);
-               if (rc != 0)
+               if (rc != X86EMUL_CONTINUE)
                        goto done;
                break;
        case 0x20 ... 0x25:
@@ -1988,7 +2637,7 @@ special_insn:
        case 0x58 ... 0x5f: /* pop reg */
        pop_instruction:
                rc = emulate_pop(ctxt, ops, &c->dst.val, c->op_bytes);
-               if (rc != 0)
+               if (rc != X86EMUL_CONTINUE)
                        goto done;
                break;
        case 0x60:      /* pusha */
@@ -1996,7 +2645,7 @@ special_insn:
                break;
        case 0x61:      /* popa */
                rc = emulate_popa(ctxt, ops);
-               if (rc != 0)
+               if (rc != X86EMUL_CONTINUE)
                        goto done;
                break;
        case 0x63:              /* movsxd */
@@ -2010,47 +2659,29 @@ special_insn:
                break;
        case 0x6c:              /* insb */
        case 0x6d:              /* insw/insd */
+               c->dst.bytes = min(c->dst.bytes, 4u);
                if (!emulator_io_permited(ctxt, ops, c->regs[VCPU_REGS_RDX],
-                                         (c->d & ByteOp) ? 1 : c->op_bytes)) {
+                                         c->dst.bytes)) {
                        kvm_inject_gp(ctxt->vcpu, 0);
                        goto done;
                }
-               if (kvm_emulate_pio_string(ctxt->vcpu,
-                               1,
-                               (c->d & ByteOp) ? 1 : c->op_bytes,
-                               c->rep_prefix ?
-                               address_mask(c, c->regs[VCPU_REGS_RCX]) : 1,
-                               (ctxt->eflags & EFLG_DF),
-                               register_address(c, es_base(ctxt),
-                                                c->regs[VCPU_REGS_RDI]),
-                               c->rep_prefix,
-                               c->regs[VCPU_REGS_RDX]) == 0) {
-                       c->eip = saved_eip;
-                       return -1;
-               }
-               return 0;
+               if (!pio_in_emulated(ctxt, ops, c->dst.bytes,
+                                    c->regs[VCPU_REGS_RDX], &c->dst.val))
+                       goto done; /* IO is needed, skip writeback */
+               break;
        case 0x6e:              /* outsb */
        case 0x6f:              /* outsw/outsd */
+               c->src.bytes = min(c->src.bytes, 4u);
                if (!emulator_io_permited(ctxt, ops, c->regs[VCPU_REGS_RDX],
-                                         (c->d & ByteOp) ? 1 : c->op_bytes)) {
+                                         c->src.bytes)) {
                        kvm_inject_gp(ctxt->vcpu, 0);
                        goto done;
                }
-               if (kvm_emulate_pio_string(ctxt->vcpu,
-                               0,
-                               (c->d & ByteOp) ? 1 : c->op_bytes,
-                               c->rep_prefix ?
-                               address_mask(c, c->regs[VCPU_REGS_RCX]) : 1,
-                               (ctxt->eflags & EFLG_DF),
-                                        register_address(c,
-                                         seg_override_base(ctxt, c),
-                                                c->regs[VCPU_REGS_RSI]),
-                               c->rep_prefix,
-                               c->regs[VCPU_REGS_RDX]) == 0) {
-                       c->eip = saved_eip;
-                       return -1;
-               }
-               return 0;
+               ops->pio_out_emulated(c->src.bytes, c->regs[VCPU_REGS_RDX],
+                                     &c->src.val, 1, ctxt->vcpu);
+
+               c->dst.type = OP_NONE; /* nothing to writeback */
+               break;
        case 0x70 ... 0x7f: /* jcc (short) */
                if (test_cc(c->b, ctxt->eflags))
                        jmp_rel(c, c->src.val);
@@ -2107,12 +2738,11 @@ special_insn:
        case 0x8c: { /* mov r/m, sreg */
                struct kvm_segment segreg;
 
-               if (c->modrm_reg <= 5)
+               if (c->modrm_reg <= VCPU_SREG_GS)
                        kvm_get_segment(ctxt->vcpu, &segreg, c->modrm_reg);
                else {
-                       printk(KERN_INFO "0x8c: Invalid segreg in modrm byte 0x%02x\n",
-                              c->modrm);
-                       goto cannot_emulate;
+                       kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+                       goto done;
                }
                c->dst.val = segreg.selector;
                break;
@@ -2132,16 +2762,16 @@ special_insn:
                }
 
                if (c->modrm_reg == VCPU_SREG_SS)
-                       toggle_interruptibility(ctxt, X86_SHADOW_INT_MOV_SS);
+                       toggle_interruptibility(ctxt, KVM_X86_SHADOW_INT_MOV_SS);
 
-               rc = kvm_load_segment_descriptor(ctxt->vcpu, sel, c->modrm_reg);
+               rc = load_segment_descriptor(ctxt, ops, sel, c->modrm_reg);
 
                c->dst.type = OP_NONE;  /* Disable writeback. */
                break;
        }
        case 0x8f:              /* pop (sole member of Grp1a) */
                rc = emulate_grp1a(ctxt, ops);
-               if (rc != 0)
+               if (rc != X86EMUL_CONTINUE)
                        goto done;
                break;
        case 0x90: /* nop / xchg r8,rax */
@@ -2175,89 +2805,16 @@ special_insn:
                c->dst.val = (unsigned long)c->regs[VCPU_REGS_RAX];
                break;
        case 0xa4 ... 0xa5:     /* movs */
-               c->dst.type = OP_MEM;
-               c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
-               c->dst.ptr = (unsigned long *)register_address(c,
-                                                  es_base(ctxt),
-                                                  c->regs[VCPU_REGS_RDI]);
-               rc = ops->read_emulated(register_address(c,
-                                               seg_override_base(ctxt, c),
-                                               c->regs[VCPU_REGS_RSI]),
-                                       &c->dst.val,
-                                       c->dst.bytes, ctxt->vcpu);
-               if (rc != X86EMUL_CONTINUE)
-                       goto done;
-               register_address_increment(c, &c->regs[VCPU_REGS_RSI],
-                                      (ctxt->eflags & EFLG_DF) ? -c->dst.bytes
-                                                          : c->dst.bytes);
-               register_address_increment(c, &c->regs[VCPU_REGS_RDI],
-                                      (ctxt->eflags & EFLG_DF) ? -c->dst.bytes
-                                                          : c->dst.bytes);
-               break;
+               goto mov;
        case 0xa6 ... 0xa7:     /* cmps */
-               c->src.type = OP_NONE; /* Disable writeback. */
-               c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
-               c->src.ptr = (unsigned long *)register_address(c,
-                                      seg_override_base(ctxt, c),
-                                                  c->regs[VCPU_REGS_RSI]);
-               rc = ops->read_emulated((unsigned long)c->src.ptr,
-                                       &c->src.val,
-                                       c->src.bytes,
-                                       ctxt->vcpu);
-               if (rc != X86EMUL_CONTINUE)
-                       goto done;
-
                c->dst.type = OP_NONE; /* Disable writeback. */
-               c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
-               c->dst.ptr = (unsigned long *)register_address(c,
-                                                  es_base(ctxt),
-                                                  c->regs[VCPU_REGS_RDI]);
-               rc = ops->read_emulated((unsigned long)c->dst.ptr,
-                                       &c->dst.val,
-                                       c->dst.bytes,
-                                       ctxt->vcpu);
-               if (rc != X86EMUL_CONTINUE)
-                       goto done;
-
                DPRINTF("cmps: mem1=0x%p mem2=0x%p\n", c->src.ptr, c->dst.ptr);
-
-               emulate_2op_SrcV("cmp", c->src, c->dst, ctxt->eflags);
-
-               register_address_increment(c, &c->regs[VCPU_REGS_RSI],
-                                      (ctxt->eflags & EFLG_DF) ? -c->src.bytes
-                                                                 : c->src.bytes);
-               register_address_increment(c, &c->regs[VCPU_REGS_RDI],
-                                      (ctxt->eflags & EFLG_DF) ? -c->dst.bytes
-                                                                 : c->dst.bytes);
-
-               break;
+               goto cmp;
        case 0xaa ... 0xab:     /* stos */
-               c->dst.type = OP_MEM;
-               c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
-               c->dst.ptr = (unsigned long *)register_address(c,
-                                                  es_base(ctxt),
-                                                  c->regs[VCPU_REGS_RDI]);
                c->dst.val = c->regs[VCPU_REGS_RAX];
-               register_address_increment(c, &c->regs[VCPU_REGS_RDI],
-                                      (ctxt->eflags & EFLG_DF) ? -c->dst.bytes
-                                                          : c->dst.bytes);
                break;
        case 0xac ... 0xad:     /* lods */
-               c->dst.type = OP_REG;
-               c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
-               c->dst.ptr = (unsigned long *)&c->regs[VCPU_REGS_RAX];
-               rc = ops->read_emulated(register_address(c,
-                                               seg_override_base(ctxt, c),
-                                               c->regs[VCPU_REGS_RSI]),
-                                       &c->dst.val,
-                                       c->dst.bytes,
-                                       ctxt->vcpu);
-               if (rc != X86EMUL_CONTINUE)
-                       goto done;
-               register_address_increment(c, &c->regs[VCPU_REGS_RSI],
-                                      (ctxt->eflags & EFLG_DF) ? -c->dst.bytes
-                                                          : c->dst.bytes);
-               break;
+               goto mov;
        case 0xae ... 0xaf:     /* scas */
                DPRINTF("Urk! I don't handle SCAS.\n");
                goto cannot_emulate;
@@ -2277,7 +2834,7 @@ special_insn:
                break;
        case 0xcb:              /* ret far */
                rc = emulate_ret_far(ctxt, ops);
-               if (rc)
+               if (rc != X86EMUL_CONTINUE)
                        goto done;
                break;
        case 0xd0 ... 0xd1:     /* Grp2 */
@@ -2290,14 +2847,10 @@ special_insn:
                break;
        case 0xe4:      /* inb */
        case 0xe5:      /* in */
-               port = c->src.val;
-               io_dir_in = 1;
-               goto do_io;
+               goto do_io_in;
        case 0xe6: /* outb */
        case 0xe7: /* out */
-               port = c->src.val;
-               io_dir_in = 0;
-               goto do_io;
+               goto do_io_out;
        case 0xe8: /* call (near) */ {
                long int rel = c->src.val;
                c->src.val = (unsigned long) c->eip;
@@ -2308,8 +2861,9 @@ special_insn:
        case 0xe9: /* jmp rel */
                goto jmp;
        case 0xea: /* jmp far */
-               if (kvm_load_segment_descriptor(ctxt->vcpu, c->src2.val,
-                                               VCPU_SREG_CS))
+       jump_far:
+               if (load_segment_descriptor(ctxt, ops, c->src2.val,
+                                           VCPU_SREG_CS))
                        goto done;
 
                c->eip = c->src.val;
@@ -2321,25 +2875,29 @@ special_insn:
                break;
        case 0xec: /* in al,dx */
        case 0xed: /* in (e/r)ax,dx */
-               port = c->regs[VCPU_REGS_RDX];
-               io_dir_in = 1;
-               goto do_io;
+               c->src.val = c->regs[VCPU_REGS_RDX];
+       do_io_in:
+               c->dst.bytes = min(c->dst.bytes, 4u);
+               if (!emulator_io_permited(ctxt, ops, c->src.val, c->dst.bytes)) {
+                       kvm_inject_gp(ctxt->vcpu, 0);
+                       goto done;
+               }
+               if (!pio_in_emulated(ctxt, ops, c->dst.bytes, c->src.val,
+                                    &c->dst.val))
+                       goto done; /* IO is needed */
+               break;
        case 0xee: /* out al,dx */
        case 0xef: /* out (e/r)ax,dx */
-               port = c->regs[VCPU_REGS_RDX];
-               io_dir_in = 0;
-       do_io:
-               if (!emulator_io_permited(ctxt, ops, port,
-                                         (c->d & ByteOp) ? 1 : c->op_bytes)) {
+               c->src.val = c->regs[VCPU_REGS_RDX];
+       do_io_out:
+               c->dst.bytes = min(c->dst.bytes, 4u);
+               if (!emulator_io_permited(ctxt, ops, c->src.val, c->dst.bytes)) {
                        kvm_inject_gp(ctxt->vcpu, 0);
                        goto done;
                }
-               if (kvm_emulate_pio(ctxt->vcpu, io_dir_in,
-                                  (c->d & ByteOp) ? 1 : c->op_bytes,
-                                  port) != 0) {
-                       c->eip = saved_eip;
-                       goto cannot_emulate;
-               }
+               ops->pio_out_emulated(c->dst.bytes, c->src.val, &c->dst.val, 1,
+                                     ctxt->vcpu);
+               c->dst.type = OP_NONE;  /* Disable writeback. */
                break;
        case 0xf4:              /* hlt */
                ctxt->vcpu->arch.halt_request = 1;
@@ -2350,16 +2908,15 @@ special_insn:
                c->dst.type = OP_NONE;  /* Disable writeback. */
                break;
        case 0xf6 ... 0xf7:     /* Grp3 */
-               rc = emulate_grp3(ctxt, ops);
-               if (rc != 0)
-                       goto done;
+               if (!emulate_grp3(ctxt, ops))
+                       goto cannot_emulate;
                break;
        case 0xf8: /* clc */
                ctxt->eflags &= ~EFLG_CF;
                c->dst.type = OP_NONE;  /* Disable writeback. */
                break;
        case 0xfa: /* cli */
-               if (emulator_bad_iopl(ctxt))
+               if (emulator_bad_iopl(ctxt, ops))
                        kvm_inject_gp(ctxt->vcpu, 0);
                else {
                        ctxt->eflags &= ~X86_EFLAGS_IF;
@@ -2367,10 +2924,10 @@ special_insn:
                }
                break;
        case 0xfb: /* sti */
-               if (emulator_bad_iopl(ctxt))
+               if (emulator_bad_iopl(ctxt, ops))
                        kvm_inject_gp(ctxt->vcpu, 0);
                else {
-                       toggle_interruptibility(ctxt, X86_SHADOW_INT_STI);
+                       toggle_interruptibility(ctxt, KVM_X86_SHADOW_INT_STI);
                        ctxt->eflags |= X86_EFLAGS_IF;
                        c->dst.type = OP_NONE;  /* Disable writeback. */
                }
@@ -2383,28 +2940,55 @@ special_insn:
                ctxt->eflags |= EFLG_DF;
                c->dst.type = OP_NONE;  /* Disable writeback. */
                break;
-       case 0xfe ... 0xff:     /* Grp4/Grp5 */
+       case 0xfe: /* Grp4 */
+       grp45:
                rc = emulate_grp45(ctxt, ops);
-               if (rc != 0)
+               if (rc != X86EMUL_CONTINUE)
                        goto done;
                break;
+       case 0xff: /* Grp5 */
+               if (c->modrm_reg == 5)
+                       goto jump_far;
+               goto grp45;
        }
 
 writeback:
        rc = writeback(ctxt, ops);
-       if (rc != 0)
+       if (rc != X86EMUL_CONTINUE)
                goto done;
 
+       /*
+        * restore dst type in case the decoding will be reused
+        * (happens for string instruction )
+        */
+       c->dst.type = saved_dst_type;
+
+       if ((c->d & SrcMask) == SrcSI)
+               string_addr_inc(ctxt, seg_override_base(ctxt, c), VCPU_REGS_RSI,
+                               &c->src);
+
+       if ((c->d & DstMask) == DstDI)
+               string_addr_inc(ctxt, es_base(ctxt), VCPU_REGS_RDI, &c->dst);
+
+       if (c->rep_prefix && (c->d & String)) {
+               struct read_cache *rc = &ctxt->decode.io_read;
+               register_address_increment(c, &c->regs[VCPU_REGS_RCX], -1);
+               /*
+                * Re-enter guest when pio read ahead buffer is empty or,
+                * if it is not used, after each 1024 iteration.
+                */
+               if ((rc->end == 0 && !(c->regs[VCPU_REGS_RCX] & 0x3ff)) ||
+                   (rc->end != 0 && rc->end == rc->pos))
+                       ctxt->restart = false;
+       }
+
        /* Commit shadow register state. */
        memcpy(ctxt->vcpu->arch.regs, c->regs, sizeof c->regs);
        kvm_rip_write(ctxt->vcpu, c->eip);
+       ops->set_rflags(ctxt->vcpu, ctxt->eflags);
 
 done:
-       if (rc == X86EMUL_UNHANDLEABLE) {
-               c->eip = saved_eip;
-               return -1;
-       }
-       return 0;
+       return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
 
 twobyte_insn:
        switch (c->b) {
@@ -2418,18 +3002,18 @@ twobyte_insn:
                                goto cannot_emulate;
 
                        rc = kvm_fix_hypercall(ctxt->vcpu);
-                       if (rc)
+                       if (rc != X86EMUL_CONTINUE)
                                goto done;
 
                        /* Let the processor re-execute the fixed hypercall */
-                       c->eip = kvm_rip_read(ctxt->vcpu);
+                       c->eip = ctxt->eip;
                        /* Disable writeback. */
                        c->dst.type = OP_NONE;
                        break;
                case 2: /* lgdt */
                        rc = read_descriptor(ctxt, ops, c->src.ptr,
                                             &size, &address, c->op_bytes);
-                       if (rc)
+                       if (rc != X86EMUL_CONTINUE)
                                goto done;
                        realmode_lgdt(ctxt->vcpu, size, address);
                        /* Disable writeback. */
@@ -2440,7 +3024,7 @@ twobyte_insn:
                                switch (c->modrm_rm) {
                                case 1:
                                        rc = kvm_fix_hypercall(ctxt->vcpu);
-                                       if (rc)
+                                       if (rc != X86EMUL_CONTINUE)
                                                goto done;
                                        break;
                                default:
@@ -2450,7 +3034,7 @@ twobyte_insn:
                                rc = read_descriptor(ctxt, ops, c->src.ptr,
                                                     &size, &address,
                                                     c->op_bytes);
-                               if (rc)
+                               if (rc != X86EMUL_CONTINUE)
                                        goto done;
                                realmode_lidt(ctxt->vcpu, size, address);
                        }
@@ -2459,15 +3043,18 @@ twobyte_insn:
                        break;
                case 4: /* smsw */
                        c->dst.bytes = 2;
-                       c->dst.val = realmode_get_cr(ctxt->vcpu, 0);
+                       c->dst.val = ops->get_cr(0, ctxt->vcpu);
                        break;
                case 6: /* lmsw */
-                       realmode_lmsw(ctxt->vcpu, (u16)c->src.val,
-                                     &ctxt->eflags);
+                       ops->set_cr(0, (ops->get_cr(0, ctxt->vcpu) & ~0x0ful) |
+                                   (c->src.val & 0x0f), ctxt->vcpu);
                        c->dst.type = OP_NONE;
                        break;
+               case 5: /* not defined */
+                       kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+                       goto done;
                case 7: /* invlpg*/
-                       emulate_invlpg(ctxt->vcpu, memop);
+                       emulate_invlpg(ctxt->vcpu, c->modrm_ea);
                        /* Disable writeback. */
                        c->dst.type = OP_NONE;
                        break;
@@ -2493,54 +3080,54 @@ twobyte_insn:
                c->dst.type = OP_NONE;
                break;
        case 0x20: /* mov cr, reg */
-               if (c->modrm_mod != 3)
-                       goto cannot_emulate;
-               c->regs[c->modrm_rm] =
-                               realmode_get_cr(ctxt->vcpu, c->modrm_reg);
+               switch (c->modrm_reg) {
+               case 1:
+               case 5 ... 7:
+               case 9 ... 15:
+                       kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+                       goto done;
+               }
+               c->regs[c->modrm_rm] = ops->get_cr(c->modrm_reg, ctxt->vcpu);
                c->dst.type = OP_NONE;  /* no writeback */
                break;
        case 0x21: /* mov from dr to reg */
-               if (c->modrm_mod != 3)
-                       goto cannot_emulate;
-               rc = emulator_get_dr(ctxt, c->modrm_reg, &c->regs[c->modrm_rm]);
-               if (rc)
-                       goto cannot_emulate;
+               if ((ops->get_cr(4, ctxt->vcpu) & X86_CR4_DE) &&
+                   (c->modrm_reg == 4 || c->modrm_reg == 5)) {
+                       kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+                       goto done;
+               }
+               emulator_get_dr(ctxt, c->modrm_reg, &c->regs[c->modrm_rm]);
                c->dst.type = OP_NONE;  /* no writeback */
                break;
        case 0x22: /* mov reg, cr */
-               if (c->modrm_mod != 3)
-                       goto cannot_emulate;
-               realmode_set_cr(ctxt->vcpu,
-                               c->modrm_reg, c->modrm_val, &ctxt->eflags);
+               ops->set_cr(c->modrm_reg, c->modrm_val, ctxt->vcpu);
                c->dst.type = OP_NONE;
                break;
        case 0x23: /* mov from reg to dr */
-               if (c->modrm_mod != 3)
-                       goto cannot_emulate;
-               rc = emulator_set_dr(ctxt, c->modrm_reg,
-                                    c->regs[c->modrm_rm]);
-               if (rc)
-                       goto cannot_emulate;
+               if ((ops->get_cr(4, ctxt->vcpu) & X86_CR4_DE) &&
+                   (c->modrm_reg == 4 || c->modrm_reg == 5)) {
+                       kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+                       goto done;
+               }
+               emulator_set_dr(ctxt, c->modrm_reg, c->regs[c->modrm_rm]);
                c->dst.type = OP_NONE;  /* no writeback */
                break;
        case 0x30:
                /* wrmsr */
                msr_data = (u32)c->regs[VCPU_REGS_RAX]
                        | ((u64)c->regs[VCPU_REGS_RDX] << 32);
-               rc = kvm_set_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], msr_data);
-               if (rc) {
+               if (kvm_set_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], msr_data)) {
                        kvm_inject_gp(ctxt->vcpu, 0);
-                       c->eip = kvm_rip_read(ctxt->vcpu);
+                       goto done;
                }
                rc = X86EMUL_CONTINUE;
                c->dst.type = OP_NONE;
                break;
        case 0x32:
                /* rdmsr */
-               rc = kvm_get_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], &msr_data);
-               if (rc) {
+               if (kvm_get_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], &msr_data)) {
                        kvm_inject_gp(ctxt->vcpu, 0);
-                       c->eip = kvm_rip_read(ctxt->vcpu);
+                       goto done;
                } else {
                        c->regs[VCPU_REGS_RAX] = (u32)msr_data;
                        c->regs[VCPU_REGS_RDX] = msr_data >> 32;
@@ -2577,7 +3164,7 @@ twobyte_insn:
                break;
        case 0xa1:       /* pop fs */
                rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_FS);
-               if (rc != 0)
+               if (rc != X86EMUL_CONTINUE)
                        goto done;
                break;
        case 0xa3:
@@ -2596,7 +3183,7 @@ twobyte_insn:
                break;
        case 0xa9:      /* pop gs */
                rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_GS);
-               if (rc != 0)
+               if (rc != X86EMUL_CONTINUE)
                        goto done;
                break;
        case 0xab:
@@ -2668,16 +3255,14 @@ twobyte_insn:
                                                        (u64) c->src.val;
                break;
        case 0xc7:              /* Grp9 (cmpxchg8b) */
-               rc = emulate_grp9(ctxt, ops, memop);
-               if (rc != 0)
+               rc = emulate_grp9(ctxt, ops);
+               if (rc != X86EMUL_CONTINUE)
                        goto done;
-               c->dst.type = OP_NONE;
                break;
        }
        goto writeback;
 
 cannot_emulate:
        DPRINTF("Cannot emulate %02x\n", c->b);
-       c->eip = saved_eip;
        return -1;
 }
index a790fa128a9fada66d5e816bc342b2b27186a92a..93825ff3338fae9940b612c0814f9a3864cbd213 100644 (file)
 #include <linux/kvm_host.h>
 #include "trace.h"
 
+static void pic_lock(struct kvm_pic *s)
+       __acquires(&s->lock)
+{
+       raw_spin_lock(&s->lock);
+}
+
+static void pic_unlock(struct kvm_pic *s)
+       __releases(&s->lock)
+{
+       bool wakeup = s->wakeup_needed;
+       struct kvm_vcpu *vcpu;
+
+       s->wakeup_needed = false;
+
+       raw_spin_unlock(&s->lock);
+
+       if (wakeup) {
+               vcpu = s->kvm->bsp_vcpu;
+               if (vcpu)
+                       kvm_vcpu_kick(vcpu);
+       }
+}
+
 static void pic_clear_isr(struct kvm_kpic_state *s, int irq)
 {
        s->isr &= ~(1 << irq);
@@ -45,19 +68,19 @@ static void pic_clear_isr(struct kvm_kpic_state *s, int irq)
         * Other interrupt may be delivered to PIC while lock is dropped but
         * it should be safe since PIC state is already updated at this stage.
         */
-       raw_spin_unlock(&s->pics_state->lock);
+       pic_unlock(s->pics_state);
        kvm_notify_acked_irq(s->pics_state->kvm, SELECT_PIC(irq), irq);
-       raw_spin_lock(&s->pics_state->lock);
+       pic_lock(s->pics_state);
 }
 
 void kvm_pic_clear_isr_ack(struct kvm *kvm)
 {
        struct kvm_pic *s = pic_irqchip(kvm);
 
-       raw_spin_lock(&s->lock);
+       pic_lock(s);
        s->pics[0].isr_ack = 0xff;
        s->pics[1].isr_ack = 0xff;
-       raw_spin_unlock(&s->lock);
+       pic_unlock(s);
 }
 
 /*
@@ -158,9 +181,9 @@ static void pic_update_irq(struct kvm_pic *s)
 
 void kvm_pic_update_irq(struct kvm_pic *s)
 {
-       raw_spin_lock(&s->lock);
+       pic_lock(s);
        pic_update_irq(s);
-       raw_spin_unlock(&s->lock);
+       pic_unlock(s);
 }
 
 int kvm_pic_set_irq(void *opaque, int irq, int level)
@@ -168,14 +191,14 @@ int kvm_pic_set_irq(void *opaque, int irq, int level)
        struct kvm_pic *s = opaque;
        int ret = -1;
 
-       raw_spin_lock(&s->lock);
+       pic_lock(s);
        if (irq >= 0 && irq < PIC_NUM_PINS) {
                ret = pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
                pic_update_irq(s);
                trace_kvm_pic_set_irq(irq >> 3, irq & 7, s->pics[irq >> 3].elcr,
                                      s->pics[irq >> 3].imr, ret == 0);
        }
-       raw_spin_unlock(&s->lock);
+       pic_unlock(s);
 
        return ret;
 }
@@ -205,7 +228,7 @@ int kvm_pic_read_irq(struct kvm *kvm)
        int irq, irq2, intno;
        struct kvm_pic *s = pic_irqchip(kvm);
 
-       raw_spin_lock(&s->lock);
+       pic_lock(s);
        irq = pic_get_irq(&s->pics[0]);
        if (irq >= 0) {
                pic_intack(&s->pics[0], irq);
@@ -230,7 +253,7 @@ int kvm_pic_read_irq(struct kvm *kvm)
                intno = s->pics[0].irq_base + irq;
        }
        pic_update_irq(s);
-       raw_spin_unlock(&s->lock);
+       pic_unlock(s);
 
        return intno;
 }
@@ -444,7 +467,7 @@ static int picdev_write(struct kvm_io_device *this,
                        printk(KERN_ERR "PIC: non byte write\n");
                return 0;
        }
-       raw_spin_lock(&s->lock);
+       pic_lock(s);
        switch (addr) {
        case 0x20:
        case 0x21:
@@ -457,7 +480,7 @@ static int picdev_write(struct kvm_io_device *this,
                elcr_ioport_write(&s->pics[addr & 1], addr, data);
                break;
        }
-       raw_spin_unlock(&s->lock);
+       pic_unlock(s);
        return 0;
 }
 
@@ -474,7 +497,7 @@ static int picdev_read(struct kvm_io_device *this,
                        printk(KERN_ERR "PIC: non byte read\n");
                return 0;
        }
-       raw_spin_lock(&s->lock);
+       pic_lock(s);
        switch (addr) {
        case 0x20:
        case 0x21:
@@ -488,7 +511,7 @@ static int picdev_read(struct kvm_io_device *this,
                break;
        }
        *(unsigned char *)val = data;
-       raw_spin_unlock(&s->lock);
+       pic_unlock(s);
        return 0;
 }
 
@@ -505,7 +528,7 @@ static void pic_irq_request(void *opaque, int level)
        s->output = level;
        if (vcpu && level && (s->pics[0].isr_ack & (1 << irq))) {
                s->pics[0].isr_ack &= ~(1 << irq);
-               kvm_vcpu_kick(vcpu);
+               s->wakeup_needed = true;
        }
 }
 
index 34b15915754d80f459088a1696c9d16f79c3bd5b..cd1f362f413d7bcee70920360388d944867a2ed9 100644 (file)
@@ -63,6 +63,7 @@ struct kvm_kpic_state {
 
 struct kvm_pic {
        raw_spinlock_t lock;
+       bool wakeup_needed;
        unsigned pending_acks;
        struct kvm *kvm;
        struct kvm_kpic_state pics[2]; /* 0 is master pic, 1 is slave pic */
index 55c7524dda549579bafdbf6089072ef6f8f5c14f..64bc6ea78d90961c2f3095fd62c3e130d3cf98aa 100644 (file)
@@ -10,9 +10,7 @@ struct kvm_timer {
 };
 
 struct kvm_timer_ops {
-        bool (*is_periodic)(struct kvm_timer *);
+       bool (*is_periodic)(struct kvm_timer *);
 };
 
-
 enum hrtimer_restart kvm_timer_fn(struct hrtimer *data);
-
index 19a8906bcaa2c5301dddf55821078248a85e23a7..81563e76e28f28a6f046630e1c13dbffd7215232 100644 (file)
@@ -148,7 +148,6 @@ module_param(oos_shadow, bool, 0644);
 
 #include <trace/events/kvm.h>
 
-#undef TRACE_INCLUDE_FILE
 #define CREATE_TRACE_POINTS
 #include "mmutrace.h"
 
@@ -174,12 +173,7 @@ struct kvm_shadow_walk_iterator {
             shadow_walk_okay(&(_walker));                      \
             shadow_walk_next(&(_walker)))
 
-
-struct kvm_unsync_walk {
-       int (*entry) (struct kvm_mmu_page *sp, struct kvm_unsync_walk *walk);
-};
-
-typedef int (*mmu_parent_walk_fn) (struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp);
+typedef int (*mmu_parent_walk_fn) (struct kvm_mmu_page *sp);
 
 static struct kmem_cache *pte_chain_cache;
 static struct kmem_cache *rmap_desc_cache;
@@ -223,7 +217,7 @@ void kvm_mmu_set_mask_ptes(u64 user_mask, u64 accessed_mask,
 }
 EXPORT_SYMBOL_GPL(kvm_mmu_set_mask_ptes);
 
-static int is_write_protection(struct kvm_vcpu *vcpu)
+static bool is_write_protection(struct kvm_vcpu *vcpu)
 {
        return kvm_read_cr0_bits(vcpu, X86_CR0_WP);
 }
@@ -327,7 +321,6 @@ static int mmu_topup_memory_cache_page(struct kvm_mmu_memory_cache *cache,
                page = alloc_page(GFP_KERNEL);
                if (!page)
                        return -ENOMEM;
-               set_page_private(page, 0);
                cache->objects[cache->nobjs++] = page_address(page);
        }
        return 0;
@@ -438,9 +431,9 @@ static void unaccount_shadowed(struct kvm *kvm, gfn_t gfn)
        int i;
 
        gfn = unalias_gfn(kvm, gfn);
+       slot = gfn_to_memslot_unaliased(kvm, gfn);
        for (i = PT_DIRECTORY_LEVEL;
             i < PT_PAGE_TABLE_LEVEL + KVM_NR_PAGE_SIZES; ++i) {
-               slot          = gfn_to_memslot_unaliased(kvm, gfn);
                write_count   = slot_largepage_idx(gfn, slot, i);
                *write_count -= 1;
                WARN_ON(*write_count < 0);
@@ -654,7 +647,6 @@ static void rmap_remove(struct kvm *kvm, u64 *spte)
 static u64 *rmap_next(struct kvm *kvm, unsigned long *rmapp, u64 *spte)
 {
        struct kvm_rmap_desc *desc;
-       struct kvm_rmap_desc *prev_desc;
        u64 *prev_spte;
        int i;
 
@@ -666,7 +658,6 @@ static u64 *rmap_next(struct kvm *kvm, unsigned long *rmapp, u64 *spte)
                return NULL;
        }
        desc = (struct kvm_rmap_desc *)(*rmapp & ~1ul);
-       prev_desc = NULL;
        prev_spte = NULL;
        while (desc) {
                for (i = 0; i < RMAP_EXT && desc->sptes[i]; ++i) {
@@ -794,7 +785,7 @@ static int kvm_handle_hva(struct kvm *kvm, unsigned long hva,
        int retval = 0;
        struct kvm_memslots *slots;
 
-       slots = rcu_dereference(kvm->memslots);
+       slots = kvm_memslots(kvm);
 
        for (i = 0; i < slots->nmemslots; i++) {
                struct kvm_memory_slot *memslot = &slots->memslots[i];
@@ -925,7 +916,6 @@ static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu,
        sp->gfns = mmu_memory_cache_alloc(&vcpu->arch.mmu_page_cache, PAGE_SIZE);
        set_page_private(virt_to_page(sp->spt), (unsigned long)sp);
        list_add(&sp->link, &vcpu->kvm->arch.active_mmu_pages);
-       INIT_LIST_HEAD(&sp->oos_link);
        bitmap_zero(sp->slot_bitmap, KVM_MEMORY_SLOTS + KVM_PRIVATE_MEM_SLOTS);
        sp->multimapped = 0;
        sp->parent_pte = parent_pte;
@@ -1009,8 +999,7 @@ static void mmu_page_remove_parent_pte(struct kvm_mmu_page *sp,
 }
 
 
-static void mmu_parent_walk(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
-                           mmu_parent_walk_fn fn)
+static void mmu_parent_walk(struct kvm_mmu_page *sp, mmu_parent_walk_fn fn)
 {
        struct kvm_pte_chain *pte_chain;
        struct hlist_node *node;
@@ -1019,8 +1008,8 @@ static void mmu_parent_walk(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
 
        if (!sp->multimapped && sp->parent_pte) {
                parent_sp = page_header(__pa(sp->parent_pte));
-               fn(vcpu, parent_sp);
-               mmu_parent_walk(vcpu, parent_sp, fn);
+               fn(parent_sp);
+               mmu_parent_walk(parent_sp, fn);
                return;
        }
        hlist_for_each_entry(pte_chain, node, &sp->parent_ptes, link)
@@ -1028,8 +1017,8 @@ static void mmu_parent_walk(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
                        if (!pte_chain->parent_ptes[i])
                                break;
                        parent_sp = page_header(__pa(pte_chain->parent_ptes[i]));
-                       fn(vcpu, parent_sp);
-                       mmu_parent_walk(vcpu, parent_sp, fn);
+                       fn(parent_sp);
+                       mmu_parent_walk(parent_sp, fn);
                }
 }
 
@@ -1066,16 +1055,15 @@ static void kvm_mmu_update_parents_unsync(struct kvm_mmu_page *sp)
                }
 }
 
-static int unsync_walk_fn(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
+static int unsync_walk_fn(struct kvm_mmu_page *sp)
 {
        kvm_mmu_update_parents_unsync(sp);
        return 1;
 }
 
-static void kvm_mmu_mark_parents_unsync(struct kvm_vcpu *vcpu,
-                                       struct kvm_mmu_page *sp)
+static void kvm_mmu_mark_parents_unsync(struct kvm_mmu_page *sp)
 {
-       mmu_parent_walk(vcpu, sp, unsync_walk_fn);
+       mmu_parent_walk(sp, unsync_walk_fn);
        kvm_mmu_update_parents_unsync(sp);
 }
 
@@ -1201,6 +1189,7 @@ static struct kvm_mmu_page *kvm_mmu_lookup_page(struct kvm *kvm, gfn_t gfn)
 static void kvm_unlink_unsync_page(struct kvm *kvm, struct kvm_mmu_page *sp)
 {
        WARN_ON(!sp->unsync);
+       trace_kvm_mmu_sync_page(sp);
        sp->unsync = 0;
        --kvm->stat.mmu_unsync;
 }
@@ -1209,12 +1198,11 @@ static int kvm_mmu_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp);
 
 static int kvm_sync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
 {
-       if (sp->role.glevels != vcpu->arch.mmu.root_level) {
+       if (sp->role.cr4_pae != !!is_pae(vcpu)) {
                kvm_mmu_zap_page(vcpu->kvm, sp);
                return 1;
        }
 
-       trace_kvm_mmu_sync_page(sp);
        if (rmap_write_protect(vcpu->kvm, sp->gfn))
                kvm_flush_remote_tlbs(vcpu->kvm);
        kvm_unlink_unsync_page(vcpu->kvm, sp);
@@ -1331,6 +1319,8 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
        role = vcpu->arch.mmu.base_role;
        role.level = level;
        role.direct = direct;
+       if (role.direct)
+               role.cr4_pae = 0;
        role.access = access;
        if (vcpu->arch.mmu.root_level <= PT32_ROOT_LEVEL) {
                quadrant = gaddr >> (PAGE_SHIFT + (PT64_PT_BITS * level));
@@ -1351,7 +1341,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
                        mmu_page_add_parent_pte(vcpu, sp, parent_pte);
                        if (sp->unsync_children) {
                                set_bit(KVM_REQ_MMU_SYNC, &vcpu->requests);
-                               kvm_mmu_mark_parents_unsync(vcpu, sp);
+                               kvm_mmu_mark_parents_unsync(sp);
                        }
                        trace_kvm_mmu_get_page(sp, false);
                        return sp;
@@ -1573,13 +1563,14 @@ static int kvm_mmu_unprotect_page(struct kvm *kvm, gfn_t gfn)
        r = 0;
        index = kvm_page_table_hashfn(gfn);
        bucket = &kvm->arch.mmu_page_hash[index];
+restart:
        hlist_for_each_entry_safe(sp, node, n, bucket, hash_link)
                if (sp->gfn == gfn && !sp->role.direct) {
                        pgprintk("%s: gfn %lx role %x\n", __func__, gfn,
                                 sp->role.word);
                        r = 1;
                        if (kvm_mmu_zap_page(kvm, sp))
-                               n = bucket->first;
+                               goto restart;
                }
        return r;
 }
@@ -1593,13 +1584,14 @@ static void mmu_unshadow(struct kvm *kvm, gfn_t gfn)
 
        index = kvm_page_table_hashfn(gfn);
        bucket = &kvm->arch.mmu_page_hash[index];
+restart:
        hlist_for_each_entry_safe(sp, node, nn, bucket, hash_link) {
                if (sp->gfn == gfn && !sp->role.direct
                    && !sp->role.invalid) {
                        pgprintk("%s: zap %lx %x\n",
                                 __func__, gfn, sp->role.word);
                        if (kvm_mmu_zap_page(kvm, sp))
-                               nn = bucket->first;
+                               goto restart;
                }
        }
 }
@@ -1626,20 +1618,6 @@ static void mmu_convert_notrap(struct kvm_mmu_page *sp)
        }
 }
 
-struct page *gva_to_page(struct kvm_vcpu *vcpu, gva_t gva)
-{
-       struct page *page;
-
-       gpa_t gpa = kvm_mmu_gva_to_gpa_read(vcpu, gva, NULL);
-
-       if (gpa == UNMAPPED_GVA)
-               return NULL;
-
-       page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT);
-
-       return page;
-}
-
 /*
  * The function is based on mtrr_type_lookup() in
  * arch/x86/kernel/cpu/mtrr/generic.c
@@ -1752,7 +1730,6 @@ static int kvm_unsync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
        struct kvm_mmu_page *s;
        struct hlist_node *node, *n;
 
-       trace_kvm_mmu_unsync_page(sp);
        index = kvm_page_table_hashfn(sp->gfn);
        bucket = &vcpu->kvm->arch.mmu_page_hash[index];
        /* don't unsync if pagetable is shadowed with multiple roles */
@@ -1762,10 +1739,11 @@ static int kvm_unsync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
                if (s->role.word != sp->role.word)
                        return 1;
        }
+       trace_kvm_mmu_unsync_page(sp);
        ++vcpu->kvm->stat.mmu_unsync;
        sp->unsync = 1;
 
-       kvm_mmu_mark_parents_unsync(vcpu, sp);
+       kvm_mmu_mark_parents_unsync(sp);
 
        mmu_convert_notrap(sp);
        return 0;
@@ -2081,21 +2059,23 @@ static int mmu_alloc_roots(struct kvm_vcpu *vcpu)
                hpa_t root = vcpu->arch.mmu.root_hpa;
 
                ASSERT(!VALID_PAGE(root));
-               if (tdp_enabled)
-                       direct = 1;
                if (mmu_check_root(vcpu, root_gfn))
                        return 1;
+               if (tdp_enabled) {
+                       direct = 1;
+                       root_gfn = 0;
+               }
+               spin_lock(&vcpu->kvm->mmu_lock);
                sp = kvm_mmu_get_page(vcpu, root_gfn, 0,
                                      PT64_ROOT_LEVEL, direct,
                                      ACC_ALL, NULL);
                root = __pa(sp->spt);
                ++sp->root_count;
+               spin_unlock(&vcpu->kvm->mmu_lock);
                vcpu->arch.mmu.root_hpa = root;
                return 0;
        }
        direct = !is_paging(vcpu);
-       if (tdp_enabled)
-               direct = 1;
        for (i = 0; i < 4; ++i) {
                hpa_t root = vcpu->arch.mmu.pae_root[i];
 
@@ -2111,11 +2091,18 @@ static int mmu_alloc_roots(struct kvm_vcpu *vcpu)
                        root_gfn = 0;
                if (mmu_check_root(vcpu, root_gfn))
                        return 1;
+               if (tdp_enabled) {
+                       direct = 1;
+                       root_gfn = i << 30;
+               }
+               spin_lock(&vcpu->kvm->mmu_lock);
                sp = kvm_mmu_get_page(vcpu, root_gfn, i << 30,
                                      PT32_ROOT_LEVEL, direct,
                                      ACC_ALL, NULL);
                root = __pa(sp->spt);
                ++sp->root_count;
+               spin_unlock(&vcpu->kvm->mmu_lock);
+
                vcpu->arch.mmu.pae_root[i] = root | PT_PRESENT_MASK;
        }
        vcpu->arch.mmu.root_hpa = __pa(vcpu->arch.mmu.pae_root);
@@ -2299,13 +2286,19 @@ static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu, int level)
                /* no rsvd bits for 2 level 4K page table entries */
                context->rsvd_bits_mask[0][1] = 0;
                context->rsvd_bits_mask[0][0] = 0;
+               context->rsvd_bits_mask[1][0] = context->rsvd_bits_mask[0][0];
+
+               if (!is_pse(vcpu)) {
+                       context->rsvd_bits_mask[1][1] = 0;
+                       break;
+               }
+
                if (is_cpuid_PSE36())
                        /* 36bits PSE 4MB page */
                        context->rsvd_bits_mask[1][1] = rsvd_bits(17, 21);
                else
                        /* 32 bits PSE 4MB page */
                        context->rsvd_bits_mask[1][1] = rsvd_bits(13, 21);
-               context->rsvd_bits_mask[1][0] = context->rsvd_bits_mask[1][0];
                break;
        case PT32E_ROOT_LEVEL:
                context->rsvd_bits_mask[0][2] =
@@ -2318,7 +2311,7 @@ static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu, int level)
                context->rsvd_bits_mask[1][1] = exb_bit_rsvd |
                        rsvd_bits(maxphyaddr, 62) |
                        rsvd_bits(13, 20);              /* large page */
-               context->rsvd_bits_mask[1][0] = context->rsvd_bits_mask[1][0];
+               context->rsvd_bits_mask[1][0] = context->rsvd_bits_mask[0][0];
                break;
        case PT64_ROOT_LEVEL:
                context->rsvd_bits_mask[0][3] = exb_bit_rsvd |
@@ -2336,7 +2329,7 @@ static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu, int level)
                context->rsvd_bits_mask[1][1] = exb_bit_rsvd |
                        rsvd_bits(maxphyaddr, 51) |
                        rsvd_bits(13, 20);              /* large page */
-               context->rsvd_bits_mask[1][0] = context->rsvd_bits_mask[1][0];
+               context->rsvd_bits_mask[1][0] = context->rsvd_bits_mask[0][0];
                break;
        }
 }
@@ -2438,7 +2431,8 @@ static int init_kvm_softmmu(struct kvm_vcpu *vcpu)
        else
                r = paging32_init_context(vcpu);
 
-       vcpu->arch.mmu.base_role.glevels = vcpu->arch.mmu.root_level;
+       vcpu->arch.mmu.base_role.cr4_pae = !!is_pae(vcpu);
+       vcpu->arch.mmu.base_role.cr0_wp = is_write_protection(vcpu);
 
        return r;
 }
@@ -2478,7 +2472,9 @@ int kvm_mmu_load(struct kvm_vcpu *vcpu)
                goto out;
        spin_lock(&vcpu->kvm->mmu_lock);
        kvm_mmu_free_some_pages(vcpu);
+       spin_unlock(&vcpu->kvm->mmu_lock);
        r = mmu_alloc_roots(vcpu);
+       spin_lock(&vcpu->kvm->mmu_lock);
        mmu_sync_roots(vcpu);
        spin_unlock(&vcpu->kvm->mmu_lock);
        if (r)
@@ -2527,7 +2523,7 @@ static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu,
         }
 
        ++vcpu->kvm->stat.mmu_pte_updated;
-       if (sp->role.glevels == PT32_ROOT_LEVEL)
+       if (!sp->role.cr4_pae)
                paging32_update_pte(vcpu, sp, spte, new);
        else
                paging64_update_pte(vcpu, sp, spte, new);
@@ -2562,36 +2558,11 @@ static bool last_updated_pte_accessed(struct kvm_vcpu *vcpu)
 }
 
 static void mmu_guess_page_from_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
-                                         const u8 *new, int bytes)
+                                         u64 gpte)
 {
        gfn_t gfn;
-       int r;
-       u64 gpte = 0;
        pfn_t pfn;
 
-       if (bytes != 4 && bytes != 8)
-               return;
-
-       /*
-        * Assume that the pte write on a page table of the same type
-        * as the current vcpu paging mode.  This is nearly always true
-        * (might be false while changing modes).  Note it is verified later
-        * by update_pte().
-        */
-       if (is_pae(vcpu)) {
-               /* Handle a 32-bit guest writing two halves of a 64-bit gpte */
-               if ((bytes == 4) && (gpa % 4 == 0)) {
-                       r = kvm_read_guest(vcpu->kvm, gpa & ~(u64)7, &gpte, 8);
-                       if (r)
-                               return;
-                       memcpy((void *)&gpte + (gpa % 8), new, 4);
-               } else if ((bytes == 8) && (gpa % 8 == 0)) {
-                       memcpy((void *)&gpte, new, 8);
-               }
-       } else {
-               if ((bytes == 4) && (gpa % 4 == 0))
-                       memcpy((void *)&gpte, new, 4);
-       }
        if (!is_present_gpte(gpte))
                return;
        gfn = (gpte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT;
@@ -2640,10 +2611,46 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
        int flooded = 0;
        int npte;
        int r;
+       int invlpg_counter;
 
        pgprintk("%s: gpa %llx bytes %d\n", __func__, gpa, bytes);
-       mmu_guess_page_from_pte_write(vcpu, gpa, new, bytes);
+
+       invlpg_counter = atomic_read(&vcpu->kvm->arch.invlpg_counter);
+
+       /*
+        * Assume that the pte write on a page table of the same type
+        * as the current vcpu paging mode.  This is nearly always true
+        * (might be false while changing modes).  Note it is verified later
+        * by update_pte().
+        */
+       if ((is_pae(vcpu) && bytes == 4) || !new) {
+               /* Handle a 32-bit guest writing two halves of a 64-bit gpte */
+               if (is_pae(vcpu)) {
+                       gpa &= ~(gpa_t)7;
+                       bytes = 8;
+               }
+               r = kvm_read_guest(vcpu->kvm, gpa, &gentry, min(bytes, 8));
+               if (r)
+                       gentry = 0;
+               new = (const u8 *)&gentry;
+       }
+
+       switch (bytes) {
+       case 4:
+               gentry = *(const u32 *)new;
+               break;
+       case 8:
+               gentry = *(const u64 *)new;
+               break;
+       default:
+               gentry = 0;
+               break;
+       }
+
+       mmu_guess_page_from_pte_write(vcpu, gpa, gentry);
        spin_lock(&vcpu->kvm->mmu_lock);
+       if (atomic_read(&vcpu->kvm->arch.invlpg_counter) != invlpg_counter)
+               gentry = 0;
        kvm_mmu_access_page(vcpu, gfn);
        kvm_mmu_free_some_pages(vcpu);
        ++vcpu->kvm->stat.mmu_pte_write;
@@ -2662,10 +2669,12 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
        }
        index = kvm_page_table_hashfn(gfn);
        bucket = &vcpu->kvm->arch.mmu_page_hash[index];
+
+restart:
        hlist_for_each_entry_safe(sp, node, n, bucket, hash_link) {
                if (sp->gfn != gfn || sp->role.direct || sp->role.invalid)
                        continue;
-               pte_size = sp->role.glevels == PT32_ROOT_LEVEL ? 4 : 8;
+               pte_size = sp->role.cr4_pae ? 8 : 4;
                misaligned = (offset ^ (offset + bytes - 1)) & ~(pte_size - 1);
                misaligned |= bytes < 4;
                if (misaligned || flooded) {
@@ -2682,14 +2691,14 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
                        pgprintk("misaligned: gpa %llx bytes %d role %x\n",
                                 gpa, bytes, sp->role.word);
                        if (kvm_mmu_zap_page(vcpu->kvm, sp))
-                               n = bucket->first;
+                               goto restart;
                        ++vcpu->kvm->stat.mmu_flooded;
                        continue;
                }
                page_offset = offset;
                level = sp->role.level;
                npte = 1;
-               if (sp->role.glevels == PT32_ROOT_LEVEL) {
+               if (!sp->role.cr4_pae) {
                        page_offset <<= 1;      /* 32->64 */
                        /*
                         * A 32-bit pde maps 4MB while the shadow pdes map
@@ -2707,20 +2716,11 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
                                continue;
                }
                spte = &sp->spt[page_offset / sizeof(*spte)];
-               if ((gpa & (pte_size - 1)) || (bytes < pte_size)) {
-                       gentry = 0;
-                       r = kvm_read_guest_atomic(vcpu->kvm,
-                                                 gpa & ~(u64)(pte_size - 1),
-                                                 &gentry, pte_size);
-                       new = (const void *)&gentry;
-                       if (r < 0)
-                               new = NULL;
-               }
                while (npte--) {
                        entry = *spte;
                        mmu_pte_write_zap_pte(vcpu, sp, spte);
-                       if (new)
-                               mmu_pte_write_new_pte(vcpu, sp, spte, new);
+                       if (gentry)
+                               mmu_pte_write_new_pte(vcpu, sp, spte, &gentry);
                        mmu_pte_write_flush_tlb(vcpu, entry, *spte);
                        ++spte;
                }
@@ -2900,22 +2900,23 @@ void kvm_mmu_zap_all(struct kvm *kvm)
        struct kvm_mmu_page *sp, *node;
 
        spin_lock(&kvm->mmu_lock);
+restart:
        list_for_each_entry_safe(sp, node, &kvm->arch.active_mmu_pages, link)
                if (kvm_mmu_zap_page(kvm, sp))
-                       node = container_of(kvm->arch.active_mmu_pages.next,
-                                           struct kvm_mmu_page, link);
+                       goto restart;
+
        spin_unlock(&kvm->mmu_lock);
 
        kvm_flush_remote_tlbs(kvm);
 }
 
-static void kvm_mmu_remove_one_alloc_mmu_page(struct kvm *kvm)
+static int kvm_mmu_remove_some_alloc_mmu_pages(struct kvm *kvm)
 {
        struct kvm_mmu_page *page;
 
        page = container_of(kvm->arch.active_mmu_pages.prev,
                            struct kvm_mmu_page, link);
-       kvm_mmu_zap_page(kvm, page);
+       return kvm_mmu_zap_page(kvm, page) + 1;
 }
 
 static int mmu_shrink(int nr_to_scan, gfp_t gfp_mask)
@@ -2927,7 +2928,7 @@ static int mmu_shrink(int nr_to_scan, gfp_t gfp_mask)
        spin_lock(&kvm_lock);
 
        list_for_each_entry(kvm, &vm_list, vm_list) {
-               int npages, idx;
+               int npages, idx, freed_pages;
 
                idx = srcu_read_lock(&kvm->srcu);
                spin_lock(&kvm->mmu_lock);
@@ -2935,8 +2936,8 @@ static int mmu_shrink(int nr_to_scan, gfp_t gfp_mask)
                         kvm->arch.n_free_mmu_pages;
                cache_count += npages;
                if (!kvm_freed && nr_to_scan > 0 && npages > 0) {
-                       kvm_mmu_remove_one_alloc_mmu_page(kvm);
-                       cache_count--;
+                       freed_pages = kvm_mmu_remove_some_alloc_mmu_pages(kvm);
+                       cache_count -= freed_pages;
                        kvm_freed = kvm;
                }
                nr_to_scan--;
@@ -3011,7 +3012,8 @@ unsigned int kvm_mmu_calculate_mmu_pages(struct kvm *kvm)
        unsigned int  nr_pages = 0;
        struct kvm_memslots *slots;
 
-       slots = rcu_dereference(kvm->memslots);
+       slots = kvm_memslots(kvm);
+
        for (i = 0; i < slots->nmemslots; i++)
                nr_pages += slots->memslots[i].npages;
 
@@ -3174,8 +3176,7 @@ static gva_t canonicalize(gva_t gva)
 }
 
 
-typedef void (*inspect_spte_fn) (struct kvm *kvm, struct kvm_mmu_page *sp,
-                                u64 *sptep);
+typedef void (*inspect_spte_fn) (struct kvm *kvm, u64 *sptep);
 
 static void __mmu_spte_walk(struct kvm *kvm, struct kvm_mmu_page *sp,
                            inspect_spte_fn fn)
@@ -3191,7 +3192,7 @@ static void __mmu_spte_walk(struct kvm *kvm, struct kvm_mmu_page *sp,
                                child = page_header(ent & PT64_BASE_ADDR_MASK);
                                __mmu_spte_walk(kvm, child, fn);
                        } else
-                               fn(kvm, sp, &sp->spt[i]);
+                               fn(kvm, &sp->spt[i]);
                }
        }
 }
@@ -3282,11 +3283,13 @@ static void audit_mappings(struct kvm_vcpu *vcpu)
 
 static int count_rmaps(struct kvm_vcpu *vcpu)
 {
+       struct kvm *kvm = vcpu->kvm;
+       struct kvm_memslots *slots;
        int nmaps = 0;
        int i, j, k, idx;
 
        idx = srcu_read_lock(&kvm->srcu);
-       slots = rcu_dereference(kvm->memslots);
+       slots = kvm_memslots(kvm);
        for (i = 0; i < KVM_MEMORY_SLOTS; ++i) {
                struct kvm_memory_slot *m = &slots->memslots[i];
                struct kvm_rmap_desc *d;
@@ -3315,7 +3318,7 @@ static int count_rmaps(struct kvm_vcpu *vcpu)
        return nmaps;
 }
 
-void inspect_spte_has_rmap(struct kvm *kvm, struct kvm_mmu_page *sp, u64 *sptep)
+void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep)
 {
        unsigned long *rmapp;
        struct kvm_mmu_page *rev_sp;
@@ -3331,14 +3334,14 @@ void inspect_spte_has_rmap(struct kvm *kvm, struct kvm_mmu_page *sp, u64 *sptep)
                        printk(KERN_ERR "%s: no memslot for gfn %ld\n",
                                         audit_msg, gfn);
                        printk(KERN_ERR "%s: index %ld of sp (gfn=%lx)\n",
-                                       audit_msg, sptep - rev_sp->spt,
+                              audit_msg, (long int)(sptep - rev_sp->spt),
                                        rev_sp->gfn);
                        dump_stack();
                        return;
                }
 
                rmapp = gfn_to_rmap(kvm, rev_sp->gfns[sptep - rev_sp->spt],
-                                   is_large_pte(*sptep));
+                                   rev_sp->role.level);
                if (!*rmapp) {
                        if (!printk_ratelimit())
                                return;
@@ -3373,7 +3376,7 @@ static void check_writable_mappings_rmap(struct kvm_vcpu *vcpu)
                                continue;
                        if (!(ent & PT_WRITABLE_MASK))
                                continue;
-                       inspect_spte_has_rmap(vcpu->kvm, sp, &pt[i]);
+                       inspect_spte_has_rmap(vcpu->kvm, &pt[i]);
                }
        }
        return;
index 3e4a5c6ca2a9df76f82273918513f24db621d6aa..42f07b1bfbc9e7553ecf8fb607cce2f040de9226 100644 (file)
@@ -6,14 +6,12 @@
 
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM kvmmmu
-#define TRACE_INCLUDE_PATH .
-#define TRACE_INCLUDE_FILE mmutrace
 
 #define KVM_MMU_PAGE_FIELDS \
        __field(__u64, gfn) \
        __field(__u32, role) \
        __field(__u32, root_count) \
-       __field(__u32, unsync)
+       __field(bool, unsync)
 
 #define KVM_MMU_PAGE_ASSIGN(sp)                             \
        __entry->gfn = sp->gfn;                      \
                                                                        \
        role.word = __entry->role;                                      \
                                                                        \
-       trace_seq_printf(p, "sp gfn %llx %u/%u q%u%s %s%s %spge"        \
+       trace_seq_printf(p, "sp gfn %llx %u%s q%u%s %s%s"               \
                         " %snxe root %u %s%c",                         \
-                        __entry->gfn, role.level, role.glevels,        \
+                        __entry->gfn, role.level,                      \
+                        role.cr4_pae ? " pae" : "",                    \
                         role.quadrant,                                 \
                         role.direct ? " direct" : "",                  \
                         access_str[role.access],                       \
                         role.invalid ? " invalid" : "",                \
-                        role.cr4_pge ? "" : "!",                       \
                         role.nxe ? "" : "!",                           \
                         __entry->root_count,                           \
                         __entry->unsync ? "unsync" : "sync", 0);       \
@@ -94,15 +92,15 @@ TRACE_EVENT(
        TP_printk("pte %llx level %u", __entry->pte, __entry->level)
 );
 
-/* We set a pte accessed bit */
-TRACE_EVENT(
-       kvm_mmu_set_accessed_bit,
+DECLARE_EVENT_CLASS(kvm_mmu_set_bit_class,
+
        TP_PROTO(unsigned long table_gfn, unsigned index, unsigned size),
+
        TP_ARGS(table_gfn, index, size),
 
        TP_STRUCT__entry(
                __field(__u64, gpa)
-               ),
+       ),
 
        TP_fast_assign(
                __entry->gpa = ((u64)table_gfn << PAGE_SHIFT)
@@ -112,22 +110,20 @@ TRACE_EVENT(
        TP_printk("gpa %llx", __entry->gpa)
 );
 
-/* We set a pte dirty bit */
-TRACE_EVENT(
-       kvm_mmu_set_dirty_bit,
+/* We set a pte accessed bit */
+DEFINE_EVENT(kvm_mmu_set_bit_class, kvm_mmu_set_accessed_bit,
+
        TP_PROTO(unsigned long table_gfn, unsigned index, unsigned size),
-       TP_ARGS(table_gfn, index, size),
 
-       TP_STRUCT__entry(
-               __field(__u64, gpa)
-               ),
+       TP_ARGS(table_gfn, index, size)
+);
 
-       TP_fast_assign(
-               __entry->gpa = ((u64)table_gfn << PAGE_SHIFT)
-                               + index * size;
-               ),
+/* We set a pte dirty bit */
+DEFINE_EVENT(kvm_mmu_set_bit_class, kvm_mmu_set_dirty_bit,
 
-       TP_printk("gpa %llx", __entry->gpa)
+       TP_PROTO(unsigned long table_gfn, unsigned index, unsigned size),
+
+       TP_ARGS(table_gfn, index, size)
 );
 
 TRACE_EVENT(
@@ -166,55 +162,45 @@ TRACE_EVENT(
                  __entry->created ? "new" : "existing")
 );
 
-TRACE_EVENT(
-       kvm_mmu_sync_page,
+DECLARE_EVENT_CLASS(kvm_mmu_page_class,
+
        TP_PROTO(struct kvm_mmu_page *sp),
        TP_ARGS(sp),
 
        TP_STRUCT__entry(
                KVM_MMU_PAGE_FIELDS
-               ),
+       ),
 
        TP_fast_assign(
                KVM_MMU_PAGE_ASSIGN(sp)
-               ),
+       ),
 
        TP_printk("%s", KVM_MMU_PAGE_PRINTK())
 );
 
-TRACE_EVENT(
-       kvm_mmu_unsync_page,
+DEFINE_EVENT(kvm_mmu_page_class, kvm_mmu_sync_page,
        TP_PROTO(struct kvm_mmu_page *sp),
-       TP_ARGS(sp),
-
-       TP_STRUCT__entry(
-               KVM_MMU_PAGE_FIELDS
-               ),
 
-       TP_fast_assign(
-               KVM_MMU_PAGE_ASSIGN(sp)
-               ),
-
-       TP_printk("%s", KVM_MMU_PAGE_PRINTK())
+       TP_ARGS(sp)
 );
 
-TRACE_EVENT(
-       kvm_mmu_zap_page,
+DEFINE_EVENT(kvm_mmu_page_class, kvm_mmu_unsync_page,
        TP_PROTO(struct kvm_mmu_page *sp),
-       TP_ARGS(sp),
 
-       TP_STRUCT__entry(
-               KVM_MMU_PAGE_FIELDS
-               ),
+       TP_ARGS(sp)
+);
 
-       TP_fast_assign(
-               KVM_MMU_PAGE_ASSIGN(sp)
-               ),
+DEFINE_EVENT(kvm_mmu_page_class, kvm_mmu_zap_page,
+       TP_PROTO(struct kvm_mmu_page *sp),
 
-       TP_printk("%s", KVM_MMU_PAGE_PRINTK())
+       TP_ARGS(sp)
 );
-
 #endif /* _TRACE_KVMMMU_H */
 
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE mmutrace
+
 /* This part must be outside protection */
 #include <trace/define_trace.h>
index 81eab9a50e6afdbe07c8d264e7db6dedcdc5daed..89d66ca4d87cb2982ae48c5877580e733ab0cce8 100644 (file)
@@ -170,7 +170,7 @@ walk:
                        goto access_error;
 
 #if PTTYPE == 64
-               if (fetch_fault && is_nx(vcpu) && (pte & PT64_NX_MASK))
+               if (fetch_fault && (pte & PT64_NX_MASK))
                        goto access_error;
 #endif
 
@@ -190,10 +190,10 @@ walk:
 
                if ((walker->level == PT_PAGE_TABLE_LEVEL) ||
                    ((walker->level == PT_DIRECTORY_LEVEL) &&
-                               (pte & PT_PAGE_SIZE_MASK)  &&
+                               is_large_pte(pte) &&
                                (PTTYPE == 64 || is_pse(vcpu))) ||
                    ((walker->level == PT_PDPE_LEVEL) &&
-                               (pte & PT_PAGE_SIZE_MASK)  &&
+                               is_large_pte(pte) &&
                                is_long_mode(vcpu))) {
                        int lvl = walker->level;
 
@@ -258,11 +258,17 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page,
        pt_element_t gpte;
        unsigned pte_access;
        pfn_t pfn;
+       u64 new_spte;
 
        gpte = *(const pt_element_t *)pte;
        if (~gpte & (PT_PRESENT_MASK | PT_ACCESSED_MASK)) {
-               if (!is_present_gpte(gpte))
-                       __set_spte(spte, shadow_notrap_nonpresent_pte);
+               if (!is_present_gpte(gpte)) {
+                       if (page->unsync)
+                               new_spte = shadow_trap_nonpresent_pte;
+                       else
+                               new_spte = shadow_notrap_nonpresent_pte;
+                       __set_spte(spte, new_spte);
+               }
                return;
        }
        pgprintk("%s: gpte %llx spte %p\n", __func__, (u64)gpte, spte);
@@ -457,6 +463,7 @@ out_unlock:
 static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva)
 {
        struct kvm_shadow_walk_iterator iterator;
+       gpa_t pte_gpa = -1;
        int level;
        u64 *sptep;
        int need_flush = 0;
@@ -467,9 +474,16 @@ static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva)
                level = iterator.level;
                sptep = iterator.sptep;
 
-               if (level == PT_PAGE_TABLE_LEVEL  ||
-                   ((level == PT_DIRECTORY_LEVEL && is_large_pte(*sptep))) ||
-                   ((level == PT_PDPE_LEVEL && is_large_pte(*sptep)))) {
+               if (is_last_spte(*sptep, level)) {
+                       struct kvm_mmu_page *sp = page_header(__pa(sptep));
+                       int offset, shift;
+
+                       shift = PAGE_SHIFT -
+                                 (PT_LEVEL_BITS - PT64_LEVEL_BITS) * level;
+                       offset = sp->role.quadrant << shift;
+
+                       pte_gpa = (sp->gfn << PAGE_SHIFT) + offset;
+                       pte_gpa += (sptep - sp->spt) * sizeof(pt_element_t);
 
                        if (is_shadow_present_pte(*sptep)) {
                                rmap_remove(vcpu->kvm, sptep);
@@ -487,7 +501,17 @@ static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva)
 
        if (need_flush)
                kvm_flush_remote_tlbs(vcpu->kvm);
+
+       atomic_inc(&vcpu->kvm->arch.invlpg_counter);
+
        spin_unlock(&vcpu->kvm->mmu_lock);
+
+       if (pte_gpa == -1)
+               return;
+
+       if (mmu_topup_memory_caches(vcpu))
+               return;
+       kvm_mmu_pte_write(vcpu, pte_gpa, NULL, sizeof(pt_element_t), 0);
 }
 
 static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr, u32 access,
@@ -551,12 +575,15 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
 {
        int i, offset, nr_present;
        bool reset_host_protection;
+       gpa_t first_pte_gpa;
 
        offset = nr_present = 0;
 
        if (PTTYPE == 32)
                offset = sp->role.quadrant << PT64_LEVEL_BITS;
 
+       first_pte_gpa = gfn_to_gpa(sp->gfn) + offset * sizeof(pt_element_t);
+
        for (i = 0; i < PT64_ENT_PER_PAGE; i++) {
                unsigned pte_access;
                pt_element_t gpte;
@@ -566,8 +593,7 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
                if (!is_shadow_present_pte(sp->spt[i]))
                        continue;
 
-               pte_gpa = gfn_to_gpa(sp->gfn);
-               pte_gpa += (i+offset) * sizeof(pt_element_t);
+               pte_gpa = first_pte_gpa + i * sizeof(pt_element_t);
 
                if (kvm_read_guest_atomic(vcpu->kvm, pte_gpa, &gpte,
                                          sizeof(pt_element_t)))
index 737361fcd503e10091d0cb0e485ede146ec9a6f1..96dc232bfc56562a9cf0b178df962ba33a5c3c43 100644 (file)
@@ -44,10 +44,11 @@ MODULE_LICENSE("GPL");
 #define SEG_TYPE_LDT 2
 #define SEG_TYPE_BUSY_TSS16 3
 
-#define SVM_FEATURE_NPT  (1 << 0)
-#define SVM_FEATURE_LBRV (1 << 1)
-#define SVM_FEATURE_SVML (1 << 2)
-#define SVM_FEATURE_PAUSE_FILTER (1 << 10)
+#define SVM_FEATURE_NPT            (1 <<  0)
+#define SVM_FEATURE_LBRV           (1 <<  1)
+#define SVM_FEATURE_SVML           (1 <<  2)
+#define SVM_FEATURE_NRIP           (1 <<  3)
+#define SVM_FEATURE_PAUSE_FILTER   (1 << 10)
 
 #define NESTED_EXIT_HOST       0       /* Exit handled on host level */
 #define NESTED_EXIT_DONE       1       /* Exit caused nested vmexit  */
@@ -70,6 +71,7 @@ struct kvm_vcpu;
 struct nested_state {
        struct vmcb *hsave;
        u64 hsave_msr;
+       u64 vm_cr_msr;
        u64 vmcb;
 
        /* These are the merged vectors */
@@ -77,6 +79,7 @@ struct nested_state {
 
        /* gpa pointers to the real vectors */
        u64 vmcb_msrpm;
+       u64 vmcb_iopm;
 
        /* A VMEXIT is required but not yet emulated */
        bool exit_required;
@@ -91,6 +94,9 @@ struct nested_state {
 
 };
 
+#define MSRPM_OFFSETS  16
+static u32 msrpm_offsets[MSRPM_OFFSETS] __read_mostly;
+
 struct vcpu_svm {
        struct kvm_vcpu vcpu;
        struct vmcb *vmcb;
@@ -110,13 +116,39 @@ struct vcpu_svm {
        struct nested_state nested;
 
        bool nmi_singlestep;
+
+       unsigned int3_injected;
+       unsigned long int3_rip;
+};
+
+#define MSR_INVALID                    0xffffffffU
+
+static struct svm_direct_access_msrs {
+       u32 index;   /* Index of the MSR */
+       bool always; /* True if intercept is always on */
+} direct_access_msrs[] = {
+       { .index = MSR_K6_STAR,                         .always = true  },
+       { .index = MSR_IA32_SYSENTER_CS,                .always = true  },
+#ifdef CONFIG_X86_64
+       { .index = MSR_GS_BASE,                         .always = true  },
+       { .index = MSR_FS_BASE,                         .always = true  },
+       { .index = MSR_KERNEL_GS_BASE,                  .always = true  },
+       { .index = MSR_LSTAR,                           .always = true  },
+       { .index = MSR_CSTAR,                           .always = true  },
+       { .index = MSR_SYSCALL_MASK,                    .always = true  },
+#endif
+       { .index = MSR_IA32_LASTBRANCHFROMIP,           .always = false },
+       { .index = MSR_IA32_LASTBRANCHTOIP,             .always = false },
+       { .index = MSR_IA32_LASTINTFROMIP,              .always = false },
+       { .index = MSR_IA32_LASTINTTOIP,                .always = false },
+       { .index = MSR_INVALID,                         .always = false },
 };
 
 /* enable NPT for AMD64 and X86 with PAE */
 #if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE)
 static bool npt_enabled = true;
 #else
-static bool npt_enabled = false;
+static bool npt_enabled;
 #endif
 static int npt = 1;
 
@@ -129,6 +161,7 @@ static void svm_flush_tlb(struct kvm_vcpu *vcpu);
 static void svm_complete_interrupts(struct vcpu_svm *svm);
 
 static int nested_svm_exit_handled(struct vcpu_svm *svm);
+static int nested_svm_intercept(struct vcpu_svm *svm);
 static int nested_svm_vmexit(struct vcpu_svm *svm);
 static int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr,
                                      bool has_error_code, u32 error_code);
@@ -163,8 +196,8 @@ static unsigned long iopm_base;
 struct kvm_ldttss_desc {
        u16 limit0;
        u16 base0;
-       unsigned base1 : 8, type : 5, dpl : 2, p : 1;
-       unsigned limit1 : 4, zero0 : 3, g : 1, base2 : 8;
+       unsigned base1:8, type:5, dpl:2, p:1;
+       unsigned limit1:4, zero0:3, g:1, base2:8;
        u32 base3;
        u32 zero1;
 } __attribute__((packed));
@@ -194,6 +227,27 @@ static u32 msrpm_ranges[] = {0, 0xc0000000, 0xc0010000};
 #define MSRS_RANGE_SIZE 2048
 #define MSRS_IN_RANGE (MSRS_RANGE_SIZE * 8 / 2)
 
+static u32 svm_msrpm_offset(u32 msr)
+{
+       u32 offset;
+       int i;
+
+       for (i = 0; i < NUM_MSR_MAPS; i++) {
+               if (msr < msrpm_ranges[i] ||
+                   msr >= msrpm_ranges[i] + MSRS_IN_RANGE)
+                       continue;
+
+               offset  = (msr - msrpm_ranges[i]) / 4; /* 4 msrs per u8 */
+               offset += (i * MSRS_RANGE_SIZE);       /* add range offset */
+
+               /* Now we have the u8 offset - but need the u32 offset */
+               return offset / 4;
+       }
+
+       /* MSR not in any range */
+       return MSR_INVALID;
+}
+
 #define MAX_INST_SIZE 15
 
 static inline u32 svm_has(u32 feat)
@@ -213,7 +267,7 @@ static inline void stgi(void)
 
 static inline void invlpga(unsigned long addr, u32 asid)
 {
-       asm volatile (__ex(SVM_INVLPGA) :: "a"(addr), "c"(asid));
+       asm volatile (__ex(SVM_INVLPGA) : : "a"(addr), "c"(asid));
 }
 
 static inline void force_new_asid(struct kvm_vcpu *vcpu)
@@ -235,23 +289,6 @@ static void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
        vcpu->arch.efer = efer;
 }
 
-static void svm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr,
-                               bool has_error_code, u32 error_code)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-
-       /* If we are within a nested VM we'd better #VMEXIT and let the
-          guest handle the exception */
-       if (nested_svm_check_exception(svm, nr, has_error_code, error_code))
-               return;
-
-       svm->vmcb->control.event_inj = nr
-               | SVM_EVTINJ_VALID
-               | (has_error_code ? SVM_EVTINJ_VALID_ERR : 0)
-               | SVM_EVTINJ_TYPE_EXEPT;
-       svm->vmcb->control.event_inj_err = error_code;
-}
-
 static int is_external_interrupt(u32 info)
 {
        info &= SVM_EVTINJ_TYPE_MASK | SVM_EVTINJ_VALID;
@@ -264,7 +301,7 @@ static u32 svm_get_interrupt_shadow(struct kvm_vcpu *vcpu, int mask)
        u32 ret = 0;
 
        if (svm->vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK)
-               ret |= X86_SHADOW_INT_STI | X86_SHADOW_INT_MOV_SS;
+               ret |= KVM_X86_SHADOW_INT_STI | KVM_X86_SHADOW_INT_MOV_SS;
        return ret & mask;
 }
 
@@ -283,6 +320,9 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
 
+       if (svm->vmcb->control.next_rip != 0)
+               svm->next_rip = svm->vmcb->control.next_rip;
+
        if (!svm->next_rip) {
                if (emulate_instruction(vcpu, 0, 0, EMULTYPE_SKIP) !=
                                EMULATE_DONE)
@@ -297,6 +337,43 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
        svm_set_interrupt_shadow(vcpu, 0);
 }
 
+static void svm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr,
+                               bool has_error_code, u32 error_code,
+                               bool reinject)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+
+       /*
+        * If we are within a nested VM we'd better #VMEXIT and let the guest
+        * handle the exception
+        */
+       if (!reinject &&
+           nested_svm_check_exception(svm, nr, has_error_code, error_code))
+               return;
+
+       if (nr == BP_VECTOR && !svm_has(SVM_FEATURE_NRIP)) {
+               unsigned long rip, old_rip = kvm_rip_read(&svm->vcpu);
+
+               /*
+                * For guest debugging where we have to reinject #BP if some
+                * INT3 is guest-owned:
+                * Emulate nRIP by moving RIP forward. Will fail if injection
+                * raises a fault that is not intercepted. Still better than
+                * failing in all cases.
+                */
+               skip_emulated_instruction(&svm->vcpu);
+               rip = kvm_rip_read(&svm->vcpu);
+               svm->int3_rip = rip + svm->vmcb->save.cs.base;
+               svm->int3_injected = rip - old_rip;
+       }
+
+       svm->vmcb->control.event_inj = nr
+               | SVM_EVTINJ_VALID
+               | (has_error_code ? SVM_EVTINJ_VALID_ERR : 0)
+               | SVM_EVTINJ_TYPE_EXEPT;
+       svm->vmcb->control.event_inj_err = error_code;
+}
+
 static int has_svm(void)
 {
        const char *msg;
@@ -319,7 +396,7 @@ static int svm_hardware_enable(void *garbage)
 
        struct svm_cpu_data *sd;
        uint64_t efer;
-       struct descriptor_table gdt_descr;
+       struct desc_ptr gdt_descr;
        struct desc_struct *gdt;
        int me = raw_smp_processor_id();
 
@@ -344,8 +421,8 @@ static int svm_hardware_enable(void *garbage)
        sd->max_asid = cpuid_ebx(SVM_CPUID_FUNC) - 1;
        sd->next_asid = sd->max_asid + 1;
 
-       kvm_get_gdt(&gdt_descr);
-       gdt = (struct desc_struct *)gdt_descr.base;
+       native_store_gdt(&gdt_descr);
+       gdt = (struct desc_struct *)gdt_descr.address;
        sd->tss_desc = (struct kvm_ldttss_desc *)(gdt + GDT_ENTRY_TSS);
 
        wrmsrl(MSR_EFER, efer | EFER_SVME);
@@ -391,42 +468,98 @@ err_1:
 
 }
 
+static bool valid_msr_intercept(u32 index)
+{
+       int i;
+
+       for (i = 0; direct_access_msrs[i].index != MSR_INVALID; i++)
+               if (direct_access_msrs[i].index == index)
+                       return true;
+
+       return false;
+}
+
 static void set_msr_interception(u32 *msrpm, unsigned msr,
                                 int read, int write)
+{
+       u8 bit_read, bit_write;
+       unsigned long tmp;
+       u32 offset;
+
+       /*
+        * If this warning triggers extend the direct_access_msrs list at the
+        * beginning of the file
+        */
+       WARN_ON(!valid_msr_intercept(msr));
+
+       offset    = svm_msrpm_offset(msr);
+       bit_read  = 2 * (msr & 0x0f);
+       bit_write = 2 * (msr & 0x0f) + 1;
+       tmp       = msrpm[offset];
+
+       BUG_ON(offset == MSR_INVALID);
+
+       read  ? clear_bit(bit_read,  &tmp) : set_bit(bit_read,  &tmp);
+       write ? clear_bit(bit_write, &tmp) : set_bit(bit_write, &tmp);
+
+       msrpm[offset] = tmp;
+}
+
+static void svm_vcpu_init_msrpm(u32 *msrpm)
 {
        int i;
 
-       for (i = 0; i < NUM_MSR_MAPS; i++) {
-               if (msr >= msrpm_ranges[i] &&
-                   msr < msrpm_ranges[i] + MSRS_IN_RANGE) {
-                       u32 msr_offset = (i * MSRS_IN_RANGE + msr -
-                                         msrpm_ranges[i]) * 2;
-
-                       u32 *base = msrpm + (msr_offset / 32);
-                       u32 msr_shift = msr_offset % 32;
-                       u32 mask = ((write) ? 0 : 2) | ((read) ? 0 : 1);
-                       *base = (*base & ~(0x3 << msr_shift)) |
-                               (mask << msr_shift);
+       memset(msrpm, 0xff, PAGE_SIZE * (1 << MSRPM_ALLOC_ORDER));
+
+       for (i = 0; direct_access_msrs[i].index != MSR_INVALID; i++) {
+               if (!direct_access_msrs[i].always)
+                       continue;
+
+               set_msr_interception(msrpm, direct_access_msrs[i].index, 1, 1);
+       }
+}
+
+static void add_msr_offset(u32 offset)
+{
+       int i;
+
+       for (i = 0; i < MSRPM_OFFSETS; ++i) {
+
+               /* Offset already in list? */
+               if (msrpm_offsets[i] == offset)
                        return;
-               }
+
+               /* Slot used by another offset? */
+               if (msrpm_offsets[i] != MSR_INVALID)
+                       continue;
+
+               /* Add offset to list */
+               msrpm_offsets[i] = offset;
+
+               return;
        }
+
+       /*
+        * If this BUG triggers the msrpm_offsets table has an overflow. Just
+        * increase MSRPM_OFFSETS in this case.
+        */
        BUG();
 }
 
-static void svm_vcpu_init_msrpm(u32 *msrpm)
+static void init_msrpm_offsets(void)
 {
-       memset(msrpm, 0xff, PAGE_SIZE * (1 << MSRPM_ALLOC_ORDER));
+       int i;
 
-#ifdef CONFIG_X86_64
-       set_msr_interception(msrpm, MSR_GS_BASE, 1, 1);
-       set_msr_interception(msrpm, MSR_FS_BASE, 1, 1);
-       set_msr_interception(msrpm, MSR_KERNEL_GS_BASE, 1, 1);
-       set_msr_interception(msrpm, MSR_LSTAR, 1, 1);
-       set_msr_interception(msrpm, MSR_CSTAR, 1, 1);
-       set_msr_interception(msrpm, MSR_SYSCALL_MASK, 1, 1);
-#endif
-       set_msr_interception(msrpm, MSR_K6_STAR, 1, 1);
-       set_msr_interception(msrpm, MSR_IA32_SYSENTER_CS, 1, 1);
+       memset(msrpm_offsets, 0xff, sizeof(msrpm_offsets));
+
+       for (i = 0; direct_access_msrs[i].index != MSR_INVALID; i++) {
+               u32 offset;
+
+               offset = svm_msrpm_offset(direct_access_msrs[i].index);
+               BUG_ON(offset == MSR_INVALID);
+
+               add_msr_offset(offset);
+       }
 }
 
 static void svm_enable_lbrv(struct vcpu_svm *svm)
@@ -467,6 +600,8 @@ static __init int svm_hardware_setup(void)
        memset(iopm_va, 0xff, PAGE_SIZE * (1 << IOPM_ALLOC_ORDER));
        iopm_base = page_to_pfn(iopm_pages) << PAGE_SHIFT;
 
+       init_msrpm_offsets();
+
        if (boot_cpu_has(X86_FEATURE_NX))
                kvm_enable_efer_bits(EFER_NX);
 
@@ -523,7 +658,7 @@ static void init_seg(struct vmcb_seg *seg)
 {
        seg->selector = 0;
        seg->attrib = SVM_SELECTOR_P_MASK | SVM_SELECTOR_S_MASK |
-               SVM_SELECTOR_WRITE_MASK; /* Read/Write Data Segment */
+                     SVM_SELECTOR_WRITE_MASK; /* Read/Write Data Segment */
        seg->limit = 0xffff;
        seg->base = 0;
 }
@@ -543,16 +678,16 @@ static void init_vmcb(struct vcpu_svm *svm)
 
        svm->vcpu.fpu_active = 1;
 
-       control->intercept_cr_read =    INTERCEPT_CR0_MASK |
+       control->intercept_cr_read =    INTERCEPT_CR0_MASK |
                                        INTERCEPT_CR3_MASK |
                                        INTERCEPT_CR4_MASK;
 
-       control->intercept_cr_write =   INTERCEPT_CR0_MASK |
+       control->intercept_cr_write =   INTERCEPT_CR0_MASK |
                                        INTERCEPT_CR3_MASK |
                                        INTERCEPT_CR4_MASK |
                                        INTERCEPT_CR8_MASK;
 
-       control->intercept_dr_read =    INTERCEPT_DR0_MASK |
+       control->intercept_dr_read =    INTERCEPT_DR0_MASK |
                                        INTERCEPT_DR1_MASK |
                                        INTERCEPT_DR2_MASK |
                                        INTERCEPT_DR3_MASK |
@@ -561,7 +696,7 @@ static void init_vmcb(struct vcpu_svm *svm)
                                        INTERCEPT_DR6_MASK |
                                        INTERCEPT_DR7_MASK;
 
-       control->intercept_dr_write =   INTERCEPT_DR0_MASK |
+       control->intercept_dr_write =   INTERCEPT_DR0_MASK |
                                        INTERCEPT_DR1_MASK |
                                        INTERCEPT_DR2_MASK |
                                        INTERCEPT_DR3_MASK |
@@ -575,7 +710,7 @@ static void init_vmcb(struct vcpu_svm *svm)
                                        (1 << MC_VECTOR);
 
 
-       control->intercept =    (1ULL << INTERCEPT_INTR) |
+       control->intercept =    (1ULL << INTERCEPT_INTR) |
                                (1ULL << INTERCEPT_NMI) |
                                (1ULL << INTERCEPT_SMI) |
                                (1ULL << INTERCEPT_SELECTIVE_CR0) |
@@ -636,7 +771,8 @@ static void init_vmcb(struct vcpu_svm *svm)
        save->rip = 0x0000fff0;
        svm->vcpu.arch.regs[VCPU_REGS_RIP] = save->rip;
 
-       /* This is the guest-visible cr0 value.
+       /*
+        * This is the guest-visible cr0 value.
         * svm_set_cr0() sets PG and WP and clears NW and CD on save->cr0.
         */
        svm->vcpu.arch.cr0 = X86_CR0_NW | X86_CR0_CD | X86_CR0_ET;
@@ -729,6 +865,7 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
        svm_vcpu_init_msrpm(svm->msrpm);
 
        svm->nested.msrpm = page_address(nested_msrpm_pages);
+       svm_vcpu_init_msrpm(svm->nested.msrpm);
 
        svm->vmcb = page_address(page);
        clear_page(svm->vmcb);
@@ -882,7 +1019,8 @@ static void svm_get_segment(struct kvm_vcpu *vcpu,
        var->db = (s->attrib >> SVM_SELECTOR_DB_SHIFT) & 1;
        var->g = (s->attrib >> SVM_SELECTOR_G_SHIFT) & 1;
 
-       /* AMD's VMCB does not have an explicit unusable field, so emulate it
+       /*
+        * AMD's VMCB does not have an explicit unusable field, so emulate it
         * for cross vendor migration purposes by "not present"
         */
        var->unusable = !var->present || (var->type == 0);
@@ -918,7 +1056,8 @@ static void svm_get_segment(struct kvm_vcpu *vcpu,
                        var->type |= 0x1;
                break;
        case VCPU_SREG_SS:
-               /* On AMD CPUs sometimes the DB bit in the segment
+               /*
+                * On AMD CPUs sometimes the DB bit in the segment
                 * descriptor is left as 1, although the whole segment has
                 * been made unusable. Clear it here to pass an Intel VMX
                 * entry check when cross vendor migrating.
@@ -936,36 +1075,36 @@ static int svm_get_cpl(struct kvm_vcpu *vcpu)
        return save->cpl;
 }
 
-static void svm_get_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
+static void svm_get_idt(struct kvm_vcpu *vcpu, struct desc_ptr *dt)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
 
-       dt->limit = svm->vmcb->save.idtr.limit;
-       dt->base = svm->vmcb->save.idtr.base;
+       dt->size = svm->vmcb->save.idtr.limit;
+       dt->address = svm->vmcb->save.idtr.base;
 }
 
-static void svm_set_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
+static void svm_set_idt(struct kvm_vcpu *vcpu, struct desc_ptr *dt)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
 
-       svm->vmcb->save.idtr.limit = dt->limit;
-       svm->vmcb->save.idtr.base = dt->base ;
+       svm->vmcb->save.idtr.limit = dt->size;
+       svm->vmcb->save.idtr.base = dt->address ;
 }
 
-static void svm_get_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
+static void svm_get_gdt(struct kvm_vcpu *vcpu, struct desc_ptr *dt)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
 
-       dt->limit = svm->vmcb->save.gdtr.limit;
-       dt->base = svm->vmcb->save.gdtr.base;
+       dt->size = svm->vmcb->save.gdtr.limit;
+       dt->address = svm->vmcb->save.gdtr.base;
 }
 
-static void svm_set_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
+static void svm_set_gdt(struct kvm_vcpu *vcpu, struct desc_ptr *dt)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
 
-       svm->vmcb->save.gdtr.limit = dt->limit;
-       svm->vmcb->save.gdtr.base = dt->base ;
+       svm->vmcb->save.gdtr.limit = dt->size;
+       svm->vmcb->save.gdtr.base = dt->address ;
 }
 
 static void svm_decache_cr0_guest_bits(struct kvm_vcpu *vcpu)
@@ -978,6 +1117,7 @@ static void svm_decache_cr4_guest_bits(struct kvm_vcpu *vcpu)
 
 static void update_cr0_intercept(struct vcpu_svm *svm)
 {
+       struct vmcb *vmcb = svm->vmcb;
        ulong gcr0 = svm->vcpu.arch.cr0;
        u64 *hcr0 = &svm->vmcb->save.cr0;
 
@@ -989,11 +1129,25 @@ static void update_cr0_intercept(struct vcpu_svm *svm)
 
 
        if (gcr0 == *hcr0 && svm->vcpu.fpu_active) {
-               svm->vmcb->control.intercept_cr_read &= ~INTERCEPT_CR0_MASK;
-               svm->vmcb->control.intercept_cr_write &= ~INTERCEPT_CR0_MASK;
+               vmcb->control.intercept_cr_read &= ~INTERCEPT_CR0_MASK;
+               vmcb->control.intercept_cr_write &= ~INTERCEPT_CR0_MASK;
+               if (is_nested(svm)) {
+                       struct vmcb *hsave = svm->nested.hsave;
+
+                       hsave->control.intercept_cr_read  &= ~INTERCEPT_CR0_MASK;
+                       hsave->control.intercept_cr_write &= ~INTERCEPT_CR0_MASK;
+                       vmcb->control.intercept_cr_read  |= svm->nested.intercept_cr_read;
+                       vmcb->control.intercept_cr_write |= svm->nested.intercept_cr_write;
+               }
        } else {
                svm->vmcb->control.intercept_cr_read |= INTERCEPT_CR0_MASK;
                svm->vmcb->control.intercept_cr_write |= INTERCEPT_CR0_MASK;
+               if (is_nested(svm)) {
+                       struct vmcb *hsave = svm->nested.hsave;
+
+                       hsave->control.intercept_cr_read |= INTERCEPT_CR0_MASK;
+                       hsave->control.intercept_cr_write |= INTERCEPT_CR0_MASK;
+               }
        }
 }
 
@@ -1001,6 +1155,27 @@ static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
 
+       if (is_nested(svm)) {
+               /*
+                * We are here because we run in nested mode, the host kvm
+                * intercepts cr0 writes but the l1 hypervisor does not.
+                * But the L1 hypervisor may intercept selective cr0 writes.
+                * This needs to be checked here.
+                */
+               unsigned long old, new;
+
+               /* Remove bits that would trigger a real cr0 write intercept */
+               old = vcpu->arch.cr0 & SVM_CR0_SELECTIVE_MASK;
+               new = cr0 & SVM_CR0_SELECTIVE_MASK;
+
+               if (old == new) {
+                       /* cr0 write with ts and mp unchanged */
+                       svm->vmcb->control.exit_code = SVM_EXIT_CR0_SEL_WRITE;
+                       if (nested_svm_exit_handled(svm) == NESTED_EXIT_DONE)
+                               return;
+               }
+       }
+
 #ifdef CONFIG_X86_64
        if (vcpu->arch.efer & EFER_LME) {
                if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) {
@@ -1134,70 +1309,11 @@ static void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *sd)
        svm->vmcb->control.asid = sd->next_asid++;
 }
 
-static int svm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *dest)
+static void svm_set_dr7(struct kvm_vcpu *vcpu, unsigned long value)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
 
-       switch (dr) {
-       case 0 ... 3:
-               *dest = vcpu->arch.db[dr];
-               break;
-       case 4:
-               if (kvm_read_cr4_bits(vcpu, X86_CR4_DE))
-                       return EMULATE_FAIL; /* will re-inject UD */
-               /* fall through */
-       case 6:
-               if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)
-                       *dest = vcpu->arch.dr6;
-               else
-                       *dest = svm->vmcb->save.dr6;
-               break;
-       case 5:
-               if (kvm_read_cr4_bits(vcpu, X86_CR4_DE))
-                       return EMULATE_FAIL; /* will re-inject UD */
-               /* fall through */
-       case 7:
-               if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)
-                       *dest = vcpu->arch.dr7;
-               else
-                       *dest = svm->vmcb->save.dr7;
-               break;
-       }
-
-       return EMULATE_DONE;
-}
-
-static int svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-
-       switch (dr) {
-       case 0 ... 3:
-               vcpu->arch.db[dr] = value;
-               if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP))
-                       vcpu->arch.eff_db[dr] = value;
-               break;
-       case 4:
-               if (kvm_read_cr4_bits(vcpu, X86_CR4_DE))
-                       return EMULATE_FAIL; /* will re-inject UD */
-               /* fall through */
-       case 6:
-               vcpu->arch.dr6 = (value & DR6_VOLATILE) | DR6_FIXED_1;
-               break;
-       case 5:
-               if (kvm_read_cr4_bits(vcpu, X86_CR4_DE))
-                       return EMULATE_FAIL; /* will re-inject UD */
-               /* fall through */
-       case 7:
-               vcpu->arch.dr7 = (value & DR7_VOLATILE) | DR7_FIXED_1;
-               if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)) {
-                       svm->vmcb->save.dr7 = vcpu->arch.dr7;
-                       vcpu->arch.switch_db_regs = (value & DR7_BP_EN_MASK);
-               }
-               break;
-       }
-
-       return EMULATE_DONE;
+       svm->vmcb->save.dr7 = value;
 }
 
 static int pf_interception(struct vcpu_svm *svm)
@@ -1234,7 +1350,7 @@ static int db_interception(struct vcpu_svm *svm)
        }
 
        if (svm->vcpu.guest_debug &
-           (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP)){
+           (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP)) {
                kvm_run->exit_reason = KVM_EXIT_DEBUG;
                kvm_run->debug.arch.pc =
                        svm->vmcb->save.cs.base + svm->vmcb->save.rip;
@@ -1268,7 +1384,22 @@ static int ud_interception(struct vcpu_svm *svm)
 static void svm_fpu_activate(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
-       svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR);
+       u32 excp;
+
+       if (is_nested(svm)) {
+               u32 h_excp, n_excp;
+
+               h_excp  = svm->nested.hsave->control.intercept_exceptions;
+               n_excp  = svm->nested.intercept_exceptions;
+               h_excp &= ~(1 << NM_VECTOR);
+               excp    = h_excp | n_excp;
+       } else {
+               excp  = svm->vmcb->control.intercept_exceptions;
+               excp &= ~(1 << NM_VECTOR);
+       }
+
+       svm->vmcb->control.intercept_exceptions = excp;
+
        svm->vcpu.fpu_active = 1;
        update_cr0_intercept(svm);
 }
@@ -1309,29 +1440,23 @@ static int shutdown_interception(struct vcpu_svm *svm)
 
 static int io_interception(struct vcpu_svm *svm)
 {
+       struct kvm_vcpu *vcpu = &svm->vcpu;
        u32 io_info = svm->vmcb->control.exit_info_1; /* address size bug? */
        int size, in, string;
        unsigned port;
 
        ++svm->vcpu.stat.io_exits;
-
-       svm->next_rip = svm->vmcb->control.exit_info_2;
-
        string = (io_info & SVM_IOIO_STR_MASK) != 0;
-
-       if (string) {
-               if (emulate_instruction(&svm->vcpu,
-                                       0, 0, 0) == EMULATE_DO_MMIO)
-                       return 0;
-               return 1;
-       }
-
        in = (io_info & SVM_IOIO_TYPE_MASK) != 0;
+       if (string || in)
+               return !(emulate_instruction(vcpu, 0, 0, 0) == EMULATE_DO_MMIO);
+
        port = io_info >> 16;
        size = (io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT;
-
+       svm->next_rip = svm->vmcb->control.exit_info_2;
        skip_emulated_instruction(&svm->vcpu);
-       return kvm_emulate_pio(&svm->vcpu, in, size, port);
+
+       return kvm_fast_pio_out(vcpu, size, port);
 }
 
 static int nmi_interception(struct vcpu_svm *svm)
@@ -1384,6 +1509,8 @@ static int nested_svm_check_permissions(struct vcpu_svm *svm)
 static int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr,
                                      bool has_error_code, u32 error_code)
 {
+       int vmexit;
+
        if (!is_nested(svm))
                return 0;
 
@@ -1392,21 +1519,28 @@ static int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr,
        svm->vmcb->control.exit_info_1 = error_code;
        svm->vmcb->control.exit_info_2 = svm->vcpu.arch.cr2;
 
-       return nested_svm_exit_handled(svm);
+       vmexit = nested_svm_intercept(svm);
+       if (vmexit == NESTED_EXIT_DONE)
+               svm->nested.exit_required = true;
+
+       return vmexit;
 }
 
-static inline int nested_svm_intr(struct vcpu_svm *svm)
+/* This function returns true if it is save to enable the irq window */
+static inline bool nested_svm_intr(struct vcpu_svm *svm)
 {
        if (!is_nested(svm))
-               return 0;
+               return true;
 
        if (!(svm->vcpu.arch.hflags & HF_VINTR_MASK))
-               return 0;
+               return true;
 
        if (!(svm->vcpu.arch.hflags & HF_HIF_MASK))
-               return 0;
+               return false;
 
-       svm->vmcb->control.exit_code = SVM_EXIT_INTR;
+       svm->vmcb->control.exit_code   = SVM_EXIT_INTR;
+       svm->vmcb->control.exit_info_1 = 0;
+       svm->vmcb->control.exit_info_2 = 0;
 
        if (svm->nested.intercept & 1ULL) {
                /*
@@ -1417,21 +1551,40 @@ static inline int nested_svm_intr(struct vcpu_svm *svm)
                 */
                svm->nested.exit_required = true;
                trace_kvm_nested_intr_vmexit(svm->vmcb->save.rip);
-               return 1;
+               return false;
        }
 
-       return 0;
+       return true;
+}
+
+/* This function returns true if it is save to enable the nmi window */
+static inline bool nested_svm_nmi(struct vcpu_svm *svm)
+{
+       if (!is_nested(svm))
+               return true;
+
+       if (!(svm->nested.intercept & (1ULL << INTERCEPT_NMI)))
+               return true;
+
+       svm->vmcb->control.exit_code = SVM_EXIT_NMI;
+       svm->nested.exit_required = true;
+
+       return false;
 }
 
-static void *nested_svm_map(struct vcpu_svm *svm, u64 gpa, enum km_type idx)
+static void *nested_svm_map(struct vcpu_svm *svm, u64 gpa, struct page **_page)
 {
        struct page *page;
 
+       might_sleep();
+
        page = gfn_to_page(svm->vcpu.kvm, gpa >> PAGE_SHIFT);
        if (is_error_page(page))
                goto error;
 
-       return kmap_atomic(page, idx);
+       *_page = page;
+
+       return kmap(page);
 
 error:
        kvm_release_page_clean(page);
@@ -1440,61 +1593,55 @@ error:
        return NULL;
 }
 
-static void nested_svm_unmap(void *addr, enum km_type idx)
+static void nested_svm_unmap(struct page *page)
 {
-       struct page *page;
+       kunmap(page);
+       kvm_release_page_dirty(page);
+}
 
-       if (!addr)
-               return;
+static int nested_svm_intercept_ioio(struct vcpu_svm *svm)
+{
+       unsigned port;
+       u8 val, bit;
+       u64 gpa;
 
-       page = kmap_atomic_to_page(addr);
+       if (!(svm->nested.intercept & (1ULL << INTERCEPT_IOIO_PROT)))
+               return NESTED_EXIT_HOST;
 
-       kunmap_atomic(addr, idx);
-       kvm_release_page_dirty(page);
+       port = svm->vmcb->control.exit_info_1 >> 16;
+       gpa  = svm->nested.vmcb_iopm + (port / 8);
+       bit  = port % 8;
+       val  = 0;
+
+       if (kvm_read_guest(svm->vcpu.kvm, gpa, &val, 1))
+               val &= (1 << bit);
+
+       return val ? NESTED_EXIT_DONE : NESTED_EXIT_HOST;
 }
 
-static bool nested_svm_exit_handled_msr(struct vcpu_svm *svm)
+static int nested_svm_exit_handled_msr(struct vcpu_svm *svm)
 {
-       u32 param = svm->vmcb->control.exit_info_1 & 1;
-       u32 msr = svm->vcpu.arch.regs[VCPU_REGS_RCX];
-       bool ret = false;
-       u32 t0, t1;
-       u8 *msrpm;
+       u32 offset, msr, value;
+       int write, mask;
 
        if (!(svm->nested.intercept & (1ULL << INTERCEPT_MSR_PROT)))
-               return false;
+               return NESTED_EXIT_HOST;
 
-       msrpm = nested_svm_map(svm, svm->nested.vmcb_msrpm, KM_USER0);
+       msr    = svm->vcpu.arch.regs[VCPU_REGS_RCX];
+       offset = svm_msrpm_offset(msr);
+       write  = svm->vmcb->control.exit_info_1 & 1;
+       mask   = 1 << ((2 * (msr & 0xf)) + write);
 
-       if (!msrpm)
-               goto out;
+       if (offset == MSR_INVALID)
+               return NESTED_EXIT_DONE;
 
-       switch (msr) {
-       case 0 ... 0x1fff:
-               t0 = (msr * 2) % 8;
-               t1 = msr / 8;
-               break;
-       case 0xc0000000 ... 0xc0001fff:
-               t0 = (8192 + msr - 0xc0000000) * 2;
-               t1 = (t0 / 8);
-               t0 %= 8;
-               break;
-       case 0xc0010000 ... 0xc0011fff:
-               t0 = (16384 + msr - 0xc0010000) * 2;
-               t1 = (t0 / 8);
-               t0 %= 8;
-               break;
-       default:
-               ret = true;
-               goto out;
-       }
+       /* Offset is in 32 bit units but need in 8 bit units */
+       offset *= 4;
 
-       ret = msrpm[t1] & ((1 << param) << t0);
-
-out:
-       nested_svm_unmap(msrpm, KM_USER0);
+       if (kvm_read_guest(svm->vcpu.kvm, svm->nested.vmcb_msrpm + offset, &value, 4))
+               return NESTED_EXIT_DONE;
 
-       return ret;
+       return (value & mask) ? NESTED_EXIT_DONE : NESTED_EXIT_HOST;
 }
 
 static int nested_svm_exit_special(struct vcpu_svm *svm)
@@ -1504,17 +1651,21 @@ static int nested_svm_exit_special(struct vcpu_svm *svm)
        switch (exit_code) {
        case SVM_EXIT_INTR:
        case SVM_EXIT_NMI:
+       case SVM_EXIT_EXCP_BASE + MC_VECTOR:
                return NESTED_EXIT_HOST;
-               /* For now we are always handling NPFs when using them */
        case SVM_EXIT_NPF:
+               /* For now we are always handling NPFs when using them */
                if (npt_enabled)
                        return NESTED_EXIT_HOST;
                break;
-       /* When we're shadowing, trap PFs */
        case SVM_EXIT_EXCP_BASE + PF_VECTOR:
+               /* When we're shadowing, trap PFs */
                if (!npt_enabled)
                        return NESTED_EXIT_HOST;
                break;
+       case SVM_EXIT_EXCP_BASE + NM_VECTOR:
+               nm_interception(svm);
+               break;
        default:
                break;
        }
@@ -1525,7 +1676,7 @@ static int nested_svm_exit_special(struct vcpu_svm *svm)
 /*
  * If this function returns true, this #vmexit was already handled
  */
-static int nested_svm_exit_handled(struct vcpu_svm *svm)
+static int nested_svm_intercept(struct vcpu_svm *svm)
 {
        u32 exit_code = svm->vmcb->control.exit_code;
        int vmexit = NESTED_EXIT_HOST;
@@ -1534,6 +1685,9 @@ static int nested_svm_exit_handled(struct vcpu_svm *svm)
        case SVM_EXIT_MSR:
                vmexit = nested_svm_exit_handled_msr(svm);
                break;
+       case SVM_EXIT_IOIO:
+               vmexit = nested_svm_intercept_ioio(svm);
+               break;
        case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR8: {
                u32 cr_bits = 1 << (exit_code - SVM_EXIT_READ_CR0);
                if (svm->nested.intercept_cr_read & cr_bits)
@@ -1564,6 +1718,10 @@ static int nested_svm_exit_handled(struct vcpu_svm *svm)
                        vmexit = NESTED_EXIT_DONE;
                break;
        }
+       case SVM_EXIT_ERR: {
+               vmexit = NESTED_EXIT_DONE;
+               break;
+       }
        default: {
                u64 exit_bits = 1ULL << (exit_code - SVM_EXIT_INTR);
                if (svm->nested.intercept & exit_bits)
@@ -1571,9 +1729,17 @@ static int nested_svm_exit_handled(struct vcpu_svm *svm)
        }
        }
 
-       if (vmexit == NESTED_EXIT_DONE) {
+       return vmexit;
+}
+
+static int nested_svm_exit_handled(struct vcpu_svm *svm)
+{
+       int vmexit;
+
+       vmexit = nested_svm_intercept(svm);
+
+       if (vmexit == NESTED_EXIT_DONE)
                nested_svm_vmexit(svm);
-       }
 
        return vmexit;
 }
@@ -1615,6 +1781,7 @@ static int nested_svm_vmexit(struct vcpu_svm *svm)
        struct vmcb *nested_vmcb;
        struct vmcb *hsave = svm->nested.hsave;
        struct vmcb *vmcb = svm->vmcb;
+       struct page *page;
 
        trace_kvm_nested_vmexit_inject(vmcb->control.exit_code,
                                       vmcb->control.exit_info_1,
@@ -1622,10 +1789,13 @@ static int nested_svm_vmexit(struct vcpu_svm *svm)
                                       vmcb->control.exit_int_info,
                                       vmcb->control.exit_int_info_err);
 
-       nested_vmcb = nested_svm_map(svm, svm->nested.vmcb, KM_USER0);
+       nested_vmcb = nested_svm_map(svm, svm->nested.vmcb, &page);
        if (!nested_vmcb)
                return 1;
 
+       /* Exit nested SVM mode */
+       svm->nested.vmcb = 0;
+
        /* Give the current vmcb to the guest */
        disable_gif(svm);
 
@@ -1635,9 +1805,10 @@ static int nested_svm_vmexit(struct vcpu_svm *svm)
        nested_vmcb->save.ds     = vmcb->save.ds;
        nested_vmcb->save.gdtr   = vmcb->save.gdtr;
        nested_vmcb->save.idtr   = vmcb->save.idtr;
-       if (npt_enabled)
-               nested_vmcb->save.cr3    = vmcb->save.cr3;
+       nested_vmcb->save.cr0    = kvm_read_cr0(&svm->vcpu);
+       nested_vmcb->save.cr3    = svm->vcpu.arch.cr3;
        nested_vmcb->save.cr2    = vmcb->save.cr2;
+       nested_vmcb->save.cr4    = svm->vcpu.arch.cr4;
        nested_vmcb->save.rflags = vmcb->save.rflags;
        nested_vmcb->save.rip    = vmcb->save.rip;
        nested_vmcb->save.rsp    = vmcb->save.rsp;
@@ -1709,10 +1880,7 @@ static int nested_svm_vmexit(struct vcpu_svm *svm)
        svm->vmcb->save.cpl = 0;
        svm->vmcb->control.exit_int_info = 0;
 
-       /* Exit nested SVM mode */
-       svm->nested.vmcb = 0;
-
-       nested_svm_unmap(nested_vmcb, KM_USER0);
+       nested_svm_unmap(page);
 
        kvm_mmu_reset_context(&svm->vcpu);
        kvm_mmu_load(&svm->vcpu);
@@ -1722,19 +1890,33 @@ static int nested_svm_vmexit(struct vcpu_svm *svm)
 
 static bool nested_svm_vmrun_msrpm(struct vcpu_svm *svm)
 {
-       u32 *nested_msrpm;
+       /*
+        * This function merges the msr permission bitmaps of kvm and the
+        * nested vmcb. It is omptimized in that it only merges the parts where
+        * the kvm msr permission bitmap may contain zero bits
+        */
        int i;
 
-       nested_msrpm = nested_svm_map(svm, svm->nested.vmcb_msrpm, KM_USER0);
-       if (!nested_msrpm)
-               return false;
+       if (!(svm->nested.intercept & (1ULL << INTERCEPT_MSR_PROT)))
+               return true;
 
-       for (i=0; i< PAGE_SIZE * (1 << MSRPM_ALLOC_ORDER) / 4; i++)
-               svm->nested.msrpm[i] = svm->msrpm[i] | nested_msrpm[i];
+       for (i = 0; i < MSRPM_OFFSETS; i++) {
+               u32 value, p;
+               u64 offset;
 
-       svm->vmcb->control.msrpm_base_pa = __pa(svm->nested.msrpm);
+               if (msrpm_offsets[i] == 0xffffffff)
+                       break;
+
+               p      = msrpm_offsets[i];
+               offset = svm->nested.vmcb_msrpm + (p * 4);
+
+               if (kvm_read_guest(svm->vcpu.kvm, offset, &value, 4))
+                       return false;
+
+               svm->nested.msrpm[p] = svm->msrpm[p] | value;
+       }
 
-       nested_svm_unmap(nested_msrpm, KM_USER0);
+       svm->vmcb->control.msrpm_base_pa = __pa(svm->nested.msrpm);
 
        return true;
 }
@@ -1744,26 +1926,34 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm)
        struct vmcb *nested_vmcb;
        struct vmcb *hsave = svm->nested.hsave;
        struct vmcb *vmcb = svm->vmcb;
+       struct page *page;
+       u64 vmcb_gpa;
 
-       nested_vmcb = nested_svm_map(svm, svm->vmcb->save.rax, KM_USER0);
+       vmcb_gpa = svm->vmcb->save.rax;
+
+       nested_vmcb = nested_svm_map(svm, svm->vmcb->save.rax, &page);
        if (!nested_vmcb)
                return false;
 
-       /* nested_vmcb is our indicator if nested SVM is activated */
-       svm->nested.vmcb = svm->vmcb->save.rax;
-
-       trace_kvm_nested_vmrun(svm->vmcb->save.rip - 3, svm->nested.vmcb,
+       trace_kvm_nested_vmrun(svm->vmcb->save.rip - 3, vmcb_gpa,
                               nested_vmcb->save.rip,
                               nested_vmcb->control.int_ctl,
                               nested_vmcb->control.event_inj,
                               nested_vmcb->control.nested_ctl);
 
+       trace_kvm_nested_intercepts(nested_vmcb->control.intercept_cr_read,
+                                   nested_vmcb->control.intercept_cr_write,
+                                   nested_vmcb->control.intercept_exceptions,
+                                   nested_vmcb->control.intercept);
+
        /* Clear internal status */
        kvm_clear_exception_queue(&svm->vcpu);
        kvm_clear_interrupt_queue(&svm->vcpu);
 
-       /* Save the old vmcb, so we don't need to pick what we save, but
-          can restore everything when a VMEXIT occurs */
+       /*
+        * Save the old vmcb, so we don't need to pick what we save, but can
+        * restore everything when a VMEXIT occurs
+        */
        hsave->save.es     = vmcb->save.es;
        hsave->save.cs     = vmcb->save.cs;
        hsave->save.ss     = vmcb->save.ss;
@@ -1803,14 +1993,17 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm)
        if (npt_enabled) {
                svm->vmcb->save.cr3 = nested_vmcb->save.cr3;
                svm->vcpu.arch.cr3 = nested_vmcb->save.cr3;
-       } else {
+       } else
                kvm_set_cr3(&svm->vcpu, nested_vmcb->save.cr3);
-               kvm_mmu_reset_context(&svm->vcpu);
-       }
+
+       /* Guest paging mode is active - reset mmu */
+       kvm_mmu_reset_context(&svm->vcpu);
+
        svm->vmcb->save.cr2 = svm->vcpu.arch.cr2 = nested_vmcb->save.cr2;
        kvm_register_write(&svm->vcpu, VCPU_REGS_RAX, nested_vmcb->save.rax);
        kvm_register_write(&svm->vcpu, VCPU_REGS_RSP, nested_vmcb->save.rsp);
        kvm_register_write(&svm->vcpu, VCPU_REGS_RIP, nested_vmcb->save.rip);
+
        /* In case we don't even reach vcpu_run, the fields are not updated */
        svm->vmcb->save.rax = nested_vmcb->save.rax;
        svm->vmcb->save.rsp = nested_vmcb->save.rsp;
@@ -1819,22 +2012,8 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm)
        svm->vmcb->save.dr6 = nested_vmcb->save.dr6;
        svm->vmcb->save.cpl = nested_vmcb->save.cpl;
 
-       /* We don't want a nested guest to be more powerful than the guest,
-          so all intercepts are ORed */
-       svm->vmcb->control.intercept_cr_read |=
-               nested_vmcb->control.intercept_cr_read;
-       svm->vmcb->control.intercept_cr_write |=
-               nested_vmcb->control.intercept_cr_write;
-       svm->vmcb->control.intercept_dr_read |=
-               nested_vmcb->control.intercept_dr_read;
-       svm->vmcb->control.intercept_dr_write |=
-               nested_vmcb->control.intercept_dr_write;
-       svm->vmcb->control.intercept_exceptions |=
-               nested_vmcb->control.intercept_exceptions;
-
-       svm->vmcb->control.intercept |= nested_vmcb->control.intercept;
-
-       svm->nested.vmcb_msrpm = nested_vmcb->control.msrpm_base_pa;
+       svm->nested.vmcb_msrpm = nested_vmcb->control.msrpm_base_pa & ~0x0fffULL;
+       svm->nested.vmcb_iopm  = nested_vmcb->control.iopm_base_pa  & ~0x0fffULL;
 
        /* cache intercepts */
        svm->nested.intercept_cr_read    = nested_vmcb->control.intercept_cr_read;
@@ -1851,13 +2030,43 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm)
        else
                svm->vcpu.arch.hflags &= ~HF_VINTR_MASK;
 
+       if (svm->vcpu.arch.hflags & HF_VINTR_MASK) {
+               /* We only want the cr8 intercept bits of the guest */
+               svm->vmcb->control.intercept_cr_read &= ~INTERCEPT_CR8_MASK;
+               svm->vmcb->control.intercept_cr_write &= ~INTERCEPT_CR8_MASK;
+       }
+
+       /* We don't want to see VMMCALLs from a nested guest */
+       svm->vmcb->control.intercept &= ~(1ULL << INTERCEPT_VMMCALL);
+
+       /*
+        * We don't want a nested guest to be more powerful than the guest, so
+        * all intercepts are ORed
+        */
+       svm->vmcb->control.intercept_cr_read |=
+               nested_vmcb->control.intercept_cr_read;
+       svm->vmcb->control.intercept_cr_write |=
+               nested_vmcb->control.intercept_cr_write;
+       svm->vmcb->control.intercept_dr_read |=
+               nested_vmcb->control.intercept_dr_read;
+       svm->vmcb->control.intercept_dr_write |=
+               nested_vmcb->control.intercept_dr_write;
+       svm->vmcb->control.intercept_exceptions |=
+               nested_vmcb->control.intercept_exceptions;
+
+       svm->vmcb->control.intercept |= nested_vmcb->control.intercept;
+
+       svm->vmcb->control.lbr_ctl = nested_vmcb->control.lbr_ctl;
        svm->vmcb->control.int_vector = nested_vmcb->control.int_vector;
        svm->vmcb->control.int_state = nested_vmcb->control.int_state;
        svm->vmcb->control.tsc_offset += nested_vmcb->control.tsc_offset;
        svm->vmcb->control.event_inj = nested_vmcb->control.event_inj;
        svm->vmcb->control.event_inj_err = nested_vmcb->control.event_inj_err;
 
-       nested_svm_unmap(nested_vmcb, KM_USER0);
+       nested_svm_unmap(page);
+
+       /* nested_vmcb is our indicator if nested SVM is activated */
+       svm->nested.vmcb = vmcb_gpa;
 
        enable_gif(svm);
 
@@ -1883,6 +2092,7 @@ static void nested_svm_vmloadsave(struct vmcb *from_vmcb, struct vmcb *to_vmcb)
 static int vmload_interception(struct vcpu_svm *svm)
 {
        struct vmcb *nested_vmcb;
+       struct page *page;
 
        if (nested_svm_check_permissions(svm))
                return 1;
@@ -1890,12 +2100,12 @@ static int vmload_interception(struct vcpu_svm *svm)
        svm->next_rip = kvm_rip_read(&svm->vcpu) + 3;
        skip_emulated_instruction(&svm->vcpu);
 
-       nested_vmcb = nested_svm_map(svm, svm->vmcb->save.rax, KM_USER0);
+       nested_vmcb = nested_svm_map(svm, svm->vmcb->save.rax, &page);
        if (!nested_vmcb)
                return 1;
 
        nested_svm_vmloadsave(nested_vmcb, svm->vmcb);
-       nested_svm_unmap(nested_vmcb, KM_USER0);
+       nested_svm_unmap(page);
 
        return 1;
 }
@@ -1903,6 +2113,7 @@ static int vmload_interception(struct vcpu_svm *svm)
 static int vmsave_interception(struct vcpu_svm *svm)
 {
        struct vmcb *nested_vmcb;
+       struct page *page;
 
        if (nested_svm_check_permissions(svm))
                return 1;
@@ -1910,12 +2121,12 @@ static int vmsave_interception(struct vcpu_svm *svm)
        svm->next_rip = kvm_rip_read(&svm->vcpu) + 3;
        skip_emulated_instruction(&svm->vcpu);
 
-       nested_vmcb = nested_svm_map(svm, svm->vmcb->save.rax, KM_USER0);
+       nested_vmcb = nested_svm_map(svm, svm->vmcb->save.rax, &page);
        if (!nested_vmcb)
                return 1;
 
        nested_svm_vmloadsave(svm->vmcb, nested_vmcb);
-       nested_svm_unmap(nested_vmcb, KM_USER0);
+       nested_svm_unmap(page);
 
        return 1;
 }
@@ -2018,6 +2229,8 @@ static int task_switch_interception(struct vcpu_svm *svm)
                svm->vmcb->control.exit_int_info & SVM_EXITINTINFO_TYPE_MASK;
        uint32_t idt_v =
                svm->vmcb->control.exit_int_info & SVM_EXITINTINFO_VALID;
+       bool has_error_code = false;
+       u32 error_code = 0;
 
        tss_selector = (u16)svm->vmcb->control.exit_info_1;
 
@@ -2038,6 +2251,12 @@ static int task_switch_interception(struct vcpu_svm *svm)
                        svm->vcpu.arch.nmi_injected = false;
                        break;
                case SVM_EXITINTINFO_TYPE_EXEPT:
+                       if (svm->vmcb->control.exit_info_2 &
+                           (1ULL << SVM_EXITINFOSHIFT_TS_HAS_ERROR_CODE)) {
+                               has_error_code = true;
+                               error_code =
+                                       (u32)svm->vmcb->control.exit_info_2;
+                       }
                        kvm_clear_exception_queue(&svm->vcpu);
                        break;
                case SVM_EXITINTINFO_TYPE_INTR:
@@ -2054,7 +2273,14 @@ static int task_switch_interception(struct vcpu_svm *svm)
             (int_vec == OF_VECTOR || int_vec == BP_VECTOR)))
                skip_emulated_instruction(&svm->vcpu);
 
-       return kvm_task_switch(&svm->vcpu, tss_selector, reason);
+       if (kvm_task_switch(&svm->vcpu, tss_selector, reason,
+                               has_error_code, error_code) == EMULATE_FAIL) {
+               svm->vcpu.run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
+               svm->vcpu.run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
+               svm->vcpu.run->internal.ndata = 0;
+               return 0;
+       }
+       return 1;
 }
 
 static int cpuid_interception(struct vcpu_svm *svm)
@@ -2145,9 +2371,11 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data)
        case MSR_IA32_SYSENTER_ESP:
                *data = svm->sysenter_esp;
                break;
-       /* Nobody will change the following 5 values in the VMCB so
-          we can safely return them on rdmsr. They will always be 0
-          until LBRV is implemented. */
+       /*
+        * Nobody will change the following 5 values in the VMCB so we can
+        * safely return them on rdmsr. They will always be 0 until LBRV is
+        * implemented.
+        */
        case MSR_IA32_DEBUGCTLMSR:
                *data = svm->vmcb->save.dbgctl;
                break;
@@ -2167,7 +2395,7 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data)
                *data = svm->nested.hsave_msr;
                break;
        case MSR_VM_CR:
-               *data = 0;
+               *data = svm->nested.vm_cr_msr;
                break;
        case MSR_IA32_UCODE_REV:
                *data = 0x01000065;
@@ -2197,6 +2425,31 @@ static int rdmsr_interception(struct vcpu_svm *svm)
        return 1;
 }
 
+static int svm_set_vm_cr(struct kvm_vcpu *vcpu, u64 data)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+       int svm_dis, chg_mask;
+
+       if (data & ~SVM_VM_CR_VALID_MASK)
+               return 1;
+
+       chg_mask = SVM_VM_CR_VALID_MASK;
+
+       if (svm->nested.vm_cr_msr & SVM_VM_CR_SVM_DIS_MASK)
+               chg_mask &= ~(SVM_VM_CR_SVM_LOCK_MASK | SVM_VM_CR_SVM_DIS_MASK);
+
+       svm->nested.vm_cr_msr &= ~chg_mask;
+       svm->nested.vm_cr_msr |= (data & chg_mask);
+
+       svm_dis = svm->nested.vm_cr_msr & SVM_VM_CR_SVM_DIS_MASK;
+
+       /* check for svm_disable while efer.svme is set */
+       if (svm_dis && (vcpu->arch.efer & EFER_SVME))
+               return 1;
+
+       return 0;
+}
+
 static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
@@ -2263,6 +2516,7 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data)
                svm->nested.hsave_msr = data;
                break;
        case MSR_VM_CR:
+               return svm_set_vm_cr(vcpu, data);
        case MSR_VM_IGNNE:
                pr_unimpl(vcpu, "unimplemented wrmsr: 0x%x data 0x%llx\n", ecx, data);
                break;
@@ -2326,16 +2580,16 @@ static int pause_interception(struct vcpu_svm *svm)
 }
 
 static int (*svm_exit_handlers[])(struct vcpu_svm *svm) = {
-       [SVM_EXIT_READ_CR0]                     = emulate_on_interception,
-       [SVM_EXIT_READ_CR3]                     = emulate_on_interception,
-       [SVM_EXIT_READ_CR4]                     = emulate_on_interception,
-       [SVM_EXIT_READ_CR8]                     = emulate_on_interception,
+       [SVM_EXIT_READ_CR0]                     = emulate_on_interception,
+       [SVM_EXIT_READ_CR3]                     = emulate_on_interception,
+       [SVM_EXIT_READ_CR4]                     = emulate_on_interception,
+       [SVM_EXIT_READ_CR8]                     = emulate_on_interception,
        [SVM_EXIT_CR0_SEL_WRITE]                = emulate_on_interception,
-       [SVM_EXIT_WRITE_CR0]                    = emulate_on_interception,
-       [SVM_EXIT_WRITE_CR3]                    = emulate_on_interception,
-       [SVM_EXIT_WRITE_CR4]                    = emulate_on_interception,
-       [SVM_EXIT_WRITE_CR8]                    = cr8_write_interception,
-       [SVM_EXIT_READ_DR0]                     = emulate_on_interception,
+       [SVM_EXIT_WRITE_CR0]                    = emulate_on_interception,
+       [SVM_EXIT_WRITE_CR3]                    = emulate_on_interception,
+       [SVM_EXIT_WRITE_CR4]                    = emulate_on_interception,
+       [SVM_EXIT_WRITE_CR8]                    = cr8_write_interception,
+       [SVM_EXIT_READ_DR0]                     = emulate_on_interception,
        [SVM_EXIT_READ_DR1]                     = emulate_on_interception,
        [SVM_EXIT_READ_DR2]                     = emulate_on_interception,
        [SVM_EXIT_READ_DR3]                     = emulate_on_interception,
@@ -2354,15 +2608,14 @@ static int (*svm_exit_handlers[])(struct vcpu_svm *svm) = {
        [SVM_EXIT_EXCP_BASE + DB_VECTOR]        = db_interception,
        [SVM_EXIT_EXCP_BASE + BP_VECTOR]        = bp_interception,
        [SVM_EXIT_EXCP_BASE + UD_VECTOR]        = ud_interception,
-       [SVM_EXIT_EXCP_BASE + PF_VECTOR]        = pf_interception,
-       [SVM_EXIT_EXCP_BASE + NM_VECTOR]        = nm_interception,
-       [SVM_EXIT_EXCP_BASE + MC_VECTOR]        = mc_interception,
-       [SVM_EXIT_INTR]                         = intr_interception,
+       [SVM_EXIT_EXCP_BASE + PF_VECTOR]        = pf_interception,
+       [SVM_EXIT_EXCP_BASE + NM_VECTOR]        = nm_interception,
+       [SVM_EXIT_EXCP_BASE + MC_VECTOR]        = mc_interception,
+       [SVM_EXIT_INTR]                         = intr_interception,
        [SVM_EXIT_NMI]                          = nmi_interception,
        [SVM_EXIT_SMI]                          = nop_on_interception,
        [SVM_EXIT_INIT]                         = nop_on_interception,
        [SVM_EXIT_VINTR]                        = interrupt_window_interception,
-       /* [SVM_EXIT_CR0_SEL_WRITE]             = emulate_on_interception, */
        [SVM_EXIT_CPUID]                        = cpuid_interception,
        [SVM_EXIT_IRET]                         = iret_interception,
        [SVM_EXIT_INVD]                         = emulate_on_interception,
@@ -2370,7 +2623,7 @@ static int (*svm_exit_handlers[])(struct vcpu_svm *svm) = {
        [SVM_EXIT_HLT]                          = halt_interception,
        [SVM_EXIT_INVLPG]                       = invlpg_interception,
        [SVM_EXIT_INVLPGA]                      = invlpga_interception,
-       [SVM_EXIT_IOIO]                         = io_interception,
+       [SVM_EXIT_IOIO]                         = io_interception,
        [SVM_EXIT_MSR]                          = msr_interception,
        [SVM_EXIT_TASK_SWITCH]                  = task_switch_interception,
        [SVM_EXIT_SHUTDOWN]                     = shutdown_interception,
@@ -2393,7 +2646,12 @@ static int handle_exit(struct kvm_vcpu *vcpu)
        struct kvm_run *kvm_run = vcpu->run;
        u32 exit_code = svm->vmcb->control.exit_code;
 
-       trace_kvm_exit(exit_code, svm->vmcb->save.rip);
+       trace_kvm_exit(exit_code, vcpu);
+
+       if (!(svm->vmcb->control.intercept_cr_write & INTERCEPT_CR0_MASK))
+               vcpu->arch.cr0 = svm->vmcb->save.cr0;
+       if (npt_enabled)
+               vcpu->arch.cr3 = svm->vmcb->save.cr3;
 
        if (unlikely(svm->nested.exit_required)) {
                nested_svm_vmexit(svm);
@@ -2422,11 +2680,6 @@ static int handle_exit(struct kvm_vcpu *vcpu)
 
        svm_complete_interrupts(svm);
 
-       if (!(svm->vmcb->control.intercept_cr_write & INTERCEPT_CR0_MASK))
-               vcpu->arch.cr0 = svm->vmcb->save.cr0;
-       if (npt_enabled)
-               vcpu->arch.cr3 = svm->vmcb->save.cr3;
-
        if (svm->vmcb->control.exit_code == SVM_EXIT_ERR) {
                kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
                kvm_run->fail_entry.hardware_entry_failure_reason
@@ -2511,6 +2764,9 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
 
+       if (is_nested(svm) && (vcpu->arch.hflags & HF_VINTR_MASK))
+               return;
+
        if (irr == -1)
                return;
 
@@ -2522,8 +2778,12 @@ static int svm_nmi_allowed(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
        struct vmcb *vmcb = svm->vmcb;
-       return !(vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) &&
-               !(svm->vcpu.arch.hflags & HF_NMI_MASK);
+       int ret;
+       ret = !(vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) &&
+             !(svm->vcpu.arch.hflags & HF_NMI_MASK);
+       ret = ret && gif_set(svm) && nested_svm_nmi(svm);
+
+       return ret;
 }
 
 static bool svm_get_nmi_mask(struct kvm_vcpu *vcpu)
@@ -2568,13 +2828,13 @@ static void enable_irq_window(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
 
-       nested_svm_intr(svm);
-
-       /* In case GIF=0 we can't rely on the CPU to tell us when
-        * GIF becomes 1, because that's a separate STGI/VMRUN intercept.
-        * The next time we get that intercept, this function will be
-        * called again though and we'll get the vintr intercept. */
-       if (gif_set(svm)) {
+       /*
+        * In case GIF=0 we can't rely on the CPU to tell us when GIF becomes
+        * 1, because that's a separate STGI/VMRUN intercept.  The next time we
+        * get that intercept, this function will be called again though and
+        * we'll get the vintr intercept.
+        */
+       if (gif_set(svm) && nested_svm_intr(svm)) {
                svm_set_vintr(svm);
                svm_inject_irq(svm, 0x0);
        }
@@ -2588,9 +2848,10 @@ static void enable_nmi_window(struct kvm_vcpu *vcpu)
            == HF_NMI_MASK)
                return; /* IRET will cause a vm exit */
 
-       /* Something prevents NMI from been injected. Single step over
-          possible problem (IRET or exception injection or interrupt
-          shadow) */
+       /*
+        * Something prevents NMI from been injected. Single step over possible
+        * problem (IRET or exception injection or interrupt shadow)
+        */
        svm->nmi_singlestep = true;
        svm->vmcb->save.rflags |= (X86_EFLAGS_TF | X86_EFLAGS_RF);
        update_db_intercept(vcpu);
@@ -2614,6 +2875,9 @@ static inline void sync_cr8_to_lapic(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
 
+       if (is_nested(svm) && (vcpu->arch.hflags & HF_VINTR_MASK))
+               return;
+
        if (!(svm->vmcb->control.intercept_cr_write & INTERCEPT_CR8_MASK)) {
                int cr8 = svm->vmcb->control.int_ctl & V_TPR_MASK;
                kvm_set_cr8(vcpu, cr8);
@@ -2625,6 +2889,9 @@ static inline void sync_lapic_to_cr8(struct kvm_vcpu *vcpu)
        struct vcpu_svm *svm = to_svm(vcpu);
        u64 cr8;
 
+       if (is_nested(svm) && (vcpu->arch.hflags & HF_VINTR_MASK))
+               return;
+
        cr8 = kvm_get_cr8(vcpu);
        svm->vmcb->control.int_ctl &= ~V_TPR_MASK;
        svm->vmcb->control.int_ctl |= cr8 & V_TPR_MASK;
@@ -2635,6 +2902,9 @@ static void svm_complete_interrupts(struct vcpu_svm *svm)
        u8 vector;
        int type;
        u32 exitintinfo = svm->vmcb->control.exit_int_info;
+       unsigned int3_injected = svm->int3_injected;
+
+       svm->int3_injected = 0;
 
        if (svm->vcpu.arch.hflags & HF_IRET_MASK)
                svm->vcpu.arch.hflags &= ~(HF_NMI_MASK | HF_IRET_MASK);
@@ -2654,18 +2924,25 @@ static void svm_complete_interrupts(struct vcpu_svm *svm)
                svm->vcpu.arch.nmi_injected = true;
                break;
        case SVM_EXITINTINFO_TYPE_EXEPT:
-               /* In case of software exception do not reinject an exception
-                  vector, but re-execute and instruction instead */
-               if (is_nested(svm))
-                       break;
-               if (kvm_exception_is_soft(vector))
+               /*
+                * In case of software exceptions, do not reinject the vector,
+                * but re-execute the instruction instead. Rewind RIP first
+                * if we emulated INT3 before.
+                */
+               if (kvm_exception_is_soft(vector)) {
+                       if (vector == BP_VECTOR && int3_injected &&
+                           kvm_is_linear_rip(&svm->vcpu, svm->int3_rip))
+                               kvm_rip_write(&svm->vcpu,
+                                             kvm_rip_read(&svm->vcpu) -
+                                             int3_injected);
                        break;
+               }
                if (exitintinfo & SVM_EXITINTINFO_VALID_ERR) {
                        u32 err = svm->vmcb->control.exit_int_info_err;
-                       kvm_queue_exception_e(&svm->vcpu, vector, err);
+                       kvm_requeue_exception_e(&svm->vcpu, vector, err);
 
                } else
-                       kvm_queue_exception(&svm->vcpu, vector);
+                       kvm_requeue_exception(&svm->vcpu, vector);
                break;
        case SVM_EXITINTINFO_TYPE_INTR:
                kvm_queue_interrupt(&svm->vcpu, vector, false);
@@ -2688,6 +2965,10 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
        u16 gs_selector;
        u16 ldt_selector;
 
+       svm->vmcb->save.rax = vcpu->arch.regs[VCPU_REGS_RAX];
+       svm->vmcb->save.rsp = vcpu->arch.regs[VCPU_REGS_RSP];
+       svm->vmcb->save.rip = vcpu->arch.regs[VCPU_REGS_RIP];
+
        /*
         * A vmexit emulation is required before the vcpu can be executed
         * again.
@@ -2695,10 +2976,6 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
        if (unlikely(svm->nested.exit_required))
                return;
 
-       svm->vmcb->save.rax = vcpu->arch.regs[VCPU_REGS_RAX];
-       svm->vmcb->save.rsp = vcpu->arch.regs[VCPU_REGS_RSP];
-       svm->vmcb->save.rip = vcpu->arch.regs[VCPU_REGS_RIP];
-
        pre_svm_run(svm);
 
        sync_lapic_to_cr8(vcpu);
@@ -2879,25 +3156,39 @@ static void svm_cpuid_update(struct kvm_vcpu *vcpu)
 {
 }
 
+static void svm_set_supported_cpuid(u32 func, struct kvm_cpuid_entry2 *entry)
+{
+       switch (func) {
+       case 0x8000000A:
+               entry->eax = 1; /* SVM revision 1 */
+               entry->ebx = 8; /* Lets support 8 ASIDs in case we add proper
+                                  ASID emulation to nested SVM */
+               entry->ecx = 0; /* Reserved */
+               entry->edx = 0; /* Do not support any additional features */
+
+               break;
+       }
+}
+
 static const struct trace_print_flags svm_exit_reasons_str[] = {
-       { SVM_EXIT_READ_CR0,                    "read_cr0" },
-       { SVM_EXIT_READ_CR3,                    "read_cr3" },
-       { SVM_EXIT_READ_CR4,                    "read_cr4" },
-       { SVM_EXIT_READ_CR8,                    "read_cr8" },
-       { SVM_EXIT_WRITE_CR0,                   "write_cr0" },
-       { SVM_EXIT_WRITE_CR3,                   "write_cr3" },
-       { SVM_EXIT_WRITE_CR4,                   "write_cr4" },
-       { SVM_EXIT_WRITE_CR8,                   "write_cr8" },
-       { SVM_EXIT_READ_DR0,                    "read_dr0" },
-       { SVM_EXIT_READ_DR1,                    "read_dr1" },
-       { SVM_EXIT_READ_DR2,                    "read_dr2" },
-       { SVM_EXIT_READ_DR3,                    "read_dr3" },
-       { SVM_EXIT_WRITE_DR0,                   "write_dr0" },
-       { SVM_EXIT_WRITE_DR1,                   "write_dr1" },
-       { SVM_EXIT_WRITE_DR2,                   "write_dr2" },
-       { SVM_EXIT_WRITE_DR3,                   "write_dr3" },
-       { SVM_EXIT_WRITE_DR5,                   "write_dr5" },
-       { SVM_EXIT_WRITE_DR7,                   "write_dr7" },
+       { SVM_EXIT_READ_CR0,                    "read_cr0" },
+       { SVM_EXIT_READ_CR3,                    "read_cr3" },
+       { SVM_EXIT_READ_CR4,                    "read_cr4" },
+       { SVM_EXIT_READ_CR8,                    "read_cr8" },
+       { SVM_EXIT_WRITE_CR0,                   "write_cr0" },
+       { SVM_EXIT_WRITE_CR3,                   "write_cr3" },
+       { SVM_EXIT_WRITE_CR4,                   "write_cr4" },
+       { SVM_EXIT_WRITE_CR8,                   "write_cr8" },
+       { SVM_EXIT_READ_DR0,                    "read_dr0" },
+       { SVM_EXIT_READ_DR1,                    "read_dr1" },
+       { SVM_EXIT_READ_DR2,                    "read_dr2" },
+       { SVM_EXIT_READ_DR3,                    "read_dr3" },
+       { SVM_EXIT_WRITE_DR0,                   "write_dr0" },
+       { SVM_EXIT_WRITE_DR1,                   "write_dr1" },
+       { SVM_EXIT_WRITE_DR2,                   "write_dr2" },
+       { SVM_EXIT_WRITE_DR3,                   "write_dr3" },
+       { SVM_EXIT_WRITE_DR5,                   "write_dr5" },
+       { SVM_EXIT_WRITE_DR7,                   "write_dr7" },
        { SVM_EXIT_EXCP_BASE + DB_VECTOR,       "DB excp" },
        { SVM_EXIT_EXCP_BASE + BP_VECTOR,       "BP excp" },
        { SVM_EXIT_EXCP_BASE + UD_VECTOR,       "UD excp" },
@@ -2946,8 +3237,10 @@ static void svm_fpu_deactivate(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
 
-       update_cr0_intercept(svm);
        svm->vmcb->control.intercept_exceptions |= 1 << NM_VECTOR;
+       if (is_nested(svm))
+               svm->nested.hsave->control.intercept_exceptions |= 1 << NM_VECTOR;
+       update_cr0_intercept(svm);
 }
 
 static struct kvm_x86_ops svm_x86_ops = {
@@ -2986,8 +3279,7 @@ static struct kvm_x86_ops svm_x86_ops = {
        .set_idt = svm_set_idt,
        .get_gdt = svm_get_gdt,
        .set_gdt = svm_set_gdt,
-       .get_dr = svm_get_dr,
-       .set_dr = svm_set_dr,
+       .set_dr7 = svm_set_dr7,
        .cache_reg = svm_cache_reg,
        .get_rflags = svm_get_rflags,
        .set_rflags = svm_set_rflags,
@@ -3023,12 +3315,14 @@ static struct kvm_x86_ops svm_x86_ops = {
        .cpuid_update = svm_cpuid_update,
 
        .rdtscp_supported = svm_rdtscp_supported,
+
+       .set_supported_cpuid = svm_set_supported_cpuid,
 };
 
 static int __init svm_init(void)
 {
        return kvm_init(&svm_x86_ops, sizeof(struct vcpu_svm),
-                             THIS_MODULE);
+                       __alignof__(struct vcpu_svm), THIS_MODULE);
 }
 
 static void __exit svm_exit(void)
index eea40439066c2eb828ded2a0d87409140b658c2f..4ddadb1a5ffe5f97f51eaa93b6c6fc9c9fe6c4c4 100644 (file)
@@ -12,7 +12,8 @@ static int __kvm_timer_fn(struct kvm_vcpu *vcpu, struct kvm_timer *ktimer)
        /*
         * There is a race window between reading and incrementing, but we do
         * not care about potentially loosing timer events in the !reinject
-        * case anyway.
+        * case anyway. Note: KVM_REQ_PENDING_TIMER is implicitly checked
+        * in vcpu_enter_guest.
         */
        if (ktimer->reinject || !atomic_read(&ktimer->pending)) {
                atomic_inc(&ktimer->pending);
index 6ad30a29f04416fd65c2fc41f43e514f8a7c0004..a6544b8e7c0f8bd96e24835d32ac5d4158c8d565 100644 (file)
@@ -5,8 +5,6 @@
 
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM kvm
-#define TRACE_INCLUDE_PATH arch/x86/kvm
-#define TRACE_INCLUDE_FILE trace
 
 /*
  * Tracepoint for guest mode entry.
@@ -184,8 +182,8 @@ TRACE_EVENT(kvm_apic,
  * Tracepoint for kvm guest exit:
  */
 TRACE_EVENT(kvm_exit,
-       TP_PROTO(unsigned int exit_reason, unsigned long guest_rip),
-       TP_ARGS(exit_reason, guest_rip),
+       TP_PROTO(unsigned int exit_reason, struct kvm_vcpu *vcpu),
+       TP_ARGS(exit_reason, vcpu),
 
        TP_STRUCT__entry(
                __field(        unsigned int,   exit_reason     )
@@ -194,7 +192,7 @@ TRACE_EVENT(kvm_exit,
 
        TP_fast_assign(
                __entry->exit_reason    = exit_reason;
-               __entry->guest_rip      = guest_rip;
+               __entry->guest_rip      = kvm_rip_read(vcpu);
        ),
 
        TP_printk("reason %s rip 0x%lx",
@@ -221,6 +219,38 @@ TRACE_EVENT(kvm_inj_virq,
        TP_printk("irq %u", __entry->irq)
 );
 
+#define EXS(x) { x##_VECTOR, "#" #x }
+
+#define kvm_trace_sym_exc                                              \
+       EXS(DE), EXS(DB), EXS(BP), EXS(OF), EXS(BR), EXS(UD), EXS(NM),  \
+       EXS(DF), EXS(TS), EXS(NP), EXS(SS), EXS(GP), EXS(PF),           \
+       EXS(MF), EXS(MC)
+
+/*
+ * Tracepoint for kvm interrupt injection:
+ */
+TRACE_EVENT(kvm_inj_exception,
+       TP_PROTO(unsigned exception, bool has_error, unsigned error_code),
+       TP_ARGS(exception, has_error, error_code),
+
+       TP_STRUCT__entry(
+               __field(        u8,     exception       )
+               __field(        u8,     has_error       )
+               __field(        u32,    error_code      )
+       ),
+
+       TP_fast_assign(
+               __entry->exception      = exception;
+               __entry->has_error      = has_error;
+               __entry->error_code     = error_code;
+       ),
+
+       TP_printk("%s (0x%x)",
+                 __print_symbolic(__entry->exception, kvm_trace_sym_exc),
+                 /* FIXME: don't print error_code if not present */
+                 __entry->has_error ? __entry->error_code : 0)
+);
+
 /*
  * Tracepoint for page fault.
  */
@@ -413,12 +443,34 @@ TRACE_EVENT(kvm_nested_vmrun,
        ),
 
        TP_printk("rip: 0x%016llx vmcb: 0x%016llx nrip: 0x%016llx int_ctl: 0x%08x "
-                 "event_inj: 0x%08x npt: %s\n",
+                 "event_inj: 0x%08x npt: %s",
                __entry->rip, __entry->vmcb, __entry->nested_rip,
                __entry->int_ctl, __entry->event_inj,
                __entry->npt ? "on" : "off")
 );
 
+TRACE_EVENT(kvm_nested_intercepts,
+           TP_PROTO(__u16 cr_read, __u16 cr_write, __u32 exceptions, __u64 intercept),
+           TP_ARGS(cr_read, cr_write, exceptions, intercept),
+
+       TP_STRUCT__entry(
+               __field(        __u16,          cr_read         )
+               __field(        __u16,          cr_write        )
+               __field(        __u32,          exceptions      )
+               __field(        __u64,          intercept       )
+       ),
+
+       TP_fast_assign(
+               __entry->cr_read        = cr_read;
+               __entry->cr_write       = cr_write;
+               __entry->exceptions     = exceptions;
+               __entry->intercept      = intercept;
+       ),
+
+       TP_printk("cr_read: %04x cr_write: %04x excp: %08x intercept: %016llx",
+               __entry->cr_read, __entry->cr_write, __entry->exceptions,
+               __entry->intercept)
+);
 /*
  * Tracepoint for #VMEXIT while nested
  */
@@ -447,7 +499,7 @@ TRACE_EVENT(kvm_nested_vmexit,
                __entry->exit_int_info_err      = exit_int_info_err;
        ),
        TP_printk("rip: 0x%016llx reason: %s ext_inf1: 0x%016llx "
-                 "ext_inf2: 0x%016llx ext_int: 0x%08x ext_int_err: 0x%08x\n",
+                 "ext_inf2: 0x%016llx ext_int: 0x%08x ext_int_err: 0x%08x",
                  __entry->rip,
                  ftrace_print_symbols_seq(p, __entry->exit_code,
                                           kvm_x86_ops->exit_reasons_str),
@@ -482,7 +534,7 @@ TRACE_EVENT(kvm_nested_vmexit_inject,
        ),
 
        TP_printk("reason: %s ext_inf1: 0x%016llx "
-                 "ext_inf2: 0x%016llx ext_int: 0x%08x ext_int_err: 0x%08x\n",
+                 "ext_inf2: 0x%016llx ext_int: 0x%08x ext_int_err: 0x%08x",
                  ftrace_print_symbols_seq(p, __entry->exit_code,
                                           kvm_x86_ops->exit_reasons_str),
                __entry->exit_info1, __entry->exit_info2,
@@ -504,7 +556,7 @@ TRACE_EVENT(kvm_nested_intr_vmexit,
                __entry->rip    =       rip
        ),
 
-       TP_printk("rip: 0x%016llx\n", __entry->rip)
+       TP_printk("rip: 0x%016llx", __entry->rip)
 );
 
 /*
@@ -526,7 +578,7 @@ TRACE_EVENT(kvm_invlpga,
                __entry->address        =       address;
        ),
 
-       TP_printk("rip: 0x%016llx asid: %d address: 0x%016llx\n",
+       TP_printk("rip: 0x%016llx asid: %d address: 0x%016llx",
                  __entry->rip, __entry->asid, __entry->address)
 );
 
@@ -547,11 +599,102 @@ TRACE_EVENT(kvm_skinit,
                __entry->slb            =       slb;
        ),
 
-       TP_printk("rip: 0x%016llx slb: 0x%08x\n",
+       TP_printk("rip: 0x%016llx slb: 0x%08x",
                  __entry->rip, __entry->slb)
 );
 
+#define __print_insn(insn, ilen) ({                             \
+       int i;                                                   \
+       const char *ret = p->buffer + p->len;                    \
+                                                                \
+       for (i = 0; i < ilen; ++i)                               \
+               trace_seq_printf(p, " %02x", insn[i]);           \
+       trace_seq_printf(p, "%c", 0);                            \
+       ret;                                                     \
+       })
+
+#define KVM_EMUL_INSN_F_CR0_PE (1 << 0)
+#define KVM_EMUL_INSN_F_EFL_VM (1 << 1)
+#define KVM_EMUL_INSN_F_CS_D   (1 << 2)
+#define KVM_EMUL_INSN_F_CS_L   (1 << 3)
+
+#define kvm_trace_symbol_emul_flags                      \
+       { 0,                        "real" },             \
+       { KVM_EMUL_INSN_F_CR0_PE                          \
+         | KVM_EMUL_INSN_F_EFL_VM, "vm16" },             \
+       { KVM_EMUL_INSN_F_CR0_PE,   "prot16" },           \
+       { KVM_EMUL_INSN_F_CR0_PE                          \
+         | KVM_EMUL_INSN_F_CS_D,   "prot32" },           \
+       { KVM_EMUL_INSN_F_CR0_PE                          \
+         | KVM_EMUL_INSN_F_CS_L,   "prot64" }
+
+#define kei_decode_mode(mode) ({                       \
+       u8 flags = 0xff;                                \
+       switch (mode) {                                 \
+       case X86EMUL_MODE_REAL:                         \
+               flags = 0;                              \
+               break;                                  \
+       case X86EMUL_MODE_VM86:                         \
+               flags = KVM_EMUL_INSN_F_EFL_VM;         \
+               break;                                  \
+       case X86EMUL_MODE_PROT16:                       \
+               flags = KVM_EMUL_INSN_F_CR0_PE;         \
+               break;                                  \
+       case X86EMUL_MODE_PROT32:                       \
+               flags = KVM_EMUL_INSN_F_CR0_PE          \
+                       | KVM_EMUL_INSN_F_CS_D;         \
+               break;                                  \
+       case X86EMUL_MODE_PROT64:                       \
+               flags = KVM_EMUL_INSN_F_CR0_PE          \
+                       | KVM_EMUL_INSN_F_CS_L;         \
+               break;                                  \
+       }                                               \
+       flags;                                          \
+       })
+
+TRACE_EVENT(kvm_emulate_insn,
+       TP_PROTO(struct kvm_vcpu *vcpu, __u8 failed),
+       TP_ARGS(vcpu, failed),
+
+       TP_STRUCT__entry(
+               __field(    __u64, rip                       )
+               __field(    __u32, csbase                    )
+               __field(    __u8,  len                       )
+               __array(    __u8,  insn,    15               )
+               __field(    __u8,  flags                     )
+               __field(    __u8,  failed                    )
+               ),
+
+       TP_fast_assign(
+               __entry->rip = vcpu->arch.emulate_ctxt.decode.fetch.start;
+               __entry->csbase = kvm_x86_ops->get_segment_base(vcpu, VCPU_SREG_CS);
+               __entry->len = vcpu->arch.emulate_ctxt.decode.eip
+                              - vcpu->arch.emulate_ctxt.decode.fetch.start;
+               memcpy(__entry->insn,
+                      vcpu->arch.emulate_ctxt.decode.fetch.data,
+                      15);
+               __entry->flags = kei_decode_mode(vcpu->arch.emulate_ctxt.mode);
+               __entry->failed = failed;
+               ),
+
+       TP_printk("%x:%llx:%s (%s)%s",
+                 __entry->csbase, __entry->rip,
+                 __print_insn(__entry->insn, __entry->len),
+                 __print_symbolic(__entry->flags,
+                                  kvm_trace_symbol_emul_flags),
+                 __entry->failed ? " failed" : ""
+               )
+       );
+
+#define trace_kvm_emulate_insn_start(vcpu) trace_kvm_emulate_insn(vcpu, 0)
+#define trace_kvm_emulate_insn_failed(vcpu) trace_kvm_emulate_insn(vcpu, 1)
+
 #endif /* _TRACE_KVM_H */
 
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH arch/x86/kvm
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
 /* This part must be outside protection */
 #include <trace/define_trace.h>
index edca080407a541a4ec331fe3a2516b6b8334eb64..859a01a07dbfb2937b8f0792e4a4aa0bbe50767b 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/moduleparam.h>
 #include <linux/ftrace_event.h>
 #include <linux/slab.h>
+#include <linux/tboot.h>
 #include "kvm_cache_regs.h"
 #include "x86.h"
 
@@ -98,6 +99,8 @@ module_param(ple_gap, int, S_IRUGO);
 static int ple_window = KVM_VMX_DEFAULT_PLE_WINDOW;
 module_param(ple_window, int, S_IRUGO);
 
+#define NR_AUTOLOAD_MSRS 1
+
 struct vmcs {
        u32 revision_id;
        u32 abort;
@@ -125,6 +128,11 @@ struct vcpu_vmx {
        u64                   msr_guest_kernel_gs_base;
 #endif
        struct vmcs          *vmcs;
+       struct msr_autoload {
+               unsigned nr;
+               struct vmx_msr_entry guest[NR_AUTOLOAD_MSRS];
+               struct vmx_msr_entry host[NR_AUTOLOAD_MSRS];
+       } msr_autoload;
        struct {
                int           loaded;
                u16           fs_sel, gs_sel, ldt_sel;
@@ -234,56 +242,56 @@ static const u32 vmx_msr_index[] = {
 };
 #define NR_VMX_MSR ARRAY_SIZE(vmx_msr_index)
 
-static inline int is_page_fault(u32 intr_info)
+static inline bool is_page_fault(u32 intr_info)
 {
        return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK |
                             INTR_INFO_VALID_MASK)) ==
                (INTR_TYPE_HARD_EXCEPTION | PF_VECTOR | INTR_INFO_VALID_MASK);
 }
 
-static inline int is_no_device(u32 intr_info)
+static inline bool is_no_device(u32 intr_info)
 {
        return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK |
                             INTR_INFO_VALID_MASK)) ==
                (INTR_TYPE_HARD_EXCEPTION | NM_VECTOR | INTR_INFO_VALID_MASK);
 }
 
-static inline int is_invalid_opcode(u32 intr_info)
+static inline bool is_invalid_opcode(u32 intr_info)
 {
        return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK |
                             INTR_INFO_VALID_MASK)) ==
                (INTR_TYPE_HARD_EXCEPTION | UD_VECTOR | INTR_INFO_VALID_MASK);
 }
 
-static inline int is_external_interrupt(u32 intr_info)
+static inline bool is_external_interrupt(u32 intr_info)
 {
        return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK))
                == (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
 }
 
-static inline int is_machine_check(u32 intr_info)
+static inline bool is_machine_check(u32 intr_info)
 {
        return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK |
                             INTR_INFO_VALID_MASK)) ==
                (INTR_TYPE_HARD_EXCEPTION | MC_VECTOR | INTR_INFO_VALID_MASK);
 }
 
-static inline int cpu_has_vmx_msr_bitmap(void)
+static inline bool cpu_has_vmx_msr_bitmap(void)
 {
        return vmcs_config.cpu_based_exec_ctrl & CPU_BASED_USE_MSR_BITMAPS;
 }
 
-static inline int cpu_has_vmx_tpr_shadow(void)
+static inline bool cpu_has_vmx_tpr_shadow(void)
 {
        return vmcs_config.cpu_based_exec_ctrl & CPU_BASED_TPR_SHADOW;
 }
 
-static inline int vm_need_tpr_shadow(struct kvm *kvm)
+static inline bool vm_need_tpr_shadow(struct kvm *kvm)
 {
        return (cpu_has_vmx_tpr_shadow()) && (irqchip_in_kernel(kvm));
 }
 
-static inline int cpu_has_secondary_exec_ctrls(void)
+static inline bool cpu_has_secondary_exec_ctrls(void)
 {
        return vmcs_config.cpu_based_exec_ctrl &
                CPU_BASED_ACTIVATE_SECONDARY_CONTROLS;
@@ -303,80 +311,80 @@ static inline bool cpu_has_vmx_flexpriority(void)
 
 static inline bool cpu_has_vmx_ept_execute_only(void)
 {
-       return !!(vmx_capability.ept & VMX_EPT_EXECUTE_ONLY_BIT);
+       return vmx_capability.ept & VMX_EPT_EXECUTE_ONLY_BIT;
 }
 
 static inline bool cpu_has_vmx_eptp_uncacheable(void)
 {
-       return !!(vmx_capability.ept & VMX_EPTP_UC_BIT);
+       return vmx_capability.ept & VMX_EPTP_UC_BIT;
 }
 
 static inline bool cpu_has_vmx_eptp_writeback(void)
 {
-       return !!(vmx_capability.ept & VMX_EPTP_WB_BIT);
+       return vmx_capability.ept & VMX_EPTP_WB_BIT;
 }
 
 static inline bool cpu_has_vmx_ept_2m_page(void)
 {
-       return !!(vmx_capability.ept & VMX_EPT_2MB_PAGE_BIT);
+       return vmx_capability.ept & VMX_EPT_2MB_PAGE_BIT;
 }
 
 static inline bool cpu_has_vmx_ept_1g_page(void)
 {
-       return !!(vmx_capability.ept & VMX_EPT_1GB_PAGE_BIT);
+       return vmx_capability.ept & VMX_EPT_1GB_PAGE_BIT;
 }
 
-static inline int cpu_has_vmx_invept_individual_addr(void)
+static inline bool cpu_has_vmx_invept_individual_addr(void)
 {
-       return !!(vmx_capability.ept & VMX_EPT_EXTENT_INDIVIDUAL_BIT);
+       return vmx_capability.ept & VMX_EPT_EXTENT_INDIVIDUAL_BIT;
 }
 
-static inline int cpu_has_vmx_invept_context(void)
+static inline bool cpu_has_vmx_invept_context(void)
 {
-       return !!(vmx_capability.ept & VMX_EPT_EXTENT_CONTEXT_BIT);
+       return vmx_capability.ept & VMX_EPT_EXTENT_CONTEXT_BIT;
 }
 
-static inline int cpu_has_vmx_invept_global(void)
+static inline bool cpu_has_vmx_invept_global(void)
 {
-       return !!(vmx_capability.ept & VMX_EPT_EXTENT_GLOBAL_BIT);
+       return vmx_capability.ept & VMX_EPT_EXTENT_GLOBAL_BIT;
 }
 
-static inline int cpu_has_vmx_ept(void)
+static inline bool cpu_has_vmx_ept(void)
 {
        return vmcs_config.cpu_based_2nd_exec_ctrl &
                SECONDARY_EXEC_ENABLE_EPT;
 }
 
-static inline int cpu_has_vmx_unrestricted_guest(void)
+static inline bool cpu_has_vmx_unrestricted_guest(void)
 {
        return vmcs_config.cpu_based_2nd_exec_ctrl &
                SECONDARY_EXEC_UNRESTRICTED_GUEST;
 }
 
-static inline int cpu_has_vmx_ple(void)
+static inline bool cpu_has_vmx_ple(void)
 {
        return vmcs_config.cpu_based_2nd_exec_ctrl &
                SECONDARY_EXEC_PAUSE_LOOP_EXITING;
 }
 
-static inline int vm_need_virtualize_apic_accesses(struct kvm *kvm)
+static inline bool vm_need_virtualize_apic_accesses(struct kvm *kvm)
 {
        return flexpriority_enabled && irqchip_in_kernel(kvm);
 }
 
-static inline int cpu_has_vmx_vpid(void)
+static inline bool cpu_has_vmx_vpid(void)
 {
        return vmcs_config.cpu_based_2nd_exec_ctrl &
                SECONDARY_EXEC_ENABLE_VPID;
 }
 
-static inline int cpu_has_vmx_rdtscp(void)
+static inline bool cpu_has_vmx_rdtscp(void)
 {
        return vmcs_config.cpu_based_2nd_exec_ctrl &
                SECONDARY_EXEC_RDTSCP;
 }
 
-static inline int cpu_has_virtual_nmis(void)
+static inline bool cpu_has_virtual_nmis(void)
 {
        return vmcs_config.pin_based_exec_ctrl & PIN_BASED_VIRTUAL_NMIS;
 }
@@ -595,16 +603,56 @@ static void update_exception_bitmap(struct kvm_vcpu *vcpu)
        vmcs_write32(EXCEPTION_BITMAP, eb);
 }
 
+static void clear_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr)
+{
+       unsigned i;
+       struct msr_autoload *m = &vmx->msr_autoload;
+
+       for (i = 0; i < m->nr; ++i)
+               if (m->guest[i].index == msr)
+                       break;
+
+       if (i == m->nr)
+               return;
+       --m->nr;
+       m->guest[i] = m->guest[m->nr];
+       m->host[i] = m->host[m->nr];
+       vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->nr);
+       vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->nr);
+}
+
+static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
+                                 u64 guest_val, u64 host_val)
+{
+       unsigned i;
+       struct msr_autoload *m = &vmx->msr_autoload;
+
+       for (i = 0; i < m->nr; ++i)
+               if (m->guest[i].index == msr)
+                       break;
+
+       if (i == m->nr) {
+               ++m->nr;
+               vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->nr);
+               vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->nr);
+       }
+
+       m->guest[i].index = msr;
+       m->guest[i].value = guest_val;
+       m->host[i].index = msr;
+       m->host[i].value = host_val;
+}
+
 static void reload_tss(void)
 {
        /*
         * VT restores TR but not its size.  Useless.
         */
-       struct descriptor_table gdt;
+       struct desc_ptr gdt;
        struct desc_struct *descs;
 
-       kvm_get_gdt(&gdt);
-       descs = (void *)gdt.base;
+       native_store_gdt(&gdt);
+       descs = (void *)gdt.address;
        descs[GDT_ENTRY_TSS].type = 9; /* available TSS */
        load_TR_desc();
 }
@@ -631,9 +679,57 @@ static bool update_transition_efer(struct vcpu_vmx *vmx, int efer_offset)
        guest_efer |= host_efer & ignore_bits;
        vmx->guest_msrs[efer_offset].data = guest_efer;
        vmx->guest_msrs[efer_offset].mask = ~ignore_bits;
+
+       clear_atomic_switch_msr(vmx, MSR_EFER);
+       /* On ept, can't emulate nx, and must switch nx atomically */
+       if (enable_ept && ((vmx->vcpu.arch.efer ^ host_efer) & EFER_NX)) {
+               guest_efer = vmx->vcpu.arch.efer;
+               if (!(guest_efer & EFER_LMA))
+                       guest_efer &= ~EFER_LME;
+               add_atomic_switch_msr(vmx, MSR_EFER, guest_efer, host_efer);
+               return false;
+       }
+
        return true;
 }
 
+static unsigned long segment_base(u16 selector)
+{
+       struct desc_ptr gdt;
+       struct desc_struct *d;
+       unsigned long table_base;
+       unsigned long v;
+
+       if (!(selector & ~3))
+               return 0;
+
+       native_store_gdt(&gdt);
+       table_base = gdt.address;
+
+       if (selector & 4) {           /* from ldt */
+               u16 ldt_selector = kvm_read_ldt();
+
+               if (!(ldt_selector & ~3))
+                       return 0;
+
+               table_base = segment_base(ldt_selector);
+       }
+       d = (struct desc_struct *)(table_base + (selector & ~7));
+       v = get_desc_base(d);
+#ifdef CONFIG_X86_64
+       if (d->s == 0 && (d->type == 2 || d->type == 9 || d->type == 11))
+               v |= ((unsigned long)((struct ldttss_desc64 *)d)->base3) << 32;
+#endif
+       return v;
+}
+
+static inline unsigned long kvm_read_tr_base(void)
+{
+       u16 tr;
+       asm("str %0" : "=g"(tr));
+       return segment_base(tr);
+}
+
 static void vmx_save_host_state(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -758,7 +854,7 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
        }
 
        if (vcpu->cpu != cpu) {
-               struct descriptor_table dt;
+               struct desc_ptr dt;
                unsigned long sysenter_esp;
 
                vcpu->cpu = cpu;
@@ -767,8 +863,8 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
                 * processors.
                 */
                vmcs_writel(HOST_TR_BASE, kvm_read_tr_base()); /* 22.2.4 */
-               kvm_get_gdt(&dt);
-               vmcs_writel(HOST_GDTR_BASE, dt.base);   /* 22.2.4 */
+               native_store_gdt(&dt);
+               vmcs_writel(HOST_GDTR_BASE, dt.address);   /* 22.2.4 */
 
                rdmsrl(MSR_IA32_SYSENTER_ESP, sysenter_esp);
                vmcs_writel(HOST_IA32_SYSENTER_ESP, sysenter_esp); /* 22.2.3 */
@@ -846,9 +942,9 @@ static u32 vmx_get_interrupt_shadow(struct kvm_vcpu *vcpu, int mask)
        int ret = 0;
 
        if (interruptibility & GUEST_INTR_STATE_STI)
-               ret |= X86_SHADOW_INT_STI;
+               ret |= KVM_X86_SHADOW_INT_STI;
        if (interruptibility & GUEST_INTR_STATE_MOV_SS)
-               ret |= X86_SHADOW_INT_MOV_SS;
+               ret |= KVM_X86_SHADOW_INT_MOV_SS;
 
        return ret & mask;
 }
@@ -860,9 +956,9 @@ static void vmx_set_interrupt_shadow(struct kvm_vcpu *vcpu, int mask)
 
        interruptibility &= ~(GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS);
 
-       if (mask & X86_SHADOW_INT_MOV_SS)
+       if (mask & KVM_X86_SHADOW_INT_MOV_SS)
                interruptibility |= GUEST_INTR_STATE_MOV_SS;
-       if (mask & X86_SHADOW_INT_STI)
+       else if (mask & KVM_X86_SHADOW_INT_STI)
                interruptibility |= GUEST_INTR_STATE_STI;
 
        if ((interruptibility != interruptibility_old))
@@ -882,7 +978,8 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
 }
 
 static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr,
-                               bool has_error_code, u32 error_code)
+                               bool has_error_code, u32 error_code,
+                               bool reinject)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
        u32 intr_info = nr | INTR_INFO_VALID_MASK;
@@ -1176,9 +1273,16 @@ static __init int vmx_disabled_by_bios(void)
        u64 msr;
 
        rdmsrl(MSR_IA32_FEATURE_CONTROL, msr);
-       return (msr & (FEATURE_CONTROL_LOCKED |
-                      FEATURE_CONTROL_VMXON_ENABLED))
-           == FEATURE_CONTROL_LOCKED;
+       if (msr & FEATURE_CONTROL_LOCKED) {
+               if (!(msr & FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX)
+                       && tboot_enabled())
+                       return 1;
+               if (!(msr & FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX)
+                       && !tboot_enabled())
+                       return 1;
+       }
+
+       return 0;
        /* locked but not enabled */
 }
 
@@ -1186,21 +1290,23 @@ static int hardware_enable(void *garbage)
 {
        int cpu = raw_smp_processor_id();
        u64 phys_addr = __pa(per_cpu(vmxarea, cpu));
-       u64 old;
+       u64 old, test_bits;
 
        if (read_cr4() & X86_CR4_VMXE)
                return -EBUSY;
 
        INIT_LIST_HEAD(&per_cpu(vcpus_on_cpu, cpu));
        rdmsrl(MSR_IA32_FEATURE_CONTROL, old);
-       if ((old & (FEATURE_CONTROL_LOCKED |
-                   FEATURE_CONTROL_VMXON_ENABLED))
-           != (FEATURE_CONTROL_LOCKED |
-               FEATURE_CONTROL_VMXON_ENABLED))
+
+       test_bits = FEATURE_CONTROL_LOCKED;
+       test_bits |= FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX;
+       if (tboot_enabled())
+               test_bits |= FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX;
+
+       if ((old & test_bits) != test_bits) {
                /* enable and lock */
-               wrmsrl(MSR_IA32_FEATURE_CONTROL, old |
-                      FEATURE_CONTROL_LOCKED |
-                      FEATURE_CONTROL_VMXON_ENABLED);
+               wrmsrl(MSR_IA32_FEATURE_CONTROL, old | test_bits);
+       }
        write_cr4(read_cr4() | X86_CR4_VMXE); /* FIXME: not cpu hotplug safe */
        asm volatile (ASM_VMX_VMXON_RAX
                      : : "a"(&phys_addr), "m"(phys_addr)
@@ -1521,7 +1627,7 @@ static gva_t rmode_tss_base(struct kvm *kvm)
                struct kvm_memslots *slots;
                gfn_t base_gfn;
 
-               slots = rcu_dereference(kvm->memslots);
+               slots = kvm_memslots(kvm);
                base_gfn = kvm->memslots->memslots[0].base_gfn +
                                 kvm->memslots->memslots[0].npages - 3;
                return base_gfn << PAGE_SHIFT;
@@ -1649,6 +1755,7 @@ static void exit_lmode(struct kvm_vcpu *vcpu)
        vmcs_write32(VM_ENTRY_CONTROLS,
                     vmcs_read32(VM_ENTRY_CONTROLS)
                     & ~VM_ENTRY_IA32E_MODE);
+       vmx_set_efer(vcpu, vcpu->arch.efer);
 }
 
 #endif
@@ -1934,28 +2041,28 @@ static void vmx_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l)
        *l = (ar >> 13) & 1;
 }
 
-static void vmx_get_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
+static void vmx_get_idt(struct kvm_vcpu *vcpu, struct desc_ptr *dt)
 {
-       dt->limit = vmcs_read32(GUEST_IDTR_LIMIT);
-       dt->base = vmcs_readl(GUEST_IDTR_BASE);
+       dt->size = vmcs_read32(GUEST_IDTR_LIMIT);
+       dt->address = vmcs_readl(GUEST_IDTR_BASE);
 }
 
-static void vmx_set_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
+static void vmx_set_idt(struct kvm_vcpu *vcpu, struct desc_ptr *dt)
 {
-       vmcs_write32(GUEST_IDTR_LIMIT, dt->limit);
-       vmcs_writel(GUEST_IDTR_BASE, dt->base);
+       vmcs_write32(GUEST_IDTR_LIMIT, dt->size);
+       vmcs_writel(GUEST_IDTR_BASE, dt->address);
 }
 
-static void vmx_get_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
+static void vmx_get_gdt(struct kvm_vcpu *vcpu, struct desc_ptr *dt)
 {
-       dt->limit = vmcs_read32(GUEST_GDTR_LIMIT);
-       dt->base = vmcs_readl(GUEST_GDTR_BASE);
+       dt->size = vmcs_read32(GUEST_GDTR_LIMIT);
+       dt->address = vmcs_readl(GUEST_GDTR_BASE);
 }
 
-static void vmx_set_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
+static void vmx_set_gdt(struct kvm_vcpu *vcpu, struct desc_ptr *dt)
 {
-       vmcs_write32(GUEST_GDTR_LIMIT, dt->limit);
-       vmcs_writel(GUEST_GDTR_BASE, dt->base);
+       vmcs_write32(GUEST_GDTR_LIMIT, dt->size);
+       vmcs_writel(GUEST_GDTR_BASE, dt->address);
 }
 
 static bool rmode_segment_valid(struct kvm_vcpu *vcpu, int seg)
@@ -2296,6 +2403,16 @@ static void allocate_vpid(struct vcpu_vmx *vmx)
        spin_unlock(&vmx_vpid_lock);
 }
 
+static void free_vpid(struct vcpu_vmx *vmx)
+{
+       if (!enable_vpid)
+               return;
+       spin_lock(&vmx_vpid_lock);
+       if (vmx->vpid != 0)
+               __clear_bit(vmx->vpid, vmx_vpid_bitmap);
+       spin_unlock(&vmx_vpid_lock);
+}
+
 static void __vmx_disable_intercept_for_msr(unsigned long *msr_bitmap, u32 msr)
 {
        int f = sizeof(unsigned long);
@@ -2334,7 +2451,7 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
        u32 junk;
        u64 host_pat, tsc_this, tsc_base;
        unsigned long a;
-       struct descriptor_table dt;
+       struct desc_ptr dt;
        int i;
        unsigned long kvm_vmx_return;
        u32 exec_control;
@@ -2415,14 +2532,16 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
 
        vmcs_write16(HOST_TR_SELECTOR, GDT_ENTRY_TSS*8);  /* 22.2.4 */
 
-       kvm_get_idt(&dt);
-       vmcs_writel(HOST_IDTR_BASE, dt.base);   /* 22.2.4 */
+       native_store_idt(&dt);
+       vmcs_writel(HOST_IDTR_BASE, dt.address);   /* 22.2.4 */
 
        asm("mov $.Lkvm_vmx_return, %0" : "=r"(kvm_vmx_return));
        vmcs_writel(HOST_RIP, kvm_vmx_return); /* 22.2.5 */
        vmcs_write32(VM_EXIT_MSR_STORE_COUNT, 0);
        vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, 0);
+       vmcs_write64(VM_EXIT_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.host));
        vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, 0);
+       vmcs_write64(VM_ENTRY_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.guest));
 
        rdmsr(MSR_IA32_SYSENTER_CS, host_sysenter_cs, junk);
        vmcs_write32(HOST_IA32_SYSENTER_CS, host_sysenter_cs);
@@ -2947,22 +3066,20 @@ static int handle_io(struct kvm_vcpu *vcpu)
        int size, in, string;
        unsigned port;
 
-       ++vcpu->stat.io_exits;
        exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
        string = (exit_qualification & 16) != 0;
+       in = (exit_qualification & 8) != 0;
 
-       if (string) {
-               if (emulate_instruction(vcpu, 0, 0, 0) == EMULATE_DO_MMIO)
-                       return 0;
-               return 1;
-       }
+       ++vcpu->stat.io_exits;
 
-       size = (exit_qualification & 7) + 1;
-       in = (exit_qualification & 8) != 0;
-       port = exit_qualification >> 16;
+       if (string || in)
+               return !(emulate_instruction(vcpu, 0, 0, 0) == EMULATE_DO_MMIO);
 
+       port = exit_qualification >> 16;
+       size = (exit_qualification & 7) + 1;
        skip_emulated_instruction(vcpu);
-       return kvm_emulate_pio(vcpu, in, size, port);
+
+       return kvm_fast_pio_out(vcpu, size, port);
 }
 
 static void
@@ -3053,19 +3170,9 @@ static int handle_cr(struct kvm_vcpu *vcpu)
        return 0;
 }
 
-static int check_dr_alias(struct kvm_vcpu *vcpu)
-{
-       if (kvm_read_cr4_bits(vcpu, X86_CR4_DE)) {
-               kvm_queue_exception(vcpu, UD_VECTOR);
-               return -1;
-       }
-       return 0;
-}
-
 static int handle_dr(struct kvm_vcpu *vcpu)
 {
        unsigned long exit_qualification;
-       unsigned long val;
        int dr, reg;
 
        /* Do not handle if the CPL > 0, will trigger GP on re-entry */
@@ -3100,67 +3207,20 @@ static int handle_dr(struct kvm_vcpu *vcpu)
        dr = exit_qualification & DEBUG_REG_ACCESS_NUM;
        reg = DEBUG_REG_ACCESS_REG(exit_qualification);
        if (exit_qualification & TYPE_MOV_FROM_DR) {
-               switch (dr) {
-               case 0 ... 3:
-                       val = vcpu->arch.db[dr];
-                       break;
-               case 4:
-                       if (check_dr_alias(vcpu) < 0)
-                               return 1;
-                       /* fall through */
-               case 6:
-                       val = vcpu->arch.dr6;
-                       break;
-               case 5:
-                       if (check_dr_alias(vcpu) < 0)
-                               return 1;
-                       /* fall through */
-               default: /* 7 */
-                       val = vcpu->arch.dr7;
-                       break;
-               }
-               kvm_register_write(vcpu, reg, val);
-       } else {
-               val = vcpu->arch.regs[reg];
-               switch (dr) {
-               case 0 ... 3:
-                       vcpu->arch.db[dr] = val;
-                       if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP))
-                               vcpu->arch.eff_db[dr] = val;
-                       break;
-               case 4:
-                       if (check_dr_alias(vcpu) < 0)
-                               return 1;
-                       /* fall through */
-               case 6:
-                       if (val & 0xffffffff00000000ULL) {
-                               kvm_inject_gp(vcpu, 0);
-                               return 1;
-                       }
-                       vcpu->arch.dr6 = (val & DR6_VOLATILE) | DR6_FIXED_1;
-                       break;
-               case 5:
-                       if (check_dr_alias(vcpu) < 0)
-                               return 1;
-                       /* fall through */
-               default: /* 7 */
-                       if (val & 0xffffffff00000000ULL) {
-                               kvm_inject_gp(vcpu, 0);
-                               return 1;
-                       }
-                       vcpu->arch.dr7 = (val & DR7_VOLATILE) | DR7_FIXED_1;
-                       if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)) {
-                               vmcs_writel(GUEST_DR7, vcpu->arch.dr7);
-                               vcpu->arch.switch_db_regs =
-                                       (val & DR7_BP_EN_MASK);
-                       }
-                       break;
-               }
-       }
+               unsigned long val;
+               if (!kvm_get_dr(vcpu, dr, &val))
+                       kvm_register_write(vcpu, reg, val);
+       } else
+               kvm_set_dr(vcpu, dr, vcpu->arch.regs[reg]);
        skip_emulated_instruction(vcpu);
        return 1;
 }
 
+static void vmx_set_dr7(struct kvm_vcpu *vcpu, unsigned long val)
+{
+       vmcs_writel(GUEST_DR7, val);
+}
+
 static int handle_cpuid(struct kvm_vcpu *vcpu)
 {
        kvm_emulate_cpuid(vcpu);
@@ -3292,6 +3352,8 @@ static int handle_task_switch(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
        unsigned long exit_qualification;
+       bool has_error_code = false;
+       u32 error_code = 0;
        u16 tss_selector;
        int reason, type, idt_v;
 
@@ -3314,6 +3376,13 @@ static int handle_task_switch(struct kvm_vcpu *vcpu)
                        kvm_clear_interrupt_queue(vcpu);
                        break;
                case INTR_TYPE_HARD_EXCEPTION:
+                       if (vmx->idt_vectoring_info &
+                           VECTORING_INFO_DELIVER_CODE_MASK) {
+                               has_error_code = true;
+                               error_code =
+                                       vmcs_read32(IDT_VECTORING_ERROR_CODE);
+                       }
+                       /* fall through */
                case INTR_TYPE_SOFT_EXCEPTION:
                        kvm_clear_exception_queue(vcpu);
                        break;
@@ -3328,8 +3397,13 @@ static int handle_task_switch(struct kvm_vcpu *vcpu)
                       type != INTR_TYPE_NMI_INTR))
                skip_emulated_instruction(vcpu);
 
-       if (!kvm_task_switch(vcpu, tss_selector, reason))
+       if (kvm_task_switch(vcpu, tss_selector, reason,
+                               has_error_code, error_code) == EMULATE_FAIL) {
+               vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
+               vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
+               vcpu->run->internal.ndata = 0;
                return 0;
+       }
 
        /* clear all local breakpoint enable flags */
        vmcs_writel(GUEST_DR7, vmcs_readl(GUEST_DR7) & ~55);
@@ -3574,7 +3648,7 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu)
        u32 exit_reason = vmx->exit_reason;
        u32 vectoring_info = vmx->idt_vectoring_info;
 
-       trace_kvm_exit(exit_reason, kvm_rip_read(vcpu));
+       trace_kvm_exit(exit_reason, vcpu);
 
        /* If guest state is invalid, start emulating */
        if (vmx->emulation_required && emulate_invalid_guest_state)
@@ -3923,10 +3997,7 @@ static void vmx_free_vcpu(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
 
-       spin_lock(&vmx_vpid_lock);
-       if (vmx->vpid != 0)
-               __clear_bit(vmx->vpid, vmx_vpid_bitmap);
-       spin_unlock(&vmx_vpid_lock);
+       free_vpid(vmx);
        vmx_free_vmcs(vcpu);
        kfree(vmx->guest_msrs);
        kvm_vcpu_uninit(vcpu);
@@ -3988,6 +4059,7 @@ free_msrs:
 uninit_vcpu:
        kvm_vcpu_uninit(&vmx->vcpu);
 free_vcpu:
+       free_vpid(vmx);
        kmem_cache_free(kvm_vcpu_cache, vmx);
        return ERR_PTR(err);
 }
@@ -4118,6 +4190,10 @@ static void vmx_cpuid_update(struct kvm_vcpu *vcpu)
        }
 }
 
+static void vmx_set_supported_cpuid(u32 func, struct kvm_cpuid_entry2 *entry)
+{
+}
+
 static struct kvm_x86_ops vmx_x86_ops = {
        .cpu_has_kvm_support = cpu_has_kvm_support,
        .disabled_by_bios = vmx_disabled_by_bios,
@@ -4154,6 +4230,7 @@ static struct kvm_x86_ops vmx_x86_ops = {
        .set_idt = vmx_set_idt,
        .get_gdt = vmx_get_gdt,
        .set_gdt = vmx_set_gdt,
+       .set_dr7 = vmx_set_dr7,
        .cache_reg = vmx_cache_reg,
        .get_rflags = vmx_get_rflags,
        .set_rflags = vmx_set_rflags,
@@ -4189,6 +4266,8 @@ static struct kvm_x86_ops vmx_x86_ops = {
        .cpuid_update = vmx_cpuid_update,
 
        .rdtscp_supported = vmx_rdtscp_supported,
+
+       .set_supported_cpuid = vmx_set_supported_cpuid,
 };
 
 static int __init vmx_init(void)
@@ -4236,7 +4315,8 @@ static int __init vmx_init(void)
 
        set_bit(0, vmx_vpid_bitmap); /* 0 is reserved for host */
 
-       r = kvm_init(&vmx_x86_ops, sizeof(struct vcpu_vmx), THIS_MODULE);
+       r = kvm_init(&vmx_x86_ops, sizeof(struct vcpu_vmx),
+                    __alignof__(struct vcpu_vmx), THIS_MODULE);
        if (r)
                goto out3;
 
index dd9bc8fb81abddc4dc633dbc20392d1b5fcf14eb..05d571f6f19615cab8a90dec413e0a39537e914a 100644 (file)
@@ -42,7 +42,7 @@
 #include <linux/slab.h>
 #include <linux/perf_event.h>
 #include <trace/events/kvm.h>
-#undef TRACE_INCLUDE_FILE
+
 #define CREATE_TRACE_POINTS
 #include "trace.h"
 
@@ -224,34 +224,6 @@ static void drop_user_return_notifiers(void *ignore)
                kvm_on_user_return(&smsr->urn);
 }
 
-unsigned long segment_base(u16 selector)
-{
-       struct descriptor_table gdt;
-       struct desc_struct *d;
-       unsigned long table_base;
-       unsigned long v;
-
-       if (selector == 0)
-               return 0;
-
-       kvm_get_gdt(&gdt);
-       table_base = gdt.base;
-
-       if (selector & 4) {           /* from ldt */
-               u16 ldt_selector = kvm_read_ldt();
-
-               table_base = segment_base(ldt_selector);
-       }
-       d = (struct desc_struct *)(table_base + (selector & ~7));
-       v = get_desc_base(d);
-#ifdef CONFIG_X86_64
-       if (d->s == 0 && (d->type == 2 || d->type == 9 || d->type == 11))
-               v |= ((unsigned long)((struct ldttss_desc64 *)d)->base3) << 32;
-#endif
-       return v;
-}
-EXPORT_SYMBOL_GPL(segment_base);
-
 u64 kvm_get_apic_base(struct kvm_vcpu *vcpu)
 {
        if (irqchip_in_kernel(vcpu->kvm))
@@ -293,7 +265,8 @@ static int exception_class(int vector)
 }
 
 static void kvm_multiple_exception(struct kvm_vcpu *vcpu,
-               unsigned nr, bool has_error, u32 error_code)
+               unsigned nr, bool has_error, u32 error_code,
+               bool reinject)
 {
        u32 prev_nr;
        int class1, class2;
@@ -304,6 +277,7 @@ static void kvm_multiple_exception(struct kvm_vcpu *vcpu,
                vcpu->arch.exception.has_error_code = has_error;
                vcpu->arch.exception.nr = nr;
                vcpu->arch.exception.error_code = error_code;
+               vcpu->arch.exception.reinject = reinject;
                return;
        }
 
@@ -332,10 +306,16 @@ static void kvm_multiple_exception(struct kvm_vcpu *vcpu,
 
 void kvm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr)
 {
-       kvm_multiple_exception(vcpu, nr, false, 0);
+       kvm_multiple_exception(vcpu, nr, false, 0, false);
 }
 EXPORT_SYMBOL_GPL(kvm_queue_exception);
 
+void kvm_requeue_exception(struct kvm_vcpu *vcpu, unsigned nr)
+{
+       kvm_multiple_exception(vcpu, nr, false, 0, true);
+}
+EXPORT_SYMBOL_GPL(kvm_requeue_exception);
+
 void kvm_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long addr,
                           u32 error_code)
 {
@@ -352,10 +332,16 @@ EXPORT_SYMBOL_GPL(kvm_inject_nmi);
 
 void kvm_queue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code)
 {
-       kvm_multiple_exception(vcpu, nr, true, error_code);
+       kvm_multiple_exception(vcpu, nr, true, error_code, false);
 }
 EXPORT_SYMBOL_GPL(kvm_queue_exception_e);
 
+void kvm_requeue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code)
+{
+       kvm_multiple_exception(vcpu, nr, true, error_code, true);
+}
+EXPORT_SYMBOL_GPL(kvm_requeue_exception_e);
+
 /*
  * Checks if cpl <= required_cpl; if true, return true.  Otherwise queue
  * a #GP and return false.
@@ -476,7 +462,6 @@ void kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
        }
 
        kvm_x86_ops->set_cr0(vcpu, cr0);
-       vcpu->arch.cr0 = cr0;
 
        kvm_mmu_reset_context(vcpu);
        return;
@@ -485,7 +470,7 @@ EXPORT_SYMBOL_GPL(kvm_set_cr0);
 
 void kvm_lmsw(struct kvm_vcpu *vcpu, unsigned long msw)
 {
-       kvm_set_cr0(vcpu, kvm_read_cr0_bits(vcpu, ~0x0ful) | (msw & 0x0f));
+       kvm_set_cr0(vcpu, kvm_read_cr0_bits(vcpu, ~0x0eul) | (msw & 0x0f));
 }
 EXPORT_SYMBOL_GPL(kvm_lmsw);
 
@@ -517,7 +502,6 @@ void kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
        }
        kvm_x86_ops->set_cr4(vcpu, cr4);
        vcpu->arch.cr4 = cr4;
-       vcpu->arch.mmu.base_role.cr4_pge = (cr4 & X86_CR4_PGE) && !tdp_enabled;
        kvm_mmu_reset_context(vcpu);
 }
 EXPORT_SYMBOL_GPL(kvm_set_cr4);
@@ -592,6 +576,80 @@ unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu)
 }
 EXPORT_SYMBOL_GPL(kvm_get_cr8);
 
+int kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val)
+{
+       switch (dr) {
+       case 0 ... 3:
+               vcpu->arch.db[dr] = val;
+               if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP))
+                       vcpu->arch.eff_db[dr] = val;
+               break;
+       case 4:
+               if (kvm_read_cr4_bits(vcpu, X86_CR4_DE)) {
+                       kvm_queue_exception(vcpu, UD_VECTOR);
+                       return 1;
+               }
+               /* fall through */
+       case 6:
+               if (val & 0xffffffff00000000ULL) {
+                       kvm_inject_gp(vcpu, 0);
+                       return 1;
+               }
+               vcpu->arch.dr6 = (val & DR6_VOLATILE) | DR6_FIXED_1;
+               break;
+       case 5:
+               if (kvm_read_cr4_bits(vcpu, X86_CR4_DE)) {
+                       kvm_queue_exception(vcpu, UD_VECTOR);
+                       return 1;
+               }
+               /* fall through */
+       default: /* 7 */
+               if (val & 0xffffffff00000000ULL) {
+                       kvm_inject_gp(vcpu, 0);
+                       return 1;
+               }
+               vcpu->arch.dr7 = (val & DR7_VOLATILE) | DR7_FIXED_1;
+               if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)) {
+                       kvm_x86_ops->set_dr7(vcpu, vcpu->arch.dr7);
+                       vcpu->arch.switch_db_regs = (val & DR7_BP_EN_MASK);
+               }
+               break;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(kvm_set_dr);
+
+int kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val)
+{
+       switch (dr) {
+       case 0 ... 3:
+               *val = vcpu->arch.db[dr];
+               break;
+       case 4:
+               if (kvm_read_cr4_bits(vcpu, X86_CR4_DE)) {
+                       kvm_queue_exception(vcpu, UD_VECTOR);
+                       return 1;
+               }
+               /* fall through */
+       case 6:
+               *val = vcpu->arch.dr6;
+               break;
+       case 5:
+               if (kvm_read_cr4_bits(vcpu, X86_CR4_DE)) {
+                       kvm_queue_exception(vcpu, UD_VECTOR);
+                       return 1;
+               }
+               /* fall through */
+       default: /* 7 */
+               *val = vcpu->arch.dr7;
+               break;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(kvm_get_dr);
+
 static inline u32 bit(int bitno)
 {
        return 1 << (bitno & 31);
@@ -606,9 +664,10 @@ static inline u32 bit(int bitno)
  * kvm-specific. Those are put in the beginning of the list.
  */
 
-#define KVM_SAVE_MSRS_BEGIN    5
+#define KVM_SAVE_MSRS_BEGIN    7
 static u32 msrs_to_save[] = {
        MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK,
+       MSR_KVM_SYSTEM_TIME_NEW, MSR_KVM_WALL_CLOCK_NEW,
        HV_X64_MSR_GUEST_OS_ID, HV_X64_MSR_HYPERCALL,
        HV_X64_MSR_APIC_ASSIST_PAGE,
        MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP,
@@ -625,48 +684,42 @@ static u32 emulated_msrs[] = {
        MSR_IA32_MISC_ENABLE,
 };
 
-static void set_efer(struct kvm_vcpu *vcpu, u64 efer)
+static int set_efer(struct kvm_vcpu *vcpu, u64 efer)
 {
-       if (efer & efer_reserved_bits) {
-               kvm_inject_gp(vcpu, 0);
-               return;
-       }
+       if (efer & efer_reserved_bits)
+               return 1;
 
        if (is_paging(vcpu)
-           && (vcpu->arch.efer & EFER_LME) != (efer & EFER_LME)) {
-               kvm_inject_gp(vcpu, 0);
-               return;
-       }
+           && (vcpu->arch.efer & EFER_LME) != (efer & EFER_LME))
+               return 1;
 
        if (efer & EFER_FFXSR) {
                struct kvm_cpuid_entry2 *feat;
 
                feat = kvm_find_cpuid_entry(vcpu, 0x80000001, 0);
-               if (!feat || !(feat->edx & bit(X86_FEATURE_FXSR_OPT))) {
-                       kvm_inject_gp(vcpu, 0);
-                       return;
-               }
+               if (!feat || !(feat->edx & bit(X86_FEATURE_FXSR_OPT)))
+                       return 1;
        }
 
        if (efer & EFER_SVME) {
                struct kvm_cpuid_entry2 *feat;
 
                feat = kvm_find_cpuid_entry(vcpu, 0x80000001, 0);
-               if (!feat || !(feat->ecx & bit(X86_FEATURE_SVM))) {
-                       kvm_inject_gp(vcpu, 0);
-                       return;
-               }
+               if (!feat || !(feat->ecx & bit(X86_FEATURE_SVM)))
+                       return 1;
        }
 
-       kvm_x86_ops->set_efer(vcpu, efer);
-
        efer &= ~EFER_LMA;
        efer |= vcpu->arch.efer & EFER_LMA;
 
+       kvm_x86_ops->set_efer(vcpu, efer);
+
        vcpu->arch.efer = efer;
 
        vcpu->arch.mmu.base_role.nxe = (efer & EFER_NX) && !tdp_enabled;
        kvm_mmu_reset_context(vcpu);
+
+       return 0;
 }
 
 void kvm_enable_efer_bits(u64 mask)
@@ -696,14 +749,22 @@ static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data)
 
 static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock)
 {
-       static int version;
+       int version;
+       int r;
        struct pvclock_wall_clock wc;
        struct timespec boot;
 
        if (!wall_clock)
                return;
 
-       version++;
+       r = kvm_read_guest(kvm, wall_clock, &version, sizeof(version));
+       if (r)
+               return;
+
+       if (version & 1)
+               ++version;  /* first time write, random junk */
+
+       ++version;
 
        kvm_write_guest(kvm, wall_clock, &version, sizeof(version));
 
@@ -796,6 +857,8 @@ static void kvm_write_guest_time(struct kvm_vcpu *v)
        vcpu->hv_clock.system_time = ts.tv_nsec +
                                     (NSEC_PER_SEC * (u64)ts.tv_sec) + v->kvm->arch.kvmclock_offset;
 
+       vcpu->hv_clock.flags = 0;
+
        /*
         * The interface expects us to write an even number signaling that the
         * update is finished. Since the guest won't see the intermediate
@@ -1087,10 +1150,10 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
 {
        switch (msr) {
        case MSR_EFER:
-               set_efer(vcpu, data);
-               break;
+               return set_efer(vcpu, data);
        case MSR_K7_HWCR:
                data &= ~(u64)0x40;     /* ignore flush filter disable */
+               data &= ~(u64)0x100;    /* ignore ignne emulation enable */
                if (data != 0) {
                        pr_unimpl(vcpu, "unimplemented HWCR wrmsr: 0x%llx\n",
                                data);
@@ -1133,10 +1196,12 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
        case MSR_IA32_MISC_ENABLE:
                vcpu->arch.ia32_misc_enable_msr = data;
                break;
+       case MSR_KVM_WALL_CLOCK_NEW:
        case MSR_KVM_WALL_CLOCK:
                vcpu->kvm->arch.wall_clock = data;
                kvm_write_wall_clock(vcpu->kvm, data);
                break;
+       case MSR_KVM_SYSTEM_TIME_NEW:
        case MSR_KVM_SYSTEM_TIME: {
                if (vcpu->arch.time_page) {
                        kvm_release_page_dirty(vcpu->arch.time_page);
@@ -1408,9 +1473,11 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
                data = vcpu->arch.efer;
                break;
        case MSR_KVM_WALL_CLOCK:
+       case MSR_KVM_WALL_CLOCK_NEW:
                data = vcpu->kvm->arch.wall_clock;
                break;
        case MSR_KVM_SYSTEM_TIME:
+       case MSR_KVM_SYSTEM_TIME_NEW:
                data = vcpu->arch.time;
                break;
        case MSR_IA32_P5_MC_ADDR:
@@ -1549,6 +1616,7 @@ int kvm_dev_ioctl_check_extension(long ext)
        case KVM_CAP_HYPERV_VAPIC:
        case KVM_CAP_HYPERV_SPIN:
        case KVM_CAP_PCI_SEGMENT:
+       case KVM_CAP_DEBUGREGS:
        case KVM_CAP_X86_ROBUST_SINGLESTEP:
                r = 1;
                break;
@@ -1769,6 +1837,7 @@ static int kvm_vcpu_ioctl_get_cpuid2(struct kvm_vcpu *vcpu,
 {
        int r;
 
+       vcpu_load(vcpu);
        r = -E2BIG;
        if (cpuid->nent < vcpu->arch.cpuid_nent)
                goto out;
@@ -1780,6 +1849,7 @@ static int kvm_vcpu_ioctl_get_cpuid2(struct kvm_vcpu *vcpu,
 
 out:
        cpuid->nent = vcpu->arch.cpuid_nent;
+       vcpu_put(vcpu);
        return r;
 }
 
@@ -1910,6 +1980,24 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
                }
                break;
        }
+       case KVM_CPUID_SIGNATURE: {
+               char signature[12] = "KVMKVMKVM\0\0";
+               u32 *sigptr = (u32 *)signature;
+               entry->eax = 0;
+               entry->ebx = sigptr[0];
+               entry->ecx = sigptr[1];
+               entry->edx = sigptr[2];
+               break;
+       }
+       case KVM_CPUID_FEATURES:
+               entry->eax = (1 << KVM_FEATURE_CLOCKSOURCE) |
+                            (1 << KVM_FEATURE_NOP_IO_DELAY) |
+                            (1 << KVM_FEATURE_CLOCKSOURCE2) |
+                            (1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT);
+               entry->ebx = 0;
+               entry->ecx = 0;
+               entry->edx = 0;
+               break;
        case 0x80000000:
                entry->eax = min(entry->eax, 0x8000001a);
                break;
@@ -1918,6 +2006,9 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
                entry->ecx &= kvm_supported_word6_x86_features;
                break;
        }
+
+       kvm_x86_ops->set_supported_cpuid(function, entry);
+
        put_cpu();
 }
 
@@ -1953,6 +2044,23 @@ static int kvm_dev_ioctl_get_supported_cpuid(struct kvm_cpuid2 *cpuid,
        for (func = 0x80000001; func <= limit && nent < cpuid->nent; ++func)
                do_cpuid_ent(&cpuid_entries[nent], func, 0,
                             &nent, cpuid->nent);
+
+
+
+       r = -E2BIG;
+       if (nent >= cpuid->nent)
+               goto out_free;
+
+       do_cpuid_ent(&cpuid_entries[nent], KVM_CPUID_SIGNATURE, 0, &nent,
+                    cpuid->nent);
+
+       r = -E2BIG;
+       if (nent >= cpuid->nent)
+               goto out_free;
+
+       do_cpuid_ent(&cpuid_entries[nent], KVM_CPUID_FEATURES, 0, &nent,
+                    cpuid->nent);
+
        r = -E2BIG;
        if (nent >= cpuid->nent)
                goto out_free;
@@ -2032,6 +2140,7 @@ static int kvm_vcpu_ioctl_x86_setup_mce(struct kvm_vcpu *vcpu,
        int r;
        unsigned bank_num = mcg_cap & 0xff, bank;
 
+       vcpu_load(vcpu);
        r = -EINVAL;
        if (!bank_num || bank_num >= KVM_MAX_MCE_BANKS)
                goto out;
@@ -2046,6 +2155,7 @@ static int kvm_vcpu_ioctl_x86_setup_mce(struct kvm_vcpu *vcpu,
        for (bank = 0; bank < bank_num; bank++)
                vcpu->arch.mce_banks[bank*4] = ~(u64)0;
 out:
+       vcpu_put(vcpu);
        return r;
 }
 
@@ -2105,14 +2215,20 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
 {
        vcpu_load(vcpu);
 
-       events->exception.injected = vcpu->arch.exception.pending;
+       events->exception.injected =
+               vcpu->arch.exception.pending &&
+               !kvm_exception_is_soft(vcpu->arch.exception.nr);
        events->exception.nr = vcpu->arch.exception.nr;
        events->exception.has_error_code = vcpu->arch.exception.has_error_code;
        events->exception.error_code = vcpu->arch.exception.error_code;
 
-       events->interrupt.injected = vcpu->arch.interrupt.pending;
+       events->interrupt.injected =
+               vcpu->arch.interrupt.pending && !vcpu->arch.interrupt.soft;
        events->interrupt.nr = vcpu->arch.interrupt.nr;
-       events->interrupt.soft = vcpu->arch.interrupt.soft;
+       events->interrupt.soft = 0;
+       events->interrupt.shadow =
+               kvm_x86_ops->get_interrupt_shadow(vcpu,
+                       KVM_X86_SHADOW_INT_MOV_SS | KVM_X86_SHADOW_INT_STI);
 
        events->nmi.injected = vcpu->arch.nmi_injected;
        events->nmi.pending = vcpu->arch.nmi_pending;
@@ -2121,7 +2237,8 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
        events->sipi_vector = vcpu->arch.sipi_vector;
 
        events->flags = (KVM_VCPUEVENT_VALID_NMI_PENDING
-                        | KVM_VCPUEVENT_VALID_SIPI_VECTOR);
+                        | KVM_VCPUEVENT_VALID_SIPI_VECTOR
+                        | KVM_VCPUEVENT_VALID_SHADOW);
 
        vcpu_put(vcpu);
 }
@@ -2130,7 +2247,8 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
                                              struct kvm_vcpu_events *events)
 {
        if (events->flags & ~(KVM_VCPUEVENT_VALID_NMI_PENDING
-                             | KVM_VCPUEVENT_VALID_SIPI_VECTOR))
+                             | KVM_VCPUEVENT_VALID_SIPI_VECTOR
+                             | KVM_VCPUEVENT_VALID_SHADOW))
                return -EINVAL;
 
        vcpu_load(vcpu);
@@ -2145,6 +2263,9 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
        vcpu->arch.interrupt.soft = events->interrupt.soft;
        if (vcpu->arch.interrupt.pending && irqchip_in_kernel(vcpu->kvm))
                kvm_pic_clear_isr_ack(vcpu->kvm);
+       if (events->flags & KVM_VCPUEVENT_VALID_SHADOW)
+               kvm_x86_ops->set_interrupt_shadow(vcpu,
+                                                 events->interrupt.shadow);
 
        vcpu->arch.nmi_injected = events->nmi.injected;
        if (events->flags & KVM_VCPUEVENT_VALID_NMI_PENDING)
@@ -2159,6 +2280,36 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
        return 0;
 }
 
+static void kvm_vcpu_ioctl_x86_get_debugregs(struct kvm_vcpu *vcpu,
+                                            struct kvm_debugregs *dbgregs)
+{
+       vcpu_load(vcpu);
+
+       memcpy(dbgregs->db, vcpu->arch.db, sizeof(vcpu->arch.db));
+       dbgregs->dr6 = vcpu->arch.dr6;
+       dbgregs->dr7 = vcpu->arch.dr7;
+       dbgregs->flags = 0;
+
+       vcpu_put(vcpu);
+}
+
+static int kvm_vcpu_ioctl_x86_set_debugregs(struct kvm_vcpu *vcpu,
+                                           struct kvm_debugregs *dbgregs)
+{
+       if (dbgregs->flags)
+               return -EINVAL;
+
+       vcpu_load(vcpu);
+
+       memcpy(vcpu->arch.db, dbgregs->db, sizeof(vcpu->arch.db));
+       vcpu->arch.dr6 = dbgregs->dr6;
+       vcpu->arch.dr7 = dbgregs->dr7;
+
+       vcpu_put(vcpu);
+
+       return 0;
+}
+
 long kvm_arch_vcpu_ioctl(struct file *filp,
                         unsigned int ioctl, unsigned long arg)
 {
@@ -2313,7 +2464,9 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
                r = -EFAULT;
                if (copy_from_user(&mce, argp, sizeof mce))
                        goto out;
+               vcpu_load(vcpu);
                r = kvm_vcpu_ioctl_x86_set_mce(vcpu, &mce);
+               vcpu_put(vcpu);
                break;
        }
        case KVM_GET_VCPU_EVENTS: {
@@ -2337,6 +2490,29 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
                r = kvm_vcpu_ioctl_x86_set_vcpu_events(vcpu, &events);
                break;
        }
+       case KVM_GET_DEBUGREGS: {
+               struct kvm_debugregs dbgregs;
+
+               kvm_vcpu_ioctl_x86_get_debugregs(vcpu, &dbgregs);
+
+               r = -EFAULT;
+               if (copy_to_user(argp, &dbgregs,
+                                sizeof(struct kvm_debugregs)))
+                       break;
+               r = 0;
+               break;
+       }
+       case KVM_SET_DEBUGREGS: {
+               struct kvm_debugregs dbgregs;
+
+               r = -EFAULT;
+               if (copy_from_user(&dbgregs, argp,
+                                  sizeof(struct kvm_debugregs)))
+                       break;
+
+               r = kvm_vcpu_ioctl_x86_set_debugregs(vcpu, &dbgregs);
+               break;
+       }
        default:
                r = -EINVAL;
        }
@@ -2390,7 +2566,7 @@ gfn_t unalias_gfn_instantiation(struct kvm *kvm, gfn_t gfn)
        struct kvm_mem_alias *alias;
        struct kvm_mem_aliases *aliases;
 
-       aliases = rcu_dereference(kvm->arch.aliases);
+       aliases = kvm_aliases(kvm);
 
        for (i = 0; i < aliases->naliases; ++i) {
                alias = &aliases->aliases[i];
@@ -2409,7 +2585,7 @@ gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
        struct kvm_mem_alias *alias;
        struct kvm_mem_aliases *aliases;
 
-       aliases = rcu_dereference(kvm->arch.aliases);
+       aliases = kvm_aliases(kvm);
 
        for (i = 0; i < aliases->naliases; ++i) {
                alias = &aliases->aliases[i];
@@ -2804,11 +2980,13 @@ long kvm_arch_vm_ioctl(struct file *filp,
                r = -EFAULT;
                if (copy_from_user(&irq_event, argp, sizeof irq_event))
                        goto out;
+               r = -ENXIO;
                if (irqchip_in_kernel(kvm)) {
                        __s32 status;
                        status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
                                        irq_event.irq, irq_event.level);
                        if (ioctl == KVM_IRQ_LINE_STATUS) {
+                               r = -EFAULT;
                                irq_event.status = status;
                                if (copy_to_user(argp, &irq_event,
                                                        sizeof irq_event))
@@ -3024,6 +3202,18 @@ static int vcpu_mmio_read(struct kvm_vcpu *vcpu, gpa_t addr, int len, void *v)
        return kvm_io_bus_read(vcpu->kvm, KVM_MMIO_BUS, addr, len, v);
 }
 
+static void kvm_set_segment(struct kvm_vcpu *vcpu,
+                       struct kvm_segment *var, int seg)
+{
+       kvm_x86_ops->set_segment(vcpu, var, seg);
+}
+
+void kvm_get_segment(struct kvm_vcpu *vcpu,
+                    struct kvm_segment *var, int seg)
+{
+       kvm_x86_ops->get_segment(vcpu, var, seg);
+}
+
 gpa_t kvm_mmu_gva_to_gpa_read(struct kvm_vcpu *vcpu, gva_t gva, u32 *error)
 {
        u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
@@ -3104,14 +3294,17 @@ static int kvm_read_guest_virt_system(gva_t addr, void *val, unsigned int bytes,
        return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, 0, error);
 }
 
-static int kvm_write_guest_virt(gva_t addr, void *val, unsigned int bytes,
-                               struct kvm_vcpu *vcpu, u32 *error)
+static int kvm_write_guest_virt_system(gva_t addr, void *val,
+                                      unsigned int bytes,
+                                      struct kvm_vcpu *vcpu,
+                                      u32 *error)
 {
        void *data = val;
        int r = X86EMUL_CONTINUE;
 
        while (bytes) {
-               gpa_t gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, error);
+               gpa_t gpa =  vcpu->arch.mmu.gva_to_gpa(vcpu, addr,
+                                                      PFERR_WRITE_MASK, error);
                unsigned offset = addr & (PAGE_SIZE-1);
                unsigned towrite = min(bytes, (unsigned)PAGE_SIZE - offset);
                int ret;
@@ -3134,7 +3327,6 @@ out:
        return r;
 }
 
-
 static int emulator_read_emulated(unsigned long addr,
                                  void *val,
                                  unsigned int bytes,
@@ -3237,9 +3429,9 @@ mmio:
 }
 
 int emulator_write_emulated(unsigned long addr,
-                                  const void *val,
-                                  unsigned int bytes,
-                                  struct kvm_vcpu *vcpu)
+                           const void *val,
+                           unsigned int bytes,
+                           struct kvm_vcpu *vcpu)
 {
        /* Crossing a page boundary? */
        if (((addr + bytes - 1) ^ addr) & PAGE_MASK) {
@@ -3257,45 +3449,150 @@ int emulator_write_emulated(unsigned long addr,
 }
 EXPORT_SYMBOL_GPL(emulator_write_emulated);
 
+#define CMPXCHG_TYPE(t, ptr, old, new) \
+       (cmpxchg((t *)(ptr), *(t *)(old), *(t *)(new)) == *(t *)(old))
+
+#ifdef CONFIG_X86_64
+#  define CMPXCHG64(ptr, old, new) CMPXCHG_TYPE(u64, ptr, old, new)
+#else
+#  define CMPXCHG64(ptr, old, new) \
+       (cmpxchg64((u64 *)(ptr), *(u64 *)(old), *(u64 *)(new)) == *(u64 *)(old))
+#endif
+
 static int emulator_cmpxchg_emulated(unsigned long addr,
                                     const void *old,
                                     const void *new,
                                     unsigned int bytes,
                                     struct kvm_vcpu *vcpu)
 {
-       printk_once(KERN_WARNING "kvm: emulating exchange as write\n");
-#ifndef CONFIG_X86_64
-       /* guests cmpxchg8b have to be emulated atomically */
-       if (bytes == 8) {
-               gpa_t gpa;
-               struct page *page;
-               char *kaddr;
-               u64 val;
+       gpa_t gpa;
+       struct page *page;
+       char *kaddr;
+       bool exchanged;
 
-               gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, NULL);
+       /* guests cmpxchg8b have to be emulated atomically */
+       if (bytes > 8 || (bytes & (bytes - 1)))
+               goto emul_write;
 
-               if (gpa == UNMAPPED_GVA ||
-                  (gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE)
-                       goto emul_write;
+       gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, NULL);
 
-               if (((gpa + bytes - 1) & PAGE_MASK) != (gpa & PAGE_MASK))
-                       goto emul_write;
+       if (gpa == UNMAPPED_GVA ||
+           (gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE)
+               goto emul_write;
 
-               val = *(u64 *)new;
+       if (((gpa + bytes - 1) & PAGE_MASK) != (gpa & PAGE_MASK))
+               goto emul_write;
 
-               page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT);
+       page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT);
 
-               kaddr = kmap_atomic(page, KM_USER0);
-               set_64bit((u64 *)(kaddr + offset_in_page(gpa)), val);
-               kunmap_atomic(kaddr, KM_USER0);
-               kvm_release_page_dirty(page);
+       kaddr = kmap_atomic(page, KM_USER0);
+       kaddr += offset_in_page(gpa);
+       switch (bytes) {
+       case 1:
+               exchanged = CMPXCHG_TYPE(u8, kaddr, old, new);
+               break;
+       case 2:
+               exchanged = CMPXCHG_TYPE(u16, kaddr, old, new);
+               break;
+       case 4:
+               exchanged = CMPXCHG_TYPE(u32, kaddr, old, new);
+               break;
+       case 8:
+               exchanged = CMPXCHG64(kaddr, old, new);
+               break;
+       default:
+               BUG();
        }
+       kunmap_atomic(kaddr, KM_USER0);
+       kvm_release_page_dirty(page);
+
+       if (!exchanged)
+               return X86EMUL_CMPXCHG_FAILED;
+
+       kvm_mmu_pte_write(vcpu, gpa, new, bytes, 1);
+
+       return X86EMUL_CONTINUE;
+
 emul_write:
-#endif
+       printk_once(KERN_WARNING "kvm: emulating exchange as write\n");
 
        return emulator_write_emulated(addr, new, bytes, vcpu);
 }
 
+static int kernel_pio(struct kvm_vcpu *vcpu, void *pd)
+{
+       /* TODO: String I/O for in kernel device */
+       int r;
+
+       if (vcpu->arch.pio.in)
+               r = kvm_io_bus_read(vcpu->kvm, KVM_PIO_BUS, vcpu->arch.pio.port,
+                                   vcpu->arch.pio.size, pd);
+       else
+               r = kvm_io_bus_write(vcpu->kvm, KVM_PIO_BUS,
+                                    vcpu->arch.pio.port, vcpu->arch.pio.size,
+                                    pd);
+       return r;
+}
+
+
+static int emulator_pio_in_emulated(int size, unsigned short port, void *val,
+                            unsigned int count, struct kvm_vcpu *vcpu)
+{
+       if (vcpu->arch.pio.count)
+               goto data_avail;
+
+       trace_kvm_pio(1, port, size, 1);
+
+       vcpu->arch.pio.port = port;
+       vcpu->arch.pio.in = 1;
+       vcpu->arch.pio.count  = count;
+       vcpu->arch.pio.size = size;
+
+       if (!kernel_pio(vcpu, vcpu->arch.pio_data)) {
+       data_avail:
+               memcpy(val, vcpu->arch.pio_data, size * count);
+               vcpu->arch.pio.count = 0;
+               return 1;
+       }
+
+       vcpu->run->exit_reason = KVM_EXIT_IO;
+       vcpu->run->io.direction = KVM_EXIT_IO_IN;
+       vcpu->run->io.size = size;
+       vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE;
+       vcpu->run->io.count = count;
+       vcpu->run->io.port = port;
+
+       return 0;
+}
+
+static int emulator_pio_out_emulated(int size, unsigned short port,
+                             const void *val, unsigned int count,
+                             struct kvm_vcpu *vcpu)
+{
+       trace_kvm_pio(0, port, size, 1);
+
+       vcpu->arch.pio.port = port;
+       vcpu->arch.pio.in = 0;
+       vcpu->arch.pio.count = count;
+       vcpu->arch.pio.size = size;
+
+       memcpy(vcpu->arch.pio_data, val, size * count);
+
+       if (!kernel_pio(vcpu, vcpu->arch.pio_data)) {
+               vcpu->arch.pio.count = 0;
+               return 1;
+       }
+
+       vcpu->run->exit_reason = KVM_EXIT_IO;
+       vcpu->run->io.direction = KVM_EXIT_IO_OUT;
+       vcpu->run->io.size = size;
+       vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE;
+       vcpu->run->io.count = count;
+       vcpu->run->io.port = port;
+
+       return 0;
+}
+
 static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg)
 {
        return kvm_x86_ops->get_segment_base(vcpu, seg);
@@ -3316,14 +3613,14 @@ int emulate_clts(struct kvm_vcpu *vcpu)
 
 int emulator_get_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long *dest)
 {
-       return kvm_x86_ops->get_dr(ctxt->vcpu, dr, dest);
+       return kvm_get_dr(ctxt->vcpu, dr, dest);
 }
 
 int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long value)
 {
        unsigned long mask = (ctxt->mode == X86EMUL_MODE_PROT64) ? ~0ULL : ~0U;
 
-       return kvm_x86_ops->set_dr(ctxt->vcpu, dr, value & mask);
+       return kvm_set_dr(ctxt->vcpu, dr, value & mask);
 }
 
 void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context)
@@ -3344,50 +3641,205 @@ void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context)
 }
 EXPORT_SYMBOL_GPL(kvm_report_emulation_failure);
 
-static struct x86_emulate_ops emulate_ops = {
-       .read_std            = kvm_read_guest_virt_system,
-       .fetch               = kvm_fetch_guest_virt,
-       .read_emulated       = emulator_read_emulated,
-       .write_emulated      = emulator_write_emulated,
-       .cmpxchg_emulated    = emulator_cmpxchg_emulated,
-};
-
-static void cache_all_regs(struct kvm_vcpu *vcpu)
+static u64 mk_cr_64(u64 curr_cr, u32 new_val)
 {
-       kvm_register_read(vcpu, VCPU_REGS_RAX);
-       kvm_register_read(vcpu, VCPU_REGS_RSP);
-       kvm_register_read(vcpu, VCPU_REGS_RIP);
-       vcpu->arch.regs_dirty = ~0;
+       return (curr_cr & ~((1ULL << 32) - 1)) | new_val;
 }
 
-int emulate_instruction(struct kvm_vcpu *vcpu,
-                       unsigned long cr2,
-                       u16 error_code,
-                       int emulation_type)
+static unsigned long emulator_get_cr(int cr, struct kvm_vcpu *vcpu)
 {
-       int r, shadow_mask;
-       struct decode_cache *c;
-       struct kvm_run *run = vcpu->run;
-
-       kvm_clear_exception_queue(vcpu);
-       vcpu->arch.mmio_fault_cr2 = cr2;
-       /*
-        * TODO: fix emulate.c to use guest_read/write_register
-        * instead of direct ->regs accesses, can save hundred cycles
-        * on Intel for instructions that don't read/change RSP, for
-        * for example.
-        */
-       cache_all_regs(vcpu);
-
-       vcpu->mmio_is_write = 0;
-       vcpu->arch.pio.string = 0;
+       unsigned long value;
+
+       switch (cr) {
+       case 0:
+               value = kvm_read_cr0(vcpu);
+               break;
+       case 2:
+               value = vcpu->arch.cr2;
+               break;
+       case 3:
+               value = vcpu->arch.cr3;
+               break;
+       case 4:
+               value = kvm_read_cr4(vcpu);
+               break;
+       case 8:
+               value = kvm_get_cr8(vcpu);
+               break;
+       default:
+               vcpu_printf(vcpu, "%s: unexpected cr %u\n", __func__, cr);
+               return 0;
+       }
+
+       return value;
+}
+
+static void emulator_set_cr(int cr, unsigned long val, struct kvm_vcpu *vcpu)
+{
+       switch (cr) {
+       case 0:
+               kvm_set_cr0(vcpu, mk_cr_64(kvm_read_cr0(vcpu), val));
+               break;
+       case 2:
+               vcpu->arch.cr2 = val;
+               break;
+       case 3:
+               kvm_set_cr3(vcpu, val);
+               break;
+       case 4:
+               kvm_set_cr4(vcpu, mk_cr_64(kvm_read_cr4(vcpu), val));
+               break;
+       case 8:
+               kvm_set_cr8(vcpu, val & 0xfUL);
+               break;
+       default:
+               vcpu_printf(vcpu, "%s: unexpected cr %u\n", __func__, cr);
+       }
+}
+
+static int emulator_get_cpl(struct kvm_vcpu *vcpu)
+{
+       return kvm_x86_ops->get_cpl(vcpu);
+}
+
+static void emulator_get_gdt(struct desc_ptr *dt, struct kvm_vcpu *vcpu)
+{
+       kvm_x86_ops->get_gdt(vcpu, dt);
+}
+
+static bool emulator_get_cached_descriptor(struct desc_struct *desc, int seg,
+                                          struct kvm_vcpu *vcpu)
+{
+       struct kvm_segment var;
+
+       kvm_get_segment(vcpu, &var, seg);
+
+       if (var.unusable)
+               return false;
+
+       if (var.g)
+               var.limit >>= 12;
+       set_desc_limit(desc, var.limit);
+       set_desc_base(desc, (unsigned long)var.base);
+       desc->type = var.type;
+       desc->s = var.s;
+       desc->dpl = var.dpl;
+       desc->p = var.present;
+       desc->avl = var.avl;
+       desc->l = var.l;
+       desc->d = var.db;
+       desc->g = var.g;
+
+       return true;
+}
+
+static void emulator_set_cached_descriptor(struct desc_struct *desc, int seg,
+                                          struct kvm_vcpu *vcpu)
+{
+       struct kvm_segment var;
+
+       /* needed to preserve selector */
+       kvm_get_segment(vcpu, &var, seg);
+
+       var.base = get_desc_base(desc);
+       var.limit = get_desc_limit(desc);
+       if (desc->g)
+               var.limit = (var.limit << 12) | 0xfff;
+       var.type = desc->type;
+       var.present = desc->p;
+       var.dpl = desc->dpl;
+       var.db = desc->d;
+       var.s = desc->s;
+       var.l = desc->l;
+       var.g = desc->g;
+       var.avl = desc->avl;
+       var.present = desc->p;
+       var.unusable = !var.present;
+       var.padding = 0;
+
+       kvm_set_segment(vcpu, &var, seg);
+       return;
+}
+
+static u16 emulator_get_segment_selector(int seg, struct kvm_vcpu *vcpu)
+{
+       struct kvm_segment kvm_seg;
+
+       kvm_get_segment(vcpu, &kvm_seg, seg);
+       return kvm_seg.selector;
+}
+
+static void emulator_set_segment_selector(u16 sel, int seg,
+                                         struct kvm_vcpu *vcpu)
+{
+       struct kvm_segment kvm_seg;
+
+       kvm_get_segment(vcpu, &kvm_seg, seg);
+       kvm_seg.selector = sel;
+       kvm_set_segment(vcpu, &kvm_seg, seg);
+}
+
+static void emulator_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
+{
+       kvm_x86_ops->set_rflags(vcpu, rflags);
+}
+
+static struct x86_emulate_ops emulate_ops = {
+       .read_std            = kvm_read_guest_virt_system,
+       .write_std           = kvm_write_guest_virt_system,
+       .fetch               = kvm_fetch_guest_virt,
+       .read_emulated       = emulator_read_emulated,
+       .write_emulated      = emulator_write_emulated,
+       .cmpxchg_emulated    = emulator_cmpxchg_emulated,
+       .pio_in_emulated     = emulator_pio_in_emulated,
+       .pio_out_emulated    = emulator_pio_out_emulated,
+       .get_cached_descriptor = emulator_get_cached_descriptor,
+       .set_cached_descriptor = emulator_set_cached_descriptor,
+       .get_segment_selector = emulator_get_segment_selector,
+       .set_segment_selector = emulator_set_segment_selector,
+       .get_gdt             = emulator_get_gdt,
+       .get_cr              = emulator_get_cr,
+       .set_cr              = emulator_set_cr,
+       .cpl                 = emulator_get_cpl,
+       .set_rflags          = emulator_set_rflags,
+};
+
+static void cache_all_regs(struct kvm_vcpu *vcpu)
+{
+       kvm_register_read(vcpu, VCPU_REGS_RAX);
+       kvm_register_read(vcpu, VCPU_REGS_RSP);
+       kvm_register_read(vcpu, VCPU_REGS_RIP);
+       vcpu->arch.regs_dirty = ~0;
+}
+
+int emulate_instruction(struct kvm_vcpu *vcpu,
+                       unsigned long cr2,
+                       u16 error_code,
+                       int emulation_type)
+{
+       int r, shadow_mask;
+       struct decode_cache *c;
+       struct kvm_run *run = vcpu->run;
+
+       kvm_clear_exception_queue(vcpu);
+       vcpu->arch.mmio_fault_cr2 = cr2;
+       /*
+        * TODO: fix emulate.c to use guest_read/write_register
+        * instead of direct ->regs accesses, can save hundred cycles
+        * on Intel for instructions that don't read/change RSP, for
+        * for example.
+        */
+       cache_all_regs(vcpu);
+
+       vcpu->mmio_is_write = 0;
 
        if (!(emulation_type & EMULTYPE_NO_DECODE)) {
                int cs_db, cs_l;
                kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
 
                vcpu->arch.emulate_ctxt.vcpu = vcpu;
-               vcpu->arch.emulate_ctxt.eflags = kvm_get_rflags(vcpu);
+               vcpu->arch.emulate_ctxt.eflags = kvm_x86_ops->get_rflags(vcpu);
+               vcpu->arch.emulate_ctxt.eip = kvm_rip_read(vcpu);
                vcpu->arch.emulate_ctxt.mode =
                        (!is_protmode(vcpu)) ? X86EMUL_MODE_REAL :
                        (vcpu->arch.emulate_ctxt.eflags & X86_EFLAGS_VM)
@@ -3396,6 +3848,7 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
                        ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
 
                r = x86_decode_insn(&vcpu->arch.emulate_ctxt, &emulate_ops);
+               trace_kvm_emulate_insn_start(vcpu);
 
                /* Only allow emulation of specific instructions on #UD
                 * (namely VMMCALL, sysenter, sysexit, syscall)*/
@@ -3428,6 +3881,7 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
                ++vcpu->stat.insn_emulation;
                if (r)  {
                        ++vcpu->stat.insn_emulation_fail;
+                       trace_kvm_emulate_insn_failed(vcpu);
                        if (kvm_mmu_unprotect_page_virt(vcpu, cr2))
                                return EMULATE_DONE;
                        return EMULATE_FAIL;
@@ -3439,16 +3893,20 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
                return EMULATE_DONE;
        }
 
+restart:
        r = x86_emulate_insn(&vcpu->arch.emulate_ctxt, &emulate_ops);
        shadow_mask = vcpu->arch.emulate_ctxt.interruptibility;
 
        if (r == 0)
                kvm_x86_ops->set_interrupt_shadow(vcpu, shadow_mask);
 
-       if (vcpu->arch.pio.string)
+       if (vcpu->arch.pio.count) {
+               if (!vcpu->arch.pio.in)
+                       vcpu->arch.pio.count = 0;
                return EMULATE_DO_MMIO;
+       }
 
-       if ((r || vcpu->mmio_is_write) && run) {
+       if (r || vcpu->mmio_is_write) {
                run->exit_reason = KVM_EXIT_MMIO;
                run->mmio.phys_addr = vcpu->mmio_phys_addr;
                memcpy(run->mmio.data, vcpu->mmio_data, 8);
@@ -3458,222 +3916,41 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
 
        if (r) {
                if (kvm_mmu_unprotect_page_virt(vcpu, cr2))
-                       return EMULATE_DONE;
+                       goto done;
                if (!vcpu->mmio_needed) {
+                       ++vcpu->stat.insn_emulation_fail;
+                       trace_kvm_emulate_insn_failed(vcpu);
                        kvm_report_emulation_failure(vcpu, "mmio");
                        return EMULATE_FAIL;
                }
                return EMULATE_DO_MMIO;
        }
 
-       kvm_set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags);
-
        if (vcpu->mmio_is_write) {
                vcpu->mmio_needed = 0;
                return EMULATE_DO_MMIO;
        }
 
-       return EMULATE_DONE;
-}
-EXPORT_SYMBOL_GPL(emulate_instruction);
-
-static int pio_copy_data(struct kvm_vcpu *vcpu)
-{
-       void *p = vcpu->arch.pio_data;
-       gva_t q = vcpu->arch.pio.guest_gva;
-       unsigned bytes;
-       int ret;
-       u32 error_code;
-
-       bytes = vcpu->arch.pio.size * vcpu->arch.pio.cur_count;
-       if (vcpu->arch.pio.in)
-               ret = kvm_write_guest_virt(q, p, bytes, vcpu, &error_code);
-       else
-               ret = kvm_read_guest_virt(q, p, bytes, vcpu, &error_code);
-
-       if (ret == X86EMUL_PROPAGATE_FAULT)
-               kvm_inject_page_fault(vcpu, q, error_code);
-
-       return ret;
-}
-
-int complete_pio(struct kvm_vcpu *vcpu)
-{
-       struct kvm_pio_request *io = &vcpu->arch.pio;
-       long delta;
-       int r;
-       unsigned long val;
-
-       if (!io->string) {
-               if (io->in) {
-                       val = kvm_register_read(vcpu, VCPU_REGS_RAX);
-                       memcpy(&val, vcpu->arch.pio_data, io->size);
-                       kvm_register_write(vcpu, VCPU_REGS_RAX, val);
-               }
-       } else {
-               if (io->in) {
-                       r = pio_copy_data(vcpu);
-                       if (r)
-                               goto out;
-               }
-
-               delta = 1;
-               if (io->rep) {
-                       delta *= io->cur_count;
-                       /*
-                        * The size of the register should really depend on
-                        * current address size.
-                        */
-                       val = kvm_register_read(vcpu, VCPU_REGS_RCX);
-                       val -= delta;
-                       kvm_register_write(vcpu, VCPU_REGS_RCX, val);
-               }
-               if (io->down)
-                       delta = -delta;
-               delta *= io->size;
-               if (io->in) {
-                       val = kvm_register_read(vcpu, VCPU_REGS_RDI);
-                       val += delta;
-                       kvm_register_write(vcpu, VCPU_REGS_RDI, val);
-               } else {
-                       val = kvm_register_read(vcpu, VCPU_REGS_RSI);
-                       val += delta;
-                       kvm_register_write(vcpu, VCPU_REGS_RSI, val);
-               }
-       }
-out:
-       io->count -= io->cur_count;
-       io->cur_count = 0;
-
-       return 0;
-}
-
-static int kernel_pio(struct kvm_vcpu *vcpu, void *pd)
-{
-       /* TODO: String I/O for in kernel device */
-       int r;
-
-       if (vcpu->arch.pio.in)
-               r = kvm_io_bus_read(vcpu->kvm, KVM_PIO_BUS, vcpu->arch.pio.port,
-                                   vcpu->arch.pio.size, pd);
-       else
-               r = kvm_io_bus_write(vcpu->kvm, KVM_PIO_BUS,
-                                    vcpu->arch.pio.port, vcpu->arch.pio.size,
-                                    pd);
-       return r;
-}
-
-static int pio_string_write(struct kvm_vcpu *vcpu)
-{
-       struct kvm_pio_request *io = &vcpu->arch.pio;
-       void *pd = vcpu->arch.pio_data;
-       int i, r = 0;
-
-       for (i = 0; i < io->cur_count; i++) {
-               if (kvm_io_bus_write(vcpu->kvm, KVM_PIO_BUS,
-                                    io->port, io->size, pd)) {
-                       r = -EOPNOTSUPP;
-                       break;
-               }
-               pd += io->size;
-       }
-       return r;
-}
-
-int kvm_emulate_pio(struct kvm_vcpu *vcpu, int in, int size, unsigned port)
-{
-       unsigned long val;
+done:
+       if (vcpu->arch.exception.pending)
+               vcpu->arch.emulate_ctxt.restart = false;
 
-       trace_kvm_pio(!in, port, size, 1);
+       if (vcpu->arch.emulate_ctxt.restart)
+               goto restart;
 
-       vcpu->run->exit_reason = KVM_EXIT_IO;
-       vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
-       vcpu->run->io.size = vcpu->arch.pio.size = size;
-       vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE;
-       vcpu->run->io.count = vcpu->arch.pio.count = vcpu->arch.pio.cur_count = 1;
-       vcpu->run->io.port = vcpu->arch.pio.port = port;
-       vcpu->arch.pio.in = in;
-       vcpu->arch.pio.string = 0;
-       vcpu->arch.pio.down = 0;
-       vcpu->arch.pio.rep = 0;
-
-       if (!vcpu->arch.pio.in) {
-               val = kvm_register_read(vcpu, VCPU_REGS_RAX);
-               memcpy(vcpu->arch.pio_data, &val, 4);
-       }
-
-       if (!kernel_pio(vcpu, vcpu->arch.pio_data)) {
-               complete_pio(vcpu);
-               return 1;
-       }
-       return 0;
+       return EMULATE_DONE;
 }
-EXPORT_SYMBOL_GPL(kvm_emulate_pio);
+EXPORT_SYMBOL_GPL(emulate_instruction);
 
-int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, int in,
-                 int size, unsigned long count, int down,
-                 gva_t address, int rep, unsigned port)
+int kvm_fast_pio_out(struct kvm_vcpu *vcpu, int size, unsigned short port)
 {
-       unsigned now, in_page;
-       int ret = 0;
-
-       trace_kvm_pio(!in, port, size, count);
-
-       vcpu->run->exit_reason = KVM_EXIT_IO;
-       vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
-       vcpu->run->io.size = vcpu->arch.pio.size = size;
-       vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE;
-       vcpu->run->io.count = vcpu->arch.pio.count = vcpu->arch.pio.cur_count = count;
-       vcpu->run->io.port = vcpu->arch.pio.port = port;
-       vcpu->arch.pio.in = in;
-       vcpu->arch.pio.string = 1;
-       vcpu->arch.pio.down = down;
-       vcpu->arch.pio.rep = rep;
-
-       if (!count) {
-               kvm_x86_ops->skip_emulated_instruction(vcpu);
-               return 1;
-       }
-
-       if (!down)
-               in_page = PAGE_SIZE - offset_in_page(address);
-       else
-               in_page = offset_in_page(address) + size;
-       now = min(count, (unsigned long)in_page / size);
-       if (!now)
-               now = 1;
-       if (down) {
-               /*
-                * String I/O in reverse.  Yuck.  Kill the guest, fix later.
-                */
-               pr_unimpl(vcpu, "guest string pio down\n");
-               kvm_inject_gp(vcpu, 0);
-               return 1;
-       }
-       vcpu->run->io.count = now;
-       vcpu->arch.pio.cur_count = now;
-
-       if (vcpu->arch.pio.cur_count == vcpu->arch.pio.count)
-               kvm_x86_ops->skip_emulated_instruction(vcpu);
-
-       vcpu->arch.pio.guest_gva = address;
-
-       if (!vcpu->arch.pio.in) {
-               /* string PIO write */
-               ret = pio_copy_data(vcpu);
-               if (ret == X86EMUL_PROPAGATE_FAULT)
-                       return 1;
-               if (ret == 0 && !pio_string_write(vcpu)) {
-                       complete_pio(vcpu);
-                       if (vcpu->arch.pio.count == 0)
-                               ret = 1;
-               }
-       }
-       /* no string PIO read support yet */
-
+       unsigned long val = kvm_register_read(vcpu, VCPU_REGS_RAX);
+       int ret = emulator_pio_out_emulated(size, port, &val, 1, vcpu);
+       /* do not return to emulator after return from userspace */
+       vcpu->arch.pio.count = 0;
        return ret;
 }
-EXPORT_SYMBOL_GPL(kvm_emulate_pio_string);
+EXPORT_SYMBOL_GPL(kvm_fast_pio_out);
 
 static void bounce_off(void *info)
 {
@@ -3996,85 +4273,20 @@ int kvm_fix_hypercall(struct kvm_vcpu *vcpu)
        return emulator_write_emulated(rip, instruction, 3, vcpu);
 }
 
-static u64 mk_cr_64(u64 curr_cr, u32 new_val)
-{
-       return (curr_cr & ~((1ULL << 32) - 1)) | new_val;
-}
-
 void realmode_lgdt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base)
 {
-       struct descriptor_table dt = { limit, base };
+       struct desc_ptr dt = { limit, base };
 
        kvm_x86_ops->set_gdt(vcpu, &dt);
 }
 
 void realmode_lidt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base)
 {
-       struct descriptor_table dt = { limit, base };
+       struct desc_ptr dt = { limit, base };
 
        kvm_x86_ops->set_idt(vcpu, &dt);
 }
 
-void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
-                  unsigned long *rflags)
-{
-       kvm_lmsw(vcpu, msw);
-       *rflags = kvm_get_rflags(vcpu);
-}
-
-unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr)
-{
-       unsigned long value;
-
-       switch (cr) {
-       case 0:
-               value = kvm_read_cr0(vcpu);
-               break;
-       case 2:
-               value = vcpu->arch.cr2;
-               break;
-       case 3:
-               value = vcpu->arch.cr3;
-               break;
-       case 4:
-               value = kvm_read_cr4(vcpu);
-               break;
-       case 8:
-               value = kvm_get_cr8(vcpu);
-               break;
-       default:
-               vcpu_printf(vcpu, "%s: unexpected cr %u\n", __func__, cr);
-               return 0;
-       }
-
-       return value;
-}
-
-void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val,
-                    unsigned long *rflags)
-{
-       switch (cr) {
-       case 0:
-               kvm_set_cr0(vcpu, mk_cr_64(kvm_read_cr0(vcpu), val));
-               *rflags = kvm_get_rflags(vcpu);
-               break;
-       case 2:
-               vcpu->arch.cr2 = val;
-               break;
-       case 3:
-               kvm_set_cr3(vcpu, val);
-               break;
-       case 4:
-               kvm_set_cr4(vcpu, mk_cr_64(kvm_read_cr4(vcpu), val));
-               break;
-       case 8:
-               kvm_set_cr8(vcpu, val & 0xfUL);
-               break;
-       default:
-               vcpu_printf(vcpu, "%s: unexpected cr %u\n", __func__, cr);
-       }
-}
-
 static int move_to_next_stateful_cpuid_entry(struct kvm_vcpu *vcpu, int i)
 {
        struct kvm_cpuid_entry2 *e = &vcpu->arch.cpuid_entries[i];
@@ -4138,9 +4350,13 @@ int cpuid_maxphyaddr(struct kvm_vcpu *vcpu)
 {
        struct kvm_cpuid_entry2 *best;
 
+       best = kvm_find_cpuid_entry(vcpu, 0x80000000, 0);
+       if (!best || best->eax < 0x80000008)
+               goto not_found;
        best = kvm_find_cpuid_entry(vcpu, 0x80000008, 0);
        if (best)
                return best->eax & 0xff;
+not_found:
        return 36;
 }
 
@@ -4254,9 +4470,13 @@ static void inject_pending_event(struct kvm_vcpu *vcpu)
 {
        /* try to reinject previous events if any */
        if (vcpu->arch.exception.pending) {
+               trace_kvm_inj_exception(vcpu->arch.exception.nr,
+                                       vcpu->arch.exception.has_error_code,
+                                       vcpu->arch.exception.error_code);
                kvm_x86_ops->queue_exception(vcpu, vcpu->arch.exception.nr,
                                          vcpu->arch.exception.has_error_code,
-                                         vcpu->arch.exception.error_code);
+                                         vcpu->arch.exception.error_code,
+                                         vcpu->arch.exception.reinject);
                return;
        }
 
@@ -4486,7 +4706,6 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
        }
 
        srcu_read_unlock(&kvm->srcu, vcpu->srcu_idx);
-       post_kvm_run_save(vcpu);
 
        vapic_exit(vcpu);
 
@@ -4514,26 +4733,17 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        if (!irqchip_in_kernel(vcpu->kvm))
                kvm_set_cr8(vcpu, kvm_run->cr8);
 
-       if (vcpu->arch.pio.cur_count) {
-               vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
-               r = complete_pio(vcpu);
-               srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
-               if (r)
-                       goto out;
-       }
-       if (vcpu->mmio_needed) {
-               memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8);
-               vcpu->mmio_read_completed = 1;
-               vcpu->mmio_needed = 0;
-
+       if (vcpu->arch.pio.count || vcpu->mmio_needed ||
+           vcpu->arch.emulate_ctxt.restart) {
+               if (vcpu->mmio_needed) {
+                       memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8);
+                       vcpu->mmio_read_completed = 1;
+                       vcpu->mmio_needed = 0;
+               }
                vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
-               r = emulate_instruction(vcpu, vcpu->arch.mmio_fault_cr2, 0,
-                                       EMULTYPE_NO_DECODE);
+               r = emulate_instruction(vcpu, 0, 0, EMULTYPE_NO_DECODE);
                srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
                if (r == EMULATE_DO_MMIO) {
-                       /*
-                        * Read-modify-write.  Back to userspace.
-                        */
                        r = 0;
                        goto out;
                }
@@ -4545,6 +4755,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        r = __vcpu_run(vcpu);
 
 out:
+       post_kvm_run_save(vcpu);
        if (vcpu->sigset_active)
                sigprocmask(SIG_SETMASK, &sigsaved, NULL);
 
@@ -4616,12 +4827,6 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
        return 0;
 }
 
-void kvm_get_segment(struct kvm_vcpu *vcpu,
-                    struct kvm_segment *var, int seg)
-{
-       kvm_x86_ops->get_segment(vcpu, var, seg);
-}
-
 void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l)
 {
        struct kvm_segment cs;
@@ -4635,7 +4840,7 @@ EXPORT_SYMBOL_GPL(kvm_get_cs_db_l_bits);
 int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
                                  struct kvm_sregs *sregs)
 {
-       struct descriptor_table dt;
+       struct desc_ptr dt;
 
        vcpu_load(vcpu);
 
@@ -4650,11 +4855,11 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
        kvm_get_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR);
 
        kvm_x86_ops->get_idt(vcpu, &dt);
-       sregs->idt.limit = dt.limit;
-       sregs->idt.base = dt.base;
+       sregs->idt.limit = dt.size;
+       sregs->idt.base = dt.address;
        kvm_x86_ops->get_gdt(vcpu, &dt);
-       sregs->gdt.limit = dt.limit;
-       sregs->gdt.base = dt.base;
+       sregs->gdt.limit = dt.size;
+       sregs->gdt.base = dt.address;
 
        sregs->cr0 = kvm_read_cr0(vcpu);
        sregs->cr2 = vcpu->arch.cr2;
@@ -4693,563 +4898,33 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
        return 0;
 }
 
-static void kvm_set_segment(struct kvm_vcpu *vcpu,
-                       struct kvm_segment *var, int seg)
+int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason,
+                   bool has_error_code, u32 error_code)
 {
-       kvm_x86_ops->set_segment(vcpu, var, seg);
-}
-
-static void seg_desct_to_kvm_desct(struct desc_struct *seg_desc, u16 selector,
-                                  struct kvm_segment *kvm_desct)
-{
-       kvm_desct->base = get_desc_base(seg_desc);
-       kvm_desct->limit = get_desc_limit(seg_desc);
-       if (seg_desc->g) {
-               kvm_desct->limit <<= 12;
-               kvm_desct->limit |= 0xfff;
-       }
-       kvm_desct->selector = selector;
-       kvm_desct->type = seg_desc->type;
-       kvm_desct->present = seg_desc->p;
-       kvm_desct->dpl = seg_desc->dpl;
-       kvm_desct->db = seg_desc->d;
-       kvm_desct->s = seg_desc->s;
-       kvm_desct->l = seg_desc->l;
-       kvm_desct->g = seg_desc->g;
-       kvm_desct->avl = seg_desc->avl;
-       if (!selector)
-               kvm_desct->unusable = 1;
-       else
-               kvm_desct->unusable = 0;
-       kvm_desct->padding = 0;
-}
-
-static void get_segment_descriptor_dtable(struct kvm_vcpu *vcpu,
-                                         u16 selector,
-                                         struct descriptor_table *dtable)
-{
-       if (selector & 1 << 2) {
-               struct kvm_segment kvm_seg;
-
-               kvm_get_segment(vcpu, &kvm_seg, VCPU_SREG_LDTR);
-
-               if (kvm_seg.unusable)
-                       dtable->limit = 0;
-               else
-                       dtable->limit = kvm_seg.limit;
-               dtable->base = kvm_seg.base;
-       }
-       else
-               kvm_x86_ops->get_gdt(vcpu, dtable);
-}
-
-/* allowed just for 8 bytes segments */
-static int load_guest_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
-                                        struct desc_struct *seg_desc)
-{
-       struct descriptor_table dtable;
-       u16 index = selector >> 3;
-       int ret;
-       u32 err;
-       gva_t addr;
-
-       get_segment_descriptor_dtable(vcpu, selector, &dtable);
-
-       if (dtable.limit < index * 8 + 7) {
-               kvm_queue_exception_e(vcpu, GP_VECTOR, selector & 0xfffc);
-               return X86EMUL_PROPAGATE_FAULT;
-       }
-       addr = dtable.base + index * 8;
-       ret = kvm_read_guest_virt_system(addr, seg_desc, sizeof(*seg_desc),
-                                        vcpu,  &err);
-       if (ret == X86EMUL_PROPAGATE_FAULT)
-               kvm_inject_page_fault(vcpu, addr, err);
-
-       return ret;
-}
-
-/* allowed just for 8 bytes segments */
-static int save_guest_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
-                                        struct desc_struct *seg_desc)
-{
-       struct descriptor_table dtable;
-       u16 index = selector >> 3;
-
-       get_segment_descriptor_dtable(vcpu, selector, &dtable);
-
-       if (dtable.limit < index * 8 + 7)
-               return 1;
-       return kvm_write_guest_virt(dtable.base + index*8, seg_desc, sizeof(*seg_desc), vcpu, NULL);
-}
-
-static gpa_t get_tss_base_addr_write(struct kvm_vcpu *vcpu,
-                              struct desc_struct *seg_desc)
-{
-       u32 base_addr = get_desc_base(seg_desc);
-
-       return kvm_mmu_gva_to_gpa_write(vcpu, base_addr, NULL);
-}
-
-static gpa_t get_tss_base_addr_read(struct kvm_vcpu *vcpu,
-                            struct desc_struct *seg_desc)
-{
-       u32 base_addr = get_desc_base(seg_desc);
-
-       return kvm_mmu_gva_to_gpa_read(vcpu, base_addr, NULL);
-}
-
-static u16 get_segment_selector(struct kvm_vcpu *vcpu, int seg)
-{
-       struct kvm_segment kvm_seg;
-
-       kvm_get_segment(vcpu, &kvm_seg, seg);
-       return kvm_seg.selector;
-}
-
-static int kvm_load_realmode_segment(struct kvm_vcpu *vcpu, u16 selector, int seg)
-{
-       struct kvm_segment segvar = {
-               .base = selector << 4,
-               .limit = 0xffff,
-               .selector = selector,
-               .type = 3,
-               .present = 1,
-               .dpl = 3,
-               .db = 0,
-               .s = 1,
-               .l = 0,
-               .g = 0,
-               .avl = 0,
-               .unusable = 0,
-       };
-       kvm_x86_ops->set_segment(vcpu, &segvar, seg);
-       return X86EMUL_CONTINUE;
-}
-
-static int is_vm86_segment(struct kvm_vcpu *vcpu, int seg)
-{
-       return (seg != VCPU_SREG_LDTR) &&
-               (seg != VCPU_SREG_TR) &&
-               (kvm_get_rflags(vcpu) & X86_EFLAGS_VM);
-}
-
-int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, int seg)
-{
-       struct kvm_segment kvm_seg;
-       struct desc_struct seg_desc;
-       u8 dpl, rpl, cpl;
-       unsigned err_vec = GP_VECTOR;
-       u32 err_code = 0;
-       bool null_selector = !(selector & ~0x3); /* 0000-0003 are null */
-       int ret;
+       int cs_db, cs_l, ret;
+       cache_all_regs(vcpu);
 
-       if (is_vm86_segment(vcpu, seg) || !is_protmode(vcpu))
-               return kvm_load_realmode_segment(vcpu, selector, seg);
+       kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
 
-       /* NULL selector is not valid for TR, CS and SS */
-       if ((seg == VCPU_SREG_CS || seg == VCPU_SREG_SS || seg == VCPU_SREG_TR)
-           && null_selector)
-               goto exception;
+       vcpu->arch.emulate_ctxt.vcpu = vcpu;
+       vcpu->arch.emulate_ctxt.eflags = kvm_x86_ops->get_rflags(vcpu);
+       vcpu->arch.emulate_ctxt.eip = kvm_rip_read(vcpu);
+       vcpu->arch.emulate_ctxt.mode =
+               (!is_protmode(vcpu)) ? X86EMUL_MODE_REAL :
+               (vcpu->arch.emulate_ctxt.eflags & X86_EFLAGS_VM)
+               ? X86EMUL_MODE_VM86 : cs_l
+               ? X86EMUL_MODE_PROT64 : cs_db
+               ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
 
-       /* TR should be in GDT only */
-       if (seg == VCPU_SREG_TR && (selector & (1 << 2)))
-               goto exception;
+       ret = emulator_task_switch(&vcpu->arch.emulate_ctxt, &emulate_ops,
+                                  tss_selector, reason, has_error_code,
+                                  error_code);
 
-       ret = load_guest_segment_descriptor(vcpu, selector, &seg_desc);
        if (ret)
-               return ret;
-
-       seg_desct_to_kvm_desct(&seg_desc, selector, &kvm_seg);
-
-       if (null_selector) { /* for NULL selector skip all following checks */
-               kvm_seg.unusable = 1;
-               goto load;
-       }
-
-       err_code = selector & 0xfffc;
-       err_vec = GP_VECTOR;
-
-       /* can't load system descriptor into segment selecor */
-       if (seg <= VCPU_SREG_GS && !kvm_seg.s)
-               goto exception;
-
-       if (!kvm_seg.present) {
-               err_vec = (seg == VCPU_SREG_SS) ? SS_VECTOR : NP_VECTOR;
-               goto exception;
-       }
-
-       rpl = selector & 3;
-       dpl = kvm_seg.dpl;
-       cpl = kvm_x86_ops->get_cpl(vcpu);
-
-       switch (seg) {
-       case VCPU_SREG_SS:
-               /*
-                * segment is not a writable data segment or segment
-                * selector's RPL != CPL or segment selector's RPL != CPL
-                */
-               if (rpl != cpl || (kvm_seg.type & 0xa) != 0x2 || dpl != cpl)
-                       goto exception;
-               break;
-       case VCPU_SREG_CS:
-               if (!(kvm_seg.type & 8))
-                       goto exception;
-
-               if (kvm_seg.type & 4) {
-                       /* conforming */
-                       if (dpl > cpl)
-                               goto exception;
-               } else {
-                       /* nonconforming */
-                       if (rpl > cpl || dpl != cpl)
-                               goto exception;
-               }
-               /* CS(RPL) <- CPL */
-               selector = (selector & 0xfffc) | cpl;
-            break;
-       case VCPU_SREG_TR:
-               if (kvm_seg.s || (kvm_seg.type != 1 && kvm_seg.type != 9))
-                       goto exception;
-               break;
-       case VCPU_SREG_LDTR:
-               if (kvm_seg.s || kvm_seg.type != 2)
-                       goto exception;
-               break;
-       default: /*  DS, ES, FS, or GS */
-               /*
-                * segment is not a data or readable code segment or
-                * ((segment is a data or nonconforming code segment)
-                * and (both RPL and CPL > DPL))
-                */
-               if ((kvm_seg.type & 0xa) == 0x8 ||
-                   (((kvm_seg.type & 0xc) != 0xc) && (rpl > dpl && cpl > dpl)))
-                       goto exception;
-               break;
-       }
-
-       if (!kvm_seg.unusable && kvm_seg.s) {
-               /* mark segment as accessed */
-               kvm_seg.type |= 1;
-               seg_desc.type |= 1;
-               save_guest_segment_descriptor(vcpu, selector, &seg_desc);
-       }
-load:
-       kvm_set_segment(vcpu, &kvm_seg, seg);
-       return X86EMUL_CONTINUE;
-exception:
-       kvm_queue_exception_e(vcpu, err_vec, err_code);
-       return X86EMUL_PROPAGATE_FAULT;
-}
-
-static void save_state_to_tss32(struct kvm_vcpu *vcpu,
-                               struct tss_segment_32 *tss)
-{
-       tss->cr3 = vcpu->arch.cr3;
-       tss->eip = kvm_rip_read(vcpu);
-       tss->eflags = kvm_get_rflags(vcpu);
-       tss->eax = kvm_register_read(vcpu, VCPU_REGS_RAX);
-       tss->ecx = kvm_register_read(vcpu, VCPU_REGS_RCX);
-       tss->edx = kvm_register_read(vcpu, VCPU_REGS_RDX);
-       tss->ebx = kvm_register_read(vcpu, VCPU_REGS_RBX);
-       tss->esp = kvm_register_read(vcpu, VCPU_REGS_RSP);
-       tss->ebp = kvm_register_read(vcpu, VCPU_REGS_RBP);
-       tss->esi = kvm_register_read(vcpu, VCPU_REGS_RSI);
-       tss->edi = kvm_register_read(vcpu, VCPU_REGS_RDI);
-       tss->es = get_segment_selector(vcpu, VCPU_SREG_ES);
-       tss->cs = get_segment_selector(vcpu, VCPU_SREG_CS);
-       tss->ss = get_segment_selector(vcpu, VCPU_SREG_SS);
-       tss->ds = get_segment_selector(vcpu, VCPU_SREG_DS);
-       tss->fs = get_segment_selector(vcpu, VCPU_SREG_FS);
-       tss->gs = get_segment_selector(vcpu, VCPU_SREG_GS);
-       tss->ldt_selector = get_segment_selector(vcpu, VCPU_SREG_LDTR);
-}
-
-static void kvm_load_segment_selector(struct kvm_vcpu *vcpu, u16 sel, int seg)
-{
-       struct kvm_segment kvm_seg;
-       kvm_get_segment(vcpu, &kvm_seg, seg);
-       kvm_seg.selector = sel;
-       kvm_set_segment(vcpu, &kvm_seg, seg);
-}
-
-static int load_state_from_tss32(struct kvm_vcpu *vcpu,
-                                 struct tss_segment_32 *tss)
-{
-       kvm_set_cr3(vcpu, tss->cr3);
-
-       kvm_rip_write(vcpu, tss->eip);
-       kvm_set_rflags(vcpu, tss->eflags | 2);
-
-       kvm_register_write(vcpu, VCPU_REGS_RAX, tss->eax);
-       kvm_register_write(vcpu, VCPU_REGS_RCX, tss->ecx);
-       kvm_register_write(vcpu, VCPU_REGS_RDX, tss->edx);
-       kvm_register_write(vcpu, VCPU_REGS_RBX, tss->ebx);
-       kvm_register_write(vcpu, VCPU_REGS_RSP, tss->esp);
-       kvm_register_write(vcpu, VCPU_REGS_RBP, tss->ebp);
-       kvm_register_write(vcpu, VCPU_REGS_RSI, tss->esi);
-       kvm_register_write(vcpu, VCPU_REGS_RDI, tss->edi);
-
-       /*
-        * SDM says that segment selectors are loaded before segment
-        * descriptors
-        */
-       kvm_load_segment_selector(vcpu, tss->ldt_selector, VCPU_SREG_LDTR);
-       kvm_load_segment_selector(vcpu, tss->es, VCPU_SREG_ES);
-       kvm_load_segment_selector(vcpu, tss->cs, VCPU_SREG_CS);
-       kvm_load_segment_selector(vcpu, tss->ss, VCPU_SREG_SS);
-       kvm_load_segment_selector(vcpu, tss->ds, VCPU_SREG_DS);
-       kvm_load_segment_selector(vcpu, tss->fs, VCPU_SREG_FS);
-       kvm_load_segment_selector(vcpu, tss->gs, VCPU_SREG_GS);
-
-       /*
-        * Now load segment descriptors. If fault happenes at this stage
-        * it is handled in a context of new task
-        */
-       if (kvm_load_segment_descriptor(vcpu, tss->ldt_selector, VCPU_SREG_LDTR))
-               return 1;
-
-       if (kvm_load_segment_descriptor(vcpu, tss->es, VCPU_SREG_ES))
-               return 1;
-
-       if (kvm_load_segment_descriptor(vcpu, tss->cs, VCPU_SREG_CS))
-               return 1;
-
-       if (kvm_load_segment_descriptor(vcpu, tss->ss, VCPU_SREG_SS))
-               return 1;
-
-       if (kvm_load_segment_descriptor(vcpu, tss->ds, VCPU_SREG_DS))
-               return 1;
-
-       if (kvm_load_segment_descriptor(vcpu, tss->fs, VCPU_SREG_FS))
-               return 1;
-
-       if (kvm_load_segment_descriptor(vcpu, tss->gs, VCPU_SREG_GS))
-               return 1;
-       return 0;
-}
-
-static void save_state_to_tss16(struct kvm_vcpu *vcpu,
-                               struct tss_segment_16 *tss)
-{
-       tss->ip = kvm_rip_read(vcpu);
-       tss->flag = kvm_get_rflags(vcpu);
-       tss->ax = kvm_register_read(vcpu, VCPU_REGS_RAX);
-       tss->cx = kvm_register_read(vcpu, VCPU_REGS_RCX);
-       tss->dx = kvm_register_read(vcpu, VCPU_REGS_RDX);
-       tss->bx = kvm_register_read(vcpu, VCPU_REGS_RBX);
-       tss->sp = kvm_register_read(vcpu, VCPU_REGS_RSP);
-       tss->bp = kvm_register_read(vcpu, VCPU_REGS_RBP);
-       tss->si = kvm_register_read(vcpu, VCPU_REGS_RSI);
-       tss->di = kvm_register_read(vcpu, VCPU_REGS_RDI);
-
-       tss->es = get_segment_selector(vcpu, VCPU_SREG_ES);
-       tss->cs = get_segment_selector(vcpu, VCPU_SREG_CS);
-       tss->ss = get_segment_selector(vcpu, VCPU_SREG_SS);
-       tss->ds = get_segment_selector(vcpu, VCPU_SREG_DS);
-       tss->ldt = get_segment_selector(vcpu, VCPU_SREG_LDTR);
-}
-
-static int load_state_from_tss16(struct kvm_vcpu *vcpu,
-                                struct tss_segment_16 *tss)
-{
-       kvm_rip_write(vcpu, tss->ip);
-       kvm_set_rflags(vcpu, tss->flag | 2);
-       kvm_register_write(vcpu, VCPU_REGS_RAX, tss->ax);
-       kvm_register_write(vcpu, VCPU_REGS_RCX, tss->cx);
-       kvm_register_write(vcpu, VCPU_REGS_RDX, tss->dx);
-       kvm_register_write(vcpu, VCPU_REGS_RBX, tss->bx);
-       kvm_register_write(vcpu, VCPU_REGS_RSP, tss->sp);
-       kvm_register_write(vcpu, VCPU_REGS_RBP, tss->bp);
-       kvm_register_write(vcpu, VCPU_REGS_RSI, tss->si);
-       kvm_register_write(vcpu, VCPU_REGS_RDI, tss->di);
-
-       /*
-        * SDM says that segment selectors are loaded before segment
-        * descriptors
-        */
-       kvm_load_segment_selector(vcpu, tss->ldt, VCPU_SREG_LDTR);
-       kvm_load_segment_selector(vcpu, tss->es, VCPU_SREG_ES);
-       kvm_load_segment_selector(vcpu, tss->cs, VCPU_SREG_CS);
-       kvm_load_segment_selector(vcpu, tss->ss, VCPU_SREG_SS);
-       kvm_load_segment_selector(vcpu, tss->ds, VCPU_SREG_DS);
-
-       /*
-        * Now load segment descriptors. If fault happenes at this stage
-        * it is handled in a context of new task
-        */
-       if (kvm_load_segment_descriptor(vcpu, tss->ldt, VCPU_SREG_LDTR))
-               return 1;
-
-       if (kvm_load_segment_descriptor(vcpu, tss->es, VCPU_SREG_ES))
-               return 1;
-
-       if (kvm_load_segment_descriptor(vcpu, tss->cs, VCPU_SREG_CS))
-               return 1;
-
-       if (kvm_load_segment_descriptor(vcpu, tss->ss, VCPU_SREG_SS))
-               return 1;
-
-       if (kvm_load_segment_descriptor(vcpu, tss->ds, VCPU_SREG_DS))
-               return 1;
-       return 0;
-}
-
-static int kvm_task_switch_16(struct kvm_vcpu *vcpu, u16 tss_selector,
-                             u16 old_tss_sel, u32 old_tss_base,
-                             struct desc_struct *nseg_desc)
-{
-       struct tss_segment_16 tss_segment_16;
-       int ret = 0;
-
-       if (kvm_read_guest(vcpu->kvm, old_tss_base, &tss_segment_16,
-                          sizeof tss_segment_16))
-               goto out;
-
-       save_state_to_tss16(vcpu, &tss_segment_16);
-
-       if (kvm_write_guest(vcpu->kvm, old_tss_base, &tss_segment_16,
-                           sizeof tss_segment_16))
-               goto out;
-
-       if (kvm_read_guest(vcpu->kvm, get_tss_base_addr_read(vcpu, nseg_desc),
-                          &tss_segment_16, sizeof tss_segment_16))
-               goto out;
-
-       if (old_tss_sel != 0xffff) {
-               tss_segment_16.prev_task_link = old_tss_sel;
-
-               if (kvm_write_guest(vcpu->kvm,
-                                   get_tss_base_addr_write(vcpu, nseg_desc),
-                                   &tss_segment_16.prev_task_link,
-                                   sizeof tss_segment_16.prev_task_link))
-                       goto out;
-       }
-
-       if (load_state_from_tss16(vcpu, &tss_segment_16))
-               goto out;
+               return EMULATE_FAIL;
 
-       ret = 1;
-out:
-       return ret;
-}
-
-static int kvm_task_switch_32(struct kvm_vcpu *vcpu, u16 tss_selector,
-                      u16 old_tss_sel, u32 old_tss_base,
-                      struct desc_struct *nseg_desc)
-{
-       struct tss_segment_32 tss_segment_32;
-       int ret = 0;
-
-       if (kvm_read_guest(vcpu->kvm, old_tss_base, &tss_segment_32,
-                          sizeof tss_segment_32))
-               goto out;
-
-       save_state_to_tss32(vcpu, &tss_segment_32);
-
-       if (kvm_write_guest(vcpu->kvm, old_tss_base, &tss_segment_32,
-                           sizeof tss_segment_32))
-               goto out;
-
-       if (kvm_read_guest(vcpu->kvm, get_tss_base_addr_read(vcpu, nseg_desc),
-                          &tss_segment_32, sizeof tss_segment_32))
-               goto out;
-
-       if (old_tss_sel != 0xffff) {
-               tss_segment_32.prev_task_link = old_tss_sel;
-
-               if (kvm_write_guest(vcpu->kvm,
-                                   get_tss_base_addr_write(vcpu, nseg_desc),
-                                   &tss_segment_32.prev_task_link,
-                                   sizeof tss_segment_32.prev_task_link))
-                       goto out;
-       }
-
-       if (load_state_from_tss32(vcpu, &tss_segment_32))
-               goto out;
-
-       ret = 1;
-out:
-       return ret;
-}
-
-int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason)
-{
-       struct kvm_segment tr_seg;
-       struct desc_struct cseg_desc;
-       struct desc_struct nseg_desc;
-       int ret = 0;
-       u32 old_tss_base = get_segment_base(vcpu, VCPU_SREG_TR);
-       u16 old_tss_sel = get_segment_selector(vcpu, VCPU_SREG_TR);
-       u32 desc_limit;
-
-       old_tss_base = kvm_mmu_gva_to_gpa_write(vcpu, old_tss_base, NULL);
-
-       /* FIXME: Handle errors. Failure to read either TSS or their
-        * descriptors should generate a pagefault.
-        */
-       if (load_guest_segment_descriptor(vcpu, tss_selector, &nseg_desc))
-               goto out;
-
-       if (load_guest_segment_descriptor(vcpu, old_tss_sel, &cseg_desc))
-               goto out;
-
-       if (reason != TASK_SWITCH_IRET) {
-               int cpl;
-
-               cpl = kvm_x86_ops->get_cpl(vcpu);
-               if ((tss_selector & 3) > nseg_desc.dpl || cpl > nseg_desc.dpl) {
-                       kvm_queue_exception_e(vcpu, GP_VECTOR, 0);
-                       return 1;
-               }
-       }
-
-       desc_limit = get_desc_limit(&nseg_desc);
-       if (!nseg_desc.p ||
-           ((desc_limit < 0x67 && (nseg_desc.type & 8)) ||
-            desc_limit < 0x2b)) {
-               kvm_queue_exception_e(vcpu, TS_VECTOR, tss_selector & 0xfffc);
-               return 1;
-       }
-
-       if (reason == TASK_SWITCH_IRET || reason == TASK_SWITCH_JMP) {
-               cseg_desc.type &= ~(1 << 1); //clear the B flag
-               save_guest_segment_descriptor(vcpu, old_tss_sel, &cseg_desc);
-       }
-
-       if (reason == TASK_SWITCH_IRET) {
-               u32 eflags = kvm_get_rflags(vcpu);
-               kvm_set_rflags(vcpu, eflags & ~X86_EFLAGS_NT);
-       }
-
-       /* set back link to prev task only if NT bit is set in eflags
-          note that old_tss_sel is not used afetr this point */
-       if (reason != TASK_SWITCH_CALL && reason != TASK_SWITCH_GATE)
-               old_tss_sel = 0xffff;
-
-       if (nseg_desc.type & 8)
-               ret = kvm_task_switch_32(vcpu, tss_selector, old_tss_sel,
-                                        old_tss_base, &nseg_desc);
-       else
-               ret = kvm_task_switch_16(vcpu, tss_selector, old_tss_sel,
-                                        old_tss_base, &nseg_desc);
-
-       if (reason == TASK_SWITCH_CALL || reason == TASK_SWITCH_GATE) {
-               u32 eflags = kvm_get_rflags(vcpu);
-               kvm_set_rflags(vcpu, eflags | X86_EFLAGS_NT);
-       }
-
-       if (reason != TASK_SWITCH_IRET) {
-               nseg_desc.type |= (1 << 1);
-               save_guest_segment_descriptor(vcpu, tss_selector,
-                                             &nseg_desc);
-       }
-
-       kvm_x86_ops->set_cr0(vcpu, kvm_read_cr0(vcpu) | X86_CR0_TS);
-       seg_desct_to_kvm_desct(&nseg_desc, tss_selector, &tr_seg);
-       tr_seg.type = 11;
-       kvm_set_segment(vcpu, &tr_seg, VCPU_SREG_TR);
-out:
-       return ret;
+       kvm_x86_ops->set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags);
+       return EMULATE_DONE;
 }
 EXPORT_SYMBOL_GPL(kvm_task_switch);
 
@@ -5258,15 +4933,15 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
 {
        int mmu_reset_needed = 0;
        int pending_vec, max_bits;
-       struct descriptor_table dt;
+       struct desc_ptr dt;
 
        vcpu_load(vcpu);
 
-       dt.limit = sregs->idt.limit;
-       dt.base = sregs->idt.base;
+       dt.size = sregs->idt.limit;
+       dt.address = sregs->idt.base;
        kvm_x86_ops->set_idt(vcpu, &dt);
-       dt.limit = sregs->gdt.limit;
-       dt.base = sregs->gdt.base;
+       dt.size = sregs->gdt.limit;
+       dt.address = sregs->gdt.base;
        kvm_x86_ops->set_gdt(vcpu, &dt);
 
        vcpu->arch.cr2 = sregs->cr2;
@@ -5365,11 +5040,9 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
                vcpu->arch.switch_db_regs = (vcpu->arch.dr7 & DR7_BP_EN_MASK);
        }
 
-       if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
-               vcpu->arch.singlestep_cs =
-                       get_segment_selector(vcpu, VCPU_SREG_CS);
-               vcpu->arch.singlestep_rip = kvm_rip_read(vcpu);
-       }
+       if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
+               vcpu->arch.singlestep_rip = kvm_rip_read(vcpu) +
+                       get_segment_base(vcpu, VCPU_SREG_CS);
 
        /*
         * Trigger an rflags update that will inject or remove the trace
@@ -5860,13 +5533,22 @@ int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu)
        return kvm_x86_ops->interrupt_allowed(vcpu);
 }
 
+bool kvm_is_linear_rip(struct kvm_vcpu *vcpu, unsigned long linear_rip)
+{
+       unsigned long current_rip = kvm_rip_read(vcpu) +
+               get_segment_base(vcpu, VCPU_SREG_CS);
+
+       return current_rip == linear_rip;
+}
+EXPORT_SYMBOL_GPL(kvm_is_linear_rip);
+
 unsigned long kvm_get_rflags(struct kvm_vcpu *vcpu)
 {
        unsigned long rflags;
 
        rflags = kvm_x86_ops->get_rflags(vcpu);
        if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
-               rflags &= ~(unsigned long)(X86_EFLAGS_TF | X86_EFLAGS_RF);
+               rflags &= ~X86_EFLAGS_TF;
        return rflags;
 }
 EXPORT_SYMBOL_GPL(kvm_get_rflags);
@@ -5874,10 +5556,8 @@ EXPORT_SYMBOL_GPL(kvm_get_rflags);
 void kvm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
 {
        if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP &&
-           vcpu->arch.singlestep_cs ==
-                       get_segment_selector(vcpu, VCPU_SREG_CS) &&
-           vcpu->arch.singlestep_rip == kvm_rip_read(vcpu))
-               rflags |= X86_EFLAGS_TF | X86_EFLAGS_RF;
+           kvm_is_linear_rip(vcpu, vcpu->arch.singlestep_rip))
+               rflags |= X86_EFLAGS_TF;
        kvm_x86_ops->set_rflags(vcpu, rflags);
 }
 EXPORT_SYMBOL_GPL(kvm_set_rflags);
@@ -5893,3 +5573,4 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_nested_vmexit_inject);
 EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_nested_intr_vmexit);
 EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_invlpga);
 EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_skinit);
+EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_nested_intercepts);
index b7a404722d2b791efa2a9ae12d636ec2e5fd0a83..f4b54458285b0d122e7bb9b0868042924bdf323f 100644 (file)
@@ -65,6 +65,13 @@ static inline int is_paging(struct kvm_vcpu *vcpu)
        return kvm_read_cr0_bits(vcpu, X86_CR0_PG);
 }
 
+static inline struct kvm_mem_aliases *kvm_aliases(struct kvm *kvm)
+{
+       return rcu_dereference_check(kvm->arch.aliases,
+                       srcu_read_lock_held(&kvm->srcu)
+                       || lockdep_is_held(&kvm->slots_lock));
+}
+
 void kvm_before_handle_nmi(struct kvm_vcpu *vcpu);
 void kvm_after_handle_nmi(struct kvm_vcpu *vcpu);
 
index 2bdf628066bd85288bf8143d50175d4f7ea6b398..9257510b4836837eb4cdff719000b716ff3bdd63 100644 (file)
@@ -1390,7 +1390,6 @@ __init void lguest_init(void)
 #endif
 #ifdef CONFIG_ACPI
        acpi_disabled = 1;
-       acpi_ht = 0;
 #endif
 
        /*
index 8948f47fde056f9e723640c7791732fe4e68ae63..a7bcc23ef96c989f5fef986cbd7816dfd551d20e 100644 (file)
@@ -33,9 +33,6 @@ int numa_off __initdata;
 static unsigned long __initdata nodemap_addr;
 static unsigned long __initdata nodemap_size;
 
-DEFINE_PER_CPU(int, node_number) = 0;
-EXPORT_PER_CPU_SYMBOL(node_number);
-
 /*
  * Map cpu index to node index
  */
@@ -809,7 +806,7 @@ void __cpuinit numa_set_node(int cpu, int node)
        per_cpu(x86_cpu_to_node_map, cpu) = node;
 
        if (node != NUMA_NO_NODE)
-               per_cpu(node_number, cpu) = node;
+               set_cpu_numa_node(cpu, node);
 }
 
 void __cpuinit numa_clear_node(int cpu)
@@ -867,7 +864,7 @@ void __cpuinit numa_remove_cpu(int cpu)
        numa_set_cpumask(cpu, 0);
 }
 
-int cpu_to_node(int cpu)
+int __cpu_to_node(int cpu)
 {
        if (early_per_cpu_ptr(x86_cpu_to_node_map)) {
                printk(KERN_WARNING
@@ -877,7 +874,7 @@ int cpu_to_node(int cpu)
        }
        return per_cpu(x86_cpu_to_node_map, cpu);
 }
-EXPORT_SYMBOL(cpu_to_node);
+EXPORT_SYMBOL(__cpu_to_node);
 
 /*
  * Same function as cpu_to_node() but used if called before the
index bbe5502ee1cbdaa7eaf5d9de15454b143b67b626..acc15b23b74342df6188d0fd0e7b356e1530e8bb 100644 (file)
@@ -336,6 +336,7 @@ int free_memtype(u64 start, u64 end)
 {
        int err = -EINVAL;
        int is_range_ram;
+       struct memtype *entry;
 
        if (!pat_enabled)
                return 0;
@@ -355,17 +356,20 @@ int free_memtype(u64 start, u64 end)
        }
 
        spin_lock(&memtype_lock);
-       err = rbt_memtype_erase(start, end);
+       entry = rbt_memtype_erase(start, end);
        spin_unlock(&memtype_lock);
 
-       if (err) {
+       if (!entry) {
                printk(KERN_INFO "%s:%d freeing invalid memtype %Lx-%Lx\n",
                        current->comm, current->pid, start, end);
+               return -EINVAL;
        }
 
+       kfree(entry);
+
        dprintk("free_memtype request 0x%Lx-0x%Lx\n", start, end);
 
-       return err;
+       return 0;
 }
 
 
index 4f39eefa3e619d7c089cc9786628ef7c0c6f8093..77e5ba153fac7bda64bb18f6ccb00324363ebdd6 100644 (file)
@@ -28,15 +28,15 @@ static inline char *cattr_name(unsigned long flags)
 #ifdef CONFIG_X86_PAT
 extern int rbt_memtype_check_insert(struct memtype *new,
                                        unsigned long *new_type);
-extern int rbt_memtype_erase(u64 start, u64 end);
+extern struct memtype *rbt_memtype_erase(u64 start, u64 end);
 extern struct memtype *rbt_memtype_lookup(u64 addr);
 extern int rbt_memtype_copy_nth_element(struct memtype *out, loff_t pos);
 #else
 static inline int rbt_memtype_check_insert(struct memtype *new,
                                        unsigned long *new_type)
 { return 0; }
-static inline int rbt_memtype_erase(u64 start, u64 end)
-{ return 0; }
+static inline struct memtype *rbt_memtype_erase(u64 start, u64 end)
+{ return NULL; }
 static inline struct memtype *rbt_memtype_lookup(u64 addr)
 { return NULL; }
 static inline int rbt_memtype_copy_nth_element(struct memtype *out, loff_t pos)
index 07de4cb8cc30d1360c5ec4e799cc2d7dda65f6a5..f537087bb740933d5d412c619bb3d5107b53c3b0 100644 (file)
@@ -231,16 +231,17 @@ int rbt_memtype_check_insert(struct memtype *new, unsigned long *ret_type)
        return err;
 }
 
-int rbt_memtype_erase(u64 start, u64 end)
+struct memtype *rbt_memtype_erase(u64 start, u64 end)
 {
        struct memtype *data;
 
        data = memtype_rb_exact_match(&memtype_rbroot, start, end);
        if (!data)
-               return -EINVAL;
+               goto out;
 
        rb_erase(&data->rb, &memtype_rbroot);
-       return 0;
+out:
+       return data;
 }
 
 struct memtype *rbt_memtype_lookup(u64 addr)
index df3d5c861cdad6e36680613b4db8df5776e6c094..308e32570d846f3eeb339bc662de5b2c50c3cb0e 100644 (file)
@@ -34,7 +34,7 @@
 /* IA32 Manual 3, 2-1 */
 static unsigned char prefix_codes[] = {
        0xF0, 0xF2, 0xF3, 0x2E, 0x36, 0x3E, 0x26, 0x64,
-       0x65, 0x2E, 0x3E, 0x66, 0x67
+       0x65, 0x66, 0x67
 };
 /* IA32 Manual 3, 3-432*/
 static unsigned int reg_rop[] = {
index 792854003ed339c742dbbeabaeff2f90e0f44a31..cac7184992567b3c178c41daf7733c6cea69fa3d 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/pagemap.h>
 #include <linux/spinlock.h>
 #include <linux/module.h>
-#include <linux/quicklist.h>
 
 #include <asm/system.h>
 #include <asm/pgtable.h>
index b110d97fb9254b564d46b423ab2378bc547a197d..a0207a7fdf394b28fafc2db730c71e86c992d536 100644 (file)
@@ -18,6 +18,8 @@ obj-$(CONFIG_X86_MRST)                += mrst.o
 obj-y                          += common.o early.o
 obj-y                          += amd_bus.o bus_numa.o
 
+obj-$(CONFIG_PCI_CNB20LE_QUIRK)        += broadcom_bus.o
+
 ifeq ($(CONFIG_PCI_DEBUG),y)
 EXTRA_CFLAGS += -DDEBUG
 endif
index 31930fd30ea95a36232c2ed7df0a6a1f97147b1f..2ec04c424a6229f7d830e78fb49f5532b804d212 100644 (file)
@@ -207,10 +207,9 @@ get_current_resources(struct acpi_device *device, int busnum,
        if (!info.res)
                goto res_alloc_fail;
 
-       info.name = kmalloc(16, GFP_KERNEL);
+       info.name = kasprintf(GFP_KERNEL, "PCI Bus %04x:%02x", domain, busnum);
        if (!info.name)
                goto name_alloc_fail;
-       sprintf(info.name, "PCI Bus %04x:%02x", domain, busnum);
 
        info.res_num = 0;
        acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource,
@@ -224,8 +223,11 @@ res_alloc_fail:
        return;
 }
 
-struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int domain, int busnum)
+struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
 {
+       struct acpi_device *device = root->device;
+       int domain = root->segment;
+       int busnum = root->secondary.start;
        struct pci_bus *bus;
        struct pci_sysdata *sd;
        int node;
diff --git a/arch/x86/pci/broadcom_bus.c b/arch/x86/pci/broadcom_bus.c
new file mode 100644 (file)
index 0000000..0846a5b
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Read address ranges from a Broadcom CNB20LE Host Bridge
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/dmi.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <asm/pci_x86.h>
+
+#include "bus_numa.h"
+
+static void __devinit cnb20le_res(struct pci_dev *dev)
+{
+       struct pci_root_info *info;
+       struct resource res;
+       u16 word1, word2;
+       u8 fbus, lbus;
+       int i;
+
+       /*
+        * The x86_pci_root_bus_res_quirks() function already refuses to use
+        * this information if ACPI _CRS was used. Therefore, we don't bother
+        * checking if ACPI is enabled, and just generate the information
+        * for both the ACPI _CRS and no ACPI cases.
+        */
+
+       info = &pci_root_info[pci_root_num];
+       pci_root_num++;
+
+       /* read the PCI bus numbers */
+       pci_read_config_byte(dev, 0x44, &fbus);
+       pci_read_config_byte(dev, 0x45, &lbus);
+       info->bus_min = fbus;
+       info->bus_max = lbus;
+
+       /*
+        * Add the legacy IDE ports on bus 0
+        *
+        * These do not exist anywhere in the bridge registers, AFAICT. I do
+        * not have the datasheet, so this is the best I can do.
+        */
+       if (fbus == 0) {
+               update_res(info, 0x01f0, 0x01f7, IORESOURCE_IO, 0);
+               update_res(info, 0x03f6, 0x03f6, IORESOURCE_IO, 0);
+               update_res(info, 0x0170, 0x0177, IORESOURCE_IO, 0);
+               update_res(info, 0x0376, 0x0376, IORESOURCE_IO, 0);
+               update_res(info, 0xffa0, 0xffaf, IORESOURCE_IO, 0);
+       }
+
+       /* read the non-prefetchable memory window */
+       pci_read_config_word(dev, 0xc0, &word1);
+       pci_read_config_word(dev, 0xc2, &word2);
+       if (word1 != word2) {
+               res.start = (word1 << 16) | 0x0000;
+               res.end   = (word2 << 16) | 0xffff;
+               res.flags = IORESOURCE_MEM;
+               update_res(info, res.start, res.end, res.flags, 0);
+       }
+
+       /* read the prefetchable memory window */
+       pci_read_config_word(dev, 0xc4, &word1);
+       pci_read_config_word(dev, 0xc6, &word2);
+       if (word1 != word2) {
+               res.start = (word1 << 16) | 0x0000;
+               res.end   = (word2 << 16) | 0xffff;
+               res.flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
+               update_res(info, res.start, res.end, res.flags, 0);
+       }
+
+       /* read the IO port window */
+       pci_read_config_word(dev, 0xd0, &word1);
+       pci_read_config_word(dev, 0xd2, &word2);
+       if (word1 != word2) {
+               res.start = word1;
+               res.end   = word2;
+               res.flags = IORESOURCE_IO;
+               update_res(info, res.start, res.end, res.flags, 0);
+       }
+
+       /* print information about this host bridge */
+       res.start = fbus;
+       res.end   = lbus;
+       res.flags = IORESOURCE_BUS;
+       dev_info(&dev->dev, "CNB20LE PCI Host Bridge (domain %04x %pR)\n",
+                           pci_domain_nr(dev->bus), &res);
+
+       for (i = 0; i < info->res_num; i++)
+               dev_info(&dev->dev, "host bridge window %pR\n", &info->res[i]);
+}
+
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_LE,
+                       cnb20le_res);
+
index cf2e93869c489ee14b8e074817a62a55dacf3845..215a27ae050d430c0deac4a29f75c08449249c96 100644 (file)
@@ -76,7 +76,7 @@ struct pci_ops pci_root_ops = {
  * This interrupt-safe spinlock protects all accesses to PCI
  * configuration space.
  */
-DEFINE_SPINLOCK(pci_config_lock);
+DEFINE_RAW_SPINLOCK(pci_config_lock);
 
 static int __devinit can_skip_ioresource_align(const struct dmi_system_id *d)
 {
index 347d882b3bb3e094feb0dd04102e4bcf2fa1a44a..bd33620b00716e5df20523d7a853841124d12092 100644 (file)
@@ -27,7 +27,7 @@ static int pci_conf1_read(unsigned int seg, unsigned int bus,
                return -EINVAL;
        }
 
-       spin_lock_irqsave(&pci_config_lock, flags);
+       raw_spin_lock_irqsave(&pci_config_lock, flags);
 
        outl(PCI_CONF1_ADDRESS(bus, devfn, reg), 0xCF8);
 
@@ -43,7 +43,7 @@ static int pci_conf1_read(unsigned int seg, unsigned int bus,
                break;
        }
 
-       spin_unlock_irqrestore(&pci_config_lock, flags);
+       raw_spin_unlock_irqrestore(&pci_config_lock, flags);
 
        return 0;
 }
@@ -56,7 +56,7 @@ static int pci_conf1_write(unsigned int seg, unsigned int bus,
        if ((bus > 255) || (devfn > 255) || (reg > 4095))
                return -EINVAL;
 
-       spin_lock_irqsave(&pci_config_lock, flags);
+       raw_spin_lock_irqsave(&pci_config_lock, flags);
 
        outl(PCI_CONF1_ADDRESS(bus, devfn, reg), 0xCF8);
 
@@ -72,7 +72,7 @@ static int pci_conf1_write(unsigned int seg, unsigned int bus,
                break;
        }
 
-       spin_unlock_irqrestore(&pci_config_lock, flags);
+       raw_spin_unlock_irqrestore(&pci_config_lock, flags);
 
        return 0;
 }
@@ -108,7 +108,7 @@ static int pci_conf2_read(unsigned int seg, unsigned int bus,
        if (dev & 0x10) 
                return PCIBIOS_DEVICE_NOT_FOUND;
 
-       spin_lock_irqsave(&pci_config_lock, flags);
+       raw_spin_lock_irqsave(&pci_config_lock, flags);
 
        outb((u8)(0xF0 | (fn << 1)), 0xCF8);
        outb((u8)bus, 0xCFA);
@@ -127,7 +127,7 @@ static int pci_conf2_read(unsigned int seg, unsigned int bus,
 
        outb(0, 0xCF8);
 
-       spin_unlock_irqrestore(&pci_config_lock, flags);
+       raw_spin_unlock_irqrestore(&pci_config_lock, flags);
 
        return 0;
 }
@@ -147,7 +147,7 @@ static int pci_conf2_write(unsigned int seg, unsigned int bus,
        if (dev & 0x10) 
                return PCIBIOS_DEVICE_NOT_FOUND;
 
-       spin_lock_irqsave(&pci_config_lock, flags);
+       raw_spin_lock_irqsave(&pci_config_lock, flags);
 
        outb((u8)(0xF0 | (fn << 1)), 0xCF8);
        outb((u8)bus, 0xCFA);
@@ -166,7 +166,7 @@ static int pci_conf2_write(unsigned int seg, unsigned int bus,
 
        outb(0, 0xCF8);    
 
-       spin_unlock_irqrestore(&pci_config_lock, flags);
+       raw_spin_unlock_irqrestore(&pci_config_lock, flags);
 
        return 0;
 }
index 5d362b5ba06f35146d40cd161b6b19ade0ff84e6..9810a0f76c91ccd58491e36051678fcf6dd40ad3 100644 (file)
@@ -589,8 +589,6 @@ static __init int intel_router_probe(struct irq_router *r, struct pci_dev *route
        case PCI_DEVICE_ID_INTEL_ICH10_1:
        case PCI_DEVICE_ID_INTEL_ICH10_2:
        case PCI_DEVICE_ID_INTEL_ICH10_3:
-       case PCI_DEVICE_ID_INTEL_CPT_LPC1:
-       case PCI_DEVICE_ID_INTEL_CPT_LPC2:
                r->name = "PIIX/ICH";
                r->get = pirq_piix_get;
                r->set = pirq_piix_set;
@@ -605,6 +603,13 @@ static __init int intel_router_probe(struct irq_router *r, struct pci_dev *route
                return 1;
        }
 
+       if ((device >= PCI_DEVICE_ID_INTEL_CPT_LPC_MIN) && 
+               (device <= PCI_DEVICE_ID_INTEL_CPT_LPC_MAX)) {
+               r->name = "PIIX/ICH";
+               r->get = pirq_piix_get;
+               r->set = pirq_piix_set;
+               return 1;
+       }
        return 0;
 }
 
index 39b9ebe8f8863d598345991c90942b5aed70ae21..a918553ebc759d6b7f43dc220d04f893adf60875 100644 (file)
@@ -483,16 +483,17 @@ static void __init pci_mmcfg_reject_broken(int early)
        list_for_each_entry(cfg, &pci_mmcfg_list, list) {
                int valid = 0;
 
-               if (!early && !acpi_disabled)
+               if (!early && !acpi_disabled) {
                        valid = is_mmconf_reserved(is_acpi_reserved, cfg, 0);
 
-               if (valid)
-                       continue;
-
-               if (!early)
-                       printk(KERN_ERR FW_BUG PREFIX
-                              "MMCONFIG at %pR not reserved in "
-                              "ACPI motherboard resources\n", &cfg->res);
+                       if (valid)
+                               continue;
+                       else
+                               printk(KERN_ERR FW_BUG PREFIX
+                                      "MMCONFIG at %pR not reserved in "
+                                      "ACPI motherboard resources\n",
+                                      &cfg->res);
+               }
 
                /* Don't try to do this check unless configuration
                   type 1 is available. how about type 2 ?*/
index 90d5fd476ed4fe3a093b514f095ca3d237023f54..a3d9c54792aef245843eef8da9a7025d7179cd85 100644 (file)
@@ -64,7 +64,7 @@ err:          *value = -1;
        if (!base)
                goto err;
 
-       spin_lock_irqsave(&pci_config_lock, flags);
+       raw_spin_lock_irqsave(&pci_config_lock, flags);
 
        pci_exp_set_dev_base(base, bus, devfn);
 
@@ -79,7 +79,7 @@ err:          *value = -1;
                *value = mmio_config_readl(mmcfg_virt_addr + reg);
                break;
        }
-       spin_unlock_irqrestore(&pci_config_lock, flags);
+       raw_spin_unlock_irqrestore(&pci_config_lock, flags);
 
        return 0;
 }
@@ -97,7 +97,7 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
        if (!base)
                return -EINVAL;
 
-       spin_lock_irqsave(&pci_config_lock, flags);
+       raw_spin_lock_irqsave(&pci_config_lock, flags);
 
        pci_exp_set_dev_base(base, bus, devfn);
 
@@ -112,7 +112,7 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
                mmio_config_writel(mmcfg_virt_addr + reg, value);
                break;
        }
-       spin_unlock_irqrestore(&pci_config_lock, flags);
+       raw_spin_unlock_irqrestore(&pci_config_lock, flags);
 
        return 0;
 }
index 8223738ad806a29db68ec20e4d45530852fa4bfd..5c9e2458df4e1cf28bb500e1256b4f3aa1e399e2 100644 (file)
@@ -37,7 +37,7 @@ static int pci_conf1_mq_read(unsigned int seg, unsigned int bus,
        if (!value || (bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255))
                return -EINVAL;
 
-       spin_lock_irqsave(&pci_config_lock, flags);
+       raw_spin_lock_irqsave(&pci_config_lock, flags);
 
        write_cf8(bus, devfn, reg);
 
@@ -62,7 +62,7 @@ static int pci_conf1_mq_read(unsigned int seg, unsigned int bus,
                break;
        }
 
-       spin_unlock_irqrestore(&pci_config_lock, flags);
+       raw_spin_unlock_irqrestore(&pci_config_lock, flags);
 
        return 0;
 }
@@ -76,7 +76,7 @@ static int pci_conf1_mq_write(unsigned int seg, unsigned int bus,
        if ((bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255)) 
                return -EINVAL;
 
-       spin_lock_irqsave(&pci_config_lock, flags);
+       raw_spin_lock_irqsave(&pci_config_lock, flags);
 
        write_cf8(bus, devfn, reg);
 
@@ -101,7 +101,7 @@ static int pci_conf1_mq_write(unsigned int seg, unsigned int bus,
                break;
        }
 
-       spin_unlock_irqrestore(&pci_config_lock, flags);
+       raw_spin_unlock_irqrestore(&pci_config_lock, flags);
 
        return 0;
 }
index 59a225c17b84264f07bb07ca4db54b8962fce9c4..2492d165096a2a696cf8332534966cfce2c848a7 100644 (file)
@@ -162,7 +162,7 @@ static int pci_bios_read(unsigned int seg, unsigned int bus,
        if (!value || (bus > 255) || (devfn > 255) || (reg > 255))
                return -EINVAL;
 
-       spin_lock_irqsave(&pci_config_lock, flags);
+       raw_spin_lock_irqsave(&pci_config_lock, flags);
 
        switch (len) {
        case 1:
@@ -213,7 +213,7 @@ static int pci_bios_read(unsigned int seg, unsigned int bus,
                break;
        }
 
-       spin_unlock_irqrestore(&pci_config_lock, flags);
+       raw_spin_unlock_irqrestore(&pci_config_lock, flags);
 
        return (int)((result & 0xff00) >> 8);
 }
@@ -228,7 +228,7 @@ static int pci_bios_write(unsigned int seg, unsigned int bus,
        if ((bus > 255) || (devfn > 255) || (reg > 255)) 
                return -EINVAL;
 
-       spin_lock_irqsave(&pci_config_lock, flags);
+       raw_spin_lock_irqsave(&pci_config_lock, flags);
 
        switch (len) {
        case 1:
@@ -269,7 +269,7 @@ static int pci_bios_write(unsigned int seg, unsigned int bus,
                break;
        }
 
-       spin_unlock_irqrestore(&pci_config_lock, flags);
+       raw_spin_unlock_irqrestore(&pci_config_lock, flags);
 
        return (int)((result & 0xff00) >> 8);
 }
index f04c9891142fa7a5090d966ac4779b0af419ebca..ed8cd3cbd4993de9619f1e6db12af3c26b166c9b 100644 (file)
@@ -29,5 +29,6 @@
 # define CACHE_WAY_SIZE ICACHE_WAY_SIZE
 #endif
 
+#define ARCH_KMALLOC_MINALIGN  L1_CACHE_BYTES
 
 #endif /* _XTENSA_CACHE_H */
index 87cb19d1b10c4a780844c39ccfb9649d9b1be8c8..26664cef8f11dc990383fb62d7a5f8f6e4d1aac1 100644 (file)
 #ifndef _XTENSA_HARDIRQ_H
 #define _XTENSA_HARDIRQ_H
 
-#include <linux/cache.h>
-#include <asm/irq.h>
-
-/* headers.S is sensitive to the offsets of these fields */
-typedef struct {
-       unsigned int __softirq_pending;
-       unsigned int __syscall_count;
-       struct task_struct * __ksoftirqd_task; /* waitqueue is too large */
-       unsigned int __nmi_count;              /* arch dependent */
-} ____cacheline_aligned irq_cpustat_t;
-
 void ack_bad_irq(unsigned int irq);
-#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
+#define ack_bad_irq ack_bad_irq
+
+#include <asm-generic/hardirq.h>
 
 #endif /* _XTENSA_HARDIRQ_H */
index 810080bb0a2b2cfa498c39fed32c11d2897763bd..b1f9fdc1d5ba98b90076965a4c50915f99829d6f 100644 (file)
 #ifndef _XTENSA_SCATTERLIST_H
 #define _XTENSA_SCATTERLIST_H
 
-#include <asm/types.h>
-
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-       unsigned long   sg_magic;
-#endif
-       unsigned long   page_link;
-       unsigned int    offset;
-       dma_addr_t      dma_address;
-       unsigned int    length;
-};
-
-/*
- * These macros should be used after a pci_map_sg call has been done
- * to get bus addresses of each of the SG entries and their lengths.
- * You should only work with the number of sg entries pci_map_sg
- * returns, or alternatively stop on the first sg_dma_len(sg) which
- * is 0.
- */
-#define sg_dma_address(sg)      ((sg)->dma_address)
-#define sg_dma_len(sg)          ((sg)->length)
-
+#include <asm-generic/scatterlist.h>
 
 #define ISA_DMA_THRESHOLD (~0UL)
 
index 8cd38484e1306ab8e12aeeb1185813960f0a8869..c64a5d387de51d9e0e4c2225a8ae348c05b331e8 100644 (file)
@@ -26,15 +26,6 @@ static unsigned int cached_irq_mask;
 
 atomic_t irq_err_count;
 
-/*
- * 'what should we do if we get a hw irq event on an illegal vector'.
- * each architecture has to answer this themselves.
- */
-void ack_bad_irq(unsigned int irq)
-{
-          printk("unexpected IRQ trap at vector %02x\n", irq);
-}
-
 /*
  * do_IRQ handles all normal device IRQ's (the special
  * SMP cross-CPU interrupts have their own specific
index 74a7518faf16caebb713c2ede9210d4939d79722..70066e3582d0b878f427832f56d5f983fc5e11bb 100644 (file)
 
 #include <linux/linkage.h>
 #include <asm/ptrace.h>
-#include <asm/ptrace.h>
 #include <asm/current.h>
 #include <asm/asm-offsets.h>
 #include <asm/pgtable.h>
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/thread_info.h>
-#include <asm/processor.h>
 
 #define WINDOW_VECTORS_SIZE   0x180
 
index f42a03029b7c01d58193ee4b4b63d2660852a46c..91874e048552364280d7905aa817e957be2f9c48 100644 (file)
@@ -10,6 +10,7 @@ obj-$(CONFIG_PCI)             += pci/
 obj-$(CONFIG_PARISC)           += parisc/
 obj-$(CONFIG_RAPIDIO)          += rapidio/
 obj-y                          += video/
+obj-y                          += idle/
 obj-$(CONFIG_ACPI)             += acpi/
 obj-$(CONFIG_SFI)              += sfi/
 # PnP must come after ACPI since it will eventually need to check if acpi
@@ -91,7 +92,6 @@ obj-$(CONFIG_EISA)            += eisa/
 obj-y                          += lguest/
 obj-$(CONFIG_CPU_FREQ)         += cpufreq/
 obj-$(CONFIG_CPU_IDLE)         += cpuidle/
-obj-y                          += idle/
 obj-$(CONFIG_MMC)              += mmc/
 obj-$(CONFIG_MEMSTICK)         += memstick/
 obj-$(CONFIG_NEW_LEDS)         += leds/
index 93d2c7971df626d6fb2db453b700c2b16a95a199..746411518802a369cb244878caa993b0293331e0 100644 (file)
@@ -360,4 +360,13 @@ config ACPI_SBS
          To compile this driver as a module, choose M here:
          the modules will be called sbs and sbshc.
 
+config ACPI_HED
+       tristate "Hardware Error Device"
+       help
+         This driver supports the Hardware Error Device (PNP0C33),
+         which is used to report some hardware errors notified via
+         SCI, mainly the corrected errors.
+
+source "drivers/acpi/apei/Kconfig"
+
 endif  # ACPI
index a8d8998dd5c5bbdf9faa25c289a627de38d9198a..6ee33169e1dc59e2f48efeab0a3094a788f19e4c 100644 (file)
@@ -19,7 +19,7 @@ obj-y                         += acpi.o \
 
 # All the builtin files are in the "acpi." module_param namespace.
 acpi-y                         += osl.o utils.o reboot.o
-acpi-y                         += hest.o
+acpi-y                         += atomicio.o
 
 # sleep related files
 acpi-y                         += wakeup.o
@@ -59,6 +59,7 @@ obj-$(CONFIG_ACPI_BATTERY)    += battery.o
 obj-$(CONFIG_ACPI_SBS)         += sbshc.o
 obj-$(CONFIG_ACPI_SBS)         += sbs.o
 obj-$(CONFIG_ACPI_POWER_METER) += power_meter.o
+obj-$(CONFIG_ACPI_HED)         += hed.o
 
 # processor has its own "processor." module_param namespace
 processor-y                    := processor_driver.o processor_throttling.o
@@ -66,3 +67,5 @@ processor-y                   += processor_idle.o processor_thermal.o
 processor-$(CONFIG_CPU_FREQ)   += processor_perflib.o
 
 obj-$(CONFIG_ACPI_PROCESSOR_AGGREGATOR) += acpi_pad.o
+
+obj-$(CONFIG_ACPI_APEI)                += apei/
index 62122134693b808f866e9b0cea0b7349bb1ac5a0..d269a8f3329cc0cbe9b5bcc8120c6a5b1c5320b7 100644 (file)
@@ -43,6 +43,10 @@ static DEFINE_MUTEX(isolated_cpus_lock);
 #define CPUID5_ECX_EXTENSIONS_SUPPORTED (0x1)
 #define CPUID5_ECX_INTERRUPT_BREAK     (0x2)
 static unsigned long power_saving_mwait_eax;
+
+static unsigned char tsc_detected_unstable;
+static unsigned char tsc_marked_unstable;
+
 static void power_saving_mwait_init(void)
 {
        unsigned int eax, ebx, ecx, edx;
@@ -87,8 +91,8 @@ static void power_saving_mwait_init(void)
 
                /*FALL THROUGH*/
        default:
-               /* TSC could halt in idle, so notify users */
-               mark_tsc_unstable("TSC halts in idle");
+               /* TSC could halt in idle */
+               tsc_detected_unstable = 1;
        }
 #endif
 }
@@ -168,16 +172,14 @@ static int power_saving_thread(void *data)
 
                do_sleep = 0;
 
-               current_thread_info()->status &= ~TS_POLLING;
-               /*
-                * TS_POLLING-cleared state must be visible before we test
-                * NEED_RESCHED:
-                */
-               smp_mb();
-
                expire_time = jiffies + HZ * (100 - idle_pct) / 100;
 
                while (!need_resched()) {
+                       if (tsc_detected_unstable && !tsc_marked_unstable) {
+                               /* TSC could halt in idle, so notify users */
+                               mark_tsc_unstable("TSC halts in idle");
+                               tsc_marked_unstable = 1;
+                       }
                        local_irq_disable();
                        cpu = smp_processor_id();
                        clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER,
@@ -200,8 +202,6 @@ static int power_saving_thread(void *data)
                        }
                }
 
-               current_thread_info()->status |= TS_POLLING;
-
                /*
                 * current sched_rt has threshold for rt task running time.
                 * When a rt task uses 95% CPU time, the rt thread will be
index 7c7bbb4d402ca31a7dcbfe766e5ed2a0eb0e47b3..d5a5efc043bf7a43ac446c815370576deaa5b096 100644 (file)
@@ -69,7 +69,7 @@ acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
 
 acpi_status acpi_enable(void)
 {
-       acpi_status status = AE_OK;
+       acpi_status status;
 
        ACPI_FUNCTION_TRACE(acpi_enable);
 
@@ -84,21 +84,30 @@ acpi_status acpi_enable(void)
        if (acpi_hw_get_mode() == ACPI_SYS_MODE_ACPI) {
                ACPI_DEBUG_PRINT((ACPI_DB_INIT,
                                  "System is already in ACPI mode\n"));
-       } else {
-               /* Transition to ACPI mode */
+               return_ACPI_STATUS(AE_OK);
+       }
 
-               status = acpi_hw_set_mode(ACPI_SYS_MODE_ACPI);
-               if (ACPI_FAILURE(status)) {
-                       ACPI_ERROR((AE_INFO,
-                                   "Could not transition to ACPI mode"));
-                       return_ACPI_STATUS(status);
-               }
+       /* Transition to ACPI mode */
 
-               ACPI_DEBUG_PRINT((ACPI_DB_INIT,
-                                 "Transition to ACPI mode successful\n"));
+       status = acpi_hw_set_mode(ACPI_SYS_MODE_ACPI);
+       if (ACPI_FAILURE(status)) {
+               ACPI_ERROR((AE_INFO,
+                           "Could not transition to ACPI mode"));
+               return_ACPI_STATUS(status);
        }
 
-       return_ACPI_STATUS(status);
+       /* Sanity check that transition succeeded */
+
+       if (acpi_hw_get_mode() != ACPI_SYS_MODE_ACPI) {
+               ACPI_ERROR((AE_INFO,
+                           "Hardware did not enter ACPI mode"));
+               return_ACPI_STATUS(AE_NO_HARDWARE_RESPONSE);
+       }
+
+       ACPI_DEBUG_PRINT((ACPI_DB_INIT,
+                         "Transition to ACPI mode successful\n"));
+
+       return_ACPI_STATUS(AE_OK);
 }
 
 ACPI_EXPORT_SYMBOL(acpi_enable)
index 679a112a7d2692b140776ec44554288b1e2557ca..b44274a0b62c66fc0326d8f7b29b60ecee2ec384 100644 (file)
@@ -63,7 +63,6 @@ acpi_status acpi_hw_set_mode(u32 mode)
 {
 
        acpi_status status;
-       u32 retry;
 
        ACPI_FUNCTION_TRACE(hw_set_mode);
 
@@ -125,24 +124,7 @@ acpi_status acpi_hw_set_mode(u32 mode)
                return_ACPI_STATUS(status);
        }
 
-       /*
-        * Some hardware takes a LONG time to switch modes. Give them 3 sec to
-        * do so, but allow faster systems to proceed more quickly.
-        */
-       retry = 3000;
-       while (retry) {
-               if (acpi_hw_get_mode() == mode) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                         "Mode %X successfully enabled\n",
-                                         mode));
-                       return_ACPI_STATUS(AE_OK);
-               }
-               acpi_os_stall(1000);
-               retry--;
-       }
-
-       ACPI_ERROR((AE_INFO, "Hardware did not change modes"));
-       return_ACPI_STATUS(AE_NO_HARDWARE_RESPONSE);
+       return_ACPI_STATUS(AE_OK);
 }
 
 /*******************************************************************************
diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig
new file mode 100644 (file)
index 0000000..f8c668f
--- /dev/null
@@ -0,0 +1,30 @@
+config ACPI_APEI
+       bool "ACPI Platform Error Interface (APEI)"
+       depends on X86
+       help
+         APEI allows to report errors (for example from the chipset)
+         to the operating system. This improves NMI handling
+         especially. In addition it supports error serialization and
+         error injection.
+
+config ACPI_APEI_GHES
+       tristate "APEI Generic Hardware Error Source"
+       depends on ACPI_APEI && X86
+       select ACPI_HED
+       help
+         Generic Hardware Error Source provides a way to report
+         platform hardware errors (such as that from chipset). It
+         works in so called "Firmware First" mode, that is, hardware
+         errors are reported to firmware firstly, then reported to
+         Linux by firmware. This way, some non-standard hardware
+         error registers or non-standard hardware link can be checked
+         by firmware to produce more valuable hardware error
+         information for Linux.
+
+config ACPI_APEI_EINJ
+       tristate "APEI Error INJection (EINJ)"
+       depends on ACPI_APEI && DEBUG_FS
+       help
+         EINJ provides a hardware error injection mechanism, it is
+         mainly used for debugging and testing the other parts of
+         APEI and some other RAS features.
diff --git a/drivers/acpi/apei/Makefile b/drivers/acpi/apei/Makefile
new file mode 100644 (file)
index 0000000..b13b03a
--- /dev/null
@@ -0,0 +1,5 @@
+obj-$(CONFIG_ACPI_APEI)                += apei.o
+obj-$(CONFIG_ACPI_APEI_GHES)   += ghes.o
+obj-$(CONFIG_ACPI_APEI_EINJ)   += einj.o
+
+apei-y := apei-base.o hest.o cper.o erst.o
diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c
new file mode 100644 (file)
index 0000000..db3946e
--- /dev/null
@@ -0,0 +1,593 @@
+/*
+ * apei-base.c - ACPI Platform Error Interface (APEI) supporting
+ * infrastructure
+ *
+ * APEI allows to report errors (for example from the chipset) to the
+ * the operating system. This improves NMI handling especially. In
+ * addition it supports error serialization and error injection.
+ *
+ * For more information about APEI, please refer to ACPI Specification
+ * version 4.0, chapter 17.
+ *
+ * This file has Common functions used by more than one APEI table,
+ * including framework of interpreter for ERST and EINJ; resource
+ * management for APEI registers.
+ *
+ * Copyright (C) 2009, Intel Corp.
+ *     Author: Huang Ying <ying.huang@intel.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+#include <linux/kref.h>
+#include <linux/rculist.h>
+#include <linux/interrupt.h>
+#include <linux/debugfs.h>
+#include <acpi/atomicio.h>
+
+#include "apei-internal.h"
+
+#define APEI_PFX "APEI: "
+
+/*
+ * APEI ERST (Error Record Serialization Table) and EINJ (Error
+ * INJection) interpreter framework.
+ */
+
+#define APEI_EXEC_PRESERVE_REGISTER    0x1
+
+void apei_exec_ctx_init(struct apei_exec_context *ctx,
+                       struct apei_exec_ins_type *ins_table,
+                       u32 instructions,
+                       struct acpi_whea_header *action_table,
+                       u32 entries)
+{
+       ctx->ins_table = ins_table;
+       ctx->instructions = instructions;
+       ctx->action_table = action_table;
+       ctx->entries = entries;
+}
+EXPORT_SYMBOL_GPL(apei_exec_ctx_init);
+
+int __apei_exec_read_register(struct acpi_whea_header *entry, u64 *val)
+{
+       int rc;
+
+       rc = acpi_atomic_read(val, &entry->register_region);
+       if (rc)
+               return rc;
+       *val >>= entry->register_region.bit_offset;
+       *val &= entry->mask;
+
+       return 0;
+}
+
+int apei_exec_read_register(struct apei_exec_context *ctx,
+                           struct acpi_whea_header *entry)
+{
+       int rc;
+       u64 val = 0;
+
+       rc = __apei_exec_read_register(entry, &val);
+       if (rc)
+               return rc;
+       ctx->value = val;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(apei_exec_read_register);
+
+int apei_exec_read_register_value(struct apei_exec_context *ctx,
+                                 struct acpi_whea_header *entry)
+{
+       int rc;
+
+       rc = apei_exec_read_register(ctx, entry);
+       if (rc)
+               return rc;
+       ctx->value = (ctx->value == entry->value);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(apei_exec_read_register_value);
+
+int __apei_exec_write_register(struct acpi_whea_header *entry, u64 val)
+{
+       int rc;
+
+       val &= entry->mask;
+       val <<= entry->register_region.bit_offset;
+       if (entry->flags & APEI_EXEC_PRESERVE_REGISTER) {
+               u64 valr = 0;
+               rc = acpi_atomic_read(&valr, &entry->register_region);
+               if (rc)
+                       return rc;
+               valr &= ~(entry->mask << entry->register_region.bit_offset);
+               val |= valr;
+       }
+       rc = acpi_atomic_write(val, &entry->register_region);
+
+       return rc;
+}
+
+int apei_exec_write_register(struct apei_exec_context *ctx,
+                            struct acpi_whea_header *entry)
+{
+       return __apei_exec_write_register(entry, ctx->value);
+}
+EXPORT_SYMBOL_GPL(apei_exec_write_register);
+
+int apei_exec_write_register_value(struct apei_exec_context *ctx,
+                                  struct acpi_whea_header *entry)
+{
+       int rc;
+
+       ctx->value = entry->value;
+       rc = apei_exec_write_register(ctx, entry);
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(apei_exec_write_register_value);
+
+int apei_exec_noop(struct apei_exec_context *ctx,
+                  struct acpi_whea_header *entry)
+{
+       return 0;
+}
+EXPORT_SYMBOL_GPL(apei_exec_noop);
+
+/*
+ * Interpret the specified action. Go through whole action table,
+ * execute all instructions belong to the action.
+ */
+int apei_exec_run(struct apei_exec_context *ctx, u8 action)
+{
+       int rc;
+       u32 i, ip;
+       struct acpi_whea_header *entry;
+       apei_exec_ins_func_t run;
+
+       ctx->ip = 0;
+
+       /*
+        * "ip" is the instruction pointer of current instruction,
+        * "ctx->ip" specifies the next instruction to executed,
+        * instruction "run" function may change the "ctx->ip" to
+        * implement "goto" semantics.
+        */
+rewind:
+       ip = 0;
+       for (i = 0; i < ctx->entries; i++) {
+               entry = &ctx->action_table[i];
+               if (entry->action != action)
+                       continue;
+               if (ip == ctx->ip) {
+                       if (entry->instruction >= ctx->instructions ||
+                           !ctx->ins_table[entry->instruction].run) {
+                               pr_warning(FW_WARN APEI_PFX
+                       "Invalid action table, unknown instruction type: %d\n",
+                                          entry->instruction);
+                               return -EINVAL;
+                       }
+                       run = ctx->ins_table[entry->instruction].run;
+                       rc = run(ctx, entry);
+                       if (rc < 0)
+                               return rc;
+                       else if (rc != APEI_EXEC_SET_IP)
+                               ctx->ip++;
+               }
+               ip++;
+               if (ctx->ip < ip)
+                       goto rewind;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(apei_exec_run);
+
+typedef int (*apei_exec_entry_func_t)(struct apei_exec_context *ctx,
+                                     struct acpi_whea_header *entry,
+                                     void *data);
+
+static int apei_exec_for_each_entry(struct apei_exec_context *ctx,
+                                   apei_exec_entry_func_t func,
+                                   void *data,
+                                   int *end)
+{
+       u8 ins;
+       int i, rc;
+       struct acpi_whea_header *entry;
+       struct apei_exec_ins_type *ins_table = ctx->ins_table;
+
+       for (i = 0; i < ctx->entries; i++) {
+               entry = ctx->action_table + i;
+               ins = entry->instruction;
+               if (end)
+                       *end = i;
+               if (ins >= ctx->instructions || !ins_table[ins].run) {
+                       pr_warning(FW_WARN APEI_PFX
+                       "Invalid action table, unknown instruction type: %d\n",
+                                  ins);
+                       return -EINVAL;
+               }
+               rc = func(ctx, entry, data);
+               if (rc)
+                       return rc;
+       }
+
+       return 0;
+}
+
+static int pre_map_gar_callback(struct apei_exec_context *ctx,
+                               struct acpi_whea_header *entry,
+                               void *data)
+{
+       u8 ins = entry->instruction;
+
+       if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER)
+               return acpi_pre_map_gar(&entry->register_region);
+
+       return 0;
+}
+
+/*
+ * Pre-map all GARs in action table to make it possible to access them
+ * in NMI handler.
+ */
+int apei_exec_pre_map_gars(struct apei_exec_context *ctx)
+{
+       int rc, end;
+
+       rc = apei_exec_for_each_entry(ctx, pre_map_gar_callback,
+                                     NULL, &end);
+       if (rc) {
+               struct apei_exec_context ctx_unmap;
+               memcpy(&ctx_unmap, ctx, sizeof(*ctx));
+               ctx_unmap.entries = end;
+               apei_exec_post_unmap_gars(&ctx_unmap);
+       }
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(apei_exec_pre_map_gars);
+
+static int post_unmap_gar_callback(struct apei_exec_context *ctx,
+                                  struct acpi_whea_header *entry,
+                                  void *data)
+{
+       u8 ins = entry->instruction;
+
+       if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER)
+               acpi_post_unmap_gar(&entry->register_region);
+
+       return 0;
+}
+
+/* Post-unmap all GAR in action table. */
+int apei_exec_post_unmap_gars(struct apei_exec_context *ctx)
+{
+       return apei_exec_for_each_entry(ctx, post_unmap_gar_callback,
+                                       NULL, NULL);
+}
+EXPORT_SYMBOL_GPL(apei_exec_post_unmap_gars);
+
+/*
+ * Resource management for GARs in APEI
+ */
+struct apei_res {
+       struct list_head list;
+       unsigned long start;
+       unsigned long end;
+};
+
+/* Collect all resources requested, to avoid conflict */
+struct apei_resources apei_resources_all = {
+       .iomem = LIST_HEAD_INIT(apei_resources_all.iomem),
+       .ioport = LIST_HEAD_INIT(apei_resources_all.ioport),
+};
+
+static int apei_res_add(struct list_head *res_list,
+                       unsigned long start, unsigned long size)
+{
+       struct apei_res *res, *resn, *res_ins = NULL;
+       unsigned long end = start + size;
+
+       if (end <= start)
+               return 0;
+repeat:
+       list_for_each_entry_safe(res, resn, res_list, list) {
+               if (res->start > end || res->end < start)
+                       continue;
+               else if (end <= res->end && start >= res->start) {
+                       kfree(res_ins);
+                       return 0;
+               }
+               list_del(&res->list);
+               res->start = start = min(res->start, start);
+               res->end = end = max(res->end, end);
+               kfree(res_ins);
+               res_ins = res;
+               goto repeat;
+       }
+
+       if (res_ins)
+               list_add(&res_ins->list, res_list);
+       else {
+               res_ins = kmalloc(sizeof(*res), GFP_KERNEL);
+               if (!res_ins)
+                       return -ENOMEM;
+               res_ins->start = start;
+               res_ins->end = end;
+               list_add(&res_ins->list, res_list);
+       }
+
+       return 0;
+}
+
+static int apei_res_sub(struct list_head *res_list1,
+                       struct list_head *res_list2)
+{
+       struct apei_res *res1, *resn1, *res2, *res;
+       res1 = list_entry(res_list1->next, struct apei_res, list);
+       resn1 = list_entry(res1->list.next, struct apei_res, list);
+       while (&res1->list != res_list1) {
+               list_for_each_entry(res2, res_list2, list) {
+                       if (res1->start >= res2->end ||
+                           res1->end <= res2->start)
+                               continue;
+                       else if (res1->end <= res2->end &&
+                                res1->start >= res2->start) {
+                               list_del(&res1->list);
+                               kfree(res1);
+                               break;
+                       } else if (res1->end > res2->end &&
+                                  res1->start < res2->start) {
+                               res = kmalloc(sizeof(*res), GFP_KERNEL);
+                               if (!res)
+                                       return -ENOMEM;
+                               res->start = res2->end;
+                               res->end = res1->end;
+                               res1->end = res2->start;
+                               list_add(&res->list, &res1->list);
+                               resn1 = res;
+                       } else {
+                               if (res1->start < res2->start)
+                                       res1->end = res2->start;
+                               else
+                                       res1->start = res2->end;
+                       }
+               }
+               res1 = resn1;
+               resn1 = list_entry(resn1->list.next, struct apei_res, list);
+       }
+
+       return 0;
+}
+
+static void apei_res_clean(struct list_head *res_list)
+{
+       struct apei_res *res, *resn;
+
+       list_for_each_entry_safe(res, resn, res_list, list) {
+               list_del(&res->list);
+               kfree(res);
+       }
+}
+
+void apei_resources_fini(struct apei_resources *resources)
+{
+       apei_res_clean(&resources->iomem);
+       apei_res_clean(&resources->ioport);
+}
+EXPORT_SYMBOL_GPL(apei_resources_fini);
+
+static int apei_resources_merge(struct apei_resources *resources1,
+                               struct apei_resources *resources2)
+{
+       int rc;
+       struct apei_res *res;
+
+       list_for_each_entry(res, &resources2->iomem, list) {
+               rc = apei_res_add(&resources1->iomem, res->start,
+                                 res->end - res->start);
+               if (rc)
+                       return rc;
+       }
+       list_for_each_entry(res, &resources2->ioport, list) {
+               rc = apei_res_add(&resources1->ioport, res->start,
+                                 res->end - res->start);
+               if (rc)
+                       return rc;
+       }
+
+       return 0;
+}
+
+/*
+ * EINJ has two groups of GARs (EINJ table entry and trigger table
+ * entry), so common resources are subtracted from the trigger table
+ * resources before the second requesting.
+ */
+int apei_resources_sub(struct apei_resources *resources1,
+                      struct apei_resources *resources2)
+{
+       int rc;
+
+       rc = apei_res_sub(&resources1->iomem, &resources2->iomem);
+       if (rc)
+               return rc;
+       return apei_res_sub(&resources1->ioport, &resources2->ioport);
+}
+EXPORT_SYMBOL_GPL(apei_resources_sub);
+
+/*
+ * IO memory/port rersource management mechanism is used to check
+ * whether memory/port area used by GARs conflicts with normal memory
+ * or IO memory/port of devices.
+ */
+int apei_resources_request(struct apei_resources *resources,
+                          const char *desc)
+{
+       struct apei_res *res, *res_bak;
+       struct resource *r;
+
+       apei_resources_sub(resources, &apei_resources_all);
+
+       list_for_each_entry(res, &resources->iomem, list) {
+               r = request_mem_region(res->start, res->end - res->start,
+                                      desc);
+               if (!r) {
+                       pr_err(APEI_PFX
+               "Can not request iomem region <%016llx-%016llx> for GARs.\n",
+                              (unsigned long long)res->start,
+                              (unsigned long long)res->end);
+                       res_bak = res;
+                       goto err_unmap_iomem;
+               }
+       }
+
+       list_for_each_entry(res, &resources->ioport, list) {
+               r = request_region(res->start, res->end - res->start, desc);
+               if (!r) {
+                       pr_err(APEI_PFX
+               "Can not request ioport region <%016llx-%016llx> for GARs.\n",
+                              (unsigned long long)res->start,
+                              (unsigned long long)res->end);
+                       res_bak = res;
+                       goto err_unmap_ioport;
+               }
+       }
+
+       apei_resources_merge(&apei_resources_all, resources);
+
+       return 0;
+err_unmap_ioport:
+       list_for_each_entry(res, &resources->ioport, list) {
+               if (res == res_bak)
+                       break;
+               release_mem_region(res->start, res->end - res->start);
+       }
+       res_bak = NULL;
+err_unmap_iomem:
+       list_for_each_entry(res, &resources->iomem, list) {
+               if (res == res_bak)
+                       break;
+               release_region(res->start, res->end - res->start);
+       }
+       return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(apei_resources_request);
+
+void apei_resources_release(struct apei_resources *resources)
+{
+       struct apei_res *res;
+
+       list_for_each_entry(res, &resources->iomem, list)
+               release_mem_region(res->start, res->end - res->start);
+       list_for_each_entry(res, &resources->ioport, list)
+               release_region(res->start, res->end - res->start);
+
+       apei_resources_sub(&apei_resources_all, resources);
+}
+EXPORT_SYMBOL_GPL(apei_resources_release);
+
+static int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr)
+{
+       u32 width, space_id;
+
+       width = reg->bit_width;
+       space_id = reg->space_id;
+       /* Handle possible alignment issues */
+       memcpy(paddr, &reg->address, sizeof(*paddr));
+       if (!*paddr) {
+               pr_warning(FW_BUG APEI_PFX
+                          "Invalid physical address in GAR [0x%llx/%u/%u]\n",
+                          *paddr, width, space_id);
+               return -EINVAL;
+       }
+
+       if ((width != 8) && (width != 16) && (width != 32) && (width != 64)) {
+               pr_warning(FW_BUG APEI_PFX
+                          "Invalid bit width in GAR [0x%llx/%u/%u]\n",
+                          *paddr, width, space_id);
+               return -EINVAL;
+       }
+
+       if (space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY &&
+           space_id != ACPI_ADR_SPACE_SYSTEM_IO) {
+               pr_warning(FW_BUG APEI_PFX
+                          "Invalid address space type in GAR [0x%llx/%u/%u]\n",
+                          *paddr, width, space_id);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int collect_res_callback(struct apei_exec_context *ctx,
+                               struct acpi_whea_header *entry,
+                               void *data)
+{
+       struct apei_resources *resources = data;
+       struct acpi_generic_address *reg = &entry->register_region;
+       u8 ins = entry->instruction;
+       u64 paddr;
+       int rc;
+
+       if (!(ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER))
+               return 0;
+
+       rc = apei_check_gar(reg, &paddr);
+       if (rc)
+               return rc;
+
+       switch (reg->space_id) {
+       case ACPI_ADR_SPACE_SYSTEM_MEMORY:
+               return apei_res_add(&resources->iomem, paddr,
+                                   reg->bit_width / 8);
+       case ACPI_ADR_SPACE_SYSTEM_IO:
+               return apei_res_add(&resources->ioport, paddr,
+                                   reg->bit_width / 8);
+       default:
+               return -EINVAL;
+       }
+}
+
+/*
+ * Same register may be used by multiple instructions in GARs, so
+ * resources are collected before requesting.
+ */
+int apei_exec_collect_resources(struct apei_exec_context *ctx,
+                               struct apei_resources *resources)
+{
+       return apei_exec_for_each_entry(ctx, collect_res_callback,
+                                       resources, NULL);
+}
+EXPORT_SYMBOL_GPL(apei_exec_collect_resources);
+
+struct dentry *apei_get_debugfs_dir(void)
+{
+       static struct dentry *dapei;
+
+       if (!dapei)
+               dapei = debugfs_create_dir("apei", NULL);
+
+       return dapei;
+}
+EXPORT_SYMBOL_GPL(apei_get_debugfs_dir);
diff --git a/drivers/acpi/apei/apei-internal.h b/drivers/acpi/apei/apei-internal.h
new file mode 100644 (file)
index 0000000..18df1e9
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * apei-internal.h - ACPI Platform Error Interface internal
+ * definations.
+ */
+
+#ifndef APEI_INTERNAL_H
+#define APEI_INTERNAL_H
+
+#include <linux/cper.h>
+
+struct apei_exec_context;
+
+typedef int (*apei_exec_ins_func_t)(struct apei_exec_context *ctx,
+                                   struct acpi_whea_header *entry);
+
+#define APEI_EXEC_INS_ACCESS_REGISTER  0x0001
+
+struct apei_exec_ins_type {
+       u32 flags;
+       apei_exec_ins_func_t run;
+};
+
+struct apei_exec_context {
+       u32 ip;
+       u64 value;
+       u64 var1;
+       u64 var2;
+       u64 src_base;
+       u64 dst_base;
+       struct apei_exec_ins_type *ins_table;
+       u32 instructions;
+       struct acpi_whea_header *action_table;
+       u32 entries;
+};
+
+void apei_exec_ctx_init(struct apei_exec_context *ctx,
+                       struct apei_exec_ins_type *ins_table,
+                       u32 instructions,
+                       struct acpi_whea_header *action_table,
+                       u32 entries);
+
+static inline void apei_exec_ctx_set_input(struct apei_exec_context *ctx,
+                                          u64 input)
+{
+       ctx->value = input;
+}
+
+static inline u64 apei_exec_ctx_get_output(struct apei_exec_context *ctx)
+{
+       return ctx->value;
+}
+
+int apei_exec_run(struct apei_exec_context *ctx, u8 action);
+
+/* Common instruction implementation */
+
+/* IP has been set in instruction function */
+#define APEI_EXEC_SET_IP       1
+
+int __apei_exec_read_register(struct acpi_whea_header *entry, u64 *val);
+int __apei_exec_write_register(struct acpi_whea_header *entry, u64 val);
+int apei_exec_read_register(struct apei_exec_context *ctx,
+                           struct acpi_whea_header *entry);
+int apei_exec_read_register_value(struct apei_exec_context *ctx,
+                                 struct acpi_whea_header *entry);
+int apei_exec_write_register(struct apei_exec_context *ctx,
+                            struct acpi_whea_header *entry);
+int apei_exec_write_register_value(struct apei_exec_context *ctx,
+                                  struct acpi_whea_header *entry);
+int apei_exec_noop(struct apei_exec_context *ctx,
+                  struct acpi_whea_header *entry);
+int apei_exec_pre_map_gars(struct apei_exec_context *ctx);
+int apei_exec_post_unmap_gars(struct apei_exec_context *ctx);
+
+struct apei_resources {
+       struct list_head iomem;
+       struct list_head ioport;
+};
+
+static inline void apei_resources_init(struct apei_resources *resources)
+{
+       INIT_LIST_HEAD(&resources->iomem);
+       INIT_LIST_HEAD(&resources->ioport);
+}
+
+void apei_resources_fini(struct apei_resources *resources);
+int apei_resources_sub(struct apei_resources *resources1,
+                      struct apei_resources *resources2);
+int apei_resources_request(struct apei_resources *resources,
+                          const char *desc);
+void apei_resources_release(struct apei_resources *resources);
+int apei_exec_collect_resources(struct apei_exec_context *ctx,
+                               struct apei_resources *resources);
+
+struct dentry;
+struct dentry *apei_get_debugfs_dir(void);
+
+#define apei_estatus_for_each_section(estatus, section)                        \
+       for (section = (struct acpi_hest_generic_data *)(estatus + 1);  \
+            (void *)section - (void *)estatus < estatus->data_length;  \
+            section = (void *)(section+1) + section->error_data_length)
+
+static inline u32 apei_estatus_len(struct acpi_hest_generic_status *estatus)
+{
+       if (estatus->raw_data_length)
+               return estatus->raw_data_offset + \
+                       estatus->raw_data_length;
+       else
+               return sizeof(*estatus) + estatus->data_length;
+}
+
+int apei_estatus_check_header(const struct acpi_hest_generic_status *estatus);
+int apei_estatus_check(const struct acpi_hest_generic_status *estatus);
+#endif
diff --git a/drivers/acpi/apei/cper.c b/drivers/acpi/apei/cper.c
new file mode 100644 (file)
index 0000000..f4cf2fc
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * UEFI Common Platform Error Record (CPER) support
+ *
+ * Copyright (C) 2010, Intel Corp.
+ *     Author: Huang Ying <ying.huang@intel.com>
+ *
+ * CPER is the format used to describe platform hardware error by
+ * various APEI tables, such as ERST, BERT and HEST etc.
+ *
+ * For more information about CPER, please refer to Appendix N of UEFI
+ * Specification version 2.3.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/cper.h>
+#include <linux/acpi.h>
+
+/*
+ * CPER record ID need to be unique even after reboot, because record
+ * ID is used as index for ERST storage, while CPER records from
+ * multiple boot may co-exist in ERST.
+ */
+u64 cper_next_record_id(void)
+{
+       static atomic64_t seq;
+
+       if (!atomic64_read(&seq))
+               atomic64_set(&seq, ((u64)get_seconds()) << 32);
+
+       return atomic64_inc_return(&seq);
+}
+EXPORT_SYMBOL_GPL(cper_next_record_id);
+
+int apei_estatus_check_header(const struct acpi_hest_generic_status *estatus)
+{
+       if (estatus->data_length &&
+           estatus->data_length < sizeof(struct acpi_hest_generic_data))
+               return -EINVAL;
+       if (estatus->raw_data_length &&
+           estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length)
+               return -EINVAL;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(apei_estatus_check_header);
+
+int apei_estatus_check(const struct acpi_hest_generic_status *estatus)
+{
+       struct acpi_hest_generic_data *gdata;
+       unsigned int data_len, gedata_len;
+       int rc;
+
+       rc = apei_estatus_check_header(estatus);
+       if (rc)
+               return rc;
+       data_len = estatus->data_length;
+       gdata = (struct acpi_hest_generic_data *)(estatus + 1);
+       while (data_len > sizeof(*gdata)) {
+               gedata_len = gdata->error_data_length;
+               if (gedata_len > data_len - sizeof(*gdata))
+                       return -EINVAL;
+               data_len -= gedata_len + sizeof(*gdata);
+       }
+       if (data_len)
+               return -EINVAL;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(apei_estatus_check);
diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c
new file mode 100644 (file)
index 0000000..465c885
--- /dev/null
@@ -0,0 +1,548 @@
+/*
+ * APEI Error INJection support
+ *
+ * EINJ provides a hardware error injection mechanism, this is useful
+ * for debugging and testing of other APEI and RAS features.
+ *
+ * For more information about EINJ, please refer to ACPI Specification
+ * version 4.0, section 17.5.
+ *
+ * Copyright 2009-2010 Intel Corp.
+ *   Author: Huang Ying <ying.huang@intel.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/nmi.h>
+#include <linux/delay.h>
+#include <acpi/acpi.h>
+
+#include "apei-internal.h"
+
+#define EINJ_PFX "EINJ: "
+
+#define SPIN_UNIT              100                     /* 100ns */
+/* Firmware should respond within 1 miliseconds */
+#define FIRMWARE_TIMEOUT       (1 * NSEC_PER_MSEC)
+
+/*
+ * Some BIOSes allow parameters to the SET_ERROR_TYPE entries in the
+ * EINJ table through an unpublished extension. Use with caution as
+ * most will ignore the parameter and make their own choice of address
+ * for error injection.
+ */
+struct einj_parameter {
+       u64 type;
+       u64 reserved1;
+       u64 reserved2;
+       u64 param1;
+       u64 param2;
+};
+
+#define EINJ_OP_BUSY                   0x1
+#define EINJ_STATUS_SUCCESS            0x0
+#define EINJ_STATUS_FAIL               0x1
+#define EINJ_STATUS_INVAL              0x2
+
+#define EINJ_TAB_ENTRY(tab)                                            \
+       ((struct acpi_whea_header *)((char *)(tab) +                    \
+                                   sizeof(struct acpi_table_einj)))
+
+static struct acpi_table_einj *einj_tab;
+
+static struct apei_resources einj_resources;
+
+static struct apei_exec_ins_type einj_ins_type[] = {
+       [ACPI_EINJ_READ_REGISTER] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run   = apei_exec_read_register,
+       },
+       [ACPI_EINJ_READ_REGISTER_VALUE] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run   = apei_exec_read_register_value,
+       },
+       [ACPI_EINJ_WRITE_REGISTER] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run   = apei_exec_write_register,
+       },
+       [ACPI_EINJ_WRITE_REGISTER_VALUE] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run   = apei_exec_write_register_value,
+       },
+       [ACPI_EINJ_NOOP] = {
+               .flags = 0,
+               .run   = apei_exec_noop,
+       },
+};
+
+/*
+ * Prevent EINJ interpreter to run simultaneously, because the
+ * corresponding firmware implementation may not work properly when
+ * invoked simultaneously.
+ */
+static DEFINE_MUTEX(einj_mutex);
+
+static struct einj_parameter *einj_param;
+
+static void einj_exec_ctx_init(struct apei_exec_context *ctx)
+{
+       apei_exec_ctx_init(ctx, einj_ins_type, ARRAY_SIZE(einj_ins_type),
+                          EINJ_TAB_ENTRY(einj_tab), einj_tab->entries);
+}
+
+static int __einj_get_available_error_type(u32 *type)
+{
+       struct apei_exec_context ctx;
+       int rc;
+
+       einj_exec_ctx_init(&ctx);
+       rc = apei_exec_run(&ctx, ACPI_EINJ_GET_ERROR_TYPE);
+       if (rc)
+               return rc;
+       *type = apei_exec_ctx_get_output(&ctx);
+
+       return 0;
+}
+
+/* Get error injection capabilities of the platform */
+static int einj_get_available_error_type(u32 *type)
+{
+       int rc;
+
+       mutex_lock(&einj_mutex);
+       rc = __einj_get_available_error_type(type);
+       mutex_unlock(&einj_mutex);
+
+       return rc;
+}
+
+static int einj_timedout(u64 *t)
+{
+       if ((s64)*t < SPIN_UNIT) {
+               pr_warning(FW_WARN EINJ_PFX
+                          "Firmware does not respond in time\n");
+               return 1;
+       }
+       *t -= SPIN_UNIT;
+       ndelay(SPIN_UNIT);
+       touch_nmi_watchdog();
+       return 0;
+}
+
+static u64 einj_get_parameter_address(void)
+{
+       int i;
+       u64 paddr = 0;
+       struct acpi_whea_header *entry;
+
+       entry = EINJ_TAB_ENTRY(einj_tab);
+       for (i = 0; i < einj_tab->entries; i++) {
+               if (entry->action == ACPI_EINJ_SET_ERROR_TYPE &&
+                   entry->instruction == ACPI_EINJ_WRITE_REGISTER &&
+                   entry->register_region.space_id ==
+                   ACPI_ADR_SPACE_SYSTEM_MEMORY)
+                       memcpy(&paddr, &entry->register_region.address,
+                              sizeof(paddr));
+               entry++;
+       }
+
+       return paddr;
+}
+
+/* do sanity check to trigger table */
+static int einj_check_trigger_header(struct acpi_einj_trigger *trigger_tab)
+{
+       if (trigger_tab->header_size != sizeof(struct acpi_einj_trigger))
+               return -EINVAL;
+       if (trigger_tab->table_size > PAGE_SIZE ||
+           trigger_tab->table_size <= trigger_tab->header_size)
+               return -EINVAL;
+       if (trigger_tab->entry_count !=
+           (trigger_tab->table_size - trigger_tab->header_size) /
+           sizeof(struct acpi_einj_entry))
+               return -EINVAL;
+
+       return 0;
+}
+
+/* Execute instructions in trigger error action table */
+static int __einj_error_trigger(u64 trigger_paddr)
+{
+       struct acpi_einj_trigger *trigger_tab = NULL;
+       struct apei_exec_context trigger_ctx;
+       struct apei_resources trigger_resources;
+       struct acpi_whea_header *trigger_entry;
+       struct resource *r;
+       u32 table_size;
+       int rc = -EIO;
+
+       r = request_mem_region(trigger_paddr, sizeof(*trigger_tab),
+                              "APEI EINJ Trigger Table");
+       if (!r) {
+               pr_err(EINJ_PFX
+       "Can not request iomem region <%016llx-%016llx> for Trigger table.\n",
+                      (unsigned long long)trigger_paddr,
+                      (unsigned long long)trigger_paddr+sizeof(*trigger_tab));
+               goto out;
+       }
+       trigger_tab = ioremap_cache(trigger_paddr, sizeof(*trigger_tab));
+       if (!trigger_tab) {
+               pr_err(EINJ_PFX "Failed to map trigger table!\n");
+               goto out_rel_header;
+       }
+       rc = einj_check_trigger_header(trigger_tab);
+       if (rc) {
+               pr_warning(FW_BUG EINJ_PFX
+                          "The trigger error action table is invalid\n");
+               goto out_rel_header;
+       }
+       rc = -EIO;
+       table_size = trigger_tab->table_size;
+       r = request_mem_region(trigger_paddr + sizeof(*trigger_tab),
+                              table_size - sizeof(*trigger_tab),
+                              "APEI EINJ Trigger Table");
+       if (!r) {
+               pr_err(EINJ_PFX
+"Can not request iomem region <%016llx-%016llx> for Trigger Table Entry.\n",
+                      (unsigned long long)trigger_paddr+sizeof(*trigger_tab),
+                      (unsigned long long)trigger_paddr + table_size);
+               goto out_rel_header;
+       }
+       iounmap(trigger_tab);
+       trigger_tab = ioremap_cache(trigger_paddr, table_size);
+       if (!trigger_tab) {
+               pr_err(EINJ_PFX "Failed to map trigger table!\n");
+               goto out_rel_entry;
+       }
+       trigger_entry = (struct acpi_whea_header *)
+               ((char *)trigger_tab + sizeof(struct acpi_einj_trigger));
+       apei_resources_init(&trigger_resources);
+       apei_exec_ctx_init(&trigger_ctx, einj_ins_type,
+                          ARRAY_SIZE(einj_ins_type),
+                          trigger_entry, trigger_tab->entry_count);
+       rc = apei_exec_collect_resources(&trigger_ctx, &trigger_resources);
+       if (rc)
+               goto out_fini;
+       rc = apei_resources_sub(&trigger_resources, &einj_resources);
+       if (rc)
+               goto out_fini;
+       rc = apei_resources_request(&trigger_resources, "APEI EINJ Trigger");
+       if (rc)
+               goto out_fini;
+       rc = apei_exec_pre_map_gars(&trigger_ctx);
+       if (rc)
+               goto out_release;
+
+       rc = apei_exec_run(&trigger_ctx, ACPI_EINJ_TRIGGER_ERROR);
+
+       apei_exec_post_unmap_gars(&trigger_ctx);
+out_release:
+       apei_resources_release(&trigger_resources);
+out_fini:
+       apei_resources_fini(&trigger_resources);
+out_rel_entry:
+       release_mem_region(trigger_paddr + sizeof(*trigger_tab),
+                          table_size - sizeof(*trigger_tab));
+out_rel_header:
+       release_mem_region(trigger_paddr, sizeof(*trigger_tab));
+out:
+       if (trigger_tab)
+               iounmap(trigger_tab);
+
+       return rc;
+}
+
+static int __einj_error_inject(u32 type, u64 param1, u64 param2)
+{
+       struct apei_exec_context ctx;
+       u64 val, trigger_paddr, timeout = FIRMWARE_TIMEOUT;
+       int rc;
+
+       einj_exec_ctx_init(&ctx);
+
+       rc = apei_exec_run(&ctx, ACPI_EINJ_BEGIN_OPERATION);
+       if (rc)
+               return rc;
+       apei_exec_ctx_set_input(&ctx, type);
+       rc = apei_exec_run(&ctx, ACPI_EINJ_SET_ERROR_TYPE);
+       if (rc)
+               return rc;
+       if (einj_param) {
+               writeq(param1, &einj_param->param1);
+               writeq(param2, &einj_param->param2);
+       }
+       rc = apei_exec_run(&ctx, ACPI_EINJ_EXECUTE_OPERATION);
+       if (rc)
+               return rc;
+       for (;;) {
+               rc = apei_exec_run(&ctx, ACPI_EINJ_CHECK_BUSY_STATUS);
+               if (rc)
+                       return rc;
+               val = apei_exec_ctx_get_output(&ctx);
+               if (!(val & EINJ_OP_BUSY))
+                       break;
+               if (einj_timedout(&timeout))
+                       return -EIO;
+       }
+       rc = apei_exec_run(&ctx, ACPI_EINJ_GET_COMMAND_STATUS);
+       if (rc)
+               return rc;
+       val = apei_exec_ctx_get_output(&ctx);
+       if (val != EINJ_STATUS_SUCCESS)
+               return -EBUSY;
+
+       rc = apei_exec_run(&ctx, ACPI_EINJ_GET_TRIGGER_TABLE);
+       if (rc)
+               return rc;
+       trigger_paddr = apei_exec_ctx_get_output(&ctx);
+       rc = __einj_error_trigger(trigger_paddr);
+       if (rc)
+               return rc;
+       rc = apei_exec_run(&ctx, ACPI_EINJ_END_OPERATION);
+
+       return rc;
+}
+
+/* Inject the specified hardware error */
+static int einj_error_inject(u32 type, u64 param1, u64 param2)
+{
+       int rc;
+
+       mutex_lock(&einj_mutex);
+       rc = __einj_error_inject(type, param1, param2);
+       mutex_unlock(&einj_mutex);
+
+       return rc;
+}
+
+static u32 error_type;
+static u64 error_param1;
+static u64 error_param2;
+static struct dentry *einj_debug_dir;
+
+static int available_error_type_show(struct seq_file *m, void *v)
+{
+       int rc;
+       u32 available_error_type = 0;
+
+       rc = einj_get_available_error_type(&available_error_type);
+       if (rc)
+               return rc;
+       if (available_error_type & 0x0001)
+               seq_printf(m, "0x00000001\tProcessor Correctable\n");
+       if (available_error_type & 0x0002)
+               seq_printf(m, "0x00000002\tProcessor Uncorrectable non-fatal\n");
+       if (available_error_type & 0x0004)
+               seq_printf(m, "0x00000004\tProcessor Uncorrectable fatal\n");
+       if (available_error_type & 0x0008)
+               seq_printf(m, "0x00000008\tMemory Correctable\n");
+       if (available_error_type & 0x0010)
+               seq_printf(m, "0x00000010\tMemory Uncorrectable non-fatal\n");
+       if (available_error_type & 0x0020)
+               seq_printf(m, "0x00000020\tMemory Uncorrectable fatal\n");
+       if (available_error_type & 0x0040)
+               seq_printf(m, "0x00000040\tPCI Express Correctable\n");
+       if (available_error_type & 0x0080)
+               seq_printf(m, "0x00000080\tPCI Express Uncorrectable non-fatal\n");
+       if (available_error_type & 0x0100)
+               seq_printf(m, "0x00000100\tPCI Express Uncorrectable fatal\n");
+       if (available_error_type & 0x0200)
+               seq_printf(m, "0x00000200\tPlatform Correctable\n");
+       if (available_error_type & 0x0400)
+               seq_printf(m, "0x00000400\tPlatform Uncorrectable non-fatal\n");
+       if (available_error_type & 0x0800)
+               seq_printf(m, "0x00000800\tPlatform Uncorrectable fatal\n");
+
+       return 0;
+}
+
+static int available_error_type_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, available_error_type_show, NULL);
+}
+
+static const struct file_operations available_error_type_fops = {
+       .open           = available_error_type_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int error_type_get(void *data, u64 *val)
+{
+       *val = error_type;
+
+       return 0;
+}
+
+static int error_type_set(void *data, u64 val)
+{
+       int rc;
+       u32 available_error_type = 0;
+
+       /* Only one error type can be specified */
+       if (val & (val - 1))
+               return -EINVAL;
+       rc = einj_get_available_error_type(&available_error_type);
+       if (rc)
+               return rc;
+       if (!(val & available_error_type))
+               return -EINVAL;
+       error_type = val;
+
+       return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(error_type_fops, error_type_get,
+                       error_type_set, "0x%llx\n");
+
+static int error_inject_set(void *data, u64 val)
+{
+       if (!error_type)
+               return -EINVAL;
+
+       return einj_error_inject(error_type, error_param1, error_param2);
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(error_inject_fops, NULL,
+                       error_inject_set, "%llu\n");
+
+static int einj_check_table(struct acpi_table_einj *einj_tab)
+{
+       if (einj_tab->header_length != sizeof(struct acpi_table_einj))
+               return -EINVAL;
+       if (einj_tab->header.length < sizeof(struct acpi_table_einj))
+               return -EINVAL;
+       if (einj_tab->entries !=
+           (einj_tab->header.length - sizeof(struct acpi_table_einj)) /
+           sizeof(struct acpi_einj_entry))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int __init einj_init(void)
+{
+       int rc;
+       u64 param_paddr;
+       acpi_status status;
+       struct dentry *fentry;
+       struct apei_exec_context ctx;
+
+       if (acpi_disabled)
+               return -ENODEV;
+
+       status = acpi_get_table(ACPI_SIG_EINJ, 0,
+                               (struct acpi_table_header **)&einj_tab);
+       if (status == AE_NOT_FOUND) {
+               pr_info(EINJ_PFX "Table is not found!\n");
+               return -ENODEV;
+       } else if (ACPI_FAILURE(status)) {
+               const char *msg = acpi_format_exception(status);
+               pr_err(EINJ_PFX "Failed to get table, %s\n", msg);
+               return -EINVAL;
+       }
+
+       rc = einj_check_table(einj_tab);
+       if (rc) {
+               pr_warning(FW_BUG EINJ_PFX "EINJ table is invalid\n");
+               return -EINVAL;
+       }
+
+       rc = -ENOMEM;
+       einj_debug_dir = debugfs_create_dir("einj", apei_get_debugfs_dir());
+       if (!einj_debug_dir)
+               goto err_cleanup;
+       fentry = debugfs_create_file("available_error_type", S_IRUSR,
+                                    einj_debug_dir, NULL,
+                                    &available_error_type_fops);
+       if (!fentry)
+               goto err_cleanup;
+       fentry = debugfs_create_file("error_type", S_IRUSR | S_IWUSR,
+                                    einj_debug_dir, NULL, &error_type_fops);
+       if (!fentry)
+               goto err_cleanup;
+       fentry = debugfs_create_x64("param1", S_IRUSR | S_IWUSR,
+                                   einj_debug_dir, &error_param1);
+       if (!fentry)
+               goto err_cleanup;
+       fentry = debugfs_create_x64("param2", S_IRUSR | S_IWUSR,
+                                   einj_debug_dir, &error_param2);
+       if (!fentry)
+               goto err_cleanup;
+       fentry = debugfs_create_file("error_inject", S_IWUSR,
+                                    einj_debug_dir, NULL, &error_inject_fops);
+       if (!fentry)
+               goto err_cleanup;
+
+       apei_resources_init(&einj_resources);
+       einj_exec_ctx_init(&ctx);
+       rc = apei_exec_collect_resources(&ctx, &einj_resources);
+       if (rc)
+               goto err_fini;
+       rc = apei_resources_request(&einj_resources, "APEI EINJ");
+       if (rc)
+               goto err_fini;
+       rc = apei_exec_pre_map_gars(&ctx);
+       if (rc)
+               goto err_release;
+       param_paddr = einj_get_parameter_address();
+       if (param_paddr) {
+               einj_param = ioremap(param_paddr, sizeof(*einj_param));
+               rc = -ENOMEM;
+               if (!einj_param)
+                       goto err_unmap;
+       }
+
+       pr_info(EINJ_PFX "Error INJection is initialized.\n");
+
+       return 0;
+
+err_unmap:
+       apei_exec_post_unmap_gars(&ctx);
+err_release:
+       apei_resources_release(&einj_resources);
+err_fini:
+       apei_resources_fini(&einj_resources);
+err_cleanup:
+       debugfs_remove_recursive(einj_debug_dir);
+
+       return rc;
+}
+
+static void __exit einj_exit(void)
+{
+       struct apei_exec_context ctx;
+
+       if (einj_param)
+               iounmap(einj_param);
+       einj_exec_ctx_init(&ctx);
+       apei_exec_post_unmap_gars(&ctx);
+       apei_resources_release(&einj_resources);
+       apei_resources_fini(&einj_resources);
+       debugfs_remove_recursive(einj_debug_dir);
+}
+
+module_init(einj_init);
+module_exit(einj_exit);
+
+MODULE_AUTHOR("Huang Ying");
+MODULE_DESCRIPTION("APEI Error INJection support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c
new file mode 100644 (file)
index 0000000..2ebc391
--- /dev/null
@@ -0,0 +1,855 @@
+/*
+ * APEI Error Record Serialization Table support
+ *
+ * ERST is a way provided by APEI to save and retrieve hardware error
+ * infomation to and from a persistent store.
+ *
+ * For more information about ERST, please refer to ACPI Specification
+ * version 4.0, section 17.4.
+ *
+ * Copyright 2010 Intel Corp.
+ *   Author: Huang Ying <ying.huang@intel.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/acpi.h>
+#include <linux/uaccess.h>
+#include <linux/cper.h>
+#include <linux/nmi.h>
+#include <acpi/apei.h>
+
+#include "apei-internal.h"
+
+#define ERST_PFX "ERST: "
+
+/* ERST command status */
+#define ERST_STATUS_SUCCESS                    0x0
+#define ERST_STATUS_NOT_ENOUGH_SPACE           0x1
+#define ERST_STATUS_HARDWARE_NOT_AVAILABLE     0x2
+#define ERST_STATUS_FAILED                     0x3
+#define ERST_STATUS_RECORD_STORE_EMPTY         0x4
+#define ERST_STATUS_RECORD_NOT_FOUND           0x5
+
+#define ERST_TAB_ENTRY(tab)                                            \
+       ((struct acpi_whea_header *)((char *)(tab) +                    \
+                                    sizeof(struct acpi_table_erst)))
+
+#define SPIN_UNIT              100                     /* 100ns */
+/* Firmware should respond within 1 miliseconds */
+#define FIRMWARE_TIMEOUT       (1 * NSEC_PER_MSEC)
+#define FIRMWARE_MAX_STALL     50                      /* 50us */
+
+int erst_disable;
+EXPORT_SYMBOL_GPL(erst_disable);
+
+static struct acpi_table_erst *erst_tab;
+
+/* ERST Error Log Address Range atrributes */
+#define ERST_RANGE_RESERVED    0x0001
+#define ERST_RANGE_NVRAM       0x0002
+#define ERST_RANGE_SLOW                0x0004
+
+/*
+ * ERST Error Log Address Range, used as buffer for reading/writing
+ * error records.
+ */
+static struct erst_erange {
+       u64 base;
+       u64 size;
+       void __iomem *vaddr;
+       u32 attr;
+} erst_erange;
+
+/*
+ * Prevent ERST interpreter to run simultaneously, because the
+ * corresponding firmware implementation may not work properly when
+ * invoked simultaneously.
+ *
+ * It is used to provide exclusive accessing for ERST Error Log
+ * Address Range too.
+ */
+static DEFINE_SPINLOCK(erst_lock);
+
+static inline int erst_errno(int command_status)
+{
+       switch (command_status) {
+       case ERST_STATUS_SUCCESS:
+               return 0;
+       case ERST_STATUS_HARDWARE_NOT_AVAILABLE:
+               return -ENODEV;
+       case ERST_STATUS_NOT_ENOUGH_SPACE:
+               return -ENOSPC;
+       case ERST_STATUS_RECORD_STORE_EMPTY:
+       case ERST_STATUS_RECORD_NOT_FOUND:
+               return -ENOENT;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int erst_timedout(u64 *t, u64 spin_unit)
+{
+       if ((s64)*t < spin_unit) {
+               pr_warning(FW_WARN ERST_PFX
+                          "Firmware does not respond in time\n");
+               return 1;
+       }
+       *t -= spin_unit;
+       ndelay(spin_unit);
+       touch_nmi_watchdog();
+       return 0;
+}
+
+static int erst_exec_load_var1(struct apei_exec_context *ctx,
+                              struct acpi_whea_header *entry)
+{
+       return __apei_exec_read_register(entry, &ctx->var1);
+}
+
+static int erst_exec_load_var2(struct apei_exec_context *ctx,
+                              struct acpi_whea_header *entry)
+{
+       return __apei_exec_read_register(entry, &ctx->var2);
+}
+
+static int erst_exec_store_var1(struct apei_exec_context *ctx,
+                               struct acpi_whea_header *entry)
+{
+       return __apei_exec_write_register(entry, ctx->var1);
+}
+
+static int erst_exec_add(struct apei_exec_context *ctx,
+                        struct acpi_whea_header *entry)
+{
+       ctx->var1 += ctx->var2;
+       return 0;
+}
+
+static int erst_exec_subtract(struct apei_exec_context *ctx,
+                             struct acpi_whea_header *entry)
+{
+       ctx->var1 -= ctx->var2;
+       return 0;
+}
+
+static int erst_exec_add_value(struct apei_exec_context *ctx,
+                              struct acpi_whea_header *entry)
+{
+       int rc;
+       u64 val;
+
+       rc = __apei_exec_read_register(entry, &val);
+       if (rc)
+               return rc;
+       val += ctx->value;
+       rc = __apei_exec_write_register(entry, val);
+       return rc;
+}
+
+static int erst_exec_subtract_value(struct apei_exec_context *ctx,
+                                   struct acpi_whea_header *entry)
+{
+       int rc;
+       u64 val;
+
+       rc = __apei_exec_read_register(entry, &val);
+       if (rc)
+               return rc;
+       val -= ctx->value;
+       rc = __apei_exec_write_register(entry, val);
+       return rc;
+}
+
+static int erst_exec_stall(struct apei_exec_context *ctx,
+                          struct acpi_whea_header *entry)
+{
+       u64 stall_time;
+
+       if (ctx->value > FIRMWARE_MAX_STALL) {
+               if (!in_nmi())
+                       pr_warning(FW_WARN ERST_PFX
+                       "Too long stall time for stall instruction: %llx.\n",
+                                  ctx->value);
+               stall_time = FIRMWARE_MAX_STALL;
+       } else
+               stall_time = ctx->value;
+       udelay(stall_time);
+       return 0;
+}
+
+static int erst_exec_stall_while_true(struct apei_exec_context *ctx,
+                                     struct acpi_whea_header *entry)
+{
+       int rc;
+       u64 val;
+       u64 timeout = FIRMWARE_TIMEOUT;
+       u64 stall_time;
+
+       if (ctx->var1 > FIRMWARE_MAX_STALL) {
+               if (!in_nmi())
+                       pr_warning(FW_WARN ERST_PFX
+               "Too long stall time for stall while true instruction: %llx.\n",
+                                  ctx->var1);
+               stall_time = FIRMWARE_MAX_STALL;
+       } else
+               stall_time = ctx->var1;
+
+       for (;;) {
+               rc = __apei_exec_read_register(entry, &val);
+               if (rc)
+                       return rc;
+               if (val != ctx->value)
+                       break;
+               if (erst_timedout(&timeout, stall_time * NSEC_PER_USEC))
+                       return -EIO;
+       }
+       return 0;
+}
+
+static int erst_exec_skip_next_instruction_if_true(
+       struct apei_exec_context *ctx,
+       struct acpi_whea_header *entry)
+{
+       int rc;
+       u64 val;
+
+       rc = __apei_exec_read_register(entry, &val);
+       if (rc)
+               return rc;
+       if (val == ctx->value) {
+               ctx->ip += 2;
+               return APEI_EXEC_SET_IP;
+       }
+
+       return 0;
+}
+
+static int erst_exec_goto(struct apei_exec_context *ctx,
+                         struct acpi_whea_header *entry)
+{
+       ctx->ip = ctx->value;
+       return APEI_EXEC_SET_IP;
+}
+
+static int erst_exec_set_src_address_base(struct apei_exec_context *ctx,
+                                         struct acpi_whea_header *entry)
+{
+       return __apei_exec_read_register(entry, &ctx->src_base);
+}
+
+static int erst_exec_set_dst_address_base(struct apei_exec_context *ctx,
+                                         struct acpi_whea_header *entry)
+{
+       return __apei_exec_read_register(entry, &ctx->dst_base);
+}
+
+static int erst_exec_move_data(struct apei_exec_context *ctx,
+                              struct acpi_whea_header *entry)
+{
+       int rc;
+       u64 offset;
+
+       rc = __apei_exec_read_register(entry, &offset);
+       if (rc)
+               return rc;
+       memmove((void *)ctx->dst_base + offset,
+               (void *)ctx->src_base + offset,
+               ctx->var2);
+
+       return 0;
+}
+
+static struct apei_exec_ins_type erst_ins_type[] = {
+       [ACPI_ERST_READ_REGISTER] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run = apei_exec_read_register,
+       },
+       [ACPI_ERST_READ_REGISTER_VALUE] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run = apei_exec_read_register_value,
+       },
+       [ACPI_ERST_WRITE_REGISTER] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run = apei_exec_write_register,
+       },
+       [ACPI_ERST_WRITE_REGISTER_VALUE] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run = apei_exec_write_register_value,
+       },
+       [ACPI_ERST_NOOP] = {
+               .flags = 0,
+               .run = apei_exec_noop,
+       },
+       [ACPI_ERST_LOAD_VAR1] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run = erst_exec_load_var1,
+       },
+       [ACPI_ERST_LOAD_VAR2] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run = erst_exec_load_var2,
+       },
+       [ACPI_ERST_STORE_VAR1] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run = erst_exec_store_var1,
+       },
+       [ACPI_ERST_ADD] = {
+               .flags = 0,
+               .run = erst_exec_add,
+       },
+       [ACPI_ERST_SUBTRACT] = {
+               .flags = 0,
+               .run = erst_exec_subtract,
+       },
+       [ACPI_ERST_ADD_VALUE] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run = erst_exec_add_value,
+       },
+       [ACPI_ERST_SUBTRACT_VALUE] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run = erst_exec_subtract_value,
+       },
+       [ACPI_ERST_STALL] = {
+               .flags = 0,
+               .run = erst_exec_stall,
+       },
+       [ACPI_ERST_STALL_WHILE_TRUE] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run = erst_exec_stall_while_true,
+       },
+       [ACPI_ERST_SKIP_NEXT_IF_TRUE] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run = erst_exec_skip_next_instruction_if_true,
+       },
+       [ACPI_ERST_GOTO] = {
+               .flags = 0,
+               .run = erst_exec_goto,
+       },
+       [ACPI_ERST_SET_SRC_ADDRESS_BASE] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run = erst_exec_set_src_address_base,
+       },
+       [ACPI_ERST_SET_DST_ADDRESS_BASE] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run = erst_exec_set_dst_address_base,
+       },
+       [ACPI_ERST_MOVE_DATA] = {
+               .flags = APEI_EXEC_INS_ACCESS_REGISTER,
+               .run = erst_exec_move_data,
+       },
+};
+
+static inline void erst_exec_ctx_init(struct apei_exec_context *ctx)
+{
+       apei_exec_ctx_init(ctx, erst_ins_type, ARRAY_SIZE(erst_ins_type),
+                          ERST_TAB_ENTRY(erst_tab), erst_tab->entries);
+}
+
+static int erst_get_erange(struct erst_erange *range)
+{
+       struct apei_exec_context ctx;
+       int rc;
+
+       erst_exec_ctx_init(&ctx);
+       rc = apei_exec_run(&ctx, ACPI_ERST_GET_ERROR_RANGE);
+       if (rc)
+               return rc;
+       range->base = apei_exec_ctx_get_output(&ctx);
+       rc = apei_exec_run(&ctx, ACPI_ERST_GET_ERROR_LENGTH);
+       if (rc)
+               return rc;
+       range->size = apei_exec_ctx_get_output(&ctx);
+       rc = apei_exec_run(&ctx, ACPI_ERST_GET_ERROR_ATTRIBUTES);
+       if (rc)
+               return rc;
+       range->attr = apei_exec_ctx_get_output(&ctx);
+
+       return 0;
+}
+
+static ssize_t __erst_get_record_count(void)
+{
+       struct apei_exec_context ctx;
+       int rc;
+
+       erst_exec_ctx_init(&ctx);
+       rc = apei_exec_run(&ctx, ACPI_ERST_GET_RECORD_COUNT);
+       if (rc)
+               return rc;
+       return apei_exec_ctx_get_output(&ctx);
+}
+
+ssize_t erst_get_record_count(void)
+{
+       ssize_t count;
+       unsigned long flags;
+
+       if (erst_disable)
+               return -ENODEV;
+
+       spin_lock_irqsave(&erst_lock, flags);
+       count = __erst_get_record_count();
+       spin_unlock_irqrestore(&erst_lock, flags);
+
+       return count;
+}
+EXPORT_SYMBOL_GPL(erst_get_record_count);
+
+static int __erst_get_next_record_id(u64 *record_id)
+{
+       struct apei_exec_context ctx;
+       int rc;
+
+       erst_exec_ctx_init(&ctx);
+       rc = apei_exec_run(&ctx, ACPI_ERST_GET_RECORD_ID);
+       if (rc)
+               return rc;
+       *record_id = apei_exec_ctx_get_output(&ctx);
+
+       return 0;
+}
+
+/*
+ * Get the record ID of an existing error record on the persistent
+ * storage. If there is no error record on the persistent storage, the
+ * returned record_id is APEI_ERST_INVALID_RECORD_ID.
+ */
+int erst_get_next_record_id(u64 *record_id)
+{
+       int rc;
+       unsigned long flags;
+
+       if (erst_disable)
+               return -ENODEV;
+
+       spin_lock_irqsave(&erst_lock, flags);
+       rc = __erst_get_next_record_id(record_id);
+       spin_unlock_irqrestore(&erst_lock, flags);
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(erst_get_next_record_id);
+
+static int __erst_write_to_storage(u64 offset)
+{
+       struct apei_exec_context ctx;
+       u64 timeout = FIRMWARE_TIMEOUT;
+       u64 val;
+       int rc;
+
+       erst_exec_ctx_init(&ctx);
+       rc = apei_exec_run(&ctx, ACPI_ERST_BEGIN_WRITE);
+       if (rc)
+               return rc;
+       apei_exec_ctx_set_input(&ctx, offset);
+       rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_OFFSET);
+       if (rc)
+               return rc;
+       rc = apei_exec_run(&ctx, ACPI_ERST_EXECUTE_OPERATION);
+       if (rc)
+               return rc;
+       for (;;) {
+               rc = apei_exec_run(&ctx, ACPI_ERST_CHECK_BUSY_STATUS);
+               if (rc)
+                       return rc;
+               val = apei_exec_ctx_get_output(&ctx);
+               if (!val)
+                       break;
+               if (erst_timedout(&timeout, SPIN_UNIT))
+                       return -EIO;
+       }
+       rc = apei_exec_run(&ctx, ACPI_ERST_GET_COMMAND_STATUS);
+       if (rc)
+               return rc;
+       val = apei_exec_ctx_get_output(&ctx);
+       rc = apei_exec_run(&ctx, ACPI_ERST_END);
+       if (rc)
+               return rc;
+
+       return erst_errno(val);
+}
+
+static int __erst_read_from_storage(u64 record_id, u64 offset)
+{
+       struct apei_exec_context ctx;
+       u64 timeout = FIRMWARE_TIMEOUT;
+       u64 val;
+       int rc;
+
+       erst_exec_ctx_init(&ctx);
+       rc = apei_exec_run(&ctx, ACPI_ERST_BEGIN_READ);
+       if (rc)
+               return rc;
+       apei_exec_ctx_set_input(&ctx, offset);
+       rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_OFFSET);
+       if (rc)
+               return rc;
+       apei_exec_ctx_set_input(&ctx, record_id);
+       rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_ID);
+       if (rc)
+               return rc;
+       rc = apei_exec_run(&ctx, ACPI_ERST_EXECUTE_OPERATION);
+       if (rc)
+               return rc;
+       for (;;) {
+               rc = apei_exec_run(&ctx, ACPI_ERST_CHECK_BUSY_STATUS);
+               if (rc)
+                       return rc;
+               val = apei_exec_ctx_get_output(&ctx);
+               if (!val)
+                       break;
+               if (erst_timedout(&timeout, SPIN_UNIT))
+                       return -EIO;
+       };
+       rc = apei_exec_run(&ctx, ACPI_ERST_GET_COMMAND_STATUS);
+       if (rc)
+               return rc;
+       val = apei_exec_ctx_get_output(&ctx);
+       rc = apei_exec_run(&ctx, ACPI_ERST_END);
+       if (rc)
+               return rc;
+
+       return erst_errno(val);
+}
+
+static int __erst_clear_from_storage(u64 record_id)
+{
+       struct apei_exec_context ctx;
+       u64 timeout = FIRMWARE_TIMEOUT;
+       u64 val;
+       int rc;
+
+       erst_exec_ctx_init(&ctx);
+       rc = apei_exec_run(&ctx, ACPI_ERST_BEGIN_CLEAR);
+       if (rc)
+               return rc;
+       apei_exec_ctx_set_input(&ctx, record_id);
+       rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_ID);
+       if (rc)
+               return rc;
+       rc = apei_exec_run(&ctx, ACPI_ERST_EXECUTE_OPERATION);
+       if (rc)
+               return rc;
+       for (;;) {
+               rc = apei_exec_run(&ctx, ACPI_ERST_CHECK_BUSY_STATUS);
+               if (rc)
+                       return rc;
+               val = apei_exec_ctx_get_output(&ctx);
+               if (!val)
+                       break;
+               if (erst_timedout(&timeout, SPIN_UNIT))
+                       return -EIO;
+       }
+       rc = apei_exec_run(&ctx, ACPI_ERST_GET_COMMAND_STATUS);
+       if (rc)
+               return rc;
+       val = apei_exec_ctx_get_output(&ctx);
+       rc = apei_exec_run(&ctx, ACPI_ERST_END);
+       if (rc)
+               return rc;
+
+       return erst_errno(val);
+}
+
+/* NVRAM ERST Error Log Address Range is not supported yet */
+static void pr_unimpl_nvram(void)
+{
+       if (printk_ratelimit())
+               pr_warning(ERST_PFX
+               "NVRAM ERST Log Address Range is not implemented yet\n");
+}
+
+static int __erst_write_to_nvram(const struct cper_record_header *record)
+{
+       /* do not print message, because printk is not safe for NMI */
+       return -ENOSYS;
+}
+
+static int __erst_read_to_erange_from_nvram(u64 record_id, u64 *offset)
+{
+       pr_unimpl_nvram();
+       return -ENOSYS;
+}
+
+static int __erst_clear_from_nvram(u64 record_id)
+{
+       pr_unimpl_nvram();
+       return -ENOSYS;
+}
+
+int erst_write(const struct cper_record_header *record)
+{
+       int rc;
+       unsigned long flags;
+       struct cper_record_header *rcd_erange;
+
+       if (erst_disable)
+               return -ENODEV;
+
+       if (memcmp(record->signature, CPER_SIG_RECORD, CPER_SIG_SIZE))
+               return -EINVAL;
+
+       if (erst_erange.attr & ERST_RANGE_NVRAM) {
+               if (!spin_trylock_irqsave(&erst_lock, flags))
+                       return -EBUSY;
+               rc = __erst_write_to_nvram(record);
+               spin_unlock_irqrestore(&erst_lock, flags);
+               return rc;
+       }
+
+       if (record->record_length > erst_erange.size)
+               return -EINVAL;
+
+       if (!spin_trylock_irqsave(&erst_lock, flags))
+               return -EBUSY;
+       memcpy(erst_erange.vaddr, record, record->record_length);
+       rcd_erange = erst_erange.vaddr;
+       /* signature for serialization system */
+       memcpy(&rcd_erange->persistence_information, "ER", 2);
+
+       rc = __erst_write_to_storage(0);
+       spin_unlock_irqrestore(&erst_lock, flags);
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(erst_write);
+
+static int __erst_read_to_erange(u64 record_id, u64 *offset)
+{
+       int rc;
+
+       if (erst_erange.attr & ERST_RANGE_NVRAM)
+               return __erst_read_to_erange_from_nvram(
+                       record_id, offset);
+
+       rc = __erst_read_from_storage(record_id, 0);
+       if (rc)
+               return rc;
+       *offset = 0;
+
+       return 0;
+}
+
+static ssize_t __erst_read(u64 record_id, struct cper_record_header *record,
+                          size_t buflen)
+{
+       int rc;
+       u64 offset, len = 0;
+       struct cper_record_header *rcd_tmp;
+
+       rc = __erst_read_to_erange(record_id, &offset);
+       if (rc)
+               return rc;
+       rcd_tmp = erst_erange.vaddr + offset;
+       len = rcd_tmp->record_length;
+       if (len <= buflen)
+               memcpy(record, rcd_tmp, len);
+
+       return len;
+}
+
+/*
+ * If return value > buflen, the buffer size is not big enough,
+ * else if return value < 0, something goes wrong,
+ * else everything is OK, and return value is record length
+ */
+ssize_t erst_read(u64 record_id, struct cper_record_header *record,
+                 size_t buflen)
+{
+       ssize_t len;
+       unsigned long flags;
+
+       if (erst_disable)
+               return -ENODEV;
+
+       spin_lock_irqsave(&erst_lock, flags);
+       len = __erst_read(record_id, record, buflen);
+       spin_unlock_irqrestore(&erst_lock, flags);
+       return len;
+}
+EXPORT_SYMBOL_GPL(erst_read);
+
+/*
+ * If return value > buflen, the buffer size is not big enough,
+ * else if return value = 0, there is no more record to read,
+ * else if return value < 0, something goes wrong,
+ * else everything is OK, and return value is record length
+ */
+ssize_t erst_read_next(struct cper_record_header *record, size_t buflen)
+{
+       int rc;
+       ssize_t len;
+       unsigned long flags;
+       u64 record_id;
+
+       if (erst_disable)
+               return -ENODEV;
+
+       spin_lock_irqsave(&erst_lock, flags);
+       rc = __erst_get_next_record_id(&record_id);
+       if (rc) {
+               spin_unlock_irqrestore(&erst_lock, flags);
+               return rc;
+       }
+       /* no more record */
+       if (record_id == APEI_ERST_INVALID_RECORD_ID) {
+               spin_unlock_irqrestore(&erst_lock, flags);
+               return 0;
+       }
+
+       len = __erst_read(record_id, record, buflen);
+       spin_unlock_irqrestore(&erst_lock, flags);
+
+       return len;
+}
+EXPORT_SYMBOL_GPL(erst_read_next);
+
+int erst_clear(u64 record_id)
+{
+       int rc;
+       unsigned long flags;
+
+       if (erst_disable)
+               return -ENODEV;
+
+       spin_lock_irqsave(&erst_lock, flags);
+       if (erst_erange.attr & ERST_RANGE_NVRAM)
+               rc = __erst_clear_from_nvram(record_id);
+       else
+               rc = __erst_clear_from_storage(record_id);
+       spin_unlock_irqrestore(&erst_lock, flags);
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(erst_clear);
+
+static int __init setup_erst_disable(char *str)
+{
+       erst_disable = 1;
+       return 0;
+}
+
+__setup("erst_disable", setup_erst_disable);
+
+static int erst_check_table(struct acpi_table_erst *erst_tab)
+{
+       if (erst_tab->header_length != sizeof(struct acpi_table_erst))
+               return -EINVAL;
+       if (erst_tab->header.length < sizeof(struct acpi_table_erst))
+               return -EINVAL;
+       if (erst_tab->entries !=
+           (erst_tab->header.length - sizeof(struct acpi_table_erst)) /
+           sizeof(struct acpi_erst_entry))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int __init erst_init(void)
+{
+       int rc = 0;
+       acpi_status status;
+       struct apei_exec_context ctx;
+       struct apei_resources erst_resources;
+       struct resource *r;
+
+       if (acpi_disabled)
+               goto err;
+
+       if (erst_disable) {
+               pr_info(ERST_PFX
+       "Error Record Serialization Table (ERST) support is disabled.\n");
+               goto err;
+       }
+
+       status = acpi_get_table(ACPI_SIG_ERST, 0,
+                               (struct acpi_table_header **)&erst_tab);
+       if (status == AE_NOT_FOUND) {
+               pr_err(ERST_PFX "Table is not found!\n");
+               goto err;
+       } else if (ACPI_FAILURE(status)) {
+               const char *msg = acpi_format_exception(status);
+               pr_err(ERST_PFX "Failed to get table, %s\n", msg);
+               rc = -EINVAL;
+               goto err;
+       }
+
+       rc = erst_check_table(erst_tab);
+       if (rc) {
+               pr_err(FW_BUG ERST_PFX "ERST table is invalid\n");
+               goto err;
+       }
+
+       apei_resources_init(&erst_resources);
+       erst_exec_ctx_init(&ctx);
+       rc = apei_exec_collect_resources(&ctx, &erst_resources);
+       if (rc)
+               goto err_fini;
+       rc = apei_resources_request(&erst_resources, "APEI ERST");
+       if (rc)
+               goto err_fini;
+       rc = apei_exec_pre_map_gars(&ctx);
+       if (rc)
+               goto err_release;
+       rc = erst_get_erange(&erst_erange);
+       if (rc) {
+               if (rc == -ENODEV)
+                       pr_info(ERST_PFX
+       "The corresponding hardware device or firmware implementation "
+       "is not available.\n");
+               else
+                       pr_err(ERST_PFX
+                              "Failed to get Error Log Address Range.\n");
+               goto err_unmap_reg;
+       }
+
+       r = request_mem_region(erst_erange.base, erst_erange.size, "APEI ERST");
+       if (!r) {
+               pr_err(ERST_PFX
+               "Can not request iomem region <0x%16llx-0x%16llx> for ERST.\n",
+               (unsigned long long)erst_erange.base,
+               (unsigned long long)erst_erange.base + erst_erange.size);
+               rc = -EIO;
+               goto err_unmap_reg;
+       }
+       rc = -ENOMEM;
+       erst_erange.vaddr = ioremap_cache(erst_erange.base,
+                                         erst_erange.size);
+       if (!erst_erange.vaddr)
+               goto err_release_erange;
+
+       pr_info(ERST_PFX
+       "Error Record Serialization Table (ERST) support is initialized.\n");
+
+       return 0;
+
+err_release_erange:
+       release_mem_region(erst_erange.base, erst_erange.size);
+err_unmap_reg:
+       apei_exec_post_unmap_gars(&ctx);
+err_release:
+       apei_resources_release(&erst_resources);
+err_fini:
+       apei_resources_fini(&erst_resources);
+err:
+       erst_disable = 1;
+       return rc;
+}
+
+device_initcall(erst_init);
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
new file mode 100644 (file)
index 0000000..fd0cc01
--- /dev/null
@@ -0,0 +1,427 @@
+/*
+ * APEI Generic Hardware Error Source support
+ *
+ * Generic Hardware Error Source provides a way to report platform
+ * hardware errors (such as that from chipset). It works in so called
+ * "Firmware First" mode, that is, hardware errors are reported to
+ * firmware firstly, then reported to Linux by firmware. This way,
+ * some non-standard hardware error registers or non-standard hardware
+ * link can be checked by firmware to produce more hardware error
+ * information for Linux.
+ *
+ * For more information about Generic Hardware Error Source, please
+ * refer to ACPI Specification version 4.0, section 17.3.2.6
+ *
+ * Now, only SCI notification type and memory errors are
+ * supported. More notification type and hardware error type will be
+ * added later.
+ *
+ * Copyright 2010 Intel Corp.
+ *   Author: Huang Ying <ying.huang@intel.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/cper.h>
+#include <linux/kdebug.h>
+#include <acpi/apei.h>
+#include <acpi/atomicio.h>
+#include <acpi/hed.h>
+#include <asm/mce.h>
+
+#include "apei-internal.h"
+
+#define GHES_PFX       "GHES: "
+
+#define GHES_ESTATUS_MAX_SIZE          65536
+
+/*
+ * One struct ghes is created for each generic hardware error
+ * source.
+ *
+ * It provides the context for APEI hardware error timer/IRQ/SCI/NMI
+ * handler. Handler for one generic hardware error source is only
+ * triggered after the previous one is done. So handler can uses
+ * struct ghes without locking.
+ *
+ * estatus: memory buffer for error status block, allocated during
+ * HEST parsing.
+ */
+#define GHES_TO_CLEAR          0x0001
+
+struct ghes {
+       struct acpi_hest_generic *generic;
+       struct acpi_hest_generic_status *estatus;
+       struct list_head list;
+       u64 buffer_paddr;
+       unsigned long flags;
+};
+
+/*
+ * Error source lists, one list for each notification method. The
+ * members in lists are struct ghes.
+ *
+ * The list members are only added in HEST parsing and deleted during
+ * module_exit, that is, single-threaded. So no lock is needed for
+ * that.
+ *
+ * But the mutual exclusion is needed between members adding/deleting
+ * and timer/IRQ/SCI/NMI handler, which may traverse the list. RCU is
+ * used for that.
+ */
+static LIST_HEAD(ghes_sci);
+
+static struct ghes *ghes_new(struct acpi_hest_generic *generic)
+{
+       struct ghes *ghes;
+       unsigned int error_block_length;
+       int rc;
+
+       ghes = kzalloc(sizeof(*ghes), GFP_KERNEL);
+       if (!ghes)
+               return ERR_PTR(-ENOMEM);
+       ghes->generic = generic;
+       INIT_LIST_HEAD(&ghes->list);
+       rc = acpi_pre_map_gar(&generic->error_status_address);
+       if (rc)
+               goto err_free;
+       error_block_length = generic->error_block_length;
+       if (error_block_length > GHES_ESTATUS_MAX_SIZE) {
+               pr_warning(FW_WARN GHES_PFX
+                          "Error status block length is too long: %u for "
+                          "generic hardware error source: %d.\n",
+                          error_block_length, generic->header.source_id);
+               error_block_length = GHES_ESTATUS_MAX_SIZE;
+       }
+       ghes->estatus = kmalloc(error_block_length, GFP_KERNEL);
+       if (!ghes->estatus) {
+               rc = -ENOMEM;
+               goto err_unmap;
+       }
+
+       return ghes;
+
+err_unmap:
+       acpi_post_unmap_gar(&generic->error_status_address);
+err_free:
+       kfree(ghes);
+       return ERR_PTR(rc);
+}
+
+static void ghes_fini(struct ghes *ghes)
+{
+       kfree(ghes->estatus);
+       acpi_post_unmap_gar(&ghes->generic->error_status_address);
+}
+
+enum {
+       GHES_SER_NO = 0x0,
+       GHES_SER_CORRECTED = 0x1,
+       GHES_SER_RECOVERABLE = 0x2,
+       GHES_SER_PANIC = 0x3,
+};
+
+static inline int ghes_severity(int severity)
+{
+       switch (severity) {
+       case CPER_SER_INFORMATIONAL:
+               return GHES_SER_NO;
+       case CPER_SER_CORRECTED:
+               return GHES_SER_CORRECTED;
+       case CPER_SER_RECOVERABLE:
+               return GHES_SER_RECOVERABLE;
+       case CPER_SER_FATAL:
+               return GHES_SER_PANIC;
+       default:
+               /* Unkown, go panic */
+               return GHES_SER_PANIC;
+       }
+}
+
+/* SCI handler run in work queue, so ioremap can be used here */
+static int ghes_copy_tofrom_phys(void *buffer, u64 paddr, u32 len,
+                                int from_phys)
+{
+       void *vaddr;
+
+       vaddr = ioremap_cache(paddr, len);
+       if (!vaddr)
+               return -ENOMEM;
+       if (from_phys)
+               memcpy(buffer, vaddr, len);
+       else
+               memcpy(vaddr, buffer, len);
+       iounmap(vaddr);
+
+       return 0;
+}
+
+static int ghes_read_estatus(struct ghes *ghes, int silent)
+{
+       struct acpi_hest_generic *g = ghes->generic;
+       u64 buf_paddr;
+       u32 len;
+       int rc;
+
+       rc = acpi_atomic_read(&buf_paddr, &g->error_status_address);
+       if (rc) {
+               if (!silent && printk_ratelimit())
+                       pr_warning(FW_WARN GHES_PFX
+"Failed to read error status block address for hardware error source: %d.\n",
+                                  g->header.source_id);
+               return -EIO;
+       }
+       if (!buf_paddr)
+               return -ENOENT;
+
+       rc = ghes_copy_tofrom_phys(ghes->estatus, buf_paddr,
+                                  sizeof(*ghes->estatus), 1);
+       if (rc)
+               return rc;
+       if (!ghes->estatus->block_status)
+               return -ENOENT;
+
+       ghes->buffer_paddr = buf_paddr;
+       ghes->flags |= GHES_TO_CLEAR;
+
+       rc = -EIO;
+       len = apei_estatus_len(ghes->estatus);
+       if (len < sizeof(*ghes->estatus))
+               goto err_read_block;
+       if (len > ghes->generic->error_block_length)
+               goto err_read_block;
+       if (apei_estatus_check_header(ghes->estatus))
+               goto err_read_block;
+       rc = ghes_copy_tofrom_phys(ghes->estatus + 1,
+                                  buf_paddr + sizeof(*ghes->estatus),
+                                  len - sizeof(*ghes->estatus), 1);
+       if (rc)
+               return rc;
+       if (apei_estatus_check(ghes->estatus))
+               goto err_read_block;
+       rc = 0;
+
+err_read_block:
+       if (rc && !silent)
+               pr_warning(FW_WARN GHES_PFX
+                          "Failed to read error status block!\n");
+       return rc;
+}
+
+static void ghes_clear_estatus(struct ghes *ghes)
+{
+       ghes->estatus->block_status = 0;
+       if (!(ghes->flags & GHES_TO_CLEAR))
+               return;
+       ghes_copy_tofrom_phys(ghes->estatus, ghes->buffer_paddr,
+                             sizeof(ghes->estatus->block_status), 0);
+       ghes->flags &= ~GHES_TO_CLEAR;
+}
+
+static void ghes_do_proc(struct ghes *ghes)
+{
+       int ser, processed = 0;
+       struct acpi_hest_generic_data *gdata;
+
+       ser = ghes_severity(ghes->estatus->error_severity);
+       apei_estatus_for_each_section(ghes->estatus, gdata) {
+#ifdef CONFIG_X86_MCE
+               if (!uuid_le_cmp(*(uuid_le *)gdata->section_type,
+                                CPER_SEC_PLATFORM_MEM)) {
+                       apei_mce_report_mem_error(
+                               ser == GHES_SER_CORRECTED,
+                               (struct cper_sec_mem_err *)(gdata+1));
+                       processed = 1;
+               }
+#endif
+       }
+
+       if (!processed && printk_ratelimit())
+               pr_warning(GHES_PFX
+               "Unknown error record from generic hardware error source: %d\n",
+                          ghes->generic->header.source_id);
+}
+
+static int ghes_proc(struct ghes *ghes)
+{
+       int rc;
+
+       rc = ghes_read_estatus(ghes, 0);
+       if (rc)
+               goto out;
+       ghes_do_proc(ghes);
+
+out:
+       ghes_clear_estatus(ghes);
+       return 0;
+}
+
+static int ghes_notify_sci(struct notifier_block *this,
+                                 unsigned long event, void *data)
+{
+       struct ghes *ghes;
+       int ret = NOTIFY_DONE;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(ghes, &ghes_sci, list) {
+               if (!ghes_proc(ghes))
+                       ret = NOTIFY_OK;
+       }
+       rcu_read_unlock();
+
+       return ret;
+}
+
+static struct notifier_block ghes_notifier_sci = {
+       .notifier_call = ghes_notify_sci,
+};
+
+static int hest_ghes_parse(struct acpi_hest_header *hest_hdr, void *data)
+{
+       struct acpi_hest_generic *generic;
+       struct ghes *ghes = NULL;
+       int rc = 0;
+
+       if (hest_hdr->type != ACPI_HEST_TYPE_GENERIC_ERROR)
+               return 0;
+
+       generic = (struct acpi_hest_generic *)hest_hdr;
+       if (!generic->enabled)
+               return 0;
+
+       if (generic->error_block_length <
+           sizeof(struct acpi_hest_generic_status)) {
+               pr_warning(FW_BUG GHES_PFX
+"Invalid error block length: %u for generic hardware error source: %d\n",
+                          generic->error_block_length,
+                          generic->header.source_id);
+               goto err;
+       }
+       if (generic->records_to_preallocate == 0) {
+               pr_warning(FW_BUG GHES_PFX
+"Invalid records to preallocate: %u for generic hardware error source: %d\n",
+                          generic->records_to_preallocate,
+                          generic->header.source_id);
+               goto err;
+       }
+       ghes = ghes_new(generic);
+       if (IS_ERR(ghes)) {
+               rc = PTR_ERR(ghes);
+               ghes = NULL;
+               goto err;
+       }
+       switch (generic->notify.type) {
+       case ACPI_HEST_NOTIFY_POLLED:
+               pr_warning(GHES_PFX
+"Generic hardware error source: %d notified via POLL is not supported!\n",
+                          generic->header.source_id);
+               break;
+       case ACPI_HEST_NOTIFY_EXTERNAL:
+       case ACPI_HEST_NOTIFY_LOCAL:
+               pr_warning(GHES_PFX
+"Generic hardware error source: %d notified via IRQ is not supported!\n",
+                          generic->header.source_id);
+               break;
+       case ACPI_HEST_NOTIFY_SCI:
+               if (list_empty(&ghes_sci))
+                       register_acpi_hed_notifier(&ghes_notifier_sci);
+               list_add_rcu(&ghes->list, &ghes_sci);
+               break;
+       case ACPI_HEST_NOTIFY_NMI:
+               pr_warning(GHES_PFX
+"Generic hardware error source: %d notified via NMI is not supported!\n",
+                          generic->header.source_id);
+               break;
+       default:
+               pr_warning(FW_WARN GHES_PFX
+       "Unknown notification type: %u for generic hardware error source: %d\n",
+                          generic->notify.type, generic->header.source_id);
+               break;
+       }
+
+       return 0;
+err:
+       if (ghes)
+               ghes_fini(ghes);
+       return rc;
+}
+
+static void ghes_cleanup(void)
+{
+       struct ghes *ghes, *nghes;
+
+       if (!list_empty(&ghes_sci))
+               unregister_acpi_hed_notifier(&ghes_notifier_sci);
+
+       synchronize_rcu();
+
+       list_for_each_entry_safe(ghes, nghes, &ghes_sci, list) {
+               list_del(&ghes->list);
+               ghes_fini(ghes);
+               kfree(ghes);
+       }
+}
+
+static int __init ghes_init(void)
+{
+       int rc;
+
+       if (acpi_disabled)
+               return -ENODEV;
+
+       if (hest_disable) {
+               pr_info(GHES_PFX "HEST is not enabled!\n");
+               return -EINVAL;
+       }
+
+       rc = apei_hest_parse(hest_ghes_parse, NULL);
+       if (rc) {
+               pr_err(GHES_PFX
+               "Error during parsing HEST generic hardware error sources.\n");
+               goto err_cleanup;
+       }
+
+       if (list_empty(&ghes_sci)) {
+               pr_info(GHES_PFX
+                       "No functional generic hardware error sources.\n");
+               rc = -ENODEV;
+               goto err_cleanup;
+       }
+
+       pr_info(GHES_PFX
+               "Generic Hardware Error Source support is initialized.\n");
+
+       return 0;
+err_cleanup:
+       ghes_cleanup();
+       return rc;
+}
+
+static void __exit ghes_exit(void)
+{
+       ghes_cleanup();
+}
+
+module_init(ghes_init);
+module_exit(ghes_exit);
+
+MODULE_AUTHOR("Huang Ying");
+MODULE_DESCRIPTION("APEI Generic Hardware Error Source support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c
new file mode 100644 (file)
index 0000000..e7f40d3
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * APEI Hardware Error Souce Table support
+ *
+ * HEST describes error sources in detail; communicates operational
+ * parameters (i.e. severity levels, masking bits, and threshold
+ * values) to Linux as necessary. It also allows the BIOS to report
+ * non-standard error sources to Linux (for example, chipset-specific
+ * error registers).
+ *
+ * For more information about HEST, please refer to ACPI Specification
+ * version 4.0, section 17.3.2.
+ *
+ * Copyright 2009 Intel Corp.
+ *   Author: Huang Ying <ying.huang@intel.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/kdebug.h>
+#include <linux/highmem.h>
+#include <linux/io.h>
+#include <acpi/apei.h>
+
+#include "apei-internal.h"
+
+#define HEST_PFX "HEST: "
+
+int hest_disable;
+EXPORT_SYMBOL_GPL(hest_disable);
+
+/* HEST table parsing */
+
+static struct acpi_table_hest *hest_tab;
+
+static int hest_void_parse(struct acpi_hest_header *hest_hdr, void *data)
+{
+       return 0;
+}
+
+static int hest_esrc_len_tab[ACPI_HEST_TYPE_RESERVED] = {
+       [ACPI_HEST_TYPE_IA32_CHECK] = -1,       /* need further calculation */
+       [ACPI_HEST_TYPE_IA32_CORRECTED_CHECK] = -1,
+       [ACPI_HEST_TYPE_IA32_NMI] = sizeof(struct acpi_hest_ia_nmi),
+       [ACPI_HEST_TYPE_AER_ROOT_PORT] = sizeof(struct acpi_hest_aer_root),
+       [ACPI_HEST_TYPE_AER_ENDPOINT] = sizeof(struct acpi_hest_aer),
+       [ACPI_HEST_TYPE_AER_BRIDGE] = sizeof(struct acpi_hest_aer_bridge),
+       [ACPI_HEST_TYPE_GENERIC_ERROR] = sizeof(struct acpi_hest_generic),
+};
+
+static int hest_esrc_len(struct acpi_hest_header *hest_hdr)
+{
+       u16 hest_type = hest_hdr->type;
+       int len;
+
+       if (hest_type >= ACPI_HEST_TYPE_RESERVED)
+               return 0;
+
+       len = hest_esrc_len_tab[hest_type];
+
+       if (hest_type == ACPI_HEST_TYPE_IA32_CORRECTED_CHECK) {
+               struct acpi_hest_ia_corrected *cmc;
+               cmc = (struct acpi_hest_ia_corrected *)hest_hdr;
+               len = sizeof(*cmc) + cmc->num_hardware_banks *
+                       sizeof(struct acpi_hest_ia_error_bank);
+       } else if (hest_type == ACPI_HEST_TYPE_IA32_CHECK) {
+               struct acpi_hest_ia_machine_check *mc;
+               mc = (struct acpi_hest_ia_machine_check *)hest_hdr;
+               len = sizeof(*mc) + mc->num_hardware_banks *
+                       sizeof(struct acpi_hest_ia_error_bank);
+       }
+       BUG_ON(len == -1);
+
+       return len;
+};
+
+int apei_hest_parse(apei_hest_func_t func, void *data)
+{
+       struct acpi_hest_header *hest_hdr;
+       int i, rc, len;
+
+       if (hest_disable)
+               return -EINVAL;
+
+       hest_hdr = (struct acpi_hest_header *)(hest_tab + 1);
+       for (i = 0; i < hest_tab->error_source_count; i++) {
+               len = hest_esrc_len(hest_hdr);
+               if (!len) {
+                       pr_warning(FW_WARN HEST_PFX
+                                  "Unknown or unused hardware error source "
+                                  "type: %d for hardware error source: %d.\n",
+                                  hest_hdr->type, hest_hdr->source_id);
+                       return -EINVAL;
+               }
+               if ((void *)hest_hdr + len >
+                   (void *)hest_tab + hest_tab->header.length) {
+                       pr_warning(FW_BUG HEST_PFX
+               "Table contents overflow for hardware error source: %d.\n",
+                               hest_hdr->source_id);
+                       return -EINVAL;
+               }
+
+               rc = func(hest_hdr, data);
+               if (rc)
+                       return rc;
+
+               hest_hdr = (void *)hest_hdr + len;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(apei_hest_parse);
+
+static int __init setup_hest_disable(char *str)
+{
+       hest_disable = 1;
+       return 0;
+}
+
+__setup("hest_disable", setup_hest_disable);
+
+static int __init hest_init(void)
+{
+       acpi_status status;
+       int rc = -ENODEV;
+
+       if (acpi_disabled)
+               goto err;
+
+       if (hest_disable) {
+               pr_info(HEST_PFX "HEST tabling parsing is disabled.\n");
+               goto err;
+       }
+
+       status = acpi_get_table(ACPI_SIG_HEST, 0,
+                               (struct acpi_table_header **)&hest_tab);
+       if (status == AE_NOT_FOUND) {
+               pr_info(HEST_PFX "Table is not found!\n");
+               goto err;
+       } else if (ACPI_FAILURE(status)) {
+               const char *msg = acpi_format_exception(status);
+               pr_err(HEST_PFX "Failed to get table, %s\n", msg);
+               rc = -EINVAL;
+               goto err;
+       }
+
+       rc = apei_hest_parse(hest_void_parse, NULL);
+       if (rc)
+               goto err;
+
+       pr_info(HEST_PFX "HEST table parsing is initialized.\n");
+
+       return 0;
+err:
+       hest_disable = 1;
+       return rc;
+}
+
+subsys_initcall(hest_init);
diff --git a/drivers/acpi/atomicio.c b/drivers/acpi/atomicio.c
new file mode 100644 (file)
index 0000000..814b192
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * atomicio.c - ACPI IO memory pre-mapping/post-unmapping, then
+ * accessing in atomic context.
+ *
+ * This is used for NMI handler to access IO memory area, because
+ * ioremap/iounmap can not be used in NMI handler. The IO memory area
+ * is pre-mapped in process context and accessed in NMI handler.
+ *
+ * Copyright (C) 2009-2010, Intel Corp.
+ *     Author: Huang Ying <ying.huang@intel.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+#include <linux/kref.h>
+#include <linux/rculist.h>
+#include <linux/interrupt.h>
+#include <acpi/atomicio.h>
+
+#define ACPI_PFX "ACPI: "
+
+static LIST_HEAD(acpi_iomaps);
+/*
+ * Used for mutual exclusion between writers of acpi_iomaps list, for
+ * synchronization between readers and writer, RCU is used.
+ */
+static DEFINE_SPINLOCK(acpi_iomaps_lock);
+
+struct acpi_iomap {
+       struct list_head list;
+       void __iomem *vaddr;
+       unsigned long size;
+       phys_addr_t paddr;
+       struct kref ref;
+};
+
+/* acpi_iomaps_lock or RCU read lock must be held before calling */
+static struct acpi_iomap *__acpi_find_iomap(phys_addr_t paddr,
+                                           unsigned long size)
+{
+       struct acpi_iomap *map;
+
+       list_for_each_entry_rcu(map, &acpi_iomaps, list) {
+               if (map->paddr + map->size >= paddr + size &&
+                   map->paddr <= paddr)
+                       return map;
+       }
+       return NULL;
+}
+
+/*
+ * Atomic "ioremap" used by NMI handler, if the specified IO memory
+ * area is not pre-mapped, NULL will be returned.
+ *
+ * acpi_iomaps_lock or RCU read lock must be held before calling
+ */
+static void __iomem *__acpi_ioremap_fast(phys_addr_t paddr,
+                                        unsigned long size)
+{
+       struct acpi_iomap *map;
+
+       map = __acpi_find_iomap(paddr, size);
+       if (map)
+               return map->vaddr + (paddr - map->paddr);
+       else
+               return NULL;
+}
+
+/* acpi_iomaps_lock must be held before calling */
+static void __iomem *__acpi_try_ioremap(phys_addr_t paddr,
+                                       unsigned long size)
+{
+       struct acpi_iomap *map;
+
+       map = __acpi_find_iomap(paddr, size);
+       if (map) {
+               kref_get(&map->ref);
+               return map->vaddr + (paddr - map->paddr);
+       } else
+               return NULL;
+}
+
+/*
+ * Used to pre-map the specified IO memory area. First try to find
+ * whether the area is already pre-mapped, if it is, increase the
+ * reference count (in __acpi_try_ioremap) and return; otherwise, do
+ * the real ioremap, and add the mapping into acpi_iomaps list.
+ */
+static void __iomem *acpi_pre_map(phys_addr_t paddr,
+                                 unsigned long size)
+{
+       void __iomem *vaddr;
+       struct acpi_iomap *map;
+       unsigned long pg_sz, flags;
+       phys_addr_t pg_off;
+
+       spin_lock_irqsave(&acpi_iomaps_lock, flags);
+       vaddr = __acpi_try_ioremap(paddr, size);
+       spin_unlock_irqrestore(&acpi_iomaps_lock, flags);
+       if (vaddr)
+               return vaddr;
+
+       pg_off = paddr & PAGE_MASK;
+       pg_sz = ((paddr + size + PAGE_SIZE - 1) & PAGE_MASK) - pg_off;
+       vaddr = ioremap(pg_off, pg_sz);
+       if (!vaddr)
+               return NULL;
+       map = kmalloc(sizeof(*map), GFP_KERNEL);
+       if (!map)
+               goto err_unmap;
+       INIT_LIST_HEAD(&map->list);
+       map->paddr = pg_off;
+       map->size = pg_sz;
+       map->vaddr = vaddr;
+       kref_init(&map->ref);
+
+       spin_lock_irqsave(&acpi_iomaps_lock, flags);
+       vaddr = __acpi_try_ioremap(paddr, size);
+       if (vaddr) {
+               spin_unlock_irqrestore(&acpi_iomaps_lock, flags);
+               iounmap(map->vaddr);
+               kfree(map);
+               return vaddr;
+       }
+       list_add_tail_rcu(&map->list, &acpi_iomaps);
+       spin_unlock_irqrestore(&acpi_iomaps_lock, flags);
+
+       return vaddr + (paddr - pg_off);
+err_unmap:
+       iounmap(vaddr);
+       return NULL;
+}
+
+/* acpi_iomaps_lock must be held before calling */
+static void __acpi_kref_del_iomap(struct kref *ref)
+{
+       struct acpi_iomap *map;
+
+       map = container_of(ref, struct acpi_iomap, ref);
+       list_del_rcu(&map->list);
+}
+
+/*
+ * Used to post-unmap the specified IO memory area. The iounmap is
+ * done only if the reference count goes zero.
+ */
+static void acpi_post_unmap(phys_addr_t paddr, unsigned long size)
+{
+       struct acpi_iomap *map;
+       unsigned long flags;
+       int del;
+
+       spin_lock_irqsave(&acpi_iomaps_lock, flags);
+       map = __acpi_find_iomap(paddr, size);
+       BUG_ON(!map);
+       del = kref_put(&map->ref, __acpi_kref_del_iomap);
+       spin_unlock_irqrestore(&acpi_iomaps_lock, flags);
+
+       if (!del)
+               return;
+
+       synchronize_rcu();
+       iounmap(map->vaddr);
+       kfree(map);
+}
+
+/* In NMI handler, should set silent = 1 */
+static int acpi_check_gar(struct acpi_generic_address *reg,
+                         u64 *paddr, int silent)
+{
+       u32 width, space_id;
+
+       width = reg->bit_width;
+       space_id = reg->space_id;
+       /* Handle possible alignment issues */
+       memcpy(paddr, &reg->address, sizeof(*paddr));
+       if (!*paddr) {
+               if (!silent)
+                       pr_warning(FW_BUG ACPI_PFX
+                       "Invalid physical address in GAR [0x%llx/%u/%u]\n",
+                                  *paddr, width, space_id);
+               return -EINVAL;
+       }
+
+       if ((width != 8) && (width != 16) && (width != 32) && (width != 64)) {
+               if (!silent)
+                       pr_warning(FW_BUG ACPI_PFX
+                                  "Invalid bit width in GAR [0x%llx/%u/%u]\n",
+                                  *paddr, width, space_id);
+               return -EINVAL;
+       }
+
+       if (space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY &&
+           space_id != ACPI_ADR_SPACE_SYSTEM_IO) {
+               if (!silent)
+                       pr_warning(FW_BUG ACPI_PFX
+                       "Invalid address space type in GAR [0x%llx/%u/%u]\n",
+                                  *paddr, width, space_id);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* Pre-map, working on GAR */
+int acpi_pre_map_gar(struct acpi_generic_address *reg)
+{
+       u64 paddr;
+       void __iomem *vaddr;
+       int rc;
+
+       if (reg->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)
+               return 0;
+
+       rc = acpi_check_gar(reg, &paddr, 0);
+       if (rc)
+               return rc;
+
+       vaddr = acpi_pre_map(paddr, reg->bit_width / 8);
+       if (!vaddr)
+               return -EIO;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(acpi_pre_map_gar);
+
+/* Post-unmap, working on GAR */
+int acpi_post_unmap_gar(struct acpi_generic_address *reg)
+{
+       u64 paddr;
+       int rc;
+
+       if (reg->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)
+               return 0;
+
+       rc = acpi_check_gar(reg, &paddr, 0);
+       if (rc)
+               return rc;
+
+       acpi_post_unmap(paddr, reg->bit_width / 8);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(acpi_post_unmap_gar);
+
+/*
+ * Can be used in atomic (including NMI) or process context. RCU read
+ * lock can only be released after the IO memory area accessing.
+ */
+static int acpi_atomic_read_mem(u64 paddr, u64 *val, u32 width)
+{
+       void __iomem *addr;
+
+       rcu_read_lock();
+       addr = __acpi_ioremap_fast(paddr, width);
+       switch (width) {
+       case 8:
+               *val = readb(addr);
+               break;
+       case 16:
+               *val = readw(addr);
+               break;
+       case 32:
+               *val = readl(addr);
+               break;
+       case 64:
+               *val = readq(addr);
+               break;
+       default:
+               return -EINVAL;
+       }
+       rcu_read_unlock();
+
+       return 0;
+}
+
+static int acpi_atomic_write_mem(u64 paddr, u64 val, u32 width)
+{
+       void __iomem *addr;
+
+       rcu_read_lock();
+       addr = __acpi_ioremap_fast(paddr, width);
+       switch (width) {
+       case 8:
+               writeb(val, addr);
+               break;
+       case 16:
+               writew(val, addr);
+               break;
+       case 32:
+               writel(val, addr);
+               break;
+       case 64:
+               writeq(val, addr);
+               break;
+       default:
+               return -EINVAL;
+       }
+       rcu_read_unlock();
+
+       return 0;
+}
+
+/* GAR accessing in atomic (including NMI) or process context */
+int acpi_atomic_read(u64 *val, struct acpi_generic_address *reg)
+{
+       u64 paddr;
+       int rc;
+
+       rc = acpi_check_gar(reg, &paddr, 1);
+       if (rc)
+               return rc;
+
+       *val = 0;
+       switch (reg->space_id) {
+       case ACPI_ADR_SPACE_SYSTEM_MEMORY:
+               return acpi_atomic_read_mem(paddr, val, reg->bit_width);
+       case ACPI_ADR_SPACE_SYSTEM_IO:
+               return acpi_os_read_port(paddr, (u32 *)val, reg->bit_width);
+       default:
+               return -EINVAL;
+       }
+}
+EXPORT_SYMBOL_GPL(acpi_atomic_read);
+
+int acpi_atomic_write(u64 val, struct acpi_generic_address *reg)
+{
+       u64 paddr;
+       int rc;
+
+       rc = acpi_check_gar(reg, &paddr, 1);
+       if (rc)
+               return rc;
+
+       switch (reg->space_id) {
+       case ACPI_ADR_SPACE_SYSTEM_MEMORY:
+               return acpi_atomic_write_mem(paddr, val, reg->bit_width);
+       case ACPI_ADR_SPACE_SYSTEM_IO:
+               return acpi_os_write_port(paddr, val, reg->bit_width);
+       default:
+               return -EINVAL;
+       }
+}
+EXPORT_SYMBOL_GPL(acpi_atomic_write);
index 9042a85796685ee66dda133e55f4617016e01d00..c1d23cd71652baeed8e64f0f39a96693921fe81a 100644 (file)
@@ -401,11 +401,6 @@ static void acpi_print_osc_error(acpi_handle handle,
        printk("\n");
 }
 
-static u8 hex_val(unsigned char c)
-{
-       return isdigit(c) ? c - '0' : toupper(c) - 'A' + 10;
-}
-
 static acpi_status acpi_str_to_uuid(char *str, u8 *uuid)
 {
        int i;
@@ -422,8 +417,8 @@ static acpi_status acpi_str_to_uuid(char *str, u8 *uuid)
                        return AE_BAD_PARAMETER;
        }
        for (i = 0; i < 16; i++) {
-               uuid[i] = hex_val(str[opc_map_to_uuid[i]]) << 4;
-               uuid[i] |= hex_val(str[opc_map_to_uuid[i] + 1]);
+               uuid[i] = hex_to_bin(str[opc_map_to_uuid[i]]) << 4;
+               uuid[i] |= hex_to_bin(str[opc_map_to_uuid[i] + 1]);
        }
        return AE_OK;
 }
index f2234db85da041ae72b450ef7b73c102000933e1..e61d4f8e62a54a42dd8f39b5c9647b2a08449e07 100644 (file)
@@ -1027,10 +1027,9 @@ int __init acpi_ec_ecdt_probe(void)
                /* Don't trust ECDT, which comes from ASUSTek */
                if (!EC_FLAGS_VALIDATE_ECDT)
                        goto install;
-               saved_ec = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
+               saved_ec = kmemdup(boot_ec, sizeof(struct acpi_ec), GFP_KERNEL);
                if (!saved_ec)
                        return -ENOMEM;
-               memcpy(saved_ec, boot_ec, sizeof(struct acpi_ec));
        /* fall through */
        }
 
diff --git a/drivers/acpi/hed.c b/drivers/acpi/hed.c
new file mode 100644 (file)
index 0000000..d0c1967
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * ACPI Hardware Error Device (PNP0C33) Driver
+ *
+ * Copyright (C) 2010, Intel Corp.
+ *     Author: Huang Ying <ying.huang@intel.com>
+ *
+ * ACPI Hardware Error Device is used to report some hardware errors
+ * notified via SCI, mainly the corrected errors.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+#include <acpi/hed.h>
+
+static struct acpi_device_id acpi_hed_ids[] = {
+       {"PNP0C33", 0},
+       {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, acpi_hed_ids);
+
+static acpi_handle hed_handle;
+
+static BLOCKING_NOTIFIER_HEAD(acpi_hed_notify_list);
+
+int register_acpi_hed_notifier(struct notifier_block *nb)
+{
+       return blocking_notifier_chain_register(&acpi_hed_notify_list, nb);
+}
+EXPORT_SYMBOL_GPL(register_acpi_hed_notifier);
+
+void unregister_acpi_hed_notifier(struct notifier_block *nb)
+{
+       blocking_notifier_chain_unregister(&acpi_hed_notify_list, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_acpi_hed_notifier);
+
+/*
+ * SCI to report hardware error is forwarded to the listeners of HED,
+ * it is used by HEST Generic Hardware Error Source with notify type
+ * SCI.
+ */
+static void acpi_hed_notify(struct acpi_device *device, u32 event)
+{
+       blocking_notifier_call_chain(&acpi_hed_notify_list, 0, NULL);
+}
+
+static int __devinit acpi_hed_add(struct acpi_device *device)
+{
+       /* Only one hardware error device */
+       if (hed_handle)
+               return -EINVAL;
+       hed_handle = device->handle;
+       return 0;
+}
+
+static int __devexit acpi_hed_remove(struct acpi_device *device, int type)
+{
+       hed_handle = NULL;
+       return 0;
+}
+
+static struct acpi_driver acpi_hed_driver = {
+       .name = "hardware_error_device",
+       .class = "hardware_error",
+       .ids = acpi_hed_ids,
+       .ops = {
+               .add = acpi_hed_add,
+               .remove = acpi_hed_remove,
+               .notify = acpi_hed_notify,
+       },
+};
+
+static int __init acpi_hed_init(void)
+{
+       if (acpi_disabled)
+               return -ENODEV;
+
+       if (acpi_bus_register_driver(&acpi_hed_driver) < 0)
+               return -ENODEV;
+
+       return 0;
+}
+
+static void __exit acpi_hed_exit(void)
+{
+       acpi_bus_unregister_driver(&acpi_hed_driver);
+}
+
+module_init(acpi_hed_init);
+module_exit(acpi_hed_exit);
+
+ACPI_MODULE_NAME("hed");
+MODULE_AUTHOR("Huang Ying");
+MODULE_DESCRIPTION("ACPI Hardware Error Device Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/hest.c b/drivers/acpi/hest.c
deleted file mode 100644 (file)
index 1c527a1..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-#include <linux/acpi.h>
-#include <linux/pci.h>
-
-#define PREFIX "ACPI: "
-
-static inline unsigned long parse_acpi_hest_ia_machine_check(struct acpi_hest_ia_machine_check *p)
-{
-       return sizeof(*p) +
-               (sizeof(struct acpi_hest_ia_error_bank) * p->num_hardware_banks);
-}
-
-static inline unsigned long parse_acpi_hest_ia_corrected(struct acpi_hest_ia_corrected *p)
-{
-       return sizeof(*p) +
-               (sizeof(struct acpi_hest_ia_error_bank) * p->num_hardware_banks);
-}
-
-static inline unsigned long parse_acpi_hest_ia_nmi(struct acpi_hest_ia_nmi *p)
-{
-       return sizeof(*p);
-}
-
-static inline unsigned long parse_acpi_hest_generic(struct acpi_hest_generic *p)
-{
-       return sizeof(*p);
-}
-
-static inline unsigned int hest_match_pci(struct acpi_hest_aer_common *p, struct pci_dev *pci)
-{
-       return  (0           == pci_domain_nr(pci->bus) &&
-                p->bus      == pci->bus->number &&
-                p->device   == PCI_SLOT(pci->devfn) &&
-                p->function == PCI_FUNC(pci->devfn));
-}
-
-static unsigned long parse_acpi_hest_aer(void *hdr, int type, struct pci_dev *pci, int *firmware_first)
-{
-       struct acpi_hest_aer_common *p = hdr + sizeof(struct acpi_hest_header);
-       unsigned long rc=0;
-       u8 pcie_type = 0;
-       u8 bridge = 0;
-       switch (type) {
-       case ACPI_HEST_TYPE_AER_ROOT_PORT:
-               rc = sizeof(struct acpi_hest_aer_root);
-               pcie_type = PCI_EXP_TYPE_ROOT_PORT;
-               break;
-       case ACPI_HEST_TYPE_AER_ENDPOINT:
-               rc = sizeof(struct acpi_hest_aer);
-               pcie_type = PCI_EXP_TYPE_ENDPOINT;
-               break;
-       case ACPI_HEST_TYPE_AER_BRIDGE:
-               rc = sizeof(struct acpi_hest_aer_bridge);
-               if ((pci->class >> 16) == PCI_BASE_CLASS_BRIDGE)
-                       bridge = 1;
-               break;
-       }
-
-       if (p->flags & ACPI_HEST_GLOBAL) {
-               if ((pci->is_pcie && (pci->pcie_type == pcie_type)) || bridge)
-                       *firmware_first = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST);
-       }
-       else
-               if (hest_match_pci(p, pci))
-                       *firmware_first = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST);
-       return rc;
-}
-
-static int acpi_hest_firmware_first(struct acpi_table_header *stdheader, struct pci_dev *pci)
-{
-       struct acpi_table_hest *hest = (struct acpi_table_hest *)stdheader;
-       void *p = (void *)hest + sizeof(*hest); /* defined by the ACPI 4.0 spec */
-       struct acpi_hest_header *hdr = p;
-
-       int i;
-       int firmware_first = 0;
-       static unsigned char printed_unused = 0;
-       static unsigned char printed_reserved = 0;
-
-       for (i=0, hdr=p; p < (((void *)hest) + hest->header.length) && i < hest->error_source_count; i++) {
-               switch (hdr->type) {
-               case ACPI_HEST_TYPE_IA32_CHECK:
-                       p += parse_acpi_hest_ia_machine_check(p);
-                       break;
-               case ACPI_HEST_TYPE_IA32_CORRECTED_CHECK:
-                       p += parse_acpi_hest_ia_corrected(p);
-                       break;
-               case ACPI_HEST_TYPE_IA32_NMI:
-                       p += parse_acpi_hest_ia_nmi(p);
-                       break;
-               /* These three should never appear */
-               case ACPI_HEST_TYPE_NOT_USED3:
-               case ACPI_HEST_TYPE_NOT_USED4:
-               case ACPI_HEST_TYPE_NOT_USED5:
-                       if (!printed_unused) {
-                               printk(KERN_DEBUG PREFIX
-                                      "HEST Error Source list contains an obsolete type (%d).\n", hdr->type);
-                               printed_unused = 1;
-                       }
-                       break;
-               case ACPI_HEST_TYPE_AER_ROOT_PORT:
-               case ACPI_HEST_TYPE_AER_ENDPOINT:
-               case ACPI_HEST_TYPE_AER_BRIDGE:
-                       p += parse_acpi_hest_aer(p, hdr->type, pci, &firmware_first);
-                       break;
-               case ACPI_HEST_TYPE_GENERIC_ERROR:
-                       p += parse_acpi_hest_generic(p);
-                       break;
-               /* These should never appear either */
-               case ACPI_HEST_TYPE_RESERVED:
-               default:
-                       if (!printed_reserved) {
-                               printk(KERN_DEBUG PREFIX
-                                      "HEST Error Source list contains a reserved type (%d).\n", hdr->type);
-                               printed_reserved = 1;
-                       }
-                       break;
-               }
-       }
-       return firmware_first;
-}
-
-int acpi_hest_firmware_first_pci(struct pci_dev *pci)
-{
-       acpi_status status = AE_NOT_FOUND;
-       struct acpi_table_header *hest = NULL;
-
-       if (acpi_disabled)
-               return 0;
-
-       status = acpi_get_table(ACPI_SIG_HEST, 1, &hest);
-
-       if (ACPI_SUCCESS(status)) {
-               if (acpi_hest_firmware_first(hest, pci)) {
-                       return 1;
-               }
-       }
-       return 0;
-}
-EXPORT_SYMBOL_GPL(acpi_hest_firmware_first_pci);
index 4bc1c4178f506d3358d844f0ad15af2bf83d5bb7..78418ce4fc78a5cf99203e7890f81f36e23a10a8 100644 (file)
@@ -1206,6 +1206,15 @@ int acpi_check_mem_region(resource_size_t start, resource_size_t n,
 }
 EXPORT_SYMBOL(acpi_check_mem_region);
 
+/*
+ * Let drivers know whether the resource checks are effective
+ */
+int acpi_resources_are_enforced(void)
+{
+       return acpi_enforce_resources == ENFORCE_RESOURCES_STRICT;
+}
+EXPORT_SYMBOL(acpi_resources_are_enforced);
+
 /*
  * Acquire a spinlock.
  *
index aefce33f2a09c88d8fb3fec7b2bd7fa57a899de2..4eac59393edc5b13e3c25283f08e6cf899fb61d7 100644 (file)
@@ -120,7 +120,8 @@ acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus)
        struct acpi_pci_root *root;
        
        list_for_each_entry(root, &acpi_pci_roots, node)
-               if ((root->segment == (u16) seg) && (root->bus_nr == (u16) bus))
+               if ((root->segment == (u16) seg) &&
+                   (root->secondary.start == (u16) bus))
                        return root->device->handle;
        return NULL;            
 }
@@ -154,7 +155,7 @@ EXPORT_SYMBOL_GPL(acpi_is_root_bridge);
 static acpi_status
 get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data)
 {
-       int *busnr = data;
+       struct resource *res = data;
        struct acpi_resource_address64 address;
 
        if (resource->type != ACPI_RESOURCE_TYPE_ADDRESS16 &&
@@ -164,28 +165,27 @@ get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data)
 
        acpi_resource_to_address64(resource, &address);
        if ((address.address_length > 0) &&
-           (address.resource_type == ACPI_BUS_NUMBER_RANGE))
-               *busnr = address.minimum;
+           (address.resource_type == ACPI_BUS_NUMBER_RANGE)) {
+               res->start = address.minimum;
+               res->end = address.minimum + address.address_length - 1;
+       }
 
        return AE_OK;
 }
 
 static acpi_status try_get_root_bridge_busnr(acpi_handle handle,
-                                            unsigned long long *bus)
+                                            struct resource *res)
 {
        acpi_status status;
-       int busnum;
 
-       busnum = -1;
+       res->start = -1;
        status =
            acpi_walk_resources(handle, METHOD_NAME__CRS,
-                               get_root_bridge_busnr_callback, &busnum);
+                               get_root_bridge_busnr_callback, res);
        if (ACPI_FAILURE(status))
                return status;
-       /* Check if we really get a bus number from _CRS */
-       if (busnum == -1)
+       if (res->start == -1)
                return AE_ERROR;
-       *bus = busnum;
        return AE_OK;
 }
 
@@ -429,34 +429,47 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
        struct acpi_device *child;
        u32 flags, base_flags;
 
+       root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
+       if (!root)
+               return -ENOMEM;
+
        segment = 0;
        status = acpi_evaluate_integer(device->handle, METHOD_NAME__SEG, NULL,
                                       &segment);
        if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
                printk(KERN_ERR PREFIX "can't evaluate _SEG\n");
-               return -ENODEV;
+               result = -ENODEV;
+               goto end;
        }
 
        /* Check _CRS first, then _BBN.  If no _BBN, default to zero. */
-       bus = 0;
-       status = try_get_root_bridge_busnr(device->handle, &bus);
+       root->secondary.flags = IORESOURCE_BUS;
+       status = try_get_root_bridge_busnr(device->handle, &root->secondary);
        if (ACPI_FAILURE(status)) {
+               /*
+                * We need both the start and end of the downstream bus range
+                * to interpret _CBA (MMCONFIG base address), so it really is
+                * supposed to be in _CRS.  If we don't find it there, all we
+                * can do is assume [_BBN-0xFF] or [0-0xFF].
+                */
+               root->secondary.end = 0xFF;
+               printk(KERN_WARNING FW_BUG PREFIX
+                      "no secondary bus range in _CRS\n");
                status = acpi_evaluate_integer(device->handle, METHOD_NAME__BBN,                                               NULL, &bus);
-               if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
-                       printk(KERN_ERR PREFIX
-                            "no bus number in _CRS and can't evaluate _BBN\n");
-                       return -ENODEV;
+               if (ACPI_SUCCESS(status))
+                       root->secondary.start = bus;
+               else if (status == AE_NOT_FOUND)
+                       root->secondary.start = 0;
+               else {
+                       printk(KERN_ERR PREFIX "can't evaluate _BBN\n");
+                       result = -ENODEV;
+                       goto end;
                }
        }
 
-       root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
-       if (!root)
-               return -ENOMEM;
-
        INIT_LIST_HEAD(&root->node);
        root->device = device;
        root->segment = segment & 0xFFFF;
-       root->bus_nr = bus & 0xFF;
        strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME);
        strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS);
        device->driver_data = root;
@@ -475,9 +488,9 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
        /* TBD: Locking */
        list_add_tail(&root->node, &acpi_pci_roots);
 
-       printk(KERN_INFO PREFIX "%s [%s] (%04x:%02x)\n",
+       printk(KERN_INFO PREFIX "%s [%s] (domain %04x %pR)\n",
               acpi_device_name(device), acpi_device_bid(device),
-              root->segment, root->bus_nr);
+              root->segment, &root->secondary);
 
        /*
         * Scan the Root Bridge
@@ -486,11 +499,11 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
         * PCI namespace does not get created until this call is made (and 
         * thus the root bridge's pci_dev does not exist).
         */
-       root->bus = pci_acpi_scan_root(device, segment, bus);
+       root->bus = pci_acpi_scan_root(root);
        if (!root->bus) {
                printk(KERN_ERR PREFIX
                            "Bus %04x:%02x not present in PCI namespace\n",
-                           root->segment, root->bus_nr);
+                           root->segment, (unsigned int)root->secondary.start);
                result = -ENODEV;
                goto end;
        }
index 5675d9747e871f1007070081fbc59557576c6d65..b1034a9ada4e74da88970cbdc65dd9c1959d9988 100644 (file)
@@ -616,7 +616,8 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device)
        acpi_processor_get_limit_info(pr);
 
 
-       acpi_processor_power_init(pr, device);
+       if (cpuidle_get_driver() == &acpi_idle_driver)
+               acpi_processor_power_init(pr, device);
 
        pr->cdev = thermal_cooling_device_register("Processor", device,
                                                &processor_cooling_ops);
@@ -920,9 +921,14 @@ static int __init acpi_processor_init(void)
        if (!acpi_processor_dir)
                return -ENOMEM;
 #endif
-       result = cpuidle_register_driver(&acpi_idle_driver);
-       if (result < 0)
-               goto out_proc;
+
+       if (!cpuidle_register_driver(&acpi_idle_driver)) {
+               printk(KERN_DEBUG "ACPI: %s registered with cpuidle\n",
+                       acpi_idle_driver.name);
+       } else {
+               printk(KERN_DEBUG "ACPI: acpi_idle yielding to %s",
+                       cpuidle_get_driver()->name);
+       }
 
        result = acpi_bus_register_driver(&acpi_processor_driver);
        if (result < 0)
@@ -941,7 +947,6 @@ static int __init acpi_processor_init(void)
 out_cpuidle:
        cpuidle_unregister_driver(&acpi_idle_driver);
 
-out_proc:
 #ifdef CONFIG_ACPI_PROCFS
        remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);
 #endif
index c3817e1f32c7b1e222f5a59c81dc328bb0d7ca71..2e8c27d48f2b75f59f0e76436ae94db5f61466a7 100644 (file)
@@ -727,19 +727,9 @@ static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset)
                        break;
                }
 
-               if (pr->power.states[i].promotion.state)
-                       seq_printf(seq, "promotion[C%zd] ",
-                                  (pr->power.states[i].promotion.state -
-                                   pr->power.states));
-               else
-                       seq_puts(seq, "promotion[--] ");
-
-               if (pr->power.states[i].demotion.state)
-                       seq_printf(seq, "demotion[C%zd] ",
-                                  (pr->power.states[i].demotion.state -
-                                   pr->power.states));
-               else
-                       seq_puts(seq, "demotion[--] ");
+               seq_puts(seq, "promotion[--] ");
+
+               seq_puts(seq, "demotion[--] ");
 
                seq_printf(seq, "latency[%03d] usage[%08d] duration[%020llu]\n",
                           pr->power.states[i].latency,
@@ -869,6 +859,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
        struct acpi_processor *pr;
        struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
        ktime_t  kt1, kt2;
+       s64 idle_time_ns;
        s64 idle_time;
        s64 sleep_ticks = 0;
 
@@ -881,6 +872,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
                return(acpi_idle_enter_c1(dev, state));
 
        local_irq_disable();
+
        if (cx->entry_method != ACPI_CSTATE_FFH) {
                current_thread_info()->status &= ~TS_POLLING;
                /*
@@ -888,12 +880,12 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
                 * NEED_RESCHED:
                 */
                smp_mb();
-       }
 
-       if (unlikely(need_resched())) {
-               current_thread_info()->status |= TS_POLLING;
-               local_irq_enable();
-               return 0;
+               if (unlikely(need_resched())) {
+                       current_thread_info()->status |= TS_POLLING;
+                       local_irq_enable();
+                       return 0;
+               }
        }
 
        /*
@@ -910,15 +902,18 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
        sched_clock_idle_sleep_event();
        acpi_idle_do_entry(cx);
        kt2 = ktime_get_real();
-       idle_time =  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(sleep_ticks*PM_TIMER_TICK_NS);
+       sched_clock_idle_wakeup_event(idle_time_ns);
 
        local_irq_enable();
-       current_thread_info()->status |= TS_POLLING;
+       if (cx->entry_method != ACPI_CSTATE_FFH)
+               current_thread_info()->status |= TS_POLLING;
 
        cx->usage++;
 
@@ -943,6 +938,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
        struct acpi_processor *pr;
        struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
        ktime_t  kt1, kt2;
+       s64 idle_time_ns;
        s64 idle_time;
        s64 sleep_ticks = 0;
 
@@ -968,6 +964,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
        }
 
        local_irq_disable();
+
        if (cx->entry_method != ACPI_CSTATE_FFH) {
                current_thread_info()->status &= ~TS_POLLING;
                /*
@@ -975,12 +972,12 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
                 * NEED_RESCHED:
                 */
                smp_mb();
-       }
 
-       if (unlikely(need_resched())) {
-               current_thread_info()->status |= TS_POLLING;
-               local_irq_enable();
-               return 0;
+               if (unlikely(need_resched())) {
+                       current_thread_info()->status |= TS_POLLING;
+                       local_irq_enable();
+                       return 0;
+               }
        }
 
        acpi_unlazy_tlb(smp_processor_id());
@@ -1025,14 +1022,17 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
                spin_unlock(&c3_lock);
        }
        kt2 = ktime_get_real();
-       idle_time =  ktime_to_us(ktime_sub(kt2, kt1));
+       idle_time_ns = ktime_to_us(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(sleep_ticks*PM_TIMER_TICK_NS);
+       sched_clock_idle_wakeup_event(idle_time_ns);
 
        local_irq_enable();
-       current_thread_info()->status |= TS_POLLING;
+       if (cx->entry_method != ACPI_CSTATE_FFH)
+               current_thread_info()->status |= TS_POLLING;
 
        cx->usage++;
 
index baa76bbf244a3ab338e9244a58591c3431ebdc75..4ab2275b4461e797bf374880c97c24db72dba386 100644 (file)
@@ -80,22 +80,6 @@ static int acpi_sleep_prepare(u32 acpi_state)
 
 #ifdef CONFIG_ACPI_SLEEP
 static u32 acpi_target_sleep_state = ACPI_STATE_S0;
-/*
- * According to the ACPI specification the BIOS should make sure that ACPI is
- * enabled and SCI_EN bit is set on wake-up from S1 - S3 sleep states.  Still,
- * some BIOSes don't do that and therefore we use acpi_enable() to enable ACPI
- * on such systems during resume.  Unfortunately that doesn't help in
- * particularly pathological cases in which SCI_EN has to be set directly on
- * resume, although the specification states very clearly that this flag is
- * owned by the hardware.  The set_sci_en_on_resume variable will be set in such
- * cases.
- */
-static bool set_sci_en_on_resume;
-
-void __init acpi_set_sci_en_on_resume(void)
-{
-       set_sci_en_on_resume = true;
-}
 
 /*
  * ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the
@@ -253,11 +237,8 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
                break;
        }
 
-       /* If ACPI is not enabled by the BIOS, we need to enable it here. */
-       if (set_sci_en_on_resume)
-               acpi_write_bit_register(ACPI_BITREG_SCI_ENABLE, 1);
-       else
-               acpi_enable();
+       /* This violates the spec but is required for bug compatibility. */
+       acpi_write_bit_register(ACPI_BITREG_SCI_ENABLE, 1);
 
        /* Reprogram control registers and execute _BFS */
        acpi_leave_sleep_state_prep(acpi_state);
@@ -346,12 +327,6 @@ static int __init init_old_suspend_ordering(const struct dmi_system_id *d)
        return 0;
 }
 
-static int __init init_set_sci_en_on_resume(const struct dmi_system_id *d)
-{
-       set_sci_en_on_resume = true;
-       return 0;
-}
-
 static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
        {
        .callback = init_old_suspend_ordering,
@@ -370,22 +345,6 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
                },
        },
        {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Apple MacBook 1,1",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."),
-               DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"),
-               },
-       },
-       {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Apple MacMini 1,1",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."),
-               DMI_MATCH(DMI_PRODUCT_NAME, "Macmini1,1"),
-               },
-       },
-       {
        .callback = init_old_suspend_ordering,
        .ident = "Asus Pundit P1-AH2 (M2N8L motherboard)",
        .matches = {
@@ -394,94 +353,6 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
                },
        },
        {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Toshiba Satellite L300",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "Satellite L300"),
-               },
-       },
-       {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Hewlett-Packard HP G7000 Notebook PC",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "HP G7000 Notebook PC"),
-               },
-       },
-       {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Hewlett-Packard HP Pavilion dv3 Notebook PC",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv3 Notebook PC"),
-               },
-       },
-       {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Hewlett-Packard Pavilion dv4",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv4"),
-               },
-       },
-       {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Hewlett-Packard Pavilion dv7",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv7"),
-               },
-       },
-       {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Hewlett-Packard Compaq Presario C700 Notebook PC",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "Compaq Presario C700 Notebook PC"),
-               },
-       },
-       {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Hewlett-Packard Compaq Presario CQ40 Notebook PC",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "Compaq Presario CQ40 Notebook PC"),
-               },
-       },
-       {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Lenovo ThinkPad T410",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-               DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T410"),
-               },
-       },
-       {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Lenovo ThinkPad T510",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-               DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T510"),
-               },
-       },
-       {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Lenovo ThinkPad W510",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-               DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad W510"),
-               },
-       },
-       {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Lenovo ThinkPad X201[s]",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-               DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X201"),
-               },
-       },
-       {
        .callback = init_old_suspend_ordering,
        .ident = "Panasonic CF51-2L",
        .matches = {
@@ -490,30 +361,6 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
                DMI_MATCH(DMI_BOARD_NAME, "CF51-2L"),
                },
        },
-       {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Dell Studio 1558",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-               DMI_MATCH(DMI_PRODUCT_NAME, "Studio 1558"),
-               },
-       },
-       {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Dell Studio 1557",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-               DMI_MATCH(DMI_PRODUCT_NAME, "Studio 1557"),
-               },
-       },
-       {
-       .callback = init_set_sci_en_on_resume,
-       .ident = "Dell Studio 1555",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-               DMI_MATCH(DMI_PRODUCT_NAME, "Studio 1555"),
-               },
-       },
        {},
 };
 #endif /* CONFIG_SUSPEND */
index 8a8f3b3382a672483924ea5a3dd1cdd742e9a11d..25b8bd149284fb7f13de1018bf66c806dd855f9e 100644 (file)
@@ -1,6 +1,6 @@
 
 extern u8 sleep_states[];
-extern int acpi_suspend (u32 state);
+extern int acpi_suspend(u32 state);
 
 extern void acpi_enable_wakeup_device_prep(u8 sleep_state);
 extern void acpi_enable_wakeup_device(u8 sleep_state);
index 8a0ed2800e6359a49f781b41d2afc44cd183225b..f336bca7c4503ec1d03d7741ee8185afae942381 100644 (file)
@@ -213,7 +213,7 @@ acpi_table_parse_entries(char *id,
        unsigned long table_end;
        acpi_size tbl_size;
 
-       if (acpi_disabled && !acpi_ht)
+       if (acpi_disabled)
                return -ENODEV;
 
        if (!handler)
@@ -280,7 +280,7 @@ int __init acpi_table_parse(char *id, acpi_table_handler handler)
        struct acpi_table_header *table = NULL;
        acpi_size tbl_size;
 
-       if (acpi_disabled && !acpi_ht)
+       if (acpi_disabled)
                return -ENODEV;
 
        if (!handler)
index a0c93b3214827a69bd4ada20fb5742b4dbbfc381..9865d46f49a8faabfe0930640b2fe3bbd10b4b89 100644 (file)
@@ -45,6 +45,7 @@
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 #include <linux/suspend.h>
+#include <acpi/video.h>
 
 #define PREFIX "ACPI: "
 
 
 #define MAX_NAME_LEN   20
 
-#define ACPI_VIDEO_DISPLAY_CRT 1
-#define ACPI_VIDEO_DISPLAY_TV  2
-#define ACPI_VIDEO_DISPLAY_DVI 3
-#define ACPI_VIDEO_DISPLAY_LCD 4
-
 #define _COMPONENT             ACPI_VIDEO_COMPONENT
 ACPI_MODULE_NAME("video");
 
@@ -1007,11 +1003,11 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
                result = acpi_video_init_brightness(device);
                if (result)
                        return;
-               name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
+               name = kasprintf(GFP_KERNEL, "acpi_video%d", count);
                if (!name)
                        return;
+               count++;
 
-               sprintf(name, "acpi_video%d", count++);
                memset(&props, 0, sizeof(struct backlight_properties));
                props.max_brightness = device->brightness->count - 3;
                device->backlight = backlight_device_register(name, NULL, device,
@@ -1067,10 +1063,10 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
                if (device->cap._DCS && device->cap._DSS) {
                        static int count;
                        char *name;
-                       name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
+                       name = kasprintf(GFP_KERNEL, "acpi_video%d", count);
                        if (!name)
                                return;
-                       sprintf(name, "acpi_video%d", count++);
+                       count++;
                        device->output_dev = video_output_register(name,
                                        NULL, device, &acpi_output_properties);
                        kfree(name);
@@ -1747,12 +1743,28 @@ acpi_video_get_device_attr(struct acpi_video_bus *video, unsigned long device_id
        return NULL;
 }
 
+static int
+acpi_video_get_device_type(struct acpi_video_bus *video,
+                          unsigned long device_id)
+{
+       struct acpi_video_enumerated_device *ids;
+       int i;
+
+       for (i = 0; i < video->attached_count; i++) {
+               ids = &video->attached_array[i];
+               if ((ids->value.int_val & 0xffff) == device_id)
+                       return ids->value.int_val;
+       }
+
+       return 0;
+}
+
 static int
 acpi_video_bus_get_one_device(struct acpi_device *device,
                              struct acpi_video_bus *video)
 {
        unsigned long long device_id;
-       int status;
+       int status, device_type;
        struct acpi_video_device *data;
        struct acpi_video_device_attrib* attribute;
 
@@ -1797,8 +1809,25 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
                        }
                        if(attribute->bios_can_detect)
                                data->flags.bios = 1;
-               } else
-                       data->flags.unknown = 1;
+               } else {
+                       /* Check for legacy IDs */
+                       device_type = acpi_video_get_device_type(video,
+                                                                device_id);
+                       /* Ignore bits 16 and 18-20 */
+                       switch (device_type & 0xffe2ffff) {
+                       case ACPI_VIDEO_DISPLAY_LEGACY_MONITOR:
+                               data->flags.crt = 1;
+                               break;
+                       case ACPI_VIDEO_DISPLAY_LEGACY_PANEL:
+                               data->flags.lcd = 1;
+                               break;
+                       case ACPI_VIDEO_DISPLAY_LEGACY_TV:
+                               data->flags.tvout = 1;
+                               break;
+                       default:
+                               data->flags.unknown = 1;
+                       }
+               }
 
                acpi_video_device_bind(video, data);
                acpi_video_device_find_cap(data);
@@ -2032,6 +2061,71 @@ out:
        return result;
 }
 
+int acpi_video_get_edid(struct acpi_device *device, int type, int device_id,
+                       void **edid)
+{
+       struct acpi_video_bus *video;
+       struct acpi_video_device *video_device;
+       union acpi_object *buffer = NULL;
+       acpi_status status;
+       int i, length;
+
+       if (!device || !acpi_driver_data(device))
+               return -EINVAL;
+
+       video = acpi_driver_data(device);
+
+       for (i = 0; i < video->attached_count; i++) {
+               video_device = video->attached_array[i].bind_info;
+               length = 256;
+
+               if (!video_device)
+                       continue;
+
+               if (type) {
+                       switch (type) {
+                       case ACPI_VIDEO_DISPLAY_CRT:
+                               if (!video_device->flags.crt)
+                                       continue;
+                               break;
+                       case ACPI_VIDEO_DISPLAY_TV:
+                               if (!video_device->flags.tvout)
+                                       continue;
+                               break;
+                       case ACPI_VIDEO_DISPLAY_DVI:
+                               if (!video_device->flags.dvi)
+                                       continue;
+                               break;
+                       case ACPI_VIDEO_DISPLAY_LCD:
+                               if (!video_device->flags.lcd)
+                                       continue;
+                               break;
+                       }
+               } else if (video_device->device_id != device_id) {
+                       continue;
+               }
+
+               status = acpi_video_device_EDID(video_device, &buffer, length);
+
+               if (ACPI_FAILURE(status) || !buffer ||
+                   buffer->type != ACPI_TYPE_BUFFER) {
+                       length = 128;
+                       status = acpi_video_device_EDID(video_device, &buffer,
+                                                       length);
+                       if (ACPI_FAILURE(status) || !buffer ||
+                           buffer->type != ACPI_TYPE_BUFFER) {
+                               continue;
+                       }
+               }
+
+               *edid = buffer->buffer.pointer;
+               return length;
+       }
+
+       return -ENODEV;
+}
+EXPORT_SYMBOL(acpi_video_get_edid);
+
 static int
 acpi_video_bus_get_devices(struct acpi_video_bus *video,
                           struct acpi_device *device)
index fc2f26b9b4071ee3f9577d1ae3a4745a0b645570..c5fef01b3c9591701fb03ae86290a6b5b643c32a 100644 (file)
@@ -250,7 +250,7 @@ static int __init acpi_backlight(char *str)
                                ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR;
                if (!strcmp("video", str))
                        acpi_video_support |=
-                               ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO;
+                               ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO;
        }
        return 1;
 }
index e68541f662b93a96125cc5b05e4cbe884e928c08..73f883333a0d821f8052319e489f585977d59821 100644 (file)
@@ -57,6 +57,8 @@ config SATA_PMP
          This option adds support for SATA Port Multipliers
          (the SATA version of an ethernet hub, or SAS expander).
 
+comment "Controllers with non-SFF native interface"
+
 config SATA_AHCI
        tristate "AHCI SATA support"
        depends on PCI
@@ -73,11 +75,12 @@ config SATA_AHCI_PLATFORM
 
          If unsure, say N.
 
-config SATA_SIL24
-       tristate "Silicon Image 3124/3132 SATA support"
-       depends on PCI
+config SATA_FSL
+       tristate "Freescale 3.0Gbps SATA support"
+       depends on FSL_SOC
        help
-         This option enables support for Silicon Image 3124/3132 Serial ATA.
+         This option enables support for Freescale 3.0Gbps SATA controller.
+         It can be found on MPC837x and MPC8315.
 
          If unsure, say N.
 
@@ -87,12 +90,11 @@ config SATA_INIC162X
        help
          This option enables support for Initio 162x Serial ATA.
 
-config SATA_FSL
-       tristate "Freescale 3.0Gbps SATA support"
-       depends on FSL_SOC
+config SATA_SIL24
+       tristate "Silicon Image 3124/3132 SATA support"
+       depends on PCI
        help
-         This option enables support for Freescale 3.0Gbps SATA controller.
-         It can be found on MPC837x and MPC8315.
+         This option enables support for Silicon Image 3124/3132 Serial ATA.
 
          If unsure, say N.
 
@@ -116,15 +118,65 @@ config ATA_SFF
 
 if ATA_SFF
 
-config SATA_SVW
-       tristate "ServerWorks Frodo / Apple K2 SATA support"
+comment "SFF controllers with custom DMA interface"
+
+config PDC_ADMA
+       tristate "Pacific Digital ADMA support"
        depends on PCI
        help
-         This option enables support for Broadcom/Serverworks/Apple K2
-         SATA support.
+         This option enables support for Pacific Digital ADMA controllers
+
+         If unsure, say N.
+
+config PATA_MPC52xx
+       tristate "Freescale MPC52xx SoC internal IDE"
+       depends on PPC_MPC52xx && PPC_BESTCOMM
+       select PPC_BESTCOMM_ATA
+       help
+         This option enables support for integrated IDE controller
+         of the Freescale MPC52xx SoC.
+
+         If unsure, say N.
+
+config PATA_OCTEON_CF
+       tristate "OCTEON Boot Bus Compact Flash support"
+       depends on CPU_CAVIUM_OCTEON
+       help
+         This option enables a polled compact flash driver for use with
+         compact flash cards attached to the OCTEON boot bus.
+
+         If unsure, say N.
+
+config SATA_QSTOR
+       tristate "Pacific Digital SATA QStor support"
+       depends on PCI
+       help
+         This option enables support for Pacific Digital Serial ATA QStor.
+
+         If unsure, say N.
+
+config SATA_SX4
+       tristate "Promise SATA SX4 support (Experimental)"
+       depends on PCI && EXPERIMENTAL
+       help
+         This option enables support for Promise Serial ATA SX4.
 
          If unsure, say N.
 
+config ATA_BMDMA
+       bool "ATA BMDMA support"
+       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.
+
+         If unuser, say Y.
+
+if ATA_BMDMA
+
+comment "SATA SFF controllers with BMDMA"
+
 config ATA_PIIX
        tristate "Intel ESB, ICH, PIIX3, PIIX4 PATA/SATA support"
        depends on PCI
@@ -152,22 +204,6 @@ config SATA_NV
 
          If unsure, say N.
 
-config PDC_ADMA
-       tristate "Pacific Digital ADMA support"
-       depends on PCI
-       help
-         This option enables support for Pacific Digital ADMA controllers
-
-         If unsure, say N.
-
-config SATA_QSTOR
-       tristate "Pacific Digital SATA QStor support"
-       depends on PCI
-       help
-         This option enables support for Pacific Digital Serial ATA QStor.
-
-         If unsure, say N.
-
 config SATA_PROMISE
        tristate "Promise SATA TX2/TX4 support"
        depends on PCI
@@ -176,14 +212,6 @@ config SATA_PROMISE
 
          If unsure, say N.
 
-config SATA_SX4
-       tristate "Promise SATA SX4 support (Experimental)"
-       depends on PCI && EXPERIMENTAL
-       help
-         This option enables support for Promise Serial ATA SX4.
-
-         If unsure, say N.
-
 config SATA_SIL
        tristate "Silicon Image SATA support"
        depends on PCI
@@ -203,6 +231,15 @@ config SATA_SIS
          enable the PATA_SIS driver in the config.
          If unsure, say N.
 
+config SATA_SVW
+       tristate "ServerWorks Frodo / Apple K2 SATA support"
+       depends on PCI
+       help
+         This option enables support for Broadcom/Serverworks/Apple K2
+         SATA support.
+
+         If unsure, say N.
+
 config SATA_ULI
        tristate "ULi Electronics SATA support"
        depends on PCI
@@ -227,14 +264,7 @@ config SATA_VITESSE
 
          If unsure, say N.
 
-config PATA_ACPI
-       tristate "ACPI firmware driver for PATA"
-       depends on ATA_ACPI
-       help
-         This option enables an ACPI method driver which drives
-         motherboard PATA controller interfaces through the ACPI
-         firmware in the BIOS. This driver can sometimes handle
-         otherwise unsupported hardware.
+comment "PATA SFF controllers with BMDMA"
 
 config PATA_ALI
        tristate "ALi PATA support"
@@ -262,40 +292,30 @@ config PATA_ARTOP
 
          If unsure, say N.
 
-config PATA_ATP867X
-       tristate "ARTOP/Acard ATP867X PATA support"
+config PATA_ATIIXP
+       tristate "ATI PATA support"
        depends on PCI
        help
-         This option enables support for ARTOP/Acard ATP867X PATA
-         controllers.
-
-         If unsure, say N.
-
-config PATA_AT32
-       tristate "Atmel AVR32 PATA support (Experimental)"
-       depends on AVR32 && PLATFORM_AT32AP && EXPERIMENTAL
-       help
-         This option enables support for the IDE devices on the
-         Atmel AT32AP platform.
+         This option enables support for the ATI ATA interfaces
+         found on the many ATI chipsets.
 
          If unsure, say N.
 
-config PATA_ATIIXP
-       tristate "ATI PATA support"
+config PATA_ATP867X
+       tristate "ARTOP/Acard ATP867X PATA support"
        depends on PCI
        help
-         This option enables support for the ATI ATA interfaces
-         found on the many ATI chipsets.
+         This option enables support for ARTOP/Acard ATP867X PATA
+         controllers.
 
          If unsure, say N.
 
-config PATA_CMD640_PCI
-       tristate "CMD640 PCI PATA support (Experimental)"
-       depends on PCI && EXPERIMENTAL
+config PATA_BF54X
+       tristate "Blackfin 54x ATAPI support"
+       depends on BF542 || BF548 || BF549
        help
-         This option enables support for the CMD640 PCI IDE
-         interface chip. Only the primary channel is currently
-         supported.
+         This option enables support for the built-in ATAPI controller on
+         Blackfin 54x family chips.
 
          If unsure, say N.
 
@@ -362,15 +382,6 @@ config PATA_EFAR
 
          If unsure, say N.
 
-config ATA_GENERIC
-       tristate "Generic ATA support"
-       depends on PCI
-       help
-         This option enables support for generic BIOS configured
-         ATA controllers via the new ATA layer
-
-         If unsure, say N.
-
 config PATA_HPT366
        tristate "HPT 366/368 PATA support"
        depends on PCI
@@ -415,12 +426,20 @@ config PATA_HPT3X3_DMA
          controllers. Enable with care as there are still some
          problems with DMA on this chipset.
 
-config PATA_ISAPNP
-       tristate "ISA Plug and Play PATA support"
-       depends on ISAPNP
+config PATA_ICSIDE
+       tristate "Acorn ICS PATA support"
+       depends on ARM && ARCH_ACORN
        help
-         This option enables support for ISA plug & play ATA
-         controllers such as those found on old soundcards.
+         On Acorn systems, say Y here if you wish to use the ICS PATA
+         interface card.  This is not required for ICS partition support.
+         If you are unsure, say N to this.
+
+config PATA_IT8213
+       tristate "IT8213 PATA support (Experimental)"
+       depends on PCI && EXPERIMENTAL
+       help
+         This option enables support for the ITE 821 PATA
+          controllers via the new ATA layer.
 
          If unsure, say N.
 
@@ -434,15 +453,6 @@ config PATA_IT821X
 
          If unsure, say N.
 
-config PATA_IT8213
-       tristate "IT8213 PATA support (Experimental)"
-       depends on PCI && EXPERIMENTAL
-       help
-         This option enables support for the ITE 821 PATA
-          controllers via the new ATA layer.
-
-         If unsure, say N.
-
 config PATA_JMICRON
        tristate "JMicron PATA support"
        depends on PCI
@@ -452,23 +462,14 @@ config PATA_JMICRON
 
          If unsure, say N.
 
-config PATA_LEGACY
-       tristate "Legacy ISA PATA support (Experimental)"
-       depends on (ISA || PCI)  && EXPERIMENTAL
-       help
-         This option enables support for ISA/VLB/PCI bus legacy PATA
-         ports and allows them to be accessed via the new ATA layer.
-
-         If unsure, say N.
-
-config PATA_TRIFLEX
-       tristate "Compaq Triflex PATA support"
-       depends on PCI
+config PATA_MACIO
+       tristate "Apple PowerMac/PowerBook internal 'MacIO' IDE"
+       depends on PPC_PMAC
        help
-         Enable support for the Compaq 'Triflex' IDE controller as found
-         on many Compaq Pentium-Pro systems, via the new ATA layer.
-
-         If unsure, say N.
+         Most IDE capable PowerMacs have IDE busses driven by a variant
+          of this controller which is part of the Apple chipset used on
+          most PowerMac models. Some models have multiple busses using
+          different chipsets, though generally, MacIO is one of them.
 
 config PATA_MARVELL
        tristate "Marvell PATA support via legacy mode"
@@ -481,32 +482,6 @@ config PATA_MARVELL
 
          If unsure, say N.
 
-config PATA_MPC52xx
-       tristate "Freescale MPC52xx SoC internal IDE"
-       depends on PPC_MPC52xx && PPC_BESTCOMM
-       select PPC_BESTCOMM_ATA
-       help
-         This option enables support for integrated IDE controller
-         of the Freescale MPC52xx SoC.
-
-         If unsure, say N.
-
-config PATA_MPIIX
-       tristate "Intel PATA MPIIX support"
-       depends on PCI
-       help
-         This option enables support for MPIIX PATA support.
-
-         If unsure, say N.
-
-config PATA_OLDPIIX
-       tristate "Intel PATA old PIIX support"
-       depends on PCI
-       help
-         This option enables support for early PIIX PATA support.
-
-         If unsure, say N.
-
 config PATA_NETCELL
        tristate "NETCELL Revolution RAID support"
        depends on PCI
@@ -525,15 +500,6 @@ config PATA_NINJA32
 
          If unsure, say N.
 
-config PATA_NS87410
-       tristate "Nat Semi NS87410 PATA support"
-       depends on PCI
-       help
-         This option enables support for the National Semiconductor
-         NS87410 PCI-IDE controller.
-
-         If unsure, say N.
-
 config PATA_NS87415
        tristate "Nat Semi NS87415 PATA support"
        depends on PCI
@@ -543,12 +509,11 @@ config PATA_NS87415
 
          If unsure, say N.
 
-config PATA_OPTI
-       tristate "OPTI621/6215 PATA support (Very Experimental)"
-       depends on PCI && EXPERIMENTAL
+config PATA_OLDPIIX
+       tristate "Intel PATA old PIIX support"
+       depends on PCI
        help
-         This option enables full PIO support for the early Opti ATA
-         controllers found on some old motherboards.
+         This option enables support for early PIIX PATA support.
 
          If unsure, say N.
 
@@ -562,24 +527,6 @@ config PATA_OPTIDMA
 
          If unsure, say N.
 
-config PATA_PALMLD
-       tristate "Palm LifeDrive PATA support"
-       depends on MACH_PALMLD
-       help
-         This option enables support for Palm LifeDrive's internal ATA
-         port via the new ATA layer.
-
-         If unsure, say N.
-
-config PATA_PCMCIA
-       tristate "PCMCIA PATA support"
-       depends on PCMCIA
-       help
-         This option enables support for PCMCIA ATA interfaces, including
-         compact flash card adapters via the new ATA layer.
-
-         If unsure, say N.
-
 config PATA_PDC2027X
        tristate "Promise PATA 2027x support"
        depends on PCI
@@ -597,12 +544,6 @@ config PATA_PDC_OLD
 
          If unsure, say N.
 
-config PATA_QDI
-       tristate "QDI VLB PATA support"
-       depends on ISA
-       help
-         Support for QDI 6500 and 6580 PATA controllers on VESA local bus.
-
 config PATA_RADISYS
        tristate "RADISYS 82600 PATA support (Experimental)"
        depends on PCI && EXPERIMENTAL
@@ -612,15 +553,6 @@ config PATA_RADISYS
 
          If unsure, say N.
 
-config PATA_RB532
-       tristate "RouterBoard 532 PATA CompactFlash support"
-       depends on MIKROTIK_RB532
-       help
-         This option enables support for the RouterBoard 532
-         PATA CompactFlash controller.
-
-         If unsure, say N.
-
 config PATA_RDC
        tristate "RDC PATA support"
        depends on PCI
@@ -631,21 +563,30 @@ config PATA_RDC
 
          If unsure, say N.
 
-config PATA_RZ1000
-       tristate "PC Tech RZ1000 PATA support"
+config PATA_SC1200
+       tristate "SC1200 PATA support"
        depends on PCI
        help
-         This option enables basic support for the PC Tech RZ1000/1
-         PATA controllers via the new ATA layer
+         This option enables support for the NatSemi/AMD SC1200 SoC
+         companion chip used with the Geode processor family.
 
          If unsure, say N.
 
-config PATA_SC1200
-       tristate "SC1200 PATA support"
+config PATA_SCC
+       tristate "Toshiba's Cell Reference Set IDE support"
+       depends on PCI && PPC_CELLEB
+       help
+         This option enables support for the built-in IDE controller on
+         Toshiba Cell Reference Board.
+
+         If unsure, say N.
+
+config PATA_SCH
+       tristate "Intel SCH PATA support"
        depends on PCI
        help
-         This option enables support for the NatSemi/AMD SC1200 SoC
-         companion chip used with the Geode processor family.
+         This option enables support for Intel SCH PATA on the Intel
+         SCH (US15W, US15L, UL11L) series host controllers.
 
          If unsure, say N.
 
@@ -683,6 +624,15 @@ config PATA_TOSHIBA
 
          If unsure, say N.
 
+config PATA_TRIFLEX
+       tristate "Compaq Triflex PATA support"
+       depends on PCI
+       help
+         Enable support for the Compaq 'Triflex' IDE controller as found
+         on many Compaq Pentium-Pro systems, via the new ATA layer.
+
+         If unsure, say N.
+
 config PATA_VIA
        tristate "VIA PATA support"
        depends on PCI
@@ -701,12 +651,99 @@ config PATA_WINBOND
 
          If unsure, say N.
 
-config PATA_WINBOND_VLB
-       tristate "Winbond W83759A VLB PATA support (Experimental)"
-       depends on ISA && EXPERIMENTAL
+endif # ATA_BMDMA
+
+comment "PIO-only SFF controllers"
+
+config PATA_AT32
+       tristate "Atmel AVR32 PATA support (Experimental)"
+       depends on AVR32 && PLATFORM_AT32AP && EXPERIMENTAL
        help
-         Support for the Winbond W83759A controller on Vesa Local Bus
-         systems.
+         This option enables support for the IDE devices on the
+         Atmel AT32AP platform.
+
+         If unsure, say N.
+
+config PATA_AT91
+       tristate "PATA support for AT91SAM9260"
+       depends on ARM && ARCH_AT91
+       help
+         This option enables support for IDE devices on the Atmel AT91SAM9260 SoC.
+
+         If unsure, say N.
+
+config PATA_CMD640_PCI
+       tristate "CMD640 PCI PATA support (Experimental)"
+       depends on PCI && EXPERIMENTAL
+       help
+         This option enables support for the CMD640 PCI IDE
+         interface chip. Only the primary channel is currently
+         supported.
+
+         If unsure, say N.
+
+config PATA_ISAPNP
+       tristate "ISA Plug and Play PATA support"
+       depends on ISAPNP
+       help
+         This option enables support for ISA plug & play ATA
+         controllers such as those found on old soundcards.
+
+         If unsure, say N.
+
+config PATA_IXP4XX_CF
+       tristate "IXP4XX Compact Flash support"
+       depends on ARCH_IXP4XX
+       help
+         This option enables support for a Compact Flash connected on
+         the ixp4xx expansion bus. This driver had been written for
+         Loft/Avila boards in mind but can work with others.
+
+         If unsure, say N.
+
+config PATA_MPIIX
+       tristate "Intel PATA MPIIX support"
+       depends on PCI
+       help
+         This option enables support for MPIIX PATA support.
+
+         If unsure, say N.
+
+config PATA_NS87410
+       tristate "Nat Semi NS87410 PATA support"
+       depends on PCI
+       help
+         This option enables support for the National Semiconductor
+         NS87410 PCI-IDE controller.
+
+         If unsure, say N.
+
+config PATA_OPTI
+       tristate "OPTI621/6215 PATA support (Very Experimental)"
+       depends on PCI && EXPERIMENTAL
+       help
+         This option enables full PIO support for the early Opti ATA
+         controllers found on some old motherboards.
+
+         If unsure, say N.
+
+config PATA_PALMLD
+       tristate "Palm LifeDrive PATA support"
+       depends on MACH_PALMLD
+       help
+         This option enables support for Palm LifeDrive's internal ATA
+         port via the new ATA layer.
+
+         If unsure, say N.
+
+config PATA_PCMCIA
+       tristate "PCMCIA PATA support"
+       depends on PCMCIA
+       help
+         This option enables support for PCMCIA ATA interfaces, including
+         compact flash card adapters via the new ATA layer.
+
+         If unsure, say N.
 
 config HAVE_PATA_PLATFORM
        bool
@@ -725,14 +762,6 @@ config PATA_PLATFORM
 
          If unsure, say N.
 
-config PATA_AT91
-       tristate "PATA support for AT91SAM9260"
-       depends on ARM && ARCH_AT91
-       help
-         This option enables support for IDE devices on the Atmel AT91SAM9260 SoC.
-
-         If unsure, say N.
-
 config PATA_OF_PLATFORM
        tristate "OpenFirmware platform device PATA support"
        depends on PATA_PLATFORM && PPC_OF
@@ -743,69 +772,65 @@ config PATA_OF_PLATFORM
 
          If unsure, say N.
 
-config PATA_ICSIDE
-       tristate "Acorn ICS PATA support"
-       depends on ARM && ARCH_ACORN
+config PATA_QDI
+       tristate "QDI VLB PATA support"
+       depends on ISA
        help
-         On Acorn systems, say Y here if you wish to use the ICS PATA
-         interface card.  This is not required for ICS partition support.
-         If you are unsure, say N to this.
+         Support for QDI 6500 and 6580 PATA controllers on VESA local bus.
 
-config PATA_IXP4XX_CF
-       tristate "IXP4XX Compact Flash support"
-       depends on ARCH_IXP4XX
+config PATA_RB532
+       tristate "RouterBoard 532 PATA CompactFlash support"
+       depends on MIKROTIK_RB532
        help
-         This option enables support for a Compact Flash connected on
-         the ixp4xx expansion bus. This driver had been written for
-         Loft/Avila boards in mind but can work with others.
+         This option enables support for the RouterBoard 532
+         PATA CompactFlash controller.
 
          If unsure, say N.
 
-config PATA_OCTEON_CF
-       tristate "OCTEON Boot Bus Compact Flash support"
-       depends on CPU_CAVIUM_OCTEON
+config PATA_RZ1000
+       tristate "PC Tech RZ1000 PATA support"
+       depends on PCI
        help
-         This option enables a polled compact flash driver for use with
-         compact flash cards attached to the OCTEON boot bus.
+         This option enables basic support for the PC Tech RZ1000/1
+         PATA controllers via the new ATA layer
 
          If unsure, say N.
 
-config PATA_SCC
-       tristate "Toshiba's Cell Reference Set IDE support"
-       depends on PCI && PPC_CELLEB
+config PATA_WINBOND_VLB
+       tristate "Winbond W83759A VLB PATA support (Experimental)"
+       depends on ISA && EXPERIMENTAL
        help
-         This option enables support for the built-in IDE controller on
-         Toshiba Cell Reference Board.
+         Support for the Winbond W83759A controller on Vesa Local Bus
+         systems.
 
-         If unsure, say N.
+comment "Generic fallback / legacy drivers"
 
-config PATA_SCH
-       tristate "Intel SCH PATA support"
-       depends on PCI
+config PATA_ACPI
+       tristate "ACPI firmware driver for PATA"
+       depends on ATA_ACPI && ATA_BMDMA
        help
-         This option enables support for Intel SCH PATA on the Intel
-         SCH (US15W, US15L, UL11L) series host controllers.
-
-         If unsure, say N.
+         This option enables an ACPI method driver which drives
+         motherboard PATA controller interfaces through the ACPI
+         firmware in the BIOS. This driver can sometimes handle
+         otherwise unsupported hardware.
 
-config PATA_BF54X
-       tristate "Blackfin 54x ATAPI support"
-       depends on BF542 || BF548 || BF549
+config ATA_GENERIC
+       tristate "Generic ATA support"
+       depends on PCI && ATA_BMDMA
        help
-         This option enables support for the built-in ATAPI controller on
-         Blackfin 54x family chips.
+         This option enables support for generic BIOS configured
+         ATA controllers via the new ATA layer
 
          If unsure, say N.
 
-config PATA_MACIO
-       tristate "Apple PowerMac/PowerBook internal 'MacIO' IDE"
-       depends on PPC_PMAC
+config PATA_LEGACY
+       tristate "Legacy ISA PATA support (Experimental)"
+       depends on (ISA || PCI) && EXPERIMENTAL
        help
-         Most IDE capable PowerMacs have IDE busses driven by a variant
-          of this controller which is part of the Apple chipset used on
-          most PowerMac models. Some models have multiple busses using
-          different chipsets, though generally, MacIO is one of them.
+         This option enables support for ISA/VLB/PCI bus legacy PATA
+         ports and allows them to be accessed via the new ATA layer.
 
+         If unsure, say N.
 
 endif # ATA_SFF
 endif # ATA
index d0a93c4ad3ec3a0ac0ec8b4905d83b3d71f3ee1f..7ef89d73df63d21323e4e47786e33ed51039ca5b 100644 (file)
@@ -1,33 +1,39 @@
 
 obj-$(CONFIG_ATA)              += libata.o
 
+# non-SFF interface
 obj-$(CONFIG_SATA_AHCI)                += ahci.o libahci.o
 obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o
-obj-$(CONFIG_SATA_SVW)         += sata_svw.o
+obj-$(CONFIG_SATA_FSL)         += sata_fsl.o
+obj-$(CONFIG_SATA_INIC162X)    += sata_inic162x.o
+obj-$(CONFIG_SATA_SIL24)       += sata_sil24.o
+
+# SFF w/ custom DMA
+obj-$(CONFIG_PDC_ADMA)         += pdc_adma.o
+obj-$(CONFIG_PATA_MPC52xx)     += pata_mpc52xx.o
+obj-$(CONFIG_PATA_OCTEON_CF)   += pata_octeon_cf.o
+obj-$(CONFIG_SATA_QSTOR)       += sata_qstor.o
+obj-$(CONFIG_SATA_SX4)         += sata_sx4.o
+
+# SFF SATA w/ BMDMA
 obj-$(CONFIG_ATA_PIIX)         += ata_piix.o
+obj-$(CONFIG_SATA_MV)          += sata_mv.o
+obj-$(CONFIG_SATA_NV)          += sata_nv.o
 obj-$(CONFIG_SATA_PROMISE)     += sata_promise.o
-obj-$(CONFIG_SATA_QSTOR)       += sata_qstor.o
 obj-$(CONFIG_SATA_SIL)         += sata_sil.o
-obj-$(CONFIG_SATA_SIL24)       += sata_sil24.o
-obj-$(CONFIG_SATA_VIA)         += sata_via.o
-obj-$(CONFIG_SATA_VITESSE)     += sata_vsc.o
 obj-$(CONFIG_SATA_SIS)         += sata_sis.o
-obj-$(CONFIG_SATA_SX4)         += sata_sx4.o
-obj-$(CONFIG_SATA_NV)          += sata_nv.o
+obj-$(CONFIG_SATA_SVW)         += sata_svw.o
 obj-$(CONFIG_SATA_ULI)         += sata_uli.o
-obj-$(CONFIG_SATA_MV)          += sata_mv.o
-obj-$(CONFIG_SATA_INIC162X)    += sata_inic162x.o
-obj-$(CONFIG_PDC_ADMA)         += pdc_adma.o
-obj-$(CONFIG_SATA_FSL)         += sata_fsl.o
-obj-$(CONFIG_PATA_MACIO)       += pata_macio.o
+obj-$(CONFIG_SATA_VIA)         += sata_via.o
+obj-$(CONFIG_SATA_VITESSE)     += sata_vsc.o
 
+# SFF PATA w/ BMDMA
 obj-$(CONFIG_PATA_ALI)         += pata_ali.o
 obj-$(CONFIG_PATA_AMD)         += pata_amd.o
 obj-$(CONFIG_PATA_ARTOP)       += pata_artop.o
-obj-$(CONFIG_PATA_ATP867X)     += pata_atp867x.o
-obj-$(CONFIG_PATA_AT32)                += pata_at32.o
 obj-$(CONFIG_PATA_ATIIXP)      += pata_atiixp.o
-obj-$(CONFIG_PATA_CMD640_PCI)  += pata_cmd640.o
+obj-$(CONFIG_PATA_ATP867X)     += pata_atp867x.o
+obj-$(CONFIG_PATA_BF54X)       += pata_bf54x.o
 obj-$(CONFIG_PATA_CMD64X)      += pata_cmd64x.o
 obj-$(CONFIG_PATA_CS5520)      += pata_cs5520.o
 obj-$(CONFIG_PATA_CS5530)      += pata_cs5530.o
@@ -39,47 +45,50 @@ obj-$(CONFIG_PATA_HPT366)   += pata_hpt366.o
 obj-$(CONFIG_PATA_HPT37X)      += pata_hpt37x.o
 obj-$(CONFIG_PATA_HPT3X2N)     += pata_hpt3x2n.o
 obj-$(CONFIG_PATA_HPT3X3)      += pata_hpt3x3.o
-obj-$(CONFIG_PATA_ISAPNP)      += pata_isapnp.o
-obj-$(CONFIG_PATA_IT821X)      += pata_it821x.o
+obj-$(CONFIG_PATA_ICSIDE)      += pata_icside.o
 obj-$(CONFIG_PATA_IT8213)      += pata_it8213.o
+obj-$(CONFIG_PATA_IT821X)      += pata_it821x.o
 obj-$(CONFIG_PATA_JMICRON)     += pata_jmicron.o
+obj-$(CONFIG_PATA_MACIO)       += pata_macio.o
+obj-$(CONFIG_PATA_MARVELL)     += pata_marvell.o
 obj-$(CONFIG_PATA_NETCELL)     += pata_netcell.o
 obj-$(CONFIG_PATA_NINJA32)     += pata_ninja32.o
-obj-$(CONFIG_PATA_NS87410)     += pata_ns87410.o
 obj-$(CONFIG_PATA_NS87415)     += pata_ns87415.o
-obj-$(CONFIG_PATA_OPTI)                += pata_opti.o
-obj-$(CONFIG_PATA_OPTIDMA)     += pata_optidma.o
-obj-$(CONFIG_PATA_MPC52xx)     += pata_mpc52xx.o
-obj-$(CONFIG_PATA_MARVELL)     += pata_marvell.o
-obj-$(CONFIG_PATA_MPIIX)       += pata_mpiix.o
 obj-$(CONFIG_PATA_OLDPIIX)     += pata_oldpiix.o
-obj-$(CONFIG_PATA_PALMLD)      += pata_palmld.o
-obj-$(CONFIG_PATA_PCMCIA)      += pata_pcmcia.o
+obj-$(CONFIG_PATA_OPTIDMA)     += pata_optidma.o
 obj-$(CONFIG_PATA_PDC2027X)    += pata_pdc2027x.o
 obj-$(CONFIG_PATA_PDC_OLD)     += pata_pdc202xx_old.o
-obj-$(CONFIG_PATA_QDI)         += pata_qdi.o
 obj-$(CONFIG_PATA_RADISYS)     += pata_radisys.o
-obj-$(CONFIG_PATA_RB532)       += pata_rb532_cf.o
 obj-$(CONFIG_PATA_RDC)         += pata_rdc.o
-obj-$(CONFIG_PATA_RZ1000)      += pata_rz1000.o
 obj-$(CONFIG_PATA_SC1200)      += pata_sc1200.o
+obj-$(CONFIG_PATA_SCC)         += pata_scc.o
+obj-$(CONFIG_PATA_SCH)         += pata_sch.o
 obj-$(CONFIG_PATA_SERVERWORKS) += pata_serverworks.o
 obj-$(CONFIG_PATA_SIL680)      += pata_sil680.o
+obj-$(CONFIG_PATA_SIS)         += pata_sis.o
 obj-$(CONFIG_PATA_TOSHIBA)     += pata_piccolo.o
+obj-$(CONFIG_PATA_TRIFLEX)     += pata_triflex.o
 obj-$(CONFIG_PATA_VIA)         += pata_via.o
 obj-$(CONFIG_PATA_WINBOND)     += pata_sl82c105.o
-obj-$(CONFIG_PATA_WINBOND_VLB) += pata_winbond.o
-obj-$(CONFIG_PATA_SIS)         += pata_sis.o
-obj-$(CONFIG_PATA_TRIFLEX)     += pata_triflex.o
+
+# SFF PIO only
+obj-$(CONFIG_PATA_AT32)                += pata_at32.o
+obj-$(CONFIG_PATA_AT91)                += pata_at91.o
+obj-$(CONFIG_PATA_CMD640_PCI)  += pata_cmd640.o
+obj-$(CONFIG_PATA_ISAPNP)      += pata_isapnp.o
 obj-$(CONFIG_PATA_IXP4XX_CF)   += pata_ixp4xx_cf.o
-obj-$(CONFIG_PATA_SCC)         += pata_scc.o
-obj-$(CONFIG_PATA_SCH)         += pata_sch.o
-obj-$(CONFIG_PATA_BF54X)       += pata_bf54x.o
-obj-$(CONFIG_PATA_OCTEON_CF)   += pata_octeon_cf.o
+obj-$(CONFIG_PATA_MPIIX)       += pata_mpiix.o
+obj-$(CONFIG_PATA_NS87410)     += pata_ns87410.o
+obj-$(CONFIG_PATA_OPTI)                += pata_opti.o
+obj-$(CONFIG_PATA_PCMCIA)      += pata_pcmcia.o
+obj-$(CONFIG_PATA_PALMLD)      += pata_palmld.o
 obj-$(CONFIG_PATA_PLATFORM)    += pata_platform.o
-obj-$(CONFIG_PATA_AT91)        += pata_at91.o
 obj-$(CONFIG_PATA_OF_PLATFORM) += pata_of_platform.o
-obj-$(CONFIG_PATA_ICSIDE)      += pata_icside.o
+obj-$(CONFIG_PATA_QDI)         += pata_qdi.o
+obj-$(CONFIG_PATA_RB532)       += pata_rb532_cf.o
+obj-$(CONFIG_PATA_RZ1000)      += pata_rz1000.o
+obj-$(CONFIG_PATA_WINBOND_VLB) += pata_winbond.o
+
 # Should be last but two libata driver
 obj-$(CONFIG_PATA_ACPI)                += pata_acpi.o
 # Should be last but one libata driver
index 33fb614f9784a71df64df398defe93fd8d9962bd..573158a9668da008482f4c85c23cef78f4f47ad3 100644 (file)
@@ -155,7 +155,7 @@ static int ata_generic_init_one(struct pci_dev *dev, const struct pci_device_id
                        return rc;
                pcim_pin_device(dev);
        }
-       return ata_pci_sff_init_one(dev, ppi, &generic_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(dev, ppi, &generic_sht, NULL, 0);
 }
 
 static struct pci_device_id ata_generic[] = {
index ec52fc61876374b0f7f1657d283e507cab23d33e..7409f98d2ae63ba4683d440b60942d774a04318b 100644 (file)
@@ -1589,7 +1589,7 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
                hpriv->map = piix_init_sata_map(pdev, port_info,
                                        piix_map_db_table[ent->driver_data]);
 
-       rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
+       rc = ata_pci_bmdma_prepare_host(pdev, ppi, &host);
        if (rc)
                return rc;
        host->private_data = hpriv;
@@ -1626,7 +1626,7 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
        host->flags |= ATA_HOST_PARALLEL_SCAN;
 
        pci_set_master(pdev);
-       return ata_pci_sff_activate_host(host, ata_sff_interrupt, &piix_sht);
+       return ata_pci_sff_activate_host(host, ata_bmdma_interrupt, &piix_sht);
 }
 
 static void piix_remove_one(struct pci_dev *pdev)
index c47373f01f89dfadd6114d03d3b1bbed15970142..06b7e49e039c1e0a2e5b630fe92a1d5d33143b8a 100644 (file)
@@ -160,6 +160,10 @@ int libata_allow_tpm = 0;
 module_param_named(allow_tpm, libata_allow_tpm, int, 0444);
 MODULE_PARM_DESC(allow_tpm, "Permit the use of TPM commands (0=off [default], 1=on)");
 
+static int atapi_an;
+module_param(atapi_an, int, 0444);
+MODULE_PARM_DESC(atapi_an, "Enable ATAPI AN media presence notification (0=0ff [default], 1=on)");
+
 MODULE_AUTHOR("Jeff Garzik");
 MODULE_DESCRIPTION("Library module for ATA devices");
 MODULE_LICENSE("GPL");
@@ -2122,6 +2126,14 @@ retry:
                goto err_out;
        }
 
+       if (dev->horkage & ATA_HORKAGE_DUMP_ID) {
+               ata_dev_printk(dev, KERN_DEBUG, "dumping IDENTIFY data, "
+                              "class=%d may_fallback=%d tried_spinup=%d\n",
+                              class, may_fallback, tried_spinup);
+               print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET,
+                              16, 2, id, ATA_ID_WORDS * sizeof(*id), true);
+       }
+
        /* Falling back doesn't make sense if ID data was read
         * successfully at least once.
         */
@@ -2510,7 +2522,8 @@ int ata_dev_configure(struct ata_device *dev)
                 * to enable ATAPI AN to discern between PHY status
                 * changed notifications and ATAPI ANs.
                 */
-               if ((ap->flags & ATA_FLAG_AN) && ata_id_has_atapi_AN(id) &&
+               if (atapi_an &&
+                   (ap->flags & ATA_FLAG_AN) && ata_id_has_atapi_AN(id) &&
                    (!sata_pmp_attached(ap) ||
                     sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf) == 0)) {
                        unsigned int err_mask;
@@ -6372,6 +6385,7 @@ static int __init ata_parse_force_one(char **cur,
                { "3.0Gbps",    .spd_limit      = 2 },
                { "noncq",      .horkage_on     = ATA_HORKAGE_NONCQ },
                { "ncq",        .horkage_off    = ATA_HORKAGE_NONCQ },
+               { "dump_id",    .horkage_on     = ATA_HORKAGE_DUMP_ID },
                { "pio0",       .xfer_mask      = 1 << (ATA_SHIFT_PIO + 0) },
                { "pio1",       .xfer_mask      = 1 << (ATA_SHIFT_PIO + 1) },
                { "pio2",       .xfer_mask      = 1 << (ATA_SHIFT_PIO + 2) },
index 19ddf924944f94be5afc1ca47da70270d72d95d9..efa4a18cfb9d92fb9a79670abf69669f96f2d436 100644 (file)
@@ -63,7 +63,6 @@ const struct ata_port_operations ata_sff_port_ops = {
        .sff_tf_read            = ata_sff_tf_read,
        .sff_exec_command       = ata_sff_exec_command,
        .sff_data_xfer          = ata_sff_data_xfer,
-       .sff_irq_clear          = ata_sff_irq_clear,
        .sff_drain_fifo         = ata_sff_drain_fifo,
 
        .lost_interrupt         = ata_sff_lost_interrupt,
@@ -395,32 +394,11 @@ void ata_sff_irq_on(struct ata_port *ap)
                ata_sff_set_devctl(ap, ap->ctl);
        ata_wait_idle(ap);
 
-       ap->ops->sff_irq_clear(ap);
+       if (ap->ops->sff_irq_clear)
+               ap->ops->sff_irq_clear(ap);
 }
 EXPORT_SYMBOL_GPL(ata_sff_irq_on);
 
-/**
- *     ata_sff_irq_clear - Clear PCI IDE BMDMA interrupt.
- *     @ap: Port associated with this ATA transaction.
- *
- *     Clear interrupt and error flags in DMA status register.
- *
- *     May be used as the irq_clear() entry in ata_port_operations.
- *
- *     LOCKING:
- *     spin_lock_irqsave(host lock)
- */
-void ata_sff_irq_clear(struct ata_port *ap)
-{
-       void __iomem *mmio = ap->ioaddr.bmdma_addr;
-
-       if (!mmio)
-               return;
-
-       iowrite8(ioread8(mmio + ATA_DMA_STATUS), mmio + ATA_DMA_STATUS);
-}
-EXPORT_SYMBOL_GPL(ata_sff_irq_clear);
-
 /**
  *     ata_sff_tf_load - send taskfile registers to host controller
  *     @ap: Port to which output is sent
@@ -820,11 +798,15 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc)
        case ATAPI_PROT_NODATA:
                ap->hsm_task_state = HSM_ST_LAST;
                break;
+#ifdef CONFIG_ATA_BMDMA
        case ATAPI_PROT_DMA:
                ap->hsm_task_state = HSM_ST_LAST;
                /* initiate bmdma */
                ap->ops->bmdma_start(qc);
                break;
+#endif /* CONFIG_ATA_BMDMA */
+       default:
+               BUG();
        }
 }
 
@@ -1491,27 +1473,27 @@ bool ata_sff_qc_fill_rtf(struct ata_queued_cmd *qc)
 }
 EXPORT_SYMBOL_GPL(ata_sff_qc_fill_rtf);
 
-/**
- *     ata_sff_host_intr - Handle host interrupt for given (port, task)
- *     @ap: Port on which interrupt arrived (possibly...)
- *     @qc: Taskfile currently active in engine
- *
- *     Handle host interrupt for given queued command.  Currently,
- *     only DMA interrupts are handled.  All other commands are
- *     handled via polling with interrupts disabled (nIEN bit).
- *
- *     LOCKING:
- *     spin_lock_irqsave(host lock)
- *
- *     RETURNS:
- *     One if interrupt was handled, zero if not (shared irq).
- */
-unsigned int ata_sff_host_intr(struct ata_port *ap,
-                                     struct ata_queued_cmd *qc)
+static unsigned int ata_sff_idle_irq(struct ata_port *ap)
 {
-       struct ata_eh_info *ehi = &ap->link.eh_info;
-       u8 status, host_stat = 0;
-       bool bmdma_stopped = false;
+       ap->stats.idle_irq++;
+
+#ifdef ATA_IRQ_TRAP
+       if ((ap->stats.idle_irq % 1000) == 0) {
+               ap->ops->sff_check_status(ap);
+               if (ap->ops->sff_irq_clear)
+                       ap->ops->sff_irq_clear(ap);
+               ata_port_printk(ap, KERN_WARNING, "irq trap\n");
+               return 1;
+       }
+#endif
+       return 0;       /* irq not handled */
+}
+
+static unsigned int __ata_sff_port_intr(struct ata_port *ap,
+                                       struct ata_queued_cmd *qc,
+                                       bool hsmv_on_idle)
+{
+       u8 status;
 
        VPRINTK("ata%u: protocol %d task_state %d\n",
                ap->print_id, qc->tf.protocol, ap->hsm_task_state);
@@ -1528,90 +1510,56 @@ unsigned int ata_sff_host_intr(struct ata_port *ap,
                 * need to check ata_is_atapi(qc->tf.protocol) again.
                 */
                if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
-                       goto idle_irq;
-               break;
-       case HSM_ST_LAST:
-               if (qc->tf.protocol == ATA_PROT_DMA ||
-                   qc->tf.protocol == ATAPI_PROT_DMA) {
-                       /* check status of DMA engine */
-                       host_stat = ap->ops->bmdma_status(ap);
-                       VPRINTK("ata%u: host_stat 0x%X\n",
-                               ap->print_id, host_stat);
-
-                       /* if it's not our irq... */
-                       if (!(host_stat & ATA_DMA_INTR))
-                               goto idle_irq;
-
-                       /* before we do anything else, clear DMA-Start bit */
-                       ap->ops->bmdma_stop(qc);
-                       bmdma_stopped = true;
-
-                       if (unlikely(host_stat & ATA_DMA_ERR)) {
-                               /* error when transfering data to/from memory */
-                               qc->err_mask |= AC_ERR_HOST_BUS;
-                               ap->hsm_task_state = HSM_ST_ERR;
-                       }
-               }
+                       return ata_sff_idle_irq(ap);
                break;
        case HSM_ST:
+       case HSM_ST_LAST:
                break;
        default:
-               goto idle_irq;
+               return ata_sff_idle_irq(ap);
        }
 
-
        /* check main status, clearing INTRQ if needed */
        status = ata_sff_irq_status(ap);
        if (status & ATA_BUSY) {
-               if (bmdma_stopped) {
+               if (hsmv_on_idle) {
                        /* BMDMA engine is already stopped, we're screwed */
                        qc->err_mask |= AC_ERR_HSM;
                        ap->hsm_task_state = HSM_ST_ERR;
                } else
-                       goto idle_irq;
+                       return ata_sff_idle_irq(ap);
        }
 
        /* clear irq events */
-       ap->ops->sff_irq_clear(ap);
+       if (ap->ops->sff_irq_clear)
+               ap->ops->sff_irq_clear(ap);
 
        ata_sff_hsm_move(ap, qc, status, 0);
 
-       if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA ||
-                                      qc->tf.protocol == ATAPI_PROT_DMA))
-               ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat);
-
        return 1;       /* irq handled */
-
-idle_irq:
-       ap->stats.idle_irq++;
-
-#ifdef ATA_IRQ_TRAP
-       if ((ap->stats.idle_irq % 1000) == 0) {
-               ap->ops->sff_check_status(ap);
-               ap->ops->sff_irq_clear(ap);
-               ata_port_printk(ap, KERN_WARNING, "irq trap\n");
-               return 1;
-       }
-#endif
-       return 0;       /* irq not handled */
 }
-EXPORT_SYMBOL_GPL(ata_sff_host_intr);
 
 /**
- *     ata_sff_interrupt - Default ATA host interrupt handler
- *     @irq: irq line (unused)
- *     @dev_instance: pointer to our ata_host information structure
+ *     ata_sff_port_intr - Handle SFF port interrupt
+ *     @ap: Port on which interrupt arrived (possibly...)
+ *     @qc: Taskfile currently active in engine
  *
- *     Default interrupt handler for PCI IDE devices.  Calls
- *     ata_sff_host_intr() for each port that is not disabled.
+ *     Handle port interrupt for given queued command.
  *
  *     LOCKING:
- *     Obtains host lock during operation.
+ *     spin_lock_irqsave(host lock)
  *
  *     RETURNS:
- *     IRQ_NONE or IRQ_HANDLED.
+ *     One if interrupt was handled, zero if not (shared irq).
  */
-irqreturn_t ata_sff_interrupt(int irq, void *dev_instance)
+unsigned int ata_sff_port_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
+{
+       return __ata_sff_port_intr(ap, qc, false);
+}
+EXPORT_SYMBOL_GPL(ata_sff_port_intr);
+
+static inline irqreturn_t __ata_sff_interrupt(int irq, void *dev_instance,
+       unsigned int (*port_intr)(struct ata_port *, struct ata_queued_cmd *))
 {
        struct ata_host *host = dev_instance;
        bool retried = false;
@@ -1631,7 +1579,7 @@ retry:
                qc = ata_qc_from_tag(ap, ap->link.active_tag);
                if (qc) {
                        if (!(qc->tf.flags & ATA_TFLAG_POLLING))
-                               handled |= ata_sff_host_intr(ap, qc);
+                               handled |= port_intr(ap, qc);
                        else
                                polling |= 1 << i;
                } else
@@ -1658,7 +1606,8 @@ retry:
 
                        if (idle & (1 << i)) {
                                ap->ops->sff_check_status(ap);
-                               ap->ops->sff_irq_clear(ap);
+                               if (ap->ops->sff_irq_clear)
+                                       ap->ops->sff_irq_clear(ap);
                        } else {
                                /* clear INTRQ and check if BUSY cleared */
                                if (!(ap->ops->sff_check_status(ap) & ATA_BUSY))
@@ -1680,6 +1629,25 @@ retry:
 
        return IRQ_RETVAL(handled);
 }
+
+/**
+ *     ata_sff_interrupt - Default SFF ATA host interrupt handler
+ *     @irq: irq line (unused)
+ *     @dev_instance: pointer to our ata_host information structure
+ *
+ *     Default interrupt handler for PCI IDE devices.  Calls
+ *     ata_sff_port_intr() for each port that is not disabled.
+ *
+ *     LOCKING:
+ *     Obtains host lock during operation.
+ *
+ *     RETURNS:
+ *     IRQ_NONE or IRQ_HANDLED.
+ */
+irqreturn_t ata_sff_interrupt(int irq, void *dev_instance)
+{
+       return __ata_sff_interrupt(irq, dev_instance, ata_sff_port_intr);
+}
 EXPORT_SYMBOL_GPL(ata_sff_interrupt);
 
 /**
@@ -1717,7 +1685,7 @@ void ata_sff_lost_interrupt(struct ata_port *ap)
                                                                status);
        /* Run the host interrupt logic as if the interrupt had not been
           lost */
-       ata_sff_host_intr(ap, qc);
+       ata_sff_port_intr(ap, qc);
 }
 EXPORT_SYMBOL_GPL(ata_sff_lost_interrupt);
 
@@ -1744,7 +1712,8 @@ void ata_sff_freeze(struct ata_port *ap)
         */
        ap->ops->sff_check_status(ap);
 
-       ap->ops->sff_irq_clear(ap);
+       if (ap->ops->sff_irq_clear)
+               ap->ops->sff_irq_clear(ap);
 }
 EXPORT_SYMBOL_GPL(ata_sff_freeze);
 
@@ -1761,7 +1730,8 @@ void ata_sff_thaw(struct ata_port *ap)
 {
        /* clear & re-enable interrupts */
        ap->ops->sff_check_status(ap);
-       ap->ops->sff_irq_clear(ap);
+       if (ap->ops->sff_irq_clear)
+               ap->ops->sff_irq_clear(ap);
        ata_sff_irq_on(ap);
 }
 EXPORT_SYMBOL_GPL(ata_sff_thaw);
@@ -2349,13 +2319,13 @@ int ata_pci_sff_init_host(struct ata_host *host)
 EXPORT_SYMBOL_GPL(ata_pci_sff_init_host);
 
 /**
- *     ata_pci_sff_prepare_host - helper to prepare native PCI ATA host
+ *     ata_pci_sff_prepare_host - helper to prepare PCI PIO-only SFF ATA host
  *     @pdev: target PCI device
  *     @ppi: array of port_info, must be enough for two ports
  *     @r_host: out argument for the initialized ATA host
  *
- *     Helper to allocate ATA host for @pdev, acquire all native PCI
- *     resources and initialize it accordingly in one go.
+ *     Helper to allocate PIO-only SFF ATA host for @pdev, acquire
+ *     all PCI resources and initialize it accordingly in one go.
  *
  *     LOCKING:
  *     Inherited from calling layer (may sleep).
@@ -2385,9 +2355,6 @@ int ata_pci_sff_prepare_host(struct pci_dev *pdev,
        if (rc)
                goto err_out;
 
-       /* init DMA related stuff */
-       ata_pci_bmdma_init(host);
-
        devres_remove_group(&pdev->dev, NULL);
        *r_host = host;
        return 0;
@@ -2492,8 +2459,21 @@ out:
 }
 EXPORT_SYMBOL_GPL(ata_pci_sff_activate_host);
 
+static const struct ata_port_info *ata_sff_find_valid_pi(
+                                       const struct ata_port_info * const *ppi)
+{
+       int i;
+
+       /* look up the first valid port_info */
+       for (i = 0; i < 2 && ppi[i]; i++)
+               if (ppi[i]->port_ops != &ata_dummy_port_ops)
+                       return ppi[i];
+
+       return NULL;
+}
+
 /**
- *     ata_pci_sff_init_one - Initialize/register PCI IDE host controller
+ *     ata_pci_sff_init_one - Initialize/register PIO-only PCI IDE controller
  *     @pdev: Controller to be initialized
  *     @ppi: array of port_info, must be enough for two ports
  *     @sht: scsi_host_template to use when registering the host
@@ -2502,11 +2482,7 @@ EXPORT_SYMBOL_GPL(ata_pci_sff_activate_host);
  *
  *     This is a helper function which can be called from a driver's
  *     xxx_init_one() probe function if the hardware uses traditional
- *     IDE taskfile registers.
- *
- *     This function calls pci_enable_device(), reserves its register
- *     regions, sets the dma mask, enables bus master mode, and calls
- *     ata_device_add()
+ *     IDE taskfile registers and is PIO only.
  *
  *     ASSUMPTION:
  *     Nobody makes a single channel controller that appears solely as
@@ -2523,20 +2499,13 @@ int ata_pci_sff_init_one(struct pci_dev *pdev,
                 struct scsi_host_template *sht, void *host_priv, int hflag)
 {
        struct device *dev = &pdev->dev;
-       const struct ata_port_info *pi = NULL;
+       const struct ata_port_info *pi;
        struct ata_host *host = NULL;
-       int i, rc;
+       int rc;
 
        DPRINTK("ENTER\n");
 
-       /* look up the first valid port_info */
-       for (i = 0; i < 2 && ppi[i]; i++) {
-               if (ppi[i]->port_ops != &ata_dummy_port_ops) {
-                       pi = ppi[i];
-                       break;
-               }
-       }
-
+       pi = ata_sff_find_valid_pi(ppi);
        if (!pi) {
                dev_printk(KERN_ERR, &pdev->dev,
                           "no valid port_info specified\n");
@@ -2557,7 +2526,6 @@ int ata_pci_sff_init_one(struct pci_dev *pdev,
        host->private_data = host_priv;
        host->flags |= hflag;
 
-       pci_set_master(pdev);
        rc = ata_pci_sff_activate_host(host, ata_sff_interrupt, sht);
 out:
        if (rc == 0)
@@ -2571,6 +2539,12 @@ EXPORT_SYMBOL_GPL(ata_pci_sff_init_one);
 
 #endif /* CONFIG_PCI */
 
+/*
+ *     BMDMA support
+ */
+
+#ifdef CONFIG_ATA_BMDMA
+
 const struct ata_port_operations ata_bmdma_port_ops = {
        .inherits               = &ata_sff_port_ops,
 
@@ -2580,6 +2554,7 @@ const struct ata_port_operations ata_bmdma_port_ops = {
        .qc_prep                = ata_bmdma_qc_prep,
        .qc_issue               = ata_bmdma_qc_issue,
 
+       .sff_irq_clear          = ata_bmdma_irq_clear,
        .bmdma_setup            = ata_bmdma_setup,
        .bmdma_start            = ata_bmdma_start,
        .bmdma_stop             = ata_bmdma_stop,
@@ -2803,6 +2778,75 @@ unsigned int ata_bmdma_qc_issue(struct ata_queued_cmd *qc)
 }
 EXPORT_SYMBOL_GPL(ata_bmdma_qc_issue);
 
+/**
+ *     ata_bmdma_port_intr - Handle BMDMA port interrupt
+ *     @ap: Port on which interrupt arrived (possibly...)
+ *     @qc: Taskfile currently active in engine
+ *
+ *     Handle port interrupt for given queued command.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host lock)
+ *
+ *     RETURNS:
+ *     One if interrupt was handled, zero if not (shared irq).
+ */
+unsigned int ata_bmdma_port_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
+{
+       struct ata_eh_info *ehi = &ap->link.eh_info;
+       u8 host_stat = 0;
+       bool bmdma_stopped = false;
+       unsigned int handled;
+
+       if (ap->hsm_task_state == HSM_ST_LAST && ata_is_dma(qc->tf.protocol)) {
+               /* check status of DMA engine */
+               host_stat = ap->ops->bmdma_status(ap);
+               VPRINTK("ata%u: host_stat 0x%X\n", ap->print_id, host_stat);
+
+               /* if it's not our irq... */
+               if (!(host_stat & ATA_DMA_INTR))
+                       return ata_sff_idle_irq(ap);
+
+               /* before we do anything else, clear DMA-Start bit */
+               ap->ops->bmdma_stop(qc);
+               bmdma_stopped = true;
+
+               if (unlikely(host_stat & ATA_DMA_ERR)) {
+                       /* error when transfering data to/from memory */
+                       qc->err_mask |= AC_ERR_HOST_BUS;
+                       ap->hsm_task_state = HSM_ST_ERR;
+               }
+       }
+
+       handled = __ata_sff_port_intr(ap, qc, bmdma_stopped);
+
+       if (unlikely(qc->err_mask) && ata_is_dma(qc->tf.protocol))
+               ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat);
+
+       return handled;
+}
+EXPORT_SYMBOL_GPL(ata_bmdma_port_intr);
+
+/**
+ *     ata_bmdma_interrupt - Default BMDMA ATA host interrupt handler
+ *     @irq: irq line (unused)
+ *     @dev_instance: pointer to our ata_host information structure
+ *
+ *     Default interrupt handler for PCI IDE devices.  Calls
+ *     ata_bmdma_port_intr() for each port that is not disabled.
+ *
+ *     LOCKING:
+ *     Obtains host lock during operation.
+ *
+ *     RETURNS:
+ *     IRQ_NONE or IRQ_HANDLED.
+ */
+irqreturn_t ata_bmdma_interrupt(int irq, void *dev_instance)
+{
+       return __ata_sff_interrupt(irq, dev_instance, ata_bmdma_port_intr);
+}
+EXPORT_SYMBOL_GPL(ata_bmdma_interrupt);
+
 /**
  *     ata_bmdma_error_handler - Stock error handler for BMDMA controller
  *     @ap: port to handle error for
@@ -2848,7 +2892,8 @@ void ata_bmdma_error_handler(struct ata_port *ap)
                /* if we're gonna thaw, make sure IRQ is clear */
                if (thaw) {
                        ap->ops->sff_check_status(ap);
-                       ap->ops->sff_irq_clear(ap);
+                       if (ap->ops->sff_irq_clear)
+                               ap->ops->sff_irq_clear(ap);
                }
        }
 
@@ -2881,6 +2926,28 @@ void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc)
 }
 EXPORT_SYMBOL_GPL(ata_bmdma_post_internal_cmd);
 
+/**
+ *     ata_bmdma_irq_clear - Clear PCI IDE BMDMA interrupt.
+ *     @ap: Port associated with this ATA transaction.
+ *
+ *     Clear interrupt and error flags in DMA status register.
+ *
+ *     May be used as the irq_clear() entry in ata_port_operations.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host lock)
+ */
+void ata_bmdma_irq_clear(struct ata_port *ap)
+{
+       void __iomem *mmio = ap->ioaddr.bmdma_addr;
+
+       if (!mmio)
+               return;
+
+       iowrite8(ioread8(mmio + ATA_DMA_STATUS), mmio + ATA_DMA_STATUS);
+}
+EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear);
+
 /**
  *     ata_bmdma_setup - Set up PCI IDE BMDMA transaction
  *     @qc: Info associated with this ATA transaction.
@@ -3137,7 +3204,100 @@ void ata_pci_bmdma_init(struct ata_host *host)
 }
 EXPORT_SYMBOL_GPL(ata_pci_bmdma_init);
 
+/**
+ *     ata_pci_bmdma_prepare_host - helper to prepare PCI BMDMA ATA host
+ *     @pdev: target PCI device
+ *     @ppi: array of port_info, must be enough for two ports
+ *     @r_host: out argument for the initialized ATA host
+ *
+ *     Helper to allocate BMDMA ATA host for @pdev, acquire all PCI
+ *     resources and initialize it accordingly in one go.
+ *
+ *     LOCKING:
+ *     Inherited from calling layer (may sleep).
+ *
+ *     RETURNS:
+ *     0 on success, -errno otherwise.
+ */
+int ata_pci_bmdma_prepare_host(struct pci_dev *pdev,
+                              const struct ata_port_info * const * ppi,
+                              struct ata_host **r_host)
+{
+       int rc;
+
+       rc = ata_pci_sff_prepare_host(pdev, ppi, r_host);
+       if (rc)
+               return rc;
+
+       ata_pci_bmdma_init(*r_host);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ata_pci_bmdma_prepare_host);
+
+/**
+ *     ata_pci_bmdma_init_one - Initialize/register BMDMA PCI IDE controller
+ *     @pdev: Controller to be initialized
+ *     @ppi: array of port_info, must be enough for two ports
+ *     @sht: scsi_host_template to use when registering the host
+ *     @host_priv: host private_data
+ *     @hflags: host flags
+ *
+ *     This function is similar to ata_pci_sff_init_one() but also
+ *     takes care of BMDMA initialization.
+ *
+ *     LOCKING:
+ *     Inherited from PCI layer (may sleep).
+ *
+ *     RETURNS:
+ *     Zero on success, negative on errno-based value on error.
+ */
+int ata_pci_bmdma_init_one(struct pci_dev *pdev,
+                          const struct ata_port_info * const * ppi,
+                          struct scsi_host_template *sht, void *host_priv,
+                          int hflags)
+{
+       struct device *dev = &pdev->dev;
+       const struct ata_port_info *pi;
+       struct ata_host *host = NULL;
+       int rc;
+
+       DPRINTK("ENTER\n");
+
+       pi = ata_sff_find_valid_pi(ppi);
+       if (!pi) {
+               dev_printk(KERN_ERR, &pdev->dev,
+                          "no valid port_info specified\n");
+               return -EINVAL;
+       }
+
+       if (!devres_open_group(dev, NULL, GFP_KERNEL))
+               return -ENOMEM;
+
+       rc = pcim_enable_device(pdev);
+       if (rc)
+               goto out;
+
+       /* prepare and activate BMDMA host */
+       rc = ata_pci_bmdma_prepare_host(pdev, ppi, &host);
+       if (rc)
+               goto out;
+       host->private_data = host_priv;
+       host->flags |= hflags;
+
+       pci_set_master(pdev);
+       rc = ata_pci_sff_activate_host(host, ata_bmdma_interrupt, sht);
+ out:
+       if (rc == 0)
+               devres_remove_group(&pdev->dev, NULL);
+       else
+               devres_release_group(&pdev->dev, NULL);
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(ata_pci_bmdma_init_one);
+
 #endif /* CONFIG_PCI */
+#endif /* CONFIG_ATA_BMDMA */
 
 /**
  *     ata_sff_port_init - Initialize SFF/BMDMA ATA port
index 066b9f301ed5a76e7de363ec083dc7cf0686a36b..c8d47034d5e99d679155f4be31b72d9c441d2e87 100644 (file)
@@ -260,7 +260,7 @@ static int pacpi_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
                        return rc;
                pcim_pin_device(pdev);
        }
-       return ata_pci_sff_init_one(pdev, ppi, &pacpi_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &pacpi_sht, NULL, 0);
 }
 
 static const struct pci_device_id pacpi_pci_tbl[] = {
index f306e10c748deb004b88126f22b9ab4d41828087..794ec6e3275dd9432b979caa9510ba5554328746 100644 (file)
@@ -583,7 +583,10 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
                        ppi[0] = &info_20_udma;
        }
 
-       return ata_pci_sff_init_one(pdev, ppi, &ali_sht, NULL, 0);
+       if (!ppi[0]->mwdma_mask && !ppi[0]->udma_mask)
+               return ata_pci_sff_init_one(pdev, ppi, &ali_sht, NULL, 0);
+       else
+               return ata_pci_bmdma_init_one(pdev, ppi, &ali_sht, NULL, 0);
 }
 
 #ifdef CONFIG_PM
index d95eca9c547ed332749daaac94b39a20331d0708..620a07cabe31d11dde15c563e53f4fd7f51337e1 100644 (file)
@@ -574,7 +574,7 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
        }
 
        /* And fire it up */
-       return ata_pci_sff_init_one(pdev, ppi, &amd_sht, hpriv, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &amd_sht, hpriv, 0);
 }
 
 #ifdef CONFIG_PM
index 4d066d6c30fa78bdc1a4ee08d7e66ea6da5e629b..ba43f0f8c880a21aa1b8b1d3b9ae3d8c3487d415 100644 (file)
@@ -421,7 +421,7 @@ static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
 
        BUG_ON(ppi[0] == NULL);
 
-       return ata_pci_sff_init_one(pdev, ppi, &artop_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &artop_sht, NULL, 0);
 }
 
 static const struct pci_device_id artop_pci_tbl[] = {
index 44d88b380ddda7257a604a04334824ff533a0d7a..43755616dc5ac619ecfd873ce0e5f48b99c2ba17 100644 (file)
@@ -246,8 +246,8 @@ static int atiixp_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
                if (!pci_test_config_bits(pdev, &atiixp_enable_bits[i]))
                        ppi[i] = &ata_dummy_port_info;
 
-       return ata_pci_sff_init_one(pdev, ppi, &atiixp_sht, NULL,
-                                               ATA_HOST_PARALLEL_SCAN);
+       return ata_pci_bmdma_init_one(pdev, ppi, &atiixp_sht, NULL,
+                                     ATA_HOST_PARALLEL_SCAN);
 }
 
 static const struct pci_device_id atiixp[] = {
index bb6e0746e07d110a5a31f561fc72c52923238031..95295935dd95e5e269b9d08b8a4a657982c29ffc 100644 (file)
@@ -525,7 +525,7 @@ static int atp867x_init_one(struct pci_dev *pdev,
 
        pci_set_master(pdev);
 
-       rc = ata_host_activate(host, pdev->irq, ata_sff_interrupt,
+       rc = ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
                                IRQF_SHARED, &atp867x_sht);
        if (rc)
                dev_printk(KERN_ERR, &pdev->dev, "failed to activate host\n");
index 6422cfd13d0d4823102e7c78b4db3e2ceed78f1c..9cae65de750e10777260d2e3e9d9bbab2026b768 100644 (file)
@@ -1214,7 +1214,7 @@ static unsigned int bfin_data_xfer(struct ata_device *dev, unsigned char *buf,
  *     bfin_irq_clear - Clear ATAPI interrupt.
  *     @ap: Port associated with this ATA transaction.
  *
- *     Note: Original code is ata_sff_irq_clear().
+ *     Note: Original code is ata_bmdma_irq_clear().
  */
 
 static void bfin_irq_clear(struct ata_port *ap)
index 4c81a71b8877e4262c6574e5e5eb669b88b3610d..9f5da1c7454be3e06f37586a77dc1377e7cd4a9d 100644 (file)
@@ -367,7 +367,7 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
        pci_write_config_byte(pdev, UDIDETCR0, 0xF0);
 #endif
 
-       return ata_pci_sff_init_one(pdev, ppi, &cmd64x_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &cmd64x_sht, NULL, 0);
 }
 
 #ifdef CONFIG_PM
index 17c5f346ff01510a32a1fe0081e56e1667b081f3..030952f1f97c6e1290dc2a35663fbb29038f4d3e 100644 (file)
@@ -221,7 +221,7 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
                        continue;
 
                rc = devm_request_irq(&pdev->dev, irq[ap->port_no],
-                                     ata_sff_interrupt, 0, DRV_NAME, host);
+                                     ata_bmdma_interrupt, 0, DRV_NAME, host);
                if (rc)
                        return rc;
 
index e809a4233a81bd2da2ad9a6e4200d2e75f0f360c..f792330f0d8e3b75899bf7c5b443e97fac7015fb 100644 (file)
@@ -324,7 +324,7 @@ static int cs5530_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
                ppi[1] = &info_palmax_secondary;
 
        /* Now kick off ATA set up */
-       return ata_pci_sff_init_one(pdev, ppi, &cs5530_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &cs5530_sht, NULL, 0);
 }
 
 #ifdef CONFIG_PM
index a02e6459fdccbf85fc362295139223d0add8efd0..03a93186aa197e8fd34b62e1fa495b8ede7779be 100644 (file)
@@ -198,7 +198,7 @@ static int cs5535_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        rdmsr(ATAC_CH0D1_PIO, timings, dummy);
        if (CS5535_BAD_PIO(timings))
                wrmsr(ATAC_CH0D1_PIO, 0xF7F4F7F4UL, 0);
-       return ata_pci_sff_init_one(dev, ppi, &cs5535_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(dev, ppi, &cs5535_sht, NULL, 0);
 }
 
 static const struct pci_device_id cs5535[] = {
index 914ae3506ff5639f249f0dd696ab04581af17847..21ee23f89e88b153ee8e35af5d75c61f83f92496 100644 (file)
@@ -260,7 +260,7 @@ static int cs5536_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                return -ENODEV;
        }
 
-       return ata_pci_sff_init_one(dev, ppi, &cs5536_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(dev, ppi, &cs5536_sht, NULL, 0);
 }
 
 static const struct pci_device_id cs5536[] = {
index 0fcc096b8daca4391f9d0d2fd188ac53979bc7e0..6d915b063d93449f7dee9d762b7002492940040e 100644 (file)
@@ -138,7 +138,7 @@ static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *i
        if (PCI_FUNC(pdev->devfn) != 1)
                return -ENODEV;
 
-       return ata_pci_sff_init_one(pdev, ppi, &cy82c693_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &cy82c693_sht, NULL, 0);
 }
 
 static const struct pci_device_id cy82c693[] = {
index 3bac0e0796912a669454b31f2678f1055656ab8c..a08834758ea2881ff41c8578b99f86b15cc1e9db 100644 (file)
@@ -277,8 +277,8 @@ static int efar_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                dev_printk(KERN_DEBUG, &pdev->dev,
                           "version " DRV_VERSION "\n");
 
-       return ata_pci_sff_init_one(pdev, ppi, &efar_sht, NULL,
-                                       ATA_HOST_PARALLEL_SCAN);
+       return ata_pci_bmdma_init_one(pdev, ppi, &efar_sht, NULL,
+                                     ATA_HOST_PARALLEL_SCAN);
 }
 
 static const struct pci_device_id efar_pci_tbl[] = {
index 8580eb3cd54db8b31f0049e68bbb7429e05124f7..7688868557b95e7bd2231599178134bd3b13d6f9 100644 (file)
@@ -361,7 +361,7 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                        break;
        }
        /* Now kick off ATA set up */
-       return ata_pci_sff_init_one(dev, ppi, &hpt36x_sht, hpriv, 0);
+       return ata_pci_bmdma_init_one(dev, ppi, &hpt36x_sht, hpriv, 0);
 }
 
 #ifdef CONFIG_PM
index 98b498b6907c441de3a2d95b6ce5df000a1ed943..9ae4c08305779a4cad19fbe466eb1ab48bc3053b 100644 (file)
@@ -987,7 +987,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        }
 
        /* Now kick off ATA set up */
-       return ata_pci_sff_init_one(dev, ppi, &hpt37x_sht, private_data, 0);
+       return ata_pci_bmdma_init_one(dev, ppi, &hpt37x_sht, private_data, 0);
 }
 
 static const struct pci_device_id hpt37x[] = {
index 8b95aeba0e74c203ea0599eb7455b3ba7cd17d7e..32f3463216b8df8b095b6af3dcc79c7142dbfda3 100644 (file)
@@ -548,7 +548,7 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                outb(inb(iobase + 0x9c) | 0x04, iobase + 0x9c);
 
        /* Now kick off ATA set up */
-       return ata_pci_sff_init_one(dev, ppi, &hpt3x2n_sht, hpriv, 0);
+       return ata_pci_bmdma_init_one(dev, ppi, &hpt3x2n_sht, hpriv, 0);
 }
 
 static const struct pci_device_id hpt3x2n[] = {
index 727a81ce4c9f3b42a1facd384cc345429fa35e4e..b63d5e2d4628ffd6d8c4a5e75ae4558944099f58 100644 (file)
@@ -248,7 +248,7 @@ static int hpt3x3_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
                ata_port_pbar_desc(ap, 4, offset_cmd[i], "cmd");
        }
        pci_set_master(pdev);
-       return ata_host_activate(host, pdev->irq, ata_sff_interrupt,
+       return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
                                 IRQF_SHARED, &hpt3x3_sht);
 }
 
index b56e8f722d20873c8ce1d49b5201522e737f2f76..9f2889fe43b25e26f085d2973df935b6243c79b0 100644 (file)
@@ -470,7 +470,7 @@ static int __devinit pata_icside_add_ports(struct pata_icside_info *info)
                pata_icside_setup_ioaddr(ap, info->base, info, info->port[i]);
        }
 
-       return ata_host_activate(host, ec->irq, ata_sff_interrupt, 0,
+       return ata_host_activate(host, ec->irq, ata_bmdma_interrupt, 0,
                                 &pata_icside_sht);
 }
 
index f971f0de88e634437251938882449d49be602bc9..4d142a2ab8fd42b72c55666b2e72275d477e8481 100644 (file)
@@ -273,7 +273,7 @@ static int it8213_init_one (struct pci_dev *pdev, const struct pci_device_id *en
                dev_printk(KERN_DEBUG, &pdev->dev,
                           "version " DRV_VERSION "\n");
 
-       return ata_pci_sff_init_one(pdev, ppi, &it8213_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &it8213_sht, NULL, 0);
 }
 
 static const struct pci_device_id it8213_pci_tbl[] = {
index 2bd2b002d14a27f4cdedd12dda2fe8eb65a6aafd..bf88f71a21f45cc727fd23e99e6227fb518d70b0 100644 (file)
@@ -933,7 +933,7 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
                else
                        ppi[0] = &info_smart;
        }
-       return ata_pci_sff_init_one(pdev, ppi, &it821x_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &it821x_sht, NULL, 0);
 }
 
 #ifdef CONFIG_PM
index 565e01e6ac7ce169805164e52a11bb456d4fb8c8..cb3babbb7035089913bbf41a0ebbafcfe80a1351 100644 (file)
@@ -144,7 +144,7 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i
        };
        const struct ata_port_info *ppi[] = { &info, NULL };
 
-       return ata_pci_sff_init_one(pdev, ppi, &jmicron_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &jmicron_sht, NULL, 0);
 }
 
 static const struct pci_device_id jmicron_pci_tbl[] = {
index 25df50f51c046d44c9a3f0579eb247b0029228d1..76640ac76888ff88ae7a330423d6bf475149282a 100644 (file)
@@ -1110,7 +1110,7 @@ static int __devinit pata_macio_common_init(struct pata_macio_priv        *priv,
 
        /* Start it up */
        priv->irq = irq;
-       return ata_host_activate(priv->host, irq, ata_sff_interrupt, 0,
+       return ata_host_activate(priv->host, irq, ata_bmdma_interrupt, 0,
                                 &pata_macio_sht);
 }
 
@@ -1140,7 +1140,7 @@ static int __devinit pata_macio_attach(struct macio_dev *mdev,
                        "Failed to allocate private memory\n");
                return -ENOMEM;
        }
-       priv->node = of_node_get(mdev->ofdev.node);
+       priv->node = of_node_get(mdev->ofdev.dev.of_node);
        priv->mdev = mdev;
        priv->dev = &mdev->ofdev.dev;
 
index e8ca02e5a71d969e4dfd852390ea8b4d119c591a..dd38083dcbeb101838e9ece0802f71bf3d541a68 100644 (file)
@@ -153,7 +153,7 @@ static int marvell_init_one (struct pci_dev *pdev, const struct pci_device_id *i
                return -ENODEV;
        }
 #endif
-       return ata_pci_sff_init_one(pdev, ppi, &marvell_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &marvell_sht, NULL, 0);
 }
 
 static const struct pci_device_id marvell_pci_tbl[] = {
index 96b11b604ae018331f21425495ec84227ff82619..f087ab55b1dfcb09c0c0dce87a045a8de7479f31 100644 (file)
@@ -659,7 +659,7 @@ mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv,
        ata_port_desc(ap, "ata_regs 0x%lx", raw_ata_regs);
 
        /* activate host */
-       return ata_host_activate(host, priv->ata_irq, ata_sff_interrupt, 0,
+       return ata_host_activate(host, priv->ata_irq, ata_bmdma_interrupt, 0,
                                 &mpc52xx_ata_sht);
 }
 
@@ -694,7 +694,7 @@ mpc52xx_ata_probe(struct of_device *op, const struct of_device_id *match)
        struct bcom_task *dmatsk = NULL;
 
        /* Get ipb frequency */
-       ipb_freq = mpc5xxx_get_bus_frequency(op->node);
+       ipb_freq = mpc5xxx_get_bus_frequency(op->dev.of_node);
        if (!ipb_freq) {
                dev_err(&op->dev, "could not determine IPB bus frequency\n");
                return -ENODEV;
@@ -702,7 +702,7 @@ mpc52xx_ata_probe(struct of_device *op, const struct of_device_id *match)
 
        /* Get device base address from device tree, request the region
         * and ioremap it. */
-       rv = of_address_to_resource(op->node, 0, &res_mem);
+       rv = of_address_to_resource(op->dev.of_node, 0, &res_mem);
        if (rv) {
                dev_err(&op->dev, "could not determine device base address\n");
                return rv;
@@ -735,14 +735,14 @@ mpc52xx_ata_probe(struct of_device *op, const struct of_device_id *match)
         * The MPC5200 ATA controller supports MWDMA modes 0, 1 and 2 and
         * UDMA modes 0, 1 and 2.
         */
-       prop = of_get_property(op->node, "mwdma-mode", &proplen);
+       prop = of_get_property(op->dev.of_node, "mwdma-mode", &proplen);
        if ((prop) && (proplen >= 4))
                mwdma_mask = ATA_MWDMA2 & ((1 << (*prop + 1)) - 1);
-       prop = of_get_property(op->node, "udma-mode", &proplen);
+       prop = of_get_property(op->dev.of_node, "udma-mode", &proplen);
        if ((prop) && (proplen >= 4))
                udma_mask = ATA_UDMA2 & ((1 << (*prop + 1)) - 1);
 
-       ata_irq = irq_of_parse_and_map(op->node, 0);
+       ata_irq = irq_of_parse_and_map(op->dev.of_node, 0);
        if (ata_irq == NO_IRQ) {
                dev_err(&op->dev, "error mapping irq\n");
                return -EINVAL;
@@ -884,9 +884,6 @@ static struct of_device_id mpc52xx_ata_of_match[] = {
 
 
 static struct of_platform_driver mpc52xx_ata_of_platform_driver = {
-       .owner          = THIS_MODULE,
-       .name           = DRV_NAME,
-       .match_table    = mpc52xx_ata_of_match,
        .probe          = mpc52xx_ata_probe,
        .remove         = mpc52xx_ata_remove,
 #ifdef CONFIG_PM
@@ -896,6 +893,7 @@ static struct of_platform_driver mpc52xx_ata_of_platform_driver = {
        .driver         = {
                .name   = DRV_NAME,
                .owner  = THIS_MODULE,
+               .of_match_table = mpc52xx_ata_of_match,
        },
 };
 
index 94f979a7f4f73f67f4d5098f38d927bbdac62ce6..3eb921c746a18acbde49d133583caca6aabfd11f 100644 (file)
@@ -82,7 +82,7 @@ static int netcell_init_one (struct pci_dev *pdev, const struct pci_device_id *e
        ata_pci_bmdma_clear_simplex(pdev);
 
        /* And let the library code do the work */
-       return ata_pci_sff_init_one(pdev, port_info, &netcell_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, port_info, &netcell_sht, NULL, 0);
 }
 
 static const struct pci_device_id netcell_pci_tbl[] = {
index dd53a66b19e3b89837dc1fbba01cbd5b209cc97f..cc50bd09aa26cc584f6359c857e345366365b714 100644 (file)
@@ -149,7 +149,7 @@ static int ninja32_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 
        ninja32_program(base);
        /* FIXME: Should we disable them at remove ? */
-       return ata_host_activate(host, dev->irq, ata_sff_interrupt,
+       return ata_host_activate(host, dev->irq, ata_bmdma_interrupt,
                                 IRQF_SHARED, &ninja32_sht);
 }
 
index fdbba2d76d3e6dec4ff334b436838a5075ffeca2..605f198f958c58697cc23d23310ff14fe6f5cb99 100644 (file)
@@ -380,7 +380,7 @@ static int ns87415_init_one (struct pci_dev *pdev, const struct pci_device_id *e
 
        ns87415_fixup(pdev);
 
-       return ata_pci_sff_init_one(pdev, ppi, &ns87415_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &ns87415_sht, NULL, 0);
 }
 
 static const struct pci_device_id ns87415_pci_tbl[] = {
index 3001109352ea516ba80ee4e2520cd84fb5b72886..06ddd91ffeda276f0ec5d0c0cfd2696f308a0cc1 100644 (file)
@@ -749,20 +749,6 @@ static void octeon_cf_dev_config(struct ata_device *dev)
        dev->max_sectors = min(dev->max_sectors, 4095U);
 }
 
-/*
- * Trap if driver tries to do standard bmdma commands.  They are not
- * supported.
- */
-static void unreachable_qc(struct ata_queued_cmd *qc)
-{
-       BUG();
-}
-
-static u8 unreachable_port(struct ata_port *ap)
-{
-       BUG();
-}
-
 /*
  * We don't do ATAPI DMA so return 0.
  */
@@ -804,10 +790,6 @@ static struct ata_port_operations octeon_cf_ops = {
        .sff_dev_select         = octeon_cf_dev_select,
        .sff_irq_on             = octeon_cf_irq_on,
        .sff_irq_clear          = octeon_cf_irq_clear,
-       .bmdma_setup            = unreachable_qc,
-       .bmdma_start            = unreachable_qc,
-       .bmdma_stop             = unreachable_qc,
-       .bmdma_status           = unreachable_port,
        .cable_detect           = ata_cable_40wire,
        .set_piomode            = octeon_cf_set_piomode,
        .set_dmamode            = octeon_cf_set_dmamode,
index 1f18ad9e4fe161a6bfa33b84fff06c5c72626228..5a1b82c08be950b3b359c203c6654f342dde57c2 100644 (file)
@@ -18,7 +18,7 @@ static int __devinit pata_of_platform_probe(struct of_device *ofdev,
                                            const struct of_device_id *match)
 {
        int ret;
-       struct device_node *dn = ofdev->node;
+       struct device_node *dn = ofdev->dev.of_node;
        struct resource io_res;
        struct resource ctl_res;
        struct resource irq_res;
@@ -91,8 +91,11 @@ static struct of_device_id pata_of_platform_match[] = {
 MODULE_DEVICE_TABLE(of, pata_of_platform_match);
 
 static struct of_platform_driver pata_of_platform_driver = {
-       .name           = "pata_of_platform",
-       .match_table    = pata_of_platform_match,
+       .driver = {
+               .name = "pata_of_platform",
+               .owner = THIS_MODULE,
+               .of_match_table = pata_of_platform_match,
+       },
        .probe          = pata_of_platform_probe,
        .remove         = __devexit_p(pata_of_platform_remove),
 };
index 988ef2627be32b220a78aa3c226c3c826fcb3795..b811c163620472d0184c6c7e22033feee120b8d1 100644 (file)
@@ -248,7 +248,7 @@ static int oldpiix_init_one (struct pci_dev *pdev, const struct pci_device_id *e
                dev_printk(KERN_DEBUG, &pdev->dev,
                           "version " DRV_VERSION "\n");
 
-       return ata_pci_sff_init_one(pdev, ppi, &oldpiix_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &oldpiix_sht, NULL, 0);
 }
 
 static const struct pci_device_id oldpiix_pci_tbl[] = {
index 76b7d12b1e8d37ed78d7196f854b8ec240780a15..0852cd07de085425d68416301111a79f45d9a4d0 100644 (file)
@@ -429,7 +429,7 @@ static int optidma_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        if (optiplus_with_udma(dev))
                ppi[0] = &info_82c700_udma;
 
-       return ata_pci_sff_init_one(dev, ppi, &optidma_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(dev, ppi, &optidma_sht, NULL, 0);
 }
 
 static const struct pci_device_id optidma[] = {
index 09f1f22c030712d31589fe9a711c94dce1b0fb6c..b183511225252bcd2411021c78fefd8e5ac5a752 100644 (file)
@@ -754,7 +754,7 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de
                return -EIO;
 
        pci_set_master(pdev);
-       return ata_host_activate(host, pdev->irq, ata_sff_interrupt,
+       return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
                                 IRQF_SHARED, &pdc2027x_sht);
 }
 
index fa1e2f3bc0fda64264992da81e0034c289d5c264..c39f213e1bbcba37605d39928125182edbb903c5 100644 (file)
@@ -337,7 +337,7 @@ static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id
                                return -ENODEV;
                }
        }
-       return ata_pci_sff_init_one(dev, ppi, &pdc202xx_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(dev, ppi, &pdc202xx_sht, NULL, 0);
 }
 
 static const struct pci_device_id pdc202xx[] = {
index 9816154148490f708fd22bcd0c1b62f98b3fa39b..cb01bf9496fe3c6ed291e1bac51f8eb1cbebe030 100644 (file)
@@ -95,7 +95,7 @@ static int ata_tosh_init_one(struct pci_dev *dev, const struct pci_device_id *id
        };
        const struct ata_port_info *ppi[] = { &info, &ata_dummy_port_info };
        /* Just one port for the moment */
-       return ata_pci_sff_init_one(dev, ppi, &tosh_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(dev, ppi, &tosh_sht, NULL, 0);
 }
 
 static struct pci_device_id ata_tosh[] = {
index a5fa388e5398acb43389e9ccaa4edbfd514c6149..8574b31f1773cc03ae0ff612f6cea0e42762e4ae 100644 (file)
@@ -227,7 +227,7 @@ static int radisys_init_one (struct pci_dev *pdev, const struct pci_device_id *e
                dev_printk(KERN_DEBUG, &pdev->dev,
                           "version " DRV_VERSION "\n");
 
-       return ata_pci_sff_init_one(pdev, ppi, &radisys_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &radisys_sht, NULL, 0);
 }
 
 static const struct pci_device_id radisys_pci_tbl[] = {
index 37092cfd7bc67a168a548570aaaef0947a0b72ea..5fbe9b166c69ff75ae002f10d434aef8ac6eca40 100644 (file)
@@ -344,7 +344,7 @@ static int __devinit rdc_init_one(struct pci_dev *pdev,
         */
        pci_read_config_dword(pdev, 0x54, &hpriv->saved_iocfg);
 
-       rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
+       rc = ata_pci_bmdma_prepare_host(pdev, ppi, &host);
        if (rc)
                return rc;
        host->private_data = hpriv;
@@ -354,7 +354,7 @@ static int __devinit rdc_init_one(struct pci_dev *pdev,
        host->flags |= ATA_HOST_PARALLEL_SCAN;
 
        pci_set_master(pdev);
-       return ata_pci_sff_activate_host(host, ata_sff_interrupt, &rdc_sht);
+       return ata_pci_sff_activate_host(host, ata_bmdma_interrupt, &rdc_sht);
 }
 
 static void rdc_remove_one(struct pci_dev *pdev)
index 6b5b63a2fd8e223cca19aa00f5195c7fdc72f3a4..e2c18257adff98673046b2215627b40407784c55 100644 (file)
@@ -237,7 +237,7 @@ static int sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        };
        const struct ata_port_info *ppi[] = { &info, NULL };
 
-       return ata_pci_sff_init_one(dev, ppi, &sc1200_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(dev, ppi, &sc1200_sht, NULL, 0);
 }
 
 static const struct pci_device_id sc1200[] = {
index 6f6193b707cb4f86da4d93f037f2893f39a65c78..d9db3f8d60efa53de94332293a466ab0cc159678 100644 (file)
@@ -875,7 +875,7 @@ static void scc_postreset(struct ata_link *link, unsigned int *classes)
  *     scc_irq_clear - Clear PCI IDE BMDMA interrupt.
  *     @ap: Port associated with this ATA transaction.
  *
- *     Note: Original code is ata_sff_irq_clear().
+ *     Note: Original code is ata_bmdma_irq_clear().
  */
 
 static void scc_irq_clear (struct ata_port *ap)
@@ -1105,7 +1105,7 @@ static int scc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        if (rc)
                return rc;
 
-       return ata_host_activate(host, pdev->irq, ata_sff_interrupt,
+       return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
                                 IRQF_SHARED, &scc_sht);
 }
 
index 86b3d0133c7c7f92b0c88966c9b48d7f02f81444..e97b32f03a6ec87ee4add617efdbc1cf466a158b 100644 (file)
@@ -179,7 +179,7 @@ static int __devinit sch_init_one(struct pci_dev *pdev,
                dev_printk(KERN_DEBUG, &pdev->dev,
                           "version " DRV_VERSION "\n");
 
-       return ata_pci_sff_init_one(pdev, ppi, &sch_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &sch_sht, NULL, 0);
 }
 
 static int __init sch_init(void)
index 43ea389df2b3bca935224445eb8dcf461da6417e..86dd714e3e1d21be4e4e755cf74d38b9f17e8069 100644 (file)
@@ -460,7 +460,7 @@ static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id
        if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
                ata_pci_bmdma_clear_simplex(pdev);
 
-       return ata_pci_sff_init_one(pdev, ppi, &serverworks_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &serverworks_sht, NULL, 0);
 }
 
 #ifdef CONFIG_PM
index 43faf106f6472d406c1124beedc782ac685eefe4..d3190d7ec304034458c6979f08f40059ac80643e 100644 (file)
@@ -374,11 +374,11 @@ static int __devinit sil680_init_one(struct pci_dev *pdev,
        ata_sff_std_ports(&host->ports[1]->ioaddr);
 
        /* Register & activate */
-       return ata_host_activate(host, pdev->irq, ata_sff_interrupt,
+       return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
                                 IRQF_SHARED, &sil680_sht);
 
 use_ioports:
-       return ata_pci_sff_init_one(pdev, ppi, &sil680_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &sil680_sht, NULL, 0);
 }
 
 #ifdef CONFIG_PM
index b6708032f321a35cc40b8a261f95c0dbafe6b15e..60cea13cccce9485b01ff73f6ff40a76821c23be 100644 (file)
@@ -826,7 +826,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 
        sis_fixup(pdev, chipset);
 
-       return ata_pci_sff_init_one(pdev, ppi, &sis_sht, chipset, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &sis_sht, chipset, 0);
 }
 
 #ifdef CONFIG_PM
index 733b042a746931062f26ed3a265f3c06c095cff0..98548f640c8eae74bc408b67273f529dd9b8a310 100644 (file)
@@ -316,7 +316,7 @@ static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id
        val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16;
        pci_write_config_dword(dev, 0x40, val);
 
-       return ata_pci_sff_init_one(dev, ppi, &sl82c105_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(dev, ppi, &sl82c105_sht, NULL, 0);
 }
 
 static const struct pci_device_id sl82c105[] = {
index 48f50600ed2a58eccb1584a9bb1e4919affcfdd4..0d1f89e571ddb35641e2860783ceb17cf9b42fe0 100644 (file)
@@ -201,7 +201,7 @@ static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
 
-       return ata_pci_sff_init_one(dev, ppi, &triflex_sht, NULL, 0);
+       return ata_pci_bmdma_init_one(dev, ppi, &triflex_sht, NULL, 0);
 }
 
 static const struct pci_device_id triflex[] = {
index 7e3e0a5598b7f28b487d4b2bf9792b319d0befae..5e659885de162e7ef3cf38e3e1f8a67098108712 100644 (file)
@@ -627,7 +627,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
        }
 
        /* We have established the device type, now fire it up */
-       return ata_pci_sff_init_one(pdev, ppi, &via_sht, (void *)config, 0);
+       return ata_pci_bmdma_init_one(pdev, ppi, &via_sht, (void *)config, 0);
 }
 
 #ifdef CONFIG_PM
index a69192b38b438411cf4b8e839cbe32dfcd357f6c..61c89b54ea23941fd937a25ec4228eca56648e10 100644 (file)
@@ -1313,7 +1313,7 @@ static int sata_fsl_probe(struct of_device *ofdev,
        dev_printk(KERN_INFO, &ofdev->dev,
                   "Sata FSL Platform/CSB Driver init\n");
 
-       hcr_base = of_iomap(ofdev->node, 0);
+       hcr_base = of_iomap(ofdev->dev.of_node, 0);
        if (!hcr_base)
                goto error_exit_with_cleanup;
 
@@ -1332,7 +1332,7 @@ static int sata_fsl_probe(struct of_device *ofdev,
        host_priv->ssr_base = ssr_base;
        host_priv->csr_base = csr_base;
 
-       irq = irq_of_parse_and_map(ofdev->node, 0);
+       irq = irq_of_parse_and_map(ofdev->dev.of_node, 0);
        if (irq < 0) {
                dev_printk(KERN_ERR, &ofdev->dev, "invalid irq from platform\n");
                goto error_exit_with_cleanup;
@@ -1427,8 +1427,11 @@ static struct of_device_id fsl_sata_match[] = {
 MODULE_DEVICE_TABLE(of, fsl_sata_match);
 
 static struct of_platform_driver fsl_sata_driver = {
-       .name           = "fsl-sata",
-       .match_table    = fsl_sata_match,
+       .driver = {
+               .name = "fsl-sata",
+               .owner = THIS_MODULE,
+               .of_match_table = fsl_sata_match,
+       },
        .probe          = sata_fsl_probe,
        .remove         = sata_fsl_remove,
 #ifdef CONFIG_PM
index f3471bc949d37c00fac70bbbec355f77692a8325..a476cd99b95d42ce666e38c17d2dd767cac4f6db 100644 (file)
@@ -675,8 +675,6 @@ static struct ata_port_operations mv5_ops = {
        .freeze                 = mv_eh_freeze,
        .thaw                   = mv_eh_thaw,
        .hardreset              = mv_hardreset,
-       .error_handler          = ata_std_error_handler, /* avoid SFF EH */
-       .post_internal_cmd      = ATA_OP_NULL,
 
        .scr_read               = mv5_scr_read,
        .scr_write              = mv5_scr_write,
@@ -2813,7 +2811,7 @@ static void mv_port_intr(struct ata_port *ap, u32 port_cause)
        } else if (!edma_was_enabled) {
                struct ata_queued_cmd *qc = mv_get_active_qc(ap);
                if (qc)
-                       ata_sff_host_intr(ap, qc);
+                       ata_bmdma_port_intr(ap, qc);
                else
                        mv_unexpected_intr(ap, edma_was_enabled);
        }
index baa8f0d2c86fad6f06ba72d8d02b3b6fcc1958b9..6fd1147841162272c493339284e8a2ab0b376291 100644 (file)
@@ -920,7 +920,7 @@ static int nv_host_intr(struct ata_port *ap, u8 irq_stat)
        }
 
        /* handle interrupt */
-       return ata_sff_host_intr(ap, qc);
+       return ata_bmdma_port_intr(ap, qc);
 }
 
 static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
@@ -1100,7 +1100,7 @@ static void nv_adma_irq_clear(struct ata_port *ap)
        u32 notifier_clears[2];
 
        if (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) {
-               ata_sff_irq_clear(ap);
+               ata_bmdma_irq_clear(ap);
                return;
        }
 
@@ -1505,7 +1505,7 @@ static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance)
 
                qc = ata_qc_from_tag(ap, ap->link.active_tag);
                if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
-                       handled += ata_sff_host_intr(ap, qc);
+                       handled += ata_bmdma_port_intr(ap, qc);
                } else {
                        /*
                         * No request pending?  Clear interrupt status
@@ -2430,7 +2430,7 @@ static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        ppi[0] = &nv_port_info[type];
        ipriv = ppi[0]->private_data;
-       rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
+       rc = ata_pci_bmdma_prepare_host(pdev, ppi, &host);
        if (rc)
                return rc;
 
index d533b3d20ca152f9bbbf12f270e4d7101816acf6..daeebf19a6a90bf84a6b2e60a60d08105b21e917 100644 (file)
@@ -120,8 +120,6 @@ static void qs_host_stop(struct ata_host *host);
 static void qs_qc_prep(struct ata_queued_cmd *qc);
 static unsigned int qs_qc_issue(struct ata_queued_cmd *qc);
 static int qs_check_atapi_dma(struct ata_queued_cmd *qc);
-static void qs_bmdma_stop(struct ata_queued_cmd *qc);
-static u8 qs_bmdma_status(struct ata_port *ap);
 static void qs_freeze(struct ata_port *ap);
 static void qs_thaw(struct ata_port *ap);
 static int qs_prereset(struct ata_link *link, unsigned long deadline);
@@ -137,8 +135,6 @@ static struct ata_port_operations qs_ata_ops = {
        .inherits               = &ata_sff_port_ops,
 
        .check_atapi_dma        = qs_check_atapi_dma,
-       .bmdma_stop             = qs_bmdma_stop,
-       .bmdma_status           = qs_bmdma_status,
        .qc_prep                = qs_qc_prep,
        .qc_issue               = qs_qc_issue,
 
@@ -190,16 +186,6 @@ static int qs_check_atapi_dma(struct ata_queued_cmd *qc)
        return 1;       /* ATAPI DMA not supported */
 }
 
-static void qs_bmdma_stop(struct ata_queued_cmd *qc)
-{
-       /* nothing */
-}
-
-static u8 qs_bmdma_status(struct ata_port *ap)
-{
-       return 0;
-}
-
 static inline void qs_enter_reg_mode(struct ata_port *ap)
 {
        u8 __iomem *chan = qs_mmio_base(ap->host) + (ap->port_no * 0x4000);
@@ -454,7 +440,7 @@ static inline unsigned int qs_intr_mmio(struct ata_host *host)
                if (!pp || pp->state != qs_state_mmio)
                        continue;
                if (!(qc->tf.flags & ATA_TFLAG_POLLING))
-                       handled |= ata_sff_host_intr(ap, qc);
+                       handled |= ata_sff_port_intr(ap, qc);
        }
        return handled;
 }
index 2dda312b6b9aa87df52adb0142af746886977665..3a4f842197197a8d121fa7431c3c083dcf0f4afc 100644 (file)
@@ -503,7 +503,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
                goto err_hsm;
 
        /* ack bmdma irq events */
-       ata_sff_irq_clear(ap);
+       ata_bmdma_irq_clear(ap);
 
        /* kick HSM in the ass */
        ata_sff_hsm_move(ap, qc, status, 0);
@@ -584,7 +584,7 @@ static void sil_thaw(struct ata_port *ap)
 
        /* clear IRQ */
        ap->ops->sff_check_status(ap);
-       ata_sff_irq_clear(ap);
+       ata_bmdma_irq_clear(ap);
 
        /* turn on SATA IRQ if supported */
        if (!(ap->flags & SIL_FLAG_NO_SATA_IRQ))
index f8a91bfd66a883312cd95db013bc6c613b260559..2bfe3ae039769492eeec9896178436d1d316ac34 100644 (file)
@@ -279,7 +279,7 @@ static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                break;
        }
 
-       rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
+       rc = ata_pci_bmdma_prepare_host(pdev, ppi, &host);
        if (rc)
                return rc;
 
@@ -308,7 +308,7 @@ static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        pci_set_master(pdev);
        pci_intx(pdev, 1);
-       return ata_host_activate(host, pdev->irq, ata_sff_interrupt,
+       return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
                                 IRQF_SHARED, &sis_sht);
 }
 
index 101fd6a198290a619b908967a8e6a5d6035d5c70..7d9db4aaf07e659196b011d5fcdf89bb594d9f3a 100644 (file)
@@ -502,7 +502,7 @@ static int k2_sata_init_one(struct pci_dev *pdev, const struct pci_device_id *en
        writel(0x0, mmio_base + K2_SATA_SIM_OFFSET);
 
        pci_set_master(pdev);
-       return ata_host_activate(host, pdev->irq, ata_sff_interrupt,
+       return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
                                 IRQF_SHARED, &k2_sata_sht);
 }
 
index d8dac17dc2c8c13b06e631b2697eaba8c5f98677..b8578c32d3442e4e00f5d3d49b6039fb04d766c4 100644 (file)
@@ -242,7 +242,7 @@ static int uli_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        pci_set_master(pdev);
        pci_intx(pdev, 1);
-       return ata_host_activate(host, pdev->irq, ata_sff_interrupt,
+       return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
                                 IRQF_SHARED, &uli_sht);
 }
 
index 08f65492cc81181ec5cf76e603102662ebaa92f3..101d8c219cafede5f3eb3792cd31ab0d9d7fe9e3 100644 (file)
@@ -308,7 +308,7 @@ static void svia_noop_freeze(struct ata_port *ap)
         * certain way.  Leave it alone and just clear pending IRQ.
         */
        ap->ops->sff_check_status(ap);
-       ata_sff_irq_clear(ap);
+       ata_bmdma_irq_clear(ap);
 }
 
 /**
@@ -463,7 +463,7 @@ static int vt6420_prepare_host(struct pci_dev *pdev, struct ata_host **r_host)
        struct ata_host *host;
        int rc;
 
-       rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
+       rc = ata_pci_bmdma_prepare_host(pdev, ppi, &host);
        if (rc)
                return rc;
        *r_host = host;
@@ -520,7 +520,7 @@ static int vt8251_prepare_host(struct pci_dev *pdev, struct ata_host **r_host)
        struct ata_host *host;
        int i, rc;
 
-       rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
+       rc = ata_pci_bmdma_prepare_host(pdev, ppi, &host);
        if (rc)
                return rc;
        *r_host = host;
@@ -628,7 +628,7 @@ static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        svia_configure(pdev);
 
        pci_set_master(pdev);
-       return ata_host_activate(host, pdev->irq, ata_sff_interrupt,
+       return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
                                 IRQF_SHARED, &svia_sht);
 }
 
index 2107952ebff1e675f9f2e8895ded48e7170348b9..b777176ff4946039eab46a18492f5b1bf7022b0e 100644 (file)
@@ -245,7 +245,7 @@ static void vsc_port_intr(u8 port_status, struct ata_port *ap)
 
        qc = ata_qc_from_tag(ap, ap->link.active_tag);
        if (qc && likely(!(qc->tf.flags & ATA_TFLAG_POLLING)))
-               handled = ata_sff_host_intr(ap, qc);
+               handled = ata_bmdma_port_intr(ap, qc);
 
        /* We received an interrupt during a polled command,
         * or some other spurious condition.  Interrupt reporting
index f7d6ebaa0418fd2d877bda38d66d2d0a27188f83..da8f176c051e19e164b0fdc362b3ba77d3e89738 100644 (file)
@@ -789,7 +789,7 @@ static int __init fore200e_sba_map(struct fore200e *fore200e)
        fore200e->bus->write(0x02, fore200e->regs.sba.isr); /* XXX hardwired interrupt level */
 
        /* get the supported DVMA burst sizes */
-       bursts = of_getintprop_default(op->node->parent, "burst-sizes", 0x00);
+       bursts = of_getintprop_default(op->dev.of_node->parent, "burst-sizes", 0x00);
 
        if (sbus_can_dma_64bit())
                sbus_set_sbus64(&op->dev, bursts);
@@ -820,18 +820,20 @@ static int __init fore200e_sba_prom_read(struct fore200e *fore200e, struct prom_
        const u8 *prop;
        int len;
 
-       prop = of_get_property(op->node, "madaddrlo2", &len);
+       prop = of_get_property(op->dev.of_node, "madaddrlo2", &len);
        if (!prop)
                return -ENODEV;
        memcpy(&prom->mac_addr[4], prop, 4);
 
-       prop = of_get_property(op->node, "madaddrhi4", &len);
+       prop = of_get_property(op->dev.of_node, "madaddrhi4", &len);
        if (!prop)
                return -ENODEV;
        memcpy(&prom->mac_addr[2], prop, 4);
 
-       prom->serial_number = of_getintprop_default(op->node, "serialnumber", 0);
-       prom->hw_revision = of_getintprop_default(op->node, "promversion", 0);
+       prom->serial_number = of_getintprop_default(op->dev.of_node,
+                                                   "serialnumber", 0);
+       prom->hw_revision = of_getintprop_default(op->dev.of_node,
+                                                 "promversion", 0);
     
        return 0;
 }
@@ -841,10 +843,10 @@ static int fore200e_sba_proc_read(struct fore200e *fore200e, char *page)
        struct of_device *op = fore200e->bus_dev;
        const struct linux_prom_registers *regs;
 
-       regs = of_get_property(op->node, "reg", NULL);
+       regs = of_get_property(op->dev.of_node, "reg", NULL);
 
        return sprintf(page, "   SBUS slot/device:\t\t%d/'%s'\n",
-                      (regs ? regs->which_io : 0), op->node->name);
+                      (regs ? regs->which_io : 0), op->dev.of_node->name);
 }
 #endif /* CONFIG_SBUS */
 
@@ -2693,8 +2695,11 @@ static const struct of_device_id fore200e_sba_match[] = {
 MODULE_DEVICE_TABLE(of, fore200e_sba_match);
 
 static struct of_platform_driver fore200e_sba_driver = {
-       .name           = "fore_200e",
-       .match_table    = fore200e_sba_match,
+       .driver = {
+               .name = "fore_200e",
+               .owner = THIS_MODULE,
+               .of_match_table = fore200e_sba_match,
+       },
        .probe          = fore200e_sba_probe,
        .remove         = __devexit_p(fore200e_sba_remove),
 };
index 3fecfb446d90b0e09c257da5950aa4cde7581061..5ad3bad2b0a53ecf0aa57d656f7aaf5a01752152 100644 (file)
@@ -37,7 +37,7 @@
 
 #define CFAG12864BFB_NAME "cfag12864bfb"
 
-static struct fb_fix_screeninfo cfag12864bfb_fix __initdata = {
+static struct fb_fix_screeninfo cfag12864bfb_fix __devinitdata = {
        .id = "cfag12864b",
        .type = FB_TYPE_PACKED_PIXELS,
        .visual = FB_VISUAL_MONO10,
@@ -48,7 +48,7 @@ static struct fb_fix_screeninfo cfag12864bfb_fix __initdata = {
        .accel = FB_ACCEL_NONE,
 };
 
-static struct fb_var_screeninfo cfag12864bfb_var __initdata = {
+static struct fb_var_screeninfo cfag12864bfb_var __devinitdata = {
        .xres = CFAG12864B_WIDTH,
        .yres = CFAG12864B_HEIGHT,
        .xres_virtual = CFAG12864B_WIDTH,
@@ -114,7 +114,7 @@ none:
        return ret;
 }
 
-static int cfag12864bfb_remove(struct platform_device *device)
+static int __devexit cfag12864bfb_remove(struct platform_device *device)
 {
        struct fb_info *info = platform_get_drvdata(device);
 
@@ -128,7 +128,7 @@ static int cfag12864bfb_remove(struct platform_device *device)
 
 static struct platform_driver cfag12864bfb_driver = {
        .probe  = cfag12864bfb_probe,
-       .remove = cfag12864bfb_remove,
+       .remove = __devexit_p(cfag12864bfb_remove),
        .driver = {
                .name   = CFAG12864BFB_NAME,
        },
index 057979a19eea10283e5db959580a6f0208c8ab80..2bdd8a94ec944f8c98432ff3aed82529159378f1 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/memory.h>
 #include <linux/node.h>
 #include <linux/hugetlb.h>
+#include <linux/compaction.h>
 #include <linux/cpumask.h>
 #include <linux/topology.h>
 #include <linux/nodemask.h>
@@ -246,6 +247,8 @@ int register_node(struct node *node, int num, struct node *parent)
                scan_unevictable_register_node(node);
 
                hugetlb_register_node(node);
+
+               compaction_register_node(node);
        }
        return error;
 }
index bf6b13206d00cbb4dda735829b6df2f740b80fa9..9fc630ce1ddb4b46f93dd2c35a459849399efa8b 100644 (file)
@@ -162,7 +162,7 @@ static int __cpuinit topology_cpu_callback(struct notifier_block *nfb,
                topology_remove_dev(cpu);
                break;
        }
-       return rc ? NOTIFY_BAD : NOTIFY_OK;
+       return notifier_from_errno(rc);
 }
 
 static int __cpuinit topology_sysfs_init(void)
index a90e83c9be96bb0bb66e4415eb86de4308d88dd8..6120922f459f3708685cffa46a51e5517c89b18c 100644 (file)
@@ -485,7 +485,7 @@ static int do_bio_filebacked(struct loop_device *lo, struct bio *bio)
                                goto out;
                        }
 
-                       ret = vfs_fsync(file, file->f_path.dentry, 0);
+                       ret = vfs_fsync(file, 0);
                        if (unlikely(ret)) {
                                ret = -EIO;
                                goto out;
@@ -495,7 +495,7 @@ static int do_bio_filebacked(struct loop_device *lo, struct bio *bio)
                ret = lo_send(lo, bio, pos);
 
                if (barrier && !ret) {
-                       ret = vfs_fsync(file, file->f_path.dentry, 0);
+                       ret = vfs_fsync(file, 0);
                        if (unlikely(ret))
                                ret = -EIO;
                }
index 59ca2b77b574dd70956e6d818a63831c12fb6636..52f2d11bc7b975e55c49881f42e49f5552fc4371 100644 (file)
@@ -1004,7 +1004,7 @@ static const struct block_device_operations floppy_fops = {
 
 static int swim3_add_device(struct macio_dev *mdev, int index)
 {
-       struct device_node *swim = mdev->ofdev.node;
+       struct device_node *swim = mdev->ofdev.dev.of_node;
        struct floppy_state *fs = &floppy_states[index];
        int rc = -EBUSY;
 
index 2138a7ae050c10c44bdba1608f441a7811ca1a22..83fa09a836ca8574a3696c888d7574a833b35447 100644 (file)
@@ -50,7 +50,7 @@ static void blk_done(struct virtqueue *vq)
        unsigned long flags;
 
        spin_lock_irqsave(&vblk->lock, flags);
-       while ((vbr = vblk->vq->vq_ops->get_buf(vblk->vq, &len)) != NULL) {
+       while ((vbr = virtqueue_get_buf(vblk->vq, &len)) != NULL) {
                int error;
 
                switch (vbr->status) {
@@ -70,6 +70,8 @@ static void blk_done(struct virtqueue *vq)
                        vbr->req->sense_len = vbr->in_hdr.sense_len;
                        vbr->req->errors = vbr->in_hdr.errors;
                }
+               if (blk_special_request(vbr->req))
+                       vbr->req->errors = (error != 0);
 
                __blk_end_request_all(vbr->req, error);
                list_del(&vbr->list);
@@ -103,6 +105,11 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
                vbr->out_hdr.sector = 0;
                vbr->out_hdr.ioprio = req_get_ioprio(vbr->req);
                break;
+       case REQ_TYPE_SPECIAL:
+               vbr->out_hdr.type = VIRTIO_BLK_T_GET_ID;
+               vbr->out_hdr.sector = 0;
+               vbr->out_hdr.ioprio = req_get_ioprio(vbr->req);
+               break;
        case REQ_TYPE_LINUX_BLOCK:
                if (req->cmd[0] == REQ_LB_OP_FLUSH) {
                        vbr->out_hdr.type = VIRTIO_BLK_T_FLUSH;
@@ -151,7 +158,7 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
                }
        }
 
-       if (vblk->vq->vq_ops->add_buf(vblk->vq, vblk->sg, out, in, vbr) < 0) {
+       if (virtqueue_add_buf(vblk->vq, vblk->sg, out, in, vbr) < 0) {
                mempool_free(vbr, vblk->pool);
                return false;
        }
@@ -180,7 +187,7 @@ static void do_virtblk_request(struct request_queue *q)
        }
 
        if (issued)
-               vblk->vq->vq_ops->kick(vblk->vq);
+               virtqueue_kick(vblk->vq);
 }
 
 static void virtblk_prepare_flush(struct request_queue *q, struct request *req)
@@ -189,12 +196,45 @@ static void virtblk_prepare_flush(struct request_queue *q, struct request *req)
        req->cmd[0] = REQ_LB_OP_FLUSH;
 }
 
+/* return id (s/n) string for *disk to *id_str
+ */
+static int virtblk_get_id(struct gendisk *disk, char *id_str)
+{
+       struct virtio_blk *vblk = disk->private_data;
+       struct request *req;
+       struct bio *bio;
+
+       bio = bio_map_kern(vblk->disk->queue, id_str, VIRTIO_BLK_ID_BYTES,
+                          GFP_KERNEL);
+       if (IS_ERR(bio))
+               return PTR_ERR(bio);
+
+       req = blk_make_request(vblk->disk->queue, bio, GFP_KERNEL);
+       if (IS_ERR(req)) {
+               bio_put(bio);
+               return PTR_ERR(req);
+       }
+
+       req->cmd_type = REQ_TYPE_SPECIAL;
+       return blk_execute_rq(vblk->disk->queue, vblk->disk, req, false);
+}
+
 static int virtblk_ioctl(struct block_device *bdev, fmode_t mode,
                         unsigned cmd, unsigned long data)
 {
        struct gendisk *disk = bdev->bd_disk;
        struct virtio_blk *vblk = disk->private_data;
 
+       if (cmd == 0x56424944) { /* 'VBID' */
+               void __user *usr_data = (void __user *)data;
+               char id_str[VIRTIO_BLK_ID_BYTES];
+               int err;
+
+               err = virtblk_get_id(disk, id_str);
+               if (!err && copy_to_user(usr_data, id_str, VIRTIO_BLK_ID_BYTES))
+                       err = -EFAULT;
+               return err;
+       }
        /*
         * Only allow the generic SCSI ioctls if the host can support it.
         */
index e1c95e208a6656c50a8e44b04bab25fc4a65d7cf..a7b83c0a7eb5575ded978fd7a2e89025d829057d 100644 (file)
@@ -1198,10 +1198,10 @@ ace_of_probe(struct of_device *op, const struct of_device_id *match)
        dev_dbg(&op->dev, "ace_of_probe(%p, %p)\n", op, match);
 
        /* device id */
-       id = of_get_property(op->node, "port-number", NULL);
+       id = of_get_property(op->dev.of_node, "port-number", NULL);
 
        /* physaddr */
-       rc = of_address_to_resource(op->node, 0, &res);
+       rc = of_address_to_resource(op->dev.of_node, 0, &res);
        if (rc) {
                dev_err(&op->dev, "invalid address\n");
                return rc;
@@ -1209,11 +1209,11 @@ ace_of_probe(struct of_device *op, const struct of_device_id *match)
        physaddr = res.start;
 
        /* irq */
-       irq = irq_of_parse_and_map(op->node, 0);
+       irq = irq_of_parse_and_map(op->dev.of_node, 0);
 
        /* bus width */
        bus_width = ACE_BUS_WIDTH_16;
-       if (of_find_property(op->node, "8-bit", NULL))
+       if (of_find_property(op->dev.of_node, "8-bit", NULL))
                bus_width = ACE_BUS_WIDTH_8;
 
        /* Call the bus-independant setup code */
@@ -1237,13 +1237,12 @@ static const struct of_device_id ace_of_match[] __devinitconst = {
 MODULE_DEVICE_TABLE(of, ace_of_match);
 
 static struct of_platform_driver ace_of_driver = {
-       .owner = THIS_MODULE,
-       .name = "xsysace",
-       .match_table = ace_of_match,
        .probe = ace_of_probe,
        .remove = __devexit_p(ace_of_remove),
        .driver = {
                .name = "xsysace",
+               .owner = THIS_MODULE,
+               .of_match_table = ace_of_match,
        },
 };
 
index cc435be0bc136840153e91bbb0ef4cbae0bf54d9..451cd7071b1df4443aa22f4b09db39591c0cb314 100644 (file)
@@ -567,7 +567,7 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        struct disk_info *d;
        struct cdrom_device_info *c;
        struct request_queue *q;
-       struct device_node *node = vdev->dev.archdata.of_node;
+       struct device_node *node = vdev->dev.of_node;
 
        deviceno = vdev->unit_address;
        if (deviceno >= VIOCD_MAX_CD)
index e21175be25d0b1c88f2b0fe3ec717f014e17b7f6..f09fc0e2062dfdf9b0d2c4d816cd4fada77c4628 100644 (file)
@@ -1121,5 +1121,12 @@ config DEVPORT
 
 source "drivers/s390/char/Kconfig"
 
+config RAMOOPS
+       tristate "Log panic/oops to a RAM buffer"
+       default n
+       help
+         This enables panic and oops messages to be logged to a circular
+         buffer in RAM where it can be read back at some later point.
+
 endmenu
 
index d39be4cf1f5d3eacedfeae1ca74f27b28304fa71..88d6eac697547a5f19018180993de5c2fdfc1b54 100644 (file)
@@ -108,6 +108,7 @@ obj-$(CONFIG_HANGCHECK_TIMER)       += hangcheck-timer.o
 obj-$(CONFIG_TCG_TPM)          += tpm/
 
 obj-$(CONFIG_PS3_FLASH)                += ps3flash.o
+obj-$(CONFIG_RAMOOPS)          += ramoops.o
 
 obj-$(CONFIG_JS_RTC)           += js-rtc.o
 js-rtc-y = rtc.o
index 67ea3a60de74580fe7ba3f99ac579725b23a2f45..70312da4c968f9e4af7c39e9a5a649b4952f8bd3 100644 (file)
@@ -384,7 +384,7 @@ static int __devinit uli_agp_init(struct pci_dev *pdev)
 {
        u32 httfea,baseaddr,enuscr;
        struct pci_dev *dev1;
-       int i;
+       int i, ret;
        unsigned size = amd64_fetch_size();
 
        dev_info(&pdev->dev, "setting up ULi AGP\n");
@@ -400,15 +400,18 @@ static int __devinit uli_agp_init(struct pci_dev *pdev)
 
        if (i == ARRAY_SIZE(uli_sizes)) {
                dev_info(&pdev->dev, "no ULi size found for %d\n", size);
-               return -ENODEV;
+               ret = -ENODEV;
+               goto put;
        }
 
        /* shadow x86-64 registers into ULi registers */
        pci_read_config_dword (k8_northbridges[0], AMD64_GARTAPERTUREBASE, &httfea);
 
        /* if x86-64 aperture base is beyond 4G, exit here */
-       if ((httfea & 0x7fff) >> (32 - 25))
-               return -ENODEV;
+       if ((httfea & 0x7fff) >> (32 - 25)) {
+               ret = -ENODEV;
+               goto put;
+       }
 
        httfea = (httfea& 0x7fff) << 25;
 
@@ -420,9 +423,10 @@ static int __devinit uli_agp_init(struct pci_dev *pdev)
        enuscr= httfea+ (size * 1024 * 1024) - 1;
        pci_write_config_dword(dev1, ULI_X86_64_HTT_FEA_REG, httfea);
        pci_write_config_dword(dev1, ULI_X86_64_ENU_SCR_REG, enuscr);
-
+       ret = 0;
+put:
        pci_dev_put(dev1);
-       return 0;
+       return ret;
 }
 
 
@@ -441,7 +445,7 @@ static int nforce3_agp_init(struct pci_dev *pdev)
 {
        u32 tmp, apbase, apbar, aplimit;
        struct pci_dev *dev1;
-       int i;
+       int i, ret;
        unsigned size = amd64_fetch_size();
 
        dev_info(&pdev->dev, "setting up Nforce3 AGP\n");
@@ -458,7 +462,8 @@ static int nforce3_agp_init(struct pci_dev *pdev)
 
        if (i == ARRAY_SIZE(nforce3_sizes)) {
                dev_info(&pdev->dev, "no NForce3 size found for %d\n", size);
-               return -ENODEV;
+               ret = -ENODEV;
+               goto put;
        }
 
        pci_read_config_dword(dev1, NVIDIA_X86_64_1_APSIZE, &tmp);
@@ -472,7 +477,8 @@ static int nforce3_agp_init(struct pci_dev *pdev)
        /* if x86-64 aperture base is beyond 4G, exit here */
        if ( (apbase & 0x7fff) >> (32 - 25) ) {
                dev_info(&pdev->dev, "aperture base > 4G\n");
-               return -ENODEV;
+               ret = -ENODEV;
+               goto put;
        }
 
        apbase = (apbase & 0x7fff) << 25;
@@ -488,9 +494,11 @@ static int nforce3_agp_init(struct pci_dev *pdev)
        pci_write_config_dword(dev1, NVIDIA_X86_64_1_APBASE2, apbase);
        pci_write_config_dword(dev1, NVIDIA_X86_64_1_APLIMIT2, aplimit);
 
+       ret = 0;
+put:
        pci_dev_put(dev1);
 
-       return 0;
+       return ret;
 }
 
 static int __devinit agp_amd64_probe(struct pci_dev *pdev,
index 56b27671adc46b23c80ca24425241048d0cae7ea..4f8d60c25a980f1dc73d648c235dcaf81fa165ec 100644 (file)
@@ -84,6 +84,7 @@ static char *serial_version = "4.30";
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/bitops.h>
+#include <linux/platform_device.h>
 
 #include <asm/setup.h>
 
@@ -1954,29 +1955,16 @@ static const struct tty_operations serial_ops = {
 /*
  * The serial driver boot-time initialization code!
  */
-static int __init rs_init(void)
+static int __init amiga_serial_probe(struct platform_device *pdev)
 {
        unsigned long flags;
        struct serial_state * state;
        int error;
 
-       if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_SERIAL))
-               return -ENODEV;
-
        serial_driver = alloc_tty_driver(1);
        if (!serial_driver)
                return -ENOMEM;
 
-       /*
-        *  We request SERDAT and SERPER only, because the serial registers are
-        *  too spreaded over the custom register space
-        */
-       if (!request_mem_region(CUSTOM_PHYSADDR+0x30, 4,
-                               "amiserial [Paula]")) {
-               error = -EBUSY;
-               goto fail_put_tty_driver;
-       }
-
        IRQ_ports = NULL;
 
        show_serial_version();
@@ -1998,7 +1986,7 @@ static int __init rs_init(void)
 
        error = tty_register_driver(serial_driver);
        if (error)
-               goto fail_release_mem_region;
+               goto fail_put_tty_driver;
 
        state = rs_table;
        state->magic = SSTATE_MAGIC;
@@ -2050,23 +2038,24 @@ static int __init rs_init(void)
        ciab.ddra |= (SER_DTR | SER_RTS);   /* outputs */
        ciab.ddra &= ~(SER_DCD | SER_CTS | SER_DSR);  /* inputs */
 
+       platform_set_drvdata(pdev, state);
+
        return 0;
 
 fail_free_irq:
        free_irq(IRQ_AMIGA_TBE, state);
 fail_unregister:
        tty_unregister_driver(serial_driver);
-fail_release_mem_region:
-       release_mem_region(CUSTOM_PHYSADDR+0x30, 4);
 fail_put_tty_driver:
        put_tty_driver(serial_driver);
        return error;
 }
 
-static __exit void rs_exit(void) 
+static int __exit amiga_serial_remove(struct platform_device *pdev)
 {
        int error;
-       struct async_struct *info = rs_table[0].info;
+       struct serial_state *state = platform_get_drvdata(pdev);
+       struct async_struct *info = state->info;
 
        /* printk("Unloading %s: version %s\n", serial_name, serial_version); */
        tasklet_kill(&info->tlet);
@@ -2075,19 +2064,38 @@ static __exit void rs_exit(void)
                       error);
        put_tty_driver(serial_driver);
 
-       if (info) {
-         rs_table[0].info = NULL;
-         kfree(info);
-       }
+       rs_table[0].info = NULL;
+       kfree(info);
 
        free_irq(IRQ_AMIGA_TBE, rs_table);
        free_irq(IRQ_AMIGA_RBF, rs_table);
 
-       release_mem_region(CUSTOM_PHYSADDR+0x30, 4);
+       platform_set_drvdata(pdev, NULL);
+
+       return error;
+}
+
+static struct platform_driver amiga_serial_driver = {
+       .remove = __exit_p(amiga_serial_remove),
+       .driver   = {
+               .name   = "amiga-serial",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init amiga_serial_init(void)
+{
+       return platform_driver_probe(&amiga_serial_driver, amiga_serial_probe);
+}
+
+module_init(amiga_serial_init);
+
+static void __exit amiga_serial_exit(void)
+{
+       platform_driver_unregister(&amiga_serial_driver);
 }
 
-module_init(rs_init)
-module_exit(rs_exit)
+module_exit(amiga_serial_exit);
 
 
 #if defined(CONFIG_SERIAL_CONSOLE) && !defined(MODULE)
@@ -2154,3 +2162,4 @@ console_initcall(amiserial_console_init);
 #endif /* CONFIG_SERIAL_CONSOLE && !MODULE */
 
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:amiga-serial");
index 4f568cb9af3f90b62c52de1af32170ee4650d29d..033e1505fca9fe3ea2fee9b2b064578ad45637f4 100644 (file)
@@ -265,8 +265,8 @@ static unsigned int apm_poll(struct file *fp, poll_table * wait)
  *   Only when everyone who has opened /dev/apm_bios with write permission
  *   has acknowledge does the actual suspend happen.
  */
-static int
-apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg)
+static long
+apm_ioctl(struct file *filp, u_int cmd, u_long arg)
 {
        struct apm_user *as = filp->private_data;
        int err = -EINVAL;
@@ -274,6 +274,7 @@ apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg)
        if (!as->suser || !as->writer)
                return -EPERM;
 
+       lock_kernel();
        switch (cmd) {
        case APM_IOC_SUSPEND:
                mutex_lock(&state_lock);
@@ -334,6 +335,7 @@ apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg)
                mutex_unlock(&state_lock);
                break;
        }
+       unlock_kernel();
 
        return err;
 }
@@ -397,7 +399,7 @@ static const struct file_operations apm_bios_fops = {
        .owner          = THIS_MODULE,
        .read           = apm_read,
        .poll           = apm_poll,
-       .ioctl          = apm_ioctl,
+       .unlocked_ioctl = apm_ioctl,
        .open           = apm_open,
        .release        = apm_release,
 };
index a7424bf7eacf02bc029e300f7e6587ec55ad580d..f4ae0e0fb631b522f1b02a0a4ea68e2f98df0897 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
+#include <linux/smp_lock.h>
 #include <linux/miscdevice.h>
 #include <linux/pci.h>
 #include <linux/wait.h>
@@ -106,8 +107,7 @@ static unsigned int DeviceErrorCount;       /* number of device error     */
 
 static ssize_t ac_read (struct file *, char __user *, size_t, loff_t *);
 static ssize_t ac_write (struct file *, const char __user *, size_t, loff_t *);
-static int ac_ioctl(struct inode *, struct file *, unsigned int,
-                   unsigned long);
+static long ac_ioctl(struct file *, unsigned int, unsigned long);
 static irqreturn_t ac_interrupt(int, void *);
 
 static const struct file_operations ac_fops = {
@@ -115,7 +115,7 @@ static const struct file_operations ac_fops = {
        .llseek = no_llseek,
        .read = ac_read,
        .write = ac_write,
-       .ioctl = ac_ioctl,
+       .unlocked_ioctl = ac_ioctl,
 };
 
 static struct miscdevice ac_miscdev = {
@@ -689,7 +689,7 @@ static irqreturn_t ac_interrupt(int vec, void *dev_instance)
 
 
 
-static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static long ac_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
      
 {                              /* @ ADG ou ATO selon le cas */
        int i;
@@ -703,15 +703,11 @@ static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
        /* In general, the device is only openable by root anyway, so we're not
           particularly concerned that bogus ioctls can flood the console. */
 
-       adgl = kmalloc(sizeof(struct st_ram_io), GFP_KERNEL);
-       if (!adgl)
-               return -ENOMEM;
+       adgl = memdup_user(argp, sizeof(struct st_ram_io));
+       if (IS_ERR(adgl))
+               return PTR_ERR(adgl);
 
-       if (copy_from_user(adgl, argp, sizeof(struct st_ram_io))) {
-               kfree(adgl);
-               return -EFAULT;
-       }
-       
+       lock_kernel();  
        IndexCard = adgl->num_card-1;
         
        if(cmd != 6 && ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) {
@@ -721,6 +717,7 @@ static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
                        warncount--;
                }
                kfree(adgl);
+               unlock_kernel();
                return -EINVAL;
        }
 
@@ -838,6 +835,7 @@ static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
        }
        Dummy = readb(apbs[IndexCard].RamIO + VERS);
        kfree(adgl);
+       unlock_kernel();
        return 0;
 }
 
index 61f0146e215dd30ff3203b65e2ca75960928d39b..dbee8688f75ceafddfd80a5be5b7dcf8affd7140 100644 (file)
@@ -232,7 +232,7 @@ ds1620_read(struct file *file, char __user *buf, size_t count, loff_t *ptr)
 }
 
 static int
-ds1620_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+ds1620_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        struct therm therm;
        union {
@@ -316,6 +316,18 @@ ds1620_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned
        return 0;
 }
 
+static long
+ds1620_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       int ret;
+
+       lock_kernel();
+       ret = ds1620_ioctl(file, cmd, arg);
+       unlock_kernel();
+
+       return ret;
+}
+
 #ifdef THERM_USE_PROC
 static int
 proc_therm_ds1620_read(char *buf, char **start, off_t offset,
@@ -344,7 +356,7 @@ static const struct file_operations ds1620_fops = {
        .owner          = THIS_MODULE,
        .open           = ds1620_open,
        .read           = ds1620_read,
-       .ioctl          = ds1620_ioctl,
+       .unlocked_ioctl = ds1620_unlocked_ioctl,
 };
 
 static struct miscdevice ds1620_miscdev = {
index 045c930e6320c89e9ac2f28fadee74e1c3607790..e3859d4eaead6e67552cdc3d2f24412a8a31067b 100644 (file)
@@ -93,8 +93,8 @@ static ssize_t dtlk_write(struct file *, const char __user *,
 static unsigned int dtlk_poll(struct file *, poll_table *);
 static int dtlk_open(struct inode *, struct file *);
 static int dtlk_release(struct inode *, struct file *);
-static int dtlk_ioctl(struct inode *inode, struct file *file,
-                     unsigned int cmd, unsigned long arg);
+static long dtlk_ioctl(struct file *file,
+                      unsigned int cmd, unsigned long arg);
 
 static const struct file_operations dtlk_fops =
 {
@@ -102,7 +102,7 @@ static const struct file_operations dtlk_fops =
        .read           = dtlk_read,
        .write          = dtlk_write,
        .poll           = dtlk_poll,
-       .ioctl          = dtlk_ioctl,
+       .unlocked_ioctl = dtlk_ioctl,
        .open           = dtlk_open,
        .release        = dtlk_release,
 };
@@ -263,10 +263,9 @@ static void dtlk_timer_tick(unsigned long data)
        wake_up_interruptible(&dtlk_process_list);
 }
 
-static int dtlk_ioctl(struct inode *inode,
-                     struct file *file,
-                     unsigned int cmd,
-                     unsigned long arg)
+static long dtlk_ioctl(struct file *file,
+                      unsigned int cmd,
+                      unsigned long arg)
 {
        char __user *argp = (char __user *)arg;
        struct dtlk_settings *sp;
@@ -276,7 +275,9 @@ static int dtlk_ioctl(struct inode *inode,
        switch (cmd) {
 
        case DTLK_INTERROGATE:
+               lock_kernel();
                sp = dtlk_interrogate();
+               unlock_kernel();
                if (copy_to_user(argp, sp, sizeof(struct dtlk_settings)))
                        return -EINVAL;
                return 0;
index fda4181b5e67af6f84927ed8807cba101deb8544..82b5a88a82d77d5351d1b1d413c4b123a382544f 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/miscdevice.h>
 #include <linux/fcntl.h>
 #include <linux/init.h>
+#include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 #include <asm/nvram.h>
 #ifdef CONFIG_PPC_PMAC
@@ -84,8 +85,7 @@ static ssize_t write_nvram(struct file *file, const char __user *buf,
        return p - buf;
 }
 
-static int nvram_ioctl(struct inode *inode, struct file *file,
-       unsigned int cmd, unsigned long arg)
+static int nvram_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        switch(cmd) {
 #ifdef CONFIG_PPC_PMAC
@@ -116,12 +116,23 @@ static int nvram_ioctl(struct inode *inode, struct file *file,
        return 0;
 }
 
+static long nvram_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       int ret;
+
+       lock_kernel();
+       ret = nvram_ioctl(file, cmd, arg);
+       unlock_kernel();
+
+       return ret;
+}
+
 const struct file_operations nvram_fops = {
        .owner          = THIS_MODULE,
        .llseek         = nvram_llseek,
        .read           = read_nvram,
        .write          = write_nvram,
-       .ioctl          = nvram_ioctl,
+       .unlocked_ioctl = nvram_unlocked_ioctl,
 };
 
 static struct miscdevice nvram_dev = {
index 31e7c91c2d9d25679a63b2b792bfbbd534e6166a..b6c2cc167c11fd39ce485f72281c79fa4e98bdd7 100644 (file)
@@ -262,7 +262,7 @@ static inline int gen_set_rtc_irq_bit(unsigned char bit)
 #endif
 }
 
-static int gen_rtc_ioctl(struct inode *inode, struct file *file,
+static int gen_rtc_ioctl(struct file *file,
                         unsigned int cmd, unsigned long arg)
 {
        struct rtc_time wtime;
@@ -332,6 +332,18 @@ static int gen_rtc_ioctl(struct inode *inode, struct file *file,
        return -EINVAL;
 }
 
+static long gen_rtc_unlocked_ioctl(struct file *file, unsigned int cmd,
+                                  unsigned long arg)
+{
+       int ret;
+
+       lock_kernel();
+       ret = gen_rtc_ioctl(file, cmd, arg);
+       unlock_kernel();
+
+       return ret;
+}
+
 /*
  *     We enforce only one user at a time here with the open/close.
  *     Also clear the previous interrupt data on an open, and clean
@@ -482,7 +494,7 @@ static const struct file_operations gen_rtc_fops = {
        .read           = gen_rtc_read,
        .poll           = gen_rtc_poll,
 #endif
-       .ioctl          = gen_rtc_ioctl,
+       .unlocked_ioctl = gen_rtc_unlocked_ioctl,
        .open           = gen_rtc_open,
        .release        = gen_rtc_release,
 };
index 712d9f271aa6b8ed7026bca1594cc3b38052287f..e0249722d25f1c8b9dd05fa6705187afc8e23256 100644 (file)
@@ -49,8 +49,9 @@
 #include <asm/uaccess.h>
 #include <linux/sysrq.h>
 #include <linux/timer.h>
+#include <linux/time.h>
 
-#define VERSION_STR "0.9.0"
+#define VERSION_STR "0.9.1"
 
 #define DEFAULT_IOFENCE_MARGIN 60      /* Default fudge factor, in seconds */
 #define DEFAULT_IOFENCE_TICK 180       /* Default timer timeout, in seconds */
@@ -119,10 +120,8 @@ __setup("hcheck_dump_tasks", hangcheck_parse_dump_tasks);
 #if defined(CONFIG_S390)
 # define HAVE_MONOTONIC
 # define TIMER_FREQ 1000000000ULL
-#elif defined(CONFIG_IA64)
-# define TIMER_FREQ ((unsigned long long)local_cpu_data->itc_freq)
 #else
-# define TIMER_FREQ (HZ*loops_per_jiffy)
+# define TIMER_FREQ 1000000000ULL
 #endif
 
 #ifdef HAVE_MONOTONIC
@@ -130,7 +129,9 @@ extern unsigned long long monotonic_clock(void);
 #else
 static inline unsigned long long monotonic_clock(void)
 {
-       return get_cycles();
+       struct timespec ts;
+       getrawmonotonic(&ts);
+       return timespec_to_ns(&ts);
 }
 #endif  /* HAVE_MONOTONIC */
 
@@ -168,6 +169,13 @@ static void hangcheck_fire(unsigned long data)
                        printk(KERN_CRIT "Hangcheck: hangcheck value past margin!\n");
                }
        }
+#if 0
+       /*
+        * Enable to investigate delays in detail
+        */
+       printk("Hangcheck: called %Ld ns since last time (%Ld ns overshoot)\n",
+                       tsc_diff, tsc_diff - hangcheck_tick*TIMER_FREQ);
+#endif
        mod_timer(&hangcheck_ticktock, jiffies + (hangcheck_tick*HZ));
        hangcheck_tsc = monotonic_clock();
 }
@@ -180,7 +188,7 @@ static int __init hangcheck_init(void)
 #if defined (HAVE_MONOTONIC)
        printk("Hangcheck: Using monotonic_clock().\n");
 #else
-       printk("Hangcheck: Using get_cycles().\n");
+       printk("Hangcheck: Using getrawmonotonic().\n");
 #endif  /* HAVE_MONOTONIC */
        hangcheck_tsc_margin =
                (unsigned long long)(hangcheck_margin + hangcheck_tick);
index 9ded667625ac06c91d1940bf79ba261b65943b59..a0a1829d3198fc19ccab2748718dbee2f814db86 100644 (file)
@@ -431,14 +431,18 @@ static int hpet_release(struct inode *inode, struct file *file)
 
 static int hpet_ioctl_common(struct hpet_dev *, int, unsigned long, int);
 
-static int
-hpet_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-          unsigned long arg)
+static long hpet_ioctl(struct file *file, unsigned int cmd,
+                       unsigned long arg)
 {
        struct hpet_dev *devp;
+       int ret;
 
        devp = file->private_data;
-       return hpet_ioctl_common(devp, cmd, arg, 0);
+       lock_kernel();
+       ret = hpet_ioctl_common(devp, cmd, arg, 0);
+       unlock_kernel();
+
+       return ret;
 }
 
 static int hpet_ioctl_ieon(struct hpet_dev *devp)
@@ -654,7 +658,7 @@ static const struct file_operations hpet_fops = {
        .llseek = no_llseek,
        .read = hpet_read,
        .poll = hpet_poll,
-       .ioctl = hpet_ioctl,
+       .unlocked_ioctl = hpet_ioctl,
        .open = hpet_open,
        .release = hpet_release,
        .fasync = hpet_fasync,
index 793b236c92662999ee7aeaf1a4bf8bef253ecc44..d4b14ff1c4c1b1b8a707cebd84c8626f5bd08520 100644 (file)
@@ -194,10 +194,8 @@ static inline void print_state(struct hvsi_struct *hp)
                "HVSI_WAIT_FOR_MCTRL_RESPONSE",
                "HVSI_FSP_DIED",
        };
-       const char *name = state_names[hp->state];
-
-       if (hp->state > ARRAY_SIZE(state_names))
-               name = "UNKNOWN";
+       const char *name = (hp->state < ARRAY_SIZE(state_names))
+               ? state_names[hp->state] : "UNKNOWN";
 
        pr_debug("hvsi%i: state = %s\n", hp->index, name);
 #endif /* DEBUG */
index 10f868eefaa6f7c026bf0e06a6eb3c5b4e95aa63..0f9cbf1aaf15963bf1acda06f52de1d33836b990 100644 (file)
@@ -660,7 +660,7 @@ static int __devinit n2rng_probe(struct of_device *op,
                                np->hvapi_major);
                        goto out_hvapi_unregister;
                }
-               np->num_units = of_getintprop_default(op->node,
+               np->num_units = of_getintprop_default(op->dev.of_node,
                                                      "rng-#units", 0);
                if (!np->num_units) {
                        dev_err(&op->dev, "VF RNG lacks rng-#units property\n");
@@ -751,8 +751,11 @@ static const struct of_device_id n2rng_match[] = {
 MODULE_DEVICE_TABLE(of, n2rng_match);
 
 static struct of_platform_driver n2rng_driver = {
-       .name           = "n2rng",
-       .match_table    = n2rng_match,
+       .driver = {
+               .name = "n2rng",
+               .owner = THIS_MODULE,
+               .of_match_table = n2rng_match,
+       },
        .probe          = n2rng_probe,
        .remove         = __devexit_p(n2rng_remove),
 };
index a8b4c401014483e4fea73ff193f93e4d306049dd..a348c7e9aa0bbb44a360afb0f92806be6cc1560b 100644 (file)
 #include <linux/amba/bus.h>
 #include <linux/hw_random.h>
 #include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+static struct clk *rng_clk;
 
 static int nmk_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
 {
@@ -40,6 +44,15 @@ static int nmk_rng_probe(struct amba_device *dev, struct amba_id *id)
        void __iomem *base;
        int ret;
 
+       rng_clk = clk_get(&dev->dev, NULL);
+       if (IS_ERR(rng_clk)) {
+               dev_err(&dev->dev, "could not get rng clock\n");
+               ret = PTR_ERR(rng_clk);
+               return ret;
+       }
+
+       clk_enable(rng_clk);
+
        ret = amba_request_regions(dev, dev->dev.init_name);
        if (ret)
                return ret;
@@ -57,6 +70,8 @@ out_unmap:
        iounmap(base);
 out_release:
        amba_release_regions(dev);
+       clk_disable(rng_clk);
+       clk_put(rng_clk);
        return ret;
 }
 
@@ -66,6 +81,8 @@ static int nmk_rng_remove(struct amba_device *dev)
        hwrng_unregister(&nmk_rng);
        iounmap(base);
        amba_release_regions(dev);
+       clk_disable(rng_clk);
+       clk_put(rng_clk);
        return 0;
 }
 
index 7fa61dd1d9d9a986fb74dd8b384893adc2ec767a..261ba8f22b8ba57872d4b15f1f71b5da05b009bd 100644 (file)
@@ -98,7 +98,7 @@ static int __devinit rng_probe(struct of_device *ofdev,
                               const struct of_device_id *match)
 {
        void __iomem *rng_regs;
-       struct device_node *rng_np = ofdev->node;
+       struct device_node *rng_np = ofdev->dev.of_node;
        struct resource res;
        int err = 0;
 
@@ -140,8 +140,11 @@ static struct of_device_id rng_match[] = {
 };
 
 static struct of_platform_driver rng_driver = {
-       .name           = "pasemi-rng",
-       .match_table    = rng_match,
+       .driver = {
+               .name = "pasemi-rng",
+               .owner = THIS_MODULE,
+               .of_match_table = rng_match,
+       },
        .probe          = rng_probe,
        .remove         = rng_remove,
 };
index 64fe0a793efd4640ed7ad2905b15f202290850e5..75f1cbd61c174b36f1e637b59d203980e61c8cac 100644 (file)
@@ -32,7 +32,7 @@ static bool busy;
 static void random_recv_done(struct virtqueue *vq)
 {
        /* We can get spurious callbacks, e.g. shared IRQs + virtio_pci. */
-       if (!vq->vq_ops->get_buf(vq, &data_avail))
+       if (!virtqueue_get_buf(vq, &data_avail))
                return;
 
        complete(&have_data);
@@ -46,10 +46,10 @@ static void register_buffer(u8 *buf, size_t size)
        sg_init_one(&sg, buf, size);
 
        /* There should always be room for one buffer. */
-       if (vq->vq_ops->add_buf(vq, &sg, 0, 1, buf) < 0)
+       if (virtqueue_add_buf(vq, &sg, 0, 1, buf) < 0)
                BUG();
 
-       vq->vq_ops->kick(vq);
+       virtqueue_kick(vq);
 }
 
 static int virtio_read(struct hwrng *rng, void *buf, size_t size, bool wait)
index 65545de3dbf4ded375e55467fcaf5a8360000dfd..d8ec92a38980b451d70d454e04d20bf931d9f858 100644 (file)
@@ -228,8 +228,7 @@ static int handle_send_req(ipmi_user_t     user,
        return rv;
 }
 
-static int ipmi_ioctl(struct inode  *inode,
-                     struct file   *file,
+static int ipmi_ioctl(struct file   *file,
                      unsigned int  cmd,
                      unsigned long data)
 {
@@ -630,6 +629,23 @@ static int ipmi_ioctl(struct inode  *inode,
        return rv;
 }
 
+/*
+ * Note: it doesn't make sense to take the BKL here but
+ *       not in compat_ipmi_ioctl. -arnd
+ */
+static long ipmi_unlocked_ioctl(struct file   *file,
+                               unsigned int  cmd,
+                               unsigned long data)
+{
+       int ret;
+
+       lock_kernel();
+       ret = ipmi_ioctl(file, cmd, data);
+       unlock_kernel();
+
+       return ret;
+}
+
 #ifdef CONFIG_COMPAT
 
 /*
@@ -802,7 +818,7 @@ static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
                if (copy_to_user(precv64, &recv64, sizeof(recv64)))
                        return -EFAULT;
 
-               rc = ipmi_ioctl(filep->f_path.dentry->d_inode, filep,
+               rc = ipmi_ioctl(filep,
                                ((cmd == COMPAT_IPMICTL_RECEIVE_MSG)
                                 ? IPMICTL_RECEIVE_MSG
                                 : IPMICTL_RECEIVE_MSG_TRUNC),
@@ -819,14 +835,14 @@ static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
                return rc;
        }
        default:
-               return ipmi_ioctl(filep->f_path.dentry->d_inode, filep, cmd, arg);
+               return ipmi_ioctl(filep, cmd, arg);
        }
 }
 #endif
 
 static const struct file_operations ipmi_fops = {
        .owner          = THIS_MODULE,
-       .ioctl          = ipmi_ioctl,
+       .unlocked_ioctl = ipmi_unlocked_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = compat_ipmi_ioctl,
 #endif
index c6ad4234378d7e5cd0818d839e81c3b641e1d426..4f3f8c9ec2629d52de7c538b5bad895628a61299 100644 (file)
@@ -2505,12 +2505,11 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum,
                        return rv;
                }
 
-               printk(KERN_INFO
-                      "ipmi: Found new BMC (man_id: 0x%6.6x, "
-                      " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
-                      bmc->id.manufacturer_id,
-                      bmc->id.product_id,
-                      bmc->id.device_id);
+               dev_info(intf->si_dev, "Found new BMC (man_id: 0x%6.6x, "
+                        "prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
+                        bmc->id.manufacturer_id,
+                        bmc->id.product_id,
+                        bmc->id.device_id);
        }
 
        /*
@@ -4037,8 +4036,8 @@ static void ipmi_request_event(void)
 
 static struct timer_list ipmi_timer;
 
-/* Call every ~100 ms. */
-#define IPMI_TIMEOUT_TIME      100
+/* Call every ~1000 ms. */
+#define IPMI_TIMEOUT_TIME      1000
 
 /* How many jiffies does it take to get to the timeout time. */
 #define IPMI_TIMEOUT_JIFFIES   ((IPMI_TIMEOUT_TIME * HZ) / 1000)
index 4462b113ba3f1e134a1eb77b650af5e2732eb9af..35603dd4e6c5276911dec0b3a11464a152beb8a5 100644 (file)
@@ -107,6 +107,14 @@ enum si_type {
 };
 static char *si_to_str[] = { "kcs", "smic", "bt" };
 
+enum ipmi_addr_src {
+       SI_INVALID = 0, SI_HOTMOD, SI_HARDCODED, SI_SPMI, SI_ACPI, SI_SMBIOS,
+       SI_PCI, SI_DEVICETREE, SI_DEFAULT
+};
+static char *ipmi_addr_src_to_str[] = { NULL, "hotmod", "hardcoded", "SPMI",
+                                       "ACPI", "SMBIOS", "PCI",
+                                       "device-tree", "default" };
+
 #define DEVICE_NAME "ipmi_si"
 
 static struct platform_driver ipmi_driver = {
@@ -188,7 +196,7 @@ struct smi_info {
        int (*irq_setup)(struct smi_info *info);
        void (*irq_cleanup)(struct smi_info *info);
        unsigned int io_size;
-       char *addr_source; /* ACPI, PCI, SMBIOS, hardcode, default. */
+       enum ipmi_addr_src addr_source; /* ACPI, PCI, SMBIOS, hardcode, etc. */
        void (*addr_source_cleanup)(struct smi_info *info);
        void *addr_source_data;
 
@@ -300,6 +308,7 @@ static int num_max_busy_us;
 
 static int unload_when_empty = 1;
 
+static int add_smi(struct smi_info *smi);
 static int try_smi_init(struct smi_info *smi);
 static void cleanup_one_si(struct smi_info *to_clean);
 
@@ -314,9 +323,14 @@ static void deliver_recv_msg(struct smi_info *smi_info,
 {
        /* Deliver the message to the upper layer with the lock
           released. */
-       spin_unlock(&(smi_info->si_lock));
-       ipmi_smi_msg_received(smi_info->intf, msg);
-       spin_lock(&(smi_info->si_lock));
+
+       if (smi_info->run_to_completion) {
+               ipmi_smi_msg_received(smi_info->intf, msg);
+       } else {
+               spin_unlock(&(smi_info->si_lock));
+               ipmi_smi_msg_received(smi_info->intf, msg);
+               spin_lock(&(smi_info->si_lock));
+       }
 }
 
 static void return_hosed_msg(struct smi_info *smi_info, int cCode)
@@ -445,6 +459,9 @@ static inline void disable_si_irq(struct smi_info *smi_info)
        if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
                start_disable_irq(smi_info);
                smi_info->interrupt_disabled = 1;
+               if (!atomic_read(&smi_info->stop_operation))
+                       mod_timer(&smi_info->si_timer,
+                                 jiffies + SI_TIMEOUT_JIFFIES);
        }
 }
 
@@ -576,9 +593,8 @@ static void handle_transaction_done(struct smi_info *smi_info)
                smi_info->handlers->get_result(smi_info->si_sm, msg, 3);
                if (msg[2] != 0) {
                        /* Error clearing flags */
-                       printk(KERN_WARNING
-                              "ipmi_si: Error clearing flags: %2.2x\n",
-                              msg[2]);
+                       dev_warn(smi_info->dev,
+                                "Error clearing flags: %2.2x\n", msg[2]);
                }
                if (smi_info->si_state == SI_CLEARING_FLAGS_THEN_SET_IRQ)
                        start_enable_irq(smi_info);
@@ -670,9 +686,8 @@ static void handle_transaction_done(struct smi_info *smi_info)
                /* We got the flags from the SMI, now handle them. */
                smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
                if (msg[2] != 0) {
-                       printk(KERN_WARNING
-                              "ipmi_si: Could not enable interrupts"
-                              ", failed get, using polled mode.\n");
+                       dev_warn(smi_info->dev, "Could not enable interrupts"
+                                ", failed get, using polled mode.\n");
                        smi_info->si_state = SI_NORMAL;
                } else {
                        msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
@@ -693,11 +708,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
 
                /* We got the flags from the SMI, now handle them. */
                smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
-               if (msg[2] != 0) {
-                       printk(KERN_WARNING
-                              "ipmi_si: Could not enable interrupts"
-                              ", failed set, using polled mode.\n");
-               }
+               if (msg[2] != 0)
+                       dev_warn(smi_info->dev, "Could not enable interrupts"
+                                ", failed set, using polled mode.\n");
+               else
+                       smi_info->interrupt_disabled = 0;
                smi_info->si_state = SI_NORMAL;
                break;
        }
@@ -709,9 +724,8 @@ static void handle_transaction_done(struct smi_info *smi_info)
                /* We got the flags from the SMI, now handle them. */
                smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
                if (msg[2] != 0) {
-                       printk(KERN_WARNING
-                              "ipmi_si: Could not disable interrupts"
-                              ", failed get.\n");
+                       dev_warn(smi_info->dev, "Could not disable interrupts"
+                                ", failed get.\n");
                        smi_info->si_state = SI_NORMAL;
                } else {
                        msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
@@ -733,9 +747,8 @@ static void handle_transaction_done(struct smi_info *smi_info)
                /* We got the flags from the SMI, now handle them. */
                smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
                if (msg[2] != 0) {
-                       printk(KERN_WARNING
-                              "ipmi_si: Could not disable interrupts"
-                              ", failed set.\n");
+                       dev_warn(smi_info->dev, "Could not disable interrupts"
+                                ", failed set.\n");
                }
                smi_info->si_state = SI_NORMAL;
                break;
@@ -877,6 +890,11 @@ static void sender(void                *send_info,
        printk("**Enqueue: %d.%9.9d\n", t.tv_sec, t.tv_usec);
 #endif
 
+       mod_timer(&smi_info->si_timer, jiffies + SI_TIMEOUT_JIFFIES);
+
+       if (smi_info->thread)
+               wake_up_process(smi_info->thread);
+
        if (smi_info->run_to_completion) {
                /*
                 * If we are running to completion, then throw it in
@@ -997,6 +1015,8 @@ static int ipmi_thread(void *data)
                        ; /* do nothing */
                else if (smi_result == SI_SM_CALL_WITH_DELAY && busy_wait)
                        schedule();
+               else if (smi_result == SI_SM_IDLE)
+                       schedule_timeout_interruptible(100);
                else
                        schedule_timeout_interruptible(0);
        }
@@ -1039,6 +1059,7 @@ static void smi_timeout(unsigned long data)
        unsigned long     flags;
        unsigned long     jiffies_now;
        long              time_diff;
+       long              timeout;
 #ifdef DEBUG_TIMING
        struct timeval    t;
 #endif
@@ -1059,9 +1080,9 @@ static void smi_timeout(unsigned long data)
 
        if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
                /* Running with interrupts, only do long timeouts. */
-               smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES;
+               timeout = jiffies + SI_TIMEOUT_JIFFIES;
                smi_inc_stat(smi_info, long_timeouts);
-               goto do_add_timer;
+               goto do_mod_timer;
        }
 
        /*
@@ -1070,14 +1091,15 @@ static void smi_timeout(unsigned long data)
         */
        if (smi_result == SI_SM_CALL_WITH_DELAY) {
                smi_inc_stat(smi_info, short_timeouts);
-               smi_info->si_timer.expires = jiffies + 1;
+               timeout = jiffies + 1;
        } else {
                smi_inc_stat(smi_info, long_timeouts);
-               smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES;
+               timeout = jiffies + SI_TIMEOUT_JIFFIES;
        }
 
- do_add_timer:
-       add_timer(&(smi_info->si_timer));
+ do_mod_timer:
+       if (smi_result != SI_SM_IDLE)
+               mod_timer(&(smi_info->si_timer), timeout);
 }
 
 static irqreturn_t si_irq_handler(int irq, void *data)
@@ -1144,10 +1166,10 @@ static int smi_start_processing(void       *send_info,
                new_smi->thread = kthread_run(ipmi_thread, new_smi,
                                              "kipmi%d", new_smi->intf_num);
                if (IS_ERR(new_smi->thread)) {
-                       printk(KERN_NOTICE "ipmi_si_intf: Could not start"
-                              " kernel thread due to error %ld, only using"
-                              " timers to drive the interface\n",
-                              PTR_ERR(new_smi->thread));
+                       dev_notice(new_smi->dev, "Could not start"
+                                  " kernel thread due to error %ld, only using"
+                                  " timers to drive the interface\n",
+                                  PTR_ERR(new_smi->thread));
                        new_smi->thread = NULL;
                }
        }
@@ -1308,14 +1330,13 @@ static int std_irq_setup(struct smi_info *info)
                                 DEVICE_NAME,
                                 info);
        if (rv) {
-               printk(KERN_WARNING
-                      "ipmi_si: %s unable to claim interrupt %d,"
-                      " running polled\n",
-                      DEVICE_NAME, info->irq);
+               dev_warn(info->dev, "%s unable to claim interrupt %d,"
+                        " running polled\n",
+                        DEVICE_NAME, info->irq);
                info->irq = 0;
        } else {
                info->irq_cleanup = std_irq_cleanup;
-               printk("  Using irq %d\n", info->irq);
+               dev_info(info->dev, "Using irq %d\n", info->irq);
        }
 
        return rv;
@@ -1406,8 +1427,8 @@ static int port_setup(struct smi_info *info)
                info->io.outputb = port_outl;
                break;
        default:
-               printk(KERN_WARNING "ipmi_si: Invalid register size: %d\n",
-                      info->io.regsize);
+               dev_warn(info->dev, "Invalid register size: %d\n",
+                        info->io.regsize);
                return -EINVAL;
        }
 
@@ -1529,8 +1550,8 @@ static int mem_setup(struct smi_info *info)
                break;
 #endif
        default:
-               printk(KERN_WARNING "ipmi_si: Invalid register size: %d\n",
-                      info->io.regsize);
+               dev_warn(info->dev, "Invalid register size: %d\n",
+                        info->io.regsize);
                return -EINVAL;
        }
 
@@ -1755,7 +1776,7 @@ static int hotmod_handler(const char *val, struct kernel_param *kp)
                                goto out;
                        }
 
-                       info->addr_source = "hotmod";
+                       info->addr_source = SI_HOTMOD;
                        info->si_type = si_type;
                        info->io.addr_data = addr;
                        info->io.addr_type = addr_space;
@@ -1777,7 +1798,9 @@ static int hotmod_handler(const char *val, struct kernel_param *kp)
                                info->irq_setup = std_irq_setup;
                        info->slave_addr = ipmb;
 
-                       try_smi_init(info);
+                       if (!add_smi(info))
+                               if (try_smi_init(info))
+                                       cleanup_one_si(info);
                } else {
                        /* remove */
                        struct smi_info *e, *tmp_e;
@@ -1813,7 +1836,8 @@ static __devinit void hardcode_find_bmc(void)
                if (!info)
                        return;
 
-               info->addr_source = "hardcoded";
+               info->addr_source = SI_HARDCODED;
+               printk(KERN_INFO PFX "probing via hardcoded address\n");
 
                if (!si_type[i] || strcmp(si_type[i], "kcs") == 0) {
                        info->si_type = SI_KCS;
@@ -1822,8 +1846,7 @@ static __devinit void hardcode_find_bmc(void)
                } else if (strcmp(si_type[i], "bt") == 0) {
                        info->si_type = SI_BT;
                } else {
-                       printk(KERN_WARNING
-                              "ipmi_si: Interface type specified "
+                       printk(KERN_WARNING PFX "Interface type specified "
                               "for interface %d, was invalid: %s\n",
                               i, si_type[i]);
                        kfree(info);
@@ -1841,11 +1864,9 @@ static __devinit void hardcode_find_bmc(void)
                        info->io.addr_data = addrs[i];
                        info->io.addr_type = IPMI_MEM_ADDR_SPACE;
                } else {
-                       printk(KERN_WARNING
-                              "ipmi_si: Interface type specified "
-                              "for interface %d, "
-                              "but port and address were not set or "
-                              "set to zero.\n", i);
+                       printk(KERN_WARNING PFX "Interface type specified "
+                              "for interface %d, but port and address were "
+                              "not set or set to zero.\n", i);
                        kfree(info);
                        continue;
                }
@@ -1863,7 +1884,9 @@ static __devinit void hardcode_find_bmc(void)
                        info->irq_setup = std_irq_setup;
                info->slave_addr = slave_addrs[i];
 
-               try_smi_init(info);
+               if (!add_smi(info))
+                       if (try_smi_init(info))
+                               cleanup_one_si(info);
        }
 }
 
@@ -1923,15 +1946,13 @@ static int acpi_gpe_irq_setup(struct smi_info *info)
                                          &ipmi_acpi_gpe,
                                          info);
        if (status != AE_OK) {
-               printk(KERN_WARNING
-                      "ipmi_si: %s unable to claim ACPI GPE %d,"
-                      " running polled\n",
-                      DEVICE_NAME, info->irq);
+               dev_warn(info->dev, "%s unable to claim ACPI GPE %d,"
+                        " running polled\n", DEVICE_NAME, info->irq);
                info->irq = 0;
                return -EINVAL;
        } else {
                info->irq_cleanup = acpi_gpe_irq_cleanup;
-               printk("  Using ACPI GPE %d\n", info->irq);
+               dev_info(info->dev, "Using ACPI GPE %d\n", info->irq);
                return 0;
        }
 }
@@ -1989,8 +2010,8 @@ static __devinit int try_init_spmi(struct SPMITable *spmi)
        u8               addr_space;
 
        if (spmi->IPMIlegacy != 1) {
-           printk(KERN_INFO "IPMI: Bad SPMI legacy %d\n", spmi->IPMIlegacy);
-           return -ENODEV;
+               printk(KERN_INFO PFX "Bad SPMI legacy %d\n", spmi->IPMIlegacy);
+               return -ENODEV;
        }
 
        if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
@@ -2000,11 +2021,12 @@ static __devinit int try_init_spmi(struct SPMITable *spmi)
 
        info = kzalloc(sizeof(*info), GFP_KERNEL);
        if (!info) {
-               printk(KERN_ERR "ipmi_si: Could not allocate SI data (3)\n");
+               printk(KERN_ERR PFX "Could not allocate SI data (3)\n");
                return -ENOMEM;
        }
 
-       info->addr_source = "SPMI";
+       info->addr_source = SI_SPMI;
+       printk(KERN_INFO PFX "probing via SPMI\n");
 
        /* Figure out the interface type. */
        switch (spmi->InterfaceType) {
@@ -2018,8 +2040,8 @@ static __devinit int try_init_spmi(struct SPMITable *spmi)
                info->si_type = SI_BT;
                break;
        default:
-               printk(KERN_INFO "ipmi_si: Unknown ACPI/SPMI SI type %d\n",
-                       spmi->InterfaceType);
+               printk(KERN_INFO PFX "Unknown ACPI/SPMI SI type %d\n",
+                      spmi->InterfaceType);
                kfree(info);
                return -EIO;
        }
@@ -2055,13 +2077,12 @@ static __devinit int try_init_spmi(struct SPMITable *spmi)
                info->io.addr_type = IPMI_IO_ADDR_SPACE;
        } else {
                kfree(info);
-               printk(KERN_WARNING
-                      "ipmi_si: Unknown ACPI I/O Address type\n");
+               printk(KERN_WARNING PFX "Unknown ACPI I/O Address type\n");
                return -EIO;
        }
        info->io.addr_data = spmi->addr.address;
 
-       try_smi_init(info);
+       add_smi(info);
 
        return 0;
 }
@@ -2093,6 +2114,7 @@ static int __devinit ipmi_pnp_probe(struct pnp_dev *dev,
 {
        struct acpi_device *acpi_dev;
        struct smi_info *info;
+       struct resource *res;
        acpi_handle handle;
        acpi_status status;
        unsigned long long tmp;
@@ -2105,7 +2127,8 @@ static int __devinit ipmi_pnp_probe(struct pnp_dev *dev,
        if (!info)
                return -ENOMEM;
 
-       info->addr_source = "ACPI";
+       info->addr_source = SI_ACPI;
+       printk(KERN_INFO PFX "probing via ACPI\n");
 
        handle = acpi_dev->handle;
 
@@ -2125,22 +2148,26 @@ static int __devinit ipmi_pnp_probe(struct pnp_dev *dev,
                info->si_type = SI_BT;
                break;
        default:
-               dev_info(&dev->dev, "unknown interface type %lld\n", tmp);
+               dev_info(&dev->dev, "unknown IPMI type %lld\n", tmp);
                goto err_free;
        }
 
-       if (pnp_port_valid(dev, 0)) {
+       res = pnp_get_resource(dev, IORESOURCE_IO, 0);
+       if (res) {
                info->io_setup = port_setup;
                info->io.addr_type = IPMI_IO_ADDR_SPACE;
-               info->io.addr_data = pnp_port_start(dev, 0);
-       } else if (pnp_mem_valid(dev, 0)) {
-               info->io_setup = mem_setup;
-               info->io.addr_type = IPMI_MEM_ADDR_SPACE;
-               info->io.addr_data = pnp_mem_start(dev, 0);
        } else {
+               res = pnp_get_resource(dev, IORESOURCE_MEM, 0);
+               if (res) {
+                       info->io_setup = mem_setup;
+                       info->io.addr_type = IPMI_MEM_ADDR_SPACE;
+               }
+       }
+       if (!res) {
                dev_err(&dev->dev, "no I/O or memory address\n");
                goto err_free;
        }
+       info->io.addr_data = res->start;
 
        info->io.regspacing = DEFAULT_REGSPACING;
        info->io.regsize = DEFAULT_REGSPACING;
@@ -2156,10 +2183,14 @@ static int __devinit ipmi_pnp_probe(struct pnp_dev *dev,
                info->irq_setup = std_irq_setup;
        }
 
-       info->dev = &acpi_dev->dev;
+       info->dev = &dev->dev;
        pnp_set_drvdata(dev, info);
 
-       return try_smi_init(info);
+       dev_info(info->dev, "%pR regsize %d spacing %d irq %d\n",
+                res, info->io.regsize, info->io.regspacing,
+                info->irq);
+
+       return add_smi(info);
 
 err_free:
        kfree(info);
@@ -2264,12 +2295,12 @@ static __devinit void try_init_dmi(struct dmi_ipmi_data *ipmi_data)
 
        info = kzalloc(sizeof(*info), GFP_KERNEL);
        if (!info) {
-               printk(KERN_ERR
-                      "ipmi_si: Could not allocate SI data\n");
+               printk(KERN_ERR PFX "Could not allocate SI data\n");
                return;
        }
 
-       info->addr_source = "SMBIOS";
+       info->addr_source = SI_SMBIOS;
+       printk(KERN_INFO PFX "probing via SMBIOS\n");
 
        switch (ipmi_data->type) {
        case 0x01: /* KCS */
@@ -2299,8 +2330,7 @@ static __devinit void try_init_dmi(struct dmi_ipmi_data *ipmi_data)
 
        default:
                kfree(info);
-               printk(KERN_WARNING
-                      "ipmi_si: Unknown SMBIOS I/O Address type: %d.\n",
+               printk(KERN_WARNING PFX "Unknown SMBIOS I/O Address type: %d\n",
                       ipmi_data->addr_space);
                return;
        }
@@ -2318,7 +2348,7 @@ static __devinit void try_init_dmi(struct dmi_ipmi_data *ipmi_data)
        if (info->irq)
                info->irq_setup = std_irq_setup;
 
-       try_smi_init(info);
+       add_smi(info);
 }
 
 static void __devinit dmi_find_bmc(void)
@@ -2368,7 +2398,8 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev,
        if (!info)
                return -ENOMEM;
 
-       info->addr_source = "PCI";
+       info->addr_source = SI_PCI;
+       dev_info(&pdev->dev, "probing via PCI");
 
        switch (class_type) {
        case PCI_ERMC_CLASSCODE_TYPE_SMIC:
@@ -2385,15 +2416,13 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev,
 
        default:
                kfree(info);
-               printk(KERN_INFO "ipmi_si: %s: Unknown IPMI type: %d\n",
-                      pci_name(pdev), class_type);
+               dev_info(&pdev->dev, "Unknown IPMI type: %d\n", class_type);
                return -ENOMEM;
        }
 
        rv = pci_enable_device(pdev);
        if (rv) {
-               printk(KERN_ERR "ipmi_si: %s: couldn't enable PCI device\n",
-                      pci_name(pdev));
+               dev_err(&pdev->dev, "couldn't enable PCI device\n");
                kfree(info);
                return rv;
        }
@@ -2421,7 +2450,11 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev,
        info->dev = &pdev->dev;
        pci_set_drvdata(pdev, info);
 
-       return try_smi_init(info);
+       dev_info(&pdev->dev, "%pR regsize %d spacing %d irq %d\n",
+               &pdev->resource[0], info->io.regsize, info->io.regspacing,
+               info->irq);
+
+       return add_smi(info);
 }
 
 static void __devexit ipmi_pci_remove(struct pci_dev *pdev)
@@ -2469,11 +2502,11 @@ static int __devinit ipmi_of_probe(struct of_device *dev,
        struct smi_info *info;
        struct resource resource;
        const int *regsize, *regspacing, *regshift;
-       struct device_node *np = dev->node;
+       struct device_node *np = dev->dev.of_node;
        int ret;
        int proplen;
 
-       dev_info(&dev->dev, PFX "probing via device tree\n");
+       dev_info(&dev->dev, "probing via device tree\n");
 
        ret = of_address_to_resource(np, 0, &resource);
        if (ret) {
@@ -2503,12 +2536,12 @@ static int __devinit ipmi_of_probe(struct of_device *dev,
 
        if (!info) {
                dev_err(&dev->dev,
-                       PFX "could not allocate memory for OF probe\n");
+                       "could not allocate memory for OF probe\n");
                return -ENOMEM;
        }
 
        info->si_type           = (enum si_type) match->data;
-       info->addr_source       = "device-tree";
+       info->addr_source       = SI_DEVICETREE;
        info->irq_setup         = std_irq_setup;
 
        if (resource.flags & IORESOURCE_IO) {
@@ -2525,16 +2558,16 @@ static int __devinit ipmi_of_probe(struct of_device *dev,
        info->io.regspacing     = regspacing ? *regspacing : DEFAULT_REGSPACING;
        info->io.regshift       = regshift ? *regshift : 0;
 
-       info->irq               = irq_of_parse_and_map(dev->node, 0);
+       info->irq               = irq_of_parse_and_map(dev->dev.of_node, 0);
        info->dev               = &dev->dev;
 
-       dev_dbg(&dev->dev, "addr 0x%lx regsize %d spacing %d irq %x\n",
+       dev_dbg(&dev->dev, "addr 0x%lx regsize %d spacing %d irq %d\n",
                info->io.addr_data, info->io.regsize, info->io.regspacing,
                info->irq);
 
        dev_set_drvdata(&dev->dev, info);
 
-       return try_smi_init(info);
+       return add_smi(info);
 }
 
 static int __devexit ipmi_of_remove(struct of_device *dev)
@@ -2555,8 +2588,11 @@ static struct of_device_id ipmi_match[] =
 };
 
 static struct of_platform_driver ipmi_of_platform_driver = {
-       .name           = "ipmi",
-       .match_table    = ipmi_match,
+       .driver = {
+               .name = "ipmi",
+               .owner = THIS_MODULE,
+               .of_match_table = ipmi_match,
+       },
        .probe          = ipmi_of_probe,
        .remove         = __devexit_p(ipmi_of_remove),
 };
@@ -2640,9 +2676,8 @@ static int try_enable_event_buffer(struct smi_info *smi_info)
 
        rv = wait_for_msg_done(smi_info);
        if (rv) {
-               printk(KERN_WARNING
-                      "ipmi_si: Error getting response from get global,"
-                      " enables command, the event buffer is not"
+               printk(KERN_WARNING PFX "Error getting response from get"
+                      " global enables command, the event buffer is not"
                       " enabled.\n");
                goto out;
        }
@@ -2654,10 +2689,8 @@ static int try_enable_event_buffer(struct smi_info *smi_info)
                        resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 ||
                        resp[1] != IPMI_GET_BMC_GLOBAL_ENABLES_CMD   ||
                        resp[2] != 0) {
-               printk(KERN_WARNING
-                      "ipmi_si: Invalid return from get global"
-                      " enables command, cannot enable the event"
-                      " buffer.\n");
+               printk(KERN_WARNING PFX "Invalid return from get global"
+                      " enables command, cannot enable the event buffer.\n");
                rv = -EINVAL;
                goto out;
        }
@@ -2673,9 +2706,8 @@ static int try_enable_event_buffer(struct smi_info *smi_info)
 
        rv = wait_for_msg_done(smi_info);
        if (rv) {
-               printk(KERN_WARNING
-                      "ipmi_si: Error getting response from set global,"
-                      " enables command, the event buffer is not"
+               printk(KERN_WARNING PFX "Error getting response from set"
+                      " global, enables command, the event buffer is not"
                       " enabled.\n");
                goto out;
        }
@@ -2686,10 +2718,8 @@ static int try_enable_event_buffer(struct smi_info *smi_info)
        if (resp_len < 3 ||
                        resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 ||
                        resp[1] != IPMI_SET_BMC_GLOBAL_ENABLES_CMD) {
-               printk(KERN_WARNING
-                      "ipmi_si: Invalid return from get global,"
-                      "enables command, not enable the event"
-                      " buffer.\n");
+               printk(KERN_WARNING PFX "Invalid return from get global,"
+                      "enables command, not enable the event buffer.\n");
                rv = -EINVAL;
                goto out;
        }
@@ -2948,7 +2978,7 @@ static __devinit void default_find_bmc(void)
                if (!info)
                        return;
 
-               info->addr_source = NULL;
+               info->addr_source = SI_DEFAULT;
 
                info->si_type = ipmi_defaults[i].type;
                info->io_setup = port_setup;
@@ -2960,14 +2990,16 @@ static __devinit void default_find_bmc(void)
                info->io.regsize = DEFAULT_REGSPACING;
                info->io.regshift = 0;
 
-               if (try_smi_init(info) == 0) {
-                       /* Found one... */
-                       printk(KERN_INFO "ipmi_si: Found default %s state"
-                              " machine at %s address 0x%lx\n",
-                              si_to_str[info->si_type],
-                              addr_space_to_str[info->io.addr_type],
-                              info->io.addr_data);
-                       return;
+               if (add_smi(info) == 0) {
+                       if ((try_smi_init(info)) == 0) {
+                               /* Found one... */
+                               printk(KERN_INFO PFX "Found default %s"
+                               " state machine at %s address 0x%lx\n",
+                               si_to_str[info->si_type],
+                               addr_space_to_str[info->io.addr_type],
+                               info->io.addr_data);
+                       } else
+                               cleanup_one_si(info);
                }
        }
 }
@@ -2986,34 +3018,48 @@ static int is_new_interface(struct smi_info *info)
        return 1;
 }
 
-static int try_smi_init(struct smi_info *new_smi)
+static int add_smi(struct smi_info *new_smi)
 {
-       int rv;
-       int i;
-
-       if (new_smi->addr_source) {
-               printk(KERN_INFO "ipmi_si: Trying %s-specified %s state"
-                      " machine at %s address 0x%lx, slave address 0x%x,"
-                      " irq %d\n",
-                      new_smi->addr_source,
-                      si_to_str[new_smi->si_type],
-                      addr_space_to_str[new_smi->io.addr_type],
-                      new_smi->io.addr_data,
-                      new_smi->slave_addr, new_smi->irq);
-       }
+       int rv = 0;
 
+       printk(KERN_INFO PFX "Adding %s-specified %s state machine",
+                       ipmi_addr_src_to_str[new_smi->addr_source],
+                       si_to_str[new_smi->si_type]);
        mutex_lock(&smi_infos_lock);
        if (!is_new_interface(new_smi)) {
-               printk(KERN_WARNING "ipmi_si: duplicate interface\n");
+               printk(KERN_CONT PFX "duplicate interface\n");
                rv = -EBUSY;
                goto out_err;
        }
 
+       printk(KERN_CONT "\n");
+
        /* So we know not to free it unless we have allocated one. */
        new_smi->intf = NULL;
        new_smi->si_sm = NULL;
        new_smi->handlers = NULL;
 
+       list_add_tail(&new_smi->link, &smi_infos);
+
+out_err:
+       mutex_unlock(&smi_infos_lock);
+       return rv;
+}
+
+static int try_smi_init(struct smi_info *new_smi)
+{
+       int rv = 0;
+       int i;
+
+       printk(KERN_INFO PFX "Trying %s-specified %s state"
+              " machine at %s address 0x%lx, slave address 0x%x,"
+              " irq %d\n",
+              ipmi_addr_src_to_str[new_smi->addr_source],
+              si_to_str[new_smi->si_type],
+              addr_space_to_str[new_smi->io.addr_type],
+              new_smi->io.addr_data,
+              new_smi->slave_addr, new_smi->irq);
+
        switch (new_smi->si_type) {
        case SI_KCS:
                new_smi->handlers = &kcs_smi_handlers;
@@ -3036,7 +3082,8 @@ static int try_smi_init(struct smi_info *new_smi)
        /* Allocate the state machine's data and initialize it. */
        new_smi->si_sm = kmalloc(new_smi->handlers->size(), GFP_KERNEL);
        if (!new_smi->si_sm) {
-               printk(KERN_ERR "Could not allocate state machine memory\n");
+               printk(KERN_ERR PFX
+                      "Could not allocate state machine memory\n");
                rv = -ENOMEM;
                goto out_err;
        }
@@ -3046,7 +3093,7 @@ static int try_smi_init(struct smi_info *new_smi)
        /* Now that we know the I/O size, we can set up the I/O. */
        rv = new_smi->io_setup(new_smi);
        if (rv) {
-               printk(KERN_ERR "Could not set up I/O space\n");
+               printk(KERN_ERR PFX "Could not set up I/O space\n");
                goto out_err;
        }
 
@@ -3056,8 +3103,7 @@ static int try_smi_init(struct smi_info *new_smi)
        /* Do low-level detection first. */
        if (new_smi->handlers->detect(new_smi->si_sm)) {
                if (new_smi->addr_source)
-                       printk(KERN_INFO "ipmi_si: Interface detection"
-                              " failed\n");
+                       printk(KERN_INFO PFX "Interface detection failed\n");
                rv = -ENODEV;
                goto out_err;
        }
@@ -3069,7 +3115,7 @@ static int try_smi_init(struct smi_info *new_smi)
        rv = try_get_dev_id(new_smi);
        if (rv) {
                if (new_smi->addr_source)
-                       printk(KERN_INFO "ipmi_si: There appears to be no BMC"
+                       printk(KERN_INFO PFX "There appears to be no BMC"
                               " at this location\n");
                goto out_err;
        }
@@ -3085,7 +3131,7 @@ static int try_smi_init(struct smi_info *new_smi)
        for (i = 0; i < SI_NUM_STATS; i++)
                atomic_set(&new_smi->stats[i], 0);
 
-       new_smi->interrupt_disabled = 0;
+       new_smi->interrupt_disabled = 1;
        atomic_set(&new_smi->stop_operation, 0);
        new_smi->intf_num = smi_num;
        smi_num++;
@@ -3111,9 +3157,8 @@ static int try_smi_init(struct smi_info *new_smi)
                new_smi->pdev = platform_device_alloc("ipmi_si",
                                                      new_smi->intf_num);
                if (!new_smi->pdev) {
-                       printk(KERN_ERR
-                              "ipmi_si_intf:"
-                              " Unable to allocate platform device\n");
+                       printk(KERN_ERR PFX
+                              "Unable to allocate platform device\n");
                        goto out_err;
                }
                new_smi->dev = &new_smi->pdev->dev;
@@ -3121,9 +3166,8 @@ static int try_smi_init(struct smi_info *new_smi)
 
                rv = platform_device_add(new_smi->pdev);
                if (rv) {
-                       printk(KERN_ERR
-                              "ipmi_si_intf:"
-                              " Unable to register system interface device:"
+                       printk(KERN_ERR PFX
+                              "Unable to register system interface device:"
                               " %d\n",
                               rv);
                        goto out_err;
@@ -3138,9 +3182,8 @@ static int try_smi_init(struct smi_info *new_smi)
                               "bmc",
                               new_smi->slave_addr);
        if (rv) {
-               printk(KERN_ERR
-                      "ipmi_si: Unable to register device: error %d\n",
-                      rv);
+               dev_err(new_smi->dev, "Unable to register device: error %d\n",
+                       rv);
                goto out_err_stop_timer;
        }
 
@@ -3148,9 +3191,7 @@ static int try_smi_init(struct smi_info *new_smi)
                                     type_file_read_proc,
                                     new_smi);
        if (rv) {
-               printk(KERN_ERR
-                      "ipmi_si: Unable to create proc entry: %d\n",
-                      rv);
+               dev_err(new_smi->dev, "Unable to create proc entry: %d\n", rv);
                goto out_err_stop_timer;
        }
 
@@ -3158,9 +3199,7 @@ static int try_smi_init(struct smi_info *new_smi)
                                     stat_file_read_proc,
                                     new_smi);
        if (rv) {
-               printk(KERN_ERR
-                      "ipmi_si: Unable to create proc entry: %d\n",
-                      rv);
+               dev_err(new_smi->dev, "Unable to create proc entry: %d\n", rv);
                goto out_err_stop_timer;
        }
 
@@ -3168,18 +3207,12 @@ static int try_smi_init(struct smi_info *new_smi)
                                     param_read_proc,
                                     new_smi);
        if (rv) {
-               printk(KERN_ERR
-                      "ipmi_si: Unable to create proc entry: %d\n",
-                      rv);
+               dev_err(new_smi->dev, "Unable to create proc entry: %d\n", rv);
                goto out_err_stop_timer;
        }
 
-       list_add_tail(&new_smi->link, &smi_infos);
-
-       mutex_unlock(&smi_infos_lock);
-
-       printk(KERN_INFO "IPMI %s interface initialized\n",
-              si_to_str[new_smi->si_type]);
+       dev_info(new_smi->dev, "IPMI %s interface initialized\n",
+                si_to_str[new_smi->si_type]);
 
        return 0;
 
@@ -3188,11 +3221,17 @@ static int try_smi_init(struct smi_info *new_smi)
        wait_for_timer_and_thread(new_smi);
 
  out_err:
-       if (new_smi->intf)
+       new_smi->interrupt_disabled = 1;
+
+       if (new_smi->intf) {
                ipmi_unregister_smi(new_smi->intf);
+               new_smi->intf = NULL;
+       }
 
-       if (new_smi->irq_cleanup)
+       if (new_smi->irq_cleanup) {
                new_smi->irq_cleanup(new_smi);
+               new_smi->irq_cleanup = NULL;
+       }
 
        /*
         * Wait until we know that we are out of any interrupt
@@ -3205,18 +3244,21 @@ static int try_smi_init(struct smi_info *new_smi)
                if (new_smi->handlers)
                        new_smi->handlers->cleanup(new_smi->si_sm);
                kfree(new_smi->si_sm);
+               new_smi->si_sm = NULL;
        }
-       if (new_smi->addr_source_cleanup)
+       if (new_smi->addr_source_cleanup) {
                new_smi->addr_source_cleanup(new_smi);
-       if (new_smi->io_cleanup)
+               new_smi->addr_source_cleanup = NULL;
+       }
+       if (new_smi->io_cleanup) {
                new_smi->io_cleanup(new_smi);
+               new_smi->io_cleanup = NULL;
+       }
 
-       if (new_smi->dev_registered)
+       if (new_smi->dev_registered) {
                platform_device_unregister(new_smi->pdev);
-
-       kfree(new_smi);
-
-       mutex_unlock(&smi_infos_lock);
+               new_smi->dev_registered = 0;
+       }
 
        return rv;
 }
@@ -3226,6 +3268,8 @@ static __devinit int init_ipmi_si(void)
        int  i;
        char *str;
        int  rv;
+       struct smi_info *e;
+       enum ipmi_addr_src type = SI_INVALID;
 
        if (initialized)
                return 0;
@@ -3234,9 +3278,7 @@ static __devinit int init_ipmi_si(void)
        /* Register the device drivers. */
        rv = driver_register(&ipmi_driver.driver);
        if (rv) {
-               printk(KERN_ERR
-                      "init_ipmi_si: Unable to register driver: %d\n",
-                      rv);
+               printk(KERN_ERR PFX "Unable to register driver: %d\n", rv);
                return rv;
        }
 
@@ -3260,38 +3302,81 @@ static __devinit int init_ipmi_si(void)
 
        hardcode_find_bmc();
 
-#ifdef CONFIG_DMI
-       dmi_find_bmc();
-#endif
+       /* If the user gave us a device, they presumably want us to use it */
+       mutex_lock(&smi_infos_lock);
+       if (!list_empty(&smi_infos)) {
+               mutex_unlock(&smi_infos_lock);
+               return 0;
+       }
+       mutex_unlock(&smi_infos_lock);
 
-#ifdef CONFIG_ACPI
-       spmi_find_bmc();
+#ifdef CONFIG_PCI
+       rv = pci_register_driver(&ipmi_pci_driver);
+       if (rv)
+               printk(KERN_ERR PFX "Unable to register PCI driver: %d\n", rv);
 #endif
+
 #ifdef CONFIG_ACPI
        pnp_register_driver(&ipmi_pnp_driver);
 #endif
 
-#ifdef CONFIG_PCI
-       rv = pci_register_driver(&ipmi_pci_driver);
-       if (rv)
-               printk(KERN_ERR
-                      "init_ipmi_si: Unable to register PCI driver: %d\n",
-                      rv);
+#ifdef CONFIG_DMI
+       dmi_find_bmc();
+#endif
+
+#ifdef CONFIG_ACPI
+       spmi_find_bmc();
 #endif
 
 #ifdef CONFIG_PPC_OF
        of_register_platform_driver(&ipmi_of_platform_driver);
 #endif
 
+       /* We prefer devices with interrupts, but in the case of a machine
+          with multiple BMCs we assume that there will be several instances
+          of a given type so if we succeed in registering a type then also
+          try to register everything else of the same type */
+
+       mutex_lock(&smi_infos_lock);
+       list_for_each_entry(e, &smi_infos, link) {
+               /* Try to register a device if it has an IRQ and we either
+                  haven't successfully registered a device yet or this
+                  device has the same type as one we successfully registered */
+               if (e->irq && (!type || e->addr_source == type)) {
+                       if (!try_smi_init(e)) {
+                               type = e->addr_source;
+                       }
+               }
+       }
+
+       /* type will only have been set if we successfully registered an si */
+       if (type) {
+               mutex_unlock(&smi_infos_lock);
+               return 0;
+       }
+
+       /* Fall back to the preferred device */
+
+       list_for_each_entry(e, &smi_infos, link) {
+               if (!e->irq && (!type || e->addr_source == type)) {
+                       if (!try_smi_init(e)) {
+                               type = e->addr_source;
+                       }
+               }
+       }
+       mutex_unlock(&smi_infos_lock);
+
+       if (type)
+               return 0;
+
        if (si_trydefaults) {
                mutex_lock(&smi_infos_lock);
                if (list_empty(&smi_infos)) {
                        /* No BMC was found, try defaults. */
                        mutex_unlock(&smi_infos_lock);
                        default_find_bmc();
-               } else {
+               } else
                        mutex_unlock(&smi_infos_lock);
-               }
        }
 
        mutex_lock(&smi_infos_lock);
@@ -3305,8 +3390,8 @@ static __devinit int init_ipmi_si(void)
                of_unregister_platform_driver(&ipmi_of_platform_driver);
 #endif
                driver_unregister(&ipmi_driver.driver);
-               printk(KERN_WARNING
-                      "ipmi_si: Unable to find any System Interface(s)\n");
+               printk(KERN_WARNING PFX
+                      "Unable to find any System Interface(s)\n");
                return -ENODEV;
        } else {
                mutex_unlock(&smi_infos_lock);
@@ -3317,7 +3402,7 @@ module_init(init_ipmi_si);
 
 static void cleanup_one_si(struct smi_info *to_clean)
 {
-       int           rv;
+       int           rv = 0;
        unsigned long flags;
 
        if (!to_clean)
@@ -3361,14 +3446,16 @@ static void cleanup_one_si(struct smi_info *to_clean)
                schedule_timeout_uninterruptible(1);
        }
 
-       rv = ipmi_unregister_smi(to_clean->intf);
+       if (to_clean->intf)
+               rv = ipmi_unregister_smi(to_clean->intf);
+
        if (rv) {
-               printk(KERN_ERR
-                      "ipmi_si: Unable to unregister device: errno=%d\n",
+               printk(KERN_ERR PFX "Unable to unregister device: errno=%d\n",
                       rv);
        }
 
-       to_clean->handlers->cleanup(to_clean->si_sm);
+       if (to_clean->handlers)
+               to_clean->handlers->cleanup(to_clean->si_sm);
 
        kfree(to_clean->si_sm);
 
index a4d57e31f713bc0c9d11f54b610ab33365e6b692..82bcdb262a3a56268237006eb7327bbfae771430 100644 (file)
@@ -659,7 +659,7 @@ static struct watchdog_info ident = {
        .identity       = "IPMI"
 };
 
-static int ipmi_ioctl(struct inode *inode, struct file *file,
+static int ipmi_ioctl(struct file *file,
                      unsigned int cmd, unsigned long arg)
 {
        void __user *argp = (void __user *)arg;
@@ -730,6 +730,19 @@ static int ipmi_ioctl(struct inode *inode, struct file *file,
        }
 }
 
+static long ipmi_unlocked_ioctl(struct file *file,
+                               unsigned int cmd,
+                               unsigned long arg)
+{
+       int ret;
+
+       lock_kernel();
+       ret = ipmi_ioctl(file, cmd, arg);
+       unlock_kernel();
+
+       return ret;
+}
+
 static ssize_t ipmi_write(struct file *file,
                          const char  __user *buf,
                          size_t      len,
@@ -880,7 +893,7 @@ static const struct file_operations ipmi_wdog_fops = {
        .read    = ipmi_read,
        .poll    = ipmi_poll,
        .write   = ipmi_write,
-       .ioctl   = ipmi_ioctl,
+       .unlocked_ioctl = ipmi_unlocked_ioctl,
        .open    = ipmi_open,
        .release = ipmi_close,
        .fasync  = ipmi_fasync,
index 92ab03d282945bfe804ee3b48d3d6f428e4d55b8..cd650ca8c679c102f135cb2a6d0d1bfb387e5bf7 100644 (file)
@@ -144,6 +144,7 @@ static int misc_open(struct inode * inode, struct file * file)
        old_fops = file->f_op;
        file->f_op = new_fops;
        if (file->f_op->open) {
+               file->private_data = c;
                err=file->f_op->open(inode,file);
                if (err) {
                        fops_put(file->f_op);
index 47e8f7b0e4c18d1893e3caba579581e7ee755762..66d2917b003f6361080e063323d88dca49fd623f 100644 (file)
@@ -296,8 +296,8 @@ checksum_err:
        return -EIO;
 }
 
-static int nvram_ioctl(struct inode *inode, struct file *file,
-                                       unsigned int cmd, unsigned long arg)
+static long nvram_ioctl(struct file *file, unsigned int cmd,
+                       unsigned long arg)
 {
        int i;
 
@@ -308,6 +308,7 @@ static int nvram_ioctl(struct inode *inode, struct file *file,
                if (!capable(CAP_SYS_ADMIN))
                        return -EACCES;
 
+               lock_kernel();
                spin_lock_irq(&rtc_lock);
 
                for (i = 0; i < NVRAM_BYTES; ++i)
@@ -315,6 +316,7 @@ static int nvram_ioctl(struct inode *inode, struct file *file,
                __nvram_set_checksum();
 
                spin_unlock_irq(&rtc_lock);
+               unlock_kernel();
                return 0;
 
        case NVRAM_SETCKS:
@@ -323,9 +325,11 @@ static int nvram_ioctl(struct inode *inode, struct file *file,
                if (!capable(CAP_SYS_ADMIN))
                        return -EACCES;
 
+               lock_kernel();
                spin_lock_irq(&rtc_lock);
                __nvram_set_checksum();
                spin_unlock_irq(&rtc_lock);
+               unlock_kernel();
                return 0;
 
        default:
@@ -422,7 +426,7 @@ static const struct file_operations nvram_fops = {
        .llseek         = nvram_llseek,
        .read           = nvram_read,
        .write          = nvram_write,
-       .ioctl          = nvram_ioctl,
+       .unlocked_ioctl = nvram_ioctl,
        .open           = nvram_open,
        .release        = nvram_release,
 };
index f80810901db66ba21d2243a713bfa274d5d5f3ef..043a1c7b86beefb3438976f3512230b9571278c3 100644 (file)
@@ -94,8 +94,9 @@ static int get_flash_id(void)
        return c2;
 }
 
-static int flash_ioctl(struct inode *inodep, struct file *filep, unsigned int cmd, unsigned long arg)
+static long flash_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
 {
+       lock_kernel();
        switch (cmd) {
        case CMD_WRITE_DISABLE:
                gbWriteBase64Enable = 0;
@@ -113,8 +114,10 @@ static int flash_ioctl(struct inode *inodep, struct file *filep, unsigned int cm
        default:
                gbWriteBase64Enable = 0;
                gbWriteEnable = 0;
+               unlock_kernel();
                return -EINVAL;
        }
+       unlock_kernel();
        return 0;
 }
 
@@ -631,7 +634,7 @@ static const struct file_operations flash_fops =
        .llseek         = flash_llseek,
        .read           = flash_read,
        .write          = flash_write,
-       .ioctl          = flash_ioctl,
+       .unlocked_ioctl = flash_ioctl,
 };
 
 static struct miscdevice flash_miscdev =
index fdd37543aa79e6d0b159767f791024d4c31e83fb..02abfddce45a192ceccae3d71f3008ba7d329767 100644 (file)
@@ -287,12 +287,10 @@ static int register_device (int minor, struct pp_struct *pp)
        char *name;
        int fl;
 
-       name = kmalloc (strlen (CHRDEV) + 3, GFP_KERNEL);
+       name = kasprintf(GFP_KERNEL, CHRDEV "%x", minor);
        if (name == NULL)
                return -ENOMEM;
 
-       sprintf (name, CHRDEV "%x", minor);
-
        port = parport_find_number (minor);
        if (!port) {
                printk (KERN_WARNING "%s: no associated port!\n", name);
index 606048b72bcf2e0adbebf8590a92e4f1b55fd5b5..85c004a518ee1d9196aebb28a75e5464fce6354b 100644 (file)
@@ -305,8 +305,7 @@ static int ps3flash_flush(struct file *file, fl_owner_t id)
        return ps3flash_writeback(ps3flash_dev);
 }
 
-static int ps3flash_fsync(struct file *file, struct dentry *dentry,
-                         int datasync)
+static int ps3flash_fsync(struct file *file, int datasync)
 {
        return ps3flash_writeback(ps3flash_dev);
 }
diff --git a/drivers/char/ramoops.c b/drivers/char/ramoops.c
new file mode 100644 (file)
index 0000000..74f00b5
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * RAM Oops/Panic logger
+ *
+ * Copyright (C) 2010 Marco Stornelli <marco.stornelli@gmail.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
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/kmsg_dump.h>
+#include <linux/time.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+
+#define RAMOOPS_KERNMSG_HDR "===="
+#define RAMOOPS_HEADER_SIZE   (5 + sizeof(struct timeval))
+
+#define RECORD_SIZE 4096
+
+static ulong mem_address;
+module_param(mem_address, ulong, 0400);
+MODULE_PARM_DESC(mem_address,
+               "start of reserved RAM used to store oops/panic logs");
+
+static ulong mem_size;
+module_param(mem_size, ulong, 0400);
+MODULE_PARM_DESC(mem_size,
+               "size of reserved RAM used to store oops/panic logs");
+
+static int dump_oops = 1;
+module_param(dump_oops, int, 0600);
+MODULE_PARM_DESC(dump_oops,
+               "set to 1 to dump oopses, 0 to only dump panics (default 1)");
+
+static struct ramoops_context {
+       struct kmsg_dumper dump;
+       void *virt_addr;
+       phys_addr_t phys_addr;
+       unsigned long size;
+       int count;
+       int max_count;
+} oops_cxt;
+
+static void ramoops_do_dump(struct kmsg_dumper *dumper,
+               enum kmsg_dump_reason reason, const char *s1, unsigned long l1,
+               const char *s2, unsigned long l2)
+{
+       struct ramoops_context *cxt = container_of(dumper,
+                       struct ramoops_context, dump);
+       unsigned long s1_start, s2_start;
+       unsigned long l1_cpy, l2_cpy;
+       int res;
+       char *buf;
+       struct timeval timestamp;
+
+       /* Only dump oopses if dump_oops is set */
+       if (reason == KMSG_DUMP_OOPS && !dump_oops)
+               return;
+
+       buf = (char *)(cxt->virt_addr + (cxt->count * RECORD_SIZE));
+       memset(buf, '\0', RECORD_SIZE);
+       res = sprintf(buf, "%s", RAMOOPS_KERNMSG_HDR);
+       buf += res;
+       do_gettimeofday(&timestamp);
+       res = sprintf(buf, "%lu.%lu\n", (long)timestamp.tv_sec, (long)timestamp.tv_usec);
+       buf += res;
+
+       l2_cpy = min(l2, (unsigned long)(RECORD_SIZE - RAMOOPS_HEADER_SIZE));
+       l1_cpy = min(l1, (unsigned long)(RECORD_SIZE - RAMOOPS_HEADER_SIZE) - l2_cpy);
+
+       s2_start = l2 - l2_cpy;
+       s1_start = l1 - l1_cpy;
+
+       memcpy(buf, s1 + s1_start, l1_cpy);
+       memcpy(buf + l1_cpy, s2 + s2_start, l2_cpy);
+
+       cxt->count = (cxt->count + 1) % cxt->max_count;
+}
+
+static int __init ramoops_init(void)
+{
+       struct ramoops_context *cxt = &oops_cxt;
+       int err = -EINVAL;
+
+       if (!mem_size) {
+               printk(KERN_ERR "ramoops: invalid size specification");
+               goto fail3;
+       }
+
+       rounddown_pow_of_two(mem_size);
+
+       if (mem_size < RECORD_SIZE) {
+               printk(KERN_ERR "ramoops: size too small");
+               goto fail3;
+       }
+
+       cxt->max_count = mem_size / RECORD_SIZE;
+       cxt->count = 0;
+       cxt->size = mem_size;
+       cxt->phys_addr = mem_address;
+
+       if (!request_mem_region(cxt->phys_addr, cxt->size, "ramoops")) {
+               printk(KERN_ERR "ramoops: request mem region failed");
+               err = -EINVAL;
+               goto fail3;
+       }
+
+       cxt->virt_addr = ioremap(cxt->phys_addr,  cxt->size);
+       if (!cxt->virt_addr) {
+               printk(KERN_ERR "ramoops: ioremap failed");
+               goto fail2;
+       }
+
+       cxt->dump.dump = ramoops_do_dump;
+       err = kmsg_dump_register(&cxt->dump);
+       if (err) {
+               printk(KERN_ERR "ramoops: registering kmsg dumper failed");
+               goto fail1;
+       }
+
+       return 0;
+
+fail1:
+       iounmap(cxt->virt_addr);
+fail2:
+       release_mem_region(cxt->phys_addr, cxt->size);
+fail3:
+       return err;
+}
+
+static void __exit ramoops_exit(void)
+{
+       struct ramoops_context *cxt = &oops_cxt;
+
+       if (kmsg_dump_unregister(&cxt->dump) < 0)
+               printk(KERN_WARNING "ramoops: could not unregister kmsg_dumper");
+
+       iounmap(cxt->virt_addr);
+       release_mem_region(cxt->phys_addr, cxt->size);
+}
+
+
+module_init(ramoops_init);
+module_exit(ramoops_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marco Stornelli <marco.stornelli@gmail.com>");
+MODULE_DESCRIPTION("RAM Oops/Panic logger/driver");
index 8756ab0daa8b3123bb4937dc128920fa0471e130..b38942f6bf3140684be8ffadfcbac7381201baa5 100644 (file)
@@ -121,13 +121,17 @@ static int raw_release(struct inode *inode, struct file *filp)
 /*
  * Forward ioctls to the underlying block device.
  */
-static int
-raw_ioctl(struct inode *inode, struct file *filp,
-                 unsigned int command, unsigned long arg)
+static long
+raw_ioctl(struct file *filp, unsigned int command, unsigned long arg)
 {
        struct block_device *bdev = filp->private_data;
+       int ret;
+
+       lock_kernel();
+       ret = blkdev_ioctl(bdev, 0, command, arg);
+       unlock_kernel();
 
-       return blkdev_ioctl(bdev, 0, command, arg);
+       return ret;
 }
 
 static void bind_device(struct raw_config_request *rq)
@@ -141,13 +145,14 @@ static void bind_device(struct raw_config_request *rq)
  * Deal with ioctls against the raw-device control interface, to bind
  * and unbind other raw devices.
  */
-static int raw_ctl_ioctl(struct inode *inode, struct file *filp,
-                       unsigned int command, unsigned long arg)
+static long raw_ctl_ioctl(struct file *filp, unsigned int command,
+                         unsigned long arg)
 {
        struct raw_config_request rq;
        struct raw_device_data *rawdev;
        int err = 0;
 
+       lock_kernel();
        switch (command) {
        case RAW_SETBIND:
        case RAW_GETBIND:
@@ -240,25 +245,26 @@ static int raw_ctl_ioctl(struct inode *inode, struct file *filp,
                break;
        }
 out:
+       unlock_kernel();
        return err;
 }
 
 static const struct file_operations raw_fops = {
-       .read   =       do_sync_read,
-       .aio_read =     generic_file_aio_read,
-       .write  =       do_sync_write,
-       .aio_write =    blkdev_aio_write,
-       .fsync  =       blkdev_fsync,
-       .open   =       raw_open,
-       .release=       raw_release,
-       .ioctl  =       raw_ioctl,
-       .owner  =       THIS_MODULE,
+       .read           = do_sync_read,
+       .aio_read       = generic_file_aio_read,
+       .write          = do_sync_write,
+       .aio_write      = blkdev_aio_write,
+       .fsync          = blkdev_fsync,
+       .open           = raw_open,
+       .release        = raw_release,
+       .unlocked_ioctl = raw_ioctl,
+       .owner          = THIS_MODULE,
 };
 
 static const struct file_operations raw_ctl_fops = {
-       .ioctl  =       raw_ctl_ioctl,
-       .open   =       raw_open,
-       .owner  =       THIS_MODULE,
+       .unlocked_ioctl = raw_ctl_ioctl,
+       .open           = raw_open,
+       .owner          = THIS_MODULE,
 };
 
 static struct cdev raw_cdev;
index 1144a04cda6e99e91f18b057be2f92f2630edda0..42f7fa442ff80653c3cbabf9c80bd1b2e05de28d 100644 (file)
@@ -866,7 +866,7 @@ static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id)
 {
        int i = vdev->unit_address;
        int j;
-       struct device_node *node = vdev->dev.archdata.of_node;
+       struct device_node *node = vdev->dev.of_node;
 
        if (i >= VIOTAPE_MAX_TAPE)
                return -ENODEV;
index 196428c2287a453b6259beff3cefd591199e6071..8c99bf1b5e9fde218dab95f2091b807a7fbb4623 100644 (file)
 #include <linux/workqueue.h>
 #include "hvc_console.h"
 
-/* Moved here from .h file in order to disable MULTIPORT. */
-#define VIRTIO_CONSOLE_F_MULTIPORT 1   /* Does host provide multiple ports? */
-
-struct virtio_console_multiport_conf {
-       struct virtio_console_config config;
-       /* max. number of ports this device can hold */
-       __u32 max_nr_ports;
-       /* number of ports added so far */
-       __u32 nr_ports;
-} __attribute__((packed));
-
-/*
- * A message that's passed between the Host and the Guest for a
- * particular port.
- */
-struct virtio_console_control {
-       __u32 id;               /* Port number */
-       __u16 event;            /* The kind of control event (see below) */
-       __u16 value;            /* Extra information for the key */
-};
-
-/* Some events for control messages */
-#define VIRTIO_CONSOLE_PORT_READY      0
-#define VIRTIO_CONSOLE_CONSOLE_PORT    1
-#define VIRTIO_CONSOLE_RESIZE          2
-#define VIRTIO_CONSOLE_PORT_OPEN       3
-#define VIRTIO_CONSOLE_PORT_NAME       4
-#define VIRTIO_CONSOLE_PORT_REMOVE     5
-
 /*
  * This is a global struct for storing common data for all the devices
  * this driver handles.
@@ -107,6 +78,9 @@ struct console {
        /* The hvc device associated with this console port */
        struct hvc_struct *hvc;
 
+       /* The size of the console */
+       struct winsize ws;
+
        /*
         * This number identifies the number that we used to register
         * with hvc in hvc_instantiate() and hvc_alloc(); this is the
@@ -139,7 +113,6 @@ struct ports_device {
         * notification
         */
        struct work_struct control_work;
-       struct work_struct config_work;
 
        struct list_head ports;
 
@@ -150,7 +123,7 @@ struct ports_device {
        spinlock_t cvq_lock;
 
        /* The current config space is stored here */
-       struct virtio_console_multiport_conf config;
+       struct virtio_console_config config;
 
        /* The virtio device we're associated with */
        struct virtio_device *vdev;
@@ -189,6 +162,9 @@ struct port {
         */
        spinlock_t inbuf_lock;
 
+       /* Protect the operations on the out_vq. */
+       spinlock_t outvq_lock;
+
        /* The IO vqs for this port */
        struct virtqueue *in_vq, *out_vq;
 
@@ -214,6 +190,8 @@ struct port {
        /* The 'id' to identify the port with the Host */
        u32 id;
 
+       bool outvq_full;
+
        /* Is the host device open */
        bool host_connected;
 
@@ -328,7 +306,7 @@ static void *get_inbuf(struct port *port)
        unsigned int len;
 
        vq = port->in_vq;
-       buf = vq->vq_ops->get_buf(vq, &len);
+       buf = virtqueue_get_buf(vq, &len);
        if (buf) {
                buf->len = len;
                buf->offset = 0;
@@ -349,8 +327,8 @@ static int add_inbuf(struct virtqueue *vq, struct port_buffer *buf)
 
        sg_init_one(sg, buf->buf, buf->size);
 
-       ret = vq->vq_ops->add_buf(vq, sg, 0, 1, buf);
-       vq->vq_ops->kick(vq);
+       ret = virtqueue_add_buf(vq, sg, 0, 1, buf);
+       virtqueue_kick(vq);
        return ret;
 }
 
@@ -366,7 +344,7 @@ static void discard_port_data(struct port *port)
        if (port->inbuf)
                buf = port->inbuf;
        else
-               buf = vq->vq_ops->get_buf(vq, &len);
+               buf = virtqueue_get_buf(vq, &len);
 
        ret = 0;
        while (buf) {
@@ -374,7 +352,7 @@ static void discard_port_data(struct port *port)
                        ret++;
                        free_buf(buf);
                }
-               buf = vq->vq_ops->get_buf(vq, &len);
+               buf = virtqueue_get_buf(vq, &len);
        }
        port->inbuf = NULL;
        if (ret)
@@ -403,57 +381,96 @@ out:
        return ret;
 }
 
-static ssize_t send_control_msg(struct port *port, unsigned int event,
-                               unsigned int value)
+static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id,
+                                 unsigned int event, unsigned int value)
 {
        struct scatterlist sg[1];
        struct virtio_console_control cpkt;
        struct virtqueue *vq;
        unsigned int len;
 
-       if (!use_multiport(port->portdev))
+       if (!use_multiport(portdev))
                return 0;
 
-       cpkt.id = port->id;
+       cpkt.id = port_id;
        cpkt.event = event;
        cpkt.value = value;
 
-       vq = port->portdev->c_ovq;
+       vq = portdev->c_ovq;
 
        sg_init_one(sg, &cpkt, sizeof(cpkt));
-       if (vq->vq_ops->add_buf(vq, sg, 1, 0, &cpkt) >= 0) {
-               vq->vq_ops->kick(vq);
-               while (!vq->vq_ops->get_buf(vq, &len))
+       if (virtqueue_add_buf(vq, sg, 1, 0, &cpkt) >= 0) {
+               virtqueue_kick(vq);
+               while (!virtqueue_get_buf(vq, &len))
                        cpu_relax();
        }
        return 0;
 }
 
-static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count)
+static ssize_t send_control_msg(struct port *port, unsigned int event,
+                               unsigned int value)
+{
+       return __send_control_msg(port->portdev, port->id, event, value);
+}
+
+/* Callers must take the port->outvq_lock */
+static void reclaim_consumed_buffers(struct port *port)
+{
+       void *buf;
+       unsigned int len;
+
+       while ((buf = virtqueue_get_buf(port->out_vq, &len))) {
+               kfree(buf);
+               port->outvq_full = false;
+       }
+}
+
+static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count,
+                       bool nonblock)
 {
        struct scatterlist sg[1];
        struct virtqueue *out_vq;
        ssize_t ret;
+       unsigned long flags;
        unsigned int len;
 
        out_vq = port->out_vq;
 
+       spin_lock_irqsave(&port->outvq_lock, flags);
+
+       reclaim_consumed_buffers(port);
+
        sg_init_one(sg, in_buf, in_count);
-       ret = out_vq->vq_ops->add_buf(out_vq, sg, 1, 0, in_buf);
+       ret = virtqueue_add_buf(out_vq, sg, 1, 0, in_buf);
 
        /* Tell Host to go! */
-       out_vq->vq_ops->kick(out_vq);
+       virtqueue_kick(out_vq);
 
        if (ret < 0) {
                in_count = 0;
-               goto fail;
+               goto done;
        }
 
-       /* Wait till the host acknowledges it pushed out the data we sent. */
-       while (!out_vq->vq_ops->get_buf(out_vq, &len))
+       if (ret == 0)
+               port->outvq_full = true;
+
+       if (nonblock)
+               goto done;
+
+       /*
+        * Wait till the host acknowledges it pushed out the data we
+        * sent.  This is done for ports in blocking mode or for data
+        * from the hvc_console; the tty operations are performed with
+        * spinlocks held so we can't sleep here.
+        */
+       while (!virtqueue_get_buf(out_vq, &len))
                cpu_relax();
-fail:
-       /* We're expected to return the amount of data we wrote */
+done:
+       spin_unlock_irqrestore(&port->outvq_lock, flags);
+       /*
+        * We're expected to return the amount of data we wrote -- all
+        * of it
+        */
        return in_count;
 }
 
@@ -503,9 +520,28 @@ static ssize_t fill_readbuf(struct port *port, char *out_buf, size_t out_count,
 }
 
 /* The condition that must be true for polling to end */
-static bool wait_is_over(struct port *port)
+static bool will_read_block(struct port *port)
+{
+       return !port_has_data(port) && port->host_connected;
+}
+
+static bool will_write_block(struct port *port)
 {
-       return port_has_data(port) || !port->host_connected;
+       bool ret;
+
+       if (!port->host_connected)
+               return true;
+
+       spin_lock_irq(&port->outvq_lock);
+       /*
+        * Check if the Host has consumed any buffers since we last
+        * sent data (this is only applicable for nonblocking ports).
+        */
+       reclaim_consumed_buffers(port);
+       ret = port->outvq_full;
+       spin_unlock_irq(&port->outvq_lock);
+
+       return ret;
 }
 
 static ssize_t port_fops_read(struct file *filp, char __user *ubuf,
@@ -528,7 +564,7 @@ static ssize_t port_fops_read(struct file *filp, char __user *ubuf,
                        return -EAGAIN;
 
                ret = wait_event_interruptible(port->waitqueue,
-                                              wait_is_over(port));
+                                              !will_read_block(port));
                if (ret < 0)
                        return ret;
        }
@@ -554,9 +590,22 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
        struct port *port;
        char *buf;
        ssize_t ret;
+       bool nonblock;
 
        port = filp->private_data;
 
+       nonblock = filp->f_flags & O_NONBLOCK;
+
+       if (will_write_block(port)) {
+               if (nonblock)
+                       return -EAGAIN;
+
+               ret = wait_event_interruptible(port->waitqueue,
+                                              !will_write_block(port));
+               if (ret < 0)
+                       return ret;
+       }
+
        count = min((size_t)(32 * 1024), count);
 
        buf = kmalloc(count, GFP_KERNEL);
@@ -569,9 +618,14 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
                goto free_buf;
        }
 
-       ret = send_buf(port, buf, count);
+       ret = send_buf(port, buf, count, nonblock);
+
+       if (nonblock && ret > 0)
+               goto out;
+
 free_buf:
        kfree(buf);
+out:
        return ret;
 }
 
@@ -586,7 +640,7 @@ static unsigned int port_fops_poll(struct file *filp, poll_table *wait)
        ret = 0;
        if (port->inbuf)
                ret |= POLLIN | POLLRDNORM;
-       if (port->host_connected)
+       if (!will_write_block(port))
                ret |= POLLOUT;
        if (!port->host_connected)
                ret |= POLLHUP;
@@ -610,6 +664,10 @@ static int port_fops_release(struct inode *inode, struct file *filp)
 
        spin_unlock_irq(&port->inbuf_lock);
 
+       spin_lock_irq(&port->outvq_lock);
+       reclaim_consumed_buffers(port);
+       spin_unlock_irq(&port->outvq_lock);
+
        return 0;
 }
 
@@ -638,6 +696,15 @@ static int port_fops_open(struct inode *inode, struct file *filp)
        port->guest_connected = true;
        spin_unlock_irq(&port->inbuf_lock);
 
+       spin_lock_irq(&port->outvq_lock);
+       /*
+        * There might be a chance that we missed reclaiming a few
+        * buffers in the window of the port getting previously closed
+        * and opening now.
+        */
+       reclaim_consumed_buffers(port);
+       spin_unlock_irq(&port->outvq_lock);
+
        /* Notify host of port being opened */
        send_control_msg(filp->private_data, VIRTIO_CONSOLE_PORT_OPEN, 1);
 
@@ -676,9 +743,9 @@ static int put_chars(u32 vtermno, const char *buf, int count)
 
        port = find_port_by_vtermno(vtermno);
        if (!port)
-               return 0;
+               return -EPIPE;
 
-       return send_buf(port, (void *)buf, count);
+       return send_buf(port, (void *)buf, count, false);
 }
 
 /*
@@ -692,9 +759,13 @@ static int get_chars(u32 vtermno, char *buf, int count)
 {
        struct port *port;
 
+       /* If we've not set up the port yet, we have no input to give. */
+       if (unlikely(early_put_chars))
+               return 0;
+
        port = find_port_by_vtermno(vtermno);
        if (!port)
-               return 0;
+               return -EPIPE;
 
        /* If we don't have an input queue yet, we can't get input. */
        BUG_ON(!port->in_vq);
@@ -705,22 +776,14 @@ static int get_chars(u32 vtermno, char *buf, int count)
 static void resize_console(struct port *port)
 {
        struct virtio_device *vdev;
-       struct winsize ws;
 
        /* The port could have been hot-unplugged */
-       if (!port)
+       if (!port || !is_console_port(port))
                return;
 
        vdev = port->portdev->vdev;
-       if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_SIZE)) {
-               vdev->config->get(vdev,
-                                 offsetof(struct virtio_console_config, cols),
-                                 &ws.ws_col, sizeof(u16));
-               vdev->config->get(vdev,
-                                 offsetof(struct virtio_console_config, rows),
-                                 &ws.ws_row, sizeof(u16));
-               hvc_resize(port->cons.hvc, ws);
-       }
+       if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_SIZE))
+               hvc_resize(port->cons.hvc, port->cons.ws);
 }
 
 /* We set the configuration at this point, since we now have a tty */
@@ -804,6 +867,13 @@ int init_port_console(struct port *port)
        spin_unlock_irq(&pdrvdata_lock);
        port->guest_connected = true;
 
+       /*
+        * Start using the new console output if this is the first
+        * console to come up.
+        */
+       if (early_put_chars)
+               early_put_chars = NULL;
+
        /* Notify host of port being opened */
        send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
 
@@ -858,6 +928,8 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf,
                               "guest_connected: %d\n", port->guest_connected);
        out_offset += snprintf(buf + out_offset, out_count - out_offset,
                               "host_connected: %d\n", port->host_connected);
+       out_offset += snprintf(buf + out_offset, out_count - out_offset,
+                              "outvq_full: %d\n", port->outvq_full);
        out_offset += snprintf(buf + out_offset, out_count - out_offset,
                               "is_console: %s\n",
                               is_console_port(port) ? "yes" : "no");
@@ -875,6 +947,153 @@ static const struct file_operations port_debugfs_ops = {
        .read  = debugfs_read,
 };
 
+static void set_console_size(struct port *port, u16 rows, u16 cols)
+{
+       if (!port || !is_console_port(port))
+               return;
+
+       port->cons.ws.ws_row = rows;
+       port->cons.ws.ws_col = cols;
+}
+
+static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock)
+{
+       struct port_buffer *buf;
+       unsigned int nr_added_bufs;
+       int ret;
+
+       nr_added_bufs = 0;
+       do {
+               buf = alloc_buf(PAGE_SIZE);
+               if (!buf)
+                       break;
+
+               spin_lock_irq(lock);
+               ret = add_inbuf(vq, buf);
+               if (ret < 0) {
+                       spin_unlock_irq(lock);
+                       free_buf(buf);
+                       break;
+               }
+               nr_added_bufs++;
+               spin_unlock_irq(lock);
+       } while (ret > 0);
+
+       return nr_added_bufs;
+}
+
+static int add_port(struct ports_device *portdev, u32 id)
+{
+       char debugfs_name[16];
+       struct port *port;
+       struct port_buffer *buf;
+       dev_t devt;
+       unsigned int nr_added_bufs;
+       int err;
+
+       port = kmalloc(sizeof(*port), GFP_KERNEL);
+       if (!port) {
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       port->portdev = portdev;
+       port->id = id;
+
+       port->name = NULL;
+       port->inbuf = NULL;
+       port->cons.hvc = NULL;
+
+       port->cons.ws.ws_row = port->cons.ws.ws_col = 0;
+
+       port->host_connected = port->guest_connected = false;
+
+       port->outvq_full = false;
+
+       port->in_vq = portdev->in_vqs[port->id];
+       port->out_vq = portdev->out_vqs[port->id];
+
+       cdev_init(&port->cdev, &port_fops);
+
+       devt = MKDEV(portdev->chr_major, id);
+       err = cdev_add(&port->cdev, devt, 1);
+       if (err < 0) {
+               dev_err(&port->portdev->vdev->dev,
+                       "Error %d adding cdev for port %u\n", err, id);
+               goto free_port;
+       }
+       port->dev = device_create(pdrvdata.class, &port->portdev->vdev->dev,
+                                 devt, port, "vport%up%u",
+                                 port->portdev->drv_index, id);
+       if (IS_ERR(port->dev)) {
+               err = PTR_ERR(port->dev);
+               dev_err(&port->portdev->vdev->dev,
+                       "Error %d creating device for port %u\n",
+                       err, id);
+               goto free_cdev;
+       }
+
+       spin_lock_init(&port->inbuf_lock);
+       spin_lock_init(&port->outvq_lock);
+       init_waitqueue_head(&port->waitqueue);
+
+       /* Fill the in_vq with buffers so the host can send us data. */
+       nr_added_bufs = fill_queue(port->in_vq, &port->inbuf_lock);
+       if (!nr_added_bufs) {
+               dev_err(port->dev, "Error allocating inbufs\n");
+               err = -ENOMEM;
+               goto free_device;
+       }
+
+       /*
+        * If we're not using multiport support, this has to be a console port
+        */
+       if (!use_multiport(port->portdev)) {
+               err = init_port_console(port);
+               if (err)
+                       goto free_inbufs;
+       }
+
+       spin_lock_irq(&portdev->ports_lock);
+       list_add_tail(&port->list, &port->portdev->ports);
+       spin_unlock_irq(&portdev->ports_lock);
+
+       /*
+        * Tell the Host we're set so that it can send us various
+        * configuration parameters for this port (eg, port name,
+        * caching, whether this is a console port, etc.)
+        */
+       send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
+
+       if (pdrvdata.debugfs_dir) {
+               /*
+                * Finally, create the debugfs file that we can use to
+                * inspect a port's state at any time
+                */
+               sprintf(debugfs_name, "vport%up%u",
+                       port->portdev->drv_index, id);
+               port->debugfs_file = debugfs_create_file(debugfs_name, 0444,
+                                                        pdrvdata.debugfs_dir,
+                                                        port,
+                                                        &port_debugfs_ops);
+       }
+       return 0;
+
+free_inbufs:
+       while ((buf = virtqueue_detach_unused_buf(port->in_vq)))
+               free_buf(buf);
+free_device:
+       device_destroy(pdrvdata.class, port->dev->devt);
+free_cdev:
+       cdev_del(&port->cdev);
+free_port:
+       kfree(port);
+fail:
+       /* The host might want to notify management sw about port add failure */
+       __send_control_msg(portdev, id, VIRTIO_CONSOLE_PORT_READY, 0);
+       return err;
+}
+
 /* Remove all port-specific data. */
 static int remove_port(struct port *port)
 {
@@ -888,7 +1107,18 @@ static int remove_port(struct port *port)
                spin_lock_irq(&pdrvdata_lock);
                list_del(&port->cons.list);
                spin_unlock_irq(&pdrvdata_lock);
+#if 0
+               /*
+                * hvc_remove() not called as removing one hvc port
+                * results in other hvc ports getting frozen.
+                *
+                * Once this is resolved in hvc, this functionality
+                * will be enabled.  Till that is done, the -EPIPE
+                * return from get_chars() above will help
+                * hvc_console.c to clean up on ports we remove here.
+                */
                hvc_remove(port->cons.hvc);
+#endif
        }
        if (port->guest_connected)
                send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
@@ -900,8 +1130,10 @@ static int remove_port(struct port *port)
        /* Remove unused data this port might have received. */
        discard_port_data(port);
 
+       reclaim_consumed_buffers(port);
+
        /* Remove buffers we queued up for the Host to send us data in. */
-       while ((buf = port->in_vq->vq_ops->detach_unused_buf(port->in_vq)))
+       while ((buf = virtqueue_detach_unused_buf(port->in_vq)))
                free_buf(buf);
 
        kfree(port->name);
@@ -924,7 +1156,7 @@ static void handle_control_message(struct ports_device *portdev,
        cpkt = (struct virtio_console_control *)(buf->buf + buf->offset);
 
        port = find_port_by_id(portdev, cpkt->id);
-       if (!port) {
+       if (!port && cpkt->event != VIRTIO_CONSOLE_PORT_ADD) {
                /* No valid header at start of buffer.  Drop it. */
                dev_dbg(&portdev->vdev->dev,
                        "Invalid index %u in control packet\n", cpkt->id);
@@ -932,6 +1164,24 @@ static void handle_control_message(struct ports_device *portdev,
        }
 
        switch (cpkt->event) {
+       case VIRTIO_CONSOLE_PORT_ADD:
+               if (port) {
+                       dev_dbg(&portdev->vdev->dev,
+                               "Port %u already added\n", port->id);
+                       send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
+                       break;
+               }
+               if (cpkt->id >= portdev->config.max_nr_ports) {
+                       dev_warn(&portdev->vdev->dev,
+                               "Request for adding port with out-of-bound id %u, max. supported id: %u\n",
+                               cpkt->id, portdev->config.max_nr_ports - 1);
+                       break;
+               }
+               add_port(portdev, cpkt->id);
+               break;
+       case VIRTIO_CONSOLE_PORT_REMOVE:
+               remove_port(port);
+               break;
        case VIRTIO_CONSOLE_CONSOLE_PORT:
                if (!cpkt->value)
                        break;
@@ -944,15 +1194,34 @@ static void handle_control_message(struct ports_device *portdev,
                 * have to notify the host first.
                 */
                break;
-       case VIRTIO_CONSOLE_RESIZE:
+       case VIRTIO_CONSOLE_RESIZE: {
+               struct {
+                       __u16 rows;
+                       __u16 cols;
+               } size;
+
                if (!is_console_port(port))
                        break;
+
+               memcpy(&size, buf->buf + buf->offset + sizeof(*cpkt),
+                      sizeof(size));
+               set_console_size(port, size.rows, size.cols);
+
                port->cons.hvc->irq_requested = 1;
                resize_console(port);
                break;
+       }
        case VIRTIO_CONSOLE_PORT_OPEN:
                port->host_connected = cpkt->value;
                wake_up_interruptible(&port->waitqueue);
+               /*
+                * If the host port got closed and the host had any
+                * unconsumed buffers, we'll be able to reclaim them
+                * now.
+                */
+               spin_lock_irq(&port->outvq_lock);
+               reclaim_consumed_buffers(port);
+               spin_unlock_irq(&port->outvq_lock);
                break;
        case VIRTIO_CONSOLE_PORT_NAME:
                /*
@@ -990,32 +1259,6 @@ static void handle_control_message(struct ports_device *portdev,
                        kobject_uevent(&port->dev->kobj, KOBJ_CHANGE);
                }
                break;
-       case VIRTIO_CONSOLE_PORT_REMOVE:
-               /*
-                * Hot unplug the port.  We don't decrement nr_ports
-                * since we don't want to deal with extra complexities
-                * of using the lowest-available port id: We can just
-                * pick up the nr_ports number as the id and not have
-                * userspace send it to us.  This helps us in two
-                * ways:
-                *
-                * - We don't need to have a 'port_id' field in the
-                *   config space when a port is hot-added.  This is a
-                *   good thing as we might queue up multiple hotplug
-                *   requests issued in our workqueue.
-                *
-                * - Another way to deal with this would have been to
-                *   use a bitmap of the active ports and select the
-                *   lowest non-active port from that map.  That
-                *   bloats the already tight config space and we
-                *   would end up artificially limiting the
-                *   max. number of ports to sizeof(bitmap).  Right
-                *   now we can support 2^32 ports (as the port id is
-                *   stored in a u32 type).
-                *
-                */
-               remove_port(port);
-               break;
        }
 }
 
@@ -1030,7 +1273,7 @@ static void control_work_handler(struct work_struct *work)
        vq = portdev->c_ivq;
 
        spin_lock(&portdev->cvq_lock);
-       while ((buf = vq->vq_ops->get_buf(vq, &len))) {
+       while ((buf = virtqueue_get_buf(vq, &len))) {
                spin_unlock(&portdev->cvq_lock);
 
                buf->len = len;
@@ -1092,204 +1335,29 @@ static void config_intr(struct virtio_device *vdev)
        struct ports_device *portdev;
 
        portdev = vdev->priv;
-       if (use_multiport(portdev)) {
-               /* Handle port hot-add */
-               schedule_work(&portdev->config_work);
-       }
-       /*
-        * We'll use this way of resizing only for legacy support.
-        * For newer userspace (VIRTIO_CONSOLE_F_MULTPORT+), use
-        * control messages to indicate console size changes so that
-        * it can be done per-port
-        */
-       resize_console(find_port_by_id(portdev, 0));
-}
-
-static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock)
-{
-       struct port_buffer *buf;
-       unsigned int nr_added_bufs;
-       int ret;
-
-       nr_added_bufs = 0;
-       do {
-               buf = alloc_buf(PAGE_SIZE);
-               if (!buf)
-                       break;
-
-               spin_lock_irq(lock);
-               ret = add_inbuf(vq, buf);
-               if (ret < 0) {
-                       spin_unlock_irq(lock);
-                       free_buf(buf);
-                       break;
-               }
-               nr_added_bufs++;
-               spin_unlock_irq(lock);
-       } while (ret > 0);
-
-       return nr_added_bufs;
-}
-
-static int add_port(struct ports_device *portdev, u32 id)
-{
-       char debugfs_name[16];
-       struct port *port;
-       struct port_buffer *buf;
-       dev_t devt;
-       unsigned int nr_added_bufs;
-       int err;
-
-       port = kmalloc(sizeof(*port), GFP_KERNEL);
-       if (!port) {
-               err = -ENOMEM;
-               goto fail;
-       }
-
-       port->portdev = portdev;
-       port->id = id;
-
-       port->name = NULL;
-       port->inbuf = NULL;
-       port->cons.hvc = NULL;
-
-       port->host_connected = port->guest_connected = false;
-
-       port->in_vq = portdev->in_vqs[port->id];
-       port->out_vq = portdev->out_vqs[port->id];
-
-       cdev_init(&port->cdev, &port_fops);
-
-       devt = MKDEV(portdev->chr_major, id);
-       err = cdev_add(&port->cdev, devt, 1);
-       if (err < 0) {
-               dev_err(&port->portdev->vdev->dev,
-                       "Error %d adding cdev for port %u\n", err, id);
-               goto free_port;
-       }
-       port->dev = device_create(pdrvdata.class, &port->portdev->vdev->dev,
-                                 devt, port, "vport%up%u",
-                                 port->portdev->drv_index, id);
-       if (IS_ERR(port->dev)) {
-               err = PTR_ERR(port->dev);
-               dev_err(&port->portdev->vdev->dev,
-                       "Error %d creating device for port %u\n",
-                       err, id);
-               goto free_cdev;
-       }
-
-       spin_lock_init(&port->inbuf_lock);
-       init_waitqueue_head(&port->waitqueue);
-
-       /* Fill the in_vq with buffers so the host can send us data. */
-       nr_added_bufs = fill_queue(port->in_vq, &port->inbuf_lock);
-       if (!nr_added_bufs) {
-               dev_err(port->dev, "Error allocating inbufs\n");
-               err = -ENOMEM;
-               goto free_device;
-       }
-
-       /*
-        * If we're not using multiport support, this has to be a console port
-        */
-       if (!use_multiport(port->portdev)) {
-               err = init_port_console(port);
-               if (err)
-                       goto free_inbufs;
-       }
-
-       spin_lock_irq(&portdev->ports_lock);
-       list_add_tail(&port->list, &port->portdev->ports);
-       spin_unlock_irq(&portdev->ports_lock);
-
-       /*
-        * Tell the Host we're set so that it can send us various
-        * configuration parameters for this port (eg, port name,
-        * caching, whether this is a console port, etc.)
-        */
-       send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
-
-       if (pdrvdata.debugfs_dir) {
-               /*
-                * Finally, create the debugfs file that we can use to
-                * inspect a port's state at any time
-                */
-               sprintf(debugfs_name, "vport%up%u",
-                       port->portdev->drv_index, id);
-               port->debugfs_file = debugfs_create_file(debugfs_name, 0444,
-                                                        pdrvdata.debugfs_dir,
-                                                        port,
-                                                        &port_debugfs_ops);
-       }
-       return 0;
-
-free_inbufs:
-       while ((buf = port->in_vq->vq_ops->detach_unused_buf(port->in_vq)))
-               free_buf(buf);
-free_device:
-       device_destroy(pdrvdata.class, port->dev->devt);
-free_cdev:
-       cdev_del(&port->cdev);
-free_port:
-       kfree(port);
-fail:
-       return err;
-}
 
-/*
- * The workhandler for config-space updates.
- *
- * This is called when ports are hot-added.
- */
-static void config_work_handler(struct work_struct *work)
-{
-       struct virtio_console_multiport_conf virtconconf;
-       struct ports_device *portdev;
-       struct virtio_device *vdev;
-       int err;
+       if (!use_multiport(portdev)) {
+               struct port *port;
+               u16 rows, cols;
 
-       portdev = container_of(work, struct ports_device, config_work);
+               vdev->config->get(vdev,
+                                 offsetof(struct virtio_console_config, cols),
+                                 &cols, sizeof(u16));
+               vdev->config->get(vdev,
+                                 offsetof(struct virtio_console_config, rows),
+                                 &rows, sizeof(u16));
 
-       vdev = portdev->vdev;
-       vdev->config->get(vdev,
-                         offsetof(struct virtio_console_multiport_conf,
-                                  nr_ports),
-                         &virtconconf.nr_ports,
-                         sizeof(virtconconf.nr_ports));
+               port = find_port_by_id(portdev, 0);
+               set_console_size(port, rows, cols);
 
-       if (portdev->config.nr_ports == virtconconf.nr_ports) {
                /*
-                * Port 0 got hot-added.  Since we already did all the
-                * other initialisation for it, just tell the Host
-                * that the port is ready if we find the port.  In
-                * case the port was hot-removed earlier, we call
-                * add_port to add the port.
+                * We'll use this way of resizing only for legacy
+                * support.  For newer userspace
+                * (VIRTIO_CONSOLE_F_MULTPORT+), use control messages
+                * to indicate console size changes so that it can be
+                * done per-port.
                 */
-               struct port *port;
-
-               port = find_port_by_id(portdev, 0);
-               if (!port)
-                       add_port(portdev, 0);
-               else
-                       send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
-               return;
-       }
-       if (virtconconf.nr_ports > portdev->config.max_nr_ports) {
-               dev_warn(&vdev->dev,
-                        "More ports specified (%u) than allowed (%u)",
-                        portdev->config.nr_ports + 1,
-                        portdev->config.max_nr_ports);
-               return;
-       }
-       if (virtconconf.nr_ports < portdev->config.nr_ports)
-               return;
-
-       /* Hot-add ports */
-       while (virtconconf.nr_ports - portdev->config.nr_ports) {
-               err = add_port(portdev, portdev->config.nr_ports);
-               if (err)
-                       break;
-               portdev->config.nr_ports++;
+               resize_console(port);
        }
 }
 
@@ -1414,7 +1482,6 @@ static const struct file_operations portdev_fops = {
 static int __devinit virtcons_probe(struct virtio_device *vdev)
 {
        struct ports_device *portdev;
-       u32 i;
        int err;
        bool multiport;
 
@@ -1443,37 +1510,19 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
        }
 
        multiport = false;
-       portdev->config.nr_ports = 1;
        portdev->config.max_nr_ports = 1;
-#if 0 /* Multiport is not quite ready yet --RR */
        if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT)) {
                multiport = true;
                vdev->features[0] |= 1 << VIRTIO_CONSOLE_F_MULTIPORT;
 
-               vdev->config->get(vdev,
-                                 offsetof(struct virtio_console_multiport_conf,
-                                          nr_ports),
-                                 &portdev->config.nr_ports,
-                                 sizeof(portdev->config.nr_ports));
-               vdev->config->get(vdev,
-                                 offsetof(struct virtio_console_multiport_conf,
-                                          max_nr_ports),
+               vdev->config->get(vdev, offsetof(struct virtio_console_config,
+                                                max_nr_ports),
                                  &portdev->config.max_nr_ports,
                                  sizeof(portdev->config.max_nr_ports));
-               if (portdev->config.nr_ports > portdev->config.max_nr_ports) {
-                       dev_warn(&vdev->dev,
-                                "More ports (%u) specified than allowed (%u). Will init %u ports.",
-                                portdev->config.nr_ports,
-                                portdev->config.max_nr_ports,
-                                portdev->config.max_nr_ports);
-
-                       portdev->config.nr_ports = portdev->config.max_nr_ports;
-               }
        }
 
        /* Let the Host know we support multiple ports.*/
        vdev->config->finalize_features(vdev);
-#endif
 
        err = init_vqs(portdev);
        if (err < 0) {
@@ -1489,7 +1538,6 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
 
                spin_lock_init(&portdev->cvq_lock);
                INIT_WORK(&portdev->control_work, &control_work_handler);
-               INIT_WORK(&portdev->config_work, &config_work_handler);
 
                nr_added_bufs = fill_queue(portdev->c_ivq, &portdev->cvq_lock);
                if (!nr_added_bufs) {
@@ -1498,16 +1546,22 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
                        err = -ENOMEM;
                        goto free_vqs;
                }
+       } else {
+               /*
+                * For backward compatibility: Create a console port
+                * if we're running on older host.
+                */
+               add_port(portdev, 0);
        }
 
-       for (i = 0; i < portdev->config.nr_ports; i++)
-               add_port(portdev, i);
-
-       /* Start using the new console output. */
-       early_put_chars = NULL;
+       __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID,
+                          VIRTIO_CONSOLE_DEVICE_READY, 1);
        return 0;
 
 free_vqs:
+       /* The host might want to notify mgmt sw about device add failure */
+       __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID,
+                          VIRTIO_CONSOLE_DEVICE_READY, 0);
        vdev->config->del_vqs(vdev);
        kfree(portdev->in_vqs);
        kfree(portdev->out_vqs);
@@ -1529,17 +1583,16 @@ static void virtcons_remove(struct virtio_device *vdev)
        portdev = vdev->priv;
 
        cancel_work_sync(&portdev->control_work);
-       cancel_work_sync(&portdev->config_work);
 
        list_for_each_entry_safe(port, port2, &portdev->ports, list)
                remove_port(port);
 
        unregister_chrdev(portdev->chr_major, "virtio-portsdev");
 
-       while ((buf = portdev->c_ivq->vq_ops->get_buf(portdev->c_ivq, &len)))
+       while ((buf = virtqueue_get_buf(portdev->c_ivq, &len)))
                free_buf(buf);
 
-       while ((buf = portdev->c_ivq->vq_ops->detach_unused_buf(portdev->c_ivq)))
+       while ((buf = virtqueue_detach_unused_buf(portdev->c_ivq)))
                free_buf(buf);
 
        vdev->config->del_vqs(vdev);
@@ -1556,6 +1609,7 @@ static struct virtio_device_id id_table[] = {
 
 static unsigned int features[] = {
        VIRTIO_CONSOLE_F_SIZE,
+       VIRTIO_CONSOLE_F_MULTIPORT,
 };
 
 static struct virtio_driver virtio_console = {
index bd1d1164fec5a49feb20cab71cbfbba51233ed9e..7cdb6ee569cd7ca592bedfea458f0b676ec937af 100644 (file)
@@ -3967,13 +3967,9 @@ static int con_font_set(struct vc_data *vc, struct console_font_op *op)
        font.charcount = op->charcount;
        font.height = op->height;
        font.width = op->width;
-       font.data = kmalloc(size, GFP_KERNEL);
-       if (!font.data)
-               return -ENOMEM;
-       if (copy_from_user(font.data, op->data, size)) {
-               kfree(font.data);
-               return -EFAULT;
-       }
+       font.data = memdup_user(op->data, size);
+       if (IS_ERR(font.data))
+               return PTR_ERR(font.data);
        acquire_console_sem();
        if (vc->vc_sw->con_font_set)
                rc = vc->vc_sw->con_font_set(vc, &font, op->flags);
index 7261b8d9087c01bfea7c8eea55d6f4c61b198b5b..ed8a9cec2a05ebefc7b171828bd08b2b6a677e1c 100644 (file)
@@ -772,18 +772,18 @@ hwicap_of_probe(struct of_device *op, const struct of_device_id *match)
 
        dev_dbg(&op->dev, "hwicap_of_probe(%p, %p)\n", op, match);
 
-       rc = of_address_to_resource(op->node, 0, &res);
+       rc = of_address_to_resource(op->dev.of_node, 0, &res);
        if (rc) {
                dev_err(&op->dev, "invalid address\n");
                return rc;
        }
 
-       id = of_get_property(op->node, "port-number", NULL);
+       id = of_get_property(op->dev.of_node, "port-number", NULL);
 
        /* It's most likely that we're using V4, if the family is not
           specified */
        regs = &v4_config_registers;
-       family = of_get_property(op->node, "xlnx,family", NULL);
+       family = of_get_property(op->dev.of_node, "xlnx,family", NULL);
 
        if (family) {
                if (!strcmp(family, "virtex2p")) {
@@ -812,13 +812,12 @@ static const struct of_device_id __devinitconst hwicap_of_match[] = {
 MODULE_DEVICE_TABLE(of, hwicap_of_match);
 
 static struct of_platform_driver hwicap_of_driver = {
-       .owner = THIS_MODULE,
-       .name = DRIVER_NAME,
-       .match_table = hwicap_of_match,
        .probe = hwicap_of_probe,
        .remove = __devexit_p(hwicap_of_remove),
        .driver = {
                .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = hwicap_of_match,
        },
 };
 
index 12fdd3987a36c2b09ab65b9d598f276e51fbf5b7..199488576a05c65bac2740d33600fc1c6fd5511f 100644 (file)
@@ -156,7 +156,7 @@ int cpuidle_enable_device(struct cpuidle_device *dev)
 
        if (dev->enabled)
                return 0;
-       if (!cpuidle_curr_driver || !cpuidle_curr_governor)
+       if (!cpuidle_get_driver() || !cpuidle_curr_governor)
                return -EIO;
        if (!dev->state_count)
                return -EINVAL;
@@ -207,7 +207,7 @@ void cpuidle_disable_device(struct cpuidle_device *dev)
 {
        if (!dev->enabled)
                return;
-       if (!cpuidle_curr_driver || !cpuidle_curr_governor)
+       if (!cpuidle_get_driver() || !cpuidle_curr_governor)
                return;
 
        dev->enabled = 0;
@@ -271,10 +271,11 @@ static int __cpuidle_register_device(struct cpuidle_device *dev)
 {
        int ret;
        struct sys_device *sys_dev = get_cpu_sysdev((unsigned long)dev->cpu);
+       struct cpuidle_driver *cpuidle_driver = cpuidle_get_driver();
 
        if (!sys_dev)
                return -EINVAL;
-       if (!try_module_get(cpuidle_curr_driver->owner))
+       if (!try_module_get(cpuidle_driver->owner))
                return -EINVAL;
 
        init_completion(&dev->kobj_unregister);
@@ -284,7 +285,7 @@ static int __cpuidle_register_device(struct cpuidle_device *dev)
        per_cpu(cpuidle_devices, dev->cpu) = dev;
        list_add(&dev->device_list, &cpuidle_detected_devices);
        if ((ret = cpuidle_add_sysfs(sys_dev))) {
-               module_put(cpuidle_curr_driver->owner);
+               module_put(cpuidle_driver->owner);
                return ret;
        }
 
@@ -325,6 +326,7 @@ EXPORT_SYMBOL_GPL(cpuidle_register_device);
 void cpuidle_unregister_device(struct cpuidle_device *dev)
 {
        struct sys_device *sys_dev = get_cpu_sysdev((unsigned long)dev->cpu);
+       struct cpuidle_driver *cpuidle_driver = cpuidle_get_driver();
 
        if (dev->registered == 0)
                return;
@@ -340,7 +342,7 @@ void cpuidle_unregister_device(struct cpuidle_device *dev)
 
        cpuidle_resume_and_unlock();
 
-       module_put(cpuidle_curr_driver->owner);
+       module_put(cpuidle_driver->owner);
 }
 
 EXPORT_SYMBOL_GPL(cpuidle_unregister_device);
index 9476ba33ee2c119e4f7a464666758b98c76f26cc..33e50d556f178232f2cef79ae45e28f6923b325f 100644 (file)
@@ -9,7 +9,6 @@
 
 /* For internal use only */
 extern struct cpuidle_governor *cpuidle_curr_governor;
-extern struct cpuidle_driver *cpuidle_curr_driver;
 extern struct list_head cpuidle_governors;
 extern struct list_head cpuidle_detected_devices;
 extern struct mutex cpuidle_lock;
index 2257004fe33d528454a8c40680c08b0ea9335348..fd1601e3d1250faaa3b4863eb27706529076bcb1 100644 (file)
@@ -14,7 +14,7 @@
 
 #include "cpuidle.h"
 
-struct cpuidle_driver *cpuidle_curr_driver;
+static struct cpuidle_driver *cpuidle_curr_driver;
 DEFINE_SPINLOCK(cpuidle_driver_lock);
 
 /**
@@ -39,14 +39,26 @@ int cpuidle_register_driver(struct cpuidle_driver *drv)
 
 EXPORT_SYMBOL_GPL(cpuidle_register_driver);
 
+/**
+ * cpuidle_get_driver - return the current driver
+ */
+struct cpuidle_driver *cpuidle_get_driver(void)
+{
+       return cpuidle_curr_driver;
+}
+EXPORT_SYMBOL_GPL(cpuidle_get_driver);
+
 /**
  * cpuidle_unregister_driver - unregisters a driver
  * @drv: the driver
  */
 void cpuidle_unregister_driver(struct cpuidle_driver *drv)
 {
-       if (!drv)
+       if (drv != cpuidle_curr_driver) {
+               WARN(1, "invalid cpuidle_unregister_driver(%s)\n",
+                       drv->name);
                return;
+       }
 
        spin_lock(&cpuidle_driver_lock);
        cpuidle_curr_driver = NULL;
index b81ad9c731ae3a153b5c9f8fb1f6c8539407c695..52ff8aa63f8449b04d5bcd046b028e23dcf6d68b 100644 (file)
 #include <linux/math64.h>
 
 #define BUCKETS 12
+#define INTERVALS 8
 #define RESOLUTION 1024
-#define DECAY 4
+#define DECAY 8
 #define MAX_INTERESTING 50000
+#define STDDEV_THRESH 400
+
 
 /*
  * Concepts and ideas behind the menu governor
  * indexed based on the magnitude of the expected duration as well as the
  * "is IO outstanding" property.
  *
+ * Repeatable-interval-detector
+ * ----------------------------
+ * There are some cases where "next timer" is a completely unusable predictor:
+ * Those cases where the interval is fixed, for example due to hardware
+ * interrupt mitigation, but also due to fixed transfer rate devices such as
+ * mice.
+ * For this, we use a different predictor: We track the duration of the last 8
+ * intervals and if the stand deviation of these 8 intervals is below a
+ * threshold value, we use the average of these intervals as prediction.
+ *
  * Limiting Performance Impact
  * ---------------------------
  * C states, especially those with large exit latencies, can have a real
@@ -104,6 +117,8 @@ struct menu_device {
        unsigned int    exit_us;
        unsigned int    bucket;
        u64             correction_factor[BUCKETS];
+       u32             intervals[INTERVALS];
+       int             interval_ptr;
 };
 
 
@@ -175,6 +190,42 @@ static u64 div_round64(u64 dividend, u32 divisor)
        return div_u64(dividend + (divisor / 2), divisor);
 }
 
+/*
+ * Try detecting repeating patterns by keeping track of the last 8
+ * intervals, and checking if the standard deviation of that set
+ * of points is below a threshold. If it is... then use the
+ * average of these 8 points as the estimated value.
+ */
+static void detect_repeating_patterns(struct menu_device *data)
+{
+       int i;
+       uint64_t avg = 0;
+       uint64_t stddev = 0; /* contains the square of the std deviation */
+
+       /* first calculate average and standard deviation of the past */
+       for (i = 0; i < INTERVALS; i++)
+               avg += data->intervals[i];
+       avg = avg / INTERVALS;
+
+       /* if the avg is beyond the known next tick, it's worthless */
+       if (avg > data->expected_us)
+               return;
+
+       for (i = 0; i < INTERVALS; i++)
+               stddev += (data->intervals[i] - avg) *
+                         (data->intervals[i] - avg);
+
+       stddev = stddev / INTERVALS;
+
+       /*
+        * now.. if stddev is small.. then assume we have a
+        * repeating pattern and predict we keep doing this.
+        */
+
+       if (avg && stddev < STDDEV_THRESH)
+               data->predicted_us = avg;
+}
+
 /**
  * menu_select - selects the next idle state to enter
  * @dev: the CPU
@@ -218,6 +269,8 @@ static int menu_select(struct cpuidle_device *dev)
        data->predicted_us = div_round64(data->expected_us * data->correction_factor[data->bucket],
                                         RESOLUTION * DECAY);
 
+       detect_repeating_patterns(data);
+
        /*
         * We want to default to C1 (hlt), not to busy polling
         * unless the timer is happening really really soon.
@@ -310,6 +363,11 @@ static void menu_update(struct cpuidle_device *dev)
                new_factor = 1;
 
        data->correction_factor[data->bucket] = new_factor;
+
+       /* update the repeating-pattern data */
+       data->intervals[data->interval_ptr++] = last_idle_us;
+       if (data->interval_ptr >= INTERVALS)
+               data->interval_ptr = 0;
 }
 
 /**
index 0ba9c8b8ee743e960eed3db8e5d9108d7c5eeadc..0310ffaec9df0536143b509847047d7ab01eba27 100644 (file)
@@ -47,10 +47,11 @@ static ssize_t show_current_driver(struct sysdev_class *class,
                                   char *buf)
 {
        ssize_t ret;
+       struct cpuidle_driver *cpuidle_driver = cpuidle_get_driver();
 
        spin_lock(&cpuidle_driver_lock);
-       if (cpuidle_curr_driver)
-               ret = sprintf(buf, "%s\n", cpuidle_curr_driver->name);
+       if (cpuidle_driver)
+               ret = sprintf(buf, "%s\n", cpuidle_driver->name);
        else
                ret = sprintf(buf, "none\n");
        spin_unlock(&cpuidle_driver_lock);
index 6c4c8b7ce3aa195e5dac4e05f7db38c6051a783b..9d65b371de64cced72bcb0f1e483913962277552 100644 (file)
@@ -1281,8 +1281,11 @@ static const struct of_device_id crypto4xx_match[] = {
 };
 
 static struct of_platform_driver crypto4xx_driver = {
-       .name           = "crypto4xx",
-       .match_table    = crypto4xx_match,
+       .driver = {
+               .name = "crypto4xx",
+               .owner = THIS_MODULE,
+               .of_match_table = crypto4xx_match,
+       },
        .probe          = crypto4xx_probe,
        .remove         = crypto4xx_remove,
 };
index 6a0f59d1fc5c4e834aaf90006ca30c7e35f8cdd9..637c105f53d262f904230c77b5bc5a5a5234fda7 100644 (file)
@@ -2398,7 +2398,7 @@ static int talitos_probe(struct of_device *ofdev,
                         const struct of_device_id *match)
 {
        struct device *dev = &ofdev->dev;
-       struct device_node *np = ofdev->node;
+       struct device_node *np = ofdev->dev.of_node;
        struct talitos_private *priv;
        const unsigned int *prop;
        int i, err;
@@ -2573,8 +2573,11 @@ static const struct of_device_id talitos_match[] = {
 MODULE_DEVICE_TABLE(of, talitos_match);
 
 static struct of_platform_driver talitos_driver = {
-       .name = "talitos",
-       .match_table = talitos_match,
+       .driver = {
+               .name = "talitos",
+               .owner = THIS_MODULE,
+               .of_match_table = talitos_match,
+       },
        .probe = talitos_probe,
        .remove = talitos_remove,
 };
index 1fdf180cbd67d55d1b4264eb3df8fb5cae12f940..8088b14ba5f7fd8077e5b9794754d2a9afa41477 100644 (file)
@@ -1315,7 +1315,7 @@ static int __devinit fsldma_of_probe(struct of_device *op,
        INIT_LIST_HEAD(&fdev->common.channels);
 
        /* ioremap the registers for use */
-       fdev->regs = of_iomap(op->node, 0);
+       fdev->regs = of_iomap(op->dev.of_node, 0);
        if (!fdev->regs) {
                dev_err(&op->dev, "unable to ioremap registers\n");
                err = -ENOMEM;
@@ -1323,7 +1323,7 @@ static int __devinit fsldma_of_probe(struct of_device *op,
        }
 
        /* map the channel IRQ if it exists, but don't hookup the handler yet */
-       fdev->irq = irq_of_parse_and_map(op->node, 0);
+       fdev->irq = irq_of_parse_and_map(op->dev.of_node, 0);
 
        dma_cap_set(DMA_MEMCPY, fdev->common.cap_mask);
        dma_cap_set(DMA_INTERRUPT, fdev->common.cap_mask);
@@ -1345,7 +1345,7 @@ static int __devinit fsldma_of_probe(struct of_device *op,
         * of_platform_bus_remove(). Instead, we manually instantiate every DMA
         * channel object.
         */
-       for_each_child_of_node(op->node, child) {
+       for_each_child_of_node(op->dev.of_node, child) {
                if (of_device_is_compatible(child, "fsl,eloplus-dma-channel")) {
                        fsl_dma_chan_probe(fdev, child,
                                FSL_DMA_IP_85XX | FSL_DMA_BIG_ENDIAN,
@@ -1411,10 +1411,13 @@ static const struct of_device_id fsldma_of_ids[] = {
 };
 
 static struct of_platform_driver fsldma_of_driver = {
-       .name           = "fsl-elo-dma",
-       .match_table    = fsldma_of_ids,
-       .probe          = fsldma_of_probe,
-       .remove         = fsldma_of_remove,
+       .driver = {
+               .name = "fsl-elo-dma",
+               .owner = THIS_MODULE,
+               .of_match_table = fsldma_of_ids,
+       },
+       .probe = fsldma_of_probe,
+       .remove = fsldma_of_remove,
 };
 
 /*----------------------------------------------------------------------------*/
index c6079fcca13fe58667ff794d63a93f71a5f14666..fa98abe4686fb06598c6f8b318e4866dff1f41be 100644 (file)
@@ -4944,12 +4944,12 @@ static const struct of_device_id ppc440spe_adma_of_match[] __devinitconst = {
 MODULE_DEVICE_TABLE(of, ppc440spe_adma_of_match);
 
 static struct of_platform_driver ppc440spe_adma_driver = {
-       .match_table = ppc440spe_adma_of_match,
        .probe = ppc440spe_adma_probe,
        .remove = __devexit_p(ppc440spe_adma_remove),
        .driver = {
                .name = "PPC440SP(E)-ADMA",
                .owner = THIS_MODULE,
+               .of_match_table = ppc440spe_adma_of_match,
        },
 };
 
index a1727522343e914ee63a5bf064ede9544374abdc..a2a519fd2a24fc3ec9f4d1daa63fba110d99684e 100644 (file)
@@ -722,6 +722,10 @@ static void sh_dmae_chan_ld_cleanup(struct sh_dmae_chan *sh_chan, bool all)
 {
        while (__ld_cleanup(sh_chan, all))
                ;
+
+       if (all)
+               /* Terminating - forgive uncompleted cookies */
+               sh_chan->completed_cookie = sh_chan->common.cookie;
 }
 
 static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan)
@@ -1188,6 +1192,7 @@ static struct platform_driver sh_dmae_driver = {
        .remove         = __exit_p(sh_dmae_remove),
        .shutdown       = sh_dmae_shutdown,
        .driver = {
+               .owner  = THIS_MODULE,
                .name   = "sh-dma-engine",
        },
 };
index 0172fa3c7a2b176ffebb2c551354a448c2fe5fa6..a1bf77c1993f32a0db84c2338270af6fff71d027 100644 (file)
@@ -188,7 +188,7 @@ static void __td_unmap_descs(struct timb_dma_desc *td_desc, bool single)
 static int td_fill_desc(struct timb_dma_chan *td_chan, u8 *dma_desc,
        struct scatterlist *sg, bool last)
 {
-       if (sg_dma_len(sg) > USHORT_MAX) {
+       if (sg_dma_len(sg) > USHRT_MAX) {
                dev_err(chan2dev(&td_chan->chan), "Too big sg element\n");
                return -EINVAL;
        }
index f2330f81cb5ea9b05f5a6c229737f627d5dba601..cace0a7b707af37b394d0e34b00afb2d9968b251 100644 (file)
@@ -294,7 +294,7 @@ static int __devinit amd76x_init_one(struct pci_dev *pdev,
 {
        debugf0("%s()\n", __func__);
 
-       /* don't need to call pci_device_enable() */
+       /* don't need to call pci_enable_device() */
        return amd76x_probe1(pdev, ent->driver_data);
 }
 
index adc10a2ac5f63b0e1dbd90ca2ca529e9e2a5b15c..996c1bdb5a34379c474d7c1100aabeb419f30996 100644 (file)
@@ -774,7 +774,7 @@ static void i5000_clear_error(struct mem_ctl_info *mci)
 static void i5000_check_error(struct mem_ctl_info *mci)
 {
        struct i5000_error_info info;
-       debugf4("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__);
+       debugf4("MC%d: %s: %s()\n", mci->mc_idx, __FILE__, __func__);
        i5000_get_error_info(mci, &info);
        i5000_process_error_info(mci, &info, 1);
 }
@@ -1353,8 +1353,8 @@ static int i5000_probe1(struct pci_dev *pdev, int dev_idx)
        int num_dimms_per_channel;
        int num_csrows;
 
-       debugf0("MC: " __FILE__ ": %s(), pdev bus %u dev=0x%x fn=0x%x\n",
-               __func__,
+       debugf0("MC: %s: %s(), pdev bus %u dev=0x%x fn=0x%x\n",
+               __FILE__, __func__,
                pdev->bus->number,
                PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
 
@@ -1389,7 +1389,7 @@ static int i5000_probe1(struct pci_dev *pdev, int dev_idx)
                return -ENOMEM;
 
        kobject_get(&mci->edac_mci_kobj);
-       debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
+       debugf0("MC: %s: %s(): mci = %p\n", __FILE__, __func__, mci);
 
        mci->dev = &pdev->dev;  /* record ptr  to the generic device */
 
@@ -1432,8 +1432,8 @@ static int i5000_probe1(struct pci_dev *pdev, int dev_idx)
 
        /* add this new MC control structure to EDAC's list of MCs */
        if (edac_mc_add_mc(mci)) {
-               debugf0("MC: " __FILE__
-                       ": %s(): failed edac_mc_add_mc()\n", __func__);
+               debugf0("MC: %s: %s(): failed edac_mc_add_mc()\n",
+                       __FILE__, __func__);
                /* FIXME: perhaps some code should go here that disables error
                 * reporting if we just enabled it
                 */
@@ -1478,7 +1478,7 @@ static int __devinit i5000_init_one(struct pci_dev *pdev,
 {
        int rc;
 
-       debugf0("MC: " __FILE__ ": %s()\n", __func__);
+       debugf0("MC: %s: %s()\n", __FILE__, __func__);
 
        /* wake up device */
        rc = pci_enable_device(pdev);
@@ -1497,7 +1497,7 @@ static void __devexit i5000_remove_one(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
 
-       debugf0(__FILE__ ": %s()\n", __func__);
+       debugf0("%s: %s()\n", __FILE__, __func__);
 
        if (i5000_pci)
                edac_pci_release_generic_ctl(i5000_pci);
@@ -1544,7 +1544,7 @@ static int __init i5000_init(void)
 {
        int pci_rc;
 
-       debugf2("MC: " __FILE__ ": %s()\n", __func__);
+       debugf2("MC: %s: %s()\n", __FILE__, __func__);
 
        /* Ensure that the OPSTATE is set correctly for POLL or NMI */
        opstate_init();
@@ -1560,7 +1560,7 @@ static int __init i5000_init(void)
  */
 static void __exit i5000_exit(void)
 {
-       debugf2("MC: " __FILE__ ": %s()\n", __func__);
+       debugf2("MC: %s: %s()\n", __FILE__, __func__);
        pci_unregister_driver(&i5000_driver);
 }
 
index f99d10655ed45cd3132f50a80144166e10aad1f5..010c1d6526f56fe6a33b2685e28ab6592dad8f80 100644 (file)
@@ -694,7 +694,7 @@ static void i5400_clear_error(struct mem_ctl_info *mci)
 static void i5400_check_error(struct mem_ctl_info *mci)
 {
        struct i5400_error_info info;
-       debugf4("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__);
+       debugf4("MC%d: %s: %s()\n", mci->mc_idx, __FILE__, __func__);
        i5400_get_error_info(mci, &info);
        i5400_process_error_info(mci, &info);
 }
@@ -1227,8 +1227,8 @@ static int i5400_probe1(struct pci_dev *pdev, int dev_idx)
        if (dev_idx >= ARRAY_SIZE(i5400_devs))
                return -EINVAL;
 
-       debugf0("MC: " __FILE__ ": %s(), pdev bus %u dev=0x%x fn=0x%x\n",
-               __func__,
+       debugf0("MC: %s: %s(), pdev bus %u dev=0x%x fn=0x%x\n",
+               __FILE__, __func__,
                pdev->bus->number,
                PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
 
@@ -1256,7 +1256,7 @@ static int i5400_probe1(struct pci_dev *pdev, int dev_idx)
        if (mci == NULL)
                return -ENOMEM;
 
-       debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
+       debugf0("MC: %s: %s(): mci = %p\n", __FILE__, __func__, mci);
 
        mci->dev = &pdev->dev;  /* record ptr  to the generic device */
 
@@ -1299,8 +1299,8 @@ static int i5400_probe1(struct pci_dev *pdev, int dev_idx)
 
        /* add this new MC control structure to EDAC's list of MCs */
        if (edac_mc_add_mc(mci)) {
-               debugf0("MC: " __FILE__
-                       ": %s(): failed edac_mc_add_mc()\n", __func__);
+               debugf0("MC: %s: %s(): failed edac_mc_add_mc()\n",
+                       __FILE__, __func__);
                /* FIXME: perhaps some code should go here that disables error
                 * reporting if we just enabled it
                 */
@@ -1344,7 +1344,7 @@ static int __devinit i5400_init_one(struct pci_dev *pdev,
 {
        int rc;
 
-       debugf0("MC: " __FILE__ ": %s()\n", __func__);
+       debugf0("MC: %s: %s()\n", __FILE__, __func__);
 
        /* wake up device */
        rc = pci_enable_device(pdev);
@@ -1363,7 +1363,7 @@ static void __devexit i5400_remove_one(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
 
-       debugf0(__FILE__ ": %s()\n", __func__);
+       debugf0("%s: %s()\n", __FILE__, __func__);
 
        if (i5400_pci)
                edac_pci_release_generic_ctl(i5400_pci);
@@ -1409,7 +1409,7 @@ static int __init i5400_init(void)
 {
        int pci_rc;
 
-       debugf2("MC: " __FILE__ ": %s()\n", __func__);
+       debugf2("MC: %s: %s()\n", __FILE__, __func__);
 
        /* Ensure that the OPSTATE is set correctly for POLL or NMI */
        opstate_init();
@@ -1425,7 +1425,7 @@ static int __init i5400_init(void)
  */
 static void __exit i5400_exit(void)
 {
-       debugf2("MC: " __FILE__ ": %s()\n", __func__);
+       debugf2("MC: %s: %s()\n", __FILE__, __func__);
        pci_unregister_driver(&i5400_driver);
 }
 
index 7f3884fcbd467426ad4beec3c53fe91ec99ad46b..a2fa1feed724dce86fa29490972a9d8298e4259c 100644 (file)
@@ -178,7 +178,7 @@ static void i82443bxgx_edacmc_check(struct mem_ctl_info *mci)
 {
        struct i82443bxgx_edacmc_error_info info;
 
-       debugf1("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__);
+       debugf1("MC%d: %s: %s()\n", mci->mc_idx, __FILE__, __func__);
        i82443bxgx_edacmc_get_error_info(mci, &info);
        i82443bxgx_edacmc_process_error_info(mci, &info, 1);
 }
@@ -198,13 +198,13 @@ static void i82443bxgx_init_csrows(struct mem_ctl_info *mci,
        for (index = 0; index < mci->nr_csrows; index++) {
                csrow = &mci->csrows[index];
                pci_read_config_byte(pdev, I82443BXGX_DRB + index, &drbar);
-               debugf1("MC%d: " __FILE__ ": %s() Row=%d DRB = %#0x\n",
-                       mci->mc_idx, __func__, index, drbar);
+               debugf1("MC%d: %s: %s() Row=%d DRB = %#0x\n",
+                       mci->mc_idx, __FILE__, __func__, index, drbar);
                row_high_limit = ((u32) drbar << 23);
                /* find the DRAM Chip Select Base address and mask */
-               debugf1("MC%d: " __FILE__ ": %s() Row=%d, "
-                       "Boundry Address=%#0x, Last = %#0x \n",
-                       mci->mc_idx, __func__, index, row_high_limit,
+               debugf1("MC%d: %s: %s() Row=%d, "
+                       "Boundry Address=%#0x, Last = %#0x\n",
+                       mci->mc_idx, __FILE__, __func__, index, row_high_limit,
                        row_high_limit_last);
 
                /* 440GX goes to 2GB, represented with a DRB of 0. */
@@ -237,7 +237,7 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
        enum mem_type mtype;
        enum edac_type edac_mode;
 
-       debugf0("MC: " __FILE__ ": %s()\n", __func__);
+       debugf0("MC: %s: %s()\n", __FILE__, __func__);
 
        /* Something is really hosed if PCI config space reads from
         * the MC aren't working.
@@ -250,7 +250,7 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
        if (mci == NULL)
                return -ENOMEM;
 
-       debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
+       debugf0("MC: %s: %s(): mci = %p\n", __FILE__, __func__, mci);
        mci->dev = &pdev->dev;
        mci->mtype_cap = MEM_FLAG_EDO | MEM_FLAG_SDR | MEM_FLAG_RDR;
        mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
@@ -336,7 +336,7 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
                        __func__);
        }
 
-       debugf3("MC: " __FILE__ ": %s(): success\n", __func__);
+       debugf3("MC: %s: %s(): success\n", __FILE__, __func__);
        return 0;
 
 fail:
@@ -352,9 +352,9 @@ static int __devinit i82443bxgx_edacmc_init_one(struct pci_dev *pdev,
 {
        int rc;
 
-       debugf0("MC: " __FILE__ ": %s()\n", __func__);
+       debugf0("MC: %s: %s()\n", __FILE__, __func__);
 
-       /* don't need to call pci_device_enable() */
+       /* don't need to call pci_enable_device() */
        rc = i82443bxgx_edacmc_probe1(pdev, ent->driver_data);
 
        if (mci_pdev == NULL)
@@ -367,7 +367,7 @@ static void __devexit i82443bxgx_edacmc_remove_one(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
 
-       debugf0(__FILE__ ": %s()\n", __func__);
+       debugf0("%s: %s()\n", __FILE__, __func__);
 
        if (i82443bxgx_pci)
                edac_pci_release_generic_ctl(i82443bxgx_pci);
index 4471647b4807eadb31b6e4e278a5298bcfed97e8..6c1886b497ff673add09b99809f065c9a294090b 100644 (file)
@@ -338,15 +338,13 @@ static struct of_device_id mpc85xx_pci_err_of_match[] = {
 };
 
 static struct of_platform_driver mpc85xx_pci_err_driver = {
-       .owner = THIS_MODULE,
-       .name = "mpc85xx_pci_err",
-       .match_table = mpc85xx_pci_err_of_match,
        .probe = mpc85xx_pci_err_probe,
        .remove = __devexit_p(mpc85xx_pci_err_remove),
        .driver = {
-                  .name = "mpc85xx_pci_err",
-                  .owner = THIS_MODULE,
-                  },
+               .name = "mpc85xx_pci_err",
+               .owner = THIS_MODULE,
+               .of_match_table = mpc85xx_pci_err_of_match,
+       },
 };
 
 #endif                         /* CONFIG_PCI */
@@ -654,15 +652,13 @@ static struct of_device_id mpc85xx_l2_err_of_match[] = {
 };
 
 static struct of_platform_driver mpc85xx_l2_err_driver = {
-       .owner = THIS_MODULE,
-       .name = "mpc85xx_l2_err",
-       .match_table = mpc85xx_l2_err_of_match,
        .probe = mpc85xx_l2_err_probe,
        .remove = mpc85xx_l2_err_remove,
        .driver = {
-                  .name = "mpc85xx_l2_err",
-                  .owner = THIS_MODULE,
-                  },
+               .name = "mpc85xx_l2_err",
+               .owner = THIS_MODULE,
+               .of_match_table = mpc85xx_l2_err_of_match,
+       },
 };
 
 /**************************** MC Err device ***************************/
@@ -1131,15 +1127,13 @@ static struct of_device_id mpc85xx_mc_err_of_match[] = {
 };
 
 static struct of_platform_driver mpc85xx_mc_err_driver = {
-       .owner = THIS_MODULE,
-       .name = "mpc85xx_mc_err",
-       .match_table = mpc85xx_mc_err_of_match,
        .probe = mpc85xx_mc_err_probe,
        .remove = mpc85xx_mc_err_remove,
        .driver = {
-                  .name = "mpc85xx_mc_err",
-                  .owner = THIS_MODULE,
-                  },
+               .name = "mpc85xx_mc_err",
+               .owner = THIS_MODULE,
+               .of_match_table = mpc85xx_mc_err_of_match,
+       },
 };
 
 #ifdef CONFIG_MPC85xx
index 11f2172aa1e6f5fb37dbe4752ec2654dc7c5d5df..9d6f6783328c80357cb794614ff79dca1e0b84d0 100644 (file)
@@ -202,13 +202,13 @@ static struct of_device_id ppc4xx_edac_match[] = {
 };
 
 static struct of_platform_driver ppc4xx_edac_driver = {
-       .match_table            = ppc4xx_edac_match,
        .probe                  = ppc4xx_edac_probe,
        .remove                 = ppc4xx_edac_remove,
-       .driver                 = {
-               .owner  = THIS_MODULE,
-               .name   = PPC4XX_EDAC_MODULE_NAME
-       }
+       .driver = {
+               .owner = THIS_MODULE,
+               .name = PPC4XX_EDAC_MODULE_NAME
+               .of_match_table = ppc4xx_edac_match,
+       },
 };
 
 /*
index d55f8e9de78878fc4379645fb26631b487f4cb7c..6a822c631ef51df8e3b8858e24ddc05839690094 100644 (file)
@@ -354,7 +354,7 @@ static int __devinit r82600_init_one(struct pci_dev *pdev,
 {
        debugf0("%s()\n", __func__);
 
-       /* don't need to call pci_device_enable() */
+       /* don't need to call pci_enable_device() */
        return r82600_probe1(pdev, ent->driver_data);
 }
 
index 5045156c5313b0c59114850f003f17ef46945c36..9dcb30466ec0a22a11092decb65474e7bdcc5191 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
-#include <linux/timer.h>
 #include <linux/workqueue.h>
 
 #include <asm/atomic.h>
@@ -63,7 +62,7 @@ static size_t config_rom_length = 1 + 4 + 1 + 1;
 #define BIB_CRC(v)             ((v) <<  0)
 #define BIB_CRC_LENGTH(v)      ((v) << 16)
 #define BIB_INFO_LENGTH(v)     ((v) << 24)
-
+#define BIB_BUS_NAME           0x31333934 /* "1394" */
 #define BIB_LINK_SPEED(v)      ((v) <<  0)
 #define BIB_GENERATION(v)      ((v) <<  4)
 #define BIB_MAX_ROM(v)         ((v) <<  8)
@@ -73,7 +72,8 @@ static size_t config_rom_length = 1 + 4 + 1 + 1;
 #define BIB_BMC                        ((1) << 28)
 #define BIB_ISC                        ((1) << 29)
 #define BIB_CMC                        ((1) << 30)
-#define BIB_IMC                        ((1) << 31)
+#define BIB_IRMC               ((1) << 31)
+#define NODE_CAPABILITIES      0x0c0083c0 /* per IEEE 1394 clause 8.3.2.6.5.2 */
 
 static void generate_config_rom(struct fw_card *card, __be32 *config_rom)
 {
@@ -91,18 +91,18 @@ static void generate_config_rom(struct fw_card *card, __be32 *config_rom)
 
        config_rom[0] = cpu_to_be32(
                BIB_CRC_LENGTH(4) | BIB_INFO_LENGTH(4) | BIB_CRC(0));
-       config_rom[1] = cpu_to_be32(0x31333934);
+       config_rom[1] = cpu_to_be32(BIB_BUS_NAME);
        config_rom[2] = cpu_to_be32(
                BIB_LINK_SPEED(card->link_speed) |
                BIB_GENERATION(card->config_rom_generation++ % 14 + 2) |
                BIB_MAX_ROM(2) |
                BIB_MAX_RECEIVE(card->max_receive) |
-               BIB_BMC | BIB_ISC | BIB_CMC | BIB_IMC);
+               BIB_BMC | BIB_ISC | BIB_CMC | BIB_IRMC);
        config_rom[3] = cpu_to_be32(card->guid >> 32);
        config_rom[4] = cpu_to_be32(card->guid);
 
        /* Generate root directory. */
-       config_rom[6] = cpu_to_be32(0x0c0083c0); /* node capabilities */
+       config_rom[6] = cpu_to_be32(NODE_CAPABILITIES);
        i = 7;
        j = 7 + descriptor_count;
 
@@ -407,13 +407,6 @@ static void fw_card_bm_work(struct work_struct *work)
        fw_card_put(card);
 }
 
-static void flush_timer_callback(unsigned long data)
-{
-       struct fw_card *card = (struct fw_card *)data;
-
-       fw_flush_transactions(card);
-}
-
 void fw_card_initialize(struct fw_card *card,
                        const struct fw_card_driver *driver,
                        struct device *device)
@@ -432,8 +425,6 @@ void fw_card_initialize(struct fw_card *card,
        init_completion(&card->done);
        INIT_LIST_HEAD(&card->transaction_list);
        spin_lock_init(&card->lock);
-       setup_timer(&card->flush_timer,
-                   flush_timer_callback, (unsigned long)card);
 
        card->local_node = NULL;
 
@@ -558,7 +549,6 @@ void fw_core_remove_card(struct fw_card *card)
        wait_for_completion(&card->done);
 
        WARN_ON(!list_empty(&card->transaction_list));
-       del_timer_sync(&card->flush_timer);
 }
 EXPORT_SYMBOL(fw_core_remove_card);
 
index 14a34d99eea25554bb123af7c44f44e8d01582a8..5bf106b9d79193138349d6e54adfd65490dfccb8 100644 (file)
@@ -227,7 +227,7 @@ static int fw_device_op_open(struct inode *inode, struct file *file)
        list_add_tail(&client->link, &device->client_list);
        mutex_unlock(&device->client_list_mutex);
 
-       return 0;
+       return nonseekable_open(inode, file);
 }
 
 static void queue_event(struct client *client, struct event *event,
@@ -1496,13 +1496,13 @@ static unsigned int fw_device_op_poll(struct file *file, poll_table * pt)
 
 const struct file_operations fw_device_ops = {
        .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
        .open           = fw_device_op_open,
        .read           = fw_device_op_read,
        .unlocked_ioctl = fw_device_op_ioctl,
-       .poll           = fw_device_op_poll,
-       .release        = fw_device_op_release,
        .mmap           = fw_device_op_mmap,
-
+       .release        = fw_device_op_release,
+       .poll           = fw_device_op_poll,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = fw_device_op_compat_ioctl,
 #endif
index 673b03f8b4ecd6cbe1ac577e845350a6bcb7dca8..fdc33ff06dc11c536b080797d1ba4a81482711b0 100644 (file)
@@ -81,7 +81,7 @@ static int close_transaction(struct fw_transaction *transaction,
        spin_lock_irqsave(&card->lock, flags);
        list_for_each_entry(t, &card->transaction_list, link) {
                if (t == transaction) {
-                       list_del(&t->link);
+                       list_del_init(&t->link);
                        card->tlabel_mask &= ~(1ULL << t->tlabel);
                        break;
                }
@@ -89,6 +89,7 @@ static int close_transaction(struct fw_transaction *transaction,
        spin_unlock_irqrestore(&card->lock, flags);
 
        if (&t->link != &card->transaction_list) {
+               del_timer_sync(&t->split_timeout_timer);
                t->callback(card, rcode, NULL, 0, t->callback_data);
                return 0;
        }
@@ -121,6 +122,31 @@ int fw_cancel_transaction(struct fw_card *card,
 }
 EXPORT_SYMBOL(fw_cancel_transaction);
 
+static void split_transaction_timeout_callback(unsigned long data)
+{
+       struct fw_transaction *t = (struct fw_transaction *)data;
+       struct fw_card *card = t->card;
+       unsigned long flags;
+
+       spin_lock_irqsave(&card->lock, flags);
+       if (list_empty(&t->link)) {
+               spin_unlock_irqrestore(&card->lock, flags);
+               return;
+       }
+       list_del(&t->link);
+       card->tlabel_mask &= ~(1ULL << t->tlabel);
+       spin_unlock_irqrestore(&card->lock, flags);
+
+       card->driver->cancel_packet(card, &t->packet);
+
+       /*
+        * At this point cancel_packet will never call the transaction
+        * callback, since we just took the transaction out of the list.
+        * So do it here.
+        */
+       t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data);
+}
+
 static void transmit_complete_callback(struct fw_packet *packet,
                                       struct fw_card *card, int status)
 {
@@ -229,6 +255,23 @@ static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
        packet->payload_mapped = false;
 }
 
+static int allocate_tlabel(struct fw_card *card)
+{
+       int tlabel;
+
+       tlabel = card->current_tlabel;
+       while (card->tlabel_mask & (1ULL << tlabel)) {
+               tlabel = (tlabel + 1) & 0x3f;
+               if (tlabel == card->current_tlabel)
+                       return -EBUSY;
+       }
+
+       card->current_tlabel = (tlabel + 1) & 0x3f;
+       card->tlabel_mask |= 1ULL << tlabel;
+
+       return tlabel;
+}
+
 /**
  * This function provides low-level access to the IEEE1394 transaction
  * logic.  Most C programs would use either fw_read(), fw_write() or
@@ -276,13 +319,6 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
        unsigned long flags;
        int tlabel;
 
-       /*
-        * Bump the flush timer up 100ms first of all so we
-        * don't race with a flush timer callback.
-        */
-
-       mod_timer(&card->flush_timer, jiffies + DIV_ROUND_UP(HZ, 10));
-
        /*
         * Allocate tlabel from the bitmap and put the transaction on
         * the list while holding the card spinlock.
@@ -290,18 +326,20 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
 
        spin_lock_irqsave(&card->lock, flags);
 
-       tlabel = card->current_tlabel;
-       if (card->tlabel_mask & (1ULL << tlabel)) {
+       tlabel = allocate_tlabel(card);
+       if (tlabel < 0) {
                spin_unlock_irqrestore(&card->lock, flags);
                callback(card, RCODE_SEND_ERROR, NULL, 0, callback_data);
                return;
        }
 
-       card->current_tlabel = (card->current_tlabel + 1) & 0x3f;
-       card->tlabel_mask |= (1ULL << tlabel);
-
        t->node_id = destination_id;
        t->tlabel = tlabel;
+       t->card = card;
+       setup_timer(&t->split_timeout_timer,
+                   split_transaction_timeout_callback, (unsigned long)t);
+       /* FIXME: start this timer later, relative to t->timestamp */
+       mod_timer(&t->split_timeout_timer, jiffies + DIV_ROUND_UP(HZ, 10));
        t->callback = callback;
        t->callback_data = callback_data;
 
@@ -347,11 +385,13 @@ int fw_run_transaction(struct fw_card *card, int tcode, int destination_id,
        struct transaction_callback_data d;
        struct fw_transaction t;
 
+       init_timer_on_stack(&t.split_timeout_timer);
        init_completion(&d.done);
        d.payload = payload;
        fw_send_request(card, &t, tcode, destination_id, generation, speed,
                        offset, payload, length, transaction_callback, &d);
        wait_for_completion(&d.done);
+       destroy_timer_on_stack(&t.split_timeout_timer);
 
        return d.rcode;
 }
@@ -394,30 +434,6 @@ void fw_send_phy_config(struct fw_card *card,
        mutex_unlock(&phy_config_mutex);
 }
 
-void fw_flush_transactions(struct fw_card *card)
-{
-       struct fw_transaction *t, *next;
-       struct list_head list;
-       unsigned long flags;
-
-       INIT_LIST_HEAD(&list);
-       spin_lock_irqsave(&card->lock, flags);
-       list_splice_init(&card->transaction_list, &list);
-       card->tlabel_mask = 0;
-       spin_unlock_irqrestore(&card->lock, flags);
-
-       list_for_each_entry_safe(t, next, &list, link) {
-               card->driver->cancel_packet(card, &t->packet);
-
-               /*
-                * At this point cancel_packet will never call the
-                * transaction callback, since we just took all the
-                * transactions out of the list.  So do it here.
-                */
-               t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data);
-       }
-}
-
 static struct fw_address_handler *lookup_overlapping_address_handler(
        struct list_head *list, unsigned long long offset, size_t length)
 {
@@ -827,8 +843,8 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
        spin_lock_irqsave(&card->lock, flags);
        list_for_each_entry(t, &card->transaction_list, link) {
                if (t->node_id == source && t->tlabel == tlabel) {
-                       list_del(&t->link);
-                       card->tlabel_mask &= ~(1 << t->tlabel);
+                       list_del_init(&t->link);
+                       card->tlabel_mask &= ~(1ULL << t->tlabel);
                        break;
                }
        }
@@ -869,6 +885,8 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
                break;
        }
 
+       del_timer_sync(&t->split_timeout_timer);
+
        /*
         * The response handler may be executed while the request handler
         * is still pending.  Cancel the request handler.
index fb0321300cce4a01b646e77a5f0d040c0f46f25d..0ecfcd95f4c500f62389aa4085c68281b648cc7c 100644 (file)
@@ -27,7 +27,12 @@ struct fw_packet;
 #define PHY_LINK_ACTIVE                0x80
 #define PHY_CONTENDER          0x40
 #define PHY_BUS_RESET          0x40
+#define PHY_EXTENDED_REGISTERS 0xe0
 #define PHY_BUS_SHORT_RESET    0x40
+#define PHY_INT_STATUS_BITS    0x3c
+#define PHY_ENABLE_ACCEL       0x02
+#define PHY_ENABLE_MULTI       0x01
+#define PHY_PAGE_SELECT                0xe0
 
 #define BANDWIDTH_AVAILABLE_INITIAL    4915
 #define BROADCAST_CHANNEL_INITIAL      (1 << 31 | 31)
@@ -215,7 +220,6 @@ void fw_core_handle_request(struct fw_card *card, struct fw_packet *request);
 void fw_core_handle_response(struct fw_card *card, struct fw_packet *packet);
 void fw_fill_response(struct fw_packet *response, u32 *request_header,
                      int rcode, void *payload, size_t length);
-void fw_flush_transactions(struct fw_card *card);
 void fw_send_phy_config(struct fw_card *card,
                        int node_id, int generation, int gap_count);
 
index a3b083a7403a20049746c69bd4ad2d716157ef55..9f627e758cfc503eb6a56b51c4f0fdd413ef4b32 100644 (file)
@@ -236,13 +236,15 @@ static char ohci_driver_name[] = KBUILD_MODNAME;
 #define QUIRK_CYCLE_TIMER              1
 #define QUIRK_RESET_PACKET             2
 #define QUIRK_BE_HEADERS               4
+#define QUIRK_NO_1394A                 8
 
 /* In case of multiple matches in ohci_quirks[], only the first one is used. */
 static const struct {
        unsigned short vendor, device, flags;
 } ohci_quirks[] = {
        {PCI_VENDOR_ID_TI,      PCI_DEVICE_ID_TI_TSB12LV22, QUIRK_CYCLE_TIMER |
-                                                           QUIRK_RESET_PACKET},
+                                                           QUIRK_RESET_PACKET |
+                                                           QUIRK_NO_1394A},
        {PCI_VENDOR_ID_TI,      PCI_ANY_ID,     QUIRK_RESET_PACKET},
        {PCI_VENDOR_ID_AL,      PCI_ANY_ID,     QUIRK_CYCLE_TIMER},
        {PCI_VENDOR_ID_NEC,     PCI_ANY_ID,     QUIRK_CYCLE_TIMER},
@@ -257,15 +259,16 @@ MODULE_PARM_DESC(quirks, "Chip quirks (default = 0"
        ", nonatomic cycle timer = "    __stringify(QUIRK_CYCLE_TIMER)
        ", reset packet generation = "  __stringify(QUIRK_RESET_PACKET)
        ", AR/selfID endianess = "      __stringify(QUIRK_BE_HEADERS)
+       ", no 1394a enhancements = "    __stringify(QUIRK_NO_1394A)
        ")");
 
-#ifdef CONFIG_FIREWIRE_OHCI_DEBUG
-
 #define OHCI_PARAM_DEBUG_AT_AR         1
 #define OHCI_PARAM_DEBUG_SELFIDS       2
 #define OHCI_PARAM_DEBUG_IRQS          4
 #define OHCI_PARAM_DEBUG_BUSRESETS     8 /* only effective before chip init */
 
+#ifdef CONFIG_FIREWIRE_OHCI_DEBUG
+
 static int param_debug;
 module_param_named(debug, param_debug, int, 0644);
 MODULE_PARM_DESC(debug, "Verbose logging (default = 0"
@@ -438,9 +441,10 @@ static void log_ar_at_event(char dir, int speed, u32 *header, int evt)
 
 #else
 
-#define log_irqs(evt)
-#define log_selfids(node_id, generation, self_id_count, sid)
-#define log_ar_at_event(dir, speed, header, evt)
+#define param_debug 0
+static inline void log_irqs(u32 evt) {}
+static inline void log_selfids(int node_id, int generation, int self_id_count, u32 *s) {}
+static inline void log_ar_at_event(char dir, int speed, u32 *header, int evt) {}
 
 #endif /* CONFIG_FIREWIRE_OHCI_DEBUG */
 
@@ -460,27 +464,71 @@ static inline void flush_writes(const struct fw_ohci *ohci)
        reg_read(ohci, OHCI1394_Version);
 }
 
-static int ohci_update_phy_reg(struct fw_card *card, int addr,
-                              int clear_bits, int set_bits)
+static int read_phy_reg(struct fw_ohci *ohci, int addr)
 {
-       struct fw_ohci *ohci = fw_ohci(card);
-       u32 val, old;
+       u32 val;
+       int i;
 
        reg_write(ohci, OHCI1394_PhyControl, OHCI1394_PhyControl_Read(addr));
-       flush_writes(ohci);
-       msleep(2);
-       val = reg_read(ohci, OHCI1394_PhyControl);
-       if ((val & OHCI1394_PhyControl_ReadDone) == 0) {
-               fw_error("failed to set phy reg bits.\n");
-               return -EBUSY;
+       for (i = 0; i < 10; i++) {
+               val = reg_read(ohci, OHCI1394_PhyControl);
+               if (val & OHCI1394_PhyControl_ReadDone)
+                       return OHCI1394_PhyControl_ReadData(val);
+
+               msleep(1);
        }
+       fw_error("failed to read phy reg\n");
+
+       return -EBUSY;
+}
+
+static int write_phy_reg(const struct fw_ohci *ohci, int addr, u32 val)
+{
+       int i;
 
-       old = OHCI1394_PhyControl_ReadData(val);
-       old = (old & ~clear_bits) | set_bits;
        reg_write(ohci, OHCI1394_PhyControl,
-                 OHCI1394_PhyControl_Write(addr, old));
+                 OHCI1394_PhyControl_Write(addr, val));
+       for (i = 0; i < 100; i++) {
+               val = reg_read(ohci, OHCI1394_PhyControl);
+               if (!(val & OHCI1394_PhyControl_WritePending))
+                       return 0;
 
-       return 0;
+               msleep(1);
+       }
+       fw_error("failed to write phy reg\n");
+
+       return -EBUSY;
+}
+
+static int ohci_update_phy_reg(struct fw_card *card, int addr,
+                              int clear_bits, int set_bits)
+{
+       struct fw_ohci *ohci = fw_ohci(card);
+       int ret;
+
+       ret = read_phy_reg(ohci, addr);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * The interrupt status bits are cleared by writing a one bit.
+        * Avoid clearing them unless explicitly requested in set_bits.
+        */
+       if (addr == 5)
+               clear_bits |= PHY_INT_STATUS_BITS;
+
+       return write_phy_reg(ohci, addr, (ret & ~clear_bits) | set_bits);
+}
+
+static int read_paged_phy_reg(struct fw_ohci *ohci, int page, int addr)
+{
+       int ret;
+
+       ret = ohci_update_phy_reg(&ohci->card, 7, PHY_PAGE_SELECT, page << 5);
+       if (ret < 0)
+               return ret;
+
+       return read_phy_reg(ohci, addr);
 }
 
 static int ar_context_add_page(struct ar_context *ctx)
@@ -1495,13 +1543,64 @@ static void copy_config_rom(__be32 *dest, const __be32 *src, size_t length)
                memset(&dest[length], 0, CONFIG_ROM_SIZE - size);
 }
 
+static int configure_1394a_enhancements(struct fw_ohci *ohci)
+{
+       bool enable_1394a;
+       int ret, clear, set, offset;
+
+       /* Check if the driver should configure link and PHY. */
+       if (!(reg_read(ohci, OHCI1394_HCControlSet) &
+             OHCI1394_HCControl_programPhyEnable))
+               return 0;
+
+       /* Paranoia: check whether the PHY supports 1394a, too. */
+       enable_1394a = false;
+       ret = read_phy_reg(ohci, 2);
+       if (ret < 0)
+               return ret;
+       if ((ret & PHY_EXTENDED_REGISTERS) == PHY_EXTENDED_REGISTERS) {
+               ret = read_paged_phy_reg(ohci, 1, 8);
+               if (ret < 0)
+                       return ret;
+               if (ret >= 1)
+                       enable_1394a = true;
+       }
+
+       if (ohci->quirks & QUIRK_NO_1394A)
+               enable_1394a = false;
+
+       /* Configure PHY and link consistently. */
+       if (enable_1394a) {
+               clear = 0;
+               set = PHY_ENABLE_ACCEL | PHY_ENABLE_MULTI;
+       } else {
+               clear = PHY_ENABLE_ACCEL | PHY_ENABLE_MULTI;
+               set = 0;
+       }
+       ret = ohci_update_phy_reg(&ohci->card, 5, clear, set);
+       if (ret < 0)
+               return ret;
+
+       if (enable_1394a)
+               offset = OHCI1394_HCControlSet;
+       else
+               offset = OHCI1394_HCControlClear;
+       reg_write(ohci, offset, OHCI1394_HCControl_aPhyEnhanceEnable);
+
+       /* Clean up: configuration has been taken care of. */
+       reg_write(ohci, OHCI1394_HCControlClear,
+                 OHCI1394_HCControl_programPhyEnable);
+
+       return 0;
+}
+
 static int ohci_enable(struct fw_card *card,
                       const __be32 *config_rom, size_t length)
 {
        struct fw_ohci *ohci = fw_ohci(card);
        struct pci_dev *dev = to_pci_dev(card->device);
        u32 lps;
-       int i;
+       int i, ret;
 
        if (software_reset(ohci)) {
                fw_error("Failed to reset ohci card.\n");
@@ -1565,10 +1664,14 @@ static int ohci_enable(struct fw_card *card,
        if (param_debug & OHCI_PARAM_DEBUG_BUSRESETS)
                reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset);
 
+       ret = configure_1394a_enhancements(ohci);
+       if (ret < 0)
+               return ret;
+
        /* Activate link_on bit and contender bit in our self ID packets.*/
-       if (ohci_update_phy_reg(card, 4, 0,
-                               PHY_LINK_ACTIVE | PHY_CONTENDER) < 0)
-               return -EIO;
+       ret = ohci_update_phy_reg(card, 4, 0, PHY_LINK_ACTIVE | PHY_CONTENDER);
+       if (ret < 0)
+               return ret;
 
        /*
         * When the link is not yet enabled, the atomic config rom
@@ -2304,7 +2407,7 @@ static const struct fw_card_driver ohci_driver = {
 };
 
 #ifdef CONFIG_PPC_PMAC
-static void ohci_pmac_on(struct pci_dev *dev)
+static void pmac_ohci_on(struct pci_dev *dev)
 {
        if (machine_is(powermac)) {
                struct device_node *ofn = pci_device_to_OF_node(dev);
@@ -2316,7 +2419,7 @@ static void ohci_pmac_on(struct pci_dev *dev)
        }
 }
 
-static void ohci_pmac_off(struct pci_dev *dev)
+static void pmac_ohci_off(struct pci_dev *dev)
 {
        if (machine_is(powermac)) {
                struct device_node *ofn = pci_device_to_OF_node(dev);
@@ -2328,15 +2431,15 @@ static void ohci_pmac_off(struct pci_dev *dev)
        }
 }
 #else
-#define ohci_pmac_on(dev)
-#define ohci_pmac_off(dev)
+static inline void pmac_ohci_on(struct pci_dev *dev) {}
+static inline void pmac_ohci_off(struct pci_dev *dev) {}
 #endif /* CONFIG_PPC_PMAC */
 
 static int __devinit pci_probe(struct pci_dev *dev,
                               const struct pci_device_id *ent)
 {
        struct fw_ohci *ohci;
-       u32 bus_options, max_receive, link_speed, version;
+       u32 bus_options, max_receive, link_speed, version, link_enh;
        u64 guid;
        int i, err, n_ir, n_it;
        size_t size;
@@ -2349,7 +2452,7 @@ static int __devinit pci_probe(struct pci_dev *dev,
 
        fw_card_initialize(&ohci->card, &ohci_driver, &dev->dev);
 
-       ohci_pmac_on(dev);
+       pmac_ohci_on(dev);
 
        err = pci_enable_device(dev);
        if (err) {
@@ -2389,6 +2492,23 @@ static int __devinit pci_probe(struct pci_dev *dev,
        if (param_quirks)
                ohci->quirks = param_quirks;
 
+       /* TI OHCI-Lynx and compatible: set recommended configuration bits. */
+       if (dev->vendor == PCI_VENDOR_ID_TI) {
+               pci_read_config_dword(dev, PCI_CFG_TI_LinkEnh, &link_enh);
+
+               /* adjust latency of ATx FIFO: use 1.7 KB threshold */
+               link_enh &= ~TI_LinkEnh_atx_thresh_mask;
+               link_enh |= TI_LinkEnh_atx_thresh_1_7K;
+
+               /* use priority arbitration for asynchronous responses */
+               link_enh |= TI_LinkEnh_enab_unfair;
+
+               /* required for aPhyEnhanceEnable to work */
+               link_enh |= TI_LinkEnh_enab_accel;
+
+               pci_write_config_dword(dev, PCI_CFG_TI_LinkEnh, link_enh);
+       }
+
        ar_context_init(&ohci->ar_request_ctx, ohci,
                        OHCI1394_AsReqRcvContextControlSet);
 
@@ -2466,7 +2586,7 @@ static int __devinit pci_probe(struct pci_dev *dev,
        pci_disable_device(dev);
  fail_free:
        kfree(&ohci->card);
-       ohci_pmac_off(dev);
+       pmac_ohci_off(dev);
  fail:
        if (err == -ENOMEM)
                fw_error("Out of memory\n");
@@ -2509,7 +2629,7 @@ static void pci_remove(struct pci_dev *dev)
        pci_release_region(dev, 0);
        pci_disable_device(dev);
        kfree(&ohci->card);
-       ohci_pmac_off(dev);
+       pmac_ohci_off(dev);
 
        fw_notify("Removed fw-ohci device.\n");
 }
@@ -2530,7 +2650,7 @@ static int pci_suspend(struct pci_dev *dev, pm_message_t state)
        err = pci_set_power_state(dev, pci_choose_state(dev, state));
        if (err)
                fw_error("pci_set_power_state failed with %d\n", err);
-       ohci_pmac_off(dev);
+       pmac_ohci_off(dev);
 
        return 0;
 }
@@ -2540,7 +2660,7 @@ static int pci_resume(struct pci_dev *dev)
        struct fw_ohci *ohci = pci_get_drvdata(dev);
        int err;
 
-       ohci_pmac_on(dev);
+       pmac_ohci_on(dev);
        pci_set_power_state(dev, PCI_D0);
        pci_restore_state(dev);
        err = pci_enable_device(dev);
index ba492d85c516260c33339c953296408e23437e16..3bc9a5d744ebf2eb8a48d93db7f4a179c361d978 100644 (file)
@@ -67,7 +67,7 @@
 #define   OHCI1394_PhyControl_ReadDone         0x80000000
 #define   OHCI1394_PhyControl_ReadData(r)      (((r) & 0x00ff0000) >> 16)
 #define   OHCI1394_PhyControl_Write(addr, data)        (((addr) << 8) | (data) | 0x00004000)
-#define   OHCI1394_PhyControl_WriteDone                0x00004000
+#define   OHCI1394_PhyControl_WritePending     0x00004000
 #define OHCI1394_IsochronousCycleTimer        0x0F0
 #define OHCI1394_AsReqFilterHiSet             0x100
 #define OHCI1394_AsReqFilterHiClear           0x104
 
 #define OHCI1394_phy_tcode             0xe
 
+/* TI extensions */
+
+#define PCI_CFG_TI_LinkEnh             0xf4
+#define  TI_LinkEnh_enab_accel         0x00000002
+#define  TI_LinkEnh_enab_unfair                0x00000080
+#define  TI_LinkEnh_atx_thresh_mask    0x00003000
+#define  TI_LinkEnh_atx_thresh_1_7K    0x00001000
+
 #endif /* _FIREWIRE_OHCI_H */
index fee678f74a191909723ef669187528015f313780..4fd0f276df5a5656d9b4d2970ce1f2e202f1de86 100644 (file)
@@ -139,6 +139,13 @@ config GPIO_MAX732X
          Board setup code must specify the model to use, and the start
          number for these GPIOs.
 
+config GPIO_MAX732X_IRQ
+       bool "Interrupt controller support for MAX732x"
+       depends on GPIO_MAX732X=y && GENERIC_HARDIRQS
+       help
+         Say yes here to enable the max732x to be used as an interrupt
+         controller. It requires the driver to be built in the kernel.
+
 config GPIO_PCA953X
        tristate "PCA953x, PCA955x, TCA64xx, and MAX7310 I/O ports"
        depends on I2C
@@ -264,10 +271,10 @@ config GPIO_BT8XX
          If unsure, say N.
 
 config GPIO_LANGWELL
-       bool "Intel Moorestown Platform Langwell GPIO support"
+       bool "Intel Langwell/Penwell GPIO support"
        depends on PCI
        help
-         Say Y here to support Intel Moorestown platform GPIO.
+         Say Y here to support Intel Langwell/Penwell GPIO.
 
 config GPIO_TIMBERDALE
        bool "Support for timberdale GPIO IP"
index 0c3c498f2260632124ecac5ffcc2f5f81773e0d2..f73a1555e49d7d92fad5da024c4face448a8e114 100644 (file)
@@ -197,7 +197,7 @@ static int chip_direction_output(struct gpio_chip *c, unsigned offset, int val)
        return 0;
 }
 
-static char *cs5535_gpio_names[] = {
+static const char * const cs5535_gpio_names[] = {
        "GPIO0", "GPIO1", "GPIO2", "GPIO3",
        "GPIO4", "GPIO5", "GPIO6", "GPIO7",
        "GPIO8", "GPIO9", "GPIO10", "GPIO11",
index cae1b8c5b08cbb7051b1e7ac67809cab5cb4e6bb..3ca36542e3385b0c62a33b703e637fac31884c93 100644 (file)
@@ -722,7 +722,7 @@ int gpio_export(unsigned gpio, bool direction_may_change)
        unsigned long           flags;
        struct gpio_desc        *desc;
        int                     status = -EINVAL;
-       char                    *ioname = NULL;
+       const char              *ioname = NULL;
 
        /* can't export until sysfs is available ... */
        if (!gpio_class.p) {
@@ -753,7 +753,7 @@ int gpio_export(unsigned gpio, bool direction_may_change)
                struct device   *dev;
 
                dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),
-                               desc, ioname ? ioname : "gpio%d", gpio);
+                               desc, ioname ? ioname : "gpio%u", gpio);
                if (!IS_ERR(dev)) {
                        status = sysfs_create_group(&dev->kobj,
                                                &gpio_attr_group);
@@ -1106,7 +1106,7 @@ unlock:
 fail:
        /* failures here can mean systems won't boot... */
        if (status)
-               pr_err("gpiochip_add: gpios %d..%d (%s) not registered\n",
+               pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n",
                        chip->base, chip->base + chip->ngpio - 1,
                        chip->label ? : "generic");
        return status;
@@ -1447,6 +1447,49 @@ fail:
 }
 EXPORT_SYMBOL_GPL(gpio_direction_output);
 
+/**
+ * gpio_set_debounce - sets @debounce time for a @gpio
+ * @gpio: the gpio to set debounce time
+ * @debounce: debounce time is microseconds
+ */
+int gpio_set_debounce(unsigned gpio, unsigned debounce)
+{
+       unsigned long           flags;
+       struct gpio_chip        *chip;
+       struct gpio_desc        *desc = &gpio_desc[gpio];
+       int                     status = -EINVAL;
+
+       spin_lock_irqsave(&gpio_lock, flags);
+
+       if (!gpio_is_valid(gpio))
+               goto fail;
+       chip = desc->chip;
+       if (!chip || !chip->set || !chip->set_debounce)
+               goto fail;
+       gpio -= chip->base;
+       if (gpio >= chip->ngpio)
+               goto fail;
+       status = gpio_ensure_requested(desc, gpio);
+       if (status < 0)
+               goto fail;
+
+       /* now we know the gpio is valid and chip won't vanish */
+
+       spin_unlock_irqrestore(&gpio_lock, flags);
+
+       might_sleep_if(extra_checks && chip->can_sleep);
+
+       return chip->set_debounce(chip, gpio, debounce);
+
+fail:
+       spin_unlock_irqrestore(&gpio_lock, flags);
+       if (status)
+               pr_debug("%s: gpio-%d status %d\n",
+                       __func__, gpio, status);
+
+       return status;
+}
+EXPORT_SYMBOL_GPL(gpio_set_debounce);
 
 /* I/O calls are only valid after configuration completed; the relevant
  * "is this a valid GPIO" error checks should already have been done.
index 41a9388f2fde03917455e77a9d18149ba3f292dc..48fc43c4bdd11fc2849a2273fcdf10e98267cc91 100644 (file)
@@ -217,7 +217,10 @@ gpiochip_add_err:
 static void __exit it8761e_gpio_exit(void)
 {
        if (gpio_ba) {
-               gpiochip_remove(&it8761e_gpio_chip);
+               int ret = gpiochip_remove(&it8761e_gpio_chip);
+
+               WARN(ret, "%s(): gpiochip_remove() failed, ret=%d\n",
+                               __func__, ret);
 
                release_region(gpio_ba, GPIO_IOSIZE);
                gpio_ba = 0;
index 00c3a14127af0059b08206fd49eabf07f8ed4cd9..8383a8d7f9945dee14f15fb6b4ba3c08a3885fe6 100644 (file)
@@ -17,6 +17,7 @@
 
 /* Supports:
  * Moorestown platform Langwell chip.
+ * Medfield platform Penwell chip.
  */
 
 #include <linux/module.h>
 #include <linux/gpio.h>
 #include <linux/slab.h>
 
-struct lnw_gpio_register {
-       u32     GPLR[2];
-       u32     GPDR[2];
-       u32     GPSR[2];
-       u32     GPCR[2];
-       u32     GRER[2];
-       u32     GFER[2];
-       u32     GEDR[2];
+/*
+ * Langwell chip has 64 pins and thus there are 2 32bit registers to control
+ * each feature, while Penwell chip has 96 pins for each block, and need 3 32bit
+ * registers to control them, so we only define the order here instead of a
+ * structure, to get a bit offset for a pin (use GPDR as an example):
+ *
+ * nreg = ngpio / 32;
+ * reg = offset / 32;
+ * bit = offset % 32;
+ * reg_addr = reg_base + GPDR * nreg * 4 + reg * 4;
+ *
+ * so the bit of reg_addr is to control pin offset's GPDR feature
+*/
+
+enum GPIO_REG {
+       GPLR = 0,       /* pin level read-only */
+       GPDR,           /* pin direction */
+       GPSR,           /* pin set */
+       GPCR,           /* pin clear */
+       GRER,           /* rising edge detect */
+       GFER,           /* falling edge detect */
+       GEDR,           /* edge detect result */
 };
 
 struct lnw_gpio {
        struct gpio_chip                chip;
-       struct lnw_gpio_register        *reg_base;
+       void                            *reg_base;
        spinlock_t                      lock;
        unsigned                        irq_base;
 };
 
-static int lnw_gpio_get(struct gpio_chip *chip, unsigned offset)
+static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset,
+                       enum GPIO_REG reg_type)
 {
        struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
+       unsigned nreg = chip->ngpio / 32;
        u8 reg = offset / 32;
-       void __iomem *gplr;
+       void __iomem *ptr;
+
+       ptr = (void __iomem *)(lnw->reg_base + reg_type * nreg * 4 + reg * 4);
+       return ptr;
+}
+
+static int lnw_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+       void __iomem *gplr = gpio_reg(chip, offset, GPLR);
 
-       gplr = (void __iomem *)(&lnw->reg_base->GPLR[reg]);
        return readl(gplr) & BIT(offset % 32);
 }
 
 static void lnw_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-       struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
-       u8 reg = offset / 32;
        void __iomem *gpsr, *gpcr;
 
        if (value) {
-               gpsr = (void __iomem *)(&lnw->reg_base->GPSR[reg]);
+               gpsr = gpio_reg(chip, offset, GPSR);
                writel(BIT(offset % 32), gpsr);
        } else {
-               gpcr = (void __iomem *)(&lnw->reg_base->GPCR[reg]);
+               gpcr = gpio_reg(chip, offset, GPCR);
                writel(BIT(offset % 32), gpcr);
        }
 }
@@ -76,12 +98,10 @@ static void lnw_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 static int lnw_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
        struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
-       u8 reg = offset / 32;
+       void __iomem *gpdr = gpio_reg(chip, offset, GPDR);
        u32 value;
        unsigned long flags;
-       void __iomem *gpdr;
 
-       gpdr = (void __iomem *)(&lnw->reg_base->GPDR[reg]);
        spin_lock_irqsave(&lnw->lock, flags);
        value = readl(gpdr);
        value &= ~BIT(offset % 32);
@@ -94,12 +114,10 @@ static int lnw_gpio_direction_output(struct gpio_chip *chip,
                        unsigned offset, int value)
 {
        struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
-       u8 reg = offset / 32;
+       void __iomem *gpdr = gpio_reg(chip, offset, GPDR);
        unsigned long flags;
-       void __iomem *gpdr;
 
        lnw_gpio_set(chip, offset, value);
-       gpdr = (void __iomem *)(&lnw->reg_base->GPDR[reg]);
        spin_lock_irqsave(&lnw->lock, flags);
        value = readl(gpdr);
        value |= BIT(offset % 32);;
@@ -118,11 +136,10 @@ static int lnw_irq_type(unsigned irq, unsigned type)
 {
        struct lnw_gpio *lnw = get_irq_chip_data(irq);
        u32 gpio = irq - lnw->irq_base;
-       u8 reg = gpio / 32;
        unsigned long flags;
        u32 value;
-       void __iomem *grer = (void __iomem *)(&lnw->reg_base->GRER[reg]);
-       void __iomem *gfer = (void __iomem *)(&lnw->reg_base->GFER[reg]);
+       void __iomem *grer = gpio_reg(&lnw->chip, gpio, GRER);
+       void __iomem *gfer = gpio_reg(&lnw->chip, gpio, GFER);
 
        if (gpio >= lnw->chip.ngpio)
                return -EINVAL;
@@ -158,8 +175,10 @@ static struct irq_chip lnw_irqchip = {
        .set_type       = lnw_irq_type,
 };
 
-static struct pci_device_id lnw_gpio_ids[] = {
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080f) },
+static DEFINE_PCI_DEVICE_TABLE(lnw_gpio_ids) = {   /* pin number */
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080f), .driver_data = 64 },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081f), .driver_data = 96 },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081a), .driver_data = 96 },
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, lnw_gpio_ids);
@@ -167,17 +186,17 @@ MODULE_DEVICE_TABLE(pci, lnw_gpio_ids);
 static void lnw_irq_handler(unsigned irq, struct irq_desc *desc)
 {
        struct lnw_gpio *lnw = (struct lnw_gpio *)get_irq_data(irq);
-       u32 reg, gpio;
+       u32 base, gpio;
        void __iomem *gedr;
        u32 gedr_v;
 
        /* check GPIO controller to check which pin triggered the interrupt */
-       for (reg = 0; reg < lnw->chip.ngpio / 32; reg++) {
-               gedr = (void __iomem *)(&lnw->reg_base->GEDR[reg]);
+       for (base = 0; base < lnw->chip.ngpio; base += 32) {
+               gedr = gpio_reg(&lnw->chip, base, GEDR);
                gedr_v = readl(gedr);
                if (!gedr_v)
                        continue;
-               for (gpio = reg*32; gpio < reg*32+32; gpio++)
+               for (gpio = base; gpio < base + 32; gpio++)
                        if (gedr_v & BIT(gpio % 32)) {
                                pr_debug("pin %d triggered\n", gpio);
                                generic_handle_irq(lnw->irq_base + gpio);
@@ -245,7 +264,7 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev,
        lnw->chip.set = lnw_gpio_set;
        lnw->chip.to_irq = lnw_gpio_to_irq;
        lnw->chip.base = gpio_base;
-       lnw->chip.ngpio = 64;
+       lnw->chip.ngpio = id->driver_data;
        lnw->chip.can_sleep = 0;
        pci_set_drvdata(pdev, lnw);
        retval = gpiochip_add(&lnw->chip);
index f7868243af899a46e69f3cb52064bb06d85bab86..9cad60f9e9620f249bf1c01f38346455476405bb 100644 (file)
@@ -17,7 +17,8 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/gpio.h>
-
+#include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/i2c.h>
 #include <linux/i2c/max732x.h>
 
@@ -31,7 +32,8 @@
  *   - Open Drain I/O
  *
  * designated by 'O', 'I' and 'P' individually according to MAXIM's
- * datasheets.
+ * datasheets. 'I' and 'P' ports are interrupt capables, some with
+ * a dedicated interrupt mask.
  *
  * There are two groups of I/O ports, each group usually includes
  * up to 8 I/O ports, and is accessed by a specific I2C address:
@@ -44,7 +46,8 @@
  *
  * Within each group of ports, there are five known combinations of
  * I/O ports: 4I4O, 4P4O, 8I, 8P, 8O, see the definitions below for
- * the detailed organization of these ports.
+ * the detailed organization of these ports. Only Goup A is interrupt
+ * capable.
  *
  * GPIO numbers start from 'gpio_base + 0' to 'gpio_base + 8/16',
  * and GPIOs from GROUP_A are numbered before those from GROUP_B
 #define GROUP_A(x)     ((x) & 0xffff)  /* I2C Addr: 0b'110xxxx */
 #define GROUP_B(x)     ((x) << 16)     /* I2C Addr: 0b'101xxxx */
 
+#define INT_NONE       0x0     /* No interrupt capability */
+#define INT_NO_MASK    0x1     /* Has interrupts, no mask */
+#define INT_INDEP_MASK 0x2     /* Has interrupts, independent mask */
+#define INT_MERGED_MASK 0x3    /* Has interrupts, merged mask */
+
+#define INT_CAPS(x)    (((uint64_t)(x)) << 32)
+
+enum {
+       MAX7319,
+       MAX7320,
+       MAX7321,
+       MAX7322,
+       MAX7323,
+       MAX7324,
+       MAX7325,
+       MAX7326,
+       MAX7327,
+};
+
+static uint64_t max732x_features[] = {
+       [MAX7319] = GROUP_A(IO_8I) | INT_CAPS(INT_MERGED_MASK),
+       [MAX7320] = GROUP_B(IO_8O),
+       [MAX7321] = GROUP_A(IO_8P) | INT_CAPS(INT_NO_MASK),
+       [MAX7322] = GROUP_A(IO_4I4O) | INT_CAPS(INT_MERGED_MASK),
+       [MAX7323] = GROUP_A(IO_4P4O) | INT_CAPS(INT_INDEP_MASK),
+       [MAX7324] = GROUP_A(IO_8I) | GROUP_B(IO_8O) | INT_CAPS(INT_MERGED_MASK),
+       [MAX7325] = GROUP_A(IO_8P) | GROUP_B(IO_8O) | INT_CAPS(INT_NO_MASK),
+       [MAX7326] = GROUP_A(IO_4I4O) | GROUP_B(IO_8O) | INT_CAPS(INT_MERGED_MASK),
+       [MAX7327] = GROUP_A(IO_4P4O) | GROUP_B(IO_8O) | INT_CAPS(INT_NO_MASK),
+};
+
 static const struct i2c_device_id max732x_id[] = {
-       { "max7319", GROUP_A(IO_8I) },
-       { "max7320", GROUP_B(IO_8O) },
-       { "max7321", GROUP_A(IO_8P) },
-       { "max7322", GROUP_A(IO_4I4O) },
-       { "max7323", GROUP_A(IO_4P4O) },
-       { "max7324", GROUP_A(IO_8I) | GROUP_B(IO_8O) },
-       { "max7325", GROUP_A(IO_8P) | GROUP_B(IO_8O) },
-       { "max7326", GROUP_A(IO_4I4O) | GROUP_B(IO_8O) },
-       { "max7327", GROUP_A(IO_4P4O) | GROUP_B(IO_8O) },
+       { "max7319", MAX7319 },
+       { "max7320", MAX7320 },
+       { "max7321", MAX7321 },
+       { "max7322", MAX7322 },
+       { "max7323", MAX7323 },
+       { "max7324", MAX7324 },
+       { "max7325", MAX7325 },
+       { "max7326", MAX7326 },
+       { "max7327", MAX7327 },
        { },
 };
 MODULE_DEVICE_TABLE(i2c, max732x_id);
@@ -96,9 +130,19 @@ struct max732x_chip {
 
        struct mutex    lock;
        uint8_t         reg_out[2];
+
+#ifdef CONFIG_GPIO_MAX732X_IRQ
+       struct mutex    irq_lock;
+       int             irq_base;
+       uint8_t         irq_mask;
+       uint8_t         irq_mask_cur;
+       uint8_t         irq_trig_raise;
+       uint8_t         irq_trig_fall;
+       uint8_t         irq_features;
+#endif
 };
 
-static int max732x_write(struct max732x_chip *chip, int group_a, uint8_t val)
+static int max732x_writeb(struct max732x_chip *chip, int group_a, uint8_t val)
 {
        struct i2c_client *client;
        int ret;
@@ -113,7 +157,7 @@ static int max732x_write(struct max732x_chip *chip, int group_a, uint8_t val)
        return 0;
 }
 
-static int max732x_read(struct max732x_chip *chip, int group_a, uint8_t *val)
+static int max732x_readb(struct max732x_chip *chip, int group_a, uint8_t *val)
 {
        struct i2c_client *client;
        int ret;
@@ -142,7 +186,7 @@ static int max732x_gpio_get_value(struct gpio_chip *gc, unsigned off)
 
        chip = container_of(gc, struct max732x_chip, gpio_chip);
 
-       ret = max732x_read(chip, is_group_a(chip, off), &reg_val);
+       ret = max732x_readb(chip, is_group_a(chip, off), &reg_val);
        if (ret < 0)
                return 0;
 
@@ -162,7 +206,7 @@ static void max732x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
        reg_out = (off > 7) ? chip->reg_out[1] : chip->reg_out[0];
        reg_out = (val) ? reg_out | mask : reg_out & ~mask;
 
-       ret = max732x_write(chip, is_group_a(chip, off), reg_out);
+       ret = max732x_writeb(chip, is_group_a(chip, off), reg_out);
        if (ret < 0)
                goto out;
 
@@ -188,6 +232,13 @@ static int max732x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
                return -EACCES;
        }
 
+       /*
+        * Open-drain pins must be set to high impedance (which is
+        * equivalent to output-high) to be turned into an input.
+        */
+       if ((mask & chip->dir_output))
+               max732x_gpio_set_value(gc, off, 1);
+
        return 0;
 }
 
@@ -209,12 +260,278 @@ static int max732x_gpio_direction_output(struct gpio_chip *gc,
        return 0;
 }
 
+#ifdef CONFIG_GPIO_MAX732X_IRQ
+static int max732x_writew(struct max732x_chip *chip, uint16_t val)
+{
+       int ret;
+
+       val = cpu_to_le16(val);
+
+       ret = i2c_master_send(chip->client_group_a, (char *)&val, 2);
+       if (ret < 0) {
+               dev_err(&chip->client_group_a->dev, "failed writing\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int max732x_readw(struct max732x_chip *chip, uint16_t *val)
+{
+       int ret;
+
+       ret = i2c_master_recv(chip->client_group_a, (char *)val, 2);
+       if (ret < 0) {
+               dev_err(&chip->client_group_a->dev, "failed reading\n");
+               return ret;
+       }
+
+       *val = le16_to_cpu(*val);
+       return 0;
+}
+
+static void max732x_irq_update_mask(struct max732x_chip *chip)
+{
+       uint16_t msg;
+
+       if (chip->irq_mask == chip->irq_mask_cur)
+               return;
+
+       chip->irq_mask = chip->irq_mask_cur;
+
+       if (chip->irq_features == INT_NO_MASK)
+               return;
+
+       mutex_lock(&chip->lock);
+
+       switch (chip->irq_features) {
+       case INT_INDEP_MASK:
+               msg = (chip->irq_mask << 8) | chip->reg_out[0];
+               max732x_writew(chip, msg);
+               break;
+
+       case INT_MERGED_MASK:
+               msg = chip->irq_mask | chip->reg_out[0];
+               max732x_writeb(chip, 1, (uint8_t)msg);
+               break;
+       }
+
+       mutex_unlock(&chip->lock);
+}
+
+static int max732x_gpio_to_irq(struct gpio_chip *gc, unsigned off)
+{
+       struct max732x_chip *chip;
+
+       chip = container_of(gc, struct max732x_chip, gpio_chip);
+       return chip->irq_base + off;
+}
+
+static void max732x_irq_mask(unsigned int irq)
+{
+       struct max732x_chip *chip = get_irq_chip_data(irq);
+
+       chip->irq_mask_cur &= ~(1 << (irq - chip->irq_base));
+}
+
+static void max732x_irq_unmask(unsigned int irq)
+{
+       struct max732x_chip *chip = get_irq_chip_data(irq);
+
+       chip->irq_mask_cur |= 1 << (irq - chip->irq_base);
+}
+
+static void max732x_irq_bus_lock(unsigned int irq)
+{
+       struct max732x_chip *chip = get_irq_chip_data(irq);
+
+       mutex_lock(&chip->irq_lock);
+       chip->irq_mask_cur = chip->irq_mask;
+}
+
+static void max732x_irq_bus_sync_unlock(unsigned int irq)
+{
+       struct max732x_chip *chip = get_irq_chip_data(irq);
+
+       max732x_irq_update_mask(chip);
+       mutex_unlock(&chip->irq_lock);
+}
+
+static int max732x_irq_set_type(unsigned int irq, unsigned int type)
+{
+       struct max732x_chip *chip = get_irq_chip_data(irq);
+       uint16_t off = irq - chip->irq_base;
+       uint16_t mask = 1 << off;
+
+       if (!(mask & chip->dir_input)) {
+               dev_dbg(&chip->client->dev, "%s port %d is output only\n",
+                       chip->client->name, off);
+               return -EACCES;
+       }
+
+       if (!(type & IRQ_TYPE_EDGE_BOTH)) {
+               dev_err(&chip->client->dev, "irq %d: unsupported type %d\n",
+                       irq, type);
+               return -EINVAL;
+       }
+
+       if (type & IRQ_TYPE_EDGE_FALLING)
+               chip->irq_trig_fall |= mask;
+       else
+               chip->irq_trig_fall &= ~mask;
+
+       if (type & IRQ_TYPE_EDGE_RISING)
+               chip->irq_trig_raise |= mask;
+       else
+               chip->irq_trig_raise &= ~mask;
+
+       return max732x_gpio_direction_input(&chip->gpio_chip, off);
+}
+
+static struct irq_chip max732x_irq_chip = {
+       .name                   = "max732x",
+       .mask                   = max732x_irq_mask,
+       .unmask                 = max732x_irq_unmask,
+       .bus_lock               = max732x_irq_bus_lock,
+       .bus_sync_unlock        = max732x_irq_bus_sync_unlock,
+       .set_type               = max732x_irq_set_type,
+};
+
+static uint8_t max732x_irq_pending(struct max732x_chip *chip)
+{
+       uint8_t cur_stat;
+       uint8_t old_stat;
+       uint8_t trigger;
+       uint8_t pending;
+       uint16_t status;
+       int ret;
+
+       ret = max732x_readw(chip, &status);
+       if (ret)
+               return 0;
+
+       trigger = status >> 8;
+       trigger &= chip->irq_mask;
+
+       if (!trigger)
+               return 0;
+
+       cur_stat = status & 0xFF;
+       cur_stat &= chip->irq_mask;
+
+       old_stat = cur_stat ^ trigger;
+
+       pending = (old_stat & chip->irq_trig_fall) |
+                 (cur_stat & chip->irq_trig_raise);
+       pending &= trigger;
+
+       return pending;
+}
+
+static irqreturn_t max732x_irq_handler(int irq, void *devid)
+{
+       struct max732x_chip *chip = devid;
+       uint8_t pending;
+       uint8_t level;
+
+       pending = max732x_irq_pending(chip);
+
+       if (!pending)
+               return IRQ_HANDLED;
+
+       do {
+               level = __ffs(pending);
+               handle_nested_irq(level + chip->irq_base);
+
+               pending &= ~(1 << level);
+       } while (pending);
+
+       return IRQ_HANDLED;
+}
+
+static int max732x_irq_setup(struct max732x_chip *chip,
+                            const struct i2c_device_id *id)
+{
+       struct i2c_client *client = chip->client;
+       struct max732x_platform_data *pdata = client->dev.platform_data;
+       int has_irq = max732x_features[id->driver_data] >> 32;
+       int ret;
+
+       if (pdata->irq_base && has_irq != INT_NONE) {
+               int lvl;
+
+               chip->irq_base = pdata->irq_base;
+               chip->irq_features = has_irq;
+               mutex_init(&chip->irq_lock);
+
+               for (lvl = 0; lvl < chip->gpio_chip.ngpio; lvl++) {
+                       int irq = lvl + chip->irq_base;
+
+                       if (!(chip->dir_input & (1 << lvl)))
+                               continue;
+
+                       set_irq_chip_data(irq, chip);
+                       set_irq_chip_and_handler(irq, &max732x_irq_chip,
+                                                handle_edge_irq);
+                       set_irq_nested_thread(irq, 1);
+#ifdef CONFIG_ARM
+                       set_irq_flags(irq, IRQF_VALID);
+#else
+                       set_irq_noprobe(irq);
+#endif
+               }
+
+               ret = request_threaded_irq(client->irq,
+                                          NULL,
+                                          max732x_irq_handler,
+                                          IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                                          dev_name(&client->dev), chip);
+               if (ret) {
+                       dev_err(&client->dev, "failed to request irq %d\n",
+                               client->irq);
+                       goto out_failed;
+               }
+
+               chip->gpio_chip.to_irq = max732x_gpio_to_irq;
+       }
+
+       return 0;
+
+out_failed:
+       chip->irq_base = 0;
+       return ret;
+}
+
+static void max732x_irq_teardown(struct max732x_chip *chip)
+{
+       if (chip->irq_base)
+               free_irq(chip->client->irq, chip);
+}
+#else /* CONFIG_GPIO_MAX732X_IRQ */
+static int max732x_irq_setup(struct max732x_chip *chip,
+                            const struct i2c_device_id *id)
+{
+       struct i2c_client *client = chip->client;
+       struct max732x_platform_data *pdata = client->dev.platform_data;
+       int has_irq = max732x_features[id->driver_data] >> 32;
+
+       if (pdata->irq_base && has_irq != INT_NONE)
+               dev_warn(&client->dev, "interrupt support not compiled in\n");
+
+       return 0;
+}
+
+static void max732x_irq_teardown(struct max732x_chip *chip)
+{
+}
+#endif
+
 static int __devinit max732x_setup_gpio(struct max732x_chip *chip,
                                        const struct i2c_device_id *id,
                                        unsigned gpio_start)
 {
        struct gpio_chip *gc = &chip->gpio_chip;
-       uint32_t id_data = id->driver_data;
+       uint32_t id_data = (uint32_t)max732x_features[id->driver_data];
        int i, port = 0;
 
        for (i = 0; i < 16; i++, id_data >>= 2) {
@@ -285,14 +602,14 @@ static int __devinit max732x_probe(struct i2c_client *client,
        switch (client->addr & 0x70) {
        case 0x60:
                chip->client_group_a = client;
-               if (nr_port > 7) {
+               if (nr_port > 8) {
                        c = i2c_new_dummy(client->adapter, addr_b);
                        chip->client_group_b = chip->client_dummy = c;
                }
                break;
        case 0x50:
                chip->client_group_b = client;
-               if (nr_port > 7) {
+               if (nr_port > 8) {
                        c = i2c_new_dummy(client->adapter, addr_a);
                        chip->client_group_a = chip->client_dummy = c;
                }
@@ -306,9 +623,13 @@ static int __devinit max732x_probe(struct i2c_client *client,
 
        mutex_init(&chip->lock);
 
-       max732x_read(chip, is_group_a(chip, 0), &chip->reg_out[0]);
-       if (nr_port > 7)
-               max732x_read(chip, is_group_a(chip, 8), &chip->reg_out[1]);
+       max732x_readb(chip, is_group_a(chip, 0), &chip->reg_out[0]);
+       if (nr_port > 8)
+               max732x_readb(chip, is_group_a(chip, 8), &chip->reg_out[1]);
+
+       ret = max732x_irq_setup(chip, id);
+       if (ret)
+               goto out_failed;
 
        ret = gpiochip_add(&chip->gpio_chip);
        if (ret)
@@ -325,6 +646,7 @@ static int __devinit max732x_probe(struct i2c_client *client,
        return 0;
 
 out_failed:
+       max732x_irq_teardown(chip);
        kfree(chip);
        return ret;
 }
@@ -352,6 +674,8 @@ static int __devexit max732x_remove(struct i2c_client *client)
                return ret;
        }
 
+       max732x_irq_teardown(chip);
+
        /* unregister any dummy i2c_client */
        if (chip->client_dummy)
                i2c_unregister_device(chip->client_dummy);
index b827c976dc6214cec1d04256182c05861b345294..a2b12aa1f2b93920b55b255efbf60ad037a4c0d0 100644 (file)
@@ -73,7 +73,7 @@ struct pca953x_chip {
        struct i2c_client *client;
        struct pca953x_platform_data *dyn_pdata;
        struct gpio_chip gpio_chip;
-       char **names;
+       const char *const *names;
 };
 
 static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val)
@@ -449,7 +449,7 @@ pca953x_get_alt_pdata(struct i2c_client *client)
        struct device_node *node;
        const uint16_t *val;
 
-       node = dev_archdata_get_node(&client->dev.archdata);
+       node = client->dev.of_node;
        if (node == NULL)
                return NULL;
 
index 105701a1f05be48e87c9862a80a907437e03863d..ee568c8fcbd01db804dc071be08a1da4b5ee6e87 100644 (file)
@@ -164,7 +164,7 @@ static int pl061_irq_type(unsigned irq, unsigned trigger)
        unsigned long flags;
        u8 gpiois, gpioibe, gpioiev;
 
-       if (offset < 0 || offset > PL061_GPIO_NR)
+       if (offset < 0 || offset >= PL061_GPIO_NR)
                return -EINVAL;
 
        spin_lock_irqsave(&chip->irq_lock, flags);
index f569ae88ab384c60d09929aeebac1983d3fcf100..c1981861bbbdb418ab58f9c9400e6c41a9430216 100644 (file)
@@ -147,7 +147,10 @@ drm_edid_block_valid(u8 *raw_edid)
                csum += raw_edid[i];
        if (csum) {
                DRM_ERROR("EDID checksum is invalid, remainder is %d\n", csum);
-               goto bad;
+
+               /* allow CEA to slide through, switches mangle this */
+               if (raw_edid[0] != 0x02)
+                       goto bad;
        }
 
        /* per-block-type checks */
index 7e663a79829f6768dfbd9c517122032faca8bb5a..266b0ff441af37b75ee555360bdcd68ce1cd881f 100644 (file)
@@ -241,7 +241,8 @@ nouveau_connector_detect(struct drm_connector *connector)
        if (nv_encoder && nv_connector->native_mode) {
                unsigned status = connector_status_connected;
 
-#ifdef CONFIG_ACPI
+#if defined(CONFIG_ACPI_BUTTON) || \
+       (defined(CONFIG_ACPI_BUTTON_MODULE) && defined(MODULE))
                if (!nouveau_ignorelid && !acpi_lid_open())
                        status = connector_status_unknown;
 #endif
index 0616c96e4b67834f9de49511d85c93614e0bf9ea..704a25d04ac92c75a20fe4f019a808c91ccd7304 100644 (file)
@@ -253,7 +253,11 @@ nv40_graph_init(struct drm_device *dev)
 
        if (!dev_priv->engine.graph.ctxprog) {
                struct nouveau_grctx ctx = {};
-               uint32_t cp[256];
+               uint32_t *cp;
+
+               cp = kmalloc(sizeof(*cp) * 256, GFP_KERNEL);
+               if (!cp)
+                       return -ENOMEM;
 
                ctx.dev = dev;
                ctx.mode = NOUVEAU_GRCTX_PROG;
@@ -265,6 +269,8 @@ nv40_graph_init(struct drm_device *dev)
                nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
                for (i = 0; i < ctx.ctxprog_len; i++)
                        nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]);
+
+               kfree(cp);
        }
 
        /* No context present currently */
index 03dd6c41dc192f272f6499d3bfea03a4556e7db9..f3f2827017ef39603bae514432f875a51472eec1 100644 (file)
@@ -707,6 +707,7 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
                break;
        case ATOM_DCPLL:
        case ATOM_PPLL_INVALID:
+       default:
                pll = &rdev->clock.dcpll;
                break;
        }
index 66a37fb75839dc11262f291a8488796efb7e373d..669feb689bfcdc6df0f8536493c4defc5bd0e42a 100644 (file)
@@ -576,6 +576,7 @@ typedef int (*radeon_packet3_check_t)(struct radeon_cs_parser *p,
  */
 int radeon_agp_init(struct radeon_device *rdev);
 void radeon_agp_resume(struct radeon_device *rdev);
+void radeon_agp_suspend(struct radeon_device *rdev);
 void radeon_agp_fini(struct radeon_device *rdev);
 
 
index 28e473f1f56fd688c339c169be1a1cbf5f11aaad..f40dfb77f9b12cfa75c90c83ec608714f15ae423 100644 (file)
@@ -270,3 +270,8 @@ void radeon_agp_fini(struct radeon_device *rdev)
        }
 #endif
 }
+
+void radeon_agp_suspend(struct radeon_device *rdev)
+{
+       radeon_agp_fini(rdev);
+}
index 6e733fdc334991ce9828dfe40e482b2e2cb9b85b..24ea683f7cf53ec5bd2a2958a0a86d95a5185624 100644 (file)
@@ -680,10 +680,18 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct
        uint8_t dac;
        union atom_supported_devices *supported_devices;
        int i, j, max_device;
-       struct bios_connector bios_connectors[ATOM_MAX_SUPPORTED_DEVICE];
+       struct bios_connector *bios_connectors;
+       size_t bc_size = sizeof(*bios_connectors) * ATOM_MAX_SUPPORTED_DEVICE;
 
-       if (!atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset))
+       bios_connectors = kzalloc(bc_size, GFP_KERNEL);
+       if (!bios_connectors)
+               return false;
+
+       if (!atom_parse_data_header(ctx, index, &size, &frev, &crev,
+                                   &data_offset)) {
+               kfree(bios_connectors);
                return false;
+       }
 
        supported_devices =
            (union atom_supported_devices *)(ctx->bios + data_offset);
@@ -851,6 +859,7 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct
 
        radeon_link_encoder_connector(dev);
 
+       kfree(bios_connectors);
        return true;
 }
 
index a20b612ffe75caf03425db39ddea73b9e7219057..fdc3fdf78acb3b45dc025ae6598942d032b99bf8 100644 (file)
@@ -754,6 +754,8 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)
        /* evict remaining vram memory */
        radeon_bo_evict_vram(rdev);
 
+       radeon_agp_suspend(rdev);
+
        pci_save_state(dev->pdev);
        if (state.event == PM_EVENT_SUSPEND) {
                /* Shut down the device */
index cc5316dcf5802e602567ab21c52f688e322a4bea..b3ba44c0a81801a9f528edf833be726a05a55c40 100644 (file)
@@ -900,9 +900,10 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev,
                        flags |= RADEON_FRONT;
        }
        if (flags & (RADEON_DEPTH|RADEON_STENCIL)) {
-               if (!dev_priv->have_z_offset)
+               if (!dev_priv->have_z_offset) {
                        printk_once(KERN_ERR "radeon: illegal depth clear request. Buggy mesa detected - please update.\n");
-               flags &= ~(RADEON_DEPTH | RADEON_STENCIL);
+                       flags &= ~(RADEON_DEPTH | RADEON_STENCIL);
+               }
        }
 
        if (flags & (RADEON_FRONT | RADEON_BACK)) {
index 76ba59b9fea1bd37595c3e3a7cfc30a2c8e8a06c..132278fa624042e84e1f44ff947808c0b7df79ac 100644 (file)
@@ -347,6 +347,14 @@ config HID_QUANTA
        ---help---
        Support for Quanta Optical Touch dual-touch panels.
 
+config HID_ROCCAT
+       tristate "Roccat special event support"
+       depends on USB_HID
+       ---help---
+       Support for Roccat special events.
+       Say Y here if you have a Roccat mouse or keyboard and want OSD or
+       macro execution support.
+
 config HID_ROCCAT_KONE
        tristate "Roccat Kone Mouse support"
        depends on USB_HID
index 22e47eaeea322ffd4e64c329e0e7be6139e9321b..987fa062736708ee99ed5181c5c5d26302231a7f 100644 (file)
@@ -48,6 +48,7 @@ obj-$(CONFIG_HID_QUANTA)      += hid-quanta.o
 obj-$(CONFIG_HID_PANTHERLORD)  += hid-pl.o
 obj-$(CONFIG_HID_PETALYNX)     += hid-petalynx.o
 obj-$(CONFIG_HID_PICOLCD)      += hid-picolcd.o
+obj-$(CONFIG_HID_ROCCAT)       += hid-roccat.o
 obj-$(CONFIG_HID_ROCCAT_KONE)  += hid-roccat-kone.o
 obj-$(CONFIG_HID_SAMSUNG)      += hid-samsung.o
 obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o
index e10e314d38cc8e620e2bc75ee3a3a3899d0e837b..aa0f7dcabcd78bcbee6c019d680d93cf9e400ad0 100644 (file)
@@ -1301,6 +1301,7 @@ static const struct hid_device_id hid_blacklist[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0012) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) },
index 56f314fbd4f9e337027fe9f890171fa026e2ece2..c94026768570b7b03f976882b4bbf7044637943b 100644 (file)
@@ -811,7 +811,7 @@ static const char *relatives[REL_MAX + 1] = {
        [REL_WHEEL] = "Wheel",          [REL_MISC] = "Misc",
 };
 
-static const char *absolutes[ABS_MAX + 1] = {
+static const char *absolutes[ABS_CNT] = {
        [ABS_X] = "X",                  [ABS_Y] = "Y",
        [ABS_Z] = "Z",                  [ABS_RX] = "Rx",
        [ABS_RY] = "Ry",                [ABS_RZ] = "Rz",
index 62416e6baecaf7611e9d536e64ac84e5d98bbad9..3975e039c3ddbedfb4e7246b3b00004ba8c70ddd 100644 (file)
@@ -73,6 +73,7 @@ static int gyration_event(struct hid_device *hdev, struct hid_field *field,
 static const struct hid_device_id gyration_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) },
        { }
 };
 MODULE_DEVICE_TABLE(hid, gyration_devices);
index 9776896cc4fc2eab0f654ffaa7ec96593c89d8ea..6af77ed0b555b595792af1c355ec2d1992559858 100644 (file)
 #define USB_VENDOR_ID_GYRATION         0x0c16
 #define USB_DEVICE_ID_GYRATION_REMOTE  0x0002
 #define USB_DEVICE_ID_GYRATION_REMOTE_2 0x0003
+#define USB_DEVICE_ID_GYRATION_REMOTE_3 0x0008
 
 #define USB_VENDOR_ID_HAPP             0x078b
 #define USB_DEVICE_ID_UGCI_DRIVING     0x0010
index 66e694054ba270c90fef0cb7a98a5c1f69c7ec2d..17f2dc04f883d0eb9462444a816d50ebf9b50b41 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include "hid-ids.h"
+#include "hid-roccat.h"
 #include "hid-roccat-kone.h"
 
 static void kone_set_settings_checksum(struct kone_settings *settings)
@@ -263,7 +264,7 @@ static int kone_get_firmware_version(struct usb_device *usb_dev, int *result)
        return 0;
 }
 
-static ssize_t kone_sysfs_read_settings(struct kobject *kobj,
+static ssize_t kone_sysfs_read_settings(struct file *fp, struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t off, size_t count) {
        struct device *dev = container_of(kobj, struct device, kobj);
@@ -287,7 +288,7 @@ static ssize_t kone_sysfs_read_settings(struct kobject *kobj,
  * This function keeps values in kone_device up to date and assumes that in
  * case of error the old data is still valid
  */
-static ssize_t kone_sysfs_write_settings(struct kobject *kobj,
+static ssize_t kone_sysfs_write_settings(struct file *fp, struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t off, size_t count) {
        struct device *dev = container_of(kobj, struct device, kobj);
@@ -342,31 +343,31 @@ static ssize_t kone_sysfs_read_profilex(struct kobject *kobj,
        return count;
 }
 
-static ssize_t kone_sysfs_read_profile1(struct kobject *kobj,
+static ssize_t kone_sysfs_read_profile1(struct file *fp, struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t off, size_t count) {
        return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 1);
 }
 
-static ssize_t kone_sysfs_read_profile2(struct kobject *kobj,
+static ssize_t kone_sysfs_read_profile2(struct file *fp, struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t off, size_t count) {
        return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 2);
 }
 
-static ssize_t kone_sysfs_read_profile3(struct kobject *kobj,
+static ssize_t kone_sysfs_read_profile3(struct file *fp, struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t off, size_t count) {
        return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 3);
 }
 
-static ssize_t kone_sysfs_read_profile4(struct kobject *kobj,
+static ssize_t kone_sysfs_read_profile4(struct file *fp, struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t off, size_t count) {
        return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 4);
 }
 
-static ssize_t kone_sysfs_read_profile5(struct kobject *kobj,
+static ssize_t kone_sysfs_read_profile5(struct file *fp, struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t off, size_t count) {
        return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 5);
@@ -404,31 +405,31 @@ static ssize_t kone_sysfs_write_profilex(struct kobject *kobj,
        return sizeof(struct kone_profile);
 }
 
-static ssize_t kone_sysfs_write_profile1(struct kobject *kobj,
+static ssize_t kone_sysfs_write_profile1(struct file *fp, struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t off, size_t count) {
        return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 1);
 }
 
-static ssize_t kone_sysfs_write_profile2(struct kobject *kobj,
+static ssize_t kone_sysfs_write_profile2(struct file *fp, struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t off, size_t count) {
        return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 2);
 }
 
-static ssize_t kone_sysfs_write_profile3(struct kobject *kobj,
+static ssize_t kone_sysfs_write_profile3(struct file *fp, struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t off, size_t count) {
        return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 3);
 }
 
-static ssize_t kone_sysfs_write_profile4(struct kobject *kobj,
+static ssize_t kone_sysfs_write_profile4(struct file *fp, struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t off, size_t count) {
        return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 4);
 }
 
-static ssize_t kone_sysfs_write_profile5(struct kobject *kobj,
+static ssize_t kone_sysfs_write_profile5(struct file *fp, struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t off, size_t count) {
        return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 5);
@@ -849,6 +850,16 @@ static int kone_init_specials(struct hid_device *hdev)
                                        "couldn't init struct kone_device\n");
                        goto exit_free;
                }
+
+               retval = roccat_connect(hdev);
+               if (retval < 0) {
+                       dev_err(&hdev->dev, "couldn't init char dev\n");
+                       /* be tolerant about not getting chrdev */
+               } else {
+                       kone->roccat_claimed = 1;
+                       kone->chrdev_minor = retval;
+               }
+
                retval = kone_create_sysfs_attributes(intf);
                if (retval) {
                        dev_err(&hdev->dev, "cannot create sysfs files\n");
@@ -868,10 +879,14 @@ exit_free:
 static void kone_remove_specials(struct hid_device *hdev)
 {
        struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+       struct kone_device *kone;
 
        if (intf->cur_altsetting->desc.bInterfaceProtocol
                        == USB_INTERFACE_PROTOCOL_MOUSE) {
                kone_remove_sysfs_attributes(intf);
+               kone = hid_get_drvdata(hdev);
+               if (kone->roccat_claimed)
+                       roccat_disconnect(kone->chrdev_minor);
                kfree(hid_get_drvdata(hdev));
        }
 }
@@ -930,6 +945,37 @@ static void kone_keep_values_up_to_date(struct kone_device *kone,
        }
 }
 
+static void kone_report_to_chrdev(struct kone_device const *kone,
+               struct kone_mouse_event const *event)
+{
+       struct kone_roccat_report roccat_report;
+
+       switch (event->event) {
+       case kone_mouse_event_switch_profile:
+       case kone_mouse_event_switch_dpi:
+       case kone_mouse_event_osd_profile:
+       case kone_mouse_event_osd_dpi:
+               roccat_report.event = event->event;
+               roccat_report.value = event->value;
+               roccat_report.key = 0;
+               roccat_report_event(kone->chrdev_minor,
+                               (uint8_t *)&roccat_report,
+                               sizeof(struct kone_roccat_report));
+               break;
+       case kone_mouse_event_call_overlong_macro:
+               if (event->value == kone_keystroke_action_press) {
+                       roccat_report.event = kone_mouse_event_call_overlong_macro;
+                       roccat_report.value = kone->actual_profile;
+                       roccat_report.key = event->macro_key;
+                       roccat_report_event(kone->chrdev_minor,
+                                       (uint8_t *)&roccat_report,
+                                       sizeof(struct kone_roccat_report));
+               }
+               break;
+       }
+
+}
+
 /*
  * Is called for keyboard- and mousepart.
  * Only mousepart gets informations about special events in its extended event
@@ -958,6 +1004,9 @@ static int kone_raw_event(struct hid_device *hdev, struct hid_report *report,
 
        kone_keep_values_up_to_date(kone, event);
 
+       if (kone->roccat_claimed)
+               kone_report_to_chrdev(kone, event);
+
        return 0; /* always do further processing */
 }
 
index b413b10a7f8a853f611119af1e9f465f1f08d893..003e6f81c195d6ed1b1cb0cf2184a774db290481 100644 (file)
@@ -189,6 +189,12 @@ enum kone_commands {
        kone_command_firmware = 0xe5a
 };
 
+struct kone_roccat_report {
+       uint8_t event;
+       uint8_t value; /* holds dpi or profile value */
+       uint8_t key; /* macro key on overlong macro execution */
+};
+
 #pragma pack(pop)
 
 struct kone_device {
@@ -219,6 +225,9 @@ struct kone_device {
         * so it's read only once
         */
        int firmware_version;
+
+       int roccat_claimed;
+       int chrdev_minor;
 };
 
 #endif
diff --git a/drivers/hid/hid-roccat.c b/drivers/hid/hid-roccat.c
new file mode 100644 (file)
index 0000000..e05d48e
--- /dev/null
@@ -0,0 +1,428 @@
+/*
+ * Roccat driver for Linux
+ *
+ * Copyright (c) 2010 Stefan Achatz <erazor_de@users.sourceforge.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 the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+/*
+ * Module roccat is a char device used to report special events of roccat
+ * hardware to userland. These events include requests for on-screen-display of
+ * profile or dpi settings or requests for execution of macro sequences that are
+ * not stored in device. The information in these events depends on hid device
+ * implementation and contains data that is not available in a single hid event
+ * or else hidraw could have been used.
+ * It is inspired by hidraw, but uses only one circular buffer for all readers.
+ */
+
+#include <linux/cdev.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+
+#include "hid-roccat.h"
+
+#define ROCCAT_FIRST_MINOR 0
+#define ROCCAT_MAX_DEVICES 8
+
+/* should be a power of 2 for performance reason */
+#define ROCCAT_CBUF_SIZE 16
+
+struct roccat_report {
+       uint8_t *value;
+       int len;
+};
+
+struct roccat_device {
+       unsigned int minor;
+       int open;
+       int exist;
+       wait_queue_head_t wait;
+       struct device *dev;
+       struct hid_device *hid;
+       struct list_head readers;
+       /* protects modifications of readers list */
+       struct mutex readers_lock;
+
+       /*
+        * circular_buffer has one writer and multiple readers with their own
+        * read pointers
+        */
+       struct roccat_report cbuf[ROCCAT_CBUF_SIZE];
+       int cbuf_end;
+       struct mutex cbuf_lock;
+};
+
+struct roccat_reader {
+       struct list_head node;
+       struct roccat_device *device;
+       int cbuf_start;
+};
+
+static int roccat_major;
+static struct class *roccat_class;
+static struct cdev roccat_cdev;
+
+static struct roccat_device *devices[ROCCAT_MAX_DEVICES];
+/* protects modifications of devices array */
+static DEFINE_MUTEX(devices_lock);
+
+static ssize_t roccat_read(struct file *file, char __user *buffer,
+               size_t count, loff_t *ppos)
+{
+       struct roccat_reader *reader = file->private_data;
+       struct roccat_device *device = reader->device;
+       struct roccat_report *report;
+       ssize_t retval = 0, len;
+       DECLARE_WAITQUEUE(wait, current);
+
+       mutex_lock(&device->cbuf_lock);
+
+       /* no data? */
+       if (reader->cbuf_start == device->cbuf_end) {
+               add_wait_queue(&device->wait, &wait);
+               set_current_state(TASK_INTERRUPTIBLE);
+
+               /* wait for data */
+               while (reader->cbuf_start == device->cbuf_end) {
+                       if (file->f_flags & O_NONBLOCK) {
+                               retval = -EAGAIN;
+                               break;
+                       }
+                       if (signal_pending(current)) {
+                               retval = -ERESTARTSYS;
+                               break;
+                       }
+                       if (!device->exist) {
+                               retval = -EIO;
+                               break;
+                       }
+
+                       mutex_unlock(&device->cbuf_lock);
+                       schedule();
+                       mutex_lock(&device->cbuf_lock);
+                       set_current_state(TASK_INTERRUPTIBLE);
+               }
+
+               set_current_state(TASK_RUNNING);
+               remove_wait_queue(&device->wait, &wait);
+       }
+
+       /* here we either have data or a reason to return if retval is set */
+       if (retval)
+               goto exit_unlock;
+
+       report = &device->cbuf[reader->cbuf_start];
+       /*
+        * If report is larger than requested amount of data, rest of report
+        * is lost!
+        */
+       len = report->len > count ? count : report->len;
+
+       if (copy_to_user(buffer, report->value, len)) {
+               retval = -EFAULT;
+               goto exit_unlock;
+       }
+       retval += len;
+       reader->cbuf_start = (reader->cbuf_start + 1) % ROCCAT_CBUF_SIZE;
+
+exit_unlock:
+       mutex_unlock(&device->cbuf_lock);
+       return retval;
+}
+
+static unsigned int roccat_poll(struct file *file, poll_table *wait)
+{
+       struct roccat_reader *reader = file->private_data;
+       poll_wait(file, &reader->device->wait, wait);
+       if (reader->cbuf_start != reader->device->cbuf_end)
+               return POLLIN | POLLRDNORM;
+       if (!reader->device->exist)
+               return POLLERR | POLLHUP;
+       return 0;
+}
+
+static int roccat_open(struct inode *inode, struct file *file)
+{
+       unsigned int minor = iminor(inode);
+       struct roccat_reader *reader;
+       struct roccat_device *device;
+       int error = 0;
+
+       reader = kzalloc(sizeof(struct roccat_reader), GFP_KERNEL);
+       if (!reader)
+               return -ENOMEM;
+
+       mutex_lock(&devices_lock);
+
+       device = devices[minor];
+
+       mutex_lock(&device->readers_lock);
+
+       if (!device) {
+               printk(KERN_EMERG "roccat device with minor %d doesn't exist\n",
+                               minor);
+               error = -ENODEV;
+               goto exit_unlock;
+       }
+
+       if (!device->open++) {
+               /* power on device on adding first reader */
+               if (device->hid->ll_driver->power) {
+                       error = device->hid->ll_driver->power(device->hid,
+                                       PM_HINT_FULLON);
+                       if (error < 0) {
+                               --device->open;
+                               goto exit_unlock;
+                       }
+               }
+               error = device->hid->ll_driver->open(device->hid);
+               if (error < 0) {
+                       if (device->hid->ll_driver->power)
+                               device->hid->ll_driver->power(device->hid,
+                                               PM_HINT_NORMAL);
+                       --device->open;
+                       goto exit_unlock;
+               }
+       }
+
+       reader->device = device;
+       /* new reader doesn't get old events */
+       reader->cbuf_start = device->cbuf_end;
+
+       list_add_tail(&reader->node, &device->readers);
+       file->private_data = reader;
+
+exit_unlock:
+       mutex_unlock(&device->readers_lock);
+       mutex_unlock(&devices_lock);
+       return error;
+}
+
+static int roccat_release(struct inode *inode, struct file *file)
+{
+       unsigned int minor = iminor(inode);
+       struct roccat_reader *reader = file->private_data;
+       struct roccat_device *device;
+
+       mutex_lock(&devices_lock);
+
+       device = devices[minor];
+       if (!device) {
+               mutex_unlock(&devices_lock);
+               printk(KERN_EMERG "roccat device with minor %d doesn't exist\n",
+                               minor);
+               return -ENODEV;
+       }
+
+       mutex_lock(&device->readers_lock);
+       list_del(&reader->node);
+       mutex_unlock(&device->readers_lock);
+       kfree(reader);
+
+       if (!--device->open) {
+               /* removing last reader */
+               if (device->exist) {
+                       if (device->hid->ll_driver->power)
+                               device->hid->ll_driver->power(device->hid,
+                                               PM_HINT_NORMAL);
+                       device->hid->ll_driver->close(device->hid);
+               } else {
+                       kfree(device);
+               }
+       }
+
+       mutex_unlock(&devices_lock);
+
+       return 0;
+}
+
+/*
+ * roccat_report_event() - output data to readers
+ * @minor: minor device number returned by roccat_connect()
+ * @data: pointer to data
+ * @len: size of data
+ *
+ * Return value is zero on success, a negative error code on failure.
+ *
+ * This is called from interrupt handler.
+ */
+int roccat_report_event(int minor, u8 const *data, int len)
+{
+       struct roccat_device *device;
+       struct roccat_reader *reader;
+       struct roccat_report *report;
+       uint8_t *new_value;
+
+       new_value = kmemdup(data, len, GFP_ATOMIC);
+       if (!new_value)
+               return -ENOMEM;
+
+       device = devices[minor];
+
+       report = &device->cbuf[device->cbuf_end];
+
+       /* passing NULL is safe */
+       kfree(report->value);
+
+       report->value = new_value;
+       report->len = len;
+       device->cbuf_end = (device->cbuf_end + 1) % ROCCAT_CBUF_SIZE;
+
+       list_for_each_entry(reader, &device->readers, node) {
+               /*
+                * As we already inserted one element, the buffer can't be
+                * empty. If start and end are equal, buffer is full and we
+                * increase start, so that slow reader misses one event, but
+                * gets the newer ones in the right order.
+                */
+               if (reader->cbuf_start == device->cbuf_end)
+                       reader->cbuf_start = (reader->cbuf_start + 1) % ROCCAT_CBUF_SIZE;
+       }
+
+       wake_up_interruptible(&device->wait);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(roccat_report_event);
+
+/*
+ * roccat_connect() - create a char device for special event output
+ * @hid: the hid device the char device should be connected to.
+ *
+ * Return value is minor device number in Range [0, ROCCAT_MAX_DEVICES] on
+ * success, a negative error code on failure.
+ */
+int roccat_connect(struct hid_device *hid)
+{
+       unsigned int minor;
+       struct roccat_device *device;
+       int temp;
+
+       device = kzalloc(sizeof(struct roccat_device), GFP_KERNEL);
+       if (!device)
+               return -ENOMEM;
+
+       mutex_lock(&devices_lock);
+
+       for (minor = 0; minor < ROCCAT_MAX_DEVICES; ++minor) {
+               if (devices[minor])
+                       continue;
+               break;
+       }
+
+       if (minor < ROCCAT_MAX_DEVICES) {
+               devices[minor] = device;
+       } else {
+               mutex_unlock(&devices_lock);
+               kfree(device);
+               return -EINVAL;
+       }
+
+       device->dev = device_create(roccat_class, &hid->dev,
+                       MKDEV(roccat_major, minor), NULL,
+                       "%s%s%d", "roccat", hid->driver->name, minor);
+
+       if (IS_ERR(device->dev)) {
+               devices[minor] = NULL;
+               mutex_unlock(&devices_lock);
+               temp = PTR_ERR(device->dev);
+               kfree(device);
+               return temp;
+       }
+
+       mutex_unlock(&devices_lock);
+
+       init_waitqueue_head(&device->wait);
+       INIT_LIST_HEAD(&device->readers);
+       mutex_init(&device->readers_lock);
+       mutex_init(&device->cbuf_lock);
+       device->minor = minor;
+       device->hid = hid;
+       device->exist = 1;
+       device->cbuf_end = 0;
+
+       return minor;
+}
+EXPORT_SYMBOL_GPL(roccat_connect);
+
+/* roccat_disconnect() - remove char device from hid device
+ * @minor: the minor device number returned by roccat_connect()
+ */
+void roccat_disconnect(int minor)
+{
+       struct roccat_device *device;
+
+       mutex_lock(&devices_lock);
+       device = devices[minor];
+       devices[minor] = NULL;
+       mutex_unlock(&devices_lock);
+
+       device->exist = 0; /* TODO exist maybe not needed */
+
+       device_destroy(roccat_class, MKDEV(roccat_major, minor));
+
+       if (device->open) {
+               device->hid->ll_driver->close(device->hid);
+               wake_up_interruptible(&device->wait);
+       } else {
+               kfree(device);
+       }
+}
+EXPORT_SYMBOL_GPL(roccat_disconnect);
+
+static const struct file_operations roccat_ops = {
+       .owner = THIS_MODULE,
+       .read = roccat_read,
+       .poll = roccat_poll,
+       .open = roccat_open,
+       .release = roccat_release,
+};
+
+static int __init roccat_init(void)
+{
+       int retval;
+       dev_t dev_id;
+
+       retval = alloc_chrdev_region(&dev_id, ROCCAT_FIRST_MINOR,
+                       ROCCAT_MAX_DEVICES, "roccat");
+
+       roccat_major = MAJOR(dev_id);
+
+       if (retval < 0) {
+               printk(KERN_WARNING "roccat: can't get major number\n");
+               return retval;
+       }
+
+       roccat_class = class_create(THIS_MODULE, "roccat");
+       if (IS_ERR(roccat_class)) {
+               retval = PTR_ERR(roccat_class);
+               unregister_chrdev_region(dev_id, ROCCAT_MAX_DEVICES);
+               return retval;
+       }
+
+       cdev_init(&roccat_cdev, &roccat_ops);
+       cdev_add(&roccat_cdev, dev_id, ROCCAT_MAX_DEVICES);
+
+       return 0;
+}
+
+static void __exit roccat_exit(void)
+{
+       dev_t dev_id = MKDEV(roccat_major, 0);
+
+       cdev_del(&roccat_cdev);
+       class_destroy(roccat_class);
+       unregister_chrdev_region(dev_id, ROCCAT_MAX_DEVICES);
+}
+
+module_init(roccat_init);
+module_exit(roccat_exit);
+
+MODULE_AUTHOR("Stefan Achatz");
+MODULE_DESCRIPTION("USB Roccat char device");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hid/hid-roccat.h b/drivers/hid/hid-roccat.h
new file mode 100644 (file)
index 0000000..d8aae0c
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef __HID_ROCCAT_H
+#define __HID_ROCCAT_H
+
+/*
+ * Copyright (c) 2010 Stefan Achatz <erazor_de@users.sourceforge.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 the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/hid.h>
+#include <linux/types.h>
+
+#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);
+#else
+static inline int roccat_connect(struct hid_device *hid) { return -1; }
+static inline void roccat_disconnect(int minor) {}
+static inline int roccat_report_event(int minor, u8 const *data, int len)
+{
+       return 0;
+}
+#endif
+
+#endif
index 9be8e1754a0bafdc850e7af7ff0932e8b05e509b..e19cf8eb6ccfa10f2ed1414387922d16eebb24ac 100644 (file)
@@ -447,13 +447,14 @@ config SENSORS_IT87
          will be called it87.
 
 config SENSORS_LM63
-       tristate "National Semiconductor LM63"
+       tristate "National Semiconductor LM63 and LM64"
        depends on I2C
        help
-         If you say yes here you get support for the National Semiconductor
-         LM63 remote diode digital temperature sensor with integrated fan
-         control.  Such chips are found on the Tyan S4882 (Thunder K8QS Pro)
-         motherboard, among others.
+         If you say yes here you get support for the National
+         Semiconductor LM63 and LM64 remote diode digital temperature
+         sensors with integrated fan control.  Such chips are found
+         on the Tyan S4882 (Thunder K8QS Pro) motherboard, among
+         others.
 
          This driver can also be built as a module.  If so, the module
          will be called lm63.
@@ -492,7 +493,8 @@ config SENSORS_LM75
                - NXP's LM75A
                - ST Microelectronics STDS75
                - TelCom (now Microchip) TCN75
-               - Texas Instruments TMP100, TMP101, TMP75, TMP175, TMP275
+               - Texas Instruments TMP100, TMP101, TMP105, TMP75, TMP175,
+                 TMP275
 
          This driver supports driver model based binding through board
          specific I2C device tables.
@@ -749,6 +751,16 @@ config SENSORS_DME1737
          This driver can also be built as a module.  If so, the module
          will be called dme1737.
 
+config SENSORS_EMC1403
+       tristate "SMSC EMC1403 thermal sensor"
+       depends on I2C
+       help
+         If you say yes here you get support for the SMSC EMC1403
+         temperature monitoring chip.
+
+         Threshold values can be configured using sysfs.
+         Data from the different diodes are accessible via sysfs.
+
 config SENSORS_SMSC47M1
        tristate "SMSC LPC47M10x and compatibles"
        help
@@ -802,6 +814,15 @@ config SENSORS_ADS7828
          This driver can also be built as a module.  If so, the module
          will be called ads7828.
 
+config SENSORS_ADS7871
+       tristate "Texas Instruments ADS7871 A/D converter"
+       depends on SPI
+       help
+         If you say yes here you get support for TI ADS7871 & ADS7870
+
+         This driver can also be built as a module.  If so, the module
+         will be called ads7871.
+
 config SENSORS_AMC6821
        tristate "Texas Instruments AMC6821"
        depends on I2C  && EXPERIMENTAL
@@ -822,6 +843,16 @@ config SENSORS_THMC50
          This driver can also be built as a module.  If so, the module
          will be called thmc50.
 
+config SENSORS_TMP102
+       tristate "Texas Instruments TMP102"
+       depends on I2C && EXPERIMENTAL
+       help
+         If you say yes here you get support for Texas Instruments TMP102
+         sensor chips.
+
+         This driver can also be built as a module.  If so, the module
+         will be called tmp102.
+
 config SENSORS_TMP401
        tristate "Texas Instruments TMP401 and compatibles"
        depends on I2C && EXPERIMENTAL
index 4aa1a3d112ad99a3894a75a558b5d85049805f69..2138ceb1a71346f46bf9cb811affb5c598bdd518 100644 (file)
@@ -29,6 +29,7 @@ obj-$(CONFIG_SENSORS_ADM1029) += adm1029.o
 obj-$(CONFIG_SENSORS_ADM1031)  += adm1031.o
 obj-$(CONFIG_SENSORS_ADM9240)  += adm9240.o
 obj-$(CONFIG_SENSORS_ADS7828)  += ads7828.o
+obj-$(CONFIG_SENSORS_ADS7871)  += ads7871.o
 obj-$(CONFIG_SENSORS_ADT7411)  += adt7411.o
 obj-$(CONFIG_SENSORS_ADT7462)  += adt7462.o
 obj-$(CONFIG_SENSORS_ADT7470)  += adt7470.o
@@ -40,6 +41,7 @@ obj-$(CONFIG_SENSORS_ATXP1)   += atxp1.o
 obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
 obj-$(CONFIG_SENSORS_DME1737)  += dme1737.o
 obj-$(CONFIG_SENSORS_DS1621)   += ds1621.o
+obj-$(CONFIG_SENSORS_EMC1403)  += emc1403.o
 obj-$(CONFIG_SENSORS_F71805F)  += f71805f.o
 obj-$(CONFIG_SENSORS_F71882FG) += f71882fg.o
 obj-$(CONFIG_SENSORS_F75375S)  += f75375s.o
@@ -89,6 +91,7 @@ obj-$(CONFIG_SENSORS_SMSC47M1)        += smsc47m1.o
 obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
 obj-$(CONFIG_SENSORS_AMC6821)  += amc6821.o
 obj-$(CONFIG_SENSORS_THMC50)   += thmc50.o
+obj-$(CONFIG_SENSORS_TMP102)   += tmp102.o
 obj-$(CONFIG_SENSORS_TMP401)   += tmp401.o
 obj-$(CONFIG_SENSORS_TMP421)   += tmp421.o
 obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o
index 1644b92e7cc47ae8f8507d777cd1ecbe64612484..15c1a9616af33ba13ae8a79823cb7d30729c42fe 100644 (file)
@@ -36,6 +36,7 @@
 #define ADM1031_REG_FAN_DIV(nr)                (0x20 + (nr))
 #define ADM1031_REG_PWM                        (0x22)
 #define ADM1031_REG_FAN_MIN(nr)                (0x10 + (nr))
+#define ADM1031_REG_FAN_FILTER         (0x23)
 
 #define ADM1031_REG_TEMP_OFFSET(nr)    (0x0d + (nr))
 #define ADM1031_REG_TEMP_MAX(nr)       (0x14 + 4 * (nr))
@@ -61,6 +62,9 @@
 #define ADM1031_CONF2_TACH2_ENABLE     0x08
 #define ADM1031_CONF2_TEMP_ENABLE(chan)        (0x10 << (chan))
 
+#define ADM1031_UPDATE_RATE_MASK       0x1c
+#define ADM1031_UPDATE_RATE_SHIFT      2
+
 /* Addresses to scan */
 static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
 
@@ -75,6 +79,7 @@ struct adm1031_data {
        int chip_type;
        char valid;             /* !=0 if following fields are valid */
        unsigned long last_updated;     /* In jiffies */
+       unsigned int update_rate;       /* In milliseconds */
        /* The chan_select_table contains the possible configurations for
         * auto fan control.
         */
@@ -738,6 +743,57 @@ static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 12);
 static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 13);
 static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 14);
 
+/* Update Rate */
+static const unsigned int update_rates[] = {
+       16000, 8000, 4000, 2000, 1000, 500, 250, 125,
+};
+
+static ssize_t show_update_rate(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adm1031_data *data = i2c_get_clientdata(client);
+
+       return sprintf(buf, "%u\n", data->update_rate);
+}
+
+static ssize_t set_update_rate(struct device *dev,
+                              struct device_attribute *attr,
+                              const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adm1031_data *data = i2c_get_clientdata(client);
+       unsigned long val;
+       int i, err;
+       u8 reg;
+
+       err = strict_strtoul(buf, 10, &val);
+       if (err)
+               return err;
+
+       /* find the nearest update rate from the table */
+       for (i = 0; i < ARRAY_SIZE(update_rates) - 1; i++) {
+               if (val >= update_rates[i])
+                       break;
+       }
+       /* if not found, we point to the last entry (lowest update rate) */
+
+       /* set the new update rate while preserving other settings */
+       reg = adm1031_read_value(client, ADM1031_REG_FAN_FILTER);
+       reg &= ~ADM1031_UPDATE_RATE_MASK;
+       reg |= i << ADM1031_UPDATE_RATE_SHIFT;
+       adm1031_write_value(client, ADM1031_REG_FAN_FILTER, reg);
+
+       mutex_lock(&data->update_lock);
+       data->update_rate = update_rates[i];
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static DEVICE_ATTR(update_rate, S_IRUGO | S_IWUSR, show_update_rate,
+                  set_update_rate);
+
 static struct attribute *adm1031_attributes[] = {
        &sensor_dev_attr_fan1_input.dev_attr.attr,
        &sensor_dev_attr_fan1_div.dev_attr.attr,
@@ -774,6 +830,7 @@ static struct attribute *adm1031_attributes[] = {
 
        &sensor_dev_attr_auto_fan1_min_pwm.dev_attr.attr,
 
+       &dev_attr_update_rate.attr,
        &dev_attr_alarms.attr,
 
        NULL
@@ -900,6 +957,7 @@ static void adm1031_init_client(struct i2c_client *client)
 {
        unsigned int read_val;
        unsigned int mask;
+       int i;
        struct adm1031_data *data = i2c_get_clientdata(client);
 
        mask = (ADM1031_CONF2_PWM1_ENABLE | ADM1031_CONF2_TACH1_ENABLE);
@@ -919,18 +977,24 @@ static void adm1031_init_client(struct i2c_client *client)
                                ADM1031_CONF1_MONITOR_ENABLE);
        }
 
+       /* Read the chip's update rate */
+       mask = ADM1031_UPDATE_RATE_MASK;
+       read_val = adm1031_read_value(client, ADM1031_REG_FAN_FILTER);
+       i = (read_val & mask) >> ADM1031_UPDATE_RATE_SHIFT;
+       data->update_rate = update_rates[i];
 }
 
 static struct adm1031_data *adm1031_update_device(struct device *dev)
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct adm1031_data *data = i2c_get_clientdata(client);
+       unsigned long next_update;
        int chan;
 
        mutex_lock(&data->update_lock);
 
-       if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
-           || !data->valid) {
+       next_update = data->last_updated + msecs_to_jiffies(data->update_rate);
+       if (time_after(jiffies, next_update) || !data->valid) {
 
                dev_dbg(&client->dev, "Starting adm1031 update\n");
                for (chan = 0;
diff --git a/drivers/hwmon/ads7871.c b/drivers/hwmon/ads7871.c
new file mode 100644 (file)
index 0000000..b300a20
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ *  ads7871 - driver for TI ADS7871 A/D converter
+ *
+ *  Copyright (c) 2010 Paul Thomas <pthomas8589@gmail.com>
+ *
+ *  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.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 or
+ *  later as publishhed by the Free Software Foundation.
+ *
+ *     You need to have something like this in struct spi_board_info
+ *     {
+ *             .modalias       = "ads7871",
+ *             .max_speed_hz   = 2*1000*1000,
+ *             .chip_select    = 0,
+ *             .bus_num        = 1,
+ *     },
+ */
+
+/*From figure 18 in the datasheet*/
+/*Register addresses*/
+#define REG_LS_BYTE    0 /*A/D Output Data, LS Byte*/
+#define REG_MS_BYTE    1 /*A/D Output Data, MS Byte*/
+#define REG_PGA_VALID  2 /*PGA Valid Register*/
+#define REG_AD_CONTROL 3 /*A/D Control Register*/
+#define REG_GAIN_MUX   4 /*Gain/Mux Register*/
+#define REG_IO_STATE   5 /*Digital I/O State Register*/
+#define REG_IO_CONTROL 6 /*Digital I/O Control Register*/
+#define REG_OSC_CONTROL        7 /*Rev/Oscillator Control Register*/
+#define REG_SER_CONTROL 24 /*Serial Interface Control Register*/
+#define REG_ID         31 /*ID Register*/
+
+/*From figure 17 in the datasheet
+* These bits get ORed with the address to form
+* the instruction byte */
+/*Instruction Bit masks*/
+#define INST_MODE_bm   (1<<7)
+#define INST_READ_bm   (1<<6)
+#define INST_16BIT_bm  (1<<5)
+
+/*From figure 18 in the datasheet*/
+/*bit masks for Rev/Oscillator Control Register*/
+#define MUX_CNV_bv     7
+#define MUX_CNV_bm     (1<<MUX_CNV_bv)
+#define MUX_M3_bm      (1<<3) /*M3 selects single ended*/
+#define MUX_G_bv       4 /*allows for reg = (gain << MUX_G_bv) | ...*/
+
+/*From figure 18 in the datasheet*/
+/*bit masks for Rev/Oscillator Control Register*/
+#define OSC_OSCR_bm    (1<<5)
+#define OSC_OSCE_bm    (1<<4)
+#define OSC_REFE_bm    (1<<3)
+#define OSC_BUFE_bm    (1<<2)
+#define OSC_R2V_bm     (1<<1)
+#define OSC_RBG_bm     (1<<0)
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/spi/spi.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+
+#define DEVICE_NAME    "ads7871"
+
+struct ads7871_data {
+       struct device   *hwmon_dev;
+       struct mutex    update_lock;
+};
+
+static int ads7871_read_reg8(struct spi_device *spi, int reg)
+{
+       int ret;
+       reg = reg | INST_READ_bm;
+       ret = spi_w8r8(spi, reg);
+       return ret;
+}
+
+static int ads7871_read_reg16(struct spi_device *spi, int reg)
+{
+       int ret;
+       reg = reg | INST_READ_bm | INST_16BIT_bm;
+       ret = spi_w8r16(spi, reg);
+       return ret;
+}
+
+static int ads7871_write_reg8(struct spi_device *spi, int reg, u8 val)
+{
+       u8 tmp[2] = {reg, val};
+       return spi_write(spi, tmp, sizeof(tmp));
+}
+
+static ssize_t show_voltage(struct device *dev,
+               struct device_attribute *da, char *buf)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int ret, val, i = 0;
+       uint8_t channel, mux_cnv;
+
+       channel = attr->index;
+       /*TODO: add support for conversions
+        *other than single ended with a gain of 1*/
+       /*MUX_M3_bm forces single ended*/
+       /*This is also where the gain of the PGA would be set*/
+       ads7871_write_reg8(spi, REG_GAIN_MUX,
+               (MUX_CNV_bm | MUX_M3_bm | channel));
+
+       ret = ads7871_read_reg8(spi, REG_GAIN_MUX);
+       mux_cnv = ((ret & MUX_CNV_bm)>>MUX_CNV_bv);
+       /*on 400MHz arm9 platform the conversion
+        *is already done when we do this test*/
+       while ((i < 2) && mux_cnv) {
+               i++;
+               ret = ads7871_read_reg8(spi, REG_GAIN_MUX);
+               mux_cnv = ((ret & MUX_CNV_bm)>>MUX_CNV_bv);
+               msleep_interruptible(1);
+       }
+
+       if (mux_cnv == 0) {
+               val = ads7871_read_reg16(spi, REG_LS_BYTE);
+               /*result in volts*10000 = (val/8192)*2.5*10000*/
+               val = ((val>>2) * 25000) / 8192;
+               return sprintf(buf, "%d\n", val);
+       } else {
+               return -1;
+       }
+}
+
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_voltage, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_voltage, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_voltage, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_voltage, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_voltage, NULL, 4);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_voltage, NULL, 5);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_voltage, NULL, 6);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_voltage, NULL, 7);
+
+static struct attribute *ads7871_attributes[] = {
+       &sensor_dev_attr_in0_input.dev_attr.attr,
+       &sensor_dev_attr_in1_input.dev_attr.attr,
+       &sensor_dev_attr_in2_input.dev_attr.attr,
+       &sensor_dev_attr_in3_input.dev_attr.attr,
+       &sensor_dev_attr_in4_input.dev_attr.attr,
+       &sensor_dev_attr_in5_input.dev_attr.attr,
+       &sensor_dev_attr_in6_input.dev_attr.attr,
+       &sensor_dev_attr_in7_input.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group ads7871_group = {
+       .attrs = ads7871_attributes,
+};
+
+static int __devinit ads7871_probe(struct spi_device *spi)
+{
+       int status, ret, err = 0;
+       uint8_t val;
+       struct ads7871_data *pdata;
+
+       dev_dbg(&spi->dev, "probe\n");
+
+       pdata = kzalloc(sizeof(struct ads7871_data), GFP_KERNEL);
+       if (!pdata) {
+               err = -ENOMEM;
+               goto exit;
+       }
+
+       status = sysfs_create_group(&spi->dev.kobj, &ads7871_group);
+       if (status < 0)
+               goto error_free;
+
+       pdata->hwmon_dev = hwmon_device_register(&spi->dev);
+       if (IS_ERR(pdata->hwmon_dev)) {
+               err = PTR_ERR(pdata->hwmon_dev);
+               goto error_remove;
+       }
+
+       spi_set_drvdata(spi, pdata);
+
+       /* Configure the SPI bus */
+       spi->mode = (SPI_MODE_0);
+       spi->bits_per_word = 8;
+       spi_setup(spi);
+
+       ads7871_write_reg8(spi, REG_SER_CONTROL, 0);
+       ads7871_write_reg8(spi, REG_AD_CONTROL, 0);
+
+       val = (OSC_OSCR_bm | OSC_OSCE_bm | OSC_REFE_bm | OSC_BUFE_bm);
+       ads7871_write_reg8(spi, REG_OSC_CONTROL, val);
+       ret = ads7871_read_reg8(spi, REG_OSC_CONTROL);
+
+       dev_dbg(&spi->dev, "REG_OSC_CONTROL write:%x, read:%x\n", val, ret);
+       /*because there is no other error checking on an SPI bus
+       we need to make sure we really have a chip*/
+       if (val != ret) {
+               err = -ENODEV;
+               goto error_remove;
+       }
+
+       return 0;
+
+error_remove:
+       sysfs_remove_group(&spi->dev.kobj, &ads7871_group);
+error_free:
+       kfree(pdata);
+exit:
+       return err;
+}
+
+static int __devexit ads7871_remove(struct spi_device *spi)
+{
+       struct ads7871_data *pdata = spi_get_drvdata(spi);
+
+       hwmon_device_unregister(pdata->hwmon_dev);
+       sysfs_remove_group(&spi->dev.kobj, &ads7871_group);
+       kfree(pdata);
+       return 0;
+}
+
+static struct spi_driver ads7871_driver = {
+       .driver = {
+               .name = DEVICE_NAME,
+               .bus = &spi_bus_type,
+               .owner = THIS_MODULE,
+       },
+
+       .probe = ads7871_probe,
+       .remove = __devexit_p(ads7871_remove),
+};
+
+static int __init ads7871_init(void)
+{
+       return spi_register_driver(&ads7871_driver);
+}
+
+static void __exit ads7871_exit(void)
+{
+       spi_unregister_driver(&ads7871_driver);
+}
+
+module_init(ads7871_init);
+module_exit(ads7871_exit);
+
+MODULE_AUTHOR("Paul Thomas <pthomas8589@gmail.com>");
+MODULE_DESCRIPTION("TI ADS7871 A/D driver");
+MODULE_LICENSE("GPL");
index f085c18d2905a602d465ef01a8d08b2a29467c28..b6598aa557a0dcfe56fb87902319dff2394b6934 100644 (file)
@@ -148,6 +148,20 @@ static const char *temperature_sensors_sets[][41] = {
 /* Set 18: MacBook Pro 2,2 */
        { "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "TM0P", "TTF0",
          "Th0H", "Th1H", "Tm0P", "Ts0P", NULL },
+/* Set 19: Macbook Pro 5,3 */
+       { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0F", "TC0P", "TG0D",
+         "TG0F", "TG0H", "TG0P", "TG0T", "TN0D", "TN0P", "TTF0", "Th2H",
+         "Tm0P", "Ts0P", "Ts0S", NULL },
+/* Set 20: MacBook Pro 5,4 */
+       { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0F", "TC0P", "TN0D",
+         "TN0P", "TTF0", "Th2H", "Ts0P", "Ts0S", NULL },
+/* Set 21: MacBook Pro 6,2 */
+       { "TB0T", "TB1T", "TB2T", "TC0C", "TC0D", "TC0P", "TC1C", "TG0D",
+         "TG0P", "TG0T", "TMCD", "TP0P", "TPCD", "Th1H", "Th2H", "Tm0P",
+         "Ts0P", "Ts0S", NULL },
+/* Set 22: MacBook Pro 7,1 */
+       { "TB0T", "TB1T", "TB2T", "TC0D", "TC0P", "TN0D", "TN0P", "TN0S",
+         "TN1D", "TN1F", "TN1G", "TN1S", "Th1H", "Ts0P", "Ts0S", NULL },
 };
 
 /* List of keys used to read/write fan speeds */
@@ -646,6 +660,17 @@ out:
                return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", left, right);
 }
 
+/* Displays sensor key as label */
+static ssize_t applesmc_show_sensor_label(struct device *dev,
+                       struct device_attribute *devattr, char *sysfsbuf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       const char *key =
+               temperature_sensors_sets[applesmc_temperature_set][attr->index];
+
+       return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", key);
+}
+
 /* Displays degree Celsius * 1000 */
 static ssize_t applesmc_show_temperature(struct device *dev,
                        struct device_attribute *devattr, char *sysfsbuf)
@@ -1113,6 +1138,86 @@ static const struct attribute_group fan_attribute_groups[] = {
 /*
  * Temperature sensors sysfs entries.
  */
+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp6_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp7_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp8_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp9_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 8);
+static SENSOR_DEVICE_ATTR(temp10_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 9);
+static SENSOR_DEVICE_ATTR(temp11_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 10);
+static SENSOR_DEVICE_ATTR(temp12_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp13_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 12);
+static SENSOR_DEVICE_ATTR(temp14_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 13);
+static SENSOR_DEVICE_ATTR(temp15_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 14);
+static SENSOR_DEVICE_ATTR(temp16_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 15);
+static SENSOR_DEVICE_ATTR(temp17_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 16);
+static SENSOR_DEVICE_ATTR(temp18_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 17);
+static SENSOR_DEVICE_ATTR(temp19_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 18);
+static SENSOR_DEVICE_ATTR(temp20_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 19);
+static SENSOR_DEVICE_ATTR(temp21_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 20);
+static SENSOR_DEVICE_ATTR(temp22_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 21);
+static SENSOR_DEVICE_ATTR(temp23_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 22);
+static SENSOR_DEVICE_ATTR(temp24_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 23);
+static SENSOR_DEVICE_ATTR(temp25_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 24);
+static SENSOR_DEVICE_ATTR(temp26_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 25);
+static SENSOR_DEVICE_ATTR(temp27_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 26);
+static SENSOR_DEVICE_ATTR(temp28_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 27);
+static SENSOR_DEVICE_ATTR(temp29_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 28);
+static SENSOR_DEVICE_ATTR(temp30_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 29);
+static SENSOR_DEVICE_ATTR(temp31_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 30);
+static SENSOR_DEVICE_ATTR(temp32_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 31);
+static SENSOR_DEVICE_ATTR(temp33_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 32);
+static SENSOR_DEVICE_ATTR(temp34_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 33);
+static SENSOR_DEVICE_ATTR(temp35_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 34);
+static SENSOR_DEVICE_ATTR(temp36_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 35);
+static SENSOR_DEVICE_ATTR(temp37_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 36);
+static SENSOR_DEVICE_ATTR(temp38_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 37);
+static SENSOR_DEVICE_ATTR(temp39_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 38);
+static SENSOR_DEVICE_ATTR(temp40_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 39);
 static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
                                        applesmc_show_temperature, NULL, 0);
 static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO,
@@ -1194,6 +1299,50 @@ static SENSOR_DEVICE_ATTR(temp39_input, S_IRUGO,
 static SENSOR_DEVICE_ATTR(temp40_input, S_IRUGO,
                                        applesmc_show_temperature, NULL, 39);
 
+static struct attribute *label_attributes[] = {
+       &sensor_dev_attr_temp1_label.dev_attr.attr,
+       &sensor_dev_attr_temp2_label.dev_attr.attr,
+       &sensor_dev_attr_temp3_label.dev_attr.attr,
+       &sensor_dev_attr_temp4_label.dev_attr.attr,
+       &sensor_dev_attr_temp5_label.dev_attr.attr,
+       &sensor_dev_attr_temp6_label.dev_attr.attr,
+       &sensor_dev_attr_temp7_label.dev_attr.attr,
+       &sensor_dev_attr_temp8_label.dev_attr.attr,
+       &sensor_dev_attr_temp9_label.dev_attr.attr,
+       &sensor_dev_attr_temp10_label.dev_attr.attr,
+       &sensor_dev_attr_temp11_label.dev_attr.attr,
+       &sensor_dev_attr_temp12_label.dev_attr.attr,
+       &sensor_dev_attr_temp13_label.dev_attr.attr,
+       &sensor_dev_attr_temp14_label.dev_attr.attr,
+       &sensor_dev_attr_temp15_label.dev_attr.attr,
+       &sensor_dev_attr_temp16_label.dev_attr.attr,
+       &sensor_dev_attr_temp17_label.dev_attr.attr,
+       &sensor_dev_attr_temp18_label.dev_attr.attr,
+       &sensor_dev_attr_temp19_label.dev_attr.attr,
+       &sensor_dev_attr_temp20_label.dev_attr.attr,
+       &sensor_dev_attr_temp21_label.dev_attr.attr,
+       &sensor_dev_attr_temp22_label.dev_attr.attr,
+       &sensor_dev_attr_temp23_label.dev_attr.attr,
+       &sensor_dev_attr_temp24_label.dev_attr.attr,
+       &sensor_dev_attr_temp25_label.dev_attr.attr,
+       &sensor_dev_attr_temp26_label.dev_attr.attr,
+       &sensor_dev_attr_temp27_label.dev_attr.attr,
+       &sensor_dev_attr_temp28_label.dev_attr.attr,
+       &sensor_dev_attr_temp29_label.dev_attr.attr,
+       &sensor_dev_attr_temp30_label.dev_attr.attr,
+       &sensor_dev_attr_temp31_label.dev_attr.attr,
+       &sensor_dev_attr_temp32_label.dev_attr.attr,
+       &sensor_dev_attr_temp33_label.dev_attr.attr,
+       &sensor_dev_attr_temp34_label.dev_attr.attr,
+       &sensor_dev_attr_temp35_label.dev_attr.attr,
+       &sensor_dev_attr_temp36_label.dev_attr.attr,
+       &sensor_dev_attr_temp37_label.dev_attr.attr,
+       &sensor_dev_attr_temp38_label.dev_attr.attr,
+       &sensor_dev_attr_temp39_label.dev_attr.attr,
+       &sensor_dev_attr_temp40_label.dev_attr.attr,
+       NULL
+};
+
 static struct attribute *temperature_attributes[] = {
        &sensor_dev_attr_temp1_input.dev_attr.attr,
        &sensor_dev_attr_temp2_input.dev_attr.attr,
@@ -1241,6 +1390,10 @@ static struct attribute *temperature_attributes[] = {
 static const struct attribute_group temperature_attributes_group =
        { .attrs = temperature_attributes };
 
+static const struct attribute_group label_attributes_group = {
+       .attrs = label_attributes
+};
+
 /* Module stuff */
 
 /*
@@ -1363,6 +1516,14 @@ static __initdata struct dmi_match_data applesmc_dmi_data[] = {
        { .accelerometer = 0, .light = 0, .temperature_set = 17 },
 /* MacBook Pro 2,2: accelerometer, backlight and temperature set 18 */
        { .accelerometer = 1, .light = 1, .temperature_set = 18 },
+/* MacBook Pro 5,3: accelerometer, backlight and temperature set 19 */
+       { .accelerometer = 1, .light = 1, .temperature_set = 19 },
+/* MacBook Pro 5,4: accelerometer, backlight and temperature set 20 */
+       { .accelerometer = 1, .light = 1, .temperature_set = 20 },
+/* MacBook Pro 6,2: accelerometer, backlight and temperature set 21 */
+       { .accelerometer = 1, .light = 1, .temperature_set = 21 },
+/* MacBook Pro 7,1: accelerometer, backlight and temperature set 22 */
+       { .accelerometer = 1, .light = 1, .temperature_set = 22 },
 };
 
 /* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1".
@@ -1376,6 +1537,22 @@ static __initdata struct dmi_system_id applesmc_whitelist[] = {
          DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
          DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir") },
                &applesmc_dmi_data[7]},
+       { applesmc_dmi_match, "Apple MacBook Pro 7", {
+         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+         DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro7") },
+               &applesmc_dmi_data[22]},
+       { applesmc_dmi_match, "Apple MacBook Pro 5,4", {
+         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+         DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,4") },
+               &applesmc_dmi_data[20]},
+       { applesmc_dmi_match, "Apple MacBook Pro 5,3", {
+         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+         DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,3") },
+               &applesmc_dmi_data[19]},
+       { applesmc_dmi_match, "Apple MacBook Pro 6", {
+         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+         DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro6") },
+               &applesmc_dmi_data[21]},
        { applesmc_dmi_match, "Apple MacBook Pro 5", {
          DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
          DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5") },
@@ -1518,7 +1695,8 @@ static int __init applesmc_init(void)
        for (i = 0;
             temperature_sensors_sets[applesmc_temperature_set][i] != NULL;
             i++) {
-               if (temperature_attributes[i] == NULL) {
+               if (temperature_attributes[i] == NULL ||
+                   label_attributes[i] == NULL) {
                        printk(KERN_ERR "applesmc: More temperature sensors "
                                "in temperature_sensors_sets (at least %i)"
                                "than available sysfs files in "
@@ -1530,6 +1708,10 @@ static int __init applesmc_init(void)
                                                temperature_attributes[i]);
                if (ret)
                        goto out_temperature;
+               ret = sysfs_create_file(&pdev->dev.kobj,
+                                               label_attributes[i]);
+               if (ret)
+                       goto out_temperature;
        }
 
        if (applesmc_accelerometer) {
@@ -1580,6 +1762,7 @@ out_accelerometer:
        if (applesmc_accelerometer)
                applesmc_release_accelerometer();
 out_temperature:
+       sysfs_remove_group(&pdev->dev.kobj, &label_attributes_group);
        sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
 out_fans:
        while (fans_handled)
@@ -1609,6 +1792,7 @@ static void __exit applesmc_exit(void)
        }
        if (applesmc_accelerometer)
                applesmc_release_accelerometer();
+       sysfs_remove_group(&pdev->dev.kobj, &label_attributes_group);
        sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
        while (fans_handled)
                sysfs_remove_group(&pdev->dev.kobj,
index 16c420240724ee72ac96933fc0953f9a12c5e9c0..653db1bda9348ebaa62d8f17f93c46a4b8cdadda 100644 (file)
@@ -1411,6 +1411,13 @@ static int __init atk0110_init(void)
 {
        int ret;
 
+       /* Make sure it's safe to access the device through ACPI */
+       if (!acpi_resources_are_enforced()) {
+               pr_err("atk: Resources not safely usable due to "
+                      "acpi_enforce_resources kernel parameter\n");
+               return -EBUSY;
+       }
+
        ret = acpi_bus_register_driver(&atk_driver);
        if (ret)
                pr_info("atk: acpi_bus_register_driver failed: %d\n", ret);
index e9b7fbc5a4476b9cfdb2bd01ec58719b097cf7cb..2988da150ed6f7a223e64e892eed6d1ca2a18895 100644 (file)
@@ -241,6 +241,55 @@ static int __devinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *
        return tjmax;
 }
 
+static int __devinit get_tjmax(struct cpuinfo_x86 *c, u32 id,
+                              struct device *dev)
+{
+       /* The 100C is default for both mobile and non mobile CPUs */
+       int err;
+       u32 eax, edx;
+       u32 val;
+
+       /* A new feature of current Intel(R) processors, the
+          IA32_TEMPERATURE_TARGET contains the TjMax value */
+       err = rdmsr_safe_on_cpu(id, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
+       if (err) {
+               dev_warn(dev, "Unable to read TjMax from CPU.\n");
+       } else {
+               val = (eax >> 16) & 0xff;
+               /*
+                * If the TjMax is not plausible, an assumption
+                * will be used
+                */
+               if ((val > 80) && (val < 120)) {
+                       dev_info(dev, "TjMax is %d C.\n", val);
+                       return val * 1000;
+               }
+       }
+
+       /*
+        * An assumption is made for early CPUs and unreadable MSR.
+        * NOTE: the given value may not be correct.
+        */
+
+       switch (c->x86_model) {
+       case 0xe:
+       case 0xf:
+       case 0x16:
+       case 0x1a:
+               dev_warn(dev, "TjMax is assumed as 100 C!\n");
+               return 100000;
+               break;
+       case 0x17:
+       case 0x1c:              /* Atom CPUs */
+               return adjust_tjmax(c, id, dev);
+               break;
+       default:
+               dev_warn(dev, "CPU (model=0x%x) is not supported yet,"
+                       " using default TjMax of 100C.\n", c->x86_model);
+               return 100000;
+       }
+}
+
 static int __devinit coretemp_probe(struct platform_device *pdev)
 {
        struct coretemp_data *data;
@@ -283,14 +332,18 @@ static int __devinit coretemp_probe(struct platform_device *pdev)
                }
        }
 
-       data->tjmax = adjust_tjmax(c, data->id, &pdev->dev);
+       data->tjmax = get_tjmax(c, data->id, &pdev->dev);
        platform_set_drvdata(pdev, data);
 
-       /* read the still undocumented IA32_TEMPERATURE_TARGET it exists
-          on older CPUs but not in this register, Atoms don't have it either */
+       /*
+        * read the still undocumented IA32_TEMPERATURE_TARGET. It exists
+        * on older CPUs but not in this register,
+        * Atoms don't have it either.
+        */
 
        if ((c->x86_model > 0xe) && (c->x86_model != 0x1c)) {
-               err = rdmsr_safe_on_cpu(data->id, 0x1a2, &eax, &edx);
+               err = rdmsr_safe_on_cpu(data->id, MSR_IA32_TEMPERATURE_TARGET,
+                   &eax, &edx);
                if (err) {
                        dev_warn(&pdev->dev, "Unable to read"
                                        " IA32_TEMPERATURE_TARGET MSR\n");
@@ -451,28 +504,20 @@ static int __init coretemp_init(void)
 
        for_each_online_cpu(i) {
                struct cpuinfo_x86 *c = &cpu_data(i);
+               /*
+                * CPUID.06H.EAX[0] indicates whether the CPU has thermal
+                * sensors. We check this bit only, all the early CPUs
+                * without thermal sensors will be filtered out.
+                */
+               if (c->cpuid_level >= 6 && (cpuid_eax(0x06) & 0x01)) {
+                       err = coretemp_device_add(i);
+                       if (err)
+                               goto exit_devices_unreg;
 
-               /* check if family 6, models 0xe (Pentium M DC),
-                 0xf (Core 2 DC 65nm), 0x16 (Core 2 SC 65nm),
-                 0x17 (Penryn 45nm), 0x1a (Nehalem), 0x1c (Atom),
-                 0x1e (Lynnfield) */
-               if ((c->cpuid_level < 0) || (c->x86 != 0x6) ||
-                   !((c->x86_model == 0xe) || (c->x86_model == 0xf) ||
-                       (c->x86_model == 0x16) || (c->x86_model == 0x17) ||
-                       (c->x86_model == 0x1a) || (c->x86_model == 0x1c) ||
-                       (c->x86_model == 0x1e))) {
-
-                       /* supported CPU not found, but report the unknown
-                          family 6 CPU */
-                       if ((c->x86 == 0x6) && (c->x86_model > 0xf))
-                               printk(KERN_WARNING DRVNAME ": Unknown CPU "
-                                       "model 0x%x\n", c->x86_model);
-                       continue;
+               } else {
+                       printk(KERN_INFO DRVNAME ": CPU (model=0x%x)"
+                               " has no thermal sensor.\n", c->x86_model);
                }
-
-               err = coretemp_device_add(i);
-               if (err)
-                       goto exit_devices_unreg;
        }
        if (list_empty(&pdev_list)) {
                err = -ENODEV;
index 823dd28a902cf8c33e7d8de2d8a21b9a56f85db1..980c17d5eeae98992345f2a2f413994f3513c79f 100644 (file)
@@ -1,12 +1,14 @@
 /*
- * dme1737.c - Driver for the SMSC DME1737, Asus A8000, SMSC SCH311x and
- *             SCH5027 Super-I/O chips integrated hardware monitoring features.
- * Copyright (c) 2007, 2008 Juerg Haefliger <juergh@gmail.com>
+ * dme1737.c - Driver for the SMSC DME1737, Asus A8000, SMSC SCH311x, SCH5027,
+ *             and SCH5127 Super-I/O chips integrated hardware monitoring
+ *             features.
+ * Copyright (c) 2007, 2008, 2009, 2010 Juerg Haefliger <juergh@gmail.com>
  *
  * This driver is an I2C/ISA hybrid, meaning that it uses the I2C bus to access
  * the chip registers if a DME1737, A8000, or SCH5027 is found and the ISA bus
- * if a SCH311x chip is found. Both types of chips have very similar hardware
- * monitoring capabilities but differ in the way they can be accessed.
+ * if a SCH311x or SCH5127 chip is found. Both types of chips have very
+ * similar hardware monitoring capabilities but differ in the way they can be
+ * accessed.
  *
  * 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
@@ -57,7 +59,7 @@ MODULE_PARM_DESC(probe_all_addr, "Include probing of non-standard LPC "
 /* Addresses to scan */
 static const unsigned short normal_i2c[] = {0x2c, 0x2d, 0x2e, I2C_CLIENT_END};
 
-enum chips { dme1737, sch5027, sch311x };
+enum chips { dme1737, sch5027, sch311x, sch5127 };
 
 /* ---------------------------------------------------------------------
  * Registers
@@ -164,10 +166,29 @@ static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23};
 #define DME1737_VERSTEP_MASK   0xf8
 #define SCH311X_DEVICE         0x8c
 #define SCH5027_VERSTEP                0x69
+#define SCH5127_DEVICE         0x8e
+
+/* Device ID values (global configuration register index 0x20) */
+#define DME1737_ID_1   0x77
+#define DME1737_ID_2   0x78
+#define SCH3112_ID     0x7c
+#define SCH3114_ID     0x7d
+#define SCH3116_ID     0x7f
+#define SCH5027_ID     0x89
+#define SCH5127_ID     0x86
 
 /* Length of ISA address segment */
 #define DME1737_EXTENT 2
 
+/* chip-dependent features */
+#define HAS_TEMP_OFFSET                (1 << 0)                /* bit 0 */
+#define HAS_VID                        (1 << 1)                /* bit 1 */
+#define HAS_ZONE3              (1 << 2)                /* bit 2 */
+#define HAS_ZONE_HYST          (1 << 3)                /* bit 3 */
+#define HAS_PWM_MIN            (1 << 4)                /* bit 4 */
+#define HAS_FAN(ix)            (1 << ((ix) + 5))       /* bits 5-10 */
+#define HAS_PWM(ix)            (1 << ((ix) + 11))      /* bits 11-16 */
+
 /* ---------------------------------------------------------------------
  * Data structures and manipulation thereof
  * --------------------------------------------------------------------- */
@@ -187,8 +208,7 @@ struct dme1737_data {
 
        u8 vid;
        u8 pwm_rr_en;
-       u8 has_pwm;
-       u8 has_fan;
+       u32 has_features;
 
        /* Register values */
        u16 in[7];
@@ -224,8 +244,11 @@ static const int IN_NOMINAL_SCH311x[] = {2500, 1500, 3300, 5000, 12000, 3300,
                                         3300};
 static const int IN_NOMINAL_SCH5027[] = {5000, 2250, 3300, 1125, 1125, 3300,
                                         3300};
+static const int IN_NOMINAL_SCH5127[] = {2500, 2250, 3300, 1125, 1125, 3300,
+                                        3300};
 #define IN_NOMINAL(type)       ((type) == sch311x ? IN_NOMINAL_SCH311x : \
                                 (type) == sch5027 ? IN_NOMINAL_SCH5027 : \
+                                (type) == sch5127 ? IN_NOMINAL_SCH5127 : \
                                 IN_NOMINAL_DME1737)
 
 /* Voltage input
@@ -568,7 +591,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
 
        /* Sample register contents every 1 sec */
        if (time_after(jiffies, data->last_update + HZ) || !data->valid) {
-               if (data->type == dme1737) {
+               if (data->has_features & HAS_VID) {
                        data->vid = dme1737_read(data, DME1737_REG_VID) &
                                0x3f;
                }
@@ -599,7 +622,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
                                        DME1737_REG_TEMP_MIN(ix));
                        data->temp_max[ix] = dme1737_read(data,
                                        DME1737_REG_TEMP_MAX(ix));
-                       if (data->type != sch5027) {
+                       if (data->has_features & HAS_TEMP_OFFSET) {
                                data->temp_offset[ix] = dme1737_read(data,
                                                DME1737_REG_TEMP_OFFSET(ix));
                        }
@@ -626,7 +649,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
                for (ix = 0; ix < ARRAY_SIZE(data->fan); ix++) {
                        /* Skip reading registers if optional fans are not
                         * present */
-                       if (!(data->has_fan & (1 << ix))) {
+                       if (!(data->has_features & HAS_FAN(ix))) {
                                continue;
                        }
                        data->fan[ix] = dme1737_read(data,
@@ -650,7 +673,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
                for (ix = 0; ix < ARRAY_SIZE(data->pwm); ix++) {
                        /* Skip reading registers if optional PWMs are not
                         * present */
-                       if (!(data->has_pwm & (1 << ix))) {
+                       if (!(data->has_features & HAS_PWM(ix))) {
                                continue;
                        }
                        data->pwm[ix] = dme1737_read(data,
@@ -672,12 +695,24 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
 
                /* Thermal zone registers */
                for (ix = 0; ix < ARRAY_SIZE(data->zone_low); ix++) {
-                       data->zone_low[ix] = dme1737_read(data,
-                                       DME1737_REG_ZONE_LOW(ix));
-                       data->zone_abs[ix] = dme1737_read(data,
-                                       DME1737_REG_ZONE_ABS(ix));
+                       /* Skip reading registers if zone3 is not present */
+                       if ((ix == 2) && !(data->has_features & HAS_ZONE3)) {
+                               continue;
+                       }
+                       /* sch5127 zone2 registers are special */
+                       if ((ix == 1) && (data->type == sch5127)) {
+                               data->zone_low[1] = dme1737_read(data,
+                                               DME1737_REG_ZONE_LOW(2));
+                               data->zone_abs[1] = dme1737_read(data,
+                                               DME1737_REG_ZONE_ABS(2));
+                       } else {
+                               data->zone_low[ix] = dme1737_read(data,
+                                               DME1737_REG_ZONE_LOW(ix));
+                               data->zone_abs[ix] = dme1737_read(data,
+                                               DME1737_REG_ZONE_ABS(ix));
+                       }
                }
-               if (data->type != sch5027) {
+               if (data->has_features & HAS_ZONE_HYST) {
                        for (ix = 0; ix < ARRAY_SIZE(data->zone_hyst); ix++) {
                                data->zone_hyst[ix] = dme1737_read(data,
                                                DME1737_REG_ZONE_HYST(ix));
@@ -1594,10 +1629,6 @@ static struct attribute *dme1737_attr[] ={
        &sensor_dev_attr_zone2_auto_point2_temp.dev_attr.attr,
        &sensor_dev_attr_zone2_auto_point3_temp.dev_attr.attr,
        &sensor_dev_attr_zone2_auto_channels_temp.dev_attr.attr,
-       &sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr,
-       &sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr,
-       &sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr,
-       &sensor_dev_attr_zone3_auto_channels_temp.dev_attr.attr,
        NULL
 };
 
@@ -1605,27 +1636,23 @@ static const struct attribute_group dme1737_group = {
        .attrs = dme1737_attr,
 };
 
-/* The following struct holds misc attributes, which are not available in all
- * chips. Their creation depends on the chip type which is determined during
- * module load. */
-static struct attribute *dme1737_misc_attr[] = {
-       /* Temperatures */
+/* The following struct holds temp offset attributes, which are not available
+ * in all chips. The following chips support them:
+ * DME1737, SCH311x */
+static struct attribute *dme1737_temp_offset_attr[] = {
        &sensor_dev_attr_temp1_offset.dev_attr.attr,
        &sensor_dev_attr_temp2_offset.dev_attr.attr,
        &sensor_dev_attr_temp3_offset.dev_attr.attr,
-       /* Zones */
-       &sensor_dev_attr_zone1_auto_point1_temp_hyst.dev_attr.attr,
-       &sensor_dev_attr_zone2_auto_point1_temp_hyst.dev_attr.attr,
-       &sensor_dev_attr_zone3_auto_point1_temp_hyst.dev_attr.attr,
        NULL
 };
 
-static const struct attribute_group dme1737_misc_group = {
-       .attrs = dme1737_misc_attr,
+static const struct attribute_group dme1737_temp_offset_group = {
+       .attrs = dme1737_temp_offset_attr,
 };
 
-/* The following struct holds VID-related attributes. Their creation
-   depends on the chip type which is determined during module load. */
+/* The following struct holds VID related attributes, which are not available
+ * in all chips. The following chips support them:
+ * DME1737 */
 static struct attribute *dme1737_vid_attr[] = {
        &dev_attr_vrm.attr,
        &dev_attr_cpu0_vid.attr,
@@ -1636,6 +1663,36 @@ static const struct attribute_group dme1737_vid_group = {
        .attrs = dme1737_vid_attr,
 };
 
+/* The following struct holds temp zone 3 related attributes, which are not
+ * available in all chips. The following chips support them:
+ * DME1737, SCH311x, SCH5027 */
+static struct attribute *dme1737_zone3_attr[] = {
+       &sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr,
+       &sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr,
+       &sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr,
+       &sensor_dev_attr_zone3_auto_channels_temp.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group dme1737_zone3_group = {
+       .attrs = dme1737_zone3_attr,
+};
+
+
+/* The following struct holds temp zone hysteresis  related attributes, which
+ * are not available in all chips. The following chips support them:
+ * DME1737, SCH311x */
+static struct attribute *dme1737_zone_hyst_attr[] = {
+       &sensor_dev_attr_zone1_auto_point1_temp_hyst.dev_attr.attr,
+       &sensor_dev_attr_zone2_auto_point1_temp_hyst.dev_attr.attr,
+       &sensor_dev_attr_zone3_auto_point1_temp_hyst.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group dme1737_zone_hyst_group = {
+       .attrs = dme1737_zone_hyst_attr,
+};
+
 /* The following structs hold the PWM attributes, some of which are optional.
  * Their creation depends on the chip configuration which is determined during
  * module load. */
@@ -1691,10 +1748,10 @@ static const struct attribute_group dme1737_pwm_group[] = {
        { .attrs = dme1737_pwm6_attr },
 };
 
-/* The following struct holds misc PWM attributes, which are not available in
- * all chips. Their creation depends on the chip type which is determined
+/* The following struct holds auto PWM min attributes, which are not available
+ * in all chips. Their creation depends on the chip type which is determined
  * during module load. */
-static struct attribute *dme1737_pwm_misc_attr[] = {
+static struct attribute *dme1737_auto_pwm_min_attr[] = {
        &sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr,
        &sensor_dev_attr_pwm2_auto_pwm_min.dev_attr.attr,
        &sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr,
@@ -1764,14 +1821,25 @@ static struct attribute *dme1737_zone_chmod_attr[] = {
        &sensor_dev_attr_zone2_auto_point1_temp.dev_attr.attr,
        &sensor_dev_attr_zone2_auto_point2_temp.dev_attr.attr,
        &sensor_dev_attr_zone2_auto_point3_temp.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group dme1737_zone_chmod_group = {
+       .attrs = dme1737_zone_chmod_attr,
+};
+
+
+/* The permissions of the following zone 3 attributes are changed to read-
+ * writeable if the chip is *not* locked. Otherwise they stay read-only. */
+static struct attribute *dme1737_zone3_chmod_attr[] = {
        &sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr,
        &sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr,
        &sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr,
        NULL
 };
 
-static const struct attribute_group dme1737_zone_chmod_group = {
-       .attrs = dme1737_zone_chmod_attr,
+static const struct attribute_group dme1737_zone3_chmod_group = {
+       .attrs = dme1737_zone3_chmod_attr,
 };
 
 /* The permissions of the following PWM attributes are changed to read-
@@ -1887,30 +1955,35 @@ static void dme1737_remove_files(struct device *dev)
        int ix;
 
        for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
-               if (data->has_fan & (1 << ix)) {
+               if (data->has_features & HAS_FAN(ix)) {
                        sysfs_remove_group(&dev->kobj,
                                           &dme1737_fan_group[ix]);
                }
        }
 
        for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
-               if (data->has_pwm & (1 << ix)) {
+               if (data->has_features & HAS_PWM(ix)) {
                        sysfs_remove_group(&dev->kobj,
                                           &dme1737_pwm_group[ix]);
-                       if (data->type != sch5027 && ix < 3) {
+                       if ((data->has_features & HAS_PWM_MIN) && ix < 3) {
                                sysfs_remove_file(&dev->kobj,
-                                                 dme1737_pwm_misc_attr[ix]);
+                                               dme1737_auto_pwm_min_attr[ix]);
                        }
                }
        }
 
-       if (data->type != sch5027) {
-               sysfs_remove_group(&dev->kobj, &dme1737_misc_group);
+       if (data->has_features & HAS_TEMP_OFFSET) {
+               sysfs_remove_group(&dev->kobj, &dme1737_temp_offset_group);
        }
-       if (data->type == dme1737) {
+       if (data->has_features & HAS_VID) {
                sysfs_remove_group(&dev->kobj, &dme1737_vid_group);
        }
-
+       if (data->has_features & HAS_ZONE3) {
+               sysfs_remove_group(&dev->kobj, &dme1737_zone3_group);
+       }
+       if (data->has_features & HAS_ZONE_HYST) {
+               sysfs_remove_group(&dev->kobj, &dme1737_zone_hyst_group);
+       }
        sysfs_remove_group(&dev->kobj, &dme1737_group);
 
        if (!data->client) {
@@ -1934,23 +2007,31 @@ static int dme1737_create_files(struct device *dev)
                goto exit_remove;
        }
 
-       /* Create misc sysfs attributes */
-       if ((data->type != sch5027) &&
+       /* Create chip-dependent sysfs attributes */
+       if ((data->has_features & HAS_TEMP_OFFSET) &&
            (err = sysfs_create_group(&dev->kobj,
-                                     &dme1737_misc_group))) {
+                                     &dme1737_temp_offset_group))) {
                goto exit_remove;
        }
-
-       /* Create VID-related sysfs attributes */
-       if ((data->type == dme1737) &&
+       if ((data->has_features & HAS_VID) &&
            (err = sysfs_create_group(&dev->kobj,
                                      &dme1737_vid_group))) {
                goto exit_remove;
        }
+       if ((data->has_features & HAS_ZONE3) &&
+           (err = sysfs_create_group(&dev->kobj,
+                                     &dme1737_zone3_group))) {
+               goto exit_remove;
+       }
+       if ((data->has_features & HAS_ZONE_HYST) &&
+           (err = sysfs_create_group(&dev->kobj,
+                                     &dme1737_zone_hyst_group))) {
+               goto exit_remove;
+       }
 
        /* Create fan sysfs attributes */
        for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
-               if (data->has_fan & (1 << ix)) {
+               if (data->has_features & HAS_FAN(ix)) {
                        if ((err = sysfs_create_group(&dev->kobj,
                                                &dme1737_fan_group[ix]))) {
                                goto exit_remove;
@@ -1960,14 +2041,14 @@ static int dme1737_create_files(struct device *dev)
 
        /* Create PWM sysfs attributes */
        for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
-               if (data->has_pwm & (1 << ix)) {
+               if (data->has_features & HAS_PWM(ix)) {
                        if ((err = sysfs_create_group(&dev->kobj,
                                                &dme1737_pwm_group[ix]))) {
                                goto exit_remove;
                        }
-                       if (data->type != sch5027 && ix < 3 &&
+                       if ((data->has_features & HAS_PWM_MIN) && ix < 3 &&
                            (err = sysfs_create_file(&dev->kobj,
-                                               dme1737_pwm_misc_attr[ix]))) {
+                                       dme1737_auto_pwm_min_attr[ix]))) {
                                goto exit_remove;
                        }
                }
@@ -1983,21 +2064,30 @@ static int dme1737_create_files(struct device *dev)
                dme1737_chmod_group(dev, &dme1737_zone_chmod_group,
                                    S_IRUGO | S_IWUSR);
 
-               /* Change permissions of misc sysfs attributes */
-               if (data->type != sch5027) {
-                       dme1737_chmod_group(dev, &dme1737_misc_group,
+               /* Change permissions of chip-dependent sysfs attributes */
+               if (data->has_features & HAS_TEMP_OFFSET) {
+                       dme1737_chmod_group(dev, &dme1737_temp_offset_group,
+                                           S_IRUGO | S_IWUSR);
+               }
+               if (data->has_features & HAS_ZONE3) {
+                       dme1737_chmod_group(dev, &dme1737_zone3_chmod_group,
+                                           S_IRUGO | S_IWUSR);
+               }
+               if (data->has_features & HAS_ZONE_HYST) {
+                       dme1737_chmod_group(dev, &dme1737_zone_hyst_group,
                                            S_IRUGO | S_IWUSR);
                }
 
                /* Change permissions of PWM sysfs attributes */
                for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_chmod_group); ix++) {
-                       if (data->has_pwm & (1 << ix)) {
+                       if (data->has_features & HAS_PWM(ix)) {
                                dme1737_chmod_group(dev,
                                                &dme1737_pwm_chmod_group[ix],
                                                S_IRUGO | S_IWUSR);
-                               if (data->type != sch5027 && ix < 3) {
+                               if ((data->has_features & HAS_PWM_MIN) &&
+                                   ix < 3) {
                                        dme1737_chmod_file(dev,
-                                               dme1737_pwm_misc_attr[ix],
+                                               dme1737_auto_pwm_min_attr[ix],
                                                S_IRUGO | S_IWUSR);
                                }
                        }
@@ -2005,7 +2095,7 @@ static int dme1737_create_files(struct device *dev)
 
                /* Change permissions of pwm[1-3] if in manual mode */
                for (ix = 0; ix < 3; ix++) {
-                       if ((data->has_pwm & (1 << ix)) &&
+                       if ((data->has_features & HAS_PWM(ix)) &&
                            (PWM_EN_FROM_REG(data->pwm_config[ix]) == 1)) {
                                dme1737_chmod_file(dev,
                                                dme1737_pwm_chmod_attr[ix],
@@ -2052,20 +2142,20 @@ static int dme1737_init_device(struct device *dev)
                return -EFAULT;
        }
 
-       /* Determine which optional fan and pwm features are enabled/present */
+       /* Determine which optional fan and pwm features are enabled (only
+        * valid for I2C devices) */
        if (client) {   /* I2C chip */
                data->config2 = dme1737_read(data, DME1737_REG_CONFIG2);
                /* Check if optional fan3 input is enabled */
                if (data->config2 & 0x04) {
-                       data->has_fan |= (1 << 2);
+                       data->has_features |= HAS_FAN(2);
                }
 
                /* Fan4 and pwm3 are only available if the client's I2C address
                 * is the default 0x2e. Otherwise the I/Os associated with
                 * these functions are used for addr enable/select. */
                if (client->addr == 0x2e) {
-                       data->has_fan |= (1 << 3);
-                       data->has_pwm |= (1 << 2);
+                       data->has_features |= HAS_FAN(3) | HAS_PWM(2);
                }
 
                /* Determine which of the optional fan[5-6] and pwm[5-6]
@@ -2077,26 +2167,40 @@ static int dme1737_init_device(struct device *dev)
                        dev_warn(dev, "Failed to query Super-IO for optional "
                                 "features.\n");
                }
-       } else {   /* ISA chip */
-               /* Fan3 and pwm3 are always available. Fan[4-5] and pwm[5-6]
-                * don't exist in the ISA chip. */
-               data->has_fan |= (1 << 2);
-               data->has_pwm |= (1 << 2);
        }
 
-       /* Fan1, fan2, pwm1, and pwm2 are always present */
-       data->has_fan |= 0x03;
-       data->has_pwm |= 0x03;
+       /* Fan[1-2] and pwm[1-2] are present in all chips */
+       data->has_features |= HAS_FAN(0) | HAS_FAN(1) | HAS_PWM(0) | HAS_PWM(1);
+
+       /* Chip-dependent features */
+       switch (data->type) {
+       case dme1737:
+               data->has_features |= HAS_TEMP_OFFSET | HAS_VID | HAS_ZONE3 |
+                       HAS_ZONE_HYST | HAS_PWM_MIN;
+               break;
+       case sch311x:
+               data->has_features |= HAS_TEMP_OFFSET | HAS_ZONE3 |
+                       HAS_ZONE_HYST | HAS_PWM_MIN | HAS_FAN(2) | HAS_PWM(2);
+               break;
+       case sch5027:
+               data->has_features |= HAS_ZONE3;
+               break;
+       case sch5127:
+               data->has_features |= HAS_FAN(2) | HAS_PWM(2);
+               break;
+       default:
+               break;
+       }
 
        dev_info(dev, "Optional features: pwm3=%s, pwm5=%s, pwm6=%s, "
                 "fan3=%s, fan4=%s, fan5=%s, fan6=%s.\n",
-                (data->has_pwm & (1 << 2)) ? "yes" : "no",
-                (data->has_pwm & (1 << 4)) ? "yes" : "no",
-                (data->has_pwm & (1 << 5)) ? "yes" : "no",
-                (data->has_fan & (1 << 2)) ? "yes" : "no",
-                (data->has_fan & (1 << 3)) ? "yes" : "no",
-                (data->has_fan & (1 << 4)) ? "yes" : "no",
-                (data->has_fan & (1 << 5)) ? "yes" : "no");
+                (data->has_features & HAS_PWM(2)) ? "yes" : "no",
+                (data->has_features & HAS_PWM(4)) ? "yes" : "no",
+                (data->has_features & HAS_PWM(5)) ? "yes" : "no",
+                (data->has_features & HAS_FAN(2)) ? "yes" : "no",
+                (data->has_features & HAS_FAN(3)) ? "yes" : "no",
+                (data->has_features & HAS_FAN(4)) ? "yes" : "no",
+                (data->has_features & HAS_FAN(5)) ? "yes" : "no");
 
        reg = dme1737_read(data, DME1737_REG_TACH_PWM);
        /* Inform if fan-to-pwm mapping differs from the default */
@@ -2122,7 +2226,7 @@ static int dme1737_init_device(struct device *dev)
                for (ix = 0; ix < 3; ix++) {
                        data->pwm_config[ix] = dme1737_read(data,
                                                DME1737_REG_PWM_CONFIG(ix));
-                       if ((data->has_pwm & (1 << ix)) &&
+                       if ((data->has_features & HAS_PWM(ix)) &&
                            (PWM_EN_FROM_REG(data->pwm_config[ix]) == -1)) {
                                dev_info(dev, "Switching pwm%d to "
                                         "manual mode.\n", ix + 1);
@@ -2142,7 +2246,7 @@ static int dme1737_init_device(struct device *dev)
        data->pwm_acz[2] = 4;   /* pwm3 -> zone3 */
 
        /* Set VRM */
-       if (data->type == dme1737) {
+       if (data->has_features & HAS_VID) {
                data->vrm = vid_which_vrm();
        }
 
@@ -2163,10 +2267,10 @@ static int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data)
        dme1737_sio_enter(sio_cip);
 
        /* Check device ID
-        * The DME1737 can return either 0x78 or 0x77 as its device ID.
-        * The SCH5027 returns 0x89 as its device ID. */
+        * We currently know about two kinds of DME1737 and SCH5027. */
        reg = force_id ? force_id : dme1737_sio_inb(sio_cip, 0x20);
-       if (!(reg == 0x77 || reg == 0x78 || reg == 0x89)) {
+       if (!(reg == DME1737_ID_1 || reg == DME1737_ID_2 ||
+             reg == SCH5027_ID)) {
                err = -ENODEV;
                goto exit;
        }
@@ -2185,16 +2289,16 @@ static int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data)
         * are enabled and available. Bits [3:2] of registers 0x43-0x46 are set
         * to '10' if the respective feature is enabled. */
        if ((inb(addr + 0x43) & 0x0c) == 0x08) { /* fan6 */
-               data->has_fan |= (1 << 5);
+               data->has_features |= HAS_FAN(5);
        }
        if ((inb(addr + 0x44) & 0x0c) == 0x08) { /* pwm6 */
-               data->has_pwm |= (1 << 5);
+               data->has_features |= HAS_PWM(5);
        }
        if ((inb(addr + 0x45) & 0x0c) == 0x08) { /* fan5 */
-               data->has_fan |= (1 << 4);
+               data->has_features |= HAS_FAN(4);
        }
        if ((inb(addr + 0x46) & 0x0c) == 0x08) { /* pwm5 */
-               data->has_pwm |= (1 << 4);
+               data->has_features |= HAS_PWM(4);
        }
 
 exit:
@@ -2222,7 +2326,6 @@ static int dme1737_i2c_detect(struct i2c_client *client,
        if (company == DME1737_COMPANY_SMSC &&
            verstep == SCH5027_VERSTEP) {
                name = "sch5027";
-
        } else if (company == DME1737_COMPANY_SMSC &&
                   (verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP) {
                name = "dme1737";
@@ -2329,10 +2432,10 @@ static int __init dme1737_isa_detect(int sio_cip, unsigned short *addr)
        dme1737_sio_enter(sio_cip);
 
        /* Check device ID
-        * We currently know about SCH3112 (0x7c), SCH3114 (0x7d), and
-        * SCH3116 (0x7f). */
+        * We currently know about SCH3112, SCH3114, SCH3116, and SCH5127 */
        reg = force_id ? force_id : dme1737_sio_inb(sio_cip, 0x20);
-       if (!(reg == 0x7c || reg == 0x7d || reg == 0x7f)) {
+       if (!(reg == SCH3112_ID || reg == SCH3114_ID || reg == SCH3116_ID ||
+             reg == SCH5127_ID)) {
                err = -ENODEV;
                goto exit;
        }
@@ -2424,23 +2527,42 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, data);
 
        /* Skip chip detection if module is loaded with force_id parameter */
-       if (!force_id) {
+       switch (force_id) {
+       case SCH3112_ID:
+       case SCH3114_ID:
+       case SCH3116_ID:
+               data->type = sch311x;
+               break;
+       case SCH5127_ID:
+               data->type = sch5127;
+               break;
+       default:
                company = dme1737_read(data, DME1737_REG_COMPANY);
                device = dme1737_read(data, DME1737_REG_DEVICE);
 
-               if (!((company == DME1737_COMPANY_SMSC) &&
-                     (device == SCH311X_DEVICE))) {
+               if ((company == DME1737_COMPANY_SMSC) &&
+                   (device == SCH311X_DEVICE)) {
+                       data->type = sch311x;
+               } else if ((company == DME1737_COMPANY_SMSC) &&
+                          (device == SCH5127_DEVICE)) {
+                       data->type = sch5127;
+               } else {
                        err = -ENODEV;
                        goto exit_kfree;
                }
        }
-       data->type = sch311x;
 
-       /* Fill in the remaining client fields and initialize the mutex */
-       data->name = "sch311x";
+       if (data->type == sch5127) {
+               data->name = "sch5127";
+       } else {
+               data->name = "sch311x";
+       }
+
+       /* Initialize the mutex */
        mutex_init(&data->update_lock);
 
-       dev_info(dev, "Found a SCH311x chip at 0x%04x\n", data->addr);
+       dev_info(dev, "Found a %s chip at 0x%04x\n",
+                data->type == sch5127 ? "SCH5127" : "SCH311x", data->addr);
 
        /* Initialize the chip */
        if ((err = dme1737_init_device(dev))) {
diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c
new file mode 100644 (file)
index 0000000..0e4b564
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ * emc1403.c - SMSC Thermal 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; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * TODO
+ *     -       cache alarm and critical limit registers
+ *     -       add emc1404 support
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/sysfs.h>
+#include <linux/mutex.h>
+
+#define THERMAL_PID_REG                0xfd
+#define THERMAL_SMSC_ID_REG    0xfe
+#define THERMAL_REVISION_REG   0xff
+
+struct thermal_data {
+       struct device *hwmon_dev;
+       struct mutex mutex;
+       /* Cache the hyst value so we don't keep re-reading it. In theory
+          we could cache it forever as nobody else should be writing it. */
+       u8 cached_hyst;
+       unsigned long hyst_valid;
+};
+
+static ssize_t show_temp(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
+       int retval = i2c_smbus_read_byte_data(client, sda->index);
+
+       if (retval < 0)
+               return retval;
+       return sprintf(buf, "%d000\n", retval);
+}
+
+static ssize_t show_bit(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct sensor_device_attribute_2 *sda = to_sensor_dev_attr_2(attr);
+       int retval = i2c_smbus_read_byte_data(client, sda->nr);
+
+       if (retval < 0)
+               return retval;
+       retval &= sda->index;
+       return sprintf(buf, "%d\n", retval ? 1 : 0);
+}
+
+static ssize_t store_temp(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
+       struct i2c_client *client = to_i2c_client(dev);
+       unsigned long val;
+       int retval;
+
+       if (strict_strtoul(buf, 10, &val))
+               return -EINVAL;
+       retval = i2c_smbus_write_byte_data(client, sda->index,
+                                       DIV_ROUND_CLOSEST(val, 1000));
+       if (retval < 0)
+               return retval;
+       return count;
+}
+
+static ssize_t show_hyst(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct thermal_data *data = i2c_get_clientdata(client);
+       struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
+       int retval;
+       int hyst;
+
+       retval = i2c_smbus_read_byte_data(client, sda->index);
+       if (retval < 0)
+               return retval;
+
+       if (time_after(jiffies, data->hyst_valid)) {
+               hyst = i2c_smbus_read_byte_data(client, 0x21);
+               if (hyst < 0)
+                       return retval;
+               data->cached_hyst = hyst;
+               data->hyst_valid = jiffies + HZ;
+       }
+       return sprintf(buf, "%d000\n", retval - data->cached_hyst);
+}
+
+static ssize_t store_hyst(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 *sda = to_sensor_dev_attr(attr);
+       int retval;
+       int hyst;
+       unsigned long val;
+
+       if (strict_strtoul(buf, 10, &val))
+               return -EINVAL;
+
+       mutex_lock(&data->mutex);
+       retval = i2c_smbus_read_byte_data(client, sda->index);
+       if (retval < 0)
+               goto fail;
+
+       hyst = val - retval * 1000;
+       hyst = DIV_ROUND_CLOSEST(hyst, 1000);
+       if (hyst < 0 || hyst > 255) {
+               retval = -ERANGE;
+               goto fail;
+       }
+
+       retval = i2c_smbus_write_byte_data(client, 0x21, hyst);
+       if (retval == 0) {
+               retval = count;
+               data->cached_hyst = hyst;
+               data->hyst_valid = jiffies + HZ;
+       }
+fail:
+       mutex_unlock(&data->mutex);
+       return retval;
+}
+
+/*
+ *     Sensors. We pass the actual i2c register to the methods.
+ */
+
+static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO | S_IWUSR,
+       show_temp, store_temp, 0x06);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR,
+       show_temp, store_temp, 0x05);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO | S_IWUSR,
+       show_temp, store_temp, 0x20);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0x00);
+static SENSOR_DEVICE_ATTR_2(temp1_min_alarm, S_IRUGO,
+       show_bit, NULL, 0x36, 0x01);
+static SENSOR_DEVICE_ATTR_2(temp1_max_alarm, S_IRUGO,
+       show_bit, NULL, 0x35, 0x01);
+static SENSOR_DEVICE_ATTR_2(temp1_crit_alarm, S_IRUGO,
+       show_bit, NULL, 0x37, 0x01);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO | S_IWUSR,
+       show_hyst, store_hyst, 0x20);
+
+static SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO | S_IWUSR,
+       show_temp, store_temp, 0x08);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO | S_IWUSR,
+       show_temp, store_temp, 0x07);
+static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO | S_IWUSR,
+       show_temp, store_temp, 0x19);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0x01);
+static SENSOR_DEVICE_ATTR_2(temp2_min_alarm, S_IRUGO,
+       show_bit, NULL, 0x36, 0x02);
+static SENSOR_DEVICE_ATTR_2(temp2_max_alarm, S_IRUGO,
+       show_bit, NULL, 0x35, 0x02);
+static SENSOR_DEVICE_ATTR_2(temp2_crit_alarm, S_IRUGO,
+       show_bit, NULL, 0x37, 0x02);
+static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO | S_IWUSR,
+       show_hyst, store_hyst, 0x19);
+
+static SENSOR_DEVICE_ATTR(temp3_min, S_IRUGO | S_IWUSR,
+       show_temp, store_temp, 0x16);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO | S_IWUSR,
+       show_temp, store_temp, 0x15);
+static SENSOR_DEVICE_ATTR(temp3_crit, S_IRUGO | S_IWUSR,
+       show_temp, store_temp, 0x1A);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 0x23);
+static SENSOR_DEVICE_ATTR_2(temp3_min_alarm, S_IRUGO,
+       show_bit, NULL, 0x36, 0x04);
+static SENSOR_DEVICE_ATTR_2(temp3_max_alarm, S_IRUGO,
+       show_bit, NULL, 0x35, 0x04);
+static SENSOR_DEVICE_ATTR_2(temp3_crit_alarm, S_IRUGO,
+       show_bit, NULL, 0x37, 0x04);
+static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO | S_IWUSR,
+       show_hyst, store_hyst, 0x1A);
+
+static struct attribute *mid_att_thermal[] = {
+       &sensor_dev_attr_temp1_min.dev_attr.attr,
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit.dev_attr.attr,
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp2_min.dev_attr.attr,
+       &sensor_dev_attr_temp2_max.dev_attr.attr,
+       &sensor_dev_attr_temp2_crit.dev_attr.attr,
+       &sensor_dev_attr_temp2_input.dev_attr.attr,
+       &sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp3_min.dev_attr.attr,
+       &sensor_dev_attr_temp3_max.dev_attr.attr,
+       &sensor_dev_attr_temp3_crit.dev_attr.attr,
+       &sensor_dev_attr_temp3_input.dev_attr.attr,
+       &sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
+       &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,
+       NULL
+};
+
+static const struct attribute_group m_thermal_gr = {
+       .attrs = mid_att_thermal
+};
+
+static int emc1403_detect(struct i2c_client *client,
+                       struct i2c_board_info *info)
+{
+       int id;
+       /* Check if thermal chip is SMSC and EMC1403 */
+
+       id = i2c_smbus_read_byte_data(client, THERMAL_SMSC_ID_REG);
+       if (id != 0x5d)
+               return -ENODEV;
+
+       /* Note: 0x25 is the 1404 which is very similar and this
+          driver could be extended */
+       id = i2c_smbus_read_byte_data(client, THERMAL_PID_REG);
+       if (id != 0x21)
+               return -ENODEV;
+
+       id = i2c_smbus_read_byte_data(client, THERMAL_REVISION_REG);
+       if (id != 0x01)
+               return -ENODEV;
+
+       strlcpy(info->type, "emc1403", I2C_NAME_SIZE);
+       return 0;
+}
+
+static int emc1403_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       int res;
+       struct thermal_data *data;
+
+       data = kzalloc(sizeof(struct thermal_data), GFP_KERNEL);
+       if (data == NULL) {
+               dev_warn(&client->dev, "out of memory");
+               return -ENOMEM;
+       }
+
+       i2c_set_clientdata(client, data);
+       mutex_init(&data->mutex);
+       data->hyst_valid = jiffies - 1;         /* Expired */
+
+       res = sysfs_create_group(&client->dev.kobj, &m_thermal_gr);
+       if (res) {
+               dev_warn(&client->dev, "create group failed\n");
+               hwmon_device_unregister(data->hwmon_dev);
+               goto thermal_error1;
+       }
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               res = PTR_ERR(data->hwmon_dev);
+               dev_warn(&client->dev, "register hwmon dev failed\n");
+               goto thermal_error2;
+       }
+       dev_info(&client->dev, "EMC1403 Thermal chip found\n");
+       return res;
+
+thermal_error2:
+       sysfs_remove_group(&client->dev.kobj, &m_thermal_gr);
+thermal_error1:
+       kfree(data);
+       return res;
+}
+
+static int emc1403_remove(struct i2c_client *client)
+{
+       struct thermal_data *data = i2c_get_clientdata(client);
+
+       hwmon_device_unregister(data->hwmon_dev);
+       sysfs_remove_group(&client->dev.kobj, &m_thermal_gr);
+       kfree(data);
+       return 0;
+}
+
+static const unsigned short emc1403_address_list[] = {
+       0x18, 0x2a, 0x4c, 0x4d, I2C_CLIENT_END
+};
+
+static const struct i2c_device_id emc1403_idtable[] = {
+       { "emc1403", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, emc1403_idtable);
+
+static struct i2c_driver sensor_emc1403 = {
+       .class = I2C_CLASS_HWMON,
+       .driver = {
+               .name = "emc1403",
+       },
+       .detect = emc1403_detect,
+       .probe = emc1403_probe,
+       .remove = emc1403_remove,
+       .id_table = emc1403_idtable,
+       .address_list = emc1403_address_list,
+};
+
+static int __init sensor_emc1403_init(void)
+{
+       return i2c_add_driver(&sensor_emc1403);
+}
+
+static void  __exit sensor_emc1403_exit(void)
+{
+       i2c_del_driver(&sensor_emc1403);
+}
+
+module_init(sensor_emc1403_init);
+module_exit(sensor_emc1403_exit);
+
+MODULE_AUTHOR("Kalhan Trisal <kalhan.trisal@intel.com");
+MODULE_DESCRIPTION("emc1403 Thermal Driver");
+MODULE_LICENSE("GPL v2");
index a95fa4256caa2af12f1b556a73837f4624d0fbcf..537841ef44b99d179318f7510dbf28dddedb0ed8 100644 (file)
@@ -856,21 +856,19 @@ static inline int superio_inb(int base, int reg)
 static int superio_inw(int base, int reg)
 {
        int val;
-       outb(reg++, base);
-       val = inb(base + 1) << 8;
-       outb(reg, base);
-       val |= inb(base + 1);
+       val  = superio_inb(base, reg) << 8;
+       val |= superio_inb(base, reg + 1);
        return val;
 }
 
 static inline void superio_enter(int base)
 {
        /* according to the datasheet the key must be send twice! */
-       outb( SIO_UNLOCK_KEY, base);
-       outb( SIO_UNLOCK_KEY, base);
+       outb(SIO_UNLOCK_KEY, base);
+       outb(SIO_UNLOCK_KEY, base);
 }
 
-static inline void superio_select( int base, int ld)
+static inline void superio_select(int base, int ld)
 {
        outb(SIO_REG_LDSEL, base);
        outb(ld, base + 1);
@@ -905,10 +903,8 @@ static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
 {
        u16 val;
 
-       outb(reg++, data->addr + ADDR_REG_OFFSET);
-       val = inb(data->addr + DATA_REG_OFFSET) << 8;
-       outb(reg, data->addr + ADDR_REG_OFFSET);
-       val |= inb(data->addr + DATA_REG_OFFSET);
+       val  = f71882fg_read8(data, reg) << 8;
+       val |= f71882fg_read8(data, reg + 1);
 
        return val;
 }
@@ -921,10 +917,8 @@ static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
 
 static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
 {
-       outb(reg++, data->addr + ADDR_REG_OFFSET);
-       outb(val >> 8, data->addr + DATA_REG_OFFSET);
-       outb(reg, data->addr + ADDR_REG_OFFSET);
-       outb(val & 255, data->addr + DATA_REG_OFFSET);
+       f71882fg_write8(data, reg,     val >> 8);
+       f71882fg_write8(data, reg + 1, val & 0xff);
 }
 
 static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr)
@@ -945,7 +939,7 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
        mutex_lock(&data->update_lock);
 
        /* Update once every 60 seconds */
-       if ( time_after(jiffies, data->last_limits + 60 * HZ ) ||
+       if (time_after(jiffies, data->last_limits + 60 * HZ) ||
                        !data->valid) {
                if (data->type == f71882fg || data->type == f71889fg) {
                        data->in1_max =
@@ -1127,8 +1121,12 @@ static ssize_t store_fan_full_speed(struct device *dev,
                                    const char *buf, size_t count)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
-       int nr = to_sensor_dev_attr_2(devattr)->index;
-       long val = simple_strtol(buf, NULL, 10);
+       int err, nr = to_sensor_dev_attr_2(devattr)->index;
+       long val;
+
+       err = strict_strtol(buf, 10, &val);
+       if (err)
+               return err;
 
        val = SENSORS_LIMIT(val, 23, 1500000);
        val = fan_to_reg(val);
@@ -1157,8 +1155,12 @@ static ssize_t store_fan_beep(struct device *dev, struct device_attribute
        *devattr, const char *buf, size_t count)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
-       int nr = to_sensor_dev_attr_2(devattr)->index;
-       unsigned long val = simple_strtoul(buf, NULL, 10);
+       int err, nr = to_sensor_dev_attr_2(devattr)->index;
+       unsigned long val;
+
+       err = strict_strtoul(buf, 10, &val);
+       if (err)
+               return err;
 
        mutex_lock(&data->update_lock);
        data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
@@ -1206,7 +1208,14 @@ static ssize_t store_in_max(struct device *dev, struct device_attribute
        *devattr, const char *buf, size_t count)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
-       long val = simple_strtol(buf, NULL, 10) / 8;
+       int err;
+       long val;
+
+       err = strict_strtol(buf, 10, &val);
+       if (err)
+               return err;
+
+       val /= 8;
        val = SENSORS_LIMIT(val, 0, 255);
 
        mutex_lock(&data->update_lock);
@@ -1233,8 +1242,12 @@ static ssize_t store_in_beep(struct device *dev, struct device_attribute
        *devattr, const char *buf, size_t count)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
-       int nr = to_sensor_dev_attr_2(devattr)->index;
-       unsigned long val = simple_strtoul(buf, NULL, 10);
+       int err, nr = to_sensor_dev_attr_2(devattr)->index;
+       unsigned long val;
+
+       err = strict_strtoul(buf, 10, &val);
+       if (err)
+               return err;
 
        mutex_lock(&data->update_lock);
        data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
@@ -1299,8 +1312,14 @@ static ssize_t store_temp_max(struct device *dev, struct device_attribute
        *devattr, const char *buf, size_t count)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
-       int nr = to_sensor_dev_attr_2(devattr)->index;
-       long val = simple_strtol(buf, NULL, 10) / 1000;
+       int err, nr = to_sensor_dev_attr_2(devattr)->index;
+       long val;
+
+       err = strict_strtol(buf, 10, &val);
+       if (err)
+               return err;
+
+       val /= 1000;
        val = SENSORS_LIMIT(val, 0, 255);
 
        mutex_lock(&data->update_lock);
@@ -1333,10 +1352,16 @@ static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
        *devattr, const char *buf, size_t count)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
-       int nr = to_sensor_dev_attr_2(devattr)->index;
-       long val = simple_strtol(buf, NULL, 10) / 1000;
+       int err, nr = to_sensor_dev_attr_2(devattr)->index;
        ssize_t ret = count;
        u8 reg;
+       long val;
+
+       err = strict_strtol(buf, 10, &val);
+       if (err)
+               return err;
+
+       val /= 1000;
 
        mutex_lock(&data->update_lock);
 
@@ -1372,8 +1397,14 @@ static ssize_t store_temp_crit(struct device *dev, struct device_attribute
        *devattr, const char *buf, size_t count)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
-       int nr = to_sensor_dev_attr_2(devattr)->index;
-       long val = simple_strtol(buf, NULL, 10) / 1000;
+       int err, nr = to_sensor_dev_attr_2(devattr)->index;
+       long val;
+
+       err = strict_strtol(buf, 10, &val);
+       if (err)
+               return err;
+
+       val /= 1000;
        val = SENSORS_LIMIT(val, 0, 255);
 
        mutex_lock(&data->update_lock);
@@ -1427,8 +1458,12 @@ static ssize_t store_temp_beep(struct device *dev, struct device_attribute
        *devattr, const char *buf, size_t count)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
-       int nr = to_sensor_dev_attr_2(devattr)->index;
-       unsigned long val = simple_strtoul(buf, NULL, 10);
+       int err, nr = to_sensor_dev_attr_2(devattr)->index;
+       unsigned long val;
+
+       err = strict_strtoul(buf, 10, &val);
+       if (err)
+               return err;
 
        mutex_lock(&data->update_lock);
        data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
@@ -1490,8 +1525,13 @@ static ssize_t store_pwm(struct device *dev,
                         size_t count)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
-       int nr = to_sensor_dev_attr_2(devattr)->index;
-       long val = simple_strtol(buf, NULL, 10);
+       int err, nr = to_sensor_dev_attr_2(devattr)->index;
+       long val;
+
+       err = strict_strtol(buf, 10, &val);
+       if (err)
+               return err;
+
        val = SENSORS_LIMIT(val, 0, 255);
 
        mutex_lock(&data->update_lock);
@@ -1551,8 +1591,12 @@ static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
                                *devattr, const char *buf, size_t count)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
-       int nr = to_sensor_dev_attr_2(devattr)->index;
-       long val = simple_strtol(buf, NULL, 10);
+       int err, nr = to_sensor_dev_attr_2(devattr)->index;
+       long val;
+
+       err = strict_strtol(buf, 10, &val);
+       if (err)
+               return err;
 
        /* Special case for F8000 pwm channel 3 which only does auto mode */
        if (data->type == f8000 && nr == 2 && val != 2)
@@ -1626,9 +1670,14 @@ static ssize_t store_pwm_auto_point_pwm(struct device *dev,
                                        const char *buf, size_t count)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
-       int pwm = to_sensor_dev_attr_2(devattr)->index;
+       int err, pwm = to_sensor_dev_attr_2(devattr)->index;
        int point = to_sensor_dev_attr_2(devattr)->nr;
-       long val = simple_strtol(buf, NULL, 10);
+       long val;
+
+       err = strict_strtol(buf, 10, &val);
+       if (err)
+               return err;
+
        val = SENSORS_LIMIT(val, 0, 255);
 
        mutex_lock(&data->update_lock);
@@ -1674,10 +1723,16 @@ static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
                                              const char *buf, size_t count)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
-       int nr = to_sensor_dev_attr_2(devattr)->index;
+       int err, nr = to_sensor_dev_attr_2(devattr)->index;
        int point = to_sensor_dev_attr_2(devattr)->nr;
-       long val = simple_strtol(buf, NULL, 10) / 1000;
        u8 reg;
+       long val;
+
+       err = strict_strtol(buf, 10, &val);
+       if (err)
+               return err;
+
+       val /= 1000;
 
        mutex_lock(&data->update_lock);
        data->pwm_auto_point_temp[nr][point] =
@@ -1716,8 +1771,12 @@ static ssize_t store_pwm_interpolate(struct device *dev,
                                     const char *buf, size_t count)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
-       int nr = to_sensor_dev_attr_2(devattr)->index;
-       unsigned long val = simple_strtoul(buf, NULL, 10);
+       int err, nr = to_sensor_dev_attr_2(devattr)->index;
+       unsigned long val;
+
+       err = strict_strtoul(buf, 10, &val);
+       if (err)
+               return err;
 
        mutex_lock(&data->update_lock);
        data->pwm_auto_point_mapping[nr] =
@@ -1752,8 +1811,12 @@ static ssize_t store_pwm_auto_point_channel(struct device *dev,
                                            const char *buf, size_t count)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
-       int nr = to_sensor_dev_attr_2(devattr)->index;
-       long val = simple_strtol(buf, NULL, 10);
+       int err, nr = to_sensor_dev_attr_2(devattr)->index;
+       long val;
+
+       err = strict_strtol(buf, 10, &val);
+       if (err)
+               return err;
 
        switch (val) {
        case 1:
@@ -1798,9 +1861,15 @@ static ssize_t store_pwm_auto_point_temp(struct device *dev,
                                         const char *buf, size_t count)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
-       int pwm = to_sensor_dev_attr_2(devattr)->index;
+       int err, pwm = to_sensor_dev_attr_2(devattr)->index;
        int point = to_sensor_dev_attr_2(devattr)->nr;
-       long val = simple_strtol(buf, NULL, 10) / 1000;
+       long val;
+
+       err = strict_strtol(buf, 10, &val);
+       if (err)
+               return err;
+
+       val /= 1000;
 
        if (data->type == f71889fg)
                val = SENSORS_LIMIT(val, -128, 127);
@@ -2109,6 +2178,13 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
        int err = -ENODEV;
        u16 devid;
 
+       /* Don't step on other drivers' I/O space by accident */
+       if (!request_region(sioaddr, 2, DRVNAME)) {
+               printk(KERN_ERR DRVNAME ": I/O address 0x%04x already in use\n",
+                               (int)sioaddr);
+               return -EBUSY;
+       }
+
        superio_enter(sioaddr);
 
        devid = superio_inw(sioaddr, SIO_REG_MANID);
@@ -2151,8 +2227,7 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
        }
 
        *address = superio_inw(sioaddr, SIO_REG_ADDR);
-       if (*address == 0)
-       {
+       if (*address == 0) {
                printk(KERN_WARNING DRVNAME ": Base address not set\n");
                goto exit;
        }
@@ -2164,6 +2239,7 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
                (int)superio_inb(sioaddr, SIO_REG_DEVREV));
 exit:
        superio_exit(sioaddr);
+       release_region(sioaddr, 2);
        return err;
 }
 
index 0627f7a5b9b822462f36341d8889f6bfb33c1986..b7ca2a9676cf8b62aab21fa7a04d205457828c6e 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/i2c.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
+#include <linux/smp_lock.h>
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include <linux/sysfs.h>
@@ -847,8 +848,7 @@ static ssize_t watchdog_write(struct file *filp, const char __user *buf,
        return count;
 }
 
-static int watchdog_ioctl(struct inode *inode, struct file *filp,
-       unsigned int cmd, unsigned long arg)
+static long watchdog_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
        static struct watchdog_info ident = {
                .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
@@ -858,6 +858,7 @@ static int watchdog_ioctl(struct inode *inode, struct file *filp,
        int i, ret = 0;
        struct fschmd_data *data = filp->private_data;
 
+       lock_kernel();
        switch (cmd) {
        case WDIOC_GETSUPPORT:
                ident.firmware_version = data->revision;
@@ -914,7 +915,7 @@ static int watchdog_ioctl(struct inode *inode, struct file *filp,
        default:
                ret = -ENOTTY;
        }
-
+       unlock_kernel();
        return ret;
 }
 
@@ -924,7 +925,7 @@ static const struct file_operations watchdog_fops = {
        .open = watchdog_open,
        .release = watchdog_release,
        .write = watchdog_write,
-       .ioctl = watchdog_ioctl,
+       .unlocked_ioctl = watchdog_ioctl,
 };
 
 
index b2f2277cad3c01c714bc36634e6c23d4f56fc317..6138f036b159956dbc4eec8282636db794485527 100644 (file)
@@ -41,6 +41,8 @@
 
 /* joystick device poll interval in milliseconds */
 #define MDPS_POLL_INTERVAL 50
+#define MDPS_POLL_MIN     0
+#define MDPS_POLL_MAX     2000
 /*
  * The sensor can also generate interrupts (DRDY) but it's pretty pointless
  * because they are generated even if the data do not change. So it's better
@@ -121,11 +123,9 @@ static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z)
        int position[3];
        int i;
 
-       mutex_lock(&lis3->mutex);
        position[0] = lis3->read_data(lis3, OUTX);
        position[1] = lis3->read_data(lis3, OUTY);
        position[2] = lis3->read_data(lis3, OUTZ);
-       mutex_unlock(&lis3->mutex);
 
        for (i = 0; i < 3; i++)
                position[i] = (position[i] * lis3->scale) / LIS3_ACCURACY;
@@ -249,8 +249,24 @@ void lis3lv02d_poweron(struct lis3lv02d *lis3)
 EXPORT_SYMBOL_GPL(lis3lv02d_poweron);
 
 
+static void lis3lv02d_joystick_poll(struct input_polled_dev *pidev)
+{
+       int x, y, z;
+
+       mutex_lock(&lis3_dev.mutex);
+       lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
+       input_report_abs(pidev->input, ABS_X, x);
+       input_report_abs(pidev->input, ABS_Y, y);
+       input_report_abs(pidev->input, ABS_Z, z);
+       input_sync(pidev->input);
+       mutex_unlock(&lis3_dev.mutex);
+}
+
 static irqreturn_t lis302dl_interrupt(int irq, void *dummy)
 {
+       if (!test_bit(0, &lis3_dev.misc_opened))
+               goto out;
+
        /*
         * Be careful: on some HP laptops the bios force DD when on battery and
         * the lid is closed. This leads to interrupts as soon as a little move
@@ -260,44 +276,93 @@ static irqreturn_t lis302dl_interrupt(int irq, void *dummy)
 
        wake_up_interruptible(&lis3_dev.misc_wait);
        kill_fasync(&lis3_dev.async_queue, SIGIO, POLL_IN);
+out:
+       if (lis3_dev.whoami == WAI_8B && lis3_dev.idev &&
+           lis3_dev.idev->input->users)
+               return IRQ_WAKE_THREAD;
        return IRQ_HANDLED;
 }
 
-static int lis3lv02d_misc_open(struct inode *inode, struct file *file)
+static void lis302dl_interrupt_handle_click(struct lis3lv02d *lis3)
 {
-       int ret;
+       struct input_dev *dev = lis3->idev->input;
+       u8 click_src;
 
-       if (test_and_set_bit(0, &lis3_dev.misc_opened))
-               return -EBUSY; /* already open */
+       mutex_lock(&lis3->mutex);
+       lis3->read(lis3, CLICK_SRC, &click_src);
 
-       atomic_set(&lis3_dev.count, 0);
+       if (click_src & CLICK_SINGLE_X) {
+               input_report_key(dev, lis3->mapped_btns[0], 1);
+               input_report_key(dev, lis3->mapped_btns[0], 0);
+       }
 
-       /*
-        * The sensor can generate interrupts for free-fall and direction
-        * detection (distinguishable with FF_WU_SRC and DD_SRC) but to keep
-        * the things simple and _fast_ we activate it only for free-fall, so
-        * no need to read register (very slow with ACPI). For the same reason,
-        * we forbid shared interrupts.
-        *
-        * IRQF_TRIGGER_RISING seems pointless on HP laptops because the
-        * io-apic is not configurable (and generates a warning) but I keep it
-        * in case of support for other hardware.
-        */
-       ret = request_irq(lis3_dev.irq, lis302dl_interrupt, IRQF_TRIGGER_RISING,
-                         DRIVER_NAME, &lis3_dev);
+       if (click_src & CLICK_SINGLE_Y) {
+               input_report_key(dev, lis3->mapped_btns[1], 1);
+               input_report_key(dev, lis3->mapped_btns[1], 0);
+       }
 
-       if (ret) {
-               clear_bit(0, &lis3_dev.misc_opened);
-               printk(KERN_ERR DRIVER_NAME ": IRQ%d allocation failed\n", lis3_dev.irq);
-               return -EBUSY;
+       if (click_src & CLICK_SINGLE_Z) {
+               input_report_key(dev, lis3->mapped_btns[2], 1);
+               input_report_key(dev, lis3->mapped_btns[2], 0);
        }
+       input_sync(dev);
+       mutex_unlock(&lis3->mutex);
+}
+
+static void lis302dl_interrupt_handle_ff_wu(struct lis3lv02d *lis3)
+{
+       u8 wu1_src;
+       u8 wu2_src;
+
+       lis3->read(lis3, FF_WU_SRC_1, &wu1_src);
+       lis3->read(lis3, FF_WU_SRC_2, &wu2_src);
+
+       wu1_src = wu1_src & FF_WU_SRC_IA ? wu1_src : 0;
+       wu2_src = wu2_src & FF_WU_SRC_IA ? wu2_src : 0;
+
+       /* joystick poll is internally protected by the lis3->mutex. */
+       if (wu1_src || wu2_src)
+               lis3lv02d_joystick_poll(lis3_dev.idev);
+}
+
+static irqreturn_t lis302dl_interrupt_thread1_8b(int irq, void *data)
+{
+
+       struct lis3lv02d *lis3 = data;
+
+       if ((lis3->pdata->irq_cfg & LIS3_IRQ1_MASK) == LIS3_IRQ1_CLICK)
+               lis302dl_interrupt_handle_click(lis3);
+       else
+               lis302dl_interrupt_handle_ff_wu(lis3);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t lis302dl_interrupt_thread2_8b(int irq, void *data)
+{
+
+       struct lis3lv02d *lis3 = data;
+
+       if ((lis3->pdata->irq_cfg & LIS3_IRQ2_MASK) == LIS3_IRQ2_CLICK)
+               lis302dl_interrupt_handle_click(lis3);
+       else
+               lis302dl_interrupt_handle_ff_wu(lis3);
+
+       return IRQ_HANDLED;
+}
+
+static int lis3lv02d_misc_open(struct inode *inode, struct file *file)
+{
+       if (test_and_set_bit(0, &lis3_dev.misc_opened))
+               return -EBUSY; /* already open */
+
+       atomic_set(&lis3_dev.count, 0);
        return 0;
 }
 
 static int lis3lv02d_misc_release(struct inode *inode, struct file *file)
 {
        fasync_helper(-1, file, 0, &lis3_dev.async_queue);
-       free_irq(lis3_dev.irq, &lis3_dev);
        clear_bit(0, &lis3_dev.misc_opened); /* release the device */
        return 0;
 }
@@ -380,22 +445,12 @@ static struct miscdevice lis3lv02d_misc_device = {
        .fops    = &lis3lv02d_misc_fops,
 };
 
-static void lis3lv02d_joystick_poll(struct input_polled_dev *pidev)
-{
-       int x, y, z;
-
-       lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
-       input_report_abs(pidev->input, ABS_X, x);
-       input_report_abs(pidev->input, ABS_Y, y);
-       input_report_abs(pidev->input, ABS_Z, z);
-       input_sync(pidev->input);
-}
-
 int lis3lv02d_joystick_enable(void)
 {
        struct input_dev *input_dev;
        int err;
        int max_val, fuzz, flat;
+       int btns[] = {BTN_X, BTN_Y, BTN_Z};
 
        if (lis3_dev.idev)
                return -EINVAL;
@@ -406,6 +461,8 @@ int lis3lv02d_joystick_enable(void)
 
        lis3_dev.idev->poll = lis3lv02d_joystick_poll;
        lis3_dev.idev->poll_interval = MDPS_POLL_INTERVAL;
+       lis3_dev.idev->poll_interval_min = MDPS_POLL_MIN;
+       lis3_dev.idev->poll_interval_max = MDPS_POLL_MAX;
        input_dev = lis3_dev.idev->input;
 
        input_dev->name       = "ST LIS3LV02DL Accelerometer";
@@ -422,6 +479,10 @@ int lis3lv02d_joystick_enable(void)
        input_set_abs_params(input_dev, ABS_Y, -max_val, max_val, fuzz, flat);
        input_set_abs_params(input_dev, ABS_Z, -max_val, max_val, fuzz, flat);
 
+       lis3_dev.mapped_btns[0] = lis3lv02d_get_axis(abs(lis3_dev.ac.x), btns);
+       lis3_dev.mapped_btns[1] = lis3lv02d_get_axis(abs(lis3_dev.ac.y), btns);
+       lis3_dev.mapped_btns[2] = lis3lv02d_get_axis(abs(lis3_dev.ac.z), btns);
+
        err = input_register_polled_device(lis3_dev.idev);
        if (err) {
                input_free_polled_device(lis3_dev.idev);
@@ -434,6 +495,11 @@ EXPORT_SYMBOL_GPL(lis3lv02d_joystick_enable);
 
 void lis3lv02d_joystick_disable(void)
 {
+       if (lis3_dev.irq)
+               free_irq(lis3_dev.irq, &lis3_dev);
+       if (lis3_dev.pdata && lis3_dev.pdata->irq2)
+               free_irq(lis3_dev.pdata->irq2, &lis3_dev);
+
        if (!lis3_dev.idev)
                return;
 
@@ -462,7 +528,9 @@ static ssize_t lis3lv02d_position_show(struct device *dev,
 {
        int x, y, z;
 
+       mutex_lock(&lis3_dev.mutex);
        lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
+       mutex_unlock(&lis3_dev.mutex);
        return sprintf(buf, "(%d,%d,%d)\n", x, y, z);
 }
 
@@ -521,12 +589,70 @@ int lis3lv02d_remove_fs(struct lis3lv02d *lis3)
 }
 EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs);
 
+static void lis3lv02d_8b_configure(struct lis3lv02d *dev,
+                               struct lis3lv02d_platform_data *p)
+{
+       int err;
+       int ctrl2 = p->hipass_ctrl;
+
+       if (p->click_flags) {
+               dev->write(dev, CLICK_CFG, p->click_flags);
+               dev->write(dev, CLICK_TIMELIMIT, p->click_time_limit);
+               dev->write(dev, CLICK_LATENCY, p->click_latency);
+               dev->write(dev, CLICK_WINDOW, p->click_window);
+               dev->write(dev, CLICK_THSZ, p->click_thresh_z & 0xf);
+               dev->write(dev, CLICK_THSY_X,
+                       (p->click_thresh_x & 0xf) |
+                       (p->click_thresh_y << 4));
+
+               if (dev->idev) {
+                       struct input_dev *input_dev = lis3_dev.idev->input;
+                       input_set_capability(input_dev, EV_KEY, BTN_X);
+                       input_set_capability(input_dev, EV_KEY, BTN_Y);
+                       input_set_capability(input_dev, EV_KEY, BTN_Z);
+               }
+       }
+
+       if (p->wakeup_flags) {
+               dev->write(dev, FF_WU_CFG_1, p->wakeup_flags);
+               dev->write(dev, FF_WU_THS_1, p->wakeup_thresh & 0x7f);
+               /* default to 2.5ms for now */
+               dev->write(dev, FF_WU_DURATION_1, 1);
+               ctrl2 ^= HP_FF_WU1; /* Xor to keep compatible with old pdata*/
+       }
+
+       if (p->wakeup_flags2) {
+               dev->write(dev, FF_WU_CFG_2, p->wakeup_flags2);
+               dev->write(dev, FF_WU_THS_2, p->wakeup_thresh2 & 0x7f);
+               /* default to 2.5ms for now */
+               dev->write(dev, FF_WU_DURATION_2, 1);
+               ctrl2 ^= HP_FF_WU2; /* Xor to keep compatible with old pdata*/
+       }
+       /* Configure hipass filters */
+       dev->write(dev, CTRL_REG2, ctrl2);
+
+       if (p->irq2) {
+               err = request_threaded_irq(p->irq2,
+                                       NULL,
+                                       lis302dl_interrupt_thread2_8b,
+                                       IRQF_TRIGGER_RISING |
+                                       IRQF_ONESHOT,
+                                       DRIVER_NAME, &lis3_dev);
+               if (err < 0)
+                       printk(KERN_ERR DRIVER_NAME
+                               "No second IRQ. Limited functionality\n");
+       }
+}
+
 /*
  * Initialise the accelerometer and the various subsystems.
  * Should be rather independent of the bus system.
  */
 int lis3lv02d_init_device(struct lis3lv02d *dev)
 {
+       int err;
+       irq_handler_t thread_fn;
+
        dev->whoami = lis3lv02d_read_8(dev, WHO_AM_I);
 
        switch (dev->whoami) {
@@ -567,25 +693,8 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
        if (dev->pdata) {
                struct lis3lv02d_platform_data *p = dev->pdata;
 
-               if (p->click_flags && (dev->whoami == WAI_8B)) {
-                       dev->write(dev, CLICK_CFG, p->click_flags);
-                       dev->write(dev, CLICK_TIMELIMIT, p->click_time_limit);
-                       dev->write(dev, CLICK_LATENCY, p->click_latency);
-                       dev->write(dev, CLICK_WINDOW, p->click_window);
-                       dev->write(dev, CLICK_THSZ, p->click_thresh_z & 0xf);
-                       dev->write(dev, CLICK_THSY_X,
-                                       (p->click_thresh_x & 0xf) |
-                                       (p->click_thresh_y << 4));
-               }
-
-               if (p->wakeup_flags && (dev->whoami == WAI_8B)) {
-                       dev->write(dev, FF_WU_CFG_1, p->wakeup_flags);
-                       dev->write(dev, FF_WU_THS_1, p->wakeup_thresh & 0x7f);
-                       /* default to 2.5ms for now */
-                       dev->write(dev, FF_WU_DURATION_1, 1);
-                       /* enable high pass filter for both free-fall units */
-                       dev->write(dev, CTRL_REG2, HP_FF_WU1 | HP_FF_WU2);
-               }
+               if (dev->whoami == WAI_8B)
+                       lis3lv02d_8b_configure(dev, p);
 
                if (p->irq_cfg)
                        dev->write(dev, CTRL_REG3, p->irq_cfg);
@@ -598,6 +707,32 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
                goto out;
        }
 
+       /*
+        * The sensor can generate interrupts for free-fall and direction
+        * detection (distinguishable with FF_WU_SRC and DD_SRC) but to keep
+        * the things simple and _fast_ we activate it only for free-fall, so
+        * no need to read register (very slow with ACPI). For the same reason,
+        * we forbid shared interrupts.
+        *
+        * IRQF_TRIGGER_RISING seems pointless on HP laptops because the
+        * io-apic is not configurable (and generates a warning) but I keep it
+        * in case of support for other hardware.
+        */
+       if (dev->whoami == WAI_8B)
+               thread_fn = lis302dl_interrupt_thread1_8b;
+       else
+               thread_fn = NULL;
+
+       err = request_threaded_irq(dev->irq, lis302dl_interrupt,
+                               thread_fn,
+                               IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+                               DRIVER_NAME, &lis3_dev);
+
+       if (err < 0) {
+               printk(KERN_ERR DRIVER_NAME "Cannot get IRQ\n");
+               goto out;
+       }
+
        if (misc_register(&lis3lv02d_misc_device))
                printk(KERN_ERR DRIVER_NAME ": misc_register failed\n");
 out:
index e6a01f44709b9de41a3821e9cfacd07bb42a9691..854091380e33887c365898a867af46e70964dee5 100644 (file)
@@ -196,6 +196,16 @@ enum lis3lv02d_dd_src {
        DD_SRC_IA       = 0x40,
 };
 
+enum lis3lv02d_click_src_8b {
+       CLICK_SINGLE_X  = 0x01,
+       CLICK_DOUBLE_X  = 0x02,
+       CLICK_SINGLE_Y  = 0x04,
+       CLICK_DOUBLE_Y  = 0x08,
+       CLICK_SINGLE_Z  = 0x10,
+       CLICK_DOUBLE_Z  = 0x20,
+       CLICK_IA        = 0x40,
+};
+
 struct axis_conversion {
        s8      x;
        s8      y;
@@ -223,6 +233,7 @@ struct lis3lv02d {
        struct platform_device  *pdev;     /* platform device */
        atomic_t                count;     /* interrupt count after last read */
        struct axis_conversion  ac;        /* hw -> logical axis */
+       int                     mapped_btns[3];
 
        u32                     irq;       /* IRQ number */
        struct fasync_struct    *async_queue; /* queue for the misc device */
index bf81aff7051dd44b009a062b9f3f5ba7799429c2..776aeb3019d2b443a585fb38b96750ca53174099 100644 (file)
@@ -53,7 +53,7 @@
  * Address is fully defined internally and cannot be changed.
  */
 
-static const unsigned short normal_i2c[] = { 0x4c, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END };
 
 /*
  * The LM63 registers
@@ -131,12 +131,15 @@ static struct lm63_data *lm63_update_device(struct device *dev);
 static int lm63_detect(struct i2c_client *client, struct i2c_board_info *info);
 static void lm63_init_client(struct i2c_client *client);
 
+enum chips { lm63, lm64 };
+
 /*
  * Driver data (common to all clients)
  */
 
 static const struct i2c_device_id lm63_id[] = {
-       { "lm63", 0 },
+       { "lm63", lm63 },
+       { "lm64", lm64 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, lm63_id);
@@ -422,6 +425,7 @@ static int lm63_detect(struct i2c_client *new_client,
        struct i2c_adapter *adapter = new_client->adapter;
        u8 man_id, chip_id, reg_config1, reg_config2;
        u8 reg_alert_status, reg_alert_mask;
+       int address = new_client->addr;
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -ENODEV;
@@ -439,7 +443,6 @@ static int lm63_detect(struct i2c_client *new_client,
                         LM63_REG_ALERT_MASK);
 
        if (man_id != 0x01 /* National Semiconductor */
-        || chip_id != 0x41 /* LM63 */
         || (reg_config1 & 0x18) != 0x00
         || (reg_config2 & 0xF8) != 0x00
         || (reg_alert_status & 0x20) != 0x00
@@ -450,7 +453,12 @@ static int lm63_detect(struct i2c_client *new_client,
                return -ENODEV;
        }
 
-       strlcpy(info->type, "lm63", I2C_NAME_SIZE);
+       if (chip_id == 0x41 && address == 0x4c)
+               strlcpy(info->type, "lm63", I2C_NAME_SIZE);
+       else if (chip_id == 0x51 && (address == 0x18 || address == 0x4e))
+               strlcpy(info->type, "lm64", I2C_NAME_SIZE);
+       else
+               return -ENODEV;
 
        return 0;
 }
index 8ae2cfe2d827257a0e1eedbd61d1dc0e9fc8d572..56463428a419ce8f4222f5504b96f57cd44503fd 100644 (file)
@@ -46,6 +46,7 @@ enum lm75_type {              /* keep sorted in alphabetical order */
        tcn75,
        tmp100,
        tmp101,
+       tmp105,
        tmp175,
        tmp275,
        tmp75,
@@ -220,6 +221,7 @@ static const struct i2c_device_id lm75_ids[] = {
        { "tcn75", tcn75, },
        { "tmp100", tmp100, },
        { "tmp101", tmp101, },
+       { "tmp105", tmp105, },
        { "tmp175", tmp175, },
        { "tmp275", tmp275, },
        { "tmp75", tmp75, },
index 7cc2708871abb7784afda170bd839517604ccb2d..760ef72eea56f943a9494ad3c052526f5d000afe 100644 (file)
@@ -982,7 +982,8 @@ static struct lm90_data *lm90_update_device(struct device *dev)
 
        mutex_lock(&data->update_lock);
 
-       if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
+       if (time_after(jiffies, data->last_updated + HZ / 2 + HZ / 10)
+        || !data->valid) {
                u8 h, l;
 
                dev_dbg(&client->dev, "Updating lm90 data.\n");
index 65c232a9d0c5a917b533e2aeac34c2c13aa4fba5..21d201befc2cdb7aeebb11c495f5ba3c10e74215 100644 (file)
@@ -45,9 +45,7 @@ enum ltc4245_cmd {
        LTC4245_VEEIN                   = 0x19,
        LTC4245_VEESENSE                = 0x1a,
        LTC4245_VEEOUT                  = 0x1b,
-       LTC4245_GPIOADC1                = 0x1c,
-       LTC4245_GPIOADC2                = 0x1d,
-       LTC4245_GPIOADC3                = 0x1e,
+       LTC4245_GPIOADC                 = 0x1c,
 };
 
 struct ltc4245_data {
@@ -61,7 +59,7 @@ struct ltc4245_data {
        u8 cregs[0x08];
 
        /* Voltage registers */
-       u8 vregs[0x0f];
+       u8 vregs[0x0d];
 };
 
 static struct ltc4245_data *ltc4245_update_device(struct device *dev)
@@ -86,7 +84,7 @@ static struct ltc4245_data *ltc4245_update_device(struct device *dev)
                                data->cregs[i] = val;
                }
 
-               /* Read voltage registers -- 0x10 to 0x1f */
+               /* Read voltage registers -- 0x10 to 0x1c */
                for (i = 0; i < ARRAY_SIZE(data->vregs); i++) {
                        val = i2c_smbus_read_byte_data(client, i+0x10);
                        if (unlikely(val < 0))
@@ -128,9 +126,7 @@ static int ltc4245_get_voltage(struct device *dev, u8 reg)
        case LTC4245_VEEOUT:
                voltage = regval * -55;
                break;
-       case LTC4245_GPIOADC1:
-       case LTC4245_GPIOADC2:
-       case LTC4245_GPIOADC3:
+       case LTC4245_GPIOADC:
                voltage = regval * 10;
                break;
        default:
@@ -297,9 +293,7 @@ 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_GPIOADC1);
-LTC4245_VOLTAGE(in10_input,                    LTC4245_GPIOADC2);
-LTC4245_VOLTAGE(in11_input,                    LTC4245_GPIOADC3);
+LTC4245_VOLTAGE(in9_input,                     LTC4245_GPIOADC);
 
 /* Power Consumption (virtual) */
 LTC4245_POWER(power1_input,                    LTC4245_12VSENSE);
@@ -342,8 +336,6 @@ static struct attribute *ltc4245_attributes[] = {
        &sensor_dev_attr_in8_min_alarm.dev_attr.attr,
 
        &sensor_dev_attr_in9_input.dev_attr.attr,
-       &sensor_dev_attr_in10_input.dev_attr.attr,
-       &sensor_dev_attr_in11_input.dev_attr.attr,
 
        &sensor_dev_attr_power1_input.dev_attr.attr,
        &sensor_dev_attr_power2_input.dev_attr.attr,
diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c
new file mode 100644 (file)
index 0000000..8013895
--- /dev/null
@@ -0,0 +1,321 @@
+/* Texas Instruments TMP102 SMBus temperature sensor driver
+ *
+ * Copyright (C) 2010 Steven King <sfking@fdwdc.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.
+ *
+ * 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/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+
+#define        DRIVER_NAME "tmp102"
+
+#define        TMP102_TEMP_REG                 0x00
+#define        TMP102_CONF_REG                 0x01
+/* note: these bit definitions are byte swapped */
+#define                TMP102_CONF_SD          0x0100
+#define                TMP102_CONF_TM          0x0200
+#define                TMP102_CONF_POL         0x0400
+#define                TMP102_CONF_F0          0x0800
+#define                TMP102_CONF_F1          0x1000
+#define                TMP102_CONF_R0          0x2000
+#define                TMP102_CONF_R1          0x4000
+#define                TMP102_CONF_OS          0x8000
+#define                TMP102_CONF_EM          0x0010
+#define                TMP102_CONF_AL          0x0020
+#define                TMP102_CONF_CR0         0x0040
+#define                TMP102_CONF_CR1         0x0080
+#define        TMP102_TLOW_REG                 0x02
+#define        TMP102_THIGH_REG                0x03
+
+struct tmp102 {
+       struct device *hwmon_dev;
+       struct mutex lock;
+       u16 config_orig;
+       unsigned long last_update;
+       int temp[3];
+};
+
+/* SMBus specifies low byte first, but the TMP102 returns high byte first,
+ * so we have to swab16 the values */
+static inline int tmp102_read_reg(struct i2c_client *client, u8 reg)
+{
+       int result = i2c_smbus_read_word_data(client, reg);
+       return result < 0 ? result : swab16(result);
+}
+
+static inline int tmp102_write_reg(struct i2c_client *client, u8 reg, u16 val)
+{
+       return i2c_smbus_write_word_data(client, reg, swab16(val));
+}
+
+/* convert left adjusted 13-bit TMP102 register value to milliCelsius */
+static inline int tmp102_reg_to_mC(s16 val)
+{
+       return ((val & ~0x01) * 1000) / 128;
+}
+
+/* convert milliCelsius to left adjusted 13-bit TMP102 register value */
+static inline u16 tmp102_mC_to_reg(int val)
+{
+       return (val * 128) / 1000;
+}
+
+static const u8 tmp102_reg[] = {
+       TMP102_TEMP_REG,
+       TMP102_TLOW_REG,
+       TMP102_THIGH_REG,
+};
+
+static struct tmp102 *tmp102_update_device(struct i2c_client *client)
+{
+       struct tmp102 *tmp102 = i2c_get_clientdata(client);
+
+       mutex_lock(&tmp102->lock);
+       if (time_after(jiffies, tmp102->last_update + HZ / 3)) {
+               int i;
+               for (i = 0; i < ARRAY_SIZE(tmp102->temp); ++i) {
+                       int status = tmp102_read_reg(client, tmp102_reg[i]);
+                       if (status > -1)
+                               tmp102->temp[i] = tmp102_reg_to_mC(status);
+               }
+               tmp102->last_update = jiffies;
+       }
+       mutex_unlock(&tmp102->lock);
+       return tmp102;
+}
+
+static ssize_t tmp102_show_temp(struct device *dev,
+                               struct device_attribute *attr,
+                               char *buf)
+{
+       struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
+       struct tmp102 *tmp102 = tmp102_update_device(to_i2c_client(dev));
+
+       return sprintf(buf, "%d\n", tmp102->temp[sda->index]);
+}
+
+static ssize_t tmp102_set_temp(struct device *dev,
+                              struct device_attribute *attr,
+                              const char *buf, size_t count)
+{
+       struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct tmp102 *tmp102 = i2c_get_clientdata(client);
+       long val;
+       int status;
+
+       if (strict_strtol(buf, 10, &val) < 0)
+               return -EINVAL;
+       val = SENSORS_LIMIT(val, -256000, 255000);
+
+       mutex_lock(&tmp102->lock);
+       tmp102->temp[sda->index] = val;
+       status = tmp102_write_reg(client, tmp102_reg[sda->index],
+                                 tmp102_mC_to_reg(val));
+       mutex_unlock(&tmp102->lock);
+       return status ? : count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, tmp102_show_temp, NULL , 0);
+
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, tmp102_show_temp,
+                         tmp102_set_temp, 1);
+
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, tmp102_show_temp,
+                         tmp102_set_temp, 2);
+
+static struct attribute *tmp102_attributes[] = {
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group tmp102_attr_group = {
+       .attrs = tmp102_attributes,
+};
+
+#define TMP102_CONFIG  (TMP102_CONF_TM | TMP102_CONF_EM | TMP102_CONF_CR1)
+#define TMP102_CONFIG_RD_ONLY (TMP102_CONF_R0 | TMP102_CONF_R1 | TMP102_CONF_AL)
+
+static int __devinit tmp102_probe(struct i2c_client *client,
+                                 const struct i2c_device_id *id)
+{
+       struct tmp102 *tmp102;
+       int status;
+
+       if (!i2c_check_functionality(client->adapter,
+                                    I2C_FUNC_SMBUS_WORD_DATA)) {
+               dev_err(&client->dev, "adapter doesnt support SMBus word "
+                       "transactions\n");
+               return -ENODEV;
+       }
+
+       tmp102 = kzalloc(sizeof(*tmp102), GFP_KERNEL);
+       if (!tmp102) {
+               dev_dbg(&client->dev, "kzalloc failed\n");
+               return -ENOMEM;
+       }
+       i2c_set_clientdata(client, tmp102);
+
+       status = tmp102_read_reg(client, TMP102_CONF_REG);
+       if (status < 0) {
+               dev_err(&client->dev, "error reading config register\n");
+               goto fail_free;
+       }
+       tmp102->config_orig = status;
+       status = tmp102_write_reg(client, TMP102_CONF_REG, TMP102_CONFIG);
+       if (status < 0) {
+               dev_err(&client->dev, "error writing config register\n");
+               goto fail_restore_config;
+       }
+       status = tmp102_read_reg(client, TMP102_CONF_REG);
+       if (status < 0) {
+               dev_err(&client->dev, "error reading config register\n");
+               goto fail_restore_config;
+       }
+       status &= ~TMP102_CONFIG_RD_ONLY;
+       if (status != TMP102_CONFIG) {
+               dev_err(&client->dev, "config settings did not stick\n");
+               status = -ENODEV;
+               goto fail_restore_config;
+       }
+       tmp102->last_update = jiffies - HZ;
+       mutex_init(&tmp102->lock);
+
+       status = sysfs_create_group(&client->dev.kobj, &tmp102_attr_group);
+       if (status) {
+               dev_dbg(&client->dev, "could not create sysfs files\n");
+               goto fail_restore_config;
+       }
+       tmp102->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(tmp102->hwmon_dev)) {
+               dev_dbg(&client->dev, "unable to register hwmon device\n");
+               status = PTR_ERR(tmp102->hwmon_dev);
+               goto fail_remove_sysfs;
+       }
+
+       dev_info(&client->dev, "initialized\n");
+
+       return 0;
+
+fail_remove_sysfs:
+       sysfs_remove_group(&client->dev.kobj, &tmp102_attr_group);
+fail_restore_config:
+       tmp102_write_reg(client, TMP102_CONF_REG, tmp102->config_orig);
+fail_free:
+       i2c_set_clientdata(client, NULL);
+       kfree(tmp102);
+
+       return status;
+}
+
+static int __devexit tmp102_remove(struct i2c_client *client)
+{
+       struct tmp102 *tmp102 = i2c_get_clientdata(client);
+
+       hwmon_device_unregister(tmp102->hwmon_dev);
+       sysfs_remove_group(&client->dev.kobj, &tmp102_attr_group);
+
+       /* Stop monitoring if device was stopped originally */
+       if (tmp102->config_orig & TMP102_CONF_SD) {
+               int config;
+
+               config = tmp102_read_reg(client, TMP102_CONF_REG);
+               if (config >= 0)
+                       tmp102_write_reg(client, TMP102_CONF_REG,
+                                        config | TMP102_CONF_SD);
+       }
+
+       i2c_set_clientdata(client, NULL);
+       kfree(tmp102);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int tmp102_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       int config;
+
+       config = tmp102_read_reg(client, TMP102_CONF_REG);
+       if (config < 0)
+               return config;
+
+       config |= TMP102_CONF_SD;
+       return tmp102_write_reg(client, TMP102_CONF_REG, config);
+}
+
+static int tmp102_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       int config;
+
+       config = tmp102_read_reg(client, TMP102_CONF_REG);
+       if (config < 0)
+               return config;
+
+       config &= ~TMP102_CONF_SD;
+       return tmp102_write_reg(client, TMP102_CONF_REG, config);
+}
+
+static const struct dev_pm_ops tmp102_dev_pm_ops = {
+       .suspend        = tmp102_suspend,
+       .resume         = tmp102_resume,
+};
+
+#define TMP102_DEV_PM_OPS (&tmp102_dev_pm_ops)
+#else
+#define        TMP102_DEV_PM_OPS NULL
+#endif /* CONFIG_PM */
+
+static const struct i2c_device_id tmp102_id[] = {
+       { "tmp102", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, tmp102_id);
+
+static struct i2c_driver tmp102_driver = {
+       .driver.name    = DRIVER_NAME,
+       .driver.pm      = TMP102_DEV_PM_OPS,
+       .probe          = tmp102_probe,
+       .remove         = __devexit_p(tmp102_remove),
+       .id_table       = tmp102_id,
+};
+
+static int __init tmp102_init(void)
+{
+       return i2c_add_driver(&tmp102_driver);
+}
+module_init(tmp102_init);
+
+static void __exit tmp102_exit(void)
+{
+       i2c_del_driver(&tmp102_driver);
+}
+module_exit(tmp102_exit);
+
+MODULE_AUTHOR("Steven King <sfking@fdwdc.com>");
+MODULE_DESCRIPTION("Texas Instruments TMP102 temperature sensor driver");
+MODULE_LICENSE("GPL");
index d14a1af9f550ae86eeffc5f585129921f41b84e2..ad8d535235c5521f2ec2ed416828706549ae276b 100644 (file)
@@ -91,17 +91,6 @@ static const u8 TMP411_TEMP_HIGHEST_LSB[2]           = { 0x33, 0x37 };
 #define TMP401_DEVICE_ID                       0x11
 #define TMP411_DEVICE_ID                       0x12
 
-/*
- * Functions declarations
- */
-
-static int tmp401_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id);
-static int tmp401_detect(struct i2c_client *client,
-                        struct i2c_board_info *info);
-static int tmp401_remove(struct i2c_client *client);
-static struct tmp401_data *tmp401_update_device(struct device *dev);
-
 /*
  * Driver data (common to all clients)
  */
@@ -113,18 +102,6 @@ static const struct i2c_device_id tmp401_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, tmp401_id);
 
-static struct i2c_driver tmp401_driver = {
-       .class          = I2C_CLASS_HWMON,
-       .driver = {
-               .name   = "tmp401",
-       },
-       .probe          = tmp401_probe,
-       .remove         = tmp401_remove,
-       .id_table       = tmp401_id,
-       .detect         = tmp401_detect,
-       .address_list   = normal_i2c,
-};
-
 /*
  * Client data (each client gets its own)
  */
@@ -194,6 +171,71 @@ static u8 tmp401_crit_temp_to_register(long temp, u8 config)
        return (temp + 500) / 1000;
 }
 
+static struct tmp401_data *tmp401_update_device_reg16(
+       struct i2c_client *client, struct tmp401_data *data)
+{
+       int i;
+
+       for (i = 0; i < 2; i++) {
+               /*
+                * High byte must be read first immediately followed
+                * by the low byte
+                */
+               data->temp[i] = i2c_smbus_read_byte_data(client,
+                       TMP401_TEMP_MSB[i]) << 8;
+               data->temp[i] |= i2c_smbus_read_byte_data(client,
+                       TMP401_TEMP_LSB[i]);
+               data->temp_low[i] = i2c_smbus_read_byte_data(client,
+                       TMP401_TEMP_LOW_LIMIT_MSB_READ[i]) << 8;
+               data->temp_low[i] |= i2c_smbus_read_byte_data(client,
+                       TMP401_TEMP_LOW_LIMIT_LSB[i]);
+               data->temp_high[i] = i2c_smbus_read_byte_data(client,
+                       TMP401_TEMP_HIGH_LIMIT_MSB_READ[i]) << 8;
+               data->temp_high[i] |= i2c_smbus_read_byte_data(client,
+                       TMP401_TEMP_HIGH_LIMIT_LSB[i]);
+               data->temp_crit[i] = i2c_smbus_read_byte_data(client,
+                       TMP401_TEMP_CRIT_LIMIT[i]);
+
+               if (data->kind == tmp411) {
+                       data->temp_lowest[i] = i2c_smbus_read_byte_data(client,
+                               TMP411_TEMP_LOWEST_MSB[i]) << 8;
+                       data->temp_lowest[i] |= i2c_smbus_read_byte_data(
+                               client, TMP411_TEMP_LOWEST_LSB[i]);
+
+                       data->temp_highest[i] = i2c_smbus_read_byte_data(
+                               client, TMP411_TEMP_HIGHEST_MSB[i]) << 8;
+                       data->temp_highest[i] |= i2c_smbus_read_byte_data(
+                               client, TMP411_TEMP_HIGHEST_LSB[i]);
+               }
+       }
+       return data;
+}
+
+static struct tmp401_data *tmp401_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct tmp401_data *data = i2c_get_clientdata(client);
+
+       mutex_lock(&data->update_lock);
+
+       if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+               data->status = i2c_smbus_read_byte_data(client, TMP401_STATUS);
+               data->config = i2c_smbus_read_byte_data(client,
+                                               TMP401_CONFIG_READ);
+               tmp401_update_device_reg16(client, data);
+
+               data->temp_crit_hyst = i2c_smbus_read_byte_data(client,
+                                               TMP401_TEMP_CRIT_HYST);
+
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+
+       mutex_unlock(&data->update_lock);
+
+       return data;
+}
+
 static ssize_t show_temp_value(struct device *dev,
        struct device_attribute *devattr, char *buf)
 {
@@ -420,30 +462,36 @@ static ssize_t reset_temp_history(struct device *dev,
 }
 
 static struct sensor_device_attribute tmp401_attr[] = {
-       SENSOR_ATTR(temp1_input, 0444, show_temp_value, NULL, 0),
-       SENSOR_ATTR(temp1_min, 0644, show_temp_min, store_temp_min, 0),
-       SENSOR_ATTR(temp1_max, 0644, show_temp_max, store_temp_max, 0),
-       SENSOR_ATTR(temp1_crit, 0644, show_temp_crit, store_temp_crit, 0),
-       SENSOR_ATTR(temp1_crit_hyst, 0644, show_temp_crit_hyst,
+       SENSOR_ATTR(temp1_input, S_IRUGO, show_temp_value, NULL, 0),
+       SENSOR_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min,
+                   store_temp_min, 0),
+       SENSOR_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
+                   store_temp_max, 0),
+       SENSOR_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp_crit,
+                   store_temp_crit, 0),
+       SENSOR_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_crit_hyst,
                    store_temp_crit_hyst, 0),
-       SENSOR_ATTR(temp1_min_alarm, 0444, show_status, NULL,
+       SENSOR_ATTR(temp1_min_alarm, S_IRUGO, show_status, NULL,
                    TMP401_STATUS_LOCAL_LOW),
-       SENSOR_ATTR(temp1_max_alarm, 0444, show_status, NULL,
+       SENSOR_ATTR(temp1_max_alarm, S_IRUGO, show_status, NULL,
                    TMP401_STATUS_LOCAL_HIGH),
-       SENSOR_ATTR(temp1_crit_alarm, 0444, show_status, NULL,
+       SENSOR_ATTR(temp1_crit_alarm, S_IRUGO, show_status, NULL,
                    TMP401_STATUS_LOCAL_CRIT),
-       SENSOR_ATTR(temp2_input, 0444, show_temp_value, NULL, 1),
-       SENSOR_ATTR(temp2_min, 0644, show_temp_min, store_temp_min, 1),
-       SENSOR_ATTR(temp2_max, 0644, show_temp_max, store_temp_max, 1),
-       SENSOR_ATTR(temp2_crit, 0644, show_temp_crit, store_temp_crit, 1),
-       SENSOR_ATTR(temp2_crit_hyst, 0444, show_temp_crit_hyst, NULL, 1),
-       SENSOR_ATTR(temp2_fault, 0444, show_status, NULL,
+       SENSOR_ATTR(temp2_input, S_IRUGO, show_temp_value, NULL, 1),
+       SENSOR_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_min,
+                   store_temp_min, 1),
+       SENSOR_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_max,
+                   store_temp_max, 1),
+       SENSOR_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp_crit,
+                   store_temp_crit, 1),
+       SENSOR_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 1),
+       SENSOR_ATTR(temp2_fault, S_IRUGO, show_status, NULL,
                    TMP401_STATUS_REMOTE_OPEN),
-       SENSOR_ATTR(temp2_min_alarm, 0444, show_status, NULL,
+       SENSOR_ATTR(temp2_min_alarm, S_IRUGO, show_status, NULL,
                    TMP401_STATUS_REMOTE_LOW),
-       SENSOR_ATTR(temp2_max_alarm, 0444, show_status, NULL,
+       SENSOR_ATTR(temp2_max_alarm, S_IRUGO, show_status, NULL,
                    TMP401_STATUS_REMOTE_HIGH),
-       SENSOR_ATTR(temp2_crit_alarm, 0444, show_status, NULL,
+       SENSOR_ATTR(temp2_crit_alarm, S_IRUGO, show_status, NULL,
                    TMP401_STATUS_REMOTE_CRIT),
 };
 
@@ -455,11 +503,11 @@ static struct sensor_device_attribute tmp401_attr[] = {
  * and remote channels.
  */
 static struct sensor_device_attribute tmp411_attr[] = {
-       SENSOR_ATTR(temp1_highest, 0444, show_temp_highest, NULL, 0),
-       SENSOR_ATTR(temp1_lowest, 0444, show_temp_lowest, NULL, 0),
-       SENSOR_ATTR(temp2_highest, 0444, show_temp_highest, NULL, 1),
-       SENSOR_ATTR(temp2_lowest, 0444, show_temp_lowest, NULL, 1),
-       SENSOR_ATTR(temp_reset_history, 0200, NULL, reset_temp_history, 0),
+       SENSOR_ATTR(temp1_highest, S_IRUGO, show_temp_highest, NULL, 0),
+       SENSOR_ATTR(temp1_lowest, S_IRUGO, show_temp_lowest, NULL, 0),
+       SENSOR_ATTR(temp2_highest, S_IRUGO, show_temp_highest, NULL, 1),
+       SENSOR_ATTR(temp2_lowest, S_IRUGO, show_temp_lowest, NULL, 1),
+       SENSOR_ATTR(temp_reset_history, S_IWUSR, NULL, reset_temp_history, 0),
 };
 
 /*
@@ -529,6 +577,27 @@ static int tmp401_detect(struct i2c_client *client,
        return 0;
 }
 
+static int tmp401_remove(struct i2c_client *client)
+{
+       struct tmp401_data *data = i2c_get_clientdata(client);
+       int i;
+
+       if (data->hwmon_dev)
+               hwmon_device_unregister(data->hwmon_dev);
+
+       for (i = 0; i < ARRAY_SIZE(tmp401_attr); i++)
+               device_remove_file(&client->dev, &tmp401_attr[i].dev_attr);
+
+       if (data->kind == tmp411) {
+               for (i = 0; i < ARRAY_SIZE(tmp411_attr); i++)
+                       device_remove_file(&client->dev,
+                                          &tmp411_attr[i].dev_attr);
+       }
+
+       kfree(data);
+       return 0;
+}
+
 static int tmp401_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
@@ -581,91 +650,17 @@ exit_remove:
        return err;
 }
 
-static int tmp401_remove(struct i2c_client *client)
-{
-       struct tmp401_data *data = i2c_get_clientdata(client);
-       int i;
-
-       if (data->hwmon_dev)
-               hwmon_device_unregister(data->hwmon_dev);
-
-       for (i = 0; i < ARRAY_SIZE(tmp401_attr); i++)
-               device_remove_file(&client->dev, &tmp401_attr[i].dev_attr);
-
-       if (data->kind == tmp411) {
-               for (i = 0; i < ARRAY_SIZE(tmp411_attr); i++)
-                       device_remove_file(&client->dev,
-                                          &tmp411_attr[i].dev_attr);
-       }
-
-       kfree(data);
-       return 0;
-}
-
-static struct tmp401_data *tmp401_update_device_reg16(
-       struct i2c_client *client, struct tmp401_data *data)
-{
-       int i;
-
-       for (i = 0; i < 2; i++) {
-               /*
-                * High byte must be read first immediately followed
-                * by the low byte
-                */
-               data->temp[i] = i2c_smbus_read_byte_data(client,
-                       TMP401_TEMP_MSB[i]) << 8;
-               data->temp[i] |= i2c_smbus_read_byte_data(client,
-                       TMP401_TEMP_LSB[i]);
-               data->temp_low[i] = i2c_smbus_read_byte_data(client,
-                       TMP401_TEMP_LOW_LIMIT_MSB_READ[i]) << 8;
-               data->temp_low[i] |= i2c_smbus_read_byte_data(client,
-                       TMP401_TEMP_LOW_LIMIT_LSB[i]);
-               data->temp_high[i] = i2c_smbus_read_byte_data(client,
-                       TMP401_TEMP_HIGH_LIMIT_MSB_READ[i]) << 8;
-               data->temp_high[i] |= i2c_smbus_read_byte_data(client,
-                       TMP401_TEMP_HIGH_LIMIT_LSB[i]);
-               data->temp_crit[i] = i2c_smbus_read_byte_data(client,
-                       TMP401_TEMP_CRIT_LIMIT[i]);
-
-               if (data->kind == tmp411) {
-                       data->temp_lowest[i] = i2c_smbus_read_byte_data(client,
-                               TMP411_TEMP_LOWEST_MSB[i]) << 8;
-                       data->temp_lowest[i] |= i2c_smbus_read_byte_data(
-                               client, TMP411_TEMP_LOWEST_LSB[i]);
-
-                       data->temp_highest[i] = i2c_smbus_read_byte_data(
-                               client, TMP411_TEMP_HIGHEST_MSB[i]) << 8;
-                       data->temp_highest[i] |= i2c_smbus_read_byte_data(
-                               client, TMP411_TEMP_HIGHEST_LSB[i]);
-               }
-       }
-       return data;
-}
-
-static struct tmp401_data *tmp401_update_device(struct device *dev)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-       struct tmp401_data *data = i2c_get_clientdata(client);
-
-       mutex_lock(&data->update_lock);
-
-       if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
-               data->status = i2c_smbus_read_byte_data(client, TMP401_STATUS);
-               data->config = i2c_smbus_read_byte_data(client,
-                                               TMP401_CONFIG_READ);
-               tmp401_update_device_reg16(client, data);
-
-               data->temp_crit_hyst = i2c_smbus_read_byte_data(client,
-                                               TMP401_TEMP_CRIT_HYST);
-
-               data->last_updated = jiffies;
-               data->valid = 1;
-       }
-
-       mutex_unlock(&data->update_lock);
-
-       return data;
-}
+static struct i2c_driver tmp401_driver = {
+       .class          = I2C_CLASS_HWMON,
+       .driver = {
+               .name   = "tmp401",
+       },
+       .probe          = tmp401_probe,
+       .remove         = tmp401_remove,
+       .id_table       = tmp401_id,
+       .detect         = tmp401_detect,
+       .address_list   = normal_i2c,
+};
 
 static int __init tmp401_init(void)
 {
index 68e90abeba966e93a55d8b216fce1d73e2d27db7..5da5942cf970763be13b716c5bd2a3c10d1af3ab 100644 (file)
@@ -300,8 +300,11 @@ static const struct of_device_id env_match[] = {
 MODULE_DEVICE_TABLE(of, env_match);
 
 static struct of_platform_driver env_driver = {
-       .name           = "ultra45_env",
-       .match_table    = env_match,
+       .driver = {
+               .name = "ultra45_env",
+               .owner = THIS_MODULE,
+               .of_match_table = env_match,
+       },
        .probe          = env_probe,
        .remove         = __devexit_p(env_remove),
 };
index 612807d9715533b3f03afcdf6738fb79767ee55e..697202e278917db50ca07c84aa92feb503e1e109 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/hwmon.h>
+#include <linux/smp_lock.h>
 #include <linux/hwmon-vid.h>
 #include <linux/hwmon-sysfs.h>
 #include <linux/err.h>
@@ -1319,8 +1320,8 @@ static ssize_t watchdog_write(struct file *filp, const char __user *buf,
        return count;
 }
 
-static int watchdog_ioctl(struct inode *inode, struct file *filp,
-                         unsigned int cmd, unsigned long arg)
+static long watchdog_ioctl(struct file *filp, unsigned int cmd,
+                          unsigned long arg)
 {
        static struct watchdog_info ident = {
                .options = WDIOF_KEEPALIVEPING |
@@ -1332,6 +1333,7 @@ static int watchdog_ioctl(struct inode *inode, struct file *filp,
        int val, ret = 0;
        struct w83793_data *data = filp->private_data;
 
+       lock_kernel();
        switch (cmd) {
        case WDIOC_GETSUPPORT:
                if (!nowayout)
@@ -1385,7 +1387,7 @@ static int watchdog_ioctl(struct inode *inode, struct file *filp,
        default:
                ret = -ENOTTY;
        }
-
+       unlock_kernel();
        return ret;
 }
 
@@ -1395,7 +1397,7 @@ static const struct file_operations watchdog_fops = {
        .open = watchdog_open,
        .release = watchdog_close,
        .write = watchdog_write,
-       .ioctl = watchdog_ioctl,
+       .unlocked_ioctl = watchdog_ioctl,
 };
 
 /*
index 16948db38973f1866fffe4df07710627b771662c..b02b4533651d8076f522e96923b09b3f3e8b289b 100644 (file)
@@ -440,7 +440,7 @@ static int __devinit cpm_i2c_setup(struct cpm_i2c *cpm)
 
        init_waitqueue_head(&cpm->i2c_wait);
 
-       cpm->irq = of_irq_to_resource(ofdev->node, 0, NULL);
+       cpm->irq = of_irq_to_resource(ofdev->dev.of_node, 0, NULL);
        if (!cpm->irq)
                return -EINVAL;
 
@@ -451,13 +451,13 @@ static int __devinit cpm_i2c_setup(struct cpm_i2c *cpm)
                return ret;
 
        /* I2C parameter RAM */
-       i2c_base = of_iomap(ofdev->node, 1);
+       i2c_base = of_iomap(ofdev->dev.of_node, 1);
        if (i2c_base == NULL) {
                ret = -EINVAL;
                goto out_irq;
        }
 
-       if (of_device_is_compatible(ofdev->node, "fsl,cpm1-i2c")) {
+       if (of_device_is_compatible(ofdev->dev.of_node, "fsl,cpm1-i2c")) {
 
                /* Check for and use a microcode relocation patch. */
                cpm->i2c_ram = i2c_base;
@@ -474,7 +474,7 @@ static int __devinit cpm_i2c_setup(struct cpm_i2c *cpm)
 
                cpm->version = 1;
 
-       } else if (of_device_is_compatible(ofdev->node, "fsl,cpm2-i2c")) {
+       } else if (of_device_is_compatible(ofdev->dev.of_node, "fsl,cpm2-i2c")) {
                cpm->i2c_addr = cpm_muram_alloc(sizeof(struct i2c_ram), 64);
                cpm->i2c_ram = cpm_muram_addr(cpm->i2c_addr);
                out_be16(i2c_base, cpm->i2c_addr);
@@ -489,24 +489,24 @@ static int __devinit cpm_i2c_setup(struct cpm_i2c *cpm)
        }
 
        /* I2C control/status registers */
-       cpm->i2c_reg = of_iomap(ofdev->node, 0);
+       cpm->i2c_reg = of_iomap(ofdev->dev.of_node, 0);
        if (cpm->i2c_reg == NULL) {
                ret = -EINVAL;
                goto out_ram;
        }
 
-       data = of_get_property(ofdev->node, "fsl,cpm-command", &len);
+       data = of_get_property(ofdev->dev.of_node, "fsl,cpm-command", &len);
        if (!data || len != 4) {
                ret = -EINVAL;
                goto out_reg;
        }
        cpm->cp_command = *data;
 
-       data = of_get_property(ofdev->node, "linux,i2c-class", &len);
+       data = of_get_property(ofdev->dev.of_node, "linux,i2c-class", &len);
        if (data && len == 4)
                cpm->adap.class = *data;
 
-       data = of_get_property(ofdev->node, "clock-frequency", &len);
+       data = of_get_property(ofdev->dev.of_node, "clock-frequency", &len);
        if (data && len == 4)
                cpm->freq = *data;
        else
@@ -661,7 +661,7 @@ static int __devinit cpm_i2c_probe(struct of_device *ofdev,
 
        /* register new adapter to i2c module... */
 
-       data = of_get_property(ofdev->node, "linux,i2c-index", &len);
+       data = of_get_property(ofdev->dev.of_node, "linux,i2c-index", &len);
        if (data && len == 4) {
                cpm->adap.nr = *data;
                result = i2c_add_numbered_adapter(&cpm->adap);
@@ -679,7 +679,7 @@ static int __devinit cpm_i2c_probe(struct of_device *ofdev,
        /*
         * register OF I2C devices
         */
-       of_register_i2c_devices(&cpm->adap, ofdev->node);
+       of_register_i2c_devices(&cpm->adap, ofdev->dev.of_node);
 
        return 0;
 out_shut:
@@ -718,13 +718,13 @@ static const struct of_device_id cpm_i2c_match[] = {
 MODULE_DEVICE_TABLE(of, cpm_i2c_match);
 
 static struct of_platform_driver cpm_i2c_driver = {
-       .match_table    = cpm_i2c_match,
        .probe          = cpm_i2c_probe,
        .remove         = __devexit_p(cpm_i2c_remove),
-       .driver         = {
-               .name   = "fsl-i2c-cpm",
-               .owner  = THIS_MODULE,
-       }
+       .driver = {
+               .name = "fsl-i2c-cpm",
+               .owner = THIS_MODULE,
+               .of_match_table = cpm_i2c_match,
+       },
 };
 
 static int __init cpm_i2c_init(void)
index f8ccc0fe95a83761f0e8c579450f0d542abde641..bf344135647a8654a47c8b343c140e68453f40d5 100644 (file)
@@ -664,7 +664,7 @@ static inline u8 iic_clckdiv(unsigned int opb)
 static int __devinit iic_request_irq(struct of_device *ofdev,
                                     struct ibm_iic_private *dev)
 {
-       struct device_node *np = ofdev->node;
+       struct device_node *np = ofdev->dev.of_node;
        int irq;
 
        if (iic_force_poll)
@@ -695,7 +695,7 @@ static int __devinit iic_request_irq(struct of_device *ofdev,
 static int __devinit iic_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 ibm_iic_private *dev;
        struct i2c_adapter *adap;
        const u32 *freq;
@@ -807,8 +807,11 @@ static const struct of_device_id ibm_iic_match[] = {
 };
 
 static struct of_platform_driver ibm_iic_driver = {
-       .name   = "ibm-iic",
-       .match_table = ibm_iic_match,
+       .driver = {
+               .name = "ibm-iic",
+               .owner = THIS_MODULE,
+               .of_match_table = ibm_iic_match,
+       },
        .probe  = iic_probe,
        .remove = __devexit_p(iic_remove),
 };
index e86cef300c7d694090a15df38cb627e4182d8c61..df00eb1f11f9ee44d3f2d6d8826ff2d15895bee8 100644 (file)
@@ -560,14 +560,14 @@ static int __devinit fsl_i2c_probe(struct of_device *op,
 
        init_waitqueue_head(&i2c->queue);
 
-       i2c->base = of_iomap(op->node, 0);
+       i2c->base = of_iomap(op->dev.of_node, 0);
        if (!i2c->base) {
                dev_err(i2c->dev, "failed to map controller\n");
                result = -ENOMEM;
                goto fail_map;
        }
 
-       i2c->irq = irq_of_parse_and_map(op->node, 0);
+       i2c->irq = irq_of_parse_and_map(op->dev.of_node, 0);
        if (i2c->irq) { /* no i2c->irq implies polling */
                result = request_irq(i2c->irq, mpc_i2c_isr,
                                     IRQF_SHARED, "i2c-mpc", i2c);
@@ -577,21 +577,22 @@ static int __devinit fsl_i2c_probe(struct of_device *op,
                }
        }
 
-       if (of_get_property(op->node, "fsl,preserve-clocking", NULL)) {
+       if (of_get_property(op->dev.of_node, "fsl,preserve-clocking", NULL)) {
                clock = MPC_I2C_CLOCK_PRESERVE;
        } else {
-               prop = of_get_property(op->node, "clock-frequency", &plen);
+               prop = of_get_property(op->dev.of_node, "clock-frequency",
+                                       &plen);
                if (prop && plen == sizeof(u32))
                        clock = *prop;
        }
 
        if (match->data) {
                struct mpc_i2c_data *data = match->data;
-               data->setup(op->node, i2c, clock, data->prescaler);
+               data->setup(op->dev.of_node, i2c, clock, data->prescaler);
        } else {
                /* Backwards compatibility */
-               if (of_get_property(op->node, "dfsrr", NULL))
-                       mpc_i2c_setup_8xxx(op->node, i2c, clock, 0);
+               if (of_get_property(op->dev.of_node, "dfsrr", NULL))
+                       mpc_i2c_setup_8xxx(op->dev.of_node, i2c, clock, 0);
        }
 
        dev_set_drvdata(&op->dev, i2c);
@@ -605,7 +606,7 @@ static int __devinit fsl_i2c_probe(struct of_device *op,
                dev_err(i2c->dev, "failed to add adapter\n");
                goto fail_add;
        }
-       of_register_i2c_devices(&i2c->adap, op->node);
+       of_register_i2c_devices(&i2c->adap, op->dev.of_node);
 
        return result;
 
@@ -674,12 +675,12 @@ MODULE_DEVICE_TABLE(of, mpc_i2c_of_match);
 
 /* Structure for a device driver */
 static struct of_platform_driver mpc_i2c_driver = {
-       .match_table    = mpc_i2c_of_match,
        .probe          = fsl_i2c_probe,
        .remove         = __devexit_p(fsl_i2c_remove),
-       .driver         = {
-               .owner  = THIS_MODULE,
-               .name   = DRV_NAME,
+       .driver = {
+               .owner = THIS_MODULE,
+               .name = DRV_NAME,
+               .of_match_table = mpc_i2c_of_match,
        },
 };
 
index db3c9f3a764796206dac6ea7210da5499fdd1cc3..e0f833cca3f1193c24480c4efc446a7568a9a3af 100644 (file)
@@ -418,6 +418,9 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
        client->dev.parent = &client->adapter->dev;
        client->dev.bus = &i2c_bus_type;
        client->dev.type = &i2c_client_type;
+#ifdef CONFIG_OF
+       client->dev.of_node = info->of_node;
+#endif
 
        dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),
                     client->addr);
index d2b8b272bc27810a5dcfa4571e0eeb789ffd0e88..cb10201a15ede79e7ec474a1dcd2ae709254d5ae 100644 (file)
@@ -633,12 +633,10 @@ static void __init cmd640_init_dev(ide_drive_t *drive)
 
 static int cmd640_test_irq(ide_hwif_t *hwif)
 {
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
        int irq_reg             = hwif->channel ? ARTTIM23 : CFR;
-       u8  irq_stat, irq_mask  = hwif->channel ? ARTTIM23_IDE23INTR :
+       u8  irq_mask            = hwif->channel ? ARTTIM23_IDE23INTR :
                                                  CFR_IDE01INTR;
-
-       pci_read_config_byte(dev, irq_reg, &irq_stat);
+       u8  irq_stat            = get_cmd640_reg(irq_reg);
 
        return (irq_stat & irq_mask) ? 1 : 0;
 }
index b9e517de6a82c778f1ded3a2d63e5c78a727adb2..3feaa26410be9b26eb30d4d52768324d3cff0294 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/zorro.h>
 #include <linux/module.h>
+#include <linux/platform_device.h>
 
 #include <asm/setup.h>
 #include <asm/amigahw.h>
 #include <asm/amigayle.h>
 
 
-    /*
-     *  Bases of the IDE interfaces
-     */
-
-#define GAYLE_BASE_4000        0xdd2020        /* A4000/A4000T */
-#define GAYLE_BASE_1200        0xda0000        /* A1200/A600 and E-Matrix 530 */
-
-#define GAYLE_IDEREG_SIZE      0x2000
-
     /*
      *  Offsets from one of the above bases
      */
@@ -68,20 +60,20 @@ MODULE_PARM_DESC(doubler, "enable support for IDE doublers");
 
 static int gayle_test_irq(ide_hwif_t *hwif)
 {
-    unsigned char ch;
+       unsigned char ch;
 
-    ch = z_readb(hwif->io_ports.irq_addr);
-    if (!(ch & GAYLE_IRQ_IDE))
-       return 0;
-    return 1;
+       ch = z_readb(hwif->io_ports.irq_addr);
+       if (!(ch & GAYLE_IRQ_IDE))
+               return 0;
+       return 1;
 }
 
 static void gayle_a1200_clear_irq(ide_drive_t *drive)
 {
-    ide_hwif_t *hwif = drive->hwif;
+       ide_hwif_t *hwif = drive->hwif;
 
-    (void)z_readb(hwif->io_ports.status_addr);
-    z_writeb(0x7c, hwif->io_ports.irq_addr);
+       (void)z_readb(hwif->io_ports.status_addr);
+       z_writeb(0x7c, hwif->io_ports.irq_addr);
 }
 
 static void __init gayle_setup_ports(struct ide_hw *hw, unsigned long base,
@@ -122,64 +114,89 @@ static const struct ide_port_info gayle_port_info = {
      *  Probe for a Gayle IDE interface (and optionally for an IDE doubler)
      */
 
-static int __init gayle_init(void)
+static int __init amiga_gayle_ide_probe(struct platform_device *pdev)
 {
-    unsigned long phys_base, res_start, res_n;
-    unsigned long base, ctrlport, irqport;
-    int a4000, i, rc;
-    struct ide_hw hw[GAYLE_NUM_HWIFS], *hws[GAYLE_NUM_HWIFS];
-    struct ide_port_info d = gayle_port_info;
-
-    if (!MACH_IS_AMIGA)
-       return -ENODEV;
-
-    if ((a4000 = AMIGAHW_PRESENT(A4000_IDE)) || AMIGAHW_PRESENT(A1200_IDE))
-       goto found;
-
-#ifdef CONFIG_ZORRO
-    if (zorro_find_device(ZORRO_PROD_MTEC_VIPER_MK_V_E_MATRIX_530_SCSI_IDE,
-                         NULL))
-       goto found;
-#endif
-    return -ENODEV;
-
-found:
-       printk(KERN_INFO "ide: Gayle IDE controller (A%d style%s)\n",
-                        a4000 ? 4000 : 1200,
-                        ide_doubler ? ", IDE doubler" : "");
-
-       if (a4000) {
-           phys_base = GAYLE_BASE_4000;
-           irqport = (unsigned long)ZTWO_VADDR(GAYLE_IRQ_4000);
-           d.port_ops = &gayle_a4000_port_ops;
-       } else {
-           phys_base = GAYLE_BASE_1200;
-           irqport = (unsigned long)ZTWO_VADDR(GAYLE_IRQ_1200);
-           d.port_ops = &gayle_a1200_port_ops;
+       struct resource *res;
+       struct gayle_ide_platform_data *pdata;
+       unsigned long base, ctrlport, irqport;
+       unsigned int i;
+       int error;
+       struct ide_hw hw[GAYLE_NUM_HWIFS], *hws[GAYLE_NUM_HWIFS];
+       struct ide_port_info d = gayle_port_info;
+       struct ide_host *host;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
+
+       if (!request_mem_region(res->start, resource_size(res), "IDE"))
+               return -EBUSY;
+
+       pdata = pdev->dev.platform_data;
+       pr_info("ide: Gayle IDE controller (A%u style%s)\n",
+               pdata->explicit_ack ? 1200 : 4000,
+               ide_doubler ? ", IDE doubler" : "");
+
+       base = (unsigned long)ZTWO_VADDR(pdata->base);
+       ctrlport = 0;
+       irqport = (unsigned long)ZTWO_VADDR(pdata->irqport);
+       if (pdata->explicit_ack)
+               d.port_ops = &gayle_a1200_port_ops;
+       else
+               d.port_ops = &gayle_a4000_port_ops;
+
+       for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++, base += GAYLE_NEXT_PORT) {
+               if (GAYLE_HAS_CONTROL_REG)
+                       ctrlport = base + GAYLE_CONTROL;
+
+               gayle_setup_ports(&hw[i], base, ctrlport, irqport);
+               hws[i] = &hw[i];
        }
 
-       res_start = ((unsigned long)phys_base) & ~(GAYLE_NEXT_PORT-1);
-       res_n = GAYLE_IDEREG_SIZE;
+       error = ide_host_add(&d, hws, i, &host);
+       if (error)
+               goto out;
 
-       if (!request_mem_region(res_start, res_n, "IDE"))
-               return -EBUSY;
+       platform_set_drvdata(pdev, host);
+       return 0;
 
-    for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++) {
-       base = (unsigned long)ZTWO_VADDR(phys_base + i * GAYLE_NEXT_PORT);
-       ctrlport = GAYLE_HAS_CONTROL_REG ? (base + GAYLE_CONTROL) : 0;
+out:
+       release_mem_region(res->start, resource_size(res));
+       return error;
+}
+
+static int __exit amiga_gayle_ide_remove(struct platform_device *pdev)
+{
+       struct ide_host *host = platform_get_drvdata(pdev);
+       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       ide_host_remove(host);
+       release_mem_region(res->start, resource_size(res));
+       return 0;
+}
 
-       gayle_setup_ports(&hw[i], base, ctrlport, irqport);
+static struct platform_driver amiga_gayle_ide_driver = {
+       .remove = __exit_p(amiga_gayle_ide_remove),
+       .driver   = {
+               .name   = "amiga-gayle-ide",
+               .owner  = THIS_MODULE,
+       },
+};
 
-       hws[i] = &hw[i];
-    }
+static int __init amiga_gayle_ide_init(void)
+{
+       return platform_driver_probe(&amiga_gayle_ide_driver,
+                                    amiga_gayle_ide_probe);
+}
 
-    rc = ide_host_add(&d, hws, i, NULL);
-    if (rc)
-       release_mem_region(res_start, res_n);
+module_init(amiga_gayle_ide_init);
 
-    return rc;
+static void __exit amiga_gayle_ide_exit(void)
+{
+       platform_driver_unregister(&amiga_gayle_ide_driver);
 }
 
-module_init(gayle_init);
+module_exit(amiga_gayle_ide_exit);
 
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:amiga-gayle-ide");
index 42965b3e30b9bb270f74be175e1b35190de714bc..542603b394e4a59997ca82940598b3a64f8edfd9 100644 (file)
@@ -95,6 +95,7 @@ static int __devinit plat_ide_probe(struct platform_device *pdev)
        plat_ide_setup_ports(&hw, base, alt_base, pdata, res_irq->start);
        hw.dev = &pdev->dev;
 
+       d.irq_flags = res_irq->flags;
        if (mmio)
                d.host_flags |= IDE_HFLAG_MMIO;
 
index c5f3841af360da3d8d62a4fc10bb10b7160f21e0..3a35ec6193d25241312cdd03595a53cdf2999a49 100644 (file)
@@ -93,13 +93,13 @@ static int pdc202xx_test_irq(ide_hwif_t *hwif)
                 * bit 7: error, bit 6: interrupting,
                 * bit 5: FIFO full, bit 4: FIFO empty
                 */
-               return ((sc1d & 0x50) == 0x50) ? 1 : 0;
+               return (sc1d & 0x40) ? 1 : 0;
        } else  {
                /*
                 * bit 3: error, bit 2: interrupting,
                 * bit 1: FIFO full, bit 0: FIFO empty
                 */
-               return ((sc1d & 0x05) == 0x05) ? 1 : 0;
+               return (sc1d & 0x04) ? 1 : 0;
        }
 }
 
@@ -241,6 +241,7 @@ static const struct ide_port_ops pdc20246_port_ops = {
 static const struct ide_port_ops pdc2026x_port_ops = {
        .set_pio_mode           = pdc202xx_set_pio_mode,
        .set_dma_mode           = pdc202xx_set_mode,
+       .test_irq               = pdc202xx_test_irq,
        .cable_detect           = pdc2026x_cable_detect,
 };
 
index 159955d16c475e69314c12efa4a19166cfec4eaf..183fa38760d85be4e520529c0747b6d88a614365 100644 (file)
@@ -1153,7 +1153,7 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
 
        if (macio_resource_count(mdev) == 0) {
                printk(KERN_WARNING "ide-pmac: no address for %s\n",
-                                   mdev->ofdev.node->full_name);
+                                   mdev->ofdev.dev.of_node->full_name);
                rc = -ENXIO;
                goto out_free_pmif;
        }
@@ -1161,7 +1161,7 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
        /* Request memory resource for IO ports */
        if (macio_request_resource(mdev, 0, "ide-pmac (ports)")) {
                printk(KERN_ERR "ide-pmac: can't request MMIO resource for "
-                               "%s!\n", mdev->ofdev.node->full_name);
+                               "%s!\n", mdev->ofdev.dev.of_node->full_name);
                rc = -EBUSY;
                goto out_free_pmif;
        }
@@ -1173,7 +1173,7 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
         */
        if (macio_irq_count(mdev) == 0) {
                printk(KERN_WARNING "ide-pmac: no intrs for device %s, using "
-                                   "13\n", mdev->ofdev.node->full_name);
+                                   "13\n", mdev->ofdev.dev.of_node->full_name);
                irq = irq_create_mapping(NULL, 13);
        } else
                irq = macio_irq(mdev, 0);
@@ -1182,7 +1182,7 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
        regbase = (unsigned long) base;
 
        pmif->mdev = mdev;
-       pmif->node = mdev->ofdev.node;
+       pmif->node = mdev->ofdev.dev.of_node;
        pmif->regbase = regbase;
        pmif->irq = irq;
        pmif->kauai_fcr = NULL;
@@ -1191,7 +1191,7 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
                if (macio_request_resource(mdev, 1, "ide-pmac (dma)"))
                        printk(KERN_WARNING "ide-pmac: can't request DMA "
                                            "resource for %s!\n",
-                                           mdev->ofdev.node->full_name);
+                                           mdev->ofdev.dev.of_node->full_name);
                else
                        pmif->dma_regs = ioremap(macio_resource_start(mdev, 1), 0x1000);
        } else
index f15e90a453d1c416fb007b046f41ee6bc0c4d866..fb5c5186d4aae6b838732cea9e370409a1198310 100644 (file)
@@ -1,3 +1,14 @@
+config INTEL_IDLE
+       tristate "Cpuidle Driver for Intel Processors"
+       depends on CPU_IDLE
+       depends on X86
+       depends on CPU_SUP_INTEL
+       depends on EXPERIMENTAL
+       help
+         Enable intel_idle, a cpuidle driver that includes knowledge of
+         native Intel hardware idle features.  The acpi_idle driver
+         can be configured at the same time, in order to handle
+         processors intel_idle does not support.
 
 menu "Memory power savings"
 depends on X86_64
index 5f68fc377e21d89679bd4867aa03f583deda2896..23d295cf10f2a785eefb17224bf13aa154970e1d 100644 (file)
@@ -1,2 +1,3 @@
 obj-$(CONFIG_I7300_IDLE)                       += i7300_idle.o
+obj-$(CONFIG_INTEL_IDLE)                       += intel_idle.o
 
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
new file mode 100755 (executable)
index 0000000..54f0fb4
--- /dev/null
@@ -0,0 +1,461 @@
+/*
+ * intel_idle.c - native hardware idle loop for modern Intel processors
+ *
+ * Copyright (c) 2010, Intel Corporation.
+ * Len Brown <len.brown@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ */
+
+/*
+ * intel_idle is a cpuidle driver that loads on specific Intel processors
+ * in lieu of the legacy ACPI processor_idle driver.  The intent is to
+ * make Linux more efficient on these processors, as intel_idle knows
+ * more than ACPI, as well as make Linux more immune to ACPI BIOS bugs.
+ */
+
+/*
+ * Design Assumptions
+ *
+ * All CPUs have same idle states as boot CPU
+ *
+ * Chipset BM_STS (bus master status) bit is a NOP
+ *     for preventing entry into deep C-stats
+ */
+
+/*
+ * Known limitations
+ *
+ * The driver currently initializes for_each_online_cpu() upon modprobe.
+ * It it unaware of subsequent processors hot-added to the system.
+ * This means that if you boot with maxcpus=n and later online
+ * processors above n, those processors will use C1 only.
+ *
+ * ACPI has a .suspend hack to turn off deep c-statees during suspend
+ * to avoid complications with the lapic timer workaround.
+ * Have not seen issues with suspend, but may need same workaround here.
+ *
+ * There is currently no kernel-based automatic probing/loading mechanism
+ * if the driver is built as a module.
+ */
+
+/* un-comment DEBUG to enable pr_debug() statements */
+#define DEBUG
+
+#include <linux/kernel.h>
+#include <linux/cpuidle.h>
+#include <linux/clockchips.h>
+#include <linux/hrtimer.h>     /* ktime_get_real() */
+#include <trace/events/power.h>
+#include <linux/sched.h>
+
+#define INTEL_IDLE_VERSION "0.4"
+#define PREFIX "intel_idle: "
+
+#define MWAIT_SUBSTATE_MASK    (0xf)
+#define MWAIT_CSTATE_MASK      (0xf)
+#define MWAIT_SUBSTATE_SIZE    (4)
+#define MWAIT_MAX_NUM_CSTATES  8
+#define CPUID_MWAIT_LEAF (5)
+#define CPUID5_ECX_EXTENSIONS_SUPPORTED (0x1)
+#define CPUID5_ECX_INTERRUPT_BREAK     (0x2)
+
+static struct cpuidle_driver intel_idle_driver = {
+       .name = "intel_idle",
+       .owner = THIS_MODULE,
+};
+/* intel_idle.max_cstate=0 disables driver */
+static int max_cstate = MWAIT_MAX_NUM_CSTATES - 1;
+static int power_policy = 7; /* 0 = max perf; 15 = max powersave */
+
+static unsigned int substates;
+static int (*choose_substate)(int);
+
+/* Reliable LAPIC Timer States, bit 1 for C1 etc.  */
+static unsigned int lapic_timer_reliable_states;
+
+static struct cpuidle_device *intel_idle_cpuidle_devices;
+static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state);
+
+static struct cpuidle_state *cpuidle_state_table;
+
+/*
+ * States are indexed by the cstate number,
+ * which is also the index into the MWAIT hint array.
+ * Thus C0 is a dummy.
+ */
+static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = {
+       { /* MWAIT C0 */ },
+       { /* MWAIT C1 */
+               .name = "NHM-C1",
+               .desc = "MWAIT 0x00",
+               .driver_data = (void *) 0x00,
+               .flags = CPUIDLE_FLAG_TIME_VALID,
+               .exit_latency = 3,
+               .power_usage = 1000,
+               .target_residency = 6,
+               .enter = &intel_idle },
+       { /* MWAIT C2 */
+               .name = "NHM-C3",
+               .desc = "MWAIT 0x10",
+               .driver_data = (void *) 0x10,
+               .flags = CPUIDLE_FLAG_TIME_VALID,
+               .exit_latency = 20,
+               .power_usage = 500,
+               .target_residency = 80,
+               .enter = &intel_idle },
+       { /* MWAIT C3 */
+               .name = "NHM-C6",
+               .desc = "MWAIT 0x20",
+               .driver_data = (void *) 0x20,
+               .flags = CPUIDLE_FLAG_TIME_VALID,
+               .exit_latency = 200,
+               .power_usage = 350,
+               .target_residency = 800,
+               .enter = &intel_idle },
+};
+
+static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
+       { /* MWAIT C0 */ },
+       { /* MWAIT C1 */
+               .name = "ATM-C1",
+               .desc = "MWAIT 0x00",
+               .driver_data = (void *) 0x00,
+               .flags = CPUIDLE_FLAG_TIME_VALID,
+               .exit_latency = 1,
+               .power_usage = 1000,
+               .target_residency = 4,
+               .enter = &intel_idle },
+       { /* MWAIT C2 */
+               .name = "ATM-C2",
+               .desc = "MWAIT 0x10",
+               .driver_data = (void *) 0x10,
+               .flags = CPUIDLE_FLAG_TIME_VALID,
+               .exit_latency = 20,
+               .power_usage = 500,
+               .target_residency = 80,
+               .enter = &intel_idle },
+       { /* MWAIT C3 */ },
+       { /* MWAIT C4 */
+               .name = "ATM-C4",
+               .desc = "MWAIT 0x30",
+               .driver_data = (void *) 0x30,
+               .flags = CPUIDLE_FLAG_TIME_VALID,
+               .exit_latency = 100,
+               .power_usage = 250,
+               .target_residency = 400,
+               .enter = &intel_idle },
+       { /* MWAIT C5 */ },
+       { /* MWAIT C6 */
+               .name = "ATM-C6",
+               .desc = "MWAIT 0x40",
+               .driver_data = (void *) 0x40,
+               .flags = CPUIDLE_FLAG_TIME_VALID,
+               .exit_latency = 200,
+               .power_usage = 150,
+               .target_residency = 800,
+               .enter = NULL },        /* disabled */
+};
+
+/*
+ * choose_tunable_substate()
+ *
+ * Run-time decision on which C-state substate to invoke
+ * If power_policy = 0, choose shallowest substate (0)
+ * If power_policy = 15, choose deepest substate
+ * If power_policy = middle, choose middle substate etc.
+ */
+static int choose_tunable_substate(int cstate)
+{
+       unsigned int num_substates;
+       unsigned int substate_choice;
+
+       power_policy &= 0xF;    /* valid range: 0-15 */
+       cstate &= 7;    /* valid range: 0-7 */
+
+       num_substates = (substates >> ((cstate) * 4)) & MWAIT_SUBSTATE_MASK;
+
+       if (num_substates <= 1)
+               return 0;
+
+       substate_choice = ((power_policy + (power_policy + 1) *
+                               (num_substates - 1)) / 16);
+
+       return substate_choice;
+}
+
+/*
+ * choose_zero_substate()
+ */
+static int choose_zero_substate(int cstate)
+{
+       return 0;
+}
+
+/**
+ * intel_idle
+ * @dev: cpuidle_device
+ * @state: cpuidle state
+ *
+ */
+static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state)
+{
+       unsigned long ecx = 1; /* break on interrupt flag */
+       unsigned long eax = (unsigned long)cpuidle_get_statedata(state);
+       unsigned int cstate;
+       ktime_t kt_before, kt_after;
+       s64 usec_delta;
+       int cpu = smp_processor_id();
+
+       cstate = (((eax) >> MWAIT_SUBSTATE_SIZE) & MWAIT_CSTATE_MASK) + 1;
+
+       eax = eax + (choose_substate)(cstate);
+
+       local_irq_disable();
+
+       if (!(lapic_timer_reliable_states & (1 << (cstate))))
+               clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
+
+       kt_before = ktime_get_real();
+
+       stop_critical_timings();
+#ifndef MODULE
+       trace_power_start(POWER_CSTATE, (eax >> 4) + 1);
+#endif
+       if (!need_resched()) {
+
+               __monitor((void *)&current_thread_info()->flags, 0, 0);
+               smp_mb();
+               if (!need_resched())
+                       __mwait(eax, ecx);
+       }
+
+       start_critical_timings();
+
+       kt_after = ktime_get_real();
+       usec_delta = ktime_to_us(ktime_sub(kt_after, kt_before));
+
+       local_irq_enable();
+
+       if (!(lapic_timer_reliable_states & (1 << (cstate))))
+               clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
+
+       return usec_delta;
+}
+
+/*
+ * intel_idle_probe()
+ */
+static int intel_idle_probe(void)
+{
+       unsigned int eax, ebx, ecx, edx;
+
+       if (max_cstate == 0) {
+               pr_debug(PREFIX "disabled\n");
+               return -EPERM;
+       }
+
+       if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
+               return -ENODEV;
+
+       if (!boot_cpu_has(X86_FEATURE_MWAIT))
+               return -ENODEV;
+
+       if (boot_cpu_data.cpuid_level < CPUID_MWAIT_LEAF)
+               return -ENODEV;
+
+       cpuid(CPUID_MWAIT_LEAF, &eax, &ebx, &ecx, &edx);
+
+       if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED) ||
+               !(ecx & CPUID5_ECX_INTERRUPT_BREAK))
+                       return -ENODEV;
+#ifdef DEBUG
+       if (substates == 0)     /* can over-ride via modparam */
+#endif
+               substates = edx;
+
+       pr_debug(PREFIX "MWAIT substates: 0x%x\n", substates);
+
+       if (boot_cpu_has(X86_FEATURE_ARAT))     /* Always Reliable APIC Timer */
+               lapic_timer_reliable_states = 0xFFFFFFFF;
+
+       if (boot_cpu_data.x86 != 6)     /* family 6 */
+               return -ENODEV;
+
+       switch (boot_cpu_data.x86_model) {
+
+       case 0x1A:      /* Core i7, Xeon 5500 series */
+       case 0x1E:      /* Core i7 and i5 Processor - Lynnfield Jasper Forest */
+       case 0x1F:      /* Core i7 and i5 Processor - Nehalem */
+       case 0x2E:      /* Nehalem-EX Xeon */
+               lapic_timer_reliable_states = (1 << 1);  /* C1 */
+
+       case 0x25:      /* Westmere */
+       case 0x2C:      /* Westmere */
+               cpuidle_state_table = nehalem_cstates;
+               choose_substate = choose_tunable_substate;
+               break;
+
+       case 0x1C:      /* 28 - Atom Processor */
+               lapic_timer_reliable_states = (1 << 2) | (1 << 1); /* C2, C1 */
+               cpuidle_state_table = atom_cstates;
+               choose_substate = choose_zero_substate;
+               break;
+#ifdef FUTURE_USE
+       case 0x17:      /* 23 - Core 2 Duo */
+               lapic_timer_reliable_states = (1 << 2) | (1 << 1); /* C2, C1 */
+#endif
+
+       default:
+               pr_debug(PREFIX "does not run on family %d model %d\n",
+                       boot_cpu_data.x86, boot_cpu_data.x86_model);
+               return -ENODEV;
+       }
+
+       pr_debug(PREFIX "v" INTEL_IDLE_VERSION
+               " model 0x%X\n", boot_cpu_data.x86_model);
+
+       pr_debug(PREFIX "lapic_timer_reliable_states 0x%x\n",
+               lapic_timer_reliable_states);
+       return 0;
+}
+
+/*
+ * intel_idle_cpuidle_devices_uninit()
+ * unregister, free cpuidle_devices
+ */
+static void intel_idle_cpuidle_devices_uninit(void)
+{
+       int i;
+       struct cpuidle_device *dev;
+
+       for_each_online_cpu(i) {
+               dev = per_cpu_ptr(intel_idle_cpuidle_devices, i);
+               cpuidle_unregister_device(dev);
+       }
+
+       free_percpu(intel_idle_cpuidle_devices);
+       return;
+}
+/*
+ * intel_idle_cpuidle_devices_init()
+ * allocate, initialize, register cpuidle_devices
+ */
+static int intel_idle_cpuidle_devices_init(void)
+{
+       int i, cstate;
+       struct cpuidle_device *dev;
+
+       intel_idle_cpuidle_devices = alloc_percpu(struct cpuidle_device);
+       if (intel_idle_cpuidle_devices == NULL)
+               return -ENOMEM;
+
+       for_each_online_cpu(i) {
+               dev = per_cpu_ptr(intel_idle_cpuidle_devices, i);
+
+               dev->state_count = 1;
+
+               for (cstate = 1; cstate < MWAIT_MAX_NUM_CSTATES; ++cstate) {
+                       int num_substates;
+
+                       if (cstate > max_cstate) {
+                               printk(PREFIX "max_cstate %d reached\n",
+                                       max_cstate);
+                               break;
+                       }
+
+                       /* does the state exist in CPUID.MWAIT? */
+                       num_substates = (substates >> ((cstate) * 4))
+                                               & MWAIT_SUBSTATE_MASK;
+                       if (num_substates == 0)
+                               continue;
+                       /* is the state not enabled? */
+                       if (cpuidle_state_table[cstate].enter == NULL) {
+                               /* does the driver not know about the state? */
+                               if (*cpuidle_state_table[cstate].name == '\0')
+                                       pr_debug(PREFIX "unaware of model 0x%x"
+                                               " MWAIT %d please"
+                                               " contact lenb@kernel.org",
+                                       boot_cpu_data.x86_model, cstate);
+                               continue;
+                       }
+
+                       if ((cstate > 2) &&
+                               !boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
+                               mark_tsc_unstable("TSC halts in idle"
+                                       " states deeper than C2");
+
+                       dev->states[dev->state_count] = /* structure copy */
+                               cpuidle_state_table[cstate];
+
+                       dev->state_count += 1;
+               }
+
+               dev->cpu = i;
+               if (cpuidle_register_device(dev)) {
+                       pr_debug(PREFIX "cpuidle_register_device %d failed!\n",
+                                i);
+                       intel_idle_cpuidle_devices_uninit();
+                       return -EIO;
+               }
+       }
+
+       return 0;
+}
+
+
+static int __init intel_idle_init(void)
+{
+       int retval;
+
+       retval = intel_idle_probe();
+       if (retval)
+               return retval;
+
+       retval = cpuidle_register_driver(&intel_idle_driver);
+       if (retval) {
+               printk(KERN_DEBUG PREFIX "intel_idle yielding to %s",
+                       cpuidle_get_driver()->name);
+               return retval;
+       }
+
+       retval = intel_idle_cpuidle_devices_init();
+       if (retval) {
+               cpuidle_unregister_driver(&intel_idle_driver);
+               return retval;
+       }
+
+       return 0;
+}
+
+static void __exit intel_idle_exit(void)
+{
+       intel_idle_cpuidle_devices_uninit();
+       cpuidle_unregister_driver(&intel_idle_driver);
+
+       return;
+}
+
+module_init(intel_idle_init);
+module_exit(intel_idle_exit);
+
+module_param(power_policy, int, 0644);
+module_param(max_cstate, int, 0444);
+#ifdef DEBUG
+module_param(substates, int, 0444);
+#endif
+
+MODULE_AUTHOR("Len Brown <len.brown@intel.com>");
+MODULE_DESCRIPTION("Cpuidle driver for Intel Hardware v" INTEL_IDLE_VERSION);
+MODULE_LICENSE("GPL");
index 9fd4a0d3206e9ee552d661df3be939f84122570d..adaefabc40e961257aa2ac1b24f34318316a2799 100644 (file)
@@ -1824,7 +1824,7 @@ static int dv1394_open(struct inode *inode, struct file *file)
               "and will not be available in the new firewire driver stack. "
               "Try libraw1394 based programs instead.\n", current->comm);
 
-       return 0;
+       return nonseekable_open(inode, file);
 }
 
 
@@ -2153,17 +2153,18 @@ static struct cdev dv1394_cdev;
 static const struct file_operations dv1394_fops=
 {
        .owner =        THIS_MODULE,
-       .poll =         dv1394_poll,
+       .poll =         dv1394_poll,
        .unlocked_ioctl = dv1394_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl = dv1394_compat_ioctl,
 #endif
        .mmap =         dv1394_mmap,
        .open =         dv1394_open,
-       .write =        dv1394_write,
-       .read =         dv1394_read,
+       .write =        dv1394_write,
+       .read =         dv1394_read,
        .release =      dv1394_release,
-       .fasync =       dv1394_fasync,
+       .fasync =       dv1394_fasync,
+       .llseek =       no_llseek,
 };
 
 
index 8aa56ac07e2920d371a5af41eca7f09c8b752380..b563d5e9fa2e5a7ea163390eb72c4e1a384505c1 100644 (file)
@@ -2834,7 +2834,7 @@ static int raw1394_open(struct inode *inode, struct file *file)
 
        file->private_data = fi;
 
-       return 0;
+       return nonseekable_open(inode, file);
 }
 
 static int raw1394_release(struct inode *inode, struct file *file)
@@ -3035,6 +3035,7 @@ static const struct file_operations raw1394_fops = {
        .poll = raw1394_poll,
        .open = raw1394_open,
        .release = raw1394_release,
+       .llseek = no_llseek,
 };
 
 static int __init init_raw1394(void)
index 949064a05675cbb766cded13fc2bba78a680ad49..a42bd6893bcf978a0dfddb83e54299c3039ed439 100644 (file)
@@ -1239,7 +1239,7 @@ static int video1394_open(struct inode *inode, struct file *file)
        ctx->current_ctx = NULL;
        file->private_data = ctx;
 
-       return 0;
+       return nonseekable_open(inode, file);
 }
 
 static int video1394_release(struct inode *inode, struct file *file)
@@ -1287,7 +1287,8 @@ static const struct file_operations video1394_fops=
        .poll =         video1394_poll,
        .mmap =         video1394_mmap,
        .open =         video1394_open,
-       .release =      video1394_release
+       .release =      video1394_release,
+       .llseek =       no_llseek,
 };
 
 /*** HOTPLUG STUFF **********************************************************/
index 330d2a423362d3fdb9434f2c9bd81369ec46b071..89d70de5e23558ded34fd48449c9d5995d25db6e 100644 (file)
@@ -43,6 +43,7 @@ config INFINIBAND_ADDR_TRANS
 
 source "drivers/infiniband/hw/mthca/Kconfig"
 source "drivers/infiniband/hw/ipath/Kconfig"
+source "drivers/infiniband/hw/qib/Kconfig"
 source "drivers/infiniband/hw/ehca/Kconfig"
 source "drivers/infiniband/hw/amso1100/Kconfig"
 source "drivers/infiniband/hw/cxgb3/Kconfig"
index 0c4e589d746e4717119a91e768b3ace6058f4d4c..9cc7a47d3e6737f22379384ac60366ea183d65dc 100644 (file)
@@ -1,6 +1,7 @@
 obj-$(CONFIG_INFINIBAND)               += core/
 obj-$(CONFIG_INFINIBAND_MTHCA)         += hw/mthca/
 obj-$(CONFIG_INFINIBAND_IPATH)         += hw/ipath/
+obj-$(CONFIG_INFINIBAND_QIB)           += hw/qib/
 obj-$(CONFIG_INFINIBAND_EHCA)          += hw/ehca/
 obj-$(CONFIG_INFINIBAND_AMSO1100)      += hw/amso1100/
 obj-$(CONFIG_INFINIBAND_CXGB3)         += hw/cxgb3/
index 05ac36e6acdb5a6df388446901a3e99e14b598b4..a565af5c2d2e8f9a6ee02a4b7224dd844445cd52 100644 (file)
@@ -38,7 +38,9 @@
 
 #include <rdma/ib_verbs.h>
 
-int  ib_device_register_sysfs(struct ib_device *device);
+int  ib_device_register_sysfs(struct ib_device *device,
+                             int (*port_callback)(struct ib_device *,
+                                                  u8, struct kobject *));
 void ib_device_unregister_sysfs(struct ib_device *device);
 
 int  ib_sysfs_setup(void);
index d1fba4153332658d4ab922f4d744cd1a1449c06b..a19effad0811a293b911eb29682e71711153419f 100644 (file)
@@ -267,7 +267,9 @@ out:
  * callback for each device that is added. @device must be allocated
  * with ib_alloc_device().
  */
-int ib_register_device(struct ib_device *device)
+int ib_register_device(struct ib_device *device,
+                      int (*port_callback)(struct ib_device *,
+                                           u8, struct kobject *))
 {
        int ret;
 
@@ -296,7 +298,7 @@ int ib_register_device(struct ib_device *device)
                goto out;
        }
 
-       ret = ib_device_register_sysfs(device);
+       ret = ib_device_register_sysfs(device, port_callback);
        if (ret) {
                printk(KERN_WARNING "Couldn't register device %s with driver model\n",
                       device->name);
index 6dc7b77d5d297e3a2f8ab267a6168aa12299263c..ef1304f151dc6fbaf9cf847a79557b1953f3e448 100644 (file)
@@ -47,8 +47,8 @@ MODULE_DESCRIPTION("kernel IB MAD API");
 MODULE_AUTHOR("Hal Rosenstock");
 MODULE_AUTHOR("Sean Hefty");
 
-int mad_sendq_size = IB_MAD_QP_SEND_SIZE;
-int mad_recvq_size = IB_MAD_QP_RECV_SIZE;
+static int mad_sendq_size = IB_MAD_QP_SEND_SIZE;
+static int mad_recvq_size = IB_MAD_QP_RECV_SIZE;
 
 module_param_named(send_queue_size, mad_sendq_size, int, 0444);
 MODULE_PARM_DESC(send_queue_size, "Size of send queue in number of work requests");
index f901957abc8b54ce68815eb19a26129a0e6b8867..3627300e2a10e1efe8d1435d32313a05b3302507 100644 (file)
@@ -475,7 +475,9 @@ err:
        return NULL;
 }
 
-static int add_port(struct ib_device *device, int port_num)
+static int add_port(struct ib_device *device, int port_num,
+                   int (*port_callback)(struct ib_device *,
+                                        u8, struct kobject *))
 {
        struct ib_port *p;
        struct ib_port_attr attr;
@@ -522,11 +524,20 @@ static int add_port(struct ib_device *device, int port_num)
        if (ret)
                goto err_free_pkey;
 
+       if (port_callback) {
+               ret = port_callback(device, port_num, &p->kobj);
+               if (ret)
+                       goto err_remove_pkey;
+       }
+
        list_add_tail(&p->kobj.entry, &device->port_list);
 
        kobject_uevent(&p->kobj, KOBJ_ADD);
        return 0;
 
+err_remove_pkey:
+       sysfs_remove_group(&p->kobj, &p->pkey_group);
+
 err_free_pkey:
        for (i = 0; i < attr.pkey_tbl_len; ++i)
                kfree(p->pkey_group.attrs[i]);
@@ -754,7 +765,9 @@ static struct attribute_group iw_stats_group = {
        .attrs  = iw_proto_stats_attrs,
 };
 
-int ib_device_register_sysfs(struct ib_device *device)
+int ib_device_register_sysfs(struct ib_device *device,
+                            int (*port_callback)(struct ib_device *,
+                                                 u8, struct kobject *))
 {
        struct device *class_dev = &device->dev;
        int ret;
@@ -785,12 +798,12 @@ int ib_device_register_sysfs(struct ib_device *device)
        }
 
        if (device->node_type == RDMA_NODE_IB_SWITCH) {
-               ret = add_port(device, 0);
+               ret = add_port(device, 0, port_callback);
                if (ret)
                        goto err_put;
        } else {
                for (i = 1; i <= device->phys_port_cnt; ++i) {
-                       ret = add_port(device, i);
+                       ret = add_port(device, i, port_callback);
                        if (ret)
                                goto err_put;
                }
index 46474842cfe9a8cd92bebf77170ae7ec02048bb2..08f948df8fa98aa933406172ee9e390ac3d3bc4e 100644 (file)
@@ -706,14 +706,9 @@ static int ib_ucm_alloc_data(const void **dest, u64 src, u32 len)
        if (!len)
                return 0;
 
-       data = kmalloc(len, GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
-
-       if (copy_from_user(data, (void __user *)(unsigned long)src, len)) {
-               kfree(data);
-               return -EFAULT;
-       }
+       data = memdup_user((void __user *)(unsigned long)src, len);
+       if (IS_ERR(data))
+               return PTR_ERR(data);
 
        *dest = data;
        return 0;
index c47f618d12e89084b4ea2945ee02b03a344373c4..aeebc4d37e3365d35dcb34653f99f8313ea66dc5 100644 (file)
@@ -865,7 +865,7 @@ int c2_register_device(struct c2_dev *dev)
        dev->ibdev.iwcm->create_listen = c2_service_create;
        dev->ibdev.iwcm->destroy_listen = c2_service_destroy;
 
-       ret = ib_register_device(&dev->ibdev);
+       ret = ib_register_device(&dev->ibdev, NULL);
        if (ret)
                goto out_free_iwcm;
 
index 19b1c4a62a2366c4018ca23ec9d5462ed8780340..fca0b4b747e4e5aedfb7668a74bb40fafdad9ff2 100644 (file)
@@ -1428,7 +1428,7 @@ int iwch_register_device(struct iwch_dev *dev)
        dev->ibdev.iwcm->rem_ref = iwch_qp_rem_ref;
        dev->ibdev.iwcm->get_qp = iwch_get_qp;
 
-       ret = ib_register_device(&dev->ibdev);
+       ret = ib_register_device(&dev->ibdev, NULL);
        if (ret)
                goto bail1;
 
index fb1aafcc294f1be1f85a6790b2bce0c340e35e0e..2447f5295482c4979fbbf88002ff2de34fe256cb 100644 (file)
@@ -373,6 +373,7 @@ static void create_read_req_cqe(struct t4_wq *wq, struct t4_cqe *hw_cqe,
                                 V_CQE_SWCQE(SW_CQE(hw_cqe)) |
                                 V_CQE_OPCODE(FW_RI_READ_REQ) |
                                 V_CQE_TYPE(1));
+       read_cqe->bits_type_ts = hw_cqe->bits_type_ts;
 }
 
 /*
@@ -780,6 +781,9 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, int entries,
        /* account for the status page. */
        entries++;
 
+       /* IQ needs one extra entry to differentiate full vs empty. */
+       entries++;
+
        /*
         * entries must be multiple of 16 for HW.
         */
@@ -801,7 +805,7 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, int entries,
 
        chp->rhp = rhp;
        chp->cq.size--;                         /* status page */
-       chp->ibcq.cqe = chp->cq.size;
+       chp->ibcq.cqe = chp->cq.size - 1;
        spin_lock_init(&chp->lock);
        atomic_set(&chp->refcnt, 1);
        init_waitqueue_head(&chp->wait);
index be23b5eab13b194aa0c90e0da7cb92c6416d897e..d870f9c17c1e85255618b3ca8068365ceb87d908 100644 (file)
@@ -306,7 +306,8 @@ static void c4iw_remove(struct c4iw_dev *dev)
        PDBG("%s c4iw_dev %p\n", __func__,  dev);
        cancel_delayed_work_sync(&dev->db_drop_task);
        list_del(&dev->entry);
-       c4iw_unregister_device(dev);
+       if (dev->registered)
+               c4iw_unregister_device(dev);
        c4iw_rdev_close(&dev->rdev);
        idr_destroy(&dev->cqidr);
        idr_destroy(&dev->qpidr);
@@ -343,12 +344,6 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
        list_add_tail(&devp->entry, &dev_list);
        mutex_unlock(&dev_mutex);
 
-       if (c4iw_register_device(devp)) {
-               printk(KERN_ERR MOD "Unable to register device\n");
-               mutex_lock(&dev_mutex);
-               c4iw_remove(devp);
-               mutex_unlock(&dev_mutex);
-       }
        if (c4iw_debugfs_root) {
                devp->debugfs_root = debugfs_create_dir(
                                        pci_name(devp->rdev.lldi.pdev),
@@ -379,9 +374,6 @@ static void *c4iw_uld_add(const struct cxgb4_lld_info *infop)
 
        for (i = 0; i < dev->rdev.lldi.nrxq; i++)
                PDBG("rxqid[%u] %u\n", i, dev->rdev.lldi.rxq_ids[i]);
-
-       printk(KERN_INFO MOD "Initialized device %s\n",
-              pci_name(dev->rdev.lldi.pdev));
 out:
        return dev;
 }
@@ -471,7 +463,41 @@ nomem:
 
 static int c4iw_uld_state_change(void *handle, enum cxgb4_state new_state)
 {
+       struct c4iw_dev *dev = handle;
+
        PDBG("%s new_state %u\n", __func__, new_state);
+       switch (new_state) {
+       case CXGB4_STATE_UP:
+               printk(KERN_INFO MOD "%s: Up\n", pci_name(dev->rdev.lldi.pdev));
+               if (!dev->registered) {
+                       int ret;
+                       ret = c4iw_register_device(dev);
+                       if (ret)
+                               printk(KERN_ERR MOD
+                                      "%s: RDMA registration failed: %d\n",
+                                      pci_name(dev->rdev.lldi.pdev), ret);
+               }
+               break;
+       case CXGB4_STATE_DOWN:
+               printk(KERN_INFO MOD "%s: Down\n",
+                      pci_name(dev->rdev.lldi.pdev));
+               if (dev->registered)
+                       c4iw_unregister_device(dev);
+               break;
+       case CXGB4_STATE_START_RECOVERY:
+               printk(KERN_INFO MOD "%s: Fatal Error\n",
+                      pci_name(dev->rdev.lldi.pdev));
+               if (dev->registered)
+                       c4iw_unregister_device(dev);
+               break;
+       case CXGB4_STATE_DETACH:
+               printk(KERN_INFO MOD "%s: Detach\n",
+                      pci_name(dev->rdev.lldi.pdev));
+               mutex_lock(&dev_mutex);
+               c4iw_remove(dev);
+               mutex_unlock(&dev_mutex);
+               break;
+       }
        return 0;
 }
 
@@ -504,14 +530,12 @@ static void __exit c4iw_exit_module(void)
 {
        struct c4iw_dev *dev, *tmp;
 
-       cxgb4_unregister_uld(CXGB4_ULD_RDMA);
-
        mutex_lock(&dev_mutex);
        list_for_each_entry_safe(dev, tmp, &dev_list, entry) {
                c4iw_remove(dev);
        }
        mutex_unlock(&dev_mutex);
-
+       cxgb4_unregister_uld(CXGB4_ULD_RDMA);
        c4iw_cm_term();
        debugfs_remove_recursive(c4iw_debugfs_root);
 }
index a6269981e81530a36822ac5a7176b8cbc00a6634..277ab589b44de93bb2c8553e8802f2f81589c694 100644 (file)
@@ -152,6 +152,7 @@ struct c4iw_dev {
        struct list_head entry;
        struct delayed_work db_drop_task;
        struct dentry *debugfs_root;
+       u8 registered;
 };
 
 static inline struct c4iw_dev *to_c4iw_dev(struct ib_device *ibdev)
index e54ff6d25691d2282cfdff4f46966cc83c8be617..7f94da1a2437ef9a3fc8fce75d717fe9ae4042f4 100644 (file)
@@ -712,8 +712,10 @@ struct ib_mr *c4iw_alloc_fast_reg_mr(struct ib_pd *pd, int pbl_depth)
        php = to_c4iw_pd(pd);
        rhp = php->rhp;
        mhp = kzalloc(sizeof(*mhp), GFP_KERNEL);
-       if (!mhp)
+       if (!mhp) {
+               ret = -ENOMEM;
                goto err;
+       }
 
        mhp->rhp = rhp;
        ret = alloc_pbl(mhp, pbl_depth);
@@ -730,8 +732,10 @@ struct ib_mr *c4iw_alloc_fast_reg_mr(struct ib_pd *pd, int pbl_depth)
        mhp->attr.state = 1;
        mmid = (stag) >> 8;
        mhp->ibmr.rkey = mhp->ibmr.lkey = stag;
-       if (insert_handle(rhp, &rhp->mmidr, mhp, mmid))
+       if (insert_handle(rhp, &rhp->mmidr, mhp, mmid)) {
+               ret = -ENOMEM;
                goto err3;
+       }
 
        PDBG("%s mmid 0x%x mhp %p stag 0x%x\n", __func__, mmid, mhp, stag);
        return &(mhp->ibmr);
@@ -755,9 +759,6 @@ struct ib_fast_reg_page_list *c4iw_alloc_fastreg_pbl(struct ib_device *device,
        dma_addr_t dma_addr;
        int size = sizeof *c4pl + page_list_len * sizeof(u64);
 
-       if (page_list_len > T4_MAX_FR_DEPTH)
-               return ERR_PTR(-EINVAL);
-
        c4pl = dma_alloc_coherent(&dev->rdev.lldi.pdev->dev, size,
                                  &dma_addr, GFP_KERNEL);
        if (!c4pl)
index dfc49020bb9cecf37e81328431a4a46a0f171678..8f645c83a125c1c9a1e3ad3ff400c3d90a0fec3a 100644 (file)
@@ -486,7 +486,7 @@ int c4iw_register_device(struct c4iw_dev *dev)
        dev->ibdev.iwcm->rem_ref = c4iw_qp_rem_ref;
        dev->ibdev.iwcm->get_qp = c4iw_get_qp;
 
-       ret = ib_register_device(&dev->ibdev);
+       ret = ib_register_device(&dev->ibdev, NULL);
        if (ret)
                goto bail1;
 
@@ -496,6 +496,7 @@ int c4iw_register_device(struct c4iw_dev *dev)
                if (ret)
                        goto bail2;
        }
+       dev->registered = 1;
        return 0;
 bail2:
        ib_unregister_device(&dev->ibdev);
@@ -514,5 +515,6 @@ void c4iw_unregister_device(struct c4iw_dev *dev)
                                   c4iw_class_attributes[i]);
        ib_unregister_device(&dev->ibdev);
        kfree(dev->ibdev.iwcm);
+       dev->registered = 0;
        return;
 }
index 83a01dc0c4c1c91c66fe5aec6e64bd1a23923560..0c28ed1eafa65236ef87e6b937d0ea77e46d1c5d 100644 (file)
@@ -572,9 +572,13 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        err = build_rdma_write(wqe, wr, &len16);
                        break;
                case IB_WR_RDMA_READ:
+               case IB_WR_RDMA_READ_WITH_INV:
                        fw_opcode = FW_RI_RDMA_READ_WR;
                        swsqe->opcode = FW_RI_READ_REQ;
-                       fw_flags = 0;
+                       if (wr->opcode == IB_WR_RDMA_READ_WITH_INV)
+                               fw_flags |= FW_RI_RDMA_READ_INVALIDATE;
+                       else
+                               fw_flags = 0;
                        err = build_rdma_read(wqe, wr, &len16);
                        if (err)
                                break;
@@ -588,6 +592,8 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        err = build_fastreg(wqe, wr, &len16);
                        break;
                case IB_WR_LOCAL_INV:
+                       if (wr->send_flags & IB_SEND_FENCE)
+                               fw_flags |= FW_RI_LOCAL_FENCE_FLAG;
                        fw_opcode = FW_RI_INV_LSTAG_WR;
                        swsqe->opcode = FW_RI_LOCAL_INV;
                        err = build_inv_stag(wqe, wr, &len16);
@@ -1339,7 +1345,6 @@ int c4iw_destroy_qp(struct ib_qp *ib_qp)
        wait_event(qhp->wait, !qhp->ep);
 
        remove_handle(rhp, &rhp->qpidr, qhp->wq.sq.qid);
-       remove_handle(rhp, &rhp->qpidr, qhp->wq.rq.qid);
        atomic_dec(&qhp->refcnt);
        wait_event(qhp->wait, !atomic_read(&qhp->refcnt));
 
@@ -1442,30 +1447,26 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
        if (ret)
                goto err2;
 
-       ret = insert_handle(rhp, &rhp->qpidr, qhp, qhp->wq.rq.qid);
-       if (ret)
-               goto err3;
-
        if (udata) {
                mm1 = kmalloc(sizeof *mm1, GFP_KERNEL);
                if (!mm1) {
                        ret = -ENOMEM;
-                       goto err4;
+                       goto err3;
                }
                mm2 = kmalloc(sizeof *mm2, GFP_KERNEL);
                if (!mm2) {
                        ret = -ENOMEM;
-                       goto err5;
+                       goto err4;
                }
                mm3 = kmalloc(sizeof *mm3, GFP_KERNEL);
                if (!mm3) {
                        ret = -ENOMEM;
-                       goto err6;
+                       goto err5;
                }
                mm4 = kmalloc(sizeof *mm4, GFP_KERNEL);
                if (!mm4) {
                        ret = -ENOMEM;
-                       goto err7;
+                       goto err6;
                }
 
                uresp.qid_mask = rhp->rdev.qpmask;
@@ -1487,7 +1488,7 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
                spin_unlock(&ucontext->mmap_lock);
                ret = ib_copy_to_udata(udata, &uresp, sizeof uresp);
                if (ret)
-                       goto err8;
+                       goto err7;
                mm1->key = uresp.sq_key;
                mm1->addr = virt_to_phys(qhp->wq.sq.queue);
                mm1->len = PAGE_ALIGN(qhp->wq.sq.memsize);
@@ -1511,16 +1512,14 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
             __func__, qhp, qhp->attr.sq_num_entries, qhp->attr.rq_num_entries,
             qhp->wq.sq.qid);
        return &qhp->ibqp;
-err8:
-       kfree(mm4);
 err7:
-       kfree(mm3);
+       kfree(mm4);
 err6:
-       kfree(mm2);
+       kfree(mm3);
 err5:
-       kfree(mm1);
+       kfree(mm2);
 err4:
-       remove_handle(rhp, &rhp->qpidr, qhp->wq.rq.qid);
+       kfree(mm1);
 err3:
        remove_handle(rhp, &rhp->qpidr, qhp->wq.sq.qid);
 err2:
index d0e8af3524082b3e9cb3bff25af04aca3394b42f..1057cb96302e36471c13a24ff3b02653f3023ef0 100644 (file)
 #define T4_MAX_NUM_QP (1<<16)
 #define T4_MAX_NUM_CQ (1<<15)
 #define T4_MAX_NUM_PD (1<<15)
-#define T4_MAX_PBL_SIZE 256
-#define T4_MAX_RQ_SIZE 1024
-#define T4_MAX_SQ_SIZE 1024
-#define T4_MAX_QP_DEPTH (T4_MAX_RQ_SIZE-1)
-#define T4_MAX_CQ_DEPTH 8192
+#define T4_EQ_STATUS_ENTRIES (L1_CACHE_BYTES > 64 ? 2 : 1)
+#define T4_MAX_EQ_SIZE (65520 - T4_EQ_STATUS_ENTRIES)
+#define T4_MAX_IQ_SIZE (65520 - 1)
+#define T4_MAX_RQ_SIZE (8192 - T4_EQ_STATUS_ENTRIES)
+#define T4_MAX_SQ_SIZE (T4_MAX_EQ_SIZE - 1)
+#define T4_MAX_QP_DEPTH (T4_MAX_RQ_SIZE - 1)
+#define T4_MAX_CQ_DEPTH (T4_MAX_IQ_SIZE - 1)
 #define T4_MAX_NUM_STAG (1<<15)
 #define T4_MAX_MR_SIZE (~0ULL - 1)
 #define T4_PAGESIZE_MASK 0xffff000  /* 4KB-128MB */
@@ -79,12 +81,11 @@ struct t4_status_page {
                        sizeof(struct fw_ri_isgl)) / sizeof(struct fw_ri_sge))
 #define T4_MAX_FR_IMMD ((T4_SQ_NUM_BYTES - sizeof(struct fw_ri_fr_nsmr_wr) - \
                        sizeof(struct fw_ri_immd)))
-#define T4_MAX_FR_DEPTH 255
+#define T4_MAX_FR_DEPTH (T4_MAX_FR_IMMD / sizeof(u64))
 
 #define T4_RQ_NUM_SLOTS 2
 #define T4_RQ_NUM_BYTES (T4_EQ_SIZE * T4_RQ_NUM_SLOTS)
-#define T4_MAX_RECV_SGE ((T4_RQ_NUM_BYTES - sizeof(struct fw_ri_recv_wr) - \
-                       sizeof(struct fw_ri_isgl)) / sizeof(struct fw_ri_sge))
+#define T4_MAX_RECV_SGE 4
 
 union t4_wr {
        struct fw_ri_res_wr res;
@@ -434,7 +435,7 @@ struct t4_cq {
        struct c4iw_rdev *rdev;
        u64 ugts;
        size_t memsize;
-       u64 timestamp;
+       __be64 bits_type_ts;
        u32 cqid;
        u16 size; /* including status page */
        u16 cidx;
@@ -449,25 +450,17 @@ struct t4_cq {
 static inline int t4_arm_cq(struct t4_cq *cq, int se)
 {
        u32 val;
-       u16 inc;
-
-       do {
-               /*
-                * inc must be less the both the max update value -and-
-                * the size of the CQ.
-                */
-               inc = cq->cidx_inc <= CIDXINC_MASK ? cq->cidx_inc :
-                                                    CIDXINC_MASK;
-               inc = inc <= (cq->size - 1) ? inc : (cq->size - 1);
-               if (inc == cq->cidx_inc)
-                       val = SEINTARM(se) | CIDXINC(inc) | TIMERREG(6) |
-                             INGRESSQID(cq->cqid);
-               else
-                       val = SEINTARM(0) | CIDXINC(inc) | TIMERREG(7) |
-                             INGRESSQID(cq->cqid);
-               cq->cidx_inc -= inc;
+
+       while (cq->cidx_inc > CIDXINC_MASK) {
+               val = SEINTARM(0) | CIDXINC(CIDXINC_MASK) | TIMERREG(7) |
+                     INGRESSQID(cq->cqid);
                writel(val, cq->gts);
-       } while (cq->cidx_inc);
+               cq->cidx_inc -= CIDXINC_MASK;
+       }
+       val = SEINTARM(se) | CIDXINC(cq->cidx_inc) | TIMERREG(6) |
+             INGRESSQID(cq->cqid);
+       writel(val, cq->gts);
+       cq->cidx_inc = 0;
        return 0;
 }
 
@@ -487,7 +480,9 @@ static inline void t4_swcq_consume(struct t4_cq *cq)
 
 static inline void t4_hwcq_consume(struct t4_cq *cq)
 {
-       cq->cidx_inc++;
+       cq->bits_type_ts = cq->queue[cq->cidx].bits_type_ts;
+       if (++cq->cidx_inc == cq->size)
+               cq->cidx_inc = 0;
        if (++cq->cidx == cq->size) {
                cq->cidx = 0;
                cq->gen ^= 1;
@@ -501,20 +496,23 @@ static inline int t4_valid_cqe(struct t4_cq *cq, struct t4_cqe *cqe)
 
 static inline int t4_next_hw_cqe(struct t4_cq *cq, struct t4_cqe **cqe)
 {
-       int ret = 0;
-       u64 bits_type_ts = be64_to_cpu(cq->queue[cq->cidx].bits_type_ts);
+       int ret;
+       u16 prev_cidx;
 
-       if (G_CQE_GENBIT(bits_type_ts) == cq->gen) {
-               *cqe = &cq->queue[cq->cidx];
-               cq->timestamp = G_CQE_TS(bits_type_ts);
-       } else if (G_CQE_TS(bits_type_ts) > cq->timestamp)
-               ret = -EOVERFLOW;
+       if (cq->cidx == 0)
+               prev_cidx = cq->size - 1;
        else
-               ret = -ENODATA;
-       if (ret == -EOVERFLOW) {
-               printk(KERN_ERR MOD "cq overflow cqid %u\n", cq->cqid);
+               prev_cidx = cq->cidx - 1;
+
+       if (cq->queue[prev_cidx].bits_type_ts != cq->bits_type_ts) {
+               ret = -EOVERFLOW;
                cq->error = 1;
-       }
+               printk(KERN_ERR MOD "cq overflow cqid %u\n", cq->cqid);
+       } else if (t4_valid_cqe(cq, &cq->queue[cq->cidx])) {
+               *cqe = &cq->queue[cq->cidx];
+               ret = 0;
+       } else
+               ret = -ENODATA;
        return ret;
 }
 
index 07cae552cafba60be9efb413b210d6e1ae767243..e571e60ecb880ca5f899d6b66466d9345f0dc9c4 100644 (file)
@@ -847,7 +847,7 @@ static int __cpuinit comp_pool_callback(struct notifier_block *nfb,
                ehca_gen_dbg("CPU: %x (CPU_PREPARE)", cpu);
                if (!create_comp_task(pool, cpu)) {
                        ehca_gen_err("Can't create comp_task for cpu: %x", cpu);
-                       return NOTIFY_BAD;
+                       return notifier_from_errno(-ENOMEM);
                }
                break;
        case CPU_UP_CANCELED:
index 129a6bebd6e37bc20f6b3f36e77b0fb7653865e5..ecb51b396c42d2a3b85e7dd29e40a28e412455cc 100644 (file)
@@ -291,8 +291,9 @@ static int ehca_sense_attributes(struct ehca_shca *shca)
        };
 
        ehca_gen_dbg("Probing adapter %s...",
-                    shca->ofdev->node->full_name);
-       loc_code = of_get_property(shca->ofdev->node, "ibm,loc-code", NULL);
+                    shca->ofdev->dev.of_node->full_name);
+       loc_code = of_get_property(shca->ofdev->dev.of_node, "ibm,loc-code",
+                                  NULL);
        if (loc_code)
                ehca_gen_dbg(" ... location lode=%s", loc_code);
 
@@ -720,16 +721,16 @@ static int __devinit ehca_probe(struct of_device *dev,
        int ret, i, eq_size;
        unsigned long flags;
 
-       handle = of_get_property(dev->node, "ibm,hca-handle", NULL);
+       handle = of_get_property(dev->dev.of_node, "ibm,hca-handle", NULL);
        if (!handle) {
                ehca_gen_err("Cannot get eHCA handle for adapter: %s.",
-                            dev->node->full_name);
+                            dev->dev.of_node->full_name);
                return -ENODEV;
        }
 
        if (!(*handle)) {
                ehca_gen_err("Wrong eHCA handle for adapter: %s.",
-                            dev->node->full_name);
+                            dev->dev.of_node->full_name);
                return -ENODEV;
        }
 
@@ -798,7 +799,7 @@ static int __devinit ehca_probe(struct of_device *dev,
                goto probe5;
        }
 
-       ret = ib_register_device(&shca->ib_device);
+       ret = ib_register_device(&shca->ib_device, NULL);
        if (ret) {
                ehca_err(&shca->ib_device,
                         "ib_register_device() failed ret=%i", ret);
@@ -936,12 +937,13 @@ static struct of_device_id ehca_device_table[] =
 MODULE_DEVICE_TABLE(of, ehca_device_table);
 
 static struct of_platform_driver ehca_driver = {
-       .name        = "ehca",
-       .match_table = ehca_device_table,
        .probe       = ehca_probe,
        .remove      = ehca_remove,
-       .driver      = {
+       .driver = {
+               .name = "ehca",
+               .owner = THIS_MODULE,
                .groups = ehca_drv_attr_groups,
+               .of_match_table = ehca_device_table,
        },
 };
 
index 3c7968f25ec2d70210d702f3e0c4966467489e53..1d9bb115cbf60799cd3c705bc0b166bb7640e7d7 100644 (file)
@@ -1,9 +1,11 @@
 config INFINIBAND_IPATH
-       tristate "QLogic InfiniPath Driver"
-       depends on 64BIT && NET
+       tristate "QLogic HTX HCA support"
+       depends on 64BIT && NET && HT_IRQ
        ---help---
-       This is a driver for QLogic InfiniPath host channel adapters,
+       This is a driver for the obsolete QLogic Hyper-Transport
+       IB host channel adapter (model QHT7140),
        including InfiniBand verbs support.  This driver allows these
        devices to be used with both kernel upper level protocols such
        as IP-over-InfiniBand as well as with userspace applications
        (in conjunction with InfiniBand userspace access).
+       For QLogic PCIe QLE based cards, use the QIB driver instead.
index bf945006198645eeff5e75f5ffa8b6f004f895ba..fa3df82681dfb9b695232bca88434d17948b4027 100644 (file)
@@ -29,13 +29,9 @@ ib_ipath-y := \
        ipath_user_pages.o \
        ipath_user_sdma.o \
        ipath_verbs_mcast.o \
-       ipath_verbs.o \
-       ipath_iba7220.o \
-       ipath_sd7220.o \
-       ipath_sd7220_img.o
+       ipath_verbs.o
 
 ib_ipath-$(CONFIG_HT_IRQ) += ipath_iba6110.o
-ib_ipath-$(CONFIG_PCI_MSI) += ipath_iba6120.o
 
 ib_ipath-$(CONFIG_X86_64) += ipath_wc_x86_64.o
 ib_ipath-$(CONFIG_PPC64) += ipath_wc_ppc64.o
index 6302626d17f005536229657b465c1be3b76c01fd..21337468c652442b7a668243f2b10510c6ae3a5b 100644 (file)
@@ -132,18 +132,13 @@ static int __devinit ipath_init_one(struct pci_dev *,
 
 /* Only needed for registration, nothing else needs this info */
 #define PCI_VENDOR_ID_PATHSCALE 0x1fc1
-#define PCI_VENDOR_ID_QLOGIC 0x1077
 #define PCI_DEVICE_ID_INFINIPATH_HT 0xd
-#define PCI_DEVICE_ID_INFINIPATH_PE800 0x10
-#define PCI_DEVICE_ID_INFINIPATH_7220 0x7220
 
 /* Number of seconds before our card status check...  */
 #define STATUS_TIMEOUT 60
 
 static const struct pci_device_id ipath_pci_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_PATHSCALE, PCI_DEVICE_ID_INFINIPATH_HT) },
-       { PCI_DEVICE(PCI_VENDOR_ID_PATHSCALE, PCI_DEVICE_ID_INFINIPATH_PE800) },
-       { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_INFINIPATH_7220) },
        { 0, }
 };
 
@@ -521,30 +516,9 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
        /* setup the chip-specific functions, as early as possible. */
        switch (ent->device) {
        case PCI_DEVICE_ID_INFINIPATH_HT:
-#ifdef CONFIG_HT_IRQ
                ipath_init_iba6110_funcs(dd);
                break;
-#else
-               ipath_dev_err(dd, "QLogic HT device 0x%x cannot work if "
-                             "CONFIG_HT_IRQ is not enabled\n", ent->device);
-               return -ENODEV;
-#endif
-       case PCI_DEVICE_ID_INFINIPATH_PE800:
-#ifdef CONFIG_PCI_MSI
-               ipath_init_iba6120_funcs(dd);
-               break;
-#else
-               ipath_dev_err(dd, "QLogic PCIE device 0x%x cannot work if "
-                             "CONFIG_PCI_MSI is not enabled\n", ent->device);
-               return -ENODEV;
-#endif
-       case PCI_DEVICE_ID_INFINIPATH_7220:
-#ifndef CONFIG_PCI_MSI
-               ipath_dbg("CONFIG_PCI_MSI is not enabled, "
-                         "using INTx for unit %u\n", dd->ipath_unit);
-#endif
-               ipath_init_iba7220_funcs(dd);
-               break;
+
        default:
                ipath_dev_err(dd, "Found unknown QLogic deviceid 0x%x, "
                              "failing\n", ent->device);
diff --git a/drivers/infiniband/hw/ipath/ipath_iba6120.c b/drivers/infiniband/hw/ipath/ipath_iba6120.c
deleted file mode 100644 (file)
index 4b4a30b..0000000
+++ /dev/null
@@ -1,1862 +0,0 @@
-/*
- * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved.
- * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     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.
- *
- * 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.
- */
-/*
- * This file contains all of the code that is specific to the
- * InfiniPath PCIe chip.
- */
-
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <rdma/ib_verbs.h>
-
-#include "ipath_kernel.h"
-#include "ipath_registers.h"
-
-static void ipath_setup_pe_setextled(struct ipath_devdata *, u64, u64);
-
-/*
- * This file contains all the chip-specific register information and
- * access functions for the QLogic InfiniPath PCI-Express chip.
- *
- * This lists the InfiniPath registers, in the actual chip layout.
- * This structure should never be directly accessed.
- */
-struct _infinipath_do_not_use_kernel_regs {
-       unsigned long long Revision;
-       unsigned long long Control;
-       unsigned long long PageAlign;
-       unsigned long long PortCnt;
-       unsigned long long DebugPortSelect;
-       unsigned long long Reserved0;
-       unsigned long long SendRegBase;
-       unsigned long long UserRegBase;
-       unsigned long long CounterRegBase;
-       unsigned long long Scratch;
-       unsigned long long Reserved1;
-       unsigned long long Reserved2;
-       unsigned long long IntBlocked;
-       unsigned long long IntMask;
-       unsigned long long IntStatus;
-       unsigned long long IntClear;
-       unsigned long long ErrorMask;
-       unsigned long long ErrorStatus;
-       unsigned long long ErrorClear;
-       unsigned long long HwErrMask;
-       unsigned long long HwErrStatus;
-       unsigned long long HwErrClear;
-       unsigned long long HwDiagCtrl;
-       unsigned long long MDIO;
-       unsigned long long IBCStatus;
-       unsigned long long IBCCtrl;
-       unsigned long long ExtStatus;
-       unsigned long long ExtCtrl;
-       unsigned long long GPIOOut;
-       unsigned long long GPIOMask;
-       unsigned long long GPIOStatus;
-       unsigned long long GPIOClear;
-       unsigned long long RcvCtrl;
-       unsigned long long RcvBTHQP;
-       unsigned long long RcvHdrSize;
-       unsigned long long RcvHdrCnt;
-       unsigned long long RcvHdrEntSize;
-       unsigned long long RcvTIDBase;
-       unsigned long long RcvTIDCnt;
-       unsigned long long RcvEgrBase;
-       unsigned long long RcvEgrCnt;
-       unsigned long long RcvBufBase;
-       unsigned long long RcvBufSize;
-       unsigned long long RxIntMemBase;
-       unsigned long long RxIntMemSize;
-       unsigned long long RcvPartitionKey;
-       unsigned long long Reserved3;
-       unsigned long long RcvPktLEDCnt;
-       unsigned long long Reserved4[8];
-       unsigned long long SendCtrl;
-       unsigned long long SendPIOBufBase;
-       unsigned long long SendPIOSize;
-       unsigned long long SendPIOBufCnt;
-       unsigned long long SendPIOAvailAddr;
-       unsigned long long TxIntMemBase;
-       unsigned long long TxIntMemSize;
-       unsigned long long Reserved5;
-       unsigned long long PCIeRBufTestReg0;
-       unsigned long long PCIeRBufTestReg1;
-       unsigned long long Reserved51[6];
-       unsigned long long SendBufferError;
-       unsigned long long SendBufferErrorCONT1;
-       unsigned long long Reserved6SBE[6];
-       unsigned long long RcvHdrAddr0;
-       unsigned long long RcvHdrAddr1;
-       unsigned long long RcvHdrAddr2;
-       unsigned long long RcvHdrAddr3;
-       unsigned long long RcvHdrAddr4;
-       unsigned long long Reserved7RHA[11];
-       unsigned long long RcvHdrTailAddr0;
-       unsigned long long RcvHdrTailAddr1;
-       unsigned long long RcvHdrTailAddr2;
-       unsigned long long RcvHdrTailAddr3;
-       unsigned long long RcvHdrTailAddr4;
-       unsigned long long Reserved8RHTA[11];
-       unsigned long long Reserved9SW[8];
-       unsigned long long SerdesConfig0;
-       unsigned long long SerdesConfig1;
-       unsigned long long SerdesStatus;
-       unsigned long long XGXSConfig;
-       unsigned long long IBPLLCfg;
-       unsigned long long Reserved10SW2[3];
-       unsigned long long PCIEQ0SerdesConfig0;
-       unsigned long long PCIEQ0SerdesConfig1;
-       unsigned long long PCIEQ0SerdesStatus;
-       unsigned long long Reserved11;
-       unsigned long long PCIEQ1SerdesConfig0;
-       unsigned long long PCIEQ1SerdesConfig1;
-       unsigned long long PCIEQ1SerdesStatus;
-       unsigned long long Reserved12;
-};
-
-struct _infinipath_do_not_use_counters {
-       __u64 LBIntCnt;
-       __u64 LBFlowStallCnt;
-       __u64 Reserved1;
-       __u64 TxUnsupVLErrCnt;
-       __u64 TxDataPktCnt;
-       __u64 TxFlowPktCnt;
-       __u64 TxDwordCnt;
-       __u64 TxLenErrCnt;
-       __u64 TxMaxMinLenErrCnt;
-       __u64 TxUnderrunCnt;
-       __u64 TxFlowStallCnt;
-       __u64 TxDroppedPktCnt;
-       __u64 RxDroppedPktCnt;
-       __u64 RxDataPktCnt;
-       __u64 RxFlowPktCnt;
-       __u64 RxDwordCnt;
-       __u64 RxLenErrCnt;
-       __u64 RxMaxMinLenErrCnt;
-       __u64 RxICRCErrCnt;
-       __u64 RxVCRCErrCnt;
-       __u64 RxFlowCtrlErrCnt;
-       __u64 RxBadFormatCnt;
-       __u64 RxLinkProblemCnt;
-       __u64 RxEBPCnt;
-       __u64 RxLPCRCErrCnt;
-       __u64 RxBufOvflCnt;
-       __u64 RxTIDFullErrCnt;
-       __u64 RxTIDValidErrCnt;
-       __u64 RxPKeyMismatchCnt;
-       __u64 RxP0HdrEgrOvflCnt;
-       __u64 RxP1HdrEgrOvflCnt;
-       __u64 RxP2HdrEgrOvflCnt;
-       __u64 RxP3HdrEgrOvflCnt;
-       __u64 RxP4HdrEgrOvflCnt;
-       __u64 RxP5HdrEgrOvflCnt;
-       __u64 RxP6HdrEgrOvflCnt;
-       __u64 RxP7HdrEgrOvflCnt;
-       __u64 RxP8HdrEgrOvflCnt;
-       __u64 Reserved6;
-       __u64 Reserved7;
-       __u64 IBStatusChangeCnt;
-       __u64 IBLinkErrRecoveryCnt;
-       __u64 IBLinkDownedCnt;
-       __u64 IBSymbolErrCnt;
-};
-
-#define IPATH_KREG_OFFSET(field) (offsetof( \
-       struct _infinipath_do_not_use_kernel_regs, field) / sizeof(u64))
-#define IPATH_CREG_OFFSET(field) (offsetof( \
-       struct _infinipath_do_not_use_counters, field) / sizeof(u64))
-
-static const struct ipath_kregs ipath_pe_kregs = {
-       .kr_control = IPATH_KREG_OFFSET(Control),
-       .kr_counterregbase = IPATH_KREG_OFFSET(CounterRegBase),
-       .kr_debugportselect = IPATH_KREG_OFFSET(DebugPortSelect),
-       .kr_errorclear = IPATH_KREG_OFFSET(ErrorClear),
-       .kr_errormask = IPATH_KREG_OFFSET(ErrorMask),
-       .kr_errorstatus = IPATH_KREG_OFFSET(ErrorStatus),
-       .kr_extctrl = IPATH_KREG_OFFSET(ExtCtrl),
-       .kr_extstatus = IPATH_KREG_OFFSET(ExtStatus),
-       .kr_gpio_clear = IPATH_KREG_OFFSET(GPIOClear),
-       .kr_gpio_mask = IPATH_KREG_OFFSET(GPIOMask),
-       .kr_gpio_out = IPATH_KREG_OFFSET(GPIOOut),
-       .kr_gpio_status = IPATH_KREG_OFFSET(GPIOStatus),
-       .kr_hwdiagctrl = IPATH_KREG_OFFSET(HwDiagCtrl),
-       .kr_hwerrclear = IPATH_KREG_OFFSET(HwErrClear),
-       .kr_hwerrmask = IPATH_KREG_OFFSET(HwErrMask),
-       .kr_hwerrstatus = IPATH_KREG_OFFSET(HwErrStatus),
-       .kr_ibcctrl = IPATH_KREG_OFFSET(IBCCtrl),
-       .kr_ibcstatus = IPATH_KREG_OFFSET(IBCStatus),
-       .kr_intblocked = IPATH_KREG_OFFSET(IntBlocked),
-       .kr_intclear = IPATH_KREG_OFFSET(IntClear),
-       .kr_intmask = IPATH_KREG_OFFSET(IntMask),
-       .kr_intstatus = IPATH_KREG_OFFSET(IntStatus),
-       .kr_mdio = IPATH_KREG_OFFSET(MDIO),
-       .kr_pagealign = IPATH_KREG_OFFSET(PageAlign),
-       .kr_partitionkey = IPATH_KREG_OFFSET(RcvPartitionKey),
-       .kr_portcnt = IPATH_KREG_OFFSET(PortCnt),
-       .kr_rcvbthqp = IPATH_KREG_OFFSET(RcvBTHQP),
-       .kr_rcvbufbase = IPATH_KREG_OFFSET(RcvBufBase),
-       .kr_rcvbufsize = IPATH_KREG_OFFSET(RcvBufSize),
-       .kr_rcvctrl = IPATH_KREG_OFFSET(RcvCtrl),
-       .kr_rcvegrbase = IPATH_KREG_OFFSET(RcvEgrBase),
-       .kr_rcvegrcnt = IPATH_KREG_OFFSET(RcvEgrCnt),
-       .kr_rcvhdrcnt = IPATH_KREG_OFFSET(RcvHdrCnt),
-       .kr_rcvhdrentsize = IPATH_KREG_OFFSET(RcvHdrEntSize),
-       .kr_rcvhdrsize = IPATH_KREG_OFFSET(RcvHdrSize),
-       .kr_rcvintmembase = IPATH_KREG_OFFSET(RxIntMemBase),
-       .kr_rcvintmemsize = IPATH_KREG_OFFSET(RxIntMemSize),
-       .kr_rcvtidbase = IPATH_KREG_OFFSET(RcvTIDBase),
-       .kr_rcvtidcnt = IPATH_KREG_OFFSET(RcvTIDCnt),
-       .kr_revision = IPATH_KREG_OFFSET(Revision),
-       .kr_scratch = IPATH_KREG_OFFSET(Scratch),
-       .kr_sendbuffererror = IPATH_KREG_OFFSET(SendBufferError),
-       .kr_sendctrl = IPATH_KREG_OFFSET(SendCtrl),
-       .kr_sendpioavailaddr = IPATH_KREG_OFFSET(SendPIOAvailAddr),
-       .kr_sendpiobufbase = IPATH_KREG_OFFSET(SendPIOBufBase),
-       .kr_sendpiobufcnt = IPATH_KREG_OFFSET(SendPIOBufCnt),
-       .kr_sendpiosize = IPATH_KREG_OFFSET(SendPIOSize),
-       .kr_sendregbase = IPATH_KREG_OFFSET(SendRegBase),
-       .kr_txintmembase = IPATH_KREG_OFFSET(TxIntMemBase),
-       .kr_txintmemsize = IPATH_KREG_OFFSET(TxIntMemSize),
-       .kr_userregbase = IPATH_KREG_OFFSET(UserRegBase),
-       .kr_serdesconfig0 = IPATH_KREG_OFFSET(SerdesConfig0),
-       .kr_serdesconfig1 = IPATH_KREG_OFFSET(SerdesConfig1),
-       .kr_serdesstatus = IPATH_KREG_OFFSET(SerdesStatus),
-       .kr_xgxsconfig = IPATH_KREG_OFFSET(XGXSConfig),
-       .kr_ibpllcfg = IPATH_KREG_OFFSET(IBPLLCfg),
-
-       /*
-        * These should not be used directly via ipath_write_kreg64(),
-        * use them with ipath_write_kreg64_port(),
-        */
-       .kr_rcvhdraddr = IPATH_KREG_OFFSET(RcvHdrAddr0),
-       .kr_rcvhdrtailaddr = IPATH_KREG_OFFSET(RcvHdrTailAddr0),
-
-       /* The rcvpktled register controls one of the debug port signals, so
-        * a packet activity LED can be connected to it. */
-       .kr_rcvpktledcnt = IPATH_KREG_OFFSET(RcvPktLEDCnt),
-       .kr_pcierbuftestreg0 = IPATH_KREG_OFFSET(PCIeRBufTestReg0),
-       .kr_pcierbuftestreg1 = IPATH_KREG_OFFSET(PCIeRBufTestReg1),
-       .kr_pcieq0serdesconfig0 = IPATH_KREG_OFFSET(PCIEQ0SerdesConfig0),
-       .kr_pcieq0serdesconfig1 = IPATH_KREG_OFFSET(PCIEQ0SerdesConfig1),
-       .kr_pcieq0serdesstatus = IPATH_KREG_OFFSET(PCIEQ0SerdesStatus),
-       .kr_pcieq1serdesconfig0 = IPATH_KREG_OFFSET(PCIEQ1SerdesConfig0),
-       .kr_pcieq1serdesconfig1 = IPATH_KREG_OFFSET(PCIEQ1SerdesConfig1),
-       .kr_pcieq1serdesstatus = IPATH_KREG_OFFSET(PCIEQ1SerdesStatus)
-};
-
-static const struct ipath_cregs ipath_pe_cregs = {
-       .cr_badformatcnt = IPATH_CREG_OFFSET(RxBadFormatCnt),
-       .cr_erricrccnt = IPATH_CREG_OFFSET(RxICRCErrCnt),
-       .cr_errlinkcnt = IPATH_CREG_OFFSET(RxLinkProblemCnt),
-       .cr_errlpcrccnt = IPATH_CREG_OFFSET(RxLPCRCErrCnt),
-       .cr_errpkey = IPATH_CREG_OFFSET(RxPKeyMismatchCnt),
-       .cr_errrcvflowctrlcnt = IPATH_CREG_OFFSET(RxFlowCtrlErrCnt),
-       .cr_err_rlencnt = IPATH_CREG_OFFSET(RxLenErrCnt),
-       .cr_errslencnt = IPATH_CREG_OFFSET(TxLenErrCnt),
-       .cr_errtidfull = IPATH_CREG_OFFSET(RxTIDFullErrCnt),
-       .cr_errtidvalid = IPATH_CREG_OFFSET(RxTIDValidErrCnt),
-       .cr_errvcrccnt = IPATH_CREG_OFFSET(RxVCRCErrCnt),
-       .cr_ibstatuschange = IPATH_CREG_OFFSET(IBStatusChangeCnt),
-       .cr_intcnt = IPATH_CREG_OFFSET(LBIntCnt),
-       .cr_invalidrlencnt = IPATH_CREG_OFFSET(RxMaxMinLenErrCnt),
-       .cr_invalidslencnt = IPATH_CREG_OFFSET(TxMaxMinLenErrCnt),
-       .cr_lbflowstallcnt = IPATH_CREG_OFFSET(LBFlowStallCnt),
-       .cr_pktrcvcnt = IPATH_CREG_OFFSET(RxDataPktCnt),
-       .cr_pktrcvflowctrlcnt = IPATH_CREG_OFFSET(RxFlowPktCnt),
-       .cr_pktsendcnt = IPATH_CREG_OFFSET(TxDataPktCnt),
-       .cr_pktsendflowcnt = IPATH_CREG_OFFSET(TxFlowPktCnt),
-       .cr_portovflcnt = IPATH_CREG_OFFSET(RxP0HdrEgrOvflCnt),
-       .cr_rcvebpcnt = IPATH_CREG_OFFSET(RxEBPCnt),
-       .cr_rcvovflcnt = IPATH_CREG_OFFSET(RxBufOvflCnt),
-       .cr_senddropped = IPATH_CREG_OFFSET(TxDroppedPktCnt),
-       .cr_sendstallcnt = IPATH_CREG_OFFSET(TxFlowStallCnt),
-       .cr_sendunderruncnt = IPATH_CREG_OFFSET(TxUnderrunCnt),
-       .cr_wordrcvcnt = IPATH_CREG_OFFSET(RxDwordCnt),
-       .cr_wordsendcnt = IPATH_CREG_OFFSET(TxDwordCnt),
-       .cr_unsupvlcnt = IPATH_CREG_OFFSET(TxUnsupVLErrCnt),
-       .cr_rxdroppktcnt = IPATH_CREG_OFFSET(RxDroppedPktCnt),
-       .cr_iblinkerrrecovcnt = IPATH_CREG_OFFSET(IBLinkErrRecoveryCnt),
-       .cr_iblinkdowncnt = IPATH_CREG_OFFSET(IBLinkDownedCnt),
-       .cr_ibsymbolerrcnt = IPATH_CREG_OFFSET(IBSymbolErrCnt)
-};
-
-/* kr_control bits */
-#define INFINIPATH_C_RESET 1U
-
-/* kr_intstatus, kr_intclear, kr_intmask bits */
-#define INFINIPATH_I_RCVURG_MASK ((1U<<5)-1)
-#define INFINIPATH_I_RCVURG_SHIFT 0
-#define INFINIPATH_I_RCVAVAIL_MASK ((1U<<5)-1)
-#define INFINIPATH_I_RCVAVAIL_SHIFT 12
-
-/* kr_hwerrclear, kr_hwerrmask, kr_hwerrstatus, bits */
-#define INFINIPATH_HWE_PCIEMEMPARITYERR_MASK  0x000000000000003fULL
-#define INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT 0
-#define INFINIPATH_HWE_PCIEPOISONEDTLP      0x0000000010000000ULL
-#define INFINIPATH_HWE_PCIECPLTIMEOUT       0x0000000020000000ULL
-#define INFINIPATH_HWE_PCIEBUSPARITYXTLH    0x0000000040000000ULL
-#define INFINIPATH_HWE_PCIEBUSPARITYXADM    0x0000000080000000ULL
-#define INFINIPATH_HWE_PCIEBUSPARITYRADM    0x0000000100000000ULL
-#define INFINIPATH_HWE_COREPLL_FBSLIP       0x0080000000000000ULL
-#define INFINIPATH_HWE_COREPLL_RFSLIP       0x0100000000000000ULL
-#define INFINIPATH_HWE_PCIE1PLLFAILED       0x0400000000000000ULL
-#define INFINIPATH_HWE_PCIE0PLLFAILED       0x0800000000000000ULL
-#define INFINIPATH_HWE_SERDESPLLFAILED      0x1000000000000000ULL
-
-#define IBA6120_IBCS_LINKTRAININGSTATE_MASK 0xf
-#define IBA6120_IBCS_LINKSTATE_SHIFT 4
-
-/* kr_extstatus bits */
-#define INFINIPATH_EXTS_FREQSEL 0x2
-#define INFINIPATH_EXTS_SERDESSEL 0x4
-#define INFINIPATH_EXTS_MEMBIST_ENDTEST     0x0000000000004000
-#define INFINIPATH_EXTS_MEMBIST_FOUND       0x0000000000008000
-
-/* kr_xgxsconfig bits */
-#define INFINIPATH_XGXS_RESET          0x5ULL
-
-#define _IPATH_GPIO_SDA_NUM 1
-#define _IPATH_GPIO_SCL_NUM 0
-
-#define IPATH_GPIO_SDA (1ULL << \
-       (_IPATH_GPIO_SDA_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT))
-#define IPATH_GPIO_SCL (1ULL << \
-       (_IPATH_GPIO_SCL_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT))
-
-#define INFINIPATH_RT_BUFSIZE_MASK 0xe0000000ULL
-#define INFINIPATH_RT_BUFSIZE_SHIFTVAL(tid) \
-       ((((tid) & INFINIPATH_RT_BUFSIZE_MASK) >> 29) + 11 - 1)
-#define INFINIPATH_RT_BUFSIZE(tid) (1 << INFINIPATH_RT_BUFSIZE_SHIFTVAL(tid))
-#define INFINIPATH_RT_IS_VALID(tid) \
-       (((tid) & INFINIPATH_RT_BUFSIZE_MASK) && \
-        ((((tid) & INFINIPATH_RT_BUFSIZE_MASK) != INFINIPATH_RT_BUFSIZE_MASK)))
-#define INFINIPATH_RT_ADDR_MASK 0x1FFFFFFFULL /* 29 bits valid */
-#define INFINIPATH_RT_ADDR_SHIFT 10
-
-#define INFINIPATH_R_INTRAVAIL_SHIFT 16
-#define INFINIPATH_R_TAILUPD_SHIFT 31
-
-/* 6120 specific hardware errors... */
-static const struct ipath_hwerror_msgs ipath_6120_hwerror_msgs[] = {
-       INFINIPATH_HWE_MSG(PCIEPOISONEDTLP, "PCIe Poisoned TLP"),
-       INFINIPATH_HWE_MSG(PCIECPLTIMEOUT, "PCIe completion timeout"),
-       /*
-        * In practice, it's unlikely wthat we'll see PCIe PLL, or bus
-        * parity or memory parity error failures, because most likely we
-        * won't be able to talk to the core of the chip.  Nonetheless, we
-        * might see them, if they are in parts of the PCIe core that aren't
-        * essential.
-        */
-       INFINIPATH_HWE_MSG(PCIE1PLLFAILED, "PCIePLL1"),
-       INFINIPATH_HWE_MSG(PCIE0PLLFAILED, "PCIePLL0"),
-       INFINIPATH_HWE_MSG(PCIEBUSPARITYXTLH, "PCIe XTLH core parity"),
-       INFINIPATH_HWE_MSG(PCIEBUSPARITYXADM, "PCIe ADM TX core parity"),
-       INFINIPATH_HWE_MSG(PCIEBUSPARITYRADM, "PCIe ADM RX core parity"),
-       INFINIPATH_HWE_MSG(RXDSYNCMEMPARITYERR, "Rx Dsync"),
-       INFINIPATH_HWE_MSG(SERDESPLLFAILED, "SerDes PLL"),
-};
-
-#define TXE_PIO_PARITY ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF | \
-                       INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC) \
-                       << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)
-#define RXE_EAGER_PARITY (INFINIPATH_HWE_RXEMEMPARITYERR_EAGERTID \
-                         << INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT)
-
-static void ipath_pe_put_tid_2(struct ipath_devdata *, u64 __iomem *,
-                              u32, unsigned long);
-
-/*
- * On platforms using this chip, and not having ordered WC stores, we
- * can get TXE parity errors due to speculative reads to the PIO buffers,
- * and this, due to a chip bug can result in (many) false parity error
- * reports.  So it's a debug print on those, and an info print on systems
- * where the speculative reads don't occur.
- */
-static void ipath_pe_txe_recover(struct ipath_devdata *dd)
-{
-       if (ipath_unordered_wc())
-               ipath_dbg("Recovering from TXE PIO parity error\n");
-       else {
-               ++ipath_stats.sps_txeparity;
-               dev_info(&dd->pcidev->dev,
-                       "Recovering from TXE PIO parity error\n");
-       }
-}
-
-
-/**
- * ipath_pe_handle_hwerrors - display hardware errors.
- * @dd: the infinipath device
- * @msg: the output buffer
- * @msgl: the size of the output buffer
- *
- * Use same msg buffer as regular errors to avoid excessive stack
- * use.  Most hardware errors are catastrophic, but for right now,
- * we'll print them and continue.  We reuse the same message buffer as
- * ipath_handle_errors() to avoid excessive stack usage.
- */
-static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg,
-                                    size_t msgl)
-{
-       ipath_err_t hwerrs;
-       u32 bits, ctrl;
-       int isfatal = 0;
-       char bitsmsg[64];
-       int log_idx;
-
-       hwerrs = ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwerrstatus);
-       if (!hwerrs) {
-               /*
-                * better than printing cofusing messages
-                * This seems to be related to clearing the crc error, or
-                * the pll error during init.
-                */
-               ipath_cdbg(VERBOSE, "Called but no hardware errors set\n");
-               return;
-       } else if (hwerrs == ~0ULL) {
-               ipath_dev_err(dd, "Read of hardware error status failed "
-                             "(all bits set); ignoring\n");
-               return;
-       }
-       ipath_stats.sps_hwerrs++;
-
-       /* Always clear the error status register, except MEMBISTFAIL,
-        * regardless of whether we continue or stop using the chip.
-        * We want that set so we know it failed, even across driver reload.
-        * We'll still ignore it in the hwerrmask.  We do this partly for
-        * diagnostics, but also for support */
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear,
-                        hwerrs&~INFINIPATH_HWE_MEMBISTFAILED);
-
-       hwerrs &= dd->ipath_hwerrmask;
-
-       /* We log some errors to EEPROM, check if we have any of those. */
-       for (log_idx = 0; log_idx < IPATH_EEP_LOG_CNT; ++log_idx)
-               if (hwerrs & dd->ipath_eep_st_masks[log_idx].hwerrs_to_log)
-                       ipath_inc_eeprom_err(dd, log_idx, 1);
-
-       /*
-        * make sure we get this much out, unless told to be quiet,
-        * or it's occurred within the last 5 seconds
-        */
-       if ((hwerrs & ~(dd->ipath_lasthwerror | TXE_PIO_PARITY |
-                       RXE_EAGER_PARITY)) ||
-           (ipath_debug & __IPATH_VERBDBG))
-               dev_info(&dd->pcidev->dev, "Hardware error: hwerr=0x%llx "
-                        "(cleared)\n", (unsigned long long) hwerrs);
-       dd->ipath_lasthwerror |= hwerrs;
-
-       if (hwerrs & ~dd->ipath_hwe_bitsextant)
-               ipath_dev_err(dd, "hwerror interrupt with unknown errors "
-                             "%llx set\n", (unsigned long long)
-                             (hwerrs & ~dd->ipath_hwe_bitsextant));
-
-       ctrl = ipath_read_kreg32(dd, dd->ipath_kregs->kr_control);
-       if ((ctrl & INFINIPATH_C_FREEZEMODE) && !ipath_diag_inuse) {
-               /*
-                * parity errors in send memory are recoverable,
-                * just cancel the send (if indicated in * sendbuffererror),
-                * count the occurrence, unfreeze (if no other handled
-                * hardware error bits are set), and continue. They can
-                * occur if a processor speculative read is done to the PIO
-                * buffer while we are sending a packet, for example.
-                */
-               if (hwerrs & TXE_PIO_PARITY) {
-                       ipath_pe_txe_recover(dd);
-                       hwerrs &= ~TXE_PIO_PARITY;
-               }
-               if (!hwerrs) {
-                       static u32 freeze_cnt;
-
-                       freeze_cnt++;
-                       ipath_dbg("Clearing freezemode on ignored or recovered "
-                                 "hardware error (%u)\n", freeze_cnt);
-                       ipath_clear_freeze(dd);
-               }
-       }
-
-       *msg = '\0';
-
-       if (hwerrs & INFINIPATH_HWE_MEMBISTFAILED) {
-               strlcat(msg, "[Memory BIST test failed, InfiniPath hardware unusable]",
-                       msgl);
-               /* ignore from now on, so disable until driver reloaded */
-               *dd->ipath_statusp |= IPATH_STATUS_HWERROR;
-               dd->ipath_hwerrmask &= ~INFINIPATH_HWE_MEMBISTFAILED;
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
-                                dd->ipath_hwerrmask);
-       }
-
-       ipath_format_hwerrors(hwerrs,
-                             ipath_6120_hwerror_msgs,
-                             sizeof(ipath_6120_hwerror_msgs)/
-                             sizeof(ipath_6120_hwerror_msgs[0]),
-                             msg, msgl);
-
-       if (hwerrs & (INFINIPATH_HWE_PCIEMEMPARITYERR_MASK
-                     << INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT)) {
-               bits = (u32) ((hwerrs >>
-                              INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT) &
-                             INFINIPATH_HWE_PCIEMEMPARITYERR_MASK);
-               snprintf(bitsmsg, sizeof bitsmsg,
-                        "[PCIe Mem Parity Errs %x] ", bits);
-               strlcat(msg, bitsmsg, msgl);
-       }
-
-#define _IPATH_PLL_FAIL (INFINIPATH_HWE_COREPLL_FBSLIP |       \
-                        INFINIPATH_HWE_COREPLL_RFSLIP )
-
-       if (hwerrs & _IPATH_PLL_FAIL) {
-               snprintf(bitsmsg, sizeof bitsmsg,
-                        "[PLL failed (%llx), InfiniPath hardware unusable]",
-                        (unsigned long long) hwerrs & _IPATH_PLL_FAIL);
-               strlcat(msg, bitsmsg, msgl);
-               /* ignore from now on, so disable until driver reloaded */
-               dd->ipath_hwerrmask &= ~(hwerrs & _IPATH_PLL_FAIL);
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
-                                dd->ipath_hwerrmask);
-       }
-
-       if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED) {
-               /*
-                * If it occurs, it is left masked since the external
-                * interface is unused
-                */
-               dd->ipath_hwerrmask &= ~INFINIPATH_HWE_SERDESPLLFAILED;
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
-                                dd->ipath_hwerrmask);
-       }
-
-       if (hwerrs) {
-               /*
-                * if any set that we aren't ignoring; only
-                * make the complaint once, in case it's stuck
-                * or recurring, and we get here multiple
-                * times.
-                */
-               ipath_dev_err(dd, "%s hardware error\n", msg);
-               if (dd->ipath_flags & IPATH_INITTED) {
-                       ipath_set_linkstate(dd, IPATH_IB_LINKDOWN);
-                       ipath_setup_pe_setextled(dd,
-                               INFINIPATH_IBCS_L_STATE_DOWN,
-                               INFINIPATH_IBCS_LT_STATE_DISABLED);
-                       ipath_dev_err(dd, "Fatal Hardware Error (freeze "
-                                         "mode), no longer usable, SN %.16s\n",
-                                         dd->ipath_serial);
-                       isfatal = 1;
-               }
-               *dd->ipath_statusp &= ~IPATH_STATUS_IB_READY;
-               /* mark as having had error */
-               *dd->ipath_statusp |= IPATH_STATUS_HWERROR;
-               /*
-                * mark as not usable, at a minimum until driver
-                * is reloaded, probably until reboot, since no
-                * other reset is possible.
-                */
-               dd->ipath_flags &= ~IPATH_INITTED;
-       } else
-               *msg = 0; /* recovered from all of them */
-
-       if (isfatal && !ipath_diag_inuse && dd->ipath_freezemsg && msg) {
-               /*
-                * for /sys status file ; if no trailing brace is copied,
-                * we'll know it was truncated.
-                */
-               snprintf(dd->ipath_freezemsg, dd->ipath_freezelen,
-                        "{%s}", msg);
-       }
-}
-
-/**
- * ipath_pe_boardname - fill in the board name
- * @dd: the infinipath device
- * @name: the output buffer
- * @namelen: the size of the output buffer
- *
- * info is based on the board revision register
- */
-static int ipath_pe_boardname(struct ipath_devdata *dd, char *name,
-                             size_t namelen)
-{
-       char *n = NULL;
-       u8 boardrev = dd->ipath_boardrev;
-       int ret;
-
-       switch (boardrev) {
-       case 0:
-               n = "InfiniPath_Emulation";
-               break;
-       case 1:
-               n = "InfiniPath_QLE7140-Bringup";
-               break;
-       case 2:
-               n = "InfiniPath_QLE7140";
-               break;
-       case 3:
-               n = "InfiniPath_QMI7140";
-               break;
-       case 4:
-               n = "InfiniPath_QEM7140";
-               break;
-       case 5:
-               n = "InfiniPath_QMH7140";
-               break;
-       case 6:
-               n = "InfiniPath_QLE7142";
-               break;
-       default:
-               ipath_dev_err(dd,
-                             "Don't yet know about board with ID %u\n",
-                             boardrev);
-               snprintf(name, namelen, "Unknown_InfiniPath_PCIe_%u",
-                        boardrev);
-               break;
-       }
-       if (n)
-               snprintf(name, namelen, "%s", n);
-
-       if (dd->ipath_majrev != 4 || !dd->ipath_minrev || dd->ipath_minrev>2) {
-               ipath_dev_err(dd, "Unsupported InfiniPath hardware revision %u.%u!\n",
-                             dd->ipath_majrev, dd->ipath_minrev);
-               ret = 1;
-       } else {
-               ret = 0;
-               if (dd->ipath_minrev >= 2)
-                       dd->ipath_f_put_tid = ipath_pe_put_tid_2;
-       }
-
-       /*
-        * set here, not in ipath_init_*_funcs because we have to do
-        * it after we can read chip registers.
-        */
-       dd->ipath_ureg_align =
-               ipath_read_kreg32(dd, dd->ipath_kregs->kr_pagealign);
-
-       return ret;
-}
-
-/**
- * ipath_pe_init_hwerrors - enable hardware errors
- * @dd: the infinipath device
- *
- * now that we have finished initializing everything that might reasonably
- * cause a hardware error, and cleared those errors bits as they occur,
- * we can enable hardware errors in the mask (potentially enabling
- * freeze mode), and enable hardware errors as errors (along with
- * everything else) in errormask
- */
-static void ipath_pe_init_hwerrors(struct ipath_devdata *dd)
-{
-       ipath_err_t val;
-       u64 extsval;
-
-       extsval = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extstatus);
-
-       if (!(extsval & INFINIPATH_EXTS_MEMBIST_ENDTEST))
-               ipath_dev_err(dd, "MemBIST did not complete!\n");
-       if (extsval & INFINIPATH_EXTS_MEMBIST_FOUND)
-               ipath_dbg("MemBIST corrected\n");
-
-       val = ~0ULL;    /* barring bugs, all hwerrors become interrupts, */
-
-       if (!dd->ipath_boardrev)        // no PLL for Emulator
-               val &= ~INFINIPATH_HWE_SERDESPLLFAILED;
-
-       if (dd->ipath_minrev < 2) {
-               /* workaround bug 9460 in internal interface bus parity
-                * checking. Fixed (HW bug 9490) in Rev2.
-                */
-               val &= ~INFINIPATH_HWE_PCIEBUSPARITYRADM;
-       }
-       dd->ipath_hwerrmask = val;
-}
-
-/**
- * ipath_pe_bringup_serdes - bring up the serdes
- * @dd: the infinipath device
- */
-static int ipath_pe_bringup_serdes(struct ipath_devdata *dd)
-{
-       u64 val, config1, prev_val;
-       int ret = 0;
-
-       ipath_dbg("Trying to bringup serdes\n");
-
-       if (ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwerrstatus) &
-           INFINIPATH_HWE_SERDESPLLFAILED) {
-               ipath_dbg("At start, serdes PLL failed bit set "
-                         "in hwerrstatus, clearing and continuing\n");
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear,
-                                INFINIPATH_HWE_SERDESPLLFAILED);
-       }
-
-       dd->ibdeltainprog = 1;
-       dd->ibsymsnap =
-            ipath_read_creg32(dd, dd->ipath_cregs->cr_ibsymbolerrcnt);
-       dd->iblnkerrsnap =
-            ipath_read_creg32(dd, dd->ipath_cregs->cr_iblinkerrrecovcnt);
-
-       val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0);
-       config1 = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig1);
-
-       ipath_cdbg(VERBOSE, "SerDes status config0=%llx config1=%llx, "
-                  "xgxsconfig %llx\n", (unsigned long long) val,
-                  (unsigned long long) config1, (unsigned long long)
-                  ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig));
-
-       /*
-        * Force reset on, also set rxdetect enable.  Must do before reading
-        * serdesstatus at least for simulation, or some of the bits in
-        * serdes status will come back as undefined and cause simulation
-        * failures
-        */
-       val |= INFINIPATH_SERDC0_RESET_PLL | INFINIPATH_SERDC0_RXDETECT_EN
-               | INFINIPATH_SERDC0_L1PWR_DN;
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val);
-       /* be sure chip saw it */
-       ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-       udelay(5);              /* need pll reset set at least for a bit */
-       /*
-        * after PLL is reset, set the per-lane Resets and TxIdle and
-        * clear the PLL reset and rxdetect (to get falling edge).
-        * Leave L1PWR bits set (permanently)
-        */
-       val &= ~(INFINIPATH_SERDC0_RXDETECT_EN | INFINIPATH_SERDC0_RESET_PLL
-                | INFINIPATH_SERDC0_L1PWR_DN);
-       val |= INFINIPATH_SERDC0_RESET_MASK | INFINIPATH_SERDC0_TXIDLE;
-       ipath_cdbg(VERBOSE, "Clearing pll reset and setting lane resets "
-                  "and txidle (%llx)\n", (unsigned long long) val);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val);
-       /* be sure chip saw it */
-       ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-       /* need PLL reset clear for at least 11 usec before lane
-        * resets cleared; give it a few more to be sure */
-       udelay(15);
-       val &= ~(INFINIPATH_SERDC0_RESET_MASK | INFINIPATH_SERDC0_TXIDLE);
-
-       ipath_cdbg(VERBOSE, "Clearing lane resets and txidle "
-                  "(writing %llx)\n", (unsigned long long) val);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val);
-       /* be sure chip saw it */
-       val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-
-       val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
-       prev_val = val;
-       if (val & INFINIPATH_XGXS_RESET)
-               val &= ~INFINIPATH_XGXS_RESET;
-       if (((val >> INFINIPATH_XGXS_RX_POL_SHIFT) &
-            INFINIPATH_XGXS_RX_POL_MASK) != dd->ipath_rx_pol_inv ) {
-               /* need to compensate for Tx inversion in partner */
-               val &= ~(INFINIPATH_XGXS_RX_POL_MASK <<
-                        INFINIPATH_XGXS_RX_POL_SHIFT);
-               val |= dd->ipath_rx_pol_inv <<
-                       INFINIPATH_XGXS_RX_POL_SHIFT;
-       }
-       if (val != prev_val)
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val);
-
-       val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0);
-
-       /* clear current and de-emphasis bits */
-       config1 &= ~0x0ffffffff00ULL;
-       /* set current to 20ma */
-       config1 |= 0x00000000000ULL;
-       /* set de-emphasis to -5.68dB */
-       config1 |= 0x0cccc000000ULL;
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig1, config1);
-
-       ipath_cdbg(VERBOSE, "done: SerDes status config0=%llx "
-                  "config1=%llx, sstatus=%llx xgxs=%llx\n",
-                  (unsigned long long) val, (unsigned long long) config1,
-                  (unsigned long long)
-                  ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesstatus),
-                  (unsigned long long)
-                  ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig));
-
-       return ret;
-}
-
-/**
- * ipath_pe_quiet_serdes - set serdes to txidle
- * @dd: the infinipath device
- * Called when driver is being unloaded
- */
-static void ipath_pe_quiet_serdes(struct ipath_devdata *dd)
-{
-       u64 val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0);
-
-       if (dd->ibsymdelta || dd->iblnkerrdelta ||
-           dd->ibdeltainprog) {
-               u64 diagc;
-               /* enable counter writes */
-               diagc = ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwdiagctrl);
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_hwdiagctrl,
-                                diagc | INFINIPATH_DC_COUNTERWREN);
-
-               if (dd->ibsymdelta || dd->ibdeltainprog) {
-                       val = ipath_read_creg32(dd,
-                                       dd->ipath_cregs->cr_ibsymbolerrcnt);
-                       if (dd->ibdeltainprog)
-                               val -= val - dd->ibsymsnap;
-                       val -= dd->ibsymdelta;
-                       ipath_write_creg(dd,
-                                 dd->ipath_cregs->cr_ibsymbolerrcnt, val);
-               }
-               if (dd->iblnkerrdelta || dd->ibdeltainprog) {
-                       val = ipath_read_creg32(dd,
-                                       dd->ipath_cregs->cr_iblinkerrrecovcnt);
-                       if (dd->ibdeltainprog)
-                               val -= val - dd->iblnkerrsnap;
-                       val -= dd->iblnkerrdelta;
-                       ipath_write_creg(dd,
-                                  dd->ipath_cregs->cr_iblinkerrrecovcnt, val);
-            }
-
-            /* and disable counter writes */
-            ipath_write_kreg(dd, dd->ipath_kregs->kr_hwdiagctrl, diagc);
-       }
-       val |= INFINIPATH_SERDC0_TXIDLE;
-       ipath_dbg("Setting TxIdleEn on serdes (config0 = %llx)\n",
-                 (unsigned long long) val);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val);
-}
-
-static int ipath_pe_intconfig(struct ipath_devdata *dd)
-{
-       u32 chiprev;
-
-       /*
-        * If the chip supports added error indication via GPIO pins,
-        * enable interrupts on those bits so the interrupt routine
-        * can count the events. Also set flag so interrupt routine
-        * can know they are expected.
-        */
-       chiprev = dd->ipath_revision >> INFINIPATH_R_CHIPREVMINOR_SHIFT;
-       if ((chiprev & INFINIPATH_R_CHIPREVMINOR_MASK) > 1) {
-               /* Rev2+ reports extra errors via internal GPIO pins */
-               dd->ipath_flags |= IPATH_GPIO_ERRINTRS;
-               dd->ipath_gpio_mask |= IPATH_GPIO_ERRINTR_MASK;
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_mask,
-                                dd->ipath_gpio_mask);
-       }
-       return 0;
-}
-
-/**
- * ipath_setup_pe_setextled - set the state of the two external LEDs
- * @dd: the infinipath device
- * @lst: the L state
- * @ltst: the LT state
-
- * These LEDs indicate the physical and logical state of IB link.
- * For this chip (at least with recommended board pinouts), LED1
- * is Yellow (logical state) and LED2 is Green (physical state),
- *
- * Note:  We try to match the Mellanox HCA LED behavior as best
- * we can.  Green indicates physical link state is OK (something is
- * plugged in, and we can train).
- * Amber indicates the link is logically up (ACTIVE).
- * Mellanox further blinks the amber LED to indicate data packet
- * activity, but we have no hardware support for that, so it would
- * require waking up every 10-20 msecs and checking the counters
- * on the chip, and then turning the LED off if appropriate.  That's
- * visible overhead, so not something we will do.
- *
- */
-static void ipath_setup_pe_setextled(struct ipath_devdata *dd, u64 lst,
-                                    u64 ltst)
-{
-       u64 extctl;
-       unsigned long flags = 0;
-
-       /* the diags use the LED to indicate diag info, so we leave
-        * the external LED alone when the diags are running */
-       if (ipath_diag_inuse)
-               return;
-
-       /* Allow override of LED display for, e.g. Locating system in rack */
-       if (dd->ipath_led_override) {
-               ltst = (dd->ipath_led_override & IPATH_LED_PHYS)
-                       ? INFINIPATH_IBCS_LT_STATE_LINKUP
-                       : INFINIPATH_IBCS_LT_STATE_DISABLED;
-               lst = (dd->ipath_led_override & IPATH_LED_LOG)
-                       ? INFINIPATH_IBCS_L_STATE_ACTIVE
-                       : INFINIPATH_IBCS_L_STATE_DOWN;
-       }
-
-       spin_lock_irqsave(&dd->ipath_gpio_lock, flags);
-       extctl = dd->ipath_extctrl & ~(INFINIPATH_EXTC_LED1PRIPORT_ON |
-                                      INFINIPATH_EXTC_LED2PRIPORT_ON);
-
-       if (ltst == INFINIPATH_IBCS_LT_STATE_LINKUP)
-               extctl |= INFINIPATH_EXTC_LED2PRIPORT_ON;
-       if (lst == INFINIPATH_IBCS_L_STATE_ACTIVE)
-               extctl |= INFINIPATH_EXTC_LED1PRIPORT_ON;
-       dd->ipath_extctrl = extctl;
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, extctl);
-       spin_unlock_irqrestore(&dd->ipath_gpio_lock, flags);
-}
-
-/**
- * ipath_setup_pe_cleanup - clean up any per-chip chip-specific stuff
- * @dd: the infinipath device
- *
- * This is called during driver unload.
- * We do the pci_disable_msi here, not in generic code, because it
- * isn't used for the HT chips. If we do end up needing pci_enable_msi
- * at some point in the future for HT, we'll move the call back
- * into the main init_one code.
- */
-static void ipath_setup_pe_cleanup(struct ipath_devdata *dd)
-{
-       dd->ipath_msi_lo = 0;   /* just in case unload fails */
-       pci_disable_msi(dd->pcidev);
-}
-
-static void ipath_6120_pcie_params(struct ipath_devdata *dd)
-{
-       u16 linkstat, speed;
-       int pos;
-
-       pos = pci_find_capability(dd->pcidev, PCI_CAP_ID_EXP);
-       if (!pos) {
-               ipath_dev_err(dd, "Can't find PCI Express capability!\n");
-               goto bail;
-       }
-
-       pci_read_config_word(dd->pcidev, pos + PCI_EXP_LNKSTA,
-                            &linkstat);
-       /*
-        * speed is bits 0-4, linkwidth is bits 4-8
-        * no defines for them in headers
-        */
-       speed = linkstat & 0xf;
-       linkstat >>= 4;
-       linkstat &= 0x1f;
-       dd->ipath_lbus_width = linkstat;
-
-       switch (speed) {
-       case 1:
-               dd->ipath_lbus_speed = 2500; /* Gen1, 2.5GHz */
-               break;
-       case 2:
-               dd->ipath_lbus_speed = 5000; /* Gen1, 5GHz */
-               break;
-       default: /* not defined, assume gen1 */
-               dd->ipath_lbus_speed = 2500;
-               break;
-       }
-
-       if (linkstat < 8)
-               ipath_dev_err(dd,
-                       "PCIe width %u (x8 HCA), performance reduced\n",
-                       linkstat);
-       else
-               ipath_cdbg(VERBOSE, "PCIe speed %u width %u (x8 HCA)\n",
-                       dd->ipath_lbus_speed, linkstat);
-
-       if (speed != 1)
-               ipath_dev_err(dd,
-                       "PCIe linkspeed %u is incorrect; "
-                       "should be 1 (2500)!\n", speed);
-bail:
-       /* fill in string, even on errors */
-       snprintf(dd->ipath_lbus_info, sizeof(dd->ipath_lbus_info),
-               "PCIe,%uMHz,x%u\n",
-               dd->ipath_lbus_speed,
-               dd->ipath_lbus_width);
-
-       return;
-}
-
-/**
- * ipath_setup_pe_config - setup PCIe config related stuff
- * @dd: the infinipath device
- * @pdev: the PCI device
- *
- * The pci_enable_msi() call will fail on systems with MSI quirks
- * such as those with AMD8131, even if the device of interest is not
- * attached to that device, (in the 2.6.13 - 2.6.15 kernels, at least, fixed
- * late in 2.6.16).
- * All that can be done is to edit the kernel source to remove the quirk
- * check until that is fixed.
- * We do not need to call enable_msi() for our HyperTransport chip,
- * even though it uses MSI, and we want to avoid the quirk warning, so
- * So we call enable_msi only for PCIe.  If we do end up needing
- * pci_enable_msi at some point in the future for HT, we'll move the
- * call back into the main init_one code.
- * We save the msi lo and hi values, so we can restore them after
- * chip reset (the kernel PCI infrastructure doesn't yet handle that
- * correctly).
- */
-static int ipath_setup_pe_config(struct ipath_devdata *dd,
-                                struct pci_dev *pdev)
-{
-       int pos, ret;
-
-       dd->ipath_msi_lo = 0;   /* used as a flag during reset processing */
-       ret = pci_enable_msi(dd->pcidev);
-       if (ret)
-               ipath_dev_err(dd, "pci_enable_msi failed: %d, "
-                             "interrupts may not work\n", ret);
-       /* continue even if it fails, we may still be OK... */
-       dd->ipath_irq = pdev->irq;
-
-       if ((pos = pci_find_capability(dd->pcidev, PCI_CAP_ID_MSI))) {
-               u16 control;
-               pci_read_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_LO,
-                                     &dd->ipath_msi_lo);
-               pci_read_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_HI,
-                                     &dd->ipath_msi_hi);
-               pci_read_config_word(dd->pcidev, pos + PCI_MSI_FLAGS,
-                                    &control);
-               /* now save the data (vector) info */
-               pci_read_config_word(dd->pcidev,
-                                    pos + ((control & PCI_MSI_FLAGS_64BIT)
-                                           ? 12 : 8),
-                                    &dd->ipath_msi_data);
-               ipath_cdbg(VERBOSE, "Read msi data 0x%x from config offset "
-                          "0x%x, control=0x%x\n", dd->ipath_msi_data,
-                          pos + ((control & PCI_MSI_FLAGS_64BIT) ? 12 : 8),
-                          control);
-               /* we save the cachelinesize also, although it doesn't
-                * really matter */
-               pci_read_config_byte(dd->pcidev, PCI_CACHE_LINE_SIZE,
-                                    &dd->ipath_pci_cacheline);
-       } else
-               ipath_dev_err(dd, "Can't find MSI capability, "
-                             "can't save MSI settings for reset\n");
-
-       ipath_6120_pcie_params(dd);
-
-       dd->ipath_link_width_supported = IB_WIDTH_1X | IB_WIDTH_4X;
-       dd->ipath_link_speed_supported = IPATH_IB_SDR;
-       dd->ipath_link_width_enabled = IB_WIDTH_4X;
-       dd->ipath_link_speed_enabled = dd->ipath_link_speed_supported;
-       /* these can't change for this chip, so set once */
-       dd->ipath_link_width_active = dd->ipath_link_width_enabled;
-       dd->ipath_link_speed_active = dd->ipath_link_speed_enabled;
-       return 0;
-}
-
-static void ipath_init_pe_variables(struct ipath_devdata *dd)
-{
-       /*
-        * setup the register offsets, since they are different for each
-        * chip
-        */
-       dd->ipath_kregs = &ipath_pe_kregs;
-       dd->ipath_cregs = &ipath_pe_cregs;
-
-       /*
-        * bits for selecting i2c direction and values,
-        * used for I2C serial flash
-        */
-       dd->ipath_gpio_sda_num = _IPATH_GPIO_SDA_NUM;
-       dd->ipath_gpio_scl_num = _IPATH_GPIO_SCL_NUM;
-       dd->ipath_gpio_sda = IPATH_GPIO_SDA;
-       dd->ipath_gpio_scl = IPATH_GPIO_SCL;
-
-       /*
-        * Fill in data for field-values that change in newer chips.
-        * We dynamically specify only the mask for LINKTRAININGSTATE
-        * and only the shift for LINKSTATE, as they are the only ones
-        * that change.  Also precalculate the 3 link states of interest
-        * and the combined mask.
-        */
-       dd->ibcs_ls_shift = IBA6120_IBCS_LINKSTATE_SHIFT;
-       dd->ibcs_lts_mask = IBA6120_IBCS_LINKTRAININGSTATE_MASK;
-       dd->ibcs_mask = (INFINIPATH_IBCS_LINKSTATE_MASK <<
-               dd->ibcs_ls_shift) | dd->ibcs_lts_mask;
-       dd->ib_init = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
-               INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
-               (INFINIPATH_IBCS_L_STATE_INIT << dd->ibcs_ls_shift);
-       dd->ib_arm = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
-               INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
-               (INFINIPATH_IBCS_L_STATE_ARM << dd->ibcs_ls_shift);
-       dd->ib_active = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
-               INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
-               (INFINIPATH_IBCS_L_STATE_ACTIVE << dd->ibcs_ls_shift);
-
-       /*
-        * Fill in data for ibcc field-values that change in newer chips.
-        * We dynamically specify only the mask for LINKINITCMD
-        * and only the shift for LINKCMD and MAXPKTLEN, as they are
-        * the only ones that change.
-        */
-       dd->ibcc_lic_mask = INFINIPATH_IBCC_LINKINITCMD_MASK;
-       dd->ibcc_lc_shift = INFINIPATH_IBCC_LINKCMD_SHIFT;
-       dd->ibcc_mpl_shift = INFINIPATH_IBCC_MAXPKTLEN_SHIFT;
-
-       /* Fill in shifts for RcvCtrl. */
-       dd->ipath_r_portenable_shift = INFINIPATH_R_PORTENABLE_SHIFT;
-       dd->ipath_r_intravail_shift = INFINIPATH_R_INTRAVAIL_SHIFT;
-       dd->ipath_r_tailupd_shift = INFINIPATH_R_TAILUPD_SHIFT;
-       dd->ipath_r_portcfg_shift = 0; /* Not on IBA6120 */
-
-       /* variables for sanity checking interrupt and errors */
-       dd->ipath_hwe_bitsextant =
-               (INFINIPATH_HWE_RXEMEMPARITYERR_MASK <<
-                INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) |
-               (INFINIPATH_HWE_TXEMEMPARITYERR_MASK <<
-                INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) |
-               (INFINIPATH_HWE_PCIEMEMPARITYERR_MASK <<
-                INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT) |
-               INFINIPATH_HWE_PCIE1PLLFAILED |
-               INFINIPATH_HWE_PCIE0PLLFAILED |
-               INFINIPATH_HWE_PCIEPOISONEDTLP |
-               INFINIPATH_HWE_PCIECPLTIMEOUT |
-               INFINIPATH_HWE_PCIEBUSPARITYXTLH |
-               INFINIPATH_HWE_PCIEBUSPARITYXADM |
-               INFINIPATH_HWE_PCIEBUSPARITYRADM |
-               INFINIPATH_HWE_MEMBISTFAILED |
-               INFINIPATH_HWE_COREPLL_FBSLIP |
-               INFINIPATH_HWE_COREPLL_RFSLIP |
-               INFINIPATH_HWE_SERDESPLLFAILED |
-               INFINIPATH_HWE_IBCBUSTOSPCPARITYERR |
-               INFINIPATH_HWE_IBCBUSFRSPCPARITYERR;
-       dd->ipath_i_bitsextant =
-               (INFINIPATH_I_RCVURG_MASK << INFINIPATH_I_RCVURG_SHIFT) |
-               (INFINIPATH_I_RCVAVAIL_MASK <<
-                INFINIPATH_I_RCVAVAIL_SHIFT) |
-               INFINIPATH_I_ERROR | INFINIPATH_I_SPIOSENT |
-               INFINIPATH_I_SPIOBUFAVAIL | INFINIPATH_I_GPIO;
-       dd->ipath_e_bitsextant =
-               INFINIPATH_E_RFORMATERR | INFINIPATH_E_RVCRC |
-               INFINIPATH_E_RICRC | INFINIPATH_E_RMINPKTLEN |
-               INFINIPATH_E_RMAXPKTLEN | INFINIPATH_E_RLONGPKTLEN |
-               INFINIPATH_E_RSHORTPKTLEN | INFINIPATH_E_RUNEXPCHAR |
-               INFINIPATH_E_RUNSUPVL | INFINIPATH_E_REBP |
-               INFINIPATH_E_RIBFLOW | INFINIPATH_E_RBADVERSION |
-               INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL |
-               INFINIPATH_E_RBADTID | INFINIPATH_E_RHDRLEN |
-               INFINIPATH_E_RHDR | INFINIPATH_E_RIBLOSTLINK |
-               INFINIPATH_E_SMINPKTLEN | INFINIPATH_E_SMAXPKTLEN |
-               INFINIPATH_E_SUNDERRUN | INFINIPATH_E_SPKTLEN |
-               INFINIPATH_E_SDROPPEDSMPPKT | INFINIPATH_E_SDROPPEDDATAPKT |
-               INFINIPATH_E_SPIOARMLAUNCH | INFINIPATH_E_SUNEXPERRPKTNUM |
-               INFINIPATH_E_SUNSUPVL | INFINIPATH_E_IBSTATUSCHANGED |
-               INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET |
-               INFINIPATH_E_HARDWARE;
-
-       dd->ipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;
-       dd->ipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;
-       dd->ipath_i_rcvavail_shift = INFINIPATH_I_RCVAVAIL_SHIFT;
-       dd->ipath_i_rcvurg_shift = INFINIPATH_I_RCVURG_SHIFT;
-
-       /*
-        * EEPROM error log 0 is TXE Parity errors. 1 is RXE Parity.
-        * 2 is Some Misc, 3 is reserved for future.
-        */
-       dd->ipath_eep_st_masks[0].hwerrs_to_log =
-               INFINIPATH_HWE_TXEMEMPARITYERR_MASK <<
-               INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT;
-
-       /* Ignore errors in PIO/PBC on systems with unordered write-combining */
-       if (ipath_unordered_wc())
-               dd->ipath_eep_st_masks[0].hwerrs_to_log &= ~TXE_PIO_PARITY;
-
-       dd->ipath_eep_st_masks[1].hwerrs_to_log =
-               INFINIPATH_HWE_RXEMEMPARITYERR_MASK <<
-               INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT;
-
-       dd->ipath_eep_st_masks[2].errs_to_log = INFINIPATH_E_RESET;
-       dd->delay_mult = 2; /* SDR, 4X, can't change */
-}
-
-/* setup the MSI stuff again after a reset.  I'd like to just call
- * pci_enable_msi() and request_irq() again, but when I do that,
- * the MSI enable bit doesn't get set in the command word, and
- * we switch to to a different interrupt vector, which is confusing,
- * so I instead just do it all inline.  Perhaps somehow can tie this
- * into the PCIe hotplug support at some point
- * Note, because I'm doing it all here, I don't call pci_disable_msi()
- * or free_irq() at the start of ipath_setup_pe_reset().
- */
-static int ipath_reinit_msi(struct ipath_devdata *dd)
-{
-       int pos;
-       u16 control;
-       int ret;
-
-       if (!dd->ipath_msi_lo) {
-               dev_info(&dd->pcidev->dev, "Can't restore MSI config, "
-                        "initial setup failed?\n");
-               ret = 0;
-               goto bail;
-       }
-
-       if (!(pos = pci_find_capability(dd->pcidev, PCI_CAP_ID_MSI))) {
-               ipath_dev_err(dd, "Can't find MSI capability, "
-                             "can't restore MSI settings\n");
-               ret = 0;
-               goto bail;
-       }
-       ipath_cdbg(VERBOSE, "Writing msi_lo 0x%x to config offset 0x%x\n",
-                  dd->ipath_msi_lo, pos + PCI_MSI_ADDRESS_LO);
-       pci_write_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_LO,
-                              dd->ipath_msi_lo);
-       ipath_cdbg(VERBOSE, "Writing msi_lo 0x%x to config offset 0x%x\n",
-                  dd->ipath_msi_hi, pos + PCI_MSI_ADDRESS_HI);
-       pci_write_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_HI,
-                              dd->ipath_msi_hi);
-       pci_read_config_word(dd->pcidev, pos + PCI_MSI_FLAGS, &control);
-       if (!(control & PCI_MSI_FLAGS_ENABLE)) {
-               ipath_cdbg(VERBOSE, "MSI control at off %x was %x, "
-                          "setting MSI enable (%x)\n", pos + PCI_MSI_FLAGS,
-                          control, control | PCI_MSI_FLAGS_ENABLE);
-               control |= PCI_MSI_FLAGS_ENABLE;
-               pci_write_config_word(dd->pcidev, pos + PCI_MSI_FLAGS,
-                                     control);
-       }
-       /* now rewrite the data (vector) info */
-       pci_write_config_word(dd->pcidev, pos +
-                             ((control & PCI_MSI_FLAGS_64BIT) ? 12 : 8),
-                             dd->ipath_msi_data);
-       /* we restore the cachelinesize also, although it doesn't really
-        * matter */
-       pci_write_config_byte(dd->pcidev, PCI_CACHE_LINE_SIZE,
-                             dd->ipath_pci_cacheline);
-       /* and now set the pci master bit again */
-       pci_set_master(dd->pcidev);
-       ret = 1;
-
-bail:
-       return ret;
-}
-
-/* This routine sleeps, so it can only be called from user context, not
- * from interrupt context.  If we need interrupt context, we can split
- * it into two routines.
-*/
-static int ipath_setup_pe_reset(struct ipath_devdata *dd)
-{
-       u64 val;
-       int i;
-       int ret;
-       u16 cmdval;
-
-       pci_read_config_word(dd->pcidev, PCI_COMMAND, &cmdval);
-
-       /* Use ERROR so it shows up in logs, etc. */
-       ipath_dev_err(dd, "Resetting InfiniPath unit %u\n", dd->ipath_unit);
-       /* keep chip from being accessed in a few places */
-       dd->ipath_flags &= ~(IPATH_INITTED|IPATH_PRESENT);
-       val = dd->ipath_control | INFINIPATH_C_RESET;
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_control, val);
-       mb();
-
-       for (i = 1; i <= 5; i++) {
-               int r;
-               /* allow MBIST, etc. to complete; longer on each retry.
-                * We sometimes get machine checks from bus timeout if no
-                * response, so for now, make it *really* long.
-                */
-               msleep(1000 + (1 + i) * 2000);
-               if ((r =
-                    pci_write_config_dword(dd->pcidev, PCI_BASE_ADDRESS_0,
-                                           dd->ipath_pcibar0)))
-                       ipath_dev_err(dd, "rewrite of BAR0 failed: %d\n",
-                                     r);
-               if ((r =
-                    pci_write_config_dword(dd->pcidev, PCI_BASE_ADDRESS_1,
-                                           dd->ipath_pcibar1)))
-                       ipath_dev_err(dd, "rewrite of BAR1 failed: %d\n",
-                                     r);
-               /* now re-enable memory access */
-               pci_write_config_word(dd->pcidev, PCI_COMMAND, cmdval);
-               if ((r = pci_enable_device(dd->pcidev)))
-                       ipath_dev_err(dd, "pci_enable_device failed after "
-                                     "reset: %d\n", r);
-               /*
-                * whether it fully enabled or not, mark as present,
-                * again (but not INITTED)
-                */
-               dd->ipath_flags |= IPATH_PRESENT;
-               val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_revision);
-               if (val == dd->ipath_revision) {
-                       ipath_cdbg(VERBOSE, "Got matching revision "
-                                  "register %llx on try %d\n",
-                                  (unsigned long long) val, i);
-                       ret = ipath_reinit_msi(dd);
-                       goto bail;
-               }
-               /* Probably getting -1 back */
-               ipath_dbg("Didn't get expected revision register, "
-                         "got %llx, try %d\n", (unsigned long long) val,
-                         i + 1);
-       }
-       ret = 0; /* failed */
-
-bail:
-       if (ret)
-               ipath_6120_pcie_params(dd);
-       return ret;
-}
-
-/**
- * ipath_pe_put_tid - write a TID in chip
- * @dd: the infinipath device
- * @tidptr: pointer to the expected TID (in chip) to update
- * @tidtype: RCVHQ_RCV_TYPE_EAGER (1) for eager, RCVHQ_RCV_TYPE_EXPECTED (0) for expected
- * @pa: physical address of in memory buffer; ipath_tidinvalid if freeing
- *
- * This exists as a separate routine to allow for special locking etc.
- * It's used for both the full cleanup on exit, as well as the normal
- * setup and teardown.
- */
-static void ipath_pe_put_tid(struct ipath_devdata *dd, u64 __iomem *tidptr,
-                            u32 type, unsigned long pa)
-{
-       u32 __iomem *tidp32 = (u32 __iomem *)tidptr;
-       unsigned long flags = 0; /* keep gcc quiet */
-       int tidx;
-       spinlock_t *tidlockp;
-
-       if (!dd->ipath_kregbase)
-               return;
-
-       if (pa != dd->ipath_tidinvalid) {
-               if (pa & ((1U << 11) - 1)) {
-                       dev_info(&dd->pcidev->dev, "BUG: physaddr %lx "
-                                "not 2KB aligned!\n", pa);
-                       return;
-               }
-               pa >>= 11;
-               /* paranoia check */
-               if (pa & ~INFINIPATH_RT_ADDR_MASK)
-                       ipath_dev_err(dd,
-                                     "BUG: Physical page address 0x%lx "
-                                     "has bits set in 31-29\n", pa);
-
-               if (type == RCVHQ_RCV_TYPE_EAGER)
-                       pa |= dd->ipath_tidtemplate;
-               else /* for now, always full 4KB page */
-                       pa |= 2 << 29;
-       }
-
-       /*
-        * Workaround chip bug 9437 by writing the scratch register
-        * before and after the TID, and with an io write barrier.
-        * We use a spinlock around the writes, so they can't intermix
-        * with other TID (eager or expected) writes (the chip bug
-        * is triggered by back to back TID writes). Unfortunately, this
-        * call can be done from interrupt level for the port 0 eager TIDs,
-        * so we have to use irqsave locks.
-        */
-       /*
-        * Assumes tidptr always > ipath_egrtidbase
-        * if type == RCVHQ_RCV_TYPE_EAGER.
-        */
-       tidx = tidptr - dd->ipath_egrtidbase;
-
-       tidlockp = (type == RCVHQ_RCV_TYPE_EAGER && tidx < dd->ipath_rcvegrcnt)
-               ? &dd->ipath_kernel_tid_lock : &dd->ipath_user_tid_lock;
-       spin_lock_irqsave(tidlockp, flags);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_scratch, 0xfeeddeaf);
-       writel(pa, tidp32);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_scratch, 0xdeadbeef);
-       mmiowb();
-       spin_unlock_irqrestore(tidlockp, flags);
-}
-
-/**
- * ipath_pe_put_tid_2 - write a TID in chip, Revision 2 or higher
- * @dd: the infinipath device
- * @tidptr: pointer to the expected TID (in chip) to update
- * @tidtype: RCVHQ_RCV_TYPE_EAGER (1) for eager, RCVHQ_RCV_TYPE_EXPECTED (0) for expected
- * @pa: physical address of in memory buffer; ipath_tidinvalid if freeing
- *
- * This exists as a separate routine to allow for selection of the
- * appropriate "flavor". The static calls in cleanup just use the
- * revision-agnostic form, as they are not performance critical.
- */
-static void ipath_pe_put_tid_2(struct ipath_devdata *dd, u64 __iomem *tidptr,
-                            u32 type, unsigned long pa)
-{
-       u32 __iomem *tidp32 = (u32 __iomem *)tidptr;
-       u32 tidx;
-
-       if (!dd->ipath_kregbase)
-               return;
-
-       if (pa != dd->ipath_tidinvalid) {
-               if (pa & ((1U << 11) - 1)) {
-                       dev_info(&dd->pcidev->dev, "BUG: physaddr %lx "
-                                "not 2KB aligned!\n", pa);
-                       return;
-               }
-               pa >>= 11;
-               /* paranoia check */
-               if (pa & ~INFINIPATH_RT_ADDR_MASK)
-                       ipath_dev_err(dd,
-                                     "BUG: Physical page address 0x%lx "
-                                     "has bits set in 31-29\n", pa);
-
-               if (type == RCVHQ_RCV_TYPE_EAGER)
-                       pa |= dd->ipath_tidtemplate;
-               else /* for now, always full 4KB page */
-                       pa |= 2 << 29;
-       }
-       tidx = tidptr - dd->ipath_egrtidbase;
-       writel(pa, tidp32);
-       mmiowb();
-}
-
-
-/**
- * ipath_pe_clear_tid - clear all TID entries for a port, expected and eager
- * @dd: the infinipath device
- * @port: the port
- *
- * clear all TID entries for a port, expected and eager.
- * Used from ipath_close().  On this chip, TIDs are only 32 bits,
- * not 64, but they are still on 64 bit boundaries, so tidbase
- * is declared as u64 * for the pointer math, even though we write 32 bits
- */
-static void ipath_pe_clear_tids(struct ipath_devdata *dd, unsigned port)
-{
-       u64 __iomem *tidbase;
-       unsigned long tidinv;
-       int i;
-
-       if (!dd->ipath_kregbase)
-               return;
-
-       ipath_cdbg(VERBOSE, "Invalidate TIDs for port %u\n", port);
-
-       tidinv = dd->ipath_tidinvalid;
-       tidbase = (u64 __iomem *)
-               ((char __iomem *)(dd->ipath_kregbase) +
-                dd->ipath_rcvtidbase +
-                port * dd->ipath_rcvtidcnt * sizeof(*tidbase));
-
-       for (i = 0; i < dd->ipath_rcvtidcnt; i++)
-               dd->ipath_f_put_tid(dd, &tidbase[i], RCVHQ_RCV_TYPE_EXPECTED,
-                                tidinv);
-
-       tidbase = (u64 __iomem *)
-               ((char __iomem *)(dd->ipath_kregbase) +
-                dd->ipath_rcvegrbase +
-                port * dd->ipath_rcvegrcnt * sizeof(*tidbase));
-
-       for (i = 0; i < dd->ipath_rcvegrcnt; i++)
-               dd->ipath_f_put_tid(dd, &tidbase[i], RCVHQ_RCV_TYPE_EAGER,
-                                tidinv);
-}
-
-/**
- * ipath_pe_tidtemplate - setup constants for TID updates
- * @dd: the infinipath device
- *
- * We setup stuff that we use a lot, to avoid calculating each time
- */
-static void ipath_pe_tidtemplate(struct ipath_devdata *dd)
-{
-       u32 egrsize = dd->ipath_rcvegrbufsize;
-
-       /* For now, we always allocate 4KB buffers (at init) so we can
-        * receive max size packets.  We may want a module parameter to
-        * specify 2KB or 4KB and/or make be per port instead of per device
-        * for those who want to reduce memory footprint.  Note that the
-        * ipath_rcvhdrentsize size must be large enough to hold the largest
-        * IB header (currently 96 bytes) that we expect to handle (plus of
-        * course the 2 dwords of RHF).
-        */
-       if (egrsize == 2048)
-               dd->ipath_tidtemplate = 1U << 29;
-       else if (egrsize == 4096)
-               dd->ipath_tidtemplate = 2U << 29;
-       else {
-               egrsize = 4096;
-               dev_info(&dd->pcidev->dev, "BUG: unsupported egrbufsize "
-                        "%u, using %u\n", dd->ipath_rcvegrbufsize,
-                        egrsize);
-               dd->ipath_tidtemplate = 2U << 29;
-       }
-       dd->ipath_tidinvalid = 0;
-}
-
-static int ipath_pe_early_init(struct ipath_devdata *dd)
-{
-       dd->ipath_flags |= IPATH_4BYTE_TID;
-       if (ipath_unordered_wc())
-               dd->ipath_flags |= IPATH_PIO_FLUSH_WC;
-
-       /*
-        * For openfabrics, we need to be able to handle an IB header of
-        * 24 dwords.  HT chip has arbitrary sized receive buffers, so we
-        * made them the same size as the PIO buffers.  This chip does not
-        * handle arbitrary size buffers, so we need the header large enough
-        * to handle largest IB header, but still have room for a 2KB MTU
-        * standard IB packet.
-        */
-       dd->ipath_rcvhdrentsize = 24;
-       dd->ipath_rcvhdrsize = IPATH_DFLT_RCVHDRSIZE;
-       dd->ipath_rhf_offset = 0;
-       dd->ipath_egrtidbase = (u64 __iomem *)
-               ((char __iomem *) dd->ipath_kregbase + dd->ipath_rcvegrbase);
-
-       dd->ipath_rcvegrbufsize = ipath_mtu4096 ? 4096 : 2048;
-       /*
-        * the min() check here is currently a nop, but it may not always
-        * be, depending on just how we do ipath_rcvegrbufsize
-        */
-       dd->ipath_ibmaxlen = min(ipath_mtu4096 ? dd->ipath_piosize4k :
-                                dd->ipath_piosize2k,
-                                dd->ipath_rcvegrbufsize +
-                                (dd->ipath_rcvhdrentsize << 2));
-       dd->ipath_init_ibmaxlen = dd->ipath_ibmaxlen;
-
-       /*
-        * We can request a receive interrupt for 1 or
-        * more packets from current offset.  For now, we set this
-        * up for a single packet.
-        */
-       dd->ipath_rhdrhead_intr_off = 1ULL<<32;
-
-       ipath_get_eeprom_info(dd);
-
-       return 0;
-}
-
-int __attribute__((weak)) ipath_unordered_wc(void)
-{
-       return 0;
-}
-
-/**
- * ipath_init_pe_get_base_info - set chip-specific flags for user code
- * @pd: the infinipath port
- * @kbase: ipath_base_info pointer
- *
- * We set the PCIE flag because the lower bandwidth on PCIe vs
- * HyperTransport can affect some user packet algorithms.
- */
-static int ipath_pe_get_base_info(struct ipath_portdata *pd, void *kbase)
-{
-       struct ipath_base_info *kinfo = kbase;
-       struct ipath_devdata *dd;
-
-       if (ipath_unordered_wc()) {
-               kinfo->spi_runtime_flags |= IPATH_RUNTIME_FORCE_WC_ORDER;
-               ipath_cdbg(PROC, "Intel processor, forcing WC order\n");
-       }
-       else
-               ipath_cdbg(PROC, "Not Intel processor, WC ordered\n");
-
-       if (pd == NULL)
-               goto done;
-
-       dd = pd->port_dd;
-
-done:
-       kinfo->spi_runtime_flags |= IPATH_RUNTIME_PCIE |
-               IPATH_RUNTIME_FORCE_PIOAVAIL | IPATH_RUNTIME_PIO_REGSWAPPED;
-       return 0;
-}
-
-static void ipath_pe_free_irq(struct ipath_devdata *dd)
-{
-       free_irq(dd->ipath_irq, dd);
-       dd->ipath_irq = 0;
-}
-
-
-static struct ipath_message_header *
-ipath_pe_get_msgheader(struct ipath_devdata *dd, __le32 *rhf_addr)
-{
-       return (struct ipath_message_header *)
-               &rhf_addr[sizeof(u64) / sizeof(u32)];
-}
-
-static void ipath_pe_config_ports(struct ipath_devdata *dd, ushort cfgports)
-{
-       dd->ipath_portcnt =
-               ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt);
-       dd->ipath_p0_rcvegrcnt =
-               ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvegrcnt);
-}
-
-static void ipath_pe_read_counters(struct ipath_devdata *dd,
-                                  struct infinipath_counters *cntrs)
-{
-       cntrs->LBIntCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBIntCnt));
-       cntrs->LBFlowStallCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBFlowStallCnt));
-       cntrs->TxSDmaDescCnt = 0;
-       cntrs->TxUnsupVLErrCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnsupVLErrCnt));
-       cntrs->TxDataPktCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDataPktCnt));
-       cntrs->TxFlowPktCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowPktCnt));
-       cntrs->TxDwordCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDwordCnt));
-       cntrs->TxLenErrCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxLenErrCnt));
-       cntrs->TxMaxMinLenErrCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxMaxMinLenErrCnt));
-       cntrs->TxUnderrunCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnderrunCnt));
-       cntrs->TxFlowStallCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowStallCnt));
-       cntrs->TxDroppedPktCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDroppedPktCnt));
-       cntrs->RxDroppedPktCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDroppedPktCnt));
-       cntrs->RxDataPktCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDataPktCnt));
-       cntrs->RxFlowPktCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowPktCnt));
-       cntrs->RxDwordCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDwordCnt));
-       cntrs->RxLenErrCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLenErrCnt));
-       cntrs->RxMaxMinLenErrCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxMaxMinLenErrCnt));
-       cntrs->RxICRCErrCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxICRCErrCnt));
-       cntrs->RxVCRCErrCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxVCRCErrCnt));
-       cntrs->RxFlowCtrlErrCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowCtrlErrCnt));
-       cntrs->RxBadFormatCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBadFormatCnt));
-       cntrs->RxLinkProblemCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLinkProblemCnt));
-       cntrs->RxEBPCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxEBPCnt));
-       cntrs->RxLPCRCErrCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLPCRCErrCnt));
-       cntrs->RxBufOvflCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBufOvflCnt));
-       cntrs->RxTIDFullErrCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDFullErrCnt));
-       cntrs->RxTIDValidErrCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDValidErrCnt));
-       cntrs->RxPKeyMismatchCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxPKeyMismatchCnt));
-       cntrs->RxP0HdrEgrOvflCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP0HdrEgrOvflCnt));
-       cntrs->RxP1HdrEgrOvflCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP1HdrEgrOvflCnt));
-       cntrs->RxP2HdrEgrOvflCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP2HdrEgrOvflCnt));
-       cntrs->RxP3HdrEgrOvflCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP3HdrEgrOvflCnt));
-       cntrs->RxP4HdrEgrOvflCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP4HdrEgrOvflCnt));
-       cntrs->RxP5HdrEgrOvflCnt = 0;
-       cntrs->RxP6HdrEgrOvflCnt = 0;
-       cntrs->RxP7HdrEgrOvflCnt = 0;
-       cntrs->RxP8HdrEgrOvflCnt = 0;
-       cntrs->RxP9HdrEgrOvflCnt = 0;
-       cntrs->RxP10HdrEgrOvflCnt = 0;
-       cntrs->RxP11HdrEgrOvflCnt = 0;
-       cntrs->RxP12HdrEgrOvflCnt = 0;
-       cntrs->RxP13HdrEgrOvflCnt = 0;
-       cntrs->RxP14HdrEgrOvflCnt = 0;
-       cntrs->RxP15HdrEgrOvflCnt = 0;
-       cntrs->RxP16HdrEgrOvflCnt = 0;
-       cntrs->IBStatusChangeCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBStatusChangeCnt));
-       cntrs->IBLinkErrRecoveryCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkErrRecoveryCnt));
-       cntrs->IBLinkDownedCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkDownedCnt));
-       cntrs->IBSymbolErrCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBSymbolErrCnt));
-       cntrs->RxVL15DroppedPktCnt = 0;
-       cntrs->RxOtherLocalPhyErrCnt = 0;
-       cntrs->PcieRetryBufDiagQwordCnt = 0;
-       cntrs->ExcessBufferOvflCnt = dd->ipath_overrun_thresh_errs;
-       cntrs->LocalLinkIntegrityErrCnt = dd->ipath_lli_errs;
-       cntrs->RxVlErrCnt = 0;
-       cntrs->RxDlidFltrCnt = 0;
-}
-
-
-/* no interrupt fallback for these chips */
-static int ipath_pe_nointr_fallback(struct ipath_devdata *dd)
-{
-       return 0;
-}
-
-
-/*
- * reset the XGXS (between serdes and IBC).  Slightly less intrusive
- * than resetting the IBC or external link state, and useful in some
- * cases to cause some retraining.  To do this right, we reset IBC
- * as well.
- */
-static void ipath_pe_xgxs_reset(struct ipath_devdata *dd)
-{
-       u64 val, prev_val;
-
-       prev_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
-       val = prev_val | INFINIPATH_XGXS_RESET;
-       prev_val &= ~INFINIPATH_XGXS_RESET; /* be sure */
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
-                        dd->ipath_control & ~INFINIPATH_C_LINKENABLE);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val);
-       ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, prev_val);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
-                        dd->ipath_control);
-}
-
-
-static int ipath_pe_get_ib_cfg(struct ipath_devdata *dd, int which)
-{
-       int ret;
-
-       switch (which) {
-       case IPATH_IB_CFG_LWID:
-               ret = dd->ipath_link_width_active;
-               break;
-       case IPATH_IB_CFG_SPD:
-               ret = dd->ipath_link_speed_active;
-               break;
-       case IPATH_IB_CFG_LWID_ENB:
-               ret = dd->ipath_link_width_enabled;
-               break;
-       case IPATH_IB_CFG_SPD_ENB:
-               ret = dd->ipath_link_speed_enabled;
-               break;
-       default:
-               ret =  -ENOTSUPP;
-               break;
-       }
-       return ret;
-}
-
-
-/* we assume range checking is already done, if needed */
-static int ipath_pe_set_ib_cfg(struct ipath_devdata *dd, int which, u32 val)
-{
-       int ret = 0;
-
-       if (which == IPATH_IB_CFG_LWID_ENB)
-               dd->ipath_link_width_enabled = val;
-       else if (which == IPATH_IB_CFG_SPD_ENB)
-               dd->ipath_link_speed_enabled = val;
-       else
-               ret = -ENOTSUPP;
-       return ret;
-}
-
-static void ipath_pe_config_jint(struct ipath_devdata *dd, u16 a, u16 b)
-{
-}
-
-
-static int ipath_pe_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs)
-{
-       if (ibup) {
-               if (dd->ibdeltainprog) {
-                       dd->ibdeltainprog = 0;
-                       dd->ibsymdelta +=
-                               ipath_read_creg32(dd,
-                                 dd->ipath_cregs->cr_ibsymbolerrcnt) -
-                               dd->ibsymsnap;
-                       dd->iblnkerrdelta +=
-                               ipath_read_creg32(dd,
-                                 dd->ipath_cregs->cr_iblinkerrrecovcnt) -
-                               dd->iblnkerrsnap;
-               }
-       } else {
-               dd->ipath_lli_counter = 0;
-               if (!dd->ibdeltainprog) {
-                       dd->ibdeltainprog = 1;
-                       dd->ibsymsnap =
-                               ipath_read_creg32(dd,
-                                 dd->ipath_cregs->cr_ibsymbolerrcnt);
-                       dd->iblnkerrsnap =
-                               ipath_read_creg32(dd,
-                                 dd->ipath_cregs->cr_iblinkerrrecovcnt);
-               }
-       }
-
-       ipath_setup_pe_setextled(dd, ipath_ib_linkstate(dd, ibcs),
-               ipath_ib_linktrstate(dd, ibcs));
-       return 0;
-}
-
-
-/**
- * ipath_init_iba6120_funcs - set up the chip-specific function pointers
- * @dd: the infinipath device
- *
- * This is global, and is called directly at init to set up the
- * chip-specific function pointers for later use.
- */
-void ipath_init_iba6120_funcs(struct ipath_devdata *dd)
-{
-       dd->ipath_f_intrsetup = ipath_pe_intconfig;
-       dd->ipath_f_bus = ipath_setup_pe_config;
-       dd->ipath_f_reset = ipath_setup_pe_reset;
-       dd->ipath_f_get_boardname = ipath_pe_boardname;
-       dd->ipath_f_init_hwerrors = ipath_pe_init_hwerrors;
-       dd->ipath_f_early_init = ipath_pe_early_init;
-       dd->ipath_f_handle_hwerrors = ipath_pe_handle_hwerrors;
-       dd->ipath_f_quiet_serdes = ipath_pe_quiet_serdes;
-       dd->ipath_f_bringup_serdes = ipath_pe_bringup_serdes;
-       dd->ipath_f_clear_tids = ipath_pe_clear_tids;
-       /*
-        * _f_put_tid may get changed after we read the chip revision,
-        * but we start with the safe version for all revs
-        */
-       dd->ipath_f_put_tid = ipath_pe_put_tid;
-       dd->ipath_f_cleanup = ipath_setup_pe_cleanup;
-       dd->ipath_f_setextled = ipath_setup_pe_setextled;
-       dd->ipath_f_get_base_info = ipath_pe_get_base_info;
-       dd->ipath_f_free_irq = ipath_pe_free_irq;
-       dd->ipath_f_tidtemplate = ipath_pe_tidtemplate;
-       dd->ipath_f_intr_fallback = ipath_pe_nointr_fallback;
-       dd->ipath_f_xgxs_reset = ipath_pe_xgxs_reset;
-       dd->ipath_f_get_msgheader = ipath_pe_get_msgheader;
-       dd->ipath_f_config_ports = ipath_pe_config_ports;
-       dd->ipath_f_read_counters = ipath_pe_read_counters;
-       dd->ipath_f_get_ib_cfg = ipath_pe_get_ib_cfg;
-       dd->ipath_f_set_ib_cfg = ipath_pe_set_ib_cfg;
-       dd->ipath_f_config_jint = ipath_pe_config_jint;
-       dd->ipath_f_ib_updown = ipath_pe_ib_updown;
-
-
-       /* initialize chip-specific variables */
-       ipath_init_pe_variables(dd);
-}
-
diff --git a/drivers/infiniband/hw/ipath/ipath_iba7220.c b/drivers/infiniband/hw/ipath/ipath_iba7220.c
deleted file mode 100644 (file)
index 34b778e..0000000
+++ /dev/null
@@ -1,2631 +0,0 @@
-/*
- * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved.
- * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     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.
- *
- * 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.
- */
-/*
- * This file contains all of the code that is specific to the
- * InfiniPath 7220 chip (except that specific to the SerDes)
- */
-
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <rdma/ib_verbs.h>
-
-#include "ipath_kernel.h"
-#include "ipath_registers.h"
-#include "ipath_7220.h"
-
-static void ipath_setup_7220_setextled(struct ipath_devdata *, u64, u64);
-
-static unsigned ipath_compat_ddr_negotiate = 1;
-
-module_param_named(compat_ddr_negotiate, ipath_compat_ddr_negotiate, uint,
-                       S_IWUSR | S_IRUGO);
-MODULE_PARM_DESC(compat_ddr_negotiate,
-               "Attempt pre-IBTA 1.2 DDR speed negotiation");
-
-static unsigned ipath_sdma_fetch_arb = 1;
-module_param_named(fetch_arb, ipath_sdma_fetch_arb, uint, S_IRUGO);
-MODULE_PARM_DESC(fetch_arb, "IBA7220: change SDMA descriptor arbitration");
-
-/*
- * This file contains almost all the chip-specific register information and
- * access functions for the QLogic InfiniPath 7220 PCI-Express chip, with the
- * exception of SerDes support, which in in ipath_sd7220.c.
- *
- * This lists the InfiniPath registers, in the actual chip layout.
- * This structure should never be directly accessed.
- */
-struct _infinipath_do_not_use_kernel_regs {
-       unsigned long long Revision;
-       unsigned long long Control;
-       unsigned long long PageAlign;
-       unsigned long long PortCnt;
-       unsigned long long DebugPortSelect;
-       unsigned long long DebugSigsIntSel; /* was Reserved0;*/
-       unsigned long long SendRegBase;
-       unsigned long long UserRegBase;
-       unsigned long long CounterRegBase;
-       unsigned long long Scratch;
-       unsigned long long EEPROMAddrCmd; /* was Reserved1; */
-       unsigned long long EEPROMData; /* was Reserved2; */
-       unsigned long long IntBlocked;
-       unsigned long long IntMask;
-       unsigned long long IntStatus;
-       unsigned long long IntClear;
-       unsigned long long ErrorMask;
-       unsigned long long ErrorStatus;
-       unsigned long long ErrorClear;
-       unsigned long long HwErrMask;
-       unsigned long long HwErrStatus;
-       unsigned long long HwErrClear;
-       unsigned long long HwDiagCtrl;
-       unsigned long long MDIO;
-       unsigned long long IBCStatus;
-       unsigned long long IBCCtrl;
-       unsigned long long ExtStatus;
-       unsigned long long ExtCtrl;
-       unsigned long long GPIOOut;
-       unsigned long long GPIOMask;
-       unsigned long long GPIOStatus;
-       unsigned long long GPIOClear;
-       unsigned long long RcvCtrl;
-       unsigned long long RcvBTHQP;
-       unsigned long long RcvHdrSize;
-       unsigned long long RcvHdrCnt;
-       unsigned long long RcvHdrEntSize;
-       unsigned long long RcvTIDBase;
-       unsigned long long RcvTIDCnt;
-       unsigned long long RcvEgrBase;
-       unsigned long long RcvEgrCnt;
-       unsigned long long RcvBufBase;
-       unsigned long long RcvBufSize;
-       unsigned long long RxIntMemBase;
-       unsigned long long RxIntMemSize;
-       unsigned long long RcvPartitionKey;
-       unsigned long long RcvQPMulticastPort;
-       unsigned long long RcvPktLEDCnt;
-       unsigned long long IBCDDRCtrl;
-       unsigned long long HRTBT_GUID;
-       unsigned long long IB_SDTEST_IF_TX;
-       unsigned long long IB_SDTEST_IF_RX;
-       unsigned long long IBCDDRCtrl2;
-       unsigned long long IBCDDRStatus;
-       unsigned long long JIntReload;
-       unsigned long long IBNCModeCtrl;
-       unsigned long long SendCtrl;
-       unsigned long long SendBufBase;
-       unsigned long long SendBufSize;
-       unsigned long long SendBufCnt;
-       unsigned long long SendAvailAddr;
-       unsigned long long TxIntMemBase;
-       unsigned long long TxIntMemSize;
-       unsigned long long SendDmaBase;
-       unsigned long long SendDmaLenGen;
-       unsigned long long SendDmaTail;
-       unsigned long long SendDmaHead;
-       unsigned long long SendDmaHeadAddr;
-       unsigned long long SendDmaBufMask0;
-       unsigned long long SendDmaBufMask1;
-       unsigned long long SendDmaBufMask2;
-       unsigned long long SendDmaStatus;
-       unsigned long long SendBufferError;
-       unsigned long long SendBufferErrorCONT1;
-       unsigned long long SendBufErr2; /* was Reserved6SBE[0/6] */
-       unsigned long long Reserved6L[2];
-       unsigned long long AvailUpdCount;
-       unsigned long long RcvHdrAddr0;
-       unsigned long long RcvHdrAddrs[16]; /* Why enumerate? */
-       unsigned long long Reserved7hdtl; /* Align next to 300 */
-       unsigned long long RcvHdrTailAddr0; /* 300, like others */
-       unsigned long long RcvHdrTailAddrs[16];
-       unsigned long long Reserved9SW[7]; /* was [8]; we have 17 ports */
-       unsigned long long IbsdEpbAccCtl; /* IB Serdes EPB access control */
-       unsigned long long IbsdEpbTransReg; /* IB Serdes EPB Transaction */
-       unsigned long long Reserved10sds; /* was SerdesStatus on */
-       unsigned long long XGXSConfig;
-       unsigned long long IBSerDesCtrl; /* Was IBPLLCfg on Monty */
-       unsigned long long EEPCtlStat; /* for "boot" EEPROM/FLASH */
-       unsigned long long EEPAddrCmd;
-       unsigned long long EEPData;
-       unsigned long long PcieEpbAccCtl;
-       unsigned long long PcieEpbTransCtl;
-       unsigned long long EfuseCtl; /* E-Fuse control */
-       unsigned long long EfuseData[4];
-       unsigned long long ProcMon;
-       /* this chip moves following two from previous 200, 208 */
-       unsigned long long PCIeRBufTestReg0;
-       unsigned long long PCIeRBufTestReg1;
-       /* added for this chip */
-       unsigned long long PCIeRBufTestReg2;
-       unsigned long long PCIeRBufTestReg3;
-       /* added for this chip, debug only */
-       unsigned long long SPC_JTAG_ACCESS_REG;
-       unsigned long long LAControlReg;
-       unsigned long long GPIODebugSelReg;
-       unsigned long long DebugPortValueReg;
-       /* added for this chip, DMA */
-       unsigned long long SendDmaBufUsed[3];
-       unsigned long long SendDmaReqTagUsed;
-       /*
-        * added for this chip, EFUSE: note that these program 64-bit
-        * words 2 and 3 */
-       unsigned long long efuse_pgm_data[2];
-       unsigned long long Reserved11LAalign[10]; /* Skip 4B0..4F8 */
-       /* we have 30 regs for DDS and RXEQ in IB SERDES */
-       unsigned long long SerDesDDSRXEQ[30];
-       unsigned long long Reserved12LAalign[2]; /* Skip 5F0, 5F8 */
-       /* added for LA debug support */
-       unsigned long long LAMemory[32];
-};
-
-struct _infinipath_do_not_use_counters {
-       __u64 LBIntCnt;
-       __u64 LBFlowStallCnt;
-       __u64 TxSDmaDescCnt;    /* was Reserved1 */
-       __u64 TxUnsupVLErrCnt;
-       __u64 TxDataPktCnt;
-       __u64 TxFlowPktCnt;
-       __u64 TxDwordCnt;
-       __u64 TxLenErrCnt;
-       __u64 TxMaxMinLenErrCnt;
-       __u64 TxUnderrunCnt;
-       __u64 TxFlowStallCnt;
-       __u64 TxDroppedPktCnt;
-       __u64 RxDroppedPktCnt;
-       __u64 RxDataPktCnt;
-       __u64 RxFlowPktCnt;
-       __u64 RxDwordCnt;
-       __u64 RxLenErrCnt;
-       __u64 RxMaxMinLenErrCnt;
-       __u64 RxICRCErrCnt;
-       __u64 RxVCRCErrCnt;
-       __u64 RxFlowCtrlErrCnt;
-       __u64 RxBadFormatCnt;
-       __u64 RxLinkProblemCnt;
-       __u64 RxEBPCnt;
-       __u64 RxLPCRCErrCnt;
-       __u64 RxBufOvflCnt;
-       __u64 RxTIDFullErrCnt;
-       __u64 RxTIDValidErrCnt;
-       __u64 RxPKeyMismatchCnt;
-       __u64 RxP0HdrEgrOvflCnt;
-       __u64 RxP1HdrEgrOvflCnt;
-       __u64 RxP2HdrEgrOvflCnt;
-       __u64 RxP3HdrEgrOvflCnt;
-       __u64 RxP4HdrEgrOvflCnt;
-       __u64 RxP5HdrEgrOvflCnt;
-       __u64 RxP6HdrEgrOvflCnt;
-       __u64 RxP7HdrEgrOvflCnt;
-       __u64 RxP8HdrEgrOvflCnt;
-       __u64 RxP9HdrEgrOvflCnt;        /* was Reserved6 */
-       __u64 RxP10HdrEgrOvflCnt;       /* was Reserved7 */
-       __u64 RxP11HdrEgrOvflCnt;       /* new for IBA7220 */
-       __u64 RxP12HdrEgrOvflCnt;       /* new for IBA7220 */
-       __u64 RxP13HdrEgrOvflCnt;       /* new for IBA7220 */
-       __u64 RxP14HdrEgrOvflCnt;       /* new for IBA7220 */
-       __u64 RxP15HdrEgrOvflCnt;       /* new for IBA7220 */
-       __u64 RxP16HdrEgrOvflCnt;       /* new for IBA7220 */
-       __u64 IBStatusChangeCnt;
-       __u64 IBLinkErrRecoveryCnt;
-       __u64 IBLinkDownedCnt;
-       __u64 IBSymbolErrCnt;
-       /* The following are new for IBA7220 */
-       __u64 RxVL15DroppedPktCnt;
-       __u64 RxOtherLocalPhyErrCnt;
-       __u64 PcieRetryBufDiagQwordCnt;
-       __u64 ExcessBufferOvflCnt;
-       __u64 LocalLinkIntegrityErrCnt;
-       __u64 RxVlErrCnt;
-       __u64 RxDlidFltrCnt;
-       __u64 Reserved8[7];
-       __u64 PSStat;
-       __u64 PSStart;
-       __u64 PSInterval;
-       __u64 PSRcvDataCount;
-       __u64 PSRcvPktsCount;
-       __u64 PSXmitDataCount;
-       __u64 PSXmitPktsCount;
-       __u64 PSXmitWaitCount;
-};
-
-#define IPATH_KREG_OFFSET(field) (offsetof( \
-       struct _infinipath_do_not_use_kernel_regs, field) / sizeof(u64))
-#define IPATH_CREG_OFFSET(field) (offsetof( \
-       struct _infinipath_do_not_use_counters, field) / sizeof(u64))
-
-static const struct ipath_kregs ipath_7220_kregs = {
-       .kr_control = IPATH_KREG_OFFSET(Control),
-       .kr_counterregbase = IPATH_KREG_OFFSET(CounterRegBase),
-       .kr_debugportselect = IPATH_KREG_OFFSET(DebugPortSelect),
-       .kr_errorclear = IPATH_KREG_OFFSET(ErrorClear),
-       .kr_errormask = IPATH_KREG_OFFSET(ErrorMask),
-       .kr_errorstatus = IPATH_KREG_OFFSET(ErrorStatus),
-       .kr_extctrl = IPATH_KREG_OFFSET(ExtCtrl),
-       .kr_extstatus = IPATH_KREG_OFFSET(ExtStatus),
-       .kr_gpio_clear = IPATH_KREG_OFFSET(GPIOClear),
-       .kr_gpio_mask = IPATH_KREG_OFFSET(GPIOMask),
-       .kr_gpio_out = IPATH_KREG_OFFSET(GPIOOut),
-       .kr_gpio_status = IPATH_KREG_OFFSET(GPIOStatus),
-       .kr_hwdiagctrl = IPATH_KREG_OFFSET(HwDiagCtrl),
-       .kr_hwerrclear = IPATH_KREG_OFFSET(HwErrClear),
-       .kr_hwerrmask = IPATH_KREG_OFFSET(HwErrMask),
-       .kr_hwerrstatus = IPATH_KREG_OFFSET(HwErrStatus),
-       .kr_ibcctrl = IPATH_KREG_OFFSET(IBCCtrl),
-       .kr_ibcstatus = IPATH_KREG_OFFSET(IBCStatus),
-       .kr_intblocked = IPATH_KREG_OFFSET(IntBlocked),
-       .kr_intclear = IPATH_KREG_OFFSET(IntClear),
-       .kr_intmask = IPATH_KREG_OFFSET(IntMask),
-       .kr_intstatus = IPATH_KREG_OFFSET(IntStatus),
-       .kr_mdio = IPATH_KREG_OFFSET(MDIO),
-       .kr_pagealign = IPATH_KREG_OFFSET(PageAlign),
-       .kr_partitionkey = IPATH_KREG_OFFSET(RcvPartitionKey),
-       .kr_portcnt = IPATH_KREG_OFFSET(PortCnt),
-       .kr_rcvbthqp = IPATH_KREG_OFFSET(RcvBTHQP),
-       .kr_rcvbufbase = IPATH_KREG_OFFSET(RcvBufBase),
-       .kr_rcvbufsize = IPATH_KREG_OFFSET(RcvBufSize),
-       .kr_rcvctrl = IPATH_KREG_OFFSET(RcvCtrl),
-       .kr_rcvegrbase = IPATH_KREG_OFFSET(RcvEgrBase),
-       .kr_rcvegrcnt = IPATH_KREG_OFFSET(RcvEgrCnt),
-       .kr_rcvhdrcnt = IPATH_KREG_OFFSET(RcvHdrCnt),
-       .kr_rcvhdrentsize = IPATH_KREG_OFFSET(RcvHdrEntSize),
-       .kr_rcvhdrsize = IPATH_KREG_OFFSET(RcvHdrSize),
-       .kr_rcvintmembase = IPATH_KREG_OFFSET(RxIntMemBase),
-       .kr_rcvintmemsize = IPATH_KREG_OFFSET(RxIntMemSize),
-       .kr_rcvtidbase = IPATH_KREG_OFFSET(RcvTIDBase),
-       .kr_rcvtidcnt = IPATH_KREG_OFFSET(RcvTIDCnt),
-       .kr_revision = IPATH_KREG_OFFSET(Revision),
-       .kr_scratch = IPATH_KREG_OFFSET(Scratch),
-       .kr_sendbuffererror = IPATH_KREG_OFFSET(SendBufferError),
-       .kr_sendctrl = IPATH_KREG_OFFSET(SendCtrl),
-       .kr_sendpioavailaddr = IPATH_KREG_OFFSET(SendAvailAddr),
-       .kr_sendpiobufbase = IPATH_KREG_OFFSET(SendBufBase),
-       .kr_sendpiobufcnt = IPATH_KREG_OFFSET(SendBufCnt),
-       .kr_sendpiosize = IPATH_KREG_OFFSET(SendBufSize),
-       .kr_sendregbase = IPATH_KREG_OFFSET(SendRegBase),
-       .kr_txintmembase = IPATH_KREG_OFFSET(TxIntMemBase),
-       .kr_txintmemsize = IPATH_KREG_OFFSET(TxIntMemSize),
-       .kr_userregbase = IPATH_KREG_OFFSET(UserRegBase),
-
-       .kr_xgxsconfig = IPATH_KREG_OFFSET(XGXSConfig),
-
-       /* send dma related regs */
-       .kr_senddmabase = IPATH_KREG_OFFSET(SendDmaBase),
-       .kr_senddmalengen = IPATH_KREG_OFFSET(SendDmaLenGen),
-       .kr_senddmatail = IPATH_KREG_OFFSET(SendDmaTail),
-       .kr_senddmahead = IPATH_KREG_OFFSET(SendDmaHead),
-       .kr_senddmaheadaddr = IPATH_KREG_OFFSET(SendDmaHeadAddr),
-       .kr_senddmabufmask0 = IPATH_KREG_OFFSET(SendDmaBufMask0),
-       .kr_senddmabufmask1 = IPATH_KREG_OFFSET(SendDmaBufMask1),
-       .kr_senddmabufmask2 = IPATH_KREG_OFFSET(SendDmaBufMask2),
-       .kr_senddmastatus = IPATH_KREG_OFFSET(SendDmaStatus),
-
-       /* SerDes related regs */
-       .kr_ibserdesctrl = IPATH_KREG_OFFSET(IBSerDesCtrl),
-       .kr_ib_epbacc = IPATH_KREG_OFFSET(IbsdEpbAccCtl),
-       .kr_ib_epbtrans = IPATH_KREG_OFFSET(IbsdEpbTransReg),
-       .kr_pcie_epbacc = IPATH_KREG_OFFSET(PcieEpbAccCtl),
-       .kr_pcie_epbtrans = IPATH_KREG_OFFSET(PcieEpbTransCtl),
-       .kr_ib_ddsrxeq = IPATH_KREG_OFFSET(SerDesDDSRXEQ),
-
-       /*
-        * These should not be used directly via ipath_read_kreg64(),
-        * use them with ipath_read_kreg64_port()
-        */
-       .kr_rcvhdraddr = IPATH_KREG_OFFSET(RcvHdrAddr0),
-       .kr_rcvhdrtailaddr = IPATH_KREG_OFFSET(RcvHdrTailAddr0),
-
-       /*
-        * The rcvpktled register controls one of the debug port signals, so
-        * a packet activity LED can be connected to it.
-        */
-       .kr_rcvpktledcnt = IPATH_KREG_OFFSET(RcvPktLEDCnt),
-       .kr_pcierbuftestreg0 = IPATH_KREG_OFFSET(PCIeRBufTestReg0),
-       .kr_pcierbuftestreg1 = IPATH_KREG_OFFSET(PCIeRBufTestReg1),
-
-       .kr_hrtbt_guid = IPATH_KREG_OFFSET(HRTBT_GUID),
-       .kr_ibcddrctrl = IPATH_KREG_OFFSET(IBCDDRCtrl),
-       .kr_ibcddrstatus = IPATH_KREG_OFFSET(IBCDDRStatus),
-       .kr_jintreload = IPATH_KREG_OFFSET(JIntReload)
-};
-
-static const struct ipath_cregs ipath_7220_cregs = {
-       .cr_badformatcnt = IPATH_CREG_OFFSET(RxBadFormatCnt),
-       .cr_erricrccnt = IPATH_CREG_OFFSET(RxICRCErrCnt),
-       .cr_errlinkcnt = IPATH_CREG_OFFSET(RxLinkProblemCnt),
-       .cr_errlpcrccnt = IPATH_CREG_OFFSET(RxLPCRCErrCnt),
-       .cr_errpkey = IPATH_CREG_OFFSET(RxPKeyMismatchCnt),
-       .cr_errrcvflowctrlcnt = IPATH_CREG_OFFSET(RxFlowCtrlErrCnt),
-       .cr_err_rlencnt = IPATH_CREG_OFFSET(RxLenErrCnt),
-       .cr_errslencnt = IPATH_CREG_OFFSET(TxLenErrCnt),
-       .cr_errtidfull = IPATH_CREG_OFFSET(RxTIDFullErrCnt),
-       .cr_errtidvalid = IPATH_CREG_OFFSET(RxTIDValidErrCnt),
-       .cr_errvcrccnt = IPATH_CREG_OFFSET(RxVCRCErrCnt),
-       .cr_ibstatuschange = IPATH_CREG_OFFSET(IBStatusChangeCnt),
-       .cr_intcnt = IPATH_CREG_OFFSET(LBIntCnt),
-       .cr_invalidrlencnt = IPATH_CREG_OFFSET(RxMaxMinLenErrCnt),
-       .cr_invalidslencnt = IPATH_CREG_OFFSET(TxMaxMinLenErrCnt),
-       .cr_lbflowstallcnt = IPATH_CREG_OFFSET(LBFlowStallCnt),
-       .cr_pktrcvcnt = IPATH_CREG_OFFSET(RxDataPktCnt),
-       .cr_pktrcvflowctrlcnt = IPATH_CREG_OFFSET(RxFlowPktCnt),
-       .cr_pktsendcnt = IPATH_CREG_OFFSET(TxDataPktCnt),
-       .cr_pktsendflowcnt = IPATH_CREG_OFFSET(TxFlowPktCnt),
-       .cr_portovflcnt = IPATH_CREG_OFFSET(RxP0HdrEgrOvflCnt),
-       .cr_rcvebpcnt = IPATH_CREG_OFFSET(RxEBPCnt),
-       .cr_rcvovflcnt = IPATH_CREG_OFFSET(RxBufOvflCnt),
-       .cr_senddropped = IPATH_CREG_OFFSET(TxDroppedPktCnt),
-       .cr_sendstallcnt = IPATH_CREG_OFFSET(TxFlowStallCnt),
-       .cr_sendunderruncnt = IPATH_CREG_OFFSET(TxUnderrunCnt),
-       .cr_wordrcvcnt = IPATH_CREG_OFFSET(RxDwordCnt),
-       .cr_wordsendcnt = IPATH_CREG_OFFSET(TxDwordCnt),
-       .cr_unsupvlcnt = IPATH_CREG_OFFSET(TxUnsupVLErrCnt),
-       .cr_rxdroppktcnt = IPATH_CREG_OFFSET(RxDroppedPktCnt),
-       .cr_iblinkerrrecovcnt = IPATH_CREG_OFFSET(IBLinkErrRecoveryCnt),
-       .cr_iblinkdowncnt = IPATH_CREG_OFFSET(IBLinkDownedCnt),
-       .cr_ibsymbolerrcnt = IPATH_CREG_OFFSET(IBSymbolErrCnt),
-       .cr_vl15droppedpktcnt = IPATH_CREG_OFFSET(RxVL15DroppedPktCnt),
-       .cr_rxotherlocalphyerrcnt =
-               IPATH_CREG_OFFSET(RxOtherLocalPhyErrCnt),
-       .cr_excessbufferovflcnt = IPATH_CREG_OFFSET(ExcessBufferOvflCnt),
-       .cr_locallinkintegrityerrcnt =
-               IPATH_CREG_OFFSET(LocalLinkIntegrityErrCnt),
-       .cr_rxvlerrcnt = IPATH_CREG_OFFSET(RxVlErrCnt),
-       .cr_rxdlidfltrcnt = IPATH_CREG_OFFSET(RxDlidFltrCnt),
-       .cr_psstat = IPATH_CREG_OFFSET(PSStat),
-       .cr_psstart = IPATH_CREG_OFFSET(PSStart),
-       .cr_psinterval = IPATH_CREG_OFFSET(PSInterval),
-       .cr_psrcvdatacount = IPATH_CREG_OFFSET(PSRcvDataCount),
-       .cr_psrcvpktscount = IPATH_CREG_OFFSET(PSRcvPktsCount),
-       .cr_psxmitdatacount = IPATH_CREG_OFFSET(PSXmitDataCount),
-       .cr_psxmitpktscount = IPATH_CREG_OFFSET(PSXmitPktsCount),
-       .cr_psxmitwaitcount = IPATH_CREG_OFFSET(PSXmitWaitCount),
-};
-
-/* kr_control bits */
-#define INFINIPATH_C_RESET (1U<<7)
-
-/* kr_intstatus, kr_intclear, kr_intmask bits */
-#define INFINIPATH_I_RCVURG_MASK ((1ULL<<17)-1)
-#define INFINIPATH_I_RCVURG_SHIFT 32
-#define INFINIPATH_I_RCVAVAIL_MASK ((1ULL<<17)-1)
-#define INFINIPATH_I_RCVAVAIL_SHIFT 0
-#define INFINIPATH_I_SERDESTRIMDONE (1ULL<<27)
-
-/* kr_hwerrclear, kr_hwerrmask, kr_hwerrstatus, bits */
-#define INFINIPATH_HWE_PCIEMEMPARITYERR_MASK  0x00000000000000ffULL
-#define INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT 0
-#define INFINIPATH_HWE_PCIEPOISONEDTLP      0x0000000010000000ULL
-#define INFINIPATH_HWE_PCIECPLTIMEOUT       0x0000000020000000ULL
-#define INFINIPATH_HWE_PCIEBUSPARITYXTLH    0x0000000040000000ULL
-#define INFINIPATH_HWE_PCIEBUSPARITYXADM    0x0000000080000000ULL
-#define INFINIPATH_HWE_PCIEBUSPARITYRADM    0x0000000100000000ULL
-#define INFINIPATH_HWE_COREPLL_FBSLIP       0x0080000000000000ULL
-#define INFINIPATH_HWE_COREPLL_RFSLIP       0x0100000000000000ULL
-#define INFINIPATH_HWE_PCIE1PLLFAILED       0x0400000000000000ULL
-#define INFINIPATH_HWE_PCIE0PLLFAILED       0x0800000000000000ULL
-#define INFINIPATH_HWE_SERDESPLLFAILED      0x1000000000000000ULL
-/* specific to this chip */
-#define INFINIPATH_HWE_PCIECPLDATAQUEUEERR         0x0000000000000040ULL
-#define INFINIPATH_HWE_PCIECPLHDRQUEUEERR          0x0000000000000080ULL
-#define INFINIPATH_HWE_SDMAMEMREADERR              0x0000000010000000ULL
-#define INFINIPATH_HWE_CLK_UC_PLLNOTLOCKED        0x2000000000000000ULL
-#define INFINIPATH_HWE_PCIESERDESQ0PCLKNOTDETECT   0x0100000000000000ULL
-#define INFINIPATH_HWE_PCIESERDESQ1PCLKNOTDETECT   0x0200000000000000ULL
-#define INFINIPATH_HWE_PCIESERDESQ2PCLKNOTDETECT   0x0400000000000000ULL
-#define INFINIPATH_HWE_PCIESERDESQ3PCLKNOTDETECT   0x0800000000000000ULL
-#define INFINIPATH_HWE_DDSRXEQMEMORYPARITYERR     0x0000008000000000ULL
-#define INFINIPATH_HWE_IB_UC_MEMORYPARITYERR      0x0000004000000000ULL
-#define INFINIPATH_HWE_PCIE_UC_OCT0MEMORYPARITYERR 0x0000001000000000ULL
-#define INFINIPATH_HWE_PCIE_UC_OCT1MEMORYPARITYERR 0x0000002000000000ULL
-
-#define IBA7220_IBCS_LINKTRAININGSTATE_MASK 0x1F
-#define IBA7220_IBCS_LINKSTATE_SHIFT 5
-#define IBA7220_IBCS_LINKSPEED_SHIFT 8
-#define IBA7220_IBCS_LINKWIDTH_SHIFT 9
-
-#define IBA7220_IBCC_LINKINITCMD_MASK 0x7ULL
-#define IBA7220_IBCC_LINKCMD_SHIFT 19
-#define IBA7220_IBCC_MAXPKTLEN_SHIFT 21
-
-/* kr_ibcddrctrl bits */
-#define IBA7220_IBC_DLIDLMC_MASK       0xFFFFFFFFUL
-#define IBA7220_IBC_DLIDLMC_SHIFT      32
-#define IBA7220_IBC_HRTBT_MASK 3
-#define IBA7220_IBC_HRTBT_SHIFT        16
-#define IBA7220_IBC_HRTBT_ENB  0x10000UL
-#define IBA7220_IBC_LANE_REV_SUPPORTED (1<<8)
-#define IBA7220_IBC_LREV_MASK  1
-#define IBA7220_IBC_LREV_SHIFT 8
-#define IBA7220_IBC_RXPOL_MASK 1
-#define IBA7220_IBC_RXPOL_SHIFT        7
-#define IBA7220_IBC_WIDTH_SHIFT        5
-#define IBA7220_IBC_WIDTH_MASK 0x3
-#define IBA7220_IBC_WIDTH_1X_ONLY      (0<<IBA7220_IBC_WIDTH_SHIFT)
-#define IBA7220_IBC_WIDTH_4X_ONLY      (1<<IBA7220_IBC_WIDTH_SHIFT)
-#define IBA7220_IBC_WIDTH_AUTONEG      (2<<IBA7220_IBC_WIDTH_SHIFT)
-#define IBA7220_IBC_SPEED_AUTONEG      (1<<1)
-#define IBA7220_IBC_SPEED_SDR          (1<<2)
-#define IBA7220_IBC_SPEED_DDR          (1<<3)
-#define IBA7220_IBC_SPEED_AUTONEG_MASK  (0x7<<1)
-#define IBA7220_IBC_IBTA_1_2_MASK      (1)
-
-/* kr_ibcddrstatus */
-/* link latency shift is 0, don't bother defining */
-#define IBA7220_DDRSTAT_LINKLAT_MASK    0x3ffffff
-
-/* kr_extstatus bits */
-#define INFINIPATH_EXTS_FREQSEL 0x2
-#define INFINIPATH_EXTS_SERDESSEL 0x4
-#define INFINIPATH_EXTS_MEMBIST_ENDTEST     0x0000000000004000
-#define INFINIPATH_EXTS_MEMBIST_DISABLED    0x0000000000008000
-
-/* kr_xgxsconfig bits */
-#define INFINIPATH_XGXS_RESET          0x5ULL
-#define INFINIPATH_XGXS_FC_SAFE        (1ULL<<63)
-
-/* kr_rcvpktledcnt */
-#define IBA7220_LEDBLINK_ON_SHIFT 32 /* 4ns period on after packet */
-#define IBA7220_LEDBLINK_OFF_SHIFT 0 /* 4ns period off before next on */
-
-#define _IPATH_GPIO_SDA_NUM 1
-#define _IPATH_GPIO_SCL_NUM 0
-
-#define IPATH_GPIO_SDA (1ULL << \
-       (_IPATH_GPIO_SDA_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT))
-#define IPATH_GPIO_SCL (1ULL << \
-       (_IPATH_GPIO_SCL_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT))
-
-#define IBA7220_R_INTRAVAIL_SHIFT 17
-#define IBA7220_R_TAILUPD_SHIFT 35
-#define IBA7220_R_PORTCFG_SHIFT 36
-
-#define INFINIPATH_JINT_PACKETSHIFT 16
-#define INFINIPATH_JINT_DEFAULT_IDLE_TICKS  0
-#define INFINIPATH_JINT_DEFAULT_MAX_PACKETS 0
-
-#define IBA7220_HDRHEAD_PKTINT_SHIFT 32 /* interrupt cnt in upper 32 bits */
-
-/*
- * the size bits give us 2^N, in KB units.  0 marks as invalid,
- * and 7 is reserved.  We currently use only 2KB and 4KB
- */
-#define IBA7220_TID_SZ_SHIFT 37 /* shift to 3bit size selector */
-#define IBA7220_TID_SZ_2K (1UL<<IBA7220_TID_SZ_SHIFT) /* 2KB */
-#define IBA7220_TID_SZ_4K (2UL<<IBA7220_TID_SZ_SHIFT) /* 4KB */
-#define IBA7220_TID_PA_SHIFT 11U /* TID addr in chip stored w/o low bits */
-
-#define IPATH_AUTONEG_TRIES 5 /* sequential retries to negotiate DDR */
-
-static char int_type[16] = "auto";
-module_param_string(interrupt_type, int_type, sizeof(int_type), 0444);
-MODULE_PARM_DESC(int_type, " interrupt_type=auto|force_msi|force_intx");
-
-/* packet rate matching delay; chip has support */
-static u8 rate_to_delay[2][2] = {
-       /* 1x, 4x */
-       {   8, 2 }, /* SDR */
-       {   4, 1 }  /* DDR */
-};
-
-/* 7220 specific hardware errors... */
-static const struct ipath_hwerror_msgs ipath_7220_hwerror_msgs[] = {
-       INFINIPATH_HWE_MSG(PCIEPOISONEDTLP, "PCIe Poisoned TLP"),
-       INFINIPATH_HWE_MSG(PCIECPLTIMEOUT, "PCIe completion timeout"),
-       /*
-        * In practice, it's unlikely wthat we'll see PCIe PLL, or bus
-        * parity or memory parity error failures, because most likely we
-        * won't be able to talk to the core of the chip.  Nonetheless, we
-        * might see them, if they are in parts of the PCIe core that aren't
-        * essential.
-        */
-       INFINIPATH_HWE_MSG(PCIE1PLLFAILED, "PCIePLL1"),
-       INFINIPATH_HWE_MSG(PCIE0PLLFAILED, "PCIePLL0"),
-       INFINIPATH_HWE_MSG(PCIEBUSPARITYXTLH, "PCIe XTLH core parity"),
-       INFINIPATH_HWE_MSG(PCIEBUSPARITYXADM, "PCIe ADM TX core parity"),
-       INFINIPATH_HWE_MSG(PCIEBUSPARITYRADM, "PCIe ADM RX core parity"),
-       INFINIPATH_HWE_MSG(RXDSYNCMEMPARITYERR, "Rx Dsync"),
-       INFINIPATH_HWE_MSG(SERDESPLLFAILED, "SerDes PLL"),
-       INFINIPATH_HWE_MSG(PCIECPLDATAQUEUEERR, "PCIe cpl header queue"),
-       INFINIPATH_HWE_MSG(PCIECPLHDRQUEUEERR, "PCIe cpl data queue"),
-       INFINIPATH_HWE_MSG(SDMAMEMREADERR, "Send DMA memory read"),
-       INFINIPATH_HWE_MSG(CLK_UC_PLLNOTLOCKED, "uC PLL clock not locked"),
-       INFINIPATH_HWE_MSG(PCIESERDESQ0PCLKNOTDETECT,
-               "PCIe serdes Q0 no clock"),
-       INFINIPATH_HWE_MSG(PCIESERDESQ1PCLKNOTDETECT,
-               "PCIe serdes Q1 no clock"),
-       INFINIPATH_HWE_MSG(PCIESERDESQ2PCLKNOTDETECT,
-               "PCIe serdes Q2 no clock"),
-       INFINIPATH_HWE_MSG(PCIESERDESQ3PCLKNOTDETECT,
-               "PCIe serdes Q3 no clock"),
-       INFINIPATH_HWE_MSG(DDSRXEQMEMORYPARITYERR,
-               "DDS RXEQ memory parity"),
-       INFINIPATH_HWE_MSG(IB_UC_MEMORYPARITYERR, "IB uC memory parity"),
-       INFINIPATH_HWE_MSG(PCIE_UC_OCT0MEMORYPARITYERR,
-               "PCIe uC oct0 memory parity"),
-       INFINIPATH_HWE_MSG(PCIE_UC_OCT1MEMORYPARITYERR,
-               "PCIe uC oct1 memory parity"),
-};
-
-static void autoneg_work(struct work_struct *);
-
-/*
- * the offset is different for different configured port numbers, since
- * port0 is fixed in size, but others can vary.   Make it a function to
- * make the issue more obvious.
-*/
-static inline u32 port_egrtid_idx(struct ipath_devdata *dd, unsigned port)
-{
-        return port ? dd->ipath_p0_rcvegrcnt +
-                (port-1) * dd->ipath_rcvegrcnt : 0;
-}
-
-static void ipath_7220_txe_recover(struct ipath_devdata *dd)
-{
-       ++ipath_stats.sps_txeparity;
-
-       dev_info(&dd->pcidev->dev,
-               "Recovering from TXE PIO parity error\n");
-       ipath_disarm_senderrbufs(dd);
-}
-
-
-/**
- * ipath_7220_handle_hwerrors - display hardware errors.
- * @dd: the infinipath device
- * @msg: the output buffer
- * @msgl: the size of the output buffer
- *
- * Use same msg buffer as regular errors to avoid excessive stack
- * use.  Most hardware errors are catastrophic, but for right now,
- * we'll print them and continue.  We reuse the same message buffer as
- * ipath_handle_errors() to avoid excessive stack usage.
- */
-static void ipath_7220_handle_hwerrors(struct ipath_devdata *dd, char *msg,
-                                      size_t msgl)
-{
-       ipath_err_t hwerrs;
-       u32 bits, ctrl;
-       int isfatal = 0;
-       char bitsmsg[64];
-       int log_idx;
-
-       hwerrs = ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwerrstatus);
-       if (!hwerrs) {
-               /*
-                * better than printing cofusing messages
-                * This seems to be related to clearing the crc error, or
-                * the pll error during init.
-                */
-               ipath_cdbg(VERBOSE, "Called but no hardware errors set\n");
-               goto bail;
-       } else if (hwerrs == ~0ULL) {
-               ipath_dev_err(dd, "Read of hardware error status failed "
-                             "(all bits set); ignoring\n");
-               goto bail;
-       }
-       ipath_stats.sps_hwerrs++;
-
-       /*
-        * Always clear the error status register, except MEMBISTFAIL,
-        * regardless of whether we continue or stop using the chip.
-        * We want that set so we know it failed, even across driver reload.
-        * We'll still ignore it in the hwerrmask.  We do this partly for
-        * diagnostics, but also for support.
-        */
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear,
-                        hwerrs&~INFINIPATH_HWE_MEMBISTFAILED);
-
-       hwerrs &= dd->ipath_hwerrmask;
-
-       /* We log some errors to EEPROM, check if we have any of those. */
-       for (log_idx = 0; log_idx < IPATH_EEP_LOG_CNT; ++log_idx)
-               if (hwerrs & dd->ipath_eep_st_masks[log_idx].hwerrs_to_log)
-                       ipath_inc_eeprom_err(dd, log_idx, 1);
-       /*
-        * Make sure we get this much out, unless told to be quiet,
-        * or it's occurred within the last 5 seconds.
-        */
-       if ((hwerrs & ~(dd->ipath_lasthwerror |
-                       ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF |
-                         INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC)
-                        << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT))) ||
-           (ipath_debug & __IPATH_VERBDBG))
-               dev_info(&dd->pcidev->dev, "Hardware error: hwerr=0x%llx "
-                        "(cleared)\n", (unsigned long long) hwerrs);
-       dd->ipath_lasthwerror |= hwerrs;
-
-       if (hwerrs & ~dd->ipath_hwe_bitsextant)
-               ipath_dev_err(dd, "hwerror interrupt with unknown errors "
-                             "%llx set\n", (unsigned long long)
-                             (hwerrs & ~dd->ipath_hwe_bitsextant));
-
-       if (hwerrs & INFINIPATH_HWE_IB_UC_MEMORYPARITYERR)
-               ipath_sd7220_clr_ibpar(dd);
-
-       ctrl = ipath_read_kreg32(dd, dd->ipath_kregs->kr_control);
-       if ((ctrl & INFINIPATH_C_FREEZEMODE) && !ipath_diag_inuse) {
-               /*
-                * Parity errors in send memory are recoverable by h/w
-                * just do housekeeping, exit freeze mode and continue.
-                */
-               if (hwerrs & ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF |
-                              INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC)
-                             << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)) {
-                       ipath_7220_txe_recover(dd);
-                       hwerrs &= ~((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF |
-                                    INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC)
-                                   << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT);
-               }
-               if (hwerrs) {
-                       /*
-                        * If any set that we aren't ignoring only make the
-                        * complaint once, in case it's stuck or recurring,
-                        * and we get here multiple times
-                        * Force link down, so switch knows, and
-                        * LEDs are turned off.
-                        */
-                       if (dd->ipath_flags & IPATH_INITTED) {
-                               ipath_set_linkstate(dd, IPATH_IB_LINKDOWN);
-                               ipath_setup_7220_setextled(dd,
-                                       INFINIPATH_IBCS_L_STATE_DOWN,
-                                       INFINIPATH_IBCS_LT_STATE_DISABLED);
-                               ipath_dev_err(dd, "Fatal Hardware Error "
-                                             "(freeze mode), no longer"
-                                             " usable, SN %.16s\n",
-                                                 dd->ipath_serial);
-                               isfatal = 1;
-                       }
-                       /*
-                        * Mark as having had an error for driver, and also
-                        * for /sys and status word mapped to user programs.
-                        * This marks unit as not usable, until reset.
-                        */
-                       *dd->ipath_statusp &= ~IPATH_STATUS_IB_READY;
-                       *dd->ipath_statusp |= IPATH_STATUS_HWERROR;
-                       dd->ipath_flags &= ~IPATH_INITTED;
-               } else {
-                       ipath_dbg("Clearing freezemode on ignored or "
-                               "recovered hardware error\n");
-                       ipath_clear_freeze(dd);
-               }
-       }
-
-       *msg = '\0';
-
-       if (hwerrs & INFINIPATH_HWE_MEMBISTFAILED) {
-               strlcat(msg, "[Memory BIST test failed, "
-                       "InfiniPath hardware unusable]", msgl);
-               /* ignore from now on, so disable until driver reloaded */
-               *dd->ipath_statusp |= IPATH_STATUS_HWERROR;
-               dd->ipath_hwerrmask &= ~INFINIPATH_HWE_MEMBISTFAILED;
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
-                                dd->ipath_hwerrmask);
-       }
-
-       ipath_format_hwerrors(hwerrs,
-                             ipath_7220_hwerror_msgs,
-                             ARRAY_SIZE(ipath_7220_hwerror_msgs),
-                             msg, msgl);
-
-       if (hwerrs & (INFINIPATH_HWE_PCIEMEMPARITYERR_MASK
-                     << INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT)) {
-               bits = (u32) ((hwerrs >>
-                              INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT) &
-                             INFINIPATH_HWE_PCIEMEMPARITYERR_MASK);
-               snprintf(bitsmsg, sizeof bitsmsg,
-                        "[PCIe Mem Parity Errs %x] ", bits);
-               strlcat(msg, bitsmsg, msgl);
-       }
-
-#define _IPATH_PLL_FAIL (INFINIPATH_HWE_COREPLL_FBSLIP |       \
-                        INFINIPATH_HWE_COREPLL_RFSLIP)
-
-       if (hwerrs & _IPATH_PLL_FAIL) {
-               snprintf(bitsmsg, sizeof bitsmsg,
-                        "[PLL failed (%llx), InfiniPath hardware unusable]",
-                        (unsigned long long) hwerrs & _IPATH_PLL_FAIL);
-               strlcat(msg, bitsmsg, msgl);
-               /* ignore from now on, so disable until driver reloaded */
-               dd->ipath_hwerrmask &= ~(hwerrs & _IPATH_PLL_FAIL);
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
-                                dd->ipath_hwerrmask);
-       }
-
-       if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED) {
-               /*
-                * If it occurs, it is left masked since the eternal
-                * interface is unused.
-                */
-               dd->ipath_hwerrmask &= ~INFINIPATH_HWE_SERDESPLLFAILED;
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
-                                dd->ipath_hwerrmask);
-       }
-
-       ipath_dev_err(dd, "%s hardware error\n", msg);
-       /*
-        * For /sys status file. if no trailing } is copied, we'll
-        * know it was truncated.
-        */
-       if (isfatal && !ipath_diag_inuse && dd->ipath_freezemsg)
-               snprintf(dd->ipath_freezemsg, dd->ipath_freezelen,
-                        "{%s}", msg);
-bail:;
-}
-
-/**
- * ipath_7220_boardname - fill in the board name
- * @dd: the infinipath device
- * @name: the output buffer
- * @namelen: the size of the output buffer
- *
- * info is based on the board revision register
- */
-static int ipath_7220_boardname(struct ipath_devdata *dd, char *name,
-       size_t namelen)
-{
-       char *n = NULL;
-       u8 boardrev = dd->ipath_boardrev;
-       int ret;
-
-       if (boardrev == 15) {
-               /*
-                * Emulator sometimes comes up all-ones, rather than zero.
-                */
-               boardrev = 0;
-               dd->ipath_boardrev = boardrev;
-       }
-       switch (boardrev) {
-       case 0:
-               n = "InfiniPath_7220_Emulation";
-               break;
-       case 1:
-               n = "InfiniPath_QLE7240";
-               break;
-       case 2:
-               n = "InfiniPath_QLE7280";
-               break;
-       case 3:
-               n = "InfiniPath_QLE7242";
-               break;
-       case 4:
-               n = "InfiniPath_QEM7240";
-               break;
-       case 5:
-               n = "InfiniPath_QMI7240";
-               break;
-       case 6:
-               n = "InfiniPath_QMI7264";
-               break;
-       case 7:
-               n = "InfiniPath_QMH7240";
-               break;
-       case 8:
-               n = "InfiniPath_QME7240";
-               break;
-       case 9:
-               n = "InfiniPath_QLE7250";
-               break;
-       case 10:
-               n = "InfiniPath_QLE7290";
-               break;
-       case 11:
-               n = "InfiniPath_QEM7250";
-               break;
-       case 12:
-               n = "InfiniPath_QLE-Bringup";
-               break;
-       default:
-               ipath_dev_err(dd,
-                             "Don't yet know about board with ID %u\n",
-                             boardrev);
-               snprintf(name, namelen, "Unknown_InfiniPath_PCIe_%u",
-                        boardrev);
-               break;
-       }
-       if (n)
-               snprintf(name, namelen, "%s", n);
-
-       if (dd->ipath_majrev != 5 || !dd->ipath_minrev ||
-               dd->ipath_minrev > 2) {
-               ipath_dev_err(dd, "Unsupported InfiniPath hardware "
-                             "revision %u.%u!\n",
-                             dd->ipath_majrev, dd->ipath_minrev);
-               ret = 1;
-       } else if (dd->ipath_minrev == 1 &&
-               !(dd->ipath_flags & IPATH_INITTED)) {
-               /* Rev1 chips are prototype. Complain at init, but allow use */
-               ipath_dev_err(dd, "Unsupported hardware "
-                             "revision %u.%u, Contact support@qlogic.com\n",
-                             dd->ipath_majrev, dd->ipath_minrev);
-               ret = 0;
-       } else
-               ret = 0;
-
-       /*
-        * Set here not in ipath_init_*_funcs because we have to do
-        * it after we can read chip registers.
-        */
-       dd->ipath_ureg_align = 0x10000;  /* 64KB alignment */
-
-       return ret;
-}
-
-/**
- * ipath_7220_init_hwerrors - enable hardware errors
- * @dd: the infinipath device
- *
- * now that we have finished initializing everything that might reasonably
- * cause a hardware error, and cleared those errors bits as they occur,
- * we can enable hardware errors in the mask (potentially enabling
- * freeze mode), and enable hardware errors as errors (along with
- * everything else) in errormask
- */
-static void ipath_7220_init_hwerrors(struct ipath_devdata *dd)
-{
-       ipath_err_t val;
-       u64 extsval;
-
-       extsval = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extstatus);
-
-       if (!(extsval & (INFINIPATH_EXTS_MEMBIST_ENDTEST |
-                       INFINIPATH_EXTS_MEMBIST_DISABLED)))
-               ipath_dev_err(dd, "MemBIST did not complete!\n");
-       if (extsval & INFINIPATH_EXTS_MEMBIST_DISABLED)
-               dev_info(&dd->pcidev->dev, "MemBIST is disabled.\n");
-
-       val = ~0ULL;    /* barring bugs, all hwerrors become interrupts, */
-
-       if (!dd->ipath_boardrev)        /* no PLL for Emulator */
-               val &= ~INFINIPATH_HWE_SERDESPLLFAILED;
-
-       if (dd->ipath_minrev == 1)
-               val &= ~(1ULL << 42); /* TXE LaunchFIFO Parity rev1 issue */
-
-       val &= ~INFINIPATH_HWE_IB_UC_MEMORYPARITYERR;
-       dd->ipath_hwerrmask = val;
-
-       /*
-        * special trigger "error" is for debugging purposes. It
-        * works around a processor/chipset problem.  The error
-        * interrupt allows us to count occurrences, but we don't
-        * want to pay the overhead for normal use.  Emulation only
-        */
-       if (!dd->ipath_boardrev)
-               dd->ipath_maskederrs = INFINIPATH_E_SENDSPECIALTRIGGER;
-}
-
-/*
- * All detailed interaction with the SerDes has been moved to ipath_sd7220.c
- *
- * The portion of IBA7220-specific bringup_serdes() that actually deals with
- * registers and memory within the SerDes itself is ipath_sd7220_init().
- */
-
-/**
- * ipath_7220_bringup_serdes - bring up the serdes
- * @dd: the infinipath device
- */
-static int ipath_7220_bringup_serdes(struct ipath_devdata *dd)
-{
-       int ret = 0;
-       u64 val, prev_val, guid;
-       int was_reset;          /* Note whether uC was reset */
-
-       ipath_dbg("Trying to bringup serdes\n");
-
-       if (ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwerrstatus) &
-           INFINIPATH_HWE_SERDESPLLFAILED) {
-               ipath_dbg("At start, serdes PLL failed bit set "
-                         "in hwerrstatus, clearing and continuing\n");
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear,
-                                INFINIPATH_HWE_SERDESPLLFAILED);
-       }
-
-       dd->ibdeltainprog = 1;
-       dd->ibsymsnap =
-            ipath_read_creg32(dd, dd->ipath_cregs->cr_ibsymbolerrcnt);
-       dd->iblnkerrsnap =
-            ipath_read_creg32(dd, dd->ipath_cregs->cr_iblinkerrrecovcnt);
-
-       if (!dd->ipath_ibcddrctrl) {
-               /* not on re-init after reset */
-               dd->ipath_ibcddrctrl =
-                       ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibcddrctrl);
-
-               if (dd->ipath_link_speed_enabled ==
-                       (IPATH_IB_SDR | IPATH_IB_DDR))
-                       dd->ipath_ibcddrctrl |=
-                               IBA7220_IBC_SPEED_AUTONEG_MASK |
-                               IBA7220_IBC_IBTA_1_2_MASK;
-               else
-                       dd->ipath_ibcddrctrl |=
-                               dd->ipath_link_speed_enabled == IPATH_IB_DDR
-                               ?  IBA7220_IBC_SPEED_DDR :
-                               IBA7220_IBC_SPEED_SDR;
-               if ((dd->ipath_link_width_enabled & (IB_WIDTH_1X |
-                       IB_WIDTH_4X)) == (IB_WIDTH_1X | IB_WIDTH_4X))
-                       dd->ipath_ibcddrctrl |= IBA7220_IBC_WIDTH_AUTONEG;
-               else
-                       dd->ipath_ibcddrctrl |=
-                               dd->ipath_link_width_enabled == IB_WIDTH_4X
-                               ? IBA7220_IBC_WIDTH_4X_ONLY :
-                               IBA7220_IBC_WIDTH_1X_ONLY;
-
-               /* always enable these on driver reload, not sticky */
-               dd->ipath_ibcddrctrl |=
-                       IBA7220_IBC_RXPOL_MASK << IBA7220_IBC_RXPOL_SHIFT;
-               dd->ipath_ibcddrctrl |=
-                       IBA7220_IBC_HRTBT_MASK << IBA7220_IBC_HRTBT_SHIFT;
-               /*
-                * automatic lane reversal detection for receive
-                * doesn't work correctly in rev 1, so disable it
-                * on that rev, otherwise enable (disabling not
-                * sticky across reload for >rev1)
-                */
-               if (dd->ipath_minrev == 1)
-                       dd->ipath_ibcddrctrl &=
-                       ~IBA7220_IBC_LANE_REV_SUPPORTED;
-               else
-                       dd->ipath_ibcddrctrl |=
-                               IBA7220_IBC_LANE_REV_SUPPORTED;
-       }
-
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcddrctrl,
-                       dd->ipath_ibcddrctrl);
-
-       ipath_write_kreg(dd, IPATH_KREG_OFFSET(IBNCModeCtrl), 0Ull);
-
-       /* IBA7220 has SERDES MPU reset in D0 of what _was_ IBPLLCfg */
-       val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibserdesctrl);
-       /* remember if uC was in Reset or not, for dactrim */
-       was_reset = (val & 1);
-       ipath_cdbg(VERBOSE, "IBReset %s xgxsconfig %llx\n",
-                  was_reset ? "Asserted" : "Negated", (unsigned long long)
-                  ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig));
-
-       if (dd->ipath_boardrev) {
-               /*
-                * Hardware is not emulator, and may have been reset. Init it.
-                * Below will release reset, but needs to know if chip was
-                * originally in reset, to only trim DACs on first time
-                * after chip reset or powercycle (not driver reload)
-                */
-               ret = ipath_sd7220_init(dd, was_reset);
-       }
-
-       val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
-       prev_val = val;
-       val |= INFINIPATH_XGXS_FC_SAFE;
-       if (val != prev_val) {
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val);
-               ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
-       }
-       if (val & INFINIPATH_XGXS_RESET)
-               val &= ~INFINIPATH_XGXS_RESET;
-       if (val != prev_val)
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val);
-
-       ipath_cdbg(VERBOSE, "done: xgxs=%llx from %llx\n",
-                  (unsigned long long)
-                  ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig),
-                  (unsigned long long) prev_val);
-
-       guid = be64_to_cpu(dd->ipath_guid);
-
-       if (!guid) {
-               /* have to have something, so use likely unique tsc */
-               guid = get_cycles();
-               ipath_dbg("No GUID for heartbeat, faking %llx\n",
-                       (unsigned long long)guid);
-       } else
-               ipath_cdbg(VERBOSE, "Wrote %llX to HRTBT_GUID\n",
-                       (unsigned long long) guid);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_hrtbt_guid, guid);
-       return ret;
-}
-
-static void ipath_7220_config_jint(struct ipath_devdata *dd,
-                                  u16 idle_ticks, u16 max_packets)
-{
-
-       /*
-        * We can request a receive interrupt for 1 or more packets
-        * from current offset.
-        */
-       if (idle_ticks == 0 || max_packets == 0)
-               /* interrupt after one packet if no mitigation */
-               dd->ipath_rhdrhead_intr_off =
-                       1ULL << IBA7220_HDRHEAD_PKTINT_SHIFT;
-       else
-               /* Turn off RcvHdrHead interrupts if using mitigation */
-               dd->ipath_rhdrhead_intr_off = 0ULL;
-
-       /* refresh kernel RcvHdrHead registers... */
-       ipath_write_ureg(dd, ur_rcvhdrhead,
-                        dd->ipath_rhdrhead_intr_off |
-                        dd->ipath_pd[0]->port_head, 0);
-
-       dd->ipath_jint_max_packets = max_packets;
-       dd->ipath_jint_idle_ticks = idle_ticks;
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_jintreload,
-                        ((u64) max_packets << INFINIPATH_JINT_PACKETSHIFT) |
-                        idle_ticks);
-}
-
-/**
- * ipath_7220_quiet_serdes - set serdes to txidle
- * @dd: the infinipath device
- * Called when driver is being unloaded
- */
-static void ipath_7220_quiet_serdes(struct ipath_devdata *dd)
-{
-       u64 val;
-       if (dd->ibsymdelta || dd->iblnkerrdelta ||
-           dd->ibdeltainprog) {
-               u64 diagc;
-               /* enable counter writes */
-               diagc = ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwdiagctrl);
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_hwdiagctrl,
-                                diagc | INFINIPATH_DC_COUNTERWREN);
-
-               if (dd->ibsymdelta || dd->ibdeltainprog) {
-                       val = ipath_read_creg32(dd,
-                                       dd->ipath_cregs->cr_ibsymbolerrcnt);
-                       if (dd->ibdeltainprog)
-                               val -= val - dd->ibsymsnap;
-                       val -= dd->ibsymdelta;
-                       ipath_write_creg(dd,
-                                 dd->ipath_cregs->cr_ibsymbolerrcnt, val);
-               }
-               if (dd->iblnkerrdelta || dd->ibdeltainprog) {
-                       val = ipath_read_creg32(dd,
-                                       dd->ipath_cregs->cr_iblinkerrrecovcnt);
-                       if (dd->ibdeltainprog)
-                               val -= val - dd->iblnkerrsnap;
-                       val -= dd->iblnkerrdelta;
-                       ipath_write_creg(dd,
-                                  dd->ipath_cregs->cr_iblinkerrrecovcnt, val);
-            }
-
-            /* and disable counter writes */
-            ipath_write_kreg(dd, dd->ipath_kregs->kr_hwdiagctrl, diagc);
-       }
-
-       dd->ipath_flags &= ~IPATH_IB_AUTONEG_INPROG;
-       wake_up(&dd->ipath_autoneg_wait);
-       cancel_delayed_work(&dd->ipath_autoneg_work);
-       flush_scheduled_work();
-       ipath_shutdown_relock_poll(dd);
-       val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
-       val |= INFINIPATH_XGXS_RESET;
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val);
-}
-
-static int ipath_7220_intconfig(struct ipath_devdata *dd)
-{
-       ipath_7220_config_jint(dd, dd->ipath_jint_idle_ticks,
-                              dd->ipath_jint_max_packets);
-       return 0;
-}
-
-/**
- * ipath_setup_7220_setextled - set the state of the two external LEDs
- * @dd: the infinipath device
- * @lst: the L state
- * @ltst: the LT state
- *
- * These LEDs indicate the physical and logical state of IB link.
- * For this chip (at least with recommended board pinouts), LED1
- * is Yellow (logical state) and LED2 is Green (physical state),
- *
- * Note:  We try to match the Mellanox HCA LED behavior as best
- * we can.  Green indicates physical link state is OK (something is
- * plugged in, and we can train).
- * Amber indicates the link is logically up (ACTIVE).
- * Mellanox further blinks the amber LED to indicate data packet
- * activity, but we have no hardware support for that, so it would
- * require waking up every 10-20 msecs and checking the counters
- * on the chip, and then turning the LED off if appropriate.  That's
- * visible overhead, so not something we will do.
- *
- */
-static void ipath_setup_7220_setextled(struct ipath_devdata *dd, u64 lst,
-                                      u64 ltst)
-{
-       u64 extctl, ledblink = 0;
-       unsigned long flags = 0;
-
-       /* the diags use the LED to indicate diag info, so we leave
-        * the external LED alone when the diags are running */
-       if (ipath_diag_inuse)
-               return;
-
-       /* Allow override of LED display for, e.g. Locating system in rack */
-       if (dd->ipath_led_override) {
-               ltst = (dd->ipath_led_override & IPATH_LED_PHYS)
-                       ? INFINIPATH_IBCS_LT_STATE_LINKUP
-                       : INFINIPATH_IBCS_LT_STATE_DISABLED;
-               lst = (dd->ipath_led_override & IPATH_LED_LOG)
-                       ? INFINIPATH_IBCS_L_STATE_ACTIVE
-                       : INFINIPATH_IBCS_L_STATE_DOWN;
-       }
-
-       spin_lock_irqsave(&dd->ipath_gpio_lock, flags);
-       extctl = dd->ipath_extctrl & ~(INFINIPATH_EXTC_LED1PRIPORT_ON |
-                                      INFINIPATH_EXTC_LED2PRIPORT_ON);
-       if (ltst == INFINIPATH_IBCS_LT_STATE_LINKUP) {
-               extctl |= INFINIPATH_EXTC_LED1PRIPORT_ON;
-               /*
-                * counts are in chip clock (4ns) periods.
-                * This is 1/16 sec (66.6ms) on,
-                * 3/16 sec (187.5 ms) off, with packets rcvd
-                */
-               ledblink = ((66600*1000UL/4) << IBA7220_LEDBLINK_ON_SHIFT)
-                       | ((187500*1000UL/4) << IBA7220_LEDBLINK_OFF_SHIFT);
-       }
-       if (lst == INFINIPATH_IBCS_L_STATE_ACTIVE)
-               extctl |= INFINIPATH_EXTC_LED2PRIPORT_ON;
-       dd->ipath_extctrl = extctl;
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, extctl);
-       spin_unlock_irqrestore(&dd->ipath_gpio_lock, flags);
-
-       if (ledblink) /* blink the LED on packet receive */
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvpktledcnt,
-                       ledblink);
-}
-
-/*
- * Similar to pci_intx(pdev, 1), except that we make sure
- * msi is off...
- */
-static void ipath_enable_intx(struct pci_dev *pdev)
-{
-       u16 cw, new;
-       int pos;
-
-       /* first, turn on INTx */
-       pci_read_config_word(pdev, PCI_COMMAND, &cw);
-       new = cw & ~PCI_COMMAND_INTX_DISABLE;
-       if (new != cw)
-               pci_write_config_word(pdev, PCI_COMMAND, new);
-
-       /* then turn off MSI */
-       pos = pci_find_capability(pdev, PCI_CAP_ID_MSI);
-       if (pos) {
-               pci_read_config_word(pdev, pos + PCI_MSI_FLAGS, &cw);
-               new = cw & ~PCI_MSI_FLAGS_ENABLE;
-               if (new != cw)
-                       pci_write_config_word(pdev, pos + PCI_MSI_FLAGS, new);
-       }
-}
-
-static int ipath_msi_enabled(struct pci_dev *pdev)
-{
-       int pos, ret = 0;
-
-       pos = pci_find_capability(pdev, PCI_CAP_ID_MSI);
-       if (pos) {
-               u16 cw;
-
-               pci_read_config_word(pdev, pos + PCI_MSI_FLAGS, &cw);
-               ret = !!(cw & PCI_MSI_FLAGS_ENABLE);
-       }
-       return ret;
-}
-
-/*
- * disable msi interrupt if enabled, and clear the flag.
- * flag is used primarily for the fallback to INTx, but
- * is also used in reinit after reset as a flag.
- */
-static void ipath_7220_nomsi(struct ipath_devdata *dd)
-{
-       dd->ipath_msi_lo = 0;
-
-       if (ipath_msi_enabled(dd->pcidev)) {
-               /*
-                * free, but don't zero; later kernels require
-                * it be freed before disable_msi, so the intx
-                * setup has to request it again.
-                */
-                if (dd->ipath_irq)
-                       free_irq(dd->ipath_irq, dd);
-               pci_disable_msi(dd->pcidev);
-       }
-}
-
-/*
- * ipath_setup_7220_cleanup - clean up any per-chip chip-specific stuff
- * @dd: the infinipath device
- *
- * Nothing but msi interrupt cleanup for now.
- *
- * This is called during driver unload.
- */
-static void ipath_setup_7220_cleanup(struct ipath_devdata *dd)
-{
-       ipath_7220_nomsi(dd);
-}
-
-
-static void ipath_7220_pcie_params(struct ipath_devdata *dd, u32 boardrev)
-{
-       u16 linkstat, minwidth, speed;
-       int pos;
-
-       pos = pci_find_capability(dd->pcidev, PCI_CAP_ID_EXP);
-       if (!pos) {
-               ipath_dev_err(dd, "Can't find PCI Express capability!\n");
-               goto bail;
-       }
-
-       pci_read_config_word(dd->pcidev, pos + PCI_EXP_LNKSTA,
-                            &linkstat);
-       /*
-        * speed is bits 0-4, linkwidth is bits 4-8
-        * no defines for them in headers
-        */
-       speed = linkstat & 0xf;
-       linkstat >>= 4;
-       linkstat &= 0x1f;
-       dd->ipath_lbus_width = linkstat;
-       switch (boardrev) {
-       case 0:
-       case 2:
-       case 10:
-       case 12:
-               minwidth = 16; /* x16 capable boards */
-               break;
-       default:
-               minwidth = 8; /* x8 capable boards */
-               break;
-       }
-
-       switch (speed) {
-       case 1:
-               dd->ipath_lbus_speed = 2500; /* Gen1, 2.5GHz */
-               break;
-       case 2:
-               dd->ipath_lbus_speed = 5000; /* Gen1, 5GHz */
-               break;
-       default: /* not defined, assume gen1 */
-               dd->ipath_lbus_speed = 2500;
-               break;
-       }
-
-       if (linkstat < minwidth)
-               ipath_dev_err(dd,
-                       "PCIe width %u (x%u HCA), performance "
-                       "reduced\n", linkstat, minwidth);
-       else
-               ipath_cdbg(VERBOSE, "PCIe speed %u width %u (x%u HCA)\n",
-                       dd->ipath_lbus_speed, linkstat, minwidth);
-
-       if (speed != 1)
-               ipath_dev_err(dd,
-                       "PCIe linkspeed %u is incorrect; "
-                       "should be 1 (2500)!\n", speed);
-
-bail:
-       /* fill in string, even on errors */
-       snprintf(dd->ipath_lbus_info, sizeof(dd->ipath_lbus_info),
-               "PCIe,%uMHz,x%u\n",
-               dd->ipath_lbus_speed,
-               dd->ipath_lbus_width);
-       return;
-}
-
-
-/**
- * ipath_setup_7220_config - setup PCIe config related stuff
- * @dd: the infinipath device
- * @pdev: the PCI device
- *
- * The pci_enable_msi() call will fail on systems with MSI quirks
- * such as those with AMD8131, even if the device of interest is not
- * attached to that device, (in the 2.6.13 - 2.6.15 kernels, at least, fixed
- * late in 2.6.16).
- * All that can be done is to edit the kernel source to remove the quirk
- * check until that is fixed.
- * We do not need to call enable_msi() for our HyperTransport chip,
- * even though it uses MSI, and we want to avoid the quirk warning, so
- * So we call enable_msi only for PCIe.  If we do end up needing
- * pci_enable_msi at some point in the future for HT, we'll move the
- * call back into the main init_one code.
- * We save the msi lo and hi values, so we can restore them after
- * chip reset (the kernel PCI infrastructure doesn't yet handle that
- * correctly).
- */
-static int ipath_setup_7220_config(struct ipath_devdata *dd,
-                                  struct pci_dev *pdev)
-{
-       int pos, ret = -1;
-       u32 boardrev;
-
-       dd->ipath_msi_lo = 0;   /* used as a flag during reset processing */
-
-       pos = pci_find_capability(pdev, PCI_CAP_ID_MSI);
-       if (!strcmp(int_type, "force_msi") || !strcmp(int_type, "auto"))
-               ret = pci_enable_msi(pdev);
-       if (ret) {
-               if (!strcmp(int_type, "force_msi")) {
-                       ipath_dev_err(dd, "pci_enable_msi failed: %d, "
-                                     "force_msi is on, so not continuing.\n",
-                                     ret);
-                       return ret;
-               }
-
-               ipath_enable_intx(pdev);
-               if (!strcmp(int_type, "auto"))
-                       ipath_dev_err(dd, "pci_enable_msi failed: %d, "
-                                     "falling back to INTx\n", ret);
-       } else if (pos) {
-               u16 control;
-               pci_read_config_dword(pdev, pos + PCI_MSI_ADDRESS_LO,
-                                     &dd->ipath_msi_lo);
-               pci_read_config_dword(pdev, pos + PCI_MSI_ADDRESS_HI,
-                                     &dd->ipath_msi_hi);
-               pci_read_config_word(pdev, pos + PCI_MSI_FLAGS,
-                                    &control);
-               /* now save the data (vector) info */
-               pci_read_config_word(pdev,
-                                    pos + ((control & PCI_MSI_FLAGS_64BIT)
-                                           ? PCI_MSI_DATA_64 :
-                                           PCI_MSI_DATA_32),
-                                    &dd->ipath_msi_data);
-       } else
-               ipath_dev_err(dd, "Can't find MSI capability, "
-                             "can't save MSI settings for reset\n");
-
-       dd->ipath_irq = pdev->irq;
-
-       /*
-        * We save the cachelinesize also, although it doesn't
-        * really matter.
-        */
-       pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE,
-                            &dd->ipath_pci_cacheline);
-
-       /*
-        * this function called early, ipath_boardrev not set yet.  Can't
-        * use ipath_read_kreg64() yet, too early in init, so use readq()
-        */
-       boardrev = (readq(&dd->ipath_kregbase[dd->ipath_kregs->kr_revision])
-                >> INFINIPATH_R_BOARDID_SHIFT) & INFINIPATH_R_BOARDID_MASK;
-
-       ipath_7220_pcie_params(dd, boardrev);
-
-       dd->ipath_flags |= IPATH_NODMA_RTAIL | IPATH_HAS_SEND_DMA |
-               IPATH_HAS_PBC_CNT | IPATH_HAS_THRESH_UPDATE;
-       dd->ipath_pioupd_thresh = 4U; /* set default update threshold */
-       return 0;
-}
-
-static void ipath_init_7220_variables(struct ipath_devdata *dd)
-{
-       /*
-        * setup the register offsets, since they are different for each
-        * chip
-        */
-       dd->ipath_kregs = &ipath_7220_kregs;
-       dd->ipath_cregs = &ipath_7220_cregs;
-
-       /*
-        * bits for selecting i2c direction and values,
-        * used for I2C serial flash
-        */
-       dd->ipath_gpio_sda_num = _IPATH_GPIO_SDA_NUM;
-       dd->ipath_gpio_scl_num = _IPATH_GPIO_SCL_NUM;
-       dd->ipath_gpio_sda = IPATH_GPIO_SDA;
-       dd->ipath_gpio_scl = IPATH_GPIO_SCL;
-
-       /*
-        * Fill in data for field-values that change in IBA7220.
-        * We dynamically specify only the mask for LINKTRAININGSTATE
-        * and only the shift for LINKSTATE, as they are the only ones
-        * that change.  Also precalculate the 3 link states of interest
-        * and the combined mask.
-        */
-       dd->ibcs_ls_shift = IBA7220_IBCS_LINKSTATE_SHIFT;
-       dd->ibcs_lts_mask = IBA7220_IBCS_LINKTRAININGSTATE_MASK;
-       dd->ibcs_mask = (INFINIPATH_IBCS_LINKSTATE_MASK <<
-               dd->ibcs_ls_shift) | dd->ibcs_lts_mask;
-       dd->ib_init = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
-               INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
-               (INFINIPATH_IBCS_L_STATE_INIT << dd->ibcs_ls_shift);
-       dd->ib_arm = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
-               INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
-               (INFINIPATH_IBCS_L_STATE_ARM << dd->ibcs_ls_shift);
-       dd->ib_active = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
-               INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
-               (INFINIPATH_IBCS_L_STATE_ACTIVE << dd->ibcs_ls_shift);
-
-       /*
-        * Fill in data for ibcc field-values that change in IBA7220.
-        * We dynamically specify only the mask for LINKINITCMD
-        * and only the shift for LINKCMD and MAXPKTLEN, as they are
-        * the only ones that change.
-        */
-       dd->ibcc_lic_mask = IBA7220_IBCC_LINKINITCMD_MASK;
-       dd->ibcc_lc_shift = IBA7220_IBCC_LINKCMD_SHIFT;
-       dd->ibcc_mpl_shift = IBA7220_IBCC_MAXPKTLEN_SHIFT;
-
-       /* Fill in shifts for RcvCtrl. */
-       dd->ipath_r_portenable_shift = INFINIPATH_R_PORTENABLE_SHIFT;
-       dd->ipath_r_intravail_shift = IBA7220_R_INTRAVAIL_SHIFT;
-       dd->ipath_r_tailupd_shift = IBA7220_R_TAILUPD_SHIFT;
-       dd->ipath_r_portcfg_shift = IBA7220_R_PORTCFG_SHIFT;
-
-       /* variables for sanity checking interrupt and errors */
-       dd->ipath_hwe_bitsextant =
-               (INFINIPATH_HWE_RXEMEMPARITYERR_MASK <<
-                INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) |
-               (INFINIPATH_HWE_TXEMEMPARITYERR_MASK <<
-                INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) |
-               (INFINIPATH_HWE_PCIEMEMPARITYERR_MASK <<
-                INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT) |
-               INFINIPATH_HWE_PCIE1PLLFAILED |
-               INFINIPATH_HWE_PCIE0PLLFAILED |
-               INFINIPATH_HWE_PCIEPOISONEDTLP |
-               INFINIPATH_HWE_PCIECPLTIMEOUT |
-               INFINIPATH_HWE_PCIEBUSPARITYXTLH |
-               INFINIPATH_HWE_PCIEBUSPARITYXADM |
-               INFINIPATH_HWE_PCIEBUSPARITYRADM |
-               INFINIPATH_HWE_MEMBISTFAILED |
-               INFINIPATH_HWE_COREPLL_FBSLIP |
-               INFINIPATH_HWE_COREPLL_RFSLIP |
-               INFINIPATH_HWE_SERDESPLLFAILED |
-               INFINIPATH_HWE_IBCBUSTOSPCPARITYERR |
-               INFINIPATH_HWE_IBCBUSFRSPCPARITYERR |
-               INFINIPATH_HWE_PCIECPLDATAQUEUEERR |
-               INFINIPATH_HWE_PCIECPLHDRQUEUEERR |
-               INFINIPATH_HWE_SDMAMEMREADERR |
-               INFINIPATH_HWE_CLK_UC_PLLNOTLOCKED |
-               INFINIPATH_HWE_PCIESERDESQ0PCLKNOTDETECT |
-               INFINIPATH_HWE_PCIESERDESQ1PCLKNOTDETECT |
-               INFINIPATH_HWE_PCIESERDESQ2PCLKNOTDETECT |
-               INFINIPATH_HWE_PCIESERDESQ3PCLKNOTDETECT |
-               INFINIPATH_HWE_DDSRXEQMEMORYPARITYERR |
-               INFINIPATH_HWE_IB_UC_MEMORYPARITYERR |
-               INFINIPATH_HWE_PCIE_UC_OCT0MEMORYPARITYERR |
-               INFINIPATH_HWE_PCIE_UC_OCT1MEMORYPARITYERR;
-       dd->ipath_i_bitsextant =
-               INFINIPATH_I_SDMAINT | INFINIPATH_I_SDMADISABLED |
-               (INFINIPATH_I_RCVURG_MASK << INFINIPATH_I_RCVURG_SHIFT) |
-               (INFINIPATH_I_RCVAVAIL_MASK <<
-                INFINIPATH_I_RCVAVAIL_SHIFT) |
-               INFINIPATH_I_ERROR | INFINIPATH_I_SPIOSENT |
-               INFINIPATH_I_SPIOBUFAVAIL | INFINIPATH_I_GPIO |
-               INFINIPATH_I_JINT | INFINIPATH_I_SERDESTRIMDONE;
-       dd->ipath_e_bitsextant =
-               INFINIPATH_E_RFORMATERR | INFINIPATH_E_RVCRC |
-               INFINIPATH_E_RICRC | INFINIPATH_E_RMINPKTLEN |
-               INFINIPATH_E_RMAXPKTLEN | INFINIPATH_E_RLONGPKTLEN |
-               INFINIPATH_E_RSHORTPKTLEN | INFINIPATH_E_RUNEXPCHAR |
-               INFINIPATH_E_RUNSUPVL | INFINIPATH_E_REBP |
-               INFINIPATH_E_RIBFLOW | INFINIPATH_E_RBADVERSION |
-               INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL |
-               INFINIPATH_E_RBADTID | INFINIPATH_E_RHDRLEN |
-               INFINIPATH_E_RHDR | INFINIPATH_E_RIBLOSTLINK |
-               INFINIPATH_E_SENDSPECIALTRIGGER |
-               INFINIPATH_E_SDMADISABLED | INFINIPATH_E_SMINPKTLEN |
-               INFINIPATH_E_SMAXPKTLEN | INFINIPATH_E_SUNDERRUN |
-               INFINIPATH_E_SPKTLEN | INFINIPATH_E_SDROPPEDSMPPKT |
-               INFINIPATH_E_SDROPPEDDATAPKT |
-               INFINIPATH_E_SPIOARMLAUNCH | INFINIPATH_E_SUNEXPERRPKTNUM |
-               INFINIPATH_E_SUNSUPVL | INFINIPATH_E_SENDBUFMISUSE |
-               INFINIPATH_E_SDMAGENMISMATCH | INFINIPATH_E_SDMAOUTOFBOUND |
-               INFINIPATH_E_SDMATAILOUTOFBOUND | INFINIPATH_E_SDMABASE |
-               INFINIPATH_E_SDMA1STDESC | INFINIPATH_E_SDMARPYTAG |
-               INFINIPATH_E_SDMADWEN | INFINIPATH_E_SDMAMISSINGDW |
-               INFINIPATH_E_SDMAUNEXPDATA |
-               INFINIPATH_E_IBSTATUSCHANGED | INFINIPATH_E_INVALIDADDR |
-               INFINIPATH_E_RESET | INFINIPATH_E_HARDWARE |
-               INFINIPATH_E_SDMADESCADDRMISALIGN |
-               INFINIPATH_E_INVALIDEEPCMD;
-
-       dd->ipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;
-       dd->ipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;
-       dd->ipath_i_rcvavail_shift = INFINIPATH_I_RCVAVAIL_SHIFT;
-       dd->ipath_i_rcvurg_shift = INFINIPATH_I_RCVURG_SHIFT;
-       dd->ipath_flags |= IPATH_INTREG_64 | IPATH_HAS_MULT_IB_SPEED
-               | IPATH_HAS_LINK_LATENCY;
-
-       /*
-        * EEPROM error log 0 is TXE Parity errors. 1 is RXE Parity.
-        * 2 is Some Misc, 3 is reserved for future.
-        */
-       dd->ipath_eep_st_masks[0].hwerrs_to_log =
-               INFINIPATH_HWE_TXEMEMPARITYERR_MASK <<
-               INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT;
-
-       dd->ipath_eep_st_masks[1].hwerrs_to_log =
-               INFINIPATH_HWE_RXEMEMPARITYERR_MASK <<
-               INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT;
-
-       dd->ipath_eep_st_masks[2].errs_to_log = INFINIPATH_E_RESET;
-
-       ipath_linkrecovery = 0;
-
-       init_waitqueue_head(&dd->ipath_autoneg_wait);
-       INIT_DELAYED_WORK(&dd->ipath_autoneg_work,  autoneg_work);
-
-       dd->ipath_link_width_supported = IB_WIDTH_1X | IB_WIDTH_4X;
-       dd->ipath_link_speed_supported = IPATH_IB_SDR | IPATH_IB_DDR;
-
-       dd->ipath_link_width_enabled = dd->ipath_link_width_supported;
-       dd->ipath_link_speed_enabled = dd->ipath_link_speed_supported;
-       /*
-        * set the initial values to reasonable default, will be set
-        * for real when link is up.
-        */
-       dd->ipath_link_width_active = IB_WIDTH_4X;
-       dd->ipath_link_speed_active = IPATH_IB_SDR;
-       dd->delay_mult = rate_to_delay[0][1];
-}
-
-
-/*
- * Setup the MSI stuff again after a reset.  I'd like to just call
- * pci_enable_msi() and request_irq() again, but when I do that,
- * the MSI enable bit doesn't get set in the command word, and
- * we switch to to a different interrupt vector, which is confusing,
- * so I instead just do it all inline.  Perhaps somehow can tie this
- * into the PCIe hotplug support at some point
- * Note, because I'm doing it all here, I don't call pci_disable_msi()
- * or free_irq() at the start of ipath_setup_7220_reset().
- */
-static int ipath_reinit_msi(struct ipath_devdata *dd)
-{
-       int ret = 0;
-
-       int pos;
-       u16 control;
-       if (!dd->ipath_msi_lo) /* Using intX, or init problem */
-               goto bail;
-
-       pos = pci_find_capability(dd->pcidev, PCI_CAP_ID_MSI);
-       if (!pos) {
-               ipath_dev_err(dd, "Can't find MSI capability, "
-                             "can't restore MSI settings\n");
-               goto bail;
-       }
-       ipath_cdbg(VERBOSE, "Writing msi_lo 0x%x to config offset 0x%x\n",
-                  dd->ipath_msi_lo, pos + PCI_MSI_ADDRESS_LO);
-       pci_write_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_LO,
-                              dd->ipath_msi_lo);
-       ipath_cdbg(VERBOSE, "Writing msi_lo 0x%x to config offset 0x%x\n",
-                  dd->ipath_msi_hi, pos + PCI_MSI_ADDRESS_HI);
-       pci_write_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_HI,
-                              dd->ipath_msi_hi);
-       pci_read_config_word(dd->pcidev, pos + PCI_MSI_FLAGS, &control);
-       if (!(control & PCI_MSI_FLAGS_ENABLE)) {
-               ipath_cdbg(VERBOSE, "MSI control at off %x was %x, "
-                          "setting MSI enable (%x)\n", pos + PCI_MSI_FLAGS,
-                          control, control | PCI_MSI_FLAGS_ENABLE);
-               control |= PCI_MSI_FLAGS_ENABLE;
-               pci_write_config_word(dd->pcidev, pos + PCI_MSI_FLAGS,
-                                     control);
-       }
-       /* now rewrite the data (vector) info */
-       pci_write_config_word(dd->pcidev, pos +
-                             ((control & PCI_MSI_FLAGS_64BIT) ? 12 : 8),
-                             dd->ipath_msi_data);
-       ret = 1;
-
-bail:
-       if (!ret) {
-               ipath_dbg("Using INTx, MSI disabled or not configured\n");
-               ipath_enable_intx(dd->pcidev);
-               ret = 1;
-       }
-       /*
-        * We restore the cachelinesize also, although it doesn't really
-        * matter.
-        */
-       pci_write_config_byte(dd->pcidev, PCI_CACHE_LINE_SIZE,
-                             dd->ipath_pci_cacheline);
-       /* and now set the pci master bit again */
-       pci_set_master(dd->pcidev);
-
-       return ret;
-}
-
-/*
- * This routine sleeps, so it can only be called from user context, not
- * from interrupt context.  If we need interrupt context, we can split
- * it into two routines.
- */
-static int ipath_setup_7220_reset(struct ipath_devdata *dd)
-{
-       u64 val;
-       int i;
-       int ret;
-       u16 cmdval;
-
-       pci_read_config_word(dd->pcidev, PCI_COMMAND, &cmdval);
-
-       /* Use dev_err so it shows up in logs, etc. */
-       ipath_dev_err(dd, "Resetting InfiniPath unit %u\n", dd->ipath_unit);
-
-       /* keep chip from being accessed in a few places */
-       dd->ipath_flags &= ~(IPATH_INITTED | IPATH_PRESENT);
-       val = dd->ipath_control | INFINIPATH_C_RESET;
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_control, val);
-       mb();
-
-       for (i = 1; i <= 5; i++) {
-               int r;
-
-               /*
-                * Allow MBIST, etc. to complete; longer on each retry.
-                * We sometimes get machine checks from bus timeout if no
-                * response, so for now, make it *really* long.
-                */
-               msleep(1000 + (1 + i) * 2000);
-               r = pci_write_config_dword(dd->pcidev, PCI_BASE_ADDRESS_0,
-                                          dd->ipath_pcibar0);
-               if (r)
-                       ipath_dev_err(dd, "rewrite of BAR0 failed: %d\n", r);
-               r = pci_write_config_dword(dd->pcidev, PCI_BASE_ADDRESS_1,
-                                          dd->ipath_pcibar1);
-               if (r)
-                       ipath_dev_err(dd, "rewrite of BAR1 failed: %d\n", r);
-               /* now re-enable memory access */
-               pci_write_config_word(dd->pcidev, PCI_COMMAND, cmdval);
-               r = pci_enable_device(dd->pcidev);
-               if (r)
-                       ipath_dev_err(dd, "pci_enable_device failed after "
-                                     "reset: %d\n", r);
-               /*
-                * whether it fully enabled or not, mark as present,
-                * again (but not INITTED)
-                */
-               dd->ipath_flags |= IPATH_PRESENT;
-               val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_revision);
-               if (val == dd->ipath_revision) {
-                       ipath_cdbg(VERBOSE, "Got matching revision "
-                                  "register %llx on try %d\n",
-                                  (unsigned long long) val, i);
-                       ret = ipath_reinit_msi(dd);
-                       goto bail;
-               }
-               /* Probably getting -1 back */
-               ipath_dbg("Didn't get expected revision register, "
-                         "got %llx, try %d\n", (unsigned long long) val,
-                         i + 1);
-       }
-       ret = 0; /* failed */
-
-bail:
-       if (ret)
-               ipath_7220_pcie_params(dd, dd->ipath_boardrev);
-
-       return ret;
-}
-
-/**
- * ipath_7220_put_tid - write a TID to the chip
- * @dd: the infinipath device
- * @tidptr: pointer to the expected TID (in chip) to update
- * @tidtype: 0 for eager, 1 for expected
- * @pa: physical address of in memory buffer; ipath_tidinvalid if freeing
- *
- * This exists as a separate routine to allow for selection of the
- * appropriate "flavor". The static calls in cleanup just use the
- * revision-agnostic form, as they are not performance critical.
- */
-static void ipath_7220_put_tid(struct ipath_devdata *dd, u64 __iomem *tidptr,
-                            u32 type, unsigned long pa)
-{
-       if (pa != dd->ipath_tidinvalid) {
-               u64 chippa = pa >> IBA7220_TID_PA_SHIFT;
-
-               /* paranoia checks */
-               if (pa != (chippa << IBA7220_TID_PA_SHIFT)) {
-                       dev_info(&dd->pcidev->dev, "BUG: physaddr %lx "
-                                "not 2KB aligned!\n", pa);
-                       return;
-               }
-               if (chippa >= (1UL << IBA7220_TID_SZ_SHIFT)) {
-                       ipath_dev_err(dd,
-                                     "BUG: Physical page address 0x%lx "
-                                     "larger than supported\n", pa);
-                       return;
-               }
-
-               if (type == RCVHQ_RCV_TYPE_EAGER)
-                       chippa |= dd->ipath_tidtemplate;
-               else /* for now, always full 4KB page */
-                       chippa |= IBA7220_TID_SZ_4K;
-               writeq(chippa, tidptr);
-       } else
-               writeq(pa, tidptr);
-       mmiowb();
-}
-
-/**
- * ipath_7220_clear_tid - clear all TID entries for a port, expected and eager
- * @dd: the infinipath device
- * @port: the port
- *
- * clear all TID entries for a port, expected and eager.
- * Used from ipath_close().  On this chip, TIDs are only 32 bits,
- * not 64, but they are still on 64 bit boundaries, so tidbase
- * is declared as u64 * for the pointer math, even though we write 32 bits
- */
-static void ipath_7220_clear_tids(struct ipath_devdata *dd, unsigned port)
-{
-       u64 __iomem *tidbase;
-       unsigned long tidinv;
-       int i;
-
-       if (!dd->ipath_kregbase)
-               return;
-
-       ipath_cdbg(VERBOSE, "Invalidate TIDs for port %u\n", port);
-
-       tidinv = dd->ipath_tidinvalid;
-       tidbase = (u64 __iomem *)
-               ((char __iomem *)(dd->ipath_kregbase) +
-                dd->ipath_rcvtidbase +
-                port * dd->ipath_rcvtidcnt * sizeof(*tidbase));
-
-       for (i = 0; i < dd->ipath_rcvtidcnt; i++)
-               ipath_7220_put_tid(dd, &tidbase[i], RCVHQ_RCV_TYPE_EXPECTED,
-                                  tidinv);
-
-       tidbase = (u64 __iomem *)
-               ((char __iomem *)(dd->ipath_kregbase) +
-                dd->ipath_rcvegrbase + port_egrtid_idx(dd, port)
-                * sizeof(*tidbase));
-
-       for (i = port ? dd->ipath_rcvegrcnt : dd->ipath_p0_rcvegrcnt; i; i--)
-               ipath_7220_put_tid(dd, &tidbase[i-1], RCVHQ_RCV_TYPE_EAGER,
-                       tidinv);
-}
-
-/**
- * ipath_7220_tidtemplate - setup constants for TID updates
- * @dd: the infinipath device
- *
- * We setup stuff that we use a lot, to avoid calculating each time
- */
-static void ipath_7220_tidtemplate(struct ipath_devdata *dd)
-{
-       /* For now, we always allocate 4KB buffers (at init) so we can
-        * receive max size packets.  We may want a module parameter to
-        * specify 2KB or 4KB and/or make be per port instead of per device
-        * for those who want to reduce memory footprint.  Note that the
-        * ipath_rcvhdrentsize size must be large enough to hold the largest
-        * IB header (currently 96 bytes) that we expect to handle (plus of
-        * course the 2 dwords of RHF).
-        */
-       if (dd->ipath_rcvegrbufsize == 2048)
-               dd->ipath_tidtemplate = IBA7220_TID_SZ_2K;
-       else if (dd->ipath_rcvegrbufsize == 4096)
-               dd->ipath_tidtemplate = IBA7220_TID_SZ_4K;
-       else {
-               dev_info(&dd->pcidev->dev, "BUG: unsupported egrbufsize "
-                        "%u, using %u\n", dd->ipath_rcvegrbufsize,
-                        4096);
-               dd->ipath_tidtemplate = IBA7220_TID_SZ_4K;
-       }
-       dd->ipath_tidinvalid = 0;
-}
-
-static int ipath_7220_early_init(struct ipath_devdata *dd)
-{
-       u32 i, s;
-
-       if (strcmp(int_type, "auto") &&
-           strcmp(int_type, "force_msi") &&
-           strcmp(int_type, "force_intx")) {
-               ipath_dev_err(dd, "Invalid interrupt_type: '%s', expecting "
-                             "auto, force_msi or force_intx\n", int_type);
-               return -EINVAL;
-       }
-
-       /*
-        * Control[4] has been added to change the arbitration within
-        * the SDMA engine between favoring data fetches over descriptor
-        * fetches.  ipath_sdma_fetch_arb==0 gives data fetches priority.
-        */
-       if (ipath_sdma_fetch_arb && (dd->ipath_minrev > 1))
-               dd->ipath_control |= 1<<4;
-
-       dd->ipath_flags |= IPATH_4BYTE_TID;
-
-       /*
-        * For openfabrics, we need to be able to handle an IB header of
-        * 24 dwords.  HT chip has arbitrary sized receive buffers, so we
-        * made them the same size as the PIO buffers.  This chip does not
-        * handle arbitrary size buffers, so we need the header large enough
-        * to handle largest IB header, but still have room for a 2KB MTU
-        * standard IB packet.
-        */
-       dd->ipath_rcvhdrentsize = 24;
-       dd->ipath_rcvhdrsize = IPATH_DFLT_RCVHDRSIZE;
-       dd->ipath_rhf_offset =
-               dd->ipath_rcvhdrentsize - sizeof(u64) / sizeof(u32);
-
-       dd->ipath_rcvegrbufsize = ipath_mtu4096 ? 4096 : 2048;
-       /*
-        * the min() check here is currently a nop, but it may not always
-        * be, depending on just how we do ipath_rcvegrbufsize
-        */
-       dd->ipath_ibmaxlen = min(ipath_mtu4096 ? dd->ipath_piosize4k :
-                                dd->ipath_piosize2k,
-                                dd->ipath_rcvegrbufsize +
-                                (dd->ipath_rcvhdrentsize << 2));
-       dd->ipath_init_ibmaxlen = dd->ipath_ibmaxlen;
-
-       ipath_7220_config_jint(dd, INFINIPATH_JINT_DEFAULT_IDLE_TICKS,
-                              INFINIPATH_JINT_DEFAULT_MAX_PACKETS);
-
-       if (dd->ipath_boardrev) /* no eeprom on emulator */
-               ipath_get_eeprom_info(dd);
-
-       /* start of code to check and print procmon */
-       s = ipath_read_kreg32(dd, IPATH_KREG_OFFSET(ProcMon));
-       s &= ~(1U<<31); /* clear done bit */
-       s |= 1U<<14; /* clear counter (write 1 to clear) */
-       ipath_write_kreg(dd, IPATH_KREG_OFFSET(ProcMon), s);
-       /* make sure clear_counter low long enough before start */
-       ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
-       ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
-
-       s &= ~(1U<<14); /* allow counter to count (before starting) */
-       ipath_write_kreg(dd, IPATH_KREG_OFFSET(ProcMon), s);
-       ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
-       ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
-       s = ipath_read_kreg32(dd, IPATH_KREG_OFFSET(ProcMon));
-
-       s |= 1U<<15; /* start the counter */
-       s &= ~(1U<<31); /* clear done bit */
-       s &= ~0x7ffU; /* clear frequency bits */
-       s |= 0xe29; /* set frequency bits, in case cleared */
-       ipath_write_kreg(dd, IPATH_KREG_OFFSET(ProcMon), s);
-
-       s = 0;
-       for (i = 500; i > 0 && !(s&(1ULL<<31)); i--) {
-               ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
-               s = ipath_read_kreg32(dd, IPATH_KREG_OFFSET(ProcMon));
-       }
-       if (!(s&(1U<<31)))
-               ipath_dev_err(dd, "ProcMon register not valid: 0x%x\n", s);
-       else
-               ipath_dbg("ProcMon=0x%x, count=0x%x\n", s, (s>>16)&0x1ff);
-
-       return 0;
-}
-
-/**
- * ipath_init_7220_get_base_info - set chip-specific flags for user code
- * @pd: the infinipath port
- * @kbase: ipath_base_info pointer
- *
- * We set the PCIE flag because the lower bandwidth on PCIe vs
- * HyperTransport can affect some user packet algorithims.
- */
-static int ipath_7220_get_base_info(struct ipath_portdata *pd, void *kbase)
-{
-       struct ipath_base_info *kinfo = kbase;
-
-       kinfo->spi_runtime_flags |=
-               IPATH_RUNTIME_PCIE | IPATH_RUNTIME_NODMA_RTAIL |
-               IPATH_RUNTIME_SDMA;
-
-       return 0;
-}
-
-static void ipath_7220_free_irq(struct ipath_devdata *dd)
-{
-       free_irq(dd->ipath_irq, dd);
-       dd->ipath_irq = 0;
-}
-
-static struct ipath_message_header *
-ipath_7220_get_msgheader(struct ipath_devdata *dd, __le32 *rhf_addr)
-{
-       u32 offset = ipath_hdrget_offset(rhf_addr);
-
-       return (struct ipath_message_header *)
-               (rhf_addr - dd->ipath_rhf_offset + offset);
-}
-
-static void ipath_7220_config_ports(struct ipath_devdata *dd, ushort cfgports)
-{
-       u32 nchipports;
-
-       nchipports = ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt);
-       if (!cfgports) {
-               int ncpus = num_online_cpus();
-
-               if (ncpus <= 4)
-                       dd->ipath_portcnt = 5;
-               else if (ncpus <= 8)
-                       dd->ipath_portcnt = 9;
-               if (dd->ipath_portcnt)
-                       ipath_dbg("Auto-configured for %u ports, %d cpus "
-                               "online\n", dd->ipath_portcnt, ncpus);
-       } else if (cfgports <= nchipports)
-               dd->ipath_portcnt = cfgports;
-       if (!dd->ipath_portcnt) /* none of the above, set to max */
-               dd->ipath_portcnt = nchipports;
-       /*
-        * chip can be configured for 5, 9, or 17 ports, and choice
-        * affects number of eager TIDs per port (1K, 2K, 4K).
-        */
-       if (dd->ipath_portcnt > 9)
-               dd->ipath_rcvctrl |= 2ULL << IBA7220_R_PORTCFG_SHIFT;
-       else if (dd->ipath_portcnt > 5)
-               dd->ipath_rcvctrl |= 1ULL << IBA7220_R_PORTCFG_SHIFT;
-       /* else configure for default 5 receive ports */
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
-                        dd->ipath_rcvctrl);
-       dd->ipath_p0_rcvegrcnt = 2048; /* always */
-       if (dd->ipath_flags & IPATH_HAS_SEND_DMA)
-               dd->ipath_pioreserved = 3; /* kpiobufs used for PIO */
-}
-
-
-static int ipath_7220_get_ib_cfg(struct ipath_devdata *dd, int which)
-{
-       int lsb, ret = 0;
-       u64 maskr; /* right-justified mask */
-
-       switch (which) {
-       case IPATH_IB_CFG_HRTBT: /* Get Heartbeat off/enable/auto */
-               lsb = IBA7220_IBC_HRTBT_SHIFT;
-               maskr = IBA7220_IBC_HRTBT_MASK;
-               break;
-
-       case IPATH_IB_CFG_LWID_ENB: /* Get allowed Link-width */
-               ret = dd->ipath_link_width_enabled;
-               goto done;
-
-       case IPATH_IB_CFG_LWID: /* Get currently active Link-width */
-               ret = dd->ipath_link_width_active;
-               goto done;
-
-       case IPATH_IB_CFG_SPD_ENB: /* Get allowed Link speeds */
-               ret = dd->ipath_link_speed_enabled;
-               goto done;
-
-       case IPATH_IB_CFG_SPD: /* Get current Link spd */
-               ret = dd->ipath_link_speed_active;
-               goto done;
-
-       case IPATH_IB_CFG_RXPOL_ENB: /* Get Auto-RX-polarity enable */
-               lsb = IBA7220_IBC_RXPOL_SHIFT;
-               maskr = IBA7220_IBC_RXPOL_MASK;
-               break;
-
-       case IPATH_IB_CFG_LREV_ENB: /* Get Auto-Lane-reversal enable */
-               lsb = IBA7220_IBC_LREV_SHIFT;
-               maskr = IBA7220_IBC_LREV_MASK;
-               break;
-
-       case IPATH_IB_CFG_LINKLATENCY:
-               ret = ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibcddrstatus)
-                       & IBA7220_DDRSTAT_LINKLAT_MASK;
-               goto done;
-
-       default:
-               ret = -ENOTSUPP;
-               goto done;
-       }
-       ret = (int)((dd->ipath_ibcddrctrl >> lsb) & maskr);
-done:
-       return ret;
-}
-
-static int ipath_7220_set_ib_cfg(struct ipath_devdata *dd, int which, u32 val)
-{
-       int lsb, ret = 0, setforce = 0;
-       u64 maskr; /* right-justified mask */
-
-       switch (which) {
-       case IPATH_IB_CFG_LIDLMC:
-               /*
-                * Set LID and LMC. Combined to avoid possible hazard
-                * caller puts LMC in 16MSbits, DLID in 16LSbits of val
-                */
-               lsb = IBA7220_IBC_DLIDLMC_SHIFT;
-               maskr = IBA7220_IBC_DLIDLMC_MASK;
-               break;
-
-       case IPATH_IB_CFG_HRTBT: /* set Heartbeat off/enable/auto */
-               if (val & IPATH_IB_HRTBT_ON &&
-                       (dd->ipath_flags & IPATH_NO_HRTBT))
-                       goto bail;
-               lsb = IBA7220_IBC_HRTBT_SHIFT;
-               maskr = IBA7220_IBC_HRTBT_MASK;
-               break;
-
-       case IPATH_IB_CFG_LWID_ENB: /* set allowed Link-width */
-               /*
-                * As with speed, only write the actual register if
-                * the link is currently down, otherwise takes effect
-                * on next link change.
-                */
-               dd->ipath_link_width_enabled = val;
-               if ((dd->ipath_flags & (IPATH_LINKDOWN|IPATH_LINKINIT)) !=
-                       IPATH_LINKDOWN)
-                       goto bail;
-               /*
-                * We set the IPATH_IB_FORCE_NOTIFY bit so updown
-                * will get called because we want update
-                * link_width_active, and the change may not take
-                * effect for some time (if we are in POLL), so this
-                * flag will force the updown routine to be called
-                * on the next ibstatuschange down interrupt, even
-                * if it's not an down->up transition.
-                */
-               val--; /* convert from IB to chip */
-               maskr = IBA7220_IBC_WIDTH_MASK;
-               lsb = IBA7220_IBC_WIDTH_SHIFT;
-               setforce = 1;
-               dd->ipath_flags |= IPATH_IB_FORCE_NOTIFY;
-               break;
-
-       case IPATH_IB_CFG_SPD_ENB: /* set allowed Link speeds */
-               /*
-                * If we turn off IB1.2, need to preset SerDes defaults,
-                * but not right now. Set a flag for the next time
-                * we command the link down.  As with width, only write the
-                * actual register if the link is currently down, otherwise
-                * takes effect on next link change.  Since setting is being
-                * explictly requested (via MAD or sysfs), clear autoneg
-                * failure status if speed autoneg is enabled.
-                */
-               dd->ipath_link_speed_enabled = val;
-               if (dd->ipath_ibcddrctrl & IBA7220_IBC_IBTA_1_2_MASK &&
-                   !(val & (val - 1)))
-                       dd->ipath_presets_needed = 1;
-               if ((dd->ipath_flags & (IPATH_LINKDOWN|IPATH_LINKINIT)) !=
-                       IPATH_LINKDOWN)
-                       goto bail;
-               /*
-                * We set the IPATH_IB_FORCE_NOTIFY bit so updown
-                * will get called because we want update
-                * link_speed_active, and the change may not take
-                * effect for some time (if we are in POLL), so this
-                * flag will force the updown routine to be called
-                * on the next ibstatuschange down interrupt, even
-                * if it's not an down->up transition.  When setting
-                * speed autoneg, clear AUTONEG_FAILED.
-                */
-               if (val == (IPATH_IB_SDR | IPATH_IB_DDR)) {
-                       val = IBA7220_IBC_SPEED_AUTONEG_MASK |
-                               IBA7220_IBC_IBTA_1_2_MASK;
-                       dd->ipath_flags &= ~IPATH_IB_AUTONEG_FAILED;
-               } else
-                       val = val == IPATH_IB_DDR ?  IBA7220_IBC_SPEED_DDR
-                               : IBA7220_IBC_SPEED_SDR;
-               maskr = IBA7220_IBC_SPEED_AUTONEG_MASK |
-                       IBA7220_IBC_IBTA_1_2_MASK;
-               lsb = 0; /* speed bits are low bits */
-               setforce = 1;
-               break;
-
-       case IPATH_IB_CFG_RXPOL_ENB: /* set Auto-RX-polarity enable */
-               lsb = IBA7220_IBC_RXPOL_SHIFT;
-               maskr = IBA7220_IBC_RXPOL_MASK;
-               break;
-
-       case IPATH_IB_CFG_LREV_ENB: /* set Auto-Lane-reversal enable */
-               lsb = IBA7220_IBC_LREV_SHIFT;
-               maskr = IBA7220_IBC_LREV_MASK;
-               break;
-
-       default:
-               ret = -ENOTSUPP;
-               goto bail;
-       }
-       dd->ipath_ibcddrctrl &= ~(maskr << lsb);
-       dd->ipath_ibcddrctrl |= (((u64) val & maskr) << lsb);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcddrctrl,
-                        dd->ipath_ibcddrctrl);
-       if (setforce)
-               dd->ipath_flags |= IPATH_IB_FORCE_NOTIFY;
-bail:
-       return ret;
-}
-
-static void ipath_7220_read_counters(struct ipath_devdata *dd,
-                                    struct infinipath_counters *cntrs)
-{
-       u64 *counters = (u64 *) cntrs;
-       int i;
-
-       for (i = 0; i < sizeof(*cntrs) / sizeof(u64); i++)
-               counters[i] = ipath_snap_cntr(dd, i);
-}
-
-/* if we are using MSI, try to fallback to INTx */
-static int ipath_7220_intr_fallback(struct ipath_devdata *dd)
-{
-       if (dd->ipath_msi_lo) {
-               dev_info(&dd->pcidev->dev, "MSI interrupt not detected,"
-                       " trying INTx interrupts\n");
-               ipath_7220_nomsi(dd);
-               ipath_enable_intx(dd->pcidev);
-               /*
-                * some newer kernels require free_irq before disable_msi,
-                * and irq can be changed during disable and intx enable
-                * and we need to therefore use the pcidev->irq value,
-                * not our saved MSI value.
-                */
-               dd->ipath_irq = dd->pcidev->irq;
-               if (request_irq(dd->ipath_irq, ipath_intr, IRQF_SHARED,
-                       IPATH_DRV_NAME, dd))
-                       ipath_dev_err(dd,
-                               "Could not re-request_irq for INTx\n");
-               return 1;
-       }
-       return 0;
-}
-
-/*
- * reset the XGXS (between serdes and IBC).  Slightly less intrusive
- * than resetting the IBC or external link state, and useful in some
- * cases to cause some retraining.  To do this right, we reset IBC
- * as well.
- */
-static void ipath_7220_xgxs_reset(struct ipath_devdata *dd)
-{
-       u64 val, prev_val;
-
-       prev_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
-       val = prev_val | INFINIPATH_XGXS_RESET;
-       prev_val &= ~INFINIPATH_XGXS_RESET; /* be sure */
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
-                        dd->ipath_control & ~INFINIPATH_C_LINKENABLE);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val);
-       ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, prev_val);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
-                        dd->ipath_control);
-}
-
-
-/* Still needs cleanup, too much hardwired stuff */
-static void autoneg_send(struct ipath_devdata *dd,
-       u32 *hdr, u32 dcnt, u32 *data)
-{
-       int i;
-       u64 cnt;
-       u32 __iomem *piobuf;
-       u32 pnum;
-
-       i = 0;
-       cnt = 7 + dcnt + 1; /* 7 dword header, dword data, icrc */
-       while (!(piobuf = ipath_getpiobuf(dd, cnt, &pnum))) {
-               if (i++ > 15) {
-                       ipath_dbg("Couldn't get pio buffer for send\n");
-                       return;
-               }
-               udelay(2);
-       }
-       if (dd->ipath_flags&IPATH_HAS_PBC_CNT)
-               cnt |= 0x80000000UL<<32; /* mark as VL15 */
-       writeq(cnt, piobuf);
-       ipath_flush_wc();
-       __iowrite32_copy(piobuf + 2, hdr, 7);
-       __iowrite32_copy(piobuf + 9, data, dcnt);
-       ipath_flush_wc();
-}
-
-/*
- * _start packet gets sent twice at start, _done gets sent twice at end
- */
-static void ipath_autoneg_send(struct ipath_devdata *dd, int which)
-{
-       static u32 swapped;
-       u32 dw, i, hcnt, dcnt, *data;
-       static u32 hdr[7] = { 0xf002ffff, 0x48ffff, 0x6400abba };
-       static u32 madpayload_start[0x40] = {
-               0x1810103, 0x1, 0x0, 0x0, 0x2c90000, 0x2c9, 0x0, 0x0,
-               0xffffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
-               0x1, 0x1388, 0x15e, 0x1, /* rest 0's */
-               };
-       static u32 madpayload_done[0x40] = {
-               0x1810103, 0x1, 0x0, 0x0, 0x2c90000, 0x2c9, 0x0, 0x0,
-               0xffffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
-               0x40000001, 0x1388, 0x15e, /* rest 0's */
-               };
-       dcnt = ARRAY_SIZE(madpayload_start);
-       hcnt = ARRAY_SIZE(hdr);
-       if (!swapped) {
-               /* for maintainability, do it at runtime */
-               for (i = 0; i < hcnt; i++) {
-                       dw = (__force u32) cpu_to_be32(hdr[i]);
-                       hdr[i] = dw;
-               }
-               for (i = 0; i < dcnt; i++) {
-                       dw = (__force u32) cpu_to_be32(madpayload_start[i]);
-                       madpayload_start[i] = dw;
-                       dw = (__force u32) cpu_to_be32(madpayload_done[i]);
-                       madpayload_done[i] = dw;
-               }
-               swapped = 1;
-       }
-
-       data = which ? madpayload_done : madpayload_start;
-       ipath_cdbg(PKT, "Sending %s special MADs\n", which?"done":"start");
-
-       autoneg_send(dd, hdr, dcnt, data);
-       ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-       udelay(2);
-       autoneg_send(dd, hdr, dcnt, data);
-       ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-       udelay(2);
-}
-
-
-
-/*
- * Do the absolute minimum to cause an IB speed change, and make it
- * ready, but don't actually trigger the change.   The caller will
- * do that when ready (if link is in Polling training state, it will
- * happen immediately, otherwise when link next goes down)
- *
- * This routine should only be used as part of the DDR autonegotation
- * code for devices that are not compliant with IB 1.2 (or code that
- * fixes things up for same).
- *
- * When link has gone down, and autoneg enabled, or autoneg has
- * failed and we give up until next time we set both speeds, and
- * then we want IBTA enabled as well as "use max enabled speed.
- */
-static void set_speed_fast(struct ipath_devdata *dd, u32 speed)
-{
-       dd->ipath_ibcddrctrl &= ~(IBA7220_IBC_SPEED_AUTONEG_MASK |
-               IBA7220_IBC_IBTA_1_2_MASK |
-               (IBA7220_IBC_WIDTH_MASK << IBA7220_IBC_WIDTH_SHIFT));
-
-       if (speed == (IPATH_IB_SDR | IPATH_IB_DDR))
-               dd->ipath_ibcddrctrl |= IBA7220_IBC_SPEED_AUTONEG_MASK |
-                       IBA7220_IBC_IBTA_1_2_MASK;
-       else
-               dd->ipath_ibcddrctrl |= speed == IPATH_IB_DDR ?
-                       IBA7220_IBC_SPEED_DDR : IBA7220_IBC_SPEED_SDR;
-
-       /*
-        * Convert from IB-style 1 = 1x, 2 = 4x, 3 = auto
-        * to chip-centric       0 = 1x, 1 = 4x, 2 = auto
-        */
-       dd->ipath_ibcddrctrl |= (u64)(dd->ipath_link_width_enabled - 1) <<
-               IBA7220_IBC_WIDTH_SHIFT;
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcddrctrl,
-                       dd->ipath_ibcddrctrl);
-       ipath_cdbg(VERBOSE, "setup for IB speed (%x) done\n", speed);
-}
-
-
-/*
- * this routine is only used when we are not talking to another
- * IB 1.2-compliant device that we think can do DDR.
- * (This includes all existing switch chips as of Oct 2007.)
- * 1.2-compliant devices go directly to DDR prior to reaching INIT
- */
-static void try_auto_neg(struct ipath_devdata *dd)
-{
-       /*
-        * required for older non-IB1.2 DDR switches.  Newer
-        * non-IB-compliant switches don't need it, but so far,
-        * aren't bothered by it either.  "Magic constant"
-        */
-       ipath_write_kreg(dd, IPATH_KREG_OFFSET(IBNCModeCtrl),
-               0x3b9dc07);
-       dd->ipath_flags |= IPATH_IB_AUTONEG_INPROG;
-       ipath_autoneg_send(dd, 0);
-       set_speed_fast(dd, IPATH_IB_DDR);
-       ipath_toggle_rclkrls(dd);
-       /* 2 msec is minimum length of a poll cycle */
-       schedule_delayed_work(&dd->ipath_autoneg_work,
-               msecs_to_jiffies(2));
-}
-
-
-static int ipath_7220_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs)
-{
-       int ret = 0, symadj = 0;
-       u32 ltstate = ipath_ib_linkstate(dd, ibcs);
-
-       dd->ipath_link_width_active =
-               ((ibcs >> IBA7220_IBCS_LINKWIDTH_SHIFT) & 1) ?
-                   IB_WIDTH_4X : IB_WIDTH_1X;
-       dd->ipath_link_speed_active =
-               ((ibcs >> IBA7220_IBCS_LINKSPEED_SHIFT) & 1) ?
-                   IPATH_IB_DDR : IPATH_IB_SDR;
-
-       if (!ibup) {
-               /*
-                * when link goes down we don't want aeq running, so it
-                * won't't interfere with IBC training, etc., and we need
-                * to go back to the static SerDes preset values
-                */
-               if (dd->ipath_x1_fix_tries &&
-                        ltstate <= INFINIPATH_IBCS_LT_STATE_SLEEPQUIET &&
-                       ltstate != INFINIPATH_IBCS_LT_STATE_LINKUP)
-                       dd->ipath_x1_fix_tries = 0;
-               if (!(dd->ipath_flags & (IPATH_IB_AUTONEG_FAILED |
-                       IPATH_IB_AUTONEG_INPROG)))
-                       set_speed_fast(dd, dd->ipath_link_speed_enabled);
-               if (!(dd->ipath_flags & IPATH_IB_AUTONEG_INPROG)) {
-                       ipath_cdbg(VERBOSE, "Setting RXEQ defaults\n");
-                       ipath_sd7220_presets(dd);
-               }
-               /* this might better in ipath_sd7220_presets() */
-               ipath_set_relock_poll(dd, ibup);
-       } else {
-               if (ipath_compat_ddr_negotiate &&
-                   !(dd->ipath_flags & (IPATH_IB_AUTONEG_FAILED |
-                       IPATH_IB_AUTONEG_INPROG)) &&
-                       dd->ipath_link_speed_active == IPATH_IB_SDR &&
-                       (dd->ipath_link_speed_enabled &
-                           (IPATH_IB_DDR | IPATH_IB_SDR)) ==
-                           (IPATH_IB_DDR | IPATH_IB_SDR) &&
-                       dd->ipath_autoneg_tries < IPATH_AUTONEG_TRIES) {
-                       /* we are SDR, and DDR auto-negotiation enabled */
-                       ++dd->ipath_autoneg_tries;
-                       ipath_dbg("DDR negotiation try, %u/%u\n",
-                               dd->ipath_autoneg_tries,
-                               IPATH_AUTONEG_TRIES);
-                       if (!dd->ibdeltainprog) {
-                               dd->ibdeltainprog = 1;
-                               dd->ibsymsnap = ipath_read_creg32(dd,
-                                       dd->ipath_cregs->cr_ibsymbolerrcnt);
-                               dd->iblnkerrsnap = ipath_read_creg32(dd,
-                                       dd->ipath_cregs->cr_iblinkerrrecovcnt);
-                       }
-                       try_auto_neg(dd);
-                       ret = 1; /* no other IB status change processing */
-               } else if ((dd->ipath_flags & IPATH_IB_AUTONEG_INPROG)
-                       && dd->ipath_link_speed_active == IPATH_IB_SDR) {
-                       ipath_autoneg_send(dd, 1);
-                       set_speed_fast(dd, IPATH_IB_DDR);
-                       udelay(2);
-                       ipath_toggle_rclkrls(dd);
-                       ret = 1; /* no other IB status change processing */
-               } else {
-                       if ((dd->ipath_flags & IPATH_IB_AUTONEG_INPROG) &&
-                               (dd->ipath_link_speed_active & IPATH_IB_DDR)) {
-                               ipath_dbg("Got to INIT with DDR autoneg\n");
-                               dd->ipath_flags &= ~(IPATH_IB_AUTONEG_INPROG
-                                       | IPATH_IB_AUTONEG_FAILED);
-                               dd->ipath_autoneg_tries = 0;
-                               /* re-enable SDR, for next link down */
-                               set_speed_fast(dd,
-                                       dd->ipath_link_speed_enabled);
-                               wake_up(&dd->ipath_autoneg_wait);
-                               symadj = 1;
-                       } else if (dd->ipath_flags & IPATH_IB_AUTONEG_FAILED) {
-                               /*
-                                * clear autoneg failure flag, and do setup
-                                * so we'll try next time link goes down and
-                                * back to INIT (possibly connected to different
-                                * device).
-                                */
-                               ipath_dbg("INIT %sDR after autoneg failure\n",
-                                       (dd->ipath_link_speed_active &
-                                         IPATH_IB_DDR) ? "D" : "S");
-                               dd->ipath_flags &= ~IPATH_IB_AUTONEG_FAILED;
-                               dd->ipath_ibcddrctrl |=
-                                       IBA7220_IBC_IBTA_1_2_MASK;
-                               ipath_write_kreg(dd,
-                                       IPATH_KREG_OFFSET(IBNCModeCtrl), 0);
-                               symadj = 1;
-                       }
-               }
-               /*
-                * if we are in 1X on rev1 only, and are in autoneg width,
-                * it could be due to an xgxs problem, so if we haven't
-                * already tried, try twice to get to 4X; if we
-                * tried, and couldn't, report it, since it will
-                * probably not be what is desired.
-                */
-               if (dd->ipath_minrev == 1 &&
-                   (dd->ipath_link_width_enabled & (IB_WIDTH_1X |
-                       IB_WIDTH_4X)) == (IB_WIDTH_1X | IB_WIDTH_4X)
-                       && dd->ipath_link_width_active == IB_WIDTH_1X
-                       && dd->ipath_x1_fix_tries < 3) {
-                    if (++dd->ipath_x1_fix_tries == 3) {
-                               dev_info(&dd->pcidev->dev,
-                                       "IB link is in 1X mode\n");
-                               if (!(dd->ipath_flags &
-                                     IPATH_IB_AUTONEG_INPROG))
-                                       symadj = 1;
-                    }
-                       else {
-                               ipath_cdbg(VERBOSE, "IB 1X in "
-                                       "auto-width, try %u to be "
-                                       "sure it's really 1X; "
-                                       "ltstate %u\n",
-                                        dd->ipath_x1_fix_tries,
-                                        ltstate);
-                               dd->ipath_f_xgxs_reset(dd);
-                               ret = 1; /* skip other processing */
-                       }
-               } else if (!(dd->ipath_flags & IPATH_IB_AUTONEG_INPROG))
-                       symadj = 1;
-
-               if (!ret) {
-                       dd->delay_mult = rate_to_delay
-                           [(ibcs >> IBA7220_IBCS_LINKSPEED_SHIFT) & 1]
-                           [(ibcs >> IBA7220_IBCS_LINKWIDTH_SHIFT) & 1];
-
-                       ipath_set_relock_poll(dd, ibup);
-               }
-       }
-
-       if (symadj) {
-               if (dd->ibdeltainprog) {
-                       dd->ibdeltainprog = 0;
-                       dd->ibsymdelta += ipath_read_creg32(dd,
-                               dd->ipath_cregs->cr_ibsymbolerrcnt) -
-                               dd->ibsymsnap;
-                       dd->iblnkerrdelta += ipath_read_creg32(dd,
-                               dd->ipath_cregs->cr_iblinkerrrecovcnt) -
-                               dd->iblnkerrsnap;
-               }
-       } else if (!ibup && !dd->ibdeltainprog
-                  && !(dd->ipath_flags & IPATH_IB_AUTONEG_INPROG)) {
-               dd->ibdeltainprog = 1;
-               dd->ibsymsnap = ipath_read_creg32(dd,
-                                    dd->ipath_cregs->cr_ibsymbolerrcnt);
-               dd->iblnkerrsnap = ipath_read_creg32(dd,
-                                    dd->ipath_cregs->cr_iblinkerrrecovcnt);
-       }
-
-       if (!ret)
-               ipath_setup_7220_setextled(dd, ipath_ib_linkstate(dd, ibcs),
-                       ltstate);
-       return ret;
-}
-
-
-/*
- * Handle the empirically determined mechanism for auto-negotiation
- * of DDR speed with switches.
- */
-static void autoneg_work(struct work_struct *work)
-{
-       struct ipath_devdata *dd;
-       u64 startms;
-       u32 lastlts, i;
-
-       dd = container_of(work, struct ipath_devdata,
-               ipath_autoneg_work.work);
-
-       startms = jiffies_to_msecs(jiffies);
-
-       /*
-        * busy wait for this first part, it should be at most a
-        * few hundred usec, since we scheduled ourselves for 2msec.
-        */
-       for (i = 0; i < 25; i++) {
-               lastlts = ipath_ib_linktrstate(dd, dd->ipath_lastibcstat);
-               if (lastlts == INFINIPATH_IBCS_LT_STATE_POLLQUIET) {
-                       ipath_set_linkstate(dd, IPATH_IB_LINKDOWN_DISABLE);
-                       break;
-               }
-               udelay(100);
-       }
-
-       if (!(dd->ipath_flags & IPATH_IB_AUTONEG_INPROG))
-               goto done; /* we got there early or told to stop */
-
-       /* we expect this to timeout */
-       if (wait_event_timeout(dd->ipath_autoneg_wait,
-               !(dd->ipath_flags & IPATH_IB_AUTONEG_INPROG),
-               msecs_to_jiffies(90)))
-               goto done;
-
-       ipath_toggle_rclkrls(dd);
-
-       /* we expect this to timeout */
-       if (wait_event_timeout(dd->ipath_autoneg_wait,
-               !(dd->ipath_flags & IPATH_IB_AUTONEG_INPROG),
-               msecs_to_jiffies(1700)))
-               goto done;
-
-       set_speed_fast(dd, IPATH_IB_SDR);
-       ipath_toggle_rclkrls(dd);
-
-       /*
-        * wait up to 250 msec for link to train and get to INIT at DDR;
-        * this should terminate early
-        */
-       wait_event_timeout(dd->ipath_autoneg_wait,
-               !(dd->ipath_flags & IPATH_IB_AUTONEG_INPROG),
-               msecs_to_jiffies(250));
-done:
-       if (dd->ipath_flags & IPATH_IB_AUTONEG_INPROG) {
-               ipath_dbg("Did not get to DDR INIT (%x) after %Lu msecs\n",
-                       ipath_ib_state(dd, dd->ipath_lastibcstat),
-                       (unsigned long long) jiffies_to_msecs(jiffies)-startms);
-               dd->ipath_flags &= ~IPATH_IB_AUTONEG_INPROG;
-               if (dd->ipath_autoneg_tries == IPATH_AUTONEG_TRIES) {
-                       dd->ipath_flags |= IPATH_IB_AUTONEG_FAILED;
-                       ipath_dbg("Giving up on DDR until next IB "
-                               "link Down\n");
-                       dd->ipath_autoneg_tries = 0;
-               }
-               set_speed_fast(dd, dd->ipath_link_speed_enabled);
-       }
-}
-
-
-/**
- * ipath_init_iba7220_funcs - set up the chip-specific function pointers
- * @dd: the infinipath device
- *
- * This is global, and is called directly at init to set up the
- * chip-specific function pointers for later use.
- */
-void ipath_init_iba7220_funcs(struct ipath_devdata *dd)
-{
-       dd->ipath_f_intrsetup = ipath_7220_intconfig;
-       dd->ipath_f_bus = ipath_setup_7220_config;
-       dd->ipath_f_reset = ipath_setup_7220_reset;
-       dd->ipath_f_get_boardname = ipath_7220_boardname;
-       dd->ipath_f_init_hwerrors = ipath_7220_init_hwerrors;
-       dd->ipath_f_early_init = ipath_7220_early_init;
-       dd->ipath_f_handle_hwerrors = ipath_7220_handle_hwerrors;
-       dd->ipath_f_quiet_serdes = ipath_7220_quiet_serdes;
-       dd->ipath_f_bringup_serdes = ipath_7220_bringup_serdes;
-       dd->ipath_f_clear_tids = ipath_7220_clear_tids;
-       dd->ipath_f_put_tid = ipath_7220_put_tid;
-       dd->ipath_f_cleanup = ipath_setup_7220_cleanup;
-       dd->ipath_f_setextled = ipath_setup_7220_setextled;
-       dd->ipath_f_get_base_info = ipath_7220_get_base_info;
-       dd->ipath_f_free_irq = ipath_7220_free_irq;
-       dd->ipath_f_tidtemplate = ipath_7220_tidtemplate;
-       dd->ipath_f_intr_fallback = ipath_7220_intr_fallback;
-       dd->ipath_f_xgxs_reset = ipath_7220_xgxs_reset;
-       dd->ipath_f_get_ib_cfg = ipath_7220_get_ib_cfg;
-       dd->ipath_f_set_ib_cfg = ipath_7220_set_ib_cfg;
-       dd->ipath_f_config_jint = ipath_7220_config_jint;
-       dd->ipath_f_config_ports = ipath_7220_config_ports;
-       dd->ipath_f_read_counters = ipath_7220_read_counters;
-       dd->ipath_f_get_msgheader = ipath_7220_get_msgheader;
-       dd->ipath_f_ib_updown = ipath_7220_ib_updown;
-
-       /* initialize chip-specific variables */
-       ipath_init_7220_variables(dd);
-}
index b3d7efcdf0214fca1d9ce5c95fa481b946d4407c..6559af60bffd62fbf162320379ff545ca4c974fc 100644 (file)
@@ -1030,8 +1030,6 @@ void ipath_free_data(struct ipath_portdata *dd);
 u32 __iomem *ipath_getpiobuf(struct ipath_devdata *, u32, u32 *);
 void ipath_chg_pioavailkernel(struct ipath_devdata *dd, unsigned start,
                                unsigned len, int avail);
-void ipath_init_iba7220_funcs(struct ipath_devdata *);
-void ipath_init_iba6120_funcs(struct ipath_devdata *);
 void ipath_init_iba6110_funcs(struct ipath_devdata *);
 void ipath_get_eeprom_info(struct ipath_devdata *);
 int ipath_update_eeprom_log(struct ipath_devdata *dd);
index 559f39be0dcc16a5b0e8ceff53005d30060c2303..dd7f26d04d46b6d9def83d3f1b1dcd8d04e75fc7 100644 (file)
@@ -2182,7 +2182,7 @@ int ipath_register_ib_device(struct ipath_devdata *dd)
        snprintf(dev->node_desc, sizeof(dev->node_desc),
                 IPATH_IDSTR " %s", init_utsname()->nodename);
 
-       ret = ib_register_device(dev);
+       ret = ib_register_device(dev, NULL);
        if (ret)
                goto err_reg;
 
index 39051417054c9c48722cd00b9431a280bfa4b185..4e94e360e43b42ed1f31685bdcb8b7387bc1b46e 100644 (file)
@@ -662,7 +662,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
        spin_lock_init(&ibdev->sm_lock);
        mutex_init(&ibdev->cap_mask_mutex);
 
-       if (ib_register_device(&ibdev->ib_dev))
+       if (ib_register_device(&ibdev->ib_dev, NULL))
                goto err_map;
 
        if (mlx4_ib_mad_init(ibdev))
index f080a784bc795da07fa380a7d72cc0aef900e0f6..1e0b4b6074ad00443bd274eb5047ad126e6732d8 100644 (file)
@@ -1403,7 +1403,7 @@ int mthca_register_device(struct mthca_dev *dev)
 
        mutex_init(&dev->cap_mask_mutex);
 
-       ret = ib_register_device(&dev->ib_dev);
+       ret = ib_register_device(&dev->ib_dev, NULL);
        if (ret)
                return ret;
 
index 86acb7d570643552405c006322d15bdc0dc30f94..57874a165083df1d62ce1bbd9f4e7635b52d071d 100644 (file)
@@ -2584,7 +2584,6 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
                                break;
                        }
                }
-               spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
 
                if (phy_data & 0x0004) {
                        if (wide_ppm_offset &&
@@ -2639,6 +2638,8 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
                }
        }
 
+       spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+
        nesadapter->mac_sw_state[mac_number] = NES_MAC_SW_IDLE;
 }
 
@@ -3422,6 +3423,7 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
        struct nes_adapter *nesadapter = nesdev->nesadapter;
        u32 aeq_info;
        u32 next_iwarp_state = 0;
+       u32 aeqe_cq_id;
        u16 async_event_id;
        u8 tcp_state;
        u8 iwarp_state;
@@ -3449,6 +3451,14 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
                        le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]), aeqe,
                        nes_tcp_state_str[tcp_state], nes_iwarp_state_str[iwarp_state]);
 
+       aeqe_cq_id = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]);
+       if (aeq_info & NES_AEQE_QP) {
+               if ((!nes_is_resource_allocated(nesadapter, nesadapter->allocated_qps,
+                               aeqe_cq_id)) ||
+                               (atomic_read(&nesqp->close_timer_started)))
+                       return;
+       }
+
        switch (async_event_id) {
                case NES_AEQE_AEID_LLP_FIN_RECEIVED:
                        if (nesqp->term_flags)
index e95e8d09ff38ecc2911470cabe9d46e54108c6de..5cc0a9ae5bb147c91e4f72297085f083f597abaa 100644 (file)
@@ -1001,6 +1001,7 @@ static int nes_netdev_change_mtu(struct net_device *netdev, int new_mtu)
        return ret;
 }
 
+
 static const char nes_ethtool_stringset[][ETH_GSTRING_LEN] = {
        "Link Change Interrupts",
        "Linearized SKBs",
@@ -1015,11 +1016,15 @@ static const char nes_ethtool_stringset[][ETH_GSTRING_LEN] = {
        "Rx Jabber Errors",
        "Rx Oversized Frames",
        "Rx Short Frames",
+       "Rx Length Errors",
+       "Rx CRC Errors",
+       "Rx Port Discard",
        "Endnode Rx Discards",
        "Endnode Rx Octets",
        "Endnode Rx Frames",
        "Endnode Tx Octets",
        "Endnode Tx Frames",
+       "Tx Errors",
        "mh detected",
        "mh pauses",
        "Retransmission Count",
@@ -1048,19 +1053,13 @@ static const char nes_ethtool_stringset[][ETH_GSTRING_LEN] = {
        "CM Nodes Destroyed",
        "CM Accel Drops",
        "CM Resets Received",
+       "Free 4Kpbls",
+       "Free 256pbls",
        "Timer Inits",
-       "CQ Depth 1",
-       "CQ Depth 4",
-       "CQ Depth 16",
-       "CQ Depth 24",
-       "CQ Depth 32",
-       "CQ Depth 128",
-       "CQ Depth 256",
        "LRO aggregated",
        "LRO flushed",
        "LRO no_desc",
 };
-
 #define NES_ETHTOOL_STAT_COUNT  ARRAY_SIZE(nes_ethtool_stringset)
 
 /**
@@ -1120,12 +1119,14 @@ static void nes_netdev_get_strings(struct net_device *netdev, u32 stringset,
 /**
  * nes_netdev_get_ethtool_stats
  */
+
 static void nes_netdev_get_ethtool_stats(struct net_device *netdev,
                struct ethtool_stats *target_ethtool_stats, u64 *target_stat_values)
 {
        u64 u64temp;
        struct nes_vnic *nesvnic = netdev_priv(netdev);
        struct nes_device *nesdev = nesvnic->nesdev;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
        u32 nic_count;
        u32 u32temp;
        u32 index = 0;
@@ -1154,6 +1155,46 @@ static void nes_netdev_get_ethtool_stats(struct net_device *netdev,
        nesvnic->nesdev->port_tx_discards += u32temp;
        nesvnic->netstats.tx_dropped += u32temp;
 
+       u32temp = nes_read_indexed(nesdev,
+                       NES_IDX_MAC_RX_SHORT_FRAMES + (nesvnic->nesdev->mac_index*0x200));
+       nesvnic->netstats.rx_dropped += u32temp;
+       nesvnic->nesdev->mac_rx_errors += u32temp;
+       nesvnic->nesdev->mac_rx_short_frames += u32temp;
+
+       u32temp = nes_read_indexed(nesdev,
+                       NES_IDX_MAC_RX_OVERSIZED_FRAMES + (nesvnic->nesdev->mac_index*0x200));
+       nesvnic->netstats.rx_dropped += u32temp;
+       nesvnic->nesdev->mac_rx_errors += u32temp;
+       nesvnic->nesdev->mac_rx_oversized_frames += u32temp;
+
+       u32temp = nes_read_indexed(nesdev,
+                       NES_IDX_MAC_RX_JABBER_FRAMES + (nesvnic->nesdev->mac_index*0x200));
+       nesvnic->netstats.rx_dropped += u32temp;
+       nesvnic->nesdev->mac_rx_errors += u32temp;
+       nesvnic->nesdev->mac_rx_jabber_frames += u32temp;
+
+       u32temp = nes_read_indexed(nesdev,
+                       NES_IDX_MAC_RX_SYMBOL_ERR_FRAMES + (nesvnic->nesdev->mac_index*0x200));
+       nesvnic->netstats.rx_dropped += u32temp;
+       nesvnic->nesdev->mac_rx_errors += u32temp;
+       nesvnic->nesdev->mac_rx_symbol_err_frames += u32temp;
+
+       u32temp = nes_read_indexed(nesdev,
+                       NES_IDX_MAC_RX_LENGTH_ERR_FRAMES + (nesvnic->nesdev->mac_index*0x200));
+       nesvnic->netstats.rx_length_errors += u32temp;
+       nesvnic->nesdev->mac_rx_errors += u32temp;
+
+       u32temp = nes_read_indexed(nesdev,
+                       NES_IDX_MAC_RX_CRC_ERR_FRAMES + (nesvnic->nesdev->mac_index*0x200));
+       nesvnic->nesdev->mac_rx_errors += u32temp;
+       nesvnic->nesdev->mac_rx_crc_errors += u32temp;
+       nesvnic->netstats.rx_crc_errors += u32temp;
+
+       u32temp = nes_read_indexed(nesdev,
+                       NES_IDX_MAC_TX_ERRORS + (nesvnic->nesdev->mac_index*0x200));
+       nesvnic->nesdev->mac_tx_errors += u32temp;
+       nesvnic->netstats.tx_errors += u32temp;
+
        for (nic_count = 0; nic_count < NES_MAX_PORT_COUNT; nic_count++) {
                if (nesvnic->qp_nic_index[nic_count] == 0xf)
                        break;
@@ -1218,11 +1259,15 @@ static void nes_netdev_get_ethtool_stats(struct net_device *netdev,
        target_stat_values[++index] = nesvnic->nesdev->mac_rx_jabber_frames;
        target_stat_values[++index] = nesvnic->nesdev->mac_rx_oversized_frames;
        target_stat_values[++index] = nesvnic->nesdev->mac_rx_short_frames;
+       target_stat_values[++index] = nesvnic->netstats.rx_length_errors;
+       target_stat_values[++index] = nesvnic->nesdev->mac_rx_crc_errors;
+       target_stat_values[++index] = nesvnic->nesdev->port_rx_discards;
        target_stat_values[++index] = nesvnic->endnode_nstat_rx_discard;
        target_stat_values[++index] = nesvnic->endnode_nstat_rx_octets;
        target_stat_values[++index] = nesvnic->endnode_nstat_rx_frames;
        target_stat_values[++index] = nesvnic->endnode_nstat_tx_octets;
        target_stat_values[++index] = nesvnic->endnode_nstat_tx_frames;
+       target_stat_values[++index] = nesvnic->nesdev->mac_tx_errors;
        target_stat_values[++index] = mh_detected;
        target_stat_values[++index] = mh_pauses_sent;
        target_stat_values[++index] = nesvnic->endnode_ipv4_tcp_retransmits;
@@ -1251,21 +1296,14 @@ static void nes_netdev_get_ethtool_stats(struct net_device *netdev,
        target_stat_values[++index] = atomic_read(&cm_nodes_destroyed);
        target_stat_values[++index] = atomic_read(&cm_accel_dropped_pkts);
        target_stat_values[++index] = atomic_read(&cm_resets_recvd);
+       target_stat_values[++index] = nesadapter->free_4kpbl;
+       target_stat_values[++index] = nesadapter->free_256pbl;
        target_stat_values[++index] = int_mod_timer_init;
-       target_stat_values[++index] = int_mod_cq_depth_1;
-       target_stat_values[++index] = int_mod_cq_depth_4;
-       target_stat_values[++index] = int_mod_cq_depth_16;
-       target_stat_values[++index] = int_mod_cq_depth_24;
-       target_stat_values[++index] = int_mod_cq_depth_32;
-       target_stat_values[++index] = int_mod_cq_depth_128;
-       target_stat_values[++index] = int_mod_cq_depth_256;
        target_stat_values[++index] = nesvnic->lro_mgr.stats.aggregated;
        target_stat_values[++index] = nesvnic->lro_mgr.stats.flushed;
        target_stat_values[++index] = nesvnic->lro_mgr.stats.no_desc;
-
 }
 
-
 /**
  * nes_netdev_get_drvinfo
  */
index 925e1f2d1d5534a04b0a54464e0812a2f125ab43..9bc2d744b2eacb18813357b5ecc0e1595a5d71a2 100644 (file)
@@ -3962,7 +3962,7 @@ int nes_register_ofa_device(struct nes_ib_device *nesibdev)
        struct nes_adapter *nesadapter = nesdev->nesadapter;
        int i, ret;
 
-       ret = ib_register_device(&nesvnic->nesibdev->ibdev);
+       ret = ib_register_device(&nesvnic->nesibdev->ibdev, NULL);
        if (ret) {
                return ret;
        }
diff --git a/drivers/infiniband/hw/qib/Kconfig b/drivers/infiniband/hw/qib/Kconfig
new file mode 100644 (file)
index 0000000..7c03a70
--- /dev/null
@@ -0,0 +1,7 @@
+config INFINIBAND_QIB
+       tristate "QLogic PCIe HCA support"
+       depends on 64BIT && NET
+       ---help---
+       This is a low-level driver for QLogic PCIe QLE InfiniBand host
+       channel adapters.  This driver does not support the QLogic
+       HyperTransport card (model QHT7140).
diff --git a/drivers/infiniband/hw/qib/Makefile b/drivers/infiniband/hw/qib/Makefile
new file mode 100644 (file)
index 0000000..c6515a1
--- /dev/null
@@ -0,0 +1,15 @@
+obj-$(CONFIG_INFINIBAND_QIB) += ib_qib.o
+
+ib_qib-y := qib_cq.o qib_diag.o qib_dma.o qib_driver.o qib_eeprom.o \
+       qib_file_ops.o qib_fs.o qib_init.o qib_intr.o qib_keys.o \
+       qib_mad.o qib_mmap.o qib_mr.o qib_pcie.o qib_pio_copy.o \
+       qib_qp.o qib_qsfp.o qib_rc.o qib_ruc.o qib_sdma.o qib_srq.o \
+       qib_sysfs.o qib_twsi.o qib_tx.o qib_uc.o qib_ud.o \
+       qib_user_pages.o qib_user_sdma.o qib_verbs_mcast.o qib_iba7220.o \
+       qib_sd7220.o qib_sd7220_img.o qib_iba7322.o qib_verbs.o
+
+# 6120 has no fallback if no MSI interrupts, others can do INTx
+ib_qib-$(CONFIG_PCI_MSI) += qib_iba6120.o
+
+ib_qib-$(CONFIG_X86_64) += qib_wc_x86_64.o
+ib_qib-$(CONFIG_PPC64) += qib_wc_ppc64.o
diff --git a/drivers/infiniband/hw/qib/qib.h b/drivers/infiniband/hw/qib/qib.h
new file mode 100644 (file)
index 0000000..32d9208
--- /dev/null
@@ -0,0 +1,1439 @@
+#ifndef _QIB_KERNEL_H
+#define _QIB_KERNEL_H
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009, 2010 QLogic Corporation.
+ * All rights reserved.
+ * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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.
+ */
+
+/*
+ * This header file is the base header file for qlogic_ib kernel code
+ * qib_user.h serves a similar purpose for user code.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/scatterlist.h>
+#include <linux/io.h>
+#include <linux/fs.h>
+#include <linux/completion.h>
+#include <linux/kref.h>
+#include <linux/sched.h>
+
+#include "qib_common.h"
+#include "qib_verbs.h"
+
+/* only s/w major version of QLogic_IB we can handle */
+#define QIB_CHIP_VERS_MAJ 2U
+
+/* don't care about this except printing */
+#define QIB_CHIP_VERS_MIN 0U
+
+/* The Organization Unique Identifier (Mfg code), and its position in GUID */
+#define QIB_OUI 0x001175
+#define QIB_OUI_LSB 40
+
+/*
+ * per driver stats, either not device nor port-specific, or
+ * summed over all of the devices and ports.
+ * They are described by name via ipathfs filesystem, so layout
+ * and number of elements can change without breaking compatibility.
+ * If members are added or deleted qib_statnames[] in qib_fs.c must
+ * change to match.
+ */
+struct qlogic_ib_stats {
+       __u64 sps_ints; /* number of interrupts handled */
+       __u64 sps_errints; /* number of error interrupts */
+       __u64 sps_txerrs; /* tx-related packet errors */
+       __u64 sps_rcverrs; /* non-crc rcv packet errors */
+       __u64 sps_hwerrs; /* hardware errors reported (parity, etc.) */
+       __u64 sps_nopiobufs; /* no pio bufs avail from kernel */
+       __u64 sps_ctxts; /* number of contexts currently open */
+       __u64 sps_lenerrs; /* number of kernel packets where RHF != LRH len */
+       __u64 sps_buffull;
+       __u64 sps_hdrfull;
+};
+
+extern struct qlogic_ib_stats qib_stats;
+extern struct pci_error_handlers qib_pci_err_handler;
+extern struct pci_driver qib_driver;
+
+#define QIB_CHIP_SWVERSION QIB_CHIP_VERS_MAJ
+/*
+ * First-cut critierion for "device is active" is
+ * two thousand dwords combined Tx, Rx traffic per
+ * 5-second interval. SMA packets are 64 dwords,
+ * and occur "a few per second", presumably each way.
+ */
+#define QIB_TRAFFIC_ACTIVE_THRESHOLD (2000)
+
+/*
+ * Struct used to indicate which errors are logged in each of the
+ * error-counters that are logged to EEPROM. A counter is incremented
+ * _once_ (saturating at 255) for each event with any bits set in
+ * the error or hwerror register masks below.
+ */
+#define QIB_EEP_LOG_CNT (4)
+struct qib_eep_log_mask {
+       u64 errs_to_log;
+       u64 hwerrs_to_log;
+};
+
+/*
+ * Below contains all data related to a single context (formerly called port).
+ */
+struct qib_ctxtdata {
+       void **rcvegrbuf;
+       dma_addr_t *rcvegrbuf_phys;
+       /* rcvhdrq base, needs mmap before useful */
+       void *rcvhdrq;
+       /* kernel virtual address where hdrqtail is updated */
+       void *rcvhdrtail_kvaddr;
+       /*
+        * temp buffer for expected send setup, allocated at open, instead
+        * of each setup call
+        */
+       void *tid_pg_list;
+       /*
+        * Shared page for kernel to signal user processes that send buffers
+        * need disarming.  The process should call QIB_CMD_DISARM_BUFS
+        * or QIB_CMD_ACK_EVENT with IPATH_EVENT_DISARM_BUFS set.
+        */
+       unsigned long *user_event_mask;
+       /* when waiting for rcv or pioavail */
+       wait_queue_head_t wait;
+       /*
+        * rcvegr bufs base, physical, must fit
+        * in 44 bits so 32 bit programs mmap64 44 bit works)
+        */
+       dma_addr_t rcvegr_phys;
+       /* mmap of hdrq, must fit in 44 bits */
+       dma_addr_t rcvhdrq_phys;
+       dma_addr_t rcvhdrqtailaddr_phys;
+
+       /*
+        * number of opens (including slave sub-contexts) on this instance
+        * (ignoring forks, dup, etc. for now)
+        */
+       int cnt;
+       /*
+        * how much space to leave at start of eager TID entries for
+        * protocol use, on each TID
+        */
+       /* instead of calculating it */
+       unsigned ctxt;
+       /* non-zero if ctxt is being shared. */
+       u16 subctxt_cnt;
+       /* non-zero if ctxt is being shared. */
+       u16 subctxt_id;
+       /* number of eager TID entries. */
+       u16 rcvegrcnt;
+       /* index of first eager TID entry. */
+       u16 rcvegr_tid_base;
+       /* number of pio bufs for this ctxt (all procs, if shared) */
+       u32 piocnt;
+       /* first pio buffer for this ctxt */
+       u32 pio_base;
+       /* chip offset of PIO buffers for this ctxt */
+       u32 piobufs;
+       /* how many alloc_pages() chunks in rcvegrbuf_pages */
+       u32 rcvegrbuf_chunks;
+       /* how many egrbufs per chunk */
+       u32 rcvegrbufs_perchunk;
+       /* order for rcvegrbuf_pages */
+       size_t rcvegrbuf_size;
+       /* rcvhdrq size (for freeing) */
+       size_t rcvhdrq_size;
+       /* per-context flags for fileops/intr communication */
+       unsigned long flag;
+       /* next expected TID to check when looking for free */
+       u32 tidcursor;
+       /* WAIT_RCV that timed out, no interrupt */
+       u32 rcvwait_to;
+       /* WAIT_PIO that timed out, no interrupt */
+       u32 piowait_to;
+       /* WAIT_RCV already happened, no wait */
+       u32 rcvnowait;
+       /* WAIT_PIO already happened, no wait */
+       u32 pionowait;
+       /* total number of polled urgent packets */
+       u32 urgent;
+       /* saved total number of polled urgent packets for poll edge trigger */
+       u32 urgent_poll;
+       /* pid of process using this ctxt */
+       pid_t pid;
+       pid_t subpid[QLOGIC_IB_MAX_SUBCTXT];
+       /* same size as task_struct .comm[], command that opened context */
+       char comm[16];
+       /* pkeys set by this use of this ctxt */
+       u16 pkeys[4];
+       /* so file ops can get at unit */
+       struct qib_devdata *dd;
+       /* so funcs that need physical port can get it easily */
+       struct qib_pportdata *ppd;
+       /* A page of memory for rcvhdrhead, rcvegrhead, rcvegrtail * N */
+       void *subctxt_uregbase;
+       /* An array of pages for the eager receive buffers * N */
+       void *subctxt_rcvegrbuf;
+       /* An array of pages for the eager header queue entries * N */
+       void *subctxt_rcvhdr_base;
+       /* The version of the library which opened this ctxt */
+       u32 userversion;
+       /* Bitmask of active slaves */
+       u32 active_slaves;
+       /* Type of packets or conditions we want to poll for */
+       u16 poll_type;
+       /* receive packet sequence counter */
+       u8 seq_cnt;
+       u8 redirect_seq_cnt;
+       /* ctxt rcvhdrq head offset */
+       u32 head;
+       u32 pkt_count;
+       /* QPs waiting for context processing */
+       struct list_head qp_wait_list;
+};
+
+struct qib_sge_state;
+
+struct qib_sdma_txreq {
+       int                 flags;
+       int                 sg_count;
+       dma_addr_t          addr;
+       void              (*callback)(struct qib_sdma_txreq *, int);
+       u16                 start_idx;  /* sdma private */
+       u16                 next_descq_idx;  /* sdma private */
+       struct list_head    list;       /* sdma private */
+};
+
+struct qib_sdma_desc {
+       __le64 qw[2];
+};
+
+struct qib_verbs_txreq {
+       struct qib_sdma_txreq   txreq;
+       struct qib_qp           *qp;
+       struct qib_swqe         *wqe;
+       u32                     dwords;
+       u16                     hdr_dwords;
+       u16                     hdr_inx;
+       struct qib_pio_header   *align_buf;
+       struct qib_mregion      *mr;
+       struct qib_sge_state    *ss;
+};
+
+#define QIB_SDMA_TXREQ_F_USELARGEBUF  0x1
+#define QIB_SDMA_TXREQ_F_HEADTOHOST   0x2
+#define QIB_SDMA_TXREQ_F_INTREQ       0x4
+#define QIB_SDMA_TXREQ_F_FREEBUF      0x8
+#define QIB_SDMA_TXREQ_F_FREEDESC     0x10
+
+#define QIB_SDMA_TXREQ_S_OK        0
+#define QIB_SDMA_TXREQ_S_SENDERROR 1
+#define QIB_SDMA_TXREQ_S_ABORTED   2
+#define QIB_SDMA_TXREQ_S_SHUTDOWN  3
+
+/*
+ * Get/Set IB link-level config parameters for f_get/set_ib_cfg()
+ * Mostly for MADs that set or query link parameters, also ipath
+ * config interfaces
+ */
+#define QIB_IB_CFG_LIDLMC 0 /* LID (LS16b) and Mask (MS16b) */
+#define QIB_IB_CFG_LWID_ENB 2 /* allowed Link-width */
+#define QIB_IB_CFG_LWID 3 /* currently active Link-width */
+#define QIB_IB_CFG_SPD_ENB 4 /* allowed Link speeds */
+#define QIB_IB_CFG_SPD 5 /* current Link spd */
+#define QIB_IB_CFG_RXPOL_ENB 6 /* Auto-RX-polarity enable */
+#define QIB_IB_CFG_LREV_ENB 7 /* Auto-Lane-reversal enable */
+#define QIB_IB_CFG_LINKLATENCY 8 /* Link Latency (IB1.2 only) */
+#define QIB_IB_CFG_HRTBT 9 /* IB heartbeat off/enable/auto; DDR/QDR only */
+#define QIB_IB_CFG_OP_VLS 10 /* operational VLs */
+#define QIB_IB_CFG_VL_HIGH_CAP 11 /* num of VL high priority weights */
+#define QIB_IB_CFG_VL_LOW_CAP 12 /* num of VL low priority weights */
+#define QIB_IB_CFG_OVERRUN_THRESH 13 /* IB overrun threshold */
+#define QIB_IB_CFG_PHYERR_THRESH 14 /* IB PHY error threshold */
+#define QIB_IB_CFG_LINKDEFAULT 15 /* IB link default (sleep/poll) */
+#define QIB_IB_CFG_PKEYS 16 /* update partition keys */
+#define QIB_IB_CFG_MTU 17 /* update MTU in IBC */
+#define QIB_IB_CFG_LSTATE 18 /* update linkcmd and linkinitcmd in IBC */
+#define QIB_IB_CFG_VL_HIGH_LIMIT 19
+#define QIB_IB_CFG_PMA_TICKS 20 /* PMA sample tick resolution */
+#define QIB_IB_CFG_PORT 21 /* switch port we are connected to */
+
+/*
+ * for CFG_LSTATE: LINKCMD in upper 16 bits, LINKINITCMD in lower 16
+ * IB_LINKINITCMD_POLL and SLEEP are also used as set/get values for
+ * QIB_IB_CFG_LINKDEFAULT cmd
+ */
+#define   IB_LINKCMD_DOWN   (0 << 16)
+#define   IB_LINKCMD_ARMED  (1 << 16)
+#define   IB_LINKCMD_ACTIVE (2 << 16)
+#define   IB_LINKINITCMD_NOP     0
+#define   IB_LINKINITCMD_POLL    1
+#define   IB_LINKINITCMD_SLEEP   2
+#define   IB_LINKINITCMD_DISABLE 3
+
+/*
+ * valid states passed to qib_set_linkstate() user call
+ */
+#define QIB_IB_LINKDOWN         0
+#define QIB_IB_LINKARM          1
+#define QIB_IB_LINKACTIVE       2
+#define QIB_IB_LINKDOWN_ONLY    3
+#define QIB_IB_LINKDOWN_SLEEP   4
+#define QIB_IB_LINKDOWN_DISABLE 5
+
+/*
+ * These 7 values (SDR, DDR, and QDR may be ORed for auto-speed
+ * negotiation) are used for the 3rd argument to path_f_set_ib_cfg
+ * with cmd QIB_IB_CFG_SPD_ENB, by direct calls or via sysfs.  They
+ * are also the the possible values for qib_link_speed_enabled and active
+ * The values were chosen to match values used within the IB spec.
+ */
+#define QIB_IB_SDR 1
+#define QIB_IB_DDR 2
+#define QIB_IB_QDR 4
+
+#define QIB_DEFAULT_MTU 4096
+
+/*
+ * Possible IB config parameters for f_get/set_ib_table()
+ */
+#define QIB_IB_TBL_VL_HIGH_ARB 1 /* Get/set VL high priority weights */
+#define QIB_IB_TBL_VL_LOW_ARB 2 /* Get/set VL low priority weights */
+
+/*
+ * Possible "operations" for f_rcvctrl(ppd, op, ctxt)
+ * these are bits so they can be combined, e.g.
+ * QIB_RCVCTRL_INTRAVAIL_ENB | QIB_RCVCTRL_CTXT_ENB
+ */
+#define QIB_RCVCTRL_TAILUPD_ENB 0x01
+#define QIB_RCVCTRL_TAILUPD_DIS 0x02
+#define QIB_RCVCTRL_CTXT_ENB 0x04
+#define QIB_RCVCTRL_CTXT_DIS 0x08
+#define QIB_RCVCTRL_INTRAVAIL_ENB 0x10
+#define QIB_RCVCTRL_INTRAVAIL_DIS 0x20
+#define QIB_RCVCTRL_PKEY_ENB 0x40  /* Note, default is enabled */
+#define QIB_RCVCTRL_PKEY_DIS 0x80
+#define QIB_RCVCTRL_BP_ENB 0x0100
+#define QIB_RCVCTRL_BP_DIS 0x0200
+#define QIB_RCVCTRL_TIDFLOW_ENB 0x0400
+#define QIB_RCVCTRL_TIDFLOW_DIS 0x0800
+
+/*
+ * Possible "operations" for f_sendctrl(ppd, op, var)
+ * these are bits so they can be combined, e.g.
+ * QIB_SENDCTRL_BUFAVAIL_ENB | QIB_SENDCTRL_ENB
+ * Some operations (e.g. DISARM, ABORT) are known to
+ * be "one-shot", so do not modify shadow.
+ */
+#define QIB_SENDCTRL_DISARM       (0x1000)
+#define QIB_SENDCTRL_DISARM_BUF(bufn) ((bufn) | QIB_SENDCTRL_DISARM)
+       /* available (0x2000) */
+#define QIB_SENDCTRL_AVAIL_DIS    (0x4000)
+#define QIB_SENDCTRL_AVAIL_ENB    (0x8000)
+#define QIB_SENDCTRL_AVAIL_BLIP  (0x10000)
+#define QIB_SENDCTRL_SEND_DIS    (0x20000)
+#define QIB_SENDCTRL_SEND_ENB    (0x40000)
+#define QIB_SENDCTRL_FLUSH       (0x80000)
+#define QIB_SENDCTRL_CLEAR      (0x100000)
+#define QIB_SENDCTRL_DISARM_ALL (0x200000)
+
+/*
+ * These are the generic indices for requesting per-port
+ * counter values via the f_portcntr function.  They
+ * are always returned as 64 bit values, although most
+ * are 32 bit counters.
+ */
+/* send-related counters */
+#define QIBPORTCNTR_PKTSEND         0U
+#define QIBPORTCNTR_WORDSEND        1U
+#define QIBPORTCNTR_PSXMITDATA      2U
+#define QIBPORTCNTR_PSXMITPKTS      3U
+#define QIBPORTCNTR_PSXMITWAIT      4U
+#define QIBPORTCNTR_SENDSTALL       5U
+/* receive-related counters */
+#define QIBPORTCNTR_PKTRCV          6U
+#define QIBPORTCNTR_PSRCVDATA       7U
+#define QIBPORTCNTR_PSRCVPKTS       8U
+#define QIBPORTCNTR_RCVEBP          9U
+#define QIBPORTCNTR_RCVOVFL         10U
+#define QIBPORTCNTR_WORDRCV         11U
+/* IB link related error counters */
+#define QIBPORTCNTR_RXLOCALPHYERR   12U
+#define QIBPORTCNTR_RXVLERR         13U
+#define QIBPORTCNTR_ERRICRC         14U
+#define QIBPORTCNTR_ERRVCRC         15U
+#define QIBPORTCNTR_ERRLPCRC        16U
+#define QIBPORTCNTR_BADFORMAT       17U
+#define QIBPORTCNTR_ERR_RLEN        18U
+#define QIBPORTCNTR_IBSYMBOLERR     19U
+#define QIBPORTCNTR_INVALIDRLEN     20U
+#define QIBPORTCNTR_UNSUPVL         21U
+#define QIBPORTCNTR_EXCESSBUFOVFL   22U
+#define QIBPORTCNTR_ERRLINK         23U
+#define QIBPORTCNTR_IBLINKDOWN      24U
+#define QIBPORTCNTR_IBLINKERRRECOV  25U
+#define QIBPORTCNTR_LLI             26U
+/* other error counters */
+#define QIBPORTCNTR_RXDROPPKT       27U
+#define QIBPORTCNTR_VL15PKTDROP     28U
+#define QIBPORTCNTR_ERRPKEY         29U
+#define QIBPORTCNTR_KHDROVFL        30U
+/* sampling counters (these are actually control registers) */
+#define QIBPORTCNTR_PSINTERVAL      31U
+#define QIBPORTCNTR_PSSTART         32U
+#define QIBPORTCNTR_PSSTAT          33U
+
+/* how often we check for packet activity for "power on hours (in seconds) */
+#define ACTIVITY_TIMER 5
+
+/* Below is an opaque struct. Each chip (device) can maintain
+ * private data needed for its operation, but not germane to the
+ * rest of the driver.  For convenience, we define another that
+ * is chip-specific, per-port
+ */
+struct qib_chip_specific;
+struct qib_chipport_specific;
+
+enum qib_sdma_states {
+       qib_sdma_state_s00_hw_down,
+       qib_sdma_state_s10_hw_start_up_wait,
+       qib_sdma_state_s20_idle,
+       qib_sdma_state_s30_sw_clean_up_wait,
+       qib_sdma_state_s40_hw_clean_up_wait,
+       qib_sdma_state_s50_hw_halt_wait,
+       qib_sdma_state_s99_running,
+};
+
+enum qib_sdma_events {
+       qib_sdma_event_e00_go_hw_down,
+       qib_sdma_event_e10_go_hw_start,
+       qib_sdma_event_e20_hw_started,
+       qib_sdma_event_e30_go_running,
+       qib_sdma_event_e40_sw_cleaned,
+       qib_sdma_event_e50_hw_cleaned,
+       qib_sdma_event_e60_hw_halted,
+       qib_sdma_event_e70_go_idle,
+       qib_sdma_event_e7220_err_halted,
+       qib_sdma_event_e7322_err_halted,
+       qib_sdma_event_e90_timer_tick,
+};
+
+extern char *qib_sdma_state_names[];
+extern char *qib_sdma_event_names[];
+
+struct sdma_set_state_action {
+       unsigned op_enable:1;
+       unsigned op_intenable:1;
+       unsigned op_halt:1;
+       unsigned op_drain:1;
+       unsigned go_s99_running_tofalse:1;
+       unsigned go_s99_running_totrue:1;
+};
+
+struct qib_sdma_state {
+       struct kref          kref;
+       struct completion    comp;
+       enum qib_sdma_states current_state;
+       struct sdma_set_state_action *set_state_action;
+       unsigned             current_op;
+       unsigned             go_s99_running;
+       unsigned             first_sendbuf;
+       unsigned             last_sendbuf; /* really last +1 */
+       /* debugging/devel */
+       enum qib_sdma_states previous_state;
+       unsigned             previous_op;
+       enum qib_sdma_events last_event;
+};
+
+struct xmit_wait {
+       struct timer_list timer;
+       u64 counter;
+       u8 flags;
+       struct cache {
+               u64 psxmitdata;
+               u64 psrcvdata;
+               u64 psxmitpkts;
+               u64 psrcvpkts;
+               u64 psxmitwait;
+       } counter_cache;
+};
+
+/*
+ * The structure below encapsulates data relevant to a physical IB Port.
+ * Current chips support only one such port, but the separation
+ * clarifies things a bit. Note that to conform to IB conventions,
+ * port-numbers are one-based. The first or only port is port1.
+ */
+struct qib_pportdata {
+       struct qib_ibport ibport_data;
+
+       struct qib_devdata *dd;
+       struct qib_chippport_specific *cpspec; /* chip-specific per-port */
+       struct kobject pport_kobj;
+       struct kobject sl2vl_kobj;
+       struct kobject diagc_kobj;
+
+       /* GUID for this interface, in network order */
+       __be64 guid;
+
+       /* QIB_POLL, etc. link-state specific flags, per port */
+       u32 lflags;
+       /* qib_lflags driver is waiting for */
+       u32 state_wanted;
+       spinlock_t lflags_lock;
+       /* number of (port-specific) interrupts for this port -- saturates... */
+       u32 int_counter;
+
+       /* ref count for each pkey */
+       atomic_t pkeyrefs[4];
+
+       /*
+        * this address is mapped readonly into user processes so they can
+        * get status cheaply, whenever they want.  One qword of status per port
+        */
+       u64 *statusp;
+
+       /* SendDMA related entries */
+       spinlock_t            sdma_lock;
+       struct qib_sdma_state sdma_state;
+       unsigned long         sdma_buf_jiffies;
+       struct qib_sdma_desc *sdma_descq;
+       u64                   sdma_descq_added;
+       u64                   sdma_descq_removed;
+       u16                   sdma_descq_cnt;
+       u16                   sdma_descq_tail;
+       u16                   sdma_descq_head;
+       u16                   sdma_next_intr;
+       u16                   sdma_reset_wait;
+       u8                    sdma_generation;
+       struct tasklet_struct sdma_sw_clean_up_task;
+       struct list_head      sdma_activelist;
+
+       dma_addr_t       sdma_descq_phys;
+       volatile __le64 *sdma_head_dma; /* DMA'ed by chip */
+       dma_addr_t       sdma_head_phys;
+
+       wait_queue_head_t state_wait; /* for state_wanted */
+
+       /* HoL blocking for SMP replies */
+       unsigned          hol_state;
+       struct timer_list hol_timer;
+
+       /*
+        * Shadow copies of registers; size indicates read access size.
+        * Most of them are readonly, but some are write-only register,
+        * where we manipulate the bits in the shadow copy, and then write
+        * the shadow copy to qlogic_ib.
+        *
+        * We deliberately make most of these 32 bits, since they have
+        * restricted range.  For any that we read, we won't to generate 32
+        * bit accesses, since Opteron will generate 2 separate 32 bit HT
+        * transactions for a 64 bit read, and we want to avoid unnecessary
+        * bus transactions.
+        */
+
+       /* This is the 64 bit group */
+       /* last ibcstatus.  opaque outside chip-specific code */
+       u64 lastibcstat;
+
+       /* these are the "32 bit" regs */
+
+       /*
+        * the following two are 32-bit bitmasks, but {test,clear,set}_bit
+        * all expect bit fields to be "unsigned long"
+        */
+       unsigned long p_rcvctrl; /* shadow per-port rcvctrl */
+       unsigned long p_sendctrl; /* shadow per-port sendctrl */
+
+       u32 ibmtu; /* The MTU programmed for this unit */
+       /*
+        * Current max size IB packet (in bytes) including IB headers, that
+        * we can send. Changes when ibmtu changes.
+        */
+       u32 ibmaxlen;
+       /*
+        * ibmaxlen at init time, limited by chip and by receive buffer
+        * size.  Not changed after init.
+        */
+       u32 init_ibmaxlen;
+       /* LID programmed for this instance */
+       u16 lid;
+       /* list of pkeys programmed; 0 if not set */
+       u16 pkeys[4];
+       /* LID mask control */
+       u8 lmc;
+       u8 link_width_supported;
+       u8 link_speed_supported;
+       u8 link_width_enabled;
+       u8 link_speed_enabled;
+       u8 link_width_active;
+       u8 link_speed_active;
+       u8 vls_supported;
+       u8 vls_operational;
+       /* Rx Polarity inversion (compensate for ~tx on partner) */
+       u8 rx_pol_inv;
+
+       u8 hw_pidx;     /* physical port index */
+       u8 port;        /* IB port number and index into dd->pports - 1 */
+
+       u8 delay_mult;
+
+       /* used to override LED behavior */
+       u8 led_override;  /* Substituted for normal value, if non-zero */
+       u16 led_override_timeoff; /* delta to next timer event */
+       u8 led_override_vals[2]; /* Alternates per blink-frame */
+       u8 led_override_phase; /* Just counts, LSB picks from vals[] */
+       atomic_t led_override_timer_active;
+       /* Used to flash LEDs in override mode */
+       struct timer_list led_override_timer;
+       struct xmit_wait cong_stats;
+       struct timer_list symerr_clear_timer;
+};
+
+/* Observers. Not to be taken lightly, possibly not to ship. */
+/*
+ * If a diag read or write is to (bottom <= offset <= top),
+ * the "hoook" is called, allowing, e.g. shadows to be
+ * updated in sync with the driver. struct diag_observer
+ * is the "visible" part.
+ */
+struct diag_observer;
+
+typedef int (*diag_hook) (struct qib_devdata *dd,
+       const struct diag_observer *op,
+       u32 offs, u64 *data, u64 mask, int only_32);
+
+struct diag_observer {
+       diag_hook hook;
+       u32 bottom;
+       u32 top;
+};
+
+extern int qib_register_observer(struct qib_devdata *dd,
+       const struct diag_observer *op);
+
+/* Only declared here, not defined. Private to diags */
+struct diag_observer_list_elt;
+
+/* device data struct now contains only "general per-device" info.
+ * fields related to a physical IB port are in a qib_pportdata struct,
+ * described above) while fields only used by a particualr chip-type are in
+ * a qib_chipdata struct, whose contents are opaque to this file.
+ */
+struct qib_devdata {
+       struct qib_ibdev verbs_dev;     /* must be first */
+       struct list_head list;
+       /* pointers to related structs for this device */
+       /* pci access data structure */
+       struct pci_dev *pcidev;
+       struct cdev *user_cdev;
+       struct cdev *diag_cdev;
+       struct device *user_device;
+       struct device *diag_device;
+
+       /* mem-mapped pointer to base of chip regs */
+       u64 __iomem *kregbase;
+       /* end of mem-mapped chip space excluding sendbuf and user regs */
+       u64 __iomem *kregend;
+       /* physical address of chip for io_remap, etc. */
+       resource_size_t physaddr;
+       /* qib_cfgctxts pointers */
+       struct qib_ctxtdata **rcd; /* Receive Context Data */
+
+       /* qib_pportdata, points to array of (physical) port-specific
+        * data structs, indexed by pidx (0..n-1)
+        */
+       struct qib_pportdata *pport;
+       struct qib_chip_specific *cspec; /* chip-specific */
+
+       /* kvirt address of 1st 2k pio buffer */
+       void __iomem *pio2kbase;
+       /* kvirt address of 1st 4k pio buffer */
+       void __iomem *pio4kbase;
+       /* mem-mapped pointer to base of PIO buffers (if using WC PAT) */
+       void __iomem *piobase;
+       /* mem-mapped pointer to base of user chip regs (if using WC PAT) */
+       u64 __iomem *userbase;
+       /*
+        * points to area where PIOavail registers will be DMA'ed.
+        * Has to be on a page of it's own, because the page will be
+        * mapped into user program space.  This copy is *ONLY* ever
+        * written by DMA, not by the driver!  Need a copy per device
+        * when we get to multiple devices
+        */
+       volatile __le64 *pioavailregs_dma; /* DMA'ed by chip */
+       /* physical address where updates occur */
+       dma_addr_t pioavailregs_phys;
+
+       /* device-specific implementations of functions needed by
+        * common code. Contrary to previous consensus, we can't
+        * really just point to a device-specific table, because we
+        * may need to "bend", e.g. *_f_put_tid
+        */
+       /* fallback to alternate interrupt type if possible */
+       int (*f_intr_fallback)(struct qib_devdata *);
+       /* hard reset chip */
+       int (*f_reset)(struct qib_devdata *);
+       void (*f_quiet_serdes)(struct qib_pportdata *);
+       int (*f_bringup_serdes)(struct qib_pportdata *);
+       int (*f_early_init)(struct qib_devdata *);
+       void (*f_clear_tids)(struct qib_devdata *, struct qib_ctxtdata *);
+       void (*f_put_tid)(struct qib_devdata *, u64 __iomem*,
+                               u32, unsigned long);
+       void (*f_cleanup)(struct qib_devdata *);
+       void (*f_setextled)(struct qib_pportdata *, u32);
+       /* fill out chip-specific fields */
+       int (*f_get_base_info)(struct qib_ctxtdata *, struct qib_base_info *);
+       /* free irq */
+       void (*f_free_irq)(struct qib_devdata *);
+       struct qib_message_header *(*f_get_msgheader)
+                                       (struct qib_devdata *, __le32 *);
+       void (*f_config_ctxts)(struct qib_devdata *);
+       int (*f_get_ib_cfg)(struct qib_pportdata *, int);
+       int (*f_set_ib_cfg)(struct qib_pportdata *, int, u32);
+       int (*f_set_ib_loopback)(struct qib_pportdata *, const char *);
+       int (*f_get_ib_table)(struct qib_pportdata *, int, void *);
+       int (*f_set_ib_table)(struct qib_pportdata *, int, void *);
+       u32 (*f_iblink_state)(u64);
+       u8 (*f_ibphys_portstate)(u64);
+       void (*f_xgxs_reset)(struct qib_pportdata *);
+       /* per chip actions needed for IB Link up/down changes */
+       int (*f_ib_updown)(struct qib_pportdata *, int, u64);
+       u32 __iomem *(*f_getsendbuf)(struct qib_pportdata *, u64, u32 *);
+       /* Read/modify/write of GPIO pins (potentially chip-specific */
+       int (*f_gpio_mod)(struct qib_devdata *dd, u32 out, u32 dir,
+               u32 mask);
+       /* Enable writes to config EEPROM (if supported) */
+       int (*f_eeprom_wen)(struct qib_devdata *dd, int wen);
+       /*
+        * modify rcvctrl shadow[s] and write to appropriate chip-regs.
+        * see above QIB_RCVCTRL_xxx_ENB/DIS for operations.
+        * (ctxt == -1) means "all contexts", only meaningful for
+        * clearing. Could remove if chip_spec shutdown properly done.
+        */
+       void (*f_rcvctrl)(struct qib_pportdata *, unsigned int op,
+               int ctxt);
+       /* Read/modify/write sendctrl appropriately for op and port. */
+       void (*f_sendctrl)(struct qib_pportdata *, u32 op);
+       void (*f_set_intr_state)(struct qib_devdata *, u32);
+       void (*f_set_armlaunch)(struct qib_devdata *, u32);
+       void (*f_wantpiobuf_intr)(struct qib_devdata *, u32);
+       int (*f_late_initreg)(struct qib_devdata *);
+       int (*f_init_sdma_regs)(struct qib_pportdata *);
+       u16 (*f_sdma_gethead)(struct qib_pportdata *);
+       int (*f_sdma_busy)(struct qib_pportdata *);
+       void (*f_sdma_update_tail)(struct qib_pportdata *, u16);
+       void (*f_sdma_set_desc_cnt)(struct qib_pportdata *, unsigned);
+       void (*f_sdma_sendctrl)(struct qib_pportdata *, unsigned);
+       void (*f_sdma_hw_clean_up)(struct qib_pportdata *);
+       void (*f_sdma_hw_start_up)(struct qib_pportdata *);
+       void (*f_sdma_init_early)(struct qib_pportdata *);
+       void (*f_set_cntr_sample)(struct qib_pportdata *, u32, u32);
+       void (*f_update_usrhead)(struct qib_ctxtdata *, u64, u32, u32);
+       u32 (*f_hdrqempty)(struct qib_ctxtdata *);
+       u64 (*f_portcntr)(struct qib_pportdata *, u32);
+       u32 (*f_read_cntrs)(struct qib_devdata *, loff_t, char **,
+               u64 **);
+       u32 (*f_read_portcntrs)(struct qib_devdata *, loff_t, u32,
+               char **, u64 **);
+       u32 (*f_setpbc_control)(struct qib_pportdata *, u32, u8, u8);
+       void (*f_initvl15_bufs)(struct qib_devdata *);
+       void (*f_init_ctxt)(struct qib_ctxtdata *);
+       void (*f_txchk_change)(struct qib_devdata *, u32, u32, u32,
+               struct qib_ctxtdata *);
+       void (*f_writescratch)(struct qib_devdata *, u32);
+       int (*f_tempsense_rd)(struct qib_devdata *, int regnum);
+
+       char *boardname; /* human readable board info */
+
+       /* template for writing TIDs  */
+       u64 tidtemplate;
+       /* value to write to free TIDs */
+       u64 tidinvalid;
+
+       /* number of registers used for pioavail */
+       u32 pioavregs;
+       /* device (not port) flags, basically device capabilities */
+       u32 flags;
+       /* last buffer for user use */
+       u32 lastctxt_piobuf;
+
+       /* saturating counter of (non-port-specific) device interrupts */
+       u32 int_counter;
+
+       /* pio bufs allocated per ctxt */
+       u32 pbufsctxt;
+       /* if remainder on bufs/ctxt, ctxts < extrabuf get 1 extra */
+       u32 ctxts_extrabuf;
+       /*
+        * number of ctxts configured as max; zero is set to number chip
+        * supports, less gives more pio bufs/ctxt, etc.
+        */
+       u32 cfgctxts;
+
+       /*
+        * hint that we should update pioavailshadow before
+        * looking for a PIO buffer
+        */
+       u32 upd_pio_shadow;
+
+       /* internal debugging stats */
+       u32 maxpkts_call;
+       u32 avgpkts_call;
+       u64 nopiobufs;
+
+       /* PCI Vendor ID (here for NodeInfo) */
+       u16 vendorid;
+       /* PCI Device ID (here for NodeInfo) */
+       u16 deviceid;
+       /* for write combining settings */
+       unsigned long wc_cookie;
+       unsigned long wc_base;
+       unsigned long wc_len;
+
+       /* shadow copy of struct page *'s for exp tid pages */
+       struct page **pageshadow;
+       /* shadow copy of dma handles for exp tid pages */
+       dma_addr_t *physshadow;
+       u64 __iomem *egrtidbase;
+       spinlock_t sendctrl_lock; /* protect changes to sendctrl shadow */
+       /* around rcd and (user ctxts) ctxt_cnt use (intr vs free) */
+       spinlock_t uctxt_lock; /* rcd and user context changes */
+       /*
+        * per unit status, see also portdata statusp
+        * mapped readonly into user processes so they can get unit and
+        * IB link status cheaply
+        */
+       u64 *devstatusp;
+       char *freezemsg; /* freeze msg if hw error put chip in freeze */
+       u32 freezelen; /* max length of freezemsg */
+       /* timer used to prevent stats overflow, error throttling, etc. */
+       struct timer_list stats_timer;
+
+       /* timer to verify interrupts work, and fallback if possible */
+       struct timer_list intrchk_timer;
+       unsigned long ureg_align; /* user register alignment */
+
+       /*
+        * Protects pioavailshadow, pioavailkernel, pio_need_disarm, and
+        * pio_writing.
+        */
+       spinlock_t pioavail_lock;
+
+       /*
+        * Shadow copies of registers; size indicates read access size.
+        * Most of them are readonly, but some are write-only register,
+        * where we manipulate the bits in the shadow copy, and then write
+        * the shadow copy to qlogic_ib.
+        *
+        * We deliberately make most of these 32 bits, since they have
+        * restricted range.  For any that we read, we won't to generate 32
+        * bit accesses, since Opteron will generate 2 separate 32 bit HT
+        * transactions for a 64 bit read, and we want to avoid unnecessary
+        * bus transactions.
+        */
+
+       /* This is the 64 bit group */
+
+       unsigned long pioavailshadow[6];
+       /* bitmap of send buffers available for the kernel to use with PIO. */
+       unsigned long pioavailkernel[6];
+       /* bitmap of send buffers which need to be disarmed. */
+       unsigned long pio_need_disarm[3];
+       /* bitmap of send buffers which are being written to. */
+       unsigned long pio_writing[3];
+       /* kr_revision shadow */
+       u64 revision;
+       /* Base GUID for device (from eeprom, network order) */
+       __be64 base_guid;
+
+       /*
+        * kr_sendpiobufbase value (chip offset of pio buffers), and the
+        * base of the 2KB buffer s(user processes only use 2K)
+        */
+       u64 piobufbase;
+       u32 pio2k_bufbase;
+
+       /* these are the "32 bit" regs */
+
+       /* number of GUIDs in the flash for this interface */
+       u32 nguid;
+       /*
+        * the following two are 32-bit bitmasks, but {test,clear,set}_bit
+        * all expect bit fields to be "unsigned long"
+        */
+       unsigned long rcvctrl; /* shadow per device rcvctrl */
+       unsigned long sendctrl; /* shadow per device sendctrl */
+
+       /* value we put in kr_rcvhdrcnt */
+       u32 rcvhdrcnt;
+       /* value we put in kr_rcvhdrsize */
+       u32 rcvhdrsize;
+       /* value we put in kr_rcvhdrentsize */
+       u32 rcvhdrentsize;
+       /* kr_ctxtcnt value */
+       u32 ctxtcnt;
+       /* kr_pagealign value */
+       u32 palign;
+       /* number of "2KB" PIO buffers */
+       u32 piobcnt2k;
+       /* size in bytes of "2KB" PIO buffers */
+       u32 piosize2k;
+       /* max usable size in dwords of a "2KB" PIO buffer before going "4KB" */
+       u32 piosize2kmax_dwords;
+       /* number of "4KB" PIO buffers */
+       u32 piobcnt4k;
+       /* size in bytes of "4KB" PIO buffers */
+       u32 piosize4k;
+       /* kr_rcvegrbase value */
+       u32 rcvegrbase;
+       /* kr_rcvtidbase value */
+       u32 rcvtidbase;
+       /* kr_rcvtidcnt value */
+       u32 rcvtidcnt;
+       /* kr_userregbase */
+       u32 uregbase;
+       /* shadow the control register contents */
+       u32 control;
+
+       /* chip address space used by 4k pio buffers */
+       u32 align4k;
+       /* size of each rcvegrbuffer */
+       u32 rcvegrbufsize;
+       /* localbus width (1, 2,4,8,16,32) from config space  */
+       u32 lbus_width;
+       /* localbus speed in MHz */
+       u32 lbus_speed;
+       int unit; /* unit # of this chip */
+
+       /* start of CHIP_SPEC move to chipspec, but need code changes */
+       /* low and high portions of MSI capability/vector */
+       u32 msi_lo;
+       /* saved after PCIe init for restore after reset */
+       u32 msi_hi;
+       /* MSI data (vector) saved for restore */
+       u16 msi_data;
+       /* so we can rewrite it after a chip reset */
+       u32 pcibar0;
+       /* so we can rewrite it after a chip reset */
+       u32 pcibar1;
+       u64 rhdrhead_intr_off;
+
+       /*
+        * ASCII serial number, from flash, large enough for original
+        * all digit strings, and longer QLogic serial number format
+        */
+       u8 serial[16];
+       /* human readable board version */
+       u8 boardversion[96];
+       u8 lbus_info[32]; /* human readable localbus info */
+       /* chip major rev, from qib_revision */
+       u8 majrev;
+       /* chip minor rev, from qib_revision */
+       u8 minrev;
+
+       /* Misc small ints */
+       /* Number of physical ports available */
+       u8 num_pports;
+       /* Lowest context number which can be used by user processes */
+       u8 first_user_ctxt;
+       u8 n_krcv_queues;
+       u8 qpn_mask;
+       u8 skip_kctxt_mask;
+
+       u16 rhf_offset; /* offset of RHF within receive header entry */
+
+       /*
+        * GPIO pins for twsi-connected devices, and device code for eeprom
+        */
+       u8 gpio_sda_num;
+       u8 gpio_scl_num;
+       u8 twsi_eeprom_dev;
+       u8 board_atten;
+
+       /* Support (including locks) for EEPROM logging of errors and time */
+       /* control access to actual counters, timer */
+       spinlock_t eep_st_lock;
+       /* control high-level access to EEPROM */
+       struct mutex eep_lock;
+       uint64_t traffic_wds;
+       /* active time is kept in seconds, but logged in hours */
+       atomic_t active_time;
+       /* Below are nominal shadow of EEPROM, new since last EEPROM update */
+       uint8_t eep_st_errs[QIB_EEP_LOG_CNT];
+       uint8_t eep_st_new_errs[QIB_EEP_LOG_CNT];
+       uint16_t eep_hrs;
+       /*
+        * masks for which bits of errs, hwerrs that cause
+        * each of the counters to increment.
+        */
+       struct qib_eep_log_mask eep_st_masks[QIB_EEP_LOG_CNT];
+       struct qib_diag_client *diag_client;
+       spinlock_t qib_diag_trans_lock; /* protect diag observer ops */
+       struct diag_observer_list_elt *diag_observer_list;
+
+       u8 psxmitwait_supported;
+       /* cycle length of PS* counters in HW (in picoseconds) */
+       u16 psxmitwait_check_rate;
+};
+
+/* hol_state values */
+#define QIB_HOL_UP       0
+#define QIB_HOL_INIT     1
+
+#define QIB_SDMA_SENDCTRL_OP_ENABLE    (1U << 0)
+#define QIB_SDMA_SENDCTRL_OP_INTENABLE (1U << 1)
+#define QIB_SDMA_SENDCTRL_OP_HALT      (1U << 2)
+#define QIB_SDMA_SENDCTRL_OP_CLEANUP   (1U << 3)
+#define QIB_SDMA_SENDCTRL_OP_DRAIN     (1U << 4)
+
+/* operation types for f_txchk_change() */
+#define TXCHK_CHG_TYPE_DIS1  3
+#define TXCHK_CHG_TYPE_ENAB1 2
+#define TXCHK_CHG_TYPE_KERN  1
+#define TXCHK_CHG_TYPE_USER  0
+
+#define QIB_CHASE_TIME msecs_to_jiffies(145)
+#define QIB_CHASE_DIS_TIME msecs_to_jiffies(160)
+
+/* Private data for file operations */
+struct qib_filedata {
+       struct qib_ctxtdata *rcd;
+       unsigned subctxt;
+       unsigned tidcursor;
+       struct qib_user_sdma_queue *pq;
+       int rec_cpu_num; /* for cpu affinity; -1 if none */
+};
+
+extern struct list_head qib_dev_list;
+extern spinlock_t qib_devs_lock;
+extern struct qib_devdata *qib_lookup(int unit);
+extern u32 qib_cpulist_count;
+extern unsigned long *qib_cpulist;
+
+extern unsigned qib_wc_pat;
+int qib_init(struct qib_devdata *, int);
+int init_chip_wc_pat(struct qib_devdata *dd, u32);
+int qib_enable_wc(struct qib_devdata *dd);
+void qib_disable_wc(struct qib_devdata *dd);
+int qib_count_units(int *npresentp, int *nupp);
+int qib_count_active_units(void);
+
+int qib_cdev_init(int minor, const char *name,
+                 const struct file_operations *fops,
+                 struct cdev **cdevp, struct device **devp);
+void qib_cdev_cleanup(struct cdev **cdevp, struct device **devp);
+int qib_dev_init(void);
+void qib_dev_cleanup(void);
+
+int qib_diag_add(struct qib_devdata *);
+void qib_diag_remove(struct qib_devdata *);
+void qib_handle_e_ibstatuschanged(struct qib_pportdata *, u64);
+void qib_sdma_update_tail(struct qib_pportdata *, u16); /* hold sdma_lock */
+
+int qib_decode_err(struct qib_devdata *dd, char *buf, size_t blen, u64 err);
+void qib_bad_intrstatus(struct qib_devdata *);
+void qib_handle_urcv(struct qib_devdata *, u64);
+
+/* clean up any per-chip chip-specific stuff */
+void qib_chip_cleanup(struct qib_devdata *);
+/* clean up any chip type-specific stuff */
+void qib_chip_done(void);
+
+/* check to see if we have to force ordering for write combining */
+int qib_unordered_wc(void);
+void qib_pio_copy(void __iomem *to, const void *from, size_t count);
+
+void qib_disarm_piobufs(struct qib_devdata *, unsigned, unsigned);
+int qib_disarm_piobufs_ifneeded(struct qib_ctxtdata *);
+void qib_disarm_piobufs_set(struct qib_devdata *, unsigned long *, unsigned);
+void qib_cancel_sends(struct qib_pportdata *);
+
+int qib_create_rcvhdrq(struct qib_devdata *, struct qib_ctxtdata *);
+int qib_setup_eagerbufs(struct qib_ctxtdata *);
+void qib_set_ctxtcnt(struct qib_devdata *);
+int qib_create_ctxts(struct qib_devdata *dd);
+struct qib_ctxtdata *qib_create_ctxtdata(struct qib_pportdata *, u32);
+void qib_init_pportdata(struct qib_pportdata *, struct qib_devdata *, u8, u8);
+void qib_free_ctxtdata(struct qib_devdata *, struct qib_ctxtdata *);
+
+u32 qib_kreceive(struct qib_ctxtdata *, u32 *, u32 *);
+int qib_reset_device(int);
+int qib_wait_linkstate(struct qib_pportdata *, u32, int);
+int qib_set_linkstate(struct qib_pportdata *, u8);
+int qib_set_mtu(struct qib_pportdata *, u16);
+int qib_set_lid(struct qib_pportdata *, u32, u8);
+void qib_hol_down(struct qib_pportdata *);
+void qib_hol_init(struct qib_pportdata *);
+void qib_hol_up(struct qib_pportdata *);
+void qib_hol_event(unsigned long);
+void qib_disable_after_error(struct qib_devdata *);
+int qib_set_uevent_bits(struct qib_pportdata *, const int);
+
+/* for use in system calls, where we want to know device type, etc. */
+#define ctxt_fp(fp) \
+       (((struct qib_filedata *)(fp)->private_data)->rcd)
+#define subctxt_fp(fp) \
+       (((struct qib_filedata *)(fp)->private_data)->subctxt)
+#define tidcursor_fp(fp) \
+       (((struct qib_filedata *)(fp)->private_data)->tidcursor)
+#define user_sdma_queue_fp(fp) \
+       (((struct qib_filedata *)(fp)->private_data)->pq)
+
+static inline struct qib_devdata *dd_from_ppd(struct qib_pportdata *ppd)
+{
+       return ppd->dd;
+}
+
+static inline struct qib_devdata *dd_from_dev(struct qib_ibdev *dev)
+{
+       return container_of(dev, struct qib_devdata, verbs_dev);
+}
+
+static inline struct qib_devdata *dd_from_ibdev(struct ib_device *ibdev)
+{
+       return dd_from_dev(to_idev(ibdev));
+}
+
+static inline struct qib_pportdata *ppd_from_ibp(struct qib_ibport *ibp)
+{
+       return container_of(ibp, struct qib_pportdata, ibport_data);
+}
+
+static inline struct qib_ibport *to_iport(struct ib_device *ibdev, u8 port)
+{
+       struct qib_devdata *dd = dd_from_ibdev(ibdev);
+       unsigned pidx = port - 1; /* IB number port from 1, hdw from 0 */
+
+       WARN_ON(pidx >= dd->num_pports);
+       return &dd->pport[pidx].ibport_data;
+}
+
+/*
+ * values for dd->flags (_device_ related flags) and
+ */
+#define QIB_HAS_LINK_LATENCY  0x1 /* supports link latency (IB 1.2) */
+#define QIB_INITTED           0x2 /* chip and driver up and initted */
+#define QIB_DOING_RESET       0x4  /* in the middle of doing chip reset */
+#define QIB_PRESENT           0x8  /* chip accesses can be done */
+#define QIB_PIO_FLUSH_WC      0x10 /* Needs Write combining flush for PIO */
+#define QIB_HAS_THRESH_UPDATE 0x40
+#define QIB_HAS_SDMA_TIMEOUT  0x80
+#define QIB_USE_SPCL_TRIG     0x100 /* SpecialTrigger launch enabled */
+#define QIB_NODMA_RTAIL       0x200 /* rcvhdrtail register DMA enabled */
+#define QIB_HAS_INTX          0x800 /* Supports INTx interrupts */
+#define QIB_HAS_SEND_DMA      0x1000 /* Supports Send DMA */
+#define QIB_HAS_VLSUPP        0x2000 /* Supports multiple VLs; PBC different */
+#define QIB_HAS_HDRSUPP       0x4000 /* Supports header suppression */
+#define QIB_BADINTR           0x8000 /* severe interrupt problems */
+#define QIB_DCA_ENABLED       0x10000 /* Direct Cache Access enabled */
+#define QIB_HAS_QSFP          0x20000 /* device (card instance) has QSFP */
+
+/*
+ * values for ppd->lflags (_ib_port_ related flags)
+ */
+#define QIBL_LINKV             0x1 /* IB link state valid */
+#define QIBL_LINKDOWN          0x8 /* IB link is down */
+#define QIBL_LINKINIT          0x10 /* IB link level is up */
+#define QIBL_LINKARMED         0x20 /* IB link is ARMED */
+#define QIBL_LINKACTIVE        0x40 /* IB link is ACTIVE */
+/* leave a gap for more IB-link state */
+#define QIBL_IB_AUTONEG_INPROG 0x1000 /* non-IBTA DDR/QDR neg active */
+#define QIBL_IB_AUTONEG_FAILED 0x2000 /* non-IBTA DDR/QDR neg failed */
+#define QIBL_IB_LINK_DISABLED  0x4000 /* Linkdown-disable forced,
+                                      * Do not try to bring up */
+#define QIBL_IB_FORCE_NOTIFY   0x8000 /* force notify on next ib change */
+
+/* IB dword length mask in PBC (lower 11 bits); same for all chips */
+#define QIB_PBC_LENGTH_MASK                     ((1 << 11) - 1)
+
+
+/* ctxt_flag bit offsets */
+               /* waiting for a packet to arrive */
+#define QIB_CTXT_WAITING_RCV   2
+               /* master has not finished initializing */
+#define QIB_CTXT_MASTER_UNINIT 4
+               /* waiting for an urgent packet to arrive */
+#define QIB_CTXT_WAITING_URG 5
+
+/* free up any allocated data at closes */
+void qib_free_data(struct qib_ctxtdata *dd);
+void qib_chg_pioavailkernel(struct qib_devdata *, unsigned, unsigned,
+                           u32, struct qib_ctxtdata *);
+struct qib_devdata *qib_init_iba7322_funcs(struct pci_dev *,
+                                          const struct pci_device_id *);
+struct qib_devdata *qib_init_iba7220_funcs(struct pci_dev *,
+                                          const struct pci_device_id *);
+struct qib_devdata *qib_init_iba6120_funcs(struct pci_dev *,
+                                          const struct pci_device_id *);
+void qib_free_devdata(struct qib_devdata *);
+struct qib_devdata *qib_alloc_devdata(struct pci_dev *pdev, size_t extra);
+
+#define QIB_TWSI_NO_DEV 0xFF
+/* Below qib_twsi_ functions must be called with eep_lock held */
+int qib_twsi_reset(struct qib_devdata *dd);
+int qib_twsi_blk_rd(struct qib_devdata *dd, int dev, int addr, void *buffer,
+                   int len);
+int qib_twsi_blk_wr(struct qib_devdata *dd, int dev, int addr,
+                   const void *buffer, int len);
+void qib_get_eeprom_info(struct qib_devdata *);
+int qib_update_eeprom_log(struct qib_devdata *dd);
+void qib_inc_eeprom_err(struct qib_devdata *dd, u32 eidx, u32 incr);
+void qib_dump_lookup_output_queue(struct qib_devdata *);
+void qib_force_pio_avail_update(struct qib_devdata *);
+void qib_clear_symerror_on_linkup(unsigned long opaque);
+
+/*
+ * Set LED override, only the two LSBs have "public" meaning, but
+ * any non-zero value substitutes them for the Link and LinkTrain
+ * LED states.
+ */
+#define QIB_LED_PHYS 1 /* Physical (linktraining) GREEN LED */
+#define QIB_LED_LOG 2  /* Logical (link) YELLOW LED */
+void qib_set_led_override(struct qib_pportdata *ppd, unsigned int val);
+
+/* send dma routines */
+int qib_setup_sdma(struct qib_pportdata *);
+void qib_teardown_sdma(struct qib_pportdata *);
+void __qib_sdma_intr(struct qib_pportdata *);
+void qib_sdma_intr(struct qib_pportdata *);
+int qib_sdma_verbs_send(struct qib_pportdata *, struct qib_sge_state *,
+                       u32, struct qib_verbs_txreq *);
+/* ppd->sdma_lock should be locked before calling this. */
+int qib_sdma_make_progress(struct qib_pportdata *dd);
+
+/* must be called under qib_sdma_lock */
+static inline u16 qib_sdma_descq_freecnt(const struct qib_pportdata *ppd)
+{
+       return ppd->sdma_descq_cnt -
+               (ppd->sdma_descq_added - ppd->sdma_descq_removed) - 1;
+}
+
+static inline int __qib_sdma_running(struct qib_pportdata *ppd)
+{
+       return ppd->sdma_state.current_state == qib_sdma_state_s99_running;
+}
+int qib_sdma_running(struct qib_pportdata *);
+
+void __qib_sdma_process_event(struct qib_pportdata *, enum qib_sdma_events);
+void qib_sdma_process_event(struct qib_pportdata *, enum qib_sdma_events);
+
+/*
+ * number of words used for protocol header if not set by qib_userinit();
+ */
+#define QIB_DFLT_RCVHDRSIZE 9
+
+/*
+ * We need to be able to handle an IB header of at least 24 dwords.
+ * We need the rcvhdrq large enough to handle largest IB header, but
+ * still have room for a 2KB MTU standard IB packet.
+ * Additionally, some processor/memory controller combinations
+ * benefit quite strongly from having the DMA'ed data be cacheline
+ * aligned and a cacheline multiple, so we set the size to 32 dwords
+ * (2 64-byte primary cachelines for pretty much all processors of
+ * interest).  The alignment hurts nothing, other than using somewhat
+ * more memory.
+ */
+#define QIB_RCVHDR_ENTSIZE 32
+
+int qib_get_user_pages(unsigned long, size_t, struct page **);
+void qib_release_user_pages(struct page **, size_t);
+int qib_eeprom_read(struct qib_devdata *, u8, void *, int);
+int qib_eeprom_write(struct qib_devdata *, u8, const void *, int);
+u32 __iomem *qib_getsendbuf_range(struct qib_devdata *, u32 *, u32, u32);
+void qib_sendbuf_done(struct qib_devdata *, unsigned);
+
+static inline void qib_clear_rcvhdrtail(const struct qib_ctxtdata *rcd)
+{
+       *((u64 *) rcd->rcvhdrtail_kvaddr) = 0ULL;
+}
+
+static inline u32 qib_get_rcvhdrtail(const struct qib_ctxtdata *rcd)
+{
+       /*
+        * volatile because it's a DMA target from the chip, routine is
+        * inlined, and don't want register caching or reordering.
+        */
+       return (u32) le64_to_cpu(
+               *((volatile __le64 *)rcd->rcvhdrtail_kvaddr)); /* DMA'ed */
+}
+
+static inline u32 qib_get_hdrqtail(const struct qib_ctxtdata *rcd)
+{
+       const struct qib_devdata *dd = rcd->dd;
+       u32 hdrqtail;
+
+       if (dd->flags & QIB_NODMA_RTAIL) {
+               __le32 *rhf_addr;
+               u32 seq;
+
+               rhf_addr = (__le32 *) rcd->rcvhdrq +
+                       rcd->head + dd->rhf_offset;
+               seq = qib_hdrget_seq(rhf_addr);
+               hdrqtail = rcd->head;
+               if (seq == rcd->seq_cnt)
+                       hdrqtail++;
+       } else
+               hdrqtail = qib_get_rcvhdrtail(rcd);
+
+       return hdrqtail;
+}
+
+/*
+ * sysfs interface.
+ */
+
+extern const char ib_qib_version[];
+
+int qib_device_create(struct qib_devdata *);
+void qib_device_remove(struct qib_devdata *);
+
+int qib_create_port_files(struct ib_device *ibdev, u8 port_num,
+                         struct kobject *kobj);
+int qib_verbs_register_sysfs(struct qib_devdata *);
+void qib_verbs_unregister_sysfs(struct qib_devdata *);
+/* Hook for sysfs read of QSFP */
+extern int qib_qsfp_dump(struct qib_pportdata *ppd, char *buf, int len);
+
+int __init qib_init_qibfs(void);
+int __exit qib_exit_qibfs(void);
+
+int qibfs_add(struct qib_devdata *);
+int qibfs_remove(struct qib_devdata *);
+
+int qib_pcie_init(struct pci_dev *, const struct pci_device_id *);
+int qib_pcie_ddinit(struct qib_devdata *, struct pci_dev *,
+                   const struct pci_device_id *);
+void qib_pcie_ddcleanup(struct qib_devdata *);
+int qib_pcie_params(struct qib_devdata *, u32, u32 *, struct msix_entry *);
+int qib_reinit_intr(struct qib_devdata *);
+void qib_enable_intx(struct pci_dev *);
+void qib_nomsi(struct qib_devdata *);
+void qib_nomsix(struct qib_devdata *);
+void qib_pcie_getcmd(struct qib_devdata *, u16 *, u8 *, u8 *);
+void qib_pcie_reenable(struct qib_devdata *, u16, u8, u8);
+
+/*
+ * dma_addr wrappers - all 0's invalid for hw
+ */
+dma_addr_t qib_map_page(struct pci_dev *, struct page *, unsigned long,
+                         size_t, int);
+const char *qib_get_unit_name(int unit);
+
+/*
+ * Flush write combining store buffers (if present) and perform a write
+ * barrier.
+ */
+#if defined(CONFIG_X86_64)
+#define qib_flush_wc() asm volatile("sfence" : : : "memory")
+#else
+#define qib_flush_wc() wmb() /* no reorder around wc flush */
+#endif
+
+/* global module parameter variables */
+extern unsigned qib_ibmtu;
+extern ushort qib_cfgctxts;
+extern ushort qib_num_cfg_vls;
+extern ushort qib_mini_init; /* If set, do few (ideally 0) writes to chip */
+extern unsigned qib_n_krcv_queues;
+extern unsigned qib_sdma_fetch_arb;
+extern unsigned qib_compat_ddr_negotiate;
+extern int qib_special_trigger;
+
+extern struct mutex qib_mutex;
+
+/* Number of seconds before our card status check...  */
+#define STATUS_TIMEOUT 60
+
+#define QIB_DRV_NAME            "ib_qib"
+#define QIB_USER_MINOR_BASE     0
+#define QIB_TRACE_MINOR         127
+#define QIB_DIAGPKT_MINOR       128
+#define QIB_DIAG_MINOR_BASE     129
+#define QIB_NMINORS             255
+
+#define PCI_VENDOR_ID_PATHSCALE 0x1fc1
+#define PCI_VENDOR_ID_QLOGIC 0x1077
+#define PCI_DEVICE_ID_QLOGIC_IB_6120 0x10
+#define PCI_DEVICE_ID_QLOGIC_IB_7220 0x7220
+#define PCI_DEVICE_ID_QLOGIC_IB_7322 0x7322
+
+/*
+ * qib_early_err is used (only!) to print early errors before devdata is
+ * allocated, or when dd->pcidev may not be valid, and at the tail end of
+ * cleanup when devdata may have been freed, etc.  qib_dev_porterr is
+ * the same as qib_dev_err, but is used when the message really needs
+ * the IB port# to be definitive as to what's happening..
+ * All of these go to the trace log, and the trace log entry is done
+ * first to avoid possible serial port delays from printk.
+ */
+#define qib_early_err(dev, fmt, ...) \
+       do { \
+               dev_info(dev, KERN_ERR QIB_DRV_NAME ": " fmt, ##__VA_ARGS__); \
+       } while (0)
+
+#define qib_dev_err(dd, fmt, ...) \
+       do { \
+               dev_err(&(dd)->pcidev->dev, "%s: " fmt, \
+                       qib_get_unit_name((dd)->unit), ##__VA_ARGS__); \
+       } while (0)
+
+#define qib_dev_porterr(dd, port, fmt, ...) \
+       do { \
+               dev_err(&(dd)->pcidev->dev, "%s: IB%u:%u " fmt, \
+                       qib_get_unit_name((dd)->unit), (dd)->unit, (port), \
+                       ##__VA_ARGS__); \
+       } while (0)
+
+#define qib_devinfo(pcidev, fmt, ...) \
+       do { \
+               dev_info(&(pcidev)->dev, fmt, ##__VA_ARGS__); \
+       } while (0)
+
+/*
+ * this is used for formatting hw error messages...
+ */
+struct qib_hwerror_msgs {
+       u64 mask;
+       const char *msg;
+};
+
+#define QLOGIC_IB_HWE_MSG(a, b) { .mask = a, .msg = b }
+
+/* in qib_intr.c... */
+void qib_format_hwerrors(u64 hwerrs,
+                        const struct qib_hwerror_msgs *hwerrmsgs,
+                        size_t nhwerrmsgs, char *msg, size_t lmsg);
+#endif                          /* _QIB_KERNEL_H */
diff --git a/drivers/infiniband/hw/qib/qib_6120_regs.h b/drivers/infiniband/hw/qib/qib_6120_regs.h
new file mode 100644 (file)
index 0000000..e16cb6f
--- /dev/null
@@ -0,0 +1,977 @@
+/*
+ * Copyright (c) 2008, 2009, 2010 QLogic Corporation. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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.
+ */
+
+/* This file is mechanically generated from RTL. Any hand-edits will be lost! */
+
+#define QIB_6120_Revision_OFFS 0x0
+#define QIB_6120_Revision_R_Simulator_LSB 0x3F
+#define QIB_6120_Revision_R_Simulator_RMASK 0x1
+#define QIB_6120_Revision_Reserved_LSB 0x28
+#define QIB_6120_Revision_Reserved_RMASK 0x7FFFFF
+#define QIB_6120_Revision_BoardID_LSB 0x20
+#define QIB_6120_Revision_BoardID_RMASK 0xFF
+#define QIB_6120_Revision_R_SW_LSB 0x18
+#define QIB_6120_Revision_R_SW_RMASK 0xFF
+#define QIB_6120_Revision_R_Arch_LSB 0x10
+#define QIB_6120_Revision_R_Arch_RMASK 0xFF
+#define QIB_6120_Revision_R_ChipRevMajor_LSB 0x8
+#define QIB_6120_Revision_R_ChipRevMajor_RMASK 0xFF
+#define QIB_6120_Revision_R_ChipRevMinor_LSB 0x0
+#define QIB_6120_Revision_R_ChipRevMinor_RMASK 0xFF
+
+#define QIB_6120_Control_OFFS 0x8
+#define QIB_6120_Control_TxLatency_LSB 0x4
+#define QIB_6120_Control_TxLatency_RMASK 0x1
+#define QIB_6120_Control_PCIERetryBufDiagEn_LSB 0x3
+#define QIB_6120_Control_PCIERetryBufDiagEn_RMASK 0x1
+#define QIB_6120_Control_LinkEn_LSB 0x2
+#define QIB_6120_Control_LinkEn_RMASK 0x1
+#define QIB_6120_Control_FreezeMode_LSB 0x1
+#define QIB_6120_Control_FreezeMode_RMASK 0x1
+#define QIB_6120_Control_SyncReset_LSB 0x0
+#define QIB_6120_Control_SyncReset_RMASK 0x1
+
+#define QIB_6120_PageAlign_OFFS 0x10
+
+#define QIB_6120_PortCnt_OFFS 0x18
+
+#define QIB_6120_SendRegBase_OFFS 0x30
+
+#define QIB_6120_UserRegBase_OFFS 0x38
+
+#define QIB_6120_CntrRegBase_OFFS 0x40
+
+#define QIB_6120_Scratch_OFFS 0x48
+#define QIB_6120_Scratch_TopHalf_LSB 0x20
+#define QIB_6120_Scratch_TopHalf_RMASK 0xFFFFFFFF
+#define QIB_6120_Scratch_BottomHalf_LSB 0x0
+#define QIB_6120_Scratch_BottomHalf_RMASK 0xFFFFFFFF
+
+#define QIB_6120_IntBlocked_OFFS 0x60
+#define QIB_6120_IntBlocked_ErrorIntBlocked_LSB 0x1F
+#define QIB_6120_IntBlocked_ErrorIntBlocked_RMASK 0x1
+#define QIB_6120_IntBlocked_PioSetIntBlocked_LSB 0x1E
+#define QIB_6120_IntBlocked_PioSetIntBlocked_RMASK 0x1
+#define QIB_6120_IntBlocked_PioBufAvailIntBlocked_LSB 0x1D
+#define QIB_6120_IntBlocked_PioBufAvailIntBlocked_RMASK 0x1
+#define QIB_6120_IntBlocked_assertGPIOIntBlocked_LSB 0x1C
+#define QIB_6120_IntBlocked_assertGPIOIntBlocked_RMASK 0x1
+#define QIB_6120_IntBlocked_Reserved_LSB 0xF
+#define QIB_6120_IntBlocked_Reserved_RMASK 0x1FFF
+#define QIB_6120_IntBlocked_RcvAvail4IntBlocked_LSB 0x10
+#define QIB_6120_IntBlocked_RcvAvail4IntBlocked_RMASK 0x1
+#define QIB_6120_IntBlocked_RcvAvail3IntBlocked_LSB 0xF
+#define QIB_6120_IntBlocked_RcvAvail3IntBlocked_RMASK 0x1
+#define QIB_6120_IntBlocked_RcvAvail2IntBlocked_LSB 0xE
+#define QIB_6120_IntBlocked_RcvAvail2IntBlocked_RMASK 0x1
+#define QIB_6120_IntBlocked_RcvAvail1IntBlocked_LSB 0xD
+#define QIB_6120_IntBlocked_RcvAvail1IntBlocked_RMASK 0x1
+#define QIB_6120_IntBlocked_RcvAvail0IntBlocked_LSB 0xC
+#define QIB_6120_IntBlocked_RcvAvail0IntBlocked_RMASK 0x1
+#define QIB_6120_IntBlocked_Reserved1_LSB 0x5
+#define QIB_6120_IntBlocked_Reserved1_RMASK 0x7F
+#define QIB_6120_IntBlocked_RcvUrg4IntBlocked_LSB 0x4
+#define QIB_6120_IntBlocked_RcvUrg4IntBlocked_RMASK 0x1
+#define QIB_6120_IntBlocked_RcvUrg3IntBlocked_LSB 0x3
+#define QIB_6120_IntBlocked_RcvUrg3IntBlocked_RMASK 0x1
+#define QIB_6120_IntBlocked_RcvUrg2IntBlocked_LSB 0x2
+#define QIB_6120_IntBlocked_RcvUrg2IntBlocked_RMASK 0x1
+#define QIB_6120_IntBlocked_RcvUrg1IntBlocked_LSB 0x1
+#define QIB_6120_IntBlocked_RcvUrg1IntBlocked_RMASK 0x1
+#define QIB_6120_IntBlocked_RcvUrg0IntBlocked_LSB 0x0
+#define QIB_6120_IntBlocked_RcvUrg0IntBlocked_RMASK 0x1
+
+#define QIB_6120_IntMask_OFFS 0x68
+#define QIB_6120_IntMask_ErrorIntMask_LSB 0x1F
+#define QIB_6120_IntMask_ErrorIntMask_RMASK 0x1
+#define QIB_6120_IntMask_PioSetIntMask_LSB 0x1E
+#define QIB_6120_IntMask_PioSetIntMask_RMASK 0x1
+#define QIB_6120_IntMask_PioBufAvailIntMask_LSB 0x1D
+#define QIB_6120_IntMask_PioBufAvailIntMask_RMASK 0x1
+#define QIB_6120_IntMask_assertGPIOIntMask_LSB 0x1C
+#define QIB_6120_IntMask_assertGPIOIntMask_RMASK 0x1
+#define QIB_6120_IntMask_Reserved_LSB 0x11
+#define QIB_6120_IntMask_Reserved_RMASK 0x7FF
+#define QIB_6120_IntMask_RcvAvail4IntMask_LSB 0x10
+#define QIB_6120_IntMask_RcvAvail4IntMask_RMASK 0x1
+#define QIB_6120_IntMask_RcvAvail3IntMask_LSB 0xF
+#define QIB_6120_IntMask_RcvAvail3IntMask_RMASK 0x1
+#define QIB_6120_IntMask_RcvAvail2IntMask_LSB 0xE
+#define QIB_6120_IntMask_RcvAvail2IntMask_RMASK 0x1
+#define QIB_6120_IntMask_RcvAvail1IntMask_LSB 0xD
+#define QIB_6120_IntMask_RcvAvail1IntMask_RMASK 0x1
+#define QIB_6120_IntMask_RcvAvail0IntMask_LSB 0xC
+#define QIB_6120_IntMask_RcvAvail0IntMask_RMASK 0x1
+#define QIB_6120_IntMask_Reserved1_LSB 0x5
+#define QIB_6120_IntMask_Reserved1_RMASK 0x7F
+#define QIB_6120_IntMask_RcvUrg4IntMask_LSB 0x4
+#define QIB_6120_IntMask_RcvUrg4IntMask_RMASK 0x1
+#define QIB_6120_IntMask_RcvUrg3IntMask_LSB 0x3
+#define QIB_6120_IntMask_RcvUrg3IntMask_RMASK 0x1
+#define QIB_6120_IntMask_RcvUrg2IntMask_LSB 0x2
+#define QIB_6120_IntMask_RcvUrg2IntMask_RMASK 0x1
+#define QIB_6120_IntMask_RcvUrg1IntMask_LSB 0x1
+#define QIB_6120_IntMask_RcvUrg1IntMask_RMASK 0x1
+#define QIB_6120_IntMask_RcvUrg0IntMask_LSB 0x0
+#define QIB_6120_IntMask_RcvUrg0IntMask_RMASK 0x1
+
+#define QIB_6120_IntStatus_OFFS 0x70
+#define QIB_6120_IntStatus_Error_LSB 0x1F
+#define QIB_6120_IntStatus_Error_RMASK 0x1
+#define QIB_6120_IntStatus_PioSent_LSB 0x1E
+#define QIB_6120_IntStatus_PioSent_RMASK 0x1
+#define QIB_6120_IntStatus_PioBufAvail_LSB 0x1D
+#define QIB_6120_IntStatus_PioBufAvail_RMASK 0x1
+#define QIB_6120_IntStatus_assertGPIO_LSB 0x1C
+#define QIB_6120_IntStatus_assertGPIO_RMASK 0x1
+#define QIB_6120_IntStatus_Reserved_LSB 0xF
+#define QIB_6120_IntStatus_Reserved_RMASK 0x1FFF
+#define QIB_6120_IntStatus_RcvAvail4_LSB 0x10
+#define QIB_6120_IntStatus_RcvAvail4_RMASK 0x1
+#define QIB_6120_IntStatus_RcvAvail3_LSB 0xF
+#define QIB_6120_IntStatus_RcvAvail3_RMASK 0x1
+#define QIB_6120_IntStatus_RcvAvail2_LSB 0xE
+#define QIB_6120_IntStatus_RcvAvail2_RMASK 0x1
+#define QIB_6120_IntStatus_RcvAvail1_LSB 0xD
+#define QIB_6120_IntStatus_RcvAvail1_RMASK 0x1
+#define QIB_6120_IntStatus_RcvAvail0_LSB 0xC
+#define QIB_6120_IntStatus_RcvAvail0_RMASK 0x1
+#define QIB_6120_IntStatus_Reserved1_LSB 0x5
+#define QIB_6120_IntStatus_Reserved1_RMASK 0x7F
+#define QIB_6120_IntStatus_RcvUrg4_LSB 0x4
+#define QIB_6120_IntStatus_RcvUrg4_RMASK 0x1
+#define QIB_6120_IntStatus_RcvUrg3_LSB 0x3
+#define QIB_6120_IntStatus_RcvUrg3_RMASK 0x1
+#define QIB_6120_IntStatus_RcvUrg2_LSB 0x2
+#define QIB_6120_IntStatus_RcvUrg2_RMASK 0x1
+#define QIB_6120_IntStatus_RcvUrg1_LSB 0x1
+#define QIB_6120_IntStatus_RcvUrg1_RMASK 0x1
+#define QIB_6120_IntStatus_RcvUrg0_LSB 0x0
+#define QIB_6120_IntStatus_RcvUrg0_RMASK 0x1
+
+#define QIB_6120_IntClear_OFFS 0x78
+#define QIB_6120_IntClear_ErrorIntClear_LSB 0x1F
+#define QIB_6120_IntClear_ErrorIntClear_RMASK 0x1
+#define QIB_6120_IntClear_PioSetIntClear_LSB 0x1E
+#define QIB_6120_IntClear_PioSetIntClear_RMASK 0x1
+#define QIB_6120_IntClear_PioBufAvailIntClear_LSB 0x1D
+#define QIB_6120_IntClear_PioBufAvailIntClear_RMASK 0x1
+#define QIB_6120_IntClear_assertGPIOIntClear_LSB 0x1C
+#define QIB_6120_IntClear_assertGPIOIntClear_RMASK 0x1
+#define QIB_6120_IntClear_Reserved_LSB 0xF
+#define QIB_6120_IntClear_Reserved_RMASK 0x1FFF
+#define QIB_6120_IntClear_RcvAvail4IntClear_LSB 0x10
+#define QIB_6120_IntClear_RcvAvail4IntClear_RMASK 0x1
+#define QIB_6120_IntClear_RcvAvail3IntClear_LSB 0xF
+#define QIB_6120_IntClear_RcvAvail3IntClear_RMASK 0x1
+#define QIB_6120_IntClear_RcvAvail2IntClear_LSB 0xE
+#define QIB_6120_IntClear_RcvAvail2IntClear_RMASK 0x1
+#define QIB_6120_IntClear_RcvAvail1IntClear_LSB 0xD
+#define QIB_6120_IntClear_RcvAvail1IntClear_RMASK 0x1
+#define QIB_6120_IntClear_RcvAvail0IntClear_LSB 0xC
+#define QIB_6120_IntClear_RcvAvail0IntClear_RMASK 0x1
+#define QIB_6120_IntClear_Reserved1_LSB 0x5
+#define QIB_6120_IntClear_Reserved1_RMASK 0x7F
+#define QIB_6120_IntClear_RcvUrg4IntClear_LSB 0x4
+#define QIB_6120_IntClear_RcvUrg4IntClear_RMASK 0x1
+#define QIB_6120_IntClear_RcvUrg3IntClear_LSB 0x3
+#define QIB_6120_IntClear_RcvUrg3IntClear_RMASK 0x1
+#define QIB_6120_IntClear_RcvUrg2IntClear_LSB 0x2
+#define QIB_6120_IntClear_RcvUrg2IntClear_RMASK 0x1
+#define QIB_6120_IntClear_RcvUrg1IntClear_LSB 0x1
+#define QIB_6120_IntClear_RcvUrg1IntClear_RMASK 0x1
+#define QIB_6120_IntClear_RcvUrg0IntClear_LSB 0x0
+#define QIB_6120_IntClear_RcvUrg0IntClear_RMASK 0x1
+
+#define QIB_6120_ErrMask_OFFS 0x80
+#define QIB_6120_ErrMask_Reserved_LSB 0x34
+#define QIB_6120_ErrMask_Reserved_RMASK 0xFFF
+#define QIB_6120_ErrMask_HardwareErrMask_LSB 0x33
+#define QIB_6120_ErrMask_HardwareErrMask_RMASK 0x1
+#define QIB_6120_ErrMask_ResetNegatedMask_LSB 0x32
+#define QIB_6120_ErrMask_ResetNegatedMask_RMASK 0x1
+#define QIB_6120_ErrMask_InvalidAddrErrMask_LSB 0x31
+#define QIB_6120_ErrMask_InvalidAddrErrMask_RMASK 0x1
+#define QIB_6120_ErrMask_IBStatusChangedMask_LSB 0x30
+#define QIB_6120_ErrMask_IBStatusChangedMask_RMASK 0x1
+#define QIB_6120_ErrMask_Reserved1_LSB 0x26
+#define QIB_6120_ErrMask_Reserved1_RMASK 0x3FF
+#define QIB_6120_ErrMask_SendUnsupportedVLErrMask_LSB 0x25
+#define QIB_6120_ErrMask_SendUnsupportedVLErrMask_RMASK 0x1
+#define QIB_6120_ErrMask_SendUnexpectedPktNumErrMask_LSB 0x24
+#define QIB_6120_ErrMask_SendUnexpectedPktNumErrMask_RMASK 0x1
+#define QIB_6120_ErrMask_SendPioArmLaunchErrMask_LSB 0x23
+#define QIB_6120_ErrMask_SendPioArmLaunchErrMask_RMASK 0x1
+#define QIB_6120_ErrMask_SendDroppedDataPktErrMask_LSB 0x22
+#define QIB_6120_ErrMask_SendDroppedDataPktErrMask_RMASK 0x1
+#define QIB_6120_ErrMask_SendDroppedSmpPktErrMask_LSB 0x21
+#define QIB_6120_ErrMask_SendDroppedSmpPktErrMask_RMASK 0x1
+#define QIB_6120_ErrMask_SendPktLenErrMask_LSB 0x20
+#define QIB_6120_ErrMask_SendPktLenErrMask_RMASK 0x1
+#define QIB_6120_ErrMask_SendUnderRunErrMask_LSB 0x1F
+#define QIB_6120_ErrMask_SendUnderRunErrMask_RMASK 0x1
+#define QIB_6120_ErrMask_SendMaxPktLenErrMask_LSB 0x1E
+#define QIB_6120_ErrMask_SendMaxPktLenErrMask_RMASK 0x1
+#define QIB_6120_ErrMask_SendMinPktLenErrMask_LSB 0x1D
+#define QIB_6120_ErrMask_SendMinPktLenErrMask_RMASK 0x1
+#define QIB_6120_ErrMask_Reserved2_LSB 0x12
+#define QIB_6120_ErrMask_Reserved2_RMASK 0x7FF
+#define QIB_6120_ErrMask_RcvIBLostLinkErrMask_LSB 0x11
+#define QIB_6120_ErrMask_RcvIBLostLinkErrMask_RMASK 0x1
+#define QIB_6120_ErrMask_RcvHdrErrMask_LSB 0x10
+#define QIB_6120_ErrMask_RcvHdrErrMask_RMASK 0x1
+#define QIB_6120_ErrMask_RcvHdrLenErrMask_LSB 0xF
+#define QIB_6120_ErrMask_RcvHdrLenErrMask_RMASK 0x1
+#define QIB_6120_ErrMask_RcvBadTidErrMask_LSB 0xE
+#define QIB_6120_ErrMask_RcvBadTidErrMask_RMASK 0x1
+#define QIB_6120_ErrMask_RcvHdrFullErrMask_LSB 0xD
+#define QIB_6120_ErrMask_RcvHdrFullErrMask_RMASK 0x1
+#define QIB_6120_ErrMask_RcvEgrFullErrMask_LSB 0xC
+#define QIB_6120_ErrMask_RcvEgrFullErrMask_RMASK 0x1
+#define QIB_6120_ErrMask_RcvBadVersionErrMask_LSB 0xB
+#define QIB_6120_ErrMask_RcvBadVersionErrMask_RMASK 0x1
+#define QIB_6120_ErrMask_RcvIBFlowErrMask_LSB 0xA
+#define QIB_6120_ErrMask_RcvIBFlowErrMask_RMASK 0x1
+#define QIB_6120_ErrMask_RcvEBPErrMask_LSB 0x9
+#define QIB_6120_ErrMask_RcvEBPErrMask_RMASK 0x1
+#define QIB_6120_ErrMask_RcvUnsupportedVLErrMask_LSB 0x8
+#define QIB_6120_ErrMask_RcvUnsupportedVLErrMask_RMASK 0x1
+#define QIB_6120_ErrMask_RcvUnexpectedCharErrMask_LSB 0x7
+#define QIB_6120_ErrMask_RcvUnexpectedCharErrMask_RMASK 0x1
+#define QIB_6120_ErrMask_RcvShortPktLenErrMask_LSB 0x6
+#define QIB_6120_ErrMask_RcvShortPktLenErrMask_RMASK 0x1
+#define QIB_6120_ErrMask_RcvLongPktLenErrMask_LSB 0x5
+#define QIB_6120_ErrMask_RcvLongPktLenErrMask_RMASK 0x1
+#define QIB_6120_ErrMask_RcvMaxPktLenErrMask_LSB 0x4
+#define QIB_6120_ErrMask_RcvMaxPktLenErrMask_RMASK 0x1
+#define QIB_6120_ErrMask_RcvMinPktLenErrMask_LSB 0x3
+#define QIB_6120_ErrMask_RcvMinPktLenErrMask_RMASK 0x1
+#define QIB_6120_ErrMask_RcvICRCErrMask_LSB 0x2
+#define QIB_6120_ErrMask_RcvICRCErrMask_RMASK 0x1
+#define QIB_6120_ErrMask_RcvVCRCErrMask_LSB 0x1
+#define QIB_6120_ErrMask_RcvVCRCErrMask_RMASK 0x1
+#define QIB_6120_ErrMask_RcvFormatErrMask_LSB 0x0
+#define QIB_6120_ErrMask_RcvFormatErrMask_RMASK 0x1
+
+#define QIB_6120_ErrStatus_OFFS 0x88
+#define QIB_6120_ErrStatus_Reserved_LSB 0x34
+#define QIB_6120_ErrStatus_Reserved_RMASK 0xFFF
+#define QIB_6120_ErrStatus_HardwareErr_LSB 0x33
+#define QIB_6120_ErrStatus_HardwareErr_RMASK 0x1
+#define QIB_6120_ErrStatus_ResetNegated_LSB 0x32
+#define QIB_6120_ErrStatus_ResetNegated_RMASK 0x1
+#define QIB_6120_ErrStatus_InvalidAddrErr_LSB 0x31
+#define QIB_6120_ErrStatus_InvalidAddrErr_RMASK 0x1
+#define QIB_6120_ErrStatus_IBStatusChanged_LSB 0x30
+#define QIB_6120_ErrStatus_IBStatusChanged_RMASK 0x1
+#define QIB_6120_ErrStatus_Reserved1_LSB 0x26
+#define QIB_6120_ErrStatus_Reserved1_RMASK 0x3FF
+#define QIB_6120_ErrStatus_SendUnsupportedVLErr_LSB 0x25
+#define QIB_6120_ErrStatus_SendUnsupportedVLErr_RMASK 0x1
+#define QIB_6120_ErrStatus_SendUnexpectedPktNumErr_LSB 0x24
+#define QIB_6120_ErrStatus_SendUnexpectedPktNumErr_RMASK 0x1
+#define QIB_6120_ErrStatus_SendPioArmLaunchErr_LSB 0x23
+#define QIB_6120_ErrStatus_SendPioArmLaunchErr_RMASK 0x1
+#define QIB_6120_ErrStatus_SendDroppedDataPktErr_LSB 0x22
+#define QIB_6120_ErrStatus_SendDroppedDataPktErr_RMASK 0x1
+#define QIB_6120_ErrStatus_SendDroppedSmpPktErr_LSB 0x21
+#define QIB_6120_ErrStatus_SendDroppedSmpPktErr_RMASK 0x1
+#define QIB_6120_ErrStatus_SendPktLenErr_LSB 0x20
+#define QIB_6120_ErrStatus_SendPktLenErr_RMASK 0x1
+#define QIB_6120_ErrStatus_SendUnderRunErr_LSB 0x1F
+#define QIB_6120_ErrStatus_SendUnderRunErr_RMASK 0x1
+#define QIB_6120_ErrStatus_SendMaxPktLenErr_LSB 0x1E
+#define QIB_6120_ErrStatus_SendMaxPktLenErr_RMASK 0x1
+#define QIB_6120_ErrStatus_SendMinPktLenErr_LSB 0x1D
+#define QIB_6120_ErrStatus_SendMinPktLenErr_RMASK 0x1
+#define QIB_6120_ErrStatus_Reserved2_LSB 0x12
+#define QIB_6120_ErrStatus_Reserved2_RMASK 0x7FF
+#define QIB_6120_ErrStatus_RcvIBLostLinkErr_LSB 0x11
+#define QIB_6120_ErrStatus_RcvIBLostLinkErr_RMASK 0x1
+#define QIB_6120_ErrStatus_RcvHdrErr_LSB 0x10
+#define QIB_6120_ErrStatus_RcvHdrErr_RMASK 0x1
+#define QIB_6120_ErrStatus_RcvHdrLenErr_LSB 0xF
+#define QIB_6120_ErrStatus_RcvHdrLenErr_RMASK 0x1
+#define QIB_6120_ErrStatus_RcvBadTidErr_LSB 0xE
+#define QIB_6120_ErrStatus_RcvBadTidErr_RMASK 0x1
+#define QIB_6120_ErrStatus_RcvHdrFullErr_LSB 0xD
+#define QIB_6120_ErrStatus_RcvHdrFullErr_RMASK 0x1
+#define QIB_6120_ErrStatus_RcvEgrFullErr_LSB 0xC
+#define QIB_6120_ErrStatus_RcvEgrFullErr_RMASK 0x1
+#define QIB_6120_ErrStatus_RcvBadVersionErr_LSB 0xB
+#define QIB_6120_ErrStatus_RcvBadVersionErr_RMASK 0x1
+#define QIB_6120_ErrStatus_RcvIBFlowErr_LSB 0xA
+#define QIB_6120_ErrStatus_RcvIBFlowErr_RMASK 0x1
+#define QIB_6120_ErrStatus_RcvEBPErr_LSB 0x9
+#define QIB_6120_ErrStatus_RcvEBPErr_RMASK 0x1
+#define QIB_6120_ErrStatus_RcvUnsupportedVLErr_LSB 0x8
+#define QIB_6120_ErrStatus_RcvUnsupportedVLErr_RMASK 0x1
+#define QIB_6120_ErrStatus_RcvUnexpectedCharErr_LSB 0x7
+#define QIB_6120_ErrStatus_RcvUnexpectedCharErr_RMASK 0x1
+#define QIB_6120_ErrStatus_RcvShortPktLenErr_LSB 0x6
+#define QIB_6120_ErrStatus_RcvShortPktLenErr_RMASK 0x1
+#define QIB_6120_ErrStatus_RcvLongPktLenErr_LSB 0x5
+#define QIB_6120_ErrStatus_RcvLongPktLenErr_RMASK 0x1
+#define QIB_6120_ErrStatus_RcvMaxPktLenErr_LSB 0x4
+#define QIB_6120_ErrStatus_RcvMaxPktLenErr_RMASK 0x1
+#define QIB_6120_ErrStatus_RcvMinPktLenErr_LSB 0x3
+#define QIB_6120_ErrStatus_RcvMinPktLenErr_RMASK 0x1
+#define QIB_6120_ErrStatus_RcvICRCErr_LSB 0x2
+#define QIB_6120_ErrStatus_RcvICRCErr_RMASK 0x1
+#define QIB_6120_ErrStatus_RcvVCRCErr_LSB 0x1
+#define QIB_6120_ErrStatus_RcvVCRCErr_RMASK 0x1
+#define QIB_6120_ErrStatus_RcvFormatErr_LSB 0x0
+#define QIB_6120_ErrStatus_RcvFormatErr_RMASK 0x1
+
+#define QIB_6120_ErrClear_OFFS 0x90
+#define QIB_6120_ErrClear_Reserved_LSB 0x34
+#define QIB_6120_ErrClear_Reserved_RMASK 0xFFF
+#define QIB_6120_ErrClear_HardwareErrClear_LSB 0x33
+#define QIB_6120_ErrClear_HardwareErrClear_RMASK 0x1
+#define QIB_6120_ErrClear_ResetNegatedClear_LSB 0x32
+#define QIB_6120_ErrClear_ResetNegatedClear_RMASK 0x1
+#define QIB_6120_ErrClear_InvalidAddrErrClear_LSB 0x31
+#define QIB_6120_ErrClear_InvalidAddrErrClear_RMASK 0x1
+#define QIB_6120_ErrClear_IBStatusChangedClear_LSB 0x30
+#define QIB_6120_ErrClear_IBStatusChangedClear_RMASK 0x1
+#define QIB_6120_ErrClear_Reserved1_LSB 0x26
+#define QIB_6120_ErrClear_Reserved1_RMASK 0x3FF
+#define QIB_6120_ErrClear_SendUnsupportedVLErrClear_LSB 0x25
+#define QIB_6120_ErrClear_SendUnsupportedVLErrClear_RMASK 0x1
+#define QIB_6120_ErrClear_SendUnexpectedPktNumErrClear_LSB 0x24
+#define QIB_6120_ErrClear_SendUnexpectedPktNumErrClear_RMASK 0x1
+#define QIB_6120_ErrClear_SendPioArmLaunchErrClear_LSB 0x23
+#define QIB_6120_ErrClear_SendPioArmLaunchErrClear_RMASK 0x1
+#define QIB_6120_ErrClear_SendDroppedDataPktErrClear_LSB 0x22
+#define QIB_6120_ErrClear_SendDroppedDataPktErrClear_RMASK 0x1
+#define QIB_6120_ErrClear_SendDroppedSmpPktErrClear_LSB 0x21
+#define QIB_6120_ErrClear_SendDroppedSmpPktErrClear_RMASK 0x1
+#define QIB_6120_ErrClear_SendPktLenErrClear_LSB 0x20
+#define QIB_6120_ErrClear_SendPktLenErrClear_RMASK 0x1
+#define QIB_6120_ErrClear_SendUnderRunErrClear_LSB 0x1F
+#define QIB_6120_ErrClear_SendUnderRunErrClear_RMASK 0x1
+#define QIB_6120_ErrClear_SendMaxPktLenErrClear_LSB 0x1E
+#define QIB_6120_ErrClear_SendMaxPktLenErrClear_RMASK 0x1
+#define QIB_6120_ErrClear_SendMinPktLenErrClear_LSB 0x1D
+#define QIB_6120_ErrClear_SendMinPktLenErrClear_RMASK 0x1
+#define QIB_6120_ErrClear_Reserved2_LSB 0x12
+#define QIB_6120_ErrClear_Reserved2_RMASK 0x7FF
+#define QIB_6120_ErrClear_RcvIBLostLinkErrClear_LSB 0x11
+#define QIB_6120_ErrClear_RcvIBLostLinkErrClear_RMASK 0x1
+#define QIB_6120_ErrClear_RcvHdrErrClear_LSB 0x10
+#define QIB_6120_ErrClear_RcvHdrErrClear_RMASK 0x1
+#define QIB_6120_ErrClear_RcvHdrLenErrClear_LSB 0xF
+#define QIB_6120_ErrClear_RcvHdrLenErrClear_RMASK 0x1
+#define QIB_6120_ErrClear_RcvBadTidErrClear_LSB 0xE
+#define QIB_6120_ErrClear_RcvBadTidErrClear_RMASK 0x1
+#define QIB_6120_ErrClear_RcvHdrFullErrClear_LSB 0xD
+#define QIB_6120_ErrClear_RcvHdrFullErrClear_RMASK 0x1
+#define QIB_6120_ErrClear_RcvEgrFullErrClear_LSB 0xC
+#define QIB_6120_ErrClear_RcvEgrFullErrClear_RMASK 0x1
+#define QIB_6120_ErrClear_RcvBadVersionErrClear_LSB 0xB
+#define QIB_6120_ErrClear_RcvBadVersionErrClear_RMASK 0x1
+#define QIB_6120_ErrClear_RcvIBFlowErrClear_LSB 0xA
+#define QIB_6120_ErrClear_RcvIBFlowErrClear_RMASK 0x1
+#define QIB_6120_ErrClear_RcvEBPErrClear_LSB 0x9
+#define QIB_6120_ErrClear_RcvEBPErrClear_RMASK 0x1
+#define QIB_6120_ErrClear_RcvUnsupportedVLErrClear_LSB 0x8
+#define QIB_6120_ErrClear_RcvUnsupportedVLErrClear_RMASK 0x1
+#define QIB_6120_ErrClear_RcvUnexpectedCharErrClear_LSB 0x7
+#define QIB_6120_ErrClear_RcvUnexpectedCharErrClear_RMASK 0x1
+#define QIB_6120_ErrClear_RcvShortPktLenErrClear_LSB 0x6
+#define QIB_6120_ErrClear_RcvShortPktLenErrClear_RMASK 0x1
+#define QIB_6120_ErrClear_RcvLongPktLenErrClear_LSB 0x5
+#define QIB_6120_ErrClear_RcvLongPktLenErrClear_RMASK 0x1
+#define QIB_6120_ErrClear_RcvMaxPktLenErrClear_LSB 0x4
+#define QIB_6120_ErrClear_RcvMaxPktLenErrClear_RMASK 0x1
+#define QIB_6120_ErrClear_RcvMinPktLenErrClear_LSB 0x3
+#define QIB_6120_ErrClear_RcvMinPktLenErrClear_RMASK 0x1
+#define QIB_6120_ErrClear_RcvICRCErrClear_LSB 0x2
+#define QIB_6120_ErrClear_RcvICRCErrClear_RMASK 0x1
+#define QIB_6120_ErrClear_RcvVCRCErrClear_LSB 0x1
+#define QIB_6120_ErrClear_RcvVCRCErrClear_RMASK 0x1
+#define QIB_6120_ErrClear_RcvFormatErrClear_LSB 0x0
+#define QIB_6120_ErrClear_RcvFormatErrClear_RMASK 0x1
+
+#define QIB_6120_HwErrMask_OFFS 0x98
+#define QIB_6120_HwErrMask_IBCBusFromSPCParityErrMask_LSB 0x3F
+#define QIB_6120_HwErrMask_IBCBusFromSPCParityErrMask_RMASK 0x1
+#define QIB_6120_HwErrMask_IBCBusToSPCParityErrMask_LSB 0x3E
+#define QIB_6120_HwErrMask_IBCBusToSPCParityErrMask_RMASK 0x1
+#define QIB_6120_HwErrMask_Reserved_LSB 0x3D
+#define QIB_6120_HwErrMask_Reserved_RMASK 0x1
+#define QIB_6120_HwErrMask_IBSerdesPClkNotDetectMask_LSB 0x3C
+#define QIB_6120_HwErrMask_IBSerdesPClkNotDetectMask_RMASK 0x1
+#define QIB_6120_HwErrMask_PCIESerdesQ0PClkNotDetectMask_LSB 0x3B
+#define QIB_6120_HwErrMask_PCIESerdesQ0PClkNotDetectMask_RMASK 0x1
+#define QIB_6120_HwErrMask_PCIESerdesQ1PClkNotDetectMask_LSB 0x3A
+#define QIB_6120_HwErrMask_PCIESerdesQ1PClkNotDetectMask_RMASK 0x1
+#define QIB_6120_HwErrMask_Reserved1_LSB 0x39
+#define QIB_6120_HwErrMask_Reserved1_RMASK 0x1
+#define QIB_6120_HwErrMask_IBPLLrfSlipMask_LSB 0x38
+#define QIB_6120_HwErrMask_IBPLLrfSlipMask_RMASK 0x1
+#define QIB_6120_HwErrMask_IBPLLfbSlipMask_LSB 0x37
+#define QIB_6120_HwErrMask_IBPLLfbSlipMask_RMASK 0x1
+#define QIB_6120_HwErrMask_PowerOnBISTFailedMask_LSB 0x36
+#define QIB_6120_HwErrMask_PowerOnBISTFailedMask_RMASK 0x1
+#define QIB_6120_HwErrMask_Reserved2_LSB 0x33
+#define QIB_6120_HwErrMask_Reserved2_RMASK 0x7
+#define QIB_6120_HwErrMask_RXEMemParityErrMask_LSB 0x2C
+#define QIB_6120_HwErrMask_RXEMemParityErrMask_RMASK 0x7F
+#define QIB_6120_HwErrMask_TXEMemParityErrMask_LSB 0x28
+#define QIB_6120_HwErrMask_TXEMemParityErrMask_RMASK 0xF
+#define QIB_6120_HwErrMask_Reserved3_LSB 0x22
+#define QIB_6120_HwErrMask_Reserved3_RMASK 0x3F
+#define QIB_6120_HwErrMask_PCIeBusParityErrMask_LSB 0x1F
+#define QIB_6120_HwErrMask_PCIeBusParityErrMask_RMASK 0x7
+#define QIB_6120_HwErrMask_PcieCplTimeoutMask_LSB 0x1E
+#define QIB_6120_HwErrMask_PcieCplTimeoutMask_RMASK 0x1
+#define QIB_6120_HwErrMask_PoisonedTLPMask_LSB 0x1D
+#define QIB_6120_HwErrMask_PoisonedTLPMask_RMASK 0x1
+#define QIB_6120_HwErrMask_Reserved4_LSB 0x6
+#define QIB_6120_HwErrMask_Reserved4_RMASK 0x7FFFFF
+#define QIB_6120_HwErrMask_PCIeMemParityErrMask_LSB 0x0
+#define QIB_6120_HwErrMask_PCIeMemParityErrMask_RMASK 0x3F
+
+#define QIB_6120_HwErrStatus_OFFS 0xA0
+#define QIB_6120_HwErrStatus_IBCBusFromSPCParityErr_LSB 0x3F
+#define QIB_6120_HwErrStatus_IBCBusFromSPCParityErr_RMASK 0x1
+#define QIB_6120_HwErrStatus_IBCBusToSPCParityErr_LSB 0x3E
+#define QIB_6120_HwErrStatus_IBCBusToSPCParityErr_RMASK 0x1
+#define QIB_6120_HwErrStatus_Reserved_LSB 0x3D
+#define QIB_6120_HwErrStatus_Reserved_RMASK 0x1
+#define QIB_6120_HwErrStatus_IBSerdesPClkNotDetect_LSB 0x3C
+#define QIB_6120_HwErrStatus_IBSerdesPClkNotDetect_RMASK 0x1
+#define QIB_6120_HwErrStatus_PCIESerdesQ0PClkNotDetect_LSB 0x3B
+#define QIB_6120_HwErrStatus_PCIESerdesQ0PClkNotDetect_RMASK 0x1
+#define QIB_6120_HwErrStatus_PCIESerdesQ1PClkNotDetect_LSB 0x3A
+#define QIB_6120_HwErrStatus_PCIESerdesQ1PClkNotDetect_RMASK 0x1
+#define QIB_6120_HwErrStatus_Reserved1_LSB 0x39
+#define QIB_6120_HwErrStatus_Reserved1_RMASK 0x1
+#define QIB_6120_HwErrStatus_IBPLLrfSlip_LSB 0x38
+#define QIB_6120_HwErrStatus_IBPLLrfSlip_RMASK 0x1
+#define QIB_6120_HwErrStatus_IBPLLfbSlip_LSB 0x37
+#define QIB_6120_HwErrStatus_IBPLLfbSlip_RMASK 0x1
+#define QIB_6120_HwErrStatus_PowerOnBISTFailed_LSB 0x36
+#define QIB_6120_HwErrStatus_PowerOnBISTFailed_RMASK 0x1
+#define QIB_6120_HwErrStatus_Reserved2_LSB 0x33
+#define QIB_6120_HwErrStatus_Reserved2_RMASK 0x7
+#define QIB_6120_HwErrStatus_RXEMemParity_LSB 0x2C
+#define QIB_6120_HwErrStatus_RXEMemParity_RMASK 0x7F
+#define QIB_6120_HwErrStatus_TXEMemParity_LSB 0x28
+#define QIB_6120_HwErrStatus_TXEMemParity_RMASK 0xF
+#define QIB_6120_HwErrStatus_Reserved3_LSB 0x22
+#define QIB_6120_HwErrStatus_Reserved3_RMASK 0x3F
+#define QIB_6120_HwErrStatus_PCIeBusParity_LSB 0x1F
+#define QIB_6120_HwErrStatus_PCIeBusParity_RMASK 0x7
+#define QIB_6120_HwErrStatus_PcieCplTimeout_LSB 0x1E
+#define QIB_6120_HwErrStatus_PcieCplTimeout_RMASK 0x1
+#define QIB_6120_HwErrStatus_PoisenedTLP_LSB 0x1D
+#define QIB_6120_HwErrStatus_PoisenedTLP_RMASK 0x1
+#define QIB_6120_HwErrStatus_Reserved4_LSB 0x6
+#define QIB_6120_HwErrStatus_Reserved4_RMASK 0x7FFFFF
+#define QIB_6120_HwErrStatus_PCIeMemParity_LSB 0x0
+#define QIB_6120_HwErrStatus_PCIeMemParity_RMASK 0x3F
+
+#define QIB_6120_HwErrClear_OFFS 0xA8
+#define QIB_6120_HwErrClear_IBCBusFromSPCParityErrClear_LSB 0x3F
+#define QIB_6120_HwErrClear_IBCBusFromSPCParityErrClear_RMASK 0x1
+#define QIB_6120_HwErrClear_IBCBusToSPCparityErrClear_LSB 0x3E
+#define QIB_6120_HwErrClear_IBCBusToSPCparityErrClear_RMASK 0x1
+#define QIB_6120_HwErrClear_Reserved_LSB 0x3D
+#define QIB_6120_HwErrClear_Reserved_RMASK 0x1
+#define QIB_6120_HwErrClear_IBSerdesPClkNotDetectClear_LSB 0x3C
+#define QIB_6120_HwErrClear_IBSerdesPClkNotDetectClear_RMASK 0x1
+#define QIB_6120_HwErrClear_PCIESerdesQ0PClkNotDetectClear_LSB 0x3B
+#define QIB_6120_HwErrClear_PCIESerdesQ0PClkNotDetectClear_RMASK 0x1
+#define QIB_6120_HwErrClear_PCIESerdesQ1PClkNotDetectClear_LSB 0x3A
+#define QIB_6120_HwErrClear_PCIESerdesQ1PClkNotDetectClear_RMASK 0x1
+#define QIB_6120_HwErrClear_Reserved1_LSB 0x39
+#define QIB_6120_HwErrClear_Reserved1_RMASK 0x1
+#define QIB_6120_HwErrClear_IBPLLrfSlipClear_LSB 0x38
+#define QIB_6120_HwErrClear_IBPLLrfSlipClear_RMASK 0x1
+#define QIB_6120_HwErrClear_IBPLLfbSlipClear_LSB 0x37
+#define QIB_6120_HwErrClear_IBPLLfbSlipClear_RMASK 0x1
+#define QIB_6120_HwErrClear_PowerOnBISTFailedClear_LSB 0x36
+#define QIB_6120_HwErrClear_PowerOnBISTFailedClear_RMASK 0x1
+#define QIB_6120_HwErrClear_Reserved2_LSB 0x33
+#define QIB_6120_HwErrClear_Reserved2_RMASK 0x7
+#define QIB_6120_HwErrClear_RXEMemParityClear_LSB 0x2C
+#define QIB_6120_HwErrClear_RXEMemParityClear_RMASK 0x7F
+#define QIB_6120_HwErrClear_TXEMemParityClear_LSB 0x28
+#define QIB_6120_HwErrClear_TXEMemParityClear_RMASK 0xF
+#define QIB_6120_HwErrClear_Reserved3_LSB 0x22
+#define QIB_6120_HwErrClear_Reserved3_RMASK 0x3F
+#define QIB_6120_HwErrClear_PCIeBusParityClr_LSB 0x1F
+#define QIB_6120_HwErrClear_PCIeBusParityClr_RMASK 0x7
+#define QIB_6120_HwErrClear_PcieCplTimeoutClear_LSB 0x1E
+#define QIB_6120_HwErrClear_PcieCplTimeoutClear_RMASK 0x1
+#define QIB_6120_HwErrClear_PoisonedTLPClear_LSB 0x1D
+#define QIB_6120_HwErrClear_PoisonedTLPClear_RMASK 0x1
+#define QIB_6120_HwErrClear_Reserved4_LSB 0x6
+#define QIB_6120_HwErrClear_Reserved4_RMASK 0x7FFFFF
+#define QIB_6120_HwErrClear_PCIeMemParityClr_LSB 0x0
+#define QIB_6120_HwErrClear_PCIeMemParityClr_RMASK 0x3F
+
+#define QIB_6120_HwDiagCtrl_OFFS 0xB0
+#define QIB_6120_HwDiagCtrl_ForceIBCBusFromSPCParityErr_LSB 0x3F
+#define QIB_6120_HwDiagCtrl_ForceIBCBusFromSPCParityErr_RMASK 0x1
+#define QIB_6120_HwDiagCtrl_ForceIBCBusToSPCParityErr_LSB 0x3E
+#define QIB_6120_HwDiagCtrl_ForceIBCBusToSPCParityErr_RMASK 0x1
+#define QIB_6120_HwDiagCtrl_CounterWrEnable_LSB 0x3D
+#define QIB_6120_HwDiagCtrl_CounterWrEnable_RMASK 0x1
+#define QIB_6120_HwDiagCtrl_CounterDisable_LSB 0x3C
+#define QIB_6120_HwDiagCtrl_CounterDisable_RMASK 0x1
+#define QIB_6120_HwDiagCtrl_Reserved_LSB 0x33
+#define QIB_6120_HwDiagCtrl_Reserved_RMASK 0x1FF
+#define QIB_6120_HwDiagCtrl_ForceRxMemParityErr_LSB 0x2C
+#define QIB_6120_HwDiagCtrl_ForceRxMemParityErr_RMASK 0x7F
+#define QIB_6120_HwDiagCtrl_ForceTxMemparityErr_LSB 0x28
+#define QIB_6120_HwDiagCtrl_ForceTxMemparityErr_RMASK 0xF
+#define QIB_6120_HwDiagCtrl_Reserved1_LSB 0x23
+#define QIB_6120_HwDiagCtrl_Reserved1_RMASK 0x1F
+#define QIB_6120_HwDiagCtrl_forcePCIeBusParity_LSB 0x1F
+#define QIB_6120_HwDiagCtrl_forcePCIeBusParity_RMASK 0xF
+#define QIB_6120_HwDiagCtrl_Reserved2_LSB 0x6
+#define QIB_6120_HwDiagCtrl_Reserved2_RMASK 0x1FFFFFF
+#define QIB_6120_HwDiagCtrl_forcePCIeMemParity_LSB 0x0
+#define QIB_6120_HwDiagCtrl_forcePCIeMemParity_RMASK 0x3F
+
+#define QIB_6120_IBCStatus_OFFS 0xC0
+#define QIB_6120_IBCStatus_TxCreditOk_LSB 0x1F
+#define QIB_6120_IBCStatus_TxCreditOk_RMASK 0x1
+#define QIB_6120_IBCStatus_TxReady_LSB 0x1E
+#define QIB_6120_IBCStatus_TxReady_RMASK 0x1
+#define QIB_6120_IBCStatus_Reserved_LSB 0x7
+#define QIB_6120_IBCStatus_Reserved_RMASK 0x7FFFFF
+#define QIB_6120_IBCStatus_LinkState_LSB 0x4
+#define QIB_6120_IBCStatus_LinkState_RMASK 0x7
+#define QIB_6120_IBCStatus_LinkTrainingState_LSB 0x0
+#define QIB_6120_IBCStatus_LinkTrainingState_RMASK 0xF
+
+#define QIB_6120_IBCCtrl_OFFS 0xC8
+#define QIB_6120_IBCCtrl_Loopback_LSB 0x3F
+#define QIB_6120_IBCCtrl_Loopback_RMASK 0x1
+#define QIB_6120_IBCCtrl_LinkDownDefaultState_LSB 0x3E
+#define QIB_6120_IBCCtrl_LinkDownDefaultState_RMASK 0x1
+#define QIB_6120_IBCCtrl_Reserved_LSB 0x2B
+#define QIB_6120_IBCCtrl_Reserved_RMASK 0x7FFFF
+#define QIB_6120_IBCCtrl_CreditScale_LSB 0x28
+#define QIB_6120_IBCCtrl_CreditScale_RMASK 0x7
+#define QIB_6120_IBCCtrl_OverrunThreshold_LSB 0x24
+#define QIB_6120_IBCCtrl_OverrunThreshold_RMASK 0xF
+#define QIB_6120_IBCCtrl_PhyerrThreshold_LSB 0x20
+#define QIB_6120_IBCCtrl_PhyerrThreshold_RMASK 0xF
+#define QIB_6120_IBCCtrl_Reserved1_LSB 0x1F
+#define QIB_6120_IBCCtrl_Reserved1_RMASK 0x1
+#define QIB_6120_IBCCtrl_MaxPktLen_LSB 0x14
+#define QIB_6120_IBCCtrl_MaxPktLen_RMASK 0x7FF
+#define QIB_6120_IBCCtrl_LinkCmd_LSB 0x12
+#define QIB_6120_IBCCtrl_LinkCmd_RMASK 0x3
+#define QIB_6120_IBCCtrl_LinkInitCmd_LSB 0x10
+#define QIB_6120_IBCCtrl_LinkInitCmd_RMASK 0x3
+#define QIB_6120_IBCCtrl_FlowCtrlWaterMark_LSB 0x8
+#define QIB_6120_IBCCtrl_FlowCtrlWaterMark_RMASK 0xFF
+#define QIB_6120_IBCCtrl_FlowCtrlPeriod_LSB 0x0
+#define QIB_6120_IBCCtrl_FlowCtrlPeriod_RMASK 0xFF
+
+#define QIB_6120_EXTStatus_OFFS 0xD0
+#define QIB_6120_EXTStatus_GPIOIn_LSB 0x30
+#define QIB_6120_EXTStatus_GPIOIn_RMASK 0xFFFF
+#define QIB_6120_EXTStatus_Reserved_LSB 0x20
+#define QIB_6120_EXTStatus_Reserved_RMASK 0xFFFF
+#define QIB_6120_EXTStatus_Reserved1_LSB 0x10
+#define QIB_6120_EXTStatus_Reserved1_RMASK 0xFFFF
+#define QIB_6120_EXTStatus_MemBISTFoundErr_LSB 0xF
+#define QIB_6120_EXTStatus_MemBISTFoundErr_RMASK 0x1
+#define QIB_6120_EXTStatus_MemBISTEndTest_LSB 0xE
+#define QIB_6120_EXTStatus_MemBISTEndTest_RMASK 0x1
+#define QIB_6120_EXTStatus_Reserved2_LSB 0x0
+#define QIB_6120_EXTStatus_Reserved2_RMASK 0x3FFF
+
+#define QIB_6120_EXTCtrl_OFFS 0xD8
+#define QIB_6120_EXTCtrl_GPIOOe_LSB 0x30
+#define QIB_6120_EXTCtrl_GPIOOe_RMASK 0xFFFF
+#define QIB_6120_EXTCtrl_GPIOInvert_LSB 0x20
+#define QIB_6120_EXTCtrl_GPIOInvert_RMASK 0xFFFF
+#define QIB_6120_EXTCtrl_Reserved_LSB 0x4
+#define QIB_6120_EXTCtrl_Reserved_RMASK 0xFFFFFFF
+#define QIB_6120_EXTCtrl_LEDPriPortGreenOn_LSB 0x3
+#define QIB_6120_EXTCtrl_LEDPriPortGreenOn_RMASK 0x1
+#define QIB_6120_EXTCtrl_LEDPriPortYellowOn_LSB 0x2
+#define QIB_6120_EXTCtrl_LEDPriPortYellowOn_RMASK 0x1
+#define QIB_6120_EXTCtrl_LEDGblOkGreenOn_LSB 0x1
+#define QIB_6120_EXTCtrl_LEDGblOkGreenOn_RMASK 0x1
+#define QIB_6120_EXTCtrl_LEDGblErrRedOff_LSB 0x0
+#define QIB_6120_EXTCtrl_LEDGblErrRedOff_RMASK 0x1
+
+#define QIB_6120_GPIOOut_OFFS 0xE0
+
+#define QIB_6120_GPIOMask_OFFS 0xE8
+
+#define QIB_6120_GPIOStatus_OFFS 0xF0
+
+#define QIB_6120_GPIOClear_OFFS 0xF8
+
+#define QIB_6120_RcvCtrl_OFFS 0x100
+#define QIB_6120_RcvCtrl_TailUpd_LSB 0x1F
+#define QIB_6120_RcvCtrl_TailUpd_RMASK 0x1
+#define QIB_6120_RcvCtrl_RcvPartitionKeyDisable_LSB 0x1E
+#define QIB_6120_RcvCtrl_RcvPartitionKeyDisable_RMASK 0x1
+#define QIB_6120_RcvCtrl_Reserved_LSB 0x15
+#define QIB_6120_RcvCtrl_Reserved_RMASK 0x1FF
+#define QIB_6120_RcvCtrl_IntrAvail_LSB 0x10
+#define QIB_6120_RcvCtrl_IntrAvail_RMASK 0x1F
+#define QIB_6120_RcvCtrl_Reserved1_LSB 0x9
+#define QIB_6120_RcvCtrl_Reserved1_RMASK 0x7F
+#define QIB_6120_RcvCtrl_Reserved2_LSB 0x5
+#define QIB_6120_RcvCtrl_Reserved2_RMASK 0xF
+#define QIB_6120_RcvCtrl_PortEnable_LSB 0x0
+#define QIB_6120_RcvCtrl_PortEnable_RMASK 0x1F
+
+#define QIB_6120_RcvBTHQP_OFFS 0x108
+#define QIB_6120_RcvBTHQP_BTHQP_Mask_LSB 0x1E
+#define QIB_6120_RcvBTHQP_BTHQP_Mask_RMASK 0x3
+#define QIB_6120_RcvBTHQP_Reserved_LSB 0x18
+#define QIB_6120_RcvBTHQP_Reserved_RMASK 0x3F
+#define QIB_6120_RcvBTHQP_RcvBTHQP_LSB 0x0
+#define QIB_6120_RcvBTHQP_RcvBTHQP_RMASK 0xFFFFFF
+
+#define QIB_6120_RcvHdrSize_OFFS 0x110
+
+#define QIB_6120_RcvHdrCnt_OFFS 0x118
+
+#define QIB_6120_RcvHdrEntSize_OFFS 0x120
+
+#define QIB_6120_RcvTIDBase_OFFS 0x128
+
+#define QIB_6120_RcvTIDCnt_OFFS 0x130
+
+#define QIB_6120_RcvEgrBase_OFFS 0x138
+
+#define QIB_6120_RcvEgrCnt_OFFS 0x140
+
+#define QIB_6120_RcvBufBase_OFFS 0x148
+
+#define QIB_6120_RcvBufSize_OFFS 0x150
+
+#define QIB_6120_RxIntMemBase_OFFS 0x158
+
+#define QIB_6120_RxIntMemSize_OFFS 0x160
+
+#define QIB_6120_RcvPartitionKey_OFFS 0x168
+
+#define QIB_6120_RcvPktLEDCnt_OFFS 0x178
+#define QIB_6120_RcvPktLEDCnt_ONperiod_LSB 0x20
+#define QIB_6120_RcvPktLEDCnt_ONperiod_RMASK 0xFFFFFFFF
+#define QIB_6120_RcvPktLEDCnt_OFFperiod_LSB 0x0
+#define QIB_6120_RcvPktLEDCnt_OFFperiod_RMASK 0xFFFFFFFF
+
+#define QIB_6120_SendCtrl_OFFS 0x1C0
+#define QIB_6120_SendCtrl_Disarm_LSB 0x1F
+#define QIB_6120_SendCtrl_Disarm_RMASK 0x1
+#define QIB_6120_SendCtrl_Reserved_LSB 0x17
+#define QIB_6120_SendCtrl_Reserved_RMASK 0xFF
+#define QIB_6120_SendCtrl_DisarmPIOBuf_LSB 0x10
+#define QIB_6120_SendCtrl_DisarmPIOBuf_RMASK 0x7F
+#define QIB_6120_SendCtrl_Reserved1_LSB 0x4
+#define QIB_6120_SendCtrl_Reserved1_RMASK 0xFFF
+#define QIB_6120_SendCtrl_PIOEnable_LSB 0x3
+#define QIB_6120_SendCtrl_PIOEnable_RMASK 0x1
+#define QIB_6120_SendCtrl_PIOBufAvailUpd_LSB 0x2
+#define QIB_6120_SendCtrl_PIOBufAvailUpd_RMASK 0x1
+#define QIB_6120_SendCtrl_PIOIntBufAvail_LSB 0x1
+#define QIB_6120_SendCtrl_PIOIntBufAvail_RMASK 0x1
+#define QIB_6120_SendCtrl_Abort_LSB 0x0
+#define QIB_6120_SendCtrl_Abort_RMASK 0x1
+
+#define QIB_6120_SendPIOBufBase_OFFS 0x1C8
+#define QIB_6120_SendPIOBufBase_Reserved_LSB 0x35
+#define QIB_6120_SendPIOBufBase_Reserved_RMASK 0x7FF
+#define QIB_6120_SendPIOBufBase_BaseAddr_LargePIO_LSB 0x20
+#define QIB_6120_SendPIOBufBase_BaseAddr_LargePIO_RMASK 0x1FFFFF
+#define QIB_6120_SendPIOBufBase_Reserved1_LSB 0x15
+#define QIB_6120_SendPIOBufBase_Reserved1_RMASK 0x7FF
+#define QIB_6120_SendPIOBufBase_BaseAddr_SmallPIO_LSB 0x0
+#define QIB_6120_SendPIOBufBase_BaseAddr_SmallPIO_RMASK 0x1FFFFF
+
+#define QIB_6120_SendPIOSize_OFFS 0x1D0
+#define QIB_6120_SendPIOSize_Reserved_LSB 0x2D
+#define QIB_6120_SendPIOSize_Reserved_RMASK 0xFFFFF
+#define QIB_6120_SendPIOSize_Size_LargePIO_LSB 0x20
+#define QIB_6120_SendPIOSize_Size_LargePIO_RMASK 0x1FFF
+#define QIB_6120_SendPIOSize_Reserved1_LSB 0xC
+#define QIB_6120_SendPIOSize_Reserved1_RMASK 0xFFFFF
+#define QIB_6120_SendPIOSize_Size_SmallPIO_LSB 0x0
+#define QIB_6120_SendPIOSize_Size_SmallPIO_RMASK 0xFFF
+
+#define QIB_6120_SendPIOBufCnt_OFFS 0x1D8
+#define QIB_6120_SendPIOBufCnt_Reserved_LSB 0x24
+#define QIB_6120_SendPIOBufCnt_Reserved_RMASK 0xFFFFFFF
+#define QIB_6120_SendPIOBufCnt_Num_LargePIO_LSB 0x20
+#define QIB_6120_SendPIOBufCnt_Num_LargePIO_RMASK 0xF
+#define QIB_6120_SendPIOBufCnt_Reserved1_LSB 0x9
+#define QIB_6120_SendPIOBufCnt_Reserved1_RMASK 0x7FFFFF
+#define QIB_6120_SendPIOBufCnt_Num_SmallPIO_LSB 0x0
+#define QIB_6120_SendPIOBufCnt_Num_SmallPIO_RMASK 0x1FF
+
+#define QIB_6120_SendPIOAvailAddr_OFFS 0x1E0
+#define QIB_6120_SendPIOAvailAddr_SendPIOAvailAddr_LSB 0x6
+#define QIB_6120_SendPIOAvailAddr_SendPIOAvailAddr_RMASK 0x3FFFFFFFF
+#define QIB_6120_SendPIOAvailAddr_Reserved_LSB 0x0
+#define QIB_6120_SendPIOAvailAddr_Reserved_RMASK 0x3F
+
+#define QIB_6120_SendBufErr0_OFFS 0x240
+#define QIB_6120_SendBufErr0_SendBufErrPIO_63_0_LSB 0x0
+#define QIB_6120_SendBufErr0_SendBufErrPIO_63_0_RMASK 0x0
+
+#define QIB_6120_RcvHdrAddr0_OFFS 0x280
+#define QIB_6120_RcvHdrAddr0_RcvHdrAddr0_LSB 0x2
+#define QIB_6120_RcvHdrAddr0_RcvHdrAddr0_RMASK 0x3FFFFFFFFF
+#define QIB_6120_RcvHdrAddr0_Reserved_LSB 0x0
+#define QIB_6120_RcvHdrAddr0_Reserved_RMASK 0x3
+
+#define QIB_6120_RcvHdrTailAddr0_OFFS 0x300
+#define QIB_6120_RcvHdrTailAddr0_RcvHdrTailAddr0_LSB 0x2
+#define QIB_6120_RcvHdrTailAddr0_RcvHdrTailAddr0_RMASK 0x3FFFFFFFFF
+#define QIB_6120_RcvHdrTailAddr0_Reserved_LSB 0x0
+#define QIB_6120_RcvHdrTailAddr0_Reserved_RMASK 0x3
+
+#define QIB_6120_SerdesCfg0_OFFS 0x3C0
+#define QIB_6120_SerdesCfg0_DisableIBTxIdleDetect_LSB 0x3F
+#define QIB_6120_SerdesCfg0_DisableIBTxIdleDetect_RMASK 0x1
+#define QIB_6120_SerdesCfg0_Reserved_LSB 0x38
+#define QIB_6120_SerdesCfg0_Reserved_RMASK 0x7F
+#define QIB_6120_SerdesCfg0_RxEqCtl_LSB 0x36
+#define QIB_6120_SerdesCfg0_RxEqCtl_RMASK 0x3
+#define QIB_6120_SerdesCfg0_TxTermAdj_LSB 0x34
+#define QIB_6120_SerdesCfg0_TxTermAdj_RMASK 0x3
+#define QIB_6120_SerdesCfg0_RxTermAdj_LSB 0x32
+#define QIB_6120_SerdesCfg0_RxTermAdj_RMASK 0x3
+#define QIB_6120_SerdesCfg0_TermAdj1_LSB 0x31
+#define QIB_6120_SerdesCfg0_TermAdj1_RMASK 0x1
+#define QIB_6120_SerdesCfg0_TermAdj0_LSB 0x30
+#define QIB_6120_SerdesCfg0_TermAdj0_RMASK 0x1
+#define QIB_6120_SerdesCfg0_LPBKA_LSB 0x2F
+#define QIB_6120_SerdesCfg0_LPBKA_RMASK 0x1
+#define QIB_6120_SerdesCfg0_LPBKB_LSB 0x2E
+#define QIB_6120_SerdesCfg0_LPBKB_RMASK 0x1
+#define QIB_6120_SerdesCfg0_LPBKC_LSB 0x2D
+#define QIB_6120_SerdesCfg0_LPBKC_RMASK 0x1
+#define QIB_6120_SerdesCfg0_LPBKD_LSB 0x2C
+#define QIB_6120_SerdesCfg0_LPBKD_RMASK 0x1
+#define QIB_6120_SerdesCfg0_PW_LSB 0x2B
+#define QIB_6120_SerdesCfg0_PW_RMASK 0x1
+#define QIB_6120_SerdesCfg0_RefSel_LSB 0x29
+#define QIB_6120_SerdesCfg0_RefSel_RMASK 0x3
+#define QIB_6120_SerdesCfg0_ParReset_LSB 0x28
+#define QIB_6120_SerdesCfg0_ParReset_RMASK 0x1
+#define QIB_6120_SerdesCfg0_ParLPBK_LSB 0x27
+#define QIB_6120_SerdesCfg0_ParLPBK_RMASK 0x1
+#define QIB_6120_SerdesCfg0_OffsetEn_LSB 0x26
+#define QIB_6120_SerdesCfg0_OffsetEn_RMASK 0x1
+#define QIB_6120_SerdesCfg0_Offset_LSB 0x1E
+#define QIB_6120_SerdesCfg0_Offset_RMASK 0xFF
+#define QIB_6120_SerdesCfg0_L2PwrDn_LSB 0x1D
+#define QIB_6120_SerdesCfg0_L2PwrDn_RMASK 0x1
+#define QIB_6120_SerdesCfg0_ResetPLL_LSB 0x1C
+#define QIB_6120_SerdesCfg0_ResetPLL_RMASK 0x1
+#define QIB_6120_SerdesCfg0_RxTermEnX_LSB 0x18
+#define QIB_6120_SerdesCfg0_RxTermEnX_RMASK 0xF
+#define QIB_6120_SerdesCfg0_BeaconTxEnX_LSB 0x14
+#define QIB_6120_SerdesCfg0_BeaconTxEnX_RMASK 0xF
+#define QIB_6120_SerdesCfg0_RxDetEnX_LSB 0x10
+#define QIB_6120_SerdesCfg0_RxDetEnX_RMASK 0xF
+#define QIB_6120_SerdesCfg0_TxIdeEnX_LSB 0xC
+#define QIB_6120_SerdesCfg0_TxIdeEnX_RMASK 0xF
+#define QIB_6120_SerdesCfg0_RxIdleEnX_LSB 0x8
+#define QIB_6120_SerdesCfg0_RxIdleEnX_RMASK 0xF
+#define QIB_6120_SerdesCfg0_L1PwrDnA_LSB 0x7
+#define QIB_6120_SerdesCfg0_L1PwrDnA_RMASK 0x1
+#define QIB_6120_SerdesCfg0_L1PwrDnB_LSB 0x6
+#define QIB_6120_SerdesCfg0_L1PwrDnB_RMASK 0x1
+#define QIB_6120_SerdesCfg0_L1PwrDnC_LSB 0x5
+#define QIB_6120_SerdesCfg0_L1PwrDnC_RMASK 0x1
+#define QIB_6120_SerdesCfg0_L1PwrDnD_LSB 0x4
+#define QIB_6120_SerdesCfg0_L1PwrDnD_RMASK 0x1
+#define QIB_6120_SerdesCfg0_ResetA_LSB 0x3
+#define QIB_6120_SerdesCfg0_ResetA_RMASK 0x1
+#define QIB_6120_SerdesCfg0_ResetB_LSB 0x2
+#define QIB_6120_SerdesCfg0_ResetB_RMASK 0x1
+#define QIB_6120_SerdesCfg0_ResetC_LSB 0x1
+#define QIB_6120_SerdesCfg0_ResetC_RMASK 0x1
+#define QIB_6120_SerdesCfg0_ResetD_LSB 0x0
+#define QIB_6120_SerdesCfg0_ResetD_RMASK 0x1
+
+#define QIB_6120_SerdesStat_OFFS 0x3D0
+#define QIB_6120_SerdesStat_Reserved_LSB 0xC
+#define QIB_6120_SerdesStat_Reserved_RMASK 0xFFFFFFFFFFFFF
+#define QIB_6120_SerdesStat_BeaconDetA_LSB 0xB
+#define QIB_6120_SerdesStat_BeaconDetA_RMASK 0x1
+#define QIB_6120_SerdesStat_BeaconDetB_LSB 0xA
+#define QIB_6120_SerdesStat_BeaconDetB_RMASK 0x1
+#define QIB_6120_SerdesStat_BeaconDetC_LSB 0x9
+#define QIB_6120_SerdesStat_BeaconDetC_RMASK 0x1
+#define QIB_6120_SerdesStat_BeaconDetD_LSB 0x8
+#define QIB_6120_SerdesStat_BeaconDetD_RMASK 0x1
+#define QIB_6120_SerdesStat_RxDetA_LSB 0x7
+#define QIB_6120_SerdesStat_RxDetA_RMASK 0x1
+#define QIB_6120_SerdesStat_RxDetB_LSB 0x6
+#define QIB_6120_SerdesStat_RxDetB_RMASK 0x1
+#define QIB_6120_SerdesStat_RxDetC_LSB 0x5
+#define QIB_6120_SerdesStat_RxDetC_RMASK 0x1
+#define QIB_6120_SerdesStat_RxDetD_LSB 0x4
+#define QIB_6120_SerdesStat_RxDetD_RMASK 0x1
+#define QIB_6120_SerdesStat_TxIdleDetA_LSB 0x3
+#define QIB_6120_SerdesStat_TxIdleDetA_RMASK 0x1
+#define QIB_6120_SerdesStat_TxIdleDetB_LSB 0x2
+#define QIB_6120_SerdesStat_TxIdleDetB_RMASK 0x1
+#define QIB_6120_SerdesStat_TxIdleDetC_LSB 0x1
+#define QIB_6120_SerdesStat_TxIdleDetC_RMASK 0x1
+#define QIB_6120_SerdesStat_TxIdleDetD_LSB 0x0
+#define QIB_6120_SerdesStat_TxIdleDetD_RMASK 0x1
+
+#define QIB_6120_XGXSCfg_OFFS 0x3D8
+#define QIB_6120_XGXSCfg_ArmLaunchErrorDisable_LSB 0x3F
+#define QIB_6120_XGXSCfg_ArmLaunchErrorDisable_RMASK 0x1
+#define QIB_6120_XGXSCfg_Reserved_LSB 0x17
+#define QIB_6120_XGXSCfg_Reserved_RMASK 0xFFFFFFFFFF
+#define QIB_6120_XGXSCfg_polarity_inv_LSB 0x13
+#define QIB_6120_XGXSCfg_polarity_inv_RMASK 0xF
+#define QIB_6120_XGXSCfg_link_sync_mask_LSB 0x9
+#define QIB_6120_XGXSCfg_link_sync_mask_RMASK 0x3FF
+#define QIB_6120_XGXSCfg_port_addr_LSB 0x4
+#define QIB_6120_XGXSCfg_port_addr_RMASK 0x1F
+#define QIB_6120_XGXSCfg_mdd_30_LSB 0x3
+#define QIB_6120_XGXSCfg_mdd_30_RMASK 0x1
+#define QIB_6120_XGXSCfg_xcv_resetn_LSB 0x2
+#define QIB_6120_XGXSCfg_xcv_resetn_RMASK 0x1
+#define QIB_6120_XGXSCfg_Reserved1_LSB 0x1
+#define QIB_6120_XGXSCfg_Reserved1_RMASK 0x1
+#define QIB_6120_XGXSCfg_tx_rx_resetn_LSB 0x0
+#define QIB_6120_XGXSCfg_tx_rx_resetn_RMASK 0x1
+
+#define QIB_6120_LBIntCnt_OFFS 0x12000
+
+#define QIB_6120_LBFlowStallCnt_OFFS 0x12008
+
+#define QIB_6120_TxUnsupVLErrCnt_OFFS 0x12018
+
+#define QIB_6120_TxDataPktCnt_OFFS 0x12020
+
+#define QIB_6120_TxFlowPktCnt_OFFS 0x12028
+
+#define QIB_6120_TxDwordCnt_OFFS 0x12030
+
+#define QIB_6120_TxLenErrCnt_OFFS 0x12038
+
+#define QIB_6120_TxMaxMinLenErrCnt_OFFS 0x12040
+
+#define QIB_6120_TxUnderrunCnt_OFFS 0x12048
+
+#define QIB_6120_TxFlowStallCnt_OFFS 0x12050
+
+#define QIB_6120_TxDroppedPktCnt_OFFS 0x12058
+
+#define QIB_6120_RxDroppedPktCnt_OFFS 0x12060
+
+#define QIB_6120_RxDataPktCnt_OFFS 0x12068
+
+#define QIB_6120_RxFlowPktCnt_OFFS 0x12070
+
+#define QIB_6120_RxDwordCnt_OFFS 0x12078
+
+#define QIB_6120_RxLenErrCnt_OFFS 0x12080
+
+#define QIB_6120_RxMaxMinLenErrCnt_OFFS 0x12088
+
+#define QIB_6120_RxICRCErrCnt_OFFS 0x12090
+
+#define QIB_6120_RxVCRCErrCnt_OFFS 0x12098
+
+#define QIB_6120_RxFlowCtrlErrCnt_OFFS 0x120A0
+
+#define QIB_6120_RxBadFormatCnt_OFFS 0x120A8
+
+#define QIB_6120_RxLinkProblemCnt_OFFS 0x120B0
+
+#define QIB_6120_RxEBPCnt_OFFS 0x120B8
+
+#define QIB_6120_RxLPCRCErrCnt_OFFS 0x120C0
+
+#define QIB_6120_RxBufOvflCnt_OFFS 0x120C8
+
+#define QIB_6120_RxTIDFullErrCnt_OFFS 0x120D0
+
+#define QIB_6120_RxTIDValidErrCnt_OFFS 0x120D8
+
+#define QIB_6120_RxPKeyMismatchCnt_OFFS 0x120E0
+
+#define QIB_6120_RxP0HdrEgrOvflCnt_OFFS 0x120E8
+
+#define QIB_6120_IBStatusChangeCnt_OFFS 0x12140
+
+#define QIB_6120_IBLinkErrRecoveryCnt_OFFS 0x12148
+
+#define QIB_6120_IBLinkDownedCnt_OFFS 0x12150
+
+#define QIB_6120_IBSymbolErrCnt_OFFS 0x12158
+
+#define QIB_6120_PcieRetryBufDiagQwordCnt_OFFS 0x12170
+
+#define QIB_6120_RcvEgrArray0_OFFS 0x14000
+
+#define QIB_6120_RcvTIDArray0_OFFS 0x54000
+
+#define QIB_6120_PIOLaunchFIFO_OFFS 0x64000
+
+#define QIB_6120_SendPIOpbcCache_OFFS 0x64800
+
+#define QIB_6120_RcvBuf1_OFFS 0x72000
+
+#define QIB_6120_RcvBuf2_OFFS 0x75000
+
+#define QIB_6120_RcvFlags_OFFS 0x77000
+
+#define QIB_6120_RcvLookupBuf1_OFFS 0x79000
+
+#define QIB_6120_RcvDMABuf_OFFS 0x7B000
+
+#define QIB_6120_MiscRXEIntMem_OFFS 0x7C000
+
+#define QIB_6120_PCIERcvBuf_OFFS 0x80000
+
+#define QIB_6120_PCIERetryBuf_OFFS 0x82000
+
+#define QIB_6120_PCIERcvBufRdToWrAddr_OFFS 0x84000
+
+#define QIB_6120_PIOBuf0_MA_OFFS 0x100000
diff --git a/drivers/infiniband/hw/qib/qib_7220.h b/drivers/infiniband/hw/qib/qib_7220.h
new file mode 100644 (file)
index 0000000..ea0bfd8
--- /dev/null
@@ -0,0 +1,156 @@
+#ifndef _QIB_7220_H
+#define _QIB_7220_H
+/*
+ * Copyright (c) 2007, 2009, 2010 QLogic Corporation. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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.
+ */
+
+/* grab register-defs auto-generated by HW */
+#include "qib_7220_regs.h"
+
+/* The number of eager receive TIDs for context zero. */
+#define IBA7220_KRCVEGRCNT      2048U
+
+#define IB_7220_LT_STATE_CFGRCVFCFG      0x09
+#define IB_7220_LT_STATE_CFGWAITRMT      0x0a
+#define IB_7220_LT_STATE_TXREVLANES      0x0d
+#define IB_7220_LT_STATE_CFGENH          0x10
+
+struct qib_chip_specific {
+       u64 __iomem *cregbase;
+       u64 *cntrs;
+       u64 *portcntrs;
+       spinlock_t sdepb_lock; /* serdes EPB bus */
+       spinlock_t rcvmod_lock; /* protect rcvctrl shadow changes */
+       spinlock_t gpio_lock; /* RMW of shadows/regs for ExtCtrl and GPIO */
+       u64 hwerrmask;
+       u64 errormask;
+       u64 gpio_out; /* shadow of kr_gpio_out, for rmw ops */
+       u64 gpio_mask; /* shadow the gpio mask register */
+       u64 extctrl; /* shadow the gpio output enable, etc... */
+       u32 ncntrs;
+       u32 nportcntrs;
+       u32 cntrnamelen;
+       u32 portcntrnamelen;
+       u32 numctxts;
+       u32 rcvegrcnt;
+       u32 autoneg_tries;
+       u32 serdes_first_init_done;
+       u32 sdmabufcnt;
+       u32 lastbuf_for_pio;
+       u32 updthresh; /* current AvailUpdThld */
+       u32 updthresh_dflt; /* default AvailUpdThld */
+       int irq;
+       u8 presets_needed;
+       u8 relock_timer_active;
+       char emsgbuf[128];
+       char sdmamsgbuf[192];
+       char bitsmsgbuf[64];
+       struct timer_list relock_timer;
+       unsigned int relock_interval; /* in jiffies */
+};
+
+struct qib_chippport_specific {
+       struct qib_pportdata pportdata;
+       wait_queue_head_t autoneg_wait;
+       struct delayed_work autoneg_work;
+       struct timer_list chase_timer;
+       /*
+        * these 5 fields are used to establish deltas for IB symbol
+        * errors and linkrecovery errors.  They can be reported on
+        * some chips during link negotiation prior to INIT, and with
+        * DDR when faking DDR negotiations with non-IBTA switches.
+        * The chip counters are adjusted at driver unload if there is
+        * a non-zero delta.
+        */
+       u64 ibdeltainprog;
+       u64 ibsymdelta;
+       u64 ibsymsnap;
+       u64 iblnkerrdelta;
+       u64 iblnkerrsnap;
+       u64 ibcctrl; /* kr_ibcctrl shadow */
+       u64 ibcddrctrl; /* kr_ibcddrctrl shadow */
+       u64 chase_end;
+       u32 last_delay_mult;
+};
+
+/*
+ * This header file provides the declarations and common definitions
+ * for (mostly) manipulation of the SerDes blocks within the IBA7220.
+ * the functions declared should only be called from within other
+ * 7220-related files such as qib_iba7220.c or qib_sd7220.c.
+ */
+int qib_sd7220_presets(struct qib_devdata *dd);
+int qib_sd7220_init(struct qib_devdata *dd);
+int qib_sd7220_prog_ld(struct qib_devdata *dd, int sdnum, u8 *img,
+                      int len, int offset);
+int qib_sd7220_prog_vfy(struct qib_devdata *dd, int sdnum, const u8 *img,
+                       int len, int offset);
+void qib_sd7220_clr_ibpar(struct qib_devdata *);
+/*
+ * Below used for sdnum parameter, selecting one of the two sections
+ * used for PCIe, or the single SerDes used for IB, which is the
+ * only one currently used
+ */
+#define IB_7220_SERDES 2
+
+int qib_sd7220_ib_load(struct qib_devdata *dd);
+int qib_sd7220_ib_vfy(struct qib_devdata *dd);
+
+static inline u32 qib_read_kreg32(const struct qib_devdata *dd,
+                                 const u16 regno)
+{
+       if (!dd->kregbase || !(dd->flags & QIB_PRESENT))
+               return -1;
+       return readl((u32 __iomem *)&dd->kregbase[regno]);
+}
+
+static inline u64 qib_read_kreg64(const struct qib_devdata *dd,
+                                 const u16 regno)
+{
+       if (!dd->kregbase || !(dd->flags & QIB_PRESENT))
+               return -1;
+
+       return readq(&dd->kregbase[regno]);
+}
+
+static inline void qib_write_kreg(const struct qib_devdata *dd,
+                                 const u16 regno, u64 value)
+{
+       if (dd->kregbase)
+               writeq(value, &dd->kregbase[regno]);
+}
+
+void set_7220_relock_poll(struct qib_devdata *, int);
+void shutdown_7220_relock_poll(struct qib_devdata *);
+void toggle_7220_rclkrls(struct qib_devdata *);
+
+
+#endif /* _QIB_7220_H */
diff --git a/drivers/infiniband/hw/qib/qib_7220_regs.h b/drivers/infiniband/hw/qib/qib_7220_regs.h
new file mode 100644 (file)
index 0000000..0da5bb7
--- /dev/null
@@ -0,0 +1,1496 @@
+/*
+ * Copyright (c) 2008, 2009, 2010 QLogic Corporation. All rights reserved.
+ *
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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.
+ *
+ */
+
+/* This file is mechanically generated from RTL. Any hand-edits will be lost! */
+
+#define QIB_7220_Revision_OFFS 0x0
+#define QIB_7220_Revision_R_Simulator_LSB 0x3F
+#define QIB_7220_Revision_R_Simulator_RMASK 0x1
+#define QIB_7220_Revision_R_Emulation_LSB 0x3E
+#define QIB_7220_Revision_R_Emulation_RMASK 0x1
+#define QIB_7220_Revision_R_Emulation_Revcode_LSB 0x28
+#define QIB_7220_Revision_R_Emulation_Revcode_RMASK 0x3FFFFF
+#define QIB_7220_Revision_BoardID_LSB 0x20
+#define QIB_7220_Revision_BoardID_RMASK 0xFF
+#define QIB_7220_Revision_R_SW_LSB 0x18
+#define QIB_7220_Revision_R_SW_RMASK 0xFF
+#define QIB_7220_Revision_R_Arch_LSB 0x10
+#define QIB_7220_Revision_R_Arch_RMASK 0xFF
+#define QIB_7220_Revision_R_ChipRevMajor_LSB 0x8
+#define QIB_7220_Revision_R_ChipRevMajor_RMASK 0xFF
+#define QIB_7220_Revision_R_ChipRevMinor_LSB 0x0
+#define QIB_7220_Revision_R_ChipRevMinor_RMASK 0xFF
+
+#define QIB_7220_Control_OFFS 0x8
+#define QIB_7220_Control_SyncResetExceptPcieIRAMRST_LSB 0x7
+#define QIB_7220_Control_SyncResetExceptPcieIRAMRST_RMASK 0x1
+#define QIB_7220_Control_PCIECplQDiagEn_LSB 0x6
+#define QIB_7220_Control_PCIECplQDiagEn_RMASK 0x1
+#define QIB_7220_Control_Reserved_LSB 0x5
+#define QIB_7220_Control_Reserved_RMASK 0x1
+#define QIB_7220_Control_TxLatency_LSB 0x4
+#define QIB_7220_Control_TxLatency_RMASK 0x1
+#define QIB_7220_Control_PCIERetryBufDiagEn_LSB 0x3
+#define QIB_7220_Control_PCIERetryBufDiagEn_RMASK 0x1
+#define QIB_7220_Control_LinkEn_LSB 0x2
+#define QIB_7220_Control_LinkEn_RMASK 0x1
+#define QIB_7220_Control_FreezeMode_LSB 0x1
+#define QIB_7220_Control_FreezeMode_RMASK 0x1
+#define QIB_7220_Control_SyncReset_LSB 0x0
+#define QIB_7220_Control_SyncReset_RMASK 0x1
+
+#define QIB_7220_PageAlign_OFFS 0x10
+
+#define QIB_7220_PortCnt_OFFS 0x18
+
+#define QIB_7220_SendRegBase_OFFS 0x30
+
+#define QIB_7220_UserRegBase_OFFS 0x38
+
+#define QIB_7220_CntrRegBase_OFFS 0x40
+
+#define QIB_7220_Scratch_OFFS 0x48
+
+#define QIB_7220_IntMask_OFFS 0x68
+#define QIB_7220_IntMask_SDmaIntMask_LSB 0x3F
+#define QIB_7220_IntMask_SDmaIntMask_RMASK 0x1
+#define QIB_7220_IntMask_SDmaDisabledMasked_LSB 0x3E
+#define QIB_7220_IntMask_SDmaDisabledMasked_RMASK 0x1
+#define QIB_7220_IntMask_Reserved_LSB 0x31
+#define QIB_7220_IntMask_Reserved_RMASK 0x1FFF
+#define QIB_7220_IntMask_RcvUrg16IntMask_LSB 0x30
+#define QIB_7220_IntMask_RcvUrg16IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvUrg15IntMask_LSB 0x2F
+#define QIB_7220_IntMask_RcvUrg15IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvUrg14IntMask_LSB 0x2E
+#define QIB_7220_IntMask_RcvUrg14IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvUrg13IntMask_LSB 0x2D
+#define QIB_7220_IntMask_RcvUrg13IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvUrg12IntMask_LSB 0x2C
+#define QIB_7220_IntMask_RcvUrg12IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvUrg11IntMask_LSB 0x2B
+#define QIB_7220_IntMask_RcvUrg11IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvUrg10IntMask_LSB 0x2A
+#define QIB_7220_IntMask_RcvUrg10IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvUrg9IntMask_LSB 0x29
+#define QIB_7220_IntMask_RcvUrg9IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvUrg8IntMask_LSB 0x28
+#define QIB_7220_IntMask_RcvUrg8IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvUrg7IntMask_LSB 0x27
+#define QIB_7220_IntMask_RcvUrg7IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvUrg6IntMask_LSB 0x26
+#define QIB_7220_IntMask_RcvUrg6IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvUrg5IntMask_LSB 0x25
+#define QIB_7220_IntMask_RcvUrg5IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvUrg4IntMask_LSB 0x24
+#define QIB_7220_IntMask_RcvUrg4IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvUrg3IntMask_LSB 0x23
+#define QIB_7220_IntMask_RcvUrg3IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvUrg2IntMask_LSB 0x22
+#define QIB_7220_IntMask_RcvUrg2IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvUrg1IntMask_LSB 0x21
+#define QIB_7220_IntMask_RcvUrg1IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvUrg0IntMask_LSB 0x20
+#define QIB_7220_IntMask_RcvUrg0IntMask_RMASK 0x1
+#define QIB_7220_IntMask_ErrorIntMask_LSB 0x1F
+#define QIB_7220_IntMask_ErrorIntMask_RMASK 0x1
+#define QIB_7220_IntMask_PioSetIntMask_LSB 0x1E
+#define QIB_7220_IntMask_PioSetIntMask_RMASK 0x1
+#define QIB_7220_IntMask_PioBufAvailIntMask_LSB 0x1D
+#define QIB_7220_IntMask_PioBufAvailIntMask_RMASK 0x1
+#define QIB_7220_IntMask_assertGPIOIntMask_LSB 0x1C
+#define QIB_7220_IntMask_assertGPIOIntMask_RMASK 0x1
+#define QIB_7220_IntMask_IBSerdesTrimDoneIntMask_LSB 0x1B
+#define QIB_7220_IntMask_IBSerdesTrimDoneIntMask_RMASK 0x1
+#define QIB_7220_IntMask_JIntMask_LSB 0x1A
+#define QIB_7220_IntMask_JIntMask_RMASK 0x1
+#define QIB_7220_IntMask_Reserved1_LSB 0x11
+#define QIB_7220_IntMask_Reserved1_RMASK 0x1FF
+#define QIB_7220_IntMask_RcvAvail16IntMask_LSB 0x10
+#define QIB_7220_IntMask_RcvAvail16IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvAvail15IntMask_LSB 0xF
+#define QIB_7220_IntMask_RcvAvail15IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvAvail14IntMask_LSB 0xE
+#define QIB_7220_IntMask_RcvAvail14IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvAvail13IntMask_LSB 0xD
+#define QIB_7220_IntMask_RcvAvail13IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvAvail12IntMask_LSB 0xC
+#define QIB_7220_IntMask_RcvAvail12IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvAvail11IntMask_LSB 0xB
+#define QIB_7220_IntMask_RcvAvail11IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvAvail10IntMask_LSB 0xA
+#define QIB_7220_IntMask_RcvAvail10IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvAvail9IntMask_LSB 0x9
+#define QIB_7220_IntMask_RcvAvail9IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvAvail8IntMask_LSB 0x8
+#define QIB_7220_IntMask_RcvAvail8IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvAvail7IntMask_LSB 0x7
+#define QIB_7220_IntMask_RcvAvail7IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvAvail6IntMask_LSB 0x6
+#define QIB_7220_IntMask_RcvAvail6IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvAvail5IntMask_LSB 0x5
+#define QIB_7220_IntMask_RcvAvail5IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvAvail4IntMask_LSB 0x4
+#define QIB_7220_IntMask_RcvAvail4IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvAvail3IntMask_LSB 0x3
+#define QIB_7220_IntMask_RcvAvail3IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvAvail2IntMask_LSB 0x2
+#define QIB_7220_IntMask_RcvAvail2IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvAvail1IntMask_LSB 0x1
+#define QIB_7220_IntMask_RcvAvail1IntMask_RMASK 0x1
+#define QIB_7220_IntMask_RcvAvail0IntMask_LSB 0x0
+#define QIB_7220_IntMask_RcvAvail0IntMask_RMASK 0x1
+
+#define QIB_7220_IntStatus_OFFS 0x70
+#define QIB_7220_IntStatus_SDmaInt_LSB 0x3F
+#define QIB_7220_IntStatus_SDmaInt_RMASK 0x1
+#define QIB_7220_IntStatus_SDmaDisabled_LSB 0x3E
+#define QIB_7220_IntStatus_SDmaDisabled_RMASK 0x1
+#define QIB_7220_IntStatus_Reserved_LSB 0x31
+#define QIB_7220_IntStatus_Reserved_RMASK 0x1FFF
+#define QIB_7220_IntStatus_RcvUrg16_LSB 0x30
+#define QIB_7220_IntStatus_RcvUrg16_RMASK 0x1
+#define QIB_7220_IntStatus_RcvUrg15_LSB 0x2F
+#define QIB_7220_IntStatus_RcvUrg15_RMASK 0x1
+#define QIB_7220_IntStatus_RcvUrg14_LSB 0x2E
+#define QIB_7220_IntStatus_RcvUrg14_RMASK 0x1
+#define QIB_7220_IntStatus_RcvUrg13_LSB 0x2D
+#define QIB_7220_IntStatus_RcvUrg13_RMASK 0x1
+#define QIB_7220_IntStatus_RcvUrg12_LSB 0x2C
+#define QIB_7220_IntStatus_RcvUrg12_RMASK 0x1
+#define QIB_7220_IntStatus_RcvUrg11_LSB 0x2B
+#define QIB_7220_IntStatus_RcvUrg11_RMASK 0x1
+#define QIB_7220_IntStatus_RcvUrg10_LSB 0x2A
+#define QIB_7220_IntStatus_RcvUrg10_RMASK 0x1
+#define QIB_7220_IntStatus_RcvUrg9_LSB 0x29
+#define QIB_7220_IntStatus_RcvUrg9_RMASK 0x1
+#define QIB_7220_IntStatus_RcvUrg8_LSB 0x28
+#define QIB_7220_IntStatus_RcvUrg8_RMASK 0x1
+#define QIB_7220_IntStatus_RcvUrg7_LSB 0x27
+#define QIB_7220_IntStatus_RcvUrg7_RMASK 0x1
+#define QIB_7220_IntStatus_RcvUrg6_LSB 0x26
+#define QIB_7220_IntStatus_RcvUrg6_RMASK 0x1
+#define QIB_7220_IntStatus_RcvUrg5_LSB 0x25
+#define QIB_7220_IntStatus_RcvUrg5_RMASK 0x1
+#define QIB_7220_IntStatus_RcvUrg4_LSB 0x24
+#define QIB_7220_IntStatus_RcvUrg4_RMASK 0x1
+#define QIB_7220_IntStatus_RcvUrg3_LSB 0x23
+#define QIB_7220_IntStatus_RcvUrg3_RMASK 0x1
+#define QIB_7220_IntStatus_RcvUrg2_LSB 0x22
+#define QIB_7220_IntStatus_RcvUrg2_RMASK 0x1
+#define QIB_7220_IntStatus_RcvUrg1_LSB 0x21
+#define QIB_7220_IntStatus_RcvUrg1_RMASK 0x1
+#define QIB_7220_IntStatus_RcvUrg0_LSB 0x20
+#define QIB_7220_IntStatus_RcvUrg0_RMASK 0x1
+#define QIB_7220_IntStatus_Error_LSB 0x1F
+#define QIB_7220_IntStatus_Error_RMASK 0x1
+#define QIB_7220_IntStatus_PioSent_LSB 0x1E
+#define QIB_7220_IntStatus_PioSent_RMASK 0x1
+#define QIB_7220_IntStatus_PioBufAvail_LSB 0x1D
+#define QIB_7220_IntStatus_PioBufAvail_RMASK 0x1
+#define QIB_7220_IntStatus_assertGPIO_LSB 0x1C
+#define QIB_7220_IntStatus_assertGPIO_RMASK 0x1
+#define QIB_7220_IntStatus_IBSerdesTrimDone_LSB 0x1B
+#define QIB_7220_IntStatus_IBSerdesTrimDone_RMASK 0x1
+#define QIB_7220_IntStatus_JInt_LSB 0x1A
+#define QIB_7220_IntStatus_JInt_RMASK 0x1
+#define QIB_7220_IntStatus_Reserved1_LSB 0x11
+#define QIB_7220_IntStatus_Reserved1_RMASK 0x1FF
+#define QIB_7220_IntStatus_RcvAvail16_LSB 0x10
+#define QIB_7220_IntStatus_RcvAvail16_RMASK 0x1
+#define QIB_7220_IntStatus_RcvAvail15_LSB 0xF
+#define QIB_7220_IntStatus_RcvAvail15_RMASK 0x1
+#define QIB_7220_IntStatus_RcvAvail14_LSB 0xE
+#define QIB_7220_IntStatus_RcvAvail14_RMASK 0x1
+#define QIB_7220_IntStatus_RcvAvail13_LSB 0xD
+#define QIB_7220_IntStatus_RcvAvail13_RMASK 0x1
+#define QIB_7220_IntStatus_RcvAvail12_LSB 0xC
+#define QIB_7220_IntStatus_RcvAvail12_RMASK 0x1
+#define QIB_7220_IntStatus_RcvAvail11_LSB 0xB
+#define QIB_7220_IntStatus_RcvAvail11_RMASK 0x1
+#define QIB_7220_IntStatus_RcvAvail10_LSB 0xA
+#define QIB_7220_IntStatus_RcvAvail10_RMASK 0x1
+#define QIB_7220_IntStatus_RcvAvail9_LSB 0x9
+#define QIB_7220_IntStatus_RcvAvail9_RMASK 0x1
+#define QIB_7220_IntStatus_RcvAvail8_LSB 0x8
+#define QIB_7220_IntStatus_RcvAvail8_RMASK 0x1
+#define QIB_7220_IntStatus_RcvAvail7_LSB 0x7
+#define QIB_7220_IntStatus_RcvAvail7_RMASK 0x1
+#define QIB_7220_IntStatus_RcvAvail6_LSB 0x6
+#define QIB_7220_IntStatus_RcvAvail6_RMASK 0x1
+#define QIB_7220_IntStatus_RcvAvail5_LSB 0x5
+#define QIB_7220_IntStatus_RcvAvail5_RMASK 0x1
+#define QIB_7220_IntStatus_RcvAvail4_LSB 0x4
+#define QIB_7220_IntStatus_RcvAvail4_RMASK 0x1
+#define QIB_7220_IntStatus_RcvAvail3_LSB 0x3
+#define QIB_7220_IntStatus_RcvAvail3_RMASK 0x1
+#define QIB_7220_IntStatus_RcvAvail2_LSB 0x2
+#define QIB_7220_IntStatus_RcvAvail2_RMASK 0x1
+#define QIB_7220_IntStatus_RcvAvail1_LSB 0x1
+#define QIB_7220_IntStatus_RcvAvail1_RMASK 0x1
+#define QIB_7220_IntStatus_RcvAvail0_LSB 0x0
+#define QIB_7220_IntStatus_RcvAvail0_RMASK 0x1
+
+#define QIB_7220_IntClear_OFFS 0x78
+#define QIB_7220_IntClear_SDmaIntClear_LSB 0x3F
+#define QIB_7220_IntClear_SDmaIntClear_RMASK 0x1
+#define QIB_7220_IntClear_SDmaDisabledClear_LSB 0x3E
+#define QIB_7220_IntClear_SDmaDisabledClear_RMASK 0x1
+#define QIB_7220_IntClear_Reserved_LSB 0x31
+#define QIB_7220_IntClear_Reserved_RMASK 0x1FFF
+#define QIB_7220_IntClear_RcvUrg16IntClear_LSB 0x30
+#define QIB_7220_IntClear_RcvUrg16IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvUrg15IntClear_LSB 0x2F
+#define QIB_7220_IntClear_RcvUrg15IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvUrg14IntClear_LSB 0x2E
+#define QIB_7220_IntClear_RcvUrg14IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvUrg13IntClear_LSB 0x2D
+#define QIB_7220_IntClear_RcvUrg13IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvUrg12IntClear_LSB 0x2C
+#define QIB_7220_IntClear_RcvUrg12IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvUrg11IntClear_LSB 0x2B
+#define QIB_7220_IntClear_RcvUrg11IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvUrg10IntClear_LSB 0x2A
+#define QIB_7220_IntClear_RcvUrg10IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvUrg9IntClear_LSB 0x29
+#define QIB_7220_IntClear_RcvUrg9IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvUrg8IntClear_LSB 0x28
+#define QIB_7220_IntClear_RcvUrg8IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvUrg7IntClear_LSB 0x27
+#define QIB_7220_IntClear_RcvUrg7IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvUrg6IntClear_LSB 0x26
+#define QIB_7220_IntClear_RcvUrg6IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvUrg5IntClear_LSB 0x25
+#define QIB_7220_IntClear_RcvUrg5IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvUrg4IntClear_LSB 0x24
+#define QIB_7220_IntClear_RcvUrg4IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvUrg3IntClear_LSB 0x23
+#define QIB_7220_IntClear_RcvUrg3IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvUrg2IntClear_LSB 0x22
+#define QIB_7220_IntClear_RcvUrg2IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvUrg1IntClear_LSB 0x21
+#define QIB_7220_IntClear_RcvUrg1IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvUrg0IntClear_LSB 0x20
+#define QIB_7220_IntClear_RcvUrg0IntClear_RMASK 0x1
+#define QIB_7220_IntClear_ErrorIntClear_LSB 0x1F
+#define QIB_7220_IntClear_ErrorIntClear_RMASK 0x1
+#define QIB_7220_IntClear_PioSetIntClear_LSB 0x1E
+#define QIB_7220_IntClear_PioSetIntClear_RMASK 0x1
+#define QIB_7220_IntClear_PioBufAvailIntClear_LSB 0x1D
+#define QIB_7220_IntClear_PioBufAvailIntClear_RMASK 0x1
+#define QIB_7220_IntClear_assertGPIOIntClear_LSB 0x1C
+#define QIB_7220_IntClear_assertGPIOIntClear_RMASK 0x1
+#define QIB_7220_IntClear_IBSerdesTrimDoneClear_LSB 0x1B
+#define QIB_7220_IntClear_IBSerdesTrimDoneClear_RMASK 0x1
+#define QIB_7220_IntClear_JIntClear_LSB 0x1A
+#define QIB_7220_IntClear_JIntClear_RMASK 0x1
+#define QIB_7220_IntClear_Reserved1_LSB 0x11
+#define QIB_7220_IntClear_Reserved1_RMASK 0x1FF
+#define QIB_7220_IntClear_RcvAvail16IntClear_LSB 0x10
+#define QIB_7220_IntClear_RcvAvail16IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvAvail15IntClear_LSB 0xF
+#define QIB_7220_IntClear_RcvAvail15IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvAvail14IntClear_LSB 0xE
+#define QIB_7220_IntClear_RcvAvail14IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvAvail13IntClear_LSB 0xD
+#define QIB_7220_IntClear_RcvAvail13IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvAvail12IntClear_LSB 0xC
+#define QIB_7220_IntClear_RcvAvail12IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvAvail11IntClear_LSB 0xB
+#define QIB_7220_IntClear_RcvAvail11IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvAvail10IntClear_LSB 0xA
+#define QIB_7220_IntClear_RcvAvail10IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvAvail9IntClear_LSB 0x9
+#define QIB_7220_IntClear_RcvAvail9IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvAvail8IntClear_LSB 0x8
+#define QIB_7220_IntClear_RcvAvail8IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvAvail7IntClear_LSB 0x7
+#define QIB_7220_IntClear_RcvAvail7IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvAvail6IntClear_LSB 0x6
+#define QIB_7220_IntClear_RcvAvail6IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvAvail5IntClear_LSB 0x5
+#define QIB_7220_IntClear_RcvAvail5IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvAvail4IntClear_LSB 0x4
+#define QIB_7220_IntClear_RcvAvail4IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvAvail3IntClear_LSB 0x3
+#define QIB_7220_IntClear_RcvAvail3IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvAvail2IntClear_LSB 0x2
+#define QIB_7220_IntClear_RcvAvail2IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvAvail1IntClear_LSB 0x1
+#define QIB_7220_IntClear_RcvAvail1IntClear_RMASK 0x1
+#define QIB_7220_IntClear_RcvAvail0IntClear_LSB 0x0
+#define QIB_7220_IntClear_RcvAvail0IntClear_RMASK 0x1
+
+#define QIB_7220_ErrMask_OFFS 0x80
+#define QIB_7220_ErrMask_Reserved_LSB 0x36
+#define QIB_7220_ErrMask_Reserved_RMASK 0x3FF
+#define QIB_7220_ErrMask_InvalidEEPCmdMask_LSB 0x35
+#define QIB_7220_ErrMask_InvalidEEPCmdMask_RMASK 0x1
+#define QIB_7220_ErrMask_SDmaDescAddrMisalignErrMask_LSB 0x34
+#define QIB_7220_ErrMask_SDmaDescAddrMisalignErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_HardwareErrMask_LSB 0x33
+#define QIB_7220_ErrMask_HardwareErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_ResetNegatedMask_LSB 0x32
+#define QIB_7220_ErrMask_ResetNegatedMask_RMASK 0x1
+#define QIB_7220_ErrMask_InvalidAddrErrMask_LSB 0x31
+#define QIB_7220_ErrMask_InvalidAddrErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_IBStatusChangedMask_LSB 0x30
+#define QIB_7220_ErrMask_IBStatusChangedMask_RMASK 0x1
+#define QIB_7220_ErrMask_SDmaUnexpDataErrMask_LSB 0x2F
+#define QIB_7220_ErrMask_SDmaUnexpDataErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_SDmaMissingDwErrMask_LSB 0x2E
+#define QIB_7220_ErrMask_SDmaMissingDwErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_SDmaDwEnErrMask_LSB 0x2D
+#define QIB_7220_ErrMask_SDmaDwEnErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_SDmaRpyTagErrMask_LSB 0x2C
+#define QIB_7220_ErrMask_SDmaRpyTagErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_SDma1stDescErrMask_LSB 0x2B
+#define QIB_7220_ErrMask_SDma1stDescErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_SDmaBaseErrMask_LSB 0x2A
+#define QIB_7220_ErrMask_SDmaBaseErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_SDmaTailOutOfBoundErrMask_LSB 0x29
+#define QIB_7220_ErrMask_SDmaTailOutOfBoundErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_SDmaOutOfBoundErrMask_LSB 0x28
+#define QIB_7220_ErrMask_SDmaOutOfBoundErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_SDmaGenMismatchErrMask_LSB 0x27
+#define QIB_7220_ErrMask_SDmaGenMismatchErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_SendBufMisuseErrMask_LSB 0x26
+#define QIB_7220_ErrMask_SendBufMisuseErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_SendUnsupportedVLErrMask_LSB 0x25
+#define QIB_7220_ErrMask_SendUnsupportedVLErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_SendUnexpectedPktNumErrMask_LSB 0x24
+#define QIB_7220_ErrMask_SendUnexpectedPktNumErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_SendPioArmLaunchErrMask_LSB 0x23
+#define QIB_7220_ErrMask_SendPioArmLaunchErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_SendDroppedDataPktErrMask_LSB 0x22
+#define QIB_7220_ErrMask_SendDroppedDataPktErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_SendDroppedSmpPktErrMask_LSB 0x21
+#define QIB_7220_ErrMask_SendDroppedSmpPktErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_SendPktLenErrMask_LSB 0x20
+#define QIB_7220_ErrMask_SendPktLenErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_SendUnderRunErrMask_LSB 0x1F
+#define QIB_7220_ErrMask_SendUnderRunErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_SendMaxPktLenErrMask_LSB 0x1E
+#define QIB_7220_ErrMask_SendMaxPktLenErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_SendMinPktLenErrMask_LSB 0x1D
+#define QIB_7220_ErrMask_SendMinPktLenErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_SDmaDisabledErrMask_LSB 0x1C
+#define QIB_7220_ErrMask_SDmaDisabledErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_SendSpecialTriggerErrMask_LSB 0x1B
+#define QIB_7220_ErrMask_SendSpecialTriggerErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_Reserved1_LSB 0x12
+#define QIB_7220_ErrMask_Reserved1_RMASK 0x1FF
+#define QIB_7220_ErrMask_RcvIBLostLinkErrMask_LSB 0x11
+#define QIB_7220_ErrMask_RcvIBLostLinkErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_RcvHdrErrMask_LSB 0x10
+#define QIB_7220_ErrMask_RcvHdrErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_RcvHdrLenErrMask_LSB 0xF
+#define QIB_7220_ErrMask_RcvHdrLenErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_RcvBadTidErrMask_LSB 0xE
+#define QIB_7220_ErrMask_RcvBadTidErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_RcvHdrFullErrMask_LSB 0xD
+#define QIB_7220_ErrMask_RcvHdrFullErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_RcvEgrFullErrMask_LSB 0xC
+#define QIB_7220_ErrMask_RcvEgrFullErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_RcvBadVersionErrMask_LSB 0xB
+#define QIB_7220_ErrMask_RcvBadVersionErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_RcvIBFlowErrMask_LSB 0xA
+#define QIB_7220_ErrMask_RcvIBFlowErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_RcvEBPErrMask_LSB 0x9
+#define QIB_7220_ErrMask_RcvEBPErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_RcvUnsupportedVLErrMask_LSB 0x8
+#define QIB_7220_ErrMask_RcvUnsupportedVLErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_RcvUnexpectedCharErrMask_LSB 0x7
+#define QIB_7220_ErrMask_RcvUnexpectedCharErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_RcvShortPktLenErrMask_LSB 0x6
+#define QIB_7220_ErrMask_RcvShortPktLenErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_RcvLongPktLenErrMask_LSB 0x5
+#define QIB_7220_ErrMask_RcvLongPktLenErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_RcvMaxPktLenErrMask_LSB 0x4
+#define QIB_7220_ErrMask_RcvMaxPktLenErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_RcvMinPktLenErrMask_LSB 0x3
+#define QIB_7220_ErrMask_RcvMinPktLenErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_RcvICRCErrMask_LSB 0x2
+#define QIB_7220_ErrMask_RcvICRCErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_RcvVCRCErrMask_LSB 0x1
+#define QIB_7220_ErrMask_RcvVCRCErrMask_RMASK 0x1
+#define QIB_7220_ErrMask_RcvFormatErrMask_LSB 0x0
+#define QIB_7220_ErrMask_RcvFormatErrMask_RMASK 0x1
+
+#define QIB_7220_ErrStatus_OFFS 0x88
+#define QIB_7220_ErrStatus_Reserved_LSB 0x36
+#define QIB_7220_ErrStatus_Reserved_RMASK 0x3FF
+#define QIB_7220_ErrStatus_InvalidEEPCmdErr_LSB 0x35
+#define QIB_7220_ErrStatus_InvalidEEPCmdErr_RMASK 0x1
+#define QIB_7220_ErrStatus_SDmaDescAddrMisalignErr_LSB 0x34
+#define QIB_7220_ErrStatus_SDmaDescAddrMisalignErr_RMASK 0x1
+#define QIB_7220_ErrStatus_HardwareErr_LSB 0x33
+#define QIB_7220_ErrStatus_HardwareErr_RMASK 0x1
+#define QIB_7220_ErrStatus_ResetNegated_LSB 0x32
+#define QIB_7220_ErrStatus_ResetNegated_RMASK 0x1
+#define QIB_7220_ErrStatus_InvalidAddrErr_LSB 0x31
+#define QIB_7220_ErrStatus_InvalidAddrErr_RMASK 0x1
+#define QIB_7220_ErrStatus_IBStatusChanged_LSB 0x30
+#define QIB_7220_ErrStatus_IBStatusChanged_RMASK 0x1
+#define QIB_7220_ErrStatus_SDmaUnexpDataErr_LSB 0x2F
+#define QIB_7220_ErrStatus_SDmaUnexpDataErr_RMASK 0x1
+#define QIB_7220_ErrStatus_SDmaMissingDwErr_LSB 0x2E
+#define QIB_7220_ErrStatus_SDmaMissingDwErr_RMASK 0x1
+#define QIB_7220_ErrStatus_SDmaDwEnErr_LSB 0x2D
+#define QIB_7220_ErrStatus_SDmaDwEnErr_RMASK 0x1
+#define QIB_7220_ErrStatus_SDmaRpyTagErr_LSB 0x2C
+#define QIB_7220_ErrStatus_SDmaRpyTagErr_RMASK 0x1
+#define QIB_7220_ErrStatus_SDma1stDescErr_LSB 0x2B
+#define QIB_7220_ErrStatus_SDma1stDescErr_RMASK 0x1
+#define QIB_7220_ErrStatus_SDmaBaseErr_LSB 0x2A
+#define QIB_7220_ErrStatus_SDmaBaseErr_RMASK 0x1
+#define QIB_7220_ErrStatus_SDmaTailOutOfBoundErr_LSB 0x29
+#define QIB_7220_ErrStatus_SDmaTailOutOfBoundErr_RMASK 0x1
+#define QIB_7220_ErrStatus_SDmaOutOfBoundErr_LSB 0x28
+#define QIB_7220_ErrStatus_SDmaOutOfBoundErr_RMASK 0x1
+#define QIB_7220_ErrStatus_SDmaGenMismatchErr_LSB 0x27
+#define QIB_7220_ErrStatus_SDmaGenMismatchErr_RMASK 0x1
+#define QIB_7220_ErrStatus_SendBufMisuseErr_LSB 0x26
+#define QIB_7220_ErrStatus_SendBufMisuseErr_RMASK 0x1
+#define QIB_7220_ErrStatus_SendUnsupportedVLErr_LSB 0x25
+#define QIB_7220_ErrStatus_SendUnsupportedVLErr_RMASK 0x1
+#define QIB_7220_ErrStatus_SendUnexpectedPktNumErr_LSB 0x24
+#define QIB_7220_ErrStatus_SendUnexpectedPktNumErr_RMASK 0x1
+#define QIB_7220_ErrStatus_SendPioArmLaunchErr_LSB 0x23
+#define QIB_7220_ErrStatus_SendPioArmLaunchErr_RMASK 0x1
+#define QIB_7220_ErrStatus_SendDroppedDataPktErr_LSB 0x22
+#define QIB_7220_ErrStatus_SendDroppedDataPktErr_RMASK 0x1
+#define QIB_7220_ErrStatus_SendDroppedSmpPktErr_LSB 0x21
+#define QIB_7220_ErrStatus_SendDroppedSmpPktErr_RMASK 0x1
+#define QIB_7220_ErrStatus_SendPktLenErr_LSB 0x20
+#define QIB_7220_ErrStatus_SendPktLenErr_RMASK 0x1
+#define QIB_7220_ErrStatus_SendUnderRunErr_LSB 0x1F
+#define QIB_7220_ErrStatus_SendUnderRunErr_RMASK 0x1
+#define QIB_7220_ErrStatus_SendMaxPktLenErr_LSB 0x1E
+#define QIB_7220_ErrStatus_SendMaxPktLenErr_RMASK 0x1
+#define QIB_7220_ErrStatus_SendMinPktLenErr_LSB 0x1D
+#define QIB_7220_ErrStatus_SendMinPktLenErr_RMASK 0x1
+#define QIB_7220_ErrStatus_SDmaDisabledErr_LSB 0x1C
+#define QIB_7220_ErrStatus_SDmaDisabledErr_RMASK 0x1
+#define QIB_7220_ErrStatus_SendSpecialTriggerErr_LSB 0x1B
+#define QIB_7220_ErrStatus_SendSpecialTriggerErr_RMASK 0x1
+#define QIB_7220_ErrStatus_Reserved1_LSB 0x12
+#define QIB_7220_ErrStatus_Reserved1_RMASK 0x1FF
+#define QIB_7220_ErrStatus_RcvIBLostLinkErr_LSB 0x11
+#define QIB_7220_ErrStatus_RcvIBLostLinkErr_RMASK 0x1
+#define QIB_7220_ErrStatus_RcvHdrErr_LSB 0x10
+#define QIB_7220_ErrStatus_RcvHdrErr_RMASK 0x1
+#define QIB_7220_ErrStatus_RcvHdrLenErr_LSB 0xF
+#define QIB_7220_ErrStatus_RcvHdrLenErr_RMASK 0x1
+#define QIB_7220_ErrStatus_RcvBadTidErr_LSB 0xE
+#define QIB_7220_ErrStatus_RcvBadTidErr_RMASK 0x1
+#define QIB_7220_ErrStatus_RcvHdrFullErr_LSB 0xD
+#define QIB_7220_ErrStatus_RcvHdrFullErr_RMASK 0x1
+#define QIB_7220_ErrStatus_RcvEgrFullErr_LSB 0xC
+#define QIB_7220_ErrStatus_RcvEgrFullErr_RMASK 0x1
+#define QIB_7220_ErrStatus_RcvBadVersionErr_LSB 0xB
+#define QIB_7220_ErrStatus_RcvBadVersionErr_RMASK 0x1
+#define QIB_7220_ErrStatus_RcvIBFlowErr_LSB 0xA
+#define QIB_7220_ErrStatus_RcvIBFlowErr_RMASK 0x1
+#define QIB_7220_ErrStatus_RcvEBPErr_LSB 0x9
+#define QIB_7220_ErrStatus_RcvEBPErr_RMASK 0x1
+#define QIB_7220_ErrStatus_RcvUnsupportedVLErr_LSB 0x8
+#define QIB_7220_ErrStatus_RcvUnsupportedVLErr_RMASK 0x1
+#define QIB_7220_ErrStatus_RcvUnexpectedCharErr_LSB 0x7
+#define QIB_7220_ErrStatus_RcvUnexpectedCharErr_RMASK 0x1
+#define QIB_7220_ErrStatus_RcvShortPktLenErr_LSB 0x6
+#define QIB_7220_ErrStatus_RcvShortPktLenErr_RMASK 0x1
+#define QIB_7220_ErrStatus_RcvLongPktLenErr_LSB 0x5
+#define QIB_7220_ErrStatus_RcvLongPktLenErr_RMASK 0x1
+#define QIB_7220_ErrStatus_RcvMaxPktLenErr_LSB 0x4
+#define QIB_7220_ErrStatus_RcvMaxPktLenErr_RMASK 0x1
+#define QIB_7220_ErrStatus_RcvMinPktLenErr_LSB 0x3
+#define QIB_7220_ErrStatus_RcvMinPktLenErr_RMASK 0x1
+#define QIB_7220_ErrStatus_RcvICRCErr_LSB 0x2
+#define QIB_7220_ErrStatus_RcvICRCErr_RMASK 0x1
+#define QIB_7220_ErrStatus_RcvVCRCErr_LSB 0x1
+#define QIB_7220_ErrStatus_RcvVCRCErr_RMASK 0x1
+#define QIB_7220_ErrStatus_RcvFormatErr_LSB 0x0
+#define QIB_7220_ErrStatus_RcvFormatErr_RMASK 0x1
+
+#define QIB_7220_ErrClear_OFFS 0x90
+#define QIB_7220_ErrClear_Reserved_LSB 0x36
+#define QIB_7220_ErrClear_Reserved_RMASK 0x3FF
+#define QIB_7220_ErrClear_InvalidEEPCmdErrClear_LSB 0x35
+#define QIB_7220_ErrClear_InvalidEEPCmdErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_SDmaDescAddrMisalignErrClear_LSB 0x34
+#define QIB_7220_ErrClear_SDmaDescAddrMisalignErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_HardwareErrClear_LSB 0x33
+#define QIB_7220_ErrClear_HardwareErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_ResetNegatedClear_LSB 0x32
+#define QIB_7220_ErrClear_ResetNegatedClear_RMASK 0x1
+#define QIB_7220_ErrClear_InvalidAddrErrClear_LSB 0x31
+#define QIB_7220_ErrClear_InvalidAddrErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_IBStatusChangedClear_LSB 0x30
+#define QIB_7220_ErrClear_IBStatusChangedClear_RMASK 0x1
+#define QIB_7220_ErrClear_SDmaUnexpDataErrClear_LSB 0x2F
+#define QIB_7220_ErrClear_SDmaUnexpDataErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_SDmaMissingDwErrClear_LSB 0x2E
+#define QIB_7220_ErrClear_SDmaMissingDwErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_SDmaDwEnErrClear_LSB 0x2D
+#define QIB_7220_ErrClear_SDmaDwEnErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_SDmaRpyTagErrClear_LSB 0x2C
+#define QIB_7220_ErrClear_SDmaRpyTagErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_SDma1stDescErrClear_LSB 0x2B
+#define QIB_7220_ErrClear_SDma1stDescErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_SDmaBaseErrClear_LSB 0x2A
+#define QIB_7220_ErrClear_SDmaBaseErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_SDmaTailOutOfBoundErrClear_LSB 0x29
+#define QIB_7220_ErrClear_SDmaTailOutOfBoundErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_SDmaOutOfBoundErrClear_LSB 0x28
+#define QIB_7220_ErrClear_SDmaOutOfBoundErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_SDmaGenMismatchErrClear_LSB 0x27
+#define QIB_7220_ErrClear_SDmaGenMismatchErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_SendBufMisuseErrClear_LSB 0x26
+#define QIB_7220_ErrClear_SendBufMisuseErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_SendUnsupportedVLErrClear_LSB 0x25
+#define QIB_7220_ErrClear_SendUnsupportedVLErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_SendUnexpectedPktNumErrClear_LSB 0x24
+#define QIB_7220_ErrClear_SendUnexpectedPktNumErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_SendPioArmLaunchErrClear_LSB 0x23
+#define QIB_7220_ErrClear_SendPioArmLaunchErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_SendDroppedDataPktErrClear_LSB 0x22
+#define QIB_7220_ErrClear_SendDroppedDataPktErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_SendDroppedSmpPktErrClear_LSB 0x21
+#define QIB_7220_ErrClear_SendDroppedSmpPktErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_SendPktLenErrClear_LSB 0x20
+#define QIB_7220_ErrClear_SendPktLenErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_SendUnderRunErrClear_LSB 0x1F
+#define QIB_7220_ErrClear_SendUnderRunErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_SendMaxPktLenErrClear_LSB 0x1E
+#define QIB_7220_ErrClear_SendMaxPktLenErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_SendMinPktLenErrClear_LSB 0x1D
+#define QIB_7220_ErrClear_SendMinPktLenErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_SDmaDisabledErrClear_LSB 0x1C
+#define QIB_7220_ErrClear_SDmaDisabledErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_SendSpecialTriggerErrClear_LSB 0x1B
+#define QIB_7220_ErrClear_SendSpecialTriggerErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_Reserved1_LSB 0x12
+#define QIB_7220_ErrClear_Reserved1_RMASK 0x1FF
+#define QIB_7220_ErrClear_RcvIBLostLinkErrClear_LSB 0x11
+#define QIB_7220_ErrClear_RcvIBLostLinkErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_RcvHdrErrClear_LSB 0x10
+#define QIB_7220_ErrClear_RcvHdrErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_RcvHdrLenErrClear_LSB 0xF
+#define QIB_7220_ErrClear_RcvHdrLenErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_RcvBadTidErrClear_LSB 0xE
+#define QIB_7220_ErrClear_RcvBadTidErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_RcvHdrFullErrClear_LSB 0xD
+#define QIB_7220_ErrClear_RcvHdrFullErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_RcvEgrFullErrClear_LSB 0xC
+#define QIB_7220_ErrClear_RcvEgrFullErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_RcvBadVersionErrClear_LSB 0xB
+#define QIB_7220_ErrClear_RcvBadVersionErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_RcvIBFlowErrClear_LSB 0xA
+#define QIB_7220_ErrClear_RcvIBFlowErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_RcvEBPErrClear_LSB 0x9
+#define QIB_7220_ErrClear_RcvEBPErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_RcvUnsupportedVLErrClear_LSB 0x8
+#define QIB_7220_ErrClear_RcvUnsupportedVLErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_RcvUnexpectedCharErrClear_LSB 0x7
+#define QIB_7220_ErrClear_RcvUnexpectedCharErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_RcvShortPktLenErrClear_LSB 0x6
+#define QIB_7220_ErrClear_RcvShortPktLenErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_RcvLongPktLenErrClear_LSB 0x5
+#define QIB_7220_ErrClear_RcvLongPktLenErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_RcvMaxPktLenErrClear_LSB 0x4
+#define QIB_7220_ErrClear_RcvMaxPktLenErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_RcvMinPktLenErrClear_LSB 0x3
+#define QIB_7220_ErrClear_RcvMinPktLenErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_RcvICRCErrClear_LSB 0x2
+#define QIB_7220_ErrClear_RcvICRCErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_RcvVCRCErrClear_LSB 0x1
+#define QIB_7220_ErrClear_RcvVCRCErrClear_RMASK 0x1
+#define QIB_7220_ErrClear_RcvFormatErrClear_LSB 0x0
+#define QIB_7220_ErrClear_RcvFormatErrClear_RMASK 0x1
+
+#define QIB_7220_HwErrMask_OFFS 0x98
+#define QIB_7220_HwErrMask_IBCBusFromSPCParityErrMask_LSB 0x3F
+#define QIB_7220_HwErrMask_IBCBusFromSPCParityErrMask_RMASK 0x1
+#define QIB_7220_HwErrMask_IBCBusToSPCParityErrMask_LSB 0x3E
+#define QIB_7220_HwErrMask_IBCBusToSPCParityErrMask_RMASK 0x1
+#define QIB_7220_HwErrMask_Clk_uC_PLLNotLockedMask_LSB 0x3D
+#define QIB_7220_HwErrMask_Clk_uC_PLLNotLockedMask_RMASK 0x1
+#define QIB_7220_HwErrMask_IBSerdesPClkNotDetectMask_LSB 0x3C
+#define QIB_7220_HwErrMask_IBSerdesPClkNotDetectMask_RMASK 0x1
+#define QIB_7220_HwErrMask_PCIESerdesQ3PClkNotDetectMask_LSB 0x3B
+#define QIB_7220_HwErrMask_PCIESerdesQ3PClkNotDetectMask_RMASK 0x1
+#define QIB_7220_HwErrMask_PCIESerdesQ2PClkNotDetectMask_LSB 0x3A
+#define QIB_7220_HwErrMask_PCIESerdesQ2PClkNotDetectMask_RMASK 0x1
+#define QIB_7220_HwErrMask_PCIESerdesQ1PClkNotDetectMask_LSB 0x39
+#define QIB_7220_HwErrMask_PCIESerdesQ1PClkNotDetectMask_RMASK 0x1
+#define QIB_7220_HwErrMask_PCIESerdesQ0PClkNotDetectMask_LSB 0x38
+#define QIB_7220_HwErrMask_PCIESerdesQ0PClkNotDetectMask_RMASK 0x1
+#define QIB_7220_HwErrMask_Reserved_LSB 0x37
+#define QIB_7220_HwErrMask_Reserved_RMASK 0x1
+#define QIB_7220_HwErrMask_PowerOnBISTFailedMask_LSB 0x36
+#define QIB_7220_HwErrMask_PowerOnBISTFailedMask_RMASK 0x1
+#define QIB_7220_HwErrMask_Reserved1_LSB 0x33
+#define QIB_7220_HwErrMask_Reserved1_RMASK 0x7
+#define QIB_7220_HwErrMask_RXEMemParityErrMask_LSB 0x2C
+#define QIB_7220_HwErrMask_RXEMemParityErrMask_RMASK 0x7F
+#define QIB_7220_HwErrMask_TXEMemParityErrMask_LSB 0x28
+#define QIB_7220_HwErrMask_TXEMemParityErrMask_RMASK 0xF
+#define QIB_7220_HwErrMask_DDSRXEQMemoryParityErrMask_LSB 0x27
+#define QIB_7220_HwErrMask_DDSRXEQMemoryParityErrMask_RMASK 0x1
+#define QIB_7220_HwErrMask_IB_uC_MemoryParityErrMask_LSB 0x26
+#define QIB_7220_HwErrMask_IB_uC_MemoryParityErrMask_RMASK 0x1
+#define QIB_7220_HwErrMask_PCIEOct1_uC_MemoryParityErrMask_LSB 0x25
+#define QIB_7220_HwErrMask_PCIEOct1_uC_MemoryParityErrMask_RMASK 0x1
+#define QIB_7220_HwErrMask_PCIEOct0_uC_MemoryParityErrMask_LSB 0x24
+#define QIB_7220_HwErrMask_PCIEOct0_uC_MemoryParityErrMask_RMASK 0x1
+#define QIB_7220_HwErrMask_Reserved2_LSB 0x22
+#define QIB_7220_HwErrMask_Reserved2_RMASK 0x3
+#define QIB_7220_HwErrMask_PCIeBusParityErrMask_LSB 0x1F
+#define QIB_7220_HwErrMask_PCIeBusParityErrMask_RMASK 0x7
+#define QIB_7220_HwErrMask_PcieCplTimeoutMask_LSB 0x1E
+#define QIB_7220_HwErrMask_PcieCplTimeoutMask_RMASK 0x1
+#define QIB_7220_HwErrMask_PoisonedTLPMask_LSB 0x1D
+#define QIB_7220_HwErrMask_PoisonedTLPMask_RMASK 0x1
+#define QIB_7220_HwErrMask_SDmaMemReadErrMask_LSB 0x1C
+#define QIB_7220_HwErrMask_SDmaMemReadErrMask_RMASK 0x1
+#define QIB_7220_HwErrMask_Reserved3_LSB 0x8
+#define QIB_7220_HwErrMask_Reserved3_RMASK 0xFFFFF
+#define QIB_7220_HwErrMask_PCIeMemParityErrMask_LSB 0x0
+#define QIB_7220_HwErrMask_PCIeMemParityErrMask_RMASK 0xFF
+
+#define QIB_7220_HwErrStatus_OFFS 0xA0
+#define QIB_7220_HwErrStatus_IBCBusFromSPCParityErr_LSB 0x3F
+#define QIB_7220_HwErrStatus_IBCBusFromSPCParityErr_RMASK 0x1
+#define QIB_7220_HwErrStatus_IBCBusToSPCParityErr_LSB 0x3E
+#define QIB_7220_HwErrStatus_IBCBusToSPCParityErr_RMASK 0x1
+#define QIB_7220_HwErrStatus_Clk_uC_PLLNotLocked_LSB 0x3D
+#define QIB_7220_HwErrStatus_Clk_uC_PLLNotLocked_RMASK 0x1
+#define QIB_7220_HwErrStatus_IBSerdesPClkNotDetect_LSB 0x3C
+#define QIB_7220_HwErrStatus_IBSerdesPClkNotDetect_RMASK 0x1
+#define QIB_7220_HwErrStatus_PCIESerdesQ3PClkNotDetect_LSB 0x3B
+#define QIB_7220_HwErrStatus_PCIESerdesQ3PClkNotDetect_RMASK 0x1
+#define QIB_7220_HwErrStatus_PCIESerdesQ2PClkNotDetect_LSB 0x3A
+#define QIB_7220_HwErrStatus_PCIESerdesQ2PClkNotDetect_RMASK 0x1
+#define QIB_7220_HwErrStatus_PCIESerdesQ1PClkNotDetect_LSB 0x39
+#define QIB_7220_HwErrStatus_PCIESerdesQ1PClkNotDetect_RMASK 0x1
+#define QIB_7220_HwErrStatus_PCIESerdesQ0PClkNotDetect_LSB 0x38
+#define QIB_7220_HwErrStatus_PCIESerdesQ0PClkNotDetect_RMASK 0x1
+#define QIB_7220_HwErrStatus_Reserved_LSB 0x37
+#define QIB_7220_HwErrStatus_Reserved_RMASK 0x1
+#define QIB_7220_HwErrStatus_PowerOnBISTFailed_LSB 0x36
+#define QIB_7220_HwErrStatus_PowerOnBISTFailed_RMASK 0x1
+#define QIB_7220_HwErrStatus_Reserved1_LSB 0x33
+#define QIB_7220_HwErrStatus_Reserved1_RMASK 0x7
+#define QIB_7220_HwErrStatus_RXEMemParity_LSB 0x2C
+#define QIB_7220_HwErrStatus_RXEMemParity_RMASK 0x7F
+#define QIB_7220_HwErrStatus_TXEMemParity_LSB 0x28
+#define QIB_7220_HwErrStatus_TXEMemParity_RMASK 0xF
+#define QIB_7220_HwErrStatus_DDSRXEQMemoryParityErr_LSB 0x27
+#define QIB_7220_HwErrStatus_DDSRXEQMemoryParityErr_RMASK 0x1
+#define QIB_7220_HwErrStatus_IB_uC_MemoryParityErr_LSB 0x26
+#define QIB_7220_HwErrStatus_IB_uC_MemoryParityErr_RMASK 0x1
+#define QIB_7220_HwErrStatus_PCIE_uC_Oct1MemoryParityErr_LSB 0x25
+#define QIB_7220_HwErrStatus_PCIE_uC_Oct1MemoryParityErr_RMASK 0x1
+#define QIB_7220_HwErrStatus_PCIE_uC_Oct0MemoryParityErr_LSB 0x24
+#define QIB_7220_HwErrStatus_PCIE_uC_Oct0MemoryParityErr_RMASK 0x1
+#define QIB_7220_HwErrStatus_Reserved2_LSB 0x22
+#define QIB_7220_HwErrStatus_Reserved2_RMASK 0x3
+#define QIB_7220_HwErrStatus_PCIeBusParity_LSB 0x1F
+#define QIB_7220_HwErrStatus_PCIeBusParity_RMASK 0x7
+#define QIB_7220_HwErrStatus_PcieCplTimeout_LSB 0x1E
+#define QIB_7220_HwErrStatus_PcieCplTimeout_RMASK 0x1
+#define QIB_7220_HwErrStatus_PoisenedTLP_LSB 0x1D
+#define QIB_7220_HwErrStatus_PoisenedTLP_RMASK 0x1
+#define QIB_7220_HwErrStatus_SDmaMemReadErr_LSB 0x1C
+#define QIB_7220_HwErrStatus_SDmaMemReadErr_RMASK 0x1
+#define QIB_7220_HwErrStatus_Reserved3_LSB 0x8
+#define QIB_7220_HwErrStatus_Reserved3_RMASK 0xFFFFF
+#define QIB_7220_HwErrStatus_PCIeMemParity_LSB 0x0
+#define QIB_7220_HwErrStatus_PCIeMemParity_RMASK 0xFF
+
+#define QIB_7220_HwErrClear_OFFS 0xA8
+#define QIB_7220_HwErrClear_IBCBusFromSPCParityErrClear_LSB 0x3F
+#define QIB_7220_HwErrClear_IBCBusFromSPCParityErrClear_RMASK 0x1
+#define QIB_7220_HwErrClear_IBCBusToSPCparityErrClear_LSB 0x3E
+#define QIB_7220_HwErrClear_IBCBusToSPCparityErrClear_RMASK 0x1
+#define QIB_7220_HwErrClear_Clk_uC_PLLNotLockedClear_LSB 0x3D
+#define QIB_7220_HwErrClear_Clk_uC_PLLNotLockedClear_RMASK 0x1
+#define QIB_7220_HwErrClear_IBSerdesPClkNotDetectClear_LSB 0x3C
+#define QIB_7220_HwErrClear_IBSerdesPClkNotDetectClear_RMASK 0x1
+#define QIB_7220_HwErrClear_PCIESerdesQ3PClkNotDetectClear_LSB 0x3B
+#define QIB_7220_HwErrClear_PCIESerdesQ3PClkNotDetectClear_RMASK 0x1
+#define QIB_7220_HwErrClear_PCIESerdesQ2PClkNotDetectClear_LSB 0x3A
+#define QIB_7220_HwErrClear_PCIESerdesQ2PClkNotDetectClear_RMASK 0x1
+#define QIB_7220_HwErrClear_PCIESerdesQ1PClkNotDetectClear_LSB 0x39
+#define QIB_7220_HwErrClear_PCIESerdesQ1PClkNotDetectClear_RMASK 0x1
+#define QIB_7220_HwErrClear_PCIESerdesQ0PClkNotDetectClear_LSB 0x38
+#define QIB_7220_HwErrClear_PCIESerdesQ0PClkNotDetectClear_RMASK 0x1
+#define QIB_7220_HwErrClear_Reserved_LSB 0x37
+#define QIB_7220_HwErrClear_Reserved_RMASK 0x1
+#define QIB_7220_HwErrClear_PowerOnBISTFailedClear_LSB 0x36
+#define QIB_7220_HwErrClear_PowerOnBISTFailedClear_RMASK 0x1
+#define QIB_7220_HwErrClear_Reserved1_LSB 0x33
+#define QIB_7220_HwErrClear_Reserved1_RMASK 0x7
+#define QIB_7220_HwErrClear_RXEMemParityClear_LSB 0x2C
+#define QIB_7220_HwErrClear_RXEMemParityClear_RMASK 0x7F
+#define QIB_7220_HwErrClear_TXEMemParityClear_LSB 0x28
+#define QIB_7220_HwErrClear_TXEMemParityClear_RMASK 0xF
+#define QIB_7220_HwErrClear_DDSRXEQMemoryParityErrClear_LSB 0x27
+#define QIB_7220_HwErrClear_DDSRXEQMemoryParityErrClear_RMASK 0x1
+#define QIB_7220_HwErrClear_IB_uC_MemoryParityErrClear_LSB 0x26
+#define QIB_7220_HwErrClear_IB_uC_MemoryParityErrClear_RMASK 0x1
+#define QIB_7220_HwErrClear_PCIE_uC_Oct1MemoryParityErrClear_LSB 0x25
+#define QIB_7220_HwErrClear_PCIE_uC_Oct1MemoryParityErrClear_RMASK 0x1
+#define QIB_7220_HwErrClear_PCIE_uC_Oct0MemoryParityErrClear_LSB 0x24
+#define QIB_7220_HwErrClear_PCIE_uC_Oct0MemoryParityErrClear_RMASK 0x1
+#define QIB_7220_HwErrClear_Reserved2_LSB 0x22
+#define QIB_7220_HwErrClear_Reserved2_RMASK 0x3
+#define QIB_7220_HwErrClear_PCIeBusParityClr_LSB 0x1F
+#define QIB_7220_HwErrClear_PCIeBusParityClr_RMASK 0x7
+#define QIB_7220_HwErrClear_PcieCplTimeoutClear_LSB 0x1E
+#define QIB_7220_HwErrClear_PcieCplTimeoutClear_RMASK 0x1
+#define QIB_7220_HwErrClear_PoisonedTLPClear_LSB 0x1D
+#define QIB_7220_HwErrClear_PoisonedTLPClear_RMASK 0x1
+#define QIB_7220_HwErrClear_SDmaMemReadErrClear_LSB 0x1C
+#define QIB_7220_HwErrClear_SDmaMemReadErrClear_RMASK 0x1
+#define QIB_7220_HwErrClear_Reserved3_LSB 0x8
+#define QIB_7220_HwErrClear_Reserved3_RMASK 0xFFFFF
+#define QIB_7220_HwErrClear_PCIeMemParityClr_LSB 0x0
+#define QIB_7220_HwErrClear_PCIeMemParityClr_RMASK 0xFF
+
+#define QIB_7220_HwDiagCtrl_OFFS 0xB0
+#define QIB_7220_HwDiagCtrl_ForceIBCBusFromSPCParityErr_LSB 0x3F
+#define QIB_7220_HwDiagCtrl_ForceIBCBusFromSPCParityErr_RMASK 0x1
+#define QIB_7220_HwDiagCtrl_ForceIBCBusToSPCParityErr_LSB 0x3E
+#define QIB_7220_HwDiagCtrl_ForceIBCBusToSPCParityErr_RMASK 0x1
+#define QIB_7220_HwDiagCtrl_CounterWrEnable_LSB 0x3D
+#define QIB_7220_HwDiagCtrl_CounterWrEnable_RMASK 0x1
+#define QIB_7220_HwDiagCtrl_CounterDisable_LSB 0x3C
+#define QIB_7220_HwDiagCtrl_CounterDisable_RMASK 0x1
+#define QIB_7220_HwDiagCtrl_Reserved_LSB 0x33
+#define QIB_7220_HwDiagCtrl_Reserved_RMASK 0x1FF
+#define QIB_7220_HwDiagCtrl_ForceRxMemParityErr_LSB 0x2C
+#define QIB_7220_HwDiagCtrl_ForceRxMemParityErr_RMASK 0x7F
+#define QIB_7220_HwDiagCtrl_ForceTxMemparityErr_LSB 0x28
+#define QIB_7220_HwDiagCtrl_ForceTxMemparityErr_RMASK 0xF
+#define QIB_7220_HwDiagCtrl_ForceDDSRXEQMemoryParityErr_LSB 0x27
+#define QIB_7220_HwDiagCtrl_ForceDDSRXEQMemoryParityErr_RMASK 0x1
+#define QIB_7220_HwDiagCtrl_ForceIB_uC_MemoryParityErr_LSB 0x26
+#define QIB_7220_HwDiagCtrl_ForceIB_uC_MemoryParityErr_RMASK 0x1
+#define QIB_7220_HwDiagCtrl_ForcePCIE_uC_Oct1MemoryParityErr_LSB 0x25
+#define QIB_7220_HwDiagCtrl_ForcePCIE_uC_Oct1MemoryParityErr_RMASK 0x1
+#define QIB_7220_HwDiagCtrl_ForcePCIE_uC_Oct0MemoryParityErr_LSB 0x24
+#define QIB_7220_HwDiagCtrl_ForcePCIE_uC_Oct0MemoryParityErr_RMASK 0x1
+#define QIB_7220_HwDiagCtrl_Reserved1_LSB 0x23
+#define QIB_7220_HwDiagCtrl_Reserved1_RMASK 0x1
+#define QIB_7220_HwDiagCtrl_forcePCIeBusParity_LSB 0x1F
+#define QIB_7220_HwDiagCtrl_forcePCIeBusParity_RMASK 0xF
+#define QIB_7220_HwDiagCtrl_Reserved2_LSB 0x8
+#define QIB_7220_HwDiagCtrl_Reserved2_RMASK 0x7FFFFF
+#define QIB_7220_HwDiagCtrl_forcePCIeMemParity_LSB 0x0
+#define QIB_7220_HwDiagCtrl_forcePCIeMemParity_RMASK 0xFF
+
+#define QIB_7220_REG_0000B8_OFFS 0xB8
+
+#define QIB_7220_IBCStatus_OFFS 0xC0
+#define QIB_7220_IBCStatus_TxCreditOk_LSB 0x1F
+#define QIB_7220_IBCStatus_TxCreditOk_RMASK 0x1
+#define QIB_7220_IBCStatus_TxReady_LSB 0x1E
+#define QIB_7220_IBCStatus_TxReady_RMASK 0x1
+#define QIB_7220_IBCStatus_Reserved_LSB 0xE
+#define QIB_7220_IBCStatus_Reserved_RMASK 0xFFFF
+#define QIB_7220_IBCStatus_IBTxLaneReversed_LSB 0xD
+#define QIB_7220_IBCStatus_IBTxLaneReversed_RMASK 0x1
+#define QIB_7220_IBCStatus_IBRxLaneReversed_LSB 0xC
+#define QIB_7220_IBCStatus_IBRxLaneReversed_RMASK 0x1
+#define QIB_7220_IBCStatus_IB_SERDES_TRIM_DONE_LSB 0xB
+#define QIB_7220_IBCStatus_IB_SERDES_TRIM_DONE_RMASK 0x1
+#define QIB_7220_IBCStatus_DDS_RXEQ_FAIL_LSB 0xA
+#define QIB_7220_IBCStatus_DDS_RXEQ_FAIL_RMASK 0x1
+#define QIB_7220_IBCStatus_LinkWidthActive_LSB 0x9
+#define QIB_7220_IBCStatus_LinkWidthActive_RMASK 0x1
+#define QIB_7220_IBCStatus_LinkSpeedActive_LSB 0x8
+#define QIB_7220_IBCStatus_LinkSpeedActive_RMASK 0x1
+#define QIB_7220_IBCStatus_LinkState_LSB 0x5
+#define QIB_7220_IBCStatus_LinkState_RMASK 0x7
+#define QIB_7220_IBCStatus_LinkTrainingState_LSB 0x0
+#define QIB_7220_IBCStatus_LinkTrainingState_RMASK 0x1F
+
+#define QIB_7220_IBCCtrl_OFFS 0xC8
+#define QIB_7220_IBCCtrl_Loopback_LSB 0x3F
+#define QIB_7220_IBCCtrl_Loopback_RMASK 0x1
+#define QIB_7220_IBCCtrl_LinkDownDefaultState_LSB 0x3E
+#define QIB_7220_IBCCtrl_LinkDownDefaultState_RMASK 0x1
+#define QIB_7220_IBCCtrl_Reserved_LSB 0x2B
+#define QIB_7220_IBCCtrl_Reserved_RMASK 0x7FFFF
+#define QIB_7220_IBCCtrl_CreditScale_LSB 0x28
+#define QIB_7220_IBCCtrl_CreditScale_RMASK 0x7
+#define QIB_7220_IBCCtrl_OverrunThreshold_LSB 0x24
+#define QIB_7220_IBCCtrl_OverrunThreshold_RMASK 0xF
+#define QIB_7220_IBCCtrl_PhyerrThreshold_LSB 0x20
+#define QIB_7220_IBCCtrl_PhyerrThreshold_RMASK 0xF
+#define QIB_7220_IBCCtrl_MaxPktLen_LSB 0x15
+#define QIB_7220_IBCCtrl_MaxPktLen_RMASK 0x7FF
+#define QIB_7220_IBCCtrl_LinkCmd_LSB 0x13
+#define QIB_7220_IBCCtrl_LinkCmd_RMASK 0x3
+#define QIB_7220_IBCCtrl_LinkInitCmd_LSB 0x10
+#define QIB_7220_IBCCtrl_LinkInitCmd_RMASK 0x7
+#define QIB_7220_IBCCtrl_FlowCtrlWaterMark_LSB 0x8
+#define QIB_7220_IBCCtrl_FlowCtrlWaterMark_RMASK 0xFF
+#define QIB_7220_IBCCtrl_FlowCtrlPeriod_LSB 0x0
+#define QIB_7220_IBCCtrl_FlowCtrlPeriod_RMASK 0xFF
+
+#define QIB_7220_EXTStatus_OFFS 0xD0
+#define QIB_7220_EXTStatus_GPIOIn_LSB 0x30
+#define QIB_7220_EXTStatus_GPIOIn_RMASK 0xFFFF
+#define QIB_7220_EXTStatus_Reserved_LSB 0x20
+#define QIB_7220_EXTStatus_Reserved_RMASK 0xFFFF
+#define QIB_7220_EXTStatus_Reserved1_LSB 0x10
+#define QIB_7220_EXTStatus_Reserved1_RMASK 0xFFFF
+#define QIB_7220_EXTStatus_MemBISTDisabled_LSB 0xF
+#define QIB_7220_EXTStatus_MemBISTDisabled_RMASK 0x1
+#define QIB_7220_EXTStatus_MemBISTEndTest_LSB 0xE
+#define QIB_7220_EXTStatus_MemBISTEndTest_RMASK 0x1
+#define QIB_7220_EXTStatus_Reserved2_LSB 0x0
+#define QIB_7220_EXTStatus_Reserved2_RMASK 0x3FFF
+
+#define QIB_7220_EXTCtrl_OFFS 0xD8
+#define QIB_7220_EXTCtrl_GPIOOe_LSB 0x30
+#define QIB_7220_EXTCtrl_GPIOOe_RMASK 0xFFFF
+#define QIB_7220_EXTCtrl_GPIOInvert_LSB 0x20
+#define QIB_7220_EXTCtrl_GPIOInvert_RMASK 0xFFFF
+#define QIB_7220_EXTCtrl_Reserved_LSB 0x4
+#define QIB_7220_EXTCtrl_Reserved_RMASK 0xFFFFFFF
+#define QIB_7220_EXTCtrl_LEDPriPortGreenOn_LSB 0x3
+#define QIB_7220_EXTCtrl_LEDPriPortGreenOn_RMASK 0x1
+#define QIB_7220_EXTCtrl_LEDPriPortYellowOn_LSB 0x2
+#define QIB_7220_EXTCtrl_LEDPriPortYellowOn_RMASK 0x1
+#define QIB_7220_EXTCtrl_LEDGblOkGreenOn_LSB 0x1
+#define QIB_7220_EXTCtrl_LEDGblOkGreenOn_RMASK 0x1
+#define QIB_7220_EXTCtrl_LEDGblErrRedOff_LSB 0x0
+#define QIB_7220_EXTCtrl_LEDGblErrRedOff_RMASK 0x1
+
+#define QIB_7220_GPIOOut_OFFS 0xE0
+
+#define QIB_7220_GPIOMask_OFFS 0xE8
+
+#define QIB_7220_GPIOStatus_OFFS 0xF0
+
+#define QIB_7220_GPIOClear_OFFS 0xF8
+
+#define QIB_7220_RcvCtrl_OFFS 0x100
+#define QIB_7220_RcvCtrl_Reserved_LSB 0x27
+#define QIB_7220_RcvCtrl_Reserved_RMASK 0x1FFFFFF
+#define QIB_7220_RcvCtrl_RcvQPMapEnable_LSB 0x26
+#define QIB_7220_RcvCtrl_RcvQPMapEnable_RMASK 0x1
+#define QIB_7220_RcvCtrl_PortCfg_LSB 0x24
+#define QIB_7220_RcvCtrl_PortCfg_RMASK 0x3
+#define QIB_7220_RcvCtrl_TailUpd_LSB 0x23
+#define QIB_7220_RcvCtrl_TailUpd_RMASK 0x1
+#define QIB_7220_RcvCtrl_RcvPartitionKeyDisable_LSB 0x22
+#define QIB_7220_RcvCtrl_RcvPartitionKeyDisable_RMASK 0x1
+#define QIB_7220_RcvCtrl_IntrAvail_LSB 0x11
+#define QIB_7220_RcvCtrl_IntrAvail_RMASK 0x1FFFF
+#define QIB_7220_RcvCtrl_PortEnable_LSB 0x0
+#define QIB_7220_RcvCtrl_PortEnable_RMASK 0x1FFFF
+
+#define QIB_7220_RcvBTHQP_OFFS 0x108
+#define QIB_7220_RcvBTHQP_Reserved_LSB 0x18
+#define QIB_7220_RcvBTHQP_Reserved_RMASK 0xFF
+#define QIB_7220_RcvBTHQP_RcvBTHQP_LSB 0x0
+#define QIB_7220_RcvBTHQP_RcvBTHQP_RMASK 0xFFFFFF
+
+#define QIB_7220_RcvHdrSize_OFFS 0x110
+
+#define QIB_7220_RcvHdrCnt_OFFS 0x118
+
+#define QIB_7220_RcvHdrEntSize_OFFS 0x120
+
+#define QIB_7220_RcvTIDBase_OFFS 0x128
+
+#define QIB_7220_RcvTIDCnt_OFFS 0x130
+
+#define QIB_7220_RcvEgrBase_OFFS 0x138
+
+#define QIB_7220_RcvEgrCnt_OFFS 0x140
+
+#define QIB_7220_RcvBufBase_OFFS 0x148
+
+#define QIB_7220_RcvBufSize_OFFS 0x150
+
+#define QIB_7220_RxIntMemBase_OFFS 0x158
+
+#define QIB_7220_RxIntMemSize_OFFS 0x160
+
+#define QIB_7220_RcvPartitionKey_OFFS 0x168
+
+#define QIB_7220_RcvQPMulticastPort_OFFS 0x170
+#define QIB_7220_RcvQPMulticastPort_Reserved_LSB 0x5
+#define QIB_7220_RcvQPMulticastPort_Reserved_RMASK 0x7FFFFFFFFFFFFFF
+#define QIB_7220_RcvQPMulticastPort_RcvQpMcPort_LSB 0x0
+#define QIB_7220_RcvQPMulticastPort_RcvQpMcPort_RMASK 0x1F
+
+#define QIB_7220_RcvPktLEDCnt_OFFS 0x178
+#define QIB_7220_RcvPktLEDCnt_ONperiod_LSB 0x20
+#define QIB_7220_RcvPktLEDCnt_ONperiod_RMASK 0xFFFFFFFF
+#define QIB_7220_RcvPktLEDCnt_OFFperiod_LSB 0x0
+#define QIB_7220_RcvPktLEDCnt_OFFperiod_RMASK 0xFFFFFFFF
+
+#define QIB_7220_IBCDDRCtrl_OFFS 0x180
+#define QIB_7220_IBCDDRCtrl_IB_DLID_MASK_LSB 0x30
+#define QIB_7220_IBCDDRCtrl_IB_DLID_MASK_RMASK 0xFFFF
+#define QIB_7220_IBCDDRCtrl_IB_DLID_LSB 0x20
+#define QIB_7220_IBCDDRCtrl_IB_DLID_RMASK 0xFFFF
+#define QIB_7220_IBCDDRCtrl_Reserved_LSB 0x1B
+#define QIB_7220_IBCDDRCtrl_Reserved_RMASK 0x1F
+#define QIB_7220_IBCDDRCtrl_HRTBT_REQ_LSB 0x1A
+#define QIB_7220_IBCDDRCtrl_HRTBT_REQ_RMASK 0x1
+#define QIB_7220_IBCDDRCtrl_HRTBT_PORT_LSB 0x12
+#define QIB_7220_IBCDDRCtrl_HRTBT_PORT_RMASK 0xFF
+#define QIB_7220_IBCDDRCtrl_HRTBT_AUTO_LSB 0x11
+#define QIB_7220_IBCDDRCtrl_HRTBT_AUTO_RMASK 0x1
+#define QIB_7220_IBCDDRCtrl_HRTBT_ENB_LSB 0x10
+#define QIB_7220_IBCDDRCtrl_HRTBT_ENB_RMASK 0x1
+#define QIB_7220_IBCDDRCtrl_SD_DDS_LSB 0xC
+#define QIB_7220_IBCDDRCtrl_SD_DDS_RMASK 0xF
+#define QIB_7220_IBCDDRCtrl_SD_DDSV_LSB 0xB
+#define QIB_7220_IBCDDRCtrl_SD_DDSV_RMASK 0x1
+#define QIB_7220_IBCDDRCtrl_SD_ADD_ENB_LSB 0xA
+#define QIB_7220_IBCDDRCtrl_SD_ADD_ENB_RMASK 0x1
+#define QIB_7220_IBCDDRCtrl_SD_RX_EQUAL_ENABLE_LSB 0x9
+#define QIB_7220_IBCDDRCtrl_SD_RX_EQUAL_ENABLE_RMASK 0x1
+#define QIB_7220_IBCDDRCtrl_IB_LANE_REV_SUPPORTED_LSB 0x8
+#define QIB_7220_IBCDDRCtrl_IB_LANE_REV_SUPPORTED_RMASK 0x1
+#define QIB_7220_IBCDDRCtrl_IB_POLARITY_REV_SUPP_LSB 0x7
+#define QIB_7220_IBCDDRCtrl_IB_POLARITY_REV_SUPP_RMASK 0x1
+#define QIB_7220_IBCDDRCtrl_IB_NUM_CHANNELS_LSB 0x5
+#define QIB_7220_IBCDDRCtrl_IB_NUM_CHANNELS_RMASK 0x3
+#define QIB_7220_IBCDDRCtrl_SD_SPEED_QDR_LSB 0x4
+#define QIB_7220_IBCDDRCtrl_SD_SPEED_QDR_RMASK 0x1
+#define QIB_7220_IBCDDRCtrl_SD_SPEED_DDR_LSB 0x3
+#define QIB_7220_IBCDDRCtrl_SD_SPEED_DDR_RMASK 0x1
+#define QIB_7220_IBCDDRCtrl_SD_SPEED_SDR_LSB 0x2
+#define QIB_7220_IBCDDRCtrl_SD_SPEED_SDR_RMASK 0x1
+#define QIB_7220_IBCDDRCtrl_SD_SPEED_LSB 0x1
+#define QIB_7220_IBCDDRCtrl_SD_SPEED_RMASK 0x1
+#define QIB_7220_IBCDDRCtrl_IB_ENHANCED_MODE_LSB 0x0
+#define QIB_7220_IBCDDRCtrl_IB_ENHANCED_MODE_RMASK 0x1
+
+#define QIB_7220_HRTBT_GUID_OFFS 0x188
+
+#define QIB_7220_IBCDDRCtrl2_OFFS 0x1A0
+#define QIB_7220_IBCDDRCtrl2_IB_BACK_PORCH_LSB 0x5
+#define QIB_7220_IBCDDRCtrl2_IB_BACK_PORCH_RMASK 0x1F
+#define QIB_7220_IBCDDRCtrl2_IB_FRONT_PORCH_LSB 0x0
+#define QIB_7220_IBCDDRCtrl2_IB_FRONT_PORCH_RMASK 0x1F
+
+#define QIB_7220_IBCDDRStatus_OFFS 0x1A8
+#define QIB_7220_IBCDDRStatus_heartbeat_timed_out_LSB 0x24
+#define QIB_7220_IBCDDRStatus_heartbeat_timed_out_RMASK 0x1
+#define QIB_7220_IBCDDRStatus_heartbeat_crosstalk_LSB 0x20
+#define QIB_7220_IBCDDRStatus_heartbeat_crosstalk_RMASK 0xF
+#define QIB_7220_IBCDDRStatus_RxEqLocalDevice_LSB 0x1E
+#define QIB_7220_IBCDDRStatus_RxEqLocalDevice_RMASK 0x3
+#define QIB_7220_IBCDDRStatus_ReqDDSLocalFromRmt_LSB 0x1A
+#define QIB_7220_IBCDDRStatus_ReqDDSLocalFromRmt_RMASK 0xF
+#define QIB_7220_IBCDDRStatus_LinkRoundTripLatency_LSB 0x0
+#define QIB_7220_IBCDDRStatus_LinkRoundTripLatency_RMASK 0x3FFFFFF
+
+#define QIB_7220_JIntReload_OFFS 0x1B0
+#define QIB_7220_JIntReload_J_limit_reload_LSB 0x10
+#define QIB_7220_JIntReload_J_limit_reload_RMASK 0xFFFF
+#define QIB_7220_JIntReload_J_reload_LSB 0x0
+#define QIB_7220_JIntReload_J_reload_RMASK 0xFFFF
+
+#define QIB_7220_IBNCModeCtrl_OFFS 0x1B8
+#define QIB_7220_IBNCModeCtrl_Reserved_LSB 0x1A
+#define QIB_7220_IBNCModeCtrl_Reserved_RMASK 0x3FFFFFFFFF
+#define QIB_7220_IBNCModeCtrl_TSMCode_TS2_LSB 0x11
+#define QIB_7220_IBNCModeCtrl_TSMCode_TS2_RMASK 0x1FF
+#define QIB_7220_IBNCModeCtrl_TSMCode_TS1_LSB 0x8
+#define QIB_7220_IBNCModeCtrl_TSMCode_TS1_RMASK 0x1FF
+#define QIB_7220_IBNCModeCtrl_Reserved1_LSB 0x3
+#define QIB_7220_IBNCModeCtrl_Reserved1_RMASK 0x1F
+#define QIB_7220_IBNCModeCtrl_TSMEnable_ignore_TSM_on_rx_LSB 0x2
+#define QIB_7220_IBNCModeCtrl_TSMEnable_ignore_TSM_on_rx_RMASK 0x1
+#define QIB_7220_IBNCModeCtrl_TSMEnable_send_TS2_LSB 0x1
+#define QIB_7220_IBNCModeCtrl_TSMEnable_send_TS2_RMASK 0x1
+#define QIB_7220_IBNCModeCtrl_TSMEnable_send_TS1_LSB 0x0
+#define QIB_7220_IBNCModeCtrl_TSMEnable_send_TS1_RMASK 0x1
+
+#define QIB_7220_SendCtrl_OFFS 0x1C0
+#define QIB_7220_SendCtrl_Disarm_LSB 0x1F
+#define QIB_7220_SendCtrl_Disarm_RMASK 0x1
+#define QIB_7220_SendCtrl_Reserved_LSB 0x1D
+#define QIB_7220_SendCtrl_Reserved_RMASK 0x3
+#define QIB_7220_SendCtrl_AvailUpdThld_LSB 0x18
+#define QIB_7220_SendCtrl_AvailUpdThld_RMASK 0x1F
+#define QIB_7220_SendCtrl_DisarmPIOBuf_LSB 0x10
+#define QIB_7220_SendCtrl_DisarmPIOBuf_RMASK 0xFF
+#define QIB_7220_SendCtrl_Reserved1_LSB 0xD
+#define QIB_7220_SendCtrl_Reserved1_RMASK 0x7
+#define QIB_7220_SendCtrl_SDmaHalt_LSB 0xC
+#define QIB_7220_SendCtrl_SDmaHalt_RMASK 0x1
+#define QIB_7220_SendCtrl_SDmaEnable_LSB 0xB
+#define QIB_7220_SendCtrl_SDmaEnable_RMASK 0x1
+#define QIB_7220_SendCtrl_SDmaSingleDescriptor_LSB 0xA
+#define QIB_7220_SendCtrl_SDmaSingleDescriptor_RMASK 0x1
+#define QIB_7220_SendCtrl_SDmaIntEnable_LSB 0x9
+#define QIB_7220_SendCtrl_SDmaIntEnable_RMASK 0x1
+#define QIB_7220_SendCtrl_Reserved2_LSB 0x5
+#define QIB_7220_SendCtrl_Reserved2_RMASK 0xF
+#define QIB_7220_SendCtrl_SSpecialTriggerEn_LSB 0x4
+#define QIB_7220_SendCtrl_SSpecialTriggerEn_RMASK 0x1
+#define QIB_7220_SendCtrl_SPioEnable_LSB 0x3
+#define QIB_7220_SendCtrl_SPioEnable_RMASK 0x1
+#define QIB_7220_SendCtrl_SendBufAvailUpd_LSB 0x2
+#define QIB_7220_SendCtrl_SendBufAvailUpd_RMASK 0x1
+#define QIB_7220_SendCtrl_SendIntBufAvail_LSB 0x1
+#define QIB_7220_SendCtrl_SendIntBufAvail_RMASK 0x1
+#define QIB_7220_SendCtrl_Abort_LSB 0x0
+#define QIB_7220_SendCtrl_Abort_RMASK 0x1
+
+#define QIB_7220_SendBufBase_OFFS 0x1C8
+#define QIB_7220_SendBufBase_Reserved_LSB 0x35
+#define QIB_7220_SendBufBase_Reserved_RMASK 0x7FF
+#define QIB_7220_SendBufBase_BaseAddr_LargePIO_LSB 0x20
+#define QIB_7220_SendBufBase_BaseAddr_LargePIO_RMASK 0x1FFFFF
+#define QIB_7220_SendBufBase_Reserved1_LSB 0x15
+#define QIB_7220_SendBufBase_Reserved1_RMASK 0x7FF
+#define QIB_7220_SendBufBase_BaseAddr_SmallPIO_LSB 0x0
+#define QIB_7220_SendBufBase_BaseAddr_SmallPIO_RMASK 0x1FFFFF
+
+#define QIB_7220_SendBufSize_OFFS 0x1D0
+#define QIB_7220_SendBufSize_Reserved_LSB 0x2D
+#define QIB_7220_SendBufSize_Reserved_RMASK 0xFFFFF
+#define QIB_7220_SendBufSize_Size_LargePIO_LSB 0x20
+#define QIB_7220_SendBufSize_Size_LargePIO_RMASK 0x1FFF
+#define QIB_7220_SendBufSize_Reserved1_LSB 0xC
+#define QIB_7220_SendBufSize_Reserved1_RMASK 0xFFFFF
+#define QIB_7220_SendBufSize_Size_SmallPIO_LSB 0x0
+#define QIB_7220_SendBufSize_Size_SmallPIO_RMASK 0xFFF
+
+#define QIB_7220_SendBufCnt_OFFS 0x1D8
+#define QIB_7220_SendBufCnt_Reserved_LSB 0x24
+#define QIB_7220_SendBufCnt_Reserved_RMASK 0xFFFFFFF
+#define QIB_7220_SendBufCnt_Num_LargeBuffers_LSB 0x20
+#define QIB_7220_SendBufCnt_Num_LargeBuffers_RMASK 0xF
+#define QIB_7220_SendBufCnt_Reserved1_LSB 0x9
+#define QIB_7220_SendBufCnt_Reserved1_RMASK 0x7FFFFF
+#define QIB_7220_SendBufCnt_Num_SmallBuffers_LSB 0x0
+#define QIB_7220_SendBufCnt_Num_SmallBuffers_RMASK 0x1FF
+
+#define QIB_7220_SendBufAvailAddr_OFFS 0x1E0
+#define QIB_7220_SendBufAvailAddr_SendBufAvailAddr_LSB 0x6
+#define QIB_7220_SendBufAvailAddr_SendBufAvailAddr_RMASK 0x3FFFFFFFF
+#define QIB_7220_SendBufAvailAddr_Reserved_LSB 0x0
+#define QIB_7220_SendBufAvailAddr_Reserved_RMASK 0x3F
+
+#define QIB_7220_TxIntMemBase_OFFS 0x1E8
+
+#define QIB_7220_TxIntMemSize_OFFS 0x1F0
+
+#define QIB_7220_SendDmaBase_OFFS 0x1F8
+#define QIB_7220_SendDmaBase_Reserved_LSB 0x30
+#define QIB_7220_SendDmaBase_Reserved_RMASK 0xFFFF
+#define QIB_7220_SendDmaBase_SendDmaBase_LSB 0x0
+#define QIB_7220_SendDmaBase_SendDmaBase_RMASK 0xFFFFFFFFFFFF
+
+#define QIB_7220_SendDmaLenGen_OFFS 0x200
+#define QIB_7220_SendDmaLenGen_Reserved_LSB 0x13
+#define QIB_7220_SendDmaLenGen_Reserved_RMASK 0x1FFFFFFFFFFF
+#define QIB_7220_SendDmaLenGen_Generation_LSB 0x10
+#define QIB_7220_SendDmaLenGen_Generation_MSB 0x12
+#define QIB_7220_SendDmaLenGen_Generation_RMASK 0x7
+#define QIB_7220_SendDmaLenGen_Length_LSB 0x0
+#define QIB_7220_SendDmaLenGen_Length_RMASK 0xFFFF
+
+#define QIB_7220_SendDmaTail_OFFS 0x208
+#define QIB_7220_SendDmaTail_Reserved_LSB 0x10
+#define QIB_7220_SendDmaTail_Reserved_RMASK 0xFFFFFFFFFFFF
+#define QIB_7220_SendDmaTail_SendDmaTail_LSB 0x0
+#define QIB_7220_SendDmaTail_SendDmaTail_RMASK 0xFFFF
+
+#define QIB_7220_SendDmaHead_OFFS 0x210
+#define QIB_7220_SendDmaHead_Reserved_LSB 0x30
+#define QIB_7220_SendDmaHead_Reserved_RMASK 0xFFFF
+#define QIB_7220_SendDmaHead_InternalSendDmaHead_LSB 0x20
+#define QIB_7220_SendDmaHead_InternalSendDmaHead_RMASK 0xFFFF
+#define QIB_7220_SendDmaHead_Reserved1_LSB 0x10
+#define QIB_7220_SendDmaHead_Reserved1_RMASK 0xFFFF
+#define QIB_7220_SendDmaHead_SendDmaHead_LSB 0x0
+#define QIB_7220_SendDmaHead_SendDmaHead_RMASK 0xFFFF
+
+#define QIB_7220_SendDmaHeadAddr_OFFS 0x218
+#define QIB_7220_SendDmaHeadAddr_Reserved_LSB 0x30
+#define QIB_7220_SendDmaHeadAddr_Reserved_RMASK 0xFFFF
+#define QIB_7220_SendDmaHeadAddr_SendDmaHeadAddr_LSB 0x0
+#define QIB_7220_SendDmaHeadAddr_SendDmaHeadAddr_RMASK 0xFFFFFFFFFFFF
+
+#define QIB_7220_SendDmaBufMask0_OFFS 0x220
+#define QIB_7220_SendDmaBufMask0_BufMask_63_0_LSB 0x0
+#define QIB_7220_SendDmaBufMask0_BufMask_63_0_RMASK 0x0
+
+#define QIB_7220_SendDmaStatus_OFFS 0x238
+#define QIB_7220_SendDmaStatus_ScoreBoardDrainInProg_LSB 0x3F
+#define QIB_7220_SendDmaStatus_ScoreBoardDrainInProg_RMASK 0x1
+#define QIB_7220_SendDmaStatus_AbortInProg_LSB 0x3E
+#define QIB_7220_SendDmaStatus_AbortInProg_RMASK 0x1
+#define QIB_7220_SendDmaStatus_InternalSDmaEnable_LSB 0x3D
+#define QIB_7220_SendDmaStatus_InternalSDmaEnable_RMASK 0x1
+#define QIB_7220_SendDmaStatus_ScbDescIndex_13_0_LSB 0x2F
+#define QIB_7220_SendDmaStatus_ScbDescIndex_13_0_RMASK 0x3FFF
+#define QIB_7220_SendDmaStatus_RpyLowAddr_6_0_LSB 0x28
+#define QIB_7220_SendDmaStatus_RpyLowAddr_6_0_RMASK 0x7F
+#define QIB_7220_SendDmaStatus_RpyTag_7_0_LSB 0x20
+#define QIB_7220_SendDmaStatus_RpyTag_7_0_RMASK 0xFF
+#define QIB_7220_SendDmaStatus_ScbFull_LSB 0x1F
+#define QIB_7220_SendDmaStatus_ScbFull_RMASK 0x1
+#define QIB_7220_SendDmaStatus_ScbEmpty_LSB 0x1E
+#define QIB_7220_SendDmaStatus_ScbEmpty_RMASK 0x1
+#define QIB_7220_SendDmaStatus_ScbEntryValid_LSB 0x1D
+#define QIB_7220_SendDmaStatus_ScbEntryValid_RMASK 0x1
+#define QIB_7220_SendDmaStatus_ScbFetchDescFlag_LSB 0x1C
+#define QIB_7220_SendDmaStatus_ScbFetchDescFlag_RMASK 0x1
+#define QIB_7220_SendDmaStatus_SplFifoReadyToGo_LSB 0x1B
+#define QIB_7220_SendDmaStatus_SplFifoReadyToGo_RMASK 0x1
+#define QIB_7220_SendDmaStatus_SplFifoDisarmed_LSB 0x1A
+#define QIB_7220_SendDmaStatus_SplFifoDisarmed_RMASK 0x1
+#define QIB_7220_SendDmaStatus_SplFifoEmpty_LSB 0x19
+#define QIB_7220_SendDmaStatus_SplFifoEmpty_RMASK 0x1
+#define QIB_7220_SendDmaStatus_SplFifoFull_LSB 0x18
+#define QIB_7220_SendDmaStatus_SplFifoFull_RMASK 0x1
+#define QIB_7220_SendDmaStatus_SplFifoBufNum_LSB 0x10
+#define QIB_7220_SendDmaStatus_SplFifoBufNum_RMASK 0xFF
+#define QIB_7220_SendDmaStatus_SplFifoDescIndex_LSB 0x0
+#define QIB_7220_SendDmaStatus_SplFifoDescIndex_RMASK 0xFFFF
+
+#define QIB_7220_SendBufErr0_OFFS 0x240
+#define QIB_7220_SendBufErr0_SendBufErr_63_0_LSB 0x0
+#define QIB_7220_SendBufErr0_SendBufErr_63_0_RMASK 0x0
+
+#define QIB_7220_RcvHdrAddr0_OFFS 0x270
+#define QIB_7220_RcvHdrAddr0_RcvHdrAddr0_LSB 0x2
+#define QIB_7220_RcvHdrAddr0_RcvHdrAddr0_RMASK 0x3FFFFFFFFF
+#define QIB_7220_RcvHdrAddr0_Reserved_LSB 0x0
+#define QIB_7220_RcvHdrAddr0_Reserved_RMASK 0x3
+
+#define QIB_7220_RcvHdrTailAddr0_OFFS 0x300
+#define QIB_7220_RcvHdrTailAddr0_RcvHdrTailAddr0_LSB 0x2
+#define QIB_7220_RcvHdrTailAddr0_RcvHdrTailAddr0_RMASK 0x3FFFFFFFFF
+#define QIB_7220_RcvHdrTailAddr0_Reserved_LSB 0x0
+#define QIB_7220_RcvHdrTailAddr0_Reserved_RMASK 0x3
+
+#define QIB_7220_ibsd_epb_access_ctrl_OFFS 0x3C0
+#define QIB_7220_ibsd_epb_access_ctrl_sw_ib_epb_req_granted_LSB 0x8
+#define QIB_7220_ibsd_epb_access_ctrl_sw_ib_epb_req_granted_RMASK 0x1
+#define QIB_7220_ibsd_epb_access_ctrl_Reserved_LSB 0x1
+#define QIB_7220_ibsd_epb_access_ctrl_Reserved_RMASK 0x7F
+#define QIB_7220_ibsd_epb_access_ctrl_sw_ib_epb_req_LSB 0x0
+#define QIB_7220_ibsd_epb_access_ctrl_sw_ib_epb_req_RMASK 0x1
+
+#define QIB_7220_ibsd_epb_transaction_reg_OFFS 0x3C8
+#define QIB_7220_ibsd_epb_transaction_reg_ib_epb_rdy_LSB 0x1F
+#define QIB_7220_ibsd_epb_transaction_reg_ib_epb_rdy_RMASK 0x1
+#define QIB_7220_ibsd_epb_transaction_reg_ib_epb_req_error_LSB 0x1E
+#define QIB_7220_ibsd_epb_transaction_reg_ib_epb_req_error_RMASK 0x1
+#define QIB_7220_ibsd_epb_transaction_reg_Reserved_LSB 0x1D
+#define QIB_7220_ibsd_epb_transaction_reg_Reserved_RMASK 0x1
+#define QIB_7220_ibsd_epb_transaction_reg_mem_data_parity_LSB 0x1C
+#define QIB_7220_ibsd_epb_transaction_reg_mem_data_parity_RMASK 0x1
+#define QIB_7220_ibsd_epb_transaction_reg_Reserved1_LSB 0x1B
+#define QIB_7220_ibsd_epb_transaction_reg_Reserved1_RMASK 0x1
+#define QIB_7220_ibsd_epb_transaction_reg_ib_epb_cs_LSB 0x19
+#define QIB_7220_ibsd_epb_transaction_reg_ib_epb_cs_RMASK 0x3
+#define QIB_7220_ibsd_epb_transaction_reg_ib_epb_read_write_LSB 0x18
+#define QIB_7220_ibsd_epb_transaction_reg_ib_epb_read_write_RMASK 0x1
+#define QIB_7220_ibsd_epb_transaction_reg_Reserved2_LSB 0x17
+#define QIB_7220_ibsd_epb_transaction_reg_Reserved2_RMASK 0x1
+#define QIB_7220_ibsd_epb_transaction_reg_ib_epb_address_LSB 0x8
+#define QIB_7220_ibsd_epb_transaction_reg_ib_epb_address_RMASK 0x7FFF
+#define QIB_7220_ibsd_epb_transaction_reg_ib_epb_data_LSB 0x0
+#define QIB_7220_ibsd_epb_transaction_reg_ib_epb_data_RMASK 0xFF
+
+#define QIB_7220_XGXSCfg_OFFS 0x3D8
+#define QIB_7220_XGXSCfg_sel_link_down_for_fctrl_lane_sync_reset_LSB 0x3F
+#define QIB_7220_XGXSCfg_sel_link_down_for_fctrl_lane_sync_reset_RMASK 0x1
+#define QIB_7220_XGXSCfg_Reserved_LSB 0x13
+#define QIB_7220_XGXSCfg_Reserved_RMASK 0xFFFFFFFFFFF
+#define QIB_7220_XGXSCfg_link_sync_mask_LSB 0x9
+#define QIB_7220_XGXSCfg_link_sync_mask_RMASK 0x3FF
+#define QIB_7220_XGXSCfg_Reserved1_LSB 0x3
+#define QIB_7220_XGXSCfg_Reserved1_RMASK 0x3F
+#define QIB_7220_XGXSCfg_xcv_reset_LSB 0x2
+#define QIB_7220_XGXSCfg_xcv_reset_RMASK 0x1
+#define QIB_7220_XGXSCfg_Reserved2_LSB 0x1
+#define QIB_7220_XGXSCfg_Reserved2_RMASK 0x1
+#define QIB_7220_XGXSCfg_tx_rx_reset_LSB 0x0
+#define QIB_7220_XGXSCfg_tx_rx_reset_RMASK 0x1
+
+#define QIB_7220_IBSerDesCtrl_OFFS 0x3E0
+#define QIB_7220_IBSerDesCtrl_Reserved_LSB 0x2D
+#define QIB_7220_IBSerDesCtrl_Reserved_RMASK 0x7FFFF
+#define QIB_7220_IBSerDesCtrl_INT_uC_LSB 0x2C
+#define QIB_7220_IBSerDesCtrl_INT_uC_RMASK 0x1
+#define QIB_7220_IBSerDesCtrl_CKSEL_uC_LSB 0x2A
+#define QIB_7220_IBSerDesCtrl_CKSEL_uC_RMASK 0x3
+#define QIB_7220_IBSerDesCtrl_PLLN_LSB 0x28
+#define QIB_7220_IBSerDesCtrl_PLLN_RMASK 0x3
+#define QIB_7220_IBSerDesCtrl_PLLM_LSB 0x25
+#define QIB_7220_IBSerDesCtrl_PLLM_RMASK 0x7
+#define QIB_7220_IBSerDesCtrl_TXOBPD_LSB 0x24
+#define QIB_7220_IBSerDesCtrl_TXOBPD_RMASK 0x1
+#define QIB_7220_IBSerDesCtrl_TWC_LSB 0x23
+#define QIB_7220_IBSerDesCtrl_TWC_RMASK 0x1
+#define QIB_7220_IBSerDesCtrl_RXIDLE_LSB 0x22
+#define QIB_7220_IBSerDesCtrl_RXIDLE_RMASK 0x1
+#define QIB_7220_IBSerDesCtrl_RXINV_LSB 0x21
+#define QIB_7220_IBSerDesCtrl_RXINV_RMASK 0x1
+#define QIB_7220_IBSerDesCtrl_TXINV_LSB 0x20
+#define QIB_7220_IBSerDesCtrl_TXINV_RMASK 0x1
+#define QIB_7220_IBSerDesCtrl_Reserved1_LSB 0x12
+#define QIB_7220_IBSerDesCtrl_Reserved1_RMASK 0x3FFF
+#define QIB_7220_IBSerDesCtrl_NumSerDesRegsToWrForRXEQ_LSB 0xD
+#define QIB_7220_IBSerDesCtrl_NumSerDesRegsToWrForRXEQ_RMASK 0x1F
+#define QIB_7220_IBSerDesCtrl_NumSerDesRegsToWrForDDS_LSB 0x8
+#define QIB_7220_IBSerDesCtrl_NumSerDesRegsToWrForDDS_RMASK 0x1F
+#define QIB_7220_IBSerDesCtrl_Reserved2_LSB 0x1
+#define QIB_7220_IBSerDesCtrl_Reserved2_RMASK 0x7F
+#define QIB_7220_IBSerDesCtrl_ResetIB_uC_Core_LSB 0x0
+#define QIB_7220_IBSerDesCtrl_ResetIB_uC_Core_RMASK 0x1
+
+#define QIB_7220_pciesd_epb_access_ctrl_OFFS 0x400
+#define QIB_7220_pciesd_epb_access_ctrl_sw_pcie_epb_req_granted_LSB 0x8
+#define QIB_7220_pciesd_epb_access_ctrl_sw_pcie_epb_req_granted_RMASK 0x1
+#define QIB_7220_pciesd_epb_access_ctrl_Reserved_LSB 0x3
+#define QIB_7220_pciesd_epb_access_ctrl_Reserved_RMASK 0x1F
+#define QIB_7220_pciesd_epb_access_ctrl_sw_pcieepb_star_en_LSB 0x1
+#define QIB_7220_pciesd_epb_access_ctrl_sw_pcieepb_star_en_RMASK 0x3
+#define QIB_7220_pciesd_epb_access_ctrl_sw_pcie_epb_req_LSB 0x0
+#define QIB_7220_pciesd_epb_access_ctrl_sw_pcie_epb_req_RMASK 0x1
+
+#define QIB_7220_pciesd_epb_transaction_reg_OFFS 0x408
+#define QIB_7220_pciesd_epb_transaction_reg_pcie_epb_rdy_LSB 0x1F
+#define QIB_7220_pciesd_epb_transaction_reg_pcie_epb_rdy_RMASK 0x1
+#define QIB_7220_pciesd_epb_transaction_reg_pcie_epb_req_error_LSB 0x1E
+#define QIB_7220_pciesd_epb_transaction_reg_pcie_epb_req_error_RMASK 0x1
+#define QIB_7220_pciesd_epb_transaction_reg_Reserved_LSB 0x1D
+#define QIB_7220_pciesd_epb_transaction_reg_Reserved_RMASK 0x1
+#define QIB_7220_pciesd_epb_transaction_reg_mem_data_parity_LSB 0x1C
+#define QIB_7220_pciesd_epb_transaction_reg_mem_data_parity_RMASK 0x1
+#define QIB_7220_pciesd_epb_transaction_reg_pcie_epb_cs_LSB 0x19
+#define QIB_7220_pciesd_epb_transaction_reg_pcie_epb_cs_RMASK 0x7
+#define QIB_7220_pciesd_epb_transaction_reg_pcie_epb_read_write_LSB 0x18
+#define QIB_7220_pciesd_epb_transaction_reg_pcie_epb_read_write_RMASK 0x1
+#define QIB_7220_pciesd_epb_transaction_reg_Reserved1_LSB 0x17
+#define QIB_7220_pciesd_epb_transaction_reg_Reserved1_RMASK 0x1
+#define QIB_7220_pciesd_epb_transaction_reg_pcie_epb_address_LSB 0x8
+#define QIB_7220_pciesd_epb_transaction_reg_pcie_epb_address_RMASK 0x7FFF
+#define QIB_7220_pciesd_epb_transaction_reg_pcie_epb_data_LSB 0x0
+#define QIB_7220_pciesd_epb_transaction_reg_pcie_epb_data_RMASK 0xFF
+
+#define QIB_7220_SerDes_DDSRXEQ0_OFFS 0x500
+#define QIB_7220_SerDes_DDSRXEQ0_reg_addr_LSB 0x4
+#define QIB_7220_SerDes_DDSRXEQ0_reg_addr_RMASK 0x3F
+#define QIB_7220_SerDes_DDSRXEQ0_element_num_LSB 0x0
+#define QIB_7220_SerDes_DDSRXEQ0_element_num_RMASK 0xF
+
+#define QIB_7220_LBIntCnt_OFFS 0x13000
+
+#define QIB_7220_LBFlowStallCnt_OFFS 0x13008
+
+#define QIB_7220_TxSDmaDescCnt_OFFS 0x13010
+
+#define QIB_7220_TxUnsupVLErrCnt_OFFS 0x13018
+
+#define QIB_7220_TxDataPktCnt_OFFS 0x13020
+
+#define QIB_7220_TxFlowPktCnt_OFFS 0x13028
+
+#define QIB_7220_TxDwordCnt_OFFS 0x13030
+
+#define QIB_7220_TxLenErrCnt_OFFS 0x13038
+
+#define QIB_7220_TxMaxMinLenErrCnt_OFFS 0x13040
+
+#define QIB_7220_TxUnderrunCnt_OFFS 0x13048
+
+#define QIB_7220_TxFlowStallCnt_OFFS 0x13050
+
+#define QIB_7220_TxDroppedPktCnt_OFFS 0x13058
+
+#define QIB_7220_RxDroppedPktCnt_OFFS 0x13060
+
+#define QIB_7220_RxDataPktCnt_OFFS 0x13068
+
+#define QIB_7220_RxFlowPktCnt_OFFS 0x13070
+
+#define QIB_7220_RxDwordCnt_OFFS 0x13078
+
+#define QIB_7220_RxLenErrCnt_OFFS 0x13080
+
+#define QIB_7220_RxMaxMinLenErrCnt_OFFS 0x13088
+
+#define QIB_7220_RxICRCErrCnt_OFFS 0x13090
+
+#define QIB_7220_RxVCRCErrCnt_OFFS 0x13098
+
+#define QIB_7220_RxFlowCtrlViolCnt_OFFS 0x130A0
+
+#define QIB_7220_RxVersionErrCnt_OFFS 0x130A8
+
+#define QIB_7220_RxLinkMalformCnt_OFFS 0x130B0
+
+#define QIB_7220_RxEBPCnt_OFFS 0x130B8
+
+#define QIB_7220_RxLPCRCErrCnt_OFFS 0x130C0
+
+#define QIB_7220_RxBufOvflCnt_OFFS 0x130C8
+
+#define QIB_7220_RxTIDFullErrCnt_OFFS 0x130D0
+
+#define QIB_7220_RxTIDValidErrCnt_OFFS 0x130D8
+
+#define QIB_7220_RxPKeyMismatchCnt_OFFS 0x130E0
+
+#define QIB_7220_RxP0HdrEgrOvflCnt_OFFS 0x130E8
+
+#define QIB_7220_IBStatusChangeCnt_OFFS 0x13170
+
+#define QIB_7220_IBLinkErrRecoveryCnt_OFFS 0x13178
+
+#define QIB_7220_IBLinkDownedCnt_OFFS 0x13180
+
+#define QIB_7220_IBSymbolErrCnt_OFFS 0x13188
+
+#define QIB_7220_RxVL15DroppedPktCnt_OFFS 0x13190
+
+#define QIB_7220_RxOtherLocalPhyErrCnt_OFFS 0x13198
+
+#define QIB_7220_PcieRetryBufDiagQwordCnt_OFFS 0x131A0
+
+#define QIB_7220_ExcessBufferOvflCnt_OFFS 0x131A8
+
+#define QIB_7220_LocalLinkIntegrityErrCnt_OFFS 0x131B0
+
+#define QIB_7220_RxVlErrCnt_OFFS 0x131B8
+
+#define QIB_7220_RxDlidFltrCnt_OFFS 0x131C0
+
+#define QIB_7220_CNT_0131C8_OFFS 0x131C8
+
+#define QIB_7220_PSStat_OFFS 0x13200
+
+#define QIB_7220_PSStart_OFFS 0x13208
+
+#define QIB_7220_PSInterval_OFFS 0x13210
+
+#define QIB_7220_PSRcvDataCount_OFFS 0x13218
+
+#define QIB_7220_PSRcvPktsCount_OFFS 0x13220
+
+#define QIB_7220_PSXmitDataCount_OFFS 0x13228
+
+#define QIB_7220_PSXmitPktsCount_OFFS 0x13230
+
+#define QIB_7220_PSXmitWaitCount_OFFS 0x13238
+
+#define QIB_7220_CNT_013240_OFFS 0x13240
+
+#define QIB_7220_RcvEgrArray_OFFS 0x14000
+
+#define QIB_7220_MEM_038000_OFFS 0x38000
+
+#define QIB_7220_RcvTIDArray0_OFFS 0x53000
+
+#define QIB_7220_PIOLaunchFIFO_OFFS 0x64000
+
+#define QIB_7220_MEM_064480_OFFS 0x64480
+
+#define QIB_7220_SendPIOpbcCache_OFFS 0x64800
+
+#define QIB_7220_MEM_064C80_OFFS 0x64C80
+
+#define QIB_7220_PreLaunchFIFO_OFFS 0x65000
+
+#define QIB_7220_MEM_065080_OFFS 0x65080
+
+#define QIB_7220_ScoreBoard_OFFS 0x65400
+
+#define QIB_7220_MEM_065440_OFFS 0x65440
+
+#define QIB_7220_DescriptorFIFO_OFFS 0x65800
+
+#define QIB_7220_MEM_065880_OFFS 0x65880
+
+#define QIB_7220_RcvBuf1_OFFS 0x72000
+
+#define QIB_7220_MEM_074800_OFFS 0x74800
+
+#define QIB_7220_RcvBuf2_OFFS 0x75000
+
+#define QIB_7220_MEM_076400_OFFS 0x76400
+
+#define QIB_7220_RcvFlags_OFFS 0x77000
+
+#define QIB_7220_MEM_078400_OFFS 0x78400
+
+#define QIB_7220_RcvLookupBuf1_OFFS 0x79000
+
+#define QIB_7220_MEM_07A400_OFFS 0x7A400
+
+#define QIB_7220_RcvDMADatBuf_OFFS 0x7B000
+
+#define QIB_7220_RcvDMAHdrBuf_OFFS 0x7B800
+
+#define QIB_7220_MiscRXEIntMem_OFFS 0x7C000
+
+#define QIB_7220_MEM_07D400_OFFS 0x7D400
+
+#define QIB_7220_PCIERcvBuf_OFFS 0x80000
+
+#define QIB_7220_PCIERetryBuf_OFFS 0x84000
+
+#define QIB_7220_PCIERcvBufRdToWrAddr_OFFS 0x88000
+
+#define QIB_7220_PCIECplBuf_OFFS 0x90000
+
+#define QIB_7220_IBSerDesMappTable_OFFS 0x94000
+
+#define QIB_7220_MEM_095000_OFFS 0x95000
+
+#define QIB_7220_SendBuf0_MA_OFFS 0x100000
+
+#define QIB_7220_MEM_1A0000_OFFS 0x1A0000
diff --git a/drivers/infiniband/hw/qib/qib_7322_regs.h b/drivers/infiniband/hw/qib/qib_7322_regs.h
new file mode 100644 (file)
index 0000000..a97440b
--- /dev/null
@@ -0,0 +1,3163 @@
+/*
+ * Copyright (c) 2008, 2009, 2010 QLogic Corporation. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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.
+ */
+
+/* This file is mechanically generated from RTL. Any hand-edits will be lost! */
+
+#define QIB_7322_Revision_OFFS 0x0
+#define QIB_7322_Revision_DEF 0x0000000002010601
+#define QIB_7322_Revision_R_Simulator_LSB 0x3F
+#define QIB_7322_Revision_R_Simulator_MSB 0x3F
+#define QIB_7322_Revision_R_Simulator_RMASK 0x1
+#define QIB_7322_Revision_R_Emulation_LSB 0x3E
+#define QIB_7322_Revision_R_Emulation_MSB 0x3E
+#define QIB_7322_Revision_R_Emulation_RMASK 0x1
+#define QIB_7322_Revision_R_Emulation_Revcode_LSB 0x28
+#define QIB_7322_Revision_R_Emulation_Revcode_MSB 0x3D
+#define QIB_7322_Revision_R_Emulation_Revcode_RMASK 0x3FFFFF
+#define QIB_7322_Revision_BoardID_LSB 0x20
+#define QIB_7322_Revision_BoardID_MSB 0x27
+#define QIB_7322_Revision_BoardID_RMASK 0xFF
+#define QIB_7322_Revision_R_SW_LSB 0x18
+#define QIB_7322_Revision_R_SW_MSB 0x1F
+#define QIB_7322_Revision_R_SW_RMASK 0xFF
+#define QIB_7322_Revision_R_Arch_LSB 0x10
+#define QIB_7322_Revision_R_Arch_MSB 0x17
+#define QIB_7322_Revision_R_Arch_RMASK 0xFF
+#define QIB_7322_Revision_R_ChipRevMajor_LSB 0x8
+#define QIB_7322_Revision_R_ChipRevMajor_MSB 0xF
+#define QIB_7322_Revision_R_ChipRevMajor_RMASK 0xFF
+#define QIB_7322_Revision_R_ChipRevMinor_LSB 0x0
+#define QIB_7322_Revision_R_ChipRevMinor_MSB 0x7
+#define QIB_7322_Revision_R_ChipRevMinor_RMASK 0xFF
+
+#define QIB_7322_Control_OFFS 0x8
+#define QIB_7322_Control_DEF 0x0000000000000000
+#define QIB_7322_Control_PCIECplQDiagEn_LSB 0x6
+#define QIB_7322_Control_PCIECplQDiagEn_MSB 0x6
+#define QIB_7322_Control_PCIECplQDiagEn_RMASK 0x1
+#define QIB_7322_Control_PCIEPostQDiagEn_LSB 0x5
+#define QIB_7322_Control_PCIEPostQDiagEn_MSB 0x5
+#define QIB_7322_Control_PCIEPostQDiagEn_RMASK 0x1
+#define QIB_7322_Control_SDmaDescFetchPriorityEn_LSB 0x4
+#define QIB_7322_Control_SDmaDescFetchPriorityEn_MSB 0x4
+#define QIB_7322_Control_SDmaDescFetchPriorityEn_RMASK 0x1
+#define QIB_7322_Control_PCIERetryBufDiagEn_LSB 0x3
+#define QIB_7322_Control_PCIERetryBufDiagEn_MSB 0x3
+#define QIB_7322_Control_PCIERetryBufDiagEn_RMASK 0x1
+#define QIB_7322_Control_FreezeMode_LSB 0x1
+#define QIB_7322_Control_FreezeMode_MSB 0x1
+#define QIB_7322_Control_FreezeMode_RMASK 0x1
+#define QIB_7322_Control_SyncReset_LSB 0x0
+#define QIB_7322_Control_SyncReset_MSB 0x0
+#define QIB_7322_Control_SyncReset_RMASK 0x1
+
+#define QIB_7322_PageAlign_OFFS 0x10
+#define QIB_7322_PageAlign_DEF 0x0000000000001000
+
+#define QIB_7322_ContextCnt_OFFS 0x18
+#define QIB_7322_ContextCnt_DEF 0x0000000000000012
+
+#define QIB_7322_Scratch_OFFS 0x20
+#define QIB_7322_Scratch_DEF 0x0000000000000000
+
+#define QIB_7322_CntrRegBase_OFFS 0x28
+#define QIB_7322_CntrRegBase_DEF 0x0000000000011000
+
+#define QIB_7322_SendRegBase_OFFS 0x30
+#define QIB_7322_SendRegBase_DEF 0x0000000000003000
+
+#define QIB_7322_UserRegBase_OFFS 0x38
+#define QIB_7322_UserRegBase_DEF 0x0000000000200000
+
+#define QIB_7322_IntMask_OFFS 0x68
+#define QIB_7322_IntMask_DEF 0x0000000000000000
+#define QIB_7322_IntMask_SDmaIntMask_1_LSB 0x3F
+#define QIB_7322_IntMask_SDmaIntMask_1_MSB 0x3F
+#define QIB_7322_IntMask_SDmaIntMask_1_RMASK 0x1
+#define QIB_7322_IntMask_SDmaIntMask_0_LSB 0x3E
+#define QIB_7322_IntMask_SDmaIntMask_0_MSB 0x3E
+#define QIB_7322_IntMask_SDmaIntMask_0_RMASK 0x1
+#define QIB_7322_IntMask_SDmaProgressIntMask_1_LSB 0x3D
+#define QIB_7322_IntMask_SDmaProgressIntMask_1_MSB 0x3D
+#define QIB_7322_IntMask_SDmaProgressIntMask_1_RMASK 0x1
+#define QIB_7322_IntMask_SDmaProgressIntMask_0_LSB 0x3C
+#define QIB_7322_IntMask_SDmaProgressIntMask_0_MSB 0x3C
+#define QIB_7322_IntMask_SDmaProgressIntMask_0_RMASK 0x1
+#define QIB_7322_IntMask_SDmaIdleIntMask_1_LSB 0x3B
+#define QIB_7322_IntMask_SDmaIdleIntMask_1_MSB 0x3B
+#define QIB_7322_IntMask_SDmaIdleIntMask_1_RMASK 0x1
+#define QIB_7322_IntMask_SDmaIdleIntMask_0_LSB 0x3A
+#define QIB_7322_IntMask_SDmaIdleIntMask_0_MSB 0x3A
+#define QIB_7322_IntMask_SDmaIdleIntMask_0_RMASK 0x1
+#define QIB_7322_IntMask_SDmaCleanupDoneMask_1_LSB 0x39
+#define QIB_7322_IntMask_SDmaCleanupDoneMask_1_MSB 0x39
+#define QIB_7322_IntMask_SDmaCleanupDoneMask_1_RMASK 0x1
+#define QIB_7322_IntMask_SDmaCleanupDoneMask_0_LSB 0x38
+#define QIB_7322_IntMask_SDmaCleanupDoneMask_0_MSB 0x38
+#define QIB_7322_IntMask_SDmaCleanupDoneMask_0_RMASK 0x1
+#define QIB_7322_IntMask_RcvUrg17IntMask_LSB 0x31
+#define QIB_7322_IntMask_RcvUrg17IntMask_MSB 0x31
+#define QIB_7322_IntMask_RcvUrg17IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvUrg16IntMask_LSB 0x30
+#define QIB_7322_IntMask_RcvUrg16IntMask_MSB 0x30
+#define QIB_7322_IntMask_RcvUrg16IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvUrg15IntMask_LSB 0x2F
+#define QIB_7322_IntMask_RcvUrg15IntMask_MSB 0x2F
+#define QIB_7322_IntMask_RcvUrg15IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvUrg14IntMask_LSB 0x2E
+#define QIB_7322_IntMask_RcvUrg14IntMask_MSB 0x2E
+#define QIB_7322_IntMask_RcvUrg14IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvUrg13IntMask_LSB 0x2D
+#define QIB_7322_IntMask_RcvUrg13IntMask_MSB 0x2D
+#define QIB_7322_IntMask_RcvUrg13IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvUrg12IntMask_LSB 0x2C
+#define QIB_7322_IntMask_RcvUrg12IntMask_MSB 0x2C
+#define QIB_7322_IntMask_RcvUrg12IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvUrg11IntMask_LSB 0x2B
+#define QIB_7322_IntMask_RcvUrg11IntMask_MSB 0x2B
+#define QIB_7322_IntMask_RcvUrg11IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvUrg10IntMask_LSB 0x2A
+#define QIB_7322_IntMask_RcvUrg10IntMask_MSB 0x2A
+#define QIB_7322_IntMask_RcvUrg10IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvUrg9IntMask_LSB 0x29
+#define QIB_7322_IntMask_RcvUrg9IntMask_MSB 0x29
+#define QIB_7322_IntMask_RcvUrg9IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvUrg8IntMask_LSB 0x28
+#define QIB_7322_IntMask_RcvUrg8IntMask_MSB 0x28
+#define QIB_7322_IntMask_RcvUrg8IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvUrg7IntMask_LSB 0x27
+#define QIB_7322_IntMask_RcvUrg7IntMask_MSB 0x27
+#define QIB_7322_IntMask_RcvUrg7IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvUrg6IntMask_LSB 0x26
+#define QIB_7322_IntMask_RcvUrg6IntMask_MSB 0x26
+#define QIB_7322_IntMask_RcvUrg6IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvUrg5IntMask_LSB 0x25
+#define QIB_7322_IntMask_RcvUrg5IntMask_MSB 0x25
+#define QIB_7322_IntMask_RcvUrg5IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvUrg4IntMask_LSB 0x24
+#define QIB_7322_IntMask_RcvUrg4IntMask_MSB 0x24
+#define QIB_7322_IntMask_RcvUrg4IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvUrg3IntMask_LSB 0x23
+#define QIB_7322_IntMask_RcvUrg3IntMask_MSB 0x23
+#define QIB_7322_IntMask_RcvUrg3IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvUrg2IntMask_LSB 0x22
+#define QIB_7322_IntMask_RcvUrg2IntMask_MSB 0x22
+#define QIB_7322_IntMask_RcvUrg2IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvUrg1IntMask_LSB 0x21
+#define QIB_7322_IntMask_RcvUrg1IntMask_MSB 0x21
+#define QIB_7322_IntMask_RcvUrg1IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvUrg0IntMask_LSB 0x20
+#define QIB_7322_IntMask_RcvUrg0IntMask_MSB 0x20
+#define QIB_7322_IntMask_RcvUrg0IntMask_RMASK 0x1
+#define QIB_7322_IntMask_ErrIntMask_1_LSB 0x1F
+#define QIB_7322_IntMask_ErrIntMask_1_MSB 0x1F
+#define QIB_7322_IntMask_ErrIntMask_1_RMASK 0x1
+#define QIB_7322_IntMask_ErrIntMask_0_LSB 0x1E
+#define QIB_7322_IntMask_ErrIntMask_0_MSB 0x1E
+#define QIB_7322_IntMask_ErrIntMask_0_RMASK 0x1
+#define QIB_7322_IntMask_ErrIntMask_LSB 0x1D
+#define QIB_7322_IntMask_ErrIntMask_MSB 0x1D
+#define QIB_7322_IntMask_ErrIntMask_RMASK 0x1
+#define QIB_7322_IntMask_AssertGPIOIntMask_LSB 0x1C
+#define QIB_7322_IntMask_AssertGPIOIntMask_MSB 0x1C
+#define QIB_7322_IntMask_AssertGPIOIntMask_RMASK 0x1
+#define QIB_7322_IntMask_SendDoneIntMask_1_LSB 0x19
+#define QIB_7322_IntMask_SendDoneIntMask_1_MSB 0x19
+#define QIB_7322_IntMask_SendDoneIntMask_1_RMASK 0x1
+#define QIB_7322_IntMask_SendDoneIntMask_0_LSB 0x18
+#define QIB_7322_IntMask_SendDoneIntMask_0_MSB 0x18
+#define QIB_7322_IntMask_SendDoneIntMask_0_RMASK 0x1
+#define QIB_7322_IntMask_SendBufAvailIntMask_LSB 0x17
+#define QIB_7322_IntMask_SendBufAvailIntMask_MSB 0x17
+#define QIB_7322_IntMask_SendBufAvailIntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvAvail17IntMask_LSB 0x11
+#define QIB_7322_IntMask_RcvAvail17IntMask_MSB 0x11
+#define QIB_7322_IntMask_RcvAvail17IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvAvail16IntMask_LSB 0x10
+#define QIB_7322_IntMask_RcvAvail16IntMask_MSB 0x10
+#define QIB_7322_IntMask_RcvAvail16IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvAvail15IntMask_LSB 0xF
+#define QIB_7322_IntMask_RcvAvail15IntMask_MSB 0xF
+#define QIB_7322_IntMask_RcvAvail15IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvAvail14IntMask_LSB 0xE
+#define QIB_7322_IntMask_RcvAvail14IntMask_MSB 0xE
+#define QIB_7322_IntMask_RcvAvail14IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvAvail13IntMask_LSB 0xD
+#define QIB_7322_IntMask_RcvAvail13IntMask_MSB 0xD
+#define QIB_7322_IntMask_RcvAvail13IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvAvail12IntMask_LSB 0xC
+#define QIB_7322_IntMask_RcvAvail12IntMask_MSB 0xC
+#define QIB_7322_IntMask_RcvAvail12IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvAvail11IntMask_LSB 0xB
+#define QIB_7322_IntMask_RcvAvail11IntMask_MSB 0xB
+#define QIB_7322_IntMask_RcvAvail11IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvAvail10IntMask_LSB 0xA
+#define QIB_7322_IntMask_RcvAvail10IntMask_MSB 0xA
+#define QIB_7322_IntMask_RcvAvail10IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvAvail9IntMask_LSB 0x9
+#define QIB_7322_IntMask_RcvAvail9IntMask_MSB 0x9
+#define QIB_7322_IntMask_RcvAvail9IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvAvail8IntMask_LSB 0x8
+#define QIB_7322_IntMask_RcvAvail8IntMask_MSB 0x8
+#define QIB_7322_IntMask_RcvAvail8IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvAvail7IntMask_LSB 0x7
+#define QIB_7322_IntMask_RcvAvail7IntMask_MSB 0x7
+#define QIB_7322_IntMask_RcvAvail7IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvAvail6IntMask_LSB 0x6
+#define QIB_7322_IntMask_RcvAvail6IntMask_MSB 0x6
+#define QIB_7322_IntMask_RcvAvail6IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvAvail5IntMask_LSB 0x5
+#define QIB_7322_IntMask_RcvAvail5IntMask_MSB 0x5
+#define QIB_7322_IntMask_RcvAvail5IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvAvail4IntMask_LSB 0x4
+#define QIB_7322_IntMask_RcvAvail4IntMask_MSB 0x4
+#define QIB_7322_IntMask_RcvAvail4IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvAvail3IntMask_LSB 0x3
+#define QIB_7322_IntMask_RcvAvail3IntMask_MSB 0x3
+#define QIB_7322_IntMask_RcvAvail3IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvAvail2IntMask_LSB 0x2
+#define QIB_7322_IntMask_RcvAvail2IntMask_MSB 0x2
+#define QIB_7322_IntMask_RcvAvail2IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvAvail1IntMask_LSB 0x1
+#define QIB_7322_IntMask_RcvAvail1IntMask_MSB 0x1
+#define QIB_7322_IntMask_RcvAvail1IntMask_RMASK 0x1
+#define QIB_7322_IntMask_RcvAvail0IntMask_LSB 0x0
+#define QIB_7322_IntMask_RcvAvail0IntMask_MSB 0x0
+#define QIB_7322_IntMask_RcvAvail0IntMask_RMASK 0x1
+
+#define QIB_7322_IntStatus_OFFS 0x70
+#define QIB_7322_IntStatus_DEF 0x0000000000000000
+#define QIB_7322_IntStatus_SDmaInt_1_LSB 0x3F
+#define QIB_7322_IntStatus_SDmaInt_1_MSB 0x3F
+#define QIB_7322_IntStatus_SDmaInt_1_RMASK 0x1
+#define QIB_7322_IntStatus_SDmaInt_0_LSB 0x3E
+#define QIB_7322_IntStatus_SDmaInt_0_MSB 0x3E
+#define QIB_7322_IntStatus_SDmaInt_0_RMASK 0x1
+#define QIB_7322_IntStatus_SDmaProgressInt_1_LSB 0x3D
+#define QIB_7322_IntStatus_SDmaProgressInt_1_MSB 0x3D
+#define QIB_7322_IntStatus_SDmaProgressInt_1_RMASK 0x1
+#define QIB_7322_IntStatus_SDmaProgressInt_0_LSB 0x3C
+#define QIB_7322_IntStatus_SDmaProgressInt_0_MSB 0x3C
+#define QIB_7322_IntStatus_SDmaProgressInt_0_RMASK 0x1
+#define QIB_7322_IntStatus_SDmaIdleInt_1_LSB 0x3B
+#define QIB_7322_IntStatus_SDmaIdleInt_1_MSB 0x3B
+#define QIB_7322_IntStatus_SDmaIdleInt_1_RMASK 0x1
+#define QIB_7322_IntStatus_SDmaIdleInt_0_LSB 0x3A
+#define QIB_7322_IntStatus_SDmaIdleInt_0_MSB 0x3A
+#define QIB_7322_IntStatus_SDmaIdleInt_0_RMASK 0x1
+#define QIB_7322_IntStatus_SDmaCleanupDone_1_LSB 0x39
+#define QIB_7322_IntStatus_SDmaCleanupDone_1_MSB 0x39
+#define QIB_7322_IntStatus_SDmaCleanupDone_1_RMASK 0x1
+#define QIB_7322_IntStatus_SDmaCleanupDone_0_LSB 0x38
+#define QIB_7322_IntStatus_SDmaCleanupDone_0_MSB 0x38
+#define QIB_7322_IntStatus_SDmaCleanupDone_0_RMASK 0x1
+#define QIB_7322_IntStatus_RcvUrg17_LSB 0x31
+#define QIB_7322_IntStatus_RcvUrg17_MSB 0x31
+#define QIB_7322_IntStatus_RcvUrg17_RMASK 0x1
+#define QIB_7322_IntStatus_RcvUrg16_LSB 0x30
+#define QIB_7322_IntStatus_RcvUrg16_MSB 0x30
+#define QIB_7322_IntStatus_RcvUrg16_RMASK 0x1
+#define QIB_7322_IntStatus_RcvUrg15_LSB 0x2F
+#define QIB_7322_IntStatus_RcvUrg15_MSB 0x2F
+#define QIB_7322_IntStatus_RcvUrg15_RMASK 0x1
+#define QIB_7322_IntStatus_RcvUrg14_LSB 0x2E
+#define QIB_7322_IntStatus_RcvUrg14_MSB 0x2E
+#define QIB_7322_IntStatus_RcvUrg14_RMASK 0x1
+#define QIB_7322_IntStatus_RcvUrg13_LSB 0x2D
+#define QIB_7322_IntStatus_RcvUrg13_MSB 0x2D
+#define QIB_7322_IntStatus_RcvUrg13_RMASK 0x1
+#define QIB_7322_IntStatus_RcvUrg12_LSB 0x2C
+#define QIB_7322_IntStatus_RcvUrg12_MSB 0x2C
+#define QIB_7322_IntStatus_RcvUrg12_RMASK 0x1
+#define QIB_7322_IntStatus_RcvUrg11_LSB 0x2B
+#define QIB_7322_IntStatus_RcvUrg11_MSB 0x2B
+#define QIB_7322_IntStatus_RcvUrg11_RMASK 0x1
+#define QIB_7322_IntStatus_RcvUrg10_LSB 0x2A
+#define QIB_7322_IntStatus_RcvUrg10_MSB 0x2A
+#define QIB_7322_IntStatus_RcvUrg10_RMASK 0x1
+#define QIB_7322_IntStatus_RcvUrg9_LSB 0x29
+#define QIB_7322_IntStatus_RcvUrg9_MSB 0x29
+#define QIB_7322_IntStatus_RcvUrg9_RMASK 0x1
+#define QIB_7322_IntStatus_RcvUrg8_LSB 0x28
+#define QIB_7322_IntStatus_RcvUrg8_MSB 0x28
+#define QIB_7322_IntStatus_RcvUrg8_RMASK 0x1
+#define QIB_7322_IntStatus_RcvUrg7_LSB 0x27
+#define QIB_7322_IntStatus_RcvUrg7_MSB 0x27
+#define QIB_7322_IntStatus_RcvUrg7_RMASK 0x1
+#define QIB_7322_IntStatus_RcvUrg6_LSB 0x26
+#define QIB_7322_IntStatus_RcvUrg6_MSB 0x26
+#define QIB_7322_IntStatus_RcvUrg6_RMASK 0x1
+#define QIB_7322_IntStatus_RcvUrg5_LSB 0x25
+#define QIB_7322_IntStatus_RcvUrg5_MSB 0x25
+#define QIB_7322_IntStatus_RcvUrg5_RMASK 0x1
+#define QIB_7322_IntStatus_RcvUrg4_LSB 0x24
+#define QIB_7322_IntStatus_RcvUrg4_MSB 0x24
+#define QIB_7322_IntStatus_RcvUrg4_RMASK 0x1
+#define QIB_7322_IntStatus_RcvUrg3_LSB 0x23
+#define QIB_7322_IntStatus_RcvUrg3_MSB 0x23
+#define QIB_7322_IntStatus_RcvUrg3_RMASK 0x1
+#define QIB_7322_IntStatus_RcvUrg2_LSB 0x22
+#define QIB_7322_IntStatus_RcvUrg2_MSB 0x22
+#define QIB_7322_IntStatus_RcvUrg2_RMASK 0x1
+#define QIB_7322_IntStatus_RcvUrg1_LSB 0x21
+#define QIB_7322_IntStatus_RcvUrg1_MSB 0x21
+#define QIB_7322_IntStatus_RcvUrg1_RMASK 0x1
+#define QIB_7322_IntStatus_RcvUrg0_LSB 0x20
+#define QIB_7322_IntStatus_RcvUrg0_MSB 0x20
+#define QIB_7322_IntStatus_RcvUrg0_RMASK 0x1
+#define QIB_7322_IntStatus_Err_1_LSB 0x1F
+#define QIB_7322_IntStatus_Err_1_MSB 0x1F
+#define QIB_7322_IntStatus_Err_1_RMASK 0x1
+#define QIB_7322_IntStatus_Err_0_LSB 0x1E
+#define QIB_7322_IntStatus_Err_0_MSB 0x1E
+#define QIB_7322_IntStatus_Err_0_RMASK 0x1
+#define QIB_7322_IntStatus_Err_LSB 0x1D
+#define QIB_7322_IntStatus_Err_MSB 0x1D
+#define QIB_7322_IntStatus_Err_RMASK 0x1
+#define QIB_7322_IntStatus_AssertGPIO_LSB 0x1C
+#define QIB_7322_IntStatus_AssertGPIO_MSB 0x1C
+#define QIB_7322_IntStatus_AssertGPIO_RMASK 0x1
+#define QIB_7322_IntStatus_SendDone_1_LSB 0x19
+#define QIB_7322_IntStatus_SendDone_1_MSB 0x19
+#define QIB_7322_IntStatus_SendDone_1_RMASK 0x1
+#define QIB_7322_IntStatus_SendDone_0_LSB 0x18
+#define QIB_7322_IntStatus_SendDone_0_MSB 0x18
+#define QIB_7322_IntStatus_SendDone_0_RMASK 0x1
+#define QIB_7322_IntStatus_SendBufAvail_LSB 0x17
+#define QIB_7322_IntStatus_SendBufAvail_MSB 0x17
+#define QIB_7322_IntStatus_SendBufAvail_RMASK 0x1
+#define QIB_7322_IntStatus_RcvAvail17_LSB 0x11
+#define QIB_7322_IntStatus_RcvAvail17_MSB 0x11
+#define QIB_7322_IntStatus_RcvAvail17_RMASK 0x1
+#define QIB_7322_IntStatus_RcvAvail16_LSB 0x10
+#define QIB_7322_IntStatus_RcvAvail16_MSB 0x10
+#define QIB_7322_IntStatus_RcvAvail16_RMASK 0x1
+#define QIB_7322_IntStatus_RcvAvail15_LSB 0xF
+#define QIB_7322_IntStatus_RcvAvail15_MSB 0xF
+#define QIB_7322_IntStatus_RcvAvail15_RMASK 0x1
+#define QIB_7322_IntStatus_RcvAvail14_LSB 0xE
+#define QIB_7322_IntStatus_RcvAvail14_MSB 0xE
+#define QIB_7322_IntStatus_RcvAvail14_RMASK 0x1
+#define QIB_7322_IntStatus_RcvAvail13_LSB 0xD
+#define QIB_7322_IntStatus_RcvAvail13_MSB 0xD
+#define QIB_7322_IntStatus_RcvAvail13_RMASK 0x1
+#define QIB_7322_IntStatus_RcvAvail12_LSB 0xC
+#define QIB_7322_IntStatus_RcvAvail12_MSB 0xC
+#define QIB_7322_IntStatus_RcvAvail12_RMASK 0x1
+#define QIB_7322_IntStatus_RcvAvail11_LSB 0xB
+#define QIB_7322_IntStatus_RcvAvail11_MSB 0xB
+#define QIB_7322_IntStatus_RcvAvail11_RMASK 0x1
+#define QIB_7322_IntStatus_RcvAvail10_LSB 0xA
+#define QIB_7322_IntStatus_RcvAvail10_MSB 0xA
+#define QIB_7322_IntStatus_RcvAvail10_RMASK 0x1
+#define QIB_7322_IntStatus_RcvAvail9_LSB 0x9
+#define QIB_7322_IntStatus_RcvAvail9_MSB 0x9
+#define QIB_7322_IntStatus_RcvAvail9_RMASK 0x1
+#define QIB_7322_IntStatus_RcvAvail8_LSB 0x8
+#define QIB_7322_IntStatus_RcvAvail8_MSB 0x8
+#define QIB_7322_IntStatus_RcvAvail8_RMASK 0x1
+#define QIB_7322_IntStatus_RcvAvail7_LSB 0x7
+#define QIB_7322_IntStatus_RcvAvail7_MSB 0x7
+#define QIB_7322_IntStatus_RcvAvail7_RMASK 0x1
+#define QIB_7322_IntStatus_RcvAvail6_LSB 0x6
+#define QIB_7322_IntStatus_RcvAvail6_MSB 0x6
+#define QIB_7322_IntStatus_RcvAvail6_RMASK 0x1
+#define QIB_7322_IntStatus_RcvAvail5_LSB 0x5
+#define QIB_7322_IntStatus_RcvAvail5_MSB 0x5
+#define QIB_7322_IntStatus_RcvAvail5_RMASK 0x1
+#define QIB_7322_IntStatus_RcvAvail4_LSB 0x4
+#define QIB_7322_IntStatus_RcvAvail4_MSB 0x4
+#define QIB_7322_IntStatus_RcvAvail4_RMASK 0x1
+#define QIB_7322_IntStatus_RcvAvail3_LSB 0x3
+#define QIB_7322_IntStatus_RcvAvail3_MSB 0x3
+#define QIB_7322_IntStatus_RcvAvail3_RMASK 0x1
+#define QIB_7322_IntStatus_RcvAvail2_LSB 0x2
+#define QIB_7322_IntStatus_RcvAvail2_MSB 0x2
+#define QIB_7322_IntStatus_RcvAvail2_RMASK 0x1
+#define QIB_7322_IntStatus_RcvAvail1_LSB 0x1
+#define QIB_7322_IntStatus_RcvAvail1_MSB 0x1
+#define QIB_7322_IntStatus_RcvAvail1_RMASK 0x1
+#define QIB_7322_IntStatus_RcvAvail0_LSB 0x0
+#define QIB_7322_IntStatus_RcvAvail0_MSB 0x0
+#define QIB_7322_IntStatus_RcvAvail0_RMASK 0x1
+
+#define QIB_7322_IntClear_OFFS 0x78
+#define QIB_7322_IntClear_DEF 0x0000000000000000
+#define QIB_7322_IntClear_SDmaIntClear_1_LSB 0x3F
+#define QIB_7322_IntClear_SDmaIntClear_1_MSB 0x3F
+#define QIB_7322_IntClear_SDmaIntClear_1_RMASK 0x1
+#define QIB_7322_IntClear_SDmaIntClear_0_LSB 0x3E
+#define QIB_7322_IntClear_SDmaIntClear_0_MSB 0x3E
+#define QIB_7322_IntClear_SDmaIntClear_0_RMASK 0x1
+#define QIB_7322_IntClear_SDmaProgressIntClear_1_LSB 0x3D
+#define QIB_7322_IntClear_SDmaProgressIntClear_1_MSB 0x3D
+#define QIB_7322_IntClear_SDmaProgressIntClear_1_RMASK 0x1
+#define QIB_7322_IntClear_SDmaProgressIntClear_0_LSB 0x3C
+#define QIB_7322_IntClear_SDmaProgressIntClear_0_MSB 0x3C
+#define QIB_7322_IntClear_SDmaProgressIntClear_0_RMASK 0x1
+#define QIB_7322_IntClear_SDmaIdleIntClear_1_LSB 0x3B
+#define QIB_7322_IntClear_SDmaIdleIntClear_1_MSB 0x3B
+#define QIB_7322_IntClear_SDmaIdleIntClear_1_RMASK 0x1
+#define QIB_7322_IntClear_SDmaIdleIntClear_0_LSB 0x3A
+#define QIB_7322_IntClear_SDmaIdleIntClear_0_MSB 0x3A
+#define QIB_7322_IntClear_SDmaIdleIntClear_0_RMASK 0x1
+#define QIB_7322_IntClear_SDmaCleanupDoneClear_1_LSB 0x39
+#define QIB_7322_IntClear_SDmaCleanupDoneClear_1_MSB 0x39
+#define QIB_7322_IntClear_SDmaCleanupDoneClear_1_RMASK 0x1
+#define QIB_7322_IntClear_SDmaCleanupDoneClear_0_LSB 0x38
+#define QIB_7322_IntClear_SDmaCleanupDoneClear_0_MSB 0x38
+#define QIB_7322_IntClear_SDmaCleanupDoneClear_0_RMASK 0x1
+#define QIB_7322_IntClear_RcvUrg17IntClear_LSB 0x31
+#define QIB_7322_IntClear_RcvUrg17IntClear_MSB 0x31
+#define QIB_7322_IntClear_RcvUrg17IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvUrg16IntClear_LSB 0x30
+#define QIB_7322_IntClear_RcvUrg16IntClear_MSB 0x30
+#define QIB_7322_IntClear_RcvUrg16IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvUrg15IntClear_LSB 0x2F
+#define QIB_7322_IntClear_RcvUrg15IntClear_MSB 0x2F
+#define QIB_7322_IntClear_RcvUrg15IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvUrg14IntClear_LSB 0x2E
+#define QIB_7322_IntClear_RcvUrg14IntClear_MSB 0x2E
+#define QIB_7322_IntClear_RcvUrg14IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvUrg13IntClear_LSB 0x2D
+#define QIB_7322_IntClear_RcvUrg13IntClear_MSB 0x2D
+#define QIB_7322_IntClear_RcvUrg13IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvUrg12IntClear_LSB 0x2C
+#define QIB_7322_IntClear_RcvUrg12IntClear_MSB 0x2C
+#define QIB_7322_IntClear_RcvUrg12IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvUrg11IntClear_LSB 0x2B
+#define QIB_7322_IntClear_RcvUrg11IntClear_MSB 0x2B
+#define QIB_7322_IntClear_RcvUrg11IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvUrg10IntClear_LSB 0x2A
+#define QIB_7322_IntClear_RcvUrg10IntClear_MSB 0x2A
+#define QIB_7322_IntClear_RcvUrg10IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvUrg9IntClear_LSB 0x29
+#define QIB_7322_IntClear_RcvUrg9IntClear_MSB 0x29
+#define QIB_7322_IntClear_RcvUrg9IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvUrg8IntClear_LSB 0x28
+#define QIB_7322_IntClear_RcvUrg8IntClear_MSB 0x28
+#define QIB_7322_IntClear_RcvUrg8IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvUrg7IntClear_LSB 0x27
+#define QIB_7322_IntClear_RcvUrg7IntClear_MSB 0x27
+#define QIB_7322_IntClear_RcvUrg7IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvUrg6IntClear_LSB 0x26
+#define QIB_7322_IntClear_RcvUrg6IntClear_MSB 0x26
+#define QIB_7322_IntClear_RcvUrg6IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvUrg5IntClear_LSB 0x25
+#define QIB_7322_IntClear_RcvUrg5IntClear_MSB 0x25
+#define QIB_7322_IntClear_RcvUrg5IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvUrg4IntClear_LSB 0x24
+#define QIB_7322_IntClear_RcvUrg4IntClear_MSB 0x24
+#define QIB_7322_IntClear_RcvUrg4IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvUrg3IntClear_LSB 0x23
+#define QIB_7322_IntClear_RcvUrg3IntClear_MSB 0x23
+#define QIB_7322_IntClear_RcvUrg3IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvUrg2IntClear_LSB 0x22
+#define QIB_7322_IntClear_RcvUrg2IntClear_MSB 0x22
+#define QIB_7322_IntClear_RcvUrg2IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvUrg1IntClear_LSB 0x21
+#define QIB_7322_IntClear_RcvUrg1IntClear_MSB 0x21
+#define QIB_7322_IntClear_RcvUrg1IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvUrg0IntClear_LSB 0x20
+#define QIB_7322_IntClear_RcvUrg0IntClear_MSB 0x20
+#define QIB_7322_IntClear_RcvUrg0IntClear_RMASK 0x1
+#define QIB_7322_IntClear_ErrIntClear_1_LSB 0x1F
+#define QIB_7322_IntClear_ErrIntClear_1_MSB 0x1F
+#define QIB_7322_IntClear_ErrIntClear_1_RMASK 0x1
+#define QIB_7322_IntClear_ErrIntClear_0_LSB 0x1E
+#define QIB_7322_IntClear_ErrIntClear_0_MSB 0x1E
+#define QIB_7322_IntClear_ErrIntClear_0_RMASK 0x1
+#define QIB_7322_IntClear_ErrIntClear_LSB 0x1D
+#define QIB_7322_IntClear_ErrIntClear_MSB 0x1D
+#define QIB_7322_IntClear_ErrIntClear_RMASK 0x1
+#define QIB_7322_IntClear_AssertGPIOIntClear_LSB 0x1C
+#define QIB_7322_IntClear_AssertGPIOIntClear_MSB 0x1C
+#define QIB_7322_IntClear_AssertGPIOIntClear_RMASK 0x1
+#define QIB_7322_IntClear_SendDoneIntClear_1_LSB 0x19
+#define QIB_7322_IntClear_SendDoneIntClear_1_MSB 0x19
+#define QIB_7322_IntClear_SendDoneIntClear_1_RMASK 0x1
+#define QIB_7322_IntClear_SendDoneIntClear_0_LSB 0x18
+#define QIB_7322_IntClear_SendDoneIntClear_0_MSB 0x18
+#define QIB_7322_IntClear_SendDoneIntClear_0_RMASK 0x1
+#define QIB_7322_IntClear_SendBufAvailIntClear_LSB 0x17
+#define QIB_7322_IntClear_SendBufAvailIntClear_MSB 0x17
+#define QIB_7322_IntClear_SendBufAvailIntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvAvail17IntClear_LSB 0x11
+#define QIB_7322_IntClear_RcvAvail17IntClear_MSB 0x11
+#define QIB_7322_IntClear_RcvAvail17IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvAvail16IntClear_LSB 0x10
+#define QIB_7322_IntClear_RcvAvail16IntClear_MSB 0x10
+#define QIB_7322_IntClear_RcvAvail16IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvAvail15IntClear_LSB 0xF
+#define QIB_7322_IntClear_RcvAvail15IntClear_MSB 0xF
+#define QIB_7322_IntClear_RcvAvail15IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvAvail14IntClear_LSB 0xE
+#define QIB_7322_IntClear_RcvAvail14IntClear_MSB 0xE
+#define QIB_7322_IntClear_RcvAvail14IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvAvail13IntClear_LSB 0xD
+#define QIB_7322_IntClear_RcvAvail13IntClear_MSB 0xD
+#define QIB_7322_IntClear_RcvAvail13IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvAvail12IntClear_LSB 0xC
+#define QIB_7322_IntClear_RcvAvail12IntClear_MSB 0xC
+#define QIB_7322_IntClear_RcvAvail12IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvAvail11IntClear_LSB 0xB
+#define QIB_7322_IntClear_RcvAvail11IntClear_MSB 0xB
+#define QIB_7322_IntClear_RcvAvail11IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvAvail10IntClear_LSB 0xA
+#define QIB_7322_IntClear_RcvAvail10IntClear_MSB 0xA
+#define QIB_7322_IntClear_RcvAvail10IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvAvail9IntClear_LSB 0x9
+#define QIB_7322_IntClear_RcvAvail9IntClear_MSB 0x9
+#define QIB_7322_IntClear_RcvAvail9IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvAvail8IntClear_LSB 0x8
+#define QIB_7322_IntClear_RcvAvail8IntClear_MSB 0x8
+#define QIB_7322_IntClear_RcvAvail8IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvAvail7IntClear_LSB 0x7
+#define QIB_7322_IntClear_RcvAvail7IntClear_MSB 0x7
+#define QIB_7322_IntClear_RcvAvail7IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvAvail6IntClear_LSB 0x6
+#define QIB_7322_IntClear_RcvAvail6IntClear_MSB 0x6
+#define QIB_7322_IntClear_RcvAvail6IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvAvail5IntClear_LSB 0x5
+#define QIB_7322_IntClear_RcvAvail5IntClear_MSB 0x5
+#define QIB_7322_IntClear_RcvAvail5IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvAvail4IntClear_LSB 0x4
+#define QIB_7322_IntClear_RcvAvail4IntClear_MSB 0x4
+#define QIB_7322_IntClear_RcvAvail4IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvAvail3IntClear_LSB 0x3
+#define QIB_7322_IntClear_RcvAvail3IntClear_MSB 0x3
+#define QIB_7322_IntClear_RcvAvail3IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvAvail2IntClear_LSB 0x2
+#define QIB_7322_IntClear_RcvAvail2IntClear_MSB 0x2
+#define QIB_7322_IntClear_RcvAvail2IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvAvail1IntClear_LSB 0x1
+#define QIB_7322_IntClear_RcvAvail1IntClear_MSB 0x1
+#define QIB_7322_IntClear_RcvAvail1IntClear_RMASK 0x1
+#define QIB_7322_IntClear_RcvAvail0IntClear_LSB 0x0
+#define QIB_7322_IntClear_RcvAvail0IntClear_MSB 0x0
+#define QIB_7322_IntClear_RcvAvail0IntClear_RMASK 0x1
+
+#define QIB_7322_ErrMask_OFFS 0x80
+#define QIB_7322_ErrMask_DEF 0x0000000000000000
+#define QIB_7322_ErrMask_ResetNegatedMask_LSB 0x3F
+#define QIB_7322_ErrMask_ResetNegatedMask_MSB 0x3F
+#define QIB_7322_ErrMask_ResetNegatedMask_RMASK 0x1
+#define QIB_7322_ErrMask_HardwareErrMask_LSB 0x3E
+#define QIB_7322_ErrMask_HardwareErrMask_MSB 0x3E
+#define QIB_7322_ErrMask_HardwareErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_InvalidAddrErrMask_LSB 0x3D
+#define QIB_7322_ErrMask_InvalidAddrErrMask_MSB 0x3D
+#define QIB_7322_ErrMask_InvalidAddrErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_SDmaVL15ErrMask_LSB 0x38
+#define QIB_7322_ErrMask_SDmaVL15ErrMask_MSB 0x38
+#define QIB_7322_ErrMask_SDmaVL15ErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_SBufVL15MisUseErrMask_LSB 0x37
+#define QIB_7322_ErrMask_SBufVL15MisUseErrMask_MSB 0x37
+#define QIB_7322_ErrMask_SBufVL15MisUseErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_InvalidEEPCmdMask_LSB 0x35
+#define QIB_7322_ErrMask_InvalidEEPCmdMask_MSB 0x35
+#define QIB_7322_ErrMask_InvalidEEPCmdMask_RMASK 0x1
+#define QIB_7322_ErrMask_RcvContextShareErrMask_LSB 0x34
+#define QIB_7322_ErrMask_RcvContextShareErrMask_MSB 0x34
+#define QIB_7322_ErrMask_RcvContextShareErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_SendVLMismatchErrMask_LSB 0x24
+#define QIB_7322_ErrMask_SendVLMismatchErrMask_MSB 0x24
+#define QIB_7322_ErrMask_SendVLMismatchErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_SendArmLaunchErrMask_LSB 0x23
+#define QIB_7322_ErrMask_SendArmLaunchErrMask_MSB 0x23
+#define QIB_7322_ErrMask_SendArmLaunchErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_SendSpecialTriggerErrMask_LSB 0x1B
+#define QIB_7322_ErrMask_SendSpecialTriggerErrMask_MSB 0x1B
+#define QIB_7322_ErrMask_SendSpecialTriggerErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_SDmaWrongPortErrMask_LSB 0x1A
+#define QIB_7322_ErrMask_SDmaWrongPortErrMask_MSB 0x1A
+#define QIB_7322_ErrMask_SDmaWrongPortErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_SDmaBufMaskDuplicateErrMask_LSB 0x19
+#define QIB_7322_ErrMask_SDmaBufMaskDuplicateErrMask_MSB 0x19
+#define QIB_7322_ErrMask_SDmaBufMaskDuplicateErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_RcvHdrFullErrMask_LSB 0xD
+#define QIB_7322_ErrMask_RcvHdrFullErrMask_MSB 0xD
+#define QIB_7322_ErrMask_RcvHdrFullErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_RcvEgrFullErrMask_LSB 0xC
+#define QIB_7322_ErrMask_RcvEgrFullErrMask_MSB 0xC
+#define QIB_7322_ErrMask_RcvEgrFullErrMask_RMASK 0x1
+
+#define QIB_7322_ErrStatus_OFFS 0x88
+#define QIB_7322_ErrStatus_DEF 0x0000000000000000
+#define QIB_7322_ErrStatus_ResetNegated_LSB 0x3F
+#define QIB_7322_ErrStatus_ResetNegated_MSB 0x3F
+#define QIB_7322_ErrStatus_ResetNegated_RMASK 0x1
+#define QIB_7322_ErrStatus_HardwareErr_LSB 0x3E
+#define QIB_7322_ErrStatus_HardwareErr_MSB 0x3E
+#define QIB_7322_ErrStatus_HardwareErr_RMASK 0x1
+#define QIB_7322_ErrStatus_InvalidAddrErr_LSB 0x3D
+#define QIB_7322_ErrStatus_InvalidAddrErr_MSB 0x3D
+#define QIB_7322_ErrStatus_InvalidAddrErr_RMASK 0x1
+#define QIB_7322_ErrStatus_SDmaVL15Err_LSB 0x38
+#define QIB_7322_ErrStatus_SDmaVL15Err_MSB 0x38
+#define QIB_7322_ErrStatus_SDmaVL15Err_RMASK 0x1
+#define QIB_7322_ErrStatus_SBufVL15MisUseErr_LSB 0x37
+#define QIB_7322_ErrStatus_SBufVL15MisUseErr_MSB 0x37
+#define QIB_7322_ErrStatus_SBufVL15MisUseErr_RMASK 0x1
+#define QIB_7322_ErrStatus_InvalidEEPCmdErr_LSB 0x35
+#define QIB_7322_ErrStatus_InvalidEEPCmdErr_MSB 0x35
+#define QIB_7322_ErrStatus_InvalidEEPCmdErr_RMASK 0x1
+#define QIB_7322_ErrStatus_RcvContextShareErr_LSB 0x34
+#define QIB_7322_ErrStatus_RcvContextShareErr_MSB 0x34
+#define QIB_7322_ErrStatus_RcvContextShareErr_RMASK 0x1
+#define QIB_7322_ErrStatus_SendVLMismatchErr_LSB 0x24
+#define QIB_7322_ErrStatus_SendVLMismatchErr_MSB 0x24
+#define QIB_7322_ErrStatus_SendVLMismatchErr_RMASK 0x1
+#define QIB_7322_ErrStatus_SendArmLaunchErr_LSB 0x23
+#define QIB_7322_ErrStatus_SendArmLaunchErr_MSB 0x23
+#define QIB_7322_ErrStatus_SendArmLaunchErr_RMASK 0x1
+#define QIB_7322_ErrStatus_SendSpecialTriggerErr_LSB 0x1B
+#define QIB_7322_ErrStatus_SendSpecialTriggerErr_MSB 0x1B
+#define QIB_7322_ErrStatus_SendSpecialTriggerErr_RMASK 0x1
+#define QIB_7322_ErrStatus_SDmaWrongPortErr_LSB 0x1A
+#define QIB_7322_ErrStatus_SDmaWrongPortErr_MSB 0x1A
+#define QIB_7322_ErrStatus_SDmaWrongPortErr_RMASK 0x1
+#define QIB_7322_ErrStatus_SDmaBufMaskDuplicateErr_LSB 0x19
+#define QIB_7322_ErrStatus_SDmaBufMaskDuplicateErr_MSB 0x19
+#define QIB_7322_ErrStatus_SDmaBufMaskDuplicateErr_RMASK 0x1
+#define QIB_7322_ErrStatus_RcvHdrFullErr_LSB 0xD
+#define QIB_7322_ErrStatus_RcvHdrFullErr_MSB 0xD
+#define QIB_7322_ErrStatus_RcvHdrFullErr_RMASK 0x1
+#define QIB_7322_ErrStatus_RcvEgrFullErr_LSB 0xC
+#define QIB_7322_ErrStatus_RcvEgrFullErr_MSB 0xC
+#define QIB_7322_ErrStatus_RcvEgrFullErr_RMASK 0x1
+
+#define QIB_7322_ErrClear_OFFS 0x90
+#define QIB_7322_ErrClear_DEF 0x0000000000000000
+#define QIB_7322_ErrClear_ResetNegatedClear_LSB 0x3F
+#define QIB_7322_ErrClear_ResetNegatedClear_MSB 0x3F
+#define QIB_7322_ErrClear_ResetNegatedClear_RMASK 0x1
+#define QIB_7322_ErrClear_HardwareErrClear_LSB 0x3E
+#define QIB_7322_ErrClear_HardwareErrClear_MSB 0x3E
+#define QIB_7322_ErrClear_HardwareErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_InvalidAddrErrClear_LSB 0x3D
+#define QIB_7322_ErrClear_InvalidAddrErrClear_MSB 0x3D
+#define QIB_7322_ErrClear_InvalidAddrErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_SDmaVL15ErrClear_LSB 0x38
+#define QIB_7322_ErrClear_SDmaVL15ErrClear_MSB 0x38
+#define QIB_7322_ErrClear_SDmaVL15ErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_SBufVL15MisUseErrClear_LSB 0x37
+#define QIB_7322_ErrClear_SBufVL15MisUseErrClear_MSB 0x37
+#define QIB_7322_ErrClear_SBufVL15MisUseErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_InvalidEEPCmdErrClear_LSB 0x35
+#define QIB_7322_ErrClear_InvalidEEPCmdErrClear_MSB 0x35
+#define QIB_7322_ErrClear_InvalidEEPCmdErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_RcvContextShareErrClear_LSB 0x34
+#define QIB_7322_ErrClear_RcvContextShareErrClear_MSB 0x34
+#define QIB_7322_ErrClear_RcvContextShareErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_SendVLMismatchErrMask_LSB 0x24
+#define QIB_7322_ErrClear_SendVLMismatchErrMask_MSB 0x24
+#define QIB_7322_ErrClear_SendVLMismatchErrMask_RMASK 0x1
+#define QIB_7322_ErrClear_SendArmLaunchErrClear_LSB 0x23
+#define QIB_7322_ErrClear_SendArmLaunchErrClear_MSB 0x23
+#define QIB_7322_ErrClear_SendArmLaunchErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_SendSpecialTriggerErrClear_LSB 0x1B
+#define QIB_7322_ErrClear_SendSpecialTriggerErrClear_MSB 0x1B
+#define QIB_7322_ErrClear_SendSpecialTriggerErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_SDmaWrongPortErrClear_LSB 0x1A
+#define QIB_7322_ErrClear_SDmaWrongPortErrClear_MSB 0x1A
+#define QIB_7322_ErrClear_SDmaWrongPortErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_SDmaBufMaskDuplicateErrClear_LSB 0x19
+#define QIB_7322_ErrClear_SDmaBufMaskDuplicateErrClear_MSB 0x19
+#define QIB_7322_ErrClear_SDmaBufMaskDuplicateErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_RcvHdrFullErrClear_LSB 0xD
+#define QIB_7322_ErrClear_RcvHdrFullErrClear_MSB 0xD
+#define QIB_7322_ErrClear_RcvHdrFullErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_RcvEgrFullErrClear_LSB 0xC
+#define QIB_7322_ErrClear_RcvEgrFullErrClear_MSB 0xC
+#define QIB_7322_ErrClear_RcvEgrFullErrClear_RMASK 0x1
+
+#define QIB_7322_HwErrMask_OFFS 0x98
+#define QIB_7322_HwErrMask_DEF 0x0000000000000000
+#define QIB_7322_HwErrMask_IBSerdesPClkNotDetectMask_1_LSB 0x3F
+#define QIB_7322_HwErrMask_IBSerdesPClkNotDetectMask_1_MSB 0x3F
+#define QIB_7322_HwErrMask_IBSerdesPClkNotDetectMask_1_RMASK 0x1
+#define QIB_7322_HwErrMask_IBSerdesPClkNotDetectMask_0_LSB 0x3E
+#define QIB_7322_HwErrMask_IBSerdesPClkNotDetectMask_0_MSB 0x3E
+#define QIB_7322_HwErrMask_IBSerdesPClkNotDetectMask_0_RMASK 0x1
+#define QIB_7322_HwErrMask_PCIESerdesPClkNotDetectMask_LSB 0x37
+#define QIB_7322_HwErrMask_PCIESerdesPClkNotDetectMask_MSB 0x37
+#define QIB_7322_HwErrMask_PCIESerdesPClkNotDetectMask_RMASK 0x1
+#define QIB_7322_HwErrMask_PowerOnBISTFailedMask_LSB 0x36
+#define QIB_7322_HwErrMask_PowerOnBISTFailedMask_MSB 0x36
+#define QIB_7322_HwErrMask_PowerOnBISTFailedMask_RMASK 0x1
+#define QIB_7322_HwErrMask_TempsenseTholdReachedMask_LSB 0x35
+#define QIB_7322_HwErrMask_TempsenseTholdReachedMask_MSB 0x35
+#define QIB_7322_HwErrMask_TempsenseTholdReachedMask_RMASK 0x1
+#define QIB_7322_HwErrMask_MemoryErrMask_LSB 0x30
+#define QIB_7322_HwErrMask_MemoryErrMask_MSB 0x30
+#define QIB_7322_HwErrMask_MemoryErrMask_RMASK 0x1
+#define QIB_7322_HwErrMask_pcie_phy_txParityErr_LSB 0x22
+#define QIB_7322_HwErrMask_pcie_phy_txParityErr_MSB 0x22
+#define QIB_7322_HwErrMask_pcie_phy_txParityErr_RMASK 0x1
+#define QIB_7322_HwErrMask_PCIeBusParityErrMask_LSB 0x1F
+#define QIB_7322_HwErrMask_PCIeBusParityErrMask_MSB 0x21
+#define QIB_7322_HwErrMask_PCIeBusParityErrMask_RMASK 0x7
+#define QIB_7322_HwErrMask_PcieCplTimeoutMask_LSB 0x1E
+#define QIB_7322_HwErrMask_PcieCplTimeoutMask_MSB 0x1E
+#define QIB_7322_HwErrMask_PcieCplTimeoutMask_RMASK 0x1
+#define QIB_7322_HwErrMask_PciePoisonedTLPMask_LSB 0x1D
+#define QIB_7322_HwErrMask_PciePoisonedTLPMask_MSB 0x1D
+#define QIB_7322_HwErrMask_PciePoisonedTLPMask_RMASK 0x1
+#define QIB_7322_HwErrMask_SDmaMemReadErrMask_1_LSB 0x1C
+#define QIB_7322_HwErrMask_SDmaMemReadErrMask_1_MSB 0x1C
+#define QIB_7322_HwErrMask_SDmaMemReadErrMask_1_RMASK 0x1
+#define QIB_7322_HwErrMask_SDmaMemReadErrMask_0_LSB 0x1B
+#define QIB_7322_HwErrMask_SDmaMemReadErrMask_0_MSB 0x1B
+#define QIB_7322_HwErrMask_SDmaMemReadErrMask_0_RMASK 0x1
+#define QIB_7322_HwErrMask_IBCBusFromSPCParityErrMask_1_LSB 0xF
+#define QIB_7322_HwErrMask_IBCBusFromSPCParityErrMask_1_MSB 0xF
+#define QIB_7322_HwErrMask_IBCBusFromSPCParityErrMask_1_RMASK 0x1
+#define QIB_7322_HwErrMask_statusValidNoEopMask_1_LSB 0xE
+#define QIB_7322_HwErrMask_statusValidNoEopMask_1_MSB 0xE
+#define QIB_7322_HwErrMask_statusValidNoEopMask_1_RMASK 0x1
+#define QIB_7322_HwErrMask_IBCBusFromSPCParityErrMask_0_LSB 0xD
+#define QIB_7322_HwErrMask_IBCBusFromSPCParityErrMask_0_MSB 0xD
+#define QIB_7322_HwErrMask_IBCBusFromSPCParityErrMask_0_RMASK 0x1
+#define QIB_7322_HwErrMask_statusValidNoEopMask_0_LSB 0xC
+#define QIB_7322_HwErrMask_statusValidNoEopMask_0_MSB 0xC
+#define QIB_7322_HwErrMask_statusValidNoEopMask_0_RMASK 0x1
+#define QIB_7322_HwErrMask_LATriggeredMask_LSB 0xB
+#define QIB_7322_HwErrMask_LATriggeredMask_MSB 0xB
+#define QIB_7322_HwErrMask_LATriggeredMask_RMASK 0x1
+
+#define QIB_7322_HwErrStatus_OFFS 0xA0
+#define QIB_7322_HwErrStatus_DEF 0x0000000000000000
+#define QIB_7322_HwErrStatus_IBSerdesPClkNotDetect_1_LSB 0x3F
+#define QIB_7322_HwErrStatus_IBSerdesPClkNotDetect_1_MSB 0x3F
+#define QIB_7322_HwErrStatus_IBSerdesPClkNotDetect_1_RMASK 0x1
+#define QIB_7322_HwErrStatus_IBSerdesPClkNotDetect_0_LSB 0x3E
+#define QIB_7322_HwErrStatus_IBSerdesPClkNotDetect_0_MSB 0x3E
+#define QIB_7322_HwErrStatus_IBSerdesPClkNotDetect_0_RMASK 0x1
+#define QIB_7322_HwErrStatus_PCIESerdesPClkNotDetect_LSB 0x37
+#define QIB_7322_HwErrStatus_PCIESerdesPClkNotDetect_MSB 0x37
+#define QIB_7322_HwErrStatus_PCIESerdesPClkNotDetect_RMASK 0x1
+#define QIB_7322_HwErrStatus_PowerOnBISTFailed_LSB 0x36
+#define QIB_7322_HwErrStatus_PowerOnBISTFailed_MSB 0x36
+#define QIB_7322_HwErrStatus_PowerOnBISTFailed_RMASK 0x1
+#define QIB_7322_HwErrStatus_TempsenseTholdReached_LSB 0x35
+#define QIB_7322_HwErrStatus_TempsenseTholdReached_MSB 0x35
+#define QIB_7322_HwErrStatus_TempsenseTholdReached_RMASK 0x1
+#define QIB_7322_HwErrStatus_MemoryErr_LSB 0x30
+#define QIB_7322_HwErrStatus_MemoryErr_MSB 0x30
+#define QIB_7322_HwErrStatus_MemoryErr_RMASK 0x1
+#define QIB_7322_HwErrStatus_pcie_phy_txParityErr_LSB 0x22
+#define QIB_7322_HwErrStatus_pcie_phy_txParityErr_MSB 0x22
+#define QIB_7322_HwErrStatus_pcie_phy_txParityErr_RMASK 0x1
+#define QIB_7322_HwErrStatus_PCIeBusParity_LSB 0x1F
+#define QIB_7322_HwErrStatus_PCIeBusParity_MSB 0x21
+#define QIB_7322_HwErrStatus_PCIeBusParity_RMASK 0x7
+#define QIB_7322_HwErrStatus_PcieCplTimeout_LSB 0x1E
+#define QIB_7322_HwErrStatus_PcieCplTimeout_MSB 0x1E
+#define QIB_7322_HwErrStatus_PcieCplTimeout_RMASK 0x1
+#define QIB_7322_HwErrStatus_PciePoisonedTLP_LSB 0x1D
+#define QIB_7322_HwErrStatus_PciePoisonedTLP_MSB 0x1D
+#define QIB_7322_HwErrStatus_PciePoisonedTLP_RMASK 0x1
+#define QIB_7322_HwErrStatus_SDmaMemReadErr_1_LSB 0x1C
+#define QIB_7322_HwErrStatus_SDmaMemReadErr_1_MSB 0x1C
+#define QIB_7322_HwErrStatus_SDmaMemReadErr_1_RMASK 0x1
+#define QIB_7322_HwErrStatus_SDmaMemReadErr_0_LSB 0x1B
+#define QIB_7322_HwErrStatus_SDmaMemReadErr_0_MSB 0x1B
+#define QIB_7322_HwErrStatus_SDmaMemReadErr_0_RMASK 0x1
+#define QIB_7322_HwErrStatus_IBCBusFromSPCParityErr_1_LSB 0xF
+#define QIB_7322_HwErrStatus_IBCBusFromSPCParityErr_1_MSB 0xF
+#define QIB_7322_HwErrStatus_IBCBusFromSPCParityErr_1_RMASK 0x1
+#define QIB_7322_HwErrStatus_statusValidNoEop_1_LSB 0xE
+#define QIB_7322_HwErrStatus_statusValidNoEop_1_MSB 0xE
+#define QIB_7322_HwErrStatus_statusValidNoEop_1_RMASK 0x1
+#define QIB_7322_HwErrStatus_IBCBusFromSPCParityErr_0_LSB 0xD
+#define QIB_7322_HwErrStatus_IBCBusFromSPCParityErr_0_MSB 0xD
+#define QIB_7322_HwErrStatus_IBCBusFromSPCParityErr_0_RMASK 0x1
+#define QIB_7322_HwErrStatus_statusValidNoEop_0_LSB 0xC
+#define QIB_7322_HwErrStatus_statusValidNoEop_0_MSB 0xC
+#define QIB_7322_HwErrStatus_statusValidNoEop_0_RMASK 0x1
+#define QIB_7322_HwErrStatus_LATriggered_LSB 0xB
+#define QIB_7322_HwErrStatus_LATriggered_MSB 0xB
+#define QIB_7322_HwErrStatus_LATriggered_RMASK 0x1
+
+#define QIB_7322_HwErrClear_OFFS 0xA8
+#define QIB_7322_HwErrClear_DEF 0x0000000000000000
+#define QIB_7322_HwErrClear_IBSerdesPClkNotDetectClear_1_LSB 0x3F
+#define QIB_7322_HwErrClear_IBSerdesPClkNotDetectClear_1_MSB 0x3F
+#define QIB_7322_HwErrClear_IBSerdesPClkNotDetectClear_1_RMASK 0x1
+#define QIB_7322_HwErrClear_IBSerdesPClkNotDetectClear_0_LSB 0x3E
+#define QIB_7322_HwErrClear_IBSerdesPClkNotDetectClear_0_MSB 0x3E
+#define QIB_7322_HwErrClear_IBSerdesPClkNotDetectClear_0_RMASK 0x1
+#define QIB_7322_HwErrClear_PCIESerdesPClkNotDetectClear_LSB 0x37
+#define QIB_7322_HwErrClear_PCIESerdesPClkNotDetectClear_MSB 0x37
+#define QIB_7322_HwErrClear_PCIESerdesPClkNotDetectClear_RMASK 0x1
+#define QIB_7322_HwErrClear_PowerOnBISTFailedClear_LSB 0x36
+#define QIB_7322_HwErrClear_PowerOnBISTFailedClear_MSB 0x36
+#define QIB_7322_HwErrClear_PowerOnBISTFailedClear_RMASK 0x1
+#define QIB_7322_HwErrClear_TempsenseTholdReachedClear_LSB 0x35
+#define QIB_7322_HwErrClear_TempsenseTholdReachedClear_MSB 0x35
+#define QIB_7322_HwErrClear_TempsenseTholdReachedClear_RMASK 0x1
+#define QIB_7322_HwErrClear_MemoryErrClear_LSB 0x30
+#define QIB_7322_HwErrClear_MemoryErrClear_MSB 0x30
+#define QIB_7322_HwErrClear_MemoryErrClear_RMASK 0x1
+#define QIB_7322_HwErrClear_pcie_phy_txParityErr_LSB 0x22
+#define QIB_7322_HwErrClear_pcie_phy_txParityErr_MSB 0x22
+#define QIB_7322_HwErrClear_pcie_phy_txParityErr_RMASK 0x1
+#define QIB_7322_HwErrClear_PCIeBusParityClear_LSB 0x1F
+#define QIB_7322_HwErrClear_PCIeBusParityClear_MSB 0x21
+#define QIB_7322_HwErrClear_PCIeBusParityClear_RMASK 0x7
+#define QIB_7322_HwErrClear_PcieCplTimeoutClear_LSB 0x1E
+#define QIB_7322_HwErrClear_PcieCplTimeoutClear_MSB 0x1E
+#define QIB_7322_HwErrClear_PcieCplTimeoutClear_RMASK 0x1
+#define QIB_7322_HwErrClear_PciePoisonedTLPClear_LSB 0x1D
+#define QIB_7322_HwErrClear_PciePoisonedTLPClear_MSB 0x1D
+#define QIB_7322_HwErrClear_PciePoisonedTLPClear_RMASK 0x1
+#define QIB_7322_HwErrClear_SDmaMemReadErrClear_1_LSB 0x1C
+#define QIB_7322_HwErrClear_SDmaMemReadErrClear_1_MSB 0x1C
+#define QIB_7322_HwErrClear_SDmaMemReadErrClear_1_RMASK 0x1
+#define QIB_7322_HwErrClear_SDmaMemReadErrClear_0_LSB 0x1B
+#define QIB_7322_HwErrClear_SDmaMemReadErrClear_0_MSB 0x1B
+#define QIB_7322_HwErrClear_SDmaMemReadErrClear_0_RMASK 0x1
+#define QIB_7322_HwErrClear_IBCBusFromSPCParityErrClear_1_LSB 0xF
+#define QIB_7322_HwErrClear_IBCBusFromSPCParityErrClear_1_MSB 0xF
+#define QIB_7322_HwErrClear_IBCBusFromSPCParityErrClear_1_RMASK 0x1
+#define QIB_7322_HwErrClear_IBCBusToSPCparityErrClear_1_LSB 0xE
+#define QIB_7322_HwErrClear_IBCBusToSPCparityErrClear_1_MSB 0xE
+#define QIB_7322_HwErrClear_IBCBusToSPCparityErrClear_1_RMASK 0x1
+#define QIB_7322_HwErrClear_IBCBusFromSPCParityErrClear_0_LSB 0xD
+#define QIB_7322_HwErrClear_IBCBusFromSPCParityErrClear_0_MSB 0xD
+#define QIB_7322_HwErrClear_IBCBusFromSPCParityErrClear_0_RMASK 0x1
+#define QIB_7322_HwErrClear_IBCBusToSPCparityErrClear_0_LSB 0xC
+#define QIB_7322_HwErrClear_IBCBusToSPCparityErrClear_0_MSB 0xC
+#define QIB_7322_HwErrClear_IBCBusToSPCparityErrClear_0_RMASK 0x1
+#define QIB_7322_HwErrClear_LATriggeredClear_LSB 0xB
+#define QIB_7322_HwErrClear_LATriggeredClear_MSB 0xB
+#define QIB_7322_HwErrClear_LATriggeredClear_RMASK 0x1
+
+#define QIB_7322_HwDiagCtrl_OFFS 0xB0
+#define QIB_7322_HwDiagCtrl_DEF 0x0000000000000000
+#define QIB_7322_HwDiagCtrl_Diagnostic_LSB 0x3F
+#define QIB_7322_HwDiagCtrl_Diagnostic_MSB 0x3F
+#define QIB_7322_HwDiagCtrl_Diagnostic_RMASK 0x1
+#define QIB_7322_HwDiagCtrl_CounterWrEnable_LSB 0x3D
+#define QIB_7322_HwDiagCtrl_CounterWrEnable_MSB 0x3D
+#define QIB_7322_HwDiagCtrl_CounterWrEnable_RMASK 0x1
+#define QIB_7322_HwDiagCtrl_CounterDisable_LSB 0x3C
+#define QIB_7322_HwDiagCtrl_CounterDisable_MSB 0x3C
+#define QIB_7322_HwDiagCtrl_CounterDisable_RMASK 0x1
+#define QIB_7322_HwDiagCtrl_forcePCIeBusParity_LSB 0x1F
+#define QIB_7322_HwDiagCtrl_forcePCIeBusParity_MSB 0x22
+#define QIB_7322_HwDiagCtrl_forcePCIeBusParity_RMASK 0xF
+#define QIB_7322_HwDiagCtrl_ForceIBCBusFromSPCParityErr_1_LSB 0xF
+#define QIB_7322_HwDiagCtrl_ForceIBCBusFromSPCParityErr_1_MSB 0xF
+#define QIB_7322_HwDiagCtrl_ForceIBCBusFromSPCParityErr_1_RMASK 0x1
+#define QIB_7322_HwDiagCtrl_ForcestatusValidNoEop_1_LSB 0xE
+#define QIB_7322_HwDiagCtrl_ForcestatusValidNoEop_1_MSB 0xE
+#define QIB_7322_HwDiagCtrl_ForcestatusValidNoEop_1_RMASK 0x1
+#define QIB_7322_HwDiagCtrl_ForceIBCBusFromSPCParityErr_0_LSB 0xD
+#define QIB_7322_HwDiagCtrl_ForceIBCBusFromSPCParityErr_0_MSB 0xD
+#define QIB_7322_HwDiagCtrl_ForceIBCBusFromSPCParityErr_0_RMASK 0x1
+#define QIB_7322_HwDiagCtrl_ForcestatusValidNoEop_0_LSB 0xC
+#define QIB_7322_HwDiagCtrl_ForcestatusValidNoEop_0_MSB 0xC
+#define QIB_7322_HwDiagCtrl_ForcestatusValidNoEop_0_RMASK 0x1
+
+#define QIB_7322_EXTStatus_OFFS 0xC0
+#define QIB_7322_EXTStatus_DEF 0x000000000000X000
+#define QIB_7322_EXTStatus_GPIOIn_LSB 0x30
+#define QIB_7322_EXTStatus_GPIOIn_MSB 0x3F
+#define QIB_7322_EXTStatus_GPIOIn_RMASK 0xFFFF
+#define QIB_7322_EXTStatus_MemBISTDisabled_LSB 0xF
+#define QIB_7322_EXTStatus_MemBISTDisabled_MSB 0xF
+#define QIB_7322_EXTStatus_MemBISTDisabled_RMASK 0x1
+#define QIB_7322_EXTStatus_MemBISTEndTest_LSB 0xE
+#define QIB_7322_EXTStatus_MemBISTEndTest_MSB 0xE
+#define QIB_7322_EXTStatus_MemBISTEndTest_RMASK 0x1
+
+#define QIB_7322_EXTCtrl_OFFS 0xC8
+#define QIB_7322_EXTCtrl_DEF 0x0000000000000000
+#define QIB_7322_EXTCtrl_GPIOOe_LSB 0x30
+#define QIB_7322_EXTCtrl_GPIOOe_MSB 0x3F
+#define QIB_7322_EXTCtrl_GPIOOe_RMASK 0xFFFF
+#define QIB_7322_EXTCtrl_GPIOInvert_LSB 0x20
+#define QIB_7322_EXTCtrl_GPIOInvert_MSB 0x2F
+#define QIB_7322_EXTCtrl_GPIOInvert_RMASK 0xFFFF
+#define QIB_7322_EXTCtrl_LEDPort1GreenOn_LSB 0x3
+#define QIB_7322_EXTCtrl_LEDPort1GreenOn_MSB 0x3
+#define QIB_7322_EXTCtrl_LEDPort1GreenOn_RMASK 0x1
+#define QIB_7322_EXTCtrl_LEDPort1YellowOn_LSB 0x2
+#define QIB_7322_EXTCtrl_LEDPort1YellowOn_MSB 0x2
+#define QIB_7322_EXTCtrl_LEDPort1YellowOn_RMASK 0x1
+#define QIB_7322_EXTCtrl_LEDPort0GreenOn_LSB 0x1
+#define QIB_7322_EXTCtrl_LEDPort0GreenOn_MSB 0x1
+#define QIB_7322_EXTCtrl_LEDPort0GreenOn_RMASK 0x1
+#define QIB_7322_EXTCtrl_LEDPort0YellowOn_LSB 0x0
+#define QIB_7322_EXTCtrl_LEDPort0YellowOn_MSB 0x0
+#define QIB_7322_EXTCtrl_LEDPort0YellowOn_RMASK 0x1
+
+#define QIB_7322_GPIOOut_OFFS 0xE0
+#define QIB_7322_GPIOOut_DEF 0x0000000000000000
+
+#define QIB_7322_GPIOMask_OFFS 0xE8
+#define QIB_7322_GPIOMask_DEF 0x0000000000000000
+
+#define QIB_7322_GPIOStatus_OFFS 0xF0
+#define QIB_7322_GPIOStatus_DEF 0x0000000000000000
+
+#define QIB_7322_GPIOClear_OFFS 0xF8
+#define QIB_7322_GPIOClear_DEF 0x0000000000000000
+
+#define QIB_7322_RcvCtrl_OFFS 0x100
+#define QIB_7322_RcvCtrl_DEF 0x0000000000000000
+#define QIB_7322_RcvCtrl_TidReDirect_LSB 0x30
+#define QIB_7322_RcvCtrl_TidReDirect_MSB 0x3F
+#define QIB_7322_RcvCtrl_TidReDirect_RMASK 0xFFFF
+#define QIB_7322_RcvCtrl_TailUpd_LSB 0x2F
+#define QIB_7322_RcvCtrl_TailUpd_MSB 0x2F
+#define QIB_7322_RcvCtrl_TailUpd_RMASK 0x1
+#define QIB_7322_RcvCtrl_XrcTypeCode_LSB 0x2C
+#define QIB_7322_RcvCtrl_XrcTypeCode_MSB 0x2E
+#define QIB_7322_RcvCtrl_XrcTypeCode_RMASK 0x7
+#define QIB_7322_RcvCtrl_TidFlowEnable_LSB 0x2B
+#define QIB_7322_RcvCtrl_TidFlowEnable_MSB 0x2B
+#define QIB_7322_RcvCtrl_TidFlowEnable_RMASK 0x1
+#define QIB_7322_RcvCtrl_ContextCfg_LSB 0x29
+#define QIB_7322_RcvCtrl_ContextCfg_MSB 0x2A
+#define QIB_7322_RcvCtrl_ContextCfg_RMASK 0x3
+#define QIB_7322_RcvCtrl_IntrAvail_LSB 0x14
+#define QIB_7322_RcvCtrl_IntrAvail_MSB 0x25
+#define QIB_7322_RcvCtrl_IntrAvail_RMASK 0x3FFFF
+#define QIB_7322_RcvCtrl_dontDropRHQFull_LSB 0x0
+#define QIB_7322_RcvCtrl_dontDropRHQFull_MSB 0x11
+#define QIB_7322_RcvCtrl_dontDropRHQFull_RMASK 0x3FFFF
+
+#define QIB_7322_RcvHdrSize_OFFS 0x110
+#define QIB_7322_RcvHdrSize_DEF 0x0000000000000000
+
+#define QIB_7322_RcvHdrCnt_OFFS 0x118
+#define QIB_7322_RcvHdrCnt_DEF 0x0000000000000000
+
+#define QIB_7322_RcvHdrEntSize_OFFS 0x120
+#define QIB_7322_RcvHdrEntSize_DEF 0x0000000000000000
+
+#define QIB_7322_RcvTIDBase_OFFS 0x128
+#define QIB_7322_RcvTIDBase_DEF 0x0000000000050000
+
+#define QIB_7322_RcvTIDCnt_OFFS 0x130
+#define QIB_7322_RcvTIDCnt_DEF 0x0000000000000200
+
+#define QIB_7322_RcvEgrBase_OFFS 0x138
+#define QIB_7322_RcvEgrBase_DEF 0x0000000000014000
+
+#define QIB_7322_RcvEgrCnt_OFFS 0x140
+#define QIB_7322_RcvEgrCnt_DEF 0x0000000000001000
+
+#define QIB_7322_RcvBufBase_OFFS 0x148
+#define QIB_7322_RcvBufBase_DEF 0x0000000000080000
+
+#define QIB_7322_RcvBufSize_OFFS 0x150
+#define QIB_7322_RcvBufSize_DEF 0x0000000000005000
+
+#define QIB_7322_RxIntMemBase_OFFS 0x158
+#define QIB_7322_RxIntMemBase_DEF 0x0000000000077000
+
+#define QIB_7322_RxIntMemSize_OFFS 0x160
+#define QIB_7322_RxIntMemSize_DEF 0x0000000000007000
+
+#define QIB_7322_feature_mask_OFFS 0x190
+#define QIB_7322_feature_mask_DEF 0x00000000000000XX
+
+#define QIB_7322_active_feature_mask_OFFS 0x198
+#define QIB_7322_active_feature_mask_DEF 0x00000000000000XX
+#define QIB_7322_active_feature_mask_Port1_QDR_Enabled_LSB 0x5
+#define QIB_7322_active_feature_mask_Port1_QDR_Enabled_MSB 0x5
+#define QIB_7322_active_feature_mask_Port1_QDR_Enabled_RMASK 0x1
+#define QIB_7322_active_feature_mask_Port1_DDR_Enabled_LSB 0x4
+#define QIB_7322_active_feature_mask_Port1_DDR_Enabled_MSB 0x4
+#define QIB_7322_active_feature_mask_Port1_DDR_Enabled_RMASK 0x1
+#define QIB_7322_active_feature_mask_Port1_SDR_Enabled_LSB 0x3
+#define QIB_7322_active_feature_mask_Port1_SDR_Enabled_MSB 0x3
+#define QIB_7322_active_feature_mask_Port1_SDR_Enabled_RMASK 0x1
+#define QIB_7322_active_feature_mask_Port0_QDR_Enabled_LSB 0x2
+#define QIB_7322_active_feature_mask_Port0_QDR_Enabled_MSB 0x2
+#define QIB_7322_active_feature_mask_Port0_QDR_Enabled_RMASK 0x1
+#define QIB_7322_active_feature_mask_Port0_DDR_Enabled_LSB 0x1
+#define QIB_7322_active_feature_mask_Port0_DDR_Enabled_MSB 0x1
+#define QIB_7322_active_feature_mask_Port0_DDR_Enabled_RMASK 0x1
+#define QIB_7322_active_feature_mask_Port0_SDR_Enabled_LSB 0x0
+#define QIB_7322_active_feature_mask_Port0_SDR_Enabled_MSB 0x0
+#define QIB_7322_active_feature_mask_Port0_SDR_Enabled_RMASK 0x1
+
+#define QIB_7322_SendCtrl_OFFS 0x1C0
+#define QIB_7322_SendCtrl_DEF 0x0000000000000000
+#define QIB_7322_SendCtrl_Disarm_LSB 0x1F
+#define QIB_7322_SendCtrl_Disarm_MSB 0x1F
+#define QIB_7322_SendCtrl_Disarm_RMASK 0x1
+#define QIB_7322_SendCtrl_SendBufAvailPad64Byte_LSB 0x1D
+#define QIB_7322_SendCtrl_SendBufAvailPad64Byte_MSB 0x1D
+#define QIB_7322_SendCtrl_SendBufAvailPad64Byte_RMASK 0x1
+#define QIB_7322_SendCtrl_AvailUpdThld_LSB 0x18
+#define QIB_7322_SendCtrl_AvailUpdThld_MSB 0x1C
+#define QIB_7322_SendCtrl_AvailUpdThld_RMASK 0x1F
+#define QIB_7322_SendCtrl_DisarmSendBuf_LSB 0x10
+#define QIB_7322_SendCtrl_DisarmSendBuf_MSB 0x17
+#define QIB_7322_SendCtrl_DisarmSendBuf_RMASK 0xFF
+#define QIB_7322_SendCtrl_SpecialTriggerEn_LSB 0x4
+#define QIB_7322_SendCtrl_SpecialTriggerEn_MSB 0x4
+#define QIB_7322_SendCtrl_SpecialTriggerEn_RMASK 0x1
+#define QIB_7322_SendCtrl_SendBufAvailUpd_LSB 0x2
+#define QIB_7322_SendCtrl_SendBufAvailUpd_MSB 0x2
+#define QIB_7322_SendCtrl_SendBufAvailUpd_RMASK 0x1
+#define QIB_7322_SendCtrl_SendIntBufAvail_LSB 0x1
+#define QIB_7322_SendCtrl_SendIntBufAvail_MSB 0x1
+#define QIB_7322_SendCtrl_SendIntBufAvail_RMASK 0x1
+
+#define QIB_7322_SendBufBase_OFFS 0x1C8
+#define QIB_7322_SendBufBase_DEF 0x0018000000100000
+#define QIB_7322_SendBufBase_BaseAddr_LargePIO_LSB 0x20
+#define QIB_7322_SendBufBase_BaseAddr_LargePIO_MSB 0x34
+#define QIB_7322_SendBufBase_BaseAddr_LargePIO_RMASK 0x1FFFFF
+#define QIB_7322_SendBufBase_BaseAddr_SmallPIO_LSB 0x0
+#define QIB_7322_SendBufBase_BaseAddr_SmallPIO_MSB 0x14
+#define QIB_7322_SendBufBase_BaseAddr_SmallPIO_RMASK 0x1FFFFF
+
+#define QIB_7322_SendBufSize_OFFS 0x1D0
+#define QIB_7322_SendBufSize_DEF 0x0000108000000880
+#define QIB_7322_SendBufSize_Size_LargePIO_LSB 0x20
+#define QIB_7322_SendBufSize_Size_LargePIO_MSB 0x2C
+#define QIB_7322_SendBufSize_Size_LargePIO_RMASK 0x1FFF
+#define QIB_7322_SendBufSize_Size_SmallPIO_LSB 0x0
+#define QIB_7322_SendBufSize_Size_SmallPIO_MSB 0xB
+#define QIB_7322_SendBufSize_Size_SmallPIO_RMASK 0xFFF
+
+#define QIB_7322_SendBufCnt_OFFS 0x1D8
+#define QIB_7322_SendBufCnt_DEF 0x0000002000000080
+#define QIB_7322_SendBufCnt_Num_LargeBuffers_LSB 0x20
+#define QIB_7322_SendBufCnt_Num_LargeBuffers_MSB 0x25
+#define QIB_7322_SendBufCnt_Num_LargeBuffers_RMASK 0x3F
+#define QIB_7322_SendBufCnt_Num_SmallBuffers_LSB 0x0
+#define QIB_7322_SendBufCnt_Num_SmallBuffers_MSB 0x8
+#define QIB_7322_SendBufCnt_Num_SmallBuffers_RMASK 0x1FF
+
+#define QIB_7322_SendBufAvailAddr_OFFS 0x1E0
+#define QIB_7322_SendBufAvailAddr_DEF 0x0000000000000000
+#define QIB_7322_SendBufAvailAddr_SendBufAvailAddr_LSB 0x6
+#define QIB_7322_SendBufAvailAddr_SendBufAvailAddr_MSB 0x27
+#define QIB_7322_SendBufAvailAddr_SendBufAvailAddr_RMASK 0x3FFFFFFFF
+
+#define QIB_7322_SendBufErr0_OFFS 0x240
+#define QIB_7322_SendBufErr0_DEF 0x0000000000000000
+#define QIB_7322_SendBufErr0_SendBufErr_63_0_LSB 0x0
+#define QIB_7322_SendBufErr0_SendBufErr_63_0_MSB 0x3F
+#define QIB_7322_SendBufErr0_SendBufErr_63_0_RMASK 0x0
+
+#define QIB_7322_AvailUpdCount_OFFS 0x268
+#define QIB_7322_AvailUpdCount_DEF 0x0000000000000000
+#define QIB_7322_AvailUpdCount_AvailUpdCount_LSB 0x0
+#define QIB_7322_AvailUpdCount_AvailUpdCount_MSB 0x4
+#define QIB_7322_AvailUpdCount_AvailUpdCount_RMASK 0x1F
+
+#define QIB_7322_RcvHdrAddr0_OFFS 0x280
+#define QIB_7322_RcvHdrAddr0_DEF 0x0000000000000000
+#define QIB_7322_RcvHdrAddr0_RcvHdrAddr_LSB 0x2
+#define QIB_7322_RcvHdrAddr0_RcvHdrAddr_MSB 0x27
+#define QIB_7322_RcvHdrAddr0_RcvHdrAddr_RMASK 0x3FFFFFFFFF
+
+#define QIB_7322_RcvHdrTailAddr0_OFFS 0x340
+#define QIB_7322_RcvHdrTailAddr0_DEF 0x0000000000000000
+#define QIB_7322_RcvHdrTailAddr0_RcvHdrTailAddr_LSB 0x2
+#define QIB_7322_RcvHdrTailAddr0_RcvHdrTailAddr_MSB 0x27
+#define QIB_7322_RcvHdrTailAddr0_RcvHdrTailAddr_RMASK 0x3FFFFFFFFF
+
+#define QIB_7322_ahb_access_ctrl_OFFS 0x460
+#define QIB_7322_ahb_access_ctrl_DEF 0x0000000000000000
+#define QIB_7322_ahb_access_ctrl_sw_sel_ahb_trgt_LSB 0x1
+#define QIB_7322_ahb_access_ctrl_sw_sel_ahb_trgt_MSB 0x2
+#define QIB_7322_ahb_access_ctrl_sw_sel_ahb_trgt_RMASK 0x3
+#define QIB_7322_ahb_access_ctrl_sw_ahb_sel_LSB 0x0
+#define QIB_7322_ahb_access_ctrl_sw_ahb_sel_MSB 0x0
+#define QIB_7322_ahb_access_ctrl_sw_ahb_sel_RMASK 0x1
+
+#define QIB_7322_ahb_transaction_reg_OFFS 0x468
+#define QIB_7322_ahb_transaction_reg_DEF 0x0000000080000000
+#define QIB_7322_ahb_transaction_reg_ahb_data_LSB 0x20
+#define QIB_7322_ahb_transaction_reg_ahb_data_MSB 0x3F
+#define QIB_7322_ahb_transaction_reg_ahb_data_RMASK 0xFFFFFFFF
+#define QIB_7322_ahb_transaction_reg_ahb_rdy_LSB 0x1F
+#define QIB_7322_ahb_transaction_reg_ahb_rdy_MSB 0x1F
+#define QIB_7322_ahb_transaction_reg_ahb_rdy_RMASK 0x1
+#define QIB_7322_ahb_transaction_reg_ahb_req_err_LSB 0x1E
+#define QIB_7322_ahb_transaction_reg_ahb_req_err_MSB 0x1E
+#define QIB_7322_ahb_transaction_reg_ahb_req_err_RMASK 0x1
+#define QIB_7322_ahb_transaction_reg_write_not_read_LSB 0x1B
+#define QIB_7322_ahb_transaction_reg_write_not_read_MSB 0x1B
+#define QIB_7322_ahb_transaction_reg_write_not_read_RMASK 0x1
+#define QIB_7322_ahb_transaction_reg_ahb_address_LSB 0x10
+#define QIB_7322_ahb_transaction_reg_ahb_address_MSB 0x1A
+#define QIB_7322_ahb_transaction_reg_ahb_address_RMASK 0x7FF
+
+#define QIB_7322_SPC_JTAG_ACCESS_REG_OFFS 0x470
+#define QIB_7322_SPC_JTAG_ACCESS_REG_DEF 0x0000000000000001
+#define QIB_7322_SPC_JTAG_ACCESS_REG_SPC_JTAG_ACCESS_EN_LSB 0xA
+#define QIB_7322_SPC_JTAG_ACCESS_REG_SPC_JTAG_ACCESS_EN_MSB 0xA
+#define QIB_7322_SPC_JTAG_ACCESS_REG_SPC_JTAG_ACCESS_EN_RMASK 0x1
+#define QIB_7322_SPC_JTAG_ACCESS_REG_bist_en_LSB 0x5
+#define QIB_7322_SPC_JTAG_ACCESS_REG_bist_en_MSB 0x9
+#define QIB_7322_SPC_JTAG_ACCESS_REG_bist_en_RMASK 0x1F
+#define QIB_7322_SPC_JTAG_ACCESS_REG_opcode_LSB 0x3
+#define QIB_7322_SPC_JTAG_ACCESS_REG_opcode_MSB 0x4
+#define QIB_7322_SPC_JTAG_ACCESS_REG_opcode_RMASK 0x3
+#define QIB_7322_SPC_JTAG_ACCESS_REG_tdi_LSB 0x2
+#define QIB_7322_SPC_JTAG_ACCESS_REG_tdi_MSB 0x2
+#define QIB_7322_SPC_JTAG_ACCESS_REG_tdi_RMASK 0x1
+#define QIB_7322_SPC_JTAG_ACCESS_REG_tdo_LSB 0x1
+#define QIB_7322_SPC_JTAG_ACCESS_REG_tdo_MSB 0x1
+#define QIB_7322_SPC_JTAG_ACCESS_REG_tdo_RMASK 0x1
+#define QIB_7322_SPC_JTAG_ACCESS_REG_rdy_LSB 0x0
+#define QIB_7322_SPC_JTAG_ACCESS_REG_rdy_MSB 0x0
+#define QIB_7322_SPC_JTAG_ACCESS_REG_rdy_RMASK 0x1
+
+#define QIB_7322_SendCheckMask0_OFFS 0x4C0
+#define QIB_7322_SendCheckMask0_DEF 0x0000000000000000
+#define QIB_7322_SendCheckMask0_SendCheckMask_63_32_LSB 0x0
+#define QIB_7322_SendCheckMask0_SendCheckMask_63_32_MSB 0x3F
+#define QIB_7322_SendCheckMask0_SendCheckMask_63_32_RMASK 0x0
+
+#define QIB_7322_SendGRHCheckMask0_OFFS 0x4E0
+#define QIB_7322_SendGRHCheckMask0_DEF 0x0000000000000000
+#define QIB_7322_SendGRHCheckMask0_SendGRHCheckMask_63_32_LSB 0x0
+#define QIB_7322_SendGRHCheckMask0_SendGRHCheckMask_63_32_MSB 0x3F
+#define QIB_7322_SendGRHCheckMask0_SendGRHCheckMask_63_32_RMASK 0x0
+
+#define QIB_7322_SendIBPacketMask0_OFFS 0x500
+#define QIB_7322_SendIBPacketMask0_DEF 0x0000000000000000
+#define QIB_7322_SendIBPacketMask0_SendIBPacketMask_63_32_LSB 0x0
+#define QIB_7322_SendIBPacketMask0_SendIBPacketMask_63_32_MSB 0x3F
+#define QIB_7322_SendIBPacketMask0_SendIBPacketMask_63_32_RMASK 0x0
+
+#define QIB_7322_IntRedirect0_OFFS 0x540
+#define QIB_7322_IntRedirect0_DEF 0x0000000000000000
+#define QIB_7322_IntRedirect0_vec11_LSB 0x37
+#define QIB_7322_IntRedirect0_vec11_MSB 0x3B
+#define QIB_7322_IntRedirect0_vec11_RMASK 0x1F
+#define QIB_7322_IntRedirect0_vec10_LSB 0x32
+#define QIB_7322_IntRedirect0_vec10_MSB 0x36
+#define QIB_7322_IntRedirect0_vec10_RMASK 0x1F
+#define QIB_7322_IntRedirect0_vec9_LSB 0x2D
+#define QIB_7322_IntRedirect0_vec9_MSB 0x31
+#define QIB_7322_IntRedirect0_vec9_RMASK 0x1F
+#define QIB_7322_IntRedirect0_vec8_LSB 0x28
+#define QIB_7322_IntRedirect0_vec8_MSB 0x2C
+#define QIB_7322_IntRedirect0_vec8_RMASK 0x1F
+#define QIB_7322_IntRedirect0_vec7_LSB 0x23
+#define QIB_7322_IntRedirect0_vec7_MSB 0x27
+#define QIB_7322_IntRedirect0_vec7_RMASK 0x1F
+#define QIB_7322_IntRedirect0_vec6_LSB 0x1E
+#define QIB_7322_IntRedirect0_vec6_MSB 0x22
+#define QIB_7322_IntRedirect0_vec6_RMASK 0x1F
+#define QIB_7322_IntRedirect0_vec5_LSB 0x19
+#define QIB_7322_IntRedirect0_vec5_MSB 0x1D
+#define QIB_7322_IntRedirect0_vec5_RMASK 0x1F
+#define QIB_7322_IntRedirect0_vec4_LSB 0x14
+#define QIB_7322_IntRedirect0_vec4_MSB 0x18
+#define QIB_7322_IntRedirect0_vec4_RMASK 0x1F
+#define QIB_7322_IntRedirect0_vec3_LSB 0xF
+#define QIB_7322_IntRedirect0_vec3_MSB 0x13
+#define QIB_7322_IntRedirect0_vec3_RMASK 0x1F
+#define QIB_7322_IntRedirect0_vec2_LSB 0xA
+#define QIB_7322_IntRedirect0_vec2_MSB 0xE
+#define QIB_7322_IntRedirect0_vec2_RMASK 0x1F
+#define QIB_7322_IntRedirect0_vec1_LSB 0x5
+#define QIB_7322_IntRedirect0_vec1_MSB 0x9
+#define QIB_7322_IntRedirect0_vec1_RMASK 0x1F
+#define QIB_7322_IntRedirect0_vec0_LSB 0x0
+#define QIB_7322_IntRedirect0_vec0_MSB 0x4
+#define QIB_7322_IntRedirect0_vec0_RMASK 0x1F
+
+#define QIB_7322_Int_Granted_OFFS 0x570
+#define QIB_7322_Int_Granted_DEF 0x0000000000000000
+
+#define QIB_7322_vec_clr_without_int_OFFS 0x578
+#define QIB_7322_vec_clr_without_int_DEF 0x0000000000000000
+
+#define QIB_7322_DCACtrlA_OFFS 0x580
+#define QIB_7322_DCACtrlA_DEF 0x0000000000000000
+#define QIB_7322_DCACtrlA_SendDMAHead1DCAEnable_LSB 0x4
+#define QIB_7322_DCACtrlA_SendDMAHead1DCAEnable_MSB 0x4
+#define QIB_7322_DCACtrlA_SendDMAHead1DCAEnable_RMASK 0x1
+#define QIB_7322_DCACtrlA_SendDMAHead0DCAEnable_LSB 0x3
+#define QIB_7322_DCACtrlA_SendDMAHead0DCAEnable_MSB 0x3
+#define QIB_7322_DCACtrlA_SendDMAHead0DCAEnable_RMASK 0x1
+#define QIB_7322_DCACtrlA_RcvTailUpdDCAEnable_LSB 0x2
+#define QIB_7322_DCACtrlA_RcvTailUpdDCAEnable_MSB 0x2
+#define QIB_7322_DCACtrlA_RcvTailUpdDCAEnable_RMASK 0x1
+#define QIB_7322_DCACtrlA_EagerDCAEnable_LSB 0x1
+#define QIB_7322_DCACtrlA_EagerDCAEnable_MSB 0x1
+#define QIB_7322_DCACtrlA_EagerDCAEnable_RMASK 0x1
+#define QIB_7322_DCACtrlA_RcvHdrqDCAEnable_LSB 0x0
+#define QIB_7322_DCACtrlA_RcvHdrqDCAEnable_MSB 0x0
+#define QIB_7322_DCACtrlA_RcvHdrqDCAEnable_RMASK 0x1
+
+#define QIB_7322_DCACtrlB_OFFS 0x588
+#define QIB_7322_DCACtrlB_DEF 0x0000000000000000
+#define QIB_7322_DCACtrlB_RcvHdrq3DCAXfrCnt_LSB 0x36
+#define QIB_7322_DCACtrlB_RcvHdrq3DCAXfrCnt_MSB 0x3B
+#define QIB_7322_DCACtrlB_RcvHdrq3DCAXfrCnt_RMASK 0x3F
+#define QIB_7322_DCACtrlB_RcvHdrq3DCAOPH_LSB 0x2E
+#define QIB_7322_DCACtrlB_RcvHdrq3DCAOPH_MSB 0x35
+#define QIB_7322_DCACtrlB_RcvHdrq3DCAOPH_RMASK 0xFF
+#define QIB_7322_DCACtrlB_RcvHdrq2DCAXfrCnt_LSB 0x28
+#define QIB_7322_DCACtrlB_RcvHdrq2DCAXfrCnt_MSB 0x2D
+#define QIB_7322_DCACtrlB_RcvHdrq2DCAXfrCnt_RMASK 0x3F
+#define QIB_7322_DCACtrlB_RcvHdrq2DCAOPH_LSB 0x20
+#define QIB_7322_DCACtrlB_RcvHdrq2DCAOPH_MSB 0x27
+#define QIB_7322_DCACtrlB_RcvHdrq2DCAOPH_RMASK 0xFF
+#define QIB_7322_DCACtrlB_RcvHdrq1DCAXfrCnt_LSB 0x16
+#define QIB_7322_DCACtrlB_RcvHdrq1DCAXfrCnt_MSB 0x1B
+#define QIB_7322_DCACtrlB_RcvHdrq1DCAXfrCnt_RMASK 0x3F
+#define QIB_7322_DCACtrlB_RcvHdrq1DCAOPH_LSB 0xE
+#define QIB_7322_DCACtrlB_RcvHdrq1DCAOPH_MSB 0x15
+#define QIB_7322_DCACtrlB_RcvHdrq1DCAOPH_RMASK 0xFF
+#define QIB_7322_DCACtrlB_RcvHdrq0DCAXfrCnt_LSB 0x8
+#define QIB_7322_DCACtrlB_RcvHdrq0DCAXfrCnt_MSB 0xD
+#define QIB_7322_DCACtrlB_RcvHdrq0DCAXfrCnt_RMASK 0x3F
+#define QIB_7322_DCACtrlB_RcvHdrq0DCAOPH_LSB 0x0
+#define QIB_7322_DCACtrlB_RcvHdrq0DCAOPH_MSB 0x7
+#define QIB_7322_DCACtrlB_RcvHdrq0DCAOPH_RMASK 0xFF
+
+#define QIB_7322_DCACtrlC_OFFS 0x590
+#define QIB_7322_DCACtrlC_DEF 0x0000000000000000
+#define QIB_7322_DCACtrlC_RcvHdrq7DCAXfrCnt_LSB 0x36
+#define QIB_7322_DCACtrlC_RcvHdrq7DCAXfrCnt_MSB 0x3B
+#define QIB_7322_DCACtrlC_RcvHdrq7DCAXfrCnt_RMASK 0x3F
+#define QIB_7322_DCACtrlC_RcvHdrq7DCAOPH_LSB 0x2E
+#define QIB_7322_DCACtrlC_RcvHdrq7DCAOPH_MSB 0x35
+#define QIB_7322_DCACtrlC_RcvHdrq7DCAOPH_RMASK 0xFF
+#define QIB_7322_DCACtrlC_RcvHdrq6DCAXfrCnt_LSB 0x28
+#define QIB_7322_DCACtrlC_RcvHdrq6DCAXfrCnt_MSB 0x2D
+#define QIB_7322_DCACtrlC_RcvHdrq6DCAXfrCnt_RMASK 0x3F
+#define QIB_7322_DCACtrlC_RcvHdrq6DCAOPH_LSB 0x20
+#define QIB_7322_DCACtrlC_RcvHdrq6DCAOPH_MSB 0x27
+#define QIB_7322_DCACtrlC_RcvHdrq6DCAOPH_RMASK 0xFF
+#define QIB_7322_DCACtrlC_RcvHdrq5DCAXfrCnt_LSB 0x16
+#define QIB_7322_DCACtrlC_RcvHdrq5DCAXfrCnt_MSB 0x1B
+#define QIB_7322_DCACtrlC_RcvHdrq5DCAXfrCnt_RMASK 0x3F
+#define QIB_7322_DCACtrlC_RcvHdrq5DCAOPH_LSB 0xE
+#define QIB_7322_DCACtrlC_RcvHdrq5DCAOPH_MSB 0x15
+#define QIB_7322_DCACtrlC_RcvHdrq5DCAOPH_RMASK 0xFF
+#define QIB_7322_DCACtrlC_RcvHdrq4DCAXfrCnt_LSB 0x8
+#define QIB_7322_DCACtrlC_RcvHdrq4DCAXfrCnt_MSB 0xD
+#define QIB_7322_DCACtrlC_RcvHdrq4DCAXfrCnt_RMASK 0x3F
+#define QIB_7322_DCACtrlC_RcvHdrq4DCAOPH_LSB 0x0
+#define QIB_7322_DCACtrlC_RcvHdrq4DCAOPH_MSB 0x7
+#define QIB_7322_DCACtrlC_RcvHdrq4DCAOPH_RMASK 0xFF
+
+#define QIB_7322_DCACtrlD_OFFS 0x598
+#define QIB_7322_DCACtrlD_DEF 0x0000000000000000
+#define QIB_7322_DCACtrlD_RcvHdrq11DCAXfrCnt_LSB 0x36
+#define QIB_7322_DCACtrlD_RcvHdrq11DCAXfrCnt_MSB 0x3B
+#define QIB_7322_DCACtrlD_RcvHdrq11DCAXfrCnt_RMASK 0x3F
+#define QIB_7322_DCACtrlD_RcvHdrq11DCAOPH_LSB 0x2E
+#define QIB_7322_DCACtrlD_RcvHdrq11DCAOPH_MSB 0x35
+#define QIB_7322_DCACtrlD_RcvHdrq11DCAOPH_RMASK 0xFF
+#define QIB_7322_DCACtrlD_RcvHdrq10DCAXfrCnt_LSB 0x28
+#define QIB_7322_DCACtrlD_RcvHdrq10DCAXfrCnt_MSB 0x2D
+#define QIB_7322_DCACtrlD_RcvHdrq10DCAXfrCnt_RMASK 0x3F
+#define QIB_7322_DCACtrlD_RcvHdrq10DCAOPH_LSB 0x20
+#define QIB_7322_DCACtrlD_RcvHdrq10DCAOPH_MSB 0x27
+#define QIB_7322_DCACtrlD_RcvHdrq10DCAOPH_RMASK 0xFF
+#define QIB_7322_DCACtrlD_RcvHdrq9DCAXfrCnt_LSB 0x16
+#define QIB_7322_DCACtrlD_RcvHdrq9DCAXfrCnt_MSB 0x1B
+#define QIB_7322_DCACtrlD_RcvHdrq9DCAXfrCnt_RMASK 0x3F
+#define QIB_7322_DCACtrlD_RcvHdrq9DCAOPH_LSB 0xE
+#define QIB_7322_DCACtrlD_RcvHdrq9DCAOPH_MSB 0x15
+#define QIB_7322_DCACtrlD_RcvHdrq9DCAOPH_RMASK 0xFF
+#define QIB_7322_DCACtrlD_RcvHdrq8DCAXfrCnt_LSB 0x8
+#define QIB_7322_DCACtrlD_RcvHdrq8DCAXfrCnt_MSB 0xD
+#define QIB_7322_DCACtrlD_RcvHdrq8DCAXfrCnt_RMASK 0x3F
+#define QIB_7322_DCACtrlD_RcvHdrq8DCAOPH_LSB 0x0
+#define QIB_7322_DCACtrlD_RcvHdrq8DCAOPH_MSB 0x7
+#define QIB_7322_DCACtrlD_RcvHdrq8DCAOPH_RMASK 0xFF
+
+#define QIB_7322_DCACtrlE_OFFS 0x5A0
+#define QIB_7322_DCACtrlE_DEF 0x0000000000000000
+#define QIB_7322_DCACtrlE_RcvHdrq15DCAXfrCnt_LSB 0x36
+#define QIB_7322_DCACtrlE_RcvHdrq15DCAXfrCnt_MSB 0x3B
+#define QIB_7322_DCACtrlE_RcvHdrq15DCAXfrCnt_RMASK 0x3F
+#define QIB_7322_DCACtrlE_RcvHdrq15DCAOPH_LSB 0x2E
+#define QIB_7322_DCACtrlE_RcvHdrq15DCAOPH_MSB 0x35
+#define QIB_7322_DCACtrlE_RcvHdrq15DCAOPH_RMASK 0xFF
+#define QIB_7322_DCACtrlE_RcvHdrq14DCAXfrCnt_LSB 0x28
+#define QIB_7322_DCACtrlE_RcvHdrq14DCAXfrCnt_MSB 0x2D
+#define QIB_7322_DCACtrlE_RcvHdrq14DCAXfrCnt_RMASK 0x3F
+#define QIB_7322_DCACtrlE_RcvHdrq14DCAOPH_LSB 0x20
+#define QIB_7322_DCACtrlE_RcvHdrq14DCAOPH_MSB 0x27
+#define QIB_7322_DCACtrlE_RcvHdrq14DCAOPH_RMASK 0xFF
+#define QIB_7322_DCACtrlE_RcvHdrq13DCAXfrCnt_LSB 0x16
+#define QIB_7322_DCACtrlE_RcvHdrq13DCAXfrCnt_MSB 0x1B
+#define QIB_7322_DCACtrlE_RcvHdrq13DCAXfrCnt_RMASK 0x3F
+#define QIB_7322_DCACtrlE_RcvHdrq13DCAOPH_LSB 0xE
+#define QIB_7322_DCACtrlE_RcvHdrq13DCAOPH_MSB 0x15
+#define QIB_7322_DCACtrlE_RcvHdrq13DCAOPH_RMASK 0xFF
+#define QIB_7322_DCACtrlE_RcvHdrq12DCAXfrCnt_LSB 0x8
+#define QIB_7322_DCACtrlE_RcvHdrq12DCAXfrCnt_MSB 0xD
+#define QIB_7322_DCACtrlE_RcvHdrq12DCAXfrCnt_RMASK 0x3F
+#define QIB_7322_DCACtrlE_RcvHdrq12DCAOPH_LSB 0x0
+#define QIB_7322_DCACtrlE_RcvHdrq12DCAOPH_MSB 0x7
+#define QIB_7322_DCACtrlE_RcvHdrq12DCAOPH_RMASK 0xFF
+
+#define QIB_7322_DCACtrlF_OFFS 0x5A8
+#define QIB_7322_DCACtrlF_DEF 0x0000000000000000
+#define QIB_7322_DCACtrlF_SendDma1DCAOPH_LSB 0x28
+#define QIB_7322_DCACtrlF_SendDma1DCAOPH_MSB 0x2F
+#define QIB_7322_DCACtrlF_SendDma1DCAOPH_RMASK 0xFF
+#define QIB_7322_DCACtrlF_SendDma0DCAOPH_LSB 0x20
+#define QIB_7322_DCACtrlF_SendDma0DCAOPH_MSB 0x27
+#define QIB_7322_DCACtrlF_SendDma0DCAOPH_RMASK 0xFF
+#define QIB_7322_DCACtrlF_RcvHdrq17DCAXfrCnt_LSB 0x16
+#define QIB_7322_DCACtrlF_RcvHdrq17DCAXfrCnt_MSB 0x1B
+#define QIB_7322_DCACtrlF_RcvHdrq17DCAXfrCnt_RMASK 0x3F
+#define QIB_7322_DCACtrlF_RcvHdrq17DCAOPH_LSB 0xE
+#define QIB_7322_DCACtrlF_RcvHdrq17DCAOPH_MSB 0x15
+#define QIB_7322_DCACtrlF_RcvHdrq17DCAOPH_RMASK 0xFF
+#define QIB_7322_DCACtrlF_RcvHdrq16DCAXfrCnt_LSB 0x8
+#define QIB_7322_DCACtrlF_RcvHdrq16DCAXfrCnt_MSB 0xD
+#define QIB_7322_DCACtrlF_RcvHdrq16DCAXfrCnt_RMASK 0x3F
+#define QIB_7322_DCACtrlF_RcvHdrq16DCAOPH_LSB 0x0
+#define QIB_7322_DCACtrlF_RcvHdrq16DCAOPH_MSB 0x7
+#define QIB_7322_DCACtrlF_RcvHdrq16DCAOPH_RMASK 0xFF
+
+#define QIB_7322_RcvAvailTimeOut0_OFFS 0xC00
+#define QIB_7322_RcvAvailTimeOut0_DEF 0x0000000000000000
+#define QIB_7322_RcvAvailTimeOut0_RcvAvailTOCount_LSB 0x10
+#define QIB_7322_RcvAvailTimeOut0_RcvAvailTOCount_MSB 0x1F
+#define QIB_7322_RcvAvailTimeOut0_RcvAvailTOCount_RMASK 0xFFFF
+#define QIB_7322_RcvAvailTimeOut0_RcvAvailTOReload_LSB 0x0
+#define QIB_7322_RcvAvailTimeOut0_RcvAvailTOReload_MSB 0xF
+#define QIB_7322_RcvAvailTimeOut0_RcvAvailTOReload_RMASK 0xFFFF
+
+#define QIB_7322_CntrRegBase_0_OFFS 0x1028
+#define QIB_7322_CntrRegBase_0_DEF 0x0000000000012000
+
+#define QIB_7322_ErrMask_0_OFFS 0x1080
+#define QIB_7322_ErrMask_0_DEF 0x0000000000000000
+#define QIB_7322_ErrMask_0_IBStatusChangedMask_LSB 0x3A
+#define QIB_7322_ErrMask_0_IBStatusChangedMask_MSB 0x3A
+#define QIB_7322_ErrMask_0_IBStatusChangedMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_SHeadersErrMask_LSB 0x39
+#define QIB_7322_ErrMask_0_SHeadersErrMask_MSB 0x39
+#define QIB_7322_ErrMask_0_SHeadersErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_VL15BufMisuseErrMask_LSB 0x36
+#define QIB_7322_ErrMask_0_VL15BufMisuseErrMask_MSB 0x36
+#define QIB_7322_ErrMask_0_VL15BufMisuseErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_SDmaHaltErrMask_LSB 0x31
+#define QIB_7322_ErrMask_0_SDmaHaltErrMask_MSB 0x31
+#define QIB_7322_ErrMask_0_SDmaHaltErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_SDmaDescAddrMisalignErrMask_LSB 0x30
+#define QIB_7322_ErrMask_0_SDmaDescAddrMisalignErrMask_MSB 0x30
+#define QIB_7322_ErrMask_0_SDmaDescAddrMisalignErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_SDmaUnexpDataErrMask_LSB 0x2F
+#define QIB_7322_ErrMask_0_SDmaUnexpDataErrMask_MSB 0x2F
+#define QIB_7322_ErrMask_0_SDmaUnexpDataErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_SDmaMissingDwErrMask_LSB 0x2E
+#define QIB_7322_ErrMask_0_SDmaMissingDwErrMask_MSB 0x2E
+#define QIB_7322_ErrMask_0_SDmaMissingDwErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_SDmaDwEnErrMask_LSB 0x2D
+#define QIB_7322_ErrMask_0_SDmaDwEnErrMask_MSB 0x2D
+#define QIB_7322_ErrMask_0_SDmaDwEnErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_SDmaRpyTagErrMask_LSB 0x2C
+#define QIB_7322_ErrMask_0_SDmaRpyTagErrMask_MSB 0x2C
+#define QIB_7322_ErrMask_0_SDmaRpyTagErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_SDma1stDescErrMask_LSB 0x2B
+#define QIB_7322_ErrMask_0_SDma1stDescErrMask_MSB 0x2B
+#define QIB_7322_ErrMask_0_SDma1stDescErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_SDmaBaseErrMask_LSB 0x2A
+#define QIB_7322_ErrMask_0_SDmaBaseErrMask_MSB 0x2A
+#define QIB_7322_ErrMask_0_SDmaBaseErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_SDmaTailOutOfBoundErrMask_LSB 0x29
+#define QIB_7322_ErrMask_0_SDmaTailOutOfBoundErrMask_MSB 0x29
+#define QIB_7322_ErrMask_0_SDmaTailOutOfBoundErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_SDmaOutOfBoundErrMask_LSB 0x28
+#define QIB_7322_ErrMask_0_SDmaOutOfBoundErrMask_MSB 0x28
+#define QIB_7322_ErrMask_0_SDmaOutOfBoundErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_SDmaGenMismatchErrMask_LSB 0x27
+#define QIB_7322_ErrMask_0_SDmaGenMismatchErrMask_MSB 0x27
+#define QIB_7322_ErrMask_0_SDmaGenMismatchErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_SendBufMisuseErrMask_LSB 0x26
+#define QIB_7322_ErrMask_0_SendBufMisuseErrMask_MSB 0x26
+#define QIB_7322_ErrMask_0_SendBufMisuseErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_SendUnsupportedVLErrMask_LSB 0x25
+#define QIB_7322_ErrMask_0_SendUnsupportedVLErrMask_MSB 0x25
+#define QIB_7322_ErrMask_0_SendUnsupportedVLErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_SendUnexpectedPktNumErrMask_LSB 0x24
+#define QIB_7322_ErrMask_0_SendUnexpectedPktNumErrMask_MSB 0x24
+#define QIB_7322_ErrMask_0_SendUnexpectedPktNumErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_SendDroppedDataPktErrMask_LSB 0x22
+#define QIB_7322_ErrMask_0_SendDroppedDataPktErrMask_MSB 0x22
+#define QIB_7322_ErrMask_0_SendDroppedDataPktErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_SendDroppedSmpPktErrMask_LSB 0x21
+#define QIB_7322_ErrMask_0_SendDroppedSmpPktErrMask_MSB 0x21
+#define QIB_7322_ErrMask_0_SendDroppedSmpPktErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_SendPktLenErrMask_LSB 0x20
+#define QIB_7322_ErrMask_0_SendPktLenErrMask_MSB 0x20
+#define QIB_7322_ErrMask_0_SendPktLenErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_SendUnderRunErrMask_LSB 0x1F
+#define QIB_7322_ErrMask_0_SendUnderRunErrMask_MSB 0x1F
+#define QIB_7322_ErrMask_0_SendUnderRunErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_SendMaxPktLenErrMask_LSB 0x1E
+#define QIB_7322_ErrMask_0_SendMaxPktLenErrMask_MSB 0x1E
+#define QIB_7322_ErrMask_0_SendMaxPktLenErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_SendMinPktLenErrMask_LSB 0x1D
+#define QIB_7322_ErrMask_0_SendMinPktLenErrMask_MSB 0x1D
+#define QIB_7322_ErrMask_0_SendMinPktLenErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_RcvIBLostLinkErrMask_LSB 0x11
+#define QIB_7322_ErrMask_0_RcvIBLostLinkErrMask_MSB 0x11
+#define QIB_7322_ErrMask_0_RcvIBLostLinkErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_RcvHdrErrMask_LSB 0x10
+#define QIB_7322_ErrMask_0_RcvHdrErrMask_MSB 0x10
+#define QIB_7322_ErrMask_0_RcvHdrErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_RcvHdrLenErrMask_LSB 0xF
+#define QIB_7322_ErrMask_0_RcvHdrLenErrMask_MSB 0xF
+#define QIB_7322_ErrMask_0_RcvHdrLenErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_RcvBadTidErrMask_LSB 0xE
+#define QIB_7322_ErrMask_0_RcvBadTidErrMask_MSB 0xE
+#define QIB_7322_ErrMask_0_RcvBadTidErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_RcvBadVersionErrMask_LSB 0xB
+#define QIB_7322_ErrMask_0_RcvBadVersionErrMask_MSB 0xB
+#define QIB_7322_ErrMask_0_RcvBadVersionErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_RcvIBFlowErrMask_LSB 0xA
+#define QIB_7322_ErrMask_0_RcvIBFlowErrMask_MSB 0xA
+#define QIB_7322_ErrMask_0_RcvIBFlowErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_RcvEBPErrMask_LSB 0x9
+#define QIB_7322_ErrMask_0_RcvEBPErrMask_MSB 0x9
+#define QIB_7322_ErrMask_0_RcvEBPErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_RcvUnsupportedVLErrMask_LSB 0x8
+#define QIB_7322_ErrMask_0_RcvUnsupportedVLErrMask_MSB 0x8
+#define QIB_7322_ErrMask_0_RcvUnsupportedVLErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_RcvUnexpectedCharErrMask_LSB 0x7
+#define QIB_7322_ErrMask_0_RcvUnexpectedCharErrMask_MSB 0x7
+#define QIB_7322_ErrMask_0_RcvUnexpectedCharErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_RcvShortPktLenErrMask_LSB 0x6
+#define QIB_7322_ErrMask_0_RcvShortPktLenErrMask_MSB 0x6
+#define QIB_7322_ErrMask_0_RcvShortPktLenErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_RcvLongPktLenErrMask_LSB 0x5
+#define QIB_7322_ErrMask_0_RcvLongPktLenErrMask_MSB 0x5
+#define QIB_7322_ErrMask_0_RcvLongPktLenErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_RcvMaxPktLenErrMask_LSB 0x4
+#define QIB_7322_ErrMask_0_RcvMaxPktLenErrMask_MSB 0x4
+#define QIB_7322_ErrMask_0_RcvMaxPktLenErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_RcvMinPktLenErrMask_LSB 0x3
+#define QIB_7322_ErrMask_0_RcvMinPktLenErrMask_MSB 0x3
+#define QIB_7322_ErrMask_0_RcvMinPktLenErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_RcvICRCErrMask_LSB 0x2
+#define QIB_7322_ErrMask_0_RcvICRCErrMask_MSB 0x2
+#define QIB_7322_ErrMask_0_RcvICRCErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_RcvVCRCErrMask_LSB 0x1
+#define QIB_7322_ErrMask_0_RcvVCRCErrMask_MSB 0x1
+#define QIB_7322_ErrMask_0_RcvVCRCErrMask_RMASK 0x1
+#define QIB_7322_ErrMask_0_RcvFormatErrMask_LSB 0x0
+#define QIB_7322_ErrMask_0_RcvFormatErrMask_MSB 0x0
+#define QIB_7322_ErrMask_0_RcvFormatErrMask_RMASK 0x1
+
+#define QIB_7322_ErrStatus_0_OFFS 0x1088
+#define QIB_7322_ErrStatus_0_DEF 0x0000000000000000
+#define QIB_7322_ErrStatus_0_IBStatusChanged_LSB 0x3A
+#define QIB_7322_ErrStatus_0_IBStatusChanged_MSB 0x3A
+#define QIB_7322_ErrStatus_0_IBStatusChanged_RMASK 0x1
+#define QIB_7322_ErrStatus_0_SHeadersErr_LSB 0x39
+#define QIB_7322_ErrStatus_0_SHeadersErr_MSB 0x39
+#define QIB_7322_ErrStatus_0_SHeadersErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_VL15BufMisuseErr_LSB 0x36
+#define QIB_7322_ErrStatus_0_VL15BufMisuseErr_MSB 0x36
+#define QIB_7322_ErrStatus_0_VL15BufMisuseErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_SDmaHaltErr_LSB 0x31
+#define QIB_7322_ErrStatus_0_SDmaHaltErr_MSB 0x31
+#define QIB_7322_ErrStatus_0_SDmaHaltErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_SDmaDescAddrMisalignErr_LSB 0x30
+#define QIB_7322_ErrStatus_0_SDmaDescAddrMisalignErr_MSB 0x30
+#define QIB_7322_ErrStatus_0_SDmaDescAddrMisalignErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_SDmaUnexpDataErr_LSB 0x2F
+#define QIB_7322_ErrStatus_0_SDmaUnexpDataErr_MSB 0x2F
+#define QIB_7322_ErrStatus_0_SDmaUnexpDataErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_SDmaMissingDwErr_LSB 0x2E
+#define QIB_7322_ErrStatus_0_SDmaMissingDwErr_MSB 0x2E
+#define QIB_7322_ErrStatus_0_SDmaMissingDwErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_SDmaDwEnErr_LSB 0x2D
+#define QIB_7322_ErrStatus_0_SDmaDwEnErr_MSB 0x2D
+#define QIB_7322_ErrStatus_0_SDmaDwEnErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_SDmaRpyTagErr_LSB 0x2C
+#define QIB_7322_ErrStatus_0_SDmaRpyTagErr_MSB 0x2C
+#define QIB_7322_ErrStatus_0_SDmaRpyTagErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_SDma1stDescErr_LSB 0x2B
+#define QIB_7322_ErrStatus_0_SDma1stDescErr_MSB 0x2B
+#define QIB_7322_ErrStatus_0_SDma1stDescErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_SDmaBaseErr_LSB 0x2A
+#define QIB_7322_ErrStatus_0_SDmaBaseErr_MSB 0x2A
+#define QIB_7322_ErrStatus_0_SDmaBaseErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_SDmaTailOutOfBoundErr_LSB 0x29
+#define QIB_7322_ErrStatus_0_SDmaTailOutOfBoundErr_MSB 0x29
+#define QIB_7322_ErrStatus_0_SDmaTailOutOfBoundErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_SDmaOutOfBoundErr_LSB 0x28
+#define QIB_7322_ErrStatus_0_SDmaOutOfBoundErr_MSB 0x28
+#define QIB_7322_ErrStatus_0_SDmaOutOfBoundErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_SDmaGenMismatchErr_LSB 0x27
+#define QIB_7322_ErrStatus_0_SDmaGenMismatchErr_MSB 0x27
+#define QIB_7322_ErrStatus_0_SDmaGenMismatchErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_SendBufMisuseErr_LSB 0x26
+#define QIB_7322_ErrStatus_0_SendBufMisuseErr_MSB 0x26
+#define QIB_7322_ErrStatus_0_SendBufMisuseErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_SendUnsupportedVLErr_LSB 0x25
+#define QIB_7322_ErrStatus_0_SendUnsupportedVLErr_MSB 0x25
+#define QIB_7322_ErrStatus_0_SendUnsupportedVLErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_SendUnexpectedPktNumErr_LSB 0x24
+#define QIB_7322_ErrStatus_0_SendUnexpectedPktNumErr_MSB 0x24
+#define QIB_7322_ErrStatus_0_SendUnexpectedPktNumErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_SendDroppedDataPktErr_LSB 0x22
+#define QIB_7322_ErrStatus_0_SendDroppedDataPktErr_MSB 0x22
+#define QIB_7322_ErrStatus_0_SendDroppedDataPktErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_SendDroppedSmpPktErr_LSB 0x21
+#define QIB_7322_ErrStatus_0_SendDroppedSmpPktErr_MSB 0x21
+#define QIB_7322_ErrStatus_0_SendDroppedSmpPktErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_SendPktLenErr_LSB 0x20
+#define QIB_7322_ErrStatus_0_SendPktLenErr_MSB 0x20
+#define QIB_7322_ErrStatus_0_SendPktLenErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_SendUnderRunErr_LSB 0x1F
+#define QIB_7322_ErrStatus_0_SendUnderRunErr_MSB 0x1F
+#define QIB_7322_ErrStatus_0_SendUnderRunErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_SendMaxPktLenErr_LSB 0x1E
+#define QIB_7322_ErrStatus_0_SendMaxPktLenErr_MSB 0x1E
+#define QIB_7322_ErrStatus_0_SendMaxPktLenErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_SendMinPktLenErr_LSB 0x1D
+#define QIB_7322_ErrStatus_0_SendMinPktLenErr_MSB 0x1D
+#define QIB_7322_ErrStatus_0_SendMinPktLenErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_RcvIBLostLinkErr_LSB 0x11
+#define QIB_7322_ErrStatus_0_RcvIBLostLinkErr_MSB 0x11
+#define QIB_7322_ErrStatus_0_RcvIBLostLinkErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_RcvHdrErr_LSB 0x10
+#define QIB_7322_ErrStatus_0_RcvHdrErr_MSB 0x10
+#define QIB_7322_ErrStatus_0_RcvHdrErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_RcvHdrLenErr_LSB 0xF
+#define QIB_7322_ErrStatus_0_RcvHdrLenErr_MSB 0xF
+#define QIB_7322_ErrStatus_0_RcvHdrLenErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_RcvBadTidErr_LSB 0xE
+#define QIB_7322_ErrStatus_0_RcvBadTidErr_MSB 0xE
+#define QIB_7322_ErrStatus_0_RcvBadTidErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_RcvBadVersionErr_LSB 0xB
+#define QIB_7322_ErrStatus_0_RcvBadVersionErr_MSB 0xB
+#define QIB_7322_ErrStatus_0_RcvBadVersionErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_RcvIBFlowErr_LSB 0xA
+#define QIB_7322_ErrStatus_0_RcvIBFlowErr_MSB 0xA
+#define QIB_7322_ErrStatus_0_RcvIBFlowErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_RcvEBPErr_LSB 0x9
+#define QIB_7322_ErrStatus_0_RcvEBPErr_MSB 0x9
+#define QIB_7322_ErrStatus_0_RcvEBPErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_RcvUnsupportedVLErr_LSB 0x8
+#define QIB_7322_ErrStatus_0_RcvUnsupportedVLErr_MSB 0x8
+#define QIB_7322_ErrStatus_0_RcvUnsupportedVLErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_RcvUnexpectedCharErr_LSB 0x7
+#define QIB_7322_ErrStatus_0_RcvUnexpectedCharErr_MSB 0x7
+#define QIB_7322_ErrStatus_0_RcvUnexpectedCharErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_RcvShortPktLenErr_LSB 0x6
+#define QIB_7322_ErrStatus_0_RcvShortPktLenErr_MSB 0x6
+#define QIB_7322_ErrStatus_0_RcvShortPktLenErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_RcvLongPktLenErr_LSB 0x5
+#define QIB_7322_ErrStatus_0_RcvLongPktLenErr_MSB 0x5
+#define QIB_7322_ErrStatus_0_RcvLongPktLenErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_RcvMaxPktLenErr_LSB 0x4
+#define QIB_7322_ErrStatus_0_RcvMaxPktLenErr_MSB 0x4
+#define QIB_7322_ErrStatus_0_RcvMaxPktLenErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_RcvMinPktLenErr_LSB 0x3
+#define QIB_7322_ErrStatus_0_RcvMinPktLenErr_MSB 0x3
+#define QIB_7322_ErrStatus_0_RcvMinPktLenErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_RcvICRCErr_LSB 0x2
+#define QIB_7322_ErrStatus_0_RcvICRCErr_MSB 0x2
+#define QIB_7322_ErrStatus_0_RcvICRCErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_RcvVCRCErr_LSB 0x1
+#define QIB_7322_ErrStatus_0_RcvVCRCErr_MSB 0x1
+#define QIB_7322_ErrStatus_0_RcvVCRCErr_RMASK 0x1
+#define QIB_7322_ErrStatus_0_RcvFormatErr_LSB 0x0
+#define QIB_7322_ErrStatus_0_RcvFormatErr_MSB 0x0
+#define QIB_7322_ErrStatus_0_RcvFormatErr_RMASK 0x1
+
+#define QIB_7322_ErrClear_0_OFFS 0x1090
+#define QIB_7322_ErrClear_0_DEF 0x0000000000000000
+#define QIB_7322_ErrClear_0_IBStatusChangedClear_LSB 0x3A
+#define QIB_7322_ErrClear_0_IBStatusChangedClear_MSB 0x3A
+#define QIB_7322_ErrClear_0_IBStatusChangedClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_SHeadersErrClear_LSB 0x39
+#define QIB_7322_ErrClear_0_SHeadersErrClear_MSB 0x39
+#define QIB_7322_ErrClear_0_SHeadersErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_VL15BufMisuseErrClear_LSB 0x36
+#define QIB_7322_ErrClear_0_VL15BufMisuseErrClear_MSB 0x36
+#define QIB_7322_ErrClear_0_VL15BufMisuseErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_SDmaHaltErrClear_LSB 0x31
+#define QIB_7322_ErrClear_0_SDmaHaltErrClear_MSB 0x31
+#define QIB_7322_ErrClear_0_SDmaHaltErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_SDmaDescAddrMisalignErrClear_LSB 0x30
+#define QIB_7322_ErrClear_0_SDmaDescAddrMisalignErrClear_MSB 0x30
+#define QIB_7322_ErrClear_0_SDmaDescAddrMisalignErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_SDmaUnexpDataErrClear_LSB 0x2F
+#define QIB_7322_ErrClear_0_SDmaUnexpDataErrClear_MSB 0x2F
+#define QIB_7322_ErrClear_0_SDmaUnexpDataErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_SDmaMissingDwErrClear_LSB 0x2E
+#define QIB_7322_ErrClear_0_SDmaMissingDwErrClear_MSB 0x2E
+#define QIB_7322_ErrClear_0_SDmaMissingDwErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_SDmaDwEnErrClear_LSB 0x2D
+#define QIB_7322_ErrClear_0_SDmaDwEnErrClear_MSB 0x2D
+#define QIB_7322_ErrClear_0_SDmaDwEnErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_SDmaRpyTagErrClear_LSB 0x2C
+#define QIB_7322_ErrClear_0_SDmaRpyTagErrClear_MSB 0x2C
+#define QIB_7322_ErrClear_0_SDmaRpyTagErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_SDma1stDescErrClear_LSB 0x2B
+#define QIB_7322_ErrClear_0_SDma1stDescErrClear_MSB 0x2B
+#define QIB_7322_ErrClear_0_SDma1stDescErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_SDmaBaseErrClear_LSB 0x2A
+#define QIB_7322_ErrClear_0_SDmaBaseErrClear_MSB 0x2A
+#define QIB_7322_ErrClear_0_SDmaBaseErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_SDmaTailOutOfBoundErrClear_LSB 0x29
+#define QIB_7322_ErrClear_0_SDmaTailOutOfBoundErrClear_MSB 0x29
+#define QIB_7322_ErrClear_0_SDmaTailOutOfBoundErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_SDmaOutOfBoundErrClear_LSB 0x28
+#define QIB_7322_ErrClear_0_SDmaOutOfBoundErrClear_MSB 0x28
+#define QIB_7322_ErrClear_0_SDmaOutOfBoundErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_SDmaGenMismatchErrClear_LSB 0x27
+#define QIB_7322_ErrClear_0_SDmaGenMismatchErrClear_MSB 0x27
+#define QIB_7322_ErrClear_0_SDmaGenMismatchErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_SendBufMisuseErrClear_LSB 0x26
+#define QIB_7322_ErrClear_0_SendBufMisuseErrClear_MSB 0x26
+#define QIB_7322_ErrClear_0_SendBufMisuseErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_SendUnsupportedVLErrClear_LSB 0x25
+#define QIB_7322_ErrClear_0_SendUnsupportedVLErrClear_MSB 0x25
+#define QIB_7322_ErrClear_0_SendUnsupportedVLErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_SendUnexpectedPktNumErrClear_LSB 0x24
+#define QIB_7322_ErrClear_0_SendUnexpectedPktNumErrClear_MSB 0x24
+#define QIB_7322_ErrClear_0_SendUnexpectedPktNumErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_SendDroppedDataPktErrClear_LSB 0x22
+#define QIB_7322_ErrClear_0_SendDroppedDataPktErrClear_MSB 0x22
+#define QIB_7322_ErrClear_0_SendDroppedDataPktErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_SendDroppedSmpPktErrClear_LSB 0x21
+#define QIB_7322_ErrClear_0_SendDroppedSmpPktErrClear_MSB 0x21
+#define QIB_7322_ErrClear_0_SendDroppedSmpPktErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_SendPktLenErrClear_LSB 0x20
+#define QIB_7322_ErrClear_0_SendPktLenErrClear_MSB 0x20
+#define QIB_7322_ErrClear_0_SendPktLenErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_SendUnderRunErrClear_LSB 0x1F
+#define QIB_7322_ErrClear_0_SendUnderRunErrClear_MSB 0x1F
+#define QIB_7322_ErrClear_0_SendUnderRunErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_SendMaxPktLenErrClear_LSB 0x1E
+#define QIB_7322_ErrClear_0_SendMaxPktLenErrClear_MSB 0x1E
+#define QIB_7322_ErrClear_0_SendMaxPktLenErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_SendMinPktLenErrClear_LSB 0x1D
+#define QIB_7322_ErrClear_0_SendMinPktLenErrClear_MSB 0x1D
+#define QIB_7322_ErrClear_0_SendMinPktLenErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_RcvIBLostLinkErrClear_LSB 0x11
+#define QIB_7322_ErrClear_0_RcvIBLostLinkErrClear_MSB 0x11
+#define QIB_7322_ErrClear_0_RcvIBLostLinkErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_RcvHdrErrClear_LSB 0x10
+#define QIB_7322_ErrClear_0_RcvHdrErrClear_MSB 0x10
+#define QIB_7322_ErrClear_0_RcvHdrErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_RcvHdrLenErrClear_LSB 0xF
+#define QIB_7322_ErrClear_0_RcvHdrLenErrClear_MSB 0xF
+#define QIB_7322_ErrClear_0_RcvHdrLenErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_RcvBadTidErrClear_LSB 0xE
+#define QIB_7322_ErrClear_0_RcvBadTidErrClear_MSB 0xE
+#define QIB_7322_ErrClear_0_RcvBadTidErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_RcvBadVersionErrClear_LSB 0xB
+#define QIB_7322_ErrClear_0_RcvBadVersionErrClear_MSB 0xB
+#define QIB_7322_ErrClear_0_RcvBadVersionErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_RcvIBFlowErrClear_LSB 0xA
+#define QIB_7322_ErrClear_0_RcvIBFlowErrClear_MSB 0xA
+#define QIB_7322_ErrClear_0_RcvIBFlowErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_RcvEBPErrClear_LSB 0x9
+#define QIB_7322_ErrClear_0_RcvEBPErrClear_MSB 0x9
+#define QIB_7322_ErrClear_0_RcvEBPErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_RcvUnsupportedVLErrClear_LSB 0x8
+#define QIB_7322_ErrClear_0_RcvUnsupportedVLErrClear_MSB 0x8
+#define QIB_7322_ErrClear_0_RcvUnsupportedVLErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_RcvUnexpectedCharErrClear_LSB 0x7
+#define QIB_7322_ErrClear_0_RcvUnexpectedCharErrClear_MSB 0x7
+#define QIB_7322_ErrClear_0_RcvUnexpectedCharErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_RcvShortPktLenErrClear_LSB 0x6
+#define QIB_7322_ErrClear_0_RcvShortPktLenErrClear_MSB 0x6
+#define QIB_7322_ErrClear_0_RcvShortPktLenErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_RcvLongPktLenErrClear_LSB 0x5
+#define QIB_7322_ErrClear_0_RcvLongPktLenErrClear_MSB 0x5
+#define QIB_7322_ErrClear_0_RcvLongPktLenErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_RcvMaxPktLenErrClear_LSB 0x4
+#define QIB_7322_ErrClear_0_RcvMaxPktLenErrClear_MSB 0x4
+#define QIB_7322_ErrClear_0_RcvMaxPktLenErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_RcvMinPktLenErrClear_LSB 0x3
+#define QIB_7322_ErrClear_0_RcvMinPktLenErrClear_MSB 0x3
+#define QIB_7322_ErrClear_0_RcvMinPktLenErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_RcvICRCErrClear_LSB 0x2
+#define QIB_7322_ErrClear_0_RcvICRCErrClear_MSB 0x2
+#define QIB_7322_ErrClear_0_RcvICRCErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_RcvVCRCErrClear_LSB 0x1
+#define QIB_7322_ErrClear_0_RcvVCRCErrClear_MSB 0x1
+#define QIB_7322_ErrClear_0_RcvVCRCErrClear_RMASK 0x1
+#define QIB_7322_ErrClear_0_RcvFormatErrClear_LSB 0x0
+#define QIB_7322_ErrClear_0_RcvFormatErrClear_MSB 0x0
+#define QIB_7322_ErrClear_0_RcvFormatErrClear_RMASK 0x1
+
+#define QIB_7322_TXEStatus_0_OFFS 0x10B8
+#define QIB_7322_TXEStatus_0_DEF 0x0000000XC00080FF
+#define QIB_7322_TXEStatus_0_TXE_IBC_Idle_LSB 0x1F
+#define QIB_7322_TXEStatus_0_TXE_IBC_Idle_MSB 0x1F
+#define QIB_7322_TXEStatus_0_TXE_IBC_Idle_RMASK 0x1
+#define QIB_7322_TXEStatus_0_RmFifoEmpty_LSB 0x1E
+#define QIB_7322_TXEStatus_0_RmFifoEmpty_MSB 0x1E
+#define QIB_7322_TXEStatus_0_RmFifoEmpty_RMASK 0x1
+#define QIB_7322_TXEStatus_0_LaFifoEmpty_VL15_LSB 0xF
+#define QIB_7322_TXEStatus_0_LaFifoEmpty_VL15_MSB 0xF
+#define QIB_7322_TXEStatus_0_LaFifoEmpty_VL15_RMASK 0x1
+#define QIB_7322_TXEStatus_0_LaFifoEmpty_VL7_LSB 0x7
+#define QIB_7322_TXEStatus_0_LaFifoEmpty_VL7_MSB 0x7
+#define QIB_7322_TXEStatus_0_LaFifoEmpty_VL7_RMASK 0x1
+#define QIB_7322_TXEStatus_0_LaFifoEmpty_VL6_LSB 0x6
+#define QIB_7322_TXEStatus_0_LaFifoEmpty_VL6_MSB 0x6
+#define QIB_7322_TXEStatus_0_LaFifoEmpty_VL6_RMASK 0x1
+#define QIB_7322_TXEStatus_0_LaFifoEmpty_VL5_LSB 0x5
+#define QIB_7322_TXEStatus_0_LaFifoEmpty_VL5_MSB 0x5
+#define QIB_7322_TXEStatus_0_LaFifoEmpty_VL5_RMASK 0x1
+#define QIB_7322_TXEStatus_0_LaFifoEmpty_VL4_LSB 0x4
+#define QIB_7322_TXEStatus_0_LaFifoEmpty_VL4_MSB 0x4
+#define QIB_7322_TXEStatus_0_LaFifoEmpty_VL4_RMASK 0x1
+#define QIB_7322_TXEStatus_0_LaFifoEmpty_VL3_LSB 0x3
+#define QIB_7322_TXEStatus_0_LaFifoEmpty_VL3_MSB 0x3
+#define QIB_7322_TXEStatus_0_LaFifoEmpty_VL3_RMASK 0x1
+#define QIB_7322_TXEStatus_0_LaFifoEmpty_VL2_LSB 0x2
+#define QIB_7322_TXEStatus_0_LaFifoEmpty_VL2_MSB 0x2
+#define QIB_7322_TXEStatus_0_LaFifoEmpty_VL2_RMASK 0x1
+#define QIB_7322_TXEStatus_0_LaFifoEmpty_VL1_LSB 0x1
+#define QIB_7322_TXEStatus_0_LaFifoEmpty_VL1_MSB 0x1
+#define QIB_7322_TXEStatus_0_LaFifoEmpty_VL1_RMASK 0x1
+#define QIB_7322_TXEStatus_0_LaFifoEmpty_VL0_LSB 0x0
+#define QIB_7322_TXEStatus_0_LaFifoEmpty_VL0_MSB 0x0
+#define QIB_7322_TXEStatus_0_LaFifoEmpty_VL0_RMASK 0x1
+
+#define QIB_7322_RcvCtrl_0_OFFS 0x1100
+#define QIB_7322_RcvCtrl_0_DEF 0x0000000000000000
+#define QIB_7322_RcvCtrl_0_RcvResetCredit_LSB 0x2A
+#define QIB_7322_RcvCtrl_0_RcvResetCredit_MSB 0x2A
+#define QIB_7322_RcvCtrl_0_RcvResetCredit_RMASK 0x1
+#define QIB_7322_RcvCtrl_0_RcvPartitionKeyDisable_LSB 0x29
+#define QIB_7322_RcvCtrl_0_RcvPartitionKeyDisable_MSB 0x29
+#define QIB_7322_RcvCtrl_0_RcvPartitionKeyDisable_RMASK 0x1
+#define QIB_7322_RcvCtrl_0_RcvQPMapEnable_LSB 0x28
+#define QIB_7322_RcvCtrl_0_RcvQPMapEnable_MSB 0x28
+#define QIB_7322_RcvCtrl_0_RcvQPMapEnable_RMASK 0x1
+#define QIB_7322_RcvCtrl_0_RcvIBPortEnable_LSB 0x27
+#define QIB_7322_RcvCtrl_0_RcvIBPortEnable_MSB 0x27
+#define QIB_7322_RcvCtrl_0_RcvIBPortEnable_RMASK 0x1
+#define QIB_7322_RcvCtrl_0_ContextEnableUser_LSB 0x2
+#define QIB_7322_RcvCtrl_0_ContextEnableUser_MSB 0x11
+#define QIB_7322_RcvCtrl_0_ContextEnableUser_RMASK 0xFFFF
+#define QIB_7322_RcvCtrl_0_ContextEnableKernel_LSB 0x0
+#define QIB_7322_RcvCtrl_0_ContextEnableKernel_MSB 0x0
+#define QIB_7322_RcvCtrl_0_ContextEnableKernel_RMASK 0x1
+
+#define QIB_7322_RcvBTHQP_0_OFFS 0x1108
+#define QIB_7322_RcvBTHQP_0_DEF 0x0000000000000000
+#define QIB_7322_RcvBTHQP_0_RcvBTHQP_LSB 0x0
+#define QIB_7322_RcvBTHQP_0_RcvBTHQP_MSB 0x17
+#define QIB_7322_RcvBTHQP_0_RcvBTHQP_RMASK 0xFFFFFF
+
+#define QIB_7322_RcvQPMapTableA_0_OFFS 0x1110
+#define QIB_7322_RcvQPMapTableA_0_DEF 0x0000000000000000
+#define QIB_7322_RcvQPMapTableA_0_RcvQPMapContext5_LSB 0x19
+#define QIB_7322_RcvQPMapTableA_0_RcvQPMapContext5_MSB 0x1D
+#define QIB_7322_RcvQPMapTableA_0_RcvQPMapContext5_RMASK 0x1F
+#define QIB_7322_RcvQPMapTableA_0_RcvQPMapContext4_LSB 0x14
+#define QIB_7322_RcvQPMapTableA_0_RcvQPMapContext4_MSB 0x18
+#define QIB_7322_RcvQPMapTableA_0_RcvQPMapContext4_RMASK 0x1F
+#define QIB_7322_RcvQPMapTableA_0_RcvQPMapContext3_LSB 0xF
+#define QIB_7322_RcvQPMapTableA_0_RcvQPMapContext3_MSB 0x13
+#define QIB_7322_RcvQPMapTableA_0_RcvQPMapContext3_RMASK 0x1F
+#define QIB_7322_RcvQPMapTableA_0_RcvQPMapContext2_LSB 0xA
+#define QIB_7322_RcvQPMapTableA_0_RcvQPMapContext2_MSB 0xE
+#define QIB_7322_RcvQPMapTableA_0_RcvQPMapContext2_RMASK 0x1F
+#define QIB_7322_RcvQPMapTableA_0_RcvQPMapContext1_LSB 0x5
+#define QIB_7322_RcvQPMapTableA_0_RcvQPMapContext1_MSB 0x9
+#define QIB_7322_RcvQPMapTableA_0_RcvQPMapContext1_RMASK 0x1F
+#define QIB_7322_RcvQPMapTableA_0_RcvQPMapContext0_LSB 0x0
+#define QIB_7322_RcvQPMapTableA_0_RcvQPMapContext0_MSB 0x4
+#define QIB_7322_RcvQPMapTableA_0_RcvQPMapContext0_RMASK 0x1F
+
+#define QIB_7322_RcvQPMapTableB_0_OFFS 0x1118
+#define QIB_7322_RcvQPMapTableB_0_DEF 0x0000000000000000
+#define QIB_7322_RcvQPMapTableB_0_RcvQPMapContext11_LSB 0x19
+#define QIB_7322_RcvQPMapTableB_0_RcvQPMapContext11_MSB 0x1D
+#define QIB_7322_RcvQPMapTableB_0_RcvQPMapContext11_RMASK 0x1F
+#define QIB_7322_RcvQPMapTableB_0_RcvQPMapContext10_LSB 0x14
+#define QIB_7322_RcvQPMapTableB_0_RcvQPMapContext10_MSB 0x18
+#define QIB_7322_RcvQPMapTableB_0_RcvQPMapContext10_RMASK 0x1F
+#define QIB_7322_RcvQPMapTableB_0_RcvQPMapContext9_LSB 0xF
+#define QIB_7322_RcvQPMapTableB_0_RcvQPMapContext9_MSB 0x13
+#define QIB_7322_RcvQPMapTableB_0_RcvQPMapContext9_RMASK 0x1F
+#define QIB_7322_RcvQPMapTableB_0_RcvQPMapContext8_LSB 0xA
+#define QIB_7322_RcvQPMapTableB_0_RcvQPMapContext8_MSB 0xE
+#define QIB_7322_RcvQPMapTableB_0_RcvQPMapContext8_RMASK 0x1F
+#define QIB_7322_RcvQPMapTableB_0_RcvQPMapContext7_LSB 0x5
+#define QIB_7322_RcvQPMapTableB_0_RcvQPMapContext7_MSB 0x9
+#define QIB_7322_RcvQPMapTableB_0_RcvQPMapContext7_RMASK 0x1F
+#define QIB_7322_RcvQPMapTableB_0_RcvQPMapContext6_LSB 0x0
+#define QIB_7322_RcvQPMapTableB_0_RcvQPMapContext6_MSB 0x4
+#define QIB_7322_RcvQPMapTableB_0_RcvQPMapContext6_RMASK 0x1F
+
+#define QIB_7322_RcvQPMapTableC_0_OFFS 0x1120
+#define QIB_7322_RcvQPMapTableC_0_DEF 0x0000000000000000
+#define QIB_7322_RcvQPMapTableC_0_RcvQPMapContext17_LSB 0x19
+#define QIB_7322_RcvQPMapTableC_0_RcvQPMapContext17_MSB 0x1D
+#define QIB_7322_RcvQPMapTableC_0_RcvQPMapContext17_RMASK 0x1F
+#define QIB_7322_RcvQPMapTableC_0_RcvQPMapContext16_LSB 0x14
+#define QIB_7322_RcvQPMapTableC_0_RcvQPMapContext16_MSB 0x18
+#define QIB_7322_RcvQPMapTableC_0_RcvQPMapContext16_RMASK 0x1F
+#define QIB_7322_RcvQPMapTableC_0_RcvQPMapContext15_LSB 0xF
+#define QIB_7322_RcvQPMapTableC_0_RcvQPMapContext15_MSB 0x13
+#define QIB_7322_RcvQPMapTableC_0_RcvQPMapContext15_RMASK 0x1F
+#define QIB_7322_RcvQPMapTableC_0_RcvQPMapContext14_LSB 0xA
+#define QIB_7322_RcvQPMapTableC_0_RcvQPMapContext14_MSB 0xE
+#define QIB_7322_RcvQPMapTableC_0_RcvQPMapContext14_RMASK 0x1F
+#define QIB_7322_RcvQPMapTableC_0_RcvQPMapContext13_LSB 0x5
+#define QIB_7322_RcvQPMapTableC_0_RcvQPMapContext13_MSB 0x9
+#define QIB_7322_RcvQPMapTableC_0_RcvQPMapContext13_RMASK 0x1F
+#define QIB_7322_RcvQPMapTableC_0_RcvQPMapContext12_LSB 0x0
+#define QIB_7322_RcvQPMapTableC_0_RcvQPMapContext12_MSB 0x4
+#define QIB_7322_RcvQPMapTableC_0_RcvQPMapContext12_RMASK 0x1F
+
+#define QIB_7322_RcvQPMapTableD_0_OFFS 0x1128
+#define QIB_7322_RcvQPMapTableD_0_DEF 0x0000000000000000
+#define QIB_7322_RcvQPMapTableD_0_RcvQPMapContext23_LSB 0x19
+#define QIB_7322_RcvQPMapTableD_0_RcvQPMapContext23_MSB 0x1D
+#define QIB_7322_RcvQPMapTableD_0_RcvQPMapContext23_RMASK 0x1F
+#define QIB_7322_RcvQPMapTableD_0_RcvQPMapContext22_LSB 0x14
+#define QIB_7322_RcvQPMapTableD_0_RcvQPMapContext22_MSB 0x18
+#define QIB_7322_RcvQPMapTableD_0_RcvQPMapContext22_RMASK 0x1F
+#define QIB_7322_RcvQPMapTableD_0_RcvQPMapContext21_LSB 0xF
+#define QIB_7322_RcvQPMapTableD_0_RcvQPMapContext21_MSB 0x13
+#define QIB_7322_RcvQPMapTableD_0_RcvQPMapContext21_RMASK 0x1F
+#define QIB_7322_RcvQPMapTableD_0_RcvQPMapContext20_LSB 0xA
+#define QIB_7322_RcvQPMapTableD_0_RcvQPMapContext20_MSB 0xE
+#define QIB_7322_RcvQPMapTableD_0_RcvQPMapContext20_RMASK 0x1F
+#define QIB_7322_RcvQPMapTableD_0_RcvQPMapContext19_LSB 0x5
+#define QIB_7322_RcvQPMapTableD_0_RcvQPMapContext19_MSB 0x9
+#define QIB_7322_RcvQPMapTableD_0_RcvQPMapContext19_RMASK 0x1F
+#define QIB_7322_RcvQPMapTableD_0_RcvQPMapContext18_LSB 0x0
+#define QIB_7322_RcvQPMapTableD_0_RcvQPMapContext18_MSB 0x4
+#define QIB_7322_RcvQPMapTableD_0_RcvQPMapContext18_RMASK 0x1F
+
+#define QIB_7322_RcvQPMapTableE_0_OFFS 0x1130
+#define QIB_7322_RcvQPMapTableE_0_DEF 0x0000000000000000
+#define QIB_7322_RcvQPMapTableE_0_RcvQPMapContext29_LSB 0x19
+#define QIB_7322_RcvQPMapTableE_0_RcvQPMapContext29_MSB 0x1D
+#define QIB_7322_RcvQPMapTableE_0_RcvQPMapContext29_RMASK 0x1F
+#define QIB_7322_RcvQPMapTableE_0_RcvQPMapContext28_LSB 0x14
+#define QIB_7322_RcvQPMapTableE_0_RcvQPMapContext28_MSB 0x18
+#define QIB_7322_RcvQPMapTableE_0_RcvQPMapContext28_RMASK 0x1F
+#define QIB_7322_RcvQPMapTableE_0_RcvQPMapContext27_LSB 0xF
+#define QIB_7322_RcvQPMapTableE_0_RcvQPMapContext27_MSB 0x13
+#define QIB_7322_RcvQPMapTableE_0_RcvQPMapContext27_RMASK 0x1F
+#define QIB_7322_RcvQPMapTableE_0_RcvQPMapContext26_LSB 0xA
+#define QIB_7322_RcvQPMapTableE_0_RcvQPMapContext26_MSB 0xE
+#define QIB_7322_RcvQPMapTableE_0_RcvQPMapContext26_RMASK 0x1F
+#define QIB_7322_RcvQPMapTableE_0_RcvQPMapContext25_LSB 0x5
+#define QIB_7322_RcvQPMapTableE_0_RcvQPMapContext25_MSB 0x9
+#define QIB_7322_RcvQPMapTableE_0_RcvQPMapContext25_RMASK 0x1F
+#define QIB_7322_RcvQPMapTableE_0_RcvQPMapContext24_LSB 0x0
+#define QIB_7322_RcvQPMapTableE_0_RcvQPMapContext24_MSB 0x4
+#define QIB_7322_RcvQPMapTableE_0_RcvQPMapContext24_RMASK 0x1F
+
+#define QIB_7322_RcvQPMapTableF_0_OFFS 0x1138
+#define QIB_7322_RcvQPMapTableF_0_DEF 0x0000000000000000
+#define QIB_7322_RcvQPMapTableF_0_RcvQPMapContext31_LSB 0x5
+#define QIB_7322_RcvQPMapTableF_0_RcvQPMapContext31_MSB 0x9
+#define QIB_7322_RcvQPMapTableF_0_RcvQPMapContext31_RMASK 0x1F
+#define QIB_7322_RcvQPMapTableF_0_RcvQPMapContext30_LSB 0x0
+#define QIB_7322_RcvQPMapTableF_0_RcvQPMapContext30_MSB 0x4
+#define QIB_7322_RcvQPMapTableF_0_RcvQPMapContext30_RMASK 0x1F
+
+#define QIB_7322_PSStat_0_OFFS 0x1140
+#define QIB_7322_PSStat_0_DEF 0x0000000000000000
+
+#define QIB_7322_PSStart_0_OFFS 0x1148
+#define QIB_7322_PSStart_0_DEF 0x0000000000000000
+
+#define QIB_7322_PSInterval_0_OFFS 0x1150
+#define QIB_7322_PSInterval_0_DEF 0x0000000000000000
+
+#define QIB_7322_RcvStatus_0_OFFS 0x1160
+#define QIB_7322_RcvStatus_0_DEF 0x0000000000000000
+#define QIB_7322_RcvStatus_0_DmaeqBlockingContext_LSB 0x1
+#define QIB_7322_RcvStatus_0_DmaeqBlockingContext_MSB 0x5
+#define QIB_7322_RcvStatus_0_DmaeqBlockingContext_RMASK 0x1F
+#define QIB_7322_RcvStatus_0_RxPktInProgress_LSB 0x0
+#define QIB_7322_RcvStatus_0_RxPktInProgress_MSB 0x0
+#define QIB_7322_RcvStatus_0_RxPktInProgress_RMASK 0x1
+
+#define QIB_7322_RcvPartitionKey_0_OFFS 0x1168
+#define QIB_7322_RcvPartitionKey_0_DEF 0x0000000000000000
+
+#define QIB_7322_RcvQPMulticastContext_0_OFFS 0x1170
+#define QIB_7322_RcvQPMulticastContext_0_DEF 0x0000000000000000
+#define QIB_7322_RcvQPMulticastContext_0_RcvQpMcContext_LSB 0x0
+#define QIB_7322_RcvQPMulticastContext_0_RcvQpMcContext_MSB 0x4
+#define QIB_7322_RcvQPMulticastContext_0_RcvQpMcContext_RMASK 0x1F
+
+#define QIB_7322_RcvPktLEDCnt_0_OFFS 0x1178
+#define QIB_7322_RcvPktLEDCnt_0_DEF 0x0000000000000000
+#define QIB_7322_RcvPktLEDCnt_0_ONperiod_LSB 0x20
+#define QIB_7322_RcvPktLEDCnt_0_ONperiod_MSB 0x3F
+#define QIB_7322_RcvPktLEDCnt_0_ONperiod_RMASK 0xFFFFFFFF
+#define QIB_7322_RcvPktLEDCnt_0_OFFperiod_LSB 0x0
+#define QIB_7322_RcvPktLEDCnt_0_OFFperiod_MSB 0x1F
+#define QIB_7322_RcvPktLEDCnt_0_OFFperiod_RMASK 0xFFFFFFFF
+
+#define QIB_7322_SendDmaIdleCnt_0_OFFS 0x1180
+#define QIB_7322_SendDmaIdleCnt_0_DEF 0x0000000000000000
+#define QIB_7322_SendDmaIdleCnt_0_SendDmaIdleCnt_LSB 0x0
+#define QIB_7322_SendDmaIdleCnt_0_SendDmaIdleCnt_MSB 0xF
+#define QIB_7322_SendDmaIdleCnt_0_SendDmaIdleCnt_RMASK 0xFFFF
+
+#define QIB_7322_SendDmaReloadCnt_0_OFFS 0x1188
+#define QIB_7322_SendDmaReloadCnt_0_DEF 0x0000000000000000
+#define QIB_7322_SendDmaReloadCnt_0_SendDmaReloadCnt_LSB 0x0
+#define QIB_7322_SendDmaReloadCnt_0_SendDmaReloadCnt_MSB 0xF
+#define QIB_7322_SendDmaReloadCnt_0_SendDmaReloadCnt_RMASK 0xFFFF
+
+#define QIB_7322_SendDmaDescCnt_0_OFFS 0x1190
+#define QIB_7322_SendDmaDescCnt_0_DEF 0x0000000000000000
+#define QIB_7322_SendDmaDescCnt_0_SendDmaDescCnt_LSB 0x0
+#define QIB_7322_SendDmaDescCnt_0_SendDmaDescCnt_MSB 0xF
+#define QIB_7322_SendDmaDescCnt_0_SendDmaDescCnt_RMASK 0xFFFF
+
+#define QIB_7322_SendCtrl_0_OFFS 0x11C0
+#define QIB_7322_SendCtrl_0_DEF 0x0000000000000000
+#define QIB_7322_SendCtrl_0_IBVLArbiterEn_LSB 0xF
+#define QIB_7322_SendCtrl_0_IBVLArbiterEn_MSB 0xF
+#define QIB_7322_SendCtrl_0_IBVLArbiterEn_RMASK 0x1
+#define QIB_7322_SendCtrl_0_TxeDrainRmFifo_LSB 0xE
+#define QIB_7322_SendCtrl_0_TxeDrainRmFifo_MSB 0xE
+#define QIB_7322_SendCtrl_0_TxeDrainRmFifo_RMASK 0x1
+#define QIB_7322_SendCtrl_0_TxeDrainLaFifo_LSB 0xD
+#define QIB_7322_SendCtrl_0_TxeDrainLaFifo_MSB 0xD
+#define QIB_7322_SendCtrl_0_TxeDrainLaFifo_RMASK 0x1
+#define QIB_7322_SendCtrl_0_SDmaHalt_LSB 0xC
+#define QIB_7322_SendCtrl_0_SDmaHalt_MSB 0xC
+#define QIB_7322_SendCtrl_0_SDmaHalt_RMASK 0x1
+#define QIB_7322_SendCtrl_0_SDmaEnable_LSB 0xB
+#define QIB_7322_SendCtrl_0_SDmaEnable_MSB 0xB
+#define QIB_7322_SendCtrl_0_SDmaEnable_RMASK 0x1
+#define QIB_7322_SendCtrl_0_SDmaSingleDescriptor_LSB 0xA
+#define QIB_7322_SendCtrl_0_SDmaSingleDescriptor_MSB 0xA
+#define QIB_7322_SendCtrl_0_SDmaSingleDescriptor_RMASK 0x1
+#define QIB_7322_SendCtrl_0_SDmaIntEnable_LSB 0x9
+#define QIB_7322_SendCtrl_0_SDmaIntEnable_MSB 0x9
+#define QIB_7322_SendCtrl_0_SDmaIntEnable_RMASK 0x1
+#define QIB_7322_SendCtrl_0_SDmaCleanup_LSB 0x8
+#define QIB_7322_SendCtrl_0_SDmaCleanup_MSB 0x8
+#define QIB_7322_SendCtrl_0_SDmaCleanup_RMASK 0x1
+#define QIB_7322_SendCtrl_0_ForceCreditUpToDate_LSB 0x7
+#define QIB_7322_SendCtrl_0_ForceCreditUpToDate_MSB 0x7
+#define QIB_7322_SendCtrl_0_ForceCreditUpToDate_RMASK 0x1
+#define QIB_7322_SendCtrl_0_SendEnable_LSB 0x3
+#define QIB_7322_SendCtrl_0_SendEnable_MSB 0x3
+#define QIB_7322_SendCtrl_0_SendEnable_RMASK 0x1
+#define QIB_7322_SendCtrl_0_TxeBypassIbc_LSB 0x1
+#define QIB_7322_SendCtrl_0_TxeBypassIbc_MSB 0x1
+#define QIB_7322_SendCtrl_0_TxeBypassIbc_RMASK 0x1
+#define QIB_7322_SendCtrl_0_TxeAbortIbc_LSB 0x0
+#define QIB_7322_SendCtrl_0_TxeAbortIbc_MSB 0x0
+#define QIB_7322_SendCtrl_0_TxeAbortIbc_RMASK 0x1
+
+#define QIB_7322_SendDmaBase_0_OFFS 0x11F8
+#define QIB_7322_SendDmaBase_0_DEF 0x0000000000000000
+#define QIB_7322_SendDmaBase_0_SendDmaBase_LSB 0x0
+#define QIB_7322_SendDmaBase_0_SendDmaBase_MSB 0x2F
+#define QIB_7322_SendDmaBase_0_SendDmaBase_RMASK 0xFFFFFFFFFFFF
+
+#define QIB_7322_SendDmaLenGen_0_OFFS 0x1200
+#define QIB_7322_SendDmaLenGen_0_DEF 0x0000000000000000
+#define QIB_7322_SendDmaLenGen_0_Generation_LSB 0x10
+#define QIB_7322_SendDmaLenGen_0_Generation_MSB 0x12
+#define QIB_7322_SendDmaLenGen_0_Generation_RMASK 0x7
+#define QIB_7322_SendDmaLenGen_0_Length_LSB 0x0
+#define QIB_7322_SendDmaLenGen_0_Length_MSB 0xF
+#define QIB_7322_SendDmaLenGen_0_Length_RMASK 0xFFFF
+
+#define QIB_7322_SendDmaTail_0_OFFS 0x1208
+#define QIB_7322_SendDmaTail_0_DEF 0x0000000000000000
+#define QIB_7322_SendDmaTail_0_SendDmaTail_LSB 0x0
+#define QIB_7322_SendDmaTail_0_SendDmaTail_MSB 0xF
+#define QIB_7322_SendDmaTail_0_SendDmaTail_RMASK 0xFFFF
+
+#define QIB_7322_SendDmaHead_0_OFFS 0x1210
+#define QIB_7322_SendDmaHead_0_DEF 0x0000000000000000
+#define QIB_7322_SendDmaHead_0_InternalSendDmaHead_LSB 0x20
+#define QIB_7322_SendDmaHead_0_InternalSendDmaHead_MSB 0x2F
+#define QIB_7322_SendDmaHead_0_InternalSendDmaHead_RMASK 0xFFFF
+#define QIB_7322_SendDmaHead_0_SendDmaHead_LSB 0x0
+#define QIB_7322_SendDmaHead_0_SendDmaHead_MSB 0xF
+#define QIB_7322_SendDmaHead_0_SendDmaHead_RMASK 0xFFFF
+
+#define QIB_7322_SendDmaHeadAddr_0_OFFS 0x1218
+#define QIB_7322_SendDmaHeadAddr_0_DEF 0x0000000000000000
+#define QIB_7322_SendDmaHeadAddr_0_SendDmaHeadAddr_LSB 0x0
+#define QIB_7322_SendDmaHeadAddr_0_SendDmaHeadAddr_MSB 0x2F
+#define QIB_7322_SendDmaHeadAddr_0_SendDmaHeadAddr_RMASK 0xFFFFFFFFFFFF
+
+#define QIB_7322_SendDmaBufMask0_0_OFFS 0x1220
+#define QIB_7322_SendDmaBufMask0_0_DEF 0x0000000000000000
+#define QIB_7322_SendDmaBufMask0_0_BufMask_63_0_LSB 0x0
+#define QIB_7322_SendDmaBufMask0_0_BufMask_63_0_MSB 0x3F
+#define QIB_7322_SendDmaBufMask0_0_BufMask_63_0_RMASK 0x0
+
+#define QIB_7322_SendDmaStatus_0_OFFS 0x1238
+#define QIB_7322_SendDmaStatus_0_DEF 0x0000000042000000
+#define QIB_7322_SendDmaStatus_0_ScoreBoardDrainInProg_LSB 0x3F
+#define QIB_7322_SendDmaStatus_0_ScoreBoardDrainInProg_MSB 0x3F
+#define QIB_7322_SendDmaStatus_0_ScoreBoardDrainInProg_RMASK 0x1
+#define QIB_7322_SendDmaStatus_0_HaltInProg_LSB 0x3E
+#define QIB_7322_SendDmaStatus_0_HaltInProg_MSB 0x3E
+#define QIB_7322_SendDmaStatus_0_HaltInProg_RMASK 0x1
+#define QIB_7322_SendDmaStatus_0_InternalSDmaHalt_LSB 0x3D
+#define QIB_7322_SendDmaStatus_0_InternalSDmaHalt_MSB 0x3D
+#define QIB_7322_SendDmaStatus_0_InternalSDmaHalt_RMASK 0x1
+#define QIB_7322_SendDmaStatus_0_ScbDescIndex_13_0_LSB 0x2F
+#define QIB_7322_SendDmaStatus_0_ScbDescIndex_13_0_MSB 0x3C
+#define QIB_7322_SendDmaStatus_0_ScbDescIndex_13_0_RMASK 0x3FFF
+#define QIB_7322_SendDmaStatus_0_RpyLowAddr_6_0_LSB 0x28
+#define QIB_7322_SendDmaStatus_0_RpyLowAddr_6_0_MSB 0x2E
+#define QIB_7322_SendDmaStatus_0_RpyLowAddr_6_0_RMASK 0x7F
+#define QIB_7322_SendDmaStatus_0_RpyTag_7_0_LSB 0x20
+#define QIB_7322_SendDmaStatus_0_RpyTag_7_0_MSB 0x27
+#define QIB_7322_SendDmaStatus_0_RpyTag_7_0_RMASK 0xFF
+#define QIB_7322_SendDmaStatus_0_ScbFull_LSB 0x1F
+#define QIB_7322_SendDmaStatus_0_ScbFull_MSB 0x1F
+#define QIB_7322_SendDmaStatus_0_ScbFull_RMASK 0x1
+#define QIB_7322_SendDmaStatus_0_ScbEmpty_LSB 0x1E
+#define QIB_7322_SendDmaStatus_0_ScbEmpty_MSB 0x1E
+#define QIB_7322_SendDmaStatus_0_ScbEmpty_RMASK 0x1
+#define QIB_7322_SendDmaStatus_0_ScbEntryValid_LSB 0x1D
+#define QIB_7322_SendDmaStatus_0_ScbEntryValid_MSB 0x1D
+#define QIB_7322_SendDmaStatus_0_ScbEntryValid_RMASK 0x1
+#define QIB_7322_SendDmaStatus_0_ScbFetchDescFlag_LSB 0x1C
+#define QIB_7322_SendDmaStatus_0_ScbFetchDescFlag_MSB 0x1C
+#define QIB_7322_SendDmaStatus_0_ScbFetchDescFlag_RMASK 0x1
+#define QIB_7322_SendDmaStatus_0_SplFifoReadyToGo_LSB 0x1B
+#define QIB_7322_SendDmaStatus_0_SplFifoReadyToGo_MSB 0x1B
+#define QIB_7322_SendDmaStatus_0_SplFifoReadyToGo_RMASK 0x1
+#define QIB_7322_SendDmaStatus_0_SplFifoDisarmed_LSB 0x1A
+#define QIB_7322_SendDmaStatus_0_SplFifoDisarmed_MSB 0x1A
+#define QIB_7322_SendDmaStatus_0_SplFifoDisarmed_RMASK 0x1
+#define QIB_7322_SendDmaStatus_0_SplFifoEmpty_LSB 0x19
+#define QIB_7322_SendDmaStatus_0_SplFifoEmpty_MSB 0x19
+#define QIB_7322_SendDmaStatus_0_SplFifoEmpty_RMASK 0x1
+#define QIB_7322_SendDmaStatus_0_SplFifoFull_LSB 0x18
+#define QIB_7322_SendDmaStatus_0_SplFifoFull_MSB 0x18
+#define QIB_7322_SendDmaStatus_0_SplFifoFull_RMASK 0x1
+#define QIB_7322_SendDmaStatus_0_SplFifoBufNum_LSB 0x10
+#define QIB_7322_SendDmaStatus_0_SplFifoBufNum_MSB 0x17
+#define QIB_7322_SendDmaStatus_0_SplFifoBufNum_RMASK 0xFF
+#define QIB_7322_SendDmaStatus_0_SplFifoDescIndex_LSB 0x0
+#define QIB_7322_SendDmaStatus_0_SplFifoDescIndex_MSB 0xF
+#define QIB_7322_SendDmaStatus_0_SplFifoDescIndex_RMASK 0xFFFF
+
+#define QIB_7322_SendDmaPriorityThld_0_OFFS 0x1258
+#define QIB_7322_SendDmaPriorityThld_0_DEF 0x0000000000000000
+#define QIB_7322_SendDmaPriorityThld_0_PriorityThreshold_LSB 0x0
+#define QIB_7322_SendDmaPriorityThld_0_PriorityThreshold_MSB 0x3
+#define QIB_7322_SendDmaPriorityThld_0_PriorityThreshold_RMASK 0xF
+
+#define QIB_7322_SendHdrErrSymptom_0_OFFS 0x1260
+#define QIB_7322_SendHdrErrSymptom_0_DEF 0x0000000000000000
+#define QIB_7322_SendHdrErrSymptom_0_NonKeyPacket_LSB 0x6
+#define QIB_7322_SendHdrErrSymptom_0_NonKeyPacket_MSB 0x6
+#define QIB_7322_SendHdrErrSymptom_0_NonKeyPacket_RMASK 0x1
+#define QIB_7322_SendHdrErrSymptom_0_GRHFail_LSB 0x5
+#define QIB_7322_SendHdrErrSymptom_0_GRHFail_MSB 0x5
+#define QIB_7322_SendHdrErrSymptom_0_GRHFail_RMASK 0x1
+#define QIB_7322_SendHdrErrSymptom_0_PkeyFail_LSB 0x4
+#define QIB_7322_SendHdrErrSymptom_0_PkeyFail_MSB 0x4
+#define QIB_7322_SendHdrErrSymptom_0_PkeyFail_RMASK 0x1
+#define QIB_7322_SendHdrErrSymptom_0_QPFail_LSB 0x3
+#define QIB_7322_SendHdrErrSymptom_0_QPFail_MSB 0x3
+#define QIB_7322_SendHdrErrSymptom_0_QPFail_RMASK 0x1
+#define QIB_7322_SendHdrErrSymptom_0_SLIDFail_LSB 0x2
+#define QIB_7322_SendHdrErrSymptom_0_SLIDFail_MSB 0x2
+#define QIB_7322_SendHdrErrSymptom_0_SLIDFail_RMASK 0x1
+#define QIB_7322_SendHdrErrSymptom_0_RawIPV6_LSB 0x1
+#define QIB_7322_SendHdrErrSymptom_0_RawIPV6_MSB 0x1
+#define QIB_7322_SendHdrErrSymptom_0_RawIPV6_RMASK 0x1
+#define QIB_7322_SendHdrErrSymptom_0_PacketTooSmall_LSB 0x0
+#define QIB_7322_SendHdrErrSymptom_0_PacketTooSmall_MSB 0x0
+#define QIB_7322_SendHdrErrSymptom_0_PacketTooSmall_RMASK 0x1
+
+#define QIB_7322_RxCreditVL0_0_OFFS 0x1280
+#define QIB_7322_RxCreditVL0_0_DEF 0x0000000000000000
+#define QIB_7322_RxCreditVL0_0_RxBufrConsumedVL_LSB 0x10
+#define QIB_7322_RxCreditVL0_0_RxBufrConsumedVL_MSB 0x1B
+#define QIB_7322_RxCreditVL0_0_RxBufrConsumedVL_RMASK 0xFFF
+#define QIB_7322_RxCreditVL0_0_RxMaxCreditVL_LSB 0x0
+#define QIB_7322_RxCreditVL0_0_RxMaxCreditVL_MSB 0xB
+#define QIB_7322_RxCreditVL0_0_RxMaxCreditVL_RMASK 0xFFF
+
+#define QIB_7322_SendDmaBufUsed0_0_OFFS 0x1480
+#define QIB_7322_SendDmaBufUsed0_0_DEF 0x0000000000000000
+#define QIB_7322_SendDmaBufUsed0_0_BufUsed_63_0_LSB 0x0
+#define QIB_7322_SendDmaBufUsed0_0_BufUsed_63_0_MSB 0x3F
+#define QIB_7322_SendDmaBufUsed0_0_BufUsed_63_0_RMASK 0x0
+
+#define QIB_7322_SendCheckControl_0_OFFS 0x14A8
+#define QIB_7322_SendCheckControl_0_DEF 0x0000000000000000
+#define QIB_7322_SendCheckControl_0_PKey_En_LSB 0x4
+#define QIB_7322_SendCheckControl_0_PKey_En_MSB 0x4
+#define QIB_7322_SendCheckControl_0_PKey_En_RMASK 0x1
+#define QIB_7322_SendCheckControl_0_BTHQP_En_LSB 0x3
+#define QIB_7322_SendCheckControl_0_BTHQP_En_MSB 0x3
+#define QIB_7322_SendCheckControl_0_BTHQP_En_RMASK 0x1
+#define QIB_7322_SendCheckControl_0_SLID_En_LSB 0x2
+#define QIB_7322_SendCheckControl_0_SLID_En_MSB 0x2
+#define QIB_7322_SendCheckControl_0_SLID_En_RMASK 0x1
+#define QIB_7322_SendCheckControl_0_RawIPV6_En_LSB 0x1
+#define QIB_7322_SendCheckControl_0_RawIPV6_En_MSB 0x1
+#define QIB_7322_SendCheckControl_0_RawIPV6_En_RMASK 0x1
+#define QIB_7322_SendCheckControl_0_PacketTooSmall_En_LSB 0x0
+#define QIB_7322_SendCheckControl_0_PacketTooSmall_En_MSB 0x0
+#define QIB_7322_SendCheckControl_0_PacketTooSmall_En_RMASK 0x1
+
+#define QIB_7322_SendIBSLIDMask_0_OFFS 0x14B0
+#define QIB_7322_SendIBSLIDMask_0_DEF 0x0000000000000000
+#define QIB_7322_SendIBSLIDMask_0_SendIBSLIDMask_15_0_LSB 0x0
+#define QIB_7322_SendIBSLIDMask_0_SendIBSLIDMask_15_0_MSB 0xF
+#define QIB_7322_SendIBSLIDMask_0_SendIBSLIDMask_15_0_RMASK 0xFFFF
+
+#define QIB_7322_SendIBSLIDAssign_0_OFFS 0x14B8
+#define QIB_7322_SendIBSLIDAssign_0_DEF 0x0000000000000000
+#define QIB_7322_SendIBSLIDAssign_0_SendIBSLIDAssign_15_0_LSB 0x0
+#define QIB_7322_SendIBSLIDAssign_0_SendIBSLIDAssign_15_0_MSB 0xF
+#define QIB_7322_SendIBSLIDAssign_0_SendIBSLIDAssign_15_0_RMASK 0xFFFF
+
+#define QIB_7322_IBCStatusA_0_OFFS 0x1540
+#define QIB_7322_IBCStatusA_0_DEF 0x0000000000000X02
+#define QIB_7322_IBCStatusA_0_TxCreditOk_VL7_LSB 0x27
+#define QIB_7322_IBCStatusA_0_TxCreditOk_VL7_MSB 0x27
+#define QIB_7322_IBCStatusA_0_TxCreditOk_VL7_RMASK 0x1
+#define QIB_7322_IBCStatusA_0_TxCreditOk_VL6_LSB 0x26
+#define QIB_7322_IBCStatusA_0_TxCreditOk_VL6_MSB 0x26
+#define QIB_7322_IBCStatusA_0_TxCreditOk_VL6_RMASK 0x1
+#define QIB_7322_IBCStatusA_0_TxCreditOk_VL5_LSB 0x25
+#define QIB_7322_IBCStatusA_0_TxCreditOk_VL5_MSB 0x25
+#define QIB_7322_IBCStatusA_0_TxCreditOk_VL5_RMASK 0x1
+#define QIB_7322_IBCStatusA_0_TxCreditOk_VL4_LSB 0x24
+#define QIB_7322_IBCStatusA_0_TxCreditOk_VL4_MSB 0x24
+#define QIB_7322_IBCStatusA_0_TxCreditOk_VL4_RMASK 0x1
+#define QIB_7322_IBCStatusA_0_TxCreditOk_VL3_LSB 0x23
+#define QIB_7322_IBCStatusA_0_TxCreditOk_VL3_MSB 0x23
+#define QIB_7322_IBCStatusA_0_TxCreditOk_VL3_RMASK 0x1
+#define QIB_7322_IBCStatusA_0_TxCreditOk_VL2_LSB 0x22
+#define QIB_7322_IBCStatusA_0_TxCreditOk_VL2_MSB 0x22
+#define QIB_7322_IBCStatusA_0_TxCreditOk_VL2_RMASK 0x1
+#define QIB_7322_IBCStatusA_0_TxCreditOk_VL1_LSB 0x21
+#define QIB_7322_IBCStatusA_0_TxCreditOk_VL1_MSB 0x21
+#define QIB_7322_IBCStatusA_0_TxCreditOk_VL1_RMASK 0x1
+#define QIB_7322_IBCStatusA_0_TxCreditOk_VL0_LSB 0x20
+#define QIB_7322_IBCStatusA_0_TxCreditOk_VL0_MSB 0x20
+#define QIB_7322_IBCStatusA_0_TxCreditOk_VL0_RMASK 0x1
+#define QIB_7322_IBCStatusA_0_TxReady_LSB 0x1E
+#define QIB_7322_IBCStatusA_0_TxReady_MSB 0x1E
+#define QIB_7322_IBCStatusA_0_TxReady_RMASK 0x1
+#define QIB_7322_IBCStatusA_0_LinkSpeedQDR_LSB 0x1D
+#define QIB_7322_IBCStatusA_0_LinkSpeedQDR_MSB 0x1D
+#define QIB_7322_IBCStatusA_0_LinkSpeedQDR_RMASK 0x1
+#define QIB_7322_IBCStatusA_0_ScrambleCapRemote_LSB 0xF
+#define QIB_7322_IBCStatusA_0_ScrambleCapRemote_MSB 0xF
+#define QIB_7322_IBCStatusA_0_ScrambleCapRemote_RMASK 0x1
+#define QIB_7322_IBCStatusA_0_ScrambleEn_LSB 0xE
+#define QIB_7322_IBCStatusA_0_ScrambleEn_MSB 0xE
+#define QIB_7322_IBCStatusA_0_ScrambleEn_RMASK 0x1
+#define QIB_7322_IBCStatusA_0_IBTxLaneReversed_LSB 0xD
+#define QIB_7322_IBCStatusA_0_IBTxLaneReversed_MSB 0xD
+#define QIB_7322_IBCStatusA_0_IBTxLaneReversed_RMASK 0x1
+#define QIB_7322_IBCStatusA_0_IBRxLaneReversed_LSB 0xC
+#define QIB_7322_IBCStatusA_0_IBRxLaneReversed_MSB 0xC
+#define QIB_7322_IBCStatusA_0_IBRxLaneReversed_RMASK 0x1
+#define QIB_7322_IBCStatusA_0_DDS_RXEQ_FAIL_LSB 0xA
+#define QIB_7322_IBCStatusA_0_DDS_RXEQ_FAIL_MSB 0xA
+#define QIB_7322_IBCStatusA_0_DDS_RXEQ_FAIL_RMASK 0x1
+#define QIB_7322_IBCStatusA_0_LinkWidthActive_LSB 0x9
+#define QIB_7322_IBCStatusA_0_LinkWidthActive_MSB 0x9
+#define QIB_7322_IBCStatusA_0_LinkWidthActive_RMASK 0x1
+#define QIB_7322_IBCStatusA_0_LinkSpeedActive_LSB 0x8
+#define QIB_7322_IBCStatusA_0_LinkSpeedActive_MSB 0x8
+#define QIB_7322_IBCStatusA_0_LinkSpeedActive_RMASK 0x1
+#define QIB_7322_IBCStatusA_0_LinkState_LSB 0x5
+#define QIB_7322_IBCStatusA_0_LinkState_MSB 0x7
+#define QIB_7322_IBCStatusA_0_LinkState_RMASK 0x7
+#define QIB_7322_IBCStatusA_0_LinkTrainingState_LSB 0x0
+#define QIB_7322_IBCStatusA_0_LinkTrainingState_MSB 0x4
+#define QIB_7322_IBCStatusA_0_LinkTrainingState_RMASK 0x1F
+
+#define QIB_7322_IBCStatusB_0_OFFS 0x1548
+#define QIB_7322_IBCStatusB_0_DEF 0x00000000XXXXXXXX
+#define QIB_7322_IBCStatusB_0_ibsd_adaptation_timer_debug_LSB 0x27
+#define QIB_7322_IBCStatusB_0_ibsd_adaptation_timer_debug_MSB 0x27
+#define QIB_7322_IBCStatusB_0_ibsd_adaptation_timer_debug_RMASK 0x1
+#define QIB_7322_IBCStatusB_0_ibsd_adaptation_timer_reached_threshold_LSB 0x26
+#define QIB_7322_IBCStatusB_0_ibsd_adaptation_timer_reached_threshold_MSB 0x26
+#define QIB_7322_IBCStatusB_0_ibsd_adaptation_timer_reached_threshold_RMASK 0x1
+#define QIB_7322_IBCStatusB_0_ibsd_adaptation_timer_started_LSB 0x25
+#define QIB_7322_IBCStatusB_0_ibsd_adaptation_timer_started_MSB 0x25
+#define QIB_7322_IBCStatusB_0_ibsd_adaptation_timer_started_RMASK 0x1
+#define QIB_7322_IBCStatusB_0_heartbeat_timed_out_LSB 0x24
+#define QIB_7322_IBCStatusB_0_heartbeat_timed_out_MSB 0x24
+#define QIB_7322_IBCStatusB_0_heartbeat_timed_out_RMASK 0x1
+#define QIB_7322_IBCStatusB_0_heartbeat_crosstalk_LSB 0x20
+#define QIB_7322_IBCStatusB_0_heartbeat_crosstalk_MSB 0x23
+#define QIB_7322_IBCStatusB_0_heartbeat_crosstalk_RMASK 0xF
+#define QIB_7322_IBCStatusB_0_RxEqLocalDevice_LSB 0x1E
+#define QIB_7322_IBCStatusB_0_RxEqLocalDevice_MSB 0x1F
+#define QIB_7322_IBCStatusB_0_RxEqLocalDevice_RMASK 0x3
+#define QIB_7322_IBCStatusB_0_ReqDDSLocalFromRmt_LSB 0x1A
+#define QIB_7322_IBCStatusB_0_ReqDDSLocalFromRmt_MSB 0x1D
+#define QIB_7322_IBCStatusB_0_ReqDDSLocalFromRmt_RMASK 0xF
+#define QIB_7322_IBCStatusB_0_LinkRoundTripLatency_LSB 0x0
+#define QIB_7322_IBCStatusB_0_LinkRoundTripLatency_MSB 0x19
+#define QIB_7322_IBCStatusB_0_LinkRoundTripLatency_RMASK 0x3FFFFFF
+
+#define QIB_7322_IBCCtrlA_0_OFFS 0x1560
+#define QIB_7322_IBCCtrlA_0_DEF 0x0000000000000000
+#define QIB_7322_IBCCtrlA_0_Loopback_LSB 0x3F
+#define QIB_7322_IBCCtrlA_0_Loopback_MSB 0x3F
+#define QIB_7322_IBCCtrlA_0_Loopback_RMASK 0x1
+#define QIB_7322_IBCCtrlA_0_LinkDownDefaultState_LSB 0x3E
+#define QIB_7322_IBCCtrlA_0_LinkDownDefaultState_MSB 0x3E
+#define QIB_7322_IBCCtrlA_0_LinkDownDefaultState_RMASK 0x1
+#define QIB_7322_IBCCtrlA_0_IBLinkEn_LSB 0x3D
+#define QIB_7322_IBCCtrlA_0_IBLinkEn_MSB 0x3D
+#define QIB_7322_IBCCtrlA_0_IBLinkEn_RMASK 0x1
+#define QIB_7322_IBCCtrlA_0_IBStatIntReductionEn_LSB 0x3C
+#define QIB_7322_IBCCtrlA_0_IBStatIntReductionEn_MSB 0x3C
+#define QIB_7322_IBCCtrlA_0_IBStatIntReductionEn_RMASK 0x1
+#define QIB_7322_IBCCtrlA_0_NumVLane_LSB 0x30
+#define QIB_7322_IBCCtrlA_0_NumVLane_MSB 0x32
+#define QIB_7322_IBCCtrlA_0_NumVLane_RMASK 0x7
+#define QIB_7322_IBCCtrlA_0_OverrunThreshold_LSB 0x24
+#define QIB_7322_IBCCtrlA_0_OverrunThreshold_MSB 0x27
+#define QIB_7322_IBCCtrlA_0_OverrunThreshold_RMASK 0xF
+#define QIB_7322_IBCCtrlA_0_PhyerrThreshold_LSB 0x20
+#define QIB_7322_IBCCtrlA_0_PhyerrThreshold_MSB 0x23
+#define QIB_7322_IBCCtrlA_0_PhyerrThreshold_RMASK 0xF
+#define QIB_7322_IBCCtrlA_0_MaxPktLen_LSB 0x15
+#define QIB_7322_IBCCtrlA_0_MaxPktLen_MSB 0x1F
+#define QIB_7322_IBCCtrlA_0_MaxPktLen_RMASK 0x7FF
+#define QIB_7322_IBCCtrlA_0_LinkCmd_LSB 0x13
+#define QIB_7322_IBCCtrlA_0_LinkCmd_MSB 0x14
+#define QIB_7322_IBCCtrlA_0_LinkCmd_RMASK 0x3
+#define QIB_7322_IBCCtrlA_0_LinkInitCmd_LSB 0x10
+#define QIB_7322_IBCCtrlA_0_LinkInitCmd_MSB 0x12
+#define QIB_7322_IBCCtrlA_0_LinkInitCmd_RMASK 0x7
+#define QIB_7322_IBCCtrlA_0_FlowCtrlWaterMark_LSB 0x8
+#define QIB_7322_IBCCtrlA_0_FlowCtrlWaterMark_MSB 0xF
+#define QIB_7322_IBCCtrlA_0_FlowCtrlWaterMark_RMASK 0xFF
+#define QIB_7322_IBCCtrlA_0_FlowCtrlPeriod_LSB 0x0
+#define QIB_7322_IBCCtrlA_0_FlowCtrlPeriod_MSB 0x7
+#define QIB_7322_IBCCtrlA_0_FlowCtrlPeriod_RMASK 0xFF
+
+#define QIB_7322_IBCCtrlB_0_OFFS 0x1568
+#define QIB_7322_IBCCtrlB_0_DEF 0x00000000000305FF
+#define QIB_7322_IBCCtrlB_0_IB_DLID_MASK_LSB 0x30
+#define QIB_7322_IBCCtrlB_0_IB_DLID_MASK_MSB 0x3F
+#define QIB_7322_IBCCtrlB_0_IB_DLID_MASK_RMASK 0xFFFF
+#define QIB_7322_IBCCtrlB_0_IB_DLID_LSB 0x20
+#define QIB_7322_IBCCtrlB_0_IB_DLID_MSB 0x2F
+#define QIB_7322_IBCCtrlB_0_IB_DLID_RMASK 0xFFFF
+#define QIB_7322_IBCCtrlB_0_IB_ENABLE_FILT_DPKT_LSB 0x1B
+#define QIB_7322_IBCCtrlB_0_IB_ENABLE_FILT_DPKT_MSB 0x1B
+#define QIB_7322_IBCCtrlB_0_IB_ENABLE_FILT_DPKT_RMASK 0x1
+#define QIB_7322_IBCCtrlB_0_HRTBT_REQ_LSB 0x1A
+#define QIB_7322_IBCCtrlB_0_HRTBT_REQ_MSB 0x1A
+#define QIB_7322_IBCCtrlB_0_HRTBT_REQ_RMASK 0x1
+#define QIB_7322_IBCCtrlB_0_HRTBT_PORT_LSB 0x12
+#define QIB_7322_IBCCtrlB_0_HRTBT_PORT_MSB 0x19
+#define QIB_7322_IBCCtrlB_0_HRTBT_PORT_RMASK 0xFF
+#define QIB_7322_IBCCtrlB_0_HRTBT_AUTO_LSB 0x11
+#define QIB_7322_IBCCtrlB_0_HRTBT_AUTO_MSB 0x11
+#define QIB_7322_IBCCtrlB_0_HRTBT_AUTO_RMASK 0x1
+#define QIB_7322_IBCCtrlB_0_HRTBT_ENB_LSB 0x10
+#define QIB_7322_IBCCtrlB_0_HRTBT_ENB_MSB 0x10
+#define QIB_7322_IBCCtrlB_0_HRTBT_ENB_RMASK 0x1
+#define QIB_7322_IBCCtrlB_0_SD_DDS_LSB 0xC
+#define QIB_7322_IBCCtrlB_0_SD_DDS_MSB 0xF
+#define QIB_7322_IBCCtrlB_0_SD_DDS_RMASK 0xF
+#define QIB_7322_IBCCtrlB_0_SD_DDSV_LSB 0xB
+#define QIB_7322_IBCCtrlB_0_SD_DDSV_MSB 0xB
+#define QIB_7322_IBCCtrlB_0_SD_DDSV_RMASK 0x1
+#define QIB_7322_IBCCtrlB_0_SD_ADD_ENB_LSB 0xA
+#define QIB_7322_IBCCtrlB_0_SD_ADD_ENB_MSB 0xA
+#define QIB_7322_IBCCtrlB_0_SD_ADD_ENB_RMASK 0x1
+#define QIB_7322_IBCCtrlB_0_SD_RX_EQUAL_ENABLE_LSB 0x9
+#define QIB_7322_IBCCtrlB_0_SD_RX_EQUAL_ENABLE_MSB 0x9
+#define QIB_7322_IBCCtrlB_0_SD_RX_EQUAL_ENABLE_RMASK 0x1
+#define QIB_7322_IBCCtrlB_0_IB_LANE_REV_SUPPORTED_LSB 0x8
+#define QIB_7322_IBCCtrlB_0_IB_LANE_REV_SUPPORTED_MSB 0x8
+#define QIB_7322_IBCCtrlB_0_IB_LANE_REV_SUPPORTED_RMASK 0x1
+#define QIB_7322_IBCCtrlB_0_IB_POLARITY_REV_SUPP_LSB 0x7
+#define QIB_7322_IBCCtrlB_0_IB_POLARITY_REV_SUPP_MSB 0x7
+#define QIB_7322_IBCCtrlB_0_IB_POLARITY_REV_SUPP_RMASK 0x1
+#define QIB_7322_IBCCtrlB_0_IB_NUM_CHANNELS_LSB 0x5
+#define QIB_7322_IBCCtrlB_0_IB_NUM_CHANNELS_MSB 0x6
+#define QIB_7322_IBCCtrlB_0_IB_NUM_CHANNELS_RMASK 0x3
+#define QIB_7322_IBCCtrlB_0_SD_SPEED_QDR_LSB 0x4
+#define QIB_7322_IBCCtrlB_0_SD_SPEED_QDR_MSB 0x4
+#define QIB_7322_IBCCtrlB_0_SD_SPEED_QDR_RMASK 0x1
+#define QIB_7322_IBCCtrlB_0_SD_SPEED_DDR_LSB 0x3
+#define QIB_7322_IBCCtrlB_0_SD_SPEED_DDR_MSB 0x3
+#define QIB_7322_IBCCtrlB_0_SD_SPEED_DDR_RMASK 0x1
+#define QIB_7322_IBCCtrlB_0_SD_SPEED_SDR_LSB 0x2
+#define QIB_7322_IBCCtrlB_0_SD_SPEED_SDR_MSB 0x2
+#define QIB_7322_IBCCtrlB_0_SD_SPEED_SDR_RMASK 0x1
+#define QIB_7322_IBCCtrlB_0_SD_SPEED_LSB 0x1
+#define QIB_7322_IBCCtrlB_0_SD_SPEED_MSB 0x1
+#define QIB_7322_IBCCtrlB_0_SD_SPEED_RMASK 0x1
+#define QIB_7322_IBCCtrlB_0_IB_ENHANCED_MODE_LSB 0x0
+#define QIB_7322_IBCCtrlB_0_IB_ENHANCED_MODE_MSB 0x0
+#define QIB_7322_IBCCtrlB_0_IB_ENHANCED_MODE_RMASK 0x1
+
+#define QIB_7322_IBCCtrlC_0_OFFS 0x1570
+#define QIB_7322_IBCCtrlC_0_DEF 0x0000000000000301
+#define QIB_7322_IBCCtrlC_0_IB_BACK_PORCH_LSB 0x5
+#define QIB_7322_IBCCtrlC_0_IB_BACK_PORCH_MSB 0x9
+#define QIB_7322_IBCCtrlC_0_IB_BACK_PORCH_RMASK 0x1F
+#define QIB_7322_IBCCtrlC_0_IB_FRONT_PORCH_LSB 0x0
+#define QIB_7322_IBCCtrlC_0_IB_FRONT_PORCH_MSB 0x4
+#define QIB_7322_IBCCtrlC_0_IB_FRONT_PORCH_RMASK 0x1F
+
+#define QIB_7322_HRTBT_GUID_0_OFFS 0x1588
+#define QIB_7322_HRTBT_GUID_0_DEF 0x0000000000000000
+
+#define QIB_7322_IB_SDTEST_IF_TX_0_OFFS 0x1590
+#define QIB_7322_IB_SDTEST_IF_TX_0_DEF 0x0000000000000000
+#define QIB_7322_IB_SDTEST_IF_TX_0_TS_TX_RX_CFG_LSB 0x30
+#define QIB_7322_IB_SDTEST_IF_TX_0_TS_TX_RX_CFG_MSB 0x3F
+#define QIB_7322_IB_SDTEST_IF_TX_0_TS_TX_RX_CFG_RMASK 0xFFFF
+#define QIB_7322_IB_SDTEST_IF_TX_0_TS_TX_TX_CFG_LSB 0x20
+#define QIB_7322_IB_SDTEST_IF_TX_0_TS_TX_TX_CFG_MSB 0x2F
+#define QIB_7322_IB_SDTEST_IF_TX_0_TS_TX_TX_CFG_RMASK 0xFFFF
+#define QIB_7322_IB_SDTEST_IF_TX_0_TS_TX_SPEED_LSB 0xD
+#define QIB_7322_IB_SDTEST_IF_TX_0_TS_TX_SPEED_MSB 0xF
+#define QIB_7322_IB_SDTEST_IF_TX_0_TS_TX_SPEED_RMASK 0x7
+#define QIB_7322_IB_SDTEST_IF_TX_0_TS_TX_OPCODE_LSB 0xB
+#define QIB_7322_IB_SDTEST_IF_TX_0_TS_TX_OPCODE_MSB 0xC
+#define QIB_7322_IB_SDTEST_IF_TX_0_TS_TX_OPCODE_RMASK 0x3
+#define QIB_7322_IB_SDTEST_IF_TX_0_CREDIT_CHANGE_LSB 0x4
+#define QIB_7322_IB_SDTEST_IF_TX_0_CREDIT_CHANGE_MSB 0x4
+#define QIB_7322_IB_SDTEST_IF_TX_0_CREDIT_CHANGE_RMASK 0x1
+#define QIB_7322_IB_SDTEST_IF_TX_0_VL_CAP_LSB 0x2
+#define QIB_7322_IB_SDTEST_IF_TX_0_VL_CAP_MSB 0x3
+#define QIB_7322_IB_SDTEST_IF_TX_0_VL_CAP_RMASK 0x3
+#define QIB_7322_IB_SDTEST_IF_TX_0_TS_3_TX_VALID_LSB 0x1
+#define QIB_7322_IB_SDTEST_IF_TX_0_TS_3_TX_VALID_MSB 0x1
+#define QIB_7322_IB_SDTEST_IF_TX_0_TS_3_TX_VALID_RMASK 0x1
+#define QIB_7322_IB_SDTEST_IF_TX_0_TS_T_TX_VALID_LSB 0x0
+#define QIB_7322_IB_SDTEST_IF_TX_0_TS_T_TX_VALID_MSB 0x0
+#define QIB_7322_IB_SDTEST_IF_TX_0_TS_T_TX_VALID_RMASK 0x1
+
+#define QIB_7322_IB_SDTEST_IF_RX_0_OFFS 0x1598
+#define QIB_7322_IB_SDTEST_IF_RX_0_DEF 0x0000000000000000
+#define QIB_7322_IB_SDTEST_IF_RX_0_TS_RX_RX_CFG_LSB 0x30
+#define QIB_7322_IB_SDTEST_IF_RX_0_TS_RX_RX_CFG_MSB 0x3F
+#define QIB_7322_IB_SDTEST_IF_RX_0_TS_RX_RX_CFG_RMASK 0xFFFF
+#define QIB_7322_IB_SDTEST_IF_RX_0_TS_RX_TX_CFG_LSB 0x20
+#define QIB_7322_IB_SDTEST_IF_RX_0_TS_RX_TX_CFG_MSB 0x2F
+#define QIB_7322_IB_SDTEST_IF_RX_0_TS_RX_TX_CFG_RMASK 0xFFFF
+#define QIB_7322_IB_SDTEST_IF_RX_0_TS_RX_B_LSB 0x18
+#define QIB_7322_IB_SDTEST_IF_RX_0_TS_RX_B_MSB 0x1F
+#define QIB_7322_IB_SDTEST_IF_RX_0_TS_RX_B_RMASK 0xFF
+#define QIB_7322_IB_SDTEST_IF_RX_0_TS_RX_A_LSB 0x10
+#define QIB_7322_IB_SDTEST_IF_RX_0_TS_RX_A_MSB 0x17
+#define QIB_7322_IB_SDTEST_IF_RX_0_TS_RX_A_RMASK 0xFF
+#define QIB_7322_IB_SDTEST_IF_RX_0_TS_3_RX_VALID_LSB 0x1
+#define QIB_7322_IB_SDTEST_IF_RX_0_TS_3_RX_VALID_MSB 0x1
+#define QIB_7322_IB_SDTEST_IF_RX_0_TS_3_RX_VALID_RMASK 0x1
+#define QIB_7322_IB_SDTEST_IF_RX_0_TS_T_RX_VALID_LSB 0x0
+#define QIB_7322_IB_SDTEST_IF_RX_0_TS_T_RX_VALID_MSB 0x0
+#define QIB_7322_IB_SDTEST_IF_RX_0_TS_T_RX_VALID_RMASK 0x1
+
+#define QIB_7322_IBNCModeCtrl_0_OFFS 0x15B8
+#define QIB_7322_IBNCModeCtrl_0_DEF 0x0000000000000000
+#define QIB_7322_IBNCModeCtrl_0_ScrambleCapRemoteForce_LSB 0x22
+#define QIB_7322_IBNCModeCtrl_0_ScrambleCapRemoteForce_MSB 0x22
+#define QIB_7322_IBNCModeCtrl_0_ScrambleCapRemoteForce_RMASK 0x1
+#define QIB_7322_IBNCModeCtrl_0_ScrambleCapRemoteMask_LSB 0x21
+#define QIB_7322_IBNCModeCtrl_0_ScrambleCapRemoteMask_MSB 0x21
+#define QIB_7322_IBNCModeCtrl_0_ScrambleCapRemoteMask_RMASK 0x1
+#define QIB_7322_IBNCModeCtrl_0_ScrambleCapLocal_LSB 0x20
+#define QIB_7322_IBNCModeCtrl_0_ScrambleCapLocal_MSB 0x20
+#define QIB_7322_IBNCModeCtrl_0_ScrambleCapLocal_RMASK 0x1
+#define QIB_7322_IBNCModeCtrl_0_TSMCode_TS2_LSB 0x11
+#define QIB_7322_IBNCModeCtrl_0_TSMCode_TS2_MSB 0x19
+#define QIB_7322_IBNCModeCtrl_0_TSMCode_TS2_RMASK 0x1FF
+#define QIB_7322_IBNCModeCtrl_0_TSMCode_TS1_LSB 0x8
+#define QIB_7322_IBNCModeCtrl_0_TSMCode_TS1_MSB 0x10
+#define QIB_7322_IBNCModeCtrl_0_TSMCode_TS1_RMASK 0x1FF
+#define QIB_7322_IBNCModeCtrl_0_TSMEnable_ignore_TSM_on_rx_LSB 0x2
+#define QIB_7322_IBNCModeCtrl_0_TSMEnable_ignore_TSM_on_rx_MSB 0x2
+#define QIB_7322_IBNCModeCtrl_0_TSMEnable_ignore_TSM_on_rx_RMASK 0x1
+#define QIB_7322_IBNCModeCtrl_0_TSMEnable_send_TS2_LSB 0x1
+#define QIB_7322_IBNCModeCtrl_0_TSMEnable_send_TS2_MSB 0x1
+#define QIB_7322_IBNCModeCtrl_0_TSMEnable_send_TS2_RMASK 0x1
+#define QIB_7322_IBNCModeCtrl_0_TSMEnable_send_TS1_LSB 0x0
+#define QIB_7322_IBNCModeCtrl_0_TSMEnable_send_TS1_MSB 0x0
+#define QIB_7322_IBNCModeCtrl_0_TSMEnable_send_TS1_RMASK 0x1
+
+#define QIB_7322_IBSerdesStatus_0_OFFS 0x15D0
+#define QIB_7322_IBSerdesStatus_0_DEF 0x0000000000000000
+
+#define QIB_7322_IBPCSConfig_0_OFFS 0x15D8
+#define QIB_7322_IBPCSConfig_0_DEF 0x0000000000000007
+#define QIB_7322_IBPCSConfig_0_link_sync_mask_LSB 0x9
+#define QIB_7322_IBPCSConfig_0_link_sync_mask_MSB 0x12
+#define QIB_7322_IBPCSConfig_0_link_sync_mask_RMASK 0x3FF
+#define QIB_7322_IBPCSConfig_0_xcv_rreset_LSB 0x2
+#define QIB_7322_IBPCSConfig_0_xcv_rreset_MSB 0x2
+#define QIB_7322_IBPCSConfig_0_xcv_rreset_RMASK 0x1
+#define QIB_7322_IBPCSConfig_0_xcv_treset_LSB 0x1
+#define QIB_7322_IBPCSConfig_0_xcv_treset_MSB 0x1
+#define QIB_7322_IBPCSConfig_0_xcv_treset_RMASK 0x1
+#define QIB_7322_IBPCSConfig_0_tx_rx_reset_LSB 0x0
+#define QIB_7322_IBPCSConfig_0_tx_rx_reset_MSB 0x0
+#define QIB_7322_IBPCSConfig_0_tx_rx_reset_RMASK 0x1
+
+#define QIB_7322_IBSerdesCtrl_0_OFFS 0x15E0
+#define QIB_7322_IBSerdesCtrl_0_DEF 0x0000000000FFA00F
+#define QIB_7322_IBSerdesCtrl_0_DISABLE_RXLATOFF_QDR_LSB 0x1A
+#define QIB_7322_IBSerdesCtrl_0_DISABLE_RXLATOFF_QDR_MSB 0x1A
+#define QIB_7322_IBSerdesCtrl_0_DISABLE_RXLATOFF_QDR_RMASK 0x1
+#define QIB_7322_IBSerdesCtrl_0_DISABLE_RXLATOFF_DDR_LSB 0x19
+#define QIB_7322_IBSerdesCtrl_0_DISABLE_RXLATOFF_DDR_MSB 0x19
+#define QIB_7322_IBSerdesCtrl_0_DISABLE_RXLATOFF_DDR_RMASK 0x1
+#define QIB_7322_IBSerdesCtrl_0_DISABLE_RXLATOFF_SDR_LSB 0x18
+#define QIB_7322_IBSerdesCtrl_0_DISABLE_RXLATOFF_SDR_MSB 0x18
+#define QIB_7322_IBSerdesCtrl_0_DISABLE_RXLATOFF_SDR_RMASK 0x1
+#define QIB_7322_IBSerdesCtrl_0_CHANNEL_RESET_N_LSB 0x14
+#define QIB_7322_IBSerdesCtrl_0_CHANNEL_RESET_N_MSB 0x17
+#define QIB_7322_IBSerdesCtrl_0_CHANNEL_RESET_N_RMASK 0xF
+#define QIB_7322_IBSerdesCtrl_0_CGMODE_LSB 0x10
+#define QIB_7322_IBSerdesCtrl_0_CGMODE_MSB 0x13
+#define QIB_7322_IBSerdesCtrl_0_CGMODE_RMASK 0xF
+#define QIB_7322_IBSerdesCtrl_0_IB_LAT_MODE_LSB 0xF
+#define QIB_7322_IBSerdesCtrl_0_IB_LAT_MODE_MSB 0xF
+#define QIB_7322_IBSerdesCtrl_0_IB_LAT_MODE_RMASK 0x1
+#define QIB_7322_IBSerdesCtrl_0_RXLOSEN_LSB 0xD
+#define QIB_7322_IBSerdesCtrl_0_RXLOSEN_MSB 0xD
+#define QIB_7322_IBSerdesCtrl_0_RXLOSEN_RMASK 0x1
+#define QIB_7322_IBSerdesCtrl_0_LPEN_LSB 0xC
+#define QIB_7322_IBSerdesCtrl_0_LPEN_MSB 0xC
+#define QIB_7322_IBSerdesCtrl_0_LPEN_RMASK 0x1
+#define QIB_7322_IBSerdesCtrl_0_PLLPD_LSB 0xB
+#define QIB_7322_IBSerdesCtrl_0_PLLPD_MSB 0xB
+#define QIB_7322_IBSerdesCtrl_0_PLLPD_RMASK 0x1
+#define QIB_7322_IBSerdesCtrl_0_TXPD_LSB 0xA
+#define QIB_7322_IBSerdesCtrl_0_TXPD_MSB 0xA
+#define QIB_7322_IBSerdesCtrl_0_TXPD_RMASK 0x1
+#define QIB_7322_IBSerdesCtrl_0_RXPD_LSB 0x9
+#define QIB_7322_IBSerdesCtrl_0_RXPD_MSB 0x9
+#define QIB_7322_IBSerdesCtrl_0_RXPD_RMASK 0x1
+#define QIB_7322_IBSerdesCtrl_0_TXIDLE_LSB 0x8
+#define QIB_7322_IBSerdesCtrl_0_TXIDLE_MSB 0x8
+#define QIB_7322_IBSerdesCtrl_0_TXIDLE_RMASK 0x1
+#define QIB_7322_IBSerdesCtrl_0_CMODE_LSB 0x0
+#define QIB_7322_IBSerdesCtrl_0_CMODE_MSB 0x6
+#define QIB_7322_IBSerdesCtrl_0_CMODE_RMASK 0x7F
+
+#define QIB_7322_IBSD_TX_DEEMPHASIS_OVERRIDE_0_OFFS 0x1600
+#define QIB_7322_IBSD_TX_DEEMPHASIS_OVERRIDE_0_DEF 0x0000000000000000
+#define QIB_7322_IBSD_TX_DEEMPHASIS_OVERRIDE_0_tx_override_deemphasis_select_LSB 0x1F
+#define QIB_7322_IBSD_TX_DEEMPHASIS_OVERRIDE_0_tx_override_deemphasis_select_MSB 0x1F
+#define QIB_7322_IBSD_TX_DEEMPHASIS_OVERRIDE_0_tx_override_deemphasis_select_RMASK 0x1
+#define QIB_7322_IBSD_TX_DEEMPHASIS_OVERRIDE_0_reset_tx_deemphasis_override_LSB 0x1E
+#define QIB_7322_IBSD_TX_DEEMPHASIS_OVERRIDE_0_reset_tx_deemphasis_override_MSB 0x1E
+#define QIB_7322_IBSD_TX_DEEMPHASIS_OVERRIDE_0_reset_tx_deemphasis_override_RMASK 0x1
+#define QIB_7322_IBSD_TX_DEEMPHASIS_OVERRIDE_0_txampcntl_d2a_LSB 0xE
+#define QIB_7322_IBSD_TX_DEEMPHASIS_OVERRIDE_0_txampcntl_d2a_MSB 0x11
+#define QIB_7322_IBSD_TX_DEEMPHASIS_OVERRIDE_0_txampcntl_d2a_RMASK 0xF
+#define QIB_7322_IBSD_TX_DEEMPHASIS_OVERRIDE_0_txc0_ena_LSB 0x9
+#define QIB_7322_IBSD_TX_DEEMPHASIS_OVERRIDE_0_txc0_ena_MSB 0xD
+#define QIB_7322_IBSD_TX_DEEMPHASIS_OVERRIDE_0_txc0_ena_RMASK 0x1F
+#define QIB_7322_IBSD_TX_DEEMPHASIS_OVERRIDE_0_txcp1_ena_LSB 0x5
+#define QIB_7322_IBSD_TX_DEEMPHASIS_OVERRIDE_0_txcp1_ena_MSB 0x8
+#define QIB_7322_IBSD_TX_DEEMPHASIS_OVERRIDE_0_txcp1_ena_RMASK 0xF
+#define QIB_7322_IBSD_TX_DEEMPHASIS_OVERRIDE_0_txcn1_xtra_emph0_LSB 0x3
+#define QIB_7322_IBSD_TX_DEEMPHASIS_OVERRIDE_0_txcn1_xtra_emph0_MSB 0x4
+#define QIB_7322_IBSD_TX_DEEMPHASIS_OVERRIDE_0_txcn1_xtra_emph0_RMASK 0x3
+#define QIB_7322_IBSD_TX_DEEMPHASIS_OVERRIDE_0_txcn1_ena_LSB 0x0
+#define QIB_7322_IBSD_TX_DEEMPHASIS_OVERRIDE_0_txcn1_ena_MSB 0x2
+#define QIB_7322_IBSD_TX_DEEMPHASIS_OVERRIDE_0_txcn1_ena_RMASK 0x7
+
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_OFFS 0x1640
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_DEF 0x0000000000000000
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenagain_sdr_ch3_LSB 0x27
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenagain_sdr_ch3_MSB 0x27
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenagain_sdr_ch3_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenagain_sdr_ch2_LSB 0x26
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenagain_sdr_ch2_MSB 0x26
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenagain_sdr_ch2_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenagain_sdr_ch1_LSB 0x25
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenagain_sdr_ch1_MSB 0x25
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenagain_sdr_ch1_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenagain_sdr_ch0_LSB 0x24
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenagain_sdr_ch0_MSB 0x24
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenagain_sdr_ch0_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenale_sdr_ch3_LSB 0x23
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenale_sdr_ch3_MSB 0x23
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenale_sdr_ch3_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenale_sdr_ch2_LSB 0x22
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenale_sdr_ch2_MSB 0x22
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenale_sdr_ch2_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenale_sdr_ch1_LSB 0x21
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenale_sdr_ch1_MSB 0x21
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenale_sdr_ch1_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenale_sdr_ch0_LSB 0x20
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenale_sdr_ch0_MSB 0x20
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenale_sdr_ch0_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenadfe_sdr_ch3_LSB 0x18
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenadfe_sdr_ch3_MSB 0x1F
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenadfe_sdr_ch3_RMASK 0xFF
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenadfe_sdr_ch2_LSB 0x10
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenadfe_sdr_ch2_MSB 0x17
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenadfe_sdr_ch2_RMASK 0xFF
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenadfe_sdr_ch1_LSB 0x8
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenadfe_sdr_ch1_MSB 0xF
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenadfe_sdr_ch1_RMASK 0xFF
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenadfe_sdr_ch0_LSB 0x0
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenadfe_sdr_ch0_MSB 0x7
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_static_disable_rxenadfe_sdr_ch0_RMASK 0xFF
+
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_OFFS 0x1648
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_DEF 0x0000000000000000
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenagain_sdr_ch3_LSB 0x27
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenagain_sdr_ch3_MSB 0x27
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenagain_sdr_ch3_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenagain_sdr_ch2_LSB 0x26
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenagain_sdr_ch2_MSB 0x26
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenagain_sdr_ch2_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenagain_sdr_ch1_LSB 0x25
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenagain_sdr_ch1_MSB 0x25
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenagain_sdr_ch1_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenagain_sdr_ch0_LSB 0x24
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenagain_sdr_ch0_MSB 0x24
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenagain_sdr_ch0_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenale_sdr_ch3_LSB 0x23
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenale_sdr_ch3_MSB 0x23
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenale_sdr_ch3_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenale_sdr_ch2_LSB 0x22
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenale_sdr_ch2_MSB 0x22
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenale_sdr_ch2_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenale_sdr_ch1_LSB 0x21
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenale_sdr_ch1_MSB 0x21
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenale_sdr_ch1_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenale_sdr_ch0_LSB 0x20
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenale_sdr_ch0_MSB 0x20
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenale_sdr_ch0_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenadfe_sdr_ch3_LSB 0x18
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenadfe_sdr_ch3_MSB 0x1F
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenadfe_sdr_ch3_RMASK 0xFF
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenadfe_sdr_ch2_LSB 0x10
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenadfe_sdr_ch2_MSB 0x17
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenadfe_sdr_ch2_RMASK 0xFF
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenadfe_sdr_ch1_LSB 0x8
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenadfe_sdr_ch1_MSB 0xF
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenadfe_sdr_ch1_RMASK 0xFF
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenadfe_sdr_ch0_LSB 0x0
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenadfe_sdr_ch0_MSB 0x7
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_dyn_disable_rxenadfe_sdr_ch0_RMASK 0xFF
+
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_OFFS 0x1650
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_DEF 0x0000000000000000
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenagain_ddr_ch3_LSB 0x27
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenagain_ddr_ch3_MSB 0x27
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenagain_ddr_ch3_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenagain_ddr_ch2_LSB 0x26
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenagain_ddr_ch2_MSB 0x26
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenagain_ddr_ch2_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenagain_ddr_ch1_LSB 0x25
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenagain_ddr_ch1_MSB 0x25
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenagain_ddr_ch1_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenagain_ddr_ch0_LSB 0x24
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenagain_ddr_ch0_MSB 0x24
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenagain_ddr_ch0_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenale_ddr_ch3_LSB 0x23
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenale_ddr_ch3_MSB 0x23
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenale_ddr_ch3_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenale_ddr_ch2_LSB 0x22
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenale_ddr_ch2_MSB 0x22
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenale_ddr_ch2_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenale_ddr_ch1_LSB 0x21
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenale_ddr_ch1_MSB 0x21
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenale_ddr_ch1_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenale_ddr_ch0_LSB 0x20
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenale_ddr_ch0_MSB 0x20
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenale_ddr_ch0_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenadfe_ddr_ch3_LSB 0x18
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenadfe_ddr_ch3_MSB 0x1F
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenadfe_ddr_ch3_RMASK 0xFF
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenadfe_ddr_ch2_LSB 0x10
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenadfe_ddr_ch2_MSB 0x17
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenadfe_ddr_ch2_RMASK 0xFF
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenadfe_ddr_ch1_LSB 0x8
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenadfe_ddr_ch1_MSB 0xF
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenadfe_ddr_ch1_RMASK 0xFF
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenadfe_ddr_ch0_LSB 0x0
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenadfe_ddr_ch0_MSB 0x7
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_static_disable_rxenadfe_ddr_ch0_RMASK 0xFF
+
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_OFFS 0x1658
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_DEF 0x0000000000000000
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenagain_ddr_ch3_LSB 0x27
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenagain_ddr_ch3_MSB 0x27
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenagain_ddr_ch3_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenagain_ddr_ch2_LSB 0x26
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenagain_ddr_ch2_MSB 0x26
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenagain_ddr_ch2_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenagain_ddr_ch1_LSB 0x25
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenagain_ddr_ch1_MSB 0x25
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenagain_ddr_ch1_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenagain_ddr_ch0_LSB 0x24
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenagain_ddr_ch0_MSB 0x24
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenagain_ddr_ch0_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenale_ddr_ch3_LSB 0x23
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenale_ddr_ch3_MSB 0x23
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenale_ddr_ch3_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenale_ddr_ch2_LSB 0x22
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenale_ddr_ch2_MSB 0x22
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenale_ddr_ch2_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenale_ddr_ch1_LSB 0x21
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenale_ddr_ch1_MSB 0x21
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenale_ddr_ch1_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenale_ddr_ch0_LSB 0x20
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenale_ddr_ch0_MSB 0x20
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenale_ddr_ch0_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenadfe_ddr_ch3_LSB 0x18
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenadfe_ddr_ch3_MSB 0x1F
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenadfe_ddr_ch3_RMASK 0xFF
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenadfe_ddr_ch2_LSB 0x10
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenadfe_ddr_ch2_MSB 0x17
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenadfe_ddr_ch2_RMASK 0xFF
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenadfe_ddr_ch1_LSB 0x8
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenadfe_ddr_ch1_MSB 0xF
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenadfe_ddr_ch1_RMASK 0xFF
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenadfe_ddr_ch0_LSB 0x0
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenadfe_ddr_ch0_MSB 0x7
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_dyn_disable_rxenadfe_ddr_ch0_RMASK 0xFF
+
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_OFFS 0x1660
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_DEF 0x0000000000000000
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenagain_qdr_ch3_LSB 0x27
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenagain_qdr_ch3_MSB 0x27
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenagain_qdr_ch3_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenagain_qdr_ch2_LSB 0x26
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenagain_qdr_ch2_MSB 0x26
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenagain_qdr_ch2_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenagain_qdr_ch1_LSB 0x25
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenagain_qdr_ch1_MSB 0x25
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenagain_qdr_ch1_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenagain_qdr_ch0_LSB 0x24
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenagain_qdr_ch0_MSB 0x24
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenagain_qdr_ch0_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenale_qdr_ch3_LSB 0x23
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenale_qdr_ch3_MSB 0x23
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenale_qdr_ch3_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenale_qdr_ch2_LSB 0x22
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenale_qdr_ch2_MSB 0x22
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenale_qdr_ch2_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenale_qdr_ch1_LSB 0x21
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenale_qdr_ch1_MSB 0x21
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenale_qdr_ch1_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenale_qdr_ch0_LSB 0x20
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenale_qdr_ch0_MSB 0x20
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenale_qdr_ch0_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenadfe_qdr_ch3_LSB 0x18
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenadfe_qdr_ch3_MSB 0x1F
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenadfe_qdr_ch3_RMASK 0xFF
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenadfe_qdr_ch2_LSB 0x10
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenadfe_qdr_ch2_MSB 0x17
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenadfe_qdr_ch2_RMASK 0xFF
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenadfe_qdr_ch1_LSB 0x8
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenadfe_qdr_ch1_MSB 0xF
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenadfe_qdr_ch1_RMASK 0xFF
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenadfe_qdr_ch0_LSB 0x0
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenadfe_qdr_ch0_MSB 0x7
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_static_disable_rxenadfe_qdr_ch0_RMASK 0xFF
+
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_OFFS 0x1668
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_DEF 0x0000000000000000
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenagain_qdr_ch3_LSB 0x27
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenagain_qdr_ch3_MSB 0x27
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenagain_qdr_ch3_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenagain_qdr_ch2_LSB 0x26
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenagain_qdr_ch2_MSB 0x26
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenagain_qdr_ch2_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenagain_qdr_ch1_LSB 0x25
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenagain_qdr_ch1_MSB 0x25
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenagain_qdr_ch1_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenagain_qdr_ch0_LSB 0x24
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenagain_qdr_ch0_MSB 0x24
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenagain_qdr_ch0_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenale_qdr_ch3_LSB 0x23
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenale_qdr_ch3_MSB 0x23
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenale_qdr_ch3_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenale_qdr_ch2_LSB 0x22
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenale_qdr_ch2_MSB 0x22
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenale_qdr_ch2_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenale_qdr_ch1_LSB 0x21
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenale_qdr_ch1_MSB 0x21
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenale_qdr_ch1_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenale_qdr_ch0_LSB 0x20
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenale_qdr_ch0_MSB 0x20
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenale_qdr_ch0_RMASK 0x1
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenadfe_qdr_ch3_LSB 0x18
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenadfe_qdr_ch3_MSB 0x1F
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenadfe_qdr_ch3_RMASK 0xFF
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenadfe_qdr_ch2_LSB 0x10
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenadfe_qdr_ch2_MSB 0x17
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenadfe_qdr_ch2_RMASK 0xFF
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenadfe_qdr_ch1_LSB 0x8
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenadfe_qdr_ch1_MSB 0xF
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenadfe_qdr_ch1_RMASK 0xFF
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenadfe_qdr_ch0_LSB 0x0
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenadfe_qdr_ch0_MSB 0x7
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_dyn_disable_rxenadfe_qdr_ch0_RMASK 0xFF
+
+#define QIB_7322_ADAPT_DISABLE_TIMER_THRESHOLD_0_OFFS 0x1670
+#define QIB_7322_ADAPT_DISABLE_TIMER_THRESHOLD_0_DEF 0x0000000000000000
+
+#define QIB_7322_HighPriorityLimit_0_OFFS 0x1BC0
+#define QIB_7322_HighPriorityLimit_0_DEF 0x0000000000000000
+#define QIB_7322_HighPriorityLimit_0_Limit_LSB 0x0
+#define QIB_7322_HighPriorityLimit_0_Limit_MSB 0x7
+#define QIB_7322_HighPriorityLimit_0_Limit_RMASK 0xFF
+
+#define QIB_7322_LowPriority0_0_OFFS 0x1C00
+#define QIB_7322_LowPriority0_0_DEF 0x0000000000000000
+#define QIB_7322_LowPriority0_0_VirtualLane_LSB 0x10
+#define QIB_7322_LowPriority0_0_VirtualLane_MSB 0x12
+#define QIB_7322_LowPriority0_0_VirtualLane_RMASK 0x7
+#define QIB_7322_LowPriority0_0_Weight_LSB 0x0
+#define QIB_7322_LowPriority0_0_Weight_MSB 0x7
+#define QIB_7322_LowPriority0_0_Weight_RMASK 0xFF
+
+#define QIB_7322_HighPriority0_0_OFFS 0x1E00
+#define QIB_7322_HighPriority0_0_DEF 0x0000000000000000
+#define QIB_7322_HighPriority0_0_VirtualLane_LSB 0x10
+#define QIB_7322_HighPriority0_0_VirtualLane_MSB 0x12
+#define QIB_7322_HighPriority0_0_VirtualLane_RMASK 0x7
+#define QIB_7322_HighPriority0_0_Weight_LSB 0x0
+#define QIB_7322_HighPriority0_0_Weight_MSB 0x7
+#define QIB_7322_HighPriority0_0_Weight_RMASK 0xFF
+
+#define QIB_7322_CntrRegBase_1_OFFS 0x2028
+#define QIB_7322_CntrRegBase_1_DEF 0x0000000000013000
+
+#define QIB_7322_RcvQPMulticastContext_1_OFFS 0x2170
+
+#define QIB_7322_SendCtrl_1_OFFS 0x21C0
+
+#define QIB_7322_SendBufAvail0_OFFS 0x3000
+#define QIB_7322_SendBufAvail0_DEF 0x0000000000000000
+#define QIB_7322_SendBufAvail0_SendBuf_31_0_LSB 0x0
+#define QIB_7322_SendBufAvail0_SendBuf_31_0_MSB 0x3F
+#define QIB_7322_SendBufAvail0_SendBuf_31_0_RMASK 0x0
+
+#define QIB_7322_MsixTable_OFFS 0x8000
+#define QIB_7322_MsixTable_DEF 0x0000000000000000
+
+#define QIB_7322_MsixPba_OFFS 0x9000
+#define QIB_7322_MsixPba_DEF 0x0000000000000000
+
+#define QIB_7322_LAMemory_OFFS 0xA000
+#define QIB_7322_LAMemory_DEF 0x0000000000000000
+
+#define QIB_7322_LBIntCnt_OFFS 0x11000
+#define QIB_7322_LBIntCnt_DEF 0x0000000000000000
+
+#define QIB_7322_LBFlowStallCnt_OFFS 0x11008
+#define QIB_7322_LBFlowStallCnt_DEF 0x0000000000000000
+
+#define QIB_7322_RxTIDFullErrCnt_OFFS 0x110D0
+#define QIB_7322_RxTIDFullErrCnt_DEF 0x0000000000000000
+
+#define QIB_7322_RxTIDValidErrCnt_OFFS 0x110D8
+#define QIB_7322_RxTIDValidErrCnt_DEF 0x0000000000000000
+
+#define QIB_7322_RxP0HdrEgrOvflCnt_OFFS 0x110E8
+#define QIB_7322_RxP0HdrEgrOvflCnt_DEF 0x0000000000000000
+
+#define QIB_7322_PcieRetryBufDiagQwordCnt_OFFS 0x111A0
+#define QIB_7322_PcieRetryBufDiagQwordCnt_DEF 0x0000000000000000
+
+#define QIB_7322_RxTidFlowDropCnt_OFFS 0x111E0
+#define QIB_7322_RxTidFlowDropCnt_DEF 0x0000000000000000
+
+#define QIB_7322_LBIntCnt_0_OFFS 0x12000
+#define QIB_7322_LBIntCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_TxCreditUpToDateTimeOut_0_OFFS 0x12008
+#define QIB_7322_TxCreditUpToDateTimeOut_0_DEF 0x0000000000000000
+
+#define QIB_7322_TxSDmaDescCnt_0_OFFS 0x12010
+#define QIB_7322_TxSDmaDescCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_TxUnsupVLErrCnt_0_OFFS 0x12018
+#define QIB_7322_TxUnsupVLErrCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_TxDataPktCnt_0_OFFS 0x12020
+#define QIB_7322_TxDataPktCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_TxFlowPktCnt_0_OFFS 0x12028
+#define QIB_7322_TxFlowPktCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_TxDwordCnt_0_OFFS 0x12030
+#define QIB_7322_TxDwordCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_TxLenErrCnt_0_OFFS 0x12038
+#define QIB_7322_TxLenErrCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_TxMaxMinLenErrCnt_0_OFFS 0x12040
+#define QIB_7322_TxMaxMinLenErrCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_TxUnderrunCnt_0_OFFS 0x12048
+#define QIB_7322_TxUnderrunCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_TxFlowStallCnt_0_OFFS 0x12050
+#define QIB_7322_TxFlowStallCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_TxDroppedPktCnt_0_OFFS 0x12058
+#define QIB_7322_TxDroppedPktCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_RxDroppedPktCnt_0_OFFS 0x12060
+#define QIB_7322_RxDroppedPktCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_RxDataPktCnt_0_OFFS 0x12068
+#define QIB_7322_RxDataPktCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_RxFlowPktCnt_0_OFFS 0x12070
+#define QIB_7322_RxFlowPktCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_RxDwordCnt_0_OFFS 0x12078
+#define QIB_7322_RxDwordCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_RxLenErrCnt_0_OFFS 0x12080
+#define QIB_7322_RxLenErrCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_RxMaxMinLenErrCnt_0_OFFS 0x12088
+#define QIB_7322_RxMaxMinLenErrCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_RxICRCErrCnt_0_OFFS 0x12090
+#define QIB_7322_RxICRCErrCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_RxVCRCErrCnt_0_OFFS 0x12098
+#define QIB_7322_RxVCRCErrCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_RxFlowCtrlViolCnt_0_OFFS 0x120A0
+#define QIB_7322_RxFlowCtrlViolCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_RxVersionErrCnt_0_OFFS 0x120A8
+#define QIB_7322_RxVersionErrCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_RxLinkMalformCnt_0_OFFS 0x120B0
+#define QIB_7322_RxLinkMalformCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_RxEBPCnt_0_OFFS 0x120B8
+#define QIB_7322_RxEBPCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_RxLPCRCErrCnt_0_OFFS 0x120C0
+#define QIB_7322_RxLPCRCErrCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_RxBufOvflCnt_0_OFFS 0x120C8
+#define QIB_7322_RxBufOvflCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_RxLenTruncateCnt_0_OFFS 0x120D0
+#define QIB_7322_RxLenTruncateCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_RxPKeyMismatchCnt_0_OFFS 0x120E0
+#define QIB_7322_RxPKeyMismatchCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_IBLinkDownedCnt_0_OFFS 0x12180
+#define QIB_7322_IBLinkDownedCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_IBSymbolErrCnt_0_OFFS 0x12188
+#define QIB_7322_IBSymbolErrCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_IBStatusChangeCnt_0_OFFS 0x12190
+#define QIB_7322_IBStatusChangeCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_IBLinkErrRecoveryCnt_0_OFFS 0x12198
+#define QIB_7322_IBLinkErrRecoveryCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_ExcessBufferOvflCnt_0_OFFS 0x121A8
+#define QIB_7322_ExcessBufferOvflCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_LocalLinkIntegrityErrCnt_0_OFFS 0x121B0
+#define QIB_7322_LocalLinkIntegrityErrCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_RxVlErrCnt_0_OFFS 0x121B8
+#define QIB_7322_RxVlErrCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_RxDlidFltrCnt_0_OFFS 0x121C0
+#define QIB_7322_RxDlidFltrCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_RxVL15DroppedPktCnt_0_OFFS 0x121C8
+#define QIB_7322_RxVL15DroppedPktCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_RxOtherLocalPhyErrCnt_0_OFFS 0x121D0
+#define QIB_7322_RxOtherLocalPhyErrCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_RxQPInvalidContextCnt_0_OFFS 0x121D8
+#define QIB_7322_RxQPInvalidContextCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_TxHeadersErrCnt_0_OFFS 0x121F8
+#define QIB_7322_TxHeadersErrCnt_0_DEF 0x0000000000000000
+
+#define QIB_7322_PSRcvDataCount_0_OFFS 0x12218
+#define QIB_7322_PSRcvDataCount_0_DEF 0x0000000000000000
+
+#define QIB_7322_PSRcvPktsCount_0_OFFS 0x12220
+#define QIB_7322_PSRcvPktsCount_0_DEF 0x0000000000000000
+
+#define QIB_7322_PSXmitDataCount_0_OFFS 0x12228
+#define QIB_7322_PSXmitDataCount_0_DEF 0x0000000000000000
+
+#define QIB_7322_PSXmitPktsCount_0_OFFS 0x12230
+#define QIB_7322_PSXmitPktsCount_0_DEF 0x0000000000000000
+
+#define QIB_7322_PSXmitWaitCount_0_OFFS 0x12238
+#define QIB_7322_PSXmitWaitCount_0_DEF 0x0000000000000000
+
+#define QIB_7322_LBIntCnt_1_OFFS 0x13000
+#define QIB_7322_LBIntCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_TxCreditUpToDateTimeOut_1_OFFS 0x13008
+#define QIB_7322_TxCreditUpToDateTimeOut_1_DEF 0x0000000000000000
+
+#define QIB_7322_TxSDmaDescCnt_1_OFFS 0x13010
+#define QIB_7322_TxSDmaDescCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_TxUnsupVLErrCnt_1_OFFS 0x13018
+#define QIB_7322_TxUnsupVLErrCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_TxDataPktCnt_1_OFFS 0x13020
+#define QIB_7322_TxDataPktCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_TxFlowPktCnt_1_OFFS 0x13028
+#define QIB_7322_TxFlowPktCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_TxDwordCnt_1_OFFS 0x13030
+#define QIB_7322_TxDwordCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_TxLenErrCnt_1_OFFS 0x13038
+#define QIB_7322_TxLenErrCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_TxMaxMinLenErrCnt_1_OFFS 0x13040
+#define QIB_7322_TxMaxMinLenErrCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_TxUnderrunCnt_1_OFFS 0x13048
+#define QIB_7322_TxUnderrunCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_TxFlowStallCnt_1_OFFS 0x13050
+#define QIB_7322_TxFlowStallCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_TxDroppedPktCnt_1_OFFS 0x13058
+#define QIB_7322_TxDroppedPktCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_RxDroppedPktCnt_1_OFFS 0x13060
+#define QIB_7322_RxDroppedPktCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_RxDataPktCnt_1_OFFS 0x13068
+#define QIB_7322_RxDataPktCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_RxFlowPktCnt_1_OFFS 0x13070
+#define QIB_7322_RxFlowPktCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_RxDwordCnt_1_OFFS 0x13078
+#define QIB_7322_RxDwordCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_RxLenErrCnt_1_OFFS 0x13080
+#define QIB_7322_RxLenErrCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_RxMaxMinLenErrCnt_1_OFFS 0x13088
+#define QIB_7322_RxMaxMinLenErrCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_RxICRCErrCnt_1_OFFS 0x13090
+#define QIB_7322_RxICRCErrCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_RxVCRCErrCnt_1_OFFS 0x13098
+#define QIB_7322_RxVCRCErrCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_RxFlowCtrlViolCnt_1_OFFS 0x130A0
+#define QIB_7322_RxFlowCtrlViolCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_RxVersionErrCnt_1_OFFS 0x130A8
+#define QIB_7322_RxVersionErrCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_RxLinkMalformCnt_1_OFFS 0x130B0
+#define QIB_7322_RxLinkMalformCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_RxEBPCnt_1_OFFS 0x130B8
+#define QIB_7322_RxEBPCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_RxLPCRCErrCnt_1_OFFS 0x130C0
+#define QIB_7322_RxLPCRCErrCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_RxBufOvflCnt_1_OFFS 0x130C8
+#define QIB_7322_RxBufOvflCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_RxLenTruncateCnt_1_OFFS 0x130D0
+#define QIB_7322_RxLenTruncateCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_RxPKeyMismatchCnt_1_OFFS 0x130E0
+#define QIB_7322_RxPKeyMismatchCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_IBLinkDownedCnt_1_OFFS 0x13180
+#define QIB_7322_IBLinkDownedCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_IBSymbolErrCnt_1_OFFS 0x13188
+#define QIB_7322_IBSymbolErrCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_IBStatusChangeCnt_1_OFFS 0x13190
+#define QIB_7322_IBStatusChangeCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_IBLinkErrRecoveryCnt_1_OFFS 0x13198
+#define QIB_7322_IBLinkErrRecoveryCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_ExcessBufferOvflCnt_1_OFFS 0x131A8
+#define QIB_7322_ExcessBufferOvflCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_LocalLinkIntegrityErrCnt_1_OFFS 0x131B0
+#define QIB_7322_LocalLinkIntegrityErrCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_RxVlErrCnt_1_OFFS 0x131B8
+#define QIB_7322_RxVlErrCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_RxDlidFltrCnt_1_OFFS 0x131C0
+#define QIB_7322_RxDlidFltrCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_RxVL15DroppedPktCnt_1_OFFS 0x131C8
+#define QIB_7322_RxVL15DroppedPktCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_RxOtherLocalPhyErrCnt_1_OFFS 0x131D0
+#define QIB_7322_RxOtherLocalPhyErrCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_RxQPInvalidContextCnt_1_OFFS 0x131D8
+#define QIB_7322_RxQPInvalidContextCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_TxHeadersErrCnt_1_OFFS 0x131F8
+#define QIB_7322_TxHeadersErrCnt_1_DEF 0x0000000000000000
+
+#define QIB_7322_PSRcvDataCount_1_OFFS 0x13218
+#define QIB_7322_PSRcvDataCount_1_DEF 0x0000000000000000
+
+#define QIB_7322_PSRcvPktsCount_1_OFFS 0x13220
+#define QIB_7322_PSRcvPktsCount_1_DEF 0x0000000000000000
+
+#define QIB_7322_PSXmitDataCount_1_OFFS 0x13228
+#define QIB_7322_PSXmitDataCount_1_DEF 0x0000000000000000
+
+#define QIB_7322_PSXmitPktsCount_1_OFFS 0x13230
+#define QIB_7322_PSXmitPktsCount_1_DEF 0x0000000000000000
+
+#define QIB_7322_PSXmitWaitCount_1_OFFS 0x13238
+#define QIB_7322_PSXmitWaitCount_1_DEF 0x0000000000000000
+
+#define QIB_7322_RcvEgrArray_OFFS 0x14000
+#define QIB_7322_RcvEgrArray_DEF 0x0000000000000000
+#define QIB_7322_RcvEgrArray_RT_BufSize_LSB 0x25
+#define QIB_7322_RcvEgrArray_RT_BufSize_MSB 0x27
+#define QIB_7322_RcvEgrArray_RT_BufSize_RMASK 0x7
+#define QIB_7322_RcvEgrArray_RT_Addr_LSB 0x0
+#define QIB_7322_RcvEgrArray_RT_Addr_MSB 0x24
+#define QIB_7322_RcvEgrArray_RT_Addr_RMASK 0x1FFFFFFFFF
+
+#define QIB_7322_RcvTIDArray0_OFFS 0x50000
+#define QIB_7322_RcvTIDArray0_DEF 0x0000000000000000
+#define QIB_7322_RcvTIDArray0_RT_BufSize_LSB 0x25
+#define QIB_7322_RcvTIDArray0_RT_BufSize_MSB 0x27
+#define QIB_7322_RcvTIDArray0_RT_BufSize_RMASK 0x7
+#define QIB_7322_RcvTIDArray0_RT_Addr_LSB 0x0
+#define QIB_7322_RcvTIDArray0_RT_Addr_MSB 0x24
+#define QIB_7322_RcvTIDArray0_RT_Addr_RMASK 0x1FFFFFFFFF
+
+#define QIB_7322_IBSD_DDS_MAP_TABLE_0_OFFS 0xD0000
+#define QIB_7322_IBSD_DDS_MAP_TABLE_0_DEF 0x0000000000000000
+
+#define QIB_7322_RcvHdrTail0_OFFS 0x200000
+#define QIB_7322_RcvHdrTail0_DEF 0x0000000000000000
+
+#define QIB_7322_RcvHdrHead0_OFFS 0x200008
+#define QIB_7322_RcvHdrHead0_DEF 0x0000000000000000
+#define QIB_7322_RcvHdrHead0_counter_LSB 0x20
+#define QIB_7322_RcvHdrHead0_counter_MSB 0x2F
+#define QIB_7322_RcvHdrHead0_counter_RMASK 0xFFFF
+#define QIB_7322_RcvHdrHead0_RcvHeadPointer_LSB 0x0
+#define QIB_7322_RcvHdrHead0_RcvHeadPointer_MSB 0x1F
+#define QIB_7322_RcvHdrHead0_RcvHeadPointer_RMASK 0xFFFFFFFF
+
+#define QIB_7322_RcvEgrIndexTail0_OFFS 0x200010
+#define QIB_7322_RcvEgrIndexTail0_DEF 0x0000000000000000
+
+#define QIB_7322_RcvEgrIndexHead0_OFFS 0x200018
+#define QIB_7322_RcvEgrIndexHead0_DEF 0x0000000000000000
+
+#define QIB_7322_RcvTIDFlowTable0_OFFS 0x201000
+#define QIB_7322_RcvTIDFlowTable0_DEF 0x0000000000000000
+#define QIB_7322_RcvTIDFlowTable0_GenMismatch_LSB 0x1C
+#define QIB_7322_RcvTIDFlowTable0_GenMismatch_MSB 0x1C
+#define QIB_7322_RcvTIDFlowTable0_GenMismatch_RMASK 0x1
+#define QIB_7322_RcvTIDFlowTable0_SeqMismatch_LSB 0x1B
+#define QIB_7322_RcvTIDFlowTable0_SeqMismatch_MSB 0x1B
+#define QIB_7322_RcvTIDFlowTable0_SeqMismatch_RMASK 0x1
+#define QIB_7322_RcvTIDFlowTable0_KeepOnGenErr_LSB 0x16
+#define QIB_7322_RcvTIDFlowTable0_KeepOnGenErr_MSB 0x16
+#define QIB_7322_RcvTIDFlowTable0_KeepOnGenErr_RMASK 0x1
+#define QIB_7322_RcvTIDFlowTable0_KeepAfterSeqErr_LSB 0x15
+#define QIB_7322_RcvTIDFlowTable0_KeepAfterSeqErr_MSB 0x15
+#define QIB_7322_RcvTIDFlowTable0_KeepAfterSeqErr_RMASK 0x1
+#define QIB_7322_RcvTIDFlowTable0_HdrSuppEnabled_LSB 0x14
+#define QIB_7322_RcvTIDFlowTable0_HdrSuppEnabled_MSB 0x14
+#define QIB_7322_RcvTIDFlowTable0_HdrSuppEnabled_RMASK 0x1
+#define QIB_7322_RcvTIDFlowTable0_FlowValid_LSB 0x13
+#define QIB_7322_RcvTIDFlowTable0_FlowValid_MSB 0x13
+#define QIB_7322_RcvTIDFlowTable0_FlowValid_RMASK 0x1
+#define QIB_7322_RcvTIDFlowTable0_GenVal_LSB 0xB
+#define QIB_7322_RcvTIDFlowTable0_GenVal_MSB 0x12
+#define QIB_7322_RcvTIDFlowTable0_GenVal_RMASK 0xFF
+#define QIB_7322_RcvTIDFlowTable0_SeqNum_LSB 0x0
+#define QIB_7322_RcvTIDFlowTable0_SeqNum_MSB 0xA
+#define QIB_7322_RcvTIDFlowTable0_SeqNum_RMASK 0x7FF
diff --git a/drivers/infiniband/hw/qib/qib_common.h b/drivers/infiniband/hw/qib/qib_common.h
new file mode 100644 (file)
index 0000000..b3955ed
--- /dev/null
@@ -0,0 +1,758 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009, 2010 QLogic Corporation.
+ * All rights reserved.
+ * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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 _QIB_COMMON_H
+#define _QIB_COMMON_H
+
+/*
+ * This file contains defines, structures, etc. that are used
+ * to communicate between kernel and user code.
+ */
+
+/* This is the IEEE-assigned OUI for QLogic Inc. QLogic_IB */
+#define QIB_SRC_OUI_1 0x00
+#define QIB_SRC_OUI_2 0x11
+#define QIB_SRC_OUI_3 0x75
+
+/* version of protocol header (known to chip also). In the long run,
+ * we should be able to generate and accept a range of version numbers;
+ * for now we only accept one, and it's compiled in.
+ */
+#define IPS_PROTO_VERSION 2
+
+/*
+ * These are compile time constants that you may want to enable or disable
+ * if you are trying to debug problems with code or performance.
+ * QIB_VERBOSE_TRACING define as 1 if you want additional tracing in
+ * fastpath code
+ * QIB_TRACE_REGWRITES define as 1 if you want register writes to be
+ * traced in faspath code
+ * _QIB_TRACING define as 0 if you want to remove all tracing in a
+ * compilation unit
+ */
+
+/*
+ * The value in the BTH QP field that QLogic_IB uses to differentiate
+ * an qlogic_ib protocol IB packet vs standard IB transport
+ * This it needs to be even (0x656b78), because the LSB is sometimes
+ * used for the MSB of context. The change may cause a problem
+ * interoperating with older software.
+ */
+#define QIB_KD_QP 0x656b78
+
+/*
+ * These are the status bits readable (in ascii form, 64bit value)
+ * from the "status" sysfs file.  For binary compatibility, values
+ * must remain as is; removed states can be reused for different
+ * purposes.
+ */
+#define QIB_STATUS_INITTED       0x1    /* basic initialization done */
+/* Chip has been found and initted */
+#define QIB_STATUS_CHIP_PRESENT 0x20
+/* IB link is at ACTIVE, usable for data traffic */
+#define QIB_STATUS_IB_READY     0x40
+/* link is configured, LID, MTU, etc. have been set */
+#define QIB_STATUS_IB_CONF      0x80
+/* A Fatal hardware error has occurred. */
+#define QIB_STATUS_HWERROR     0x200
+
+/*
+ * The list of usermode accessible registers.  Also see Reg_* later in file.
+ */
+enum qib_ureg {
+       /* (RO)  DMA RcvHdr to be used next. */
+       ur_rcvhdrtail = 0,
+       /* (RW)  RcvHdr entry to be processed next by host. */
+       ur_rcvhdrhead = 1,
+       /* (RO)  Index of next Eager index to use. */
+       ur_rcvegrindextail = 2,
+       /* (RW)  Eager TID to be processed next */
+       ur_rcvegrindexhead = 3,
+       /* For internal use only; max register number. */
+       _QIB_UregMax
+};
+
+/* bit values for spi_runtime_flags */
+#define QIB_RUNTIME_PCIE                0x0002
+#define QIB_RUNTIME_FORCE_WC_ORDER      0x0004
+#define QIB_RUNTIME_RCVHDR_COPY         0x0008
+#define QIB_RUNTIME_MASTER              0x0010
+#define QIB_RUNTIME_RCHK                0x0020
+#define QIB_RUNTIME_NODMA_RTAIL         0x0080
+#define QIB_RUNTIME_SPECIAL_TRIGGER     0x0100
+#define QIB_RUNTIME_SDMA                0x0200
+#define QIB_RUNTIME_FORCE_PIOAVAIL      0x0400
+#define QIB_RUNTIME_PIO_REGSWAPPED      0x0800
+#define QIB_RUNTIME_CTXT_MSB_IN_QP      0x1000
+#define QIB_RUNTIME_CTXT_REDIRECT       0x2000
+#define QIB_RUNTIME_HDRSUPP             0x4000
+
+/*
+ * This structure is returned by qib_userinit() immediately after
+ * open to get implementation-specific info, and info specific to this
+ * instance.
+ *
+ * This struct must have explict pad fields where type sizes
+ * may result in different alignments between 32 and 64 bit
+ * programs, since the 64 bit * bit kernel requires the user code
+ * to have matching offsets
+ */
+struct qib_base_info {
+       /* version of hardware, for feature checking. */
+       __u32 spi_hw_version;
+       /* version of software, for feature checking. */
+       __u32 spi_sw_version;
+       /* QLogic_IB context assigned, goes into sent packets */
+       __u16 spi_ctxt;
+       __u16 spi_subctxt;
+       /*
+        * IB MTU, packets IB data must be less than this.
+        * The MTU is in bytes, and will be a multiple of 4 bytes.
+        */
+       __u32 spi_mtu;
+       /*
+        * Size of a PIO buffer.  Any given packet's total size must be less
+        * than this (in words).  Included is the starting control word, so
+        * if 513 is returned, then total pkt size is 512 words or less.
+        */
+       __u32 spi_piosize;
+       /* size of the TID cache in qlogic_ib, in entries */
+       __u32 spi_tidcnt;
+       /* size of the TID Eager list in qlogic_ib, in entries */
+       __u32 spi_tidegrcnt;
+       /* size of a single receive header queue entry in words. */
+       __u32 spi_rcvhdrent_size;
+       /*
+        * Count of receive header queue entries allocated.
+        * This may be less than the spu_rcvhdrcnt passed in!.
+        */
+       __u32 spi_rcvhdr_cnt;
+
+       /* per-chip and other runtime features bitmap (QIB_RUNTIME_*) */
+       __u32 spi_runtime_flags;
+
+       /* address where hardware receive header queue is mapped */
+       __u64 spi_rcvhdr_base;
+
+       /* user program. */
+
+       /* base address of eager TID receive buffers used by hardware. */
+       __u64 spi_rcv_egrbufs;
+
+       /* Allocated by initialization code, not by protocol. */
+
+       /*
+        * Size of each TID buffer in host memory, starting at
+        * spi_rcv_egrbufs.  The buffers are virtually contiguous.
+        */
+       __u32 spi_rcv_egrbufsize;
+       /*
+        * The special QP (queue pair) value that identifies an qlogic_ib
+        * protocol packet from standard IB packets.  More, probably much
+        * more, to be added.
+        */
+       __u32 spi_qpair;
+
+       /*
+        * User register base for init code, not to be used directly by
+        * protocol or applications.  Always points to chip registers,
+        * for normal or shared context.
+        */
+       __u64 spi_uregbase;
+       /*
+        * Maximum buffer size in bytes that can be used in a single TID
+        * entry (assuming the buffer is aligned to this boundary).  This is
+        * the minimum of what the hardware and software support Guaranteed
+        * to be a power of 2.
+        */
+       __u32 spi_tid_maxsize;
+       /*
+        * alignment of each pio send buffer (byte count
+        * to add to spi_piobufbase to get to second buffer)
+        */
+       __u32 spi_pioalign;
+       /*
+        * The index of the first pio buffer available to this process;
+        * needed to do lookup in spi_pioavailaddr; not added to
+        * spi_piobufbase.
+        */
+       __u32 spi_pioindex;
+        /* number of buffers mapped for this process */
+       __u32 spi_piocnt;
+
+       /*
+        * Base address of writeonly pio buffers for this process.
+        * Each buffer has spi_piosize words, and is aligned on spi_pioalign
+        * boundaries.  spi_piocnt buffers are mapped from this address
+        */
+       __u64 spi_piobufbase;
+
+       /*
+        * Base address of readonly memory copy of the pioavail registers.
+        * There are 2 bits for each buffer.
+        */
+       __u64 spi_pioavailaddr;
+
+       /*
+        * Address where driver updates a copy of the interface and driver
+        * status (QIB_STATUS_*) as a 64 bit value.  It's followed by a
+        * link status qword (formerly combined with driver status), then a
+        * string indicating hardware error, if there was one.
+        */
+       __u64 spi_status;
+
+       /* number of chip ctxts available to user processes */
+       __u32 spi_nctxts;
+       __u16 spi_unit; /* unit number of chip we are using */
+       __u16 spi_port; /* IB port number we are using */
+       /* num bufs in each contiguous set */
+       __u32 spi_rcv_egrperchunk;
+       /* size in bytes of each contiguous set */
+       __u32 spi_rcv_egrchunksize;
+       /* total size of mmap to cover full rcvegrbuffers */
+       __u32 spi_rcv_egrbuftotlen;
+       __u32 spi_rhf_offset; /* dword offset in hdrqent for rcvhdr flags */
+       /* address of readonly memory copy of the rcvhdrq tail register. */
+       __u64 spi_rcvhdr_tailaddr;
+
+       /*
+        * shared memory pages for subctxts if ctxt is shared; these cover
+        * all the processes in the group sharing a single context.
+        * all have enough space for the num_subcontexts value on this job.
+        */
+       __u64 spi_subctxt_uregbase;
+       __u64 spi_subctxt_rcvegrbuf;
+       __u64 spi_subctxt_rcvhdr_base;
+
+       /* shared memory page for send buffer disarm status */
+       __u64 spi_sendbuf_status;
+} __attribute__ ((aligned(8)));
+
+/*
+ * This version number is given to the driver by the user code during
+ * initialization in the spu_userversion field of qib_user_info, so
+ * the driver can check for compatibility with user code.
+ *
+ * The major version changes when data structures
+ * change in an incompatible way.  The driver must be the same or higher
+ * for initialization to succeed.  In some cases, a higher version
+ * driver will not interoperate with older software, and initialization
+ * will return an error.
+ */
+#define QIB_USER_SWMAJOR 1
+
+/*
+ * Minor version differences are always compatible
+ * a within a major version, however if user software is larger
+ * than driver software, some new features and/or structure fields
+ * may not be implemented; the user code must deal with this if it
+ * cares, or it must abort after initialization reports the difference.
+ */
+#define QIB_USER_SWMINOR 10
+
+#define QIB_USER_SWVERSION ((QIB_USER_SWMAJOR << 16) | QIB_USER_SWMINOR)
+
+#ifndef QIB_KERN_TYPE
+#define QIB_KERN_TYPE 0
+#define QIB_IDSTR "QLogic kernel.org driver"
+#endif
+
+/*
+ * Similarly, this is the kernel version going back to the user.  It's
+ * slightly different, in that we want to tell if the driver was built as
+ * part of a QLogic release, or from the driver from openfabrics.org,
+ * kernel.org, or a standard distribution, for support reasons.
+ * The high bit is 0 for non-QLogic and 1 for QLogic-built/supplied.
+ *
+ * It's returned by the driver to the user code during initialization in the
+ * spi_sw_version field of qib_base_info, so the user code can in turn
+ * check for compatibility with the kernel.
+*/
+#define QIB_KERN_SWVERSION ((QIB_KERN_TYPE << 31) | QIB_USER_SWVERSION)
+
+/*
+ * This structure is passed to qib_userinit() to tell the driver where
+ * user code buffers are, sizes, etc.   The offsets and sizes of the
+ * fields must remain unchanged, for binary compatibility.  It can
+ * be extended, if userversion is changed so user code can tell, if needed
+ */
+struct qib_user_info {
+       /*
+        * version of user software, to detect compatibility issues.
+        * Should be set to QIB_USER_SWVERSION.
+        */
+       __u32 spu_userversion;
+
+       __u32 _spu_unused2;
+
+       /* size of struct base_info to write to */
+       __u32 spu_base_info_size;
+
+       __u32 _spu_unused3;
+
+       /*
+        * If two or more processes wish to share a context, each process
+        * must set the spu_subctxt_cnt and spu_subctxt_id to the same
+        * values.  The only restriction on the spu_subctxt_id is that
+        * it be unique for a given node.
+        */
+       __u16 spu_subctxt_cnt;
+       __u16 spu_subctxt_id;
+
+       __u32 spu_port; /* IB port requested by user if > 0 */
+
+       /*
+        * address of struct base_info to write to
+        */
+       __u64 spu_base_info;
+
+} __attribute__ ((aligned(8)));
+
+/* User commands. */
+
+/* 16 available, was: old set up userspace (for old user code) */
+#define QIB_CMD_CTXT_INFO       17      /* find out what resources we got */
+#define QIB_CMD_RECV_CTRL       18      /* control receipt of packets */
+#define QIB_CMD_TID_UPDATE      19      /* update expected TID entries */
+#define QIB_CMD_TID_FREE        20      /* free expected TID entries */
+#define QIB_CMD_SET_PART_KEY    21      /* add partition key */
+/* 22 available, was: return info on slave processes (for old user code) */
+#define QIB_CMD_ASSIGN_CTXT     23      /* allocate HCA and ctxt */
+#define QIB_CMD_USER_INIT       24      /* set up userspace */
+#define QIB_CMD_UNUSED_1        25
+#define QIB_CMD_UNUSED_2        26
+#define QIB_CMD_PIOAVAILUPD     27      /* force an update of PIOAvail reg */
+#define QIB_CMD_POLL_TYPE       28      /* set the kind of polling we want */
+#define QIB_CMD_ARMLAUNCH_CTRL  29      /* armlaunch detection control */
+/* 30 is unused */
+#define QIB_CMD_SDMA_INFLIGHT   31      /* sdma inflight counter request */
+#define QIB_CMD_SDMA_COMPLETE   32      /* sdma completion counter request */
+/* 33 available, was a testing feature  */
+#define QIB_CMD_DISARM_BUFS     34      /* disarm send buffers w/ errors */
+#define QIB_CMD_ACK_EVENT       35      /* ack & clear bits */
+#define QIB_CMD_CPUS_LIST       36      /* list of cpus allocated, for pinned
+                                        * processes: qib_cpus_list */
+
+/*
+ * QIB_CMD_ACK_EVENT obsoletes QIB_CMD_DISARM_BUFS, but we keep it for
+ * compatibility with libraries from previous release.   The ACK_EVENT
+ * will take appropriate driver action (if any, just DISARM for now),
+ * then clear the bits passed in as part of the mask.  These bits are
+ * in the first 64bit word at spi_sendbuf_status, and are passed to
+ * the driver in the event_mask union as well.
+ */
+#define _QIB_EVENT_DISARM_BUFS_BIT     0
+#define _QIB_EVENT_LINKDOWN_BIT                1
+#define _QIB_EVENT_LID_CHANGE_BIT      2
+#define _QIB_EVENT_LMC_CHANGE_BIT      3
+#define _QIB_EVENT_SL2VL_CHANGE_BIT    4
+#define _QIB_MAX_EVENT_BIT _QIB_EVENT_SL2VL_CHANGE_BIT
+
+#define QIB_EVENT_DISARM_BUFS_BIT      (1UL << _QIB_EVENT_DISARM_BUFS_BIT)
+#define QIB_EVENT_LINKDOWN_BIT         (1UL << _QIB_EVENT_LINKDOWN_BIT)
+#define QIB_EVENT_LID_CHANGE_BIT       (1UL << _QIB_EVENT_LID_CHANGE_BIT)
+#define QIB_EVENT_LMC_CHANGE_BIT       (1UL << _QIB_EVENT_LMC_CHANGE_BIT)
+#define QIB_EVENT_SL2VL_CHANGE_BIT     (1UL << _QIB_EVENT_SL2VL_CHANGE_BIT)
+
+
+/*
+ * Poll types
+ */
+#define QIB_POLL_TYPE_ANYRCV     0x0
+#define QIB_POLL_TYPE_URGENT     0x1
+
+struct qib_ctxt_info {
+       __u16 num_active;       /* number of active units */
+       __u16 unit;             /* unit (chip) assigned to caller */
+       __u16 port;             /* IB port assigned to caller (1-based) */
+       __u16 ctxt;             /* ctxt on unit assigned to caller */
+       __u16 subctxt;          /* subctxt on unit assigned to caller */
+       __u16 num_ctxts;        /* number of ctxts available on unit */
+       __u16 num_subctxts;     /* number of subctxts opened on ctxt */
+       __u16 rec_cpu;          /* cpu # for affinity (ffff if none) */
+};
+
+struct qib_tid_info {
+       __u32 tidcnt;
+       /* make structure same size in 32 and 64 bit */
+       __u32 tid__unused;
+       /* virtual address of first page in transfer */
+       __u64 tidvaddr;
+       /* pointer (same size 32/64 bit) to __u16 tid array */
+       __u64 tidlist;
+
+       /*
+        * pointer (same size 32/64 bit) to bitmap of TIDs used
+        * for this call; checked for being large enough at open
+        */
+       __u64 tidmap;
+};
+
+struct qib_cmd {
+       __u32 type;                     /* command type */
+       union {
+               struct qib_tid_info tid_info;
+               struct qib_user_info user_info;
+
+               /*
+                * address in userspace where we should put the sdma
+                * inflight counter
+                */
+               __u64 sdma_inflight;
+               /*
+                * address in userspace where we should put the sdma
+                * completion counter
+                */
+               __u64 sdma_complete;
+               /* address in userspace of struct qib_ctxt_info to
+                  write result to */
+               __u64 ctxt_info;
+               /* enable/disable receipt of packets */
+               __u32 recv_ctrl;
+               /* enable/disable armlaunch errors (non-zero to enable) */
+               __u32 armlaunch_ctrl;
+               /* partition key to set */
+               __u16 part_key;
+               /* user address of __u32 bitmask of active slaves */
+               __u64 slave_mask_addr;
+               /* type of polling we want */
+               __u16 poll_type;
+               /* back pressure enable bit for one particular context */
+               __u8 ctxt_bp;
+               /* qib_user_event_ack(), IPATH_EVENT_* bits */
+               __u64 event_mask;
+       } cmd;
+};
+
+struct qib_iovec {
+       /* Pointer to data, but same size 32 and 64 bit */
+       __u64 iov_base;
+
+       /*
+        * Length of data; don't need 64 bits, but want
+        * qib_sendpkt to remain same size as before 32 bit changes, so...
+        */
+       __u64 iov_len;
+};
+
+/*
+ * Describes a single packet for send.  Each packet can have one or more
+ * buffers, but the total length (exclusive of IB headers) must be less
+ * than the MTU, and if using the PIO method, entire packet length,
+ * including IB headers, must be less than the qib_piosize value (words).
+ * Use of this necessitates including sys/uio.h
+ */
+struct __qib_sendpkt {
+       __u32 sps_flags;        /* flags for packet (TBD) */
+       __u32 sps_cnt;          /* number of entries to use in sps_iov */
+       /* array of iov's describing packet. TEMPORARY */
+       struct qib_iovec sps_iov[4];
+};
+
+/*
+ * Diagnostics can send a packet by "writing" the following
+ * structs to the diag data special file.
+ * This allows a custom
+ * pbc (+ static rate) qword, so that special modes and deliberate
+ * changes to CRCs can be used. The elements were also re-ordered
+ * for better alignment and to avoid padding issues.
+ */
+#define _DIAG_XPKT_VERS 3
+struct qib_diag_xpkt {
+       __u16 version;
+       __u16 unit;
+       __u16 port;
+       __u16 len;
+       __u64 data;
+       __u64 pbc_wd;
+};
+
+/*
+ * Data layout in I2C flash (for GUID, etc.)
+ * All fields are little-endian binary unless otherwise stated
+ */
+#define QIB_FLASH_VERSION 2
+struct qib_flash {
+       /* flash layout version (QIB_FLASH_VERSION) */
+       __u8 if_fversion;
+       /* checksum protecting if_length bytes */
+       __u8 if_csum;
+       /*
+        * valid length (in use, protected by if_csum), including
+        * if_fversion and if_csum themselves)
+        */
+       __u8 if_length;
+       /* the GUID, in network order */
+       __u8 if_guid[8];
+       /* number of GUIDs to use, starting from if_guid */
+       __u8 if_numguid;
+       /* the (last 10 characters of) board serial number, in ASCII */
+       char if_serial[12];
+       /* board mfg date (YYYYMMDD ASCII) */
+       char if_mfgdate[8];
+       /* last board rework/test date (YYYYMMDD ASCII) */
+       char if_testdate[8];
+       /* logging of error counts, TBD */
+       __u8 if_errcntp[4];
+       /* powered on hours, updated at driver unload */
+       __u8 if_powerhour[2];
+       /* ASCII free-form comment field */
+       char if_comment[32];
+       /* Backwards compatible prefix for longer QLogic Serial Numbers */
+       char if_sprefix[4];
+       /* 82 bytes used, min flash size is 128 bytes */
+       __u8 if_future[46];
+};
+
+/*
+ * These are the counters implemented in the chip, and are listed in order.
+ * The InterCaps naming is taken straight from the chip spec.
+ */
+struct qlogic_ib_counters {
+       __u64 LBIntCnt;
+       __u64 LBFlowStallCnt;
+       __u64 TxSDmaDescCnt;    /* was Reserved1 */
+       __u64 TxUnsupVLErrCnt;
+       __u64 TxDataPktCnt;
+       __u64 TxFlowPktCnt;
+       __u64 TxDwordCnt;
+       __u64 TxLenErrCnt;
+       __u64 TxMaxMinLenErrCnt;
+       __u64 TxUnderrunCnt;
+       __u64 TxFlowStallCnt;
+       __u64 TxDroppedPktCnt;
+       __u64 RxDroppedPktCnt;
+       __u64 RxDataPktCnt;
+       __u64 RxFlowPktCnt;
+       __u64 RxDwordCnt;
+       __u64 RxLenErrCnt;
+       __u64 RxMaxMinLenErrCnt;
+       __u64 RxICRCErrCnt;
+       __u64 RxVCRCErrCnt;
+       __u64 RxFlowCtrlErrCnt;
+       __u64 RxBadFormatCnt;
+       __u64 RxLinkProblemCnt;
+       __u64 RxEBPCnt;
+       __u64 RxLPCRCErrCnt;
+       __u64 RxBufOvflCnt;
+       __u64 RxTIDFullErrCnt;
+       __u64 RxTIDValidErrCnt;
+       __u64 RxPKeyMismatchCnt;
+       __u64 RxP0HdrEgrOvflCnt;
+       __u64 RxP1HdrEgrOvflCnt;
+       __u64 RxP2HdrEgrOvflCnt;
+       __u64 RxP3HdrEgrOvflCnt;
+       __u64 RxP4HdrEgrOvflCnt;
+       __u64 RxP5HdrEgrOvflCnt;
+       __u64 RxP6HdrEgrOvflCnt;
+       __u64 RxP7HdrEgrOvflCnt;
+       __u64 RxP8HdrEgrOvflCnt;
+       __u64 RxP9HdrEgrOvflCnt;
+       __u64 RxP10HdrEgrOvflCnt;
+       __u64 RxP11HdrEgrOvflCnt;
+       __u64 RxP12HdrEgrOvflCnt;
+       __u64 RxP13HdrEgrOvflCnt;
+       __u64 RxP14HdrEgrOvflCnt;
+       __u64 RxP15HdrEgrOvflCnt;
+       __u64 RxP16HdrEgrOvflCnt;
+       __u64 IBStatusChangeCnt;
+       __u64 IBLinkErrRecoveryCnt;
+       __u64 IBLinkDownedCnt;
+       __u64 IBSymbolErrCnt;
+       __u64 RxVL15DroppedPktCnt;
+       __u64 RxOtherLocalPhyErrCnt;
+       __u64 PcieRetryBufDiagQwordCnt;
+       __u64 ExcessBufferOvflCnt;
+       __u64 LocalLinkIntegrityErrCnt;
+       __u64 RxVlErrCnt;
+       __u64 RxDlidFltrCnt;
+};
+
+/*
+ * The next set of defines are for packet headers, and chip register
+ * and memory bits that are visible to and/or used by user-mode software.
+ */
+
+/* RcvHdrFlags bits */
+#define QLOGIC_IB_RHF_LENGTH_MASK 0x7FF
+#define QLOGIC_IB_RHF_LENGTH_SHIFT 0
+#define QLOGIC_IB_RHF_RCVTYPE_MASK 0x7
+#define QLOGIC_IB_RHF_RCVTYPE_SHIFT 11
+#define QLOGIC_IB_RHF_EGRINDEX_MASK 0xFFF
+#define QLOGIC_IB_RHF_EGRINDEX_SHIFT 16
+#define QLOGIC_IB_RHF_SEQ_MASK 0xF
+#define QLOGIC_IB_RHF_SEQ_SHIFT 0
+#define QLOGIC_IB_RHF_HDRQ_OFFSET_MASK 0x7FF
+#define QLOGIC_IB_RHF_HDRQ_OFFSET_SHIFT 4
+#define QLOGIC_IB_RHF_H_ICRCERR   0x80000000
+#define QLOGIC_IB_RHF_H_VCRCERR   0x40000000
+#define QLOGIC_IB_RHF_H_PARITYERR 0x20000000
+#define QLOGIC_IB_RHF_H_LENERR    0x10000000
+#define QLOGIC_IB_RHF_H_MTUERR    0x08000000
+#define QLOGIC_IB_RHF_H_IHDRERR   0x04000000
+#define QLOGIC_IB_RHF_H_TIDERR    0x02000000
+#define QLOGIC_IB_RHF_H_MKERR     0x01000000
+#define QLOGIC_IB_RHF_H_IBERR     0x00800000
+#define QLOGIC_IB_RHF_H_ERR_MASK  0xFF800000
+#define QLOGIC_IB_RHF_L_USE_EGR   0x80000000
+#define QLOGIC_IB_RHF_L_SWA       0x00008000
+#define QLOGIC_IB_RHF_L_SWB       0x00004000
+
+/* qlogic_ib header fields */
+#define QLOGIC_IB_I_VERS_MASK 0xF
+#define QLOGIC_IB_I_VERS_SHIFT 28
+#define QLOGIC_IB_I_CTXT_MASK 0xF
+#define QLOGIC_IB_I_CTXT_SHIFT 24
+#define QLOGIC_IB_I_TID_MASK 0x7FF
+#define QLOGIC_IB_I_TID_SHIFT 13
+#define QLOGIC_IB_I_OFFSET_MASK 0x1FFF
+#define QLOGIC_IB_I_OFFSET_SHIFT 0
+
+/* K_PktFlags bits */
+#define QLOGIC_IB_KPF_INTR 0x1
+#define QLOGIC_IB_KPF_SUBCTXT_MASK 0x3
+#define QLOGIC_IB_KPF_SUBCTXT_SHIFT 1
+
+#define QLOGIC_IB_MAX_SUBCTXT   4
+
+/* SendPIO per-buffer control */
+#define QLOGIC_IB_SP_TEST    0x40
+#define QLOGIC_IB_SP_TESTEBP 0x20
+#define QLOGIC_IB_SP_TRIGGER_SHIFT  15
+
+/* SendPIOAvail bits */
+#define QLOGIC_IB_SENDPIOAVAIL_BUSY_SHIFT 1
+#define QLOGIC_IB_SENDPIOAVAIL_CHECK_SHIFT 0
+
+/* qlogic_ib header format */
+struct qib_header {
+       /*
+        * Version - 4 bits, Context - 4 bits, TID - 10 bits and Offset -
+        * 14 bits before ECO change ~28 Dec 03.  After that, Vers 4,
+        * Context 4, TID 11, offset 13.
+        */
+       __le32 ver_ctxt_tid_offset;
+       __le16 chksum;
+       __le16 pkt_flags;
+};
+
+/*
+ * qlogic_ib user message header format.
+ * This structure contains the first 4 fields common to all protocols
+ * that employ qlogic_ib.
+ */
+struct qib_message_header {
+       __be16 lrh[4];
+       __be32 bth[3];
+       /* fields below this point are in host byte order */
+       struct qib_header iph;
+       __u8 sub_opcode;
+};
+
+/* IB - LRH header consts */
+#define QIB_LRH_GRH 0x0003      /* 1. word of IB LRH - next header: GRH */
+#define QIB_LRH_BTH 0x0002      /* 1. word of IB LRH - next header: BTH */
+
+/* misc. */
+#define SIZE_OF_CRC 1
+
+#define QIB_DEFAULT_P_KEY 0xFFFF
+#define QIB_PERMISSIVE_LID 0xFFFF
+#define QIB_AETH_CREDIT_SHIFT 24
+#define QIB_AETH_CREDIT_MASK 0x1F
+#define QIB_AETH_CREDIT_INVAL 0x1F
+#define QIB_PSN_MASK 0xFFFFFF
+#define QIB_MSN_MASK 0xFFFFFF
+#define QIB_QPN_MASK 0xFFFFFF
+#define QIB_MULTICAST_LID_BASE 0xC000
+#define QIB_EAGER_TID_ID QLOGIC_IB_I_TID_MASK
+#define QIB_MULTICAST_QPN 0xFFFFFF
+
+/* Receive Header Queue: receive type (from qlogic_ib) */
+#define RCVHQ_RCV_TYPE_EXPECTED  0
+#define RCVHQ_RCV_TYPE_EAGER     1
+#define RCVHQ_RCV_TYPE_NON_KD    2
+#define RCVHQ_RCV_TYPE_ERROR     3
+
+#define QIB_HEADER_QUEUE_WORDS 9
+
+/* functions for extracting fields from rcvhdrq entries for the driver.
+ */
+static inline __u32 qib_hdrget_err_flags(const __le32 *rbuf)
+{
+       return __le32_to_cpu(rbuf[1]) & QLOGIC_IB_RHF_H_ERR_MASK;
+}
+
+static inline __u32 qib_hdrget_rcv_type(const __le32 *rbuf)
+{
+       return (__le32_to_cpu(rbuf[0]) >> QLOGIC_IB_RHF_RCVTYPE_SHIFT) &
+               QLOGIC_IB_RHF_RCVTYPE_MASK;
+}
+
+static inline __u32 qib_hdrget_length_in_bytes(const __le32 *rbuf)
+{
+       return ((__le32_to_cpu(rbuf[0]) >> QLOGIC_IB_RHF_LENGTH_SHIFT) &
+               QLOGIC_IB_RHF_LENGTH_MASK) << 2;
+}
+
+static inline __u32 qib_hdrget_index(const __le32 *rbuf)
+{
+       return (__le32_to_cpu(rbuf[0]) >> QLOGIC_IB_RHF_EGRINDEX_SHIFT) &
+               QLOGIC_IB_RHF_EGRINDEX_MASK;
+}
+
+static inline __u32 qib_hdrget_seq(const __le32 *rbuf)
+{
+       return (__le32_to_cpu(rbuf[1]) >> QLOGIC_IB_RHF_SEQ_SHIFT) &
+               QLOGIC_IB_RHF_SEQ_MASK;
+}
+
+static inline __u32 qib_hdrget_offset(const __le32 *rbuf)
+{
+       return (__le32_to_cpu(rbuf[1]) >> QLOGIC_IB_RHF_HDRQ_OFFSET_SHIFT) &
+               QLOGIC_IB_RHF_HDRQ_OFFSET_MASK;
+}
+
+static inline __u32 qib_hdrget_use_egr_buf(const __le32 *rbuf)
+{
+       return __le32_to_cpu(rbuf[0]) & QLOGIC_IB_RHF_L_USE_EGR;
+}
+
+static inline __u32 qib_hdrget_qib_ver(__le32 hdrword)
+{
+       return (__le32_to_cpu(hdrword) >> QLOGIC_IB_I_VERS_SHIFT) &
+               QLOGIC_IB_I_VERS_MASK;
+}
+
+#endif                          /* _QIB_COMMON_H */
diff --git a/drivers/infiniband/hw/qib/qib_cq.c b/drivers/infiniband/hw/qib/qib_cq.c
new file mode 100644 (file)
index 0000000..a86cbf8
--- /dev/null
@@ -0,0 +1,484 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2010 QLogic Corporation. All rights reserved.
+ * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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/err.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#include "qib_verbs.h"
+
+/**
+ * qib_cq_enter - add a new entry to the completion queue
+ * @cq: completion queue
+ * @entry: work completion entry to add
+ * @sig: true if @entry is a solicitated entry
+ *
+ * This may be called with qp->s_lock held.
+ */
+void qib_cq_enter(struct qib_cq *cq, struct ib_wc *entry, int solicited)
+{
+       struct qib_cq_wc *wc;
+       unsigned long flags;
+       u32 head;
+       u32 next;
+
+       spin_lock_irqsave(&cq->lock, flags);
+
+       /*
+        * Note that the head pointer might be writable by user processes.
+        * Take care to verify it is a sane value.
+        */
+       wc = cq->queue;
+       head = wc->head;
+       if (head >= (unsigned) cq->ibcq.cqe) {
+               head = cq->ibcq.cqe;
+               next = 0;
+       } else
+               next = head + 1;
+       if (unlikely(next == wc->tail)) {
+               spin_unlock_irqrestore(&cq->lock, flags);
+               if (cq->ibcq.event_handler) {
+                       struct ib_event ev;
+
+                       ev.device = cq->ibcq.device;
+                       ev.element.cq = &cq->ibcq;
+                       ev.event = IB_EVENT_CQ_ERR;
+                       cq->ibcq.event_handler(&ev, cq->ibcq.cq_context);
+               }
+               return;
+       }
+       if (cq->ip) {
+               wc->uqueue[head].wr_id = entry->wr_id;
+               wc->uqueue[head].status = entry->status;
+               wc->uqueue[head].opcode = entry->opcode;
+               wc->uqueue[head].vendor_err = entry->vendor_err;
+               wc->uqueue[head].byte_len = entry->byte_len;
+               wc->uqueue[head].ex.imm_data =
+                       (__u32 __force)entry->ex.imm_data;
+               wc->uqueue[head].qp_num = entry->qp->qp_num;
+               wc->uqueue[head].src_qp = entry->src_qp;
+               wc->uqueue[head].wc_flags = entry->wc_flags;
+               wc->uqueue[head].pkey_index = entry->pkey_index;
+               wc->uqueue[head].slid = entry->slid;
+               wc->uqueue[head].sl = entry->sl;
+               wc->uqueue[head].dlid_path_bits = entry->dlid_path_bits;
+               wc->uqueue[head].port_num = entry->port_num;
+               /* Make sure entry is written before the head index. */
+               smp_wmb();
+       } else
+               wc->kqueue[head] = *entry;
+       wc->head = next;
+
+       if (cq->notify == IB_CQ_NEXT_COMP ||
+           (cq->notify == IB_CQ_SOLICITED && solicited)) {
+               cq->notify = IB_CQ_NONE;
+               cq->triggered++;
+               /*
+                * This will cause send_complete() to be called in
+                * another thread.
+                */
+               queue_work(qib_cq_wq, &cq->comptask);
+       }
+
+       spin_unlock_irqrestore(&cq->lock, flags);
+}
+
+/**
+ * qib_poll_cq - poll for work completion entries
+ * @ibcq: the completion queue to poll
+ * @num_entries: the maximum number of entries to return
+ * @entry: pointer to array where work completions are placed
+ *
+ * Returns the number of completion entries polled.
+ *
+ * This may be called from interrupt context.  Also called by ib_poll_cq()
+ * in the generic verbs code.
+ */
+int qib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
+{
+       struct qib_cq *cq = to_icq(ibcq);
+       struct qib_cq_wc *wc;
+       unsigned long flags;
+       int npolled;
+       u32 tail;
+
+       /* The kernel can only poll a kernel completion queue */
+       if (cq->ip) {
+               npolled = -EINVAL;
+               goto bail;
+       }
+
+       spin_lock_irqsave(&cq->lock, flags);
+
+       wc = cq->queue;
+       tail = wc->tail;
+       if (tail > (u32) cq->ibcq.cqe)
+               tail = (u32) cq->ibcq.cqe;
+       for (npolled = 0; npolled < num_entries; ++npolled, ++entry) {
+               if (tail == wc->head)
+                       break;
+               /* The kernel doesn't need a RMB since it has the lock. */
+               *entry = wc->kqueue[tail];
+               if (tail >= cq->ibcq.cqe)
+                       tail = 0;
+               else
+                       tail++;
+       }
+       wc->tail = tail;
+
+       spin_unlock_irqrestore(&cq->lock, flags);
+
+bail:
+       return npolled;
+}
+
+static void send_complete(struct work_struct *work)
+{
+       struct qib_cq *cq = container_of(work, struct qib_cq, comptask);
+
+       /*
+        * The completion handler will most likely rearm the notification
+        * and poll for all pending entries.  If a new completion entry
+        * is added while we are in this routine, queue_work()
+        * won't call us again until we return so we check triggered to
+        * see if we need to call the handler again.
+        */
+       for (;;) {
+               u8 triggered = cq->triggered;
+
+               /*
+                * IPoIB connected mode assumes the callback is from a
+                * soft IRQ. We simulate this by blocking "bottom halves".
+                * See the implementation for ipoib_cm_handle_tx_wc(),
+                * netif_tx_lock_bh() and netif_tx_lock().
+                */
+               local_bh_disable();
+               cq->ibcq.comp_handler(&cq->ibcq, cq->ibcq.cq_context);
+               local_bh_enable();
+
+               if (cq->triggered == triggered)
+                       return;
+       }
+}
+
+/**
+ * qib_create_cq - create a completion queue
+ * @ibdev: the device this completion queue is attached to
+ * @entries: the minimum size of the completion queue
+ * @context: unused by the QLogic_IB driver
+ * @udata: user data for libibverbs.so
+ *
+ * Returns a pointer to the completion queue or negative errno values
+ * for failure.
+ *
+ * Called by ib_create_cq() in the generic verbs code.
+ */
+struct ib_cq *qib_create_cq(struct ib_device *ibdev, int entries,
+                           int comp_vector, struct ib_ucontext *context,
+                           struct ib_udata *udata)
+{
+       struct qib_ibdev *dev = to_idev(ibdev);
+       struct qib_cq *cq;
+       struct qib_cq_wc *wc;
+       struct ib_cq *ret;
+       u32 sz;
+
+       if (entries < 1 || entries > ib_qib_max_cqes) {
+               ret = ERR_PTR(-EINVAL);
+               goto done;
+       }
+
+       /* Allocate the completion queue structure. */
+       cq = kmalloc(sizeof(*cq), GFP_KERNEL);
+       if (!cq) {
+               ret = ERR_PTR(-ENOMEM);
+               goto done;
+       }
+
+       /*
+        * Allocate the completion queue entries and head/tail pointers.
+        * This is allocated separately so that it can be resized and
+        * also mapped into user space.
+        * We need to use vmalloc() in order to support mmap and large
+        * numbers of entries.
+        */
+       sz = sizeof(*wc);
+       if (udata && udata->outlen >= sizeof(__u64))
+               sz += sizeof(struct ib_uverbs_wc) * (entries + 1);
+       else
+               sz += sizeof(struct ib_wc) * (entries + 1);
+       wc = vmalloc_user(sz);
+       if (!wc) {
+               ret = ERR_PTR(-ENOMEM);
+               goto bail_cq;
+       }
+
+       /*
+        * Return the address of the WC as the offset to mmap.
+        * See qib_mmap() for details.
+        */
+       if (udata && udata->outlen >= sizeof(__u64)) {
+               int err;
+
+               cq->ip = qib_create_mmap_info(dev, sz, context, wc);
+               if (!cq->ip) {
+                       ret = ERR_PTR(-ENOMEM);
+                       goto bail_wc;
+               }
+
+               err = ib_copy_to_udata(udata, &cq->ip->offset,
+                                      sizeof(cq->ip->offset));
+               if (err) {
+                       ret = ERR_PTR(err);
+                       goto bail_ip;
+               }
+       } else
+               cq->ip = NULL;
+
+       spin_lock(&dev->n_cqs_lock);
+       if (dev->n_cqs_allocated == ib_qib_max_cqs) {
+               spin_unlock(&dev->n_cqs_lock);
+               ret = ERR_PTR(-ENOMEM);
+               goto bail_ip;
+       }
+
+       dev->n_cqs_allocated++;
+       spin_unlock(&dev->n_cqs_lock);
+
+       if (cq->ip) {
+               spin_lock_irq(&dev->pending_lock);
+               list_add(&cq->ip->pending_mmaps, &dev->pending_mmaps);
+               spin_unlock_irq(&dev->pending_lock);
+       }
+
+       /*
+        * ib_create_cq() will initialize cq->ibcq except for cq->ibcq.cqe.
+        * The number of entries should be >= the number requested or return
+        * an error.
+        */
+       cq->ibcq.cqe = entries;
+       cq->notify = IB_CQ_NONE;
+       cq->triggered = 0;
+       spin_lock_init(&cq->lock);
+       INIT_WORK(&cq->comptask, send_complete);
+       wc->head = 0;
+       wc->tail = 0;
+       cq->queue = wc;
+
+       ret = &cq->ibcq;
+
+       goto done;
+
+bail_ip:
+       kfree(cq->ip);
+bail_wc:
+       vfree(wc);
+bail_cq:
+       kfree(cq);
+done:
+       return ret;
+}
+
+/**
+ * qib_destroy_cq - destroy a completion queue
+ * @ibcq: the completion queue to destroy.
+ *
+ * Returns 0 for success.
+ *
+ * Called by ib_destroy_cq() in the generic verbs code.
+ */
+int qib_destroy_cq(struct ib_cq *ibcq)
+{
+       struct qib_ibdev *dev = to_idev(ibcq->device);
+       struct qib_cq *cq = to_icq(ibcq);
+
+       flush_work(&cq->comptask);
+       spin_lock(&dev->n_cqs_lock);
+       dev->n_cqs_allocated--;
+       spin_unlock(&dev->n_cqs_lock);
+       if (cq->ip)
+               kref_put(&cq->ip->ref, qib_release_mmap_info);
+       else
+               vfree(cq->queue);
+       kfree(cq);
+
+       return 0;
+}
+
+/**
+ * qib_req_notify_cq - change the notification type for a completion queue
+ * @ibcq: the completion queue
+ * @notify_flags: the type of notification to request
+ *
+ * Returns 0 for success.
+ *
+ * This may be called from interrupt context.  Also called by
+ * ib_req_notify_cq() in the generic verbs code.
+ */
+int qib_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags notify_flags)
+{
+       struct qib_cq *cq = to_icq(ibcq);
+       unsigned long flags;
+       int ret = 0;
+
+       spin_lock_irqsave(&cq->lock, flags);
+       /*
+        * Don't change IB_CQ_NEXT_COMP to IB_CQ_SOLICITED but allow
+        * any other transitions (see C11-31 and C11-32 in ch. 11.4.2.2).
+        */
+       if (cq->notify != IB_CQ_NEXT_COMP)
+               cq->notify = notify_flags & IB_CQ_SOLICITED_MASK;
+
+       if ((notify_flags & IB_CQ_REPORT_MISSED_EVENTS) &&
+           cq->queue->head != cq->queue->tail)
+               ret = 1;
+
+       spin_unlock_irqrestore(&cq->lock, flags);
+
+       return ret;
+}
+
+/**
+ * qib_resize_cq - change the size of the CQ
+ * @ibcq: the completion queue
+ *
+ * Returns 0 for success.
+ */
+int qib_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
+{
+       struct qib_cq *cq = to_icq(ibcq);
+       struct qib_cq_wc *old_wc;
+       struct qib_cq_wc *wc;
+       u32 head, tail, n;
+       int ret;
+       u32 sz;
+
+       if (cqe < 1 || cqe > ib_qib_max_cqes) {
+               ret = -EINVAL;
+               goto bail;
+       }
+
+       /*
+        * Need to use vmalloc() if we want to support large #s of entries.
+        */
+       sz = sizeof(*wc);
+       if (udata && udata->outlen >= sizeof(__u64))
+               sz += sizeof(struct ib_uverbs_wc) * (cqe + 1);
+       else
+               sz += sizeof(struct ib_wc) * (cqe + 1);
+       wc = vmalloc_user(sz);
+       if (!wc) {
+               ret = -ENOMEM;
+               goto bail;
+       }
+
+       /* Check that we can write the offset to mmap. */
+       if (udata && udata->outlen >= sizeof(__u64)) {
+               __u64 offset = 0;
+
+               ret = ib_copy_to_udata(udata, &offset, sizeof(offset));
+               if (ret)
+                       goto bail_free;
+       }
+
+       spin_lock_irq(&cq->lock);
+       /*
+        * Make sure head and tail are sane since they
+        * might be user writable.
+        */
+       old_wc = cq->queue;
+       head = old_wc->head;
+       if (head > (u32) cq->ibcq.cqe)
+               head = (u32) cq->ibcq.cqe;
+       tail = old_wc->tail;
+       if (tail > (u32) cq->ibcq.cqe)
+               tail = (u32) cq->ibcq.cqe;
+       if (head < tail)
+               n = cq->ibcq.cqe + 1 + head - tail;
+       else
+               n = head - tail;
+       if (unlikely((u32)cqe < n)) {
+               ret = -EINVAL;
+               goto bail_unlock;
+       }
+       for (n = 0; tail != head; n++) {
+               if (cq->ip)
+                       wc->uqueue[n] = old_wc->uqueue[tail];
+               else
+                       wc->kqueue[n] = old_wc->kqueue[tail];
+               if (tail == (u32) cq->ibcq.cqe)
+                       tail = 0;
+               else
+                       tail++;
+       }
+       cq->ibcq.cqe = cqe;
+       wc->head = n;
+       wc->tail = 0;
+       cq->queue = wc;
+       spin_unlock_irq(&cq->lock);
+
+       vfree(old_wc);
+
+       if (cq->ip) {
+               struct qib_ibdev *dev = to_idev(ibcq->device);
+               struct qib_mmap_info *ip = cq->ip;
+
+               qib_update_mmap_info(dev, ip, sz, wc);
+
+               /*
+                * Return the offset to mmap.
+                * See qib_mmap() for details.
+                */
+               if (udata && udata->outlen >= sizeof(__u64)) {
+                       ret = ib_copy_to_udata(udata, &ip->offset,
+                                              sizeof(ip->offset));
+                       if (ret)
+                               goto bail;
+               }
+
+               spin_lock_irq(&dev->pending_lock);
+               if (list_empty(&ip->pending_mmaps))
+                       list_add(&ip->pending_mmaps, &dev->pending_mmaps);
+               spin_unlock_irq(&dev->pending_lock);
+       }
+
+       ret = 0;
+       goto bail;
+
+bail_unlock:
+       spin_unlock_irq(&cq->lock);
+bail_free:
+       vfree(wc);
+bail:
+       return ret;
+}
diff --git a/drivers/infiniband/hw/qib/qib_diag.c b/drivers/infiniband/hw/qib/qib_diag.c
new file mode 100644 (file)
index 0000000..ca98dd5
--- /dev/null
@@ -0,0 +1,894 @@
+/*
+ * Copyright (c) 2010 QLogic Corporation. All rights reserved.
+ * Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved.
+ * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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.
+ */
+
+/*
+ * This file contains support for diagnostic functions.  It is accessed by
+ * opening the qib_diag device, normally minor number 129.  Diagnostic use
+ * of the QLogic_IB chip may render the chip or board unusable until the
+ * driver is unloaded, or in some cases, until the system is rebooted.
+ *
+ * Accesses to the chip through this interface are not similar to going
+ * through the /sys/bus/pci resource mmap interface.
+ */
+
+#include <linux/io.h>
+#include <linux/pci.h>
+#include <linux/poll.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+
+#include "qib.h"
+#include "qib_common.h"
+
+/*
+ * Each client that opens the diag device must read then write
+ * offset 0, to prevent lossage from random cat or od. diag_state
+ * sequences this "handshake".
+ */
+enum diag_state { UNUSED = 0, OPENED, INIT, READY };
+
+/* State for an individual client. PID so children cannot abuse handshake */
+static struct qib_diag_client {
+       struct qib_diag_client *next;
+       struct qib_devdata *dd;
+       pid_t pid;
+       enum diag_state state;
+} *client_pool;
+
+/*
+ * Get a client struct. Recycled if possible, else kmalloc.
+ * Must be called with qib_mutex held
+ */
+static struct qib_diag_client *get_client(struct qib_devdata *dd)
+{
+       struct qib_diag_client *dc;
+
+       dc = client_pool;
+       if (dc)
+               /* got from pool remove it and use */
+               client_pool = dc->next;
+       else
+               /* None in pool, alloc and init */
+               dc = kmalloc(sizeof *dc, GFP_KERNEL);
+
+       if (dc) {
+               dc->next = NULL;
+               dc->dd = dd;
+               dc->pid = current->pid;
+               dc->state = OPENED;
+       }
+       return dc;
+}
+
+/*
+ * Return to pool. Must be called with qib_mutex held
+ */
+static void return_client(struct qib_diag_client *dc)
+{
+       struct qib_devdata *dd = dc->dd;
+       struct qib_diag_client *tdc, *rdc;
+
+       rdc = NULL;
+       if (dc == dd->diag_client) {
+               dd->diag_client = dc->next;
+               rdc = dc;
+       } else {
+               tdc = dc->dd->diag_client;
+               while (tdc) {
+                       if (dc == tdc->next) {
+                               tdc->next = dc->next;
+                               rdc = dc;
+                               break;
+                       }
+                       tdc = tdc->next;
+               }
+       }
+       if (rdc) {
+               rdc->state = UNUSED;
+               rdc->dd = NULL;
+               rdc->pid = 0;
+               rdc->next = client_pool;
+               client_pool = rdc;
+       }
+}
+
+static int qib_diag_open(struct inode *in, struct file *fp);
+static int qib_diag_release(struct inode *in, struct file *fp);
+static ssize_t qib_diag_read(struct file *fp, char __user *data,
+                            size_t count, loff_t *off);
+static ssize_t qib_diag_write(struct file *fp, const char __user *data,
+                             size_t count, loff_t *off);
+
+static const struct file_operations diag_file_ops = {
+       .owner = THIS_MODULE,
+       .write = qib_diag_write,
+       .read = qib_diag_read,
+       .open = qib_diag_open,
+       .release = qib_diag_release
+};
+
+static atomic_t diagpkt_count = ATOMIC_INIT(0);
+static struct cdev *diagpkt_cdev;
+static struct device *diagpkt_device;
+
+static ssize_t qib_diagpkt_write(struct file *fp, const char __user *data,
+                                size_t count, loff_t *off);
+
+static const struct file_operations diagpkt_file_ops = {
+       .owner = THIS_MODULE,
+       .write = qib_diagpkt_write,
+};
+
+int qib_diag_add(struct qib_devdata *dd)
+{
+       char name[16];
+       int ret = 0;
+
+       if (atomic_inc_return(&diagpkt_count) == 1) {
+               ret = qib_cdev_init(QIB_DIAGPKT_MINOR, "ipath_diagpkt",
+                                   &diagpkt_file_ops, &diagpkt_cdev,
+                                   &diagpkt_device);
+               if (ret)
+                       goto done;
+       }
+
+       snprintf(name, sizeof(name), "ipath_diag%d", dd->unit);
+       ret = qib_cdev_init(QIB_DIAG_MINOR_BASE + dd->unit, name,
+                           &diag_file_ops, &dd->diag_cdev,
+                           &dd->diag_device);
+done:
+       return ret;
+}
+
+static void qib_unregister_observers(struct qib_devdata *dd);
+
+void qib_diag_remove(struct qib_devdata *dd)
+{
+       struct qib_diag_client *dc;
+
+       if (atomic_dec_and_test(&diagpkt_count))
+               qib_cdev_cleanup(&diagpkt_cdev, &diagpkt_device);
+
+       qib_cdev_cleanup(&dd->diag_cdev, &dd->diag_device);
+
+       /*
+        * Return all diag_clients of this device. There should be none,
+        * as we are "guaranteed" that no clients are still open
+        */
+       while (dd->diag_client)
+               return_client(dd->diag_client);
+
+       /* Now clean up all unused client structs */
+       while (client_pool) {
+               dc = client_pool;
+               client_pool = dc->next;
+               kfree(dc);
+       }
+       /* Clean up observer list */
+       qib_unregister_observers(dd);
+}
+
+/* qib_remap_ioaddr32 - remap an offset into chip address space to __iomem *
+ *
+ * @dd: the qlogic_ib device
+ * @offs: the offset in chip-space
+ * @cntp: Pointer to max (byte) count for transfer starting at offset
+ * This returns a u32 __iomem * so it can be used for both 64 and 32-bit
+ * mapping. It is needed because with the use of PAT for control of
+ * write-combining, the logically contiguous address-space of the chip
+ * may be split into virtually non-contiguous spaces, with different
+ * attributes, which are them mapped to contiguous physical space
+ * based from the first BAR.
+ *
+ * The code below makes the same assumptions as were made in
+ * init_chip_wc_pat() (qib_init.c), copied here:
+ * Assumes chip address space looks like:
+ *             - kregs + sregs + cregs + uregs (in any order)
+ *             - piobufs (2K and 4K bufs in either order)
+ *     or:
+ *             - kregs + sregs + cregs (in any order)
+ *             - piobufs (2K and 4K bufs in either order)
+ *             - uregs
+ *
+ * If cntp is non-NULL, returns how many bytes from offset can be accessed
+ * Returns 0 if the offset is not mapped.
+ */
+static u32 __iomem *qib_remap_ioaddr32(struct qib_devdata *dd, u32 offset,
+                                      u32 *cntp)
+{
+       u32 kreglen;
+       u32 snd_bottom, snd_lim = 0;
+       u32 __iomem *krb32 = (u32 __iomem *)dd->kregbase;
+       u32 __iomem *map = NULL;
+       u32 cnt = 0;
+
+       /* First, simplest case, offset is within the first map. */
+       kreglen = (dd->kregend - dd->kregbase) * sizeof(u64);
+       if (offset < kreglen) {
+               map = krb32 + (offset / sizeof(u32));
+               cnt = kreglen - offset;
+               goto mapped;
+       }
+
+       /*
+        * Next check for user regs, the next most common case,
+        * and a cheap check because if they are not in the first map
+        * they are last in chip.
+        */
+       if (dd->userbase) {
+               /* If user regs mapped, they are after send, so set limit. */
+               u32 ulim = (dd->cfgctxts * dd->ureg_align) + dd->uregbase;
+               snd_lim = dd->uregbase;
+               krb32 = (u32 __iomem *)dd->userbase;
+               if (offset >= dd->uregbase && offset < ulim) {
+                       map = krb32 + (offset - dd->uregbase) / sizeof(u32);
+                       cnt = ulim - offset;
+                       goto mapped;
+               }
+       }
+
+       /*
+        * Lastly, check for offset within Send Buffers.
+        * This is gnarly because struct devdata is deliberately vague
+        * about things like 7322 VL15 buffers, and we are not in
+        * chip-specific code here, so should not make many assumptions.
+        * The one we _do_ make is that the only chip that has more sndbufs
+        * than we admit is the 7322, and it has userregs above that, so
+        * we know the snd_lim.
+        */
+       /* Assume 2K buffers are first. */
+       snd_bottom = dd->pio2k_bufbase;
+       if (snd_lim == 0) {
+               u32 tot2k = dd->piobcnt2k * ALIGN(dd->piosize2k, dd->palign);
+               snd_lim = snd_bottom + tot2k;
+       }
+       /* If 4k buffers exist, account for them by bumping
+        * appropriate limit.
+        */
+       if (dd->piobcnt4k) {
+               u32 tot4k = dd->piobcnt4k * dd->align4k;
+               u32 offs4k = dd->piobufbase >> 32;
+               if (snd_bottom > offs4k)
+                       snd_bottom = offs4k;
+               else {
+                       /* 4k above 2k. Bump snd_lim, if needed*/
+                       if (!dd->userbase)
+                               snd_lim = offs4k + tot4k;
+               }
+       }
+       /*
+        * Judgement call: can we ignore the space between SendBuffs and
+        * UserRegs, where we would like to see vl15 buffs, but not more?
+        */
+       if (offset >= snd_bottom && offset < snd_lim) {
+               offset -= snd_bottom;
+               map = (u32 __iomem *)dd->piobase + (offset / sizeof(u32));
+               cnt = snd_lim - offset;
+       }
+
+mapped:
+       if (cntp)
+               *cntp = cnt;
+       return map;
+}
+
+/*
+ * qib_read_umem64 - read a 64-bit quantity from the chip into user space
+ * @dd: the qlogic_ib device
+ * @uaddr: the location to store the data in user memory
+ * @regoffs: the offset from BAR0 (_NOT_ full pointer, anymore)
+ * @count: number of bytes to copy (multiple of 32 bits)
+ *
+ * This function also localizes all chip memory accesses.
+ * The copy should be written such that we read full cacheline packets
+ * from the chip.  This is usually used for a single qword
+ *
+ * NOTE:  This assumes the chip address is 64-bit aligned.
+ */
+static int qib_read_umem64(struct qib_devdata *dd, void __user *uaddr,
+                          u32 regoffs, size_t count)
+{
+       const u64 __iomem *reg_addr;
+       const u64 __iomem *reg_end;
+       u32 limit;
+       int ret;
+
+       reg_addr = (const u64 __iomem *)qib_remap_ioaddr32(dd, regoffs, &limit);
+       if (reg_addr == NULL || limit == 0 || !(dd->flags & QIB_PRESENT)) {
+               ret = -EINVAL;
+               goto bail;
+       }
+       if (count >= limit)
+               count = limit;
+       reg_end = reg_addr + (count / sizeof(u64));
+
+       /* not very efficient, but it works for now */
+       while (reg_addr < reg_end) {
+               u64 data = readq(reg_addr);
+
+               if (copy_to_user(uaddr, &data, sizeof(u64))) {
+                       ret = -EFAULT;
+                       goto bail;
+               }
+               reg_addr++;
+               uaddr += sizeof(u64);
+       }
+       ret = 0;
+bail:
+       return ret;
+}
+
+/*
+ * qib_write_umem64 - write a 64-bit quantity to the chip from user space
+ * @dd: the qlogic_ib device
+ * @regoffs: the offset from BAR0 (_NOT_ full pointer, anymore)
+ * @uaddr: the source of the data in user memory
+ * @count: the number of bytes to copy (multiple of 32 bits)
+ *
+ * This is usually used for a single qword
+ * NOTE:  This assumes the chip address is 64-bit aligned.
+ */
+
+static int qib_write_umem64(struct qib_devdata *dd, u32 regoffs,
+                           const void __user *uaddr, size_t count)
+{
+       u64 __iomem *reg_addr;
+       const u64 __iomem *reg_end;
+       u32 limit;
+       int ret;
+
+       reg_addr = (u64 __iomem *)qib_remap_ioaddr32(dd, regoffs, &limit);
+       if (reg_addr == NULL || limit == 0 || !(dd->flags & QIB_PRESENT)) {
+               ret = -EINVAL;
+               goto bail;
+       }
+       if (count >= limit)
+               count = limit;
+       reg_end = reg_addr + (count / sizeof(u64));
+
+       /* not very efficient, but it works for now */
+       while (reg_addr < reg_end) {
+               u64 data;
+               if (copy_from_user(&data, uaddr, sizeof(data))) {
+                       ret = -EFAULT;
+                       goto bail;
+               }
+               writeq(data, reg_addr);
+
+               reg_addr++;
+               uaddr += sizeof(u64);
+       }
+       ret = 0;
+bail:
+       return ret;
+}
+
+/*
+ * qib_read_umem32 - read a 32-bit quantity from the chip into user space
+ * @dd: the qlogic_ib device
+ * @uaddr: the location to store the data in user memory
+ * @regoffs: the offset from BAR0 (_NOT_ full pointer, anymore)
+ * @count: number of bytes to copy
+ *
+ * read 32 bit values, not 64 bit; for memories that only
+ * support 32 bit reads; usually a single dword.
+ */
+static int qib_read_umem32(struct qib_devdata *dd, void __user *uaddr,
+                          u32 regoffs, size_t count)
+{
+       const u32 __iomem *reg_addr;
+       const u32 __iomem *reg_end;
+       u32 limit;
+       int ret;
+
+       reg_addr = qib_remap_ioaddr32(dd, regoffs, &limit);
+       if (reg_addr == NULL || limit == 0 || !(dd->flags & QIB_PRESENT)) {
+               ret = -EINVAL;
+               goto bail;
+       }
+       if (count >= limit)
+               count = limit;
+       reg_end = reg_addr + (count / sizeof(u32));
+
+       /* not very efficient, but it works for now */
+       while (reg_addr < reg_end) {
+               u32 data = readl(reg_addr);
+
+               if (copy_to_user(uaddr, &data, sizeof(data))) {
+                       ret = -EFAULT;
+                       goto bail;
+               }
+
+               reg_addr++;
+               uaddr += sizeof(u32);
+
+       }
+       ret = 0;
+bail:
+       return ret;
+}
+
+/*
+ * qib_write_umem32 - write a 32-bit quantity to the chip from user space
+ * @dd: the qlogic_ib device
+ * @regoffs: the offset from BAR0 (_NOT_ full pointer, anymore)
+ * @uaddr: the source of the data in user memory
+ * @count: number of bytes to copy
+ *
+ * write 32 bit values, not 64 bit; for memories that only
+ * support 32 bit write; usually a single dword.
+ */
+
+static int qib_write_umem32(struct qib_devdata *dd, u32 regoffs,
+                           const void __user *uaddr, size_t count)
+{
+       u32 __iomem *reg_addr;
+       const u32 __iomem *reg_end;
+       u32 limit;
+       int ret;
+
+       reg_addr = qib_remap_ioaddr32(dd, regoffs, &limit);
+       if (reg_addr == NULL || limit == 0 || !(dd->flags & QIB_PRESENT)) {
+               ret = -EINVAL;
+               goto bail;
+       }
+       if (count >= limit)
+               count = limit;
+       reg_end = reg_addr + (count / sizeof(u32));
+
+       while (reg_addr < reg_end) {
+               u32 data;
+
+               if (copy_from_user(&data, uaddr, sizeof(data))) {
+                       ret = -EFAULT;
+                       goto bail;
+               }
+               writel(data, reg_addr);
+
+               reg_addr++;
+               uaddr += sizeof(u32);
+       }
+       ret = 0;
+bail:
+       return ret;
+}
+
+static int qib_diag_open(struct inode *in, struct file *fp)
+{
+       int unit = iminor(in) - QIB_DIAG_MINOR_BASE;
+       struct qib_devdata *dd;
+       struct qib_diag_client *dc;
+       int ret;
+
+       mutex_lock(&qib_mutex);
+
+       dd = qib_lookup(unit);
+
+       if (dd == NULL || !(dd->flags & QIB_PRESENT) ||
+           !dd->kregbase) {
+               ret = -ENODEV;
+               goto bail;
+       }
+
+       dc = get_client(dd);
+       if (!dc) {
+               ret = -ENOMEM;
+               goto bail;
+       }
+       dc->next = dd->diag_client;
+       dd->diag_client = dc;
+       fp->private_data = dc;
+       ret = 0;
+bail:
+       mutex_unlock(&qib_mutex);
+
+       return ret;
+}
+
+/**
+ * qib_diagpkt_write - write an IB packet
+ * @fp: the diag data device file pointer
+ * @data: qib_diag_pkt structure saying where to get the packet
+ * @count: size of data to write
+ * @off: unused by this code
+ */
+static ssize_t qib_diagpkt_write(struct file *fp,
+                                const char __user *data,
+                                size_t count, loff_t *off)
+{
+       u32 __iomem *piobuf;
+       u32 plen, clen, pbufn;
+       struct qib_diag_xpkt dp;
+       u32 *tmpbuf = NULL;
+       struct qib_devdata *dd;
+       struct qib_pportdata *ppd;
+       ssize_t ret = 0;
+
+       if (count != sizeof(dp)) {
+               ret = -EINVAL;
+               goto bail;
+       }
+       if (copy_from_user(&dp, data, sizeof(dp))) {
+               ret = -EFAULT;
+               goto bail;
+       }
+
+       dd = qib_lookup(dp.unit);
+       if (!dd || !(dd->flags & QIB_PRESENT) || !dd->kregbase) {
+               ret = -ENODEV;
+               goto bail;
+       }
+       if (!(dd->flags & QIB_INITTED)) {
+               /* no hardware, freeze, etc. */
+               ret = -ENODEV;
+               goto bail;
+       }
+
+       if (dp.version != _DIAG_XPKT_VERS) {
+               qib_dev_err(dd, "Invalid version %u for diagpkt_write\n",
+                           dp.version);
+               ret = -EINVAL;
+               goto bail;
+       }
+       /* send count must be an exact number of dwords */
+       if (dp.len & 3) {
+               ret = -EINVAL;
+               goto bail;
+       }
+       if (!dp.port || dp.port > dd->num_pports) {
+               ret = -EINVAL;
+               goto bail;
+       }
+       ppd = &dd->pport[dp.port - 1];
+
+       /* need total length before first word written */
+       /* +1 word is for the qword padding */
+       plen = sizeof(u32) + dp.len;
+       clen = dp.len >> 2;
+
+       if ((plen + 4) > ppd->ibmaxlen) {
+               ret = -EINVAL;
+               goto bail;      /* before writing pbc */
+       }
+       tmpbuf = vmalloc(plen);
+       if (!tmpbuf) {
+               qib_devinfo(dd->pcidev, "Unable to allocate tmp buffer, "
+                        "failing\n");
+               ret = -ENOMEM;
+               goto bail;
+       }
+
+       if (copy_from_user(tmpbuf,
+                          (const void __user *) (unsigned long) dp.data,
+                          dp.len)) {
+               ret = -EFAULT;
+               goto bail;
+       }
+
+       plen >>= 2;             /* in dwords */
+
+       if (dp.pbc_wd == 0)
+               dp.pbc_wd = plen;
+
+       piobuf = dd->f_getsendbuf(ppd, dp.pbc_wd, &pbufn);
+       if (!piobuf) {
+               ret = -EBUSY;
+               goto bail;
+       }
+       /* disarm it just to be extra sure */
+       dd->f_sendctrl(dd->pport, QIB_SENDCTRL_DISARM_BUF(pbufn));
+
+       /* disable header check on pbufn for this packet */
+       dd->f_txchk_change(dd, pbufn, 1, TXCHK_CHG_TYPE_DIS1, NULL);
+
+       writeq(dp.pbc_wd, piobuf);
+       /*
+        * Copy all but the trigger word, then flush, so it's written
+        * to chip before trigger word, then write trigger word, then
+        * flush again, so packet is sent.
+        */
+       if (dd->flags & QIB_PIO_FLUSH_WC) {
+               qib_flush_wc();
+               qib_pio_copy(piobuf + 2, tmpbuf, clen - 1);
+               qib_flush_wc();
+               __raw_writel(tmpbuf[clen - 1], piobuf + clen + 1);
+       } else
+               qib_pio_copy(piobuf + 2, tmpbuf, clen);
+
+       if (dd->flags & QIB_USE_SPCL_TRIG) {
+               u32 spcl_off = (pbufn >= dd->piobcnt2k) ? 2047 : 1023;
+
+               qib_flush_wc();
+               __raw_writel(0xaebecede, piobuf + spcl_off);
+       }
+
+       /*
+        * Ensure buffer is written to the chip, then re-enable
+        * header checks (if supported by chip).  The txchk
+        * code will ensure seen by chip before returning.
+        */
+       qib_flush_wc();
+       qib_sendbuf_done(dd, pbufn);
+       dd->f_txchk_change(dd, pbufn, 1, TXCHK_CHG_TYPE_ENAB1, NULL);
+
+       ret = sizeof(dp);
+
+bail:
+       vfree(tmpbuf);
+       return ret;
+}
+
+static int qib_diag_release(struct inode *in, struct file *fp)
+{
+       mutex_lock(&qib_mutex);
+       return_client(fp->private_data);
+       fp->private_data = NULL;
+       mutex_unlock(&qib_mutex);
+       return 0;
+}
+
+/*
+ * Chip-specific code calls to register its interest in
+ * a specific range.
+ */
+struct diag_observer_list_elt {
+       struct diag_observer_list_elt *next;
+       const struct diag_observer *op;
+};
+
+int qib_register_observer(struct qib_devdata *dd,
+                         const struct diag_observer *op)
+{
+       struct diag_observer_list_elt *olp;
+       int ret = -EINVAL;
+
+       if (!dd || !op)
+               goto bail;
+       ret = -ENOMEM;
+       olp = vmalloc(sizeof *olp);
+       if (!olp) {
+               printk(KERN_ERR QIB_DRV_NAME ": vmalloc for observer failed\n");
+               goto bail;
+       }
+       if (olp) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&dd->qib_diag_trans_lock, flags);
+               olp->op = op;
+               olp->next = dd->diag_observer_list;
+               dd->diag_observer_list = olp;
+               spin_unlock_irqrestore(&dd->qib_diag_trans_lock, flags);
+               ret = 0;
+       }
+bail:
+       return ret;
+}
+
+/* Remove all registered observers when device is closed */
+static void qib_unregister_observers(struct qib_devdata *dd)
+{
+       struct diag_observer_list_elt *olp;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dd->qib_diag_trans_lock, flags);
+       olp = dd->diag_observer_list;
+       while (olp) {
+               /* Pop one observer, let go of lock */
+               dd->diag_observer_list = olp->next;
+               spin_unlock_irqrestore(&dd->qib_diag_trans_lock, flags);
+               vfree(olp);
+               /* try again. */
+               spin_lock_irqsave(&dd->qib_diag_trans_lock, flags);
+               olp = dd->diag_observer_list;
+       }
+       spin_unlock_irqrestore(&dd->qib_diag_trans_lock, flags);
+}
+
+/*
+ * Find the observer, if any, for the specified address. Initial implementation
+ * is simple stack of observers. This must be called with diag transaction
+ * lock held.
+ */
+static const struct diag_observer *diag_get_observer(struct qib_devdata *dd,
+                                                    u32 addr)
+{
+       struct diag_observer_list_elt *olp;
+       const struct diag_observer *op = NULL;
+
+       olp = dd->diag_observer_list;
+       while (olp) {
+               op = olp->op;
+               if (addr >= op->bottom && addr <= op->top)
+                       break;
+               olp = olp->next;
+       }
+       if (!olp)
+               op = NULL;
+
+       return op;
+}
+
+static ssize_t qib_diag_read(struct file *fp, char __user *data,
+                            size_t count, loff_t *off)
+{
+       struct qib_diag_client *dc = fp->private_data;
+       struct qib_devdata *dd = dc->dd;
+       void __iomem *kreg_base;
+       ssize_t ret;
+
+       if (dc->pid != current->pid) {
+               ret = -EPERM;
+               goto bail;
+       }
+
+       kreg_base = dd->kregbase;
+
+       if (count == 0)
+               ret = 0;
+       else if ((count % 4) || (*off % 4))
+               /* address or length is not 32-bit aligned, hence invalid */
+               ret = -EINVAL;
+       else if (dc->state < READY && (*off || count != 8))
+               ret = -EINVAL;  /* prevent cat /dev/qib_diag* */
+       else {
+               unsigned long flags;
+               u64 data64 = 0;
+               int use_32;
+               const struct diag_observer *op;
+
+               use_32 = (count % 8) || (*off % 8);
+               ret = -1;
+               spin_lock_irqsave(&dd->qib_diag_trans_lock, flags);
+               /*
+                * Check for observer on this address range.
+                * we only support a single 32 or 64-bit read
+                * via observer, currently.
+                */
+               op = diag_get_observer(dd, *off);
+               if (op) {
+                       u32 offset = *off;
+                       ret = op->hook(dd, op, offset, &data64, 0, use_32);
+               }
+               /*
+                * We need to release lock before any copy_to_user(),
+                * whether implicit in qib_read_umem* or explicit below.
+                */
+               spin_unlock_irqrestore(&dd->qib_diag_trans_lock, flags);
+               if (!op) {
+                       if (use_32)
+                               /*
+                                * Address or length is not 64-bit aligned;
+                                * do 32-bit rd
+                                */
+                               ret = qib_read_umem32(dd, data, (u32) *off,
+                                                     count);
+                       else
+                               ret = qib_read_umem64(dd, data, (u32) *off,
+                                                     count);
+               } else if (ret == count) {
+                       /* Below finishes case where observer existed */
+                       ret = copy_to_user(data, &data64, use_32 ?
+                                          sizeof(u32) : sizeof(u64));
+                       if (ret)
+                               ret = -EFAULT;
+               }
+       }
+
+       if (ret >= 0) {
+               *off += count;
+               ret = count;
+               if (dc->state == OPENED)
+                       dc->state = INIT;
+       }
+bail:
+       return ret;
+}
+
+static ssize_t qib_diag_write(struct file *fp, const char __user *data,
+                             size_t count, loff_t *off)
+{
+       struct qib_diag_client *dc = fp->private_data;
+       struct qib_devdata *dd = dc->dd;
+       void __iomem *kreg_base;
+       ssize_t ret;
+
+       if (dc->pid != current->pid) {
+               ret = -EPERM;
+               goto bail;
+       }
+
+       kreg_base = dd->kregbase;
+
+       if (count == 0)
+               ret = 0;
+       else if ((count % 4) || (*off % 4))
+               /* address or length is not 32-bit aligned, hence invalid */
+               ret = -EINVAL;
+       else if (dc->state < READY &&
+               ((*off || count != 8) || dc->state != INIT))
+               /* No writes except second-step of init seq */
+               ret = -EINVAL;  /* before any other write allowed */
+       else {
+               unsigned long flags;
+               const struct diag_observer *op = NULL;
+               int use_32 =  (count % 8) || (*off % 8);
+
+               /*
+                * Check for observer on this address range.
+                * We only support a single 32 or 64-bit write
+                * via observer, currently. This helps, because
+                * we would otherwise have to jump through hoops
+                * to make "diag transaction" meaningful when we
+                * cannot do a copy_from_user while holding the lock.
+                */
+               if (count == 4 || count == 8) {
+                       u64 data64;
+                       u32 offset = *off;
+                       ret = copy_from_user(&data64, data, count);
+                       if (ret) {
+                               ret = -EFAULT;
+                               goto bail;
+                       }
+                       spin_lock_irqsave(&dd->qib_diag_trans_lock, flags);
+                       op = diag_get_observer(dd, *off);
+                       if (op)
+                               ret = op->hook(dd, op, offset, &data64, ~0Ull,
+                                              use_32);
+                       spin_unlock_irqrestore(&dd->qib_diag_trans_lock, flags);
+               }
+
+               if (!op) {
+                       if (use_32)
+                               /*
+                                * Address or length is not 64-bit aligned;
+                                * do 32-bit write
+                                */
+                               ret = qib_write_umem32(dd, (u32) *off, data,
+                                                      count);
+                       else
+                               ret = qib_write_umem64(dd, (u32) *off, data,
+                                                      count);
+               }
+       }
+
+       if (ret >= 0) {
+               *off += count;
+               ret = count;
+               if (dc->state == INIT)
+                       dc->state = READY; /* all read/write OK now */
+       }
+bail:
+       return ret;
+}
diff --git a/drivers/infiniband/hw/qib/qib_dma.c b/drivers/infiniband/hw/qib/qib_dma.c
new file mode 100644 (file)
index 0000000..2920bb3
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2006, 2009, 2010 QLogic, Corporation. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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/types.h>
+#include <linux/scatterlist.h>
+
+#include "qib_verbs.h"
+
+#define BAD_DMA_ADDRESS ((u64) 0)
+
+/*
+ * The following functions implement driver specific replacements
+ * for the ib_dma_*() functions.
+ *
+ * These functions return kernel virtual addresses instead of
+ * device bus addresses since the driver uses the CPU to copy
+ * data instead of using hardware DMA.
+ */
+
+static int qib_mapping_error(struct ib_device *dev, u64 dma_addr)
+{
+       return dma_addr == BAD_DMA_ADDRESS;
+}
+
+static u64 qib_dma_map_single(struct ib_device *dev, void *cpu_addr,
+                             size_t size, enum dma_data_direction direction)
+{
+       BUG_ON(!valid_dma_direction(direction));
+       return (u64) cpu_addr;
+}
+
+static void qib_dma_unmap_single(struct ib_device *dev, u64 addr, size_t size,
+                                enum dma_data_direction direction)
+{
+       BUG_ON(!valid_dma_direction(direction));
+}
+
+static u64 qib_dma_map_page(struct ib_device *dev, struct page *page,
+                           unsigned long offset, size_t size,
+                           enum dma_data_direction direction)
+{
+       u64 addr;
+
+       BUG_ON(!valid_dma_direction(direction));
+
+       if (offset + size > PAGE_SIZE) {
+               addr = BAD_DMA_ADDRESS;
+               goto done;
+       }
+
+       addr = (u64) page_address(page);
+       if (addr)
+               addr += offset;
+       /* TODO: handle highmem pages */
+
+done:
+       return addr;
+}
+
+static void qib_dma_unmap_page(struct ib_device *dev, u64 addr, size_t size,
+                              enum dma_data_direction direction)
+{
+       BUG_ON(!valid_dma_direction(direction));
+}
+
+static int qib_map_sg(struct ib_device *dev, struct scatterlist *sgl,
+                     int nents, enum dma_data_direction direction)
+{
+       struct scatterlist *sg;
+       u64 addr;
+       int i;
+       int ret = nents;
+
+       BUG_ON(!valid_dma_direction(direction));
+
+       for_each_sg(sgl, sg, nents, i) {
+               addr = (u64) page_address(sg_page(sg));
+               /* TODO: handle highmem pages */
+               if (!addr) {
+                       ret = 0;
+                       break;
+               }
+       }
+       return ret;
+}
+
+static void qib_unmap_sg(struct ib_device *dev,
+                        struct scatterlist *sg, int nents,
+                        enum dma_data_direction direction)
+{
+       BUG_ON(!valid_dma_direction(direction));
+}
+
+static u64 qib_sg_dma_address(struct ib_device *dev, struct scatterlist *sg)
+{
+       u64 addr = (u64) page_address(sg_page(sg));
+
+       if (addr)
+               addr += sg->offset;
+       return addr;
+}
+
+static unsigned int qib_sg_dma_len(struct ib_device *dev,
+                                  struct scatterlist *sg)
+{
+       return sg->length;
+}
+
+static void qib_sync_single_for_cpu(struct ib_device *dev, u64 addr,
+                                   size_t size, enum dma_data_direction dir)
+{
+}
+
+static void qib_sync_single_for_device(struct ib_device *dev, u64 addr,
+                                      size_t size,
+                                      enum dma_data_direction dir)
+{
+}
+
+static void *qib_dma_alloc_coherent(struct ib_device *dev, size_t size,
+                                   u64 *dma_handle, gfp_t flag)
+{
+       struct page *p;
+       void *addr = NULL;
+
+       p = alloc_pages(flag, get_order(size));
+       if (p)
+               addr = page_address(p);
+       if (dma_handle)
+               *dma_handle = (u64) addr;
+       return addr;
+}
+
+static void qib_dma_free_coherent(struct ib_device *dev, size_t size,
+                                 void *cpu_addr, u64 dma_handle)
+{
+       free_pages((unsigned long) cpu_addr, get_order(size));
+}
+
+struct ib_dma_mapping_ops qib_dma_mapping_ops = {
+       .mapping_error = qib_mapping_error,
+       .map_single = qib_dma_map_single,
+       .unmap_single = qib_dma_unmap_single,
+       .map_page = qib_dma_map_page,
+       .unmap_page = qib_dma_unmap_page,
+       .map_sg = qib_map_sg,
+       .unmap_sg = qib_unmap_sg,
+       .dma_address = qib_sg_dma_address,
+       .dma_len = qib_sg_dma_len,
+       .sync_single_for_cpu = qib_sync_single_for_cpu,
+       .sync_single_for_device = qib_sync_single_for_device,
+       .alloc_coherent = qib_dma_alloc_coherent,
+       .free_coherent = qib_dma_free_coherent
+};
diff --git a/drivers/infiniband/hw/qib/qib_driver.c b/drivers/infiniband/hw/qib/qib_driver.c
new file mode 100644 (file)
index 0000000..f15ce07
--- /dev/null
@@ -0,0 +1,665 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved.
+ * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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/spinlock.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/vmalloc.h>
+
+#include "qib.h"
+
+/*
+ * The size has to be longer than this string, so we can append
+ * board/chip information to it in the init code.
+ */
+const char ib_qib_version[] = QIB_IDSTR "\n";
+
+DEFINE_SPINLOCK(qib_devs_lock);
+LIST_HEAD(qib_dev_list);
+DEFINE_MUTEX(qib_mutex);       /* general driver use */
+
+unsigned qib_ibmtu;
+module_param_named(ibmtu, qib_ibmtu, uint, S_IRUGO);
+MODULE_PARM_DESC(ibmtu, "Set max IB MTU (0=2KB, 1=256, 2=512, ... 5=4096");
+
+unsigned qib_compat_ddr_negotiate = 1;
+module_param_named(compat_ddr_negotiate, qib_compat_ddr_negotiate, uint,
+                  S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(compat_ddr_negotiate,
+                "Attempt pre-IBTA 1.2 DDR speed negotiation");
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("QLogic <support@qlogic.com>");
+MODULE_DESCRIPTION("QLogic IB driver");
+
+/*
+ * QIB_PIO_MAXIBHDR is the max IB header size allowed for in our
+ * PIO send buffers.  This is well beyond anything currently
+ * defined in the InfiniBand spec.
+ */
+#define QIB_PIO_MAXIBHDR 128
+
+struct qlogic_ib_stats qib_stats;
+
+const char *qib_get_unit_name(int unit)
+{
+       static char iname[16];
+
+       snprintf(iname, sizeof iname, "infinipath%u", unit);
+       return iname;
+}
+
+/*
+ * Return count of units with at least one port ACTIVE.
+ */
+int qib_count_active_units(void)
+{
+       struct qib_devdata *dd;
+       struct qib_pportdata *ppd;
+       unsigned long flags;
+       int pidx, nunits_active = 0;
+
+       spin_lock_irqsave(&qib_devs_lock, flags);
+       list_for_each_entry(dd, &qib_dev_list, list) {
+               if (!(dd->flags & QIB_PRESENT) || !dd->kregbase)
+                       continue;
+               for (pidx = 0; pidx < dd->num_pports; ++pidx) {
+                       ppd = dd->pport + pidx;
+                       if (ppd->lid && (ppd->lflags & (QIBL_LINKINIT |
+                                        QIBL_LINKARMED | QIBL_LINKACTIVE))) {
+                               nunits_active++;
+                               break;
+                       }
+               }
+       }
+       spin_unlock_irqrestore(&qib_devs_lock, flags);
+       return nunits_active;
+}
+
+/*
+ * Return count of all units, optionally return in arguments
+ * the number of usable (present) units, and the number of
+ * ports that are up.
+ */
+int qib_count_units(int *npresentp, int *nupp)
+{
+       int nunits = 0, npresent = 0, nup = 0;
+       struct qib_devdata *dd;
+       unsigned long flags;
+       int pidx;
+       struct qib_pportdata *ppd;
+
+       spin_lock_irqsave(&qib_devs_lock, flags);
+
+       list_for_each_entry(dd, &qib_dev_list, list) {
+               nunits++;
+               if ((dd->flags & QIB_PRESENT) && dd->kregbase)
+                       npresent++;
+               for (pidx = 0; pidx < dd->num_pports; ++pidx) {
+                       ppd = dd->pport + pidx;
+                       if (ppd->lid && (ppd->lflags & (QIBL_LINKINIT |
+                                        QIBL_LINKARMED | QIBL_LINKACTIVE)))
+                               nup++;
+               }
+       }
+
+       spin_unlock_irqrestore(&qib_devs_lock, flags);
+
+       if (npresentp)
+               *npresentp = npresent;
+       if (nupp)
+               *nupp = nup;
+
+       return nunits;
+}
+
+/**
+ * qib_wait_linkstate - wait for an IB link state change to occur
+ * @dd: the qlogic_ib device
+ * @state: the state to wait for
+ * @msecs: the number of milliseconds to wait
+ *
+ * wait up to msecs milliseconds for IB link state change to occur for
+ * now, take the easy polling route.  Currently used only by
+ * qib_set_linkstate.  Returns 0 if state reached, otherwise
+ * -ETIMEDOUT state can have multiple states set, for any of several
+ * transitions.
+ */
+int qib_wait_linkstate(struct qib_pportdata *ppd, u32 state, int msecs)
+{
+       int ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ppd->lflags_lock, flags);
+       if (ppd->state_wanted) {
+               spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+               ret = -EBUSY;
+               goto bail;
+       }
+       ppd->state_wanted = state;
+       spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+       wait_event_interruptible_timeout(ppd->state_wait,
+                                        (ppd->lflags & state),
+                                        msecs_to_jiffies(msecs));
+       spin_lock_irqsave(&ppd->lflags_lock, flags);
+       ppd->state_wanted = 0;
+       spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+
+       if (!(ppd->lflags & state))
+               ret = -ETIMEDOUT;
+       else
+               ret = 0;
+bail:
+       return ret;
+}
+
+int qib_set_linkstate(struct qib_pportdata *ppd, u8 newstate)
+{
+       u32 lstate;
+       int ret;
+       struct qib_devdata *dd = ppd->dd;
+       unsigned long flags;
+
+       switch (newstate) {
+       case QIB_IB_LINKDOWN_ONLY:
+               dd->f_set_ib_cfg(ppd, QIB_IB_CFG_LSTATE,
+                                IB_LINKCMD_DOWN | IB_LINKINITCMD_NOP);
+               /* don't wait */
+               ret = 0;
+               goto bail;
+
+       case QIB_IB_LINKDOWN:
+               dd->f_set_ib_cfg(ppd, QIB_IB_CFG_LSTATE,
+                                IB_LINKCMD_DOWN | IB_LINKINITCMD_POLL);
+               /* don't wait */
+               ret = 0;
+               goto bail;
+
+       case QIB_IB_LINKDOWN_SLEEP:
+               dd->f_set_ib_cfg(ppd, QIB_IB_CFG_LSTATE,
+                                IB_LINKCMD_DOWN | IB_LINKINITCMD_SLEEP);
+               /* don't wait */
+               ret = 0;
+               goto bail;
+
+       case QIB_IB_LINKDOWN_DISABLE:
+               dd->f_set_ib_cfg(ppd, QIB_IB_CFG_LSTATE,
+                                IB_LINKCMD_DOWN | IB_LINKINITCMD_DISABLE);
+               /* don't wait */
+               ret = 0;
+               goto bail;
+
+       case QIB_IB_LINKARM:
+               if (ppd->lflags & QIBL_LINKARMED) {
+                       ret = 0;
+                       goto bail;
+               }
+               if (!(ppd->lflags & (QIBL_LINKINIT | QIBL_LINKACTIVE))) {
+                       ret = -EINVAL;
+                       goto bail;
+               }
+               /*
+                * Since the port can be ACTIVE when we ask for ARMED,
+                * clear QIBL_LINKV so we can wait for a transition.
+                * If the link isn't ARMED, then something else happened
+                * and there is no point waiting for ARMED.
+                */
+               spin_lock_irqsave(&ppd->lflags_lock, flags);
+               ppd->lflags &= ~QIBL_LINKV;
+               spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+               dd->f_set_ib_cfg(ppd, QIB_IB_CFG_LSTATE,
+                                IB_LINKCMD_ARMED | IB_LINKINITCMD_NOP);
+               lstate = QIBL_LINKV;
+               break;
+
+       case QIB_IB_LINKACTIVE:
+               if (ppd->lflags & QIBL_LINKACTIVE) {
+                       ret = 0;
+                       goto bail;
+               }
+               if (!(ppd->lflags & QIBL_LINKARMED)) {
+                       ret = -EINVAL;
+                       goto bail;
+               }
+               dd->f_set_ib_cfg(ppd, QIB_IB_CFG_LSTATE,
+                                IB_LINKCMD_ACTIVE | IB_LINKINITCMD_NOP);
+               lstate = QIBL_LINKACTIVE;
+               break;
+
+       default:
+               ret = -EINVAL;
+               goto bail;
+       }
+       ret = qib_wait_linkstate(ppd, lstate, 10);
+
+bail:
+       return ret;
+}
+
+/*
+ * Get address of eager buffer from it's index (allocated in chunks, not
+ * contiguous).
+ */
+static inline void *qib_get_egrbuf(const struct qib_ctxtdata *rcd, u32 etail)
+{
+       const u32 chunk = etail / rcd->rcvegrbufs_perchunk;
+       const u32 idx =  etail % rcd->rcvegrbufs_perchunk;
+
+       return rcd->rcvegrbuf[chunk] + idx * rcd->dd->rcvegrbufsize;
+}
+
+/*
+ * Returns 1 if error was a CRC, else 0.
+ * Needed for some chip's synthesized error counters.
+ */
+static u32 qib_rcv_hdrerr(struct qib_pportdata *ppd, u32 ctxt,
+                         u32 eflags, u32 l, u32 etail, __le32 *rhf_addr,
+                         struct qib_message_header *hdr)
+{
+       u32 ret = 0;
+
+       if (eflags & (QLOGIC_IB_RHF_H_ICRCERR | QLOGIC_IB_RHF_H_VCRCERR))
+               ret = 1;
+       return ret;
+}
+
+/*
+ * qib_kreceive - receive a packet
+ * @rcd: the qlogic_ib context
+ * @llic: gets count of good packets needed to clear lli,
+ *          (used with chips that need need to track crcs for lli)
+ *
+ * called from interrupt handler for errors or receive interrupt
+ * Returns number of CRC error packets, needed by some chips for
+ * local link integrity tracking.   crcs are adjusted down by following
+ * good packets, if any, and count of good packets is also tracked.
+ */
+u32 qib_kreceive(struct qib_ctxtdata *rcd, u32 *llic, u32 *npkts)
+{
+       struct qib_devdata *dd = rcd->dd;
+       struct qib_pportdata *ppd = rcd->ppd;
+       __le32 *rhf_addr;
+       void *ebuf;
+       const u32 rsize = dd->rcvhdrentsize;        /* words */
+       const u32 maxcnt = dd->rcvhdrcnt * rsize;   /* words */
+       u32 etail = -1, l, hdrqtail;
+       struct qib_message_header *hdr;
+       u32 eflags, etype, tlen, i = 0, updegr = 0, crcs = 0;
+       int last;
+       u64 lval;
+       struct qib_qp *qp, *nqp;
+
+       l = rcd->head;
+       rhf_addr = (__le32 *) rcd->rcvhdrq + l + dd->rhf_offset;
+       if (dd->flags & QIB_NODMA_RTAIL) {
+               u32 seq = qib_hdrget_seq(rhf_addr);
+               if (seq != rcd->seq_cnt)
+                       goto bail;
+               hdrqtail = 0;
+       } else {
+               hdrqtail = qib_get_rcvhdrtail(rcd);
+               if (l == hdrqtail)
+                       goto bail;
+               smp_rmb();  /* prevent speculative reads of dma'ed hdrq */
+       }
+
+       for (last = 0, i = 1; !last; i += !last) {
+               hdr = dd->f_get_msgheader(dd, rhf_addr);
+               eflags = qib_hdrget_err_flags(rhf_addr);
+               etype = qib_hdrget_rcv_type(rhf_addr);
+               /* total length */
+               tlen = qib_hdrget_length_in_bytes(rhf_addr);
+               ebuf = NULL;
+               if ((dd->flags & QIB_NODMA_RTAIL) ?
+                   qib_hdrget_use_egr_buf(rhf_addr) :
+                   (etype != RCVHQ_RCV_TYPE_EXPECTED)) {
+                       etail = qib_hdrget_index(rhf_addr);
+                       updegr = 1;
+                       if (tlen > sizeof(*hdr) ||
+                           etype >= RCVHQ_RCV_TYPE_NON_KD)
+                               ebuf = qib_get_egrbuf(rcd, etail);
+               }
+               if (!eflags) {
+                       u16 lrh_len = be16_to_cpu(hdr->lrh[2]) << 2;
+
+                       if (lrh_len != tlen) {
+                               qib_stats.sps_lenerrs++;
+                               goto move_along;
+                       }
+               }
+               if (etype == RCVHQ_RCV_TYPE_NON_KD && !eflags &&
+                   ebuf == NULL &&
+                   tlen > (dd->rcvhdrentsize - 2 + 1 -
+                               qib_hdrget_offset(rhf_addr)) << 2) {
+                       goto move_along;
+               }
+
+               /*
+                * Both tiderr and qibhdrerr are set for all plain IB
+                * packets; only qibhdrerr should be set.
+                */
+               if (unlikely(eflags))
+                       crcs += qib_rcv_hdrerr(ppd, rcd->ctxt, eflags, l,
+                                              etail, rhf_addr, hdr);
+               else if (etype == RCVHQ_RCV_TYPE_NON_KD) {
+                       qib_ib_rcv(rcd, hdr, ebuf, tlen);
+                       if (crcs)
+                               crcs--;
+                       else if (llic && *llic)
+                               --*llic;
+               }
+move_along:
+               l += rsize;
+               if (l >= maxcnt)
+                       l = 0;
+               rhf_addr = (__le32 *) rcd->rcvhdrq + l + dd->rhf_offset;
+               if (dd->flags & QIB_NODMA_RTAIL) {
+                       u32 seq = qib_hdrget_seq(rhf_addr);
+
+                       if (++rcd->seq_cnt > 13)
+                               rcd->seq_cnt = 1;
+                       if (seq != rcd->seq_cnt)
+                               last = 1;
+               } else if (l == hdrqtail)
+                       last = 1;
+               /*
+                * Update head regs etc., every 16 packets, if not last pkt,
+                * to help prevent rcvhdrq overflows, when many packets
+                * are processed and queue is nearly full.
+                * Don't request an interrupt for intermediate updates.
+                */
+               lval = l;
+               if (!last && !(i & 0xf)) {
+                       dd->f_update_usrhead(rcd, lval, updegr, etail);
+                       updegr = 0;
+               }
+       }
+
+       rcd->head = l;
+       rcd->pkt_count += i;
+
+       /*
+        * Iterate over all QPs waiting to respond.
+        * The list won't change since the IRQ is only run on one CPU.
+        */
+       list_for_each_entry_safe(qp, nqp, &rcd->qp_wait_list, rspwait) {
+               list_del_init(&qp->rspwait);
+               if (qp->r_flags & QIB_R_RSP_NAK) {
+                       qp->r_flags &= ~QIB_R_RSP_NAK;
+                       qib_send_rc_ack(qp);
+               }
+               if (qp->r_flags & QIB_R_RSP_SEND) {
+                       unsigned long flags;
+
+                       qp->r_flags &= ~QIB_R_RSP_SEND;
+                       spin_lock_irqsave(&qp->s_lock, flags);
+                       if (ib_qib_state_ops[qp->state] &
+                                       QIB_PROCESS_OR_FLUSH_SEND)
+                               qib_schedule_send(qp);
+                       spin_unlock_irqrestore(&qp->s_lock, flags);
+               }
+               if (atomic_dec_and_test(&qp->refcount))
+                       wake_up(&qp->wait);
+       }
+
+bail:
+       /* Report number of packets consumed */
+       if (npkts)
+               *npkts = i;
+
+       /*
+        * Always write head at end, and setup rcv interrupt, even
+        * if no packets were processed.
+        */
+       lval = (u64)rcd->head | dd->rhdrhead_intr_off;
+       dd->f_update_usrhead(rcd, lval, updegr, etail);
+       return crcs;
+}
+
+/**
+ * qib_set_mtu - set the MTU
+ * @ppd: the perport data
+ * @arg: the new MTU
+ *
+ * We can handle "any" incoming size, the issue here is whether we
+ * need to restrict our outgoing size.   For now, we don't do any
+ * sanity checking on this, and we don't deal with what happens to
+ * programs that are already running when the size changes.
+ * NOTE: changing the MTU will usually cause the IBC to go back to
+ * link INIT state...
+ */
+int qib_set_mtu(struct qib_pportdata *ppd, u16 arg)
+{
+       u32 piosize;
+       int ret, chk;
+
+       if (arg != 256 && arg != 512 && arg != 1024 && arg != 2048 &&
+           arg != 4096) {
+               ret = -EINVAL;
+               goto bail;
+       }
+       chk = ib_mtu_enum_to_int(qib_ibmtu);
+       if (chk > 0 && arg > chk) {
+               ret = -EINVAL;
+               goto bail;
+       }
+
+       piosize = ppd->ibmaxlen;
+       ppd->ibmtu = arg;
+
+       if (arg >= (piosize - QIB_PIO_MAXIBHDR)) {
+               /* Only if it's not the initial value (or reset to it) */
+               if (piosize != ppd->init_ibmaxlen) {
+                       if (arg > piosize && arg <= ppd->init_ibmaxlen)
+                               piosize = ppd->init_ibmaxlen - 2 * sizeof(u32);
+                       ppd->ibmaxlen = piosize;
+               }
+       } else if ((arg + QIB_PIO_MAXIBHDR) != ppd->ibmaxlen) {
+               piosize = arg + QIB_PIO_MAXIBHDR - 2 * sizeof(u32);
+               ppd->ibmaxlen = piosize;
+       }
+
+       ppd->dd->f_set_ib_cfg(ppd, QIB_IB_CFG_MTU, 0);
+
+       ret = 0;
+
+bail:
+       return ret;
+}
+
+int qib_set_lid(struct qib_pportdata *ppd, u32 lid, u8 lmc)
+{
+       struct qib_devdata *dd = ppd->dd;
+       ppd->lid = lid;
+       ppd->lmc = lmc;
+
+       dd->f_set_ib_cfg(ppd, QIB_IB_CFG_LIDLMC,
+                        lid | (~((1U << lmc) - 1)) << 16);
+
+       qib_devinfo(dd->pcidev, "IB%u:%u got a lid: 0x%x\n",
+                   dd->unit, ppd->port, lid);
+
+       return 0;
+}
+
+/*
+ * Following deal with the "obviously simple" task of overriding the state
+ * of the LEDS, which normally indicate link physical and logical status.
+ * The complications arise in dealing with different hardware mappings
+ * and the board-dependent routine being called from interrupts.
+ * and then there's the requirement to _flash_ them.
+ */
+#define LED_OVER_FREQ_SHIFT 8
+#define LED_OVER_FREQ_MASK (0xFF<<LED_OVER_FREQ_SHIFT)
+/* Below is "non-zero" to force override, but both actual LEDs are off */
+#define LED_OVER_BOTH_OFF (8)
+
+static void qib_run_led_override(unsigned long opaque)
+{
+       struct qib_pportdata *ppd = (struct qib_pportdata *)opaque;
+       struct qib_devdata *dd = ppd->dd;
+       int timeoff;
+       int ph_idx;
+
+       if (!(dd->flags & QIB_INITTED))
+               return;
+
+       ph_idx = ppd->led_override_phase++ & 1;
+       ppd->led_override = ppd->led_override_vals[ph_idx];
+       timeoff = ppd->led_override_timeoff;
+
+       dd->f_setextled(ppd, 1);
+       /*
+        * don't re-fire the timer if user asked for it to be off; we let
+        * it fire one more time after they turn it off to simplify
+        */
+       if (ppd->led_override_vals[0] || ppd->led_override_vals[1])
+               mod_timer(&ppd->led_override_timer, jiffies + timeoff);
+}
+
+void qib_set_led_override(struct qib_pportdata *ppd, unsigned int val)
+{
+       struct qib_devdata *dd = ppd->dd;
+       int timeoff, freq;
+
+       if (!(dd->flags & QIB_INITTED))
+               return;
+
+       /* First check if we are blinking. If not, use 1HZ polling */
+       timeoff = HZ;
+       freq = (val & LED_OVER_FREQ_MASK) >> LED_OVER_FREQ_SHIFT;
+
+       if (freq) {
+               /* For blink, set each phase from one nybble of val */
+               ppd->led_override_vals[0] = val & 0xF;
+               ppd->led_override_vals[1] = (val >> 4) & 0xF;
+               timeoff = (HZ << 4)/freq;
+       } else {
+               /* Non-blink set both phases the same. */
+               ppd->led_override_vals[0] = val & 0xF;
+               ppd->led_override_vals[1] = val & 0xF;
+       }
+       ppd->led_override_timeoff = timeoff;
+
+       /*
+        * If the timer has not already been started, do so. Use a "quick"
+        * timeout so the function will be called soon, to look at our request.
+        */
+       if (atomic_inc_return(&ppd->led_override_timer_active) == 1) {
+               /* Need to start timer */
+               init_timer(&ppd->led_override_timer);
+               ppd->led_override_timer.function = qib_run_led_override;
+               ppd->led_override_timer.data = (unsigned long) ppd;
+               ppd->led_override_timer.expires = jiffies + 1;
+               add_timer(&ppd->led_override_timer);
+       } else {
+               if (ppd->led_override_vals[0] || ppd->led_override_vals[1])
+                       mod_timer(&ppd->led_override_timer, jiffies + 1);
+               atomic_dec(&ppd->led_override_timer_active);
+       }
+}
+
+/**
+ * qib_reset_device - reset the chip if possible
+ * @unit: the device to reset
+ *
+ * Whether or not reset is successful, we attempt to re-initialize the chip
+ * (that is, much like a driver unload/reload).  We clear the INITTED flag
+ * so that the various entry points will fail until we reinitialize.  For
+ * now, we only allow this if no user contexts are open that use chip resources
+ */
+int qib_reset_device(int unit)
+{
+       int ret, i;
+       struct qib_devdata *dd = qib_lookup(unit);
+       struct qib_pportdata *ppd;
+       unsigned long flags;
+       int pidx;
+
+       if (!dd) {
+               ret = -ENODEV;
+               goto bail;
+       }
+
+       qib_devinfo(dd->pcidev, "Reset on unit %u requested\n", unit);
+
+       if (!dd->kregbase || !(dd->flags & QIB_PRESENT)) {
+               qib_devinfo(dd->pcidev, "Invalid unit number %u or "
+                           "not initialized or not present\n", unit);
+               ret = -ENXIO;
+               goto bail;
+       }
+
+       spin_lock_irqsave(&dd->uctxt_lock, flags);
+       if (dd->rcd)
+               for (i = dd->first_user_ctxt; i < dd->cfgctxts; i++) {
+                       if (!dd->rcd[i] || !dd->rcd[i]->cnt)
+                               continue;
+                       spin_unlock_irqrestore(&dd->uctxt_lock, flags);
+                       ret = -EBUSY;
+                       goto bail;
+               }
+       spin_unlock_irqrestore(&dd->uctxt_lock, flags);
+
+       for (pidx = 0; pidx < dd->num_pports; ++pidx) {
+               ppd = dd->pport + pidx;
+               if (atomic_read(&ppd->led_override_timer_active)) {
+                       /* Need to stop LED timer, _then_ shut off LEDs */
+                       del_timer_sync(&ppd->led_override_timer);
+                       atomic_set(&ppd->led_override_timer_active, 0);
+               }
+
+               /* Shut off LEDs after we are sure timer is not running */
+               ppd->led_override = LED_OVER_BOTH_OFF;
+               dd->f_setextled(ppd, 0);
+               if (dd->flags & QIB_HAS_SEND_DMA)
+                       qib_teardown_sdma(ppd);
+       }
+
+       ret = dd->f_reset(dd);
+       if (ret == 1)
+               ret = qib_init(dd, 1);
+       else
+               ret = -EAGAIN;
+       if (ret)
+               qib_dev_err(dd, "Reinitialize unit %u after "
+                           "reset failed with %d\n", unit, ret);
+       else
+               qib_devinfo(dd->pcidev, "Reinitialized unit %u after "
+                           "resetting\n", unit);
+
+bail:
+       return ret;
+}
diff --git a/drivers/infiniband/hw/qib/qib_eeprom.c b/drivers/infiniband/hw/qib/qib_eeprom.c
new file mode 100644 (file)
index 0000000..92d9cfe
--- /dev/null
@@ -0,0 +1,451 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved.
+ * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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/delay.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+
+#include "qib.h"
+
+/*
+ * Functions specific to the serial EEPROM on cards handled by ib_qib.
+ * The actual serail interface code is in qib_twsi.c. This file is a client
+ */
+
+/**
+ * qib_eeprom_read - receives bytes from the eeprom via I2C
+ * @dd: the qlogic_ib device
+ * @eeprom_offset: address to read from
+ * @buffer: where to store result
+ * @len: number of bytes to receive
+ */
+int qib_eeprom_read(struct qib_devdata *dd, u8 eeprom_offset,
+                   void *buff, int len)
+{
+       int ret;
+
+       ret = mutex_lock_interruptible(&dd->eep_lock);
+       if (!ret) {
+               ret = qib_twsi_reset(dd);
+               if (ret)
+                       qib_dev_err(dd, "EEPROM Reset for read failed\n");
+               else
+                       ret = qib_twsi_blk_rd(dd, dd->twsi_eeprom_dev,
+                                             eeprom_offset, buff, len);
+               mutex_unlock(&dd->eep_lock);
+       }
+
+       return ret;
+}
+
+/*
+ * Actually update the eeprom, first doing write enable if
+ * needed, then restoring write enable state.
+ * Must be called with eep_lock held
+ */
+static int eeprom_write_with_enable(struct qib_devdata *dd, u8 offset,
+                    const void *buf, int len)
+{
+       int ret, pwen;
+
+       pwen = dd->f_eeprom_wen(dd, 1);
+       ret = qib_twsi_reset(dd);
+       if (ret)
+               qib_dev_err(dd, "EEPROM Reset for write failed\n");
+       else
+               ret = qib_twsi_blk_wr(dd, dd->twsi_eeprom_dev,
+                                     offset, buf, len);
+       dd->f_eeprom_wen(dd, pwen);
+       return ret;
+}
+
+/**
+ * qib_eeprom_write - writes data to the eeprom via I2C
+ * @dd: the qlogic_ib device
+ * @eeprom_offset: where to place data
+ * @buffer: data to write
+ * @len: number of bytes to write
+ */
+int qib_eeprom_write(struct qib_devdata *dd, u8 eeprom_offset,
+                    const void *buff, int len)
+{
+       int ret;
+
+       ret = mutex_lock_interruptible(&dd->eep_lock);
+       if (!ret) {
+               ret = eeprom_write_with_enable(dd, eeprom_offset, buff, len);
+               mutex_unlock(&dd->eep_lock);
+       }
+
+       return ret;
+}
+
+static u8 flash_csum(struct qib_flash *ifp, int adjust)
+{
+       u8 *ip = (u8 *) ifp;
+       u8 csum = 0, len;
+
+       /*
+        * Limit length checksummed to max length of actual data.
+        * Checksum of erased eeprom will still be bad, but we avoid
+        * reading past the end of the buffer we were passed.
+        */
+       len = ifp->if_length;
+       if (len > sizeof(struct qib_flash))
+               len = sizeof(struct qib_flash);
+       while (len--)
+               csum += *ip++;
+       csum -= ifp->if_csum;
+       csum = ~csum;
+       if (adjust)
+               ifp->if_csum = csum;
+
+       return csum;
+}
+
+/**
+ * qib_get_eeprom_info- get the GUID et al. from the TSWI EEPROM device
+ * @dd: the qlogic_ib device
+ *
+ * We have the capability to use the nguid field, and get
+ * the guid from the first chip's flash, to use for all of them.
+ */
+void qib_get_eeprom_info(struct qib_devdata *dd)
+{
+       void *buf;
+       struct qib_flash *ifp;
+       __be64 guid;
+       int len, eep_stat;
+       u8 csum, *bguid;
+       int t = dd->unit;
+       struct qib_devdata *dd0 = qib_lookup(0);
+
+       if (t && dd0->nguid > 1 && t <= dd0->nguid) {
+               u8 oguid;
+               dd->base_guid = dd0->base_guid;
+               bguid = (u8 *) &dd->base_guid;
+
+               oguid = bguid[7];
+               bguid[7] += t;
+               if (oguid > bguid[7]) {
+                       if (bguid[6] == 0xff) {
+                               if (bguid[5] == 0xff) {
+                                       qib_dev_err(dd, "Can't set %s GUID"
+                                                   " from base, wraps to"
+                                                   " OUI!\n",
+                                                   qib_get_unit_name(t));
+                                       dd->base_guid = 0;
+                                       goto bail;
+                               }
+                               bguid[5]++;
+                       }
+                       bguid[6]++;
+               }
+               dd->nguid = 1;
+               goto bail;
+       }
+
+       /*
+        * Read full flash, not just currently used part, since it may have
+        * been written with a newer definition.
+        * */
+       len = sizeof(struct qib_flash);
+       buf = vmalloc(len);
+       if (!buf) {
+               qib_dev_err(dd, "Couldn't allocate memory to read %u "
+                           "bytes from eeprom for GUID\n", len);
+               goto bail;
+       }
+
+       /*
+        * Use "public" eeprom read function, which does locking and
+        * figures out device. This will migrate to chip-specific.
+        */
+       eep_stat = qib_eeprom_read(dd, 0, buf, len);
+
+       if (eep_stat) {
+               qib_dev_err(dd, "Failed reading GUID from eeprom\n");
+               goto done;
+       }
+       ifp = (struct qib_flash *)buf;
+
+       csum = flash_csum(ifp, 0);
+       if (csum != ifp->if_csum) {
+               qib_devinfo(dd->pcidev, "Bad I2C flash checksum: "
+                        "0x%x, not 0x%x\n", csum, ifp->if_csum);
+               goto done;
+       }
+       if (*(__be64 *) ifp->if_guid == cpu_to_be64(0) ||
+           *(__be64 *) ifp->if_guid == ~cpu_to_be64(0)) {
+               qib_dev_err(dd, "Invalid GUID %llx from flash; ignoring\n",
+                           *(unsigned long long *) ifp->if_guid);
+               /* don't allow GUID if all 0 or all 1's */
+               goto done;
+       }
+
+       /* complain, but allow it */
+       if (*(u64 *) ifp->if_guid == 0x100007511000000ULL)
+               qib_devinfo(dd->pcidev, "Warning, GUID %llx is "
+                        "default, probably not correct!\n",
+                        *(unsigned long long *) ifp->if_guid);
+
+       bguid = ifp->if_guid;
+       if (!bguid[0] && !bguid[1] && !bguid[2]) {
+               /*
+                * Original incorrect GUID format in flash; fix in
+                * core copy, by shifting up 2 octets; don't need to
+                * change top octet, since both it and shifted are 0.
+                */
+               bguid[1] = bguid[3];
+               bguid[2] = bguid[4];
+               bguid[3] = 0;
+               bguid[4] = 0;
+               guid = *(__be64 *) ifp->if_guid;
+       } else
+               guid = *(__be64 *) ifp->if_guid;
+       dd->base_guid = guid;
+       dd->nguid = ifp->if_numguid;
+       /*
+        * Things are slightly complicated by the desire to transparently
+        * support both the Pathscale 10-digit serial number and the QLogic
+        * 13-character version.
+        */
+       if ((ifp->if_fversion > 1) && ifp->if_sprefix[0] &&
+           ((u8 *) ifp->if_sprefix)[0] != 0xFF) {
+               char *snp = dd->serial;
+
+               /*
+                * This board has a Serial-prefix, which is stored
+                * elsewhere for backward-compatibility.
+                */
+               memcpy(snp, ifp->if_sprefix, sizeof ifp->if_sprefix);
+               snp[sizeof ifp->if_sprefix] = '\0';
+               len = strlen(snp);
+               snp += len;
+               len = (sizeof dd->serial) - len;
+               if (len > sizeof ifp->if_serial)
+                       len = sizeof ifp->if_serial;
+               memcpy(snp, ifp->if_serial, len);
+       } else
+               memcpy(dd->serial, ifp->if_serial,
+                      sizeof ifp->if_serial);
+       if (!strstr(ifp->if_comment, "Tested successfully"))
+               qib_dev_err(dd, "Board SN %s did not pass functional "
+                           "test: %s\n", dd->serial, ifp->if_comment);
+
+       memcpy(&dd->eep_st_errs, &ifp->if_errcntp, QIB_EEP_LOG_CNT);
+       /*
+        * Power-on (actually "active") hours are kept as little-endian value
+        * in EEPROM, but as seconds in a (possibly as small as 24-bit)
+        * atomic_t while running.
+        */
+       atomic_set(&dd->active_time, 0);
+       dd->eep_hrs = ifp->if_powerhour[0] | (ifp->if_powerhour[1] << 8);
+
+done:
+       vfree(buf);
+
+bail:;
+}
+
+/**
+ * qib_update_eeprom_log - copy active-time and error counters to eeprom
+ * @dd: the qlogic_ib device
+ *
+ * Although the time is kept as seconds in the qib_devdata struct, it is
+ * rounded to hours for re-write, as we have only 16 bits in EEPROM.
+ * First-cut code reads whole (expected) struct qib_flash, modifies,
+ * re-writes. Future direction: read/write only what we need, assuming
+ * that the EEPROM had to have been "good enough" for driver init, and
+ * if not, we aren't making it worse.
+ *
+ */
+int qib_update_eeprom_log(struct qib_devdata *dd)
+{
+       void *buf;
+       struct qib_flash *ifp;
+       int len, hi_water;
+       uint32_t new_time, new_hrs;
+       u8 csum;
+       int ret, idx;
+       unsigned long flags;
+
+       /* first, check if we actually need to do anything. */
+       ret = 0;
+       for (idx = 0; idx < QIB_EEP_LOG_CNT; ++idx) {
+               if (dd->eep_st_new_errs[idx]) {
+                       ret = 1;
+                       break;
+               }
+       }
+       new_time = atomic_read(&dd->active_time);
+
+       if (ret == 0 && new_time < 3600)
+               goto bail;
+
+       /*
+        * The quick-check above determined that there is something worthy
+        * of logging, so get current contents and do a more detailed idea.
+        * read full flash, not just currently used part, since it may have
+        * been written with a newer definition
+        */
+       len = sizeof(struct qib_flash);
+       buf = vmalloc(len);
+       ret = 1;
+       if (!buf) {
+               qib_dev_err(dd, "Couldn't allocate memory to read %u "
+                           "bytes from eeprom for logging\n", len);
+               goto bail;
+       }
+
+       /* Grab semaphore and read current EEPROM. If we get an
+        * error, let go, but if not, keep it until we finish write.
+        */
+       ret = mutex_lock_interruptible(&dd->eep_lock);
+       if (ret) {
+               qib_dev_err(dd, "Unable to acquire EEPROM for logging\n");
+               goto free_bail;
+       }
+       ret = qib_twsi_blk_rd(dd, dd->twsi_eeprom_dev, 0, buf, len);
+       if (ret) {
+               mutex_unlock(&dd->eep_lock);
+               qib_dev_err(dd, "Unable read EEPROM for logging\n");
+               goto free_bail;
+       }
+       ifp = (struct qib_flash *)buf;
+
+       csum = flash_csum(ifp, 0);
+       if (csum != ifp->if_csum) {
+               mutex_unlock(&dd->eep_lock);
+               qib_dev_err(dd, "EEPROM cks err (0x%02X, S/B 0x%02X)\n",
+                           csum, ifp->if_csum);
+               ret = 1;
+               goto free_bail;
+       }
+       hi_water = 0;
+       spin_lock_irqsave(&dd->eep_st_lock, flags);
+       for (idx = 0; idx < QIB_EEP_LOG_CNT; ++idx) {
+               int new_val = dd->eep_st_new_errs[idx];
+               if (new_val) {
+                       /*
+                        * If we have seen any errors, add to EEPROM values
+                        * We need to saturate at 0xFF (255) and we also
+                        * would need to adjust the checksum if we were
+                        * trying to minimize EEPROM traffic
+                        * Note that we add to actual current count in EEPROM,
+                        * in case it was altered while we were running.
+                        */
+                       new_val += ifp->if_errcntp[idx];
+                       if (new_val > 0xFF)
+                               new_val = 0xFF;
+                       if (ifp->if_errcntp[idx] != new_val) {
+                               ifp->if_errcntp[idx] = new_val;
+                               hi_water = offsetof(struct qib_flash,
+                                                   if_errcntp) + idx;
+                       }
+                       /*
+                        * update our shadow (used to minimize EEPROM
+                        * traffic), to match what we are about to write.
+                        */
+                       dd->eep_st_errs[idx] = new_val;
+                       dd->eep_st_new_errs[idx] = 0;
+               }
+       }
+       /*
+        * Now update active-time. We would like to round to the nearest hour
+        * but unless atomic_t are sure to be proper signed ints we cannot,
+        * because we need to account for what we "transfer" to EEPROM and
+        * if we log an hour at 31 minutes, then we would need to set
+        * active_time to -29 to accurately count the _next_ hour.
+        */
+       if (new_time >= 3600) {
+               new_hrs = new_time / 3600;
+               atomic_sub((new_hrs * 3600), &dd->active_time);
+               new_hrs += dd->eep_hrs;
+               if (new_hrs > 0xFFFF)
+                       new_hrs = 0xFFFF;
+               dd->eep_hrs = new_hrs;
+               if ((new_hrs & 0xFF) != ifp->if_powerhour[0]) {
+                       ifp->if_powerhour[0] = new_hrs & 0xFF;
+                       hi_water = offsetof(struct qib_flash, if_powerhour);
+               }
+               if ((new_hrs >> 8) != ifp->if_powerhour[1]) {
+                       ifp->if_powerhour[1] = new_hrs >> 8;
+                       hi_water = offsetof(struct qib_flash, if_powerhour) + 1;
+               }
+       }
+       /*
+        * There is a tiny possibility that we could somehow fail to write
+        * the EEPROM after updating our shadows, but problems from holding
+        * the spinlock too long are a much bigger issue.
+        */
+       spin_unlock_irqrestore(&dd->eep_st_lock, flags);
+       if (hi_water) {
+               /* we made some change to the data, uopdate cksum and write */
+               csum = flash_csum(ifp, 1);
+               ret = eeprom_write_with_enable(dd, 0, buf, hi_water + 1);
+       }
+       mutex_unlock(&dd->eep_lock);
+       if (ret)
+               qib_dev_err(dd, "Failed updating EEPROM\n");
+
+free_bail:
+       vfree(buf);
+bail:
+       return ret;
+}
+
+/**
+ * qib_inc_eeprom_err - increment one of the four error counters
+ * that are logged to EEPROM.
+ * @dd: the qlogic_ib device
+ * @eidx: 0..3, the counter to increment
+ * @incr: how much to add
+ *
+ * Each counter is 8-bits, and saturates at 255 (0xFF). They
+ * are copied to the EEPROM (aka flash) whenever qib_update_eeprom_log()
+ * is called, but it can only be called in a context that allows sleep.
+ * This function can be called even at interrupt level.
+ */
+void qib_inc_eeprom_err(struct qib_devdata *dd, u32 eidx, u32 incr)
+{
+       uint new_val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dd->eep_st_lock, flags);
+       new_val = dd->eep_st_new_errs[eidx] + incr;
+       if (new_val > 255)
+               new_val = 255;
+       dd->eep_st_new_errs[eidx] = new_val;
+       spin_unlock_irqrestore(&dd->eep_st_lock, flags);
+}
diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c
new file mode 100644 (file)
index 0000000..a142a9e
--- /dev/null
@@ -0,0 +1,2317 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009, 2010 QLogic Corporation.
+ * All rights reserved.
+ * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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/pci.h>
+#include <linux/poll.h>
+#include <linux/cdev.h>
+#include <linux/swap.h>
+#include <linux/vmalloc.h>
+#include <linux/highmem.h>
+#include <linux/io.h>
+#include <linux/uio.h>
+#include <linux/jiffies.h>
+#include <asm/pgtable.h>
+#include <linux/delay.h>
+
+#include "qib.h"
+#include "qib_common.h"
+#include "qib_user_sdma.h"
+
+static int qib_open(struct inode *, struct file *);
+static int qib_close(struct inode *, struct file *);
+static ssize_t qib_write(struct file *, const char __user *, size_t, loff_t *);
+static ssize_t qib_aio_write(struct kiocb *, const struct iovec *,
+                            unsigned long, loff_t);
+static unsigned int qib_poll(struct file *, struct poll_table_struct *);
+static int qib_mmapf(struct file *, struct vm_area_struct *);
+
+static const struct file_operations qib_file_ops = {
+       .owner = THIS_MODULE,
+       .write = qib_write,
+       .aio_write = qib_aio_write,
+       .open = qib_open,
+       .release = qib_close,
+       .poll = qib_poll,
+       .mmap = qib_mmapf
+};
+
+/*
+ * Convert kernel virtual addresses to physical addresses so they don't
+ * potentially conflict with the chip addresses used as mmap offsets.
+ * It doesn't really matter what mmap offset we use as long as we can
+ * interpret it correctly.
+ */
+static u64 cvt_kvaddr(void *p)
+{
+       struct page *page;
+       u64 paddr = 0;
+
+       page = vmalloc_to_page(p);
+       if (page)
+               paddr = page_to_pfn(page) << PAGE_SHIFT;
+
+       return paddr;
+}
+
+static int qib_get_base_info(struct file *fp, void __user *ubase,
+                            size_t ubase_size)
+{
+       struct qib_ctxtdata *rcd = ctxt_fp(fp);
+       int ret = 0;
+       struct qib_base_info *kinfo = NULL;
+       struct qib_devdata *dd = rcd->dd;
+       struct qib_pportdata *ppd = rcd->ppd;
+       unsigned subctxt_cnt;
+       int shared, master;
+       size_t sz;
+
+       subctxt_cnt = rcd->subctxt_cnt;
+       if (!subctxt_cnt) {
+               shared = 0;
+               master = 0;
+               subctxt_cnt = 1;
+       } else {
+               shared = 1;
+               master = !subctxt_fp(fp);
+       }
+
+       sz = sizeof(*kinfo);
+       /* If context sharing is not requested, allow the old size structure */
+       if (!shared)
+               sz -= 7 * sizeof(u64);
+       if (ubase_size < sz) {
+               ret = -EINVAL;
+               goto bail;
+       }
+
+       kinfo = kzalloc(sizeof(*kinfo), GFP_KERNEL);
+       if (kinfo == NULL) {
+               ret = -ENOMEM;
+               goto bail;
+       }
+
+       ret = dd->f_get_base_info(rcd, kinfo);
+       if (ret < 0)
+               goto bail;
+
+       kinfo->spi_rcvhdr_cnt = dd->rcvhdrcnt;
+       kinfo->spi_rcvhdrent_size = dd->rcvhdrentsize;
+       kinfo->spi_tidegrcnt = rcd->rcvegrcnt;
+       kinfo->spi_rcv_egrbufsize = dd->rcvegrbufsize;
+       /*
+        * have to mmap whole thing
+        */
+       kinfo->spi_rcv_egrbuftotlen =
+               rcd->rcvegrbuf_chunks * rcd->rcvegrbuf_size;
+       kinfo->spi_rcv_egrperchunk = rcd->rcvegrbufs_perchunk;
+       kinfo->spi_rcv_egrchunksize = kinfo->spi_rcv_egrbuftotlen /
+               rcd->rcvegrbuf_chunks;
+       kinfo->spi_tidcnt = dd->rcvtidcnt / subctxt_cnt;
+       if (master)
+               kinfo->spi_tidcnt += dd->rcvtidcnt % subctxt_cnt;
+       /*
+        * for this use, may be cfgctxts summed over all chips that
+        * are are configured and present
+        */
+       kinfo->spi_nctxts = dd->cfgctxts;
+       /* unit (chip/board) our context is on */
+       kinfo->spi_unit = dd->unit;
+       kinfo->spi_port = ppd->port;
+       /* for now, only a single page */
+       kinfo->spi_tid_maxsize = PAGE_SIZE;
+
+       /*
+        * Doing this per context, and based on the skip value, etc.  This has
+        * to be the actual buffer size, since the protocol code treats it
+        * as an array.
+        *
+        * These have to be set to user addresses in the user code via mmap.
+        * These values are used on return to user code for the mmap target
+        * addresses only.  For 32 bit, same 44 bit address problem, so use
+        * the physical address, not virtual.  Before 2.6.11, using the
+        * page_address() macro worked, but in 2.6.11, even that returns the
+        * full 64 bit address (upper bits all 1's).  So far, using the
+        * physical addresses (or chip offsets, for chip mapping) works, but
+        * no doubt some future kernel release will change that, and we'll be
+        * on to yet another method of dealing with this.
+        * Normally only one of rcvhdr_tailaddr or rhf_offset is useful
+        * since the chips with non-zero rhf_offset don't normally
+        * enable tail register updates to host memory, but for testing,
+        * both can be enabled and used.
+        */
+       kinfo->spi_rcvhdr_base = (u64) rcd->rcvhdrq_phys;
+       kinfo->spi_rcvhdr_tailaddr = (u64) rcd->rcvhdrqtailaddr_phys;
+       kinfo->spi_rhf_offset = dd->rhf_offset;
+       kinfo->spi_rcv_egrbufs = (u64) rcd->rcvegr_phys;
+       kinfo->spi_pioavailaddr = (u64) dd->pioavailregs_phys;
+       /* setup per-unit (not port) status area for user programs */
+       kinfo->spi_status = (u64) kinfo->spi_pioavailaddr +
+               (char *) ppd->statusp -
+               (char *) dd->pioavailregs_dma;
+       kinfo->spi_uregbase = (u64) dd->uregbase + dd->ureg_align * rcd->ctxt;
+       if (!shared) {
+               kinfo->spi_piocnt = rcd->piocnt;
+               kinfo->spi_piobufbase = (u64) rcd->piobufs;
+               kinfo->spi_sendbuf_status = cvt_kvaddr(rcd->user_event_mask);
+       } else if (master) {
+               kinfo->spi_piocnt = (rcd->piocnt / subctxt_cnt) +
+                                   (rcd->piocnt % subctxt_cnt);
+               /* Master's PIO buffers are after all the slave's */
+               kinfo->spi_piobufbase = (u64) rcd->piobufs +
+                       dd->palign *
+                       (rcd->piocnt - kinfo->spi_piocnt);
+       } else {
+               unsigned slave = subctxt_fp(fp) - 1;
+
+               kinfo->spi_piocnt = rcd->piocnt / subctxt_cnt;
+               kinfo->spi_piobufbase = (u64) rcd->piobufs +
+                       dd->palign * kinfo->spi_piocnt * slave;
+       }
+
+       if (shared) {
+               kinfo->spi_sendbuf_status =
+                       cvt_kvaddr(&rcd->user_event_mask[subctxt_fp(fp)]);
+               /* only spi_subctxt_* fields should be set in this block! */
+               kinfo->spi_subctxt_uregbase = cvt_kvaddr(rcd->subctxt_uregbase);
+
+               kinfo->spi_subctxt_rcvegrbuf =
+                       cvt_kvaddr(rcd->subctxt_rcvegrbuf);
+               kinfo->spi_subctxt_rcvhdr_base =
+                       cvt_kvaddr(rcd->subctxt_rcvhdr_base);
+       }
+
+       /*
+        * All user buffers are 2KB buffers.  If we ever support
+        * giving 4KB buffers to user processes, this will need some
+        * work.  Can't use piobufbase directly, because it has
+        * both 2K and 4K buffer base values.
+        */
+       kinfo->spi_pioindex = (kinfo->spi_piobufbase - dd->pio2k_bufbase) /
+               dd->palign;
+       kinfo->spi_pioalign = dd->palign;
+       kinfo->spi_qpair = QIB_KD_QP;
+       /*
+        * user mode PIO buffers are always 2KB, even when 4KB can
+        * be received, and sent via the kernel; this is ibmaxlen
+        * for 2K MTU.
+        */
+       kinfo->spi_piosize = dd->piosize2k - 2 * sizeof(u32);
+       kinfo->spi_mtu = ppd->ibmaxlen; /* maxlen, not ibmtu */
+       kinfo->spi_ctxt = rcd->ctxt;
+       kinfo->spi_subctxt = subctxt_fp(fp);
+       kinfo->spi_sw_version = QIB_KERN_SWVERSION;
+       kinfo->spi_sw_version |= 1U << 31; /* QLogic-built, not kernel.org */
+       kinfo->spi_hw_version = dd->revision;
+
+       if (master)
+               kinfo->spi_runtime_flags |= QIB_RUNTIME_MASTER;
+
+       sz = (ubase_size < sizeof(*kinfo)) ? ubase_size : sizeof(*kinfo);
+       if (copy_to_user(ubase, kinfo, sz))
+               ret = -EFAULT;
+bail:
+       kfree(kinfo);
+       return ret;
+}
+
+/**
+ * qib_tid_update - update a context TID
+ * @rcd: the context
+ * @fp: the qib device file
+ * @ti: the TID information
+ *
+ * The new implementation as of Oct 2004 is that the driver assigns
+ * the tid and returns it to the caller.   To reduce search time, we
+ * keep a cursor for each context, walking the shadow tid array to find
+ * one that's not in use.
+ *
+ * For now, if we can't allocate the full list, we fail, although
+ * in the long run, we'll allocate as many as we can, and the
+ * caller will deal with that by trying the remaining pages later.
+ * That means that when we fail, we have to mark the tids as not in
+ * use again, in our shadow copy.
+ *
+ * It's up to the caller to free the tids when they are done.
+ * We'll unlock the pages as they free them.
+ *
+ * Also, right now we are locking one page at a time, but since
+ * the intended use of this routine is for a single group of
+ * virtually contiguous pages, that should change to improve
+ * performance.
+ */
+static int qib_tid_update(struct qib_ctxtdata *rcd, struct file *fp,
+                         const struct qib_tid_info *ti)
+{
+       int ret = 0, ntids;
+       u32 tid, ctxttid, cnt, i, tidcnt, tidoff;
+       u16 *tidlist;
+       struct qib_devdata *dd = rcd->dd;
+       u64 physaddr;
+       unsigned long vaddr;
+       u64 __iomem *tidbase;
+       unsigned long tidmap[8];
+       struct page **pagep = NULL;
+       unsigned subctxt = subctxt_fp(fp);
+
+       if (!dd->pageshadow) {
+               ret = -ENOMEM;
+               goto done;
+       }
+
+       cnt = ti->tidcnt;
+       if (!cnt) {
+               ret = -EFAULT;
+               goto done;
+       }
+       ctxttid = rcd->ctxt * dd->rcvtidcnt;
+       if (!rcd->subctxt_cnt) {
+               tidcnt = dd->rcvtidcnt;
+               tid = rcd->tidcursor;
+               tidoff = 0;
+       } else if (!subctxt) {
+               tidcnt = (dd->rcvtidcnt / rcd->subctxt_cnt) +
+                        (dd->rcvtidcnt % rcd->subctxt_cnt);
+               tidoff = dd->rcvtidcnt - tidcnt;
+               ctxttid += tidoff;
+               tid = tidcursor_fp(fp);
+       } else {
+               tidcnt = dd->rcvtidcnt / rcd->subctxt_cnt;
+               tidoff = tidcnt * (subctxt - 1);
+               ctxttid += tidoff;
+               tid = tidcursor_fp(fp);
+       }
+       if (cnt > tidcnt) {
+               /* make sure it all fits in tid_pg_list */
+               qib_devinfo(dd->pcidev, "Process tried to allocate %u "
+                        "TIDs, only trying max (%u)\n", cnt, tidcnt);
+               cnt = tidcnt;
+       }
+       pagep = (struct page **) rcd->tid_pg_list;
+       tidlist = (u16 *) &pagep[dd->rcvtidcnt];
+       pagep += tidoff;
+       tidlist += tidoff;
+
+       memset(tidmap, 0, sizeof(tidmap));
+       /* before decrement; chip actual # */
+       ntids = tidcnt;
+       tidbase = (u64 __iomem *) (((char __iomem *) dd->kregbase) +
+                                  dd->rcvtidbase +
+                                  ctxttid * sizeof(*tidbase));
+
+       /* virtual address of first page in transfer */
+       vaddr = ti->tidvaddr;
+       if (!access_ok(VERIFY_WRITE, (void __user *) vaddr,
+                      cnt * PAGE_SIZE)) {
+               ret = -EFAULT;
+               goto done;
+       }
+       ret = qib_get_user_pages(vaddr, cnt, pagep);
+       if (ret) {
+               /*
+                * if (ret == -EBUSY)
+                * We can't continue because the pagep array won't be
+                * initialized. This should never happen,
+                * unless perhaps the user has mpin'ed the pages
+                * themselves.
+                */
+               qib_devinfo(dd->pcidev,
+                        "Failed to lock addr %p, %u pages: "
+                        "errno %d\n", (void *) vaddr, cnt, -ret);
+               goto done;
+       }
+       for (i = 0; i < cnt; i++, vaddr += PAGE_SIZE) {
+               for (; ntids--; tid++) {
+                       if (tid == tidcnt)
+                               tid = 0;
+                       if (!dd->pageshadow[ctxttid + tid])
+                               break;
+               }
+               if (ntids < 0) {
+                       /*
+                        * Oops, wrapped all the way through their TIDs,
+                        * and didn't have enough free; see comments at
+                        * start of routine
+                        */
+                       i--;    /* last tidlist[i] not filled in */
+                       ret = -ENOMEM;
+                       break;
+               }
+               tidlist[i] = tid + tidoff;
+               /* we "know" system pages and TID pages are same size */
+               dd->pageshadow[ctxttid + tid] = pagep[i];
+               dd->physshadow[ctxttid + tid] =
+                       qib_map_page(dd->pcidev, pagep[i], 0, PAGE_SIZE,
+                                    PCI_DMA_FROMDEVICE);
+               /*
+                * don't need atomic or it's overhead
+                */
+               __set_bit(tid, tidmap);
+               physaddr = dd->physshadow[ctxttid + tid];
+               /* PERFORMANCE: below should almost certainly be cached */
+               dd->f_put_tid(dd, &tidbase[tid],
+                                 RCVHQ_RCV_TYPE_EXPECTED, physaddr);
+               /*
+                * don't check this tid in qib_ctxtshadow, since we
+                * just filled it in; start with the next one.
+                */
+               tid++;
+       }
+
+       if (ret) {
+               u32 limit;
+cleanup:
+               /* jump here if copy out of updated info failed... */
+               /* same code that's in qib_free_tid() */
+               limit = sizeof(tidmap) * BITS_PER_BYTE;
+               if (limit > tidcnt)
+                       /* just in case size changes in future */
+                       limit = tidcnt;
+               tid = find_first_bit((const unsigned long *)tidmap, limit);
+               for (; tid < limit; tid++) {
+                       if (!test_bit(tid, tidmap))
+                               continue;
+                       if (dd->pageshadow[ctxttid + tid]) {
+                               dma_addr_t phys;
+
+                               phys = dd->physshadow[ctxttid + tid];
+                               dd->physshadow[ctxttid + tid] = dd->tidinvalid;
+                               /* PERFORMANCE: below should almost certainly
+                                * be cached
+                                */
+                               dd->f_put_tid(dd, &tidbase[tid],
+                                             RCVHQ_RCV_TYPE_EXPECTED,
+                                             dd->tidinvalid);
+                               pci_unmap_page(dd->pcidev, phys, PAGE_SIZE,
+                                              PCI_DMA_FROMDEVICE);
+                               dd->pageshadow[ctxttid + tid] = NULL;
+                       }
+               }
+               qib_release_user_pages(pagep, cnt);
+       } else {
+               /*
+                * Copy the updated array, with qib_tid's filled in, back
+                * to user.  Since we did the copy in already, this "should
+                * never fail" If it does, we have to clean up...
+                */
+               if (copy_to_user((void __user *)
+                                (unsigned long) ti->tidlist,
+                                tidlist, cnt * sizeof(*tidlist))) {
+                       ret = -EFAULT;
+                       goto cleanup;
+               }
+               if (copy_to_user((void __user *) (unsigned long) ti->tidmap,
+                                tidmap, sizeof tidmap)) {
+                       ret = -EFAULT;
+                       goto cleanup;
+               }
+               if (tid == tidcnt)
+                       tid = 0;
+               if (!rcd->subctxt_cnt)
+                       rcd->tidcursor = tid;
+               else
+                       tidcursor_fp(fp) = tid;
+       }
+
+done:
+       return ret;
+}
+
+/**
+ * qib_tid_free - free a context TID
+ * @rcd: the context
+ * @subctxt: the subcontext
+ * @ti: the TID info
+ *
+ * right now we are unlocking one page at a time, but since
+ * the intended use of this routine is for a single group of
+ * virtually contiguous pages, that should change to improve
+ * performance.  We check that the TID is in range for this context
+ * but otherwise don't check validity; if user has an error and
+ * frees the wrong tid, it's only their own data that can thereby
+ * be corrupted.  We do check that the TID was in use, for sanity
+ * We always use our idea of the saved address, not the address that
+ * they pass in to us.
+ */
+static int qib_tid_free(struct qib_ctxtdata *rcd, unsigned subctxt,
+                       const struct qib_tid_info *ti)
+{
+       int ret = 0;
+       u32 tid, ctxttid, cnt, limit, tidcnt;
+       struct qib_devdata *dd = rcd->dd;
+       u64 __iomem *tidbase;
+       unsigned long tidmap[8];
+
+       if (!dd->pageshadow) {
+               ret = -ENOMEM;
+               goto done;
+       }
+
+       if (copy_from_user(tidmap, (void __user *)(unsigned long)ti->tidmap,
+                          sizeof tidmap)) {
+               ret = -EFAULT;
+               goto done;
+       }
+
+       ctxttid = rcd->ctxt * dd->rcvtidcnt;
+       if (!rcd->subctxt_cnt)
+               tidcnt = dd->rcvtidcnt;
+       else if (!subctxt) {
+               tidcnt = (dd->rcvtidcnt / rcd->subctxt_cnt) +
+                        (dd->rcvtidcnt % rcd->subctxt_cnt);
+               ctxttid += dd->rcvtidcnt - tidcnt;
+       } else {
+               tidcnt = dd->rcvtidcnt / rcd->subctxt_cnt;
+               ctxttid += tidcnt * (subctxt - 1);
+       }
+       tidbase = (u64 __iomem *) ((char __iomem *)(dd->kregbase) +
+                                  dd->rcvtidbase +
+                                  ctxttid * sizeof(*tidbase));
+
+       limit = sizeof(tidmap) * BITS_PER_BYTE;
+       if (limit > tidcnt)
+               /* just in case size changes in future */
+               limit = tidcnt;
+       tid = find_first_bit(tidmap, limit);
+       for (cnt = 0; tid < limit; tid++) {
+               /*
+                * small optimization; if we detect a run of 3 or so without
+                * any set, use find_first_bit again.  That's mainly to
+                * accelerate the case where we wrapped, so we have some at
+                * the beginning, and some at the end, and a big gap
+                * in the middle.
+                */
+               if (!test_bit(tid, tidmap))
+                       continue;
+               cnt++;
+               if (dd->pageshadow[ctxttid + tid]) {
+                       struct page *p;
+                       dma_addr_t phys;
+
+                       p = dd->pageshadow[ctxttid + tid];
+                       dd->pageshadow[ctxttid + tid] = NULL;
+                       phys = dd->physshadow[ctxttid + tid];
+                       dd->physshadow[ctxttid + tid] = dd->tidinvalid;
+                       /* PERFORMANCE: below should almost certainly be
+                        * cached
+                        */
+                       dd->f_put_tid(dd, &tidbase[tid],
+                                     RCVHQ_RCV_TYPE_EXPECTED, dd->tidinvalid);
+                       pci_unmap_page(dd->pcidev, phys, PAGE_SIZE,
+                                      PCI_DMA_FROMDEVICE);
+                       qib_release_user_pages(&p, 1);
+               }
+       }
+done:
+       return ret;
+}
+
+/**
+ * qib_set_part_key - set a partition key
+ * @rcd: the context
+ * @key: the key
+ *
+ * We can have up to 4 active at a time (other than the default, which is
+ * always allowed).  This is somewhat tricky, since multiple contexts may set
+ * the same key, so we reference count them, and clean up at exit.  All 4
+ * partition keys are packed into a single qlogic_ib register.  It's an
+ * error for a process to set the same pkey multiple times.  We provide no
+ * mechanism to de-allocate a pkey at this time, we may eventually need to
+ * do that.  I've used the atomic operations, and no locking, and only make
+ * a single pass through what's available.  This should be more than
+ * adequate for some time. I'll think about spinlocks or the like if and as
+ * it's necessary.
+ */
+static int qib_set_part_key(struct qib_ctxtdata *rcd, u16 key)
+{
+       struct qib_pportdata *ppd = rcd->ppd;
+       int i, any = 0, pidx = -1;
+       u16 lkey = key & 0x7FFF;
+       int ret;
+
+       if (lkey == (QIB_DEFAULT_P_KEY & 0x7FFF)) {
+               /* nothing to do; this key always valid */
+               ret = 0;
+               goto bail;
+       }
+
+       if (!lkey) {
+               ret = -EINVAL;
+               goto bail;
+       }
+
+       /*
+        * Set the full membership bit, because it has to be
+        * set in the register or the packet, and it seems
+        * cleaner to set in the register than to force all
+        * callers to set it.
+        */
+       key |= 0x8000;
+
+       for (i = 0; i < ARRAY_SIZE(rcd->pkeys); i++) {
+               if (!rcd->pkeys[i] && pidx == -1)
+                       pidx = i;
+               if (rcd->pkeys[i] == key) {
+                       ret = -EEXIST;
+                       goto bail;
+               }
+       }
+       if (pidx == -1) {
+               ret = -EBUSY;
+               goto bail;
+       }
+       for (any = i = 0; i < ARRAY_SIZE(ppd->pkeys); i++) {
+               if (!ppd->pkeys[i]) {
+                       any++;
+                       continue;
+               }
+               if (ppd->pkeys[i] == key) {
+                       atomic_t *pkrefs = &ppd->pkeyrefs[i];
+
+                       if (atomic_inc_return(pkrefs) > 1) {
+                               rcd->pkeys[pidx] = key;
+                               ret = 0;
+                               goto bail;
+                       } else {
+                               /*
+                                * lost race, decrement count, catch below
+                                */
+                               atomic_dec(pkrefs);
+                               any++;
+                       }
+               }
+               if ((ppd->pkeys[i] & 0x7FFF) == lkey) {
+                       /*
+                        * It makes no sense to have both the limited and
+                        * full membership PKEY set at the same time since
+                        * the unlimited one will disable the limited one.
+                        */
+                       ret = -EEXIST;
+                       goto bail;
+               }
+       }
+       if (!any) {
+               ret = -EBUSY;
+               goto bail;
+       }
+       for (any = i = 0; i < ARRAY_SIZE(ppd->pkeys); i++) {
+               if (!ppd->pkeys[i] &&
+                   atomic_inc_return(&ppd->pkeyrefs[i]) == 1) {
+                       rcd->pkeys[pidx] = key;
+                       ppd->pkeys[i] = key;
+                       (void) ppd->dd->f_set_ib_cfg(ppd, QIB_IB_CFG_PKEYS, 0);
+                       ret = 0;
+                       goto bail;
+               }
+       }
+       ret = -EBUSY;
+
+bail:
+       return ret;
+}
+
+/**
+ * qib_manage_rcvq - manage a context's receive queue
+ * @rcd: the context
+ * @subctxt: the subcontext
+ * @start_stop: action to carry out
+ *
+ * start_stop == 0 disables receive on the context, for use in queue
+ * overflow conditions.  start_stop==1 re-enables, to be used to
+ * re-init the software copy of the head register
+ */
+static int qib_manage_rcvq(struct qib_ctxtdata *rcd, unsigned subctxt,
+                          int start_stop)
+{
+       struct qib_devdata *dd = rcd->dd;
+       unsigned int rcvctrl_op;
+
+       if (subctxt)
+               goto bail;
+       /* atomically clear receive enable ctxt. */
+       if (start_stop) {
+               /*
+                * On enable, force in-memory copy of the tail register to
+                * 0, so that protocol code doesn't have to worry about
+                * whether or not the chip has yet updated the in-memory
+                * copy or not on return from the system call. The chip
+                * always resets it's tail register back to 0 on a
+                * transition from disabled to enabled.
+                */
+               if (rcd->rcvhdrtail_kvaddr)
+                       qib_clear_rcvhdrtail(rcd);
+               rcvctrl_op = QIB_RCVCTRL_CTXT_ENB;
+       } else
+               rcvctrl_op = QIB_RCVCTRL_CTXT_DIS;
+       dd->f_rcvctrl(rcd->ppd, rcvctrl_op, rcd->ctxt);
+       /* always; new head should be equal to new tail; see above */
+bail:
+       return 0;
+}
+
+static void qib_clean_part_key(struct qib_ctxtdata *rcd,
+                              struct qib_devdata *dd)
+{
+       int i, j, pchanged = 0;
+       u64 oldpkey;
+       struct qib_pportdata *ppd = rcd->ppd;
+
+       /* for debugging only */
+       oldpkey = (u64) ppd->pkeys[0] |
+               ((u64) ppd->pkeys[1] << 16) |
+               ((u64) ppd->pkeys[2] << 32) |
+               ((u64) ppd->pkeys[3] << 48);
+
+       for (i = 0; i < ARRAY_SIZE(rcd->pkeys); i++) {
+               if (!rcd->pkeys[i])
+                       continue;
+               for (j = 0; j < ARRAY_SIZE(ppd->pkeys); j++) {
+                       /* check for match independent of the global bit */
+                       if ((ppd->pkeys[j] & 0x7fff) !=
+                           (rcd->pkeys[i] & 0x7fff))
+                               continue;
+                       if (atomic_dec_and_test(&ppd->pkeyrefs[j])) {
+                               ppd->pkeys[j] = 0;
+                               pchanged++;
+                       }
+                       break;
+               }
+               rcd->pkeys[i] = 0;
+       }
+       if (pchanged)
+               (void) ppd->dd->f_set_ib_cfg(ppd, QIB_IB_CFG_PKEYS, 0);
+}
+
+/* common code for the mappings on dma_alloc_coherent mem */
+static int qib_mmap_mem(struct vm_area_struct *vma, struct qib_ctxtdata *rcd,
+                       unsigned len, void *kvaddr, u32 write_ok, char *what)
+{
+       struct qib_devdata *dd = rcd->dd;
+       unsigned long pfn;
+       int ret;
+
+       if ((vma->vm_end - vma->vm_start) > len) {
+               qib_devinfo(dd->pcidev,
+                        "FAIL on %s: len %lx > %x\n", what,
+                        vma->vm_end - vma->vm_start, len);
+               ret = -EFAULT;
+               goto bail;
+       }
+
+       /*
+        * shared context user code requires rcvhdrq mapped r/w, others
+        * only allowed readonly mapping.
+        */
+       if (!write_ok) {
+               if (vma->vm_flags & VM_WRITE) {
+                       qib_devinfo(dd->pcidev,
+                                "%s must be mapped readonly\n", what);
+                       ret = -EPERM;
+                       goto bail;
+               }
+
+               /* don't allow them to later change with mprotect */
+               vma->vm_flags &= ~VM_MAYWRITE;
+       }
+
+       pfn = virt_to_phys(kvaddr) >> PAGE_SHIFT;
+       ret = remap_pfn_range(vma, vma->vm_start, pfn,
+                             len, vma->vm_page_prot);
+       if (ret)
+               qib_devinfo(dd->pcidev, "%s ctxt%u mmap of %lx, %x "
+                        "bytes failed: %d\n", what, rcd->ctxt,
+                        pfn, len, ret);
+bail:
+       return ret;
+}
+
+static int mmap_ureg(struct vm_area_struct *vma, struct qib_devdata *dd,
+                    u64 ureg)
+{
+       unsigned long phys;
+       unsigned long sz;
+       int ret;
+
+       /*
+        * This is real hardware, so use io_remap.  This is the mechanism
+        * for the user process to update the head registers for their ctxt
+        * in the chip.
+        */
+       sz = dd->flags & QIB_HAS_HDRSUPP ? 2 * PAGE_SIZE : PAGE_SIZE;
+       if ((vma->vm_end - vma->vm_start) > sz) {
+               qib_devinfo(dd->pcidev, "FAIL mmap userreg: reqlen "
+                        "%lx > PAGE\n", vma->vm_end - vma->vm_start);
+               ret = -EFAULT;
+       } else {
+               phys = dd->physaddr + ureg;
+               vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+               vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND;
+               ret = io_remap_pfn_range(vma, vma->vm_start,
+                                        phys >> PAGE_SHIFT,
+                                        vma->vm_end - vma->vm_start,
+                                        vma->vm_page_prot);
+       }
+       return ret;
+}
+
+static int mmap_piobufs(struct vm_area_struct *vma,
+                       struct qib_devdata *dd,
+                       struct qib_ctxtdata *rcd,
+                       unsigned piobufs, unsigned piocnt)
+{
+       unsigned long phys;
+       int ret;
+
+       /*
+        * When we map the PIO buffers in the chip, we want to map them as
+        * writeonly, no read possible; unfortunately, x86 doesn't allow
+        * for this in hardware, but we still prevent users from asking
+        * for it.
+        */
+       if ((vma->vm_end - vma->vm_start) > (piocnt * dd->palign)) {
+               qib_devinfo(dd->pcidev, "FAIL mmap piobufs: "
+                        "reqlen %lx > PAGE\n",
+                        vma->vm_end - vma->vm_start);
+               ret = -EINVAL;
+               goto bail;
+       }
+
+       phys = dd->physaddr + piobufs;
+
+#if defined(__powerpc__)
+       /* There isn't a generic way to specify writethrough mappings */
+       pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
+       pgprot_val(vma->vm_page_prot) |= _PAGE_WRITETHRU;
+       pgprot_val(vma->vm_page_prot) &= ~_PAGE_GUARDED;
+#endif
+
+       /*
+        * don't allow them to later change to readable with mprotect (for when
+        * not initially mapped readable, as is normally the case)
+        */
+       vma->vm_flags &= ~VM_MAYREAD;
+       vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND;
+
+       if (qib_wc_pat)
+               vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+       ret = io_remap_pfn_range(vma, vma->vm_start, phys >> PAGE_SHIFT,
+                                vma->vm_end - vma->vm_start,
+                                vma->vm_page_prot);
+bail:
+       return ret;
+}
+
+static int mmap_rcvegrbufs(struct vm_area_struct *vma,
+                          struct qib_ctxtdata *rcd)
+{
+       struct qib_devdata *dd = rcd->dd;
+       unsigned long start, size;
+       size_t total_size, i;
+       unsigned long pfn;
+       int ret;
+
+       size = rcd->rcvegrbuf_size;
+       total_size = rcd->rcvegrbuf_chunks * size;
+       if ((vma->vm_end - vma->vm_start) > total_size) {
+               qib_devinfo(dd->pcidev, "FAIL on egr bufs: "
+                        "reqlen %lx > actual %lx\n",
+                        vma->vm_end - vma->vm_start,
+                        (unsigned long) total_size);
+               ret = -EINVAL;
+               goto bail;
+       }
+
+       if (vma->vm_flags & VM_WRITE) {
+               qib_devinfo(dd->pcidev, "Can't map eager buffers as "
+                        "writable (flags=%lx)\n", vma->vm_flags);
+               ret = -EPERM;
+               goto bail;
+       }
+       /* don't allow them to later change to writeable with mprotect */
+       vma->vm_flags &= ~VM_MAYWRITE;
+
+       start = vma->vm_start;
+
+       for (i = 0; i < rcd->rcvegrbuf_chunks; i++, start += size) {
+               pfn = virt_to_phys(rcd->rcvegrbuf[i]) >> PAGE_SHIFT;
+               ret = remap_pfn_range(vma, start, pfn, size,
+                                     vma->vm_page_prot);
+               if (ret < 0)
+                       goto bail;
+       }
+       ret = 0;
+
+bail:
+       return ret;
+}
+
+/*
+ * qib_file_vma_fault - handle a VMA page fault.
+ */
+static int qib_file_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+       struct page *page;
+
+       page = vmalloc_to_page((void *)(vmf->pgoff << PAGE_SHIFT));
+       if (!page)
+               return VM_FAULT_SIGBUS;
+
+       get_page(page);
+       vmf->page = page;
+
+       return 0;
+}
+
+static struct vm_operations_struct qib_file_vm_ops = {
+       .fault = qib_file_vma_fault,
+};
+
+static int mmap_kvaddr(struct vm_area_struct *vma, u64 pgaddr,
+                      struct qib_ctxtdata *rcd, unsigned subctxt)
+{
+       struct qib_devdata *dd = rcd->dd;
+       unsigned subctxt_cnt;
+       unsigned long len;
+       void *addr;
+       size_t size;
+       int ret = 0;
+
+       subctxt_cnt = rcd->subctxt_cnt;
+       size = rcd->rcvegrbuf_chunks * rcd->rcvegrbuf_size;
+
+       /*
+        * Each process has all the subctxt uregbase, rcvhdrq, and
+        * rcvegrbufs mmapped - as an array for all the processes,
+        * and also separately for this process.
+        */
+       if (pgaddr == cvt_kvaddr(rcd->subctxt_uregbase)) {
+               addr = rcd->subctxt_uregbase;
+               size = PAGE_SIZE * subctxt_cnt;
+       } else if (pgaddr == cvt_kvaddr(rcd->subctxt_rcvhdr_base)) {
+               addr = rcd->subctxt_rcvhdr_base;
+               size = rcd->rcvhdrq_size * subctxt_cnt;
+       } else if (pgaddr == cvt_kvaddr(rcd->subctxt_rcvegrbuf)) {
+               addr = rcd->subctxt_rcvegrbuf;
+               size *= subctxt_cnt;
+       } else if (pgaddr == cvt_kvaddr(rcd->subctxt_uregbase +
+                                       PAGE_SIZE * subctxt)) {
+               addr = rcd->subctxt_uregbase + PAGE_SIZE * subctxt;
+               size = PAGE_SIZE;
+       } else if (pgaddr == cvt_kvaddr(rcd->subctxt_rcvhdr_base +
+                                       rcd->rcvhdrq_size * subctxt)) {
+               addr = rcd->subctxt_rcvhdr_base +
+                       rcd->rcvhdrq_size * subctxt;
+               size = rcd->rcvhdrq_size;
+       } else if (pgaddr == cvt_kvaddr(&rcd->user_event_mask[subctxt])) {
+               addr = rcd->user_event_mask;
+               size = PAGE_SIZE;
+       } else if (pgaddr == cvt_kvaddr(rcd->subctxt_rcvegrbuf +
+                                       size * subctxt)) {
+               addr = rcd->subctxt_rcvegrbuf + size * subctxt;
+               /* rcvegrbufs are read-only on the slave */
+               if (vma->vm_flags & VM_WRITE) {
+                       qib_devinfo(dd->pcidev,
+                                "Can't map eager buffers as "
+                                "writable (flags=%lx)\n", vma->vm_flags);
+                       ret = -EPERM;
+                       goto bail;
+               }
+               /*
+                * Don't allow permission to later change to writeable
+                * with mprotect.
+                */
+               vma->vm_flags &= ~VM_MAYWRITE;
+       } else
+               goto bail;
+       len = vma->vm_end - vma->vm_start;
+       if (len > size) {
+               ret = -EINVAL;
+               goto bail;
+       }
+
+       vma->vm_pgoff = (unsigned long) addr >> PAGE_SHIFT;
+       vma->vm_ops = &qib_file_vm_ops;
+       vma->vm_flags |= VM_RESERVED | VM_DONTEXPAND;
+       ret = 1;
+
+bail:
+       return ret;
+}
+
+/**
+ * qib_mmapf - mmap various structures into user space
+ * @fp: the file pointer
+ * @vma: the VM area
+ *
+ * We use this to have a shared buffer between the kernel and the user code
+ * for the rcvhdr queue, egr buffers, and the per-context user regs and pio
+ * buffers in the chip.  We have the open and close entries so we can bump
+ * the ref count and keep the driver from being unloaded while still mapped.
+ */
+static int qib_mmapf(struct file *fp, struct vm_area_struct *vma)
+{
+       struct qib_ctxtdata *rcd;
+       struct qib_devdata *dd;
+       u64 pgaddr, ureg;
+       unsigned piobufs, piocnt;
+       int ret, match = 1;
+
+       rcd = ctxt_fp(fp);
+       if (!rcd || !(vma->vm_flags & VM_SHARED)) {
+               ret = -EINVAL;
+               goto bail;
+       }
+       dd = rcd->dd;
+
+       /*
+        * This is the qib_do_user_init() code, mapping the shared buffers
+        * and per-context user registers into the user process. The address
+        * referred to by vm_pgoff is the file offset passed via mmap().
+        * For shared contexts, this is the kernel vmalloc() address of the
+        * pages to share with the master.
+        * For non-shared or master ctxts, this is a physical address.
+        * We only do one mmap for each space mapped.
+        */
+       pgaddr = vma->vm_pgoff << PAGE_SHIFT;
+
+       /*
+        * Check for 0 in case one of the allocations failed, but user
+        * called mmap anyway.
+        */
+       if (!pgaddr)  {
+               ret = -EINVAL;
+               goto bail;
+       }
+
+       /*
+        * Physical addresses must fit in 40 bits for our hardware.
+        * Check for kernel virtual addresses first, anything else must
+        * match a HW or memory address.
+        */
+       ret = mmap_kvaddr(vma, pgaddr, rcd, subctxt_fp(fp));
+       if (ret) {
+               if (ret > 0)
+                       ret = 0;
+               goto bail;
+       }
+
+       ureg = dd->uregbase + dd->ureg_align * rcd->ctxt;
+       if (!rcd->subctxt_cnt) {
+               /* ctxt is not shared */
+               piocnt = rcd->piocnt;
+               piobufs = rcd->piobufs;
+       } else if (!subctxt_fp(fp)) {
+               /* caller is the master */
+               piocnt = (rcd->piocnt / rcd->subctxt_cnt) +
+                        (rcd->piocnt % rcd->subctxt_cnt);
+               piobufs = rcd->piobufs +
+                       dd->palign * (rcd->piocnt - piocnt);
+       } else {
+               unsigned slave = subctxt_fp(fp) - 1;
+
+               /* caller is a slave */
+               piocnt = rcd->piocnt / rcd->subctxt_cnt;
+               piobufs = rcd->piobufs + dd->palign * piocnt * slave;
+       }
+
+       if (pgaddr == ureg)
+               ret = mmap_ureg(vma, dd, ureg);
+       else if (pgaddr == piobufs)
+               ret = mmap_piobufs(vma, dd, rcd, piobufs, piocnt);
+       else if (pgaddr == dd->pioavailregs_phys)
+               /* in-memory copy of pioavail registers */
+               ret = qib_mmap_mem(vma, rcd, PAGE_SIZE,
+                                  (void *) dd->pioavailregs_dma, 0,
+                                  "pioavail registers");
+       else if (pgaddr == rcd->rcvegr_phys)
+               ret = mmap_rcvegrbufs(vma, rcd);
+       else if (pgaddr == (u64) rcd->rcvhdrq_phys)
+               /*
+                * The rcvhdrq itself; multiple pages, contiguous
+                * from an i/o perspective.  Shared contexts need
+                * to map r/w, so we allow writing.
+                */
+               ret = qib_mmap_mem(vma, rcd, rcd->rcvhdrq_size,
+                                  rcd->rcvhdrq, 1, "rcvhdrq");
+       else if (pgaddr == (u64) rcd->rcvhdrqtailaddr_phys)
+               /* in-memory copy of rcvhdrq tail register */
+               ret = qib_mmap_mem(vma, rcd, PAGE_SIZE,
+                                  rcd->rcvhdrtail_kvaddr, 0,
+                                  "rcvhdrq tail");
+       else
+               match = 0;
+       if (!match)
+               ret = -EINVAL;
+
+       vma->vm_private_data = NULL;
+
+       if (ret < 0)
+               qib_devinfo(dd->pcidev,
+                        "mmap Failure %d: off %llx len %lx\n",
+                        -ret, (unsigned long long)pgaddr,
+                        vma->vm_end - vma->vm_start);
+bail:
+       return ret;
+}
+
+static unsigned int qib_poll_urgent(struct qib_ctxtdata *rcd,
+                                   struct file *fp,
+                                   struct poll_table_struct *pt)
+{
+       struct qib_devdata *dd = rcd->dd;
+       unsigned pollflag;
+
+       poll_wait(fp, &rcd->wait, pt);
+
+       spin_lock_irq(&dd->uctxt_lock);
+       if (rcd->urgent != rcd->urgent_poll) {
+               pollflag = POLLIN | POLLRDNORM;
+               rcd->urgent_poll = rcd->urgent;
+       } else {
+               pollflag = 0;
+               set_bit(QIB_CTXT_WAITING_URG, &rcd->flag);
+       }
+       spin_unlock_irq(&dd->uctxt_lock);
+
+       return pollflag;
+}
+
+static unsigned int qib_poll_next(struct qib_ctxtdata *rcd,
+                                 struct file *fp,
+                                 struct poll_table_struct *pt)
+{
+       struct qib_devdata *dd = rcd->dd;
+       unsigned pollflag;
+
+       poll_wait(fp, &rcd->wait, pt);
+
+       spin_lock_irq(&dd->uctxt_lock);
+       if (dd->f_hdrqempty(rcd)) {
+               set_bit(QIB_CTXT_WAITING_RCV, &rcd->flag);
+               dd->f_rcvctrl(rcd->ppd, QIB_RCVCTRL_INTRAVAIL_ENB, rcd->ctxt);
+               pollflag = 0;
+       } else
+               pollflag = POLLIN | POLLRDNORM;
+       spin_unlock_irq(&dd->uctxt_lock);
+
+       return pollflag;
+}
+
+static unsigned int qib_poll(struct file *fp, struct poll_table_struct *pt)
+{
+       struct qib_ctxtdata *rcd;
+       unsigned pollflag;
+
+       rcd = ctxt_fp(fp);
+       if (!rcd)
+               pollflag = POLLERR;
+       else if (rcd->poll_type == QIB_POLL_TYPE_URGENT)
+               pollflag = qib_poll_urgent(rcd, fp, pt);
+       else  if (rcd->poll_type == QIB_POLL_TYPE_ANYRCV)
+               pollflag = qib_poll_next(rcd, fp, pt);
+       else /* invalid */
+               pollflag = POLLERR;
+
+       return pollflag;
+}
+
+/*
+ * Check that userland and driver are compatible for subcontexts.
+ */
+static int qib_compatible_subctxts(int user_swmajor, int user_swminor)
+{
+       /* this code is written long-hand for clarity */
+       if (QIB_USER_SWMAJOR != user_swmajor) {
+               /* no promise of compatibility if major mismatch */
+               return 0;
+       }
+       if (QIB_USER_SWMAJOR == 1) {
+               switch (QIB_USER_SWMINOR) {
+               case 0:
+               case 1:
+               case 2:
+                       /* no subctxt implementation so cannot be compatible */
+                       return 0;
+               case 3:
+                       /* 3 is only compatible with itself */
+                       return user_swminor == 3;
+               default:
+                       /* >= 4 are compatible (or are expected to be) */
+                       return user_swminor >= 4;
+               }
+       }
+       /* make no promises yet for future major versions */
+       return 0;
+}
+
+static int init_subctxts(struct qib_devdata *dd,
+                        struct qib_ctxtdata *rcd,
+                        const struct qib_user_info *uinfo)
+{
+       int ret = 0;
+       unsigned num_subctxts;
+       size_t size;
+
+       /*
+        * If the user is requesting zero subctxts,
+        * skip the subctxt allocation.
+        */
+       if (uinfo->spu_subctxt_cnt <= 0)
+               goto bail;
+       num_subctxts = uinfo->spu_subctxt_cnt;
+
+       /* Check for subctxt compatibility */
+       if (!qib_compatible_subctxts(uinfo->spu_userversion >> 16,
+               uinfo->spu_userversion & 0xffff)) {
+               qib_devinfo(dd->pcidev,
+                        "Mismatched user version (%d.%d) and driver "
+                        "version (%d.%d) while context sharing. Ensure "
+                        "that driver and library are from the same "
+                        "release.\n",
+                        (int) (uinfo->spu_userversion >> 16),
+                        (int) (uinfo->spu_userversion & 0xffff),
+                        QIB_USER_SWMAJOR, QIB_USER_SWMINOR);
+               goto bail;
+       }
+       if (num_subctxts > QLOGIC_IB_MAX_SUBCTXT) {
+               ret = -EINVAL;
+               goto bail;
+       }
+
+       rcd->subctxt_uregbase = vmalloc_user(PAGE_SIZE * num_subctxts);
+       if (!rcd->subctxt_uregbase) {
+               ret = -ENOMEM;
+               goto bail;
+       }
+       /* Note: rcd->rcvhdrq_size isn't initialized yet. */
+       size = ALIGN(dd->rcvhdrcnt * dd->rcvhdrentsize *
+                    sizeof(u32), PAGE_SIZE) * num_subctxts;
+       rcd->subctxt_rcvhdr_base = vmalloc_user(size);
+       if (!rcd->subctxt_rcvhdr_base) {
+               ret = -ENOMEM;
+               goto bail_ureg;
+       }
+
+       rcd->subctxt_rcvegrbuf = vmalloc_user(rcd->rcvegrbuf_chunks *
+                                             rcd->rcvegrbuf_size *
+                                             num_subctxts);
+       if (!rcd->subctxt_rcvegrbuf) {
+               ret = -ENOMEM;
+               goto bail_rhdr;
+       }
+
+       rcd->subctxt_cnt = uinfo->spu_subctxt_cnt;
+       rcd->subctxt_id = uinfo->spu_subctxt_id;
+       rcd->active_slaves = 1;
+       rcd->redirect_seq_cnt = 1;
+       set_bit(QIB_CTXT_MASTER_UNINIT, &rcd->flag);
+       goto bail;
+
+bail_rhdr:
+       vfree(rcd->subctxt_rcvhdr_base);
+bail_ureg:
+       vfree(rcd->subctxt_uregbase);
+       rcd->subctxt_uregbase = NULL;
+bail:
+       return ret;
+}
+
+static int setup_ctxt(struct qib_pportdata *ppd, int ctxt,
+                     struct file *fp, const struct qib_user_info *uinfo)
+{
+       struct qib_devdata *dd = ppd->dd;
+       struct qib_ctxtdata *rcd;
+       void *ptmp = NULL;
+       int ret;
+
+       rcd = qib_create_ctxtdata(ppd, ctxt);
+
+       /*
+        * Allocate memory for use in qib_tid_update() at open to
+        * reduce cost of expected send setup per message segment
+        */
+       if (rcd)
+               ptmp = kmalloc(dd->rcvtidcnt * sizeof(u16) +
+                              dd->rcvtidcnt * sizeof(struct page **),
+                              GFP_KERNEL);
+
+       if (!rcd || !ptmp) {
+               qib_dev_err(dd, "Unable to allocate ctxtdata "
+                           "memory, failing open\n");
+               ret = -ENOMEM;
+               goto bailerr;
+       }
+       rcd->userversion = uinfo->spu_userversion;
+       ret = init_subctxts(dd, rcd, uinfo);
+       if (ret)
+               goto bailerr;
+       rcd->tid_pg_list = ptmp;
+       rcd->pid = current->pid;
+       init_waitqueue_head(&dd->rcd[ctxt]->wait);
+       strlcpy(rcd->comm, current->comm, sizeof(rcd->comm));
+       ctxt_fp(fp) = rcd;
+       qib_stats.sps_ctxts++;
+       ret = 0;
+       goto bail;
+
+bailerr:
+       dd->rcd[ctxt] = NULL;
+       kfree(rcd);
+       kfree(ptmp);
+bail:
+       return ret;
+}
+
+static inline int usable(struct qib_pportdata *ppd, int active_only)
+{
+       struct qib_devdata *dd = ppd->dd;
+       u32 linkok = active_only ? QIBL_LINKACTIVE :
+                (QIBL_LINKINIT | QIBL_LINKARMED | QIBL_LINKACTIVE);
+
+       return dd && (dd->flags & QIB_PRESENT) && dd->kregbase && ppd->lid &&
+               (ppd->lflags & linkok);
+}
+
+static int find_free_ctxt(int unit, struct file *fp,
+                         const struct qib_user_info *uinfo)
+{
+       struct qib_devdata *dd = qib_lookup(unit);
+       struct qib_pportdata *ppd = NULL;
+       int ret;
+       u32 ctxt;
+
+       if (!dd || (uinfo->spu_port && uinfo->spu_port > dd->num_pports)) {
+               ret = -ENODEV;
+               goto bail;
+       }
+
+       /*
+        * If users requests specific port, only try that one port, else
+        * select "best" port below, based on context.
+        */
+       if (uinfo->spu_port) {
+               ppd = dd->pport + uinfo->spu_port - 1;
+               if (!usable(ppd, 0)) {
+                       ret = -ENETDOWN;
+                       goto bail;
+               }
+       }
+
+       for (ctxt = dd->first_user_ctxt; ctxt < dd->cfgctxts; ctxt++) {
+               if (dd->rcd[ctxt])
+                       continue;
+               /*
+                * The setting and clearing of user context rcd[x] protected
+                * by the qib_mutex
+                */
+               if (!ppd) {
+                       /* choose port based on ctxt, if up, else 1st up */
+                       ppd = dd->pport + (ctxt % dd->num_pports);
+                       if (!usable(ppd, 0)) {
+                               int i;
+                               for (i = 0; i < dd->num_pports; i++) {
+                                       ppd = dd->pport + i;
+                                       if (usable(ppd, 0))
+                                               break;
+                               }
+                               if (i == dd->num_pports) {
+                                       ret = -ENETDOWN;
+                                       goto bail;
+                               }
+                       }
+               }
+               ret = setup_ctxt(ppd, ctxt, fp, uinfo);
+               goto bail;
+       }
+       ret = -EBUSY;
+
+bail:
+       return ret;
+}
+
+static int get_a_ctxt(struct file *fp, const struct qib_user_info *uinfo)
+{
+       struct qib_pportdata *ppd;
+       int ret = 0, devmax;
+       int npresent, nup;
+       int ndev;
+       u32 port = uinfo->spu_port, ctxt;
+
+       devmax = qib_count_units(&npresent, &nup);
+
+       for (ndev = 0; ndev < devmax; ndev++) {
+               struct qib_devdata *dd = qib_lookup(ndev);
+
+               /* device portion of usable() */
+               if (!(dd && (dd->flags & QIB_PRESENT) && dd->kregbase))
+                       continue;
+               for (ctxt = dd->first_user_ctxt; ctxt < dd->cfgctxts; ctxt++) {
+                       if (dd->rcd[ctxt])
+                               continue;
+                       if (port) {
+                               if (port > dd->num_pports)
+                                       continue;
+                               ppd = dd->pport + port - 1;
+                               if (!usable(ppd, 0))
+                                       continue;
+                       } else {
+                               /*
+                                * choose port based on ctxt, if up, else
+                                * first port that's up for multi-port HCA
+                                */
+                               ppd = dd->pport + (ctxt % dd->num_pports);
+                               if (!usable(ppd, 0)) {
+                                       int j;
+
+                                       ppd = NULL;
+                                       for (j = 0; j < dd->num_pports &&
+                                               !ppd; j++)
+                                               if (usable(dd->pport + j, 0))
+                                                       ppd = dd->pport + j;
+                                       if (!ppd)
+                                               continue; /* to next unit */
+                               }
+                       }
+                       ret = setup_ctxt(ppd, ctxt, fp, uinfo);
+                       goto done;
+               }
+       }
+
+       if (npresent) {
+               if (nup == 0)
+                       ret = -ENETDOWN;
+               else
+                       ret = -EBUSY;
+       } else
+               ret = -ENXIO;
+
+done:
+       return ret;
+}
+
+static int find_shared_ctxt(struct file *fp,
+                           const struct qib_user_info *uinfo)
+{
+       int devmax, ndev, i;
+       int ret = 0;
+
+       devmax = qib_count_units(NULL, NULL);
+
+       for (ndev = 0; ndev < devmax; ndev++) {
+               struct qib_devdata *dd = qib_lookup(ndev);
+
+               /* device portion of usable() */
+               if (!(dd && (dd->flags & QIB_PRESENT) && dd->kregbase))
+                       continue;
+               for (i = dd->first_user_ctxt; i < dd->cfgctxts; i++) {
+                       struct qib_ctxtdata *rcd = dd->rcd[i];
+
+                       /* Skip ctxts which are not yet open */
+                       if (!rcd || !rcd->cnt)
+                               continue;
+                       /* Skip ctxt if it doesn't match the requested one */
+                       if (rcd->subctxt_id != uinfo->spu_subctxt_id)
+                               continue;
+                       /* Verify the sharing process matches the master */
+                       if (rcd->subctxt_cnt != uinfo->spu_subctxt_cnt ||
+                           rcd->userversion != uinfo->spu_userversion ||
+                           rcd->cnt >= rcd->subctxt_cnt) {
+                               ret = -EINVAL;
+                               goto done;
+                       }
+                       ctxt_fp(fp) = rcd;
+                       subctxt_fp(fp) = rcd->cnt++;
+                       rcd->subpid[subctxt_fp(fp)] = current->pid;
+                       tidcursor_fp(fp) = 0;
+                       rcd->active_slaves |= 1 << subctxt_fp(fp);
+                       ret = 1;
+                       goto done;
+               }
+       }
+
+done:
+       return ret;
+}
+
+static int qib_open(struct inode *in, struct file *fp)
+{
+       /* The real work is performed later in qib_assign_ctxt() */
+       fp->private_data = kzalloc(sizeof(struct qib_filedata), GFP_KERNEL);
+       if (fp->private_data) /* no cpu affinity by default */
+               ((struct qib_filedata *)fp->private_data)->rec_cpu_num = -1;
+       return fp->private_data ? 0 : -ENOMEM;
+}
+
+/*
+ * Get ctxt early, so can set affinity prior to memory allocation.
+ */
+static int qib_assign_ctxt(struct file *fp, const struct qib_user_info *uinfo)
+{
+       int ret;
+       int i_minor;
+       unsigned swmajor, swminor;
+
+       /* Check to be sure we haven't already initialized this file */
+       if (ctxt_fp(fp)) {
+               ret = -EINVAL;
+               goto done;
+       }
+
+       /* for now, if major version is different, bail */
+       swmajor = uinfo->spu_userversion >> 16;
+       if (swmajor != QIB_USER_SWMAJOR) {
+               ret = -ENODEV;
+               goto done;
+       }
+
+       swminor = uinfo->spu_userversion & 0xffff;
+
+       mutex_lock(&qib_mutex);
+
+       if (qib_compatible_subctxts(swmajor, swminor) &&
+           uinfo->spu_subctxt_cnt) {
+               ret = find_shared_ctxt(fp, uinfo);
+               if (ret) {
+                       if (ret > 0)
+                               ret = 0;
+                       goto done_chk_sdma;
+               }
+       }
+
+       i_minor = iminor(fp->f_dentry->d_inode) - QIB_USER_MINOR_BASE;
+       if (i_minor)
+               ret = find_free_ctxt(i_minor - 1, fp, uinfo);
+       else
+               ret = get_a_ctxt(fp, uinfo);
+
+done_chk_sdma:
+       if (!ret) {
+               struct qib_filedata *fd = fp->private_data;
+               const struct qib_ctxtdata *rcd = fd->rcd;
+               const struct qib_devdata *dd = rcd->dd;
+
+               if (dd->flags & QIB_HAS_SEND_DMA) {
+                       fd->pq = qib_user_sdma_queue_create(&dd->pcidev->dev,
+                                                           dd->unit,
+                                                           rcd->ctxt,
+                                                           fd->subctxt);
+                       if (!fd->pq)
+                               ret = -ENOMEM;
+               }
+
+               /*
+                * If process has NOT already set it's affinity, select and
+                * reserve a processor for it, as a rendevous for all
+                * users of the driver.  If they don't actually later
+                * set affinity to this cpu, or set it to some other cpu,
+                * it just means that sooner or later we don't recommend
+                * a cpu, and let the scheduler do it's best.
+                */
+               if (!ret && cpus_weight(current->cpus_allowed) >=
+                   qib_cpulist_count) {
+                       int cpu;
+                       cpu = find_first_zero_bit(qib_cpulist,
+                                                 qib_cpulist_count);
+                       if (cpu != qib_cpulist_count) {
+                               __set_bit(cpu, qib_cpulist);
+                               fd->rec_cpu_num = cpu;
+                       }
+               } else if (cpus_weight(current->cpus_allowed) == 1 &&
+                       test_bit(first_cpu(current->cpus_allowed),
+                                qib_cpulist))
+                       qib_devinfo(dd->pcidev, "%s PID %u affinity "
+                                   "set to cpu %d; already allocated\n",
+                                   current->comm, current->pid,
+                                   first_cpu(current->cpus_allowed));
+       }
+
+       mutex_unlock(&qib_mutex);
+
+done:
+       return ret;
+}
+
+
+static int qib_do_user_init(struct file *fp,
+                           const struct qib_user_info *uinfo)
+{
+       int ret;
+       struct qib_ctxtdata *rcd = ctxt_fp(fp);
+       struct qib_devdata *dd;
+       unsigned uctxt;
+
+       /* Subctxts don't need to initialize anything since master did it. */
+       if (subctxt_fp(fp)) {
+               ret = wait_event_interruptible(rcd->wait,
+                       !test_bit(QIB_CTXT_MASTER_UNINIT, &rcd->flag));
+               goto bail;
+       }
+
+       dd = rcd->dd;
+
+       /* some ctxts may get extra buffers, calculate that here */
+       uctxt = rcd->ctxt - dd->first_user_ctxt;
+       if (uctxt < dd->ctxts_extrabuf) {
+               rcd->piocnt = dd->pbufsctxt + 1;
+               rcd->pio_base = rcd->piocnt * uctxt;
+       } else {
+               rcd->piocnt = dd->pbufsctxt;
+               rcd->pio_base = rcd->piocnt * uctxt +
+                       dd->ctxts_extrabuf;
+       }
+
+       /*
+        * All user buffers are 2KB buffers.  If we ever support
+        * giving 4KB buffers to user processes, this will need some
+        * work.  Can't use piobufbase directly, because it has
+        * both 2K and 4K buffer base values.  So check and handle.
+        */
+       if ((rcd->pio_base + rcd->piocnt) > dd->piobcnt2k) {
+               if (rcd->pio_base >= dd->piobcnt2k) {
+                       qib_dev_err(dd,
+                                   "%u:ctxt%u: no 2KB buffers available\n",
+                                   dd->unit, rcd->ctxt);
+                       ret = -ENOBUFS;
+                       goto bail;
+               }
+               rcd->piocnt = dd->piobcnt2k - rcd->pio_base;
+               qib_dev_err(dd, "Ctxt%u: would use 4KB bufs, using %u\n",
+                           rcd->ctxt, rcd->piocnt);
+       }
+
+       rcd->piobufs = dd->pio2k_bufbase + rcd->pio_base * dd->palign;
+       qib_chg_pioavailkernel(dd, rcd->pio_base, rcd->piocnt,
+                              TXCHK_CHG_TYPE_USER, rcd);
+       /*
+        * try to ensure that processes start up with consistent avail update
+        * for their own range, at least.   If system very quiet, it might
+        * have the in-memory copy out of date at startup for this range of
+        * buffers, when a context gets re-used.  Do after the chg_pioavail
+        * and before the rest of setup, so it's "almost certain" the dma
+        * will have occurred (can't 100% guarantee, but should be many
+        * decimals of 9s, with this ordering), given how much else happens
+        * after this.
+        */
+       dd->f_sendctrl(dd->pport, QIB_SENDCTRL_AVAIL_BLIP);
+
+       /*
+        * Now allocate the rcvhdr Q and eager TIDs; skip the TID
+        * array for time being.  If rcd->ctxt > chip-supported,
+        * we need to do extra stuff here to handle by handling overflow
+        * through ctxt 0, someday
+        */
+       ret = qib_create_rcvhdrq(dd, rcd);
+       if (!ret)
+               ret = qib_setup_eagerbufs(rcd);
+       if (ret)
+               goto bail_pio;
+
+       rcd->tidcursor = 0; /* start at beginning after open */
+
+       /* initialize poll variables... */
+       rcd->urgent = 0;
+       rcd->urgent_poll = 0;
+
+       /*
+        * Now enable the ctxt for receive.
+        * For chips that are set to DMA the tail register to memory
+        * when they change (and when the update bit transitions from
+        * 0 to 1.  So for those chips, we turn it off and then back on.
+        * This will (very briefly) affect any other open ctxts, but the
+        * duration is very short, and therefore isn't an issue.  We
+        * explictly set the in-memory tail copy to 0 beforehand, so we
+        * don't have to wait to be sure the DMA update has happened
+        * (chip resets head/tail to 0 on transition to enable).
+        */
+       if (rcd->rcvhdrtail_kvaddr)
+               qib_clear_rcvhdrtail(rcd);
+
+       dd->f_rcvctrl(rcd->ppd, QIB_RCVCTRL_CTXT_ENB | QIB_RCVCTRL_TIDFLOW_ENB,
+                     rcd->ctxt);
+
+       /* Notify any waiting slaves */
+       if (rcd->subctxt_cnt) {
+               clear_bit(QIB_CTXT_MASTER_UNINIT, &rcd->flag);
+               wake_up(&rcd->wait);
+       }
+       return 0;
+
+bail_pio:
+       qib_chg_pioavailkernel(dd, rcd->pio_base, rcd->piocnt,
+                              TXCHK_CHG_TYPE_KERN, rcd);
+bail:
+       return ret;
+}
+
+/**
+ * unlock_exptid - unlock any expected TID entries context still had in use
+ * @rcd: ctxt
+ *
+ * We don't actually update the chip here, because we do a bulk update
+ * below, using f_clear_tids.
+ */
+static void unlock_expected_tids(struct qib_ctxtdata *rcd)
+{
+       struct qib_devdata *dd = rcd->dd;
+       int ctxt_tidbase = rcd->ctxt * dd->rcvtidcnt;
+       int i, cnt = 0, maxtid = ctxt_tidbase + dd->rcvtidcnt;
+
+       for (i = ctxt_tidbase; i < maxtid; i++) {
+               struct page *p = dd->pageshadow[i];
+               dma_addr_t phys;
+
+               if (!p)
+                       continue;
+
+               phys = dd->physshadow[i];
+               dd->physshadow[i] = dd->tidinvalid;
+               dd->pageshadow[i] = NULL;
+               pci_unmap_page(dd->pcidev, phys, PAGE_SIZE,
+                              PCI_DMA_FROMDEVICE);
+               qib_release_user_pages(&p, 1);
+               cnt++;
+       }
+}
+
+static int qib_close(struct inode *in, struct file *fp)
+{
+       int ret = 0;
+       struct qib_filedata *fd;
+       struct qib_ctxtdata *rcd;
+       struct qib_devdata *dd;
+       unsigned long flags;
+       unsigned ctxt;
+       pid_t pid;
+
+       mutex_lock(&qib_mutex);
+
+       fd = (struct qib_filedata *) fp->private_data;
+       fp->private_data = NULL;
+       rcd = fd->rcd;
+       if (!rcd) {
+               mutex_unlock(&qib_mutex);
+               goto bail;
+       }
+
+       dd = rcd->dd;
+
+       /* ensure all pio buffer writes in progress are flushed */
+       qib_flush_wc();
+
+       /* drain user sdma queue */
+       if (fd->pq) {
+               qib_user_sdma_queue_drain(rcd->ppd, fd->pq);
+               qib_user_sdma_queue_destroy(fd->pq);
+       }
+
+       if (fd->rec_cpu_num != -1)
+               __clear_bit(fd->rec_cpu_num, qib_cpulist);
+
+       if (--rcd->cnt) {
+               /*
+                * XXX If the master closes the context before the slave(s),
+                * revoke the mmap for the eager receive queue so
+                * the slave(s) don't wait for receive data forever.
+                */
+               rcd->active_slaves &= ~(1 << fd->subctxt);
+               rcd->subpid[fd->subctxt] = 0;
+               mutex_unlock(&qib_mutex);
+               goto bail;
+       }
+
+       /* early; no interrupt users after this */
+       spin_lock_irqsave(&dd->uctxt_lock, flags);
+       ctxt = rcd->ctxt;
+       dd->rcd[ctxt] = NULL;
+       pid = rcd->pid;
+       rcd->pid = 0;
+       spin_unlock_irqrestore(&dd->uctxt_lock, flags);
+
+       if (rcd->rcvwait_to || rcd->piowait_to ||
+           rcd->rcvnowait || rcd->pionowait) {
+               rcd->rcvwait_to = 0;
+               rcd->piowait_to = 0;
+               rcd->rcvnowait = 0;
+               rcd->pionowait = 0;
+       }
+       if (rcd->flag)
+               rcd->flag = 0;
+
+       if (dd->kregbase) {
+               /* atomically clear receive enable ctxt and intr avail. */
+               dd->f_rcvctrl(rcd->ppd, QIB_RCVCTRL_CTXT_DIS |
+                                 QIB_RCVCTRL_INTRAVAIL_DIS, ctxt);
+
+               /* clean up the pkeys for this ctxt user */
+               qib_clean_part_key(rcd, dd);
+               qib_disarm_piobufs(dd, rcd->pio_base, rcd->piocnt);
+               qib_chg_pioavailkernel(dd, rcd->pio_base,
+                                      rcd->piocnt, TXCHK_CHG_TYPE_KERN, NULL);
+
+               dd->f_clear_tids(dd, rcd);
+
+               if (dd->pageshadow)
+                       unlock_expected_tids(rcd);
+               qib_stats.sps_ctxts--;
+       }
+
+       mutex_unlock(&qib_mutex);
+       qib_free_ctxtdata(dd, rcd); /* after releasing the mutex */
+
+bail:
+       kfree(fd);
+       return ret;
+}
+
+static int qib_ctxt_info(struct file *fp, struct qib_ctxt_info __user *uinfo)
+{
+       struct qib_ctxt_info info;
+       int ret;
+       size_t sz;
+       struct qib_ctxtdata *rcd = ctxt_fp(fp);
+       struct qib_filedata *fd;
+
+       fd = (struct qib_filedata *) fp->private_data;
+
+       info.num_active = qib_count_active_units();
+       info.unit = rcd->dd->unit;
+       info.port = rcd->ppd->port;
+       info.ctxt = rcd->ctxt;
+       info.subctxt =  subctxt_fp(fp);
+       /* Number of user ctxts available for this device. */
+       info.num_ctxts = rcd->dd->cfgctxts - rcd->dd->first_user_ctxt;
+       info.num_subctxts = rcd->subctxt_cnt;
+       info.rec_cpu = fd->rec_cpu_num;
+       sz = sizeof(info);
+
+       if (copy_to_user(uinfo, &info, sz)) {
+               ret = -EFAULT;
+               goto bail;
+       }
+       ret = 0;
+
+bail:
+       return ret;
+}
+
+static int qib_sdma_get_inflight(struct qib_user_sdma_queue *pq,
+                                u32 __user *inflightp)
+{
+       const u32 val = qib_user_sdma_inflight_counter(pq);
+
+       if (put_user(val, inflightp))
+               return -EFAULT;
+
+       return 0;
+}
+
+static int qib_sdma_get_complete(struct qib_pportdata *ppd,
+                                struct qib_user_sdma_queue *pq,
+                                u32 __user *completep)
+{
+       u32 val;
+       int err;
+
+       if (!pq)
+               return -EINVAL;
+
+       err = qib_user_sdma_make_progress(ppd, pq);
+       if (err < 0)
+               return err;
+
+       val = qib_user_sdma_complete_counter(pq);
+       if (put_user(val, completep))
+               return -EFAULT;
+
+       return 0;
+}
+
+static int disarm_req_delay(struct qib_ctxtdata *rcd)
+{
+       int ret = 0;
+
+       if (!usable(rcd->ppd, 1)) {
+               int i;
+               /*
+                * if link is down, or otherwise not usable, delay
+                * the caller up to 30 seconds, so we don't thrash
+                * in trying to get the chip back to ACTIVE, and
+                * set flag so they make the call again.
+                */
+               if (rcd->user_event_mask) {
+                       /*
+                        * subctxt_cnt is 0 if not shared, so do base
+                        * separately, first, then remaining subctxt, if any
+                        */
+                       set_bit(_QIB_EVENT_DISARM_BUFS_BIT,
+                               &rcd->user_event_mask[0]);
+                       for (i = 1; i < rcd->subctxt_cnt; i++)
+                               set_bit(_QIB_EVENT_DISARM_BUFS_BIT,
+                                       &rcd->user_event_mask[i]);
+               }
+               for (i = 0; !usable(rcd->ppd, 1) && i < 300; i++)
+                       msleep(100);
+               ret = -ENETDOWN;
+       }
+       return ret;
+}
+
+/*
+ * Find all user contexts in use, and set the specified bit in their
+ * event mask.
+ * See also find_ctxt() for a similar use, that is specific to send buffers.
+ */
+int qib_set_uevent_bits(struct qib_pportdata *ppd, const int evtbit)
+{
+       struct qib_ctxtdata *rcd;
+       unsigned ctxt;
+       int ret = 0;
+
+       spin_lock(&ppd->dd->uctxt_lock);
+       for (ctxt = ppd->dd->first_user_ctxt; ctxt < ppd->dd->cfgctxts;
+            ctxt++) {
+               rcd = ppd->dd->rcd[ctxt];
+               if (!rcd)
+                       continue;
+               if (rcd->user_event_mask) {
+                       int i;
+                       /*
+                        * subctxt_cnt is 0 if not shared, so do base
+                        * separately, first, then remaining subctxt, if any
+                        */
+                       set_bit(evtbit, &rcd->user_event_mask[0]);
+                       for (i = 1; i < rcd->subctxt_cnt; i++)
+                               set_bit(evtbit, &rcd->user_event_mask[i]);
+               }
+               ret = 1;
+               break;
+       }
+       spin_unlock(&ppd->dd->uctxt_lock);
+
+       return ret;
+}
+
+/*
+ * clear the event notifier events for this context.
+ * For the DISARM_BUFS case, we also take action (this obsoletes
+ * the older QIB_CMD_DISARM_BUFS, but we keep it for backwards
+ * compatibility.
+ * Other bits don't currently require actions, just atomically clear.
+ * User process then performs actions appropriate to bit having been
+ * set, if desired, and checks again in future.
+ */
+static int qib_user_event_ack(struct qib_ctxtdata *rcd, int subctxt,
+                             unsigned long events)
+{
+       int ret = 0, i;
+
+       for (i = 0; i <= _QIB_MAX_EVENT_BIT; i++) {
+               if (!test_bit(i, &events))
+                       continue;
+               if (i == _QIB_EVENT_DISARM_BUFS_BIT) {
+                       (void)qib_disarm_piobufs_ifneeded(rcd);
+                       ret = disarm_req_delay(rcd);
+               } else
+                       clear_bit(i, &rcd->user_event_mask[subctxt]);
+       }
+       return ret;
+}
+
+static ssize_t qib_write(struct file *fp, const char __user *data,
+                        size_t count, loff_t *off)
+{
+       const struct qib_cmd __user *ucmd;
+       struct qib_ctxtdata *rcd;
+       const void __user *src;
+       size_t consumed, copy = 0;
+       struct qib_cmd cmd;
+       ssize_t ret = 0;
+       void *dest;
+
+       if (count < sizeof(cmd.type)) {
+               ret = -EINVAL;
+               goto bail;
+       }
+
+       ucmd = (const struct qib_cmd __user *) data;
+
+       if (copy_from_user(&cmd.type, &ucmd->type, sizeof(cmd.type))) {
+               ret = -EFAULT;
+               goto bail;
+       }
+
+       consumed = sizeof(cmd.type);
+
+       switch (cmd.type) {
+       case QIB_CMD_ASSIGN_CTXT:
+       case QIB_CMD_USER_INIT:
+               copy = sizeof(cmd.cmd.user_info);
+               dest = &cmd.cmd.user_info;
+               src = &ucmd->cmd.user_info;
+               break;
+
+       case QIB_CMD_RECV_CTRL:
+               copy = sizeof(cmd.cmd.recv_ctrl);
+               dest = &cmd.cmd.recv_ctrl;
+               src = &ucmd->cmd.recv_ctrl;
+               break;
+
+       case QIB_CMD_CTXT_INFO:
+               copy = sizeof(cmd.cmd.ctxt_info);
+               dest = &cmd.cmd.ctxt_info;
+               src = &ucmd->cmd.ctxt_info;
+               break;
+
+       case QIB_CMD_TID_UPDATE:
+       case QIB_CMD_TID_FREE:
+               copy = sizeof(cmd.cmd.tid_info);
+               dest = &cmd.cmd.tid_info;
+               src = &ucmd->cmd.tid_info;
+               break;
+
+       case QIB_CMD_SET_PART_KEY:
+               copy = sizeof(cmd.cmd.part_key);
+               dest = &cmd.cmd.part_key;
+               src = &ucmd->cmd.part_key;
+               break;
+
+       case QIB_CMD_DISARM_BUFS:
+       case QIB_CMD_PIOAVAILUPD: /* force an update of PIOAvail reg */
+               copy = 0;
+               src = NULL;
+               dest = NULL;
+               break;
+
+       case QIB_CMD_POLL_TYPE:
+               copy = sizeof(cmd.cmd.poll_type);
+               dest = &cmd.cmd.poll_type;
+               src = &ucmd->cmd.poll_type;
+               break;
+
+       case QIB_CMD_ARMLAUNCH_CTRL:
+               copy = sizeof(cmd.cmd.armlaunch_ctrl);
+               dest = &cmd.cmd.armlaunch_ctrl;
+               src = &ucmd->cmd.armlaunch_ctrl;
+               break;
+
+       case QIB_CMD_SDMA_INFLIGHT:
+               copy = sizeof(cmd.cmd.sdma_inflight);
+               dest = &cmd.cmd.sdma_inflight;
+               src = &ucmd->cmd.sdma_inflight;
+               break;
+
+       case QIB_CMD_SDMA_COMPLETE:
+               copy = sizeof(cmd.cmd.sdma_complete);
+               dest = &cmd.cmd.sdma_complete;
+               src = &ucmd->cmd.sdma_complete;
+               break;
+
+       case QIB_CMD_ACK_EVENT:
+               copy = sizeof(cmd.cmd.event_mask);
+               dest = &cmd.cmd.event_mask;
+               src = &ucmd->cmd.event_mask;
+               break;
+
+       default:
+               ret = -EINVAL;
+               goto bail;
+       }
+
+       if (copy) {
+               if ((count - consumed) < copy) {
+                       ret = -EINVAL;
+                       goto bail;
+               }
+               if (copy_from_user(dest, src, copy)) {
+                       ret = -EFAULT;
+                       goto bail;
+               }
+               consumed += copy;
+       }
+
+       rcd = ctxt_fp(fp);
+       if (!rcd && cmd.type != QIB_CMD_ASSIGN_CTXT) {
+               ret = -EINVAL;
+               goto bail;
+       }
+
+       switch (cmd.type) {
+       case QIB_CMD_ASSIGN_CTXT:
+               ret = qib_assign_ctxt(fp, &cmd.cmd.user_info);
+               if (ret)
+                       goto bail;
+               break;
+
+       case QIB_CMD_USER_INIT:
+               ret = qib_do_user_init(fp, &cmd.cmd.user_info);
+               if (ret)
+                       goto bail;
+               ret = qib_get_base_info(fp, (void __user *) (unsigned long)
+                                       cmd.cmd.user_info.spu_base_info,
+                                       cmd.cmd.user_info.spu_base_info_size);
+               break;
+
+       case QIB_CMD_RECV_CTRL:
+               ret = qib_manage_rcvq(rcd, subctxt_fp(fp), cmd.cmd.recv_ctrl);
+               break;
+
+       case QIB_CMD_CTXT_INFO:
+               ret = qib_ctxt_info(fp, (struct qib_ctxt_info __user *)
+                                   (unsigned long) cmd.cmd.ctxt_info);
+               break;
+
+       case QIB_CMD_TID_UPDATE:
+               ret = qib_tid_update(rcd, fp, &cmd.cmd.tid_info);
+               break;
+
+       case QIB_CMD_TID_FREE:
+               ret = qib_tid_free(rcd, subctxt_fp(fp), &cmd.cmd.tid_info);
+               break;
+
+       case QIB_CMD_SET_PART_KEY:
+               ret = qib_set_part_key(rcd, cmd.cmd.part_key);
+               break;
+
+       case QIB_CMD_DISARM_BUFS:
+               (void)qib_disarm_piobufs_ifneeded(rcd);
+               ret = disarm_req_delay(rcd);
+               break;
+
+       case QIB_CMD_PIOAVAILUPD:
+               qib_force_pio_avail_update(rcd->dd);
+               break;
+
+       case QIB_CMD_POLL_TYPE:
+               rcd->poll_type = cmd.cmd.poll_type;
+               break;
+
+       case QIB_CMD_ARMLAUNCH_CTRL:
+               rcd->dd->f_set_armlaunch(rcd->dd, cmd.cmd.armlaunch_ctrl);
+               break;
+
+       case QIB_CMD_SDMA_INFLIGHT:
+               ret = qib_sdma_get_inflight(user_sdma_queue_fp(fp),
+                                           (u32 __user *) (unsigned long)
+                                           cmd.cmd.sdma_inflight);
+               break;
+
+       case QIB_CMD_SDMA_COMPLETE:
+               ret = qib_sdma_get_complete(rcd->ppd,
+                                           user_sdma_queue_fp(fp),
+                                           (u32 __user *) (unsigned long)
+                                           cmd.cmd.sdma_complete);
+               break;
+
+       case QIB_CMD_ACK_EVENT:
+               ret = qib_user_event_ack(rcd, subctxt_fp(fp),
+                                        cmd.cmd.event_mask);
+               break;
+       }
+
+       if (ret >= 0)
+               ret = consumed;
+
+bail:
+       return ret;
+}
+
+static ssize_t qib_aio_write(struct kiocb *iocb, const struct iovec *iov,
+                            unsigned long dim, loff_t off)
+{
+       struct qib_filedata *fp = iocb->ki_filp->private_data;
+       struct qib_ctxtdata *rcd = ctxt_fp(iocb->ki_filp);
+       struct qib_user_sdma_queue *pq = fp->pq;
+
+       if (!dim || !pq)
+               return -EINVAL;
+
+       return qib_user_sdma_writev(rcd, pq, iov, dim);
+}
+
+static struct class *qib_class;
+static dev_t qib_dev;
+
+int qib_cdev_init(int minor, const char *name,
+                 const struct file_operations *fops,
+                 struct cdev **cdevp, struct device **devp)
+{
+       const dev_t dev = MKDEV(MAJOR(qib_dev), minor);
+       struct cdev *cdev;
+       struct device *device = NULL;
+       int ret;
+
+       cdev = cdev_alloc();
+       if (!cdev) {
+               printk(KERN_ERR QIB_DRV_NAME
+                      ": Could not allocate cdev for minor %d, %s\n",
+                      minor, name);
+               ret = -ENOMEM;
+               goto done;
+       }
+
+       cdev->owner = THIS_MODULE;
+       cdev->ops = fops;
+       kobject_set_name(&cdev->kobj, name);
+
+       ret = cdev_add(cdev, dev, 1);
+       if (ret < 0) {
+               printk(KERN_ERR QIB_DRV_NAME
+                      ": Could not add cdev for minor %d, %s (err %d)\n",
+                      minor, name, -ret);
+               goto err_cdev;
+       }
+
+       device = device_create(qib_class, NULL, dev, NULL, name);
+       if (!IS_ERR(device))
+               goto done;
+       ret = PTR_ERR(device);
+       device = NULL;
+       printk(KERN_ERR QIB_DRV_NAME ": Could not create "
+              "device for minor %d, %s (err %d)\n",
+              minor, name, -ret);
+err_cdev:
+       cdev_del(cdev);
+       cdev = NULL;
+done:
+       *cdevp = cdev;
+       *devp = device;
+       return ret;
+}
+
+void qib_cdev_cleanup(struct cdev **cdevp, struct device **devp)
+{
+       struct device *device = *devp;
+
+       if (device) {
+               device_unregister(device);
+               *devp = NULL;
+       }
+
+       if (*cdevp) {
+               cdev_del(*cdevp);
+               *cdevp = NULL;
+       }
+}
+
+static struct cdev *wildcard_cdev;
+static struct device *wildcard_device;
+
+int __init qib_dev_init(void)
+{
+       int ret;
+
+       ret = alloc_chrdev_region(&qib_dev, 0, QIB_NMINORS, QIB_DRV_NAME);
+       if (ret < 0) {
+               printk(KERN_ERR QIB_DRV_NAME ": Could not allocate "
+                      "chrdev region (err %d)\n", -ret);
+               goto done;
+       }
+
+       qib_class = class_create(THIS_MODULE, "ipath");
+       if (IS_ERR(qib_class)) {
+               ret = PTR_ERR(qib_class);
+               printk(KERN_ERR QIB_DRV_NAME ": Could not create "
+                      "device class (err %d)\n", -ret);
+               unregister_chrdev_region(qib_dev, QIB_NMINORS);
+       }
+
+done:
+       return ret;
+}
+
+void qib_dev_cleanup(void)
+{
+       if (qib_class) {
+               class_destroy(qib_class);
+               qib_class = NULL;
+       }
+
+       unregister_chrdev_region(qib_dev, QIB_NMINORS);
+}
+
+static atomic_t user_count = ATOMIC_INIT(0);
+
+static void qib_user_remove(struct qib_devdata *dd)
+{
+       if (atomic_dec_return(&user_count) == 0)
+               qib_cdev_cleanup(&wildcard_cdev, &wildcard_device);
+
+       qib_cdev_cleanup(&dd->user_cdev, &dd->user_device);
+}
+
+static int qib_user_add(struct qib_devdata *dd)
+{
+       char name[10];
+       int ret;
+
+       if (atomic_inc_return(&user_count) == 1) {
+               ret = qib_cdev_init(0, "ipath", &qib_file_ops,
+                                   &wildcard_cdev, &wildcard_device);
+               if (ret)
+                       goto done;
+       }
+
+       snprintf(name, sizeof(name), "ipath%d", dd->unit);
+       ret = qib_cdev_init(dd->unit + 1, name, &qib_file_ops,
+                           &dd->user_cdev, &dd->user_device);
+       if (ret)
+               qib_user_remove(dd);
+done:
+       return ret;
+}
+
+/*
+ * Create per-unit files in /dev
+ */
+int qib_device_create(struct qib_devdata *dd)
+{
+       int r, ret;
+
+       r = qib_user_add(dd);
+       ret = qib_diag_add(dd);
+       if (r && !ret)
+               ret = r;
+       return ret;
+}
+
+/*
+ * Remove per-unit files in /dev
+ * void, core kernel returns no errors for this stuff
+ */
+void qib_device_remove(struct qib_devdata *dd)
+{
+       qib_user_remove(dd);
+       qib_diag_remove(dd);
+}
diff --git a/drivers/infiniband/hw/qib/qib_fs.c b/drivers/infiniband/hw/qib/qib_fs.c
new file mode 100644 (file)
index 0000000..edef852
--- /dev/null
@@ -0,0 +1,618 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved.
+ * Copyright (c) 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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>
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/pagemap.h>
+#include <linux/init.h>
+#include <linux/namei.h>
+
+#include "qib.h"
+
+#define QIBFS_MAGIC 0x726a77
+
+static struct super_block *qib_super;
+
+#define private2dd(file) ((file)->f_dentry->d_inode->i_private)
+
+static int qibfs_mknod(struct inode *dir, struct dentry *dentry,
+                      int mode, const struct file_operations *fops,
+                      void *data)
+{
+       int error;
+       struct inode *inode = new_inode(dir->i_sb);
+
+       if (!inode) {
+               error = -EPERM;
+               goto bail;
+       }
+
+       inode->i_mode = mode;
+       inode->i_uid = 0;
+       inode->i_gid = 0;
+       inode->i_blocks = 0;
+       inode->i_atime = CURRENT_TIME;
+       inode->i_mtime = inode->i_atime;
+       inode->i_ctime = inode->i_atime;
+       inode->i_private = data;
+       if ((mode & S_IFMT) == S_IFDIR) {
+               inode->i_op = &simple_dir_inode_operations;
+               inc_nlink(inode);
+               inc_nlink(dir);
+       }
+
+       inode->i_fop = fops;
+
+       d_instantiate(dentry, inode);
+       error = 0;
+
+bail:
+       return error;
+}
+
+static int create_file(const char *name, mode_t mode,
+                      struct dentry *parent, struct dentry **dentry,
+                      const struct file_operations *fops, void *data)
+{
+       int error;
+
+       *dentry = NULL;
+       mutex_lock(&parent->d_inode->i_mutex);
+       *dentry = lookup_one_len(name, parent, strlen(name));
+       if (!IS_ERR(*dentry))
+               error = qibfs_mknod(parent->d_inode, *dentry,
+                                   mode, fops, data);
+       else
+               error = PTR_ERR(*dentry);
+       mutex_unlock(&parent->d_inode->i_mutex);
+
+       return error;
+}
+
+static ssize_t driver_stats_read(struct file *file, char __user *buf,
+                                size_t count, loff_t *ppos)
+{
+       return simple_read_from_buffer(buf, count, ppos, &qib_stats,
+                                      sizeof qib_stats);
+}
+
+/*
+ * driver stats field names, one line per stat, single string.  Used by
+ * programs like ipathstats to print the stats in a way which works for
+ * different versions of drivers, without changing program source.
+ * if qlogic_ib_stats changes, this needs to change.  Names need to be
+ * 12 chars or less (w/o newline), for proper display by ipathstats utility.
+ */
+static const char qib_statnames[] =
+       "KernIntr\n"
+       "ErrorIntr\n"
+       "Tx_Errs\n"
+       "Rcv_Errs\n"
+       "H/W_Errs\n"
+       "NoPIOBufs\n"
+       "CtxtsOpen\n"
+       "RcvLen_Errs\n"
+       "EgrBufFull\n"
+       "EgrHdrFull\n"
+       ;
+
+static ssize_t driver_names_read(struct file *file, char __user *buf,
+                                size_t count, loff_t *ppos)
+{
+       return simple_read_from_buffer(buf, count, ppos, qib_statnames,
+               sizeof qib_statnames - 1); /* no null */
+}
+
+static const struct file_operations driver_ops[] = {
+       { .read = driver_stats_read, },
+       { .read = driver_names_read, },
+};
+
+/* read the per-device counters */
+static ssize_t dev_counters_read(struct file *file, char __user *buf,
+                                size_t count, loff_t *ppos)
+{
+       u64 *counters;
+       size_t avail;
+       struct qib_devdata *dd = private2dd(file);
+
+       avail = dd->f_read_cntrs(dd, *ppos, NULL, &counters);
+       return simple_read_from_buffer(buf, count, ppos, counters, avail);
+}
+
+/* read the per-device counters */
+static ssize_t dev_names_read(struct file *file, char __user *buf,
+                             size_t count, loff_t *ppos)
+{
+       char *names;
+       size_t avail;
+       struct qib_devdata *dd = private2dd(file);
+
+       avail = dd->f_read_cntrs(dd, *ppos, &names, NULL);
+       return simple_read_from_buffer(buf, count, ppos, names, avail);
+}
+
+static const struct file_operations cntr_ops[] = {
+       { .read = dev_counters_read, },
+       { .read = dev_names_read, },
+};
+
+/*
+ * Could use file->f_dentry->d_inode->i_ino to figure out which file,
+ * instead of separate routine for each, but for now, this works...
+ */
+
+/* read the per-port names (same for each port) */
+static ssize_t portnames_read(struct file *file, char __user *buf,
+                             size_t count, loff_t *ppos)
+{
+       char *names;
+       size_t avail;
+       struct qib_devdata *dd = private2dd(file);
+
+       avail = dd->f_read_portcntrs(dd, *ppos, 0, &names, NULL);
+       return simple_read_from_buffer(buf, count, ppos, names, avail);
+}
+
+/* read the per-port counters for port 1 (pidx 0) */
+static ssize_t portcntrs_1_read(struct file *file, char __user *buf,
+                               size_t count, loff_t *ppos)
+{
+       u64 *counters;
+       size_t avail;
+       struct qib_devdata *dd = private2dd(file);
+
+       avail = dd->f_read_portcntrs(dd, *ppos, 0, NULL, &counters);
+       return simple_read_from_buffer(buf, count, ppos, counters, avail);
+}
+
+/* read the per-port counters for port 2 (pidx 1) */
+static ssize_t portcntrs_2_read(struct file *file, char __user *buf,
+                               size_t count, loff_t *ppos)
+{
+       u64 *counters;
+       size_t avail;
+       struct qib_devdata *dd = private2dd(file);
+
+       avail = dd->f_read_portcntrs(dd, *ppos, 1, NULL, &counters);
+       return simple_read_from_buffer(buf, count, ppos, counters, avail);
+}
+
+static const struct file_operations portcntr_ops[] = {
+       { .read = portnames_read, },
+       { .read = portcntrs_1_read, },
+       { .read = portcntrs_2_read, },
+};
+
+/*
+ * read the per-port QSFP data for port 1 (pidx 0)
+ */
+static ssize_t qsfp_1_read(struct file *file, char __user *buf,
+                          size_t count, loff_t *ppos)
+{
+       struct qib_devdata *dd = private2dd(file);
+       char *tmp;
+       int ret;
+
+       tmp = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!tmp)
+               return -ENOMEM;
+
+       ret = qib_qsfp_dump(dd->pport, tmp, PAGE_SIZE);
+       if (ret > 0)
+               ret = simple_read_from_buffer(buf, count, ppos, tmp, ret);
+       kfree(tmp);
+       return ret;
+}
+
+/*
+ * read the per-port QSFP data for port 2 (pidx 1)
+ */
+static ssize_t qsfp_2_read(struct file *file, char __user *buf,
+                          size_t count, loff_t *ppos)
+{
+       struct qib_devdata *dd = private2dd(file);
+       char *tmp;
+       int ret;
+
+       if (dd->num_pports < 2)
+               return -ENODEV;
+
+       tmp = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!tmp)
+               return -ENOMEM;
+
+       ret = qib_qsfp_dump(dd->pport + 1, tmp, PAGE_SIZE);
+       if (ret > 0)
+               ret = simple_read_from_buffer(buf, count, ppos, tmp, ret);
+       kfree(tmp);
+       return ret;
+}
+
+static const struct file_operations qsfp_ops[] = {
+       { .read = qsfp_1_read, },
+       { .read = qsfp_2_read, },
+};
+
+static ssize_t flash_read(struct file *file, char __user *buf,
+                         size_t count, loff_t *ppos)
+{
+       struct qib_devdata *dd;
+       ssize_t ret;
+       loff_t pos;
+       char *tmp;
+
+       pos = *ppos;
+
+       if (pos < 0) {
+               ret = -EINVAL;
+               goto bail;
+       }
+
+       if (pos >= sizeof(struct qib_flash)) {
+               ret = 0;
+               goto bail;
+       }
+
+       if (count > sizeof(struct qib_flash) - pos)
+               count = sizeof(struct qib_flash) - pos;
+
+       tmp = kmalloc(count, GFP_KERNEL);
+       if (!tmp) {
+               ret = -ENOMEM;
+               goto bail;
+       }
+
+       dd = private2dd(file);
+       if (qib_eeprom_read(dd, pos, tmp, count)) {
+               qib_dev_err(dd, "failed to read from flash\n");
+               ret = -ENXIO;
+               goto bail_tmp;
+       }
+
+       if (copy_to_user(buf, tmp, count)) {
+               ret = -EFAULT;
+               goto bail_tmp;
+       }
+
+       *ppos = pos + count;
+       ret = count;
+
+bail_tmp:
+       kfree(tmp);
+
+bail:
+       return ret;
+}
+
+static ssize_t flash_write(struct file *file, const char __user *buf,
+                          size_t count, loff_t *ppos)
+{
+       struct qib_devdata *dd;
+       ssize_t ret;
+       loff_t pos;
+       char *tmp;
+
+       pos = *ppos;
+
+       if (pos != 0) {
+               ret = -EINVAL;
+               goto bail;
+       }
+
+       if (count != sizeof(struct qib_flash)) {
+               ret = -EINVAL;
+               goto bail;
+       }
+
+       tmp = kmalloc(count, GFP_KERNEL);
+       if (!tmp) {
+               ret = -ENOMEM;
+               goto bail;
+       }
+
+       if (copy_from_user(tmp, buf, count)) {
+               ret = -EFAULT;
+               goto bail_tmp;
+       }
+
+       dd = private2dd(file);
+       if (qib_eeprom_write(dd, pos, tmp, count)) {
+               ret = -ENXIO;
+               qib_dev_err(dd, "failed to write to flash\n");
+               goto bail_tmp;
+       }
+
+       *ppos = pos + count;
+       ret = count;
+
+bail_tmp:
+       kfree(tmp);
+
+bail:
+       return ret;
+}
+
+static const struct file_operations flash_ops = {
+       .read = flash_read,
+       .write = flash_write,
+};
+
+static int add_cntr_files(struct super_block *sb, struct qib_devdata *dd)
+{
+       struct dentry *dir, *tmp;
+       char unit[10];
+       int ret, i;
+
+       /* create the per-unit directory */
+       snprintf(unit, sizeof unit, "%u", dd->unit);
+       ret = create_file(unit, S_IFDIR|S_IRUGO|S_IXUGO, sb->s_root, &dir,
+                         &simple_dir_operations, dd);
+       if (ret) {
+               printk(KERN_ERR "create_file(%s) failed: %d\n", unit, ret);
+               goto bail;
+       }
+
+       /* create the files in the new directory */
+       ret = create_file("counters", S_IFREG|S_IRUGO, dir, &tmp,
+                         &cntr_ops[0], dd);
+       if (ret) {
+               printk(KERN_ERR "create_file(%s/counters) failed: %d\n",
+                      unit, ret);
+               goto bail;
+       }
+       ret = create_file("counter_names", S_IFREG|S_IRUGO, dir, &tmp,
+                         &cntr_ops[1], dd);
+       if (ret) {
+               printk(KERN_ERR "create_file(%s/counter_names) failed: %d\n",
+                      unit, ret);
+               goto bail;
+       }
+       ret = create_file("portcounter_names", S_IFREG|S_IRUGO, dir, &tmp,
+                         &portcntr_ops[0], dd);
+       if (ret) {
+               printk(KERN_ERR "create_file(%s/%s) failed: %d\n",
+                      unit, "portcounter_names", ret);
+               goto bail;
+       }
+       for (i = 1; i <= dd->num_pports; i++) {
+               char fname[24];
+
+               sprintf(fname, "port%dcounters", i);
+               /* create the files in the new directory */
+               ret = create_file(fname, S_IFREG|S_IRUGO, dir, &tmp,
+                                 &portcntr_ops[i], dd);
+               if (ret) {
+                       printk(KERN_ERR "create_file(%s/%s) failed: %d\n",
+                               unit, fname, ret);
+                       goto bail;
+               }
+               if (!(dd->flags & QIB_HAS_QSFP))
+                       continue;
+               sprintf(fname, "qsfp%d", i);
+               ret = create_file(fname, S_IFREG|S_IRUGO, dir, &tmp,
+                                 &qsfp_ops[i - 1], dd);
+               if (ret) {
+                       printk(KERN_ERR "create_file(%s/%s) failed: %d\n",
+                               unit, fname, ret);
+                       goto bail;
+               }
+       }
+
+       ret = create_file("flash", S_IFREG|S_IWUSR|S_IRUGO, dir, &tmp,
+                         &flash_ops, dd);
+       if (ret)
+               printk(KERN_ERR "create_file(%s/flash) failed: %d\n",
+                       unit, ret);
+bail:
+       return ret;
+}
+
+static int remove_file(struct dentry *parent, char *name)
+{
+       struct dentry *tmp;
+       int ret;
+
+       tmp = lookup_one_len(name, parent, strlen(name));
+
+       if (IS_ERR(tmp)) {
+               ret = PTR_ERR(tmp);
+               goto bail;
+       }
+
+       spin_lock(&dcache_lock);
+       spin_lock(&tmp->d_lock);
+       if (!(d_unhashed(tmp) && tmp->d_inode)) {
+               dget_locked(tmp);
+               __d_drop(tmp);
+               spin_unlock(&tmp->d_lock);
+               spin_unlock(&dcache_lock);
+               simple_unlink(parent->d_inode, tmp);
+       } else {
+               spin_unlock(&tmp->d_lock);
+               spin_unlock(&dcache_lock);
+       }
+
+       ret = 0;
+bail:
+       /*
+        * We don't expect clients to care about the return value, but
+        * it's there if they need it.
+        */
+       return ret;
+}
+
+static int remove_device_files(struct super_block *sb,
+                              struct qib_devdata *dd)
+{
+       struct dentry *dir, *root;
+       char unit[10];
+       int ret, i;
+
+       root = dget(sb->s_root);
+       mutex_lock(&root->d_inode->i_mutex);
+       snprintf(unit, sizeof unit, "%u", dd->unit);
+       dir = lookup_one_len(unit, root, strlen(unit));
+
+       if (IS_ERR(dir)) {
+               ret = PTR_ERR(dir);
+               printk(KERN_ERR "Lookup of %s failed\n", unit);
+               goto bail;
+       }
+
+       remove_file(dir, "counters");
+       remove_file(dir, "counter_names");
+       remove_file(dir, "portcounter_names");
+       for (i = 0; i < dd->num_pports; i++) {
+               char fname[24];
+
+               sprintf(fname, "port%dcounters", i + 1);
+               remove_file(dir, fname);
+               if (dd->flags & QIB_HAS_QSFP) {
+                       sprintf(fname, "qsfp%d", i + 1);
+                       remove_file(dir, fname);
+               }
+       }
+       remove_file(dir, "flash");
+       d_delete(dir);
+       ret = simple_rmdir(root->d_inode, dir);
+
+bail:
+       mutex_unlock(&root->d_inode->i_mutex);
+       dput(root);
+       return ret;
+}
+
+/*
+ * This fills everything in when the fs is mounted, to handle umount/mount
+ * after device init.  The direct add_cntr_files() call handles adding
+ * them from the init code, when the fs is already mounted.
+ */
+static int qibfs_fill_super(struct super_block *sb, void *data, int silent)
+{
+       struct qib_devdata *dd, *tmp;
+       unsigned long flags;
+       int ret;
+
+       static struct tree_descr files[] = {
+               [2] = {"driver_stats", &driver_ops[0], S_IRUGO},
+               [3] = {"driver_stats_names", &driver_ops[1], S_IRUGO},
+               {""},
+       };
+
+       ret = simple_fill_super(sb, QIBFS_MAGIC, files);
+       if (ret) {
+               printk(KERN_ERR "simple_fill_super failed: %d\n", ret);
+               goto bail;
+       }
+
+       spin_lock_irqsave(&qib_devs_lock, flags);
+
+       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);
+                       goto bail;
+               }
+               spin_lock_irqsave(&qib_devs_lock, flags);
+       }
+
+       spin_unlock_irqrestore(&qib_devs_lock, flags);
+
+bail:
+       return ret;
+}
+
+static int qibfs_get_sb(struct file_system_type *fs_type, int flags,
+                       const char *dev_name, void *data, struct vfsmount *mnt)
+{
+       int ret = get_sb_single(fs_type, flags, data,
+                               qibfs_fill_super, mnt);
+       if (ret >= 0)
+               qib_super = mnt->mnt_sb;
+       return ret;
+}
+
+static void qibfs_kill_super(struct super_block *s)
+{
+       kill_litter_super(s);
+       qib_super = NULL;
+}
+
+int qibfs_add(struct qib_devdata *dd)
+{
+       int ret;
+
+       /*
+        * On first unit initialized, qib_super will not yet exist
+        * because nobody has yet tried to mount the filesystem, so
+        * we can't consider that to be an error; if an error occurs
+        * during the mount, that will get a complaint, so this is OK.
+        * add_cntr_files() for all units is done at mount from
+        * qibfs_fill_super(), so one way or another, everything works.
+        */
+       if (qib_super == NULL)
+               ret = 0;
+       else
+               ret = add_cntr_files(qib_super, dd);
+       return ret;
+}
+
+int qibfs_remove(struct qib_devdata *dd)
+{
+       int ret = 0;
+
+       if (qib_super)
+               ret = remove_device_files(qib_super, dd);
+
+       return ret;
+}
+
+static struct file_system_type qibfs_fs_type = {
+       .owner =        THIS_MODULE,
+       .name =         "ipathfs",
+       .get_sb =       qibfs_get_sb,
+       .kill_sb =      qibfs_kill_super,
+};
+
+int __init qib_init_qibfs(void)
+{
+       return register_filesystem(&qibfs_fs_type);
+}
+
+int __exit qib_exit_qibfs(void)
+{
+       return unregister_filesystem(&qibfs_fs_type);
+}
diff --git a/drivers/infiniband/hw/qib/qib_iba6120.c b/drivers/infiniband/hw/qib/qib_iba6120.c
new file mode 100644 (file)
index 0000000..1eadadc
--- /dev/null
@@ -0,0 +1,3576 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009, 2010 QLogic Corporation.
+ * All rights reserved.
+ * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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.
+ */
+/*
+ * This file contains all of the code that is specific to the
+ * QLogic_IB 6120 PCIe chip.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <rdma/ib_verbs.h>
+
+#include "qib.h"
+#include "qib_6120_regs.h"
+
+static void qib_6120_setup_setextled(struct qib_pportdata *, u32);
+static void sendctrl_6120_mod(struct qib_pportdata *ppd, u32 op);
+static u8 qib_6120_phys_portstate(u64);
+static u32 qib_6120_iblink_state(u64);
+
+/*
+ * This file contains all the chip-specific register information and
+ * access functions for the QLogic QLogic_IB PCI-Express chip.
+ *
+ */
+
+/* KREG_IDX uses machine-generated #defines */
+#define KREG_IDX(regname) (QIB_6120_##regname##_OFFS / sizeof(u64))
+
+/* Use defines to tie machine-generated names to lower-case names */
+#define kr_extctrl KREG_IDX(EXTCtrl)
+#define kr_extstatus KREG_IDX(EXTStatus)
+#define kr_gpio_clear KREG_IDX(GPIOClear)
+#define kr_gpio_mask KREG_IDX(GPIOMask)
+#define kr_gpio_out KREG_IDX(GPIOOut)
+#define kr_gpio_status KREG_IDX(GPIOStatus)
+#define kr_rcvctrl KREG_IDX(RcvCtrl)
+#define kr_sendctrl KREG_IDX(SendCtrl)
+#define kr_partitionkey KREG_IDX(RcvPartitionKey)
+#define kr_hwdiagctrl KREG_IDX(HwDiagCtrl)
+#define kr_ibcstatus KREG_IDX(IBCStatus)
+#define kr_ibcctrl KREG_IDX(IBCCtrl)
+#define kr_sendbuffererror KREG_IDX(SendBufErr0)
+#define kr_rcvbthqp KREG_IDX(RcvBTHQP)
+#define kr_counterregbase KREG_IDX(CntrRegBase)
+#define kr_palign KREG_IDX(PageAlign)
+#define kr_rcvegrbase KREG_IDX(RcvEgrBase)
+#define kr_rcvegrcnt KREG_IDX(RcvEgrCnt)
+#define kr_rcvhdrcnt KREG_IDX(RcvHdrCnt)
+#define kr_rcvhdrentsize KREG_IDX(RcvHdrEntSize)
+#define kr_rcvhdrsize KREG_IDX(RcvHdrSize)
+#define kr_rcvtidbase KREG_IDX(RcvTIDBase)
+#define kr_rcvtidcnt KREG_IDX(RcvTIDCnt)
+#define kr_scratch KREG_IDX(Scratch)
+#define kr_sendctrl KREG_IDX(SendCtrl)
+#define kr_sendpioavailaddr KREG_IDX(SendPIOAvailAddr)
+#define kr_sendpiobufbase KREG_IDX(SendPIOBufBase)
+#define kr_sendpiobufcnt KREG_IDX(SendPIOBufCnt)
+#define kr_sendpiosize KREG_IDX(SendPIOSize)
+#define kr_sendregbase KREG_IDX(SendRegBase)
+#define kr_userregbase KREG_IDX(UserRegBase)
+#define kr_control KREG_IDX(Control)
+#define kr_intclear KREG_IDX(IntClear)
+#define kr_intmask KREG_IDX(IntMask)
+#define kr_intstatus KREG_IDX(IntStatus)
+#define kr_errclear KREG_IDX(ErrClear)
+#define kr_errmask KREG_IDX(ErrMask)
+#define kr_errstatus KREG_IDX(ErrStatus)
+#define kr_hwerrclear KREG_IDX(HwErrClear)
+#define kr_hwerrmask KREG_IDX(HwErrMask)
+#define kr_hwerrstatus KREG_IDX(HwErrStatus)
+#define kr_revision KREG_IDX(Revision)
+#define kr_portcnt KREG_IDX(PortCnt)
+#define kr_serdes_cfg0 KREG_IDX(SerdesCfg0)
+#define kr_serdes_cfg1 (kr_serdes_cfg0 + 1)
+#define kr_serdes_stat KREG_IDX(SerdesStat)
+#define kr_xgxs_cfg KREG_IDX(XGXSCfg)
+
+/* These must only be written via qib_write_kreg_ctxt() */
+#define kr_rcvhdraddr KREG_IDX(RcvHdrAddr0)
+#define kr_rcvhdrtailaddr KREG_IDX(RcvHdrTailAddr0)
+
+#define CREG_IDX(regname) ((QIB_6120_##regname##_OFFS - \
+                       QIB_6120_LBIntCnt_OFFS) / sizeof(u64))
+
+#define cr_badformat CREG_IDX(RxBadFormatCnt)
+#define cr_erricrc CREG_IDX(RxICRCErrCnt)
+#define cr_errlink CREG_IDX(RxLinkProblemCnt)
+#define cr_errlpcrc CREG_IDX(RxLPCRCErrCnt)
+#define cr_errpkey CREG_IDX(RxPKeyMismatchCnt)
+#define cr_rcvflowctrl_err CREG_IDX(RxFlowCtrlErrCnt)
+#define cr_err_rlen CREG_IDX(RxLenErrCnt)
+#define cr_errslen CREG_IDX(TxLenErrCnt)
+#define cr_errtidfull CREG_IDX(RxTIDFullErrCnt)
+#define cr_errtidvalid CREG_IDX(RxTIDValidErrCnt)
+#define cr_errvcrc CREG_IDX(RxVCRCErrCnt)
+#define cr_ibstatuschange CREG_IDX(IBStatusChangeCnt)
+#define cr_lbint CREG_IDX(LBIntCnt)
+#define cr_invalidrlen CREG_IDX(RxMaxMinLenErrCnt)
+#define cr_invalidslen CREG_IDX(TxMaxMinLenErrCnt)
+#define cr_lbflowstall CREG_IDX(LBFlowStallCnt)
+#define cr_pktrcv CREG_IDX(RxDataPktCnt)
+#define cr_pktrcvflowctrl CREG_IDX(RxFlowPktCnt)
+#define cr_pktsend CREG_IDX(TxDataPktCnt)
+#define cr_pktsendflow CREG_IDX(TxFlowPktCnt)
+#define cr_portovfl CREG_IDX(RxP0HdrEgrOvflCnt)
+#define cr_rcvebp CREG_IDX(RxEBPCnt)
+#define cr_rcvovfl CREG_IDX(RxBufOvflCnt)
+#define cr_senddropped CREG_IDX(TxDroppedPktCnt)
+#define cr_sendstall CREG_IDX(TxFlowStallCnt)
+#define cr_sendunderrun CREG_IDX(TxUnderrunCnt)
+#define cr_wordrcv CREG_IDX(RxDwordCnt)
+#define cr_wordsend CREG_IDX(TxDwordCnt)
+#define cr_txunsupvl CREG_IDX(TxUnsupVLErrCnt)
+#define cr_rxdroppkt CREG_IDX(RxDroppedPktCnt)
+#define cr_iblinkerrrecov CREG_IDX(IBLinkErrRecoveryCnt)
+#define cr_iblinkdown CREG_IDX(IBLinkDownedCnt)
+#define cr_ibsymbolerr CREG_IDX(IBSymbolErrCnt)
+
+#define SYM_RMASK(regname, fldname) ((u64)              \
+       QIB_6120_##regname##_##fldname##_RMASK)
+#define SYM_MASK(regname, fldname) ((u64)               \
+       QIB_6120_##regname##_##fldname##_RMASK <<       \
+        QIB_6120_##regname##_##fldname##_LSB)
+#define SYM_LSB(regname, fldname) (QIB_6120_##regname##_##fldname##_LSB)
+
+#define SYM_FIELD(value, regname, fldname) ((u64) \
+       (((value) >> SYM_LSB(regname, fldname)) & \
+        SYM_RMASK(regname, fldname)))
+#define ERR_MASK(fldname) SYM_MASK(ErrMask, fldname##Mask)
+#define HWE_MASK(fldname) SYM_MASK(HwErrMask, fldname##Mask)
+
+/* link training states, from IBC */
+#define IB_6120_LT_STATE_DISABLED        0x00
+#define IB_6120_LT_STATE_LINKUP          0x01
+#define IB_6120_LT_STATE_POLLACTIVE      0x02
+#define IB_6120_LT_STATE_POLLQUIET       0x03
+#define IB_6120_LT_STATE_SLEEPDELAY      0x04
+#define IB_6120_LT_STATE_SLEEPQUIET      0x05
+#define IB_6120_LT_STATE_CFGDEBOUNCE     0x08
+#define IB_6120_LT_STATE_CFGRCVFCFG      0x09
+#define IB_6120_LT_STATE_CFGWAITRMT      0x0a
+#define IB_6120_LT_STATE_CFGIDLE 0x0b
+#define IB_6120_LT_STATE_RECOVERRETRAIN  0x0c
+#define IB_6120_LT_STATE_RECOVERWAITRMT  0x0e
+#define IB_6120_LT_STATE_RECOVERIDLE     0x0f
+
+/* link state machine states from IBC */
+#define IB_6120_L_STATE_DOWN             0x0
+#define IB_6120_L_STATE_INIT             0x1
+#define IB_6120_L_STATE_ARM              0x2
+#define IB_6120_L_STATE_ACTIVE           0x3
+#define IB_6120_L_STATE_ACT_DEFER        0x4
+
+static const u8 qib_6120_physportstate[0x20] = {
+       [IB_6120_LT_STATE_DISABLED] = IB_PHYSPORTSTATE_DISABLED,
+       [IB_6120_LT_STATE_LINKUP] = IB_PHYSPORTSTATE_LINKUP,
+       [IB_6120_LT_STATE_POLLACTIVE] = IB_PHYSPORTSTATE_POLL,
+       [IB_6120_LT_STATE_POLLQUIET] = IB_PHYSPORTSTATE_POLL,
+       [IB_6120_LT_STATE_SLEEPDELAY] = IB_PHYSPORTSTATE_SLEEP,
+       [IB_6120_LT_STATE_SLEEPQUIET] = IB_PHYSPORTSTATE_SLEEP,
+       [IB_6120_LT_STATE_CFGDEBOUNCE] =
+               IB_PHYSPORTSTATE_CFG_TRAIN,
+       [IB_6120_LT_STATE_CFGRCVFCFG] =
+               IB_PHYSPORTSTATE_CFG_TRAIN,
+       [IB_6120_LT_STATE_CFGWAITRMT] =
+               IB_PHYSPORTSTATE_CFG_TRAIN,
+       [IB_6120_LT_STATE_CFGIDLE] = IB_PHYSPORTSTATE_CFG_TRAIN,
+       [IB_6120_LT_STATE_RECOVERRETRAIN] =
+               IB_PHYSPORTSTATE_LINK_ERR_RECOVER,
+       [IB_6120_LT_STATE_RECOVERWAITRMT] =
+               IB_PHYSPORTSTATE_LINK_ERR_RECOVER,
+       [IB_6120_LT_STATE_RECOVERIDLE] =
+               IB_PHYSPORTSTATE_LINK_ERR_RECOVER,
+       [0x10] = IB_PHYSPORTSTATE_CFG_TRAIN,
+       [0x11] = IB_PHYSPORTSTATE_CFG_TRAIN,
+       [0x12] = IB_PHYSPORTSTATE_CFG_TRAIN,
+       [0x13] = IB_PHYSPORTSTATE_CFG_TRAIN,
+       [0x14] = IB_PHYSPORTSTATE_CFG_TRAIN,
+       [0x15] = IB_PHYSPORTSTATE_CFG_TRAIN,
+       [0x16] = IB_PHYSPORTSTATE_CFG_TRAIN,
+       [0x17] = IB_PHYSPORTSTATE_CFG_TRAIN
+};
+
+
+struct qib_chip_specific {
+       u64 __iomem *cregbase;
+       u64 *cntrs;
+       u64 *portcntrs;
+       void *dummy_hdrq;   /* used after ctxt close */
+       dma_addr_t dummy_hdrq_phys;
+       spinlock_t kernel_tid_lock; /* no back to back kernel TID writes */
+       spinlock_t user_tid_lock; /* no back to back user TID writes */
+       spinlock_t rcvmod_lock; /* protect rcvctrl shadow changes */
+       spinlock_t gpio_lock; /* RMW of shadows/regs for ExtCtrl and GPIO */
+       u64 hwerrmask;
+       u64 errormask;
+       u64 gpio_out; /* shadow of kr_gpio_out, for rmw ops */
+       u64 gpio_mask; /* shadow the gpio mask register */
+       u64 extctrl; /* shadow the gpio output enable, etc... */
+       /*
+        * these 5 fields are used to establish deltas for IB symbol
+        * errors and linkrecovery errors.  They can be reported on
+        * some chips during link negotiation prior to INIT, and with
+        * DDR when faking DDR negotiations with non-IBTA switches.
+        * The chip counters are adjusted at driver unload if there is
+        * a non-zero delta.
+        */
+       u64 ibdeltainprog;
+       u64 ibsymdelta;
+       u64 ibsymsnap;
+       u64 iblnkerrdelta;
+       u64 iblnkerrsnap;
+       u64 ibcctrl; /* shadow for kr_ibcctrl */
+       u32 lastlinkrecov; /* link recovery issue */
+       int irq;
+       u32 cntrnamelen;
+       u32 portcntrnamelen;
+       u32 ncntrs;
+       u32 nportcntrs;
+       /* used with gpio interrupts to implement IB counters */
+       u32 rxfc_unsupvl_errs;
+       u32 overrun_thresh_errs;
+       /*
+        * these count only cases where _successive_ LocalLinkIntegrity
+        * errors were seen in the receive headers of IB standard packets
+        */
+       u32 lli_errs;
+       u32 lli_counter;
+       u64 lli_thresh;
+       u64 sword; /* total dwords sent (sample result) */
+       u64 rword; /* total dwords received (sample result) */
+       u64 spkts; /* total packets sent (sample result) */
+       u64 rpkts; /* total packets received (sample result) */
+       u64 xmit_wait; /* # of ticks no data sent (sample result) */
+       struct timer_list pma_timer;
+       char emsgbuf[128];
+       char bitsmsgbuf[64];
+       u8 pma_sample_status;
+};
+
+/* ibcctrl bits */
+#define QLOGIC_IB_IBCC_LINKINITCMD_DISABLE 1
+/* cycle through TS1/TS2 till OK */
+#define QLOGIC_IB_IBCC_LINKINITCMD_POLL 2
+/* wait for TS1, then go on */
+#define QLOGIC_IB_IBCC_LINKINITCMD_SLEEP 3
+#define QLOGIC_IB_IBCC_LINKINITCMD_SHIFT 16
+
+#define QLOGIC_IB_IBCC_LINKCMD_DOWN 1           /* move to 0x11 */
+#define QLOGIC_IB_IBCC_LINKCMD_ARMED 2          /* move to 0x21 */
+#define QLOGIC_IB_IBCC_LINKCMD_ACTIVE 3 /* move to 0x31 */
+#define QLOGIC_IB_IBCC_LINKCMD_SHIFT 18
+
+/*
+ * We could have a single register get/put routine, that takes a group type,
+ * but this is somewhat clearer and cleaner.  It also gives us some error
+ * checking.  64 bit register reads should always work, but are inefficient
+ * on opteron (the northbridge always generates 2 separate HT 32 bit reads),
+ * so we use kreg32 wherever possible.  User register and counter register
+ * reads are always 32 bit reads, so only one form of those routines.
+ */
+
+/**
+ * qib_read_ureg32 - read 32-bit virtualized per-context register
+ * @dd: device
+ * @regno: register number
+ * @ctxt: context number
+ *
+ * Return the contents of a register that is virtualized to be per context.
+ * Returns -1 on errors (not distinguishable from valid contents at
+ * runtime; we may add a separate error variable at some point).
+ */
+static inline u32 qib_read_ureg32(const struct qib_devdata *dd,
+                                 enum qib_ureg regno, int ctxt)
+{
+       if (!dd->kregbase || !(dd->flags & QIB_PRESENT))
+               return 0;
+
+       if (dd->userbase)
+               return readl(regno + (u64 __iomem *)
+                            ((char __iomem *)dd->userbase +
+                             dd->ureg_align * ctxt));
+       else
+               return readl(regno + (u64 __iomem *)
+                            (dd->uregbase +
+                             (char __iomem *)dd->kregbase +
+                             dd->ureg_align * ctxt));
+}
+
+/**
+ * qib_write_ureg - write 32-bit virtualized per-context register
+ * @dd: device
+ * @regno: register number
+ * @value: value
+ * @ctxt: context
+ *
+ * Write the contents of a register that is virtualized to be per context.
+ */
+static inline void qib_write_ureg(const struct qib_devdata *dd,
+                                 enum qib_ureg regno, u64 value, int ctxt)
+{
+       u64 __iomem *ubase;
+       if (dd->userbase)
+               ubase = (u64 __iomem *)
+                       ((char __iomem *) dd->userbase +
+                        dd->ureg_align * ctxt);
+       else
+               ubase = (u64 __iomem *)
+                       (dd->uregbase +
+                        (char __iomem *) dd->kregbase +
+                        dd->ureg_align * ctxt);
+
+       if (dd->kregbase && (dd->flags & QIB_PRESENT))
+               writeq(value, &ubase[regno]);
+}
+
+static inline u32 qib_read_kreg32(const struct qib_devdata *dd,
+                                 const u16 regno)
+{
+       if (!dd->kregbase || !(dd->flags & QIB_PRESENT))
+               return -1;
+       return readl((u32 __iomem *)&dd->kregbase[regno]);
+}
+
+static inline u64 qib_read_kreg64(const struct qib_devdata *dd,
+                                 const u16 regno)
+{
+       if (!dd->kregbase || !(dd->flags & QIB_PRESENT))
+               return -1;
+
+       return readq(&dd->kregbase[regno]);
+}
+
+static inline void qib_write_kreg(const struct qib_devdata *dd,
+                                 const u16 regno, u64 value)
+{
+       if (dd->kregbase && (dd->flags & QIB_PRESENT))
+               writeq(value, &dd->kregbase[regno]);
+}
+
+/**
+ * qib_write_kreg_ctxt - write a device's per-ctxt 64-bit kernel register
+ * @dd: the qlogic_ib device
+ * @regno: the register number to write
+ * @ctxt: the context containing the register
+ * @value: the value to write
+ */
+static inline void qib_write_kreg_ctxt(const struct qib_devdata *dd,
+                                      const u16 regno, unsigned ctxt,
+                                      u64 value)
+{
+       qib_write_kreg(dd, regno + ctxt, value);
+}
+
+static inline void write_6120_creg(const struct qib_devdata *dd,
+                                  u16 regno, u64 value)
+{
+       if (dd->cspec->cregbase && (dd->flags & QIB_PRESENT))
+               writeq(value, &dd->cspec->cregbase[regno]);
+}
+
+static inline u64 read_6120_creg(const struct qib_devdata *dd, u16 regno)
+{
+       if (!dd->cspec->cregbase || !(dd->flags & QIB_PRESENT))
+               return 0;
+       return readq(&dd->cspec->cregbase[regno]);
+}
+
+static inline u32 read_6120_creg32(const struct qib_devdata *dd, u16 regno)
+{
+       if (!dd->cspec->cregbase || !(dd->flags & QIB_PRESENT))
+               return 0;
+       return readl(&dd->cspec->cregbase[regno]);
+}
+
+/* kr_control bits */
+#define QLOGIC_IB_C_RESET 1U
+
+/* kr_intstatus, kr_intclear, kr_intmask bits */
+#define QLOGIC_IB_I_RCVURG_MASK ((1U << 5) - 1)
+#define QLOGIC_IB_I_RCVURG_SHIFT 0
+#define QLOGIC_IB_I_RCVAVAIL_MASK ((1U << 5) - 1)
+#define QLOGIC_IB_I_RCVAVAIL_SHIFT 12
+
+#define QLOGIC_IB_C_FREEZEMODE 0x00000002
+#define QLOGIC_IB_C_LINKENABLE 0x00000004
+#define QLOGIC_IB_I_ERROR               0x0000000080000000ULL
+#define QLOGIC_IB_I_SPIOSENT            0x0000000040000000ULL
+#define QLOGIC_IB_I_SPIOBUFAVAIL        0x0000000020000000ULL
+#define QLOGIC_IB_I_GPIO                0x0000000010000000ULL
+#define QLOGIC_IB_I_BITSEXTANT \
+               ((QLOGIC_IB_I_RCVURG_MASK << QLOGIC_IB_I_RCVURG_SHIFT) | \
+               (QLOGIC_IB_I_RCVAVAIL_MASK << \
+                QLOGIC_IB_I_RCVAVAIL_SHIFT) | \
+               QLOGIC_IB_I_ERROR | QLOGIC_IB_I_SPIOSENT | \
+               QLOGIC_IB_I_SPIOBUFAVAIL | QLOGIC_IB_I_GPIO)
+
+/* kr_hwerrclear, kr_hwerrmask, kr_hwerrstatus, bits */
+#define QLOGIC_IB_HWE_PCIEMEMPARITYERR_MASK  0x000000000000003fULL
+#define QLOGIC_IB_HWE_PCIEMEMPARITYERR_SHIFT 0
+#define QLOGIC_IB_HWE_PCIEPOISONEDTLP      0x0000000010000000ULL
+#define QLOGIC_IB_HWE_PCIECPLTIMEOUT       0x0000000020000000ULL
+#define QLOGIC_IB_HWE_PCIEBUSPARITYXTLH    0x0000000040000000ULL
+#define QLOGIC_IB_HWE_PCIEBUSPARITYXADM    0x0000000080000000ULL
+#define QLOGIC_IB_HWE_PCIEBUSPARITYRADM    0x0000000100000000ULL
+#define QLOGIC_IB_HWE_COREPLL_FBSLIP       0x0080000000000000ULL
+#define QLOGIC_IB_HWE_COREPLL_RFSLIP       0x0100000000000000ULL
+#define QLOGIC_IB_HWE_PCIE1PLLFAILED       0x0400000000000000ULL
+#define QLOGIC_IB_HWE_PCIE0PLLFAILED       0x0800000000000000ULL
+#define QLOGIC_IB_HWE_SERDESPLLFAILED      0x1000000000000000ULL
+
+
+/* kr_extstatus bits */
+#define QLOGIC_IB_EXTS_FREQSEL 0x2
+#define QLOGIC_IB_EXTS_SERDESSEL 0x4
+#define QLOGIC_IB_EXTS_MEMBIST_ENDTEST     0x0000000000004000
+#define QLOGIC_IB_EXTS_MEMBIST_FOUND       0x0000000000008000
+
+/* kr_xgxsconfig bits */
+#define QLOGIC_IB_XGXS_RESET          0x5ULL
+
+#define _QIB_GPIO_SDA_NUM 1
+#define _QIB_GPIO_SCL_NUM 0
+
+/* Bits in GPIO for the added IB link interrupts */
+#define GPIO_RXUVL_BIT 3
+#define GPIO_OVRUN_BIT 4
+#define GPIO_LLI_BIT 5
+#define GPIO_ERRINTR_MASK 0x38
+
+
+#define QLOGIC_IB_RT_BUFSIZE_MASK 0xe0000000ULL
+#define QLOGIC_IB_RT_BUFSIZE_SHIFTVAL(tid) \
+       ((((tid) & QLOGIC_IB_RT_BUFSIZE_MASK) >> 29) + 11 - 1)
+#define QLOGIC_IB_RT_BUFSIZE(tid) (1 << QLOGIC_IB_RT_BUFSIZE_SHIFTVAL(tid))
+#define QLOGIC_IB_RT_IS_VALID(tid) \
+       (((tid) & QLOGIC_IB_RT_BUFSIZE_MASK) && \
+        ((((tid) & QLOGIC_IB_RT_BUFSIZE_MASK) != QLOGIC_IB_RT_BUFSIZE_MASK)))
+#define QLOGIC_IB_RT_ADDR_MASK 0x1FFFFFFFULL /* 29 bits valid */
+#define QLOGIC_IB_RT_ADDR_SHIFT 10
+
+#define QLOGIC_IB_R_INTRAVAIL_SHIFT 16
+#define QLOGIC_IB_R_TAILUPD_SHIFT 31
+#define IBA6120_R_PKEY_DIS_SHIFT 30
+
+#define PBC_6120_VL15_SEND_CTRL (1ULL << 31) /* pbc; VL15; link_buf only */
+
+#define IBCBUSFRSPCPARITYERR HWE_MASK(IBCBusFromSPCParityErr)
+#define IBCBUSTOSPCPARITYERR HWE_MASK(IBCBusToSPCParityErr)
+
+#define SYM_MASK_BIT(regname, fldname, bit) ((u64) \
+       ((1ULL << (SYM_LSB(regname, fldname) + (bit)))))
+
+#define TXEMEMPARITYERR_PIOBUF \
+       SYM_MASK_BIT(HwErrMask, TXEMemParityErrMask, 0)
+#define TXEMEMPARITYERR_PIOPBC \
+       SYM_MASK_BIT(HwErrMask, TXEMemParityErrMask, 1)
+#define TXEMEMPARITYERR_PIOLAUNCHFIFO \
+       SYM_MASK_BIT(HwErrMask, TXEMemParityErrMask, 2)
+
+#define RXEMEMPARITYERR_RCVBUF \
+       SYM_MASK_BIT(HwErrMask, RXEMemParityErrMask, 0)
+#define RXEMEMPARITYERR_LOOKUPQ \
+       SYM_MASK_BIT(HwErrMask, RXEMemParityErrMask, 1)
+#define RXEMEMPARITYERR_EXPTID \
+       SYM_MASK_BIT(HwErrMask, RXEMemParityErrMask, 2)
+#define RXEMEMPARITYERR_EAGERTID \
+       SYM_MASK_BIT(HwErrMask, RXEMemParityErrMask, 3)
+#define RXEMEMPARITYERR_FLAGBUF \
+       SYM_MASK_BIT(HwErrMask, RXEMemParityErrMask, 4)
+#define RXEMEMPARITYERR_DATAINFO \
+       SYM_MASK_BIT(HwErrMask, RXEMemParityErrMask, 5)
+#define RXEMEMPARITYERR_HDRINFO \
+       SYM_MASK_BIT(HwErrMask, RXEMemParityErrMask, 6)
+
+/* 6120 specific hardware errors... */
+static const struct qib_hwerror_msgs qib_6120_hwerror_msgs[] = {
+       /* generic hardware errors */
+       QLOGIC_IB_HWE_MSG(IBCBUSFRSPCPARITYERR, "QIB2IB Parity"),
+       QLOGIC_IB_HWE_MSG(IBCBUSTOSPCPARITYERR, "IB2QIB Parity"),
+
+       QLOGIC_IB_HWE_MSG(TXEMEMPARITYERR_PIOBUF,
+                         "TXE PIOBUF Memory Parity"),
+       QLOGIC_IB_HWE_MSG(TXEMEMPARITYERR_PIOPBC,
+                         "TXE PIOPBC Memory Parity"),
+       QLOGIC_IB_HWE_MSG(TXEMEMPARITYERR_PIOLAUNCHFIFO,
+                         "TXE PIOLAUNCHFIFO Memory Parity"),
+
+       QLOGIC_IB_HWE_MSG(RXEMEMPARITYERR_RCVBUF,
+                         "RXE RCVBUF Memory Parity"),
+       QLOGIC_IB_HWE_MSG(RXEMEMPARITYERR_LOOKUPQ,
+                         "RXE LOOKUPQ Memory Parity"),
+       QLOGIC_IB_HWE_MSG(RXEMEMPARITYERR_EAGERTID,
+                         "RXE EAGERTID Memory Parity"),
+       QLOGIC_IB_HWE_MSG(RXEMEMPARITYERR_EXPTID,
+                         "RXE EXPTID Memory Parity"),
+       QLOGIC_IB_HWE_MSG(RXEMEMPARITYERR_FLAGBUF,
+                         "RXE FLAGBUF Memory Parity"),
+       QLOGIC_IB_HWE_MSG(RXEMEMPARITYERR_DATAINFO,
+                         "RXE DATAINFO Memory Parity"),
+       QLOGIC_IB_HWE_MSG(RXEMEMPARITYERR_HDRINFO,
+                         "RXE HDRINFO Memory Parity"),
+
+       /* chip-specific hardware errors */
+       QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_PCIEPOISONEDTLP,
+                         "PCIe Poisoned TLP"),
+       QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_PCIECPLTIMEOUT,
+                         "PCIe completion timeout"),
+       /*
+        * In practice, it's unlikely wthat we'll see PCIe PLL, or bus
+        * parity or memory parity error failures, because most likely we
+        * won't be able to talk to the core of the chip.  Nonetheless, we
+        * might see them, if they are in parts of the PCIe core that aren't
+        * essential.
+        */
+       QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_PCIE1PLLFAILED,
+                         "PCIePLL1"),
+       QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_PCIE0PLLFAILED,
+                         "PCIePLL0"),
+       QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_PCIEBUSPARITYXTLH,
+                         "PCIe XTLH core parity"),
+       QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_PCIEBUSPARITYXADM,
+                         "PCIe ADM TX core parity"),
+       QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_PCIEBUSPARITYRADM,
+                         "PCIe ADM RX core parity"),
+       QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_SERDESPLLFAILED,
+                         "SerDes PLL"),
+};
+
+#define TXE_PIO_PARITY (TXEMEMPARITYERR_PIOBUF | TXEMEMPARITYERR_PIOPBC)
+#define _QIB_PLL_FAIL (QLOGIC_IB_HWE_COREPLL_FBSLIP |   \
+               QLOGIC_IB_HWE_COREPLL_RFSLIP)
+
+       /* variables for sanity checking interrupt and errors */
+#define IB_HWE_BITSEXTANT \
+       (HWE_MASK(RXEMemParityErr) |                                    \
+        HWE_MASK(TXEMemParityErr) |                                    \
+        (QLOGIC_IB_HWE_PCIEMEMPARITYERR_MASK <<                        \
+         QLOGIC_IB_HWE_PCIEMEMPARITYERR_SHIFT) |                       \
+        QLOGIC_IB_HWE_PCIE1PLLFAILED |                                 \
+        QLOGIC_IB_HWE_PCIE0PLLFAILED |                                 \
+        QLOGIC_IB_HWE_PCIEPOISONEDTLP |                                \
+        QLOGIC_IB_HWE_PCIECPLTIMEOUT |                                 \
+        QLOGIC_IB_HWE_PCIEBUSPARITYXTLH |                              \
+        QLOGIC_IB_HWE_PCIEBUSPARITYXADM |                              \
+        QLOGIC_IB_HWE_PCIEBUSPARITYRADM |                              \
+        HWE_MASK(PowerOnBISTFailed) |                                  \
+        QLOGIC_IB_HWE_COREPLL_FBSLIP |                                 \
+        QLOGIC_IB_HWE_COREPLL_RFSLIP |                                 \
+        QLOGIC_IB_HWE_SERDESPLLFAILED |                                \
+        HWE_MASK(IBCBusToSPCParityErr) |                               \
+        HWE_MASK(IBCBusFromSPCParityErr))
+
+#define IB_E_BITSEXTANT \
+       (ERR_MASK(RcvFormatErr) | ERR_MASK(RcvVCRCErr) |                \
+        ERR_MASK(RcvICRCErr) | ERR_MASK(RcvMinPktLenErr) |             \
+        ERR_MASK(RcvMaxPktLenErr) | ERR_MASK(RcvLongPktLenErr) |       \
+        ERR_MASK(RcvShortPktLenErr) | ERR_MASK(RcvUnexpectedCharErr) | \
+        ERR_MASK(RcvUnsupportedVLErr) | ERR_MASK(RcvEBPErr) |          \
+        ERR_MASK(RcvIBFlowErr) | ERR_MASK(RcvBadVersionErr) |          \
+        ERR_MASK(RcvEgrFullErr) | ERR_MASK(RcvHdrFullErr) |            \
+        ERR_MASK(RcvBadTidErr) | ERR_MASK(RcvHdrLenErr) |              \
+        ERR_MASK(RcvHdrErr) | ERR_MASK(RcvIBLostLinkErr) |             \
+        ERR_MASK(SendMinPktLenErr) | ERR_MASK(SendMaxPktLenErr) |      \
+        ERR_MASK(SendUnderRunErr) | ERR_MASK(SendPktLenErr) |          \
+        ERR_MASK(SendDroppedSmpPktErr) |                               \
+        ERR_MASK(SendDroppedDataPktErr) |                              \
+        ERR_MASK(SendPioArmLaunchErr) |                                \
+        ERR_MASK(SendUnexpectedPktNumErr) |                            \
+        ERR_MASK(SendUnsupportedVLErr) | ERR_MASK(IBStatusChanged) |   \
+        ERR_MASK(InvalidAddrErr) | ERR_MASK(ResetNegated) |            \
+        ERR_MASK(HardwareErr))
+
+#define QLOGIC_IB_E_PKTERRS ( \
+               ERR_MASK(SendPktLenErr) |                               \
+               ERR_MASK(SendDroppedDataPktErr) |                       \
+               ERR_MASK(RcvVCRCErr) |                                  \
+               ERR_MASK(RcvICRCErr) |                                  \
+               ERR_MASK(RcvShortPktLenErr) |                           \
+               ERR_MASK(RcvEBPErr))
+
+/* These are all rcv-related errors which we want to count for stats */
+#define E_SUM_PKTERRS                                          \
+       (ERR_MASK(RcvHdrLenErr) | ERR_MASK(RcvBadTidErr) |              \
+        ERR_MASK(RcvBadVersionErr) | ERR_MASK(RcvHdrErr) |             \
+        ERR_MASK(RcvLongPktLenErr) | ERR_MASK(RcvShortPktLenErr) |     \
+        ERR_MASK(RcvMaxPktLenErr) | ERR_MASK(RcvMinPktLenErr) |        \
+        ERR_MASK(RcvFormatErr) | ERR_MASK(RcvUnsupportedVLErr) |       \
+        ERR_MASK(RcvUnexpectedCharErr) | ERR_MASK(RcvEBPErr))
+
+/* These are all send-related errors which we want to count for stats */
+#define E_SUM_ERRS                                                     \
+       (ERR_MASK(SendPioArmLaunchErr) |                                \
+        ERR_MASK(SendUnexpectedPktNumErr) |                            \
+        ERR_MASK(SendDroppedDataPktErr) |                              \
+        ERR_MASK(SendDroppedSmpPktErr) |                               \
+        ERR_MASK(SendMaxPktLenErr) | ERR_MASK(SendUnsupportedVLErr) |  \
+        ERR_MASK(SendMinPktLenErr) | ERR_MASK(SendPktLenErr) |         \
+        ERR_MASK(InvalidAddrErr))
+
+/*
+ * this is similar to E_SUM_ERRS, but can't ignore armlaunch, don't ignore
+ * errors not related to freeze and cancelling buffers.  Can't ignore
+ * armlaunch because could get more while still cleaning up, and need
+ * to cancel those as they happen.
+ */
+#define E_SPKT_ERRS_IGNORE \
+       (ERR_MASK(SendDroppedDataPktErr) |                              \
+        ERR_MASK(SendDroppedSmpPktErr) |                               \
+        ERR_MASK(SendMaxPktLenErr) | ERR_MASK(SendMinPktLenErr) |      \
+        ERR_MASK(SendPktLenErr))
+
+/*
+ * these are errors that can occur when the link changes state while
+ * a packet is being sent or received.  This doesn't cover things
+ * like EBP or VCRC that can be the result of a sending having the
+ * link change state, so we receive a "known bad" packet.
+ */
+#define E_SUM_LINK_PKTERRS             \
+       (ERR_MASK(SendDroppedDataPktErr) |                              \
+        ERR_MASK(SendDroppedSmpPktErr) |                               \
+        ERR_MASK(SendMinPktLenErr) | ERR_MASK(SendPktLenErr) |         \
+        ERR_MASK(RcvShortPktLenErr) | ERR_MASK(RcvMinPktLenErr) |      \
+        ERR_MASK(RcvUnexpectedCharErr))
+
+static void qib_6120_put_tid_2(struct qib_devdata *, u64 __iomem *,
+                              u32, unsigned long);
+
+/*
+ * On platforms using this chip, and not having ordered WC stores, we
+ * can get TXE parity errors due to speculative reads to the PIO buffers,
+ * and this, due to a chip issue can result in (many) false parity error
+ * reports.  So it's a debug print on those, and an info print on systems
+ * where the speculative reads don't occur.
+ */
+static void qib_6120_txe_recover(struct qib_devdata *dd)
+{
+       if (!qib_unordered_wc())
+               qib_devinfo(dd->pcidev,
+                           "Recovering from TXE PIO parity error\n");
+}
+
+/* enable/disable chip from delivering interrupts */
+static void qib_6120_set_intr_state(struct qib_devdata *dd, u32 enable)
+{
+       if (enable) {
+               if (dd->flags & QIB_BADINTR)
+                       return;
+               qib_write_kreg(dd, kr_intmask, ~0ULL);
+               /* force re-interrupt of any pending interrupts. */
+               qib_write_kreg(dd, kr_intclear, 0ULL);
+       } else
+               qib_write_kreg(dd, kr_intmask, 0ULL);
+}
+
+/*
+ * Try to cleanup as much as possible for anything that might have gone
+ * wrong while in freeze mode, such as pio buffers being written by user
+ * processes (causing armlaunch), send errors due to going into freeze mode,
+ * etc., and try to avoid causing extra interrupts while doing so.
+ * Forcibly update the in-memory pioavail register copies after cleanup
+ * because the chip won't do it while in freeze mode (the register values
+ * themselves are kept correct).
+ * Make sure that we don't lose any important interrupts by using the chip
+ * feature that says that writing 0 to a bit in *clear that is set in
+ * *status will cause an interrupt to be generated again (if allowed by
+ * the *mask value).
+ * This is in chip-specific code because of all of the register accesses,
+ * even though the details are similar on most chips
+ */
+static void qib_6120_clear_freeze(struct qib_devdata *dd)
+{
+       /* disable error interrupts, to avoid confusion */
+       qib_write_kreg(dd, kr_errmask, 0ULL);
+
+       /* also disable interrupts; errormask is sometimes overwriten */
+       qib_6120_set_intr_state(dd, 0);
+
+       qib_cancel_sends(dd->pport);
+
+       /* clear the freeze, and be sure chip saw it */
+       qib_write_kreg(dd, kr_control, dd->control);
+       qib_read_kreg32(dd, kr_scratch);
+
+       /* force in-memory update now we are out of freeze */
+       qib_force_pio_avail_update(dd);
+
+       /*
+        * force new interrupt if any hwerr, error or interrupt bits are
+        * still set, and clear "safe" send packet errors related to freeze
+        * and cancelling sends.  Re-enable error interrupts before possible
+        * force of re-interrupt on pending interrupts.
+        */
+       qib_write_kreg(dd, kr_hwerrclear, 0ULL);
+       qib_write_kreg(dd, kr_errclear, E_SPKT_ERRS_IGNORE);
+       qib_write_kreg(dd, kr_errmask, dd->cspec->errormask);
+       qib_6120_set_intr_state(dd, 1);
+}
+
+/**
+ * qib_handle_6120_hwerrors - display hardware errors.
+ * @dd: the qlogic_ib device
+ * @msg: the output buffer
+ * @msgl: the size of the output buffer
+ *
+ * Use same msg buffer as regular errors to avoid excessive stack
+ * use.  Most hardware errors are catastrophic, but for right now,
+ * we'll print them and continue.  Reuse the same message buffer as
+ * handle_6120_errors() to avoid excessive stack usage.
+ */
+static void qib_handle_6120_hwerrors(struct qib_devdata *dd, char *msg,
+                                    size_t msgl)
+{
+       u64 hwerrs;
+       u32 bits, ctrl;
+       int isfatal = 0;
+       char *bitsmsg;
+       int log_idx;
+
+       hwerrs = qib_read_kreg64(dd, kr_hwerrstatus);
+       if (!hwerrs)
+               return;
+       if (hwerrs == ~0ULL) {
+               qib_dev_err(dd, "Read of hardware error status failed "
+                           "(all bits set); ignoring\n");
+               return;
+       }
+       qib_stats.sps_hwerrs++;
+
+       /* Always clear the error status register, except MEMBISTFAIL,
+        * regardless of whether we continue or stop using the chip.
+        * We want that set so we know it failed, even across driver reload.
+        * We'll still ignore it in the hwerrmask.  We do this partly for
+        * diagnostics, but also for support */
+       qib_write_kreg(dd, kr_hwerrclear,
+                      hwerrs & ~HWE_MASK(PowerOnBISTFailed));
+
+       hwerrs &= dd->cspec->hwerrmask;
+
+       /* We log some errors to EEPROM, check if we have any of those. */
+       for (log_idx = 0; log_idx < QIB_EEP_LOG_CNT; ++log_idx)
+               if (hwerrs & dd->eep_st_masks[log_idx].hwerrs_to_log)
+                       qib_inc_eeprom_err(dd, log_idx, 1);
+
+       /*
+        * Make sure we get this much out, unless told to be quiet,
+        * or it's occurred within the last 5 seconds.
+        */
+       if (hwerrs & ~(TXE_PIO_PARITY | RXEMEMPARITYERR_EAGERTID))
+               qib_devinfo(dd->pcidev, "Hardware error: hwerr=0x%llx "
+                        "(cleared)\n", (unsigned long long) hwerrs);
+
+       if (hwerrs & ~IB_HWE_BITSEXTANT)
+               qib_dev_err(dd, "hwerror interrupt with unknown errors "
+                           "%llx set\n", (unsigned long long)
+                           (hwerrs & ~IB_HWE_BITSEXTANT));
+
+       ctrl = qib_read_kreg32(dd, kr_control);
+       if ((ctrl & QLOGIC_IB_C_FREEZEMODE) && !dd->diag_client) {
+               /*
+                * Parity errors in send memory are recoverable,
+                * just cancel the send (if indicated in * sendbuffererror),
+                * count the occurrence, unfreeze (if no other handled
+                * hardware error bits are set), and continue. They can
+                * occur if a processor speculative read is done to the PIO
+                * buffer while we are sending a packet, for example.
+                */
+               if (hwerrs & TXE_PIO_PARITY) {
+                       qib_6120_txe_recover(dd);
+                       hwerrs &= ~TXE_PIO_PARITY;
+               }
+
+               if (!hwerrs) {
+                       static u32 freeze_cnt;
+
+                       freeze_cnt++;
+                       qib_6120_clear_freeze(dd);
+               } else
+                       isfatal = 1;
+       }
+
+       *msg = '\0';
+
+       if (hwerrs & HWE_MASK(PowerOnBISTFailed)) {
+               isfatal = 1;
+               strlcat(msg, "[Memory BIST test failed, InfiniPath hardware"
+                       " unusable]", msgl);
+               /* ignore from now on, so disable until driver reloaded */
+               dd->cspec->hwerrmask &= ~HWE_MASK(PowerOnBISTFailed);
+               qib_write_kreg(dd, kr_hwerrmask, dd->cspec->hwerrmask);
+       }
+
+       qib_format_hwerrors(hwerrs, qib_6120_hwerror_msgs,
+                           ARRAY_SIZE(qib_6120_hwerror_msgs), msg, msgl);
+
+       bitsmsg = dd->cspec->bitsmsgbuf;
+       if (hwerrs & (QLOGIC_IB_HWE_PCIEMEMPARITYERR_MASK <<
+                     QLOGIC_IB_HWE_PCIEMEMPARITYERR_SHIFT)) {
+               bits = (u32) ((hwerrs >>
+                              QLOGIC_IB_HWE_PCIEMEMPARITYERR_SHIFT) &
+                             QLOGIC_IB_HWE_PCIEMEMPARITYERR_MASK);
+               snprintf(bitsmsg, sizeof dd->cspec->bitsmsgbuf,
+                        "[PCIe Mem Parity Errs %x] ", bits);
+               strlcat(msg, bitsmsg, msgl);
+       }
+
+       if (hwerrs & _QIB_PLL_FAIL) {
+               isfatal = 1;
+               snprintf(bitsmsg, sizeof dd->cspec->bitsmsgbuf,
+                        "[PLL failed (%llx), InfiniPath hardware unusable]",
+                        (unsigned long long) hwerrs & _QIB_PLL_FAIL);
+               strlcat(msg, bitsmsg, msgl);
+               /* ignore from now on, so disable until driver reloaded */
+               dd->cspec->hwerrmask &= ~(hwerrs & _QIB_PLL_FAIL);
+               qib_write_kreg(dd, kr_hwerrmask, dd->cspec->hwerrmask);
+       }
+
+       if (hwerrs & QLOGIC_IB_HWE_SERDESPLLFAILED) {
+               /*
+                * If it occurs, it is left masked since the external
+                * interface is unused
+                */
+               dd->cspec->hwerrmask &= ~QLOGIC_IB_HWE_SERDESPLLFAILED;
+               qib_write_kreg(dd, kr_hwerrmask, dd->cspec->hwerrmask);
+       }
+
+       if (hwerrs)
+               /*
+                * if any set that we aren't ignoring; only
+                * make the complaint once, in case it's stuck
+                * or recurring, and we get here multiple
+                * times.
+                */
+               qib_dev_err(dd, "%s hardware error\n", msg);
+       else
+               *msg = 0; /* recovered from all of them */
+
+       if (isfatal && !dd->diag_client) {
+               qib_dev_err(dd, "Fatal Hardware Error, no longer"
+                           " usable, SN %.16s\n", dd->serial);
+               /*
+                * for /sys status file and user programs to print; if no
+                * trailing brace is copied, we'll know it was truncated.
+                */
+               if (dd->freezemsg)
+                       snprintf(dd->freezemsg, dd->freezelen,
+                                "{%s}", msg);
+               qib_disable_after_error(dd);
+       }
+}
+
+/*
+ * Decode the error status into strings, deciding whether to always
+ * print * it or not depending on "normal packet errors" vs everything
+ * else.   Return 1 if "real" errors, otherwise 0 if only packet
+ * errors, so caller can decide what to print with the string.
+ */
+static int qib_decode_6120_err(struct qib_devdata *dd, char *buf, size_t blen,
+                              u64 err)
+{
+       int iserr = 1;
+
+       *buf = '\0';
+       if (err & QLOGIC_IB_E_PKTERRS) {
+               if (!(err & ~QLOGIC_IB_E_PKTERRS))
+                       iserr = 0;
+               if ((err & ERR_MASK(RcvICRCErr)) &&
+                   !(err&(ERR_MASK(RcvVCRCErr)|ERR_MASK(RcvEBPErr))))
+                       strlcat(buf, "CRC ", blen);
+               if (!iserr)
+                       goto done;
+       }
+       if (err & ERR_MASK(RcvHdrLenErr))
+               strlcat(buf, "rhdrlen ", blen);
+       if (err & ERR_MASK(RcvBadTidErr))
+               strlcat(buf, "rbadtid ", blen);
+       if (err & ERR_MASK(RcvBadVersionErr))
+               strlcat(buf, "rbadversion ", blen);
+       if (err & ERR_MASK(RcvHdrErr))
+               strlcat(buf, "rhdr ", blen);
+       if (err & ERR_MASK(RcvLongPktLenErr))
+               strlcat(buf, "rlongpktlen ", blen);
+       if (err & ERR_MASK(RcvMaxPktLenErr))
+               strlcat(buf, "rmaxpktlen ", blen);
+       if (err & ERR_MASK(RcvMinPktLenErr))
+               strlcat(buf, "rminpktlen ", blen);
+       if (err & ERR_MASK(SendMinPktLenErr))
+               strlcat(buf, "sminpktlen ", blen);
+       if (err & ERR_MASK(RcvFormatErr))
+               strlcat(buf, "rformaterr ", blen);
+       if (err & ERR_MASK(RcvUnsupportedVLErr))
+               strlcat(buf, "runsupvl ", blen);
+       if (err & ERR_MASK(RcvUnexpectedCharErr))
+               strlcat(buf, "runexpchar ", blen);
+       if (err & ERR_MASK(RcvIBFlowErr))
+               strlcat(buf, "ribflow ", blen);
+       if (err & ERR_MASK(SendUnderRunErr))
+               strlcat(buf, "sunderrun ", blen);
+       if (err & ERR_MASK(SendPioArmLaunchErr))
+               strlcat(buf, "spioarmlaunch ", blen);
+       if (err & ERR_MASK(SendUnexpectedPktNumErr))
+               strlcat(buf, "sunexperrpktnum ", blen);
+       if (err & ERR_MASK(SendDroppedSmpPktErr))
+               strlcat(buf, "sdroppedsmppkt ", blen);
+       if (err & ERR_MASK(SendMaxPktLenErr))
+               strlcat(buf, "smaxpktlen ", blen);
+       if (err & ERR_MASK(SendUnsupportedVLErr))
+               strlcat(buf, "sunsupVL ", blen);
+       if (err & ERR_MASK(InvalidAddrErr))
+               strlcat(buf, "invalidaddr ", blen);
+       if (err & ERR_MASK(RcvEgrFullErr))
+               strlcat(buf, "rcvegrfull ", blen);
+       if (err & ERR_MASK(RcvHdrFullErr))
+               strlcat(buf, "rcvhdrfull ", blen);
+       if (err & ERR_MASK(IBStatusChanged))
+               strlcat(buf, "ibcstatuschg ", blen);
+       if (err & ERR_MASK(RcvIBLostLinkErr))
+               strlcat(buf, "riblostlink ", blen);
+       if (err & ERR_MASK(HardwareErr))
+               strlcat(buf, "hardware ", blen);
+       if (err & ERR_MASK(ResetNegated))
+               strlcat(buf, "reset ", blen);
+done:
+       return iserr;
+}
+
+/*
+ * Called when we might have an error that is specific to a particular
+ * PIO buffer, and may need to cancel that buffer, so it can be re-used.
+ */
+static void qib_disarm_6120_senderrbufs(struct qib_pportdata *ppd)
+{
+       unsigned long sbuf[2];
+       struct qib_devdata *dd = ppd->dd;
+
+       /*
+        * It's possible that sendbuffererror could have bits set; might
+        * have already done this as a result of hardware error handling.
+        */
+       sbuf[0] = qib_read_kreg64(dd, kr_sendbuffererror);
+       sbuf[1] = qib_read_kreg64(dd, kr_sendbuffererror + 1);
+
+       if (sbuf[0] || sbuf[1])
+               qib_disarm_piobufs_set(dd, sbuf,
+                                      dd->piobcnt2k + dd->piobcnt4k);
+}
+
+static int chk_6120_linkrecovery(struct qib_devdata *dd, u64 ibcs)
+{
+       int ret = 1;
+       u32 ibstate = qib_6120_iblink_state(ibcs);
+       u32 linkrecov = read_6120_creg32(dd, cr_iblinkerrrecov);
+
+       if (linkrecov != dd->cspec->lastlinkrecov) {
+               /* and no more until active again */
+               dd->cspec->lastlinkrecov = 0;
+               qib_set_linkstate(dd->pport, QIB_IB_LINKDOWN);
+               ret = 0;
+       }
+       if (ibstate == IB_PORT_ACTIVE)
+               dd->cspec->lastlinkrecov =
+                       read_6120_creg32(dd, cr_iblinkerrrecov);
+       return ret;
+}
+
+static void handle_6120_errors(struct qib_devdata *dd, u64 errs)
+{
+       char *msg;
+       u64 ignore_this_time = 0;
+       u64 iserr = 0;
+       int log_idx;
+       struct qib_pportdata *ppd = dd->pport;
+       u64 mask;
+
+       /* don't report errors that are masked */
+       errs &= dd->cspec->errormask;
+       msg = dd->cspec->emsgbuf;
+
+       /* do these first, they are most important */
+       if (errs & ERR_MASK(HardwareErr))
+               qib_handle_6120_hwerrors(dd, msg, sizeof dd->cspec->emsgbuf);
+       else
+               for (log_idx = 0; log_idx < QIB_EEP_LOG_CNT; ++log_idx)
+                       if (errs & dd->eep_st_masks[log_idx].errs_to_log)
+                               qib_inc_eeprom_err(dd, log_idx, 1);
+
+       if (errs & ~IB_E_BITSEXTANT)
+               qib_dev_err(dd, "error interrupt with unknown errors "
+                           "%llx set\n",
+                           (unsigned long long) (errs & ~IB_E_BITSEXTANT));
+
+       if (errs & E_SUM_ERRS) {
+               qib_disarm_6120_senderrbufs(ppd);
+               if ((errs & E_SUM_LINK_PKTERRS) &&
+                   !(ppd->lflags & QIBL_LINKACTIVE)) {
+                       /*
+                        * This can happen when trying to bring the link
+                        * up, but the IB link changes state at the "wrong"
+                        * time. The IB logic then complains that the packet
+                        * isn't valid.  We don't want to confuse people, so
+                        * we just don't print them, except at debug
+                        */
+                       ignore_this_time = errs & E_SUM_LINK_PKTERRS;
+               }
+       } else if ((errs & E_SUM_LINK_PKTERRS) &&
+                  !(ppd->lflags & QIBL_LINKACTIVE)) {
+               /*
+                * This can happen when SMA is trying to bring the link
+                * up, but the IB link changes state at the "wrong" time.
+                * The IB logic then complains that the packet isn't
+                * valid.  We don't want to confuse people, so we just
+                * don't print them, except at debug
+                */
+               ignore_this_time = errs & E_SUM_LINK_PKTERRS;
+       }
+
+       qib_write_kreg(dd, kr_errclear, errs);
+
+       errs &= ~ignore_this_time;
+       if (!errs)
+               goto done;
+
+       /*
+        * The ones we mask off are handled specially below
+        * or above.
+        */
+       mask = ERR_MASK(IBStatusChanged) | ERR_MASK(RcvEgrFullErr) |
+               ERR_MASK(RcvHdrFullErr) | ERR_MASK(HardwareErr);
+       qib_decode_6120_err(dd, msg, sizeof dd->cspec->emsgbuf, errs & ~mask);
+
+       if (errs & E_SUM_PKTERRS)
+               qib_stats.sps_rcverrs++;
+       if (errs & E_SUM_ERRS)
+               qib_stats.sps_txerrs++;
+
+       iserr = errs & ~(E_SUM_PKTERRS | QLOGIC_IB_E_PKTERRS);
+
+       if (errs & ERR_MASK(IBStatusChanged)) {
+               u64 ibcs = qib_read_kreg64(dd, kr_ibcstatus);
+               u32 ibstate = qib_6120_iblink_state(ibcs);
+               int handle = 1;
+
+               if (ibstate != IB_PORT_INIT && dd->cspec->lastlinkrecov)
+                       handle = chk_6120_linkrecovery(dd, ibcs);
+               /*
+                * Since going into a recovery state causes the link state
+                * to go down and since recovery is transitory, it is better
+                * if we "miss" ever seeing the link training state go into
+                * recovery (i.e., ignore this transition for link state
+                * special handling purposes) without updating lastibcstat.
+                */
+               if (handle && qib_6120_phys_portstate(ibcs) ==
+                                           IB_PHYSPORTSTATE_LINK_ERR_RECOVER)
+                       handle = 0;
+               if (handle)
+                       qib_handle_e_ibstatuschanged(ppd, ibcs);
+       }
+
+       if (errs & ERR_MASK(ResetNegated)) {
+               qib_dev_err(dd, "Got reset, requires re-init "
+                             "(unload and reload driver)\n");
+               dd->flags &= ~QIB_INITTED;  /* needs re-init */
+               /* mark as having had error */
+               *dd->devstatusp |= QIB_STATUS_HWERROR;
+               *dd->pport->statusp &= ~QIB_STATUS_IB_CONF;
+       }
+
+       if (*msg && iserr)
+               qib_dev_porterr(dd, ppd->port, "%s error\n", msg);
+
+       if (ppd->state_wanted & ppd->lflags)
+               wake_up_interruptible(&ppd->state_wait);
+
+       /*
+        * If there were hdrq or egrfull errors, wake up any processes
+        * waiting in poll.  We used to try to check which contexts had
+        * the overflow, but given the cost of that and the chip reads
+        * to support it, it's better to just wake everybody up if we
+        * get an overflow; waiters can poll again if it's not them.
+        */
+       if (errs & (ERR_MASK(RcvEgrFullErr) | ERR_MASK(RcvHdrFullErr))) {
+               qib_handle_urcv(dd, ~0U);
+               if (errs & ERR_MASK(RcvEgrFullErr))
+                       qib_stats.sps_buffull++;
+               else
+                       qib_stats.sps_hdrfull++;
+       }
+done:
+       return;
+}
+
+/**
+ * qib_6120_init_hwerrors - enable hardware errors
+ * @dd: the qlogic_ib device
+ *
+ * now that we have finished initializing everything that might reasonably
+ * cause a hardware error, and cleared those errors bits as they occur,
+ * we can enable hardware errors in the mask (potentially enabling
+ * freeze mode), and enable hardware errors as errors (along with
+ * everything else) in errormask
+ */
+static void qib_6120_init_hwerrors(struct qib_devdata *dd)
+{
+       u64 val;
+       u64 extsval;
+
+       extsval = qib_read_kreg64(dd, kr_extstatus);
+
+       if (!(extsval & QLOGIC_IB_EXTS_MEMBIST_ENDTEST))
+               qib_dev_err(dd, "MemBIST did not complete!\n");
+
+       /* init so all hwerrors interrupt, and enter freeze, ajdust below */
+       val = ~0ULL;
+       if (dd->minrev < 2) {
+               /*
+                * Avoid problem with internal interface bus parity
+                * checking. Fixed in Rev2.
+                */
+               val &= ~QLOGIC_IB_HWE_PCIEBUSPARITYRADM;
+       }
+       /* avoid some intel cpu's speculative read freeze mode issue */
+       val &= ~TXEMEMPARITYERR_PIOBUF;
+
+       dd->cspec->hwerrmask = val;
+
+       qib_write_kreg(dd, kr_hwerrclear, ~HWE_MASK(PowerOnBISTFailed));
+       qib_write_kreg(dd, kr_hwerrmask, dd->cspec->hwerrmask);
+
+       /* clear all */
+       qib_write_kreg(dd, kr_errclear, ~0ULL);
+       /* enable errors that are masked, at least this first time. */
+       qib_write_kreg(dd, kr_errmask, ~0ULL);
+       dd->cspec->errormask = qib_read_kreg64(dd, kr_errmask);
+       /* clear any interrupts up to this point (ints still not enabled) */
+       qib_write_kreg(dd, kr_intclear, ~0ULL);
+
+       qib_write_kreg(dd, kr_rcvbthqp,
+                      dd->qpn_mask << (QIB_6120_RcvBTHQP_BTHQP_Mask_LSB - 1) |
+                      QIB_KD_QP);
+}
+
+/*
+ * Disable and enable the armlaunch error.  Used for PIO bandwidth testing
+ * on chips that are count-based, rather than trigger-based.  There is no
+ * reference counting, but that's also fine, given the intended use.
+ * Only chip-specific because it's all register accesses
+ */
+static void qib_set_6120_armlaunch(struct qib_devdata *dd, u32 enable)
+{
+       if (enable) {
+               qib_write_kreg(dd, kr_errclear,
+                              ERR_MASK(SendPioArmLaunchErr));
+               dd->cspec->errormask |= ERR_MASK(SendPioArmLaunchErr);
+       } else
+               dd->cspec->errormask &= ~ERR_MASK(SendPioArmLaunchErr);
+       qib_write_kreg(dd, kr_errmask, dd->cspec->errormask);
+}
+
+/*
+ * Formerly took parameter <which> in pre-shifted,
+ * pre-merged form with LinkCmd and LinkInitCmd
+ * together, and assuming the zero was NOP.
+ */
+static void qib_set_ib_6120_lstate(struct qib_pportdata *ppd, u16 linkcmd,
+                                  u16 linitcmd)
+{
+       u64 mod_wd;
+       struct qib_devdata *dd = ppd->dd;
+       unsigned long flags;
+
+       if (linitcmd == QLOGIC_IB_IBCC_LINKINITCMD_DISABLE) {
+               /*
+                * If we are told to disable, note that so link-recovery
+                * code does not attempt to bring us back up.
+                */
+               spin_lock_irqsave(&ppd->lflags_lock, flags);
+               ppd->lflags |= QIBL_IB_LINK_DISABLED;
+               spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+       } else if (linitcmd || linkcmd == QLOGIC_IB_IBCC_LINKCMD_DOWN) {
+               /*
+                * Any other linkinitcmd will lead to LINKDOWN and then
+                * to INIT (if all is well), so clear flag to let
+                * link-recovery code attempt to bring us back up.
+                */
+               spin_lock_irqsave(&ppd->lflags_lock, flags);
+               ppd->lflags &= ~QIBL_IB_LINK_DISABLED;
+               spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+       }
+
+       mod_wd = (linkcmd << QLOGIC_IB_IBCC_LINKCMD_SHIFT) |
+               (linitcmd << QLOGIC_IB_IBCC_LINKINITCMD_SHIFT);
+
+       qib_write_kreg(dd, kr_ibcctrl, dd->cspec->ibcctrl | mod_wd);
+       /* write to chip to prevent back-to-back writes of control reg */
+       qib_write_kreg(dd, kr_scratch, 0);
+}
+
+/**
+ * qib_6120_bringup_serdes - bring up the serdes
+ * @dd: the qlogic_ib device
+ */
+static int qib_6120_bringup_serdes(struct qib_pportdata *ppd)
+{
+       struct qib_devdata *dd = ppd->dd;
+       u64 val, config1, prev_val, hwstat, ibc;
+
+       /* Put IBC in reset, sends disabled */
+       dd->control &= ~QLOGIC_IB_C_LINKENABLE;
+       qib_write_kreg(dd, kr_control, 0ULL);
+
+       dd->cspec->ibdeltainprog = 1;
+       dd->cspec->ibsymsnap = read_6120_creg32(dd, cr_ibsymbolerr);
+       dd->cspec->iblnkerrsnap = read_6120_creg32(dd, cr_iblinkerrrecov);
+
+       /* flowcontrolwatermark is in units of KBytes */
+       ibc = 0x5ULL << SYM_LSB(IBCCtrl, FlowCtrlWaterMark);
+       /*
+        * How often flowctrl sent.  More or less in usecs; balance against
+        * watermark value, so that in theory senders always get a flow
+        * control update in time to not let the IB link go idle.
+        */
+       ibc |= 0x3ULL << SYM_LSB(IBCCtrl, FlowCtrlPeriod);
+       /* max error tolerance */
+       dd->cspec->lli_thresh = 0xf;
+       ibc |= (u64) dd->cspec->lli_thresh << SYM_LSB(IBCCtrl, PhyerrThreshold);
+       /* use "real" buffer space for */
+       ibc |= 4ULL << SYM_LSB(IBCCtrl, CreditScale);
+       /* IB credit flow control. */
+       ibc |= 0xfULL << SYM_LSB(IBCCtrl, OverrunThreshold);
+       /*
+        * set initial max size pkt IBC will send, including ICRC; it's the
+        * PIO buffer size in dwords, less 1; also see qib_set_mtu()
+        */
+       ibc |= ((u64)(ppd->ibmaxlen >> 2) + 1) << SYM_LSB(IBCCtrl, MaxPktLen);
+       dd->cspec->ibcctrl = ibc; /* without linkcmd or linkinitcmd! */
+
+       /* initially come up waiting for TS1, without sending anything. */
+       val = dd->cspec->ibcctrl | (QLOGIC_IB_IBCC_LINKINITCMD_DISABLE <<
+               QLOGIC_IB_IBCC_LINKINITCMD_SHIFT);
+       qib_write_kreg(dd, kr_ibcctrl, val);
+
+       val = qib_read_kreg64(dd, kr_serdes_cfg0);
+       config1 = qib_read_kreg64(dd, kr_serdes_cfg1);
+
+       /*
+        * Force reset on, also set rxdetect enable.  Must do before reading
+        * serdesstatus at least for simulation, or some of the bits in
+        * serdes status will come back as undefined and cause simulation
+        * failures
+        */
+       val |= SYM_MASK(SerdesCfg0, ResetPLL) |
+               SYM_MASK(SerdesCfg0, RxDetEnX) |
+               (SYM_MASK(SerdesCfg0, L1PwrDnA) |
+                SYM_MASK(SerdesCfg0, L1PwrDnB) |
+                SYM_MASK(SerdesCfg0, L1PwrDnC) |
+                SYM_MASK(SerdesCfg0, L1PwrDnD));
+       qib_write_kreg(dd, kr_serdes_cfg0, val);
+       /* be sure chip saw it */
+       qib_read_kreg64(dd, kr_scratch);
+       udelay(5);              /* need pll reset set at least for a bit */
+       /*
+        * after PLL is reset, set the per-lane Resets and TxIdle and
+        * clear the PLL reset and rxdetect (to get falling edge).
+        * Leave L1PWR bits set (permanently)
+        */
+       val &= ~(SYM_MASK(SerdesCfg0, RxDetEnX) |
+                SYM_MASK(SerdesCfg0, ResetPLL) |
+                (SYM_MASK(SerdesCfg0, L1PwrDnA) |
+                 SYM_MASK(SerdesCfg0, L1PwrDnB) |
+                 SYM_MASK(SerdesCfg0, L1PwrDnC) |
+                 SYM_MASK(SerdesCfg0, L1PwrDnD)));
+       val |= (SYM_MASK(SerdesCfg0, ResetA) |
+               SYM_MASK(SerdesCfg0, ResetB) |
+               SYM_MASK(SerdesCfg0, ResetC) |
+               SYM_MASK(SerdesCfg0, ResetD)) |
+               SYM_MASK(SerdesCfg0, TxIdeEnX);
+       qib_write_kreg(dd, kr_serdes_cfg0, val);
+       /* be sure chip saw it */
+       (void) qib_read_kreg64(dd, kr_scratch);
+       /* need PLL reset clear for at least 11 usec before lane
+        * resets cleared; give it a few more to be sure */
+       udelay(15);
+       val &= ~((SYM_MASK(SerdesCfg0, ResetA) |
+                 SYM_MASK(SerdesCfg0, ResetB) |
+                 SYM_MASK(SerdesCfg0, ResetC) |
+                 SYM_MASK(SerdesCfg0, ResetD)) |
+                SYM_MASK(SerdesCfg0, TxIdeEnX));
+
+       qib_write_kreg(dd, kr_serdes_cfg0, val);
+       /* be sure chip saw it */
+       (void) qib_read_kreg64(dd, kr_scratch);
+
+       val = qib_read_kreg64(dd, kr_xgxs_cfg);
+       prev_val = val;
+       if (val & QLOGIC_IB_XGXS_RESET)
+               val &= ~QLOGIC_IB_XGXS_RESET;
+       if (SYM_FIELD(val, XGXSCfg, polarity_inv) != ppd->rx_pol_inv) {
+               /* need to compensate for Tx inversion in partner */
+               val &= ~SYM_MASK(XGXSCfg, polarity_inv);
+               val |= (u64)ppd->rx_pol_inv << SYM_LSB(XGXSCfg, polarity_inv);
+       }
+       if (val != prev_val)
+               qib_write_kreg(dd, kr_xgxs_cfg, val);
+
+       val = qib_read_kreg64(dd, kr_serdes_cfg0);
+
+       /* clear current and de-emphasis bits */
+       config1 &= ~0x0ffffffff00ULL;
+       /* set current to 20ma */
+       config1 |= 0x00000000000ULL;
+       /* set de-emphasis to -5.68dB */
+       config1 |= 0x0cccc000000ULL;
+       qib_write_kreg(dd, kr_serdes_cfg1, config1);
+
+       /* base and port guid same for single port */
+       ppd->guid = dd->base_guid;
+
+       /*
+        * the process of setting and un-resetting the serdes normally
+        * causes a serdes PLL error, so check for that and clear it
+        * here.  Also clearr hwerr bit in errstatus, but not others.
+        */
+       hwstat = qib_read_kreg64(dd, kr_hwerrstatus);
+       if (hwstat) {
+               /* should just have PLL, clear all set, in an case */
+               if (hwstat & ~QLOGIC_IB_HWE_SERDESPLLFAILED)
+                       qib_write_kreg(dd, kr_hwerrclear, hwstat);
+               qib_write_kreg(dd, kr_errclear, ERR_MASK(HardwareErr));
+       }
+
+       dd->control |= QLOGIC_IB_C_LINKENABLE;
+       dd->control &= ~QLOGIC_IB_C_FREEZEMODE;
+       qib_write_kreg(dd, kr_control, dd->control);
+
+       return 0;
+}
+
+/**
+ * qib_6120_quiet_serdes - set serdes to txidle
+ * @ppd: physical port of the qlogic_ib device
+ * Called when driver is being unloaded
+ */
+static void qib_6120_quiet_serdes(struct qib_pportdata *ppd)
+{
+       struct qib_devdata *dd = ppd->dd;
+       u64 val;
+
+       qib_set_ib_6120_lstate(ppd, 0, QLOGIC_IB_IBCC_LINKINITCMD_DISABLE);
+
+       /* disable IBC */
+       dd->control &= ~QLOGIC_IB_C_LINKENABLE;
+       qib_write_kreg(dd, kr_control,
+                      dd->control | QLOGIC_IB_C_FREEZEMODE);
+
+       if (dd->cspec->ibsymdelta || dd->cspec->iblnkerrdelta ||
+           dd->cspec->ibdeltainprog) {
+               u64 diagc;
+
+               /* enable counter writes */
+               diagc = qib_read_kreg64(dd, kr_hwdiagctrl);
+               qib_write_kreg(dd, kr_hwdiagctrl,
+                              diagc | SYM_MASK(HwDiagCtrl, CounterWrEnable));
+
+               if (dd->cspec->ibsymdelta || dd->cspec->ibdeltainprog) {
+                       val = read_6120_creg32(dd, cr_ibsymbolerr);
+                       if (dd->cspec->ibdeltainprog)
+                               val -= val - dd->cspec->ibsymsnap;
+                       val -= dd->cspec->ibsymdelta;
+                       write_6120_creg(dd, cr_ibsymbolerr, val);
+               }
+               if (dd->cspec->iblnkerrdelta || dd->cspec->ibdeltainprog) {
+                       val = read_6120_creg32(dd, cr_iblinkerrrecov);
+                       if (dd->cspec->ibdeltainprog)
+                               val -= val - dd->cspec->iblnkerrsnap;
+                       val -= dd->cspec->iblnkerrdelta;
+                       write_6120_creg(dd, cr_iblinkerrrecov, val);
+               }
+
+               /* and disable counter writes */
+               qib_write_kreg(dd, kr_hwdiagctrl, diagc);
+       }
+
+       val = qib_read_kreg64(dd, kr_serdes_cfg0);
+       val |= SYM_MASK(SerdesCfg0, TxIdeEnX);
+       qib_write_kreg(dd, kr_serdes_cfg0, val);
+}
+
+/**
+ * qib_6120_setup_setextled - set the state of the two external LEDs
+ * @dd: the qlogic_ib device
+ * @on: whether the link is up or not
+ *
+ * The exact combo of LEDs if on is true is determined by looking
+ * at the ibcstatus.
+
+ * These LEDs indicate the physical and logical state of IB link.
+ * For this chip (at least with recommended board pinouts), LED1
+ * is Yellow (logical state) and LED2 is Green (physical state),
+ *
+ * Note:  We try to match the Mellanox HCA LED behavior as best
+ * we can.  Green indicates physical link state is OK (something is
+ * plugged in, and we can train).
+ * Amber indicates the link is logically up (ACTIVE).
+ * Mellanox further blinks the amber LED to indicate data packet
+ * activity, but we have no hardware support for that, so it would
+ * require waking up every 10-20 msecs and checking the counters
+ * on the chip, and then turning the LED off if appropriate.  That's
+ * visible overhead, so not something we will do.
+ *
+ */
+static void qib_6120_setup_setextled(struct qib_pportdata *ppd, u32 on)
+{
+       u64 extctl, val, lst, ltst;
+       unsigned long flags;
+       struct qib_devdata *dd = ppd->dd;
+
+       /*
+        * The diags use the LED to indicate diag info, so we leave
+        * the external LED alone when the diags are running.
+        */
+       if (dd->diag_client)
+               return;
+
+       /* Allow override of LED display for, e.g. Locating system in rack */
+       if (ppd->led_override) {
+               ltst = (ppd->led_override & QIB_LED_PHYS) ?
+                       IB_PHYSPORTSTATE_LINKUP : IB_PHYSPORTSTATE_DISABLED,
+               lst = (ppd->led_override & QIB_LED_LOG) ?
+                       IB_PORT_ACTIVE : IB_PORT_DOWN;
+       } else if (on) {
+               val = qib_read_kreg64(dd, kr_ibcstatus);
+               ltst = qib_6120_phys_portstate(val);
+               lst = qib_6120_iblink_state(val);
+       } else {
+               ltst = 0;
+               lst = 0;
+       }
+
+       spin_lock_irqsave(&dd->cspec->gpio_lock, flags);
+       extctl = dd->cspec->extctrl & ~(SYM_MASK(EXTCtrl, LEDPriPortGreenOn) |
+                                SYM_MASK(EXTCtrl, LEDPriPortYellowOn));
+
+       if (ltst == IB_PHYSPORTSTATE_LINKUP)
+               extctl |= SYM_MASK(EXTCtrl, LEDPriPortYellowOn);
+       if (lst == IB_PORT_ACTIVE)
+               extctl |= SYM_MASK(EXTCtrl, LEDPriPortGreenOn);
+       dd->cspec->extctrl = extctl;
+       qib_write_kreg(dd, kr_extctrl, extctl);
+       spin_unlock_irqrestore(&dd->cspec->gpio_lock, flags);
+}
+
+static void qib_6120_free_irq(struct qib_devdata *dd)
+{
+       if (dd->cspec->irq) {
+               free_irq(dd->cspec->irq, dd);
+               dd->cspec->irq = 0;
+       }
+       qib_nomsi(dd);
+}
+
+/**
+ * qib_6120_setup_cleanup - clean up any per-chip chip-specific stuff
+ * @dd: the qlogic_ib device
+ *
+ * This is called during driver unload.
+*/
+static void qib_6120_setup_cleanup(struct qib_devdata *dd)
+{
+       qib_6120_free_irq(dd);
+       kfree(dd->cspec->cntrs);
+       kfree(dd->cspec->portcntrs);
+       if (dd->cspec->dummy_hdrq) {
+               dma_free_coherent(&dd->pcidev->dev,
+                                 ALIGN(dd->rcvhdrcnt *
+                                       dd->rcvhdrentsize *
+                                       sizeof(u32), PAGE_SIZE),
+                                 dd->cspec->dummy_hdrq,
+                                 dd->cspec->dummy_hdrq_phys);
+               dd->cspec->dummy_hdrq = NULL;
+       }
+}
+
+static void qib_wantpiobuf_6120_intr(struct qib_devdata *dd, u32 needint)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&dd->sendctrl_lock, flags);
+       if (needint)
+               dd->sendctrl |= SYM_MASK(SendCtrl, PIOIntBufAvail);
+       else
+               dd->sendctrl &= ~SYM_MASK(SendCtrl, PIOIntBufAvail);
+       qib_write_kreg(dd, kr_sendctrl, dd->sendctrl);
+       qib_write_kreg(dd, kr_scratch, 0ULL);
+       spin_unlock_irqrestore(&dd->sendctrl_lock, flags);
+}
+
+/*
+ * handle errors and unusual events first, separate function
+ * to improve cache hits for fast path interrupt handling
+ */
+static noinline void unlikely_6120_intr(struct qib_devdata *dd, u64 istat)
+{
+       if (unlikely(istat & ~QLOGIC_IB_I_BITSEXTANT))
+               qib_dev_err(dd, "interrupt with unknown interrupts %Lx set\n",
+                           istat & ~QLOGIC_IB_I_BITSEXTANT);
+
+       if (istat & QLOGIC_IB_I_ERROR) {
+               u64 estat = 0;
+
+               qib_stats.sps_errints++;
+               estat = qib_read_kreg64(dd, kr_errstatus);
+               if (!estat)
+                       qib_devinfo(dd->pcidev, "error interrupt (%Lx), "
+                                "but no error bits set!\n", istat);
+               handle_6120_errors(dd, estat);
+       }
+
+       if (istat & QLOGIC_IB_I_GPIO) {
+               u32 gpiostatus;
+               u32 to_clear = 0;
+
+               /*
+                * GPIO_3..5 on IBA6120 Rev2 chips indicate
+                * errors that we need to count.
+                */
+               gpiostatus = qib_read_kreg32(dd, kr_gpio_status);
+               /* First the error-counter case. */
+               if (gpiostatus & GPIO_ERRINTR_MASK) {
+                       /* want to clear the bits we see asserted. */
+                       to_clear |= (gpiostatus & GPIO_ERRINTR_MASK);
+
+                       /*
+                        * Count appropriately, clear bits out of our copy,
+                        * as they have been "handled".
+                        */
+                       if (gpiostatus & (1 << GPIO_RXUVL_BIT))
+                               dd->cspec->rxfc_unsupvl_errs++;
+                       if (gpiostatus & (1 << GPIO_OVRUN_BIT))
+                               dd->cspec->overrun_thresh_errs++;
+                       if (gpiostatus & (1 << GPIO_LLI_BIT))
+                               dd->cspec->lli_errs++;
+                       gpiostatus &= ~GPIO_ERRINTR_MASK;
+               }
+               if (gpiostatus) {
+                       /*
+                        * Some unexpected bits remain. If they could have
+                        * caused the interrupt, complain and clear.
+                        * To avoid repetition of this condition, also clear
+                        * the mask. It is almost certainly due to error.
+                        */
+                       const u32 mask = qib_read_kreg32(dd, kr_gpio_mask);
+
+                       /*
+                        * Also check that the chip reflects our shadow,
+                        * and report issues, If they caused the interrupt.
+                        * we will suppress by refreshing from the shadow.
+                        */
+                       if (mask & gpiostatus) {
+                               to_clear |= (gpiostatus & mask);
+                               dd->cspec->gpio_mask &= ~(gpiostatus & mask);
+                               qib_write_kreg(dd, kr_gpio_mask,
+                                              dd->cspec->gpio_mask);
+                       }
+               }
+               if (to_clear)
+                       qib_write_kreg(dd, kr_gpio_clear, (u64) to_clear);
+       }
+}
+
+static irqreturn_t qib_6120intr(int irq, void *data)
+{
+       struct qib_devdata *dd = data;
+       irqreturn_t ret;
+       u32 istat, ctxtrbits, rmask, crcs = 0;
+       unsigned i;
+
+       if ((dd->flags & (QIB_PRESENT | QIB_BADINTR)) != QIB_PRESENT) {
+               /*
+                * This return value is not great, but we do not want the
+                * interrupt core code to remove our interrupt handler
+                * because we don't appear to be handling an interrupt
+                * during a chip reset.
+                */
+               ret = IRQ_HANDLED;
+               goto bail;
+       }
+
+       istat = qib_read_kreg32(dd, kr_intstatus);
+
+       if (unlikely(!istat)) {
+               ret = IRQ_NONE; /* not our interrupt, or already handled */
+               goto bail;
+       }
+       if (unlikely(istat == -1)) {
+               qib_bad_intrstatus(dd);
+               /* don't know if it was our interrupt or not */
+               ret = IRQ_NONE;
+               goto bail;
+       }
+
+       qib_stats.sps_ints++;
+       if (dd->int_counter != (u32) -1)
+               dd->int_counter++;
+
+       if (unlikely(istat & (~QLOGIC_IB_I_BITSEXTANT |
+                             QLOGIC_IB_I_GPIO | QLOGIC_IB_I_ERROR)))
+               unlikely_6120_intr(dd, istat);
+
+       /*
+        * Clear the interrupt bits we found set, relatively early, so we
+        * "know" know the chip will have seen this by the time we process
+        * the queue, and will re-interrupt if necessary.  The processor
+        * itself won't take the interrupt again until we return.
+        */
+       qib_write_kreg(dd, kr_intclear, istat);
+
+       /*
+        * Handle kernel receive queues before checking for pio buffers
+        * available since receives can overflow; piobuf waiters can afford
+        * a few extra cycles, since they were waiting anyway.
+        */
+       ctxtrbits = istat &
+               ((QLOGIC_IB_I_RCVAVAIL_MASK << QLOGIC_IB_I_RCVAVAIL_SHIFT) |
+                (QLOGIC_IB_I_RCVURG_MASK << QLOGIC_IB_I_RCVURG_SHIFT));
+       if (ctxtrbits) {
+               rmask = (1U << QLOGIC_IB_I_RCVAVAIL_SHIFT) |
+                       (1U << QLOGIC_IB_I_RCVURG_SHIFT);
+               for (i = 0; i < dd->first_user_ctxt; i++) {
+                       if (ctxtrbits & rmask) {
+                               ctxtrbits &= ~rmask;
+                               crcs += qib_kreceive(dd->rcd[i],
+                                                    &dd->cspec->lli_counter,
+                                                    NULL);
+                       }
+                       rmask <<= 1;
+               }
+               if (crcs) {
+                       u32 cntr = dd->cspec->lli_counter;
+                       cntr += crcs;
+                       if (cntr) {
+                               if (cntr > dd->cspec->lli_thresh) {
+                                       dd->cspec->lli_counter = 0;
+                                       dd->cspec->lli_errs++;
+                               } else
+                                       dd->cspec->lli_counter += cntr;
+                       }
+               }
+
+
+               if (ctxtrbits) {
+                       ctxtrbits =
+                               (ctxtrbits >> QLOGIC_IB_I_RCVAVAIL_SHIFT) |
+                               (ctxtrbits >> QLOGIC_IB_I_RCVURG_SHIFT);
+                       qib_handle_urcv(dd, ctxtrbits);
+               }
+       }
+
+       if ((istat & QLOGIC_IB_I_SPIOBUFAVAIL) && (dd->flags & QIB_INITTED))
+               qib_ib_piobufavail(dd);
+
+       ret = IRQ_HANDLED;
+bail:
+       return ret;
+}
+
+/*
+ * Set up our chip-specific interrupt handler
+ * The interrupt type has already been setup, so
+ * we just need to do the registration and error checking.
+ */
+static void qib_setup_6120_interrupt(struct qib_devdata *dd)
+{
+       /*
+        * If the chip supports added error indication via GPIO pins,
+        * enable interrupts on those bits so the interrupt routine
+        * can count the events. Also set flag so interrupt routine
+        * can know they are expected.
+        */
+       if (SYM_FIELD(dd->revision, Revision_R,
+                     ChipRevMinor) > 1) {
+               /* Rev2+ reports extra errors via internal GPIO pins */
+               dd->cspec->gpio_mask |= GPIO_ERRINTR_MASK;
+               qib_write_kreg(dd, kr_gpio_mask, dd->cspec->gpio_mask);
+       }
+
+       if (!dd->cspec->irq)
+               qib_dev_err(dd, "irq is 0, BIOS error?  Interrupts won't "
+                           "work\n");
+       else {
+               int ret;
+               ret = request_irq(dd->cspec->irq, qib_6120intr, 0,
+                                 QIB_DRV_NAME, dd);
+               if (ret)
+                       qib_dev_err(dd, "Couldn't setup interrupt "
+                                   "(irq=%d): %d\n", dd->cspec->irq,
+                                   ret);
+       }
+}
+
+/**
+ * pe_boardname - fill in the board name
+ * @dd: the qlogic_ib device
+ *
+ * info is based on the board revision register
+ */
+static void pe_boardname(struct qib_devdata *dd)
+{
+       char *n;
+       u32 boardid, namelen;
+
+       boardid = SYM_FIELD(dd->revision, Revision,
+                           BoardID);
+
+       switch (boardid) {
+       case 2:
+               n = "InfiniPath_QLE7140";
+               break;
+       default:
+               qib_dev_err(dd, "Unknown 6120 board with ID %u\n", boardid);
+               n = "Unknown_InfiniPath_6120";
+               break;
+       }
+       namelen = strlen(n) + 1;
+       dd->boardname = kmalloc(namelen, GFP_KERNEL);
+       if (!dd->boardname)
+               qib_dev_err(dd, "Failed allocation for board name: %s\n", n);
+       else
+               snprintf(dd->boardname, namelen, "%s", n);
+
+       if (dd->majrev != 4 || !dd->minrev || dd->minrev > 2)
+               qib_dev_err(dd, "Unsupported InfiniPath hardware revision "
+                           "%u.%u!\n", dd->majrev, dd->minrev);
+
+       snprintf(dd->boardversion, sizeof(dd->boardversion),
+                "ChipABI %u.%u, %s, InfiniPath%u %u.%u, SW Compat %u\n",
+                QIB_CHIP_VERS_MAJ, QIB_CHIP_VERS_MIN, dd->boardname,
+                (unsigned)SYM_FIELD(dd->revision, Revision_R, Arch),
+                dd->majrev, dd->minrev,
+                (unsigned)SYM_FIELD(dd->revision, Revision_R, SW));
+
+}
+
+/*
+ * This routine sleeps, so it can only be called from user context, not
+ * from interrupt context.  If we need interrupt context, we can split
+ * it into two routines.
+ */
+static int qib_6120_setup_reset(struct qib_devdata *dd)
+{
+       u64 val;
+       int i;
+       int ret;
+       u16 cmdval;
+       u8 int_line, clinesz;
+
+       qib_pcie_getcmd(dd, &cmdval, &int_line, &clinesz);
+
+       /* Use ERROR so it shows up in logs, etc. */
+       qib_dev_err(dd, "Resetting InfiniPath unit %u\n", dd->unit);
+
+       /* no interrupts till re-initted */
+       qib_6120_set_intr_state(dd, 0);
+
+       dd->cspec->ibdeltainprog = 0;
+       dd->cspec->ibsymdelta = 0;
+       dd->cspec->iblnkerrdelta = 0;
+
+       /*
+        * Keep chip from being accessed until we are ready.  Use
+        * writeq() directly, to allow the write even though QIB_PRESENT
+        * isnt' set.
+        */
+       dd->flags &= ~(QIB_INITTED | QIB_PRESENT);
+       dd->int_counter = 0; /* so we check interrupts work again */
+       val = dd->control | QLOGIC_IB_C_RESET;
+       writeq(val, &dd->kregbase[kr_control]);
+       mb(); /* prevent compiler re-ordering around actual reset */
+
+       for (i = 1; i <= 5; i++) {
+               /*
+                * Allow MBIST, etc. to complete; longer on each retry.
+                * We sometimes get machine checks from bus timeout if no
+                * response, so for now, make it *really* long.
+                */
+               msleep(1000 + (1 + i) * 2000);
+
+               qib_pcie_reenable(dd, cmdval, int_line, clinesz);
+
+               /*
+                * Use readq directly, so we don't need to mark it as PRESENT
+                * until we get a successful indication that all is well.
+                */
+               val = readq(&dd->kregbase[kr_revision]);
+               if (val == dd->revision) {
+                       dd->flags |= QIB_PRESENT; /* it's back */
+                       ret = qib_reinit_intr(dd);
+                       goto bail;
+               }
+       }
+       ret = 0; /* failed */
+
+bail:
+       if (ret) {
+               if (qib_pcie_params(dd, dd->lbus_width, NULL, NULL))
+                       qib_dev_err(dd, "Reset failed to setup PCIe or "
+                                   "interrupts; continuing anyway\n");
+               /* clear the reset error, init error/hwerror mask */
+               qib_6120_init_hwerrors(dd);
+               /* for Rev2 error interrupts; nop for rev 1 */
+               qib_write_kreg(dd, kr_gpio_mask, dd->cspec->gpio_mask);
+               /* clear the reset error, init error/hwerror mask */
+               qib_6120_init_hwerrors(dd);
+       }
+       return ret;
+}
+
+/**
+ * qib_6120_put_tid - write a TID in chip
+ * @dd: the qlogic_ib device
+ * @tidptr: pointer to the expected TID (in chip) to update
+ * @tidtype: RCVHQ_RCV_TYPE_EAGER (1) for eager, RCVHQ_RCV_TYPE_EXPECTED (0)
+ * for expected
+ * @pa: physical address of in memory buffer; tidinvalid if freeing
+ *
+ * This exists as a separate routine to allow for special locking etc.
+ * It's used for both the full cleanup on exit, as well as the normal
+ * setup and teardown.
+ */
+static void qib_6120_put_tid(struct qib_devdata *dd, u64 __iomem *tidptr,
+                            u32 type, unsigned long pa)
+{
+       u32 __iomem *tidp32 = (u32 __iomem *)tidptr;
+       unsigned long flags;
+       int tidx;
+       spinlock_t *tidlockp; /* select appropriate spinlock */
+
+       if (!dd->kregbase)
+               return;
+
+       if (pa != dd->tidinvalid) {
+               if (pa & ((1U << 11) - 1)) {
+                       qib_dev_err(dd, "Physaddr %lx not 2KB aligned!\n",
+                                   pa);
+                       return;
+               }
+               pa >>= 11;
+               if (pa & ~QLOGIC_IB_RT_ADDR_MASK) {
+                       qib_dev_err(dd, "Physical page address 0x%lx "
+                                   "larger than supported\n", pa);
+                       return;
+               }
+
+               if (type == RCVHQ_RCV_TYPE_EAGER)
+                       pa |= dd->tidtemplate;
+               else /* for now, always full 4KB page */
+                       pa |= 2 << 29;
+       }
+
+       /*
+        * Avoid chip issue by writing the scratch register
+        * before and after the TID, and with an io write barrier.
+        * We use a spinlock around the writes, so they can't intermix
+        * with other TID (eager or expected) writes (the chip problem
+        * is triggered by back to back TID writes). Unfortunately, this
+        * call can be done from interrupt level for the ctxt 0 eager TIDs,
+        * so we have to use irqsave locks.
+        */
+       /*
+        * Assumes tidptr always > egrtidbase
+        * if type == RCVHQ_RCV_TYPE_EAGER.
+        */
+       tidx = tidptr - dd->egrtidbase;
+
+       tidlockp = (type == RCVHQ_RCV_TYPE_EAGER && tidx < dd->rcvhdrcnt)
+               ? &dd->cspec->kernel_tid_lock : &dd->cspec->user_tid_lock;
+       spin_lock_irqsave(tidlockp, flags);
+       qib_write_kreg(dd, kr_scratch, 0xfeeddeaf);
+       writel(pa, tidp32);
+       qib_write_kreg(dd, kr_scratch, 0xdeadbeef);
+       mmiowb();
+       spin_unlock_irqrestore(tidlockp, flags);
+}
+
+/**
+ * qib_6120_put_tid_2 - write a TID in chip, Revision 2 or higher
+ * @dd: the qlogic_ib device
+ * @tidptr: pointer to the expected TID (in chip) to update
+ * @tidtype: RCVHQ_RCV_TYPE_EAGER (1) for eager, RCVHQ_RCV_TYPE_EXPECTED (0)
+ * for expected
+ * @pa: physical address of in memory buffer; tidinvalid if freeing
+ *
+ * This exists as a separate routine to allow for selection of the
+ * appropriate "flavor". The static calls in cleanup just use the
+ * revision-agnostic form, as they are not performance critical.
+ */
+static void qib_6120_put_tid_2(struct qib_devdata *dd, u64 __iomem *tidptr,
+                              u32 type, unsigned long pa)
+{
+       u32 __iomem *tidp32 = (u32 __iomem *)tidptr;
+       u32 tidx;
+
+       if (!dd->kregbase)
+               return;
+
+       if (pa != dd->tidinvalid) {
+               if (pa & ((1U << 11) - 1)) {
+                       qib_dev_err(dd, "Physaddr %lx not 2KB aligned!\n",
+                                   pa);
+                       return;
+               }
+               pa >>= 11;
+               if (pa & ~QLOGIC_IB_RT_ADDR_MASK) {
+                       qib_dev_err(dd, "Physical page address 0x%lx "
+                                   "larger than supported\n", pa);
+                       return;
+               }
+
+               if (type == RCVHQ_RCV_TYPE_EAGER)
+                       pa |= dd->tidtemplate;
+               else /* for now, always full 4KB page */
+                       pa |= 2 << 29;
+       }
+       tidx = tidptr - dd->egrtidbase;
+       writel(pa, tidp32);
+       mmiowb();
+}
+
+
+/**
+ * qib_6120_clear_tids - clear all TID entries for a context, expected and eager
+ * @dd: the qlogic_ib device
+ * @ctxt: the context
+ *
+ * clear all TID entries for a context, expected and eager.
+ * Used from qib_close().  On this chip, TIDs are only 32 bits,
+ * not 64, but they are still on 64 bit boundaries, so tidbase
+ * is declared as u64 * for the pointer math, even though we write 32 bits
+ */
+static void qib_6120_clear_tids(struct qib_devdata *dd,
+                               struct qib_ctxtdata *rcd)
+{
+       u64 __iomem *tidbase;
+       unsigned long tidinv;
+       u32 ctxt;
+       int i;
+
+       if (!dd->kregbase || !rcd)
+               return;
+
+       ctxt = rcd->ctxt;
+
+       tidinv = dd->tidinvalid;
+       tidbase = (u64 __iomem *)
+               ((char __iomem *)(dd->kregbase) +
+                dd->rcvtidbase +
+                ctxt * dd->rcvtidcnt * sizeof(*tidbase));
+
+       for (i = 0; i < dd->rcvtidcnt; i++)
+               /* use func pointer because could be one of two funcs */
+               dd->f_put_tid(dd, &tidbase[i], RCVHQ_RCV_TYPE_EXPECTED,
+                                 tidinv);
+
+       tidbase = (u64 __iomem *)
+               ((char __iomem *)(dd->kregbase) +
+                dd->rcvegrbase +
+                rcd->rcvegr_tid_base * sizeof(*tidbase));
+
+       for (i = 0; i < rcd->rcvegrcnt; i++)
+               /* use func pointer because could be one of two funcs */
+               dd->f_put_tid(dd, &tidbase[i], RCVHQ_RCV_TYPE_EAGER,
+                                 tidinv);
+}
+
+/**
+ * qib_6120_tidtemplate - setup constants for TID updates
+ * @dd: the qlogic_ib device
+ *
+ * We setup stuff that we use a lot, to avoid calculating each time
+ */
+static void qib_6120_tidtemplate(struct qib_devdata *dd)
+{
+       u32 egrsize = dd->rcvegrbufsize;
+
+       /*
+        * For now, we always allocate 4KB buffers (at init) so we can
+        * receive max size packets.  We may want a module parameter to
+        * specify 2KB or 4KB and/or make be per ctxt instead of per device
+        * for those who want to reduce memory footprint.  Note that the
+        * rcvhdrentsize size must be large enough to hold the largest
+        * IB header (currently 96 bytes) that we expect to handle (plus of
+        * course the 2 dwords of RHF).
+        */
+       if (egrsize == 2048)
+               dd->tidtemplate = 1U << 29;
+       else if (egrsize == 4096)
+               dd->tidtemplate = 2U << 29;
+       dd->tidinvalid = 0;
+}
+
+int __attribute__((weak)) qib_unordered_wc(void)
+{
+       return 0;
+}
+
+/**
+ * qib_6120_get_base_info - set chip-specific flags for user code
+ * @rcd: the qlogic_ib ctxt
+ * @kbase: qib_base_info pointer
+ *
+ * We set the PCIE flag because the lower bandwidth on PCIe vs
+ * HyperTransport can affect some user packet algorithms.
+ */
+static int qib_6120_get_base_info(struct qib_ctxtdata *rcd,
+                                 struct qib_base_info *kinfo)
+{
+       if (qib_unordered_wc())
+               kinfo->spi_runtime_flags |= QIB_RUNTIME_FORCE_WC_ORDER;
+
+       kinfo->spi_runtime_flags |= QIB_RUNTIME_PCIE |
+               QIB_RUNTIME_FORCE_PIOAVAIL | QIB_RUNTIME_PIO_REGSWAPPED;
+       return 0;
+}
+
+
+static struct qib_message_header *
+qib_6120_get_msgheader(struct qib_devdata *dd, __le32 *rhf_addr)
+{
+       return (struct qib_message_header *)
+               &rhf_addr[sizeof(u64) / sizeof(u32)];
+}
+
+static void qib_6120_config_ctxts(struct qib_devdata *dd)
+{
+       dd->ctxtcnt = qib_read_kreg32(dd, kr_portcnt);
+       if (qib_n_krcv_queues > 1) {
+               dd->first_user_ctxt = qib_n_krcv_queues * dd->num_pports;
+               if (dd->first_user_ctxt > dd->ctxtcnt)
+                       dd->first_user_ctxt = dd->ctxtcnt;
+               dd->qpn_mask = dd->first_user_ctxt <= 2 ? 2 : 6;
+       } else
+               dd->first_user_ctxt = dd->num_pports;
+       dd->n_krcv_queues = dd->first_user_ctxt;
+}
+
+static void qib_update_6120_usrhead(struct qib_ctxtdata *rcd, u64 hd,
+                                   u32 updegr, u32 egrhd)
+{
+       qib_write_ureg(rcd->dd, ur_rcvhdrhead, hd, rcd->ctxt);
+       if (updegr)
+               qib_write_ureg(rcd->dd, ur_rcvegrindexhead, egrhd, rcd->ctxt);
+}
+
+static u32 qib_6120_hdrqempty(struct qib_ctxtdata *rcd)
+{
+       u32 head, tail;
+
+       head = qib_read_ureg32(rcd->dd, ur_rcvhdrhead, rcd->ctxt);
+       if (rcd->rcvhdrtail_kvaddr)
+               tail = qib_get_rcvhdrtail(rcd);
+       else
+               tail = qib_read_ureg32(rcd->dd, ur_rcvhdrtail, rcd->ctxt);
+       return head == tail;
+}
+
+/*
+ * Used when we close any ctxt, for DMA already in flight
+ * at close.  Can't be done until we know hdrq size, so not
+ * early in chip init.
+ */
+static void alloc_dummy_hdrq(struct qib_devdata *dd)
+{
+       dd->cspec->dummy_hdrq = dma_alloc_coherent(&dd->pcidev->dev,
+                                       dd->rcd[0]->rcvhdrq_size,
+                                       &dd->cspec->dummy_hdrq_phys,
+                                       GFP_KERNEL | __GFP_COMP);
+       if (!dd->cspec->dummy_hdrq) {
+               qib_devinfo(dd->pcidev, "Couldn't allocate dummy hdrq\n");
+               /* fallback to just 0'ing */
+               dd->cspec->dummy_hdrq_phys = 0UL;
+       }
+}
+
+/*
+ * Modify the RCVCTRL register in chip-specific way. This
+ * is a function because bit positions and (future) register
+ * location is chip-specific, but the needed operations are
+ * generic. <op> is a bit-mask because we often want to
+ * do multiple modifications.
+ */
+static void rcvctrl_6120_mod(struct qib_pportdata *ppd, unsigned int op,
+                            int ctxt)
+{
+       struct qib_devdata *dd = ppd->dd;
+       u64 mask, val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dd->cspec->rcvmod_lock, flags);
+
+       if (op & QIB_RCVCTRL_TAILUPD_ENB)
+               dd->rcvctrl |= (1ULL << QLOGIC_IB_R_TAILUPD_SHIFT);
+       if (op & QIB_RCVCTRL_TAILUPD_DIS)
+               dd->rcvctrl &= ~(1ULL << QLOGIC_IB_R_TAILUPD_SHIFT);
+       if (op & QIB_RCVCTRL_PKEY_ENB)
+               dd->rcvctrl &= ~(1ULL << IBA6120_R_PKEY_DIS_SHIFT);
+       if (op & QIB_RCVCTRL_PKEY_DIS)
+               dd->rcvctrl |= (1ULL << IBA6120_R_PKEY_DIS_SHIFT);
+       if (ctxt < 0)
+               mask = (1ULL << dd->ctxtcnt) - 1;
+       else
+               mask = (1ULL << ctxt);
+       if (op & QIB_RCVCTRL_CTXT_ENB) {
+               /* always done for specific ctxt */
+               dd->rcvctrl |= (mask << SYM_LSB(RcvCtrl, PortEnable));
+               if (!(dd->flags & QIB_NODMA_RTAIL))
+                       dd->rcvctrl |= 1ULL << QLOGIC_IB_R_TAILUPD_SHIFT;
+               /* Write these registers before the context is enabled. */
+               qib_write_kreg_ctxt(dd, kr_rcvhdrtailaddr, ctxt,
+                       dd->rcd[ctxt]->rcvhdrqtailaddr_phys);
+               qib_write_kreg_ctxt(dd, kr_rcvhdraddr, ctxt,
+                       dd->rcd[ctxt]->rcvhdrq_phys);
+
+               if (ctxt == 0 && !dd->cspec->dummy_hdrq)
+                       alloc_dummy_hdrq(dd);
+       }
+       if (op & QIB_RCVCTRL_CTXT_DIS)
+               dd->rcvctrl &= ~(mask << SYM_LSB(RcvCtrl, PortEnable));
+       if (op & QIB_RCVCTRL_INTRAVAIL_ENB)
+               dd->rcvctrl |= (mask << QLOGIC_IB_R_INTRAVAIL_SHIFT);
+       if (op & QIB_RCVCTRL_INTRAVAIL_DIS)
+               dd->rcvctrl &= ~(mask << QLOGIC_IB_R_INTRAVAIL_SHIFT);
+       qib_write_kreg(dd, kr_rcvctrl, dd->rcvctrl);
+       if ((op & QIB_RCVCTRL_INTRAVAIL_ENB) && dd->rhdrhead_intr_off) {
+               /* arm rcv interrupt */
+               val = qib_read_ureg32(dd, ur_rcvhdrhead, ctxt) |
+                       dd->rhdrhead_intr_off;
+               qib_write_ureg(dd, ur_rcvhdrhead, val, ctxt);
+       }
+       if (op & QIB_RCVCTRL_CTXT_ENB) {
+               /*
+                * Init the context registers also; if we were
+                * disabled, tail and head should both be zero
+                * already from the enable, but since we don't
+                * know, we have to do it explictly.
+                */
+               val = qib_read_ureg32(dd, ur_rcvegrindextail, ctxt);
+               qib_write_ureg(dd, ur_rcvegrindexhead, val, ctxt);
+
+               val = qib_read_ureg32(dd, ur_rcvhdrtail, ctxt);
+               dd->rcd[ctxt]->head = val;
+               /* If kctxt, interrupt on next receive. */
+               if (ctxt < dd->first_user_ctxt)
+                       val |= dd->rhdrhead_intr_off;
+               qib_write_ureg(dd, ur_rcvhdrhead, val, ctxt);
+       }
+       if (op & QIB_RCVCTRL_CTXT_DIS) {
+               /*
+                * Be paranoid, and never write 0's to these, just use an
+                * unused page.  Of course,
+                * rcvhdraddr points to a large chunk of memory, so this
+                * could still trash things, but at least it won't trash
+                * page 0, and by disabling the ctxt, it should stop "soon",
+                * even if a packet or two is in already in flight after we
+                * disabled the ctxt.  Only 6120 has this issue.
+                */
+               if (ctxt >= 0) {
+                       qib_write_kreg_ctxt(dd, kr_rcvhdrtailaddr, ctxt,
+                                           dd->cspec->dummy_hdrq_phys);
+                       qib_write_kreg_ctxt(dd, kr_rcvhdraddr, ctxt,
+                                           dd->cspec->dummy_hdrq_phys);
+               } else {
+                       unsigned i;
+
+                       for (i = 0; i < dd->cfgctxts; i++) {
+                               qib_write_kreg_ctxt(dd, kr_rcvhdrtailaddr,
+                                           i, dd->cspec->dummy_hdrq_phys);
+                               qib_write_kreg_ctxt(dd, kr_rcvhdraddr,
+                                           i, dd->cspec->dummy_hdrq_phys);
+                       }
+               }
+       }
+       spin_unlock_irqrestore(&dd->cspec->rcvmod_lock, flags);
+}
+
+/*
+ * Modify the SENDCTRL register in chip-specific way. This
+ * is a function there may be multiple such registers with
+ * slightly different layouts. Only operations actually used
+ * are implemented yet.
+ * Chip requires no back-back sendctrl writes, so write
+ * scratch register after writing sendctrl
+ */
+static void sendctrl_6120_mod(struct qib_pportdata *ppd, u32 op)
+{
+       struct qib_devdata *dd = ppd->dd;
+       u64 tmp_dd_sendctrl;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dd->sendctrl_lock, flags);
+
+       /* First the ones that are "sticky", saved in shadow */
+       if (op & QIB_SENDCTRL_CLEAR)
+               dd->sendctrl = 0;
+       if (op & QIB_SENDCTRL_SEND_DIS)
+               dd->sendctrl &= ~SYM_MASK(SendCtrl, PIOEnable);
+       else if (op & QIB_SENDCTRL_SEND_ENB)
+               dd->sendctrl |= SYM_MASK(SendCtrl, PIOEnable);
+       if (op & QIB_SENDCTRL_AVAIL_DIS)
+               dd->sendctrl &= ~SYM_MASK(SendCtrl, PIOBufAvailUpd);
+       else if (op & QIB_SENDCTRL_AVAIL_ENB)
+               dd->sendctrl |= SYM_MASK(SendCtrl, PIOBufAvailUpd);
+
+       if (op & QIB_SENDCTRL_DISARM_ALL) {
+               u32 i, last;
+
+               tmp_dd_sendctrl = dd->sendctrl;
+               /*
+                * disarm any that are not yet launched, disabling sends
+                * and updates until done.
+                */
+               last = dd->piobcnt2k + dd->piobcnt4k;
+               tmp_dd_sendctrl &=
+                       ~(SYM_MASK(SendCtrl, PIOEnable) |
+                         SYM_MASK(SendCtrl, PIOBufAvailUpd));
+               for (i = 0; i < last; i++) {
+                       qib_write_kreg(dd, kr_sendctrl, tmp_dd_sendctrl |
+                                      SYM_MASK(SendCtrl, Disarm) | i);
+                       qib_write_kreg(dd, kr_scratch, 0);
+               }
+       }
+
+       tmp_dd_sendctrl = dd->sendctrl;
+
+       if (op & QIB_SENDCTRL_FLUSH)
+               tmp_dd_sendctrl |= SYM_MASK(SendCtrl, Abort);
+       if (op & QIB_SENDCTRL_DISARM)
+               tmp_dd_sendctrl |= SYM_MASK(SendCtrl, Disarm) |
+                       ((op & QIB_6120_SendCtrl_DisarmPIOBuf_RMASK) <<
+                        SYM_LSB(SendCtrl, DisarmPIOBuf));
+       if (op & QIB_SENDCTRL_AVAIL_BLIP)
+               tmp_dd_sendctrl &= ~SYM_MASK(SendCtrl, PIOBufAvailUpd);
+
+       qib_write_kreg(dd, kr_sendctrl, tmp_dd_sendctrl);
+       qib_write_kreg(dd, kr_scratch, 0);
+
+       if (op & QIB_SENDCTRL_AVAIL_BLIP) {
+               qib_write_kreg(dd, kr_sendctrl, dd->sendctrl);
+               qib_write_kreg(dd, kr_scratch, 0);
+       }
+
+       spin_unlock_irqrestore(&dd->sendctrl_lock, flags);
+
+       if (op & QIB_SENDCTRL_FLUSH) {
+               u32 v;
+               /*
+                * ensure writes have hit chip, then do a few
+                * more reads, to allow DMA of pioavail registers
+                * to occur, so in-memory copy is in sync with
+                * the chip.  Not always safe to sleep.
+                */
+               v = qib_read_kreg32(dd, kr_scratch);
+               qib_write_kreg(dd, kr_scratch, v);
+               v = qib_read_kreg32(dd, kr_scratch);
+               qib_write_kreg(dd, kr_scratch, v);
+               qib_read_kreg32(dd, kr_scratch);
+       }
+}
+
+/**
+ * qib_portcntr_6120 - read a per-port counter
+ * @dd: the qlogic_ib device
+ * @creg: the counter to snapshot
+ */
+static u64 qib_portcntr_6120(struct qib_pportdata *ppd, u32 reg)
+{
+       u64 ret = 0ULL;
+       struct qib_devdata *dd = ppd->dd;
+       u16 creg;
+       /* 0xffff for unimplemented or synthesized counters */
+       static const u16 xlator[] = {
+               [QIBPORTCNTR_PKTSEND] = cr_pktsend,
+               [QIBPORTCNTR_WORDSEND] = cr_wordsend,
+               [QIBPORTCNTR_PSXMITDATA] = 0xffff,
+               [QIBPORTCNTR_PSXMITPKTS] = 0xffff,
+               [QIBPORTCNTR_PSXMITWAIT] = 0xffff,
+               [QIBPORTCNTR_SENDSTALL] = cr_sendstall,
+               [QIBPORTCNTR_PKTRCV] = cr_pktrcv,
+               [QIBPORTCNTR_PSRCVDATA] = 0xffff,
+               [QIBPORTCNTR_PSRCVPKTS] = 0xffff,
+               [QIBPORTCNTR_RCVEBP] = cr_rcvebp,
+               [QIBPORTCNTR_RCVOVFL] = cr_rcvovfl,
+               [QIBPORTCNTR_WORDRCV] = cr_wordrcv,
+               [QIBPORTCNTR_RXDROPPKT] = cr_rxdroppkt,
+               [QIBPORTCNTR_RXLOCALPHYERR] = 0xffff,
+               [QIBPORTCNTR_RXVLERR] = 0xffff,
+               [QIBPORTCNTR_ERRICRC] = cr_erricrc,
+               [QIBPORTCNTR_ERRVCRC] = cr_errvcrc,
+               [QIBPORTCNTR_ERRLPCRC] = cr_errlpcrc,
+               [QIBPORTCNTR_BADFORMAT] = cr_badformat,
+               [QIBPORTCNTR_ERR_RLEN] = cr_err_rlen,
+               [QIBPORTCNTR_IBSYMBOLERR] = cr_ibsymbolerr,
+               [QIBPORTCNTR_INVALIDRLEN] = cr_invalidrlen,
+               [QIBPORTCNTR_UNSUPVL] = cr_txunsupvl,
+               [QIBPORTCNTR_EXCESSBUFOVFL] = 0xffff,
+               [QIBPORTCNTR_ERRLINK] = cr_errlink,
+               [QIBPORTCNTR_IBLINKDOWN] = cr_iblinkdown,
+               [QIBPORTCNTR_IBLINKERRRECOV] = cr_iblinkerrrecov,
+               [QIBPORTCNTR_LLI] = 0xffff,
+               [QIBPORTCNTR_PSINTERVAL] = 0xffff,
+               [QIBPORTCNTR_PSSTART] = 0xffff,
+               [QIBPORTCNTR_PSSTAT] = 0xffff,
+               [QIBPORTCNTR_VL15PKTDROP] = 0xffff,
+               [QIBPORTCNTR_ERRPKEY] = cr_errpkey,
+               [QIBPORTCNTR_KHDROVFL] = 0xffff,
+       };
+
+       if (reg >= ARRAY_SIZE(xlator)) {
+               qib_devinfo(ppd->dd->pcidev,
+                        "Unimplemented portcounter %u\n", reg);
+               goto done;
+       }
+       creg = xlator[reg];
+
+       /* handle counters requests not implemented as chip counters */
+       if (reg == QIBPORTCNTR_LLI)
+               ret = dd->cspec->lli_errs;
+       else if (reg == QIBPORTCNTR_EXCESSBUFOVFL)
+               ret = dd->cspec->overrun_thresh_errs;
+       else if (reg == QIBPORTCNTR_KHDROVFL) {
+               int i;
+
+               /* sum over all kernel contexts */
+               for (i = 0; i < dd->first_user_ctxt; i++)
+                       ret += read_6120_creg32(dd, cr_portovfl + i);
+       } else if (reg == QIBPORTCNTR_PSSTAT)
+               ret = dd->cspec->pma_sample_status;
+       if (creg == 0xffff)
+               goto done;
+
+       /*
+        * only fast incrementing counters are 64bit; use 32 bit reads to
+        * avoid two independent reads when on opteron
+        */
+       if (creg == cr_wordsend || creg == cr_wordrcv ||
+           creg == cr_pktsend || creg == cr_pktrcv)
+               ret = read_6120_creg(dd, creg);
+       else
+               ret = read_6120_creg32(dd, creg);
+       if (creg == cr_ibsymbolerr) {
+               if (dd->cspec->ibdeltainprog)
+                       ret -= ret - dd->cspec->ibsymsnap;
+               ret -= dd->cspec->ibsymdelta;
+       } else if (creg == cr_iblinkerrrecov) {
+               if (dd->cspec->ibdeltainprog)
+                       ret -= ret - dd->cspec->iblnkerrsnap;
+               ret -= dd->cspec->iblnkerrdelta;
+       }
+       if (reg == QIBPORTCNTR_RXDROPPKT) /* add special cased count */
+               ret += dd->cspec->rxfc_unsupvl_errs;
+
+done:
+       return ret;
+}
+
+/*
+ * Device counter names (not port-specific), one line per stat,
+ * single string.  Used by utilities like ipathstats to print the stats
+ * in a way which works for different versions of drivers, without changing
+ * the utility.  Names need to be 12 chars or less (w/o newline), for proper
+ * display by utility.
+ * Non-error counters are first.
+ * Start of "error" conters is indicated by a leading "E " on the first
+ * "error" counter, and doesn't count in label length.
+ * The EgrOvfl list needs to be last so we truncate them at the configured
+ * context count for the device.
+ * cntr6120indices contains the corresponding register indices.
+ */
+static const char cntr6120names[] =
+       "Interrupts\n"
+       "HostBusStall\n"
+       "E RxTIDFull\n"
+       "RxTIDInvalid\n"
+       "Ctxt0EgrOvfl\n"
+       "Ctxt1EgrOvfl\n"
+       "Ctxt2EgrOvfl\n"
+       "Ctxt3EgrOvfl\n"
+       "Ctxt4EgrOvfl\n";
+
+static const size_t cntr6120indices[] = {
+       cr_lbint,
+       cr_lbflowstall,
+       cr_errtidfull,
+       cr_errtidvalid,
+       cr_portovfl + 0,
+       cr_portovfl + 1,
+       cr_portovfl + 2,
+       cr_portovfl + 3,
+       cr_portovfl + 4,
+};
+
+/*
+ * same as cntr6120names and cntr6120indices, but for port-specific counters.
+ * portcntr6120indices is somewhat complicated by some registers needing
+ * adjustments of various kinds, and those are ORed with _PORT_VIRT_FLAG
+ */
+static const char portcntr6120names[] =
+       "TxPkt\n"
+       "TxFlowPkt\n"
+       "TxWords\n"
+       "RxPkt\n"
+       "RxFlowPkt\n"
+       "RxWords\n"
+       "TxFlowStall\n"
+       "E IBStatusChng\n"
+       "IBLinkDown\n"
+       "IBLnkRecov\n"
+       "IBRxLinkErr\n"
+       "IBSymbolErr\n"
+       "RxLLIErr\n"
+       "RxBadFormat\n"
+       "RxBadLen\n"
+       "RxBufOvrfl\n"
+       "RxEBP\n"
+       "RxFlowCtlErr\n"
+       "RxICRCerr\n"
+       "RxLPCRCerr\n"
+       "RxVCRCerr\n"
+       "RxInvalLen\n"
+       "RxInvalPKey\n"
+       "RxPktDropped\n"
+       "TxBadLength\n"
+       "TxDropped\n"
+       "TxInvalLen\n"
+       "TxUnderrun\n"
+       "TxUnsupVL\n"
+       ;
+
+#define _PORT_VIRT_FLAG 0x8000 /* "virtual", need adjustments */
+static const size_t portcntr6120indices[] = {
+       QIBPORTCNTR_PKTSEND | _PORT_VIRT_FLAG,
+       cr_pktsendflow,
+       QIBPORTCNTR_WORDSEND | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_PKTRCV | _PORT_VIRT_FLAG,
+       cr_pktrcvflowctrl,
+       QIBPORTCNTR_WORDRCV | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_SENDSTALL | _PORT_VIRT_FLAG,
+       cr_ibstatuschange,
+       QIBPORTCNTR_IBLINKDOWN | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_IBLINKERRRECOV | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_ERRLINK | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_IBSYMBOLERR | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_LLI | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_BADFORMAT | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_ERR_RLEN | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_RCVOVFL | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_RCVEBP | _PORT_VIRT_FLAG,
+       cr_rcvflowctrl_err,
+       QIBPORTCNTR_ERRICRC | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_ERRLPCRC | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_ERRVCRC | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_INVALIDRLEN | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_ERRPKEY | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_RXDROPPKT | _PORT_VIRT_FLAG,
+       cr_invalidslen,
+       cr_senddropped,
+       cr_errslen,
+       cr_sendunderrun,
+       cr_txunsupvl,
+};
+
+/* do all the setup to make the counter reads efficient later */
+static void init_6120_cntrnames(struct qib_devdata *dd)
+{
+       int i, j = 0;
+       char *s;
+
+       for (i = 0, s = (char *)cntr6120names; s && j <= dd->cfgctxts;
+            i++) {
+               /* we always have at least one counter before the egrovfl */
+               if (!j && !strncmp("Ctxt0EgrOvfl", s + 1, 12))
+                       j = 1;
+               s = strchr(s + 1, '\n');
+               if (s && j)
+                       j++;
+       }
+       dd->cspec->ncntrs = i;
+       if (!s)
+               /* full list; size is without terminating null */
+               dd->cspec->cntrnamelen = sizeof(cntr6120names) - 1;
+       else
+               dd->cspec->cntrnamelen = 1 + s - cntr6120names;
+       dd->cspec->cntrs = kmalloc(dd->cspec->ncntrs
+               * sizeof(u64), GFP_KERNEL);
+       if (!dd->cspec->cntrs)
+               qib_dev_err(dd, "Failed allocation for counters\n");
+
+       for (i = 0, s = (char *)portcntr6120names; s; i++)
+               s = strchr(s + 1, '\n');
+       dd->cspec->nportcntrs = i - 1;
+       dd->cspec->portcntrnamelen = sizeof(portcntr6120names) - 1;
+       dd->cspec->portcntrs = kmalloc(dd->cspec->nportcntrs
+               * sizeof(u64), GFP_KERNEL);
+       if (!dd->cspec->portcntrs)
+               qib_dev_err(dd, "Failed allocation for portcounters\n");
+}
+
+static u32 qib_read_6120cntrs(struct qib_devdata *dd, loff_t pos, char **namep,
+                             u64 **cntrp)
+{
+       u32 ret;
+
+       if (namep) {
+               ret = dd->cspec->cntrnamelen;
+               if (pos >= ret)
+                       ret = 0; /* final read after getting everything */
+               else
+                       *namep = (char *)cntr6120names;
+       } else {
+               u64 *cntr = dd->cspec->cntrs;
+               int i;
+
+               ret = dd->cspec->ncntrs * sizeof(u64);
+               if (!cntr || pos >= ret) {
+                       /* everything read, or couldn't get memory */
+                       ret = 0;
+                       goto done;
+               }
+               if (pos >= ret) {
+                       ret = 0; /* final read after getting everything */
+                       goto done;
+               }
+               *cntrp = cntr;
+               for (i = 0; i < dd->cspec->ncntrs; i++)
+                       *cntr++ = read_6120_creg32(dd, cntr6120indices[i]);
+       }
+done:
+       return ret;
+}
+
+static u32 qib_read_6120portcntrs(struct qib_devdata *dd, loff_t pos, u32 port,
+                                 char **namep, u64 **cntrp)
+{
+       u32 ret;
+
+       if (namep) {
+               ret = dd->cspec->portcntrnamelen;
+               if (pos >= ret)
+                       ret = 0; /* final read after getting everything */
+               else
+                       *namep = (char *)portcntr6120names;
+       } else {
+               u64 *cntr = dd->cspec->portcntrs;
+               struct qib_pportdata *ppd = &dd->pport[port];
+               int i;
+
+               ret = dd->cspec->nportcntrs * sizeof(u64);
+               if (!cntr || pos >= ret) {
+                       /* everything read, or couldn't get memory */
+                       ret = 0;
+                       goto done;
+               }
+               *cntrp = cntr;
+               for (i = 0; i < dd->cspec->nportcntrs; i++) {
+                       if (portcntr6120indices[i] & _PORT_VIRT_FLAG)
+                               *cntr++ = qib_portcntr_6120(ppd,
+                                       portcntr6120indices[i] &
+                                       ~_PORT_VIRT_FLAG);
+                       else
+                               *cntr++ = read_6120_creg32(dd,
+                                          portcntr6120indices[i]);
+               }
+       }
+done:
+       return ret;
+}
+
+static void qib_chk_6120_errormask(struct qib_devdata *dd)
+{
+       static u32 fixed;
+       u32 ctrl;
+       unsigned long errormask;
+       unsigned long hwerrs;
+
+       if (!dd->cspec->errormask || !(dd->flags & QIB_INITTED))
+               return;
+
+       errormask = qib_read_kreg64(dd, kr_errmask);
+
+       if (errormask == dd->cspec->errormask)
+               return;
+       fixed++;
+
+       hwerrs = qib_read_kreg64(dd, kr_hwerrstatus);
+       ctrl = qib_read_kreg32(dd, kr_control);
+
+       qib_write_kreg(dd, kr_errmask,
+               dd->cspec->errormask);
+
+       if ((hwerrs & dd->cspec->hwerrmask) ||
+           (ctrl & QLOGIC_IB_C_FREEZEMODE)) {
+               qib_write_kreg(dd, kr_hwerrclear, 0ULL);
+               qib_write_kreg(dd, kr_errclear, 0ULL);
+               /* force re-interrupt of pending events, just in case */
+               qib_write_kreg(dd, kr_intclear, 0ULL);
+               qib_devinfo(dd->pcidev,
+                        "errormask fixed(%u) %lx->%lx, ctrl %x hwerr %lx\n",
+                        fixed, errormask, (unsigned long)dd->cspec->errormask,
+                        ctrl, hwerrs);
+       }
+}
+
+/**
+ * qib_get_faststats - get word counters from chip before they overflow
+ * @opaque - contains a pointer to the qlogic_ib device qib_devdata
+ *
+ * This needs more work; in particular, decision on whether we really
+ * need traffic_wds done the way it is
+ * called from add_timer
+ */
+static void qib_get_6120_faststats(unsigned long opaque)
+{
+       struct qib_devdata *dd = (struct qib_devdata *) opaque;
+       struct qib_pportdata *ppd = dd->pport;
+       unsigned long flags;
+       u64 traffic_wds;
+
+       /*
+        * don't access the chip while running diags, or memory diags can
+        * fail
+        */
+       if (!(dd->flags & QIB_INITTED) || dd->diag_client)
+               /* but re-arm the timer, for diags case; won't hurt other */
+               goto done;
+
+       /*
+        * We now try to maintain an activity timer, based on traffic
+        * exceeding a threshold, so we need to check the word-counts
+        * even if they are 64-bit.
+        */
+       traffic_wds = qib_portcntr_6120(ppd, cr_wordsend) +
+               qib_portcntr_6120(ppd, cr_wordrcv);
+       spin_lock_irqsave(&dd->eep_st_lock, flags);
+       traffic_wds -= dd->traffic_wds;
+       dd->traffic_wds += traffic_wds;
+       if (traffic_wds  >= QIB_TRAFFIC_ACTIVE_THRESHOLD)
+               atomic_add(5, &dd->active_time); /* S/B #define */
+       spin_unlock_irqrestore(&dd->eep_st_lock, flags);
+
+       qib_chk_6120_errormask(dd);
+done:
+       mod_timer(&dd->stats_timer, jiffies + HZ * ACTIVITY_TIMER);
+}
+
+/* no interrupt fallback for these chips */
+static int qib_6120_nointr_fallback(struct qib_devdata *dd)
+{
+       return 0;
+}
+
+/*
+ * reset the XGXS (between serdes and IBC).  Slightly less intrusive
+ * than resetting the IBC or external link state, and useful in some
+ * cases to cause some retraining.  To do this right, we reset IBC
+ * as well.
+ */
+static void qib_6120_xgxs_reset(struct qib_pportdata *ppd)
+{
+       u64 val, prev_val;
+       struct qib_devdata *dd = ppd->dd;
+
+       prev_val = qib_read_kreg64(dd, kr_xgxs_cfg);
+       val = prev_val | QLOGIC_IB_XGXS_RESET;
+       prev_val &= ~QLOGIC_IB_XGXS_RESET; /* be sure */
+       qib_write_kreg(dd, kr_control,
+                      dd->control & ~QLOGIC_IB_C_LINKENABLE);
+       qib_write_kreg(dd, kr_xgxs_cfg, val);
+       qib_read_kreg32(dd, kr_scratch);
+       qib_write_kreg(dd, kr_xgxs_cfg, prev_val);
+       qib_write_kreg(dd, kr_control, dd->control);
+}
+
+static int qib_6120_get_ib_cfg(struct qib_pportdata *ppd, int which)
+{
+       int ret;
+
+       switch (which) {
+       case QIB_IB_CFG_LWID:
+               ret = ppd->link_width_active;
+               break;
+
+       case QIB_IB_CFG_SPD:
+               ret = ppd->link_speed_active;
+               break;
+
+       case QIB_IB_CFG_LWID_ENB:
+               ret = ppd->link_width_enabled;
+               break;
+
+       case QIB_IB_CFG_SPD_ENB:
+               ret = ppd->link_speed_enabled;
+               break;
+
+       case QIB_IB_CFG_OP_VLS:
+               ret = ppd->vls_operational;
+               break;
+
+       case QIB_IB_CFG_VL_HIGH_CAP:
+               ret = 0;
+               break;
+
+       case QIB_IB_CFG_VL_LOW_CAP:
+               ret = 0;
+               break;
+
+       case QIB_IB_CFG_OVERRUN_THRESH: /* IB overrun threshold */
+               ret = SYM_FIELD(ppd->dd->cspec->ibcctrl, IBCCtrl,
+                               OverrunThreshold);
+               break;
+
+       case QIB_IB_CFG_PHYERR_THRESH: /* IB PHY error threshold */
+               ret = SYM_FIELD(ppd->dd->cspec->ibcctrl, IBCCtrl,
+                               PhyerrThreshold);
+               break;
+
+       case QIB_IB_CFG_LINKDEFAULT: /* IB link default (sleep/poll) */
+               /* will only take effect when the link state changes */
+               ret = (ppd->dd->cspec->ibcctrl &
+                      SYM_MASK(IBCCtrl, LinkDownDefaultState)) ?
+                       IB_LINKINITCMD_SLEEP : IB_LINKINITCMD_POLL;
+               break;
+
+       case QIB_IB_CFG_HRTBT: /* Get Heartbeat off/enable/auto */
+               ret = 0; /* no heartbeat on this chip */
+               break;
+
+       case QIB_IB_CFG_PMA_TICKS:
+               ret = 250; /* 1 usec. */
+               break;
+
+       default:
+               ret =  -EINVAL;
+               break;
+       }
+       return ret;
+}
+
+/*
+ * We assume range checking is already done, if needed.
+ */
+static int qib_6120_set_ib_cfg(struct qib_pportdata *ppd, int which, u32 val)
+{
+       struct qib_devdata *dd = ppd->dd;
+       int ret = 0;
+       u64 val64;
+       u16 lcmd, licmd;
+
+       switch (which) {
+       case QIB_IB_CFG_LWID_ENB:
+               ppd->link_width_enabled = val;
+               break;
+
+       case QIB_IB_CFG_SPD_ENB:
+               ppd->link_speed_enabled = val;
+               break;
+
+       case QIB_IB_CFG_OVERRUN_THRESH: /* IB overrun threshold */
+               val64 = SYM_FIELD(dd->cspec->ibcctrl, IBCCtrl,
+                                 OverrunThreshold);
+               if (val64 != val) {
+                       dd->cspec->ibcctrl &=
+                               ~SYM_MASK(IBCCtrl, OverrunThreshold);
+                       dd->cspec->ibcctrl |= (u64) val <<
+                               SYM_LSB(IBCCtrl, OverrunThreshold);
+                       qib_write_kreg(dd, kr_ibcctrl, dd->cspec->ibcctrl);
+                       qib_write_kreg(dd, kr_scratch, 0);
+               }
+               break;
+
+       case QIB_IB_CFG_PHYERR_THRESH: /* IB PHY error threshold */
+               val64 = SYM_FIELD(dd->cspec->ibcctrl, IBCCtrl,
+                                 PhyerrThreshold);
+               if (val64 != val) {
+                       dd->cspec->ibcctrl &=
+                               ~SYM_MASK(IBCCtrl, PhyerrThreshold);
+                       dd->cspec->ibcctrl |= (u64) val <<
+                               SYM_LSB(IBCCtrl, PhyerrThreshold);
+                       qib_write_kreg(dd, kr_ibcctrl, dd->cspec->ibcctrl);
+                       qib_write_kreg(dd, kr_scratch, 0);
+               }
+               break;
+
+       case QIB_IB_CFG_PKEYS: /* update pkeys */
+               val64 = (u64) ppd->pkeys[0] | ((u64) ppd->pkeys[1] << 16) |
+                       ((u64) ppd->pkeys[2] << 32) |
+                       ((u64) ppd->pkeys[3] << 48);
+               qib_write_kreg(dd, kr_partitionkey, val64);
+               break;
+
+       case QIB_IB_CFG_LINKDEFAULT: /* IB link default (sleep/poll) */
+               /* will only take effect when the link state changes */
+               if (val == IB_LINKINITCMD_POLL)
+                       dd->cspec->ibcctrl &=
+                               ~SYM_MASK(IBCCtrl, LinkDownDefaultState);
+               else /* SLEEP */
+                       dd->cspec->ibcctrl |=
+                               SYM_MASK(IBCCtrl, LinkDownDefaultState);
+               qib_write_kreg(dd, kr_ibcctrl, dd->cspec->ibcctrl);
+               qib_write_kreg(dd, kr_scratch, 0);
+               break;
+
+       case QIB_IB_CFG_MTU: /* update the MTU in IBC */
+               /*
+                * Update our housekeeping variables, and set IBC max
+                * size, same as init code; max IBC is max we allow in
+                * buffer, less the qword pbc, plus 1 for ICRC, in dwords
+                * Set even if it's unchanged, print debug message only
+                * on changes.
+                */
+               val = (ppd->ibmaxlen >> 2) + 1;
+               dd->cspec->ibcctrl &= ~SYM_MASK(IBCCtrl, MaxPktLen);
+               dd->cspec->ibcctrl |= (u64)val <<
+                       SYM_LSB(IBCCtrl, MaxPktLen);
+               qib_write_kreg(dd, kr_ibcctrl, dd->cspec->ibcctrl);
+               qib_write_kreg(dd, kr_scratch, 0);
+               break;
+
+       case QIB_IB_CFG_LSTATE: /* set the IB link state */
+               switch (val & 0xffff0000) {
+               case IB_LINKCMD_DOWN:
+                       lcmd = QLOGIC_IB_IBCC_LINKCMD_DOWN;
+                       if (!dd->cspec->ibdeltainprog) {
+                               dd->cspec->ibdeltainprog = 1;
+                               dd->cspec->ibsymsnap =
+                                       read_6120_creg32(dd, cr_ibsymbolerr);
+                               dd->cspec->iblnkerrsnap =
+                                       read_6120_creg32(dd, cr_iblinkerrrecov);
+                       }
+                       break;
+
+               case IB_LINKCMD_ARMED:
+                       lcmd = QLOGIC_IB_IBCC_LINKCMD_ARMED;
+                       break;
+
+               case IB_LINKCMD_ACTIVE:
+                       lcmd = QLOGIC_IB_IBCC_LINKCMD_ACTIVE;
+                       break;
+
+               default:
+                       ret = -EINVAL;
+                       qib_dev_err(dd, "bad linkcmd req 0x%x\n", val >> 16);
+                       goto bail;
+               }
+               switch (val & 0xffff) {
+               case IB_LINKINITCMD_NOP:
+                       licmd = 0;
+                       break;
+
+               case IB_LINKINITCMD_POLL:
+                       licmd = QLOGIC_IB_IBCC_LINKINITCMD_POLL;
+                       break;
+
+               case IB_LINKINITCMD_SLEEP:
+                       licmd = QLOGIC_IB_IBCC_LINKINITCMD_SLEEP;
+                       break;
+
+               case IB_LINKINITCMD_DISABLE:
+                       licmd = QLOGIC_IB_IBCC_LINKINITCMD_DISABLE;
+                       break;
+
+               default:
+                       ret = -EINVAL;
+                       qib_dev_err(dd, "bad linkinitcmd req 0x%x\n",
+                                   val & 0xffff);
+                       goto bail;
+               }
+               qib_set_ib_6120_lstate(ppd, lcmd, licmd);
+               goto bail;
+
+       case QIB_IB_CFG_HRTBT:
+               ret = -EINVAL;
+               break;
+
+       default:
+               ret = -EINVAL;
+       }
+bail:
+       return ret;
+}
+
+static int qib_6120_set_loopback(struct qib_pportdata *ppd, const char *what)
+{
+       int ret = 0;
+       if (!strncmp(what, "ibc", 3)) {
+               ppd->dd->cspec->ibcctrl |= SYM_MASK(IBCCtrl, Loopback);
+               qib_devinfo(ppd->dd->pcidev, "Enabling IB%u:%u IBC loopback\n",
+                        ppd->dd->unit, ppd->port);
+       } else if (!strncmp(what, "off", 3)) {
+               ppd->dd->cspec->ibcctrl &= ~SYM_MASK(IBCCtrl, Loopback);
+               qib_devinfo(ppd->dd->pcidev, "Disabling IB%u:%u IBC loopback "
+                           "(normal)\n", ppd->dd->unit, ppd->port);
+       } else
+               ret = -EINVAL;
+       if (!ret) {
+               qib_write_kreg(ppd->dd, kr_ibcctrl, ppd->dd->cspec->ibcctrl);
+               qib_write_kreg(ppd->dd, kr_scratch, 0);
+       }
+       return ret;
+}
+
+static void pma_6120_timer(unsigned long data)
+{
+       struct qib_pportdata *ppd = (struct qib_pportdata *)data;
+       struct qib_chip_specific *cs = ppd->dd->cspec;
+       struct qib_ibport *ibp = &ppd->ibport_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ibp->lock, flags);
+       if (cs->pma_sample_status == IB_PMA_SAMPLE_STATUS_STARTED) {
+               cs->pma_sample_status = IB_PMA_SAMPLE_STATUS_RUNNING;
+               qib_snapshot_counters(ppd, &cs->sword, &cs->rword,
+                                     &cs->spkts, &cs->rpkts, &cs->xmit_wait);
+               mod_timer(&cs->pma_timer,
+                         jiffies + usecs_to_jiffies(ibp->pma_sample_interval));
+       } else if (cs->pma_sample_status == IB_PMA_SAMPLE_STATUS_RUNNING) {
+               u64 ta, tb, tc, td, te;
+
+               cs->pma_sample_status = IB_PMA_SAMPLE_STATUS_DONE;
+               qib_snapshot_counters(ppd, &ta, &tb, &tc, &td, &te);
+
+               cs->sword = ta - cs->sword;
+               cs->rword = tb - cs->rword;
+               cs->spkts = tc - cs->spkts;
+               cs->rpkts = td - cs->rpkts;
+               cs->xmit_wait = te - cs->xmit_wait;
+       }
+       spin_unlock_irqrestore(&ibp->lock, flags);
+}
+
+/*
+ * Note that the caller has the ibp->lock held.
+ */
+static void qib_set_cntr_6120_sample(struct qib_pportdata *ppd, u32 intv,
+                                    u32 start)
+{
+       struct qib_chip_specific *cs = ppd->dd->cspec;
+
+       if (start && intv) {
+               cs->pma_sample_status = IB_PMA_SAMPLE_STATUS_STARTED;
+               mod_timer(&cs->pma_timer, jiffies + usecs_to_jiffies(start));
+       } else if (intv) {
+               cs->pma_sample_status = IB_PMA_SAMPLE_STATUS_RUNNING;
+               qib_snapshot_counters(ppd, &cs->sword, &cs->rword,
+                                     &cs->spkts, &cs->rpkts, &cs->xmit_wait);
+               mod_timer(&cs->pma_timer, jiffies + usecs_to_jiffies(intv));
+       } else {
+               cs->pma_sample_status = IB_PMA_SAMPLE_STATUS_DONE;
+               cs->sword = 0;
+               cs->rword = 0;
+               cs->spkts = 0;
+               cs->rpkts = 0;
+               cs->xmit_wait = 0;
+       }
+}
+
+static u32 qib_6120_iblink_state(u64 ibcs)
+{
+       u32 state = (u32)SYM_FIELD(ibcs, IBCStatus, LinkState);
+
+       switch (state) {
+       case IB_6120_L_STATE_INIT:
+               state = IB_PORT_INIT;
+               break;
+       case IB_6120_L_STATE_ARM:
+               state = IB_PORT_ARMED;
+               break;
+       case IB_6120_L_STATE_ACTIVE:
+               /* fall through */
+       case IB_6120_L_STATE_ACT_DEFER:
+               state = IB_PORT_ACTIVE;
+               break;
+       default: /* fall through */
+       case IB_6120_L_STATE_DOWN:
+               state = IB_PORT_DOWN;
+               break;
+       }
+       return state;
+}
+
+/* returns the IBTA port state, rather than the IBC link training state */
+static u8 qib_6120_phys_portstate(u64 ibcs)
+{
+       u8 state = (u8)SYM_FIELD(ibcs, IBCStatus, LinkTrainingState);
+       return qib_6120_physportstate[state];
+}
+
+static int qib_6120_ib_updown(struct qib_pportdata *ppd, int ibup, u64 ibcs)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ppd->lflags_lock, flags);
+       ppd->lflags &= ~QIBL_IB_FORCE_NOTIFY;
+       spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+
+       if (ibup) {
+               if (ppd->dd->cspec->ibdeltainprog) {
+                       ppd->dd->cspec->ibdeltainprog = 0;
+                       ppd->dd->cspec->ibsymdelta +=
+                               read_6120_creg32(ppd->dd, cr_ibsymbolerr) -
+                                       ppd->dd->cspec->ibsymsnap;
+                       ppd->dd->cspec->iblnkerrdelta +=
+                               read_6120_creg32(ppd->dd, cr_iblinkerrrecov) -
+                                       ppd->dd->cspec->iblnkerrsnap;
+               }
+               qib_hol_init(ppd);
+       } else {
+               ppd->dd->cspec->lli_counter = 0;
+               if (!ppd->dd->cspec->ibdeltainprog) {
+                       ppd->dd->cspec->ibdeltainprog = 1;
+                       ppd->dd->cspec->ibsymsnap =
+                               read_6120_creg32(ppd->dd, cr_ibsymbolerr);
+                       ppd->dd->cspec->iblnkerrsnap =
+                               read_6120_creg32(ppd->dd, cr_iblinkerrrecov);
+               }
+               qib_hol_down(ppd);
+       }
+
+       qib_6120_setup_setextled(ppd, ibup);
+
+       return 0;
+}
+
+/* Does read/modify/write to appropriate registers to
+ * set output and direction bits selected by mask.
+ * these are in their canonical postions (e.g. lsb of
+ * dir will end up in D48 of extctrl on existing chips).
+ * returns contents of GP Inputs.
+ */
+static int gpio_6120_mod(struct qib_devdata *dd, u32 out, u32 dir, u32 mask)
+{
+       u64 read_val, new_out;
+       unsigned long flags;
+
+       if (mask) {
+               /* some bits being written, lock access to GPIO */
+               dir &= mask;
+               out &= mask;
+               spin_lock_irqsave(&dd->cspec->gpio_lock, flags);
+               dd->cspec->extctrl &= ~((u64)mask << SYM_LSB(EXTCtrl, GPIOOe));
+               dd->cspec->extctrl |= ((u64) dir << SYM_LSB(EXTCtrl, GPIOOe));
+               new_out = (dd->cspec->gpio_out & ~mask) | out;
+
+               qib_write_kreg(dd, kr_extctrl, dd->cspec->extctrl);
+               qib_write_kreg(dd, kr_gpio_out, new_out);
+               dd->cspec->gpio_out = new_out;
+               spin_unlock_irqrestore(&dd->cspec->gpio_lock, flags);
+       }
+       /*
+        * It is unlikely that a read at this time would get valid
+        * data on a pin whose direction line was set in the same
+        * call to this function. We include the read here because
+        * that allows us to potentially combine a change on one pin with
+        * a read on another, and because the old code did something like
+        * this.
+        */
+       read_val = qib_read_kreg64(dd, kr_extstatus);
+       return SYM_FIELD(read_val, EXTStatus, GPIOIn);
+}
+
+/*
+ * Read fundamental info we need to use the chip.  These are
+ * the registers that describe chip capabilities, and are
+ * saved in shadow registers.
+ */
+static void get_6120_chip_params(struct qib_devdata *dd)
+{
+       u64 val;
+       u32 piobufs;
+       int mtu;
+
+       dd->uregbase = qib_read_kreg32(dd, kr_userregbase);
+
+       dd->rcvtidcnt = qib_read_kreg32(dd, kr_rcvtidcnt);
+       dd->rcvtidbase = qib_read_kreg32(dd, kr_rcvtidbase);
+       dd->rcvegrbase = qib_read_kreg32(dd, kr_rcvegrbase);
+       dd->palign = qib_read_kreg32(dd, kr_palign);
+       dd->piobufbase = qib_read_kreg64(dd, kr_sendpiobufbase);
+       dd->pio2k_bufbase = dd->piobufbase & 0xffffffff;
+
+       dd->rcvhdrcnt = qib_read_kreg32(dd, kr_rcvegrcnt);
+
+       val = qib_read_kreg64(dd, kr_sendpiosize);
+       dd->piosize2k = val & ~0U;
+       dd->piosize4k = val >> 32;
+
+       mtu = ib_mtu_enum_to_int(qib_ibmtu);
+       if (mtu == -1)
+               mtu = QIB_DEFAULT_MTU;
+       dd->pport->ibmtu = (u32)mtu;
+
+       val = qib_read_kreg64(dd, kr_sendpiobufcnt);
+       dd->piobcnt2k = val & ~0U;
+       dd->piobcnt4k = val >> 32;
+       /* these may be adjusted in init_chip_wc_pat() */
+       dd->pio2kbase = (u32 __iomem *)
+               (((char __iomem *)dd->kregbase) + dd->pio2k_bufbase);
+       if (dd->piobcnt4k) {
+               dd->pio4kbase = (u32 __iomem *)
+                       (((char __iomem *) dd->kregbase) +
+                        (dd->piobufbase >> 32));
+               /*
+                * 4K buffers take 2 pages; we use roundup just to be
+                * paranoid; we calculate it once here, rather than on
+                * ever buf allocate
+                */
+               dd->align4k = ALIGN(dd->piosize4k, dd->palign);
+       }
+
+       piobufs = dd->piobcnt4k + dd->piobcnt2k;
+
+       dd->pioavregs = ALIGN(piobufs, sizeof(u64) * BITS_PER_BYTE / 2) /
+               (sizeof(u64) * BITS_PER_BYTE / 2);
+}
+
+/*
+ * The chip base addresses in cspec and cpspec have to be set
+ * after possible init_chip_wc_pat(), rather than in
+ * get_6120_chip_params(), so split out as separate function
+ */
+static void set_6120_baseaddrs(struct qib_devdata *dd)
+{
+       u32 cregbase;
+       cregbase = qib_read_kreg32(dd, kr_counterregbase);
+       dd->cspec->cregbase = (u64 __iomem *)
+               ((char __iomem *) dd->kregbase + cregbase);
+
+       dd->egrtidbase = (u64 __iomem *)
+               ((char __iomem *) dd->kregbase + dd->rcvegrbase);
+}
+
+/*
+ * Write the final few registers that depend on some of the
+ * init setup.  Done late in init, just before bringing up
+ * the serdes.
+ */
+static int qib_late_6120_initreg(struct qib_devdata *dd)
+{
+       int ret = 0;
+       u64 val;
+
+       qib_write_kreg(dd, kr_rcvhdrentsize, dd->rcvhdrentsize);
+       qib_write_kreg(dd, kr_rcvhdrsize, dd->rcvhdrsize);
+       qib_write_kreg(dd, kr_rcvhdrcnt, dd->rcvhdrcnt);
+       qib_write_kreg(dd, kr_sendpioavailaddr, dd->pioavailregs_phys);
+       val = qib_read_kreg64(dd, kr_sendpioavailaddr);
+       if (val != dd->pioavailregs_phys) {
+               qib_dev_err(dd, "Catastrophic software error, "
+                           "SendPIOAvailAddr written as %lx, "
+                           "read back as %llx\n",
+                           (unsigned long) dd->pioavailregs_phys,
+                           (unsigned long long) val);
+               ret = -EINVAL;
+       }
+       return ret;
+}
+
+static int init_6120_variables(struct qib_devdata *dd)
+{
+       int ret = 0;
+       struct qib_pportdata *ppd;
+       u32 sbufs;
+
+       ppd = (struct qib_pportdata *)(dd + 1);
+       dd->pport = ppd;
+       dd->num_pports = 1;
+
+       dd->cspec = (struct qib_chip_specific *)(ppd + dd->num_pports);
+       ppd->cpspec = NULL; /* not used in this chip */
+
+       spin_lock_init(&dd->cspec->kernel_tid_lock);
+       spin_lock_init(&dd->cspec->user_tid_lock);
+       spin_lock_init(&dd->cspec->rcvmod_lock);
+       spin_lock_init(&dd->cspec->gpio_lock);
+
+       /* we haven't yet set QIB_PRESENT, so use read directly */
+       dd->revision = readq(&dd->kregbase[kr_revision]);
+
+       if ((dd->revision & 0xffffffffU) == 0xffffffffU) {
+               qib_dev_err(dd, "Revision register read failure, "
+                           "giving up initialization\n");
+               ret = -ENODEV;
+               goto bail;
+       }
+       dd->flags |= QIB_PRESENT;  /* now register routines work */
+
+       dd->majrev = (u8) SYM_FIELD(dd->revision, Revision_R,
+                                   ChipRevMajor);
+       dd->minrev = (u8) SYM_FIELD(dd->revision, Revision_R,
+                                   ChipRevMinor);
+
+       get_6120_chip_params(dd);
+       pe_boardname(dd); /* fill in boardname */
+
+       /*
+        * GPIO bits for TWSI data and clock,
+        * used for serial EEPROM.
+        */
+       dd->gpio_sda_num = _QIB_GPIO_SDA_NUM;
+       dd->gpio_scl_num = _QIB_GPIO_SCL_NUM;
+       dd->twsi_eeprom_dev = QIB_TWSI_NO_DEV;
+
+       if (qib_unordered_wc())
+               dd->flags |= QIB_PIO_FLUSH_WC;
+
+       /*
+        * EEPROM error log 0 is TXE Parity errors. 1 is RXE Parity.
+        * 2 is Some Misc, 3 is reserved for future.
+        */
+       dd->eep_st_masks[0].hwerrs_to_log = HWE_MASK(TXEMemParityErr);
+
+       /* Ignore errors in PIO/PBC on systems with unordered write-combining */
+       if (qib_unordered_wc())
+               dd->eep_st_masks[0].hwerrs_to_log &= ~TXE_PIO_PARITY;
+
+       dd->eep_st_masks[1].hwerrs_to_log = HWE_MASK(RXEMemParityErr);
+
+       dd->eep_st_masks[2].errs_to_log = ERR_MASK(ResetNegated);
+
+       qib_init_pportdata(ppd, dd, 0, 1);
+       ppd->link_width_supported = IB_WIDTH_1X | IB_WIDTH_4X;
+       ppd->link_speed_supported = QIB_IB_SDR;
+       ppd->link_width_enabled = IB_WIDTH_4X;
+       ppd->link_speed_enabled = ppd->link_speed_supported;
+       /* these can't change for this chip, so set once */
+       ppd->link_width_active = ppd->link_width_enabled;
+       ppd->link_speed_active = ppd->link_speed_enabled;
+       ppd->vls_supported = IB_VL_VL0;
+       ppd->vls_operational = ppd->vls_supported;
+
+       dd->rcvhdrentsize = QIB_RCVHDR_ENTSIZE;
+       dd->rcvhdrsize = QIB_DFLT_RCVHDRSIZE;
+       dd->rhf_offset = 0;
+
+       /* we always allocate at least 2048 bytes for eager buffers */
+       ret = ib_mtu_enum_to_int(qib_ibmtu);
+       dd->rcvegrbufsize = ret != -1 ? max(ret, 2048) : QIB_DEFAULT_MTU;
+
+       qib_6120_tidtemplate(dd);
+
+       /*
+        * We can request a receive interrupt for 1 or
+        * more packets from current offset.  For now, we set this
+        * up for a single packet.
+        */
+       dd->rhdrhead_intr_off = 1ULL << 32;
+
+       /* setup the stats timer; the add_timer is done at end of init */
+       init_timer(&dd->stats_timer);
+       dd->stats_timer.function = qib_get_6120_faststats;
+       dd->stats_timer.data = (unsigned long) dd;
+
+       init_timer(&dd->cspec->pma_timer);
+       dd->cspec->pma_timer.function = pma_6120_timer;
+       dd->cspec->pma_timer.data = (unsigned long) ppd;
+
+       dd->ureg_align = qib_read_kreg32(dd, kr_palign);
+
+       dd->piosize2kmax_dwords = dd->piosize2k >> 2;
+       qib_6120_config_ctxts(dd);
+       qib_set_ctxtcnt(dd);
+
+       if (qib_wc_pat) {
+               ret = init_chip_wc_pat(dd, 0);
+               if (ret)
+                       goto bail;
+       }
+       set_6120_baseaddrs(dd); /* set chip access pointers now */
+
+       ret = 0;
+       if (qib_mini_init)
+               goto bail;
+
+       qib_num_cfg_vls = 1; /* if any 6120's, only one VL */
+
+       ret = qib_create_ctxts(dd);
+       init_6120_cntrnames(dd);
+
+       /* use all of 4KB buffers for the kernel, otherwise 16 */
+       sbufs = dd->piobcnt4k ?  dd->piobcnt4k : 16;
+
+       dd->lastctxt_piobuf = dd->piobcnt2k + dd->piobcnt4k - sbufs;
+       dd->pbufsctxt = dd->lastctxt_piobuf /
+               (dd->cfgctxts - dd->first_user_ctxt);
+
+       if (ret)
+               goto bail;
+bail:
+       return ret;
+}
+
+/*
+ * For this chip, we want to use the same buffer every time
+ * when we are trying to bring the link up (they are always VL15
+ * packets).  At that link state the packet should always go out immediately
+ * (or at least be discarded at the tx interface if the link is down).
+ * If it doesn't, and the buffer isn't available, that means some other
+ * sender has gotten ahead of us, and is preventing our packet from going
+ * out.  In that case, we flush all packets, and try again.  If that still
+ * fails, we fail the request, and hope things work the next time around.
+ *
+ * We don't need very complicated heuristics on whether the packet had
+ * time to go out or not, since even at SDR 1X, it goes out in very short
+ * time periods, covered by the chip reads done here and as part of the
+ * flush.
+ */
+static u32 __iomem *get_6120_link_buf(struct qib_pportdata *ppd, u32 *bnum)
+{
+       u32 __iomem *buf;
+       u32 lbuf = ppd->dd->piobcnt2k + ppd->dd->piobcnt4k - 1;
+
+       /*
+        * always blip to get avail list updated, since it's almost
+        * always needed, and is fairly cheap.
+        */
+       sendctrl_6120_mod(ppd->dd->pport, QIB_SENDCTRL_AVAIL_BLIP);
+       qib_read_kreg64(ppd->dd, kr_scratch); /* extra chip flush */
+       buf = qib_getsendbuf_range(ppd->dd, bnum, lbuf, lbuf);
+       if (buf)
+               goto done;
+
+       sendctrl_6120_mod(ppd, QIB_SENDCTRL_DISARM_ALL | QIB_SENDCTRL_FLUSH |
+                         QIB_SENDCTRL_AVAIL_BLIP);
+       ppd->dd->upd_pio_shadow  = 1; /* update our idea of what's busy */
+       qib_read_kreg64(ppd->dd, kr_scratch); /* extra chip flush */
+       buf = qib_getsendbuf_range(ppd->dd, bnum, lbuf, lbuf);
+done:
+       return buf;
+}
+
+static u32 __iomem *qib_6120_getsendbuf(struct qib_pportdata *ppd, u64 pbc,
+                                       u32 *pbufnum)
+{
+       u32 first, last, plen = pbc & QIB_PBC_LENGTH_MASK;
+       struct qib_devdata *dd = ppd->dd;
+       u32 __iomem *buf;
+
+       if (((pbc >> 32) & PBC_6120_VL15_SEND_CTRL) &&
+               !(ppd->lflags & (QIBL_IB_AUTONEG_INPROG | QIBL_LINKACTIVE)))
+               buf = get_6120_link_buf(ppd, pbufnum);
+       else {
+
+               if ((plen + 1) > dd->piosize2kmax_dwords)
+                       first = dd->piobcnt2k;
+               else
+                       first = 0;
+               /* try 4k if all 2k busy, so same last for both sizes */
+               last = dd->piobcnt2k + dd->piobcnt4k - 1;
+               buf = qib_getsendbuf_range(dd, pbufnum, first, last);
+       }
+       return buf;
+}
+
+static int init_sdma_6120_regs(struct qib_pportdata *ppd)
+{
+       return -ENODEV;
+}
+
+static u16 qib_sdma_6120_gethead(struct qib_pportdata *ppd)
+{
+       return 0;
+}
+
+static int qib_sdma_6120_busy(struct qib_pportdata *ppd)
+{
+       return 0;
+}
+
+static void qib_sdma_update_6120_tail(struct qib_pportdata *ppd, u16 tail)
+{
+}
+
+static void qib_6120_sdma_sendctrl(struct qib_pportdata *ppd, unsigned op)
+{
+}
+
+static void qib_sdma_set_6120_desc_cnt(struct qib_pportdata *ppd, unsigned cnt)
+{
+}
+
+/*
+ * the pbc doesn't need a VL15 indicator, but we need it for link_buf.
+ * The chip ignores the bit if set.
+ */
+static u32 qib_6120_setpbc_control(struct qib_pportdata *ppd, u32 plen,
+                                  u8 srate, u8 vl)
+{
+       return vl == 15 ? PBC_6120_VL15_SEND_CTRL : 0;
+}
+
+static void qib_6120_initvl15_bufs(struct qib_devdata *dd)
+{
+}
+
+static void qib_6120_init_ctxt(struct qib_ctxtdata *rcd)
+{
+       rcd->rcvegrcnt = rcd->dd->rcvhdrcnt;
+       rcd->rcvegr_tid_base = rcd->ctxt * rcd->rcvegrcnt;
+}
+
+static void qib_6120_txchk_change(struct qib_devdata *dd, u32 start,
+       u32 len, u32 avail, struct qib_ctxtdata *rcd)
+{
+}
+
+static void writescratch(struct qib_devdata *dd, u32 val)
+{
+       (void) qib_write_kreg(dd, kr_scratch, val);
+}
+
+static int qib_6120_tempsense_rd(struct qib_devdata *dd, int regnum)
+{
+       return -ENXIO;
+}
+
+/* Dummy function, as 6120 boards never disable EEPROM Write */
+static int qib_6120_eeprom_wen(struct qib_devdata *dd, int wen)
+{
+       return 1;
+}
+
+/**
+ * qib_init_iba6120_funcs - set up the chip-specific function pointers
+ * @pdev: pci_dev of the qlogic_ib device
+ * @ent: pci_device_id matching this chip
+ *
+ * This is global, and is called directly at init to set up the
+ * chip-specific function pointers for later use.
+ *
+ * It also allocates/partially-inits the qib_devdata struct for
+ * this device.
+ */
+struct qib_devdata *qib_init_iba6120_funcs(struct pci_dev *pdev,
+                                          const struct pci_device_id *ent)
+{
+       struct qib_devdata *dd;
+       int ret;
+
+       dd = qib_alloc_devdata(pdev, sizeof(struct qib_pportdata) +
+                              sizeof(struct qib_chip_specific));
+       if (IS_ERR(dd))
+               goto bail;
+
+       dd->f_bringup_serdes    = qib_6120_bringup_serdes;
+       dd->f_cleanup           = qib_6120_setup_cleanup;
+       dd->f_clear_tids        = qib_6120_clear_tids;
+       dd->f_free_irq          = qib_6120_free_irq;
+       dd->f_get_base_info     = qib_6120_get_base_info;
+       dd->f_get_msgheader     = qib_6120_get_msgheader;
+       dd->f_getsendbuf        = qib_6120_getsendbuf;
+       dd->f_gpio_mod          = gpio_6120_mod;
+       dd->f_eeprom_wen        = qib_6120_eeprom_wen;
+       dd->f_hdrqempty         = qib_6120_hdrqempty;
+       dd->f_ib_updown         = qib_6120_ib_updown;
+       dd->f_init_ctxt         = qib_6120_init_ctxt;
+       dd->f_initvl15_bufs     = qib_6120_initvl15_bufs;
+       dd->f_intr_fallback     = qib_6120_nointr_fallback;
+       dd->f_late_initreg      = qib_late_6120_initreg;
+       dd->f_setpbc_control    = qib_6120_setpbc_control;
+       dd->f_portcntr          = qib_portcntr_6120;
+       dd->f_put_tid           = (dd->minrev >= 2) ?
+                                     qib_6120_put_tid_2 :
+                                     qib_6120_put_tid;
+       dd->f_quiet_serdes      = qib_6120_quiet_serdes;
+       dd->f_rcvctrl           = rcvctrl_6120_mod;
+       dd->f_read_cntrs        = qib_read_6120cntrs;
+       dd->f_read_portcntrs    = qib_read_6120portcntrs;
+       dd->f_reset             = qib_6120_setup_reset;
+       dd->f_init_sdma_regs    = init_sdma_6120_regs;
+       dd->f_sdma_busy         = qib_sdma_6120_busy;
+       dd->f_sdma_gethead      = qib_sdma_6120_gethead;
+       dd->f_sdma_sendctrl     = qib_6120_sdma_sendctrl;
+       dd->f_sdma_set_desc_cnt = qib_sdma_set_6120_desc_cnt;
+       dd->f_sdma_update_tail  = qib_sdma_update_6120_tail;
+       dd->f_sendctrl          = sendctrl_6120_mod;
+       dd->f_set_armlaunch     = qib_set_6120_armlaunch;
+       dd->f_set_cntr_sample   = qib_set_cntr_6120_sample;
+       dd->f_iblink_state      = qib_6120_iblink_state;
+       dd->f_ibphys_portstate  = qib_6120_phys_portstate;
+       dd->f_get_ib_cfg        = qib_6120_get_ib_cfg;
+       dd->f_set_ib_cfg        = qib_6120_set_ib_cfg;
+       dd->f_set_ib_loopback   = qib_6120_set_loopback;
+       dd->f_set_intr_state    = qib_6120_set_intr_state;
+       dd->f_setextled         = qib_6120_setup_setextled;
+       dd->f_txchk_change      = qib_6120_txchk_change;
+       dd->f_update_usrhead    = qib_update_6120_usrhead;
+       dd->f_wantpiobuf_intr   = qib_wantpiobuf_6120_intr;
+       dd->f_xgxs_reset        = qib_6120_xgxs_reset;
+       dd->f_writescratch      = writescratch;
+       dd->f_tempsense_rd      = qib_6120_tempsense_rd;
+       /*
+        * Do remaining pcie setup and save pcie values in dd.
+        * Any error printing is already done by the init code.
+        * On return, we have the chip mapped and accessible,
+        * but chip registers are not set up until start of
+        * init_6120_variables.
+        */
+       ret = qib_pcie_ddinit(dd, pdev, ent);
+       if (ret < 0)
+               goto bail_free;
+
+       /* initialize chip-specific variables */
+       ret = init_6120_variables(dd);
+       if (ret)
+               goto bail_cleanup;
+
+       if (qib_mini_init)
+               goto bail;
+
+       if (qib_pcie_params(dd, 8, NULL, NULL))
+               qib_dev_err(dd, "Failed to setup PCIe or interrupts; "
+                           "continuing anyway\n");
+       dd->cspec->irq = pdev->irq; /* save IRQ */
+
+       /* clear diagctrl register, in case diags were running and crashed */
+       qib_write_kreg(dd, kr_hwdiagctrl, 0);
+
+       if (qib_read_kreg64(dd, kr_hwerrstatus) &
+           QLOGIC_IB_HWE_SERDESPLLFAILED)
+               qib_write_kreg(dd, kr_hwerrclear,
+                              QLOGIC_IB_HWE_SERDESPLLFAILED);
+
+       /* setup interrupt handler (interrupt type handled above) */
+       qib_setup_6120_interrupt(dd);
+       /* Note that qpn_mask is set by qib_6120_config_ctxts() first */
+       qib_6120_init_hwerrors(dd);
+
+       goto bail;
+
+bail_cleanup:
+       qib_pcie_ddcleanup(dd);
+bail_free:
+       qib_free_devdata(dd);
+       dd = ERR_PTR(ret);
+bail:
+       return dd;
+}
diff --git a/drivers/infiniband/hw/qib/qib_iba7220.c b/drivers/infiniband/hw/qib/qib_iba7220.c
new file mode 100644 (file)
index 0000000..6fd8d74
--- /dev/null
@@ -0,0 +1,4618 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009, 2010 QLogic Corporation.
+ * All rights reserved.
+ * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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.
+ */
+/*
+ * This file contains all of the code that is specific to the
+ * QLogic_IB 7220 chip (except that specific to the SerDes)
+ */
+
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <rdma/ib_verbs.h>
+
+#include "qib.h"
+#include "qib_7220.h"
+
+static void qib_setup_7220_setextled(struct qib_pportdata *, u32);
+static void qib_7220_handle_hwerrors(struct qib_devdata *, char *, size_t);
+static void sendctrl_7220_mod(struct qib_pportdata *ppd, u32 op);
+static u32 qib_7220_iblink_state(u64);
+static u8 qib_7220_phys_portstate(u64);
+static void qib_sdma_update_7220_tail(struct qib_pportdata *, u16);
+static void qib_set_ib_7220_lstate(struct qib_pportdata *, u16, u16);
+
+/*
+ * This file contains almost all the chip-specific register information and
+ * access functions for the QLogic QLogic_IB 7220 PCI-Express chip, with the
+ * exception of SerDes support, which in in qib_sd7220.c.
+ */
+
+/* Below uses machine-generated qib_chipnum_regs.h file */
+#define KREG_IDX(regname) (QIB_7220_##regname##_OFFS / sizeof(u64))
+
+/* Use defines to tie machine-generated names to lower-case names */
+#define kr_control KREG_IDX(Control)
+#define kr_counterregbase KREG_IDX(CntrRegBase)
+#define kr_errclear KREG_IDX(ErrClear)
+#define kr_errmask KREG_IDX(ErrMask)
+#define kr_errstatus KREG_IDX(ErrStatus)
+#define kr_extctrl KREG_IDX(EXTCtrl)
+#define kr_extstatus KREG_IDX(EXTStatus)
+#define kr_gpio_clear KREG_IDX(GPIOClear)
+#define kr_gpio_mask KREG_IDX(GPIOMask)
+#define kr_gpio_out KREG_IDX(GPIOOut)
+#define kr_gpio_status KREG_IDX(GPIOStatus)
+#define kr_hrtbt_guid KREG_IDX(HRTBT_GUID)
+#define kr_hwdiagctrl KREG_IDX(HwDiagCtrl)
+#define kr_hwerrclear KREG_IDX(HwErrClear)
+#define kr_hwerrmask KREG_IDX(HwErrMask)
+#define kr_hwerrstatus KREG_IDX(HwErrStatus)
+#define kr_ibcctrl KREG_IDX(IBCCtrl)
+#define kr_ibcddrctrl KREG_IDX(IBCDDRCtrl)
+#define kr_ibcddrstatus KREG_IDX(IBCDDRStatus)
+#define kr_ibcstatus KREG_IDX(IBCStatus)
+#define kr_ibserdesctrl KREG_IDX(IBSerDesCtrl)
+#define kr_intclear KREG_IDX(IntClear)
+#define kr_intmask KREG_IDX(IntMask)
+#define kr_intstatus KREG_IDX(IntStatus)
+#define kr_ncmodectrl KREG_IDX(IBNCModeCtrl)
+#define kr_palign KREG_IDX(PageAlign)
+#define kr_partitionkey KREG_IDX(RcvPartitionKey)
+#define kr_portcnt KREG_IDX(PortCnt)
+#define kr_rcvbthqp KREG_IDX(RcvBTHQP)
+#define kr_rcvctrl KREG_IDX(RcvCtrl)
+#define kr_rcvegrbase KREG_IDX(RcvEgrBase)
+#define kr_rcvegrcnt KREG_IDX(RcvEgrCnt)
+#define kr_rcvhdrcnt KREG_IDX(RcvHdrCnt)
+#define kr_rcvhdrentsize KREG_IDX(RcvHdrEntSize)
+#define kr_rcvhdrsize KREG_IDX(RcvHdrSize)
+#define kr_rcvpktledcnt KREG_IDX(RcvPktLEDCnt)
+#define kr_rcvtidbase KREG_IDX(RcvTIDBase)
+#define kr_rcvtidcnt KREG_IDX(RcvTIDCnt)
+#define kr_revision KREG_IDX(Revision)
+#define kr_scratch KREG_IDX(Scratch)
+#define kr_sendbuffererror KREG_IDX(SendBufErr0)
+#define kr_sendctrl KREG_IDX(SendCtrl)
+#define kr_senddmabase KREG_IDX(SendDmaBase)
+#define kr_senddmabufmask0 KREG_IDX(SendDmaBufMask0)
+#define kr_senddmabufmask1 (KREG_IDX(SendDmaBufMask0) + 1)
+#define kr_senddmabufmask2 (KREG_IDX(SendDmaBufMask0) + 2)
+#define kr_senddmahead KREG_IDX(SendDmaHead)
+#define kr_senddmaheadaddr KREG_IDX(SendDmaHeadAddr)
+#define kr_senddmalengen KREG_IDX(SendDmaLenGen)
+#define kr_senddmastatus KREG_IDX(SendDmaStatus)
+#define kr_senddmatail KREG_IDX(SendDmaTail)
+#define kr_sendpioavailaddr KREG_IDX(SendBufAvailAddr)
+#define kr_sendpiobufbase KREG_IDX(SendBufBase)
+#define kr_sendpiobufcnt KREG_IDX(SendBufCnt)
+#define kr_sendpiosize KREG_IDX(SendBufSize)
+#define kr_sendregbase KREG_IDX(SendRegBase)
+#define kr_userregbase KREG_IDX(UserRegBase)
+#define kr_xgxs_cfg KREG_IDX(XGXSCfg)
+
+/* These must only be written via qib_write_kreg_ctxt() */
+#define kr_rcvhdraddr KREG_IDX(RcvHdrAddr0)
+#define kr_rcvhdrtailaddr KREG_IDX(RcvHdrTailAddr0)
+
+
+#define CREG_IDX(regname) ((QIB_7220_##regname##_OFFS - \
+                       QIB_7220_LBIntCnt_OFFS) / sizeof(u64))
+
+#define cr_badformat CREG_IDX(RxVersionErrCnt)
+#define cr_erricrc CREG_IDX(RxICRCErrCnt)
+#define cr_errlink CREG_IDX(RxLinkMalformCnt)
+#define cr_errlpcrc CREG_IDX(RxLPCRCErrCnt)
+#define cr_errpkey CREG_IDX(RxPKeyMismatchCnt)
+#define cr_rcvflowctrl_err CREG_IDX(RxFlowCtrlViolCnt)
+#define cr_err_rlen CREG_IDX(RxLenErrCnt)
+#define cr_errslen CREG_IDX(TxLenErrCnt)
+#define cr_errtidfull CREG_IDX(RxTIDFullErrCnt)
+#define cr_errtidvalid CREG_IDX(RxTIDValidErrCnt)
+#define cr_errvcrc CREG_IDX(RxVCRCErrCnt)
+#define cr_ibstatuschange CREG_IDX(IBStatusChangeCnt)
+#define cr_lbint CREG_IDX(LBIntCnt)
+#define cr_invalidrlen CREG_IDX(RxMaxMinLenErrCnt)
+#define cr_invalidslen CREG_IDX(TxMaxMinLenErrCnt)
+#define cr_lbflowstall CREG_IDX(LBFlowStallCnt)
+#define cr_pktrcv CREG_IDX(RxDataPktCnt)
+#define cr_pktrcvflowctrl CREG_IDX(RxFlowPktCnt)
+#define cr_pktsend CREG_IDX(TxDataPktCnt)
+#define cr_pktsendflow CREG_IDX(TxFlowPktCnt)
+#define cr_portovfl CREG_IDX(RxP0HdrEgrOvflCnt)
+#define cr_rcvebp CREG_IDX(RxEBPCnt)
+#define cr_rcvovfl CREG_IDX(RxBufOvflCnt)
+#define cr_senddropped CREG_IDX(TxDroppedPktCnt)
+#define cr_sendstall CREG_IDX(TxFlowStallCnt)
+#define cr_sendunderrun CREG_IDX(TxUnderrunCnt)
+#define cr_wordrcv CREG_IDX(RxDwordCnt)
+#define cr_wordsend CREG_IDX(TxDwordCnt)
+#define cr_txunsupvl CREG_IDX(TxUnsupVLErrCnt)
+#define cr_rxdroppkt CREG_IDX(RxDroppedPktCnt)
+#define cr_iblinkerrrecov CREG_IDX(IBLinkErrRecoveryCnt)
+#define cr_iblinkdown CREG_IDX(IBLinkDownedCnt)
+#define cr_ibsymbolerr CREG_IDX(IBSymbolErrCnt)
+#define cr_vl15droppedpkt CREG_IDX(RxVL15DroppedPktCnt)
+#define cr_rxotherlocalphyerr CREG_IDX(RxOtherLocalPhyErrCnt)
+#define cr_excessbufferovfl CREG_IDX(ExcessBufferOvflCnt)
+#define cr_locallinkintegrityerr CREG_IDX(LocalLinkIntegrityErrCnt)
+#define cr_rxvlerr CREG_IDX(RxVlErrCnt)
+#define cr_rxdlidfltr CREG_IDX(RxDlidFltrCnt)
+#define cr_psstat CREG_IDX(PSStat)
+#define cr_psstart CREG_IDX(PSStart)
+#define cr_psinterval CREG_IDX(PSInterval)
+#define cr_psrcvdatacount CREG_IDX(PSRcvDataCount)
+#define cr_psrcvpktscount CREG_IDX(PSRcvPktsCount)
+#define cr_psxmitdatacount CREG_IDX(PSXmitDataCount)
+#define cr_psxmitpktscount CREG_IDX(PSXmitPktsCount)
+#define cr_psxmitwaitcount CREG_IDX(PSXmitWaitCount)
+#define cr_txsdmadesc CREG_IDX(TxSDmaDescCnt)
+#define cr_pcieretrydiag CREG_IDX(PcieRetryBufDiagQwordCnt)
+
+#define SYM_RMASK(regname, fldname) ((u64)              \
+       QIB_7220_##regname##_##fldname##_RMASK)
+#define SYM_MASK(regname, fldname) ((u64)               \
+       QIB_7220_##regname##_##fldname##_RMASK <<       \
+        QIB_7220_##regname##_##fldname##_LSB)
+#define SYM_LSB(regname, fldname) (QIB_7220_##regname##_##fldname##_LSB)
+#define SYM_FIELD(value, regname, fldname) ((u64) \
+       (((value) >> SYM_LSB(regname, fldname)) & \
+        SYM_RMASK(regname, fldname)))
+#define ERR_MASK(fldname) SYM_MASK(ErrMask, fldname##Mask)
+#define HWE_MASK(fldname) SYM_MASK(HwErrMask, fldname##Mask)
+
+/* ibcctrl bits */
+#define QLOGIC_IB_IBCC_LINKINITCMD_DISABLE 1
+/* cycle through TS1/TS2 till OK */
+#define QLOGIC_IB_IBCC_LINKINITCMD_POLL 2
+/* wait for TS1, then go on */
+#define QLOGIC_IB_IBCC_LINKINITCMD_SLEEP 3
+#define QLOGIC_IB_IBCC_LINKINITCMD_SHIFT 16
+
+#define QLOGIC_IB_IBCC_LINKCMD_DOWN 1           /* move to 0x11 */
+#define QLOGIC_IB_IBCC_LINKCMD_ARMED 2          /* move to 0x21 */
+#define QLOGIC_IB_IBCC_LINKCMD_ACTIVE 3 /* move to 0x31 */
+
+#define BLOB_7220_IBCHG 0x81
+
+/*
+ * We could have a single register get/put routine, that takes a group type,
+ * but this is somewhat clearer and cleaner.  It also gives us some error
+ * checking.  64 bit register reads should always work, but are inefficient
+ * on opteron (the northbridge always generates 2 separate HT 32 bit reads),
+ * so we use kreg32 wherever possible.  User register and counter register
+ * reads are always 32 bit reads, so only one form of those routines.
+ */
+
+/**
+ * qib_read_ureg32 - read 32-bit virtualized per-context register
+ * @dd: device
+ * @regno: register number
+ * @ctxt: context number
+ *
+ * Return the contents of a register that is virtualized to be per context.
+ * Returns -1 on errors (not distinguishable from valid contents at
+ * runtime; we may add a separate error variable at some point).
+ */
+static inline u32 qib_read_ureg32(const struct qib_devdata *dd,
+                                 enum qib_ureg regno, int ctxt)
+{
+       if (!dd->kregbase || !(dd->flags & QIB_PRESENT))
+               return 0;
+
+       if (dd->userbase)
+               return readl(regno + (u64 __iomem *)
+                            ((char __iomem *)dd->userbase +
+                             dd->ureg_align * ctxt));
+       else
+               return readl(regno + (u64 __iomem *)
+                            (dd->uregbase +
+                             (char __iomem *)dd->kregbase +
+                             dd->ureg_align * ctxt));
+}
+
+/**
+ * qib_write_ureg - write 32-bit virtualized per-context register
+ * @dd: device
+ * @regno: register number
+ * @value: value
+ * @ctxt: context
+ *
+ * Write the contents of a register that is virtualized to be per context.
+ */
+static inline void qib_write_ureg(const struct qib_devdata *dd,
+                                 enum qib_ureg regno, u64 value, int ctxt)
+{
+       u64 __iomem *ubase;
+
+       if (dd->userbase)
+               ubase = (u64 __iomem *)
+                       ((char __iomem *) dd->userbase +
+                        dd->ureg_align * ctxt);
+       else
+               ubase = (u64 __iomem *)
+                       (dd->uregbase +
+                        (char __iomem *) dd->kregbase +
+                        dd->ureg_align * ctxt);
+
+       if (dd->kregbase && (dd->flags & QIB_PRESENT))
+               writeq(value, &ubase[regno]);
+}
+
+/**
+ * qib_write_kreg_ctxt - write a device's per-ctxt 64-bit kernel register
+ * @dd: the qlogic_ib device
+ * @regno: the register number to write
+ * @ctxt: the context containing the register
+ * @value: the value to write
+ */
+static inline void qib_write_kreg_ctxt(const struct qib_devdata *dd,
+                                      const u16 regno, unsigned ctxt,
+                                      u64 value)
+{
+       qib_write_kreg(dd, regno + ctxt, value);
+}
+
+static inline void write_7220_creg(const struct qib_devdata *dd,
+                                  u16 regno, u64 value)
+{
+       if (dd->cspec->cregbase && (dd->flags & QIB_PRESENT))
+               writeq(value, &dd->cspec->cregbase[regno]);
+}
+
+static inline u64 read_7220_creg(const struct qib_devdata *dd, u16 regno)
+{
+       if (!dd->cspec->cregbase || !(dd->flags & QIB_PRESENT))
+               return 0;
+       return readq(&dd->cspec->cregbase[regno]);
+}
+
+static inline u32 read_7220_creg32(const struct qib_devdata *dd, u16 regno)
+{
+       if (!dd->cspec->cregbase || !(dd->flags & QIB_PRESENT))
+               return 0;
+       return readl(&dd->cspec->cregbase[regno]);
+}
+
+/* kr_revision bits */
+#define QLOGIC_IB_R_EMULATORREV_MASK ((1ULL << 22) - 1)
+#define QLOGIC_IB_R_EMULATORREV_SHIFT 40
+
+/* kr_control bits */
+#define QLOGIC_IB_C_RESET (1U << 7)
+
+/* kr_intstatus, kr_intclear, kr_intmask bits */
+#define QLOGIC_IB_I_RCVURG_MASK ((1ULL << 17) - 1)
+#define QLOGIC_IB_I_RCVURG_SHIFT 32
+#define QLOGIC_IB_I_RCVAVAIL_MASK ((1ULL << 17) - 1)
+#define QLOGIC_IB_I_RCVAVAIL_SHIFT 0
+#define QLOGIC_IB_I_SERDESTRIMDONE (1ULL << 27)
+
+#define QLOGIC_IB_C_FREEZEMODE 0x00000002
+#define QLOGIC_IB_C_LINKENABLE 0x00000004
+
+#define QLOGIC_IB_I_SDMAINT             0x8000000000000000ULL
+#define QLOGIC_IB_I_SDMADISABLED        0x4000000000000000ULL
+#define QLOGIC_IB_I_ERROR               0x0000000080000000ULL
+#define QLOGIC_IB_I_SPIOSENT            0x0000000040000000ULL
+#define QLOGIC_IB_I_SPIOBUFAVAIL        0x0000000020000000ULL
+#define QLOGIC_IB_I_GPIO                0x0000000010000000ULL
+
+/* variables for sanity checking interrupt and errors */
+#define QLOGIC_IB_I_BITSEXTANT \
+               (QLOGIC_IB_I_SDMAINT | QLOGIC_IB_I_SDMADISABLED | \
+               (QLOGIC_IB_I_RCVURG_MASK << QLOGIC_IB_I_RCVURG_SHIFT) | \
+               (QLOGIC_IB_I_RCVAVAIL_MASK << \
+                QLOGIC_IB_I_RCVAVAIL_SHIFT) | \
+               QLOGIC_IB_I_ERROR | QLOGIC_IB_I_SPIOSENT | \
+               QLOGIC_IB_I_SPIOBUFAVAIL | QLOGIC_IB_I_GPIO | \
+               QLOGIC_IB_I_SERDESTRIMDONE)
+
+#define IB_HWE_BITSEXTANT \
+              (HWE_MASK(RXEMemParityErr) | \
+               HWE_MASK(TXEMemParityErr) | \
+               (QLOGIC_IB_HWE_PCIEMEMPARITYERR_MASK <<  \
+                QLOGIC_IB_HWE_PCIEMEMPARITYERR_SHIFT) | \
+               QLOGIC_IB_HWE_PCIE1PLLFAILED | \
+               QLOGIC_IB_HWE_PCIE0PLLFAILED | \
+               QLOGIC_IB_HWE_PCIEPOISONEDTLP | \
+               QLOGIC_IB_HWE_PCIECPLTIMEOUT | \
+               QLOGIC_IB_HWE_PCIEBUSPARITYXTLH | \
+               QLOGIC_IB_HWE_PCIEBUSPARITYXADM | \
+               QLOGIC_IB_HWE_PCIEBUSPARITYRADM | \
+               HWE_MASK(PowerOnBISTFailed) |     \
+               QLOGIC_IB_HWE_COREPLL_FBSLIP | \
+               QLOGIC_IB_HWE_COREPLL_RFSLIP | \
+               QLOGIC_IB_HWE_SERDESPLLFAILED | \
+               HWE_MASK(IBCBusToSPCParityErr) | \
+               HWE_MASK(IBCBusFromSPCParityErr) | \
+               QLOGIC_IB_HWE_PCIECPLDATAQUEUEERR | \
+               QLOGIC_IB_HWE_PCIECPLHDRQUEUEERR | \
+               QLOGIC_IB_HWE_SDMAMEMREADERR | \
+               QLOGIC_IB_HWE_CLK_UC_PLLNOTLOCKED | \
+               QLOGIC_IB_HWE_PCIESERDESQ0PCLKNOTDETECT | \
+               QLOGIC_IB_HWE_PCIESERDESQ1PCLKNOTDETECT | \
+               QLOGIC_IB_HWE_PCIESERDESQ2PCLKNOTDETECT | \
+               QLOGIC_IB_HWE_PCIESERDESQ3PCLKNOTDETECT | \
+               QLOGIC_IB_HWE_DDSRXEQMEMORYPARITYERR | \
+               QLOGIC_IB_HWE_IB_UC_MEMORYPARITYERR | \
+               QLOGIC_IB_HWE_PCIE_UC_OCT0MEMORYPARITYERR | \
+               QLOGIC_IB_HWE_PCIE_UC_OCT1MEMORYPARITYERR)
+
+#define IB_E_BITSEXTANT                                                        \
+       (ERR_MASK(RcvFormatErr) | ERR_MASK(RcvVCRCErr) |                \
+        ERR_MASK(RcvICRCErr) | ERR_MASK(RcvMinPktLenErr) |             \
+        ERR_MASK(RcvMaxPktLenErr) | ERR_MASK(RcvLongPktLenErr) |       \
+        ERR_MASK(RcvShortPktLenErr) | ERR_MASK(RcvUnexpectedCharErr) | \
+        ERR_MASK(RcvUnsupportedVLErr) | ERR_MASK(RcvEBPErr) |          \
+        ERR_MASK(RcvIBFlowErr) | ERR_MASK(RcvBadVersionErr) |          \
+        ERR_MASK(RcvEgrFullErr) | ERR_MASK(RcvHdrFullErr) |            \
+        ERR_MASK(RcvBadTidErr) | ERR_MASK(RcvHdrLenErr) |              \
+        ERR_MASK(RcvHdrErr) | ERR_MASK(RcvIBLostLinkErr) |             \
+        ERR_MASK(SendSpecialTriggerErr) |                              \
+        ERR_MASK(SDmaDisabledErr) | ERR_MASK(SendMinPktLenErr) |       \
+        ERR_MASK(SendMaxPktLenErr) | ERR_MASK(SendUnderRunErr) |       \
+        ERR_MASK(SendPktLenErr) | ERR_MASK(SendDroppedSmpPktErr) |     \
+        ERR_MASK(SendDroppedDataPktErr) |                              \
+        ERR_MASK(SendPioArmLaunchErr) |                                \
+        ERR_MASK(SendUnexpectedPktNumErr) |                            \
+        ERR_MASK(SendUnsupportedVLErr) | ERR_MASK(SendBufMisuseErr) |  \
+        ERR_MASK(SDmaGenMismatchErr) | ERR_MASK(SDmaOutOfBoundErr) |   \
+        ERR_MASK(SDmaTailOutOfBoundErr) | ERR_MASK(SDmaBaseErr) |      \
+        ERR_MASK(SDma1stDescErr) | ERR_MASK(SDmaRpyTagErr) |           \
+        ERR_MASK(SDmaDwEnErr) | ERR_MASK(SDmaMissingDwErr) |           \
+        ERR_MASK(SDmaUnexpDataErr) |                                   \
+        ERR_MASK(IBStatusChanged) | ERR_MASK(InvalidAddrErr) |         \
+        ERR_MASK(ResetNegated) | ERR_MASK(HardwareErr) |               \
+        ERR_MASK(SDmaDescAddrMisalignErr) |                            \
+        ERR_MASK(InvalidEEPCmd))
+
+/* kr_hwerrclear, kr_hwerrmask, kr_hwerrstatus, bits */
+#define QLOGIC_IB_HWE_PCIEMEMPARITYERR_MASK  0x00000000000000ffULL
+#define QLOGIC_IB_HWE_PCIEMEMPARITYERR_SHIFT 0
+#define QLOGIC_IB_HWE_PCIEPOISONEDTLP      0x0000000010000000ULL
+#define QLOGIC_IB_HWE_PCIECPLTIMEOUT       0x0000000020000000ULL
+#define QLOGIC_IB_HWE_PCIEBUSPARITYXTLH    0x0000000040000000ULL
+#define QLOGIC_IB_HWE_PCIEBUSPARITYXADM    0x0000000080000000ULL
+#define QLOGIC_IB_HWE_PCIEBUSPARITYRADM    0x0000000100000000ULL
+#define QLOGIC_IB_HWE_COREPLL_FBSLIP       0x0080000000000000ULL
+#define QLOGIC_IB_HWE_COREPLL_RFSLIP       0x0100000000000000ULL
+#define QLOGIC_IB_HWE_PCIE1PLLFAILED       0x0400000000000000ULL
+#define QLOGIC_IB_HWE_PCIE0PLLFAILED       0x0800000000000000ULL
+#define QLOGIC_IB_HWE_SERDESPLLFAILED      0x1000000000000000ULL
+/* specific to this chip */
+#define QLOGIC_IB_HWE_PCIECPLDATAQUEUEERR         0x0000000000000040ULL
+#define QLOGIC_IB_HWE_PCIECPLHDRQUEUEERR          0x0000000000000080ULL
+#define QLOGIC_IB_HWE_SDMAMEMREADERR              0x0000000010000000ULL
+#define QLOGIC_IB_HWE_CLK_UC_PLLNOTLOCKED          0x2000000000000000ULL
+#define QLOGIC_IB_HWE_PCIESERDESQ0PCLKNOTDETECT   0x0100000000000000ULL
+#define QLOGIC_IB_HWE_PCIESERDESQ1PCLKNOTDETECT   0x0200000000000000ULL
+#define QLOGIC_IB_HWE_PCIESERDESQ2PCLKNOTDETECT   0x0400000000000000ULL
+#define QLOGIC_IB_HWE_PCIESERDESQ3PCLKNOTDETECT   0x0800000000000000ULL
+#define QLOGIC_IB_HWE_DDSRXEQMEMORYPARITYERR       0x0000008000000000ULL
+#define QLOGIC_IB_HWE_IB_UC_MEMORYPARITYERR        0x0000004000000000ULL
+#define QLOGIC_IB_HWE_PCIE_UC_OCT0MEMORYPARITYERR 0x0000001000000000ULL
+#define QLOGIC_IB_HWE_PCIE_UC_OCT1MEMORYPARITYERR 0x0000002000000000ULL
+
+#define IBA7220_IBCC_LINKCMD_SHIFT 19
+
+/* kr_ibcddrctrl bits */
+#define IBA7220_IBC_DLIDLMC_MASK        0xFFFFFFFFUL
+#define IBA7220_IBC_DLIDLMC_SHIFT       32
+
+#define IBA7220_IBC_HRTBT_MASK  (SYM_RMASK(IBCDDRCtrl, HRTBT_AUTO) | \
+                                SYM_RMASK(IBCDDRCtrl, HRTBT_ENB))
+#define IBA7220_IBC_HRTBT_SHIFT SYM_LSB(IBCDDRCtrl, HRTBT_ENB)
+
+#define IBA7220_IBC_LANE_REV_SUPPORTED (1<<8)
+#define IBA7220_IBC_LREV_MASK   1
+#define IBA7220_IBC_LREV_SHIFT  8
+#define IBA7220_IBC_RXPOL_MASK  1
+#define IBA7220_IBC_RXPOL_SHIFT 7
+#define IBA7220_IBC_WIDTH_SHIFT 5
+#define IBA7220_IBC_WIDTH_MASK  0x3
+#define IBA7220_IBC_WIDTH_1X_ONLY       (0 << IBA7220_IBC_WIDTH_SHIFT)
+#define IBA7220_IBC_WIDTH_4X_ONLY       (1 << IBA7220_IBC_WIDTH_SHIFT)
+#define IBA7220_IBC_WIDTH_AUTONEG       (2 << IBA7220_IBC_WIDTH_SHIFT)
+#define IBA7220_IBC_SPEED_AUTONEG       (1 << 1)
+#define IBA7220_IBC_SPEED_SDR           (1 << 2)
+#define IBA7220_IBC_SPEED_DDR           (1 << 3)
+#define IBA7220_IBC_SPEED_AUTONEG_MASK  (0x7 << 1)
+#define IBA7220_IBC_IBTA_1_2_MASK       (1)
+
+/* kr_ibcddrstatus */
+/* link latency shift is 0, don't bother defining */
+#define IBA7220_DDRSTAT_LINKLAT_MASK    0x3ffffff
+
+/* kr_extstatus bits */
+#define QLOGIC_IB_EXTS_FREQSEL 0x2
+#define QLOGIC_IB_EXTS_SERDESSEL 0x4
+#define QLOGIC_IB_EXTS_MEMBIST_ENDTEST     0x0000000000004000
+#define QLOGIC_IB_EXTS_MEMBIST_DISABLED    0x0000000000008000
+
+/* kr_xgxsconfig bits */
+#define QLOGIC_IB_XGXS_RESET          0x5ULL
+#define QLOGIC_IB_XGXS_FC_SAFE        (1ULL << 63)
+
+/* kr_rcvpktledcnt */
+#define IBA7220_LEDBLINK_ON_SHIFT 32 /* 4ns period on after packet */
+#define IBA7220_LEDBLINK_OFF_SHIFT 0 /* 4ns period off before next on */
+
+#define _QIB_GPIO_SDA_NUM 1
+#define _QIB_GPIO_SCL_NUM 0
+#define QIB_TWSI_EEPROM_DEV 0xA2 /* All Production 7220 cards. */
+#define QIB_TWSI_TEMP_DEV 0x98
+
+/* HW counter clock is at 4nsec */
+#define QIB_7220_PSXMITWAIT_CHECK_RATE 4000
+
+#define IBA7220_R_INTRAVAIL_SHIFT 17
+#define IBA7220_R_PKEY_DIS_SHIFT 34
+#define IBA7220_R_TAILUPD_SHIFT 35
+#define IBA7220_R_CTXTCFG_SHIFT 36
+
+#define IBA7220_HDRHEAD_PKTINT_SHIFT 32 /* interrupt cnt in upper 32 bits */
+
+/*
+ * the size bits give us 2^N, in KB units.  0 marks as invalid,
+ * and 7 is reserved.  We currently use only 2KB and 4KB
+ */
+#define IBA7220_TID_SZ_SHIFT 37 /* shift to 3bit size selector */
+#define IBA7220_TID_SZ_2K (1UL << IBA7220_TID_SZ_SHIFT) /* 2KB */
+#define IBA7220_TID_SZ_4K (2UL << IBA7220_TID_SZ_SHIFT) /* 4KB */
+#define IBA7220_TID_PA_SHIFT 11U /* TID addr in chip stored w/o low bits */
+#define PBC_7220_VL15_SEND (1ULL << 63) /* pbc; VL15, no credit check */
+#define PBC_7220_VL15_SEND_CTRL (1ULL << 31) /* control version of same */
+
+#define AUTONEG_TRIES 5 /* sequential retries to negotiate DDR */
+
+/* packet rate matching delay multiplier */
+static u8 rate_to_delay[2][2] = {
+       /* 1x, 4x */
+       {   8, 2 }, /* SDR */
+       {   4, 1 }  /* DDR */
+};
+
+static u8 ib_rate_to_delay[IB_RATE_120_GBPS + 1] = {
+       [IB_RATE_2_5_GBPS] = 8,
+       [IB_RATE_5_GBPS] = 4,
+       [IB_RATE_10_GBPS] = 2,
+       [IB_RATE_20_GBPS] = 1
+};
+
+#define IBA7220_LINKSPEED_SHIFT SYM_LSB(IBCStatus, LinkSpeedActive)
+#define IBA7220_LINKWIDTH_SHIFT SYM_LSB(IBCStatus, LinkWidthActive)
+
+/* link training states, from IBC */
+#define IB_7220_LT_STATE_DISABLED        0x00
+#define IB_7220_LT_STATE_LINKUP          0x01
+#define IB_7220_LT_STATE_POLLACTIVE      0x02
+#define IB_7220_LT_STATE_POLLQUIET       0x03
+#define IB_7220_LT_STATE_SLEEPDELAY      0x04
+#define IB_7220_LT_STATE_SLEEPQUIET      0x05
+#define IB_7220_LT_STATE_CFGDEBOUNCE     0x08
+#define IB_7220_LT_STATE_CFGRCVFCFG      0x09
+#define IB_7220_LT_STATE_CFGWAITRMT      0x0a
+#define IB_7220_LT_STATE_CFGIDLE 0x0b
+#define IB_7220_LT_STATE_RECOVERRETRAIN  0x0c
+#define IB_7220_LT_STATE_RECOVERWAITRMT  0x0e
+#define IB_7220_LT_STATE_RECOVERIDLE     0x0f
+
+/* link state machine states from IBC */
+#define IB_7220_L_STATE_DOWN             0x0
+#define IB_7220_L_STATE_INIT             0x1
+#define IB_7220_L_STATE_ARM              0x2
+#define IB_7220_L_STATE_ACTIVE           0x3
+#define IB_7220_L_STATE_ACT_DEFER        0x4
+
+static const u8 qib_7220_physportstate[0x20] = {
+       [IB_7220_LT_STATE_DISABLED] = IB_PHYSPORTSTATE_DISABLED,
+       [IB_7220_LT_STATE_LINKUP] = IB_PHYSPORTSTATE_LINKUP,
+       [IB_7220_LT_STATE_POLLACTIVE] = IB_PHYSPORTSTATE_POLL,
+       [IB_7220_LT_STATE_POLLQUIET] = IB_PHYSPORTSTATE_POLL,
+       [IB_7220_LT_STATE_SLEEPDELAY] = IB_PHYSPORTSTATE_SLEEP,
+       [IB_7220_LT_STATE_SLEEPQUIET] = IB_PHYSPORTSTATE_SLEEP,
+       [IB_7220_LT_STATE_CFGDEBOUNCE] =
+               IB_PHYSPORTSTATE_CFG_TRAIN,
+       [IB_7220_LT_STATE_CFGRCVFCFG] =
+               IB_PHYSPORTSTATE_CFG_TRAIN,
+       [IB_7220_LT_STATE_CFGWAITRMT] =
+               IB_PHYSPORTSTATE_CFG_TRAIN,
+       [IB_7220_LT_STATE_CFGIDLE] = IB_PHYSPORTSTATE_CFG_TRAIN,
+       [IB_7220_LT_STATE_RECOVERRETRAIN] =
+               IB_PHYSPORTSTATE_LINK_ERR_RECOVER,
+       [IB_7220_LT_STATE_RECOVERWAITRMT] =
+               IB_PHYSPORTSTATE_LINK_ERR_RECOVER,
+       [IB_7220_LT_STATE_RECOVERIDLE] =
+               IB_PHYSPORTSTATE_LINK_ERR_RECOVER,
+       [0x10] = IB_PHYSPORTSTATE_CFG_TRAIN,
+       [0x11] = IB_PHYSPORTSTATE_CFG_TRAIN,
+       [0x12] = IB_PHYSPORTSTATE_CFG_TRAIN,
+       [0x13] = IB_PHYSPORTSTATE_CFG_TRAIN,
+       [0x14] = IB_PHYSPORTSTATE_CFG_TRAIN,
+       [0x15] = IB_PHYSPORTSTATE_CFG_TRAIN,
+       [0x16] = IB_PHYSPORTSTATE_CFG_TRAIN,
+       [0x17] = IB_PHYSPORTSTATE_CFG_TRAIN
+};
+
+int qib_special_trigger;
+module_param_named(special_trigger, qib_special_trigger, int, S_IRUGO);
+MODULE_PARM_DESC(special_trigger, "Enable SpecialTrigger arm/launch");
+
+#define IBCBUSFRSPCPARITYERR HWE_MASK(IBCBusFromSPCParityErr)
+#define IBCBUSTOSPCPARITYERR HWE_MASK(IBCBusToSPCParityErr)
+
+#define SYM_MASK_BIT(regname, fldname, bit) ((u64) \
+       (1ULL << (SYM_LSB(regname, fldname) + (bit))))
+
+#define TXEMEMPARITYERR_PIOBUF \
+       SYM_MASK_BIT(HwErrMask, TXEMemParityErrMask, 0)
+#define TXEMEMPARITYERR_PIOPBC \
+       SYM_MASK_BIT(HwErrMask, TXEMemParityErrMask, 1)
+#define TXEMEMPARITYERR_PIOLAUNCHFIFO \
+       SYM_MASK_BIT(HwErrMask, TXEMemParityErrMask, 2)
+
+#define RXEMEMPARITYERR_RCVBUF \
+       SYM_MASK_BIT(HwErrMask, RXEMemParityErrMask, 0)
+#define RXEMEMPARITYERR_LOOKUPQ \
+       SYM_MASK_BIT(HwErrMask, RXEMemParityErrMask, 1)
+#define RXEMEMPARITYERR_EXPTID \
+       SYM_MASK_BIT(HwErrMask, RXEMemParityErrMask, 2)
+#define RXEMEMPARITYERR_EAGERTID \
+       SYM_MASK_BIT(HwErrMask, RXEMemParityErrMask, 3)
+#define RXEMEMPARITYERR_FLAGBUF \
+       SYM_MASK_BIT(HwErrMask, RXEMemParityErrMask, 4)
+#define RXEMEMPARITYERR_DATAINFO \
+       SYM_MASK_BIT(HwErrMask, RXEMemParityErrMask, 5)
+#define RXEMEMPARITYERR_HDRINFO \
+       SYM_MASK_BIT(HwErrMask, RXEMemParityErrMask, 6)
+
+/* 7220 specific hardware errors... */
+static const struct qib_hwerror_msgs qib_7220_hwerror_msgs[] = {
+       /* generic hardware errors */
+       QLOGIC_IB_HWE_MSG(IBCBUSFRSPCPARITYERR, "QIB2IB Parity"),
+       QLOGIC_IB_HWE_MSG(IBCBUSTOSPCPARITYERR, "IB2QIB Parity"),
+
+       QLOGIC_IB_HWE_MSG(TXEMEMPARITYERR_PIOBUF,
+                         "TXE PIOBUF Memory Parity"),
+       QLOGIC_IB_HWE_MSG(TXEMEMPARITYERR_PIOPBC,
+                         "TXE PIOPBC Memory Parity"),
+       QLOGIC_IB_HWE_MSG(TXEMEMPARITYERR_PIOLAUNCHFIFO,
+                         "TXE PIOLAUNCHFIFO Memory Parity"),
+
+       QLOGIC_IB_HWE_MSG(RXEMEMPARITYERR_RCVBUF,
+                         "RXE RCVBUF Memory Parity"),
+       QLOGIC_IB_HWE_MSG(RXEMEMPARITYERR_LOOKUPQ,
+                         "RXE LOOKUPQ Memory Parity"),
+       QLOGIC_IB_HWE_MSG(RXEMEMPARITYERR_EAGERTID,
+                         "RXE EAGERTID Memory Parity"),
+       QLOGIC_IB_HWE_MSG(RXEMEMPARITYERR_EXPTID,
+                         "RXE EXPTID Memory Parity"),
+       QLOGIC_IB_HWE_MSG(RXEMEMPARITYERR_FLAGBUF,
+                         "RXE FLAGBUF Memory Parity"),
+       QLOGIC_IB_HWE_MSG(RXEMEMPARITYERR_DATAINFO,
+                         "RXE DATAINFO Memory Parity"),
+       QLOGIC_IB_HWE_MSG(RXEMEMPARITYERR_HDRINFO,
+                         "RXE HDRINFO Memory Parity"),
+
+       /* chip-specific hardware errors */
+       QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_PCIEPOISONEDTLP,
+                         "PCIe Poisoned TLP"),
+       QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_PCIECPLTIMEOUT,
+                         "PCIe completion timeout"),
+       /*
+        * In practice, it's unlikely wthat we'll see PCIe PLL, or bus
+        * parity or memory parity error failures, because most likely we
+        * won't be able to talk to the core of the chip.  Nonetheless, we
+        * might see them, if they are in parts of the PCIe core that aren't
+        * essential.
+        */
+       QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_PCIE1PLLFAILED,
+                         "PCIePLL1"),
+       QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_PCIE0PLLFAILED,
+                         "PCIePLL0"),
+       QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_PCIEBUSPARITYXTLH,
+                         "PCIe XTLH core parity"),
+       QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_PCIEBUSPARITYXADM,
+                         "PCIe ADM TX core parity"),
+       QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_PCIEBUSPARITYRADM,
+                         "PCIe ADM RX core parity"),
+       QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_SERDESPLLFAILED,
+                         "SerDes PLL"),
+       QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_PCIECPLDATAQUEUEERR,
+                         "PCIe cpl header queue"),
+       QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_PCIECPLHDRQUEUEERR,
+                         "PCIe cpl data queue"),
+       QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_SDMAMEMREADERR,
+                         "Send DMA memory read"),
+       QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_CLK_UC_PLLNOTLOCKED,
+                         "uC PLL clock not locked"),
+       QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_PCIESERDESQ0PCLKNOTDETECT,
+                         "PCIe serdes Q0 no clock"),
+       QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_PCIESERDESQ1PCLKNOTDETECT,
+                         "PCIe serdes Q1 no clock"),
+       QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_PCIESERDESQ2PCLKNOTDETECT,
+                         "PCIe serdes Q2 no clock"),
+       QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_PCIESERDESQ3PCLKNOTDETECT,
+                         "PCIe serdes Q3 no clock"),
+       QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_DDSRXEQMEMORYPARITYERR,
+                         "DDS RXEQ memory parity"),
+       QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_IB_UC_MEMORYPARITYERR,
+                         "IB uC memory parity"),
+       QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_PCIE_UC_OCT0MEMORYPARITYERR,
+                         "PCIe uC oct0 memory parity"),
+       QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_PCIE_UC_OCT1MEMORYPARITYERR,
+                         "PCIe uC oct1 memory parity"),
+};
+
+#define RXE_PARITY (RXEMEMPARITYERR_EAGERTID|RXEMEMPARITYERR_EXPTID)
+
+#define QLOGIC_IB_E_PKTERRS (\
+               ERR_MASK(SendPktLenErr) |                               \
+               ERR_MASK(SendDroppedDataPktErr) |                       \
+               ERR_MASK(RcvVCRCErr) |                                  \
+               ERR_MASK(RcvICRCErr) |                                  \
+               ERR_MASK(RcvShortPktLenErr) |                           \
+               ERR_MASK(RcvEBPErr))
+
+/* Convenience for decoding Send DMA errors */
+#define QLOGIC_IB_E_SDMAERRS ( \
+               ERR_MASK(SDmaGenMismatchErr) |                          \
+               ERR_MASK(SDmaOutOfBoundErr) |                           \
+               ERR_MASK(SDmaTailOutOfBoundErr) | ERR_MASK(SDmaBaseErr) | \
+               ERR_MASK(SDma1stDescErr) | ERR_MASK(SDmaRpyTagErr) |    \
+               ERR_MASK(SDmaDwEnErr) | ERR_MASK(SDmaMissingDwErr) |    \
+               ERR_MASK(SDmaUnexpDataErr) |                            \
+               ERR_MASK(SDmaDescAddrMisalignErr) |                     \
+               ERR_MASK(SDmaDisabledErr) |                             \
+               ERR_MASK(SendBufMisuseErr))
+
+/* These are all rcv-related errors which we want to count for stats */
+#define E_SUM_PKTERRS \
+       (ERR_MASK(RcvHdrLenErr) | ERR_MASK(RcvBadTidErr) |              \
+        ERR_MASK(RcvBadVersionErr) | ERR_MASK(RcvHdrErr) |             \
+        ERR_MASK(RcvLongPktLenErr) | ERR_MASK(RcvShortPktLenErr) |     \
+        ERR_MASK(RcvMaxPktLenErr) | ERR_MASK(RcvMinPktLenErr) |        \
+        ERR_MASK(RcvFormatErr) | ERR_MASK(RcvUnsupportedVLErr) |       \
+        ERR_MASK(RcvUnexpectedCharErr) | ERR_MASK(RcvEBPErr))
+
+/* These are all send-related errors which we want to count for stats */
+#define E_SUM_ERRS \
+       (ERR_MASK(SendPioArmLaunchErr) | ERR_MASK(SendUnexpectedPktNumErr) | \
+        ERR_MASK(SendDroppedDataPktErr) | ERR_MASK(SendDroppedSmpPktErr) | \
+        ERR_MASK(SendMaxPktLenErr) | ERR_MASK(SendUnsupportedVLErr) |  \
+        ERR_MASK(SendMinPktLenErr) | ERR_MASK(SendPktLenErr) |         \
+        ERR_MASK(InvalidAddrErr))
+
+/*
+ * this is similar to E_SUM_ERRS, but can't ignore armlaunch, don't ignore
+ * errors not related to freeze and cancelling buffers.  Can't ignore
+ * armlaunch because could get more while still cleaning up, and need
+ * to cancel those as they happen.
+ */
+#define E_SPKT_ERRS_IGNORE \
+       (ERR_MASK(SendDroppedDataPktErr) | ERR_MASK(SendDroppedSmpPktErr) | \
+        ERR_MASK(SendMaxPktLenErr) | ERR_MASK(SendMinPktLenErr) |      \
+        ERR_MASK(SendPktLenErr))
+
+/*
+ * these are errors that can occur when the link changes state while
+ * a packet is being sent or received.  This doesn't cover things
+ * like EBP or VCRC that can be the result of a sending having the
+ * link change state, so we receive a "known bad" packet.
+ */
+#define E_SUM_LINK_PKTERRS \
+       (ERR_MASK(SendDroppedDataPktErr) | ERR_MASK(SendDroppedSmpPktErr) | \
+        ERR_MASK(SendMinPktLenErr) | ERR_MASK(SendPktLenErr) |         \
+        ERR_MASK(RcvShortPktLenErr) | ERR_MASK(RcvMinPktLenErr) |      \
+        ERR_MASK(RcvUnexpectedCharErr))
+
+static void autoneg_7220_work(struct work_struct *);
+static u32 __iomem *qib_7220_getsendbuf(struct qib_pportdata *, u64, u32 *);
+
+/*
+ * Called when we might have an error that is specific to a particular
+ * PIO buffer, and may need to cancel that buffer, so it can be re-used.
+ * because we don't need to force the update of pioavail.
+ */
+static void qib_disarm_7220_senderrbufs(struct qib_pportdata *ppd)
+{
+       unsigned long sbuf[3];
+       struct qib_devdata *dd = ppd->dd;
+
+       /*
+        * It's possible that sendbuffererror could have bits set; might
+        * have already done this as a result of hardware error handling.
+        */
+       /* read these before writing errorclear */
+       sbuf[0] = qib_read_kreg64(dd, kr_sendbuffererror);
+       sbuf[1] = qib_read_kreg64(dd, kr_sendbuffererror + 1);
+       sbuf[2] = qib_read_kreg64(dd, kr_sendbuffererror + 2);
+
+       if (sbuf[0] || sbuf[1] || sbuf[2])
+               qib_disarm_piobufs_set(dd, sbuf,
+                                      dd->piobcnt2k + dd->piobcnt4k);
+}
+
+static void qib_7220_txe_recover(struct qib_devdata *dd)
+{
+       qib_devinfo(dd->pcidev, "Recovering from TXE PIO parity error\n");
+       qib_disarm_7220_senderrbufs(dd->pport);
+}
+
+/*
+ * This is called with interrupts disabled and sdma_lock held.
+ */
+static void qib_7220_sdma_sendctrl(struct qib_pportdata *ppd, unsigned op)
+{
+       struct qib_devdata *dd = ppd->dd;
+       u64 set_sendctrl = 0;
+       u64 clr_sendctrl = 0;
+
+       if (op & QIB_SDMA_SENDCTRL_OP_ENABLE)
+               set_sendctrl |= SYM_MASK(SendCtrl, SDmaEnable);
+       else
+               clr_sendctrl |= SYM_MASK(SendCtrl, SDmaEnable);
+
+       if (op & QIB_SDMA_SENDCTRL_OP_INTENABLE)
+               set_sendctrl |= SYM_MASK(SendCtrl, SDmaIntEnable);
+       else
+               clr_sendctrl |= SYM_MASK(SendCtrl, SDmaIntEnable);
+
+       if (op & QIB_SDMA_SENDCTRL_OP_HALT)
+               set_sendctrl |= SYM_MASK(SendCtrl, SDmaHalt);
+       else
+               clr_sendctrl |= SYM_MASK(SendCtrl, SDmaHalt);
+
+       spin_lock(&dd->sendctrl_lock);
+
+       dd->sendctrl |= set_sendctrl;
+       dd->sendctrl &= ~clr_sendctrl;
+
+       qib_write_kreg(dd, kr_sendctrl, dd->sendctrl);
+       qib_write_kreg(dd, kr_scratch, 0);
+
+       spin_unlock(&dd->sendctrl_lock);
+}
+
+static void qib_decode_7220_sdma_errs(struct qib_pportdata *ppd,
+                                     u64 err, char *buf, size_t blen)
+{
+       static const struct {
+               u64 err;
+               const char *msg;
+       } errs[] = {
+               { ERR_MASK(SDmaGenMismatchErr),
+                 "SDmaGenMismatch" },
+               { ERR_MASK(SDmaOutOfBoundErr),
+                 "SDmaOutOfBound" },
+               { ERR_MASK(SDmaTailOutOfBoundErr),
+                 "SDmaTailOutOfBound" },
+               { ERR_MASK(SDmaBaseErr),
+                 "SDmaBase" },
+               { ERR_MASK(SDma1stDescErr),
+                 "SDma1stDesc" },
+               { ERR_MASK(SDmaRpyTagErr),
+                 "SDmaRpyTag" },
+               { ERR_MASK(SDmaDwEnErr),
+                 "SDmaDwEn" },
+               { ERR_MASK(SDmaMissingDwErr),
+                 "SDmaMissingDw" },
+               { ERR_MASK(SDmaUnexpDataErr),
+                 "SDmaUnexpData" },
+               { ERR_MASK(SDmaDescAddrMisalignErr),
+                 "SDmaDescAddrMisalign" },
+               { ERR_MASK(SendBufMisuseErr),
+                 "SendBufMisuse" },
+               { ERR_MASK(SDmaDisabledErr),
+                 "SDmaDisabled" },
+       };
+       int i;
+       size_t bidx = 0;
+
+       for (i = 0; i < ARRAY_SIZE(errs); i++) {
+               if (err & errs[i].err)
+                       bidx += scnprintf(buf + bidx, blen - bidx,
+                                        "%s ", errs[i].msg);
+       }
+}
+
+/*
+ * This is called as part of link down clean up so disarm and flush
+ * all send buffers so that SMP packets can be sent.
+ */
+static void qib_7220_sdma_hw_clean_up(struct qib_pportdata *ppd)
+{
+       /* This will trigger the Abort interrupt */
+       sendctrl_7220_mod(ppd, QIB_SENDCTRL_DISARM_ALL | QIB_SENDCTRL_FLUSH |
+                         QIB_SENDCTRL_AVAIL_BLIP);
+       ppd->dd->upd_pio_shadow  = 1; /* update our idea of what's busy */
+}
+
+static void qib_sdma_7220_setlengen(struct qib_pportdata *ppd)
+{
+       /*
+        * Set SendDmaLenGen and clear and set
+        * the MSB of the generation count to enable generation checking
+        * and load the internal generation counter.
+        */
+       qib_write_kreg(ppd->dd, kr_senddmalengen, ppd->sdma_descq_cnt);
+       qib_write_kreg(ppd->dd, kr_senddmalengen,
+                      ppd->sdma_descq_cnt |
+                      (1ULL << QIB_7220_SendDmaLenGen_Generation_MSB));
+}
+
+static void qib_7220_sdma_hw_start_up(struct qib_pportdata *ppd)
+{
+       qib_sdma_7220_setlengen(ppd);
+       qib_sdma_update_7220_tail(ppd, 0); /* Set SendDmaTail */
+       ppd->sdma_head_dma[0] = 0;
+}
+
+#define DISABLES_SDMA (                                                        \
+               ERR_MASK(SDmaDisabledErr) |                             \
+               ERR_MASK(SDmaBaseErr) |                                 \
+               ERR_MASK(SDmaTailOutOfBoundErr) |                       \
+               ERR_MASK(SDmaOutOfBoundErr) |                           \
+               ERR_MASK(SDma1stDescErr) |                              \
+               ERR_MASK(SDmaRpyTagErr) |                               \
+               ERR_MASK(SDmaGenMismatchErr) |                          \
+               ERR_MASK(SDmaDescAddrMisalignErr) |                     \
+               ERR_MASK(SDmaMissingDwErr) |                            \
+               ERR_MASK(SDmaDwEnErr))
+
+static void sdma_7220_errors(struct qib_pportdata *ppd, u64 errs)
+{
+       unsigned long flags;
+       struct qib_devdata *dd = ppd->dd;
+       char *msg;
+
+       errs &= QLOGIC_IB_E_SDMAERRS;
+
+       msg = dd->cspec->sdmamsgbuf;
+       qib_decode_7220_sdma_errs(ppd, errs, msg, sizeof dd->cspec->sdmamsgbuf);
+       spin_lock_irqsave(&ppd->sdma_lock, flags);
+
+       if (errs & ERR_MASK(SendBufMisuseErr)) {
+               unsigned long sbuf[3];
+
+               sbuf[0] = qib_read_kreg64(dd, kr_sendbuffererror);
+               sbuf[1] = qib_read_kreg64(dd, kr_sendbuffererror + 1);
+               sbuf[2] = qib_read_kreg64(dd, kr_sendbuffererror + 2);
+
+               qib_dev_err(ppd->dd,
+                           "IB%u:%u SendBufMisuse: %04lx %016lx %016lx\n",
+                           ppd->dd->unit, ppd->port, sbuf[2], sbuf[1],
+                           sbuf[0]);
+       }
+
+       if (errs & ERR_MASK(SDmaUnexpDataErr))
+               qib_dev_err(dd, "IB%u:%u SDmaUnexpData\n", ppd->dd->unit,
+                           ppd->port);
+
+       switch (ppd->sdma_state.current_state) {
+       case qib_sdma_state_s00_hw_down:
+               /* not expecting any interrupts */
+               break;
+
+       case qib_sdma_state_s10_hw_start_up_wait:
+               /* handled in intr path */
+               break;
+
+       case qib_sdma_state_s20_idle:
+               /* not expecting any interrupts */
+               break;
+
+       case qib_sdma_state_s30_sw_clean_up_wait:
+               /* not expecting any interrupts */
+               break;
+
+       case qib_sdma_state_s40_hw_clean_up_wait:
+               if (errs & ERR_MASK(SDmaDisabledErr))
+                       __qib_sdma_process_event(ppd,
+                               qib_sdma_event_e50_hw_cleaned);
+               break;
+
+       case qib_sdma_state_s50_hw_halt_wait:
+               /* handled in intr path */
+               break;
+
+       case qib_sdma_state_s99_running:
+               if (errs & DISABLES_SDMA)
+                       __qib_sdma_process_event(ppd,
+                               qib_sdma_event_e7220_err_halted);
+               break;
+       }
+
+       spin_unlock_irqrestore(&ppd->sdma_lock, flags);
+}
+
+/*
+ * Decode the error status into strings, deciding whether to always
+ * print * it or not depending on "normal packet errors" vs everything
+ * else.   Return 1 if "real" errors, otherwise 0 if only packet
+ * errors, so caller can decide what to print with the string.
+ */
+static int qib_decode_7220_err(struct qib_devdata *dd, char *buf, size_t blen,
+                              u64 err)
+{
+       int iserr = 1;
+
+       *buf = '\0';
+       if (err & QLOGIC_IB_E_PKTERRS) {
+               if (!(err & ~QLOGIC_IB_E_PKTERRS))
+                       iserr = 0;
+               if ((err & ERR_MASK(RcvICRCErr)) &&
+                   !(err & (ERR_MASK(RcvVCRCErr) | ERR_MASK(RcvEBPErr))))
+                       strlcat(buf, "CRC ", blen);
+               if (!iserr)
+                       goto done;
+       }
+       if (err & ERR_MASK(RcvHdrLenErr))
+               strlcat(buf, "rhdrlen ", blen);
+       if (err & ERR_MASK(RcvBadTidErr))
+               strlcat(buf, "rbadtid ", blen);
+       if (err & ERR_MASK(RcvBadVersionErr))
+               strlcat(buf, "rbadversion ", blen);
+       if (err & ERR_MASK(RcvHdrErr))
+               strlcat(buf, "rhdr ", blen);
+       if (err & ERR_MASK(SendSpecialTriggerErr))
+               strlcat(buf, "sendspecialtrigger ", blen);
+       if (err & ERR_MASK(RcvLongPktLenErr))
+               strlcat(buf, "rlongpktlen ", blen);
+       if (err & ERR_MASK(RcvMaxPktLenErr))
+               strlcat(buf, "rmaxpktlen ", blen);
+       if (err & ERR_MASK(RcvMinPktLenErr))
+               strlcat(buf, "rminpktlen ", blen);
+       if (err & ERR_MASK(SendMinPktLenErr))
+               strlcat(buf, "sminpktlen ", blen);
+       if (err & ERR_MASK(RcvFormatErr))
+               strlcat(buf, "rformaterr ", blen);
+       if (err & ERR_MASK(RcvUnsupportedVLErr))
+               strlcat(buf, "runsupvl ", blen);
+       if (err & ERR_MASK(RcvUnexpectedCharErr))
+               strlcat(buf, "runexpchar ", blen);
+       if (err & ERR_MASK(RcvIBFlowErr))
+               strlcat(buf, "ribflow ", blen);
+       if (err & ERR_MASK(SendUnderRunErr))
+               strlcat(buf, "sunderrun ", blen);
+       if (err & ERR_MASK(SendPioArmLaunchErr))
+               strlcat(buf, "spioarmlaunch ", blen);
+       if (err & ERR_MASK(SendUnexpectedPktNumErr))
+               strlcat(buf, "sunexperrpktnum ", blen);
+       if (err & ERR_MASK(SendDroppedSmpPktErr))
+               strlcat(buf, "sdroppedsmppkt ", blen);
+       if (err & ERR_MASK(SendMaxPktLenErr))
+               strlcat(buf, "smaxpktlen ", blen);
+       if (err & ERR_MASK(SendUnsupportedVLErr))
+               strlcat(buf, "sunsupVL ", blen);
+       if (err & ERR_MASK(InvalidAddrErr))
+               strlcat(buf, "invalidaddr ", blen);
+       if (err & ERR_MASK(RcvEgrFullErr))
+               strlcat(buf, "rcvegrfull ", blen);
+       if (err & ERR_MASK(RcvHdrFullErr))
+               strlcat(buf, "rcvhdrfull ", blen);
+       if (err & ERR_MASK(IBStatusChanged))
+               strlcat(buf, "ibcstatuschg ", blen);
+       if (err & ERR_MASK(RcvIBLostLinkErr))
+               strlcat(buf, "riblostlink ", blen);
+       if (err & ERR_MASK(HardwareErr))
+               strlcat(buf, "hardware ", blen);
+       if (err & ERR_MASK(ResetNegated))
+               strlcat(buf, "reset ", blen);
+       if (err & QLOGIC_IB_E_SDMAERRS)
+               qib_decode_7220_sdma_errs(dd->pport, err, buf, blen);
+       if (err & ERR_MASK(InvalidEEPCmd))
+               strlcat(buf, "invalideepromcmd ", blen);
+done:
+       return iserr;
+}
+
+static void reenable_7220_chase(unsigned long opaque)
+{
+       struct qib_pportdata *ppd = (struct qib_pportdata *)opaque;
+       ppd->cpspec->chase_timer.expires = 0;
+       qib_set_ib_7220_lstate(ppd, QLOGIC_IB_IBCC_LINKCMD_DOWN,
+               QLOGIC_IB_IBCC_LINKINITCMD_POLL);
+}
+
+static void handle_7220_chase(struct qib_pportdata *ppd, u64 ibcst)
+{
+       u8 ibclt;
+       u64 tnow;
+
+       ibclt = (u8)SYM_FIELD(ibcst, IBCStatus, LinkTrainingState);
+
+       /*
+        * Detect and handle the state chase issue, where we can
+        * get stuck if we are unlucky on timing on both sides of
+        * the link.   If we are, we disable, set a timer, and
+        * then re-enable.
+        */
+       switch (ibclt) {
+       case IB_7220_LT_STATE_CFGRCVFCFG:
+       case IB_7220_LT_STATE_CFGWAITRMT:
+       case IB_7220_LT_STATE_TXREVLANES:
+       case IB_7220_LT_STATE_CFGENH:
+               tnow = get_jiffies_64();
+               if (ppd->cpspec->chase_end &&
+                   time_after64(tnow, ppd->cpspec->chase_end)) {
+                       ppd->cpspec->chase_end = 0;
+                       qib_set_ib_7220_lstate(ppd,
+                               QLOGIC_IB_IBCC_LINKCMD_DOWN,
+                               QLOGIC_IB_IBCC_LINKINITCMD_DISABLE);
+                       ppd->cpspec->chase_timer.expires = jiffies +
+                               QIB_CHASE_DIS_TIME;
+                       add_timer(&ppd->cpspec->chase_timer);
+               } else if (!ppd->cpspec->chase_end)
+                       ppd->cpspec->chase_end = tnow + QIB_CHASE_TIME;
+               break;
+
+       default:
+               ppd->cpspec->chase_end = 0;
+               break;
+       }
+}
+
+static void handle_7220_errors(struct qib_devdata *dd, u64 errs)
+{
+       char *msg;
+       u64 ignore_this_time = 0;
+       u64 iserr = 0;
+       int log_idx;
+       struct qib_pportdata *ppd = dd->pport;
+       u64 mask;
+
+       /* don't report errors that are masked */
+       errs &= dd->cspec->errormask;
+       msg = dd->cspec->emsgbuf;
+
+       /* do these first, they are most important */
+       if (errs & ERR_MASK(HardwareErr))
+               qib_7220_handle_hwerrors(dd, msg, sizeof dd->cspec->emsgbuf);
+       else
+               for (log_idx = 0; log_idx < QIB_EEP_LOG_CNT; ++log_idx)
+                       if (errs & dd->eep_st_masks[log_idx].errs_to_log)
+                               qib_inc_eeprom_err(dd, log_idx, 1);
+
+       if (errs & QLOGIC_IB_E_SDMAERRS)
+               sdma_7220_errors(ppd, errs);
+
+       if (errs & ~IB_E_BITSEXTANT)
+               qib_dev_err(dd, "error interrupt with unknown errors "
+                           "%llx set\n", (unsigned long long)
+                           (errs & ~IB_E_BITSEXTANT));
+
+       if (errs & E_SUM_ERRS) {
+               qib_disarm_7220_senderrbufs(ppd);
+               if ((errs & E_SUM_LINK_PKTERRS) &&
+                   !(ppd->lflags & QIBL_LINKACTIVE)) {
+                       /*
+                        * This can happen when trying to bring the link
+                        * up, but the IB link changes state at the "wrong"
+                        * time. The IB logic then complains that the packet
+                        * isn't valid.  We don't want to confuse people, so
+                        * we just don't print them, except at debug
+                        */
+                       ignore_this_time = errs & E_SUM_LINK_PKTERRS;
+               }
+       } else if ((errs & E_SUM_LINK_PKTERRS) &&
+                  !(ppd->lflags & QIBL_LINKACTIVE)) {
+               /*
+                * This can happen when SMA is trying to bring the link
+                * up, but the IB link changes state at the "wrong" time.
+                * The IB logic then complains that the packet isn't
+                * valid.  We don't want to confuse people, so we just
+                * don't print them, except at debug
+                */
+               ignore_this_time = errs & E_SUM_LINK_PKTERRS;
+       }
+
+       qib_write_kreg(dd, kr_errclear, errs);
+
+       errs &= ~ignore_this_time;
+       if (!errs)
+               goto done;
+
+       /*
+        * The ones we mask off are handled specially below
+        * or above.  Also mask SDMADISABLED by default as it
+        * is too chatty.
+        */
+       mask = ERR_MASK(IBStatusChanged) |
+               ERR_MASK(RcvEgrFullErr) | ERR_MASK(RcvHdrFullErr) |
+               ERR_MASK(HardwareErr) | ERR_MASK(SDmaDisabledErr);
+
+       qib_decode_7220_err(dd, msg, sizeof dd->cspec->emsgbuf, errs & ~mask);
+
+       if (errs & E_SUM_PKTERRS)
+               qib_stats.sps_rcverrs++;
+       if (errs & E_SUM_ERRS)
+               qib_stats.sps_txerrs++;
+       iserr = errs & ~(E_SUM_PKTERRS | QLOGIC_IB_E_PKTERRS |
+                        ERR_MASK(SDmaDisabledErr));
+
+       if (errs & ERR_MASK(IBStatusChanged)) {
+               u64 ibcs;
+
+               ibcs = qib_read_kreg64(dd, kr_ibcstatus);
+               if (!(ppd->lflags & QIBL_IB_AUTONEG_INPROG))
+                       handle_7220_chase(ppd, ibcs);
+
+               /* Update our picture of width and speed from chip */
+               ppd->link_width_active =
+                       ((ibcs >> IBA7220_LINKWIDTH_SHIFT) & 1) ?
+                           IB_WIDTH_4X : IB_WIDTH_1X;
+               ppd->link_speed_active =
+                       ((ibcs >> IBA7220_LINKSPEED_SHIFT) & 1) ?
+                           QIB_IB_DDR : QIB_IB_SDR;
+
+               /*
+                * Since going into a recovery state causes the link state
+                * to go down and since recovery is transitory, it is better
+                * if we "miss" ever seeing the link training state go into
+                * recovery (i.e., ignore this transition for link state
+                * special handling purposes) without updating lastibcstat.
+                */
+               if (qib_7220_phys_portstate(ibcs) !=
+                                           IB_PHYSPORTSTATE_LINK_ERR_RECOVER)
+                       qib_handle_e_ibstatuschanged(ppd, ibcs);
+       }
+
+       if (errs & ERR_MASK(ResetNegated)) {
+               qib_dev_err(dd, "Got reset, requires re-init "
+                           "(unload and reload driver)\n");
+               dd->flags &= ~QIB_INITTED;  /* needs re-init */
+               /* mark as having had error */
+               *dd->devstatusp |= QIB_STATUS_HWERROR;
+               *dd->pport->statusp &= ~QIB_STATUS_IB_CONF;
+       }
+
+       if (*msg && iserr)
+               qib_dev_porterr(dd, ppd->port, "%s error\n", msg);
+
+       if (ppd->state_wanted & ppd->lflags)
+               wake_up_interruptible(&ppd->state_wait);
+
+       /*
+        * If there were hdrq or egrfull errors, wake up any processes
+        * waiting in poll.  We used to try to check which contexts had
+        * the overflow, but given the cost of that and the chip reads
+        * to support it, it's better to just wake everybody up if we
+        * get an overflow; waiters can poll again if it's not them.
+        */
+       if (errs & (ERR_MASK(RcvEgrFullErr) | ERR_MASK(RcvHdrFullErr))) {
+               qib_handle_urcv(dd, ~0U);
+               if (errs & ERR_MASK(RcvEgrFullErr))
+                       qib_stats.sps_buffull++;
+               else
+                       qib_stats.sps_hdrfull++;
+       }
+done:
+       return;
+}
+
+/* enable/disable chip from delivering interrupts */
+static void qib_7220_set_intr_state(struct qib_devdata *dd, u32 enable)
+{
+       if (enable) {
+               if (dd->flags & QIB_BADINTR)
+                       return;
+               qib_write_kreg(dd, kr_intmask, ~0ULL);
+               /* force re-interrupt of any pending interrupts. */
+               qib_write_kreg(dd, kr_intclear, 0ULL);
+       } else
+               qib_write_kreg(dd, kr_intmask, 0ULL);
+}
+
+/*
+ * Try to cleanup as much as possible for anything that might have gone
+ * wrong while in freeze mode, such as pio buffers being written by user
+ * processes (causing armlaunch), send errors due to going into freeze mode,
+ * etc., and try to avoid causing extra interrupts while doing so.
+ * Forcibly update the in-memory pioavail register copies after cleanup
+ * because the chip won't do it while in freeze mode (the register values
+ * themselves are kept correct).
+ * Make sure that we don't lose any important interrupts by using the chip
+ * feature that says that writing 0 to a bit in *clear that is set in
+ * *status will cause an interrupt to be generated again (if allowed by
+ * the *mask value).
+ * This is in chip-specific code because of all of the register accesses,
+ * even though the details are similar on most chips.
+ */
+static void qib_7220_clear_freeze(struct qib_devdata *dd)
+{
+       /* disable error interrupts, to avoid confusion */
+       qib_write_kreg(dd, kr_errmask, 0ULL);
+
+       /* also disable interrupts; errormask is sometimes overwriten */
+       qib_7220_set_intr_state(dd, 0);
+
+       qib_cancel_sends(dd->pport);
+
+       /* clear the freeze, and be sure chip saw it */
+       qib_write_kreg(dd, kr_control, dd->control);
+       qib_read_kreg32(dd, kr_scratch);
+
+       /* force in-memory update now we are out of freeze */
+       qib_force_pio_avail_update(dd);
+
+       /*
+        * force new interrupt if any hwerr, error or interrupt bits are
+        * still set, and clear "safe" send packet errors related to freeze
+        * and cancelling sends.  Re-enable error interrupts before possible
+        * force of re-interrupt on pending interrupts.
+        */
+       qib_write_kreg(dd, kr_hwerrclear, 0ULL);
+       qib_write_kreg(dd, kr_errclear, E_SPKT_ERRS_IGNORE);
+       qib_write_kreg(dd, kr_errmask, dd->cspec->errormask);
+       qib_7220_set_intr_state(dd, 1);
+}
+
+/**
+ * qib_7220_handle_hwerrors - display hardware errors.
+ * @dd: the qlogic_ib device
+ * @msg: the output buffer
+ * @msgl: the size of the output buffer
+ *
+ * Use same msg buffer as regular errors to avoid excessive stack
+ * use.  Most hardware errors are catastrophic, but for right now,
+ * we'll print them and continue.  We reuse the same message buffer as
+ * handle_7220_errors() to avoid excessive stack usage.
+ */
+static void qib_7220_handle_hwerrors(struct qib_devdata *dd, char *msg,
+                                    size_t msgl)
+{
+       u64 hwerrs;
+       u32 bits, ctrl;
+       int isfatal = 0;
+       char *bitsmsg;
+       int log_idx;
+
+       hwerrs = qib_read_kreg64(dd, kr_hwerrstatus);
+       if (!hwerrs)
+               goto bail;
+       if (hwerrs == ~0ULL) {
+               qib_dev_err(dd, "Read of hardware error status failed "
+                           "(all bits set); ignoring\n");
+               goto bail;
+       }
+       qib_stats.sps_hwerrs++;
+
+       /*
+        * Always clear the error status register, except MEMBISTFAIL,
+        * regardless of whether we continue or stop using the chip.
+        * We want that set so we know it failed, even across driver reload.
+        * We'll still ignore it in the hwerrmask.  We do this partly for
+        * diagnostics, but also for support.
+        */
+       qib_write_kreg(dd, kr_hwerrclear,
+                      hwerrs & ~HWE_MASK(PowerOnBISTFailed));
+
+       hwerrs &= dd->cspec->hwerrmask;
+
+       /* We log some errors to EEPROM, check if we have any of those. */
+       for (log_idx = 0; log_idx < QIB_EEP_LOG_CNT; ++log_idx)
+               if (hwerrs & dd->eep_st_masks[log_idx].hwerrs_to_log)
+                       qib_inc_eeprom_err(dd, log_idx, 1);
+       if (hwerrs & ~(TXEMEMPARITYERR_PIOBUF | TXEMEMPARITYERR_PIOPBC |
+                      RXE_PARITY))
+               qib_devinfo(dd->pcidev, "Hardware error: hwerr=0x%llx "
+                        "(cleared)\n", (unsigned long long) hwerrs);
+
+       if (hwerrs & ~IB_HWE_BITSEXTANT)
+               qib_dev_err(dd, "hwerror interrupt with unknown errors "
+                           "%llx set\n", (unsigned long long)
+                           (hwerrs & ~IB_HWE_BITSEXTANT));
+
+       if (hwerrs & QLOGIC_IB_HWE_IB_UC_MEMORYPARITYERR)
+               qib_sd7220_clr_ibpar(dd);
+
+       ctrl = qib_read_kreg32(dd, kr_control);
+       if ((ctrl & QLOGIC_IB_C_FREEZEMODE) && !dd->diag_client) {
+               /*
+                * Parity errors in send memory are recoverable by h/w
+                * just do housekeeping, exit freeze mode and continue.
+                */
+               if (hwerrs & (TXEMEMPARITYERR_PIOBUF |
+                             TXEMEMPARITYERR_PIOPBC)) {
+                       qib_7220_txe_recover(dd);
+                       hwerrs &= ~(TXEMEMPARITYERR_PIOBUF |
+                                   TXEMEMPARITYERR_PIOPBC);
+               }
+               if (hwerrs)
+                       isfatal = 1;
+               else
+                       qib_7220_clear_freeze(dd);
+       }
+
+       *msg = '\0';
+
+       if (hwerrs & HWE_MASK(PowerOnBISTFailed)) {
+               isfatal = 1;
+               strlcat(msg, "[Memory BIST test failed, "
+                       "InfiniPath hardware unusable]", msgl);
+               /* ignore from now on, so disable until driver reloaded */
+               dd->cspec->hwerrmask &= ~HWE_MASK(PowerOnBISTFailed);
+               qib_write_kreg(dd, kr_hwerrmask, dd->cspec->hwerrmask);
+       }
+
+       qib_format_hwerrors(hwerrs, qib_7220_hwerror_msgs,
+                           ARRAY_SIZE(qib_7220_hwerror_msgs), msg, msgl);
+
+       bitsmsg = dd->cspec->bitsmsgbuf;
+       if (hwerrs & (QLOGIC_IB_HWE_PCIEMEMPARITYERR_MASK <<
+                     QLOGIC_IB_HWE_PCIEMEMPARITYERR_SHIFT)) {
+               bits = (u32) ((hwerrs >>
+                              QLOGIC_IB_HWE_PCIEMEMPARITYERR_SHIFT) &
+                             QLOGIC_IB_HWE_PCIEMEMPARITYERR_MASK);
+               snprintf(bitsmsg, sizeof dd->cspec->bitsmsgbuf,
+                        "[PCIe Mem Parity Errs %x] ", bits);
+               strlcat(msg, bitsmsg, msgl);
+       }
+
+#define _QIB_PLL_FAIL (QLOGIC_IB_HWE_COREPLL_FBSLIP |   \
+                        QLOGIC_IB_HWE_COREPLL_RFSLIP)
+
+       if (hwerrs & _QIB_PLL_FAIL) {
+               isfatal = 1;
+               snprintf(bitsmsg, sizeof dd->cspec->bitsmsgbuf,
+                        "[PLL failed (%llx), InfiniPath hardware unusable]",
+                        (unsigned long long) hwerrs & _QIB_PLL_FAIL);
+               strlcat(msg, bitsmsg, msgl);
+               /* ignore from now on, so disable until driver reloaded */
+               dd->cspec->hwerrmask &= ~(hwerrs & _QIB_PLL_FAIL);
+               qib_write_kreg(dd, kr_hwerrmask, dd->cspec->hwerrmask);
+       }
+
+       if (hwerrs & QLOGIC_IB_HWE_SERDESPLLFAILED) {
+               /*
+                * If it occurs, it is left masked since the eternal
+                * interface is unused.
+                */
+               dd->cspec->hwerrmask &= ~QLOGIC_IB_HWE_SERDESPLLFAILED;
+               qib_write_kreg(dd, kr_hwerrmask, dd->cspec->hwerrmask);
+       }
+
+       qib_dev_err(dd, "%s hardware error\n", msg);
+
+       if (isfatal && !dd->diag_client) {
+               qib_dev_err(dd, "Fatal Hardware Error, no longer"
+                           " usable, SN %.16s\n", dd->serial);
+               /*
+                * For /sys status file and user programs to print; if no
+                * trailing brace is copied, we'll know it was truncated.
+                */
+               if (dd->freezemsg)
+                       snprintf(dd->freezemsg, dd->freezelen,
+                                "{%s}", msg);
+               qib_disable_after_error(dd);
+       }
+bail:;
+}
+
+/**
+ * qib_7220_init_hwerrors - enable hardware errors
+ * @dd: the qlogic_ib device
+ *
+ * now that we have finished initializing everything that might reasonably
+ * cause a hardware error, and cleared those errors bits as they occur,
+ * we can enable hardware errors in the mask (potentially enabling
+ * freeze mode), and enable hardware errors as errors (along with
+ * everything else) in errormask
+ */
+static void qib_7220_init_hwerrors(struct qib_devdata *dd)
+{
+       u64 val;
+       u64 extsval;
+
+       extsval = qib_read_kreg64(dd, kr_extstatus);
+
+       if (!(extsval & (QLOGIC_IB_EXTS_MEMBIST_ENDTEST |
+                        QLOGIC_IB_EXTS_MEMBIST_DISABLED)))
+               qib_dev_err(dd, "MemBIST did not complete!\n");
+       if (extsval & QLOGIC_IB_EXTS_MEMBIST_DISABLED)
+               qib_devinfo(dd->pcidev, "MemBIST is disabled.\n");
+
+       val = ~0ULL;    /* default to all hwerrors become interrupts, */
+
+       val &= ~QLOGIC_IB_HWE_IB_UC_MEMORYPARITYERR;
+       dd->cspec->hwerrmask = val;
+
+       qib_write_kreg(dd, kr_hwerrclear, ~HWE_MASK(PowerOnBISTFailed));
+       qib_write_kreg(dd, kr_hwerrmask, dd->cspec->hwerrmask);
+
+       /* clear all */
+       qib_write_kreg(dd, kr_errclear, ~0ULL);
+       /* enable errors that are masked, at least this first time. */
+       qib_write_kreg(dd, kr_errmask, ~0ULL);
+       dd->cspec->errormask = qib_read_kreg64(dd, kr_errmask);
+       /* clear any interrupts up to this point (ints still not enabled) */
+       qib_write_kreg(dd, kr_intclear, ~0ULL);
+}
+
+/*
+ * Disable and enable the armlaunch error.  Used for PIO bandwidth testing
+ * on chips that are count-based, rather than trigger-based.  There is no
+ * reference counting, but that's also fine, given the intended use.
+ * Only chip-specific because it's all register accesses
+ */
+static void qib_set_7220_armlaunch(struct qib_devdata *dd, u32 enable)
+{
+       if (enable) {
+               qib_write_kreg(dd, kr_errclear, ERR_MASK(SendPioArmLaunchErr));
+               dd->cspec->errormask |= ERR_MASK(SendPioArmLaunchErr);
+       } else
+               dd->cspec->errormask &= ~ERR_MASK(SendPioArmLaunchErr);
+       qib_write_kreg(dd, kr_errmask, dd->cspec->errormask);
+}
+
+/*
+ * Formerly took parameter <which> in pre-shifted,
+ * pre-merged form with LinkCmd and LinkInitCmd
+ * together, and assuming the zero was NOP.
+ */
+static void qib_set_ib_7220_lstate(struct qib_pportdata *ppd, u16 linkcmd,
+                                  u16 linitcmd)
+{
+       u64 mod_wd;
+       struct qib_devdata *dd = ppd->dd;
+       unsigned long flags;
+
+       if (linitcmd == QLOGIC_IB_IBCC_LINKINITCMD_DISABLE) {
+               /*
+                * If we are told to disable, note that so link-recovery
+                * code does not attempt to bring us back up.
+                */
+               spin_lock_irqsave(&ppd->lflags_lock, flags);
+               ppd->lflags |= QIBL_IB_LINK_DISABLED;
+               spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+       } else if (linitcmd || linkcmd == QLOGIC_IB_IBCC_LINKCMD_DOWN) {
+               /*
+                * Any other linkinitcmd will lead to LINKDOWN and then
+                * to INIT (if all is well), so clear flag to let
+                * link-recovery code attempt to bring us back up.
+                */
+               spin_lock_irqsave(&ppd->lflags_lock, flags);
+               ppd->lflags &= ~QIBL_IB_LINK_DISABLED;
+               spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+       }
+
+       mod_wd = (linkcmd << IBA7220_IBCC_LINKCMD_SHIFT) |
+               (linitcmd << QLOGIC_IB_IBCC_LINKINITCMD_SHIFT);
+
+       qib_write_kreg(dd, kr_ibcctrl, ppd->cpspec->ibcctrl | mod_wd);
+       /* write to chip to prevent back-to-back writes of ibc reg */
+       qib_write_kreg(dd, kr_scratch, 0);
+}
+
+/*
+ * All detailed interaction with the SerDes has been moved to qib_sd7220.c
+ *
+ * The portion of IBA7220-specific bringup_serdes() that actually deals with
+ * registers and memory within the SerDes itself is qib_sd7220_init().
+ */
+
+/**
+ * qib_7220_bringup_serdes - bring up the serdes
+ * @ppd: physical port on the qlogic_ib device
+ */
+static int qib_7220_bringup_serdes(struct qib_pportdata *ppd)
+{
+       struct qib_devdata *dd = ppd->dd;
+       u64 val, prev_val, guid, ibc;
+       int ret = 0;
+
+       /* Put IBC in reset, sends disabled */
+       dd->control &= ~QLOGIC_IB_C_LINKENABLE;
+       qib_write_kreg(dd, kr_control, 0ULL);
+
+       if (qib_compat_ddr_negotiate) {
+               ppd->cpspec->ibdeltainprog = 1;
+               ppd->cpspec->ibsymsnap = read_7220_creg32(dd, cr_ibsymbolerr);
+               ppd->cpspec->iblnkerrsnap =
+                       read_7220_creg32(dd, cr_iblinkerrrecov);
+       }
+
+       /* flowcontrolwatermark is in units of KBytes */
+       ibc = 0x5ULL << SYM_LSB(IBCCtrl, FlowCtrlWaterMark);
+       /*
+        * How often flowctrl sent.  More or less in usecs; balance against
+        * watermark value, so that in theory senders always get a flow
+        * control update in time to not let the IB link go idle.
+        */
+       ibc |= 0x3ULL << SYM_LSB(IBCCtrl, FlowCtrlPeriod);
+       /* max error tolerance */
+       ibc |= 0xfULL << SYM_LSB(IBCCtrl, PhyerrThreshold);
+       /* use "real" buffer space for */
+       ibc |= 4ULL << SYM_LSB(IBCCtrl, CreditScale);
+       /* IB credit flow control. */
+       ibc |= 0xfULL << SYM_LSB(IBCCtrl, OverrunThreshold);
+       /*
+        * set initial max size pkt IBC will send, including ICRC; it's the
+        * PIO buffer size in dwords, less 1; also see qib_set_mtu()
+        */
+       ibc |= ((u64)(ppd->ibmaxlen >> 2) + 1) << SYM_LSB(IBCCtrl, MaxPktLen);
+       ppd->cpspec->ibcctrl = ibc; /* without linkcmd or linkinitcmd! */
+
+       /* initially come up waiting for TS1, without sending anything. */
+       val = ppd->cpspec->ibcctrl | (QLOGIC_IB_IBCC_LINKINITCMD_DISABLE <<
+               QLOGIC_IB_IBCC_LINKINITCMD_SHIFT);
+       qib_write_kreg(dd, kr_ibcctrl, val);
+
+       if (!ppd->cpspec->ibcddrctrl) {
+               /* not on re-init after reset */
+               ppd->cpspec->ibcddrctrl = qib_read_kreg64(dd, kr_ibcddrctrl);
+
+               if (ppd->link_speed_enabled == (QIB_IB_SDR | QIB_IB_DDR))
+                       ppd->cpspec->ibcddrctrl |=
+                               IBA7220_IBC_SPEED_AUTONEG_MASK |
+                               IBA7220_IBC_IBTA_1_2_MASK;
+               else
+                       ppd->cpspec->ibcddrctrl |=
+                               ppd->link_speed_enabled == QIB_IB_DDR ?
+                               IBA7220_IBC_SPEED_DDR : IBA7220_IBC_SPEED_SDR;
+               if ((ppd->link_width_enabled & (IB_WIDTH_1X | IB_WIDTH_4X)) ==
+                   (IB_WIDTH_1X | IB_WIDTH_4X))
+                       ppd->cpspec->ibcddrctrl |= IBA7220_IBC_WIDTH_AUTONEG;
+               else
+                       ppd->cpspec->ibcddrctrl |=
+                               ppd->link_width_enabled == IB_WIDTH_4X ?
+                               IBA7220_IBC_WIDTH_4X_ONLY :
+                               IBA7220_IBC_WIDTH_1X_ONLY;
+
+               /* always enable these on driver reload, not sticky */
+               ppd->cpspec->ibcddrctrl |=
+                       IBA7220_IBC_RXPOL_MASK << IBA7220_IBC_RXPOL_SHIFT;
+               ppd->cpspec->ibcddrctrl |=
+                       IBA7220_IBC_HRTBT_MASK << IBA7220_IBC_HRTBT_SHIFT;
+
+               /* enable automatic lane reversal detection for receive */
+               ppd->cpspec->ibcddrctrl |= IBA7220_IBC_LANE_REV_SUPPORTED;
+       } else
+               /* write to chip to prevent back-to-back writes of ibc reg */
+               qib_write_kreg(dd, kr_scratch, 0);
+
+       qib_write_kreg(dd, kr_ibcddrctrl, ppd->cpspec->ibcddrctrl);
+       qib_write_kreg(dd, kr_scratch, 0);
+
+       qib_write_kreg(dd, kr_ncmodectrl, 0Ull);
+       qib_write_kreg(dd, kr_scratch, 0);
+
+       ret = qib_sd7220_init(dd);
+
+       val = qib_read_kreg64(dd, kr_xgxs_cfg);
+       prev_val = val;
+       val |= QLOGIC_IB_XGXS_FC_SAFE;
+       if (val != prev_val) {
+               qib_write_kreg(dd, kr_xgxs_cfg, val);
+               qib_read_kreg32(dd, kr_scratch);
+       }
+       if (val & QLOGIC_IB_XGXS_RESET)
+               val &= ~QLOGIC_IB_XGXS_RESET;
+       if (val != prev_val)
+               qib_write_kreg(dd, kr_xgxs_cfg, val);
+
+       /* first time through, set port guid */
+       if (!ppd->guid)
+               ppd->guid = dd->base_guid;
+       guid = be64_to_cpu(ppd->guid);
+
+       qib_write_kreg(dd, kr_hrtbt_guid, guid);
+       if (!ret) {
+               dd->control |= QLOGIC_IB_C_LINKENABLE;
+               qib_write_kreg(dd, kr_control, dd->control);
+       } else
+               /* write to chip to prevent back-to-back writes of ibc reg */
+               qib_write_kreg(dd, kr_scratch, 0);
+       return ret;
+}
+
+/**
+ * qib_7220_quiet_serdes - set serdes to txidle
+ * @ppd: physical port of the qlogic_ib device
+ * Called when driver is being unloaded
+ */
+static void qib_7220_quiet_serdes(struct qib_pportdata *ppd)
+{
+       u64 val;
+       struct qib_devdata *dd = ppd->dd;
+       unsigned long flags;
+
+       /* disable IBC */
+       dd->control &= ~QLOGIC_IB_C_LINKENABLE;
+       qib_write_kreg(dd, kr_control,
+                      dd->control | QLOGIC_IB_C_FREEZEMODE);
+
+       ppd->cpspec->chase_end = 0;
+       if (ppd->cpspec->chase_timer.data) /* if initted */
+               del_timer_sync(&ppd->cpspec->chase_timer);
+
+       if (ppd->cpspec->ibsymdelta || ppd->cpspec->iblnkerrdelta ||
+           ppd->cpspec->ibdeltainprog) {
+               u64 diagc;
+
+               /* enable counter writes */
+               diagc = qib_read_kreg64(dd, kr_hwdiagctrl);
+               qib_write_kreg(dd, kr_hwdiagctrl,
+                              diagc | SYM_MASK(HwDiagCtrl, CounterWrEnable));
+
+               if (ppd->cpspec->ibsymdelta || ppd->cpspec->ibdeltainprog) {
+                       val = read_7220_creg32(dd, cr_ibsymbolerr);
+                       if (ppd->cpspec->ibdeltainprog)
+                               val -= val - ppd->cpspec->ibsymsnap;
+                       val -= ppd->cpspec->ibsymdelta;
+                       write_7220_creg(dd, cr_ibsymbolerr, val);
+               }
+               if (ppd->cpspec->iblnkerrdelta || ppd->cpspec->ibdeltainprog) {
+                       val = read_7220_creg32(dd, cr_iblinkerrrecov);
+                       if (ppd->cpspec->ibdeltainprog)
+                               val -= val - ppd->cpspec->iblnkerrsnap;
+                       val -= ppd->cpspec->iblnkerrdelta;
+                       write_7220_creg(dd, cr_iblinkerrrecov, val);
+               }
+
+               /* and disable counter writes */
+               qib_write_kreg(dd, kr_hwdiagctrl, diagc);
+       }
+       qib_set_ib_7220_lstate(ppd, 0, QLOGIC_IB_IBCC_LINKINITCMD_DISABLE);
+
+       spin_lock_irqsave(&ppd->lflags_lock, flags);
+       ppd->lflags &= ~QIBL_IB_AUTONEG_INPROG;
+       spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+       wake_up(&ppd->cpspec->autoneg_wait);
+       cancel_delayed_work(&ppd->cpspec->autoneg_work);
+       flush_scheduled_work();
+
+       shutdown_7220_relock_poll(ppd->dd);
+       val = qib_read_kreg64(ppd->dd, kr_xgxs_cfg);
+       val |= QLOGIC_IB_XGXS_RESET;
+       qib_write_kreg(ppd->dd, kr_xgxs_cfg, val);
+}
+
+/**
+ * qib_setup_7220_setextled - set the state of the two external LEDs
+ * @dd: the qlogic_ib device
+ * @on: whether the link is up or not
+ *
+ * The exact combo of LEDs if on is true is determined by looking
+ * at the ibcstatus.
+ *
+ * These LEDs indicate the physical and logical state of IB link.
+ * For this chip (at least with recommended board pinouts), LED1
+ * is Yellow (logical state) and LED2 is Green (physical state),
+ *
+ * Note:  We try to match the Mellanox HCA LED behavior as best
+ * we can.  Green indicates physical link state is OK (something is
+ * plugged in, and we can train).
+ * Amber indicates the link is logically up (ACTIVE).
+ * Mellanox further blinks the amber LED to indicate data packet
+ * activity, but we have no hardware support for that, so it would
+ * require waking up every 10-20 msecs and checking the counters
+ * on the chip, and then turning the LED off if appropriate.  That's
+ * visible overhead, so not something we will do.
+ *
+ */
+static void qib_setup_7220_setextled(struct qib_pportdata *ppd, u32 on)
+{
+       struct qib_devdata *dd = ppd->dd;
+       u64 extctl, ledblink = 0, val, lst, ltst;
+       unsigned long flags;
+
+       /*
+        * The diags use the LED to indicate diag info, so we leave
+        * the external LED alone when the diags are running.
+        */
+       if (dd->diag_client)
+               return;
+
+       if (ppd->led_override) {
+               ltst = (ppd->led_override & QIB_LED_PHYS) ?
+                       IB_PHYSPORTSTATE_LINKUP : IB_PHYSPORTSTATE_DISABLED,
+               lst = (ppd->led_override & QIB_LED_LOG) ?
+                       IB_PORT_ACTIVE : IB_PORT_DOWN;
+       } else if (on) {
+               val = qib_read_kreg64(dd, kr_ibcstatus);
+               ltst = qib_7220_phys_portstate(val);
+               lst = qib_7220_iblink_state(val);
+       } else {
+               ltst = 0;
+               lst = 0;
+       }
+
+       spin_lock_irqsave(&dd->cspec->gpio_lock, flags);
+       extctl = dd->cspec->extctrl & ~(SYM_MASK(EXTCtrl, LEDPriPortGreenOn) |
+                                SYM_MASK(EXTCtrl, LEDPriPortYellowOn));
+       if (ltst == IB_PHYSPORTSTATE_LINKUP) {
+               extctl |= SYM_MASK(EXTCtrl, LEDPriPortGreenOn);
+               /*
+                * counts are in chip clock (4ns) periods.
+                * This is 1/16 sec (66.6ms) on,
+                * 3/16 sec (187.5 ms) off, with packets rcvd
+                */
+               ledblink = ((66600 * 1000UL / 4) << IBA7220_LEDBLINK_ON_SHIFT)
+                       | ((187500 * 1000UL / 4) << IBA7220_LEDBLINK_OFF_SHIFT);
+       }
+       if (lst == IB_PORT_ACTIVE)
+               extctl |= SYM_MASK(EXTCtrl, LEDPriPortYellowOn);
+       dd->cspec->extctrl = extctl;
+       qib_write_kreg(dd, kr_extctrl, extctl);
+       spin_unlock_irqrestore(&dd->cspec->gpio_lock, flags);
+
+       if (ledblink) /* blink the LED on packet receive */
+               qib_write_kreg(dd, kr_rcvpktledcnt, ledblink);
+}
+
+static void qib_7220_free_irq(struct qib_devdata *dd)
+{
+       if (dd->cspec->irq) {
+               free_irq(dd->cspec->irq, dd);
+               dd->cspec->irq = 0;
+       }
+       qib_nomsi(dd);
+}
+
+/*
+ * qib_setup_7220_cleanup - clean up any per-chip chip-specific stuff
+ * @dd: the qlogic_ib device
+ *
+ * This is called during driver unload.
+ *
+ */
+static void qib_setup_7220_cleanup(struct qib_devdata *dd)
+{
+       qib_7220_free_irq(dd);
+       kfree(dd->cspec->cntrs);
+       kfree(dd->cspec->portcntrs);
+}
+
+/*
+ * This is only called for SDmaInt.
+ * SDmaDisabled is handled on the error path.
+ */
+static void sdma_7220_intr(struct qib_pportdata *ppd, u64 istat)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ppd->sdma_lock, flags);
+
+       switch (ppd->sdma_state.current_state) {
+       case qib_sdma_state_s00_hw_down:
+               break;
+
+       case qib_sdma_state_s10_hw_start_up_wait:
+               __qib_sdma_process_event(ppd, qib_sdma_event_e20_hw_started);
+               break;
+
+       case qib_sdma_state_s20_idle:
+               break;
+
+       case qib_sdma_state_s30_sw_clean_up_wait:
+               break;
+
+       case qib_sdma_state_s40_hw_clean_up_wait:
+               break;
+
+       case qib_sdma_state_s50_hw_halt_wait:
+               __qib_sdma_process_event(ppd, qib_sdma_event_e60_hw_halted);
+               break;
+
+       case qib_sdma_state_s99_running:
+               /* too chatty to print here */
+               __qib_sdma_intr(ppd);
+               break;
+       }
+       spin_unlock_irqrestore(&ppd->sdma_lock, flags);
+}
+
+static void qib_wantpiobuf_7220_intr(struct qib_devdata *dd, u32 needint)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&dd->sendctrl_lock, flags);
+       if (needint) {
+               if (!(dd->sendctrl & SYM_MASK(SendCtrl, SendBufAvailUpd)))
+                       goto done;
+               /*
+                * blip the availupd off, next write will be on, so
+                * we ensure an avail update, regardless of threshold or
+                * buffers becoming free, whenever we want an interrupt
+                */
+               qib_write_kreg(dd, kr_sendctrl, dd->sendctrl &
+                       ~SYM_MASK(SendCtrl, SendBufAvailUpd));
+               qib_write_kreg(dd, kr_scratch, 0ULL);
+               dd->sendctrl |= SYM_MASK(SendCtrl, SendIntBufAvail);
+       } else
+               dd->sendctrl &= ~SYM_MASK(SendCtrl, SendIntBufAvail);
+       qib_write_kreg(dd, kr_sendctrl, dd->sendctrl);
+       qib_write_kreg(dd, kr_scratch, 0ULL);
+done:
+       spin_unlock_irqrestore(&dd->sendctrl_lock, flags);
+}
+
+/*
+ * Handle errors and unusual events first, separate function
+ * to improve cache hits for fast path interrupt handling.
+ */
+static noinline void unlikely_7220_intr(struct qib_devdata *dd, u64 istat)
+{
+       if (unlikely(istat & ~QLOGIC_IB_I_BITSEXTANT))
+               qib_dev_err(dd,
+                           "interrupt with unknown interrupts %Lx set\n",
+                           istat & ~QLOGIC_IB_I_BITSEXTANT);
+
+       if (istat & QLOGIC_IB_I_GPIO) {
+               u32 gpiostatus;
+
+               /*
+                * Boards for this chip currently don't use GPIO interrupts,
+                * so clear by writing GPIOstatus to GPIOclear, and complain
+                * to alert developer. To avoid endless repeats, clear
+                * the bits in the mask, since there is some kind of
+                * programming error or chip problem.
+                */
+               gpiostatus = qib_read_kreg32(dd, kr_gpio_status);
+               /*
+                * In theory, writing GPIOstatus to GPIOclear could
+                * have a bad side-effect on some diagnostic that wanted
+                * to poll for a status-change, but the various shadows
+                * make that problematic at best. Diags will just suppress
+                * all GPIO interrupts during such tests.
+                */
+               qib_write_kreg(dd, kr_gpio_clear, gpiostatus);
+
+               if (gpiostatus) {
+                       const u32 mask = qib_read_kreg32(dd, kr_gpio_mask);
+                       u32 gpio_irq = mask & gpiostatus;
+
+                       /*
+                        * A bit set in status and (chip) Mask register
+                        * would cause an interrupt. Since we are not
+                        * expecting any, report it. Also check that the
+                        * chip reflects our shadow, report issues,
+                        * and refresh from the shadow.
+                        */
+                       /*
+                        * Clear any troublemakers, and update chip
+                        * from shadow
+                        */
+                       dd->cspec->gpio_mask &= ~gpio_irq;
+                       qib_write_kreg(dd, kr_gpio_mask, dd->cspec->gpio_mask);
+               }
+       }
+
+       if (istat & QLOGIC_IB_I_ERROR) {
+               u64 estat;
+
+               qib_stats.sps_errints++;
+               estat = qib_read_kreg64(dd, kr_errstatus);
+               if (!estat)
+                       qib_devinfo(dd->pcidev, "error interrupt (%Lx), "
+                                "but no error bits set!\n", istat);
+               else
+                       handle_7220_errors(dd, estat);
+       }
+}
+
+static irqreturn_t qib_7220intr(int irq, void *data)
+{
+       struct qib_devdata *dd = data;
+       irqreturn_t ret;
+       u64 istat;
+       u64 ctxtrbits;
+       u64 rmask;
+       unsigned i;
+
+       if ((dd->flags & (QIB_PRESENT | QIB_BADINTR)) != QIB_PRESENT) {
+               /*
+                * This return value is not great, but we do not want the
+                * interrupt core code to remove our interrupt handler
+                * because we don't appear to be handling an interrupt
+                * during a chip reset.
+                */
+               ret = IRQ_HANDLED;
+               goto bail;
+       }
+
+       istat = qib_read_kreg64(dd, kr_intstatus);
+
+       if (unlikely(!istat)) {
+               ret = IRQ_NONE; /* not our interrupt, or already handled */
+               goto bail;
+       }
+       if (unlikely(istat == -1)) {
+               qib_bad_intrstatus(dd);
+               /* don't know if it was our interrupt or not */
+               ret = IRQ_NONE;
+               goto bail;
+       }
+
+       qib_stats.sps_ints++;
+       if (dd->int_counter != (u32) -1)
+               dd->int_counter++;
+
+       if (unlikely(istat & (~QLOGIC_IB_I_BITSEXTANT |
+                             QLOGIC_IB_I_GPIO | QLOGIC_IB_I_ERROR)))
+               unlikely_7220_intr(dd, istat);
+
+       /*
+        * Clear the interrupt bits we found set, relatively early, so we
+        * "know" know the chip will have seen this by the time we process
+        * the queue, and will re-interrupt if necessary.  The processor
+        * itself won't take the interrupt again until we return.
+        */
+       qib_write_kreg(dd, kr_intclear, istat);
+
+       /*
+        * Handle kernel receive queues before checking for pio buffers
+        * available since receives can overflow; piobuf waiters can afford
+        * a few extra cycles, since they were waiting anyway.
+        */
+       ctxtrbits = istat &
+               ((QLOGIC_IB_I_RCVAVAIL_MASK << QLOGIC_IB_I_RCVAVAIL_SHIFT) |
+                (QLOGIC_IB_I_RCVURG_MASK << QLOGIC_IB_I_RCVURG_SHIFT));
+       if (ctxtrbits) {
+               rmask = (1ULL << QLOGIC_IB_I_RCVAVAIL_SHIFT) |
+                       (1ULL << QLOGIC_IB_I_RCVURG_SHIFT);
+               for (i = 0; i < dd->first_user_ctxt; i++) {
+                       if (ctxtrbits & rmask) {
+                               ctxtrbits &= ~rmask;
+                               qib_kreceive(dd->rcd[i], NULL, NULL);
+                       }
+                       rmask <<= 1;
+               }
+               if (ctxtrbits) {
+                       ctxtrbits =
+                               (ctxtrbits >> QLOGIC_IB_I_RCVAVAIL_SHIFT) |
+                               (ctxtrbits >> QLOGIC_IB_I_RCVURG_SHIFT);
+                       qib_handle_urcv(dd, ctxtrbits);
+               }
+       }
+
+       /* only call for SDmaInt */
+       if (istat & QLOGIC_IB_I_SDMAINT)
+               sdma_7220_intr(dd->pport, istat);
+
+       if ((istat & QLOGIC_IB_I_SPIOBUFAVAIL) && (dd->flags & QIB_INITTED))
+               qib_ib_piobufavail(dd);
+
+       ret = IRQ_HANDLED;
+bail:
+       return ret;
+}
+
+/*
+ * Set up our chip-specific interrupt handler.
+ * The interrupt type has already been setup, so
+ * we just need to do the registration and error checking.
+ * If we are using MSI interrupts, we may fall back to
+ * INTx later, if the interrupt handler doesn't get called
+ * within 1/2 second (see verify_interrupt()).
+ */
+static void qib_setup_7220_interrupt(struct qib_devdata *dd)
+{
+       if (!dd->cspec->irq)
+               qib_dev_err(dd, "irq is 0, BIOS error?  Interrupts won't "
+                           "work\n");
+       else {
+               int ret = request_irq(dd->cspec->irq, qib_7220intr,
+                       dd->msi_lo ? 0 : IRQF_SHARED,
+                       QIB_DRV_NAME, dd);
+
+               if (ret)
+                       qib_dev_err(dd, "Couldn't setup %s interrupt "
+                                   "(irq=%d): %d\n", dd->msi_lo ?
+                                   "MSI" : "INTx", dd->cspec->irq, ret);
+       }
+}
+
+/**
+ * qib_7220_boardname - fill in the board name
+ * @dd: the qlogic_ib device
+ *
+ * info is based on the board revision register
+ */
+static void qib_7220_boardname(struct qib_devdata *dd)
+{
+       char *n;
+       u32 boardid, namelen;
+
+       boardid = SYM_FIELD(dd->revision, Revision,
+                           BoardID);
+
+       switch (boardid) {
+       case 1:
+               n = "InfiniPath_QLE7240";
+               break;
+       case 2:
+               n = "InfiniPath_QLE7280";
+               break;
+       default:
+               qib_dev_err(dd, "Unknown 7220 board with ID %u\n", boardid);
+               n = "Unknown_InfiniPath_7220";
+               break;
+       }
+
+       namelen = strlen(n) + 1;
+       dd->boardname = kmalloc(namelen, GFP_KERNEL);
+       if (!dd->boardname)
+               qib_dev_err(dd, "Failed allocation for board name: %s\n", n);
+       else
+               snprintf(dd->boardname, namelen, "%s", n);
+
+       if (dd->majrev != 5 || !dd->minrev || dd->minrev > 2)
+               qib_dev_err(dd, "Unsupported InfiniPath hardware "
+                           "revision %u.%u!\n",
+                           dd->majrev, dd->minrev);
+
+       snprintf(dd->boardversion, sizeof(dd->boardversion),
+                "ChipABI %u.%u, %s, InfiniPath%u %u.%u, SW Compat %u\n",
+                QIB_CHIP_VERS_MAJ, QIB_CHIP_VERS_MIN, dd->boardname,
+                (unsigned)SYM_FIELD(dd->revision, Revision_R, Arch),
+                dd->majrev, dd->minrev,
+                (unsigned)SYM_FIELD(dd->revision, Revision_R, SW));
+}
+
+/*
+ * This routine sleeps, so it can only be called from user context, not
+ * from interrupt context.
+ */
+static int qib_setup_7220_reset(struct qib_devdata *dd)
+{
+       u64 val;
+       int i;
+       int ret;
+       u16 cmdval;
+       u8 int_line, clinesz;
+       unsigned long flags;
+
+       qib_pcie_getcmd(dd, &cmdval, &int_line, &clinesz);
+
+       /* Use dev_err so it shows up in logs, etc. */
+       qib_dev_err(dd, "Resetting InfiniPath unit %u\n", dd->unit);
+
+       /* no interrupts till re-initted */
+       qib_7220_set_intr_state(dd, 0);
+
+       dd->pport->cpspec->ibdeltainprog = 0;
+       dd->pport->cpspec->ibsymdelta = 0;
+       dd->pport->cpspec->iblnkerrdelta = 0;
+
+       /*
+        * Keep chip from being accessed until we are ready.  Use
+        * writeq() directly, to allow the write even though QIB_PRESENT
+        * isnt' set.
+        */
+       dd->flags &= ~(QIB_INITTED | QIB_PRESENT);
+       dd->int_counter = 0; /* so we check interrupts work again */
+       val = dd->control | QLOGIC_IB_C_RESET;
+       writeq(val, &dd->kregbase[kr_control]);
+       mb(); /* prevent compiler reordering around actual reset */
+
+       for (i = 1; i <= 5; i++) {
+               /*
+                * Allow MBIST, etc. to complete; longer on each retry.
+                * We sometimes get machine checks from bus timeout if no
+                * response, so for now, make it *really* long.
+                */
+               msleep(1000 + (1 + i) * 2000);
+
+               qib_pcie_reenable(dd, cmdval, int_line, clinesz);
+
+               /*
+                * Use readq directly, so we don't need to mark it as PRESENT
+                * until we get a successful indication that all is well.
+                */
+               val = readq(&dd->kregbase[kr_revision]);
+               if (val == dd->revision) {
+                       dd->flags |= QIB_PRESENT; /* it's back */
+                       ret = qib_reinit_intr(dd);
+                       goto bail;
+               }
+       }
+       ret = 0; /* failed */
+
+bail:
+       if (ret) {
+               if (qib_pcie_params(dd, dd->lbus_width, NULL, NULL))
+                       qib_dev_err(dd, "Reset failed to setup PCIe or "
+                                   "interrupts; continuing anyway\n");
+
+               /* hold IBC in reset, no sends, etc till later */
+               qib_write_kreg(dd, kr_control, 0ULL);
+
+               /* clear the reset error, init error/hwerror mask */
+               qib_7220_init_hwerrors(dd);
+
+               /* do setup similar to speed or link-width changes */
+               if (dd->pport->cpspec->ibcddrctrl & IBA7220_IBC_IBTA_1_2_MASK)
+                       dd->cspec->presets_needed = 1;
+               spin_lock_irqsave(&dd->pport->lflags_lock, flags);
+               dd->pport->lflags |= QIBL_IB_FORCE_NOTIFY;
+               dd->pport->lflags &= ~QIBL_IB_AUTONEG_FAILED;
+               spin_unlock_irqrestore(&dd->pport->lflags_lock, flags);
+       }
+
+       return ret;
+}
+
+/**
+ * qib_7220_put_tid - write a TID to the chip
+ * @dd: the qlogic_ib device
+ * @tidptr: pointer to the expected TID (in chip) to update
+ * @tidtype: 0 for eager, 1 for expected
+ * @pa: physical address of in memory buffer; tidinvalid if freeing
+ */
+static void qib_7220_put_tid(struct qib_devdata *dd, u64 __iomem *tidptr,
+                            u32 type, unsigned long pa)
+{
+       if (pa != dd->tidinvalid) {
+               u64 chippa = pa >> IBA7220_TID_PA_SHIFT;
+
+               /* paranoia checks */
+               if (pa != (chippa << IBA7220_TID_PA_SHIFT)) {
+                       qib_dev_err(dd, "Physaddr %lx not 2KB aligned!\n",
+                                   pa);
+                       return;
+               }
+               if (chippa >= (1UL << IBA7220_TID_SZ_SHIFT)) {
+                       qib_dev_err(dd, "Physical page address 0x%lx "
+                               "larger than supported\n", pa);
+                       return;
+               }
+
+               if (type == RCVHQ_RCV_TYPE_EAGER)
+                       chippa |= dd->tidtemplate;
+               else /* for now, always full 4KB page */
+                       chippa |= IBA7220_TID_SZ_4K;
+               pa = chippa;
+       }
+       writeq(pa, tidptr);
+       mmiowb();
+}
+
+/**
+ * qib_7220_clear_tids - clear all TID entries for a ctxt, expected and eager
+ * @dd: the qlogic_ib device
+ * @ctxt: the ctxt
+ *
+ * clear all TID entries for a ctxt, expected and eager.
+ * Used from qib_close().  On this chip, TIDs are only 32 bits,
+ * not 64, but they are still on 64 bit boundaries, so tidbase
+ * is declared as u64 * for the pointer math, even though we write 32 bits
+ */
+static void qib_7220_clear_tids(struct qib_devdata *dd,
+                               struct qib_ctxtdata *rcd)
+{
+       u64 __iomem *tidbase;
+       unsigned long tidinv;
+       u32 ctxt;
+       int i;
+
+       if (!dd->kregbase || !rcd)
+               return;
+
+       ctxt = rcd->ctxt;
+
+       tidinv = dd->tidinvalid;
+       tidbase = (u64 __iomem *)
+               ((char __iomem *)(dd->kregbase) +
+                dd->rcvtidbase +
+                ctxt * dd->rcvtidcnt * sizeof(*tidbase));
+
+       for (i = 0; i < dd->rcvtidcnt; i++)
+               qib_7220_put_tid(dd, &tidbase[i], RCVHQ_RCV_TYPE_EXPECTED,
+                                tidinv);
+
+       tidbase = (u64 __iomem *)
+               ((char __iomem *)(dd->kregbase) +
+                dd->rcvegrbase +
+                rcd->rcvegr_tid_base * sizeof(*tidbase));
+
+       for (i = 0; i < rcd->rcvegrcnt; i++)
+               qib_7220_put_tid(dd, &tidbase[i], RCVHQ_RCV_TYPE_EAGER,
+                                tidinv);
+}
+
+/**
+ * qib_7220_tidtemplate - setup constants for TID updates
+ * @dd: the qlogic_ib device
+ *
+ * We setup stuff that we use a lot, to avoid calculating each time
+ */
+static void qib_7220_tidtemplate(struct qib_devdata *dd)
+{
+       if (dd->rcvegrbufsize == 2048)
+               dd->tidtemplate = IBA7220_TID_SZ_2K;
+       else if (dd->rcvegrbufsize == 4096)
+               dd->tidtemplate = IBA7220_TID_SZ_4K;
+       dd->tidinvalid = 0;
+}
+
+/**
+ * qib_init_7220_get_base_info - set chip-specific flags for user code
+ * @rcd: the qlogic_ib ctxt
+ * @kbase: qib_base_info pointer
+ *
+ * We set the PCIE flag because the lower bandwidth on PCIe vs
+ * HyperTransport can affect some user packet algorithims.
+ */
+static int qib_7220_get_base_info(struct qib_ctxtdata *rcd,
+                                 struct qib_base_info *kinfo)
+{
+       kinfo->spi_runtime_flags |= QIB_RUNTIME_PCIE |
+               QIB_RUNTIME_NODMA_RTAIL | QIB_RUNTIME_SDMA;
+
+       if (rcd->dd->flags & QIB_USE_SPCL_TRIG)
+               kinfo->spi_runtime_flags |= QIB_RUNTIME_SPECIAL_TRIGGER;
+
+       return 0;
+}
+
+static struct qib_message_header *
+qib_7220_get_msgheader(struct qib_devdata *dd, __le32 *rhf_addr)
+{
+       u32 offset = qib_hdrget_offset(rhf_addr);
+
+       return (struct qib_message_header *)
+               (rhf_addr - dd->rhf_offset + offset);
+}
+
+static void qib_7220_config_ctxts(struct qib_devdata *dd)
+{
+       unsigned long flags;
+       u32 nchipctxts;
+
+       nchipctxts = qib_read_kreg32(dd, kr_portcnt);
+       dd->cspec->numctxts = nchipctxts;
+       if (qib_n_krcv_queues > 1) {
+               dd->qpn_mask = 0x3f;
+               dd->first_user_ctxt = qib_n_krcv_queues * dd->num_pports;
+               if (dd->first_user_ctxt > nchipctxts)
+                       dd->first_user_ctxt = nchipctxts;
+       } else
+               dd->first_user_ctxt = dd->num_pports;
+       dd->n_krcv_queues = dd->first_user_ctxt;
+
+       if (!qib_cfgctxts) {
+               int nctxts = dd->first_user_ctxt + num_online_cpus();
+
+               if (nctxts <= 5)
+                       dd->ctxtcnt = 5;
+               else if (nctxts <= 9)
+                       dd->ctxtcnt = 9;
+               else if (nctxts <= nchipctxts)
+                       dd->ctxtcnt = nchipctxts;
+       } else if (qib_cfgctxts <= nchipctxts)
+               dd->ctxtcnt = qib_cfgctxts;
+       if (!dd->ctxtcnt) /* none of the above, set to max */
+               dd->ctxtcnt = nchipctxts;
+
+       /*
+        * Chip can be configured for 5, 9, or 17 ctxts, and choice
+        * affects number of eager TIDs per ctxt (1K, 2K, 4K).
+        * Lock to be paranoid about later motion, etc.
+        */
+       spin_lock_irqsave(&dd->cspec->rcvmod_lock, flags);
+       if (dd->ctxtcnt > 9)
+               dd->rcvctrl |= 2ULL << IBA7220_R_CTXTCFG_SHIFT;
+       else if (dd->ctxtcnt > 5)
+               dd->rcvctrl |= 1ULL << IBA7220_R_CTXTCFG_SHIFT;
+       /* else configure for default 5 receive ctxts */
+       if (dd->qpn_mask)
+               dd->rcvctrl |= 1ULL << QIB_7220_RcvCtrl_RcvQPMapEnable_LSB;
+       qib_write_kreg(dd, kr_rcvctrl, dd->rcvctrl);
+       spin_unlock_irqrestore(&dd->cspec->rcvmod_lock, flags);
+
+       /* kr_rcvegrcnt changes based on the number of contexts enabled */
+       dd->cspec->rcvegrcnt = qib_read_kreg32(dd, kr_rcvegrcnt);
+       dd->rcvhdrcnt = max(dd->cspec->rcvegrcnt, IBA7220_KRCVEGRCNT);
+}
+
+static int qib_7220_get_ib_cfg(struct qib_pportdata *ppd, int which)
+{
+       int lsb, ret = 0;
+       u64 maskr; /* right-justified mask */
+
+       switch (which) {
+       case QIB_IB_CFG_LWID_ENB: /* Get allowed Link-width */
+               ret = ppd->link_width_enabled;
+               goto done;
+
+       case QIB_IB_CFG_LWID: /* Get currently active Link-width */
+               ret = ppd->link_width_active;
+               goto done;
+
+       case QIB_IB_CFG_SPD_ENB: /* Get allowed Link speeds */
+               ret = ppd->link_speed_enabled;
+               goto done;
+
+       case QIB_IB_CFG_SPD: /* Get current Link spd */
+               ret = ppd->link_speed_active;
+               goto done;
+
+       case QIB_IB_CFG_RXPOL_ENB: /* Get Auto-RX-polarity enable */
+               lsb = IBA7220_IBC_RXPOL_SHIFT;
+               maskr = IBA7220_IBC_RXPOL_MASK;
+               break;
+
+       case QIB_IB_CFG_LREV_ENB: /* Get Auto-Lane-reversal enable */
+               lsb = IBA7220_IBC_LREV_SHIFT;
+               maskr = IBA7220_IBC_LREV_MASK;
+               break;
+
+       case QIB_IB_CFG_LINKLATENCY:
+               ret = qib_read_kreg64(ppd->dd, kr_ibcddrstatus)
+                       & IBA7220_DDRSTAT_LINKLAT_MASK;
+               goto done;
+
+       case QIB_IB_CFG_OP_VLS:
+               ret = ppd->vls_operational;
+               goto done;
+
+       case QIB_IB_CFG_VL_HIGH_CAP:
+               ret = 0;
+               goto done;
+
+       case QIB_IB_CFG_VL_LOW_CAP:
+               ret = 0;
+               goto done;
+
+       case QIB_IB_CFG_OVERRUN_THRESH: /* IB overrun threshold */
+               ret = SYM_FIELD(ppd->cpspec->ibcctrl, IBCCtrl,
+                               OverrunThreshold);
+               goto done;
+
+       case QIB_IB_CFG_PHYERR_THRESH: /* IB PHY error threshold */
+               ret = SYM_FIELD(ppd->cpspec->ibcctrl, IBCCtrl,
+                               PhyerrThreshold);
+               goto done;
+
+       case QIB_IB_CFG_LINKDEFAULT: /* IB link default (sleep/poll) */
+               /* will only take effect when the link state changes */
+               ret = (ppd->cpspec->ibcctrl &
+                      SYM_MASK(IBCCtrl, LinkDownDefaultState)) ?
+                       IB_LINKINITCMD_SLEEP : IB_LINKINITCMD_POLL;
+               goto done;
+
+       case QIB_IB_CFG_HRTBT: /* Get Heartbeat off/enable/auto */
+               lsb = IBA7220_IBC_HRTBT_SHIFT;
+               maskr = IBA7220_IBC_HRTBT_MASK;
+               break;
+
+       case QIB_IB_CFG_PMA_TICKS:
+               /*
+                * 0x00 = 10x link transfer rate or 4 nsec. for 2.5Gbs
+                * Since the clock is always 250MHz, the value is 1 or 0.
+                */
+               ret = (ppd->link_speed_active == QIB_IB_DDR);
+               goto done;
+
+       default:
+               ret = -EINVAL;
+               goto done;
+       }
+       ret = (int)((ppd->cpspec->ibcddrctrl >> lsb) & maskr);
+done:
+       return ret;
+}
+
+static int qib_7220_set_ib_cfg(struct qib_pportdata *ppd, int which, u32 val)
+{
+       struct qib_devdata *dd = ppd->dd;
+       u64 maskr; /* right-justified mask */
+       int lsb, ret = 0, setforce = 0;
+       u16 lcmd, licmd;
+       unsigned long flags;
+
+       switch (which) {
+       case QIB_IB_CFG_LIDLMC:
+               /*
+                * Set LID and LMC. Combined to avoid possible hazard
+                * caller puts LMC in 16MSbits, DLID in 16LSbits of val
+                */
+               lsb = IBA7220_IBC_DLIDLMC_SHIFT;
+               maskr = IBA7220_IBC_DLIDLMC_MASK;
+               break;
+
+       case QIB_IB_CFG_LWID_ENB: /* set allowed Link-width */
+               /*
+                * As with speed, only write the actual register if
+                * the link is currently down, otherwise takes effect
+                * on next link change.
+                */
+               ppd->link_width_enabled = val;
+               if (!(ppd->lflags & QIBL_LINKDOWN))
+                       goto bail;
+               /*
+                * We set the QIBL_IB_FORCE_NOTIFY bit so updown
+                * will get called because we want update
+                * link_width_active, and the change may not take
+                * effect for some time (if we are in POLL), so this
+                * flag will force the updown routine to be called
+                * on the next ibstatuschange down interrupt, even
+                * if it's not an down->up transition.
+                */
+               val--; /* convert from IB to chip */
+               maskr = IBA7220_IBC_WIDTH_MASK;
+               lsb = IBA7220_IBC_WIDTH_SHIFT;
+               setforce = 1;
+               spin_lock_irqsave(&ppd->lflags_lock, flags);
+               ppd->lflags |= QIBL_IB_FORCE_NOTIFY;
+               spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+               break;
+
+       case QIB_IB_CFG_SPD_ENB: /* set allowed Link speeds */
+               /*
+                * If we turn off IB1.2, need to preset SerDes defaults,
+                * but not right now. Set a flag for the next time
+                * we command the link down.  As with width, only write the
+                * actual register if the link is currently down, otherwise
+                * takes effect on next link change.  Since setting is being
+                * explictly requested (via MAD or sysfs), clear autoneg
+                * failure status if speed autoneg is enabled.
+                */
+               ppd->link_speed_enabled = val;
+               if ((ppd->cpspec->ibcddrctrl & IBA7220_IBC_IBTA_1_2_MASK) &&
+                   !(val & (val - 1)))
+                       dd->cspec->presets_needed = 1;
+               if (!(ppd->lflags & QIBL_LINKDOWN))
+                       goto bail;
+               /*
+                * We set the QIBL_IB_FORCE_NOTIFY bit so updown
+                * will get called because we want update
+                * link_speed_active, and the change may not take
+                * effect for some time (if we are in POLL), so this
+                * flag will force the updown routine to be called
+                * on the next ibstatuschange down interrupt, even
+                * if it's not an down->up transition.
+                */
+               if (val == (QIB_IB_SDR | QIB_IB_DDR)) {
+                       val = IBA7220_IBC_SPEED_AUTONEG_MASK |
+                               IBA7220_IBC_IBTA_1_2_MASK;
+                       spin_lock_irqsave(&ppd->lflags_lock, flags);
+                       ppd->lflags &= ~QIBL_IB_AUTONEG_FAILED;
+                       spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+               } else
+                       val = val == QIB_IB_DDR ?
+                               IBA7220_IBC_SPEED_DDR : IBA7220_IBC_SPEED_SDR;
+               maskr = IBA7220_IBC_SPEED_AUTONEG_MASK |
+                       IBA7220_IBC_IBTA_1_2_MASK;
+               /* IBTA 1.2 mode + speed bits are contiguous */
+               lsb = SYM_LSB(IBCDDRCtrl, IB_ENHANCED_MODE);
+               setforce = 1;
+               break;
+
+       case QIB_IB_CFG_RXPOL_ENB: /* set Auto-RX-polarity enable */
+               lsb = IBA7220_IBC_RXPOL_SHIFT;
+               maskr = IBA7220_IBC_RXPOL_MASK;
+               break;
+
+       case QIB_IB_CFG_LREV_ENB: /* set Auto-Lane-reversal enable */
+               lsb = IBA7220_IBC_LREV_SHIFT;
+               maskr = IBA7220_IBC_LREV_MASK;
+               break;
+
+       case QIB_IB_CFG_OVERRUN_THRESH: /* IB overrun threshold */
+               maskr = SYM_FIELD(ppd->cpspec->ibcctrl, IBCCtrl,
+                                 OverrunThreshold);
+               if (maskr != val) {
+                       ppd->cpspec->ibcctrl &=
+                               ~SYM_MASK(IBCCtrl, OverrunThreshold);
+                       ppd->cpspec->ibcctrl |= (u64) val <<
+                               SYM_LSB(IBCCtrl, OverrunThreshold);
+                       qib_write_kreg(dd, kr_ibcctrl, ppd->cpspec->ibcctrl);
+                       qib_write_kreg(dd, kr_scratch, 0);
+               }
+               goto bail;
+
+       case QIB_IB_CFG_PHYERR_THRESH: /* IB PHY error threshold */
+               maskr = SYM_FIELD(ppd->cpspec->ibcctrl, IBCCtrl,
+                                 PhyerrThreshold);
+               if (maskr != val) {
+                       ppd->cpspec->ibcctrl &=
+                               ~SYM_MASK(IBCCtrl, PhyerrThreshold);
+                       ppd->cpspec->ibcctrl |= (u64) val <<
+                               SYM_LSB(IBCCtrl, PhyerrThreshold);
+                       qib_write_kreg(dd, kr_ibcctrl, ppd->cpspec->ibcctrl);
+                       qib_write_kreg(dd, kr_scratch, 0);
+               }
+               goto bail;
+
+       case QIB_IB_CFG_PKEYS: /* update pkeys */
+               maskr = (u64) ppd->pkeys[0] | ((u64) ppd->pkeys[1] << 16) |
+                       ((u64) ppd->pkeys[2] << 32) |
+                       ((u64) ppd->pkeys[3] << 48);
+               qib_write_kreg(dd, kr_partitionkey, maskr);
+               goto bail;
+
+       case QIB_IB_CFG_LINKDEFAULT: /* IB link default (sleep/poll) */
+               /* will only take effect when the link state changes */
+               if (val == IB_LINKINITCMD_POLL)
+                       ppd->cpspec->ibcctrl &=
+                               ~SYM_MASK(IBCCtrl, LinkDownDefaultState);
+               else /* SLEEP */
+                       ppd->cpspec->ibcctrl |=
+                               SYM_MASK(IBCCtrl, LinkDownDefaultState);
+               qib_write_kreg(dd, kr_ibcctrl, ppd->cpspec->ibcctrl);
+               qib_write_kreg(dd, kr_scratch, 0);
+               goto bail;
+
+       case QIB_IB_CFG_MTU: /* update the MTU in IBC */
+               /*
+                * Update our housekeeping variables, and set IBC max
+                * size, same as init code; max IBC is max we allow in
+                * buffer, less the qword pbc, plus 1 for ICRC, in dwords
+                * Set even if it's unchanged, print debug message only
+                * on changes.
+                */
+               val = (ppd->ibmaxlen >> 2) + 1;
+               ppd->cpspec->ibcctrl &= ~SYM_MASK(IBCCtrl, MaxPktLen);
+               ppd->cpspec->ibcctrl |= (u64)val << SYM_LSB(IBCCtrl, MaxPktLen);
+               qib_write_kreg(dd, kr_ibcctrl, ppd->cpspec->ibcctrl);
+               qib_write_kreg(dd, kr_scratch, 0);
+               goto bail;
+
+       case QIB_IB_CFG_LSTATE: /* set the IB link state */
+               switch (val & 0xffff0000) {
+               case IB_LINKCMD_DOWN:
+                       lcmd = QLOGIC_IB_IBCC_LINKCMD_DOWN;
+                       if (!ppd->cpspec->ibdeltainprog &&
+                           qib_compat_ddr_negotiate) {
+                               ppd->cpspec->ibdeltainprog = 1;
+                               ppd->cpspec->ibsymsnap =
+                                       read_7220_creg32(dd, cr_ibsymbolerr);
+                               ppd->cpspec->iblnkerrsnap =
+                                       read_7220_creg32(dd, cr_iblinkerrrecov);
+                       }
+                       break;
+
+               case IB_LINKCMD_ARMED:
+                       lcmd = QLOGIC_IB_IBCC_LINKCMD_ARMED;
+                       break;
+
+               case IB_LINKCMD_ACTIVE:
+                       lcmd = QLOGIC_IB_IBCC_LINKCMD_ACTIVE;
+                       break;
+
+               default:
+                       ret = -EINVAL;
+                       qib_dev_err(dd, "bad linkcmd req 0x%x\n", val >> 16);
+                       goto bail;
+               }
+               switch (val & 0xffff) {
+               case IB_LINKINITCMD_NOP:
+                       licmd = 0;
+                       break;
+
+               case IB_LINKINITCMD_POLL:
+                       licmd = QLOGIC_IB_IBCC_LINKINITCMD_POLL;
+                       break;
+
+               case IB_LINKINITCMD_SLEEP:
+                       licmd = QLOGIC_IB_IBCC_LINKINITCMD_SLEEP;
+                       break;
+
+               case IB_LINKINITCMD_DISABLE:
+                       licmd = QLOGIC_IB_IBCC_LINKINITCMD_DISABLE;
+                       ppd->cpspec->chase_end = 0;
+                       /*
+                        * stop state chase counter and timer, if running.
+                        * wait forpending timer, but don't clear .data (ppd)!
+                        */
+                       if (ppd->cpspec->chase_timer.expires) {
+                               del_timer_sync(&ppd->cpspec->chase_timer);
+                               ppd->cpspec->chase_timer.expires = 0;
+                       }
+                       break;
+
+               default:
+                       ret = -EINVAL;
+                       qib_dev_err(dd, "bad linkinitcmd req 0x%x\n",
+                                   val & 0xffff);
+                       goto bail;
+               }
+               qib_set_ib_7220_lstate(ppd, lcmd, licmd);
+               goto bail;
+
+       case QIB_IB_CFG_HRTBT: /* set Heartbeat off/enable/auto */
+               if (val > IBA7220_IBC_HRTBT_MASK) {
+                       ret = -EINVAL;
+                       goto bail;
+               }
+               lsb = IBA7220_IBC_HRTBT_SHIFT;
+               maskr = IBA7220_IBC_HRTBT_MASK;
+               break;
+
+       default:
+               ret = -EINVAL;
+               goto bail;
+       }
+       ppd->cpspec->ibcddrctrl &= ~(maskr << lsb);
+       ppd->cpspec->ibcddrctrl |= (((u64) val & maskr) << lsb);
+       qib_write_kreg(dd, kr_ibcddrctrl, ppd->cpspec->ibcddrctrl);
+       qib_write_kreg(dd, kr_scratch, 0);
+       if (setforce) {
+               spin_lock_irqsave(&ppd->lflags_lock, flags);
+               ppd->lflags |= QIBL_IB_FORCE_NOTIFY;
+               spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+       }
+bail:
+       return ret;
+}
+
+static int qib_7220_set_loopback(struct qib_pportdata *ppd, const char *what)
+{
+       int ret = 0;
+       u64 val, ddr;
+
+       if (!strncmp(what, "ibc", 3)) {
+               ppd->cpspec->ibcctrl |= SYM_MASK(IBCCtrl, Loopback);
+               val = 0; /* disable heart beat, so link will come up */
+               qib_devinfo(ppd->dd->pcidev, "Enabling IB%u:%u IBC loopback\n",
+                        ppd->dd->unit, ppd->port);
+       } else if (!strncmp(what, "off", 3)) {
+               ppd->cpspec->ibcctrl &= ~SYM_MASK(IBCCtrl, Loopback);
+               /* enable heart beat again */
+               val = IBA7220_IBC_HRTBT_MASK << IBA7220_IBC_HRTBT_SHIFT;
+               qib_devinfo(ppd->dd->pcidev, "Disabling IB%u:%u IBC loopback "
+                           "(normal)\n", ppd->dd->unit, ppd->port);
+       } else
+               ret = -EINVAL;
+       if (!ret) {
+               qib_write_kreg(ppd->dd, kr_ibcctrl, ppd->cpspec->ibcctrl);
+               ddr = ppd->cpspec->ibcddrctrl & ~(IBA7220_IBC_HRTBT_MASK
+                                            << IBA7220_IBC_HRTBT_SHIFT);
+               ppd->cpspec->ibcddrctrl = ddr | val;
+               qib_write_kreg(ppd->dd, kr_ibcddrctrl,
+                              ppd->cpspec->ibcddrctrl);
+               qib_write_kreg(ppd->dd, kr_scratch, 0);
+       }
+       return ret;
+}
+
+static void qib_update_7220_usrhead(struct qib_ctxtdata *rcd, u64 hd,
+                                   u32 updegr, u32 egrhd)
+{
+       qib_write_ureg(rcd->dd, ur_rcvhdrhead, hd, rcd->ctxt);
+       if (updegr)
+               qib_write_ureg(rcd->dd, ur_rcvegrindexhead, egrhd, rcd->ctxt);
+}
+
+static u32 qib_7220_hdrqempty(struct qib_ctxtdata *rcd)
+{
+       u32 head, tail;
+
+       head = qib_read_ureg32(rcd->dd, ur_rcvhdrhead, rcd->ctxt);
+       if (rcd->rcvhdrtail_kvaddr)
+               tail = qib_get_rcvhdrtail(rcd);
+       else
+               tail = qib_read_ureg32(rcd->dd, ur_rcvhdrtail, rcd->ctxt);
+       return head == tail;
+}
+
+/*
+ * Modify the RCVCTRL register in chip-specific way. This
+ * is a function because bit positions and (future) register
+ * location is chip-specifc, but the needed operations are
+ * generic. <op> is a bit-mask because we often want to
+ * do multiple modifications.
+ */
+static void rcvctrl_7220_mod(struct qib_pportdata *ppd, unsigned int op,
+                            int ctxt)
+{
+       struct qib_devdata *dd = ppd->dd;
+       u64 mask, val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dd->cspec->rcvmod_lock, flags);
+       if (op & QIB_RCVCTRL_TAILUPD_ENB)
+               dd->rcvctrl |= (1ULL << IBA7220_R_TAILUPD_SHIFT);
+       if (op & QIB_RCVCTRL_TAILUPD_DIS)
+               dd->rcvctrl &= ~(1ULL << IBA7220_R_TAILUPD_SHIFT);
+       if (op & QIB_RCVCTRL_PKEY_ENB)
+               dd->rcvctrl &= ~(1ULL << IBA7220_R_PKEY_DIS_SHIFT);
+       if (op & QIB_RCVCTRL_PKEY_DIS)
+               dd->rcvctrl |= (1ULL << IBA7220_R_PKEY_DIS_SHIFT);
+       if (ctxt < 0)
+               mask = (1ULL << dd->ctxtcnt) - 1;
+       else
+               mask = (1ULL << ctxt);
+       if (op & QIB_RCVCTRL_CTXT_ENB) {
+               /* always done for specific ctxt */
+               dd->rcvctrl |= (mask << SYM_LSB(RcvCtrl, PortEnable));
+               if (!(dd->flags & QIB_NODMA_RTAIL))
+                       dd->rcvctrl |= 1ULL << IBA7220_R_TAILUPD_SHIFT;
+               /* Write these registers before the context is enabled. */
+               qib_write_kreg_ctxt(dd, kr_rcvhdrtailaddr, ctxt,
+                       dd->rcd[ctxt]->rcvhdrqtailaddr_phys);
+               qib_write_kreg_ctxt(dd, kr_rcvhdraddr, ctxt,
+                       dd->rcd[ctxt]->rcvhdrq_phys);
+               dd->rcd[ctxt]->seq_cnt = 1;
+       }
+       if (op & QIB_RCVCTRL_CTXT_DIS)
+               dd->rcvctrl &= ~(mask << SYM_LSB(RcvCtrl, PortEnable));
+       if (op & QIB_RCVCTRL_INTRAVAIL_ENB)
+               dd->rcvctrl |= (mask << IBA7220_R_INTRAVAIL_SHIFT);
+       if (op & QIB_RCVCTRL_INTRAVAIL_DIS)
+               dd->rcvctrl &= ~(mask << IBA7220_R_INTRAVAIL_SHIFT);
+       qib_write_kreg(dd, kr_rcvctrl, dd->rcvctrl);
+       if ((op & QIB_RCVCTRL_INTRAVAIL_ENB) && dd->rhdrhead_intr_off) {
+               /* arm rcv interrupt */
+               val = qib_read_ureg32(dd, ur_rcvhdrhead, ctxt) |
+                       dd->rhdrhead_intr_off;
+               qib_write_ureg(dd, ur_rcvhdrhead, val, ctxt);
+       }
+       if (op & QIB_RCVCTRL_CTXT_ENB) {
+               /*
+                * Init the context registers also; if we were
+                * disabled, tail and head should both be zero
+                * already from the enable, but since we don't
+                * know, we have to do it explictly.
+                */
+               val = qib_read_ureg32(dd, ur_rcvegrindextail, ctxt);
+               qib_write_ureg(dd, ur_rcvegrindexhead, val, ctxt);
+
+               val = qib_read_ureg32(dd, ur_rcvhdrtail, ctxt);
+               dd->rcd[ctxt]->head = val;
+               /* If kctxt, interrupt on next receive. */
+               if (ctxt < dd->first_user_ctxt)
+                       val |= dd->rhdrhead_intr_off;
+               qib_write_ureg(dd, ur_rcvhdrhead, val, ctxt);
+       }
+       if (op & QIB_RCVCTRL_CTXT_DIS) {
+               if (ctxt >= 0) {
+                       qib_write_kreg_ctxt(dd, kr_rcvhdrtailaddr, ctxt, 0);
+                       qib_write_kreg_ctxt(dd, kr_rcvhdraddr, ctxt, 0);
+               } else {
+                       unsigned i;
+
+                       for (i = 0; i < dd->cfgctxts; i++) {
+                               qib_write_kreg_ctxt(dd, kr_rcvhdrtailaddr,
+                                                   i, 0);
+                               qib_write_kreg_ctxt(dd, kr_rcvhdraddr, i, 0);
+                       }
+               }
+       }
+       spin_unlock_irqrestore(&dd->cspec->rcvmod_lock, flags);
+}
+
+/*
+ * Modify the SENDCTRL register in chip-specific way. This
+ * is a function there may be multiple such registers with
+ * slightly different layouts. To start, we assume the
+ * "canonical" register layout of the first chips.
+ * Chip requires no back-back sendctrl writes, so write
+ * scratch register after writing sendctrl
+ */
+static void sendctrl_7220_mod(struct qib_pportdata *ppd, u32 op)
+{
+       struct qib_devdata *dd = ppd->dd;
+       u64 tmp_dd_sendctrl;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dd->sendctrl_lock, flags);
+
+       /* First the ones that are "sticky", saved in shadow */
+       if (op & QIB_SENDCTRL_CLEAR)
+               dd->sendctrl = 0;
+       if (op & QIB_SENDCTRL_SEND_DIS)
+               dd->sendctrl &= ~SYM_MASK(SendCtrl, SPioEnable);
+       else if (op & QIB_SENDCTRL_SEND_ENB) {
+               dd->sendctrl |= SYM_MASK(SendCtrl, SPioEnable);
+               if (dd->flags & QIB_USE_SPCL_TRIG)
+                       dd->sendctrl |= SYM_MASK(SendCtrl,
+                                                SSpecialTriggerEn);
+       }
+       if (op & QIB_SENDCTRL_AVAIL_DIS)
+               dd->sendctrl &= ~SYM_MASK(SendCtrl, SendBufAvailUpd);
+       else if (op & QIB_SENDCTRL_AVAIL_ENB)
+               dd->sendctrl |= SYM_MASK(SendCtrl, SendBufAvailUpd);
+
+       if (op & QIB_SENDCTRL_DISARM_ALL) {
+               u32 i, last;
+
+               tmp_dd_sendctrl = dd->sendctrl;
+               /*
+                * disarm any that are not yet launched, disabling sends
+                * and updates until done.
+                */
+               last = dd->piobcnt2k + dd->piobcnt4k;
+               tmp_dd_sendctrl &=
+                       ~(SYM_MASK(SendCtrl, SPioEnable) |
+                         SYM_MASK(SendCtrl, SendBufAvailUpd));
+               for (i = 0; i < last; i++) {
+                       qib_write_kreg(dd, kr_sendctrl,
+                                      tmp_dd_sendctrl |
+                                      SYM_MASK(SendCtrl, Disarm) | i);
+                       qib_write_kreg(dd, kr_scratch, 0);
+               }
+       }
+
+       tmp_dd_sendctrl = dd->sendctrl;
+
+       if (op & QIB_SENDCTRL_FLUSH)
+               tmp_dd_sendctrl |= SYM_MASK(SendCtrl, Abort);
+       if (op & QIB_SENDCTRL_DISARM)
+               tmp_dd_sendctrl |= SYM_MASK(SendCtrl, Disarm) |
+                       ((op & QIB_7220_SendCtrl_DisarmPIOBuf_RMASK) <<
+                        SYM_LSB(SendCtrl, DisarmPIOBuf));
+       if ((op & QIB_SENDCTRL_AVAIL_BLIP) &&
+           (dd->sendctrl & SYM_MASK(SendCtrl, SendBufAvailUpd)))
+               tmp_dd_sendctrl &= ~SYM_MASK(SendCtrl, SendBufAvailUpd);
+
+       qib_write_kreg(dd, kr_sendctrl, tmp_dd_sendctrl);
+       qib_write_kreg(dd, kr_scratch, 0);
+
+       if (op & QIB_SENDCTRL_AVAIL_BLIP) {
+               qib_write_kreg(dd, kr_sendctrl, dd->sendctrl);
+               qib_write_kreg(dd, kr_scratch, 0);
+       }
+
+       spin_unlock_irqrestore(&dd->sendctrl_lock, flags);
+
+       if (op & QIB_SENDCTRL_FLUSH) {
+               u32 v;
+               /*
+                * ensure writes have hit chip, then do a few
+                * more reads, to allow DMA of pioavail registers
+                * to occur, so in-memory copy is in sync with
+                * the chip.  Not always safe to sleep.
+                */
+               v = qib_read_kreg32(dd, kr_scratch);
+               qib_write_kreg(dd, kr_scratch, v);
+               v = qib_read_kreg32(dd, kr_scratch);
+               qib_write_kreg(dd, kr_scratch, v);
+               qib_read_kreg32(dd, kr_scratch);
+       }
+}
+
+/**
+ * qib_portcntr_7220 - read a per-port counter
+ * @dd: the qlogic_ib device
+ * @creg: the counter to snapshot
+ */
+static u64 qib_portcntr_7220(struct qib_pportdata *ppd, u32 reg)
+{
+       u64 ret = 0ULL;
+       struct qib_devdata *dd = ppd->dd;
+       u16 creg;
+       /* 0xffff for unimplemented or synthesized counters */
+       static const u16 xlator[] = {
+               [QIBPORTCNTR_PKTSEND] = cr_pktsend,
+               [QIBPORTCNTR_WORDSEND] = cr_wordsend,
+               [QIBPORTCNTR_PSXMITDATA] = cr_psxmitdatacount,
+               [QIBPORTCNTR_PSXMITPKTS] = cr_psxmitpktscount,
+               [QIBPORTCNTR_PSXMITWAIT] = cr_psxmitwaitcount,
+               [QIBPORTCNTR_SENDSTALL] = cr_sendstall,
+               [QIBPORTCNTR_PKTRCV] = cr_pktrcv,
+               [QIBPORTCNTR_PSRCVDATA] = cr_psrcvdatacount,
+               [QIBPORTCNTR_PSRCVPKTS] = cr_psrcvpktscount,
+               [QIBPORTCNTR_RCVEBP] = cr_rcvebp,
+               [QIBPORTCNTR_RCVOVFL] = cr_rcvovfl,
+               [QIBPORTCNTR_WORDRCV] = cr_wordrcv,
+               [QIBPORTCNTR_RXDROPPKT] = cr_rxdroppkt,
+               [QIBPORTCNTR_RXLOCALPHYERR] = cr_rxotherlocalphyerr,
+               [QIBPORTCNTR_RXVLERR] = cr_rxvlerr,
+               [QIBPORTCNTR_ERRICRC] = cr_erricrc,
+               [QIBPORTCNTR_ERRVCRC] = cr_errvcrc,
+               [QIBPORTCNTR_ERRLPCRC] = cr_errlpcrc,
+               [QIBPORTCNTR_BADFORMAT] = cr_badformat,
+               [QIBPORTCNTR_ERR_RLEN] = cr_err_rlen,
+               [QIBPORTCNTR_IBSYMBOLERR] = cr_ibsymbolerr,
+               [QIBPORTCNTR_INVALIDRLEN] = cr_invalidrlen,
+               [QIBPORTCNTR_UNSUPVL] = cr_txunsupvl,
+               [QIBPORTCNTR_EXCESSBUFOVFL] = cr_excessbufferovfl,
+               [QIBPORTCNTR_ERRLINK] = cr_errlink,
+               [QIBPORTCNTR_IBLINKDOWN] = cr_iblinkdown,
+               [QIBPORTCNTR_IBLINKERRRECOV] = cr_iblinkerrrecov,
+               [QIBPORTCNTR_LLI] = cr_locallinkintegrityerr,
+               [QIBPORTCNTR_PSINTERVAL] = cr_psinterval,
+               [QIBPORTCNTR_PSSTART] = cr_psstart,
+               [QIBPORTCNTR_PSSTAT] = cr_psstat,
+               [QIBPORTCNTR_VL15PKTDROP] = cr_vl15droppedpkt,
+               [QIBPORTCNTR_ERRPKEY] = cr_errpkey,
+               [QIBPORTCNTR_KHDROVFL] = 0xffff,
+       };
+
+       if (reg >= ARRAY_SIZE(xlator)) {
+               qib_devinfo(ppd->dd->pcidev,
+                        "Unimplemented portcounter %u\n", reg);
+               goto done;
+       }
+       creg = xlator[reg];
+
+       if (reg == QIBPORTCNTR_KHDROVFL) {
+               int i;
+
+               /* sum over all kernel contexts */
+               for (i = 0; i < dd->first_user_ctxt; i++)
+                       ret += read_7220_creg32(dd, cr_portovfl + i);
+       }
+       if (creg == 0xffff)
+               goto done;
+
+       /*
+        * only fast incrementing counters are 64bit; use 32 bit reads to
+        * avoid two independent reads when on opteron
+        */
+       if ((creg == cr_wordsend || creg == cr_wordrcv ||
+            creg == cr_pktsend || creg == cr_pktrcv))
+               ret = read_7220_creg(dd, creg);
+       else
+               ret = read_7220_creg32(dd, creg);
+       if (creg == cr_ibsymbolerr) {
+               if (dd->pport->cpspec->ibdeltainprog)
+                       ret -= ret - ppd->cpspec->ibsymsnap;
+               ret -= dd->pport->cpspec->ibsymdelta;
+       } else if (creg == cr_iblinkerrrecov) {
+               if (dd->pport->cpspec->ibdeltainprog)
+                       ret -= ret - ppd->cpspec->iblnkerrsnap;
+               ret -= dd->pport->cpspec->iblnkerrdelta;
+       }
+done:
+       return ret;
+}
+
+/*
+ * Device counter names (not port-specific), one line per stat,
+ * single string.  Used by utilities like ipathstats to print the stats
+ * in a way which works for different versions of drivers, without changing
+ * the utility.  Names need to be 12 chars or less (w/o newline), for proper
+ * display by utility.
+ * Non-error counters are first.
+ * Start of "error" conters is indicated by a leading "E " on the first
+ * "error" counter, and doesn't count in label length.
+ * The EgrOvfl list needs to be last so we truncate them at the configured
+ * context count for the device.
+ * cntr7220indices contains the corresponding register indices.
+ */
+static const char cntr7220names[] =
+       "Interrupts\n"
+       "HostBusStall\n"
+       "E RxTIDFull\n"
+       "RxTIDInvalid\n"
+       "Ctxt0EgrOvfl\n"
+       "Ctxt1EgrOvfl\n"
+       "Ctxt2EgrOvfl\n"
+       "Ctxt3EgrOvfl\n"
+       "Ctxt4EgrOvfl\n"
+       "Ctxt5EgrOvfl\n"
+       "Ctxt6EgrOvfl\n"
+       "Ctxt7EgrOvfl\n"
+       "Ctxt8EgrOvfl\n"
+       "Ctxt9EgrOvfl\n"
+       "Ctx10EgrOvfl\n"
+       "Ctx11EgrOvfl\n"
+       "Ctx12EgrOvfl\n"
+       "Ctx13EgrOvfl\n"
+       "Ctx14EgrOvfl\n"
+       "Ctx15EgrOvfl\n"
+       "Ctx16EgrOvfl\n";
+
+static const size_t cntr7220indices[] = {
+       cr_lbint,
+       cr_lbflowstall,
+       cr_errtidfull,
+       cr_errtidvalid,
+       cr_portovfl + 0,
+       cr_portovfl + 1,
+       cr_portovfl + 2,
+       cr_portovfl + 3,
+       cr_portovfl + 4,
+       cr_portovfl + 5,
+       cr_portovfl + 6,
+       cr_portovfl + 7,
+       cr_portovfl + 8,
+       cr_portovfl + 9,
+       cr_portovfl + 10,
+       cr_portovfl + 11,
+       cr_portovfl + 12,
+       cr_portovfl + 13,
+       cr_portovfl + 14,
+       cr_portovfl + 15,
+       cr_portovfl + 16,
+};
+
+/*
+ * same as cntr7220names and cntr7220indices, but for port-specific counters.
+ * portcntr7220indices is somewhat complicated by some registers needing
+ * adjustments of various kinds, and those are ORed with _PORT_VIRT_FLAG
+ */
+static const char portcntr7220names[] =
+       "TxPkt\n"
+       "TxFlowPkt\n"
+       "TxWords\n"
+       "RxPkt\n"
+       "RxFlowPkt\n"
+       "RxWords\n"
+       "TxFlowStall\n"
+       "TxDmaDesc\n"  /* 7220 and 7322-only */
+       "E RxDlidFltr\n"  /* 7220 and 7322-only */
+       "IBStatusChng\n"
+       "IBLinkDown\n"
+       "IBLnkRecov\n"
+       "IBRxLinkErr\n"
+       "IBSymbolErr\n"
+       "RxLLIErr\n"
+       "RxBadFormat\n"
+       "RxBadLen\n"
+       "RxBufOvrfl\n"
+       "RxEBP\n"
+       "RxFlowCtlErr\n"
+       "RxICRCerr\n"
+       "RxLPCRCerr\n"
+       "RxVCRCerr\n"
+       "RxInvalLen\n"
+       "RxInvalPKey\n"
+       "RxPktDropped\n"
+       "TxBadLength\n"
+       "TxDropped\n"
+       "TxInvalLen\n"
+       "TxUnderrun\n"
+       "TxUnsupVL\n"
+       "RxLclPhyErr\n" /* 7220 and 7322-only */
+       "RxVL15Drop\n" /* 7220 and 7322-only */
+       "RxVlErr\n" /* 7220 and 7322-only */
+       "XcessBufOvfl\n" /* 7220 and 7322-only */
+       ;
+
+#define _PORT_VIRT_FLAG 0x8000 /* "virtual", need adjustments */
+static const size_t portcntr7220indices[] = {
+       QIBPORTCNTR_PKTSEND | _PORT_VIRT_FLAG,
+       cr_pktsendflow,
+       QIBPORTCNTR_WORDSEND | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_PKTRCV | _PORT_VIRT_FLAG,
+       cr_pktrcvflowctrl,
+       QIBPORTCNTR_WORDRCV | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_SENDSTALL | _PORT_VIRT_FLAG,
+       cr_txsdmadesc,
+       cr_rxdlidfltr,
+       cr_ibstatuschange,
+       QIBPORTCNTR_IBLINKDOWN | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_IBLINKERRRECOV | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_ERRLINK | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_IBSYMBOLERR | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_LLI | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_BADFORMAT | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_ERR_RLEN | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_RCVOVFL | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_RCVEBP | _PORT_VIRT_FLAG,
+       cr_rcvflowctrl_err,
+       QIBPORTCNTR_ERRICRC | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_ERRLPCRC | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_ERRVCRC | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_INVALIDRLEN | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_ERRPKEY | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_RXDROPPKT | _PORT_VIRT_FLAG,
+       cr_invalidslen,
+       cr_senddropped,
+       cr_errslen,
+       cr_sendunderrun,
+       cr_txunsupvl,
+       QIBPORTCNTR_RXLOCALPHYERR | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_VL15PKTDROP | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_RXVLERR | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_EXCESSBUFOVFL | _PORT_VIRT_FLAG,
+};
+
+/* do all the setup to make the counter reads efficient later */
+static void init_7220_cntrnames(struct qib_devdata *dd)
+{
+       int i, j = 0;
+       char *s;
+
+       for (i = 0, s = (char *)cntr7220names; s && j <= dd->cfgctxts;
+            i++) {
+               /* we always have at least one counter before the egrovfl */
+               if (!j && !strncmp("Ctxt0EgrOvfl", s + 1, 12))
+                       j = 1;
+               s = strchr(s + 1, '\n');
+               if (s && j)
+                       j++;
+       }
+       dd->cspec->ncntrs = i;
+       if (!s)
+               /* full list; size is without terminating null */
+               dd->cspec->cntrnamelen = sizeof(cntr7220names) - 1;
+       else
+               dd->cspec->cntrnamelen = 1 + s - cntr7220names;
+       dd->cspec->cntrs = kmalloc(dd->cspec->ncntrs
+               * sizeof(u64), GFP_KERNEL);
+       if (!dd->cspec->cntrs)
+               qib_dev_err(dd, "Failed allocation for counters\n");
+
+       for (i = 0, s = (char *)portcntr7220names; s; i++)
+               s = strchr(s + 1, '\n');
+       dd->cspec->nportcntrs = i - 1;
+       dd->cspec->portcntrnamelen = sizeof(portcntr7220names) - 1;
+       dd->cspec->portcntrs = kmalloc(dd->cspec->nportcntrs
+               * sizeof(u64), GFP_KERNEL);
+       if (!dd->cspec->portcntrs)
+               qib_dev_err(dd, "Failed allocation for portcounters\n");
+}
+
+static u32 qib_read_7220cntrs(struct qib_devdata *dd, loff_t pos, char **namep,
+                             u64 **cntrp)
+{
+       u32 ret;
+
+       if (!dd->cspec->cntrs) {
+               ret = 0;
+               goto done;
+       }
+
+       if (namep) {
+               *namep = (char *)cntr7220names;
+               ret = dd->cspec->cntrnamelen;
+               if (pos >= ret)
+                       ret = 0; /* final read after getting everything */
+       } else {
+               u64 *cntr = dd->cspec->cntrs;
+               int i;
+
+               ret = dd->cspec->ncntrs * sizeof(u64);
+               if (!cntr || pos >= ret) {
+                       /* everything read, or couldn't get memory */
+                       ret = 0;
+                       goto done;
+               }
+
+               *cntrp = cntr;
+               for (i = 0; i < dd->cspec->ncntrs; i++)
+                       *cntr++ = read_7220_creg32(dd, cntr7220indices[i]);
+       }
+done:
+       return ret;
+}
+
+static u32 qib_read_7220portcntrs(struct qib_devdata *dd, loff_t pos, u32 port,
+                                 char **namep, u64 **cntrp)
+{
+       u32 ret;
+
+       if (!dd->cspec->portcntrs) {
+               ret = 0;
+               goto done;
+       }
+       if (namep) {
+               *namep = (char *)portcntr7220names;
+               ret = dd->cspec->portcntrnamelen;
+               if (pos >= ret)
+                       ret = 0; /* final read after getting everything */
+       } else {
+               u64 *cntr = dd->cspec->portcntrs;
+               struct qib_pportdata *ppd = &dd->pport[port];
+               int i;
+
+               ret = dd->cspec->nportcntrs * sizeof(u64);
+               if (!cntr || pos >= ret) {
+                       /* everything read, or couldn't get memory */
+                       ret = 0;
+                       goto done;
+               }
+               *cntrp = cntr;
+               for (i = 0; i < dd->cspec->nportcntrs; i++) {
+                       if (portcntr7220indices[i] & _PORT_VIRT_FLAG)
+                               *cntr++ = qib_portcntr_7220(ppd,
+                                       portcntr7220indices[i] &
+                                       ~_PORT_VIRT_FLAG);
+                       else
+                               *cntr++ = read_7220_creg32(dd,
+                                          portcntr7220indices[i]);
+               }
+       }
+done:
+       return ret;
+}
+
+/**
+ * qib_get_7220_faststats - get word counters from chip before they overflow
+ * @opaque - contains a pointer to the qlogic_ib device qib_devdata
+ *
+ * This needs more work; in particular, decision on whether we really
+ * need traffic_wds done the way it is
+ * called from add_timer
+ */
+static void qib_get_7220_faststats(unsigned long opaque)
+{
+       struct qib_devdata *dd = (struct qib_devdata *) opaque;
+       struct qib_pportdata *ppd = dd->pport;
+       unsigned long flags;
+       u64 traffic_wds;
+
+       /*
+        * don't access the chip while running diags, or memory diags can
+        * fail
+        */
+       if (!(dd->flags & QIB_INITTED) || dd->diag_client)
+               /* but re-arm the timer, for diags case; won't hurt other */
+               goto done;
+
+       /*
+        * We now try to maintain an activity timer, based on traffic
+        * exceeding a threshold, so we need to check the word-counts
+        * even if they are 64-bit.
+        */
+       traffic_wds = qib_portcntr_7220(ppd, cr_wordsend) +
+               qib_portcntr_7220(ppd, cr_wordrcv);
+       spin_lock_irqsave(&dd->eep_st_lock, flags);
+       traffic_wds -= dd->traffic_wds;
+       dd->traffic_wds += traffic_wds;
+       if (traffic_wds  >= QIB_TRAFFIC_ACTIVE_THRESHOLD)
+               atomic_add(5, &dd->active_time); /* S/B #define */
+       spin_unlock_irqrestore(&dd->eep_st_lock, flags);
+done:
+       mod_timer(&dd->stats_timer, jiffies + HZ * ACTIVITY_TIMER);
+}
+
+/*
+ * If we are using MSI, try to fallback to INTx.
+ */
+static int qib_7220_intr_fallback(struct qib_devdata *dd)
+{
+       if (!dd->msi_lo)
+               return 0;
+
+       qib_devinfo(dd->pcidev, "MSI interrupt not detected,"
+                " trying INTx interrupts\n");
+       qib_7220_free_irq(dd);
+       qib_enable_intx(dd->pcidev);
+       /*
+        * Some newer kernels require free_irq before disable_msi,
+        * and irq can be changed during disable and INTx enable
+        * and we need to therefore use the pcidev->irq value,
+        * not our saved MSI value.
+        */
+       dd->cspec->irq = dd->pcidev->irq;
+       qib_setup_7220_interrupt(dd);
+       return 1;
+}
+
+/*
+ * Reset the XGXS (between serdes and IBC).  Slightly less intrusive
+ * than resetting the IBC or external link state, and useful in some
+ * cases to cause some retraining.  To do this right, we reset IBC
+ * as well.
+ */
+static void qib_7220_xgxs_reset(struct qib_pportdata *ppd)
+{
+       u64 val, prev_val;
+       struct qib_devdata *dd = ppd->dd;
+
+       prev_val = qib_read_kreg64(dd, kr_xgxs_cfg);
+       val = prev_val | QLOGIC_IB_XGXS_RESET;
+       prev_val &= ~QLOGIC_IB_XGXS_RESET; /* be sure */
+       qib_write_kreg(dd, kr_control,
+                      dd->control & ~QLOGIC_IB_C_LINKENABLE);
+       qib_write_kreg(dd, kr_xgxs_cfg, val);
+       qib_read_kreg32(dd, kr_scratch);
+       qib_write_kreg(dd, kr_xgxs_cfg, prev_val);
+       qib_write_kreg(dd, kr_control, dd->control);
+}
+
+/*
+ * For this chip, we want to use the same buffer every time
+ * when we are trying to bring the link up (they are always VL15
+ * packets).  At that link state the packet should always go out immediately
+ * (or at least be discarded at the tx interface if the link is down).
+ * If it doesn't, and the buffer isn't available, that means some other
+ * sender has gotten ahead of us, and is preventing our packet from going
+ * out.  In that case, we flush all packets, and try again.  If that still
+ * fails, we fail the request, and hope things work the next time around.
+ *
+ * We don't need very complicated heuristics on whether the packet had
+ * time to go out or not, since even at SDR 1X, it goes out in very short
+ * time periods, covered by the chip reads done here and as part of the
+ * flush.
+ */
+static u32 __iomem *get_7220_link_buf(struct qib_pportdata *ppd, u32 *bnum)
+{
+       u32 __iomem *buf;
+       u32 lbuf = ppd->dd->cspec->lastbuf_for_pio;
+       int do_cleanup;
+       unsigned long flags;
+
+       /*
+        * always blip to get avail list updated, since it's almost
+        * always needed, and is fairly cheap.
+        */
+       sendctrl_7220_mod(ppd->dd->pport, QIB_SENDCTRL_AVAIL_BLIP);
+       qib_read_kreg64(ppd->dd, kr_scratch); /* extra chip flush */
+       buf = qib_getsendbuf_range(ppd->dd, bnum, lbuf, lbuf);
+       if (buf)
+               goto done;
+
+       spin_lock_irqsave(&ppd->sdma_lock, flags);
+       if (ppd->sdma_state.current_state == qib_sdma_state_s20_idle &&
+           ppd->sdma_state.current_state != qib_sdma_state_s00_hw_down) {
+               __qib_sdma_process_event(ppd, qib_sdma_event_e00_go_hw_down);
+               do_cleanup = 0;
+       } else {
+               do_cleanup = 1;
+               qib_7220_sdma_hw_clean_up(ppd);
+       }
+       spin_unlock_irqrestore(&ppd->sdma_lock, flags);
+
+       if (do_cleanup) {
+               qib_read_kreg64(ppd->dd, kr_scratch); /* extra chip flush */
+               buf = qib_getsendbuf_range(ppd->dd, bnum, lbuf, lbuf);
+       }
+done:
+       return buf;
+}
+
+/*
+ * This code for non-IBTA-compliant IB speed negotiation is only known to
+ * work for the SDR to DDR transition, and only between an HCA and a switch
+ * with recent firmware.  It is based on observed heuristics, rather than
+ * actual knowledge of the non-compliant speed negotiation.
+ * It has a number of hard-coded fields, since the hope is to rewrite this
+ * when a spec is available on how the negoation is intended to work.
+ */
+static void autoneg_7220_sendpkt(struct qib_pportdata *ppd, u32 *hdr,
+                                u32 dcnt, u32 *data)
+{
+       int i;
+       u64 pbc;
+       u32 __iomem *piobuf;
+       u32 pnum;
+       struct qib_devdata *dd = ppd->dd;
+
+       i = 0;
+       pbc = 7 + dcnt + 1; /* 7 dword header, dword data, icrc */
+       pbc |= PBC_7220_VL15_SEND;
+       while (!(piobuf = get_7220_link_buf(ppd, &pnum))) {
+               if (i++ > 5)
+                       return;
+               udelay(2);
+       }
+       sendctrl_7220_mod(dd->pport, QIB_SENDCTRL_DISARM_BUF(pnum));
+       writeq(pbc, piobuf);
+       qib_flush_wc();
+       qib_pio_copy(piobuf + 2, hdr, 7);
+       qib_pio_copy(piobuf + 9, data, dcnt);
+       if (dd->flags & QIB_USE_SPCL_TRIG) {
+               u32 spcl_off = (pnum >= dd->piobcnt2k) ? 2047 : 1023;
+
+               qib_flush_wc();
+               __raw_writel(0xaebecede, piobuf + spcl_off);
+       }
+       qib_flush_wc();
+       qib_sendbuf_done(dd, pnum);
+}
+
+/*
+ * _start packet gets sent twice at start, _done gets sent twice at end
+ */
+static void autoneg_7220_send(struct qib_pportdata *ppd, int which)
+{
+       struct qib_devdata *dd = ppd->dd;
+       static u32 swapped;
+       u32 dw, i, hcnt, dcnt, *data;
+       static u32 hdr[7] = { 0xf002ffff, 0x48ffff, 0x6400abba };
+       static u32 madpayload_start[0x40] = {
+               0x1810103, 0x1, 0x0, 0x0, 0x2c90000, 0x2c9, 0x0, 0x0,
+               0xffffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+               0x1, 0x1388, 0x15e, 0x1, /* rest 0's */
+               };
+       static u32 madpayload_done[0x40] = {
+               0x1810103, 0x1, 0x0, 0x0, 0x2c90000, 0x2c9, 0x0, 0x0,
+               0xffffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+               0x40000001, 0x1388, 0x15e, /* rest 0's */
+               };
+
+       dcnt = ARRAY_SIZE(madpayload_start);
+       hcnt = ARRAY_SIZE(hdr);
+       if (!swapped) {
+               /* for maintainability, do it at runtime */
+               for (i = 0; i < hcnt; i++) {
+                       dw = (__force u32) cpu_to_be32(hdr[i]);
+                       hdr[i] = dw;
+               }
+               for (i = 0; i < dcnt; i++) {
+                       dw = (__force u32) cpu_to_be32(madpayload_start[i]);
+                       madpayload_start[i] = dw;
+                       dw = (__force u32) cpu_to_be32(madpayload_done[i]);
+                       madpayload_done[i] = dw;
+               }
+               swapped = 1;
+       }
+
+       data = which ? madpayload_done : madpayload_start;
+
+       autoneg_7220_sendpkt(ppd, hdr, dcnt, data);
+       qib_read_kreg64(dd, kr_scratch);
+       udelay(2);
+       autoneg_7220_sendpkt(ppd, hdr, dcnt, data);
+       qib_read_kreg64(dd, kr_scratch);
+       udelay(2);
+}
+
+/*
+ * Do the absolute minimum to cause an IB speed change, and make it
+ * ready, but don't actually trigger the change.   The caller will
+ * do that when ready (if link is in Polling training state, it will
+ * happen immediately, otherwise when link next goes down)
+ *
+ * This routine should only be used as part of the DDR autonegotation
+ * code for devices that are not compliant with IB 1.2 (or code that
+ * fixes things up for same).
+ *
+ * When link has gone down, and autoneg enabled, or autoneg has
+ * failed and we give up until next time we set both speeds, and
+ * then we want IBTA enabled as well as "use max enabled speed.
+ */
+static void set_7220_ibspeed_fast(struct qib_pportdata *ppd, u32 speed)
+{
+       ppd->cpspec->ibcddrctrl &= ~(IBA7220_IBC_SPEED_AUTONEG_MASK |
+               IBA7220_IBC_IBTA_1_2_MASK);
+
+       if (speed == (QIB_IB_SDR | QIB_IB_DDR))
+               ppd->cpspec->ibcddrctrl |= IBA7220_IBC_SPEED_AUTONEG_MASK |
+                       IBA7220_IBC_IBTA_1_2_MASK;
+       else
+               ppd->cpspec->ibcddrctrl |= speed == QIB_IB_DDR ?
+                       IBA7220_IBC_SPEED_DDR : IBA7220_IBC_SPEED_SDR;
+
+       qib_write_kreg(ppd->dd, kr_ibcddrctrl, ppd->cpspec->ibcddrctrl);
+       qib_write_kreg(ppd->dd, kr_scratch, 0);
+}
+
+/*
+ * This routine is only used when we are not talking to another
+ * IB 1.2-compliant device that we think can do DDR.
+ * (This includes all existing switch chips as of Oct 2007.)
+ * 1.2-compliant devices go directly to DDR prior to reaching INIT
+ */
+static void try_7220_autoneg(struct qib_pportdata *ppd)
+{
+       unsigned long flags;
+
+       /*
+        * Required for older non-IB1.2 DDR switches.  Newer
+        * non-IB-compliant switches don't need it, but so far,
+        * aren't bothered by it either.  "Magic constant"
+        */
+       qib_write_kreg(ppd->dd, kr_ncmodectrl, 0x3b9dc07);
+
+       spin_lock_irqsave(&ppd->lflags_lock, flags);
+       ppd->lflags |= QIBL_IB_AUTONEG_INPROG;
+       spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+       autoneg_7220_send(ppd, 0);
+       set_7220_ibspeed_fast(ppd, QIB_IB_DDR);
+
+       toggle_7220_rclkrls(ppd->dd);
+       /* 2 msec is minimum length of a poll cycle */
+       schedule_delayed_work(&ppd->cpspec->autoneg_work,
+                             msecs_to_jiffies(2));
+}
+
+/*
+ * Handle the empirically determined mechanism for auto-negotiation
+ * of DDR speed with switches.
+ */
+static void autoneg_7220_work(struct work_struct *work)
+{
+       struct qib_pportdata *ppd;
+       struct qib_devdata *dd;
+       u64 startms;
+       u32 i;
+       unsigned long flags;
+
+       ppd = &container_of(work, struct qib_chippport_specific,
+                           autoneg_work.work)->pportdata;
+       dd = ppd->dd;
+
+       startms = jiffies_to_msecs(jiffies);
+
+       /*
+        * Busy wait for this first part, it should be at most a
+        * few hundred usec, since we scheduled ourselves for 2msec.
+        */
+       for (i = 0; i < 25; i++) {
+               if (SYM_FIELD(ppd->lastibcstat, IBCStatus, LinkTrainingState)
+                    == IB_7220_LT_STATE_POLLQUIET) {
+                       qib_set_linkstate(ppd, QIB_IB_LINKDOWN_DISABLE);
+                       break;
+               }
+               udelay(100);
+       }
+
+       if (!(ppd->lflags & QIBL_IB_AUTONEG_INPROG))
+               goto done; /* we got there early or told to stop */
+
+       /* we expect this to timeout */
+       if (wait_event_timeout(ppd->cpspec->autoneg_wait,
+                              !(ppd->lflags & QIBL_IB_AUTONEG_INPROG),
+                              msecs_to_jiffies(90)))
+               goto done;
+
+       toggle_7220_rclkrls(dd);
+
+       /* we expect this to timeout */
+       if (wait_event_timeout(ppd->cpspec->autoneg_wait,
+                              !(ppd->lflags & QIBL_IB_AUTONEG_INPROG),
+                              msecs_to_jiffies(1700)))
+               goto done;
+
+       set_7220_ibspeed_fast(ppd, QIB_IB_SDR);
+       toggle_7220_rclkrls(dd);
+
+       /*
+        * Wait up to 250 msec for link to train and get to INIT at DDR;
+        * this should terminate early.
+        */
+       wait_event_timeout(ppd->cpspec->autoneg_wait,
+               !(ppd->lflags & QIBL_IB_AUTONEG_INPROG),
+               msecs_to_jiffies(250));
+done:
+       if (ppd->lflags & QIBL_IB_AUTONEG_INPROG) {
+               spin_lock_irqsave(&ppd->lflags_lock, flags);
+               ppd->lflags &= ~QIBL_IB_AUTONEG_INPROG;
+               if (dd->cspec->autoneg_tries == AUTONEG_TRIES) {
+                       ppd->lflags |= QIBL_IB_AUTONEG_FAILED;
+                       dd->cspec->autoneg_tries = 0;
+               }
+               spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+               set_7220_ibspeed_fast(ppd, ppd->link_speed_enabled);
+       }
+}
+
+static u32 qib_7220_iblink_state(u64 ibcs)
+{
+       u32 state = (u32)SYM_FIELD(ibcs, IBCStatus, LinkState);
+
+       switch (state) {
+       case IB_7220_L_STATE_INIT:
+               state = IB_PORT_INIT;
+               break;
+       case IB_7220_L_STATE_ARM:
+               state = IB_PORT_ARMED;
+               break;
+       case IB_7220_L_STATE_ACTIVE:
+               /* fall through */
+       case IB_7220_L_STATE_ACT_DEFER:
+               state = IB_PORT_ACTIVE;
+               break;
+       default: /* fall through */
+       case IB_7220_L_STATE_DOWN:
+               state = IB_PORT_DOWN;
+               break;
+       }
+       return state;
+}
+
+/* returns the IBTA port state, rather than the IBC link training state */
+static u8 qib_7220_phys_portstate(u64 ibcs)
+{
+       u8 state = (u8)SYM_FIELD(ibcs, IBCStatus, LinkTrainingState);
+       return qib_7220_physportstate[state];
+}
+
+static int qib_7220_ib_updown(struct qib_pportdata *ppd, int ibup, u64 ibcs)
+{
+       int ret = 0, symadj = 0;
+       struct qib_devdata *dd = ppd->dd;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ppd->lflags_lock, flags);
+       ppd->lflags &= ~QIBL_IB_FORCE_NOTIFY;
+       spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+
+       if (!ibup) {
+               /*
+                * When the link goes down we don't want AEQ running, so it
+                * won't interfere with IBC training, etc., and we need
+                * to go back to the static SerDes preset values.
+                */
+               if (!(ppd->lflags & (QIBL_IB_AUTONEG_FAILED |
+                                    QIBL_IB_AUTONEG_INPROG)))
+                       set_7220_ibspeed_fast(ppd, ppd->link_speed_enabled);
+               if (!(ppd->lflags & QIBL_IB_AUTONEG_INPROG)) {
+                       qib_sd7220_presets(dd);
+                       qib_cancel_sends(ppd); /* initial disarm, etc. */
+                       spin_lock_irqsave(&ppd->sdma_lock, flags);
+                       if (__qib_sdma_running(ppd))
+                               __qib_sdma_process_event(ppd,
+                                       qib_sdma_event_e70_go_idle);
+                       spin_unlock_irqrestore(&ppd->sdma_lock, flags);
+               }
+               /* this might better in qib_sd7220_presets() */
+               set_7220_relock_poll(dd, ibup);
+       } else {
+               if (qib_compat_ddr_negotiate &&
+                   !(ppd->lflags & (QIBL_IB_AUTONEG_FAILED |
+                                    QIBL_IB_AUTONEG_INPROG)) &&
+                   ppd->link_speed_active == QIB_IB_SDR &&
+                   (ppd->link_speed_enabled & (QIB_IB_DDR | QIB_IB_SDR)) ==
+                   (QIB_IB_DDR | QIB_IB_SDR) &&
+                   dd->cspec->autoneg_tries < AUTONEG_TRIES) {
+                       /* we are SDR, and DDR auto-negotiation enabled */
+                       ++dd->cspec->autoneg_tries;
+                       if (!ppd->cpspec->ibdeltainprog) {
+                               ppd->cpspec->ibdeltainprog = 1;
+                               ppd->cpspec->ibsymsnap = read_7220_creg32(dd,
+                                       cr_ibsymbolerr);
+                               ppd->cpspec->iblnkerrsnap = read_7220_creg32(dd,
+                                       cr_iblinkerrrecov);
+                       }
+                       try_7220_autoneg(ppd);
+                       ret = 1; /* no other IB status change processing */
+               } else if ((ppd->lflags & QIBL_IB_AUTONEG_INPROG) &&
+                          ppd->link_speed_active == QIB_IB_SDR) {
+                       autoneg_7220_send(ppd, 1);
+                       set_7220_ibspeed_fast(ppd, QIB_IB_DDR);
+                       udelay(2);
+                       toggle_7220_rclkrls(dd);
+                       ret = 1; /* no other IB status change processing */
+               } else {
+                       if ((ppd->lflags & QIBL_IB_AUTONEG_INPROG) &&
+                           (ppd->link_speed_active & QIB_IB_DDR)) {
+                               spin_lock_irqsave(&ppd->lflags_lock, flags);
+                               ppd->lflags &= ~(QIBL_IB_AUTONEG_INPROG |
+                                                QIBL_IB_AUTONEG_FAILED);
+                               spin_unlock_irqrestore(&ppd->lflags_lock,
+                                                      flags);
+                               dd->cspec->autoneg_tries = 0;
+                               /* re-enable SDR, for next link down */
+                               set_7220_ibspeed_fast(ppd,
+                                                     ppd->link_speed_enabled);
+                               wake_up(&ppd->cpspec->autoneg_wait);
+                               symadj = 1;
+                       } else if (ppd->lflags & QIBL_IB_AUTONEG_FAILED) {
+                               /*
+                                * Clear autoneg failure flag, and do setup
+                                * so we'll try next time link goes down and
+                                * back to INIT (possibly connected to a
+                                * different device).
+                                */
+                               spin_lock_irqsave(&ppd->lflags_lock, flags);
+                               ppd->lflags &= ~QIBL_IB_AUTONEG_FAILED;
+                               spin_unlock_irqrestore(&ppd->lflags_lock,
+                                                      flags);
+                               ppd->cpspec->ibcddrctrl |=
+                                       IBA7220_IBC_IBTA_1_2_MASK;
+                               qib_write_kreg(dd, kr_ncmodectrl, 0);
+                               symadj = 1;
+                       }
+               }
+
+               if (!(ppd->lflags & QIBL_IB_AUTONEG_INPROG))
+                       symadj = 1;
+
+               if (!ret) {
+                       ppd->delay_mult = rate_to_delay
+                           [(ibcs >> IBA7220_LINKSPEED_SHIFT) & 1]
+                           [(ibcs >> IBA7220_LINKWIDTH_SHIFT) & 1];
+
+                       set_7220_relock_poll(dd, ibup);
+                       spin_lock_irqsave(&ppd->sdma_lock, flags);
+                       /*
+                        * Unlike 7322, the 7220 needs this, due to lack of
+                        * interrupt in some cases when we have sdma active
+                        * when the link goes down.
+                        */
+                       if (ppd->sdma_state.current_state !=
+                           qib_sdma_state_s20_idle)
+                               __qib_sdma_process_event(ppd,
+                                       qib_sdma_event_e00_go_hw_down);
+                       spin_unlock_irqrestore(&ppd->sdma_lock, flags);
+               }
+       }
+
+       if (symadj) {
+               if (ppd->cpspec->ibdeltainprog) {
+                       ppd->cpspec->ibdeltainprog = 0;
+                       ppd->cpspec->ibsymdelta += read_7220_creg32(ppd->dd,
+                               cr_ibsymbolerr) - ppd->cpspec->ibsymsnap;
+                       ppd->cpspec->iblnkerrdelta += read_7220_creg32(ppd->dd,
+                               cr_iblinkerrrecov) - ppd->cpspec->iblnkerrsnap;
+               }
+       } else if (!ibup && qib_compat_ddr_negotiate &&
+                  !ppd->cpspec->ibdeltainprog &&
+                       !(ppd->lflags & QIBL_IB_AUTONEG_INPROG)) {
+               ppd->cpspec->ibdeltainprog = 1;
+               ppd->cpspec->ibsymsnap = read_7220_creg32(ppd->dd,
+                                                         cr_ibsymbolerr);
+               ppd->cpspec->iblnkerrsnap = read_7220_creg32(ppd->dd,
+                                                    cr_iblinkerrrecov);
+       }
+
+       if (!ret)
+               qib_setup_7220_setextled(ppd, ibup);
+       return ret;
+}
+
+/*
+ * Does read/modify/write to appropriate registers to
+ * set output and direction bits selected by mask.
+ * these are in their canonical postions (e.g. lsb of
+ * dir will end up in D48 of extctrl on existing chips).
+ * returns contents of GP Inputs.
+ */
+static int gpio_7220_mod(struct qib_devdata *dd, u32 out, u32 dir, u32 mask)
+{
+       u64 read_val, new_out;
+       unsigned long flags;
+
+       if (mask) {
+               /* some bits being written, lock access to GPIO */
+               dir &= mask;
+               out &= mask;
+               spin_lock_irqsave(&dd->cspec->gpio_lock, flags);
+               dd->cspec->extctrl &= ~((u64)mask << SYM_LSB(EXTCtrl, GPIOOe));
+               dd->cspec->extctrl |= ((u64) dir << SYM_LSB(EXTCtrl, GPIOOe));
+               new_out = (dd->cspec->gpio_out & ~mask) | out;
+
+               qib_write_kreg(dd, kr_extctrl, dd->cspec->extctrl);
+               qib_write_kreg(dd, kr_gpio_out, new_out);
+               dd->cspec->gpio_out = new_out;
+               spin_unlock_irqrestore(&dd->cspec->gpio_lock, flags);
+       }
+       /*
+        * It is unlikely that a read at this time would get valid
+        * data on a pin whose direction line was set in the same
+        * call to this function. We include the read here because
+        * that allows us to potentially combine a change on one pin with
+        * a read on another, and because the old code did something like
+        * this.
+        */
+       read_val = qib_read_kreg64(dd, kr_extstatus);
+       return SYM_FIELD(read_val, EXTStatus, GPIOIn);
+}
+
+/*
+ * Read fundamental info we need to use the chip.  These are
+ * the registers that describe chip capabilities, and are
+ * saved in shadow registers.
+ */
+static void get_7220_chip_params(struct qib_devdata *dd)
+{
+       u64 val;
+       u32 piobufs;
+       int mtu;
+
+       dd->uregbase = qib_read_kreg32(dd, kr_userregbase);
+
+       dd->rcvtidcnt = qib_read_kreg32(dd, kr_rcvtidcnt);
+       dd->rcvtidbase = qib_read_kreg32(dd, kr_rcvtidbase);
+       dd->rcvegrbase = qib_read_kreg32(dd, kr_rcvegrbase);
+       dd->palign = qib_read_kreg32(dd, kr_palign);
+       dd->piobufbase = qib_read_kreg64(dd, kr_sendpiobufbase);
+       dd->pio2k_bufbase = dd->piobufbase & 0xffffffff;
+
+       val = qib_read_kreg64(dd, kr_sendpiosize);
+       dd->piosize2k = val & ~0U;
+       dd->piosize4k = val >> 32;
+
+       mtu = ib_mtu_enum_to_int(qib_ibmtu);
+       if (mtu == -1)
+               mtu = QIB_DEFAULT_MTU;
+       dd->pport->ibmtu = (u32)mtu;
+
+       val = qib_read_kreg64(dd, kr_sendpiobufcnt);
+       dd->piobcnt2k = val & ~0U;
+       dd->piobcnt4k = val >> 32;
+       /* these may be adjusted in init_chip_wc_pat() */
+       dd->pio2kbase = (u32 __iomem *)
+               ((char __iomem *) dd->kregbase + dd->pio2k_bufbase);
+       if (dd->piobcnt4k) {
+               dd->pio4kbase = (u32 __iomem *)
+                       ((char __iomem *) dd->kregbase +
+                        (dd->piobufbase >> 32));
+               /*
+                * 4K buffers take 2 pages; we use roundup just to be
+                * paranoid; we calculate it once here, rather than on
+                * ever buf allocate
+                */
+               dd->align4k = ALIGN(dd->piosize4k, dd->palign);
+       }
+
+       piobufs = dd->piobcnt4k + dd->piobcnt2k;
+
+       dd->pioavregs = ALIGN(piobufs, sizeof(u64) * BITS_PER_BYTE / 2) /
+               (sizeof(u64) * BITS_PER_BYTE / 2);
+}
+
+/*
+ * The chip base addresses in cspec and cpspec have to be set
+ * after possible init_chip_wc_pat(), rather than in
+ * qib_get_7220_chip_params(), so split out as separate function
+ */
+static void set_7220_baseaddrs(struct qib_devdata *dd)
+{
+       u32 cregbase;
+       /* init after possible re-map in init_chip_wc_pat() */
+       cregbase = qib_read_kreg32(dd, kr_counterregbase);
+       dd->cspec->cregbase = (u64 __iomem *)
+               ((char __iomem *) dd->kregbase + cregbase);
+
+       dd->egrtidbase = (u64 __iomem *)
+               ((char __iomem *) dd->kregbase + dd->rcvegrbase);
+}
+
+
+#define SENDCTRL_SHADOWED (SYM_MASK(SendCtrl, SendIntBufAvail) |       \
+                          SYM_MASK(SendCtrl, SPioEnable) |             \
+                          SYM_MASK(SendCtrl, SSpecialTriggerEn) |      \
+                          SYM_MASK(SendCtrl, SendBufAvailUpd) |        \
+                          SYM_MASK(SendCtrl, AvailUpdThld) |           \
+                          SYM_MASK(SendCtrl, SDmaEnable) |             \
+                          SYM_MASK(SendCtrl, SDmaIntEnable) |          \
+                          SYM_MASK(SendCtrl, SDmaHalt) |               \
+                          SYM_MASK(SendCtrl, SDmaSingleDescriptor))
+
+static int sendctrl_hook(struct qib_devdata *dd,
+                        const struct diag_observer *op,
+                        u32 offs, u64 *data, u64 mask, int only_32)
+{
+       unsigned long flags;
+       unsigned idx = offs / sizeof(u64);
+       u64 local_data, all_bits;
+
+       if (idx != kr_sendctrl) {
+               qib_dev_err(dd, "SendCtrl Hook called with offs %X, %s-bit\n",
+                           offs, only_32 ? "32" : "64");
+               return 0;
+       }
+
+       all_bits = ~0ULL;
+       if (only_32)
+               all_bits >>= 32;
+       spin_lock_irqsave(&dd->sendctrl_lock, flags);
+       if ((mask & all_bits) != all_bits) {
+               /*
+                * At least some mask bits are zero, so we need
+                * to read. The judgement call is whether from
+                * reg or shadow. First-cut: read reg, and complain
+                * if any bits which should be shadowed are different
+                * from their shadowed value.
+                */
+               if (only_32)
+                       local_data = (u64)qib_read_kreg32(dd, idx);
+               else
+                       local_data = qib_read_kreg64(dd, idx);
+               qib_dev_err(dd, "Sendctrl -> %X, Shad -> %X\n",
+                           (u32)local_data, (u32)dd->sendctrl);
+               if ((local_data & SENDCTRL_SHADOWED) !=
+                   (dd->sendctrl & SENDCTRL_SHADOWED))
+                       qib_dev_err(dd, "Sendctrl read: %X shadow is %X\n",
+                               (u32)local_data, (u32) dd->sendctrl);
+               *data = (local_data & ~mask) | (*data & mask);
+       }
+       if (mask) {
+               /*
+                * At least some mask bits are one, so we need
+                * to write, but only shadow some bits.
+                */
+               u64 sval, tval; /* Shadowed, transient */
+
+               /*
+                * New shadow val is bits we don't want to touch,
+                * ORed with bits we do, that are intended for shadow.
+                */
+               sval = (dd->sendctrl & ~mask);
+               sval |= *data & SENDCTRL_SHADOWED & mask;
+               dd->sendctrl = sval;
+               tval = sval | (*data & ~SENDCTRL_SHADOWED & mask);
+               qib_dev_err(dd, "Sendctrl <- %X, Shad <- %X\n",
+                           (u32)tval, (u32)sval);
+               qib_write_kreg(dd, kr_sendctrl, tval);
+               qib_write_kreg(dd, kr_scratch, 0Ull);
+       }
+       spin_unlock_irqrestore(&dd->sendctrl_lock, flags);
+
+       return only_32 ? 4 : 8;
+}
+
+static const struct diag_observer sendctrl_observer = {
+       sendctrl_hook, kr_sendctrl * sizeof(u64),
+       kr_sendctrl * sizeof(u64)
+};
+
+/*
+ * write the final few registers that depend on some of the
+ * init setup.  Done late in init, just before bringing up
+ * the serdes.
+ */
+static int qib_late_7220_initreg(struct qib_devdata *dd)
+{
+       int ret = 0;
+       u64 val;
+
+       qib_write_kreg(dd, kr_rcvhdrentsize, dd->rcvhdrentsize);
+       qib_write_kreg(dd, kr_rcvhdrsize, dd->rcvhdrsize);
+       qib_write_kreg(dd, kr_rcvhdrcnt, dd->rcvhdrcnt);
+       qib_write_kreg(dd, kr_sendpioavailaddr, dd->pioavailregs_phys);
+       val = qib_read_kreg64(dd, kr_sendpioavailaddr);
+       if (val != dd->pioavailregs_phys) {
+               qib_dev_err(dd, "Catastrophic software error, "
+                           "SendPIOAvailAddr written as %lx, "
+                           "read back as %llx\n",
+                           (unsigned long) dd->pioavailregs_phys,
+                           (unsigned long long) val);
+               ret = -EINVAL;
+       }
+       qib_register_observer(dd, &sendctrl_observer);
+       return ret;
+}
+
+static int qib_init_7220_variables(struct qib_devdata *dd)
+{
+       struct qib_chippport_specific *cpspec;
+       struct qib_pportdata *ppd;
+       int ret = 0;
+       u32 sbufs, updthresh;
+
+       cpspec = (struct qib_chippport_specific *)(dd + 1);
+       ppd = &cpspec->pportdata;
+       dd->pport = ppd;
+       dd->num_pports = 1;
+
+       dd->cspec = (struct qib_chip_specific *)(cpspec + dd->num_pports);
+       ppd->cpspec = cpspec;
+
+       spin_lock_init(&dd->cspec->sdepb_lock);
+       spin_lock_init(&dd->cspec->rcvmod_lock);
+       spin_lock_init(&dd->cspec->gpio_lock);
+
+       /* we haven't yet set QIB_PRESENT, so use read directly */
+       dd->revision = readq(&dd->kregbase[kr_revision]);
+
+       if ((dd->revision & 0xffffffffU) == 0xffffffffU) {
+               qib_dev_err(dd, "Revision register read failure, "
+                           "giving up initialization\n");
+               ret = -ENODEV;
+               goto bail;
+       }
+       dd->flags |= QIB_PRESENT;  /* now register routines work */
+
+       dd->majrev = (u8) SYM_FIELD(dd->revision, Revision_R,
+                                   ChipRevMajor);
+       dd->minrev = (u8) SYM_FIELD(dd->revision, Revision_R,
+                                   ChipRevMinor);
+
+       get_7220_chip_params(dd);
+       qib_7220_boardname(dd);
+
+       /*
+        * GPIO bits for TWSI data and clock,
+        * used for serial EEPROM.
+        */
+       dd->gpio_sda_num = _QIB_GPIO_SDA_NUM;
+       dd->gpio_scl_num = _QIB_GPIO_SCL_NUM;
+       dd->twsi_eeprom_dev = QIB_TWSI_EEPROM_DEV;
+
+       dd->flags |= QIB_HAS_INTX | QIB_HAS_LINK_LATENCY |
+               QIB_NODMA_RTAIL | QIB_HAS_THRESH_UPDATE;
+       dd->flags |= qib_special_trigger ?
+               QIB_USE_SPCL_TRIG : QIB_HAS_SEND_DMA;
+
+       /*
+        * EEPROM error log 0 is TXE Parity errors. 1 is RXE Parity.
+        * 2 is Some Misc, 3 is reserved for future.
+        */
+       dd->eep_st_masks[0].hwerrs_to_log = HWE_MASK(TXEMemParityErr);
+
+       dd->eep_st_masks[1].hwerrs_to_log = HWE_MASK(RXEMemParityErr);
+
+       dd->eep_st_masks[2].errs_to_log = ERR_MASK(ResetNegated);
+
+       init_waitqueue_head(&cpspec->autoneg_wait);
+       INIT_DELAYED_WORK(&cpspec->autoneg_work, autoneg_7220_work);
+
+       qib_init_pportdata(ppd, dd, 0, 1);
+       ppd->link_width_supported = IB_WIDTH_1X | IB_WIDTH_4X;
+       ppd->link_speed_supported = QIB_IB_SDR | QIB_IB_DDR;
+
+       ppd->link_width_enabled = ppd->link_width_supported;
+       ppd->link_speed_enabled = ppd->link_speed_supported;
+       /*
+        * Set the initial values to reasonable default, will be set
+        * for real when link is up.
+        */
+       ppd->link_width_active = IB_WIDTH_4X;
+       ppd->link_speed_active = QIB_IB_SDR;
+       ppd->delay_mult = rate_to_delay[0][1];
+       ppd->vls_supported = IB_VL_VL0;
+       ppd->vls_operational = ppd->vls_supported;
+
+       if (!qib_mini_init)
+               qib_write_kreg(dd, kr_rcvbthqp, QIB_KD_QP);
+
+       init_timer(&ppd->cpspec->chase_timer);
+       ppd->cpspec->chase_timer.function = reenable_7220_chase;
+       ppd->cpspec->chase_timer.data = (unsigned long)ppd;
+
+       qib_num_cfg_vls = 1; /* if any 7220's, only one VL */
+
+       dd->rcvhdrentsize = QIB_RCVHDR_ENTSIZE;
+       dd->rcvhdrsize = QIB_DFLT_RCVHDRSIZE;
+       dd->rhf_offset =
+               dd->rcvhdrentsize - sizeof(u64) / sizeof(u32);
+
+       /* we always allocate at least 2048 bytes for eager buffers */
+       ret = ib_mtu_enum_to_int(qib_ibmtu);
+       dd->rcvegrbufsize = ret != -1 ? max(ret, 2048) : QIB_DEFAULT_MTU;
+
+       qib_7220_tidtemplate(dd);
+
+       /*
+        * We can request a receive interrupt for 1 or
+        * more packets from current offset.  For now, we set this
+        * up for a single packet.
+        */
+       dd->rhdrhead_intr_off = 1ULL << 32;
+
+       /* setup the stats timer; the add_timer is done at end of init */
+       init_timer(&dd->stats_timer);
+       dd->stats_timer.function = qib_get_7220_faststats;
+       dd->stats_timer.data = (unsigned long) dd;
+       dd->stats_timer.expires = jiffies + ACTIVITY_TIMER * HZ;
+
+       /*
+        * Control[4] has been added to change the arbitration within
+        * the SDMA engine between favoring data fetches over descriptor
+        * fetches.  qib_sdma_fetch_arb==0 gives data fetches priority.
+        */
+       if (qib_sdma_fetch_arb)
+               dd->control |= 1 << 4;
+
+       dd->ureg_align = 0x10000;  /* 64KB alignment */
+
+       dd->piosize2kmax_dwords = (dd->piosize2k >> 2)-1;
+       qib_7220_config_ctxts(dd);
+       qib_set_ctxtcnt(dd);  /* needed for PAT setup */
+
+       if (qib_wc_pat) {
+               ret = init_chip_wc_pat(dd, 0);
+               if (ret)
+                       goto bail;
+       }
+       set_7220_baseaddrs(dd); /* set chip access pointers now */
+
+       ret = 0;
+       if (qib_mini_init)
+               goto bail;
+
+       ret = qib_create_ctxts(dd);
+       init_7220_cntrnames(dd);
+
+       /* use all of 4KB buffers for the kernel SDMA, zero if !SDMA.
+        * reserve the update threshold amount for other kernel use, such
+        * as sending SMI, MAD, and ACKs, or 3, whichever is greater,
+        * unless we aren't enabling SDMA, in which case we want to use
+        * all the 4k bufs for the kernel.
+        * if this was less than the update threshold, we could wait
+        * a long time for an update.  Coded this way because we
+        * sometimes change the update threshold for various reasons,
+        * and we want this to remain robust.
+        */
+       updthresh = 8U; /* update threshold */
+       if (dd->flags & QIB_HAS_SEND_DMA) {
+               dd->cspec->sdmabufcnt =  dd->piobcnt4k;
+               sbufs = updthresh > 3 ? updthresh : 3;
+       } else {
+               dd->cspec->sdmabufcnt = 0;
+               sbufs = dd->piobcnt4k;
+       }
+
+       dd->cspec->lastbuf_for_pio = dd->piobcnt2k + dd->piobcnt4k -
+               dd->cspec->sdmabufcnt;
+       dd->lastctxt_piobuf = dd->cspec->lastbuf_for_pio - sbufs;
+       dd->cspec->lastbuf_for_pio--; /* range is <= , not < */
+       dd->pbufsctxt = dd->lastctxt_piobuf /
+               (dd->cfgctxts - dd->first_user_ctxt);
+
+       /*
+        * if we are at 16 user contexts, we will have one 7 sbufs
+        * per context, so drop the update threshold to match.  We
+        * want to update before we actually run out, at low pbufs/ctxt
+        * so give ourselves some margin
+        */
+       if ((dd->pbufsctxt - 2) < updthresh)
+               updthresh = dd->pbufsctxt - 2;
+
+       dd->cspec->updthresh_dflt = updthresh;
+       dd->cspec->updthresh = updthresh;
+
+       /* before full enable, no interrupts, no locking needed */
+       dd->sendctrl |= (updthresh & SYM_RMASK(SendCtrl, AvailUpdThld))
+                            << SYM_LSB(SendCtrl, AvailUpdThld);
+
+       dd->psxmitwait_supported = 1;
+       dd->psxmitwait_check_rate = QIB_7220_PSXMITWAIT_CHECK_RATE;
+bail:
+       return ret;
+}
+
+static u32 __iomem *qib_7220_getsendbuf(struct qib_pportdata *ppd, u64 pbc,
+                                       u32 *pbufnum)
+{
+       u32 first, last, plen = pbc & QIB_PBC_LENGTH_MASK;
+       struct qib_devdata *dd = ppd->dd;
+       u32 __iomem *buf;
+
+       if (((pbc >> 32) & PBC_7220_VL15_SEND_CTRL) &&
+               !(ppd->lflags & (QIBL_IB_AUTONEG_INPROG | QIBL_LINKACTIVE)))
+               buf = get_7220_link_buf(ppd, pbufnum);
+       else {
+               if ((plen + 1) > dd->piosize2kmax_dwords)
+                       first = dd->piobcnt2k;
+               else
+                       first = 0;
+               /* try 4k if all 2k busy, so same last for both sizes */
+               last = dd->cspec->lastbuf_for_pio;
+               buf = qib_getsendbuf_range(dd, pbufnum, first, last);
+       }
+       return buf;
+}
+
+/* these 2 "counters" are really control registers, and are always RW */
+static void qib_set_cntr_7220_sample(struct qib_pportdata *ppd, u32 intv,
+                                    u32 start)
+{
+       write_7220_creg(ppd->dd, cr_psinterval, intv);
+       write_7220_creg(ppd->dd, cr_psstart, start);
+}
+
+/*
+ * NOTE: no real attempt is made to generalize the SDMA stuff.
+ * At some point "soon" we will have a new more generalized
+ * set of sdma interface, and then we'll clean this up.
+ */
+
+/* Must be called with sdma_lock held, or before init finished */
+static void qib_sdma_update_7220_tail(struct qib_pportdata *ppd, u16 tail)
+{
+       /* Commit writes to memory and advance the tail on the chip */
+       wmb();
+       ppd->sdma_descq_tail = tail;
+       qib_write_kreg(ppd->dd, kr_senddmatail, tail);
+}
+
+static void qib_sdma_set_7220_desc_cnt(struct qib_pportdata *ppd, unsigned cnt)
+{
+}
+
+static struct sdma_set_state_action sdma_7220_action_table[] = {
+       [qib_sdma_state_s00_hw_down] = {
+               .op_enable = 0,
+               .op_intenable = 0,
+               .op_halt = 0,
+               .go_s99_running_tofalse = 1,
+       },
+       [qib_sdma_state_s10_hw_start_up_wait] = {
+               .op_enable = 1,
+               .op_intenable = 1,
+               .op_halt = 1,
+       },
+       [qib_sdma_state_s20_idle] = {
+               .op_enable = 1,
+               .op_intenable = 1,
+               .op_halt = 1,
+       },
+       [qib_sdma_state_s30_sw_clean_up_wait] = {
+               .op_enable = 0,
+               .op_intenable = 1,
+               .op_halt = 0,
+       },
+       [qib_sdma_state_s40_hw_clean_up_wait] = {
+               .op_enable = 1,
+               .op_intenable = 1,
+               .op_halt = 1,
+       },
+       [qib_sdma_state_s50_hw_halt_wait] = {
+               .op_enable = 1,
+               .op_intenable = 1,
+               .op_halt = 1,
+       },
+       [qib_sdma_state_s99_running] = {
+               .op_enable = 1,
+               .op_intenable = 1,
+               .op_halt = 0,
+               .go_s99_running_totrue = 1,
+       },
+};
+
+static void qib_7220_sdma_init_early(struct qib_pportdata *ppd)
+{
+       ppd->sdma_state.set_state_action = sdma_7220_action_table;
+}
+
+static int init_sdma_7220_regs(struct qib_pportdata *ppd)
+{
+       struct qib_devdata *dd = ppd->dd;
+       unsigned i, n;
+       u64 senddmabufmask[3] = { 0 };
+
+       /* Set SendDmaBase */
+       qib_write_kreg(dd, kr_senddmabase, ppd->sdma_descq_phys);
+       qib_sdma_7220_setlengen(ppd);
+       qib_sdma_update_7220_tail(ppd, 0); /* Set SendDmaTail */
+       /* Set SendDmaHeadAddr */
+       qib_write_kreg(dd, kr_senddmaheadaddr, ppd->sdma_head_phys);
+
+       /*
+        * Reserve all the former "kernel" piobufs, using high number range
+        * so we get as many 4K buffers as possible
+        */
+       n = dd->piobcnt2k + dd->piobcnt4k;
+       i = n - dd->cspec->sdmabufcnt;
+
+       for (; i < n; ++i) {
+               unsigned word = i / 64;
+               unsigned bit = i & 63;
+
+               BUG_ON(word >= 3);
+               senddmabufmask[word] |= 1ULL << bit;
+       }
+       qib_write_kreg(dd, kr_senddmabufmask0, senddmabufmask[0]);
+       qib_write_kreg(dd, kr_senddmabufmask1, senddmabufmask[1]);
+       qib_write_kreg(dd, kr_senddmabufmask2, senddmabufmask[2]);
+
+       ppd->sdma_state.first_sendbuf = i;
+       ppd->sdma_state.last_sendbuf = n;
+
+       return 0;
+}
+
+/* sdma_lock must be held */
+static u16 qib_sdma_7220_gethead(struct qib_pportdata *ppd)
+{
+       struct qib_devdata *dd = ppd->dd;
+       int sane;
+       int use_dmahead;
+       u16 swhead;
+       u16 swtail;
+       u16 cnt;
+       u16 hwhead;
+
+       use_dmahead = __qib_sdma_running(ppd) &&
+               (dd->flags & QIB_HAS_SDMA_TIMEOUT);
+retry:
+       hwhead = use_dmahead ?
+               (u16)le64_to_cpu(*ppd->sdma_head_dma) :
+               (u16)qib_read_kreg32(dd, kr_senddmahead);
+
+       swhead = ppd->sdma_descq_head;
+       swtail = ppd->sdma_descq_tail;
+       cnt = ppd->sdma_descq_cnt;
+
+       if (swhead < swtail) {
+               /* not wrapped */
+               sane = (hwhead >= swhead) & (hwhead <= swtail);
+       } else if (swhead > swtail) {
+               /* wrapped around */
+               sane = ((hwhead >= swhead) && (hwhead < cnt)) ||
+                       (hwhead <= swtail);
+       } else {
+               /* empty */
+               sane = (hwhead == swhead);
+       }
+
+       if (unlikely(!sane)) {
+               if (use_dmahead) {
+                       /* try one more time, directly from the register */
+                       use_dmahead = 0;
+                       goto retry;
+               }
+               /* assume no progress */
+               hwhead = swhead;
+       }
+
+       return hwhead;
+}
+
+static int qib_sdma_7220_busy(struct qib_pportdata *ppd)
+{
+       u64 hwstatus = qib_read_kreg64(ppd->dd, kr_senddmastatus);
+
+       return (hwstatus & SYM_MASK(SendDmaStatus, ScoreBoardDrainInProg)) ||
+              (hwstatus & SYM_MASK(SendDmaStatus, AbortInProg)) ||
+              (hwstatus & SYM_MASK(SendDmaStatus, InternalSDmaEnable)) ||
+              !(hwstatus & SYM_MASK(SendDmaStatus, ScbEmpty));
+}
+
+/*
+ * Compute the amount of delay before sending the next packet if the
+ * port's send rate differs from the static rate set for the QP.
+ * Since the delay affects this packet but the amount of the delay is
+ * based on the length of the previous packet, use the last delay computed
+ * and save the delay count for this packet to be used next time
+ * we get here.
+ */
+static u32 qib_7220_setpbc_control(struct qib_pportdata *ppd, u32 plen,
+                                  u8 srate, u8 vl)
+{
+       u8 snd_mult = ppd->delay_mult;
+       u8 rcv_mult = ib_rate_to_delay[srate];
+       u32 ret = ppd->cpspec->last_delay_mult;
+
+       ppd->cpspec->last_delay_mult = (rcv_mult > snd_mult) ?
+               (plen * (rcv_mult - snd_mult) + 1) >> 1 : 0;
+
+       /* Indicate VL15, if necessary */
+       if (vl == 15)
+               ret |= PBC_7220_VL15_SEND_CTRL;
+       return ret;
+}
+
+static void qib_7220_initvl15_bufs(struct qib_devdata *dd)
+{
+}
+
+static void qib_7220_init_ctxt(struct qib_ctxtdata *rcd)
+{
+       if (!rcd->ctxt) {
+               rcd->rcvegrcnt = IBA7220_KRCVEGRCNT;
+               rcd->rcvegr_tid_base = 0;
+       } else {
+               rcd->rcvegrcnt = rcd->dd->cspec->rcvegrcnt;
+               rcd->rcvegr_tid_base = IBA7220_KRCVEGRCNT +
+                       (rcd->ctxt - 1) * rcd->rcvegrcnt;
+       }
+}
+
+static void qib_7220_txchk_change(struct qib_devdata *dd, u32 start,
+                                 u32 len, u32 which, struct qib_ctxtdata *rcd)
+{
+       int i;
+       unsigned long flags;
+
+       switch (which) {
+       case TXCHK_CHG_TYPE_KERN:
+               /* see if we need to raise avail update threshold */
+               spin_lock_irqsave(&dd->uctxt_lock, flags);
+               for (i = dd->first_user_ctxt;
+                    dd->cspec->updthresh != dd->cspec->updthresh_dflt
+                    && i < dd->cfgctxts; i++)
+                       if (dd->rcd[i] && dd->rcd[i]->subctxt_cnt &&
+                          ((dd->rcd[i]->piocnt / dd->rcd[i]->subctxt_cnt) - 1)
+                          < dd->cspec->updthresh_dflt)
+                               break;
+               spin_unlock_irqrestore(&dd->uctxt_lock, flags);
+               if (i == dd->cfgctxts) {
+                       spin_lock_irqsave(&dd->sendctrl_lock, flags);
+                       dd->cspec->updthresh = dd->cspec->updthresh_dflt;
+                       dd->sendctrl &= ~SYM_MASK(SendCtrl, AvailUpdThld);
+                       dd->sendctrl |= (dd->cspec->updthresh &
+                                        SYM_RMASK(SendCtrl, AvailUpdThld)) <<
+                                          SYM_LSB(SendCtrl, AvailUpdThld);
+                       spin_unlock_irqrestore(&dd->sendctrl_lock, flags);
+                       sendctrl_7220_mod(dd->pport, QIB_SENDCTRL_AVAIL_BLIP);
+               }
+               break;
+       case TXCHK_CHG_TYPE_USER:
+               spin_lock_irqsave(&dd->sendctrl_lock, flags);
+               if (rcd && rcd->subctxt_cnt && ((rcd->piocnt
+                       / rcd->subctxt_cnt) - 1) < dd->cspec->updthresh) {
+                       dd->cspec->updthresh = (rcd->piocnt /
+                                               rcd->subctxt_cnt) - 1;
+                       dd->sendctrl &= ~SYM_MASK(SendCtrl, AvailUpdThld);
+                       dd->sendctrl |= (dd->cspec->updthresh &
+                                       SYM_RMASK(SendCtrl, AvailUpdThld))
+                                       << SYM_LSB(SendCtrl, AvailUpdThld);
+                       spin_unlock_irqrestore(&dd->sendctrl_lock, flags);
+                       sendctrl_7220_mod(dd->pport, QIB_SENDCTRL_AVAIL_BLIP);
+               } else
+                       spin_unlock_irqrestore(&dd->sendctrl_lock, flags);
+               break;
+       }
+}
+
+static void writescratch(struct qib_devdata *dd, u32 val)
+{
+       qib_write_kreg(dd, kr_scratch, val);
+}
+
+#define VALID_TS_RD_REG_MASK 0xBF
+/**
+ * qib_7220_tempsense_read - read register of temp sensor via TWSI
+ * @dd: the qlogic_ib device
+ * @regnum: register to read from
+ *
+ * returns reg contents (0..255) or < 0 for error
+ */
+static int qib_7220_tempsense_rd(struct qib_devdata *dd, int regnum)
+{
+       int ret;
+       u8 rdata;
+
+       if (regnum > 7) {
+               ret = -EINVAL;
+               goto bail;
+       }
+
+       /* return a bogus value for (the one) register we do not have */
+       if (!((1 << regnum) & VALID_TS_RD_REG_MASK)) {
+               ret = 0;
+               goto bail;
+       }
+
+       ret = mutex_lock_interruptible(&dd->eep_lock);
+       if (ret)
+               goto bail;
+
+       ret = qib_twsi_blk_rd(dd, QIB_TWSI_TEMP_DEV, regnum, &rdata, 1);
+       if (!ret)
+               ret = rdata;
+
+       mutex_unlock(&dd->eep_lock);
+
+       /*
+        * There are three possibilities here:
+        * ret is actual value (0..255)
+        * ret is -ENXIO or -EINVAL from twsi code or this file
+        * ret is -EINTR from mutex_lock_interruptible.
+        */
+bail:
+       return ret;
+}
+
+/* Dummy function, as 7220 boards never disable EEPROM Write */
+static int qib_7220_eeprom_wen(struct qib_devdata *dd, int wen)
+{
+       return 1;
+}
+
+/**
+ * qib_init_iba7220_funcs - set up the chip-specific function pointers
+ * @dev: the pci_dev for qlogic_ib device
+ * @ent: pci_device_id struct for this dev
+ *
+ * This is global, and is called directly at init to set up the
+ * chip-specific function pointers for later use.
+ */
+struct qib_devdata *qib_init_iba7220_funcs(struct pci_dev *pdev,
+                                          const struct pci_device_id *ent)
+{
+       struct qib_devdata *dd;
+       int ret;
+       u32 boardid, minwidth;
+
+       dd = qib_alloc_devdata(pdev, sizeof(struct qib_chip_specific) +
+               sizeof(struct qib_chippport_specific));
+       if (IS_ERR(dd))
+               goto bail;
+
+       dd->f_bringup_serdes    = qib_7220_bringup_serdes;
+       dd->f_cleanup           = qib_setup_7220_cleanup;
+       dd->f_clear_tids        = qib_7220_clear_tids;
+       dd->f_free_irq          = qib_7220_free_irq;
+       dd->f_get_base_info     = qib_7220_get_base_info;
+       dd->f_get_msgheader     = qib_7220_get_msgheader;
+       dd->f_getsendbuf        = qib_7220_getsendbuf;
+       dd->f_gpio_mod          = gpio_7220_mod;
+       dd->f_eeprom_wen        = qib_7220_eeprom_wen;
+       dd->f_hdrqempty         = qib_7220_hdrqempty;
+       dd->f_ib_updown         = qib_7220_ib_updown;
+       dd->f_init_ctxt         = qib_7220_init_ctxt;
+       dd->f_initvl15_bufs     = qib_7220_initvl15_bufs;
+       dd->f_intr_fallback     = qib_7220_intr_fallback;
+       dd->f_late_initreg      = qib_late_7220_initreg;
+       dd->f_setpbc_control    = qib_7220_setpbc_control;
+       dd->f_portcntr          = qib_portcntr_7220;
+       dd->f_put_tid           = qib_7220_put_tid;
+       dd->f_quiet_serdes      = qib_7220_quiet_serdes;
+       dd->f_rcvctrl           = rcvctrl_7220_mod;
+       dd->f_read_cntrs        = qib_read_7220cntrs;
+       dd->f_read_portcntrs    = qib_read_7220portcntrs;
+       dd->f_reset             = qib_setup_7220_reset;
+       dd->f_init_sdma_regs    = init_sdma_7220_regs;
+       dd->f_sdma_busy         = qib_sdma_7220_busy;
+       dd->f_sdma_gethead      = qib_sdma_7220_gethead;
+       dd->f_sdma_sendctrl     = qib_7220_sdma_sendctrl;
+       dd->f_sdma_set_desc_cnt = qib_sdma_set_7220_desc_cnt;
+       dd->f_sdma_update_tail  = qib_sdma_update_7220_tail;
+       dd->f_sdma_hw_clean_up  = qib_7220_sdma_hw_clean_up;
+       dd->f_sdma_hw_start_up  = qib_7220_sdma_hw_start_up;
+       dd->f_sdma_init_early   = qib_7220_sdma_init_early;
+       dd->f_sendctrl          = sendctrl_7220_mod;
+       dd->f_set_armlaunch     = qib_set_7220_armlaunch;
+       dd->f_set_cntr_sample   = qib_set_cntr_7220_sample;
+       dd->f_iblink_state      = qib_7220_iblink_state;
+       dd->f_ibphys_portstate  = qib_7220_phys_portstate;
+       dd->f_get_ib_cfg        = qib_7220_get_ib_cfg;
+       dd->f_set_ib_cfg        = qib_7220_set_ib_cfg;
+       dd->f_set_ib_loopback   = qib_7220_set_loopback;
+       dd->f_set_intr_state    = qib_7220_set_intr_state;
+       dd->f_setextled         = qib_setup_7220_setextled;
+       dd->f_txchk_change      = qib_7220_txchk_change;
+       dd->f_update_usrhead    = qib_update_7220_usrhead;
+       dd->f_wantpiobuf_intr   = qib_wantpiobuf_7220_intr;
+       dd->f_xgxs_reset        = qib_7220_xgxs_reset;
+       dd->f_writescratch      = writescratch;
+       dd->f_tempsense_rd      = qib_7220_tempsense_rd;
+       /*
+        * Do remaining pcie setup and save pcie values in dd.
+        * Any error printing is already done by the init code.
+        * On return, we have the chip mapped, but chip registers
+        * are not set up until start of qib_init_7220_variables.
+        */
+       ret = qib_pcie_ddinit(dd, pdev, ent);
+       if (ret < 0)
+               goto bail_free;
+
+       /* initialize chip-specific variables */
+       ret = qib_init_7220_variables(dd);
+       if (ret)
+               goto bail_cleanup;
+
+       if (qib_mini_init)
+               goto bail;
+
+       boardid = SYM_FIELD(dd->revision, Revision,
+                           BoardID);
+       switch (boardid) {
+       case 0:
+       case 2:
+       case 10:
+       case 12:
+               minwidth = 16; /* x16 capable boards */
+               break;
+       default:
+               minwidth = 8; /* x8 capable boards */
+               break;
+       }
+       if (qib_pcie_params(dd, minwidth, NULL, NULL))
+               qib_dev_err(dd, "Failed to setup PCIe or interrupts; "
+                           "continuing anyway\n");
+
+       /* save IRQ for possible later use */
+       dd->cspec->irq = pdev->irq;
+
+       if (qib_read_kreg64(dd, kr_hwerrstatus) &
+           QLOGIC_IB_HWE_SERDESPLLFAILED)
+               qib_write_kreg(dd, kr_hwerrclear,
+                              QLOGIC_IB_HWE_SERDESPLLFAILED);
+
+       /* setup interrupt handler (interrupt type handled above) */
+       qib_setup_7220_interrupt(dd);
+       qib_7220_init_hwerrors(dd);
+
+       /* clear diagctrl register, in case diags were running and crashed */
+       qib_write_kreg(dd, kr_hwdiagctrl, 0);
+
+       goto bail;
+
+bail_cleanup:
+       qib_pcie_ddcleanup(dd);
+bail_free:
+       qib_free_devdata(dd);
+       dd = ERR_PTR(ret);
+bail:
+       return dd;
+}
diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c
new file mode 100644 (file)
index 0000000..503992d
--- /dev/null
@@ -0,0 +1,7645 @@
+/*
+ * Copyright (c) 2008, 2009, 2010 QLogic Corporation. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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.
+ */
+
+/*
+ * This file contains all of the code that is specific to the
+ * InfiniPath 7322 chip
+ */
+
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_smi.h>
+
+#include "qib.h"
+#include "qib_7322_regs.h"
+#include "qib_qsfp.h"
+
+#include "qib_mad.h"
+
+static void qib_setup_7322_setextled(struct qib_pportdata *, u32);
+static void qib_7322_handle_hwerrors(struct qib_devdata *, char *, size_t);
+static void sendctrl_7322_mod(struct qib_pportdata *ppd, u32 op);
+static irqreturn_t qib_7322intr(int irq, void *data);
+static irqreturn_t qib_7322bufavail(int irq, void *data);
+static irqreturn_t sdma_intr(int irq, void *data);
+static irqreturn_t sdma_idle_intr(int irq, void *data);
+static irqreturn_t sdma_progress_intr(int irq, void *data);
+static irqreturn_t sdma_cleanup_intr(int irq, void *data);
+static void qib_7322_txchk_change(struct qib_devdata *, u32, u32, u32,
+                                 struct qib_ctxtdata *rcd);
+static u8 qib_7322_phys_portstate(u64);
+static u32 qib_7322_iblink_state(u64);
+static void qib_set_ib_7322_lstate(struct qib_pportdata *ppd, u16 linkcmd,
+                                  u16 linitcmd);
+static void force_h1(struct qib_pportdata *);
+static void adj_tx_serdes(struct qib_pportdata *);
+static u32 qib_7322_setpbc_control(struct qib_pportdata *, u32, u8, u8);
+static void qib_7322_mini_pcs_reset(struct qib_pportdata *);
+
+static u32 ahb_mod(struct qib_devdata *, int, int, int, u32, u32);
+static void ibsd_wr_allchans(struct qib_pportdata *, int, unsigned, unsigned);
+
+#define BMASK(msb, lsb) (((1 << ((msb) + 1 - (lsb))) - 1) << (lsb))
+
+/* LE2 serdes values for different cases */
+#define LE2_DEFAULT 5
+#define LE2_5m 4
+#define LE2_QME 0
+
+/* Below is special-purpose, so only really works for the IB SerDes blocks. */
+#define IBSD(hw_pidx) (hw_pidx + 2)
+
+/* these are variables for documentation and experimentation purposes */
+static const unsigned rcv_int_timeout = 375;
+static const unsigned rcv_int_count = 16;
+static const unsigned sdma_idle_cnt = 64;
+
+/* Time to stop altering Rx Equalization parameters, after link up. */
+#define RXEQ_DISABLE_MSECS 2500
+
+/*
+ * Number of VLs we are configured to use (to allow for more
+ * credits per vl, etc.)
+ */
+ushort qib_num_cfg_vls = 2;
+module_param_named(num_vls, qib_num_cfg_vls, ushort, S_IRUGO);
+MODULE_PARM_DESC(num_vls, "Set number of Virtual Lanes to use (1-8)");
+
+static ushort qib_chase = 1;
+module_param_named(chase, qib_chase, ushort, S_IRUGO);
+MODULE_PARM_DESC(chase, "Enable state chase handling");
+
+static ushort qib_long_atten = 10; /* 10 dB ~= 5m length */
+module_param_named(long_attenuation, qib_long_atten, ushort, S_IRUGO);
+MODULE_PARM_DESC(long_attenuation, \
+                "attenuation cutoff (dB) for long copper cable setup");
+
+static ushort qib_singleport;
+module_param_named(singleport, qib_singleport, ushort, S_IRUGO);
+MODULE_PARM_DESC(singleport, "Use only IB port 1; more per-port buffer space");
+
+#define MAX_ATTEN_LEN 64 /* plenty for any real system */
+/* for read back, default index is ~5m copper cable */
+static char txselect_list[MAX_ATTEN_LEN] = "10";
+static struct kparam_string kp_txselect = {
+       .string = txselect_list,
+       .maxlen = MAX_ATTEN_LEN
+};
+static int  setup_txselect(const char *, struct kernel_param *);
+module_param_call(txselect, setup_txselect, param_get_string,
+                 &kp_txselect, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(txselect, \
+                "Tx serdes indices (for no QSFP or invalid QSFP data)");
+
+#define BOARD_QME7342 5
+#define BOARD_QMH7342 6
+#define IS_QMH(dd) (SYM_FIELD((dd)->revision, Revision, BoardID) == \
+                   BOARD_QMH7342)
+#define IS_QME(dd) (SYM_FIELD((dd)->revision, Revision, BoardID) == \
+                   BOARD_QME7342)
+
+#define KREG_IDX(regname)     (QIB_7322_##regname##_OFFS / sizeof(u64))
+
+#define KREG_IBPORT_IDX(regname) ((QIB_7322_##regname##_0_OFFS / sizeof(u64)))
+
+#define MASK_ACROSS(lsb, msb) \
+       (((1ULL << ((msb) + 1 - (lsb))) - 1) << (lsb))
+
+#define SYM_RMASK(regname, fldname) ((u64)              \
+       QIB_7322_##regname##_##fldname##_RMASK)
+
+#define SYM_MASK(regname, fldname) ((u64)               \
+       QIB_7322_##regname##_##fldname##_RMASK <<       \
+        QIB_7322_##regname##_##fldname##_LSB)
+
+#define SYM_FIELD(value, regname, fldname) ((u64)      \
+       (((value) >> SYM_LSB(regname, fldname)) &       \
+        SYM_RMASK(regname, fldname)))
+
+/* useful for things like LaFifoEmpty_0...7, TxCreditOK_0...7, etc. */
+#define SYM_FIELD_ACROSS(value, regname, fldname, nbits) \
+       (((value) >> SYM_LSB(regname, fldname)) & MASK_ACROSS(0, nbits))
+
+#define HWE_MASK(fldname) SYM_MASK(HwErrMask, fldname##Mask)
+#define ERR_MASK(fldname) SYM_MASK(ErrMask, fldname##Mask)
+#define ERR_MASK_N(fldname) SYM_MASK(ErrMask_0, fldname##Mask)
+#define INT_MASK(fldname) SYM_MASK(IntMask, fldname##IntMask)
+#define INT_MASK_P(fldname, port) SYM_MASK(IntMask, fldname##IntMask##_##port)
+/* Below because most, but not all, fields of IntMask have that full suffix */
+#define INT_MASK_PM(fldname, port) SYM_MASK(IntMask, fldname##Mask##_##port)
+
+
+#define SYM_LSB(regname, fldname) (QIB_7322_##regname##_##fldname##_LSB)
+
+/*
+ * the size bits give us 2^N, in KB units.  0 marks as invalid,
+ * and 7 is reserved.  We currently use only 2KB and 4KB
+ */
+#define IBA7322_TID_SZ_SHIFT QIB_7322_RcvTIDArray0_RT_BufSize_LSB
+#define IBA7322_TID_SZ_2K (1UL<<IBA7322_TID_SZ_SHIFT) /* 2KB */
+#define IBA7322_TID_SZ_4K (2UL<<IBA7322_TID_SZ_SHIFT) /* 4KB */
+#define IBA7322_TID_PA_SHIFT 11U /* TID addr in chip stored w/o low bits */
+
+#define SendIBSLIDAssignMask \
+       QIB_7322_SendIBSLIDAssign_0_SendIBSLIDAssign_15_0_RMASK
+#define SendIBSLMCMask \
+       QIB_7322_SendIBSLIDMask_0_SendIBSLIDMask_15_0_RMASK
+
+#define ExtLED_IB1_YEL SYM_MASK(EXTCtrl, LEDPort0YellowOn)
+#define ExtLED_IB1_GRN SYM_MASK(EXTCtrl, LEDPort0GreenOn)
+#define ExtLED_IB2_YEL SYM_MASK(EXTCtrl, LEDPort1YellowOn)
+#define ExtLED_IB2_GRN SYM_MASK(EXTCtrl, LEDPort1GreenOn)
+#define ExtLED_IB1_MASK (ExtLED_IB1_YEL | ExtLED_IB1_GRN)
+#define ExtLED_IB2_MASK (ExtLED_IB2_YEL | ExtLED_IB2_GRN)
+
+#define _QIB_GPIO_SDA_NUM 1
+#define _QIB_GPIO_SCL_NUM 0
+#define QIB_EEPROM_WEN_NUM 14
+#define QIB_TWSI_EEPROM_DEV 0xA2 /* All Production 7322 cards. */
+
+/* HW counter clock is at 4nsec */
+#define QIB_7322_PSXMITWAIT_CHECK_RATE 4000
+
+/* full speed IB port 1 only */
+#define PORT_SPD_CAP (QIB_IB_SDR | QIB_IB_DDR | QIB_IB_QDR)
+#define PORT_SPD_CAP_SHIFT 3
+
+/* full speed featuremask, both ports */
+#define DUAL_PORT_CAP (PORT_SPD_CAP | (PORT_SPD_CAP << PORT_SPD_CAP_SHIFT))
+
+/*
+ * This file contains almost all the chip-specific register information and
+ * access functions for the FAKED QLogic InfiniPath 7322 PCI-Express chip.
+ */
+
+/* Use defines to tie machine-generated names to lower-case names */
+#define kr_contextcnt KREG_IDX(ContextCnt)
+#define kr_control KREG_IDX(Control)
+#define kr_counterregbase KREG_IDX(CntrRegBase)
+#define kr_errclear KREG_IDX(ErrClear)
+#define kr_errmask KREG_IDX(ErrMask)
+#define kr_errstatus KREG_IDX(ErrStatus)
+#define kr_extctrl KREG_IDX(EXTCtrl)
+#define kr_extstatus KREG_IDX(EXTStatus)
+#define kr_gpio_clear KREG_IDX(GPIOClear)
+#define kr_gpio_mask KREG_IDX(GPIOMask)
+#define kr_gpio_out KREG_IDX(GPIOOut)
+#define kr_gpio_status KREG_IDX(GPIOStatus)
+#define kr_hwdiagctrl KREG_IDX(HwDiagCtrl)
+#define kr_debugportval KREG_IDX(DebugPortValueReg)
+#define kr_fmask KREG_IDX(feature_mask)
+#define kr_act_fmask KREG_IDX(active_feature_mask)
+#define kr_hwerrclear KREG_IDX(HwErrClear)
+#define kr_hwerrmask KREG_IDX(HwErrMask)
+#define kr_hwerrstatus KREG_IDX(HwErrStatus)
+#define kr_intclear KREG_IDX(IntClear)
+#define kr_intmask KREG_IDX(IntMask)
+#define kr_intredirect KREG_IDX(IntRedirect0)
+#define kr_intstatus KREG_IDX(IntStatus)
+#define kr_pagealign KREG_IDX(PageAlign)
+#define kr_rcvavailtimeout KREG_IDX(RcvAvailTimeOut0)
+#define kr_rcvctrl KREG_IDX(RcvCtrl) /* Common, but chip also has per-port */
+#define kr_rcvegrbase KREG_IDX(RcvEgrBase)
+#define kr_rcvegrcnt KREG_IDX(RcvEgrCnt)
+#define kr_rcvhdrcnt KREG_IDX(RcvHdrCnt)
+#define kr_rcvhdrentsize KREG_IDX(RcvHdrEntSize)
+#define kr_rcvhdrsize KREG_IDX(RcvHdrSize)
+#define kr_rcvtidbase KREG_IDX(RcvTIDBase)
+#define kr_rcvtidcnt KREG_IDX(RcvTIDCnt)
+#define kr_revision KREG_IDX(Revision)
+#define kr_scratch KREG_IDX(Scratch)
+#define kr_sendbuffererror KREG_IDX(SendBufErr0) /* and base for 1 and 2 */
+#define kr_sendcheckmask KREG_IDX(SendCheckMask0) /* and 1, 2 */
+#define kr_sendctrl KREG_IDX(SendCtrl)
+#define kr_sendgrhcheckmask KREG_IDX(SendGRHCheckMask0) /* and 1, 2 */
+#define kr_sendibpktmask KREG_IDX(SendIBPacketMask0) /* and 1, 2 */
+#define kr_sendpioavailaddr KREG_IDX(SendBufAvailAddr)
+#define kr_sendpiobufbase KREG_IDX(SendBufBase)
+#define kr_sendpiobufcnt KREG_IDX(SendBufCnt)
+#define kr_sendpiosize KREG_IDX(SendBufSize)
+#define kr_sendregbase KREG_IDX(SendRegBase)
+#define kr_sendbufavail0 KREG_IDX(SendBufAvail0)
+#define kr_userregbase KREG_IDX(UserRegBase)
+#define kr_intgranted KREG_IDX(Int_Granted)
+#define kr_vecclr_wo_int KREG_IDX(vec_clr_without_int)
+#define kr_intblocked KREG_IDX(IntBlocked)
+#define kr_r_access KREG_IDX(SPC_JTAG_ACCESS_REG)
+
+/*
+ * per-port kernel registers.  Access only with qib_read_kreg_port()
+ * or qib_write_kreg_port()
+ */
+#define krp_errclear KREG_IBPORT_IDX(ErrClear)
+#define krp_errmask KREG_IBPORT_IDX(ErrMask)
+#define krp_errstatus KREG_IBPORT_IDX(ErrStatus)
+#define krp_highprio_0 KREG_IBPORT_IDX(HighPriority0)
+#define krp_highprio_limit KREG_IBPORT_IDX(HighPriorityLimit)
+#define krp_hrtbt_guid KREG_IBPORT_IDX(HRTBT_GUID)
+#define krp_ib_pcsconfig KREG_IBPORT_IDX(IBPCSConfig)
+#define krp_ibcctrl_a KREG_IBPORT_IDX(IBCCtrlA)
+#define krp_ibcctrl_b KREG_IBPORT_IDX(IBCCtrlB)
+#define krp_ibcctrl_c KREG_IBPORT_IDX(IBCCtrlC)
+#define krp_ibcstatus_a KREG_IBPORT_IDX(IBCStatusA)
+#define krp_ibcstatus_b KREG_IBPORT_IDX(IBCStatusB)
+#define krp_txestatus KREG_IBPORT_IDX(TXEStatus)
+#define krp_lowprio_0 KREG_IBPORT_IDX(LowPriority0)
+#define krp_ncmodectrl KREG_IBPORT_IDX(IBNCModeCtrl)
+#define krp_partitionkey KREG_IBPORT_IDX(RcvPartitionKey)
+#define krp_psinterval KREG_IBPORT_IDX(PSInterval)
+#define krp_psstart KREG_IBPORT_IDX(PSStart)
+#define krp_psstat KREG_IBPORT_IDX(PSStat)
+#define krp_rcvbthqp KREG_IBPORT_IDX(RcvBTHQP)
+#define krp_rcvctrl KREG_IBPORT_IDX(RcvCtrl)
+#define krp_rcvpktledcnt KREG_IBPORT_IDX(RcvPktLEDCnt)
+#define krp_rcvqpmaptable KREG_IBPORT_IDX(RcvQPMapTableA)
+#define krp_rxcreditvl0 KREG_IBPORT_IDX(RxCreditVL0)
+#define krp_rxcreditvl15 (KREG_IBPORT_IDX(RxCreditVL0)+15)
+#define krp_sendcheckcontrol KREG_IBPORT_IDX(SendCheckControl)
+#define krp_sendctrl KREG_IBPORT_IDX(SendCtrl)
+#define krp_senddmabase KREG_IBPORT_IDX(SendDmaBase)
+#define krp_senddmabufmask0 KREG_IBPORT_IDX(SendDmaBufMask0)
+#define krp_senddmabufmask1 (KREG_IBPORT_IDX(SendDmaBufMask0) + 1)
+#define krp_senddmabufmask2 (KREG_IBPORT_IDX(SendDmaBufMask0) + 2)
+#define krp_senddmabuf_use0 KREG_IBPORT_IDX(SendDmaBufUsed0)
+#define krp_senddmabuf_use1 (KREG_IBPORT_IDX(SendDmaBufUsed0) + 1)
+#define krp_senddmabuf_use2 (KREG_IBPORT_IDX(SendDmaBufUsed0) + 2)
+#define krp_senddmadesccnt KREG_IBPORT_IDX(SendDmaDescCnt)
+#define krp_senddmahead KREG_IBPORT_IDX(SendDmaHead)
+#define krp_senddmaheadaddr KREG_IBPORT_IDX(SendDmaHeadAddr)
+#define krp_senddmaidlecnt KREG_IBPORT_IDX(SendDmaIdleCnt)
+#define krp_senddmalengen KREG_IBPORT_IDX(SendDmaLenGen)
+#define krp_senddmaprioritythld KREG_IBPORT_IDX(SendDmaPriorityThld)
+#define krp_senddmareloadcnt KREG_IBPORT_IDX(SendDmaReloadCnt)
+#define krp_senddmastatus KREG_IBPORT_IDX(SendDmaStatus)
+#define krp_senddmatail KREG_IBPORT_IDX(SendDmaTail)
+#define krp_sendhdrsymptom KREG_IBPORT_IDX(SendHdrErrSymptom)
+#define krp_sendslid KREG_IBPORT_IDX(SendIBSLIDAssign)
+#define krp_sendslidmask KREG_IBPORT_IDX(SendIBSLIDMask)
+#define krp_ibsdtestiftx KREG_IBPORT_IDX(IB_SDTEST_IF_TX)
+#define krp_adapt_dis_timer KREG_IBPORT_IDX(ADAPT_DISABLE_TIMER_THRESHOLD)
+#define krp_tx_deemph_override KREG_IBPORT_IDX(IBSD_TX_DEEMPHASIS_OVERRIDE)
+#define krp_serdesctrl KREG_IBPORT_IDX(IBSerdesCtrl)
+
+/*
+ * Per-context kernel registers.  Acess only with qib_read_kreg_ctxt()
+ * or qib_write_kreg_ctxt()
+ */
+#define krc_rcvhdraddr KREG_IDX(RcvHdrAddr0)
+#define krc_rcvhdrtailaddr KREG_IDX(RcvHdrTailAddr0)
+
+/*
+ * TID Flow table, per context.  Reduces
+ * number of hdrq updates to one per flow (or on errors).
+ * context 0 and 1 share same memory, but have distinct
+ * addresses.  Since for now, we never use expected sends
+ * on kernel contexts, we don't worry about that (we initialize
+ * those entries for ctxt 0/1 on driver load twice, for example).
+ */
+#define NUM_TIDFLOWS_CTXT 0x20 /* 0x20 per context; have to hardcode */
+#define ur_rcvflowtable (KREG_IDX(RcvTIDFlowTable0) - KREG_IDX(RcvHdrTail0))
+
+/* these are the error bits in the tid flows, and are W1C */
+#define TIDFLOW_ERRBITS  ( \
+       (SYM_MASK(RcvTIDFlowTable0, GenMismatch) << \
+       SYM_LSB(RcvTIDFlowTable0, GenMismatch)) | \
+       (SYM_MASK(RcvTIDFlowTable0, SeqMismatch) << \
+       SYM_LSB(RcvTIDFlowTable0, SeqMismatch)))
+
+/* Most (not all) Counters are per-IBport.
+ * Requires LBIntCnt is at offset 0 in the group
+ */
+#define CREG_IDX(regname) \
+((QIB_7322_##regname##_0_OFFS - QIB_7322_LBIntCnt_OFFS) / sizeof(u64))
+
+#define crp_badformat CREG_IDX(RxVersionErrCnt)
+#define crp_err_rlen CREG_IDX(RxLenErrCnt)
+#define crp_erricrc CREG_IDX(RxICRCErrCnt)
+#define crp_errlink CREG_IDX(RxLinkMalformCnt)
+#define crp_errlpcrc CREG_IDX(RxLPCRCErrCnt)
+#define crp_errpkey CREG_IDX(RxPKeyMismatchCnt)
+#define crp_errvcrc CREG_IDX(RxVCRCErrCnt)
+#define crp_excessbufferovfl CREG_IDX(ExcessBufferOvflCnt)
+#define crp_iblinkdown CREG_IDX(IBLinkDownedCnt)
+#define crp_iblinkerrrecov CREG_IDX(IBLinkErrRecoveryCnt)
+#define crp_ibstatuschange CREG_IDX(IBStatusChangeCnt)
+#define crp_ibsymbolerr CREG_IDX(IBSymbolErrCnt)
+#define crp_invalidrlen CREG_IDX(RxMaxMinLenErrCnt)
+#define crp_locallinkintegrityerr CREG_IDX(LocalLinkIntegrityErrCnt)
+#define crp_pktrcv CREG_IDX(RxDataPktCnt)
+#define crp_pktrcvflowctrl CREG_IDX(RxFlowPktCnt)
+#define crp_pktsend CREG_IDX(TxDataPktCnt)
+#define crp_pktsendflow CREG_IDX(TxFlowPktCnt)
+#define crp_psrcvdatacount CREG_IDX(PSRcvDataCount)
+#define crp_psrcvpktscount CREG_IDX(PSRcvPktsCount)
+#define crp_psxmitdatacount CREG_IDX(PSXmitDataCount)
+#define crp_psxmitpktscount CREG_IDX(PSXmitPktsCount)
+#define crp_psxmitwaitcount CREG_IDX(PSXmitWaitCount)
+#define crp_rcvebp CREG_IDX(RxEBPCnt)
+#define crp_rcvflowctrlviol CREG_IDX(RxFlowCtrlViolCnt)
+#define crp_rcvovfl CREG_IDX(RxBufOvflCnt)
+#define crp_rxdlidfltr CREG_IDX(RxDlidFltrCnt)
+#define crp_rxdroppkt CREG_IDX(RxDroppedPktCnt)
+#define crp_rxotherlocalphyerr CREG_IDX(RxOtherLocalPhyErrCnt)
+#define crp_rxqpinvalidctxt CREG_IDX(RxQPInvalidContextCnt)
+#define crp_rxvlerr CREG_IDX(RxVlErrCnt)
+#define crp_sendstall CREG_IDX(TxFlowStallCnt)
+#define crp_txdroppedpkt CREG_IDX(TxDroppedPktCnt)
+#define crp_txhdrerr CREG_IDX(TxHeadersErrCnt)
+#define crp_txlenerr CREG_IDX(TxLenErrCnt)
+#define crp_txlenerr CREG_IDX(TxLenErrCnt)
+#define crp_txminmaxlenerr CREG_IDX(TxMaxMinLenErrCnt)
+#define crp_txsdmadesc CREG_IDX(TxSDmaDescCnt)
+#define crp_txunderrun CREG_IDX(TxUnderrunCnt)
+#define crp_txunsupvl CREG_IDX(TxUnsupVLErrCnt)
+#define crp_vl15droppedpkt CREG_IDX(RxVL15DroppedPktCnt)
+#define crp_wordrcv CREG_IDX(RxDwordCnt)
+#define crp_wordsend CREG_IDX(TxDwordCnt)
+#define crp_tx_creditstalls CREG_IDX(TxCreditUpToDateTimeOut)
+
+/* these are the (few) counters that are not port-specific */
+#define CREG_DEVIDX(regname) ((QIB_7322_##regname##_OFFS - \
+                       QIB_7322_LBIntCnt_OFFS) / sizeof(u64))
+#define cr_base_egrovfl CREG_DEVIDX(RxP0HdrEgrOvflCnt)
+#define cr_lbint CREG_DEVIDX(LBIntCnt)
+#define cr_lbstall CREG_DEVIDX(LBFlowStallCnt)
+#define cr_pcieretrydiag CREG_DEVIDX(PcieRetryBufDiagQwordCnt)
+#define cr_rxtidflowdrop CREG_DEVIDX(RxTidFlowDropCnt)
+#define cr_tidfull CREG_DEVIDX(RxTIDFullErrCnt)
+#define cr_tidinvalid CREG_DEVIDX(RxTIDValidErrCnt)
+
+/* no chip register for # of IB ports supported, so define */
+#define NUM_IB_PORTS 2
+
+/* 1 VL15 buffer per hardware IB port, no register for this, so define */
+#define NUM_VL15_BUFS NUM_IB_PORTS
+
+/*
+ * context 0 and 1 are special, and there is no chip register that
+ * defines this value, so we have to define it here.
+ * These are all allocated to either 0 or 1 for single port
+ * hardware configuration, otherwise each gets half
+ */
+#define KCTXT0_EGRCNT 2048
+
+/* values for vl and port fields in PBC, 7322-specific */
+#define PBC_PORT_SEL_LSB 26
+#define PBC_PORT_SEL_RMASK 1
+#define PBC_VL_NUM_LSB 27
+#define PBC_VL_NUM_RMASK 7
+#define PBC_7322_VL15_SEND (1ULL << 63) /* pbc; VL15, no credit check */
+#define PBC_7322_VL15_SEND_CTRL (1ULL << 31) /* control version of same */
+
+static u8 ib_rate_to_delay[IB_RATE_120_GBPS + 1] = {
+       [IB_RATE_2_5_GBPS] = 16,
+       [IB_RATE_5_GBPS] = 8,
+       [IB_RATE_10_GBPS] = 4,
+       [IB_RATE_20_GBPS] = 2,
+       [IB_RATE_30_GBPS] = 2,
+       [IB_RATE_40_GBPS] = 1
+};
+
+#define IBA7322_LINKSPEED_SHIFT SYM_LSB(IBCStatusA_0, LinkSpeedActive)
+#define IBA7322_LINKWIDTH_SHIFT SYM_LSB(IBCStatusA_0, LinkWidthActive)
+
+/* link training states, from IBC */
+#define IB_7322_LT_STATE_DISABLED        0x00
+#define IB_7322_LT_STATE_LINKUP          0x01
+#define IB_7322_LT_STATE_POLLACTIVE      0x02
+#define IB_7322_LT_STATE_POLLQUIET       0x03
+#define IB_7322_LT_STATE_SLEEPDELAY      0x04
+#define IB_7322_LT_STATE_SLEEPQUIET      0x05
+#define IB_7322_LT_STATE_CFGDEBOUNCE     0x08
+#define IB_7322_LT_STATE_CFGRCVFCFG      0x09
+#define IB_7322_LT_STATE_CFGWAITRMT      0x0a
+#define IB_7322_LT_STATE_CFGIDLE         0x0b
+#define IB_7322_LT_STATE_RECOVERRETRAIN  0x0c
+#define IB_7322_LT_STATE_TXREVLANES      0x0d
+#define IB_7322_LT_STATE_RECOVERWAITRMT  0x0e
+#define IB_7322_LT_STATE_RECOVERIDLE     0x0f
+#define IB_7322_LT_STATE_CFGENH          0x10
+#define IB_7322_LT_STATE_CFGTEST         0x11
+
+/* link state machine states from IBC */
+#define IB_7322_L_STATE_DOWN             0x0
+#define IB_7322_L_STATE_INIT             0x1
+#define IB_7322_L_STATE_ARM              0x2
+#define IB_7322_L_STATE_ACTIVE           0x3
+#define IB_7322_L_STATE_ACT_DEFER        0x4
+
+static const u8 qib_7322_physportstate[0x20] = {
+       [IB_7322_LT_STATE_DISABLED] = IB_PHYSPORTSTATE_DISABLED,
+       [IB_7322_LT_STATE_LINKUP] = IB_PHYSPORTSTATE_LINKUP,
+       [IB_7322_LT_STATE_POLLACTIVE] = IB_PHYSPORTSTATE_POLL,
+       [IB_7322_LT_STATE_POLLQUIET] = IB_PHYSPORTSTATE_POLL,
+       [IB_7322_LT_STATE_SLEEPDELAY] = IB_PHYSPORTSTATE_SLEEP,
+       [IB_7322_LT_STATE_SLEEPQUIET] = IB_PHYSPORTSTATE_SLEEP,
+       [IB_7322_LT_STATE_CFGDEBOUNCE] = IB_PHYSPORTSTATE_CFG_TRAIN,
+       [IB_7322_LT_STATE_CFGRCVFCFG] =
+               IB_PHYSPORTSTATE_CFG_TRAIN,
+       [IB_7322_LT_STATE_CFGWAITRMT] =
+               IB_PHYSPORTSTATE_CFG_TRAIN,
+       [IB_7322_LT_STATE_CFGIDLE] = IB_PHYSPORTSTATE_CFG_IDLE,
+       [IB_7322_LT_STATE_RECOVERRETRAIN] =
+               IB_PHYSPORTSTATE_LINK_ERR_RECOVER,
+       [IB_7322_LT_STATE_RECOVERWAITRMT] =
+               IB_PHYSPORTSTATE_LINK_ERR_RECOVER,
+       [IB_7322_LT_STATE_RECOVERIDLE] =
+               IB_PHYSPORTSTATE_LINK_ERR_RECOVER,
+       [IB_7322_LT_STATE_CFGENH] = IB_PHYSPORTSTATE_CFG_ENH,
+       [IB_7322_LT_STATE_CFGTEST] = IB_PHYSPORTSTATE_CFG_TRAIN,
+       [0x12] = IB_PHYSPORTSTATE_CFG_TRAIN,
+       [0x13] = IB_PHYSPORTSTATE_CFG_WAIT_ENH,
+       [0x14] = IB_PHYSPORTSTATE_CFG_TRAIN,
+       [0x15] = IB_PHYSPORTSTATE_CFG_TRAIN,
+       [0x16] = IB_PHYSPORTSTATE_CFG_TRAIN,
+       [0x17] = IB_PHYSPORTSTATE_CFG_TRAIN
+};
+
+struct qib_chip_specific {
+       u64 __iomem *cregbase;
+       u64 *cntrs;
+       spinlock_t rcvmod_lock; /* protect rcvctrl shadow changes */
+       spinlock_t gpio_lock; /* RMW of shadows/regs for ExtCtrl and GPIO */
+       u64 main_int_mask;      /* clear bits which have dedicated handlers */
+       u64 int_enable_mask;  /* for per port interrupts in single port mode */
+       u64 errormask;
+       u64 hwerrmask;
+       u64 gpio_out; /* shadow of kr_gpio_out, for rmw ops */
+       u64 gpio_mask; /* shadow the gpio mask register */
+       u64 extctrl; /* shadow the gpio output enable, etc... */
+       u32 ncntrs;
+       u32 nportcntrs;
+       u32 cntrnamelen;
+       u32 portcntrnamelen;
+       u32 numctxts;
+       u32 rcvegrcnt;
+       u32 updthresh; /* current AvailUpdThld */
+       u32 updthresh_dflt; /* default AvailUpdThld */
+       u32 r1;
+       int irq;
+       u32 num_msix_entries;
+       u32 sdmabufcnt;
+       u32 lastbuf_for_pio;
+       u32 stay_in_freeze;
+       u32 recovery_ports_initted;
+       struct msix_entry *msix_entries;
+       void  **msix_arg;
+       unsigned long *sendchkenable;
+       unsigned long *sendgrhchk;
+       unsigned long *sendibchk;
+       u32 rcvavail_timeout[18];
+       char emsgbuf[128]; /* for device error interrupt msg buffer */
+};
+
+/* Table of entries in "human readable" form Tx Emphasis. */
+struct txdds_ent {
+       u8 amp;
+       u8 pre;
+       u8 main;
+       u8 post;
+};
+
+struct vendor_txdds_ent {
+       u8 oui[QSFP_VOUI_LEN];
+       u8 *partnum;
+       struct txdds_ent sdr;
+       struct txdds_ent ddr;
+       struct txdds_ent qdr;
+};
+
+static void write_tx_serdes_param(struct qib_pportdata *, struct txdds_ent *);
+
+#define TXDDS_TABLE_SZ 16 /* number of entries per speed in onchip table */
+#define TXDDS_EXTRA_SZ 11 /* number of extra tx settings entries */
+#define SERDES_CHANS 4 /* yes, it's obvious, but one less magic number */
+
+#define H1_FORCE_VAL 8
+#define H1_FORCE_QME 1 /*  may be overridden via setup_txselect() */
+#define H1_FORCE_QMH 7 /*  may be overridden via setup_txselect() */
+
+/* The static and dynamic registers are paired, and the pairs indexed by spd */
+#define krp_static_adapt_dis(spd) (KREG_IBPORT_IDX(ADAPT_DISABLE_STATIC_SDR) \
+       + ((spd) * 2))
+
+#define QDR_DFE_DISABLE_DELAY 4000 /* msec after LINKUP */
+#define QDR_STATIC_ADAPT_DOWN 0xf0f0f0f0ULL /* link down, H1-H4 QDR adapts */
+#define QDR_STATIC_ADAPT_DOWN_R1 0ULL /* r1 link down, H1-H4 QDR adapts */
+#define QDR_STATIC_ADAPT_INIT 0xffffffffffULL /* up, disable H0,H1-8, LE */
+#define QDR_STATIC_ADAPT_INIT_R1 0xf0ffffffffULL /* r1 up, disable H0,H1-8 */
+
+struct qib_chippport_specific {
+       u64 __iomem *kpregbase;
+       u64 __iomem *cpregbase;
+       u64 *portcntrs;
+       struct qib_pportdata *ppd;
+       wait_queue_head_t autoneg_wait;
+       struct delayed_work autoneg_work;
+       struct delayed_work ipg_work;
+       struct timer_list chase_timer;
+       /*
+        * these 5 fields are used to establish deltas for IB symbol
+        * errors and linkrecovery errors.  They can be reported on
+        * some chips during link negotiation prior to INIT, and with
+        * DDR when faking DDR negotiations with non-IBTA switches.
+        * The chip counters are adjusted at driver unload if there is
+        * a non-zero delta.
+        */
+       u64 ibdeltainprog;
+       u64 ibsymdelta;
+       u64 ibsymsnap;
+       u64 iblnkerrdelta;
+       u64 iblnkerrsnap;
+       u64 iblnkdownsnap;
+       u64 iblnkdowndelta;
+       u64 ibmalfdelta;
+       u64 ibmalfsnap;
+       u64 ibcctrl_a; /* krp_ibcctrl_a shadow */
+       u64 ibcctrl_b; /* krp_ibcctrl_b shadow */
+       u64 qdr_dfe_time;
+       u64 chase_end;
+       u32 autoneg_tries;
+       u32 recovery_init;
+       u32 qdr_dfe_on;
+       u32 qdr_reforce;
+       /*
+        * Per-bay per-channel rcv QMH H1 values and Tx values for QDR.
+        * entry zero is unused, to simplify indexing
+        */
+       u8 h1_val;
+       u8 no_eep;  /* txselect table index to use if no qsfp info */
+       u8 ipg_tries;
+       u8 ibmalfusesnap;
+       struct qib_qsfp_data qsfp_data;
+       char epmsgbuf[192]; /* for port error interrupt msg buffer */
+};
+
+static struct {
+       const char *name;
+       irq_handler_t handler;
+       int lsb;
+       int port; /* 0 if not port-specific, else port # */
+} irq_table[] = {
+       { QIB_DRV_NAME, qib_7322intr, -1, 0 },
+       { QIB_DRV_NAME " (buf avail)", qib_7322bufavail,
+               SYM_LSB(IntStatus, SendBufAvail), 0 },
+       { QIB_DRV_NAME " (sdma 0)", sdma_intr,
+               SYM_LSB(IntStatus, SDmaInt_0), 1 },
+       { QIB_DRV_NAME " (sdma 1)", sdma_intr,
+               SYM_LSB(IntStatus, SDmaInt_1), 2 },
+       { QIB_DRV_NAME " (sdmaI 0)", sdma_idle_intr,
+               SYM_LSB(IntStatus, SDmaIdleInt_0), 1 },
+       { QIB_DRV_NAME " (sdmaI 1)", sdma_idle_intr,
+               SYM_LSB(IntStatus, SDmaIdleInt_1), 2 },
+       { QIB_DRV_NAME " (sdmaP 0)", sdma_progress_intr,
+               SYM_LSB(IntStatus, SDmaProgressInt_0), 1 },
+       { QIB_DRV_NAME " (sdmaP 1)", sdma_progress_intr,
+               SYM_LSB(IntStatus, SDmaProgressInt_1), 2 },
+       { QIB_DRV_NAME " (sdmaC 0)", sdma_cleanup_intr,
+               SYM_LSB(IntStatus, SDmaCleanupDone_0), 1 },
+       { QIB_DRV_NAME " (sdmaC 1)", sdma_cleanup_intr,
+               SYM_LSB(IntStatus, SDmaCleanupDone_1), 2 },
+};
+
+/* ibcctrl bits */
+#define QLOGIC_IB_IBCC_LINKINITCMD_DISABLE 1
+/* cycle through TS1/TS2 till OK */
+#define QLOGIC_IB_IBCC_LINKINITCMD_POLL 2
+/* wait for TS1, then go on */
+#define QLOGIC_IB_IBCC_LINKINITCMD_SLEEP 3
+#define QLOGIC_IB_IBCC_LINKINITCMD_SHIFT 16
+
+#define QLOGIC_IB_IBCC_LINKCMD_DOWN 1           /* move to 0x11 */
+#define QLOGIC_IB_IBCC_LINKCMD_ARMED 2          /* move to 0x21 */
+#define QLOGIC_IB_IBCC_LINKCMD_ACTIVE 3 /* move to 0x31 */
+
+#define BLOB_7322_IBCHG 0x101
+
+static inline void qib_write_kreg(const struct qib_devdata *dd,
+                                 const u32 regno, u64 value);
+static inline u32 qib_read_kreg32(const struct qib_devdata *, const u32);
+static void write_7322_initregs(struct qib_devdata *);
+static void write_7322_init_portregs(struct qib_pportdata *);
+static void setup_7322_link_recovery(struct qib_pportdata *, u32);
+static void check_7322_rxe_status(struct qib_pportdata *);
+static u32 __iomem *qib_7322_getsendbuf(struct qib_pportdata *, u64, u32 *);
+
+/**
+ * qib_read_ureg32 - read 32-bit virtualized per-context register
+ * @dd: device
+ * @regno: register number
+ * @ctxt: context number
+ *
+ * Return the contents of a register that is virtualized to be per context.
+ * Returns -1 on errors (not distinguishable from valid contents at
+ * runtime; we may add a separate error variable at some point).
+ */
+static inline u32 qib_read_ureg32(const struct qib_devdata *dd,
+                                 enum qib_ureg regno, int ctxt)
+{
+       if (!dd->kregbase || !(dd->flags & QIB_PRESENT))
+               return 0;
+       return readl(regno + (u64 __iomem *)(
+               (dd->ureg_align * ctxt) + (dd->userbase ?
+                (char __iomem *)dd->userbase :
+                (char __iomem *)dd->kregbase + dd->uregbase)));
+}
+
+/**
+ * qib_read_ureg - read virtualized per-context register
+ * @dd: device
+ * @regno: register number
+ * @ctxt: context number
+ *
+ * Return the contents of a register that is virtualized to be per context.
+ * Returns -1 on errors (not distinguishable from valid contents at
+ * runtime; we may add a separate error variable at some point).
+ */
+static inline u64 qib_read_ureg(const struct qib_devdata *dd,
+                               enum qib_ureg regno, int ctxt)
+{
+
+       if (!dd->kregbase || !(dd->flags & QIB_PRESENT))
+               return 0;
+       return readq(regno + (u64 __iomem *)(
+               (dd->ureg_align * ctxt) + (dd->userbase ?
+                (char __iomem *)dd->userbase :
+                (char __iomem *)dd->kregbase + dd->uregbase)));
+}
+
+/**
+ * qib_write_ureg - write virtualized per-context register
+ * @dd: device
+ * @regno: register number
+ * @value: value
+ * @ctxt: context
+ *
+ * Write the contents of a register that is virtualized to be per context.
+ */
+static inline void qib_write_ureg(const struct qib_devdata *dd,
+                                 enum qib_ureg regno, u64 value, int ctxt)
+{
+       u64 __iomem *ubase;
+       if (dd->userbase)
+               ubase = (u64 __iomem *)
+                       ((char __iomem *) dd->userbase +
+                        dd->ureg_align * ctxt);
+       else
+               ubase = (u64 __iomem *)
+                       (dd->uregbase +
+                        (char __iomem *) dd->kregbase +
+                        dd->ureg_align * ctxt);
+
+       if (dd->kregbase && (dd->flags & QIB_PRESENT))
+               writeq(value, &ubase[regno]);
+}
+
+static inline u32 qib_read_kreg32(const struct qib_devdata *dd,
+                                 const u32 regno)
+{
+       if (!dd->kregbase || !(dd->flags & QIB_PRESENT))
+               return -1;
+       return readl((u32 __iomem *) &dd->kregbase[regno]);
+}
+
+static inline u64 qib_read_kreg64(const struct qib_devdata *dd,
+                                 const u32 regno)
+{
+       if (!dd->kregbase || !(dd->flags & QIB_PRESENT))
+               return -1;
+       return readq(&dd->kregbase[regno]);
+}
+
+static inline void qib_write_kreg(const struct qib_devdata *dd,
+                                 const u32 regno, u64 value)
+{
+       if (dd->kregbase && (dd->flags & QIB_PRESENT))
+               writeq(value, &dd->kregbase[regno]);
+}
+
+/*
+ * not many sanity checks for the port-specific kernel register routines,
+ * since they are only used when it's known to be safe.
+*/
+static inline u64 qib_read_kreg_port(const struct qib_pportdata *ppd,
+                                    const u16 regno)
+{
+       if (!ppd->cpspec->kpregbase || !(ppd->dd->flags & QIB_PRESENT))
+               return 0ULL;
+       return readq(&ppd->cpspec->kpregbase[regno]);
+}
+
+static inline void qib_write_kreg_port(const struct qib_pportdata *ppd,
+                                      const u16 regno, u64 value)
+{
+       if (ppd->cpspec && ppd->dd && ppd->cpspec->kpregbase &&
+           (ppd->dd->flags & QIB_PRESENT))
+               writeq(value, &ppd->cpspec->kpregbase[regno]);
+}
+
+/**
+ * qib_write_kreg_ctxt - write a device's per-ctxt 64-bit kernel register
+ * @dd: the qlogic_ib device
+ * @regno: the register number to write
+ * @ctxt: the context containing the register
+ * @value: the value to write
+ */
+static inline void qib_write_kreg_ctxt(const struct qib_devdata *dd,
+                                      const u16 regno, unsigned ctxt,
+                                      u64 value)
+{
+       qib_write_kreg(dd, regno + ctxt, value);
+}
+
+static inline u64 read_7322_creg(const struct qib_devdata *dd, u16 regno)
+{
+       if (!dd->cspec->cregbase || !(dd->flags & QIB_PRESENT))
+               return 0;
+       return readq(&dd->cspec->cregbase[regno]);
+
+
+}
+
+static inline u32 read_7322_creg32(const struct qib_devdata *dd, u16 regno)
+{
+       if (!dd->cspec->cregbase || !(dd->flags & QIB_PRESENT))
+               return 0;
+       return readl(&dd->cspec->cregbase[regno]);
+
+
+}
+
+static inline void write_7322_creg_port(const struct qib_pportdata *ppd,
+                                       u16 regno, u64 value)
+{
+       if (ppd->cpspec && ppd->cpspec->cpregbase &&
+           (ppd->dd->flags & QIB_PRESENT))
+               writeq(value, &ppd->cpspec->cpregbase[regno]);
+}
+
+static inline u64 read_7322_creg_port(const struct qib_pportdata *ppd,
+                                     u16 regno)
+{
+       if (!ppd->cpspec || !ppd->cpspec->cpregbase ||
+           !(ppd->dd->flags & QIB_PRESENT))
+               return 0;
+       return readq(&ppd->cpspec->cpregbase[regno]);
+}
+
+static inline u32 read_7322_creg32_port(const struct qib_pportdata *ppd,
+                                       u16 regno)
+{
+       if (!ppd->cpspec || !ppd->cpspec->cpregbase ||
+           !(ppd->dd->flags & QIB_PRESENT))
+               return 0;
+       return readl(&ppd->cpspec->cpregbase[regno]);
+}
+
+/* bits in Control register */
+#define QLOGIC_IB_C_RESET SYM_MASK(Control, SyncReset)
+#define QLOGIC_IB_C_SDMAFETCHPRIOEN SYM_MASK(Control, SDmaDescFetchPriorityEn)
+
+/* bits in general interrupt regs */
+#define QIB_I_RCVURG_LSB SYM_LSB(IntMask, RcvUrg0IntMask)
+#define QIB_I_RCVURG_RMASK MASK_ACROSS(0, 17)
+#define QIB_I_RCVURG_MASK (QIB_I_RCVURG_RMASK << QIB_I_RCVURG_LSB)
+#define QIB_I_RCVAVAIL_LSB SYM_LSB(IntMask, RcvAvail0IntMask)
+#define QIB_I_RCVAVAIL_RMASK MASK_ACROSS(0, 17)
+#define QIB_I_RCVAVAIL_MASK (QIB_I_RCVAVAIL_RMASK << QIB_I_RCVAVAIL_LSB)
+#define QIB_I_C_ERROR INT_MASK(Err)
+
+#define QIB_I_SPIOSENT (INT_MASK_P(SendDone, 0) | INT_MASK_P(SendDone, 1))
+#define QIB_I_SPIOBUFAVAIL INT_MASK(SendBufAvail)
+#define QIB_I_GPIO INT_MASK(AssertGPIO)
+#define QIB_I_P_SDMAINT(pidx) \
+       (INT_MASK_P(SDma, pidx) | INT_MASK_P(SDmaIdle, pidx) | \
+        INT_MASK_P(SDmaProgress, pidx) | \
+        INT_MASK_PM(SDmaCleanupDone, pidx))
+
+/* Interrupt bits that are "per port" */
+#define QIB_I_P_BITSEXTANT(pidx) \
+       (INT_MASK_P(Err, pidx) | INT_MASK_P(SendDone, pidx) | \
+       INT_MASK_P(SDma, pidx) | INT_MASK_P(SDmaIdle, pidx) | \
+       INT_MASK_P(SDmaProgress, pidx) | \
+       INT_MASK_PM(SDmaCleanupDone, pidx))
+
+/* Interrupt bits that are common to a device */
+/* currently unused: QIB_I_SPIOSENT */
+#define QIB_I_C_BITSEXTANT \
+       (QIB_I_RCVURG_MASK | QIB_I_RCVAVAIL_MASK | \
+       QIB_I_SPIOSENT | \
+       QIB_I_C_ERROR | QIB_I_SPIOBUFAVAIL | QIB_I_GPIO)
+
+#define QIB_I_BITSEXTANT (QIB_I_C_BITSEXTANT | \
+       QIB_I_P_BITSEXTANT(0) | QIB_I_P_BITSEXTANT(1))
+
+/*
+ * Error bits that are "per port".
+ */
+#define QIB_E_P_IBSTATUSCHANGED ERR_MASK_N(IBStatusChanged)
+#define QIB_E_P_SHDR ERR_MASK_N(SHeadersErr)
+#define QIB_E_P_VL15_BUF_MISUSE ERR_MASK_N(VL15BufMisuseErr)
+#define QIB_E_P_SND_BUF_MISUSE ERR_MASK_N(SendBufMisuseErr)
+#define QIB_E_P_SUNSUPVL ERR_MASK_N(SendUnsupportedVLErr)
+#define QIB_E_P_SUNEXP_PKTNUM ERR_MASK_N(SendUnexpectedPktNumErr)
+#define QIB_E_P_SDROP_DATA ERR_MASK_N(SendDroppedDataPktErr)
+#define QIB_E_P_SDROP_SMP ERR_MASK_N(SendDroppedSmpPktErr)
+#define QIB_E_P_SPKTLEN ERR_MASK_N(SendPktLenErr)
+#define QIB_E_P_SUNDERRUN ERR_MASK_N(SendUnderRunErr)
+#define QIB_E_P_SMAXPKTLEN ERR_MASK_N(SendMaxPktLenErr)
+#define QIB_E_P_SMINPKTLEN ERR_MASK_N(SendMinPktLenErr)
+#define QIB_E_P_RIBLOSTLINK ERR_MASK_N(RcvIBLostLinkErr)
+#define QIB_E_P_RHDR ERR_MASK_N(RcvHdrErr)
+#define QIB_E_P_RHDRLEN ERR_MASK_N(RcvHdrLenErr)
+#define QIB_E_P_RBADTID ERR_MASK_N(RcvBadTidErr)
+#define QIB_E_P_RBADVERSION ERR_MASK_N(RcvBadVersionErr)
+#define QIB_E_P_RIBFLOW ERR_MASK_N(RcvIBFlowErr)
+#define QIB_E_P_REBP ERR_MASK_N(RcvEBPErr)
+#define QIB_E_P_RUNSUPVL ERR_MASK_N(RcvUnsupportedVLErr)
+#define QIB_E_P_RUNEXPCHAR ERR_MASK_N(RcvUnexpectedCharErr)
+#define QIB_E_P_RSHORTPKTLEN ERR_MASK_N(RcvShortPktLenErr)
+#define QIB_E_P_RLONGPKTLEN ERR_MASK_N(RcvLongPktLenErr)
+#define QIB_E_P_RMAXPKTLEN ERR_MASK_N(RcvMaxPktLenErr)
+#define QIB_E_P_RMINPKTLEN ERR_MASK_N(RcvMinPktLenErr)
+#define QIB_E_P_RICRC ERR_MASK_N(RcvICRCErr)
+#define QIB_E_P_RVCRC ERR_MASK_N(RcvVCRCErr)
+#define QIB_E_P_RFORMATERR ERR_MASK_N(RcvFormatErr)
+
+#define QIB_E_P_SDMA1STDESC ERR_MASK_N(SDma1stDescErr)
+#define QIB_E_P_SDMABASE ERR_MASK_N(SDmaBaseErr)
+#define QIB_E_P_SDMADESCADDRMISALIGN ERR_MASK_N(SDmaDescAddrMisalignErr)
+#define QIB_E_P_SDMADWEN ERR_MASK_N(SDmaDwEnErr)
+#define QIB_E_P_SDMAGENMISMATCH ERR_MASK_N(SDmaGenMismatchErr)
+#define QIB_E_P_SDMAHALT ERR_MASK_N(SDmaHaltErr)
+#define QIB_E_P_SDMAMISSINGDW ERR_MASK_N(SDmaMissingDwErr)
+#define QIB_E_P_SDMAOUTOFBOUND ERR_MASK_N(SDmaOutOfBoundErr)
+#define QIB_E_P_SDMARPYTAG ERR_MASK_N(SDmaRpyTagErr)
+#define QIB_E_P_SDMATAILOUTOFBOUND ERR_MASK_N(SDmaTailOutOfBoundErr)
+#define QIB_E_P_SDMAUNEXPDATA ERR_MASK_N(SDmaUnexpDataErr)
+
+/* Error bits that are common to a device */
+#define QIB_E_RESET ERR_MASK(ResetNegated)
+#define QIB_E_HARDWARE ERR_MASK(HardwareErr)
+#define QIB_E_INVALIDADDR ERR_MASK(InvalidAddrErr)
+
+
+/*
+ * Per chip (rather than per-port) errors.  Most either do
+ * nothing but trigger a print (because they self-recover, or
+ * always occur in tandem with other errors that handle the
+ * issue), or because they indicate errors with no recovery,
+ * but we want to know that they happened.
+ */
+#define QIB_E_SBUF_VL15_MISUSE ERR_MASK(SBufVL15MisUseErr)
+#define QIB_E_BADEEP ERR_MASK(InvalidEEPCmd)
+#define QIB_E_VLMISMATCH ERR_MASK(SendVLMismatchErr)
+#define QIB_E_ARMLAUNCH ERR_MASK(SendArmLaunchErr)
+#define QIB_E_SPCLTRIG ERR_MASK(SendSpecialTriggerErr)
+#define QIB_E_RRCVHDRFULL ERR_MASK(RcvHdrFullErr)
+#define QIB_E_RRCVEGRFULL ERR_MASK(RcvEgrFullErr)
+#define QIB_E_RCVCTXTSHARE ERR_MASK(RcvContextShareErr)
+
+/* SDMA chip errors (not per port)
+ * QIB_E_SDMA_BUF_DUP needs no special handling, because we will also get
+ * the SDMAHALT error immediately, so we just print the dup error via the
+ * E_AUTO mechanism.  This is true of most of the per-port fatal errors
+ * as well, but since this is port-independent, by definition, it's
+ * handled a bit differently.  SDMA_VL15 and SDMA_WRONG_PORT are per
+ * packet send errors, and so are handled in the same manner as other
+ * per-packet errors.
+ */
+#define QIB_E_SDMA_VL15 ERR_MASK(SDmaVL15Err)
+#define QIB_E_SDMA_WRONG_PORT ERR_MASK(SDmaWrongPortErr)
+#define QIB_E_SDMA_BUF_DUP ERR_MASK(SDmaBufMaskDuplicateErr)
+
+/*
+ * Below functionally equivalent to legacy QLOGIC_IB_E_PKTERRS
+ * it is used to print "common" packet errors.
+ */
+#define QIB_E_P_PKTERRS (QIB_E_P_SPKTLEN |\
+       QIB_E_P_SDROP_DATA | QIB_E_P_RVCRC |\
+       QIB_E_P_RICRC | QIB_E_P_RSHORTPKTLEN |\
+       QIB_E_P_VL15_BUF_MISUSE | QIB_E_P_SHDR | \
+       QIB_E_P_REBP)
+
+/* Error Bits that Packet-related (Receive, per-port) */
+#define QIB_E_P_RPKTERRS (\
+       QIB_E_P_RHDRLEN | QIB_E_P_RBADTID | \
+       QIB_E_P_RBADVERSION | QIB_E_P_RHDR | \
+       QIB_E_P_RLONGPKTLEN | QIB_E_P_RSHORTPKTLEN |\
+       QIB_E_P_RMAXPKTLEN | QIB_E_P_RMINPKTLEN | \
+       QIB_E_P_RFORMATERR | QIB_E_P_RUNSUPVL | \
+       QIB_E_P_RUNEXPCHAR | QIB_E_P_RIBFLOW | QIB_E_P_REBP)
+
+/*
+ * Error bits that are Send-related (per port)
+ * (ARMLAUNCH excluded from E_SPKTERRS because it gets special handling).
+ * All of these potentially need to have a buffer disarmed
+ */
+#define QIB_E_P_SPKTERRS (\
+       QIB_E_P_SUNEXP_PKTNUM |\
+       QIB_E_P_SDROP_DATA | QIB_E_P_SDROP_SMP |\
+       QIB_E_P_SMAXPKTLEN |\
+       QIB_E_P_VL15_BUF_MISUSE | QIB_E_P_SHDR | \
+       QIB_E_P_SMINPKTLEN | QIB_E_P_SPKTLEN | \
+       QIB_E_P_SND_BUF_MISUSE | QIB_E_P_SUNSUPVL)
+
+#define QIB_E_SPKTERRS ( \
+               QIB_E_SBUF_VL15_MISUSE | QIB_E_VLMISMATCH | \
+               ERR_MASK_N(SendUnsupportedVLErr) |                      \
+               QIB_E_SPCLTRIG | QIB_E_SDMA_VL15 | QIB_E_SDMA_WRONG_PORT)
+
+#define QIB_E_P_SDMAERRS ( \
+       QIB_E_P_SDMAHALT | \
+       QIB_E_P_SDMADESCADDRMISALIGN | \
+       QIB_E_P_SDMAUNEXPDATA | \
+       QIB_E_P_SDMAMISSINGDW | \
+       QIB_E_P_SDMADWEN | \
+       QIB_E_P_SDMARPYTAG | \
+       QIB_E_P_SDMA1STDESC | \
+       QIB_E_P_SDMABASE | \
+       QIB_E_P_SDMATAILOUTOFBOUND | \
+       QIB_E_P_SDMAOUTOFBOUND | \
+       QIB_E_P_SDMAGENMISMATCH)
+
+/*
+ * This sets some bits more than once, but makes it more obvious which
+ * bits are not handled under other categories, and the repeat definition
+ * is not a problem.
+ */
+#define QIB_E_P_BITSEXTANT ( \
+       QIB_E_P_SPKTERRS | QIB_E_P_PKTERRS | QIB_E_P_RPKTERRS | \
+       QIB_E_P_RIBLOSTLINK | QIB_E_P_IBSTATUSCHANGED | \
+       QIB_E_P_SND_BUF_MISUSE | QIB_E_P_SUNDERRUN | \
+       QIB_E_P_SHDR | QIB_E_P_VL15_BUF_MISUSE | QIB_E_P_SDMAERRS \
+       )
+
+/*
+ * These are errors that can occur when the link
+ * changes state while a packet is being sent or received.  This doesn't
+ * cover things like EBP or VCRC that can be the result of a sending
+ * having the link change state, so we receive a "known bad" packet.
+ * All of these are "per port", so renamed:
+ */
+#define QIB_E_P_LINK_PKTERRS (\
+       QIB_E_P_SDROP_DATA | QIB_E_P_SDROP_SMP |\
+       QIB_E_P_SMINPKTLEN | QIB_E_P_SPKTLEN |\
+       QIB_E_P_RSHORTPKTLEN | QIB_E_P_RMINPKTLEN |\
+       QIB_E_P_RUNEXPCHAR)
+
+/*
+ * This sets some bits more than once, but makes it more obvious which
+ * bits are not handled under other categories (such as QIB_E_SPKTERRS),
+ * and the repeat definition is not a problem.
+ */
+#define QIB_E_C_BITSEXTANT (\
+       QIB_E_HARDWARE | QIB_E_INVALIDADDR | QIB_E_BADEEP |\
+       QIB_E_ARMLAUNCH | QIB_E_VLMISMATCH | QIB_E_RRCVHDRFULL |\
+       QIB_E_RRCVEGRFULL | QIB_E_RESET | QIB_E_SBUF_VL15_MISUSE)
+
+/* Likewise Neuter E_SPKT_ERRS_IGNORE */
+#define E_SPKT_ERRS_IGNORE 0
+
+#define QIB_EXTS_MEMBIST_DISABLED \
+       SYM_MASK(EXTStatus, MemBISTDisabled)
+#define QIB_EXTS_MEMBIST_ENDTEST \
+       SYM_MASK(EXTStatus, MemBISTEndTest)
+
+#define QIB_E_SPIOARMLAUNCH \
+       ERR_MASK(SendArmLaunchErr)
+
+#define IBA7322_IBCC_LINKINITCMD_MASK SYM_RMASK(IBCCtrlA_0, LinkInitCmd)
+#define IBA7322_IBCC_LINKCMD_SHIFT SYM_LSB(IBCCtrlA_0, LinkCmd)
+
+/*
+ * IBTA_1_2 is set when multiple speeds are enabled (normal),
+ * and also if forced QDR (only QDR enabled).  It's enabled for the
+ * forced QDR case so that scrambling will be enabled by the TS3
+ * exchange, when supported by both sides of the link.
+ */
+#define IBA7322_IBC_IBTA_1_2_MASK SYM_MASK(IBCCtrlB_0, IB_ENHANCED_MODE)
+#define IBA7322_IBC_MAX_SPEED_MASK SYM_MASK(IBCCtrlB_0, SD_SPEED)
+#define IBA7322_IBC_SPEED_QDR SYM_MASK(IBCCtrlB_0, SD_SPEED_QDR)
+#define IBA7322_IBC_SPEED_DDR SYM_MASK(IBCCtrlB_0, SD_SPEED_DDR)
+#define IBA7322_IBC_SPEED_SDR SYM_MASK(IBCCtrlB_0, SD_SPEED_SDR)
+#define IBA7322_IBC_SPEED_MASK (SYM_MASK(IBCCtrlB_0, SD_SPEED_SDR) | \
+       SYM_MASK(IBCCtrlB_0, SD_SPEED_DDR) | SYM_MASK(IBCCtrlB_0, SD_SPEED_QDR))
+#define IBA7322_IBC_SPEED_LSB SYM_LSB(IBCCtrlB_0, SD_SPEED_SDR)
+
+#define IBA7322_LEDBLINK_OFF_SHIFT SYM_LSB(RcvPktLEDCnt_0, OFFperiod)
+#define IBA7322_LEDBLINK_ON_SHIFT SYM_LSB(RcvPktLEDCnt_0, ONperiod)
+
+#define IBA7322_IBC_WIDTH_AUTONEG SYM_MASK(IBCCtrlB_0, IB_NUM_CHANNELS)
+#define IBA7322_IBC_WIDTH_4X_ONLY (1<<SYM_LSB(IBCCtrlB_0, IB_NUM_CHANNELS))
+#define IBA7322_IBC_WIDTH_1X_ONLY (0<<SYM_LSB(IBCCtrlB_0, IB_NUM_CHANNELS))
+
+#define IBA7322_IBC_RXPOL_MASK SYM_MASK(IBCCtrlB_0, IB_POLARITY_REV_SUPP)
+#define IBA7322_IBC_RXPOL_LSB SYM_LSB(IBCCtrlB_0, IB_POLARITY_REV_SUPP)
+#define IBA7322_IBC_HRTBT_MASK (SYM_MASK(IBCCtrlB_0, HRTBT_AUTO) | \
+       SYM_MASK(IBCCtrlB_0, HRTBT_ENB))
+#define IBA7322_IBC_HRTBT_RMASK (IBA7322_IBC_HRTBT_MASK >> \
+       SYM_LSB(IBCCtrlB_0, HRTBT_ENB))
+#define IBA7322_IBC_HRTBT_LSB SYM_LSB(IBCCtrlB_0, HRTBT_ENB)
+
+#define IBA7322_REDIRECT_VEC_PER_REG 12
+
+#define IBA7322_SENDCHK_PKEY SYM_MASK(SendCheckControl_0, PKey_En)
+#define IBA7322_SENDCHK_BTHQP SYM_MASK(SendCheckControl_0, BTHQP_En)
+#define IBA7322_SENDCHK_SLID SYM_MASK(SendCheckControl_0, SLID_En)
+#define IBA7322_SENDCHK_RAW_IPV6 SYM_MASK(SendCheckControl_0, RawIPV6_En)
+#define IBA7322_SENDCHK_MINSZ SYM_MASK(SendCheckControl_0, PacketTooSmall_En)
+
+#define AUTONEG_TRIES 3 /* sequential retries to negotiate DDR */
+
+#define HWE_AUTO(fldname) { .mask = SYM_MASK(HwErrMask, fldname##Mask), \
+       .msg = #fldname }
+#define HWE_AUTO_P(fldname, port) { .mask = SYM_MASK(HwErrMask, \
+       fldname##Mask##_##port), .msg = #fldname }
+static const struct qib_hwerror_msgs qib_7322_hwerror_msgs[] = {
+       HWE_AUTO_P(IBSerdesPClkNotDetect, 1),
+       HWE_AUTO_P(IBSerdesPClkNotDetect, 0),
+       HWE_AUTO(PCIESerdesPClkNotDetect),
+       HWE_AUTO(PowerOnBISTFailed),
+       HWE_AUTO(TempsenseTholdReached),
+       HWE_AUTO(MemoryErr),
+       HWE_AUTO(PCIeBusParityErr),
+       HWE_AUTO(PcieCplTimeout),
+       HWE_AUTO(PciePoisonedTLP),
+       HWE_AUTO_P(SDmaMemReadErr, 1),
+       HWE_AUTO_P(SDmaMemReadErr, 0),
+       HWE_AUTO_P(IBCBusFromSPCParityErr, 1),
+       HWE_AUTO_P(IBCBusFromSPCParityErr, 0),
+       HWE_AUTO_P(statusValidNoEop, 1),
+       HWE_AUTO_P(statusValidNoEop, 0),
+       HWE_AUTO(LATriggered),
+       { .mask = 0 }
+};
+
+#define E_AUTO(fldname) { .mask = SYM_MASK(ErrMask, fldname##Mask), \
+       .msg = #fldname }
+#define E_P_AUTO(fldname) { .mask = SYM_MASK(ErrMask_0, fldname##Mask), \
+       .msg = #fldname }
+static const struct qib_hwerror_msgs qib_7322error_msgs[] = {
+       E_AUTO(ResetNegated),
+       E_AUTO(HardwareErr),
+       E_AUTO(InvalidAddrErr),
+       E_AUTO(SDmaVL15Err),
+       E_AUTO(SBufVL15MisUseErr),
+       E_AUTO(InvalidEEPCmd),
+       E_AUTO(RcvContextShareErr),
+       E_AUTO(SendVLMismatchErr),
+       E_AUTO(SendArmLaunchErr),
+       E_AUTO(SendSpecialTriggerErr),
+       E_AUTO(SDmaWrongPortErr),
+       E_AUTO(SDmaBufMaskDuplicateErr),
+       E_AUTO(RcvHdrFullErr),
+       E_AUTO(RcvEgrFullErr),
+       { .mask = 0 }
+};
+
+static const struct  qib_hwerror_msgs qib_7322p_error_msgs[] = {
+       E_P_AUTO(IBStatusChanged),
+       E_P_AUTO(SHeadersErr),
+       E_P_AUTO(VL15BufMisuseErr),
+       /*
+        * SDmaHaltErr is not really an error, make it clearer;
+        */
+       {.mask = SYM_MASK(ErrMask_0, SDmaHaltErrMask), .msg = "SDmaHalted"},
+       E_P_AUTO(SDmaDescAddrMisalignErr),
+       E_P_AUTO(SDmaUnexpDataErr),
+       E_P_AUTO(SDmaMissingDwErr),
+       E_P_AUTO(SDmaDwEnErr),
+       E_P_AUTO(SDmaRpyTagErr),
+       E_P_AUTO(SDma1stDescErr),
+       E_P_AUTO(SDmaBaseErr),
+       E_P_AUTO(SDmaTailOutOfBoundErr),
+       E_P_AUTO(SDmaOutOfBoundErr),
+       E_P_AUTO(SDmaGenMismatchErr),
+       E_P_AUTO(SendBufMisuseErr),
+       E_P_AUTO(SendUnsupportedVLErr),
+       E_P_AUTO(SendUnexpectedPktNumErr),
+       E_P_AUTO(SendDroppedDataPktErr),
+       E_P_AUTO(SendDroppedSmpPktErr),
+       E_P_AUTO(SendPktLenErr),
+       E_P_AUTO(SendUnderRunErr),
+       E_P_AUTO(SendMaxPktLenErr),
+       E_P_AUTO(SendMinPktLenErr),
+       E_P_AUTO(RcvIBLostLinkErr),
+       E_P_AUTO(RcvHdrErr),
+       E_P_AUTO(RcvHdrLenErr),
+       E_P_AUTO(RcvBadTidErr),
+       E_P_AUTO(RcvBadVersionErr),
+       E_P_AUTO(RcvIBFlowErr),
+       E_P_AUTO(RcvEBPErr),
+       E_P_AUTO(RcvUnsupportedVLErr),
+       E_P_AUTO(RcvUnexpectedCharErr),
+       E_P_AUTO(RcvShortPktLenErr),
+       E_P_AUTO(RcvLongPktLenErr),
+       E_P_AUTO(RcvMaxPktLenErr),
+       E_P_AUTO(RcvMinPktLenErr),
+       E_P_AUTO(RcvICRCErr),
+       E_P_AUTO(RcvVCRCErr),
+       E_P_AUTO(RcvFormatErr),
+       { .mask = 0 }
+};
+
+/*
+ * Below generates "auto-message" for interrupts not specific to any port or
+ * context
+ */
+#define INTR_AUTO(fldname) { .mask = SYM_MASK(IntMask, fldname##Mask), \
+       .msg = #fldname }
+/* Below generates "auto-message" for interrupts specific to a port */
+#define INTR_AUTO_P(fldname) { .mask = MASK_ACROSS(\
+       SYM_LSB(IntMask, fldname##Mask##_0), \
+       SYM_LSB(IntMask, fldname##Mask##_1)), \
+       .msg = #fldname "_P" }
+/* For some reason, the SerDesTrimDone bits are reversed */
+#define INTR_AUTO_PI(fldname) { .mask = MASK_ACROSS(\
+       SYM_LSB(IntMask, fldname##Mask##_1), \
+       SYM_LSB(IntMask, fldname##Mask##_0)), \
+       .msg = #fldname "_P" }
+/*
+ * Below generates "auto-message" for interrupts specific to a context,
+ * with ctxt-number appended
+ */
+#define INTR_AUTO_C(fldname) { .mask = MASK_ACROSS(\
+       SYM_LSB(IntMask, fldname##0IntMask), \
+       SYM_LSB(IntMask, fldname##17IntMask)), \
+       .msg = #fldname "_C"}
+
+static const struct  qib_hwerror_msgs qib_7322_intr_msgs[] = {
+       INTR_AUTO_P(SDmaInt),
+       INTR_AUTO_P(SDmaProgressInt),
+       INTR_AUTO_P(SDmaIdleInt),
+       INTR_AUTO_P(SDmaCleanupDone),
+       INTR_AUTO_C(RcvUrg),
+       INTR_AUTO_P(ErrInt),
+       INTR_AUTO(ErrInt),      /* non-port-specific errs */
+       INTR_AUTO(AssertGPIOInt),
+       INTR_AUTO_P(SendDoneInt),
+       INTR_AUTO(SendBufAvailInt),
+       INTR_AUTO_C(RcvAvail),
+       { .mask = 0 }
+};
+
+#define TXSYMPTOM_AUTO_P(fldname) \
+       { .mask = SYM_MASK(SendHdrErrSymptom_0, fldname), .msg = #fldname }
+static const struct  qib_hwerror_msgs hdrchk_msgs[] = {
+       TXSYMPTOM_AUTO_P(NonKeyPacket),
+       TXSYMPTOM_AUTO_P(GRHFail),
+       TXSYMPTOM_AUTO_P(PkeyFail),
+       TXSYMPTOM_AUTO_P(QPFail),
+       TXSYMPTOM_AUTO_P(SLIDFail),
+       TXSYMPTOM_AUTO_P(RawIPV6),
+       TXSYMPTOM_AUTO_P(PacketTooSmall),
+       { .mask = 0 }
+};
+
+#define IBA7322_HDRHEAD_PKTINT_SHIFT 32 /* interrupt cnt in upper 32 bits */
+
+/*
+ * Called when we might have an error that is specific to a particular
+ * PIO buffer, and may need to cancel that buffer, so it can be re-used,
+ * because we don't need to force the update of pioavail
+ */
+static void qib_disarm_7322_senderrbufs(struct qib_pportdata *ppd)
+{
+       struct qib_devdata *dd = ppd->dd;
+       u32 i;
+       int any;
+       u32 piobcnt = dd->piobcnt2k + dd->piobcnt4k + NUM_VL15_BUFS;
+       u32 regcnt = (piobcnt + BITS_PER_LONG - 1) / BITS_PER_LONG;
+       unsigned long sbuf[4];
+
+       /*
+        * It's possible that sendbuffererror could have bits set; might
+        * have already done this as a result of hardware error handling.
+        */
+       any = 0;
+       for (i = 0; i < regcnt; ++i) {
+               sbuf[i] = qib_read_kreg64(dd, kr_sendbuffererror + i);
+               if (sbuf[i]) {
+                       any = 1;
+                       qib_write_kreg(dd, kr_sendbuffererror + i, sbuf[i]);
+               }
+       }
+
+       if (any)
+               qib_disarm_piobufs_set(dd, sbuf, piobcnt);
+}
+
+/* No txe_recover yet, if ever */
+
+/* No decode__errors yet */
+static void err_decode(char *msg, size_t len, u64 errs,
+                      const struct qib_hwerror_msgs *msp)
+{
+       u64 these, lmask;
+       int took, multi, n = 0;
+
+       while (msp && msp->mask) {
+               multi = (msp->mask & (msp->mask - 1));
+               while (errs & msp->mask) {
+                       these = (errs & msp->mask);
+                       lmask = (these & (these - 1)) ^ these;
+                       if (len) {
+                               if (n++) {
+                                       /* separate the strings */
+                                       *msg++ = ',';
+                                       len--;
+                               }
+                               took = scnprintf(msg, len, "%s", msp->msg);
+                               len -= took;
+                               msg += took;
+                       }
+                       errs &= ~lmask;
+                       if (len && multi) {
+                               /* More than one bit this mask */
+                               int idx = -1;
+
+                               while (lmask & msp->mask) {
+                                       ++idx;
+                                       lmask >>= 1;
+                               }
+                               took = scnprintf(msg, len, "_%d", idx);
+                               len -= took;
+                               msg += took;
+                       }
+               }
+               ++msp;
+       }
+       /* If some bits are left, show in hex. */
+       if (len && errs)
+               snprintf(msg, len, "%sMORE:%llX", n ? "," : "",
+                       (unsigned long long) errs);
+}
+
+/* only called if r1 set */
+static void flush_fifo(struct qib_pportdata *ppd)
+{
+       struct qib_devdata *dd = ppd->dd;
+       u32 __iomem *piobuf;
+       u32 bufn;
+       u32 *hdr;
+       u64 pbc;
+       const unsigned hdrwords = 7;
+       static struct qib_ib_header ibhdr = {
+               .lrh[0] = cpu_to_be16(0xF000 | QIB_LRH_BTH),
+               .lrh[1] = IB_LID_PERMISSIVE,
+               .lrh[2] = cpu_to_be16(hdrwords + SIZE_OF_CRC),
+               .lrh[3] = IB_LID_PERMISSIVE,
+               .u.oth.bth[0] = cpu_to_be32(
+                       (IB_OPCODE_UD_SEND_ONLY << 24) | QIB_DEFAULT_P_KEY),
+               .u.oth.bth[1] = cpu_to_be32(0),
+               .u.oth.bth[2] = cpu_to_be32(0),
+               .u.oth.u.ud.deth[0] = cpu_to_be32(0),
+               .u.oth.u.ud.deth[1] = cpu_to_be32(0),
+       };
+
+       /*
+        * Send a dummy VL15 packet to flush the launch FIFO.
+        * This will not actually be sent since the TxeBypassIbc bit is set.
+        */
+       pbc = PBC_7322_VL15_SEND |
+               (((u64)ppd->hw_pidx) << (PBC_PORT_SEL_LSB + 32)) |
+               (hdrwords + SIZE_OF_CRC);
+       piobuf = qib_7322_getsendbuf(ppd, pbc, &bufn);
+       if (!piobuf)
+               return;
+       writeq(pbc, piobuf);
+       hdr = (u32 *) &ibhdr;
+       if (dd->flags & QIB_PIO_FLUSH_WC) {
+               qib_flush_wc();
+               qib_pio_copy(piobuf + 2, hdr, hdrwords - 1);
+               qib_flush_wc();
+               __raw_writel(hdr[hdrwords - 1], piobuf + hdrwords + 1);
+               qib_flush_wc();
+       } else
+               qib_pio_copy(piobuf + 2, hdr, hdrwords);
+       qib_sendbuf_done(dd, bufn);
+}
+
+/*
+ * This is called with interrupts disabled and sdma_lock held.
+ */
+static void qib_7322_sdma_sendctrl(struct qib_pportdata *ppd, unsigned op)
+{
+       struct qib_devdata *dd = ppd->dd;
+       u64 set_sendctrl = 0;
+       u64 clr_sendctrl = 0;
+
+       if (op & QIB_SDMA_SENDCTRL_OP_ENABLE)
+               set_sendctrl |= SYM_MASK(SendCtrl_0, SDmaEnable);
+       else
+               clr_sendctrl |= SYM_MASK(SendCtrl_0, SDmaEnable);
+
+       if (op & QIB_SDMA_SENDCTRL_OP_INTENABLE)
+               set_sendctrl |= SYM_MASK(SendCtrl_0, SDmaIntEnable);
+       else
+               clr_sendctrl |= SYM_MASK(SendCtrl_0, SDmaIntEnable);
+
+       if (op & QIB_SDMA_SENDCTRL_OP_HALT)
+               set_sendctrl |= SYM_MASK(SendCtrl_0, SDmaHalt);
+       else
+               clr_sendctrl |= SYM_MASK(SendCtrl_0, SDmaHalt);
+
+       if (op & QIB_SDMA_SENDCTRL_OP_DRAIN)
+               set_sendctrl |= SYM_MASK(SendCtrl_0, TxeBypassIbc) |
+                               SYM_MASK(SendCtrl_0, TxeAbortIbc) |
+                               SYM_MASK(SendCtrl_0, TxeDrainRmFifo);
+       else
+               clr_sendctrl |= SYM_MASK(SendCtrl_0, TxeBypassIbc) |
+                               SYM_MASK(SendCtrl_0, TxeAbortIbc) |
+                               SYM_MASK(SendCtrl_0, TxeDrainRmFifo);
+
+       spin_lock(&dd->sendctrl_lock);
+
+       /* If we are draining everything, block sends first */
+       if (op & QIB_SDMA_SENDCTRL_OP_DRAIN) {
+               ppd->p_sendctrl &= ~SYM_MASK(SendCtrl_0, SendEnable);
+               qib_write_kreg_port(ppd, krp_sendctrl, ppd->p_sendctrl);
+               qib_write_kreg(dd, kr_scratch, 0);
+       }
+
+       ppd->p_sendctrl |= set_sendctrl;
+       ppd->p_sendctrl &= ~clr_sendctrl;
+
+       if (op & QIB_SDMA_SENDCTRL_OP_CLEANUP)
+               qib_write_kreg_port(ppd, krp_sendctrl,
+                                   ppd->p_sendctrl |
+                                   SYM_MASK(SendCtrl_0, SDmaCleanup));
+       else
+               qib_write_kreg_port(ppd, krp_sendctrl, ppd->p_sendctrl);
+       qib_write_kreg(dd, kr_scratch, 0);
+
+       if (op & QIB_SDMA_SENDCTRL_OP_DRAIN) {
+               ppd->p_sendctrl |= SYM_MASK(SendCtrl_0, SendEnable);
+               qib_write_kreg_port(ppd, krp_sendctrl, ppd->p_sendctrl);
+               qib_write_kreg(dd, kr_scratch, 0);
+       }
+
+       spin_unlock(&dd->sendctrl_lock);
+
+       if ((op & QIB_SDMA_SENDCTRL_OP_DRAIN) && ppd->dd->cspec->r1)
+               flush_fifo(ppd);
+}
+
+static void qib_7322_sdma_hw_clean_up(struct qib_pportdata *ppd)
+{
+       __qib_sdma_process_event(ppd, qib_sdma_event_e50_hw_cleaned);
+}
+
+static void qib_sdma_7322_setlengen(struct qib_pportdata *ppd)
+{
+       /*
+        * Set SendDmaLenGen and clear and set
+        * the MSB of the generation count to enable generation checking
+        * and load the internal generation counter.
+        */
+       qib_write_kreg_port(ppd, krp_senddmalengen, ppd->sdma_descq_cnt);
+       qib_write_kreg_port(ppd, krp_senddmalengen,
+                           ppd->sdma_descq_cnt |
+                           (1ULL << QIB_7322_SendDmaLenGen_0_Generation_MSB));
+}
+
+/*
+ * Must be called with sdma_lock held, or before init finished.
+ */
+static void qib_sdma_update_7322_tail(struct qib_pportdata *ppd, u16 tail)
+{
+       /* Commit writes to memory and advance the tail on the chip */
+       wmb();
+       ppd->sdma_descq_tail = tail;
+       qib_write_kreg_port(ppd, krp_senddmatail, tail);
+}
+
+/*
+ * This is called with interrupts disabled and sdma_lock held.
+ */
+static void qib_7322_sdma_hw_start_up(struct qib_pportdata *ppd)
+{
+       /*
+        * Drain all FIFOs.
+        * The hardware doesn't require this but we do it so that verbs
+        * and user applications don't wait for link active to send stale
+        * data.
+        */
+       sendctrl_7322_mod(ppd, QIB_SENDCTRL_FLUSH);
+
+       qib_sdma_7322_setlengen(ppd);
+       qib_sdma_update_7322_tail(ppd, 0); /* Set SendDmaTail */
+       ppd->sdma_head_dma[0] = 0;
+       qib_7322_sdma_sendctrl(ppd,
+               ppd->sdma_state.current_op | QIB_SDMA_SENDCTRL_OP_CLEANUP);
+}
+
+#define DISABLES_SDMA ( \
+       QIB_E_P_SDMAHALT | \
+       QIB_E_P_SDMADESCADDRMISALIGN | \
+       QIB_E_P_SDMAMISSINGDW | \
+       QIB_E_P_SDMADWEN | \
+       QIB_E_P_SDMARPYTAG | \
+       QIB_E_P_SDMA1STDESC | \
+       QIB_E_P_SDMABASE | \
+       QIB_E_P_SDMATAILOUTOFBOUND | \
+       QIB_E_P_SDMAOUTOFBOUND | \
+       QIB_E_P_SDMAGENMISMATCH)
+
+static void sdma_7322_p_errors(struct qib_pportdata *ppd, u64 errs)
+{
+       unsigned long flags;
+       struct qib_devdata *dd = ppd->dd;
+
+       errs &= QIB_E_P_SDMAERRS;
+
+       if (errs & QIB_E_P_SDMAUNEXPDATA)
+               qib_dev_err(dd, "IB%u:%u SDmaUnexpData\n", dd->unit,
+                           ppd->port);
+
+       spin_lock_irqsave(&ppd->sdma_lock, flags);
+
+       switch (ppd->sdma_state.current_state) {
+       case qib_sdma_state_s00_hw_down:
+               break;
+
+       case qib_sdma_state_s10_hw_start_up_wait:
+               if (errs & QIB_E_P_SDMAHALT)
+                       __qib_sdma_process_event(ppd,
+                               qib_sdma_event_e20_hw_started);
+               break;
+
+       case qib_sdma_state_s20_idle:
+               break;
+
+       case qib_sdma_state_s30_sw_clean_up_wait:
+               break;
+
+       case qib_sdma_state_s40_hw_clean_up_wait:
+               if (errs & QIB_E_P_SDMAHALT)
+                       __qib_sdma_process_event(ppd,
+                               qib_sdma_event_e50_hw_cleaned);
+               break;
+
+       case qib_sdma_state_s50_hw_halt_wait:
+               if (errs & QIB_E_P_SDMAHALT)
+                       __qib_sdma_process_event(ppd,
+                               qib_sdma_event_e60_hw_halted);
+               break;
+
+       case qib_sdma_state_s99_running:
+               __qib_sdma_process_event(ppd, qib_sdma_event_e7322_err_halted);
+               __qib_sdma_process_event(ppd, qib_sdma_event_e60_hw_halted);
+               break;
+       }
+
+       spin_unlock_irqrestore(&ppd->sdma_lock, flags);
+}
+
+/*
+ * handle per-device errors (not per-port errors)
+ */
+static noinline void handle_7322_errors(struct qib_devdata *dd)
+{
+       char *msg;
+       u64 iserr = 0;
+       u64 errs;
+       u64 mask;
+       int log_idx;
+
+       qib_stats.sps_errints++;
+       errs = qib_read_kreg64(dd, kr_errstatus);
+       if (!errs) {
+               qib_devinfo(dd->pcidev, "device error interrupt, "
+                        "but no error bits set!\n");
+               goto done;
+       }
+
+       /* don't report errors that are masked */
+       errs &= dd->cspec->errormask;
+       msg = dd->cspec->emsgbuf;
+
+       /* do these first, they are most important */
+       if (errs & QIB_E_HARDWARE) {
+               *msg = '\0';
+               qib_7322_handle_hwerrors(dd, msg, sizeof dd->cspec->emsgbuf);
+       } else
+               for (log_idx = 0; log_idx < QIB_EEP_LOG_CNT; ++log_idx)
+                       if (errs & dd->eep_st_masks[log_idx].errs_to_log)
+                               qib_inc_eeprom_err(dd, log_idx, 1);
+
+       if (errs & QIB_E_SPKTERRS) {
+               qib_disarm_7322_senderrbufs(dd->pport);
+               qib_stats.sps_txerrs++;
+       } else if (errs & QIB_E_INVALIDADDR)
+               qib_stats.sps_txerrs++;
+       else if (errs & QIB_E_ARMLAUNCH) {
+               qib_stats.sps_txerrs++;
+               qib_disarm_7322_senderrbufs(dd->pport);
+       }
+       qib_write_kreg(dd, kr_errclear, errs);
+
+       /*
+        * The ones we mask off are handled specially below
+        * or above.  Also mask SDMADISABLED by default as it
+        * is too chatty.
+        */
+       mask = QIB_E_HARDWARE;
+       *msg = '\0';
+
+       err_decode(msg, sizeof dd->cspec->emsgbuf, errs & ~mask,
+                  qib_7322error_msgs);
+
+       /*
+        * Getting reset is a tragedy for all ports. Mark the device
+        * _and_ the ports as "offline" in way meaningful to each.
+        */
+       if (errs & QIB_E_RESET) {
+               int pidx;
+
+               qib_dev_err(dd, "Got reset, requires re-init "
+                           "(unload and reload driver)\n");
+               dd->flags &= ~QIB_INITTED;  /* needs re-init */
+               /* mark as having had error */
+               *dd->devstatusp |= QIB_STATUS_HWERROR;
+               for (pidx = 0; pidx < dd->num_pports; ++pidx)
+                       if (dd->pport[pidx].link_speed_supported)
+                               *dd->pport[pidx].statusp &= ~QIB_STATUS_IB_CONF;
+       }
+
+       if (*msg && iserr)
+               qib_dev_err(dd, "%s error\n", msg);
+
+       /*
+        * If there were hdrq or egrfull errors, wake up any processes
+        * waiting in poll.  We used to try to check which contexts had
+        * the overflow, but given the cost of that and the chip reads
+        * to support it, it's better to just wake everybody up if we
+        * get an overflow; waiters can poll again if it's not them.
+        */
+       if (errs & (ERR_MASK(RcvEgrFullErr) | ERR_MASK(RcvHdrFullErr))) {
+               qib_handle_urcv(dd, ~0U);
+               if (errs & ERR_MASK(RcvEgrFullErr))
+                       qib_stats.sps_buffull++;
+               else
+                       qib_stats.sps_hdrfull++;
+       }
+
+done:
+       return;
+}
+
+static void reenable_chase(unsigned long opaque)
+{
+       struct qib_pportdata *ppd = (struct qib_pportdata *)opaque;
+
+       ppd->cpspec->chase_timer.expires = 0;
+       qib_set_ib_7322_lstate(ppd, QLOGIC_IB_IBCC_LINKCMD_DOWN,
+               QLOGIC_IB_IBCC_LINKINITCMD_POLL);
+}
+
+static void disable_chase(struct qib_pportdata *ppd, u64 tnow, u8 ibclt)
+{
+       ppd->cpspec->chase_end = 0;
+
+       if (!qib_chase)
+               return;
+
+       qib_set_ib_7322_lstate(ppd, QLOGIC_IB_IBCC_LINKCMD_DOWN,
+               QLOGIC_IB_IBCC_LINKINITCMD_DISABLE);
+       ppd->cpspec->chase_timer.expires = jiffies + QIB_CHASE_DIS_TIME;
+       add_timer(&ppd->cpspec->chase_timer);
+}
+
+static void handle_serdes_issues(struct qib_pportdata *ppd, u64 ibcst)
+{
+       u8 ibclt;
+       u64 tnow;
+
+       ibclt = (u8)SYM_FIELD(ibcst, IBCStatusA_0, LinkTrainingState);
+
+       /*
+        * Detect and handle the state chase issue, where we can
+        * get stuck if we are unlucky on timing on both sides of
+        * the link.   If we are, we disable, set a timer, and
+        * then re-enable.
+        */
+       switch (ibclt) {
+       case IB_7322_LT_STATE_CFGRCVFCFG:
+       case IB_7322_LT_STATE_CFGWAITRMT:
+       case IB_7322_LT_STATE_TXREVLANES:
+       case IB_7322_LT_STATE_CFGENH:
+               tnow = get_jiffies_64();
+               if (ppd->cpspec->chase_end &&
+                    time_after64(tnow, ppd->cpspec->chase_end))
+                       disable_chase(ppd, tnow, ibclt);
+               else if (!ppd->cpspec->chase_end)
+                       ppd->cpspec->chase_end = tnow + QIB_CHASE_TIME;
+               break;
+       default:
+               ppd->cpspec->chase_end = 0;
+               break;
+       }
+
+       if (ibclt == IB_7322_LT_STATE_CFGTEST &&
+           (ibcst & SYM_MASK(IBCStatusA_0, LinkSpeedQDR))) {
+               force_h1(ppd);
+               ppd->cpspec->qdr_reforce = 1;
+       } else if (ppd->cpspec->qdr_reforce &&
+               (ibcst & SYM_MASK(IBCStatusA_0, LinkSpeedQDR)) &&
+                (ibclt == IB_7322_LT_STATE_CFGENH ||
+               ibclt == IB_7322_LT_STATE_CFGIDLE ||
+               ibclt == IB_7322_LT_STATE_LINKUP))
+               force_h1(ppd);
+
+       if ((IS_QMH(ppd->dd) || IS_QME(ppd->dd)) &&
+           ppd->link_speed_enabled == QIB_IB_QDR &&
+           (ibclt == IB_7322_LT_STATE_CFGTEST ||
+            ibclt == IB_7322_LT_STATE_CFGENH ||
+            (ibclt >= IB_7322_LT_STATE_POLLACTIVE &&
+             ibclt <= IB_7322_LT_STATE_SLEEPQUIET)))
+               adj_tx_serdes(ppd);
+
+       if (!ppd->cpspec->qdr_dfe_on && ibclt != IB_7322_LT_STATE_LINKUP &&
+           ibclt <= IB_7322_LT_STATE_SLEEPQUIET) {
+               ppd->cpspec->qdr_dfe_on = 1;
+               ppd->cpspec->qdr_dfe_time = 0;
+               /* On link down, reenable QDR adaptation */
+               qib_write_kreg_port(ppd, krp_static_adapt_dis(2),
+                       ppd->dd->cspec->r1 ?
+                                   QDR_STATIC_ADAPT_DOWN_R1 :
+                                   QDR_STATIC_ADAPT_DOWN);
+       }
+}
+
+/*
+ * This is per-pport error handling.
+ * will likely get it's own MSIx interrupt (one for each port,
+ * although just a single handler).
+ */
+static noinline void handle_7322_p_errors(struct qib_pportdata *ppd)
+{
+       char *msg;
+       u64 ignore_this_time = 0, iserr = 0, errs, fmask;
+       struct qib_devdata *dd = ppd->dd;
+
+       /* do this as soon as possible */
+       fmask = qib_read_kreg64(dd, kr_act_fmask);
+       if (!fmask)
+               check_7322_rxe_status(ppd);
+
+       errs = qib_read_kreg_port(ppd, krp_errstatus);
+       if (!errs)
+               qib_devinfo(dd->pcidev,
+                        "Port%d error interrupt, but no error bits set!\n",
+                        ppd->port);
+       if (!fmask)
+               errs &= ~QIB_E_P_IBSTATUSCHANGED;
+       if (!errs)
+               goto done;
+
+       msg = ppd->cpspec->epmsgbuf;
+       *msg = '\0';
+
+       if (errs & ~QIB_E_P_BITSEXTANT) {
+               err_decode(msg, sizeof ppd->cpspec->epmsgbuf,
+                          errs & ~QIB_E_P_BITSEXTANT, qib_7322p_error_msgs);
+               if (!*msg)
+                       snprintf(msg, sizeof ppd->cpspec->epmsgbuf,
+                                "no others");
+               qib_dev_porterr(dd, ppd->port, "error interrupt with unknown"
+                               " errors 0x%016Lx set (and %s)\n",
+                               (errs & ~QIB_E_P_BITSEXTANT), msg);
+               *msg = '\0';
+       }
+
+       if (errs & QIB_E_P_SHDR) {
+               u64 symptom;
+
+               /* determine cause, then write to clear */
+               symptom = qib_read_kreg_port(ppd, krp_sendhdrsymptom);
+               qib_write_kreg_port(ppd, krp_sendhdrsymptom, 0);
+               err_decode(msg, sizeof ppd->cpspec->epmsgbuf, symptom,
+                          hdrchk_msgs);
+               *msg = '\0';
+               /* senderrbuf cleared in SPKTERRS below */
+       }
+
+       if (errs & QIB_E_P_SPKTERRS) {
+               if ((errs & QIB_E_P_LINK_PKTERRS) &&
+                   !(ppd->lflags & QIBL_LINKACTIVE)) {
+                       /*
+                        * This can happen when trying to bring the link
+                        * up, but the IB link changes state at the "wrong"
+                        * time. The IB logic then complains that the packet
+                        * isn't valid.  We don't want to confuse people, so
+                        * we just don't print them, except at debug
+                        */
+                       err_decode(msg, sizeof ppd->cpspec->epmsgbuf,
+                                  (errs & QIB_E_P_LINK_PKTERRS),
+                                  qib_7322p_error_msgs);
+                       *msg = '\0';
+                       ignore_this_time = errs & QIB_E_P_LINK_PKTERRS;
+               }
+               qib_disarm_7322_senderrbufs(ppd);
+       } else if ((errs & QIB_E_P_LINK_PKTERRS) &&
+                  !(ppd->lflags & QIBL_LINKACTIVE)) {
+               /*
+                * This can happen when SMA is trying to bring the link
+                * up, but the IB link changes state at the "wrong" time.
+                * The IB logic then complains that the packet isn't
+                * valid.  We don't want to confuse people, so we just
+                * don't print them, except at debug
+                */
+               err_decode(msg, sizeof ppd->cpspec->epmsgbuf, errs,
+                          qib_7322p_error_msgs);
+               ignore_this_time = errs & QIB_E_P_LINK_PKTERRS;
+               *msg = '\0';
+       }
+
+       qib_write_kreg_port(ppd, krp_errclear, errs);
+
+       errs &= ~ignore_this_time;
+       if (!errs)
+               goto done;
+
+       if (errs & QIB_E_P_RPKTERRS)
+               qib_stats.sps_rcverrs++;
+       if (errs & QIB_E_P_SPKTERRS)
+               qib_stats.sps_txerrs++;
+
+       iserr = errs & ~(QIB_E_P_RPKTERRS | QIB_E_P_PKTERRS);
+
+       if (errs & QIB_E_P_SDMAERRS)
+               sdma_7322_p_errors(ppd, errs);
+
+       if (errs & QIB_E_P_IBSTATUSCHANGED) {
+               u64 ibcs;
+               u8 ltstate;
+
+               ibcs = qib_read_kreg_port(ppd, krp_ibcstatus_a);
+               ltstate = qib_7322_phys_portstate(ibcs);
+
+               if (!(ppd->lflags & QIBL_IB_AUTONEG_INPROG))
+                       handle_serdes_issues(ppd, ibcs);
+               if (!(ppd->cpspec->ibcctrl_a &
+                     SYM_MASK(IBCCtrlA_0, IBStatIntReductionEn))) {
+                       /*
+                        * We got our interrupt, so init code should be
+                        * happy and not try alternatives. Now squelch
+                        * other "chatter" from link-negotiation (pre Init)
+                        */
+                       ppd->cpspec->ibcctrl_a |=
+                               SYM_MASK(IBCCtrlA_0, IBStatIntReductionEn);
+                       qib_write_kreg_port(ppd, krp_ibcctrl_a,
+                                           ppd->cpspec->ibcctrl_a);
+               }
+
+               /* Update our picture of width and speed from chip */
+               ppd->link_width_active =
+                       (ibcs & SYM_MASK(IBCStatusA_0, LinkWidthActive)) ?
+                           IB_WIDTH_4X : IB_WIDTH_1X;
+               ppd->link_speed_active = (ibcs & SYM_MASK(IBCStatusA_0,
+                       LinkSpeedQDR)) ? QIB_IB_QDR : (ibcs &
+                         SYM_MASK(IBCStatusA_0, LinkSpeedActive)) ?
+                                  QIB_IB_DDR : QIB_IB_SDR;
+
+               if ((ppd->lflags & QIBL_IB_LINK_DISABLED) && ltstate !=
+                   IB_PHYSPORTSTATE_DISABLED)
+                       qib_set_ib_7322_lstate(ppd, 0,
+                              QLOGIC_IB_IBCC_LINKINITCMD_DISABLE);
+               else
+                       /*
+                        * Since going into a recovery state causes the link
+                        * state to go down and since recovery is transitory,
+                        * it is better if we "miss" ever seeing the link
+                        * training state go into recovery (i.e., ignore this
+                        * transition for link state special handling purposes)
+                        * without updating lastibcstat.
+                        */
+                       if (ltstate != IB_PHYSPORTSTATE_LINK_ERR_RECOVER &&
+                           ltstate != IB_PHYSPORTSTATE_RECOVERY_RETRAIN &&
+                           ltstate != IB_PHYSPORTSTATE_RECOVERY_WAITRMT &&
+                           ltstate != IB_PHYSPORTSTATE_RECOVERY_IDLE)
+                               qib_handle_e_ibstatuschanged(ppd, ibcs);
+       }
+       if (*msg && iserr)
+               qib_dev_porterr(dd, ppd->port, "%s error\n", msg);
+
+       if (ppd->state_wanted & ppd->lflags)
+               wake_up_interruptible(&ppd->state_wait);
+done:
+       return;
+}
+
+/* enable/disable chip from delivering interrupts */
+static void qib_7322_set_intr_state(struct qib_devdata *dd, u32 enable)
+{
+       if (enable) {
+               if (dd->flags & QIB_BADINTR)
+                       return;
+               qib_write_kreg(dd, kr_intmask, dd->cspec->int_enable_mask);
+               /* cause any pending enabled interrupts to be re-delivered */
+               qib_write_kreg(dd, kr_intclear, 0ULL);
+               if (dd->cspec->num_msix_entries) {
+                       /* and same for MSIx */
+                       u64 val = qib_read_kreg64(dd, kr_intgranted);
+                       if (val)
+                               qib_write_kreg(dd, kr_intgranted, val);
+               }
+       } else
+               qib_write_kreg(dd, kr_intmask, 0ULL);
+}
+
+/*
+ * Try to cleanup as much as possible for anything that might have gone
+ * wrong while in freeze mode, such as pio buffers being written by user
+ * processes (causing armlaunch), send errors due to going into freeze mode,
+ * etc., and try to avoid causing extra interrupts while doing so.
+ * Forcibly update the in-memory pioavail register copies after cleanup
+ * because the chip won't do it while in freeze mode (the register values
+ * themselves are kept correct).
+ * Make sure that we don't lose any important interrupts by using the chip
+ * feature that says that writing 0 to a bit in *clear that is set in
+ * *status will cause an interrupt to be generated again (if allowed by
+ * the *mask value).
+ * This is in chip-specific code because of all of the register accesses,
+ * even though the details are similar on most chips.
+ */
+static void qib_7322_clear_freeze(struct qib_devdata *dd)
+{
+       int pidx;
+
+       /* disable error interrupts, to avoid confusion */
+       qib_write_kreg(dd, kr_errmask, 0ULL);
+
+       for (pidx = 0; pidx < dd->num_pports; ++pidx)
+               if (dd->pport[pidx].link_speed_supported)
+                       qib_write_kreg_port(dd->pport + pidx, krp_errmask,
+                                           0ULL);
+
+       /* also disable interrupts; errormask is sometimes overwriten */
+       qib_7322_set_intr_state(dd, 0);
+
+       /* clear the freeze, and be sure chip saw it */
+       qib_write_kreg(dd, kr_control, dd->control);
+       qib_read_kreg32(dd, kr_scratch);
+
+       /*
+        * Force new interrupt if any hwerr, error or interrupt bits are
+        * still set, and clear "safe" send packet errors related to freeze
+        * and cancelling sends.  Re-enable error interrupts before possible
+        * force of re-interrupt on pending interrupts.
+        */
+       qib_write_kreg(dd, kr_hwerrclear, 0ULL);
+       qib_write_kreg(dd, kr_errclear, E_SPKT_ERRS_IGNORE);
+       qib_write_kreg(dd, kr_errmask, dd->cspec->errormask);
+       /* We need to purge per-port errs and reset mask, too */
+       for (pidx = 0; pidx < dd->num_pports; ++pidx) {
+               if (!dd->pport[pidx].link_speed_supported)
+                       continue;
+               qib_write_kreg_port(dd->pport + pidx, krp_errclear, ~0Ull);
+               qib_write_kreg_port(dd->pport + pidx, krp_errmask, ~0Ull);
+       }
+       qib_7322_set_intr_state(dd, 1);
+}
+
+/* no error handling to speak of */
+/**
+ * qib_7322_handle_hwerrors - display hardware errors.
+ * @dd: the qlogic_ib device
+ * @msg: the output buffer
+ * @msgl: the size of the output buffer
+ *
+ * Use same msg buffer as regular errors to avoid excessive stack
+ * use.  Most hardware errors are catastrophic, but for right now,
+ * we'll print them and continue.  We reuse the same message buffer as
+ * qib_handle_errors() to avoid excessive stack usage.
+ */
+static void qib_7322_handle_hwerrors(struct qib_devdata *dd, char *msg,
+                                    size_t msgl)
+{
+       u64 hwerrs;
+       u32 ctrl;
+       int isfatal = 0;
+
+       hwerrs = qib_read_kreg64(dd, kr_hwerrstatus);
+       if (!hwerrs)
+               goto bail;
+       if (hwerrs == ~0ULL) {
+               qib_dev_err(dd, "Read of hardware error status failed "
+                           "(all bits set); ignoring\n");
+               goto bail;
+       }
+       qib_stats.sps_hwerrs++;
+
+       /* Always clear the error status register, except BIST fail */
+       qib_write_kreg(dd, kr_hwerrclear, hwerrs &
+                      ~HWE_MASK(PowerOnBISTFailed));
+
+       hwerrs &= dd->cspec->hwerrmask;
+
+       /* no EEPROM logging, yet */
+
+       if (hwerrs)
+               qib_devinfo(dd->pcidev, "Hardware error: hwerr=0x%llx "
+                           "(cleared)\n", (unsigned long long) hwerrs);
+
+       ctrl = qib_read_kreg32(dd, kr_control);
+       if ((ctrl & SYM_MASK(Control, FreezeMode)) && !dd->diag_client) {
+               /*
+                * No recovery yet...
+                */
+               if ((hwerrs & ~HWE_MASK(LATriggered)) ||
+                   dd->cspec->stay_in_freeze) {
+                       /*
+                        * If any set that we aren't ignoring only make the
+                        * complaint once, in case it's stuck or recurring,
+                        * and we get here multiple times
+                        * Force link down, so switch knows, and
+                        * LEDs are turned off.
+                        */
+                       if (dd->flags & QIB_INITTED)
+                               isfatal = 1;
+               } else
+                       qib_7322_clear_freeze(dd);
+       }
+
+       if (hwerrs & HWE_MASK(PowerOnBISTFailed)) {
+               isfatal = 1;
+               strlcpy(msg, "[Memory BIST test failed, "
+                       "InfiniPath hardware unusable]", msgl);
+               /* ignore from now on, so disable until driver reloaded */
+               dd->cspec->hwerrmask &= ~HWE_MASK(PowerOnBISTFailed);
+               qib_write_kreg(dd, kr_hwerrmask, dd->cspec->hwerrmask);
+       }
+
+       err_decode(msg, msgl, hwerrs, qib_7322_hwerror_msgs);
+
+       /* Ignore esoteric PLL failures et al. */
+
+       qib_dev_err(dd, "%s hardware error\n", msg);
+
+       if (isfatal && !dd->diag_client) {
+               qib_dev_err(dd, "Fatal Hardware Error, no longer"
+                           " usable, SN %.16s\n", dd->serial);
+               /*
+                * for /sys status file and user programs to print; if no
+                * trailing brace is copied, we'll know it was truncated.
+                */
+               if (dd->freezemsg)
+                       snprintf(dd->freezemsg, dd->freezelen,
+                                "{%s}", msg);
+               qib_disable_after_error(dd);
+       }
+bail:;
+}
+
+/**
+ * qib_7322_init_hwerrors - enable hardware errors
+ * @dd: the qlogic_ib device
+ *
+ * now that we have finished initializing everything that might reasonably
+ * cause a hardware error, and cleared those errors bits as they occur,
+ * we can enable hardware errors in the mask (potentially enabling
+ * freeze mode), and enable hardware errors as errors (along with
+ * everything else) in errormask
+ */
+static void qib_7322_init_hwerrors(struct qib_devdata *dd)
+{
+       int pidx;
+       u64 extsval;
+
+       extsval = qib_read_kreg64(dd, kr_extstatus);
+       if (!(extsval & (QIB_EXTS_MEMBIST_DISABLED |
+                        QIB_EXTS_MEMBIST_ENDTEST)))
+               qib_dev_err(dd, "MemBIST did not complete!\n");
+
+       /* never clear BIST failure, so reported on each driver load */
+       qib_write_kreg(dd, kr_hwerrclear, ~HWE_MASK(PowerOnBISTFailed));
+       qib_write_kreg(dd, kr_hwerrmask, dd->cspec->hwerrmask);
+
+       /* clear all */
+       qib_write_kreg(dd, kr_errclear, ~0ULL);
+       /* enable errors that are masked, at least this first time. */
+       qib_write_kreg(dd, kr_errmask, ~0ULL);
+       dd->cspec->errormask = qib_read_kreg64(dd, kr_errmask);
+       for (pidx = 0; pidx < dd->num_pports; ++pidx)
+               if (dd->pport[pidx].link_speed_supported)
+                       qib_write_kreg_port(dd->pport + pidx, krp_errmask,
+                                           ~0ULL);
+}
+
+/*
+ * Disable and enable the armlaunch error.  Used for PIO bandwidth testing
+ * on chips that are count-based, rather than trigger-based.  There is no
+ * reference counting, but that's also fine, given the intended use.
+ * Only chip-specific because it's all register accesses
+ */
+static void qib_set_7322_armlaunch(struct qib_devdata *dd, u32 enable)
+{
+       if (enable) {
+               qib_write_kreg(dd, kr_errclear, QIB_E_SPIOARMLAUNCH);
+               dd->cspec->errormask |= QIB_E_SPIOARMLAUNCH;
+       } else
+               dd->cspec->errormask &= ~QIB_E_SPIOARMLAUNCH;
+       qib_write_kreg(dd, kr_errmask, dd->cspec->errormask);
+}
+
+/*
+ * Formerly took parameter <which> in pre-shifted,
+ * pre-merged form with LinkCmd and LinkInitCmd
+ * together, and assuming the zero was NOP.
+ */
+static void qib_set_ib_7322_lstate(struct qib_pportdata *ppd, u16 linkcmd,
+                                  u16 linitcmd)
+{
+       u64 mod_wd;
+       struct qib_devdata *dd = ppd->dd;
+       unsigned long flags;
+
+       if (linitcmd == QLOGIC_IB_IBCC_LINKINITCMD_DISABLE) {
+               /*
+                * If we are told to disable, note that so link-recovery
+                * code does not attempt to bring us back up.
+                * Also reset everything that we can, so we start
+                * completely clean when re-enabled (before we
+                * actually issue the disable to the IBC)
+                */
+               qib_7322_mini_pcs_reset(ppd);
+               spin_lock_irqsave(&ppd->lflags_lock, flags);
+               ppd->lflags |= QIBL_IB_LINK_DISABLED;
+               spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+       } else if (linitcmd || linkcmd == QLOGIC_IB_IBCC_LINKCMD_DOWN) {
+               /*
+                * Any other linkinitcmd will lead to LINKDOWN and then
+                * to INIT (if all is well), so clear flag to let
+                * link-recovery code attempt to bring us back up.
+                */
+               spin_lock_irqsave(&ppd->lflags_lock, flags);
+               ppd->lflags &= ~QIBL_IB_LINK_DISABLED;
+               spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+               /*
+                * Clear status change interrupt reduction so the
+                * new state is seen.
+                */
+               ppd->cpspec->ibcctrl_a &=
+                       ~SYM_MASK(IBCCtrlA_0, IBStatIntReductionEn);
+       }
+
+       mod_wd = (linkcmd << IBA7322_IBCC_LINKCMD_SHIFT) |
+               (linitcmd << QLOGIC_IB_IBCC_LINKINITCMD_SHIFT);
+
+       qib_write_kreg_port(ppd, krp_ibcctrl_a, ppd->cpspec->ibcctrl_a |
+                           mod_wd);
+       /* write to chip to prevent back-to-back writes of ibc reg */
+       qib_write_kreg(dd, kr_scratch, 0);
+
+}
+
+/*
+ * The total RCV buffer memory is 64KB, used for both ports, and is
+ * in units of 64 bytes (same as IB flow control credit unit).
+ * The consumedVL unit in the same registers are in 32 byte units!
+ * So, a VL15 packet needs 4.50 IB credits, and 9 rx buffer chunks,
+ * and we can therefore allocate just 9 IB credits for 2 VL15 packets
+ * in krp_rxcreditvl15, rather than 10.
+ */
+#define RCV_BUF_UNITSZ 64
+#define NUM_RCV_BUF_UNITS(dd) ((64 * 1024) / (RCV_BUF_UNITSZ * dd->num_pports))
+
+static void set_vls(struct qib_pportdata *ppd)
+{
+       int i, numvls, totcred, cred_vl, vl0extra;
+       struct qib_devdata *dd = ppd->dd;
+       u64 val;
+
+       numvls = qib_num_vls(ppd->vls_operational);
+
+       /*
+        * Set up per-VL credits. Below is kluge based on these assumptions:
+        * 1) port is disabled at the time early_init is called.
+        * 2) give VL15 17 credits, for two max-plausible packets.
+        * 3) Give VL0-N the rest, with any rounding excess used for VL0
+        */
+       /* 2 VL15 packets @ 288 bytes each (including IB headers) */
+       totcred = NUM_RCV_BUF_UNITS(dd);
+       cred_vl = (2 * 288 + RCV_BUF_UNITSZ - 1) / RCV_BUF_UNITSZ;
+       totcred -= cred_vl;
+       qib_write_kreg_port(ppd, krp_rxcreditvl15, (u64) cred_vl);
+       cred_vl = totcred / numvls;
+       vl0extra = totcred - cred_vl * numvls;
+       qib_write_kreg_port(ppd, krp_rxcreditvl0, cred_vl + vl0extra);
+       for (i = 1; i < numvls; i++)
+               qib_write_kreg_port(ppd, krp_rxcreditvl0 + i, cred_vl);
+       for (; i < 8; i++) /* no buffer space for other VLs */
+               qib_write_kreg_port(ppd, krp_rxcreditvl0 + i, 0);
+
+       /* Notify IBC that credits need to be recalculated */
+       val = qib_read_kreg_port(ppd, krp_ibsdtestiftx);
+       val |= SYM_MASK(IB_SDTEST_IF_TX_0, CREDIT_CHANGE);
+       qib_write_kreg_port(ppd, krp_ibsdtestiftx, val);
+       qib_write_kreg(dd, kr_scratch, 0ULL);
+       val &= ~SYM_MASK(IB_SDTEST_IF_TX_0, CREDIT_CHANGE);
+       qib_write_kreg_port(ppd, krp_ibsdtestiftx, val);
+
+       for (i = 0; i < numvls; i++)
+               val = qib_read_kreg_port(ppd, krp_rxcreditvl0 + i);
+       val = qib_read_kreg_port(ppd, krp_rxcreditvl15);
+
+       /* Change the number of operational VLs */
+       ppd->cpspec->ibcctrl_a = (ppd->cpspec->ibcctrl_a &
+                               ~SYM_MASK(IBCCtrlA_0, NumVLane)) |
+               ((u64)(numvls - 1) << SYM_LSB(IBCCtrlA_0, NumVLane));
+       qib_write_kreg_port(ppd, krp_ibcctrl_a, ppd->cpspec->ibcctrl_a);
+       qib_write_kreg(dd, kr_scratch, 0ULL);
+}
+
+/*
+ * The code that deals with actual SerDes is in serdes_7322_init().
+ * Compared to the code for iba7220, it is minimal.
+ */
+static int serdes_7322_init(struct qib_pportdata *ppd);
+
+/**
+ * qib_7322_bringup_serdes - bring up the serdes
+ * @ppd: physical port on the qlogic_ib device
+ */
+static int qib_7322_bringup_serdes(struct qib_pportdata *ppd)
+{
+       struct qib_devdata *dd = ppd->dd;
+       u64 val, guid, ibc;
+       unsigned long flags;
+       int ret = 0;
+
+       /*
+        * SerDes model not in Pd, but still need to
+        * set up much of IBCCtrl and IBCDDRCtrl; move elsewhere
+        * eventually.
+        */
+       /* Put IBC in reset, sends disabled (should be in reset already) */
+       ppd->cpspec->ibcctrl_a &= ~SYM_MASK(IBCCtrlA_0, IBLinkEn);
+       qib_write_kreg_port(ppd, krp_ibcctrl_a, ppd->cpspec->ibcctrl_a);
+       qib_write_kreg(dd, kr_scratch, 0ULL);
+
+       if (qib_compat_ddr_negotiate) {
+               ppd->cpspec->ibdeltainprog = 1;
+               ppd->cpspec->ibsymsnap = read_7322_creg32_port(ppd,
+                                               crp_ibsymbolerr);
+               ppd->cpspec->iblnkerrsnap = read_7322_creg32_port(ppd,
+                                               crp_iblinkerrrecov);
+       }
+
+       /* flowcontrolwatermark is in units of KBytes */
+       ibc = 0x5ULL << SYM_LSB(IBCCtrlA_0, FlowCtrlWaterMark);
+       /*
+        * Flow control is sent this often, even if no changes in
+        * buffer space occur.  Units are 128ns for this chip.
+        * Set to 3usec.
+        */
+       ibc |= 24ULL << SYM_LSB(IBCCtrlA_0, FlowCtrlPeriod);
+       /* max error tolerance */
+       ibc |= 0xfULL << SYM_LSB(IBCCtrlA_0, PhyerrThreshold);
+       /* IB credit flow control. */
+       ibc |= 0xfULL << SYM_LSB(IBCCtrlA_0, OverrunThreshold);
+       /*
+        * set initial max size pkt IBC will send, including ICRC; it's the
+        * PIO buffer size in dwords, less 1; also see qib_set_mtu()
+        */
+       ibc |= ((u64)(ppd->ibmaxlen >> 2) + 1) <<
+               SYM_LSB(IBCCtrlA_0, MaxPktLen);
+       ppd->cpspec->ibcctrl_a = ibc; /* without linkcmd or linkinitcmd! */
+
+       /* initially come up waiting for TS1, without sending anything. */
+       val = ppd->cpspec->ibcctrl_a | (QLOGIC_IB_IBCC_LINKINITCMD_DISABLE <<
+               QLOGIC_IB_IBCC_LINKINITCMD_SHIFT);
+
+       /*
+        * Reset the PCS interface to the serdes (and also ibc, which is still
+        * in reset from above).  Writes new value of ibcctrl_a as last step.
+        */
+       qib_7322_mini_pcs_reset(ppd);
+       qib_write_kreg(dd, kr_scratch, 0ULL);
+
+       if (!ppd->cpspec->ibcctrl_b) {
+               unsigned lse = ppd->link_speed_enabled;
+
+               /*
+                * Not on re-init after reset, establish shadow
+                * and force initial config.
+                */
+               ppd->cpspec->ibcctrl_b = qib_read_kreg_port(ppd,
+                                                            krp_ibcctrl_b);
+               ppd->cpspec->ibcctrl_b &= ~(IBA7322_IBC_SPEED_QDR |
+                               IBA7322_IBC_SPEED_DDR |
+                               IBA7322_IBC_SPEED_SDR |
+                               IBA7322_IBC_WIDTH_AUTONEG |
+                               SYM_MASK(IBCCtrlB_0, IB_LANE_REV_SUPPORTED));
+               if (lse & (lse - 1)) /* Muliple speeds enabled */
+                       ppd->cpspec->ibcctrl_b |=
+                               (lse << IBA7322_IBC_SPEED_LSB) |
+                               IBA7322_IBC_IBTA_1_2_MASK |
+                               IBA7322_IBC_MAX_SPEED_MASK;
+               else
+                       ppd->cpspec->ibcctrl_b |= (lse == QIB_IB_QDR) ?
+                               IBA7322_IBC_SPEED_QDR |
+                                IBA7322_IBC_IBTA_1_2_MASK :
+                               (lse == QIB_IB_DDR) ?
+                                       IBA7322_IBC_SPEED_DDR :
+                                       IBA7322_IBC_SPEED_SDR;
+               if ((ppd->link_width_enabled & (IB_WIDTH_1X | IB_WIDTH_4X)) ==
+                   (IB_WIDTH_1X | IB_WIDTH_4X))
+                       ppd->cpspec->ibcctrl_b |= IBA7322_IBC_WIDTH_AUTONEG;
+               else
+                       ppd->cpspec->ibcctrl_b |=
+                               ppd->link_width_enabled == IB_WIDTH_4X ?
+                               IBA7322_IBC_WIDTH_4X_ONLY :
+                               IBA7322_IBC_WIDTH_1X_ONLY;
+
+               /* always enable these on driver reload, not sticky */
+               ppd->cpspec->ibcctrl_b |= (IBA7322_IBC_RXPOL_MASK |
+                       IBA7322_IBC_HRTBT_MASK);
+       }
+       qib_write_kreg_port(ppd, krp_ibcctrl_b, ppd->cpspec->ibcctrl_b);
+
+       /* setup so we have more time at CFGTEST to change H1 */
+       val = qib_read_kreg_port(ppd, krp_ibcctrl_c);
+       val &= ~SYM_MASK(IBCCtrlC_0, IB_FRONT_PORCH);
+       val |= 0xfULL << SYM_LSB(IBCCtrlC_0, IB_FRONT_PORCH);
+       qib_write_kreg_port(ppd, krp_ibcctrl_c, val);
+
+       serdes_7322_init(ppd);
+
+       guid = be64_to_cpu(ppd->guid);
+       if (!guid) {
+               if (dd->base_guid)
+                       guid = be64_to_cpu(dd->base_guid) + ppd->port - 1;
+               ppd->guid = cpu_to_be64(guid);
+       }
+
+       qib_write_kreg_port(ppd, krp_hrtbt_guid, guid);
+       /* write to chip to prevent back-to-back writes of ibc reg */
+       qib_write_kreg(dd, kr_scratch, 0);
+
+       /* Enable port */
+       ppd->cpspec->ibcctrl_a |= SYM_MASK(IBCCtrlA_0, IBLinkEn);
+       set_vls(ppd);
+
+       /* be paranoid against later code motion, etc. */
+       spin_lock_irqsave(&dd->cspec->rcvmod_lock, flags);
+       ppd->p_rcvctrl |= SYM_MASK(RcvCtrl_0, RcvIBPortEnable);
+       qib_write_kreg_port(ppd, krp_rcvctrl, ppd->p_rcvctrl);
+       spin_unlock_irqrestore(&dd->cspec->rcvmod_lock, flags);
+
+       /* Also enable IBSTATUSCHG interrupt.  */
+       val = qib_read_kreg_port(ppd, krp_errmask);
+       qib_write_kreg_port(ppd, krp_errmask,
+               val | ERR_MASK_N(IBStatusChanged));
+
+       /* Always zero until we start messing with SerDes for real */
+       return ret;
+}
+
+/**
+ * qib_7322_quiet_serdes - set serdes to txidle
+ * @dd: the qlogic_ib device
+ * Called when driver is being unloaded
+ */
+static void qib_7322_mini_quiet_serdes(struct qib_pportdata *ppd)
+{
+       u64 val;
+       unsigned long flags;
+
+       qib_set_ib_7322_lstate(ppd, 0, QLOGIC_IB_IBCC_LINKINITCMD_DISABLE);
+
+       spin_lock_irqsave(&ppd->lflags_lock, flags);
+       ppd->lflags &= ~QIBL_IB_AUTONEG_INPROG;
+       spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+       wake_up(&ppd->cpspec->autoneg_wait);
+       cancel_delayed_work(&ppd->cpspec->autoneg_work);
+       if (ppd->dd->cspec->r1)
+               cancel_delayed_work(&ppd->cpspec->ipg_work);
+       flush_scheduled_work();
+
+       ppd->cpspec->chase_end = 0;
+       if (ppd->cpspec->chase_timer.data) /* if initted */
+               del_timer_sync(&ppd->cpspec->chase_timer);
+
+       /*
+        * Despite the name, actually disables IBC as well. Do it when
+        * we are as sure as possible that no more packets can be
+        * received, following the down and the PCS reset.
+        * The actual disabling happens in qib_7322_mini_pci_reset(),
+        * along with the PCS being reset.
+        */
+       ppd->cpspec->ibcctrl_a &= ~SYM_MASK(IBCCtrlA_0, IBLinkEn);
+       qib_7322_mini_pcs_reset(ppd);
+
+       /*
+        * Update the adjusted counters so the adjustment persists
+        * across driver reload.
+        */
+       if (ppd->cpspec->ibsymdelta || ppd->cpspec->iblnkerrdelta ||
+           ppd->cpspec->ibdeltainprog || ppd->cpspec->iblnkdowndelta) {
+               struct qib_devdata *dd = ppd->dd;
+               u64 diagc;
+
+               /* enable counter writes */
+               diagc = qib_read_kreg64(dd, kr_hwdiagctrl);
+               qib_write_kreg(dd, kr_hwdiagctrl,
+                              diagc | SYM_MASK(HwDiagCtrl, CounterWrEnable));
+
+               if (ppd->cpspec->ibsymdelta || ppd->cpspec->ibdeltainprog) {
+                       val = read_7322_creg32_port(ppd, crp_ibsymbolerr);
+                       if (ppd->cpspec->ibdeltainprog)
+                               val -= val - ppd->cpspec->ibsymsnap;
+                       val -= ppd->cpspec->ibsymdelta;
+                       write_7322_creg_port(ppd, crp_ibsymbolerr, val);
+               }
+               if (ppd->cpspec->iblnkerrdelta || ppd->cpspec->ibdeltainprog) {
+                       val = read_7322_creg32_port(ppd, crp_iblinkerrrecov);
+                       if (ppd->cpspec->ibdeltainprog)
+                               val -= val - ppd->cpspec->iblnkerrsnap;
+                       val -= ppd->cpspec->iblnkerrdelta;
+                       write_7322_creg_port(ppd, crp_iblinkerrrecov, val);
+               }
+               if (ppd->cpspec->iblnkdowndelta) {
+                       val = read_7322_creg32_port(ppd, crp_iblinkdown);
+                       val += ppd->cpspec->iblnkdowndelta;
+                       write_7322_creg_port(ppd, crp_iblinkdown, val);
+               }
+               /*
+                * No need to save ibmalfdelta since IB perfcounters
+                * are cleared on driver reload.
+                */
+
+               /* and disable counter writes */
+               qib_write_kreg(dd, kr_hwdiagctrl, diagc);
+       }
+}
+
+/**
+ * qib_setup_7322_setextled - set the state of the two external LEDs
+ * @ppd: physical port on the qlogic_ib device
+ * @on: whether the link is up or not
+ *
+ * The exact combo of LEDs if on is true is determined by looking
+ * at the ibcstatus.
+ *
+ * These LEDs indicate the physical and logical state of IB link.
+ * For this chip (at least with recommended board pinouts), LED1
+ * is Yellow (logical state) and LED2 is Green (physical state),
+ *
+ * Note:  We try to match the Mellanox HCA LED behavior as best
+ * we can.  Green indicates physical link state is OK (something is
+ * plugged in, and we can train).
+ * Amber indicates the link is logically up (ACTIVE).
+ * Mellanox further blinks the amber LED to indicate data packet
+ * activity, but we have no hardware support for that, so it would
+ * require waking up every 10-20 msecs and checking the counters
+ * on the chip, and then turning the LED off if appropriate.  That's
+ * visible overhead, so not something we will do.
+ */
+static void qib_setup_7322_setextled(struct qib_pportdata *ppd, u32 on)
+{
+       struct qib_devdata *dd = ppd->dd;
+       u64 extctl, ledblink = 0, val;
+       unsigned long flags;
+       int yel, grn;
+
+       /*
+        * The diags use the LED to indicate diag info, so we leave
+        * the external LED alone when the diags are running.
+        */
+       if (dd->diag_client)
+               return;
+
+       /* Allow override of LED display for, e.g. Locating system in rack */
+       if (ppd->led_override) {
+               grn = (ppd->led_override & QIB_LED_PHYS);
+               yel = (ppd->led_override & QIB_LED_LOG);
+       } else if (on) {
+               val = qib_read_kreg_port(ppd, krp_ibcstatus_a);
+               grn = qib_7322_phys_portstate(val) ==
+                       IB_PHYSPORTSTATE_LINKUP;
+               yel = qib_7322_iblink_state(val) == IB_PORT_ACTIVE;
+       } else {
+               grn = 0;
+               yel = 0;
+       }
+
+       spin_lock_irqsave(&dd->cspec->gpio_lock, flags);
+       extctl = dd->cspec->extctrl & (ppd->port == 1 ?
+               ~ExtLED_IB1_MASK : ~ExtLED_IB2_MASK);
+       if (grn) {
+               extctl |= ppd->port == 1 ? ExtLED_IB1_GRN : ExtLED_IB2_GRN;
+               /*
+                * Counts are in chip clock (4ns) periods.
+                * This is 1/16 sec (66.6ms) on,
+                * 3/16 sec (187.5 ms) off, with packets rcvd.
+                */
+               ledblink = ((66600 * 1000UL / 4) << IBA7322_LEDBLINK_ON_SHIFT) |
+                       ((187500 * 1000UL / 4) << IBA7322_LEDBLINK_OFF_SHIFT);
+       }
+       if (yel)
+               extctl |= ppd->port == 1 ? ExtLED_IB1_YEL : ExtLED_IB2_YEL;
+       dd->cspec->extctrl = extctl;
+       qib_write_kreg(dd, kr_extctrl, dd->cspec->extctrl);
+       spin_unlock_irqrestore(&dd->cspec->gpio_lock, flags);
+
+       if (ledblink) /* blink the LED on packet receive */
+               qib_write_kreg_port(ppd, krp_rcvpktledcnt, ledblink);
+}
+
+/*
+ * Disable MSIx interrupt if enabled, call generic MSIx code
+ * to cleanup, and clear pending MSIx interrupts.
+ * Used for fallback to INTx, after reset, and when MSIx setup fails.
+ */
+static void qib_7322_nomsix(struct qib_devdata *dd)
+{
+       u64 intgranted;
+       int n;
+
+       dd->cspec->main_int_mask = ~0ULL;
+       n = dd->cspec->num_msix_entries;
+       if (n) {
+               int i;
+
+               dd->cspec->num_msix_entries = 0;
+               for (i = 0; i < n; i++)
+                       free_irq(dd->cspec->msix_entries[i].vector,
+                                dd->cspec->msix_arg[i]);
+               qib_nomsix(dd);
+       }
+       /* make sure no MSIx interrupts are left pending */
+       intgranted = qib_read_kreg64(dd, kr_intgranted);
+       if (intgranted)
+               qib_write_kreg(dd, kr_intgranted, intgranted);
+}
+
+static void qib_7322_free_irq(struct qib_devdata *dd)
+{
+       if (dd->cspec->irq) {
+               free_irq(dd->cspec->irq, dd);
+               dd->cspec->irq = 0;
+       }
+       qib_7322_nomsix(dd);
+}
+
+static void qib_setup_7322_cleanup(struct qib_devdata *dd)
+{
+       int i;
+
+       qib_7322_free_irq(dd);
+       kfree(dd->cspec->cntrs);
+       kfree(dd->cspec->sendchkenable);
+       kfree(dd->cspec->sendgrhchk);
+       kfree(dd->cspec->sendibchk);
+       kfree(dd->cspec->msix_entries);
+       kfree(dd->cspec->msix_arg);
+       for (i = 0; i < dd->num_pports; i++) {
+               unsigned long flags;
+               u32 mask = QSFP_GPIO_MOD_PRS_N |
+                       (QSFP_GPIO_MOD_PRS_N << QSFP_GPIO_PORT2_SHIFT);
+
+               kfree(dd->pport[i].cpspec->portcntrs);
+               if (dd->flags & QIB_HAS_QSFP) {
+                       spin_lock_irqsave(&dd->cspec->gpio_lock, flags);
+                       dd->cspec->gpio_mask &= ~mask;
+                       qib_write_kreg(dd, kr_gpio_mask, dd->cspec->gpio_mask);
+                       spin_unlock_irqrestore(&dd->cspec->gpio_lock, flags);
+                       qib_qsfp_deinit(&dd->pport[i].cpspec->qsfp_data);
+               }
+               if (dd->pport[i].ibport_data.smi_ah)
+                       ib_destroy_ah(&dd->pport[i].ibport_data.smi_ah->ibah);
+       }
+}
+
+/* handle SDMA interrupts */
+static void sdma_7322_intr(struct qib_devdata *dd, u64 istat)
+{
+       struct qib_pportdata *ppd0 = &dd->pport[0];
+       struct qib_pportdata *ppd1 = &dd->pport[1];
+       u64 intr0 = istat & (INT_MASK_P(SDma, 0) |
+               INT_MASK_P(SDmaIdle, 0) | INT_MASK_P(SDmaProgress, 0));
+       u64 intr1 = istat & (INT_MASK_P(SDma, 1) |
+               INT_MASK_P(SDmaIdle, 1) | INT_MASK_P(SDmaProgress, 1));
+
+       if (intr0)
+               qib_sdma_intr(ppd0);
+       if (intr1)
+               qib_sdma_intr(ppd1);
+
+       if (istat & INT_MASK_PM(SDmaCleanupDone, 0))
+               qib_sdma_process_event(ppd0, qib_sdma_event_e20_hw_started);
+       if (istat & INT_MASK_PM(SDmaCleanupDone, 1))
+               qib_sdma_process_event(ppd1, qib_sdma_event_e20_hw_started);
+}
+
+/*
+ * Set or clear the Send buffer available interrupt enable bit.
+ */
+static void qib_wantpiobuf_7322_intr(struct qib_devdata *dd, u32 needint)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&dd->sendctrl_lock, flags);
+       if (needint)
+               dd->sendctrl |= SYM_MASK(SendCtrl, SendIntBufAvail);
+       else
+               dd->sendctrl &= ~SYM_MASK(SendCtrl, SendIntBufAvail);
+       qib_write_kreg(dd, kr_sendctrl, dd->sendctrl);
+       qib_write_kreg(dd, kr_scratch, 0ULL);
+       spin_unlock_irqrestore(&dd->sendctrl_lock, flags);
+}
+
+/*
+ * Somehow got an interrupt with reserved bits set in interrupt status.
+ * Print a message so we know it happened, then clear them.
+ * keep mainline interrupt handler cache-friendly
+ */
+static noinline void unknown_7322_ibits(struct qib_devdata *dd, u64 istat)
+{
+       u64 kills;
+       char msg[128];
+
+       kills = istat & ~QIB_I_BITSEXTANT;
+       qib_dev_err(dd, "Clearing reserved interrupt(s) 0x%016llx:"
+                   " %s\n", (unsigned long long) kills, msg);
+       qib_write_kreg(dd, kr_intmask, (dd->cspec->int_enable_mask & ~kills));
+}
+
+/* keep mainline interrupt handler cache-friendly */
+static noinline void unknown_7322_gpio_intr(struct qib_devdata *dd)
+{
+       u32 gpiostatus;
+       int handled = 0;
+       int pidx;
+
+       /*
+        * Boards for this chip currently don't use GPIO interrupts,
+        * so clear by writing GPIOstatus to GPIOclear, and complain
+        * to developer.  To avoid endless repeats, clear
+        * the bits in the mask, since there is some kind of
+        * programming error or chip problem.
+        */
+       gpiostatus = qib_read_kreg32(dd, kr_gpio_status);
+       /*
+        * In theory, writing GPIOstatus to GPIOclear could
+        * have a bad side-effect on some diagnostic that wanted
+        * to poll for a status-change, but the various shadows
+        * make that problematic at best. Diags will just suppress
+        * all GPIO interrupts during such tests.
+        */
+       qib_write_kreg(dd, kr_gpio_clear, gpiostatus);
+       /*
+        * Check for QSFP MOD_PRS changes
+        * only works for single port if IB1 != pidx1
+        */
+       for (pidx = 0; pidx < dd->num_pports && (dd->flags & QIB_HAS_QSFP);
+            ++pidx) {
+               struct qib_pportdata *ppd;
+               struct qib_qsfp_data *qd;
+               u32 mask;
+               if (!dd->pport[pidx].link_speed_supported)
+                       continue;
+               mask = QSFP_GPIO_MOD_PRS_N;
+               ppd = dd->pport + pidx;
+               mask <<= (QSFP_GPIO_PORT2_SHIFT * ppd->hw_pidx);
+               if (gpiostatus & dd->cspec->gpio_mask & mask) {
+                       u64 pins;
+                       qd = &ppd->cpspec->qsfp_data;
+                       gpiostatus &= ~mask;
+                       pins = qib_read_kreg64(dd, kr_extstatus);
+                       pins >>= SYM_LSB(EXTStatus, GPIOIn);
+                       if (!(pins & mask)) {
+                               ++handled;
+                               qd->t_insert = get_jiffies_64();
+                               schedule_work(&qd->work);
+                       }
+               }
+       }
+
+       if (gpiostatus && !handled) {
+               const u32 mask = qib_read_kreg32(dd, kr_gpio_mask);
+               u32 gpio_irq = mask & gpiostatus;
+
+               /*
+                * Clear any troublemakers, and update chip from shadow
+                */
+               dd->cspec->gpio_mask &= ~gpio_irq;
+               qib_write_kreg(dd, kr_gpio_mask, dd->cspec->gpio_mask);
+       }
+}
+
+/*
+ * Handle errors and unusual events first, separate function
+ * to improve cache hits for fast path interrupt handling.
+ */
+static noinline void unlikely_7322_intr(struct qib_devdata *dd, u64 istat)
+{
+       if (istat & ~QIB_I_BITSEXTANT)
+               unknown_7322_ibits(dd, istat);
+       if (istat & QIB_I_GPIO)
+               unknown_7322_gpio_intr(dd);
+       if (istat & QIB_I_C_ERROR)
+               handle_7322_errors(dd);
+       if (istat & INT_MASK_P(Err, 0) && dd->rcd[0])
+               handle_7322_p_errors(dd->rcd[0]->ppd);
+       if (istat & INT_MASK_P(Err, 1) && dd->rcd[1])
+               handle_7322_p_errors(dd->rcd[1]->ppd);
+}
+
+/*
+ * Dynamically adjust the rcv int timeout for a context based on incoming
+ * packet rate.
+ */
+static void adjust_rcv_timeout(struct qib_ctxtdata *rcd, int npkts)
+{
+       struct qib_devdata *dd = rcd->dd;
+       u32 timeout = dd->cspec->rcvavail_timeout[rcd->ctxt];
+
+       /*
+        * Dynamically adjust idle timeout on chip
+        * based on number of packets processed.
+        */
+       if (npkts < rcv_int_count && timeout > 2)
+               timeout >>= 1;
+       else if (npkts >= rcv_int_count && timeout < rcv_int_timeout)
+               timeout = min(timeout << 1, rcv_int_timeout);
+       else
+               return;
+
+       dd->cspec->rcvavail_timeout[rcd->ctxt] = timeout;
+       qib_write_kreg(dd, kr_rcvavailtimeout + rcd->ctxt, timeout);
+}
+
+/*
+ * This is the main interrupt handler.
+ * It will normally only be used for low frequency interrupts but may
+ * have to handle all interrupts if INTx is enabled or fewer than normal
+ * MSIx interrupts were allocated.
+ * This routine should ignore the interrupt bits for any of the
+ * dedicated MSIx handlers.
+ */
+static irqreturn_t qib_7322intr(int irq, void *data)
+{
+       struct qib_devdata *dd = data;
+       irqreturn_t ret;
+       u64 istat;
+       u64 ctxtrbits;
+       u64 rmask;
+       unsigned i;
+       u32 npkts;
+
+       if ((dd->flags & (QIB_PRESENT | QIB_BADINTR)) != QIB_PRESENT) {
+               /*
+                * This return value is not great, but we do not want the
+                * interrupt core code to remove our interrupt handler
+                * because we don't appear to be handling an interrupt
+                * during a chip reset.
+                */
+               ret = IRQ_HANDLED;
+               goto bail;
+       }
+
+       istat = qib_read_kreg64(dd, kr_intstatus);
+
+       if (unlikely(istat == ~0ULL)) {
+               qib_bad_intrstatus(dd);
+               qib_dev_err(dd, "Interrupt status all f's, skipping\n");
+               /* don't know if it was our interrupt or not */
+               ret = IRQ_NONE;
+               goto bail;
+       }
+
+       istat &= dd->cspec->main_int_mask;
+       if (unlikely(!istat)) {
+               /* already handled, or shared and not us */
+               ret = IRQ_NONE;
+               goto bail;
+       }
+
+       qib_stats.sps_ints++;
+       if (dd->int_counter != (u32) -1)
+               dd->int_counter++;
+
+       /* handle "errors" of various kinds first, device ahead of port */
+       if (unlikely(istat & (~QIB_I_BITSEXTANT | QIB_I_GPIO |
+                             QIB_I_C_ERROR | INT_MASK_P(Err, 0) |
+                             INT_MASK_P(Err, 1))))
+               unlikely_7322_intr(dd, istat);
+
+       /*
+        * Clear the interrupt bits we found set, relatively early, so we
+        * "know" know the chip will have seen this by the time we process
+        * the queue, and will re-interrupt if necessary.  The processor
+        * itself won't take the interrupt again until we return.
+        */
+       qib_write_kreg(dd, kr_intclear, istat);
+
+       /*
+        * Handle kernel receive queues before checking for pio buffers
+        * available since receives can overflow; piobuf waiters can afford
+        * a few extra cycles, since they were waiting anyway.
+        */
+       ctxtrbits = istat & (QIB_I_RCVAVAIL_MASK | QIB_I_RCVURG_MASK);
+       if (ctxtrbits) {
+               rmask = (1ULL << QIB_I_RCVAVAIL_LSB) |
+                       (1ULL << QIB_I_RCVURG_LSB);
+               for (i = 0; i < dd->first_user_ctxt; i++) {
+                       if (ctxtrbits & rmask) {
+                               ctxtrbits &= ~rmask;
+                               if (dd->rcd[i]) {
+                                       qib_kreceive(dd->rcd[i], NULL, &npkts);
+                                       adjust_rcv_timeout(dd->rcd[i], npkts);
+                               }
+                       }
+                       rmask <<= 1;
+               }
+               if (ctxtrbits) {
+                       ctxtrbits = (ctxtrbits >> QIB_I_RCVAVAIL_LSB) |
+                               (ctxtrbits >> QIB_I_RCVURG_LSB);
+                       qib_handle_urcv(dd, ctxtrbits);
+               }
+       }
+
+       if (istat & (QIB_I_P_SDMAINT(0) | QIB_I_P_SDMAINT(1)))
+               sdma_7322_intr(dd, istat);
+
+       if ((istat & QIB_I_SPIOBUFAVAIL) && (dd->flags & QIB_INITTED))
+               qib_ib_piobufavail(dd);
+
+       ret = IRQ_HANDLED;
+bail:
+       return ret;
+}
+
+/*
+ * Dedicated receive packet available interrupt handler.
+ */
+static irqreturn_t qib_7322pintr(int irq, void *data)
+{
+       struct qib_ctxtdata *rcd = data;
+       struct qib_devdata *dd = rcd->dd;
+       u32 npkts;
+
+       if ((dd->flags & (QIB_PRESENT | QIB_BADINTR)) != QIB_PRESENT)
+               /*
+                * This return value is not great, but we do not want the
+                * interrupt core code to remove our interrupt handler
+                * because we don't appear to be handling an interrupt
+                * during a chip reset.
+                */
+               return IRQ_HANDLED;
+
+       qib_stats.sps_ints++;
+       if (dd->int_counter != (u32) -1)
+               dd->int_counter++;
+
+       /* Clear the interrupt bit we expect to be set. */
+       qib_write_kreg(dd, kr_intclear, ((1ULL << QIB_I_RCVAVAIL_LSB) |
+                      (1ULL << QIB_I_RCVURG_LSB)) << rcd->ctxt);
+
+       qib_kreceive(rcd, NULL, &npkts);
+       adjust_rcv_timeout(rcd, npkts);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * Dedicated Send buffer available interrupt handler.
+ */
+static irqreturn_t qib_7322bufavail(int irq, void *data)
+{
+       struct qib_devdata *dd = data;
+
+       if ((dd->flags & (QIB_PRESENT | QIB_BADINTR)) != QIB_PRESENT)
+               /*
+                * This return value is not great, but we do not want the
+                * interrupt core code to remove our interrupt handler
+                * because we don't appear to be handling an interrupt
+                * during a chip reset.
+                */
+               return IRQ_HANDLED;
+
+       qib_stats.sps_ints++;
+       if (dd->int_counter != (u32) -1)
+               dd->int_counter++;
+
+       /* Clear the interrupt bit we expect to be set. */
+       qib_write_kreg(dd, kr_intclear, QIB_I_SPIOBUFAVAIL);
+
+       /* qib_ib_piobufavail() will clear the want PIO interrupt if needed */
+       if (dd->flags & QIB_INITTED)
+               qib_ib_piobufavail(dd);
+       else
+               qib_wantpiobuf_7322_intr(dd, 0);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * Dedicated Send DMA interrupt handler.
+ */
+static irqreturn_t sdma_intr(int irq, void *data)
+{
+       struct qib_pportdata *ppd = data;
+       struct qib_devdata *dd = ppd->dd;
+
+       if ((dd->flags & (QIB_PRESENT | QIB_BADINTR)) != QIB_PRESENT)
+               /*
+                * This return value is not great, but we do not want the
+                * interrupt core code to remove our interrupt handler
+                * because we don't appear to be handling an interrupt
+                * during a chip reset.
+                */
+               return IRQ_HANDLED;
+
+       qib_stats.sps_ints++;
+       if (dd->int_counter != (u32) -1)
+               dd->int_counter++;
+
+       /* Clear the interrupt bit we expect to be set. */
+       qib_write_kreg(dd, kr_intclear, ppd->hw_pidx ?
+                      INT_MASK_P(SDma, 1) : INT_MASK_P(SDma, 0));
+       qib_sdma_intr(ppd);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * Dedicated Send DMA idle interrupt handler.
+ */
+static irqreturn_t sdma_idle_intr(int irq, void *data)
+{
+       struct qib_pportdata *ppd = data;
+       struct qib_devdata *dd = ppd->dd;
+
+       if ((dd->flags & (QIB_PRESENT | QIB_BADINTR)) != QIB_PRESENT)
+               /*
+                * This return value is not great, but we do not want the
+                * interrupt core code to remove our interrupt handler
+                * because we don't appear to be handling an interrupt
+                * during a chip reset.
+                */
+               return IRQ_HANDLED;
+
+       qib_stats.sps_ints++;
+       if (dd->int_counter != (u32) -1)
+               dd->int_counter++;
+
+       /* Clear the interrupt bit we expect to be set. */
+       qib_write_kreg(dd, kr_intclear, ppd->hw_pidx ?
+                      INT_MASK_P(SDmaIdle, 1) : INT_MASK_P(SDmaIdle, 0));
+       qib_sdma_intr(ppd);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * Dedicated Send DMA progress interrupt handler.
+ */
+static irqreturn_t sdma_progress_intr(int irq, void *data)
+{
+       struct qib_pportdata *ppd = data;
+       struct qib_devdata *dd = ppd->dd;
+
+       if ((dd->flags & (QIB_PRESENT | QIB_BADINTR)) != QIB_PRESENT)
+               /*
+                * This return value is not great, but we do not want the
+                * interrupt core code to remove our interrupt handler
+                * because we don't appear to be handling an interrupt
+                * during a chip reset.
+                */
+               return IRQ_HANDLED;
+
+       qib_stats.sps_ints++;
+       if (dd->int_counter != (u32) -1)
+               dd->int_counter++;
+
+       /* Clear the interrupt bit we expect to be set. */
+       qib_write_kreg(dd, kr_intclear, ppd->hw_pidx ?
+                      INT_MASK_P(SDmaProgress, 1) :
+                      INT_MASK_P(SDmaProgress, 0));
+       qib_sdma_intr(ppd);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * Dedicated Send DMA cleanup interrupt handler.
+ */
+static irqreturn_t sdma_cleanup_intr(int irq, void *data)
+{
+       struct qib_pportdata *ppd = data;
+       struct qib_devdata *dd = ppd->dd;
+
+       if ((dd->flags & (QIB_PRESENT | QIB_BADINTR)) != QIB_PRESENT)
+               /*
+                * This return value is not great, but we do not want the
+                * interrupt core code to remove our interrupt handler
+                * because we don't appear to be handling an interrupt
+                * during a chip reset.
+                */
+               return IRQ_HANDLED;
+
+       qib_stats.sps_ints++;
+       if (dd->int_counter != (u32) -1)
+               dd->int_counter++;
+
+       /* Clear the interrupt bit we expect to be set. */
+       qib_write_kreg(dd, kr_intclear, ppd->hw_pidx ?
+                      INT_MASK_PM(SDmaCleanupDone, 1) :
+                      INT_MASK_PM(SDmaCleanupDone, 0));
+       qib_sdma_process_event(ppd, qib_sdma_event_e20_hw_started);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * Set up our chip-specific interrupt handler.
+ * The interrupt type has already been setup, so
+ * we just need to do the registration and error checking.
+ * If we are using MSIx interrupts, we may fall back to
+ * INTx later, if the interrupt handler doesn't get called
+ * within 1/2 second (see verify_interrupt()).
+ */
+static void qib_setup_7322_interrupt(struct qib_devdata *dd, int clearpend)
+{
+       int ret, i, msixnum;
+       u64 redirect[6];
+       u64 mask;
+
+       if (!dd->num_pports)
+               return;
+
+       if (clearpend) {
+               /*
+                * if not switching interrupt types, be sure interrupts are
+                * disabled, and then clear anything pending at this point,
+                * because we are starting clean.
+                */
+               qib_7322_set_intr_state(dd, 0);
+
+               /* clear the reset error, init error/hwerror mask */
+               qib_7322_init_hwerrors(dd);
+
+               /* clear any interrupt bits that might be set */
+               qib_write_kreg(dd, kr_intclear, ~0ULL);
+
+               /* make sure no pending MSIx intr, and clear diag reg */
+               qib_write_kreg(dd, kr_intgranted, ~0ULL);
+               qib_write_kreg(dd, kr_vecclr_wo_int, ~0ULL);
+       }
+
+       if (!dd->cspec->num_msix_entries) {
+               /* Try to get INTx interrupt */
+try_intx:
+               if (!dd->pcidev->irq) {
+                       qib_dev_err(dd, "irq is 0, BIOS error?  "
+                                   "Interrupts won't work\n");
+                       goto bail;
+               }
+               ret = request_irq(dd->pcidev->irq, qib_7322intr,
+                                 IRQF_SHARED, QIB_DRV_NAME, dd);
+               if (ret) {
+                       qib_dev_err(dd, "Couldn't setup INTx "
+                                   "interrupt (irq=%d): %d\n",
+                                   dd->pcidev->irq, ret);
+                       goto bail;
+               }
+               dd->cspec->irq = dd->pcidev->irq;
+               dd->cspec->main_int_mask = ~0ULL;
+               goto bail;
+       }
+
+       /* Try to get MSIx interrupts */
+       memset(redirect, 0, sizeof redirect);
+       mask = ~0ULL;
+       msixnum = 0;
+       for (i = 0; msixnum < dd->cspec->num_msix_entries; i++) {
+               irq_handler_t handler;
+               const char *name;
+               void *arg;
+               u64 val;
+               int lsb, reg, sh;
+
+               if (i < ARRAY_SIZE(irq_table)) {
+                       if (irq_table[i].port) {
+                               /* skip if for a non-configured port */
+                               if (irq_table[i].port > dd->num_pports)
+                                       continue;
+                               arg = dd->pport + irq_table[i].port - 1;
+                       } else
+                               arg = dd;
+                       lsb = irq_table[i].lsb;
+                       handler = irq_table[i].handler;
+                       name = irq_table[i].name;
+               } else {
+                       unsigned ctxt;
+
+                       ctxt = i - ARRAY_SIZE(irq_table);
+                       /* per krcvq context receive interrupt */
+                       arg = dd->rcd[ctxt];
+                       if (!arg)
+                               continue;
+                       lsb = QIB_I_RCVAVAIL_LSB + ctxt;
+                       handler = qib_7322pintr;
+                       name = QIB_DRV_NAME " (kctx)";
+               }
+               ret = request_irq(dd->cspec->msix_entries[msixnum].vector,
+                                 handler, 0, name, arg);
+               if (ret) {
+                       /*
+                        * Shouldn't happen since the enable said we could
+                        * have as many as we are trying to setup here.
+                        */
+                       qib_dev_err(dd, "Couldn't setup MSIx "
+                                   "interrupt (vec=%d, irq=%d): %d\n", msixnum,
+                                   dd->cspec->msix_entries[msixnum].vector,
+                                   ret);
+                       qib_7322_nomsix(dd);
+                       goto try_intx;
+               }
+               dd->cspec->msix_arg[msixnum] = arg;
+               if (lsb >= 0) {
+                       reg = lsb / IBA7322_REDIRECT_VEC_PER_REG;
+                       sh = (lsb % IBA7322_REDIRECT_VEC_PER_REG) *
+                               SYM_LSB(IntRedirect0, vec1);
+                       mask &= ~(1ULL << lsb);
+                       redirect[reg] |= ((u64) msixnum) << sh;
+               }
+               val = qib_read_kreg64(dd, 2 * msixnum + 1 +
+                       (QIB_7322_MsixTable_OFFS / sizeof(u64)));
+               msixnum++;
+       }
+       /* Initialize the vector mapping */
+       for (i = 0; i < ARRAY_SIZE(redirect); i++)
+               qib_write_kreg(dd, kr_intredirect + i, redirect[i]);
+       dd->cspec->main_int_mask = mask;
+bail:;
+}
+
+/**
+ * qib_7322_boardname - fill in the board name and note features
+ * @dd: the qlogic_ib device
+ *
+ * info will be based on the board revision register
+ */
+static unsigned qib_7322_boardname(struct qib_devdata *dd)
+{
+       /* Will need enumeration of board-types here */
+       char *n;
+       u32 boardid, namelen;
+       unsigned features = DUAL_PORT_CAP;
+
+       boardid = SYM_FIELD(dd->revision, Revision, BoardID);
+
+       switch (boardid) {
+       case 0:
+               n = "InfiniPath_QLE7342_Emulation";
+               break;
+       case 1:
+               n = "InfiniPath_QLE7340";
+               dd->flags |= QIB_HAS_QSFP;
+               features = PORT_SPD_CAP;
+               break;
+       case 2:
+               n = "InfiniPath_QLE7342";
+               dd->flags |= QIB_HAS_QSFP;
+               break;
+       case 3:
+               n = "InfiniPath_QMI7342";
+               break;
+       case 4:
+               n = "InfiniPath_Unsupported7342";
+               qib_dev_err(dd, "Unsupported version of QMH7342\n");
+               features = 0;
+               break;
+       case BOARD_QMH7342:
+               n = "InfiniPath_QMH7342";
+               features = 0x24;
+               break;
+       case BOARD_QME7342:
+               n = "InfiniPath_QME7342";
+               break;
+       case 15:
+               n = "InfiniPath_QLE7342_TEST";
+               dd->flags |= QIB_HAS_QSFP;
+               break;
+       default:
+               n = "InfiniPath_QLE73xy_UNKNOWN";
+               qib_dev_err(dd, "Unknown 7322 board type %u\n", boardid);
+               break;
+       }
+       dd->board_atten = 1; /* index into txdds_Xdr */
+
+       namelen = strlen(n) + 1;
+       dd->boardname = kmalloc(namelen, GFP_KERNEL);
+       if (!dd->boardname)
+               qib_dev_err(dd, "Failed allocation for board name: %s\n", n);
+       else
+               snprintf(dd->boardname, namelen, "%s", n);
+
+       snprintf(dd->boardversion, sizeof(dd->boardversion),
+                "ChipABI %u.%u, %s, InfiniPath%u %u.%u, SW Compat %u\n",
+                QIB_CHIP_VERS_MAJ, QIB_CHIP_VERS_MIN, dd->boardname,
+                (unsigned)SYM_FIELD(dd->revision, Revision_R, Arch),
+                dd->majrev, dd->minrev,
+                (unsigned)SYM_FIELD(dd->revision, Revision_R, SW));
+
+       if (qib_singleport && (features >> PORT_SPD_CAP_SHIFT) & PORT_SPD_CAP) {
+               qib_devinfo(dd->pcidev, "IB%u: Forced to single port mode"
+                           " by module parameter\n", dd->unit);
+               features &= PORT_SPD_CAP;
+       }
+
+       return features;
+}
+
+/*
+ * This routine sleeps, so it can only be called from user context, not
+ * from interrupt context.
+ */
+static int qib_do_7322_reset(struct qib_devdata *dd)
+{
+       u64 val;
+       u64 *msix_vecsave;
+       int i, msix_entries, ret = 1;
+       u16 cmdval;
+       u8 int_line, clinesz;
+       unsigned long flags;
+
+       /* Use dev_err so it shows up in logs, etc. */
+       qib_dev_err(dd, "Resetting InfiniPath unit %u\n", dd->unit);
+
+       qib_pcie_getcmd(dd, &cmdval, &int_line, &clinesz);
+
+       msix_entries = dd->cspec->num_msix_entries;
+
+       /* no interrupts till re-initted */
+       qib_7322_set_intr_state(dd, 0);
+
+       if (msix_entries) {
+               qib_7322_nomsix(dd);
+               /* can be up to 512 bytes, too big for stack */
+               msix_vecsave = kmalloc(2 * dd->cspec->num_msix_entries *
+                       sizeof(u64), GFP_KERNEL);
+               if (!msix_vecsave)
+                       qib_dev_err(dd, "No mem to save MSIx data\n");
+       } else
+               msix_vecsave = NULL;
+
+       /*
+        * Core PCI (as of 2.6.18) doesn't save or rewrite the full vector
+        * info that is set up by the BIOS, so we have to save and restore
+        * it ourselves.   There is some risk something could change it,
+        * after we save it, but since we have disabled the MSIx, it
+        * shouldn't be touched...
+        */
+       for (i = 0; i < msix_entries; i++) {
+               u64 vecaddr, vecdata;
+               vecaddr = qib_read_kreg64(dd, 2 * i +
+                                 (QIB_7322_MsixTable_OFFS / sizeof(u64)));
+               vecdata = qib_read_kreg64(dd, 1 + 2 * i +
+                                 (QIB_7322_MsixTable_OFFS / sizeof(u64)));
+               if (msix_vecsave) {
+                       msix_vecsave[2 * i] = vecaddr;
+                       /* save it without the masked bit set */
+                       msix_vecsave[1 + 2 * i] = vecdata & ~0x100000000ULL;
+               }
+       }
+
+       dd->pport->cpspec->ibdeltainprog = 0;
+       dd->pport->cpspec->ibsymdelta = 0;
+       dd->pport->cpspec->iblnkerrdelta = 0;
+       dd->pport->cpspec->ibmalfdelta = 0;
+       dd->int_counter = 0; /* so we check interrupts work again */
+
+       /*
+        * Keep chip from being accessed until we are ready.  Use
+        * writeq() directly, to allow the write even though QIB_PRESENT
+        * isnt' set.
+        */
+       dd->flags &= ~(QIB_INITTED | QIB_PRESENT | QIB_BADINTR);
+       dd->flags |= QIB_DOING_RESET;
+       val = dd->control | QLOGIC_IB_C_RESET;
+       writeq(val, &dd->kregbase[kr_control]);
+
+       for (i = 1; i <= 5; i++) {
+               /*
+                * Allow MBIST, etc. to complete; longer on each retry.
+                * We sometimes get machine checks from bus timeout if no
+                * response, so for now, make it *really* long.
+                */
+               msleep(1000 + (1 + i) * 3000);
+
+               qib_pcie_reenable(dd, cmdval, int_line, clinesz);
+
+               /*
+                * Use readq directly, so we don't need to mark it as PRESENT
+                * until we get a successful indication that all is well.
+                */
+               val = readq(&dd->kregbase[kr_revision]);
+               if (val == dd->revision)
+                       break;
+               if (i == 5) {
+                       qib_dev_err(dd, "Failed to initialize after reset, "
+                                   "unusable\n");
+                       ret = 0;
+                       goto  bail;
+               }
+       }
+
+       dd->flags |= QIB_PRESENT; /* it's back */
+
+       if (msix_entries) {
+               /* restore the MSIx vector address and data if saved above */
+               for (i = 0; i < msix_entries; i++) {
+                       dd->cspec->msix_entries[i].entry = i;
+                       if (!msix_vecsave || !msix_vecsave[2 * i])
+                               continue;
+                       qib_write_kreg(dd, 2 * i +
+                               (QIB_7322_MsixTable_OFFS / sizeof(u64)),
+                               msix_vecsave[2 * i]);
+                       qib_write_kreg(dd, 1 + 2 * i +
+                               (QIB_7322_MsixTable_OFFS / sizeof(u64)),
+                               msix_vecsave[1 + 2 * i]);
+               }
+       }
+
+       /* initialize the remaining registers.  */
+       for (i = 0; i < dd->num_pports; ++i)
+               write_7322_init_portregs(&dd->pport[i]);
+       write_7322_initregs(dd);
+
+       if (qib_pcie_params(dd, dd->lbus_width,
+                           &dd->cspec->num_msix_entries,
+                           dd->cspec->msix_entries))
+               qib_dev_err(dd, "Reset failed to setup PCIe or interrupts; "
+                               "continuing anyway\n");
+
+       qib_setup_7322_interrupt(dd, 1);
+
+       for (i = 0; i < dd->num_pports; ++i) {
+               struct qib_pportdata *ppd = &dd->pport[i];
+
+               spin_lock_irqsave(&ppd->lflags_lock, flags);
+               ppd->lflags |= QIBL_IB_FORCE_NOTIFY;
+               ppd->lflags &= ~QIBL_IB_AUTONEG_FAILED;
+               spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+       }
+
+bail:
+       dd->flags &= ~QIB_DOING_RESET; /* OK or not, no longer resetting */
+       kfree(msix_vecsave);
+       return ret;
+}
+
+/**
+ * qib_7322_put_tid - write a TID to the chip
+ * @dd: the qlogic_ib device
+ * @tidptr: pointer to the expected TID (in chip) to update
+ * @tidtype: 0 for eager, 1 for expected
+ * @pa: physical address of in memory buffer; tidinvalid if freeing
+ */
+static void qib_7322_put_tid(struct qib_devdata *dd, u64 __iomem *tidptr,
+                            u32 type, unsigned long pa)
+{
+       if (!(dd->flags & QIB_PRESENT))
+               return;
+       if (pa != dd->tidinvalid) {
+               u64 chippa = pa >> IBA7322_TID_PA_SHIFT;
+
+               /* paranoia checks */
+               if (pa != (chippa << IBA7322_TID_PA_SHIFT)) {
+                       qib_dev_err(dd, "Physaddr %lx not 2KB aligned!\n",
+                                   pa);
+                       return;
+               }
+               if (chippa >= (1UL << IBA7322_TID_SZ_SHIFT)) {
+                       qib_dev_err(dd, "Physical page address 0x%lx "
+                               "larger than supported\n", pa);
+                       return;
+               }
+
+               if (type == RCVHQ_RCV_TYPE_EAGER)
+                       chippa |= dd->tidtemplate;
+               else /* for now, always full 4KB page */
+                       chippa |= IBA7322_TID_SZ_4K;
+               pa = chippa;
+       }
+       writeq(pa, tidptr);
+       mmiowb();
+}
+
+/**
+ * qib_7322_clear_tids - clear all TID entries for a ctxt, expected and eager
+ * @dd: the qlogic_ib device
+ * @ctxt: the ctxt
+ *
+ * clear all TID entries for a ctxt, expected and eager.
+ * Used from qib_close().
+ */
+static void qib_7322_clear_tids(struct qib_devdata *dd,
+                               struct qib_ctxtdata *rcd)
+{
+       u64 __iomem *tidbase;
+       unsigned long tidinv;
+       u32 ctxt;
+       int i;
+
+       if (!dd->kregbase || !rcd)
+               return;
+
+       ctxt = rcd->ctxt;
+
+       tidinv = dd->tidinvalid;
+       tidbase = (u64 __iomem *)
+               ((char __iomem *) dd->kregbase +
+                dd->rcvtidbase +
+                ctxt * dd->rcvtidcnt * sizeof(*tidbase));
+
+       for (i = 0; i < dd->rcvtidcnt; i++)
+               qib_7322_put_tid(dd, &tidbase[i], RCVHQ_RCV_TYPE_EXPECTED,
+                                tidinv);
+
+       tidbase = (u64 __iomem *)
+               ((char __iomem *) dd->kregbase +
+                dd->rcvegrbase +
+                rcd->rcvegr_tid_base * sizeof(*tidbase));
+
+       for (i = 0; i < rcd->rcvegrcnt; i++)
+               qib_7322_put_tid(dd, &tidbase[i], RCVHQ_RCV_TYPE_EAGER,
+                                tidinv);
+}
+
+/**
+ * qib_7322_tidtemplate - setup constants for TID updates
+ * @dd: the qlogic_ib device
+ *
+ * We setup stuff that we use a lot, to avoid calculating each time
+ */
+static void qib_7322_tidtemplate(struct qib_devdata *dd)
+{
+       /*
+        * For now, we always allocate 4KB buffers (at init) so we can
+        * receive max size packets.  We may want a module parameter to
+        * specify 2KB or 4KB and/or make it per port instead of per device
+        * for those who want to reduce memory footprint.  Note that the
+        * rcvhdrentsize size must be large enough to hold the largest
+        * IB header (currently 96 bytes) that we expect to handle (plus of
+        * course the 2 dwords of RHF).
+        */
+       if (dd->rcvegrbufsize == 2048)
+               dd->tidtemplate = IBA7322_TID_SZ_2K;
+       else if (dd->rcvegrbufsize == 4096)
+               dd->tidtemplate = IBA7322_TID_SZ_4K;
+       dd->tidinvalid = 0;
+}
+
+/**
+ * qib_init_7322_get_base_info - set chip-specific flags for user code
+ * @rcd: the qlogic_ib ctxt
+ * @kbase: qib_base_info pointer
+ *
+ * We set the PCIE flag because the lower bandwidth on PCIe vs
+ * HyperTransport can affect some user packet algorithims.
+ */
+
+static int qib_7322_get_base_info(struct qib_ctxtdata *rcd,
+                                 struct qib_base_info *kinfo)
+{
+       kinfo->spi_runtime_flags |= QIB_RUNTIME_CTXT_MSB_IN_QP |
+               QIB_RUNTIME_PCIE | QIB_RUNTIME_NODMA_RTAIL |
+               QIB_RUNTIME_HDRSUPP | QIB_RUNTIME_SDMA;
+       if (rcd->dd->cspec->r1)
+               kinfo->spi_runtime_flags |= QIB_RUNTIME_RCHK;
+       if (rcd->dd->flags & QIB_USE_SPCL_TRIG)
+               kinfo->spi_runtime_flags |= QIB_RUNTIME_SPECIAL_TRIGGER;
+
+       return 0;
+}
+
+static struct qib_message_header *
+qib_7322_get_msgheader(struct qib_devdata *dd, __le32 *rhf_addr)
+{
+       u32 offset = qib_hdrget_offset(rhf_addr);
+
+       return (struct qib_message_header *)
+               (rhf_addr - dd->rhf_offset + offset);
+}
+
+/*
+ * Configure number of contexts.
+ */
+static void qib_7322_config_ctxts(struct qib_devdata *dd)
+{
+       unsigned long flags;
+       u32 nchipctxts;
+
+       nchipctxts = qib_read_kreg32(dd, kr_contextcnt);
+       dd->cspec->numctxts = nchipctxts;
+       if (qib_n_krcv_queues > 1 && dd->num_pports) {
+               /*
+                * Set the mask for which bits from the QPN are used
+                * to select a context number.
+                */
+               dd->qpn_mask = 0x3f;
+               dd->first_user_ctxt = NUM_IB_PORTS +
+                       (qib_n_krcv_queues - 1) * dd->num_pports;
+               if (dd->first_user_ctxt > nchipctxts)
+                       dd->first_user_ctxt = nchipctxts;
+               dd->n_krcv_queues = dd->first_user_ctxt / dd->num_pports;
+       } else {
+               dd->first_user_ctxt = NUM_IB_PORTS;
+               dd->n_krcv_queues = 1;
+       }
+
+       if (!qib_cfgctxts) {
+               int nctxts = dd->first_user_ctxt + num_online_cpus();
+
+               if (nctxts <= 6)
+                       dd->ctxtcnt = 6;
+               else if (nctxts <= 10)
+                       dd->ctxtcnt = 10;
+               else if (nctxts <= nchipctxts)
+                       dd->ctxtcnt = nchipctxts;
+       } else if (qib_cfgctxts < dd->num_pports)
+               dd->ctxtcnt = dd->num_pports;
+       else if (qib_cfgctxts <= nchipctxts)
+               dd->ctxtcnt = qib_cfgctxts;
+       if (!dd->ctxtcnt) /* none of the above, set to max */
+               dd->ctxtcnt = nchipctxts;
+
+       /*
+        * Chip can be configured for 6, 10, or 18 ctxts, and choice
+        * affects number of eager TIDs per ctxt (1K, 2K, 4K).
+        * Lock to be paranoid about later motion, etc.
+        */
+       spin_lock_irqsave(&dd->cspec->rcvmod_lock, flags);
+       if (dd->ctxtcnt > 10)
+               dd->rcvctrl |= 2ULL << SYM_LSB(RcvCtrl, ContextCfg);
+       else if (dd->ctxtcnt > 6)
+               dd->rcvctrl |= 1ULL << SYM_LSB(RcvCtrl, ContextCfg);
+       /* else configure for default 6 receive ctxts */
+
+       /* The XRC opcode is 5. */
+       dd->rcvctrl |= 5ULL << SYM_LSB(RcvCtrl, XrcTypeCode);
+
+       /*
+        * RcvCtrl *must* be written here so that the
+        * chip understands how to change rcvegrcnt below.
+        */
+       qib_write_kreg(dd, kr_rcvctrl, dd->rcvctrl);
+       spin_unlock_irqrestore(&dd->cspec->rcvmod_lock, flags);
+
+       /* kr_rcvegrcnt changes based on the number of contexts enabled */
+       dd->cspec->rcvegrcnt = qib_read_kreg32(dd, kr_rcvegrcnt);
+       dd->rcvhdrcnt = max(dd->cspec->rcvegrcnt,
+                               dd->num_pports > 1 ? 1024U : 2048U);
+}
+
+static int qib_7322_get_ib_cfg(struct qib_pportdata *ppd, int which)
+{
+
+       int lsb, ret = 0;
+       u64 maskr; /* right-justified mask */
+
+       switch (which) {
+
+       case QIB_IB_CFG_LWID_ENB: /* Get allowed Link-width */
+               ret = ppd->link_width_enabled;
+               goto done;
+
+       case QIB_IB_CFG_LWID: /* Get currently active Link-width */
+               ret = ppd->link_width_active;
+               goto done;
+
+       case QIB_IB_CFG_SPD_ENB: /* Get allowed Link speeds */
+               ret = ppd->link_speed_enabled;
+               goto done;
+
+       case QIB_IB_CFG_SPD: /* Get current Link spd */
+               ret = ppd->link_speed_active;
+               goto done;
+
+       case QIB_IB_CFG_RXPOL_ENB: /* Get Auto-RX-polarity enable */
+               lsb = SYM_LSB(IBCCtrlB_0, IB_POLARITY_REV_SUPP);
+               maskr = SYM_RMASK(IBCCtrlB_0, IB_POLARITY_REV_SUPP);
+               break;
+
+       case QIB_IB_CFG_LREV_ENB: /* Get Auto-Lane-reversal enable */
+               lsb = SYM_LSB(IBCCtrlB_0, IB_LANE_REV_SUPPORTED);
+               maskr = SYM_RMASK(IBCCtrlB_0, IB_LANE_REV_SUPPORTED);
+               break;
+
+       case QIB_IB_CFG_LINKLATENCY:
+               ret = qib_read_kreg_port(ppd, krp_ibcstatus_b) &
+                       SYM_MASK(IBCStatusB_0, LinkRoundTripLatency);
+               goto done;
+
+       case QIB_IB_CFG_OP_VLS:
+               ret = ppd->vls_operational;
+               goto done;
+
+       case QIB_IB_CFG_VL_HIGH_CAP:
+               ret = 16;
+               goto done;
+
+       case QIB_IB_CFG_VL_LOW_CAP:
+               ret = 16;
+               goto done;
+
+       case QIB_IB_CFG_OVERRUN_THRESH: /* IB overrun threshold */
+               ret = SYM_FIELD(ppd->cpspec->ibcctrl_a, IBCCtrlA_0,
+                               OverrunThreshold);
+               goto done;
+
+       case QIB_IB_CFG_PHYERR_THRESH: /* IB PHY error threshold */
+               ret = SYM_FIELD(ppd->cpspec->ibcctrl_a, IBCCtrlA_0,
+                               PhyerrThreshold);
+               goto done;
+
+       case QIB_IB_CFG_LINKDEFAULT: /* IB link default (sleep/poll) */
+               /* will only take effect when the link state changes */
+               ret = (ppd->cpspec->ibcctrl_a &
+                      SYM_MASK(IBCCtrlA_0, LinkDownDefaultState)) ?
+                       IB_LINKINITCMD_SLEEP : IB_LINKINITCMD_POLL;
+               goto done;
+
+       case QIB_IB_CFG_HRTBT: /* Get Heartbeat off/enable/auto */
+               lsb = IBA7322_IBC_HRTBT_LSB;
+               maskr = IBA7322_IBC_HRTBT_RMASK; /* OR of AUTO and ENB */
+               break;
+
+       case QIB_IB_CFG_PMA_TICKS:
+               /*
+                * 0x00 = 10x link transfer rate or 4 nsec. for 2.5Gbs
+                * Since the clock is always 250MHz, the value is 3, 1 or 0.
+                */
+               if (ppd->link_speed_active == QIB_IB_QDR)
+                       ret = 3;
+               else if (ppd->link_speed_active == QIB_IB_DDR)
+                       ret = 1;
+               else
+                       ret = 0;
+               goto done;
+
+       default:
+               ret = -EINVAL;
+               goto done;
+       }
+       ret = (int)((ppd->cpspec->ibcctrl_b >> lsb) & maskr);
+done:
+       return ret;
+}
+
+/*
+ * Below again cribbed liberally from older version. Do not lean
+ * heavily on it.
+ */
+#define IBA7322_IBC_DLIDLMC_SHIFT QIB_7322_IBCCtrlB_0_IB_DLID_LSB
+#define IBA7322_IBC_DLIDLMC_MASK (QIB_7322_IBCCtrlB_0_IB_DLID_RMASK \
+       | (QIB_7322_IBCCtrlB_0_IB_DLID_MASK_RMASK << 16))
+
+static int qib_7322_set_ib_cfg(struct qib_pportdata *ppd, int which, u32 val)
+{
+       struct qib_devdata *dd = ppd->dd;
+       u64 maskr; /* right-justified mask */
+       int lsb, ret = 0;
+       u16 lcmd, licmd;
+       unsigned long flags;
+
+       switch (which) {
+       case QIB_IB_CFG_LIDLMC:
+               /*
+                * Set LID and LMC. Combined to avoid possible hazard
+                * caller puts LMC in 16MSbits, DLID in 16LSbits of val
+                */
+               lsb = IBA7322_IBC_DLIDLMC_SHIFT;
+               maskr = IBA7322_IBC_DLIDLMC_MASK;
+               /*
+                * For header-checking, the SLID in the packet will
+                * be masked with SendIBSLMCMask, and compared
+                * with SendIBSLIDAssignMask. Make sure we do not
+                * set any bits not covered by the mask, or we get
+                * false-positives.
+                */
+               qib_write_kreg_port(ppd, krp_sendslid,
+                                   val & (val >> 16) & SendIBSLIDAssignMask);
+               qib_write_kreg_port(ppd, krp_sendslidmask,
+                                   (val >> 16) & SendIBSLMCMask);
+               break;
+
+       case QIB_IB_CFG_LWID_ENB: /* set allowed Link-width */
+               ppd->link_width_enabled = val;
+               /* convert IB value to chip register value */
+               if (val == IB_WIDTH_1X)
+                       val = 0;
+               else if (val == IB_WIDTH_4X)
+                       val = 1;
+               else
+                       val = 3;
+               maskr = SYM_RMASK(IBCCtrlB_0, IB_NUM_CHANNELS);
+               lsb = SYM_LSB(IBCCtrlB_0, IB_NUM_CHANNELS);
+               break;
+
+       case QIB_IB_CFG_SPD_ENB: /* set allowed Link speeds */
+               /*
+                * As with width, only write the actual register if the
+                * link is currently down, otherwise takes effect on next
+                * link change.  Since setting is being explictly requested
+                * (via MAD or sysfs), clear autoneg failure status if speed
+                * autoneg is enabled.
+                */
+               ppd->link_speed_enabled = val;
+               val <<= IBA7322_IBC_SPEED_LSB;
+               maskr = IBA7322_IBC_SPEED_MASK | IBA7322_IBC_IBTA_1_2_MASK |
+                       IBA7322_IBC_MAX_SPEED_MASK;
+               if (val & (val - 1)) {
+                       /* Muliple speeds enabled */
+                       val |= IBA7322_IBC_IBTA_1_2_MASK |
+                               IBA7322_IBC_MAX_SPEED_MASK;
+                       spin_lock_irqsave(&ppd->lflags_lock, flags);
+                       ppd->lflags &= ~QIBL_IB_AUTONEG_FAILED;
+                       spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+               } else if (val & IBA7322_IBC_SPEED_QDR)
+                       val |= IBA7322_IBC_IBTA_1_2_MASK;
+               /* IBTA 1.2 mode + min/max + speed bits are contiguous */
+               lsb = SYM_LSB(IBCCtrlB_0, IB_ENHANCED_MODE);
+               break;
+
+       case QIB_IB_CFG_RXPOL_ENB: /* set Auto-RX-polarity enable */
+               lsb = SYM_LSB(IBCCtrlB_0, IB_POLARITY_REV_SUPP);
+               maskr = SYM_RMASK(IBCCtrlB_0, IB_POLARITY_REV_SUPP);
+               break;
+
+       case QIB_IB_CFG_LREV_ENB: /* set Auto-Lane-reversal enable */
+               lsb = SYM_LSB(IBCCtrlB_0, IB_LANE_REV_SUPPORTED);
+               maskr = SYM_RMASK(IBCCtrlB_0, IB_LANE_REV_SUPPORTED);
+               break;
+
+       case QIB_IB_CFG_OVERRUN_THRESH: /* IB overrun threshold */
+               maskr = SYM_FIELD(ppd->cpspec->ibcctrl_a, IBCCtrlA_0,
+                                 OverrunThreshold);
+               if (maskr != val) {
+                       ppd->cpspec->ibcctrl_a &=
+                               ~SYM_MASK(IBCCtrlA_0, OverrunThreshold);
+                       ppd->cpspec->ibcctrl_a |= (u64) val <<
+                               SYM_LSB(IBCCtrlA_0, OverrunThreshold);
+                       qib_write_kreg_port(ppd, krp_ibcctrl_a,
+                                           ppd->cpspec->ibcctrl_a);
+                       qib_write_kreg(dd, kr_scratch, 0ULL);
+               }
+               goto bail;
+
+       case QIB_IB_CFG_PHYERR_THRESH: /* IB PHY error threshold */
+               maskr = SYM_FIELD(ppd->cpspec->ibcctrl_a, IBCCtrlA_0,
+                                 PhyerrThreshold);
+               if (maskr != val) {
+                       ppd->cpspec->ibcctrl_a &=
+                               ~SYM_MASK(IBCCtrlA_0, PhyerrThreshold);
+                       ppd->cpspec->ibcctrl_a |= (u64) val <<
+                               SYM_LSB(IBCCtrlA_0, PhyerrThreshold);
+                       qib_write_kreg_port(ppd, krp_ibcctrl_a,
+                                           ppd->cpspec->ibcctrl_a);
+                       qib_write_kreg(dd, kr_scratch, 0ULL);
+               }
+               goto bail;
+
+       case QIB_IB_CFG_PKEYS: /* update pkeys */
+               maskr = (u64) ppd->pkeys[0] | ((u64) ppd->pkeys[1] << 16) |
+                       ((u64) ppd->pkeys[2] << 32) |
+                       ((u64) ppd->pkeys[3] << 48);
+               qib_write_kreg_port(ppd, krp_partitionkey, maskr);
+               goto bail;
+
+       case QIB_IB_CFG_LINKDEFAULT: /* IB link default (sleep/poll) */
+               /* will only take effect when the link state changes */
+               if (val == IB_LINKINITCMD_POLL)
+                       ppd->cpspec->ibcctrl_a &=
+                               ~SYM_MASK(IBCCtrlA_0, LinkDownDefaultState);
+               else /* SLEEP */
+                       ppd->cpspec->ibcctrl_a |=
+                               SYM_MASK(IBCCtrlA_0, LinkDownDefaultState);
+               qib_write_kreg_port(ppd, krp_ibcctrl_a, ppd->cpspec->ibcctrl_a);
+               qib_write_kreg(dd, kr_scratch, 0ULL);
+               goto bail;
+
+       case QIB_IB_CFG_MTU: /* update the MTU in IBC */
+               /*
+                * Update our housekeeping variables, and set IBC max
+                * size, same as init code; max IBC is max we allow in
+                * buffer, less the qword pbc, plus 1 for ICRC, in dwords
+                * Set even if it's unchanged, print debug message only
+                * on changes.
+                */
+               val = (ppd->ibmaxlen >> 2) + 1;
+               ppd->cpspec->ibcctrl_a &= ~SYM_MASK(IBCCtrlA_0, MaxPktLen);
+               ppd->cpspec->ibcctrl_a |= (u64)val <<
+                       SYM_LSB(IBCCtrlA_0, MaxPktLen);
+               qib_write_kreg_port(ppd, krp_ibcctrl_a,
+                                   ppd->cpspec->ibcctrl_a);
+               qib_write_kreg(dd, kr_scratch, 0ULL);
+               goto bail;
+
+       case QIB_IB_CFG_LSTATE: /* set the IB link state */
+               switch (val & 0xffff0000) {
+               case IB_LINKCMD_DOWN:
+                       lcmd = QLOGIC_IB_IBCC_LINKCMD_DOWN;
+                       ppd->cpspec->ibmalfusesnap = 1;
+                       ppd->cpspec->ibmalfsnap = read_7322_creg32_port(ppd,
+                               crp_errlink);
+                       if (!ppd->cpspec->ibdeltainprog &&
+                           qib_compat_ddr_negotiate) {
+                               ppd->cpspec->ibdeltainprog = 1;
+                               ppd->cpspec->ibsymsnap =
+                                       read_7322_creg32_port(ppd,
+                                                             crp_ibsymbolerr);
+                               ppd->cpspec->iblnkerrsnap =
+                                       read_7322_creg32_port(ppd,
+                                                     crp_iblinkerrrecov);
+                       }
+                       break;
+
+               case IB_LINKCMD_ARMED:
+                       lcmd = QLOGIC_IB_IBCC_LINKCMD_ARMED;
+                       if (ppd->cpspec->ibmalfusesnap) {
+                               ppd->cpspec->ibmalfusesnap = 0;
+                               ppd->cpspec->ibmalfdelta +=
+                                       read_7322_creg32_port(ppd,
+                                                             crp_errlink) -
+                                       ppd->cpspec->ibmalfsnap;
+                       }
+                       break;
+
+               case IB_LINKCMD_ACTIVE:
+                       lcmd = QLOGIC_IB_IBCC_LINKCMD_ACTIVE;
+                       break;
+
+               default:
+                       ret = -EINVAL;
+                       qib_dev_err(dd, "bad linkcmd req 0x%x\n", val >> 16);
+                       goto bail;
+               }
+               switch (val & 0xffff) {
+               case IB_LINKINITCMD_NOP:
+                       licmd = 0;
+                       break;
+
+               case IB_LINKINITCMD_POLL:
+                       licmd = QLOGIC_IB_IBCC_LINKINITCMD_POLL;
+                       break;
+
+               case IB_LINKINITCMD_SLEEP:
+                       licmd = QLOGIC_IB_IBCC_LINKINITCMD_SLEEP;
+                       break;
+
+               case IB_LINKINITCMD_DISABLE:
+                       licmd = QLOGIC_IB_IBCC_LINKINITCMD_DISABLE;
+                       ppd->cpspec->chase_end = 0;
+                       /*
+                        * stop state chase counter and timer, if running.
+                        * wait forpending timer, but don't clear .data (ppd)!
+                        */
+                       if (ppd->cpspec->chase_timer.expires) {
+                               del_timer_sync(&ppd->cpspec->chase_timer);
+                               ppd->cpspec->chase_timer.expires = 0;
+                       }
+                       break;
+
+               default:
+                       ret = -EINVAL;
+                       qib_dev_err(dd, "bad linkinitcmd req 0x%x\n",
+                                   val & 0xffff);
+                       goto bail;
+               }
+               qib_set_ib_7322_lstate(ppd, lcmd, licmd);
+               goto bail;
+
+       case QIB_IB_CFG_OP_VLS:
+               if (ppd->vls_operational != val) {
+                       ppd->vls_operational = val;
+                       set_vls(ppd);
+               }
+               goto bail;
+
+       case QIB_IB_CFG_VL_HIGH_LIMIT:
+               qib_write_kreg_port(ppd, krp_highprio_limit, val);
+               goto bail;
+
+       case QIB_IB_CFG_HRTBT: /* set Heartbeat off/enable/auto */
+               if (val > 3) {
+                       ret = -EINVAL;
+                       goto bail;
+               }
+               lsb = IBA7322_IBC_HRTBT_LSB;
+               maskr = IBA7322_IBC_HRTBT_RMASK; /* OR of AUTO and ENB */
+               break;
+
+       case QIB_IB_CFG_PORT:
+               /* val is the port number of the switch we are connected to. */
+               if (ppd->dd->cspec->r1) {
+                       cancel_delayed_work(&ppd->cpspec->ipg_work);
+                       ppd->cpspec->ipg_tries = 0;
+               }
+               goto bail;
+
+       default:
+               ret = -EINVAL;
+               goto bail;
+       }
+       ppd->cpspec->ibcctrl_b &= ~(maskr << lsb);
+       ppd->cpspec->ibcctrl_b |= (((u64) val & maskr) << lsb);
+       qib_write_kreg_port(ppd, krp_ibcctrl_b, ppd->cpspec->ibcctrl_b);
+       qib_write_kreg(dd, kr_scratch, 0);
+bail:
+       return ret;
+}
+
+static int qib_7322_set_loopback(struct qib_pportdata *ppd, const char *what)
+{
+       int ret = 0;
+       u64 val, ctrlb;
+
+       /* only IBC loopback, may add serdes and xgxs loopbacks later */
+       if (!strncmp(what, "ibc", 3)) {
+               ppd->cpspec->ibcctrl_a |= SYM_MASK(IBCCtrlA_0,
+                                                      Loopback);
+               val = 0; /* disable heart beat, so link will come up */
+               qib_devinfo(ppd->dd->pcidev, "Enabling IB%u:%u IBC loopback\n",
+                        ppd->dd->unit, ppd->port);
+       } else if (!strncmp(what, "off", 3)) {
+               ppd->cpspec->ibcctrl_a &= ~SYM_MASK(IBCCtrlA_0,
+                                                       Loopback);
+               /* enable heart beat again */
+               val = IBA7322_IBC_HRTBT_RMASK << IBA7322_IBC_HRTBT_LSB;
+               qib_devinfo(ppd->dd->pcidev, "Disabling IB%u:%u IBC loopback "
+                           "(normal)\n", ppd->dd->unit, ppd->port);
+       } else
+               ret = -EINVAL;
+       if (!ret) {
+               qib_write_kreg_port(ppd, krp_ibcctrl_a,
+                                   ppd->cpspec->ibcctrl_a);
+               ctrlb = ppd->cpspec->ibcctrl_b & ~(IBA7322_IBC_HRTBT_MASK
+                                            << IBA7322_IBC_HRTBT_LSB);
+               ppd->cpspec->ibcctrl_b = ctrlb | val;
+               qib_write_kreg_port(ppd, krp_ibcctrl_b,
+                                   ppd->cpspec->ibcctrl_b);
+               qib_write_kreg(ppd->dd, kr_scratch, 0);
+       }
+       return ret;
+}
+
+static void get_vl_weights(struct qib_pportdata *ppd, unsigned regno,
+                          struct ib_vl_weight_elem *vl)
+{
+       unsigned i;
+
+       for (i = 0; i < 16; i++, regno++, vl++) {
+               u32 val = qib_read_kreg_port(ppd, regno);
+
+               vl->vl = (val >> SYM_LSB(LowPriority0_0, VirtualLane)) &
+                       SYM_RMASK(LowPriority0_0, VirtualLane);
+               vl->weight = (val >> SYM_LSB(LowPriority0_0, Weight)) &
+                       SYM_RMASK(LowPriority0_0, Weight);
+       }
+}
+
+static void set_vl_weights(struct qib_pportdata *ppd, unsigned regno,
+                          struct ib_vl_weight_elem *vl)
+{
+       unsigned i;
+
+       for (i = 0; i < 16; i++, regno++, vl++) {
+               u64 val;
+
+               val = ((vl->vl & SYM_RMASK(LowPriority0_0, VirtualLane)) <<
+                       SYM_LSB(LowPriority0_0, VirtualLane)) |
+                     ((vl->weight & SYM_RMASK(LowPriority0_0, Weight)) <<
+                       SYM_LSB(LowPriority0_0, Weight));
+               qib_write_kreg_port(ppd, regno, val);
+       }
+       if (!(ppd->p_sendctrl & SYM_MASK(SendCtrl_0, IBVLArbiterEn))) {
+               struct qib_devdata *dd = ppd->dd;
+               unsigned long flags;
+
+               spin_lock_irqsave(&dd->sendctrl_lock, flags);
+               ppd->p_sendctrl |= SYM_MASK(SendCtrl_0, IBVLArbiterEn);
+               qib_write_kreg_port(ppd, krp_sendctrl, ppd->p_sendctrl);
+               qib_write_kreg(dd, kr_scratch, 0);
+               spin_unlock_irqrestore(&dd->sendctrl_lock, flags);
+       }
+}
+
+static int qib_7322_get_ib_table(struct qib_pportdata *ppd, int which, void *t)
+{
+       switch (which) {
+       case QIB_IB_TBL_VL_HIGH_ARB:
+               get_vl_weights(ppd, krp_highprio_0, t);
+               break;
+
+       case QIB_IB_TBL_VL_LOW_ARB:
+               get_vl_weights(ppd, krp_lowprio_0, t);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int qib_7322_set_ib_table(struct qib_pportdata *ppd, int which, void *t)
+{
+       switch (which) {
+       case QIB_IB_TBL_VL_HIGH_ARB:
+               set_vl_weights(ppd, krp_highprio_0, t);
+               break;
+
+       case QIB_IB_TBL_VL_LOW_ARB:
+               set_vl_weights(ppd, krp_lowprio_0, t);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static void qib_update_7322_usrhead(struct qib_ctxtdata *rcd, u64 hd,
+                                   u32 updegr, u32 egrhd)
+{
+       qib_write_ureg(rcd->dd, ur_rcvhdrhead, hd, rcd->ctxt);
+       qib_write_ureg(rcd->dd, ur_rcvhdrhead, hd, rcd->ctxt);
+       if (updegr)
+               qib_write_ureg(rcd->dd, ur_rcvegrindexhead, egrhd, rcd->ctxt);
+}
+
+static u32 qib_7322_hdrqempty(struct qib_ctxtdata *rcd)
+{
+       u32 head, tail;
+
+       head = qib_read_ureg32(rcd->dd, ur_rcvhdrhead, rcd->ctxt);
+       if (rcd->rcvhdrtail_kvaddr)
+               tail = qib_get_rcvhdrtail(rcd);
+       else
+               tail = qib_read_ureg32(rcd->dd, ur_rcvhdrtail, rcd->ctxt);
+       return head == tail;
+}
+
+#define RCVCTRL_COMMON_MODS (QIB_RCVCTRL_CTXT_ENB | \
+       QIB_RCVCTRL_CTXT_DIS | \
+       QIB_RCVCTRL_TIDFLOW_ENB | \
+       QIB_RCVCTRL_TIDFLOW_DIS | \
+       QIB_RCVCTRL_TAILUPD_ENB | \
+       QIB_RCVCTRL_TAILUPD_DIS | \
+       QIB_RCVCTRL_INTRAVAIL_ENB | \
+       QIB_RCVCTRL_INTRAVAIL_DIS | \
+       QIB_RCVCTRL_BP_ENB | \
+       QIB_RCVCTRL_BP_DIS)
+
+#define RCVCTRL_PORT_MODS (QIB_RCVCTRL_CTXT_ENB | \
+       QIB_RCVCTRL_CTXT_DIS | \
+       QIB_RCVCTRL_PKEY_DIS | \
+       QIB_RCVCTRL_PKEY_ENB)
+
+/*
+ * Modify the RCVCTRL register in chip-specific way. This
+ * is a function because bit positions and (future) register
+ * location is chip-specifc, but the needed operations are
+ * generic. <op> is a bit-mask because we often want to
+ * do multiple modifications.
+ */
+static void rcvctrl_7322_mod(struct qib_pportdata *ppd, unsigned int op,
+                            int ctxt)
+{
+       struct qib_devdata *dd = ppd->dd;
+       struct qib_ctxtdata *rcd;
+       u64 mask, val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dd->cspec->rcvmod_lock, flags);
+
+       if (op & QIB_RCVCTRL_TIDFLOW_ENB)
+               dd->rcvctrl |= SYM_MASK(RcvCtrl, TidFlowEnable);
+       if (op & QIB_RCVCTRL_TIDFLOW_DIS)
+               dd->rcvctrl &= ~SYM_MASK(RcvCtrl, TidFlowEnable);
+       if (op & QIB_RCVCTRL_TAILUPD_ENB)
+               dd->rcvctrl |= SYM_MASK(RcvCtrl, TailUpd);
+       if (op & QIB_RCVCTRL_TAILUPD_DIS)
+               dd->rcvctrl &= ~SYM_MASK(RcvCtrl, TailUpd);
+       if (op & QIB_RCVCTRL_PKEY_ENB)
+               ppd->p_rcvctrl &= ~SYM_MASK(RcvCtrl_0, RcvPartitionKeyDisable);
+       if (op & QIB_RCVCTRL_PKEY_DIS)
+               ppd->p_rcvctrl |= SYM_MASK(RcvCtrl_0, RcvPartitionKeyDisable);
+       if (ctxt < 0) {
+               mask = (1ULL << dd->ctxtcnt) - 1;
+               rcd = NULL;
+       } else {
+               mask = (1ULL << ctxt);
+               rcd = dd->rcd[ctxt];
+       }
+       if ((op & QIB_RCVCTRL_CTXT_ENB) && rcd) {
+               ppd->p_rcvctrl |=
+                       (mask << SYM_LSB(RcvCtrl_0, ContextEnableKernel));
+               if (!(dd->flags & QIB_NODMA_RTAIL)) {
+                       op |= QIB_RCVCTRL_TAILUPD_ENB; /* need reg write */
+                       dd->rcvctrl |= SYM_MASK(RcvCtrl, TailUpd);
+               }
+               /* Write these registers before the context is enabled. */
+               qib_write_kreg_ctxt(dd, krc_rcvhdrtailaddr, ctxt,
+                                   rcd->rcvhdrqtailaddr_phys);
+               qib_write_kreg_ctxt(dd, krc_rcvhdraddr, ctxt,
+                                   rcd->rcvhdrq_phys);
+               rcd->seq_cnt = 1;
+       }
+       if (op & QIB_RCVCTRL_CTXT_DIS)
+               ppd->p_rcvctrl &=
+                       ~(mask << SYM_LSB(RcvCtrl_0, ContextEnableKernel));
+       if (op & QIB_RCVCTRL_BP_ENB)
+               dd->rcvctrl |= mask << SYM_LSB(RcvCtrl, dontDropRHQFull);
+       if (op & QIB_RCVCTRL_BP_DIS)
+               dd->rcvctrl &= ~(mask << SYM_LSB(RcvCtrl, dontDropRHQFull));
+       if (op & QIB_RCVCTRL_INTRAVAIL_ENB)
+               dd->rcvctrl |= (mask << SYM_LSB(RcvCtrl, IntrAvail));
+       if (op & QIB_RCVCTRL_INTRAVAIL_DIS)
+               dd->rcvctrl &= ~(mask << SYM_LSB(RcvCtrl, IntrAvail));
+       /*
+        * Decide which registers to write depending on the ops enabled.
+        * Special case is "flush" (no bits set at all)
+        * which needs to write both.
+        */
+       if (op == 0 || (op & RCVCTRL_COMMON_MODS))
+               qib_write_kreg(dd, kr_rcvctrl, dd->rcvctrl);
+       if (op == 0 || (op & RCVCTRL_PORT_MODS))
+               qib_write_kreg_port(ppd, krp_rcvctrl, ppd->p_rcvctrl);
+       if ((op & QIB_RCVCTRL_CTXT_ENB) && dd->rcd[ctxt]) {
+               /*
+                * Init the context registers also; if we were
+                * disabled, tail and head should both be zero
+                * already from the enable, but since we don't
+                * know, we have to do it explictly.
+                */
+               val = qib_read_ureg32(dd, ur_rcvegrindextail, ctxt);
+               qib_write_ureg(dd, ur_rcvegrindexhead, val, ctxt);
+
+               /* be sure enabling write seen; hd/tl should be 0 */
+               (void) qib_read_kreg32(dd, kr_scratch);
+               val = qib_read_ureg32(dd, ur_rcvhdrtail, ctxt);
+               dd->rcd[ctxt]->head = val;
+               /* If kctxt, interrupt on next receive. */
+               if (ctxt < dd->first_user_ctxt)
+                       val |= dd->rhdrhead_intr_off;
+               qib_write_ureg(dd, ur_rcvhdrhead, val, ctxt);
+       } else if ((op & QIB_RCVCTRL_INTRAVAIL_ENB) &&
+               dd->rcd[ctxt] && dd->rhdrhead_intr_off) {
+               /* arm rcv interrupt */
+               val = dd->rcd[ctxt]->head | dd->rhdrhead_intr_off;
+               qib_write_ureg(dd, ur_rcvhdrhead, val, ctxt);
+       }
+       if (op & QIB_RCVCTRL_CTXT_DIS) {
+               unsigned f;
+
+               /* Now that the context is disabled, clear these registers. */
+               if (ctxt >= 0) {
+                       qib_write_kreg_ctxt(dd, krc_rcvhdrtailaddr, ctxt, 0);
+                       qib_write_kreg_ctxt(dd, krc_rcvhdraddr, ctxt, 0);
+                       for (f = 0; f < NUM_TIDFLOWS_CTXT; f++)
+                               qib_write_ureg(dd, ur_rcvflowtable + f,
+                                              TIDFLOW_ERRBITS, ctxt);
+               } else {
+                       unsigned i;
+
+                       for (i = 0; i < dd->cfgctxts; i++) {
+                               qib_write_kreg_ctxt(dd, krc_rcvhdrtailaddr,
+                                                   i, 0);
+                               qib_write_kreg_ctxt(dd, krc_rcvhdraddr, i, 0);
+                               for (f = 0; f < NUM_TIDFLOWS_CTXT; f++)
+                                       qib_write_ureg(dd, ur_rcvflowtable + f,
+                                                      TIDFLOW_ERRBITS, i);
+                       }
+               }
+       }
+       spin_unlock_irqrestore(&dd->cspec->rcvmod_lock, flags);
+}
+
+/*
+ * Modify the SENDCTRL register in chip-specific way. This
+ * is a function where there are multiple such registers with
+ * slightly different layouts.
+ * The chip doesn't allow back-to-back sendctrl writes, so write
+ * the scratch register after writing sendctrl.
+ *
+ * Which register is written depends on the operation.
+ * Most operate on the common register, while
+ * SEND_ENB and SEND_DIS operate on the per-port ones.
+ * SEND_ENB is included in common because it can change SPCL_TRIG
+ */
+#define SENDCTRL_COMMON_MODS (\
+       QIB_SENDCTRL_CLEAR | \
+       QIB_SENDCTRL_AVAIL_DIS | \
+       QIB_SENDCTRL_AVAIL_ENB | \
+       QIB_SENDCTRL_AVAIL_BLIP | \
+       QIB_SENDCTRL_DISARM | \
+       QIB_SENDCTRL_DISARM_ALL | \
+       QIB_SENDCTRL_SEND_ENB)
+
+#define SENDCTRL_PORT_MODS (\
+       QIB_SENDCTRL_CLEAR | \
+       QIB_SENDCTRL_SEND_ENB | \
+       QIB_SENDCTRL_SEND_DIS | \
+       QIB_SENDCTRL_FLUSH)
+
+static void sendctrl_7322_mod(struct qib_pportdata *ppd, u32 op)
+{
+       struct qib_devdata *dd = ppd->dd;
+       u64 tmp_dd_sendctrl;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dd->sendctrl_lock, flags);
+
+       /* First the dd ones that are "sticky", saved in shadow */
+       if (op & QIB_SENDCTRL_CLEAR)
+               dd->sendctrl = 0;
+       if (op & QIB_SENDCTRL_AVAIL_DIS)
+               dd->sendctrl &= ~SYM_MASK(SendCtrl, SendBufAvailUpd);
+       else if (op & QIB_SENDCTRL_AVAIL_ENB) {
+               dd->sendctrl |= SYM_MASK(SendCtrl, SendBufAvailUpd);
+               if (dd->flags & QIB_USE_SPCL_TRIG)
+                       dd->sendctrl |= SYM_MASK(SendCtrl, SpecialTriggerEn);
+       }
+
+       /* Then the ppd ones that are "sticky", saved in shadow */
+       if (op & QIB_SENDCTRL_SEND_DIS)
+               ppd->p_sendctrl &= ~SYM_MASK(SendCtrl_0, SendEnable);
+       else if (op & QIB_SENDCTRL_SEND_ENB)
+               ppd->p_sendctrl |= SYM_MASK(SendCtrl_0, SendEnable);
+
+       if (op & QIB_SENDCTRL_DISARM_ALL) {
+               u32 i, last;
+
+               tmp_dd_sendctrl = dd->sendctrl;
+               last = dd->piobcnt2k + dd->piobcnt4k + NUM_VL15_BUFS;
+               /*
+                * Disarm any buffers that are not yet launched,
+                * disabling updates until done.
+                */
+               tmp_dd_sendctrl &= ~SYM_MASK(SendCtrl, SendBufAvailUpd);
+               for (i = 0; i < last; i++) {
+                       qib_write_kreg(dd, kr_sendctrl,
+                                      tmp_dd_sendctrl |
+                                      SYM_MASK(SendCtrl, Disarm) | i);
+                       qib_write_kreg(dd, kr_scratch, 0);
+               }
+       }
+
+       if (op & QIB_SENDCTRL_FLUSH) {
+               u64 tmp_ppd_sendctrl = ppd->p_sendctrl;
+
+               /*
+                * Now drain all the fifos.  The Abort bit should never be
+                * needed, so for now, at least, we don't use it.
+                */
+               tmp_ppd_sendctrl |=
+                       SYM_MASK(SendCtrl_0, TxeDrainRmFifo) |
+                       SYM_MASK(SendCtrl_0, TxeDrainLaFifo) |
+                       SYM_MASK(SendCtrl_0, TxeBypassIbc);
+               qib_write_kreg_port(ppd, krp_sendctrl, tmp_ppd_sendctrl);
+               qib_write_kreg(dd, kr_scratch, 0);
+       }
+
+       tmp_dd_sendctrl = dd->sendctrl;
+
+       if (op & QIB_SENDCTRL_DISARM)
+               tmp_dd_sendctrl |= SYM_MASK(SendCtrl, Disarm) |
+                       ((op & QIB_7322_SendCtrl_DisarmSendBuf_RMASK) <<
+                        SYM_LSB(SendCtrl, DisarmSendBuf));
+       if ((op & QIB_SENDCTRL_AVAIL_BLIP) &&
+           (dd->sendctrl & SYM_MASK(SendCtrl, SendBufAvailUpd)))
+               tmp_dd_sendctrl &= ~SYM_MASK(SendCtrl, SendBufAvailUpd);
+
+       if (op == 0 || (op & SENDCTRL_COMMON_MODS)) {
+               qib_write_kreg(dd, kr_sendctrl, tmp_dd_sendctrl);
+               qib_write_kreg(dd, kr_scratch, 0);
+       }
+
+       if (op == 0 || (op & SENDCTRL_PORT_MODS)) {
+               qib_write_kreg_port(ppd, krp_sendctrl, ppd->p_sendctrl);
+               qib_write_kreg(dd, kr_scratch, 0);
+       }
+
+       if (op & QIB_SENDCTRL_AVAIL_BLIP) {
+               qib_write_kreg(dd, kr_sendctrl, dd->sendctrl);
+               qib_write_kreg(dd, kr_scratch, 0);
+       }
+
+       spin_unlock_irqrestore(&dd->sendctrl_lock, flags);
+
+       if (op & QIB_SENDCTRL_FLUSH) {
+               u32 v;
+               /*
+                * ensure writes have hit chip, then do a few
+                * more reads, to allow DMA of pioavail registers
+                * to occur, so in-memory copy is in sync with
+                * the chip.  Not always safe to sleep.
+                */
+               v = qib_read_kreg32(dd, kr_scratch);
+               qib_write_kreg(dd, kr_scratch, v);
+               v = qib_read_kreg32(dd, kr_scratch);
+               qib_write_kreg(dd, kr_scratch, v);
+               qib_read_kreg32(dd, kr_scratch);
+       }
+}
+
+#define _PORT_VIRT_FLAG 0x8000U /* "virtual", need adjustments */
+#define _PORT_64BIT_FLAG 0x10000U /* not "virtual", but 64bit */
+#define _PORT_CNTR_IDXMASK 0x7fffU /* mask off flags above */
+
+/**
+ * qib_portcntr_7322 - read a per-port chip counter
+ * @ppd: the qlogic_ib pport
+ * @creg: the counter to read (not a chip offset)
+ */
+static u64 qib_portcntr_7322(struct qib_pportdata *ppd, u32 reg)
+{
+       struct qib_devdata *dd = ppd->dd;
+       u64 ret = 0ULL;
+       u16 creg;
+       /* 0xffff for unimplemented or synthesized counters */
+       static const u32 xlator[] = {
+               [QIBPORTCNTR_PKTSEND] = crp_pktsend | _PORT_64BIT_FLAG,
+               [QIBPORTCNTR_WORDSEND] = crp_wordsend | _PORT_64BIT_FLAG,
+               [QIBPORTCNTR_PSXMITDATA] = crp_psxmitdatacount,
+               [QIBPORTCNTR_PSXMITPKTS] = crp_psxmitpktscount,
+               [QIBPORTCNTR_PSXMITWAIT] = crp_psxmitwaitcount,
+               [QIBPORTCNTR_SENDSTALL] = crp_sendstall,
+               [QIBPORTCNTR_PKTRCV] = crp_pktrcv | _PORT_64BIT_FLAG,
+               [QIBPORTCNTR_PSRCVDATA] = crp_psrcvdatacount,
+               [QIBPORTCNTR_PSRCVPKTS] = crp_psrcvpktscount,
+               [QIBPORTCNTR_RCVEBP] = crp_rcvebp,
+               [QIBPORTCNTR_RCVOVFL] = crp_rcvovfl,
+               [QIBPORTCNTR_WORDRCV] = crp_wordrcv | _PORT_64BIT_FLAG,
+               [QIBPORTCNTR_RXDROPPKT] = 0xffff, /* not needed  for 7322 */
+               [QIBPORTCNTR_RXLOCALPHYERR] = crp_rxotherlocalphyerr,
+               [QIBPORTCNTR_RXVLERR] = crp_rxvlerr,
+               [QIBPORTCNTR_ERRICRC] = crp_erricrc,
+               [QIBPORTCNTR_ERRVCRC] = crp_errvcrc,
+               [QIBPORTCNTR_ERRLPCRC] = crp_errlpcrc,
+               [QIBPORTCNTR_BADFORMAT] = crp_badformat,
+               [QIBPORTCNTR_ERR_RLEN] = crp_err_rlen,
+               [QIBPORTCNTR_IBSYMBOLERR] = crp_ibsymbolerr,
+               [QIBPORTCNTR_INVALIDRLEN] = crp_invalidrlen,
+               [QIBPORTCNTR_UNSUPVL] = crp_txunsupvl,
+               [QIBPORTCNTR_EXCESSBUFOVFL] = crp_excessbufferovfl,
+               [QIBPORTCNTR_ERRLINK] = crp_errlink,
+               [QIBPORTCNTR_IBLINKDOWN] = crp_iblinkdown,
+               [QIBPORTCNTR_IBLINKERRRECOV] = crp_iblinkerrrecov,
+               [QIBPORTCNTR_LLI] = crp_locallinkintegrityerr,
+               [QIBPORTCNTR_VL15PKTDROP] = crp_vl15droppedpkt,
+               [QIBPORTCNTR_ERRPKEY] = crp_errpkey,
+               /*
+                * the next 3 aren't really counters, but were implemented
+                * as counters in older chips, so still get accessed as
+                * though they were counters from this code.
+                */
+               [QIBPORTCNTR_PSINTERVAL] = krp_psinterval,
+               [QIBPORTCNTR_PSSTART] = krp_psstart,
+               [QIBPORTCNTR_PSSTAT] = krp_psstat,
+               /* pseudo-counter, summed for all ports */
+               [QIBPORTCNTR_KHDROVFL] = 0xffff,
+       };
+
+       if (reg >= ARRAY_SIZE(xlator)) {
+               qib_devinfo(ppd->dd->pcidev,
+                        "Unimplemented portcounter %u\n", reg);
+               goto done;
+       }
+       creg = xlator[reg] & _PORT_CNTR_IDXMASK;
+
+       /* handle non-counters and special cases first */
+       if (reg == QIBPORTCNTR_KHDROVFL) {
+               int i;
+
+               /* sum over all kernel contexts (skip if mini_init) */
+               for (i = 0; dd->rcd && i < dd->first_user_ctxt; i++) {
+                       struct qib_ctxtdata *rcd = dd->rcd[i];
+
+                       if (!rcd || rcd->ppd != ppd)
+                               continue;
+                       ret += read_7322_creg32(dd, cr_base_egrovfl + i);
+               }
+               goto done;
+       } else if (reg == QIBPORTCNTR_RXDROPPKT) {
+               /*
+                * Used as part of the synthesis of port_rcv_errors
+                * in the verbs code for IBTA counters.  Not needed for 7322,
+                * because all the errors are already counted by other cntrs.
+                */
+               goto done;
+       } else if (reg == QIBPORTCNTR_PSINTERVAL ||
+                  reg == QIBPORTCNTR_PSSTART || reg == QIBPORTCNTR_PSSTAT) {
+               /* were counters in older chips, now per-port kernel regs */
+               ret = qib_read_kreg_port(ppd, creg);
+               goto done;
+       }
+
+       /*
+        * Only fast increment counters are 64 bits; use 32 bit reads to
+        * avoid two independent reads when on Opteron.
+        */
+       if (xlator[reg] & _PORT_64BIT_FLAG)
+               ret = read_7322_creg_port(ppd, creg);
+       else
+               ret = read_7322_creg32_port(ppd, creg);
+       if (creg == crp_ibsymbolerr) {
+               if (ppd->cpspec->ibdeltainprog)
+                       ret -= ret - ppd->cpspec->ibsymsnap;
+               ret -= ppd->cpspec->ibsymdelta;
+       } else if (creg == crp_iblinkerrrecov) {
+               if (ppd->cpspec->ibdeltainprog)
+                       ret -= ret - ppd->cpspec->iblnkerrsnap;
+               ret -= ppd->cpspec->iblnkerrdelta;
+       } else if (creg == crp_errlink)
+               ret -= ppd->cpspec->ibmalfdelta;
+       else if (creg == crp_iblinkdown)
+               ret += ppd->cpspec->iblnkdowndelta;
+done:
+       return ret;
+}
+
+/*
+ * Device counter names (not port-specific), one line per stat,
+ * single string.  Used by utilities like ipathstats to print the stats
+ * in a way which works for different versions of drivers, without changing
+ * the utility.  Names need to be 12 chars or less (w/o newline), for proper
+ * display by utility.
+ * Non-error counters are first.
+ * Start of "error" conters is indicated by a leading "E " on the first
+ * "error" counter, and doesn't count in label length.
+ * The EgrOvfl list needs to be last so we truncate them at the configured
+ * context count for the device.
+ * cntr7322indices contains the corresponding register indices.
+ */
+static const char cntr7322names[] =
+       "Interrupts\n"
+       "HostBusStall\n"
+       "E RxTIDFull\n"
+       "RxTIDInvalid\n"
+       "RxTIDFloDrop\n" /* 7322 only */
+       "Ctxt0EgrOvfl\n"
+       "Ctxt1EgrOvfl\n"
+       "Ctxt2EgrOvfl\n"
+       "Ctxt3EgrOvfl\n"
+       "Ctxt4EgrOvfl\n"
+       "Ctxt5EgrOvfl\n"
+       "Ctxt6EgrOvfl\n"
+       "Ctxt7EgrOvfl\n"
+       "Ctxt8EgrOvfl\n"
+       "Ctxt9EgrOvfl\n"
+       "Ctx10EgrOvfl\n"
+       "Ctx11EgrOvfl\n"
+       "Ctx12EgrOvfl\n"
+       "Ctx13EgrOvfl\n"
+       "Ctx14EgrOvfl\n"
+       "Ctx15EgrOvfl\n"
+       "Ctx16EgrOvfl\n"
+       "Ctx17EgrOvfl\n"
+       ;
+
+static const u32 cntr7322indices[] = {
+       cr_lbint | _PORT_64BIT_FLAG,
+       cr_lbstall | _PORT_64BIT_FLAG,
+       cr_tidfull,
+       cr_tidinvalid,
+       cr_rxtidflowdrop,
+       cr_base_egrovfl + 0,
+       cr_base_egrovfl + 1,
+       cr_base_egrovfl + 2,
+       cr_base_egrovfl + 3,
+       cr_base_egrovfl + 4,
+       cr_base_egrovfl + 5,
+       cr_base_egrovfl + 6,
+       cr_base_egrovfl + 7,
+       cr_base_egrovfl + 8,
+       cr_base_egrovfl + 9,
+       cr_base_egrovfl + 10,
+       cr_base_egrovfl + 11,
+       cr_base_egrovfl + 12,
+       cr_base_egrovfl + 13,
+       cr_base_egrovfl + 14,
+       cr_base_egrovfl + 15,
+       cr_base_egrovfl + 16,
+       cr_base_egrovfl + 17,
+};
+
+/*
+ * same as cntr7322names and cntr7322indices, but for port-specific counters.
+ * portcntr7322indices is somewhat complicated by some registers needing
+ * adjustments of various kinds, and those are ORed with _PORT_VIRT_FLAG
+ */
+static const char portcntr7322names[] =
+       "TxPkt\n"
+       "TxFlowPkt\n"
+       "TxWords\n"
+       "RxPkt\n"
+       "RxFlowPkt\n"
+       "RxWords\n"
+       "TxFlowStall\n"
+       "TxDmaDesc\n"  /* 7220 and 7322-only */
+       "E RxDlidFltr\n"  /* 7220 and 7322-only */
+       "IBStatusChng\n"
+       "IBLinkDown\n"
+       "IBLnkRecov\n"
+       "IBRxLinkErr\n"
+       "IBSymbolErr\n"
+       "RxLLIErr\n"
+       "RxBadFormat\n"
+       "RxBadLen\n"
+       "RxBufOvrfl\n"
+       "RxEBP\n"
+       "RxFlowCtlErr\n"
+       "RxICRCerr\n"
+       "RxLPCRCerr\n"
+       "RxVCRCerr\n"
+       "RxInvalLen\n"
+       "RxInvalPKey\n"
+       "RxPktDropped\n"
+       "TxBadLength\n"
+       "TxDropped\n"
+       "TxInvalLen\n"
+       "TxUnderrun\n"
+       "TxUnsupVL\n"
+       "RxLclPhyErr\n" /* 7220 and 7322-only from here down */
+       "RxVL15Drop\n"
+       "RxVlErr\n"
+       "XcessBufOvfl\n"
+       "RxQPBadCtxt\n" /* 7322-only from here down */
+       "TXBadHeader\n"
+       ;
+
+static const u32 portcntr7322indices[] = {
+       QIBPORTCNTR_PKTSEND | _PORT_VIRT_FLAG,
+       crp_pktsendflow,
+       QIBPORTCNTR_WORDSEND | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_PKTRCV | _PORT_VIRT_FLAG,
+       crp_pktrcvflowctrl,
+       QIBPORTCNTR_WORDRCV | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_SENDSTALL | _PORT_VIRT_FLAG,
+       crp_txsdmadesc | _PORT_64BIT_FLAG,
+       crp_rxdlidfltr,
+       crp_ibstatuschange,
+       QIBPORTCNTR_IBLINKDOWN | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_IBLINKERRRECOV | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_ERRLINK | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_IBSYMBOLERR | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_LLI | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_BADFORMAT | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_ERR_RLEN | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_RCVOVFL | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_RCVEBP | _PORT_VIRT_FLAG,
+       crp_rcvflowctrlviol,
+       QIBPORTCNTR_ERRICRC | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_ERRLPCRC | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_ERRVCRC | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_INVALIDRLEN | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_ERRPKEY | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_RXDROPPKT | _PORT_VIRT_FLAG,
+       crp_txminmaxlenerr,
+       crp_txdroppedpkt,
+       crp_txlenerr,
+       crp_txunderrun,
+       crp_txunsupvl,
+       QIBPORTCNTR_RXLOCALPHYERR | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_VL15PKTDROP | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_RXVLERR | _PORT_VIRT_FLAG,
+       QIBPORTCNTR_EXCESSBUFOVFL | _PORT_VIRT_FLAG,
+       crp_rxqpinvalidctxt,
+       crp_txhdrerr,
+};
+
+/* do all the setup to make the counter reads efficient later */
+static void init_7322_cntrnames(struct qib_devdata *dd)
+{
+       int i, j = 0;
+       char *s;
+
+       for (i = 0, s = (char *)cntr7322names; s && j <= dd->cfgctxts;
+            i++) {
+               /* we always have at least one counter before the egrovfl */
+               if (!j && !strncmp("Ctxt0EgrOvfl", s + 1, 12))
+                       j = 1;
+               s = strchr(s + 1, '\n');
+               if (s && j)
+                       j++;
+       }
+       dd->cspec->ncntrs = i;
+       if (!s)
+               /* full list; size is without terminating null */
+               dd->cspec->cntrnamelen = sizeof(cntr7322names) - 1;
+       else
+               dd->cspec->cntrnamelen = 1 + s - cntr7322names;
+       dd->cspec->cntrs = kmalloc(dd->cspec->ncntrs
+               * sizeof(u64), GFP_KERNEL);
+       if (!dd->cspec->cntrs)
+               qib_dev_err(dd, "Failed allocation for counters\n");
+
+       for (i = 0, s = (char *)portcntr7322names; s; i++)
+               s = strchr(s + 1, '\n');
+       dd->cspec->nportcntrs = i - 1;
+       dd->cspec->portcntrnamelen = sizeof(portcntr7322names) - 1;
+       for (i = 0; i < dd->num_pports; ++i) {
+               dd->pport[i].cpspec->portcntrs = kmalloc(dd->cspec->nportcntrs
+                       * sizeof(u64), GFP_KERNEL);
+               if (!dd->pport[i].cpspec->portcntrs)
+                       qib_dev_err(dd, "Failed allocation for"
+                                   " portcounters\n");
+       }
+}
+
+static u32 qib_read_7322cntrs(struct qib_devdata *dd, loff_t pos, char **namep,
+                             u64 **cntrp)
+{
+       u32 ret;
+
+       if (namep) {
+               ret = dd->cspec->cntrnamelen;
+               if (pos >= ret)
+                       ret = 0; /* final read after getting everything */
+               else
+                       *namep = (char *) cntr7322names;
+       } else {
+               u64 *cntr = dd->cspec->cntrs;
+               int i;
+
+               ret = dd->cspec->ncntrs * sizeof(u64);
+               if (!cntr || pos >= ret) {
+                       /* everything read, or couldn't get memory */
+                       ret = 0;
+                       goto done;
+               }
+               *cntrp = cntr;
+               for (i = 0; i < dd->cspec->ncntrs; i++)
+                       if (cntr7322indices[i] & _PORT_64BIT_FLAG)
+                               *cntr++ = read_7322_creg(dd,
+                                                        cntr7322indices[i] &
+                                                        _PORT_CNTR_IDXMASK);
+                       else
+                               *cntr++ = read_7322_creg32(dd,
+                                                          cntr7322indices[i]);
+       }
+done:
+       return ret;
+}
+
+static u32 qib_read_7322portcntrs(struct qib_devdata *dd, loff_t pos, u32 port,
+                                 char **namep, u64 **cntrp)
+{
+       u32 ret;
+
+       if (namep) {
+               ret = dd->cspec->portcntrnamelen;
+               if (pos >= ret)
+                       ret = 0; /* final read after getting everything */
+               else
+                       *namep = (char *)portcntr7322names;
+       } else {
+               struct qib_pportdata *ppd = &dd->pport[port];
+               u64 *cntr = ppd->cpspec->portcntrs;
+               int i;
+
+               ret = dd->cspec->nportcntrs * sizeof(u64);
+               if (!cntr || pos >= ret) {
+                       /* everything read, or couldn't get memory */
+                       ret = 0;
+                       goto done;
+               }
+               *cntrp = cntr;
+               for (i = 0; i < dd->cspec->nportcntrs; i++) {
+                       if (portcntr7322indices[i] & _PORT_VIRT_FLAG)
+                               *cntr++ = qib_portcntr_7322(ppd,
+                                       portcntr7322indices[i] &
+                                       _PORT_CNTR_IDXMASK);
+                       else if (portcntr7322indices[i] & _PORT_64BIT_FLAG)
+                               *cntr++ = read_7322_creg_port(ppd,
+                                          portcntr7322indices[i] &
+                                           _PORT_CNTR_IDXMASK);
+                       else
+                               *cntr++ = read_7322_creg32_port(ppd,
+                                          portcntr7322indices[i]);
+               }
+       }
+done:
+       return ret;
+}
+
+/**
+ * qib_get_7322_faststats - get word counters from chip before they overflow
+ * @opaque - contains a pointer to the qlogic_ib device qib_devdata
+ *
+ * VESTIGIAL IBA7322 has no "small fast counters", so the only
+ * real purpose of this function is to maintain the notion of
+ * "active time", which in turn is only logged into the eeprom,
+ * which we don;t have, yet, for 7322-based boards.
+ *
+ * called from add_timer
+ */
+static void qib_get_7322_faststats(unsigned long opaque)
+{
+       struct qib_devdata *dd = (struct qib_devdata *) opaque;
+       struct qib_pportdata *ppd;
+       unsigned long flags;
+       u64 traffic_wds;
+       int pidx;
+
+       for (pidx = 0; pidx < dd->num_pports; ++pidx) {
+               ppd = dd->pport + pidx;
+
+               /*
+                * If port isn't enabled or not operational ports, or
+                * diags is running (can cause memory diags to fail)
+                * skip this port this time.
+                */
+               if (!ppd->link_speed_supported || !(dd->flags & QIB_INITTED)
+                   || dd->diag_client)
+                       continue;
+
+               /*
+                * Maintain an activity timer, based on traffic
+                * exceeding a threshold, so we need to check the word-counts
+                * even if they are 64-bit.
+                */
+               traffic_wds = qib_portcntr_7322(ppd, QIBPORTCNTR_WORDRCV) +
+                       qib_portcntr_7322(ppd, QIBPORTCNTR_WORDSEND);
+               spin_lock_irqsave(&ppd->dd->eep_st_lock, flags);
+               traffic_wds -= ppd->dd->traffic_wds;
+               ppd->dd->traffic_wds += traffic_wds;
+               if (traffic_wds >= QIB_TRAFFIC_ACTIVE_THRESHOLD)
+                       atomic_add(ACTIVITY_TIMER, &ppd->dd->active_time);
+               spin_unlock_irqrestore(&ppd->dd->eep_st_lock, flags);
+               if (ppd->cpspec->qdr_dfe_on && (ppd->link_speed_active &
+                                               QIB_IB_QDR) &&
+                   (ppd->lflags & (QIBL_LINKINIT | QIBL_LINKARMED |
+                                   QIBL_LINKACTIVE)) &&
+                   ppd->cpspec->qdr_dfe_time &&
+                   time_after64(get_jiffies_64(), ppd->cpspec->qdr_dfe_time)) {
+                       ppd->cpspec->qdr_dfe_on = 0;
+
+                       qib_write_kreg_port(ppd, krp_static_adapt_dis(2),
+                                           ppd->dd->cspec->r1 ?
+                                           QDR_STATIC_ADAPT_INIT_R1 :
+                                           QDR_STATIC_ADAPT_INIT);
+                       force_h1(ppd);
+               }
+       }
+       mod_timer(&dd->stats_timer, jiffies + HZ * ACTIVITY_TIMER);
+}
+
+/*
+ * If we were using MSIx, try to fallback to INTx.
+ */
+static int qib_7322_intr_fallback(struct qib_devdata *dd)
+{
+       if (!dd->cspec->num_msix_entries)
+               return 0; /* already using INTx */
+
+       qib_devinfo(dd->pcidev, "MSIx interrupt not detected,"
+                " trying INTx interrupts\n");
+       qib_7322_nomsix(dd);
+       qib_enable_intx(dd->pcidev);
+       qib_setup_7322_interrupt(dd, 0);
+       return 1;
+}
+
+/*
+ * Reset the XGXS (between serdes and IBC).  Slightly less intrusive
+ * than resetting the IBC or external link state, and useful in some
+ * cases to cause some retraining.  To do this right, we reset IBC
+ * as well, then return to previous state (which may be still in reset)
+ * NOTE: some callers of this "know" this writes the current value
+ * of cpspec->ibcctrl_a as part of it's operation, so if that changes,
+ * check all callers.
+ */
+static void qib_7322_mini_pcs_reset(struct qib_pportdata *ppd)
+{
+       u64 val;
+       struct qib_devdata *dd = ppd->dd;
+       const u64 reset_bits = SYM_MASK(IBPCSConfig_0, xcv_rreset) |
+               SYM_MASK(IBPCSConfig_0, xcv_treset) |
+               SYM_MASK(IBPCSConfig_0, tx_rx_reset);
+
+       val = qib_read_kreg_port(ppd, krp_ib_pcsconfig);
+       qib_write_kreg_port(ppd, krp_ibcctrl_a,
+                           ppd->cpspec->ibcctrl_a &
+                           ~SYM_MASK(IBCCtrlA_0, IBLinkEn));
+
+       qib_write_kreg_port(ppd, krp_ib_pcsconfig, val | reset_bits);
+       qib_read_kreg32(dd, kr_scratch);
+       qib_write_kreg_port(ppd, krp_ib_pcsconfig, val & ~reset_bits);
+       qib_write_kreg_port(ppd, krp_ibcctrl_a, ppd->cpspec->ibcctrl_a);
+       qib_write_kreg(dd, kr_scratch, 0ULL);
+}
+
+/*
+ * This code for non-IBTA-compliant IB speed negotiation is only known to
+ * work for the SDR to DDR transition, and only between an HCA and a switch
+ * with recent firmware.  It is based on observed heuristics, rather than
+ * actual knowledge of the non-compliant speed negotiation.
+ * It has a number of hard-coded fields, since the hope is to rewrite this
+ * when a spec is available on how the negoation is intended to work.
+ */
+static void autoneg_7322_sendpkt(struct qib_pportdata *ppd, u32 *hdr,
+                                u32 dcnt, u32 *data)
+{
+       int i;
+       u64 pbc;
+       u32 __iomem *piobuf;
+       u32 pnum, control, len;
+       struct qib_devdata *dd = ppd->dd;
+
+       i = 0;
+       len = 7 + dcnt + 1; /* 7 dword header, dword data, icrc */
+       control = qib_7322_setpbc_control(ppd, len, 0, 15);
+       pbc = ((u64) control << 32) | len;
+       while (!(piobuf = qib_7322_getsendbuf(ppd, pbc, &pnum))) {
+               if (i++ > 15)
+                       return;
+               udelay(2);
+       }
+       /* disable header check on this packet, since it can't be valid */
+       dd->f_txchk_change(dd, pnum, 1, TXCHK_CHG_TYPE_DIS1, NULL);
+       writeq(pbc, piobuf);
+       qib_flush_wc();
+       qib_pio_copy(piobuf + 2, hdr, 7);
+       qib_pio_copy(piobuf + 9, data, dcnt);
+       if (dd->flags & QIB_USE_SPCL_TRIG) {
+               u32 spcl_off = (pnum >= dd->piobcnt2k) ? 2047 : 1023;
+
+               qib_flush_wc();
+               __raw_writel(0xaebecede, piobuf + spcl_off);
+       }
+       qib_flush_wc();
+       qib_sendbuf_done(dd, pnum);
+       /* and re-enable hdr check */
+       dd->f_txchk_change(dd, pnum, 1, TXCHK_CHG_TYPE_ENAB1, NULL);
+}
+
+/*
+ * _start packet gets sent twice at start, _done gets sent twice at end
+ */
+static void qib_autoneg_7322_send(struct qib_pportdata *ppd, int which)
+{
+       struct qib_devdata *dd = ppd->dd;
+       static u32 swapped;
+       u32 dw, i, hcnt, dcnt, *data;
+       static u32 hdr[7] = { 0xf002ffff, 0x48ffff, 0x6400abba };
+       static u32 madpayload_start[0x40] = {
+               0x1810103, 0x1, 0x0, 0x0, 0x2c90000, 0x2c9, 0x0, 0x0,
+               0xffffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+               0x1, 0x1388, 0x15e, 0x1, /* rest 0's */
+               };
+       static u32 madpayload_done[0x40] = {
+               0x1810103, 0x1, 0x0, 0x0, 0x2c90000, 0x2c9, 0x0, 0x0,
+               0xffffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+               0x40000001, 0x1388, 0x15e, /* rest 0's */
+               };
+
+       dcnt = ARRAY_SIZE(madpayload_start);
+       hcnt = ARRAY_SIZE(hdr);
+       if (!swapped) {
+               /* for maintainability, do it at runtime */
+               for (i = 0; i < hcnt; i++) {
+                       dw = (__force u32) cpu_to_be32(hdr[i]);
+                       hdr[i] = dw;
+               }
+               for (i = 0; i < dcnt; i++) {
+                       dw = (__force u32) cpu_to_be32(madpayload_start[i]);
+                       madpayload_start[i] = dw;
+                       dw = (__force u32) cpu_to_be32(madpayload_done[i]);
+                       madpayload_done[i] = dw;
+               }
+               swapped = 1;
+       }
+
+       data = which ? madpayload_done : madpayload_start;
+
+       autoneg_7322_sendpkt(ppd, hdr, dcnt, data);
+       qib_read_kreg64(dd, kr_scratch);
+       udelay(2);
+       autoneg_7322_sendpkt(ppd, hdr, dcnt, data);
+       qib_read_kreg64(dd, kr_scratch);
+       udelay(2);
+}
+
+/*
+ * Do the absolute minimum to cause an IB speed change, and make it
+ * ready, but don't actually trigger the change.   The caller will
+ * do that when ready (if link is in Polling training state, it will
+ * happen immediately, otherwise when link next goes down)
+ *
+ * This routine should only be used as part of the DDR autonegotation
+ * code for devices that are not compliant with IB 1.2 (or code that
+ * fixes things up for same).
+ *
+ * When link has gone down, and autoneg enabled, or autoneg has
+ * failed and we give up until next time we set both speeds, and
+ * then we want IBTA enabled as well as "use max enabled speed.
+ */
+static void set_7322_ibspeed_fast(struct qib_pportdata *ppd, u32 speed)
+{
+       u64 newctrlb;
+       newctrlb = ppd->cpspec->ibcctrl_b & ~(IBA7322_IBC_SPEED_MASK |
+                                   IBA7322_IBC_IBTA_1_2_MASK |
+                                   IBA7322_IBC_MAX_SPEED_MASK);
+
+       if (speed & (speed - 1)) /* multiple speeds */
+               newctrlb |= (speed << IBA7322_IBC_SPEED_LSB) |
+                                   IBA7322_IBC_IBTA_1_2_MASK |
+                                   IBA7322_IBC_MAX_SPEED_MASK;
+       else
+               newctrlb |= speed == QIB_IB_QDR ?
+                       IBA7322_IBC_SPEED_QDR | IBA7322_IBC_IBTA_1_2_MASK :
+                       ((speed == QIB_IB_DDR ?
+                         IBA7322_IBC_SPEED_DDR : IBA7322_IBC_SPEED_SDR));
+
+       if (newctrlb == ppd->cpspec->ibcctrl_b)
+               return;
+
+       ppd->cpspec->ibcctrl_b = newctrlb;
+       qib_write_kreg_port(ppd, krp_ibcctrl_b, ppd->cpspec->ibcctrl_b);
+       qib_write_kreg(ppd->dd, kr_scratch, 0);
+}
+
+/*
+ * This routine is only used when we are not talking to another
+ * IB 1.2-compliant device that we think can do DDR.
+ * (This includes all existing switch chips as of Oct 2007.)
+ * 1.2-compliant devices go directly to DDR prior to reaching INIT
+ */
+static void try_7322_autoneg(struct qib_pportdata *ppd)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ppd->lflags_lock, flags);
+       ppd->lflags |= QIBL_IB_AUTONEG_INPROG;
+       spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+       qib_autoneg_7322_send(ppd, 0);
+       set_7322_ibspeed_fast(ppd, QIB_IB_DDR);
+       qib_7322_mini_pcs_reset(ppd);
+       /* 2 msec is minimum length of a poll cycle */
+       schedule_delayed_work(&ppd->cpspec->autoneg_work,
+                             msecs_to_jiffies(2));
+}
+
+/*
+ * Handle the empirically determined mechanism for auto-negotiation
+ * of DDR speed with switches.
+ */
+static void autoneg_7322_work(struct work_struct *work)
+{
+       struct qib_pportdata *ppd;
+       struct qib_devdata *dd;
+       u64 startms;
+       u32 i;
+       unsigned long flags;
+
+       ppd = container_of(work, struct qib_chippport_specific,
+                           autoneg_work.work)->ppd;
+       dd = ppd->dd;
+
+       startms = jiffies_to_msecs(jiffies);
+
+       /*
+        * Busy wait for this first part, it should be at most a
+        * few hundred usec, since we scheduled ourselves for 2msec.
+        */
+       for (i = 0; i < 25; i++) {
+               if (SYM_FIELD(ppd->lastibcstat, IBCStatusA_0, LinkState)
+                    == IB_7322_LT_STATE_POLLQUIET) {
+                       qib_set_linkstate(ppd, QIB_IB_LINKDOWN_DISABLE);
+                       break;
+               }
+               udelay(100);
+       }
+
+       if (!(ppd->lflags & QIBL_IB_AUTONEG_INPROG))
+               goto done; /* we got there early or told to stop */
+
+       /* we expect this to timeout */
+       if (wait_event_timeout(ppd->cpspec->autoneg_wait,
+                              !(ppd->lflags & QIBL_IB_AUTONEG_INPROG),
+                              msecs_to_jiffies(90)))
+               goto done;
+       qib_7322_mini_pcs_reset(ppd);
+
+       /* we expect this to timeout */
+       if (wait_event_timeout(ppd->cpspec->autoneg_wait,
+                              !(ppd->lflags & QIBL_IB_AUTONEG_INPROG),
+                              msecs_to_jiffies(1700)))
+               goto done;
+       qib_7322_mini_pcs_reset(ppd);
+
+       set_7322_ibspeed_fast(ppd, QIB_IB_SDR);
+
+       /*
+        * Wait up to 250 msec for link to train and get to INIT at DDR;
+        * this should terminate early.
+        */
+       wait_event_timeout(ppd->cpspec->autoneg_wait,
+               !(ppd->lflags & QIBL_IB_AUTONEG_INPROG),
+               msecs_to_jiffies(250));
+done:
+       if (ppd->lflags & QIBL_IB_AUTONEG_INPROG) {
+               spin_lock_irqsave(&ppd->lflags_lock, flags);
+               ppd->lflags &= ~QIBL_IB_AUTONEG_INPROG;
+               if (ppd->cpspec->autoneg_tries == AUTONEG_TRIES) {
+                       ppd->lflags |= QIBL_IB_AUTONEG_FAILED;
+                       ppd->cpspec->autoneg_tries = 0;
+               }
+               spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+               set_7322_ibspeed_fast(ppd, ppd->link_speed_enabled);
+       }
+}
+
+/*
+ * This routine is used to request IPG set in the QLogic switch.
+ * Only called if r1.
+ */
+static void try_7322_ipg(struct qib_pportdata *ppd)
+{
+       struct qib_ibport *ibp = &ppd->ibport_data;
+       struct ib_mad_send_buf *send_buf;
+       struct ib_mad_agent *agent;
+       struct ib_smp *smp;
+       unsigned delay;
+       int ret;
+
+       agent = ibp->send_agent;
+       if (!agent)
+               goto retry;
+
+       send_buf = ib_create_send_mad(agent, 0, 0, 0, IB_MGMT_MAD_HDR,
+                                     IB_MGMT_MAD_DATA, GFP_ATOMIC);
+       if (IS_ERR(send_buf))
+               goto retry;
+
+       if (!ibp->smi_ah) {
+               struct ib_ah_attr attr;
+               struct ib_ah *ah;
+
+               memset(&attr, 0, sizeof attr);
+               attr.dlid = be16_to_cpu(IB_LID_PERMISSIVE);
+               attr.port_num = ppd->port;
+               ah = ib_create_ah(ibp->qp0->ibqp.pd, &attr);
+               if (IS_ERR(ah))
+                       ret = -EINVAL;
+               else {
+                       send_buf->ah = ah;
+                       ibp->smi_ah = to_iah(ah);
+                       ret = 0;
+               }
+       } else {
+               send_buf->ah = &ibp->smi_ah->ibah;
+               ret = 0;
+       }
+
+       smp = send_buf->mad;
+       smp->base_version = IB_MGMT_BASE_VERSION;
+       smp->mgmt_class = IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE;
+       smp->class_version = 1;
+       smp->method = IB_MGMT_METHOD_SEND;
+       smp->hop_cnt = 1;
+       smp->attr_id = QIB_VENDOR_IPG;
+       smp->attr_mod = 0;
+
+       if (!ret)
+               ret = ib_post_send_mad(send_buf, NULL);
+       if (ret)
+               ib_free_send_mad(send_buf);
+retry:
+       delay = 2 << ppd->cpspec->ipg_tries;
+       schedule_delayed_work(&ppd->cpspec->ipg_work, msecs_to_jiffies(delay));
+}
+
+/*
+ * Timeout handler for setting IPG.
+ * Only called if r1.
+ */
+static void ipg_7322_work(struct work_struct *work)
+{
+       struct qib_pportdata *ppd;
+
+       ppd = container_of(work, struct qib_chippport_specific,
+                          ipg_work.work)->ppd;
+       if ((ppd->lflags & (QIBL_LINKINIT | QIBL_LINKARMED | QIBL_LINKACTIVE))
+           && ++ppd->cpspec->ipg_tries <= 10)
+               try_7322_ipg(ppd);
+}
+
+static u32 qib_7322_iblink_state(u64 ibcs)
+{
+       u32 state = (u32)SYM_FIELD(ibcs, IBCStatusA_0, LinkState);
+
+       switch (state) {
+       case IB_7322_L_STATE_INIT:
+               state = IB_PORT_INIT;
+               break;
+       case IB_7322_L_STATE_ARM:
+               state = IB_PORT_ARMED;
+               break;
+       case IB_7322_L_STATE_ACTIVE:
+               /* fall through */
+       case IB_7322_L_STATE_ACT_DEFER:
+               state = IB_PORT_ACTIVE;
+               break;
+       default: /* fall through */
+       case IB_7322_L_STATE_DOWN:
+               state = IB_PORT_DOWN;
+               break;
+       }
+       return state;
+}
+
+/* returns the IBTA port state, rather than the IBC link training state */
+static u8 qib_7322_phys_portstate(u64 ibcs)
+{
+       u8 state = (u8)SYM_FIELD(ibcs, IBCStatusA_0, LinkTrainingState);
+       return qib_7322_physportstate[state];
+}
+
+static int qib_7322_ib_updown(struct qib_pportdata *ppd, int ibup, u64 ibcs)
+{
+       int ret = 0, symadj = 0;
+       unsigned long flags;
+       int mult;
+
+       spin_lock_irqsave(&ppd->lflags_lock, flags);
+       ppd->lflags &= ~QIBL_IB_FORCE_NOTIFY;
+       spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+
+       /* Update our picture of width and speed from chip */
+       if (ibcs & SYM_MASK(IBCStatusA_0, LinkSpeedQDR)) {
+               ppd->link_speed_active = QIB_IB_QDR;
+               mult = 4;
+       } else if (ibcs & SYM_MASK(IBCStatusA_0, LinkSpeedActive)) {
+               ppd->link_speed_active = QIB_IB_DDR;
+               mult = 2;
+       } else {
+               ppd->link_speed_active = QIB_IB_SDR;
+               mult = 1;
+       }
+       if (ibcs & SYM_MASK(IBCStatusA_0, LinkWidthActive)) {
+               ppd->link_width_active = IB_WIDTH_4X;
+               mult *= 4;
+       } else
+               ppd->link_width_active = IB_WIDTH_1X;
+       ppd->delay_mult = ib_rate_to_delay[mult_to_ib_rate(mult)];
+
+       if (!ibup) {
+               u64 clr;
+
+               /* Link went down. */
+               /* do IPG MAD again after linkdown, even if last time failed */
+               ppd->cpspec->ipg_tries = 0;
+               clr = qib_read_kreg_port(ppd, krp_ibcstatus_b) &
+                       (SYM_MASK(IBCStatusB_0, heartbeat_timed_out) |
+                        SYM_MASK(IBCStatusB_0, heartbeat_crosstalk));
+               if (clr)
+                       qib_write_kreg_port(ppd, krp_ibcstatus_b, clr);
+               if (!(ppd->lflags & (QIBL_IB_AUTONEG_FAILED |
+                                    QIBL_IB_AUTONEG_INPROG)))
+                       set_7322_ibspeed_fast(ppd, ppd->link_speed_enabled);
+               if (!(ppd->lflags & QIBL_IB_AUTONEG_INPROG)) {
+                       /* unlock the Tx settings, speed may change */
+                       qib_write_kreg_port(ppd, krp_tx_deemph_override,
+                               SYM_MASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
+                               reset_tx_deemphasis_override));
+                       qib_cancel_sends(ppd);
+                       /* on link down, ensure sane pcs state */
+                       qib_7322_mini_pcs_reset(ppd);
+                       spin_lock_irqsave(&ppd->sdma_lock, flags);
+                       if (__qib_sdma_running(ppd))
+                               __qib_sdma_process_event(ppd,
+                                       qib_sdma_event_e70_go_idle);
+                       spin_unlock_irqrestore(&ppd->sdma_lock, flags);
+               }
+               clr = read_7322_creg32_port(ppd, crp_iblinkdown);
+               if (clr == ppd->cpspec->iblnkdownsnap)
+                       ppd->cpspec->iblnkdowndelta++;
+       } else {
+               if (qib_compat_ddr_negotiate &&
+                   !(ppd->lflags & (QIBL_IB_AUTONEG_FAILED |
+                                    QIBL_IB_AUTONEG_INPROG)) &&
+                   ppd->link_speed_active == QIB_IB_SDR &&
+                   (ppd->link_speed_enabled & QIB_IB_DDR)
+                   && ppd->cpspec->autoneg_tries < AUTONEG_TRIES) {
+                       /* we are SDR, and auto-negotiation enabled */
+                       ++ppd->cpspec->autoneg_tries;
+                       if (!ppd->cpspec->ibdeltainprog) {
+                               ppd->cpspec->ibdeltainprog = 1;
+                               ppd->cpspec->ibsymdelta +=
+                                       read_7322_creg32_port(ppd,
+                                               crp_ibsymbolerr) -
+                                               ppd->cpspec->ibsymsnap;
+                               ppd->cpspec->iblnkerrdelta +=
+                                       read_7322_creg32_port(ppd,
+                                               crp_iblinkerrrecov) -
+                                               ppd->cpspec->iblnkerrsnap;
+                       }
+                       try_7322_autoneg(ppd);
+                       ret = 1; /* no other IB status change processing */
+               } else if ((ppd->lflags & QIBL_IB_AUTONEG_INPROG) &&
+                          ppd->link_speed_active == QIB_IB_SDR) {
+                       qib_autoneg_7322_send(ppd, 1);
+                       set_7322_ibspeed_fast(ppd, QIB_IB_DDR);
+                       qib_7322_mini_pcs_reset(ppd);
+                       udelay(2);
+                       ret = 1; /* no other IB status change processing */
+               } else if ((ppd->lflags & QIBL_IB_AUTONEG_INPROG) &&
+                          (ppd->link_speed_active & QIB_IB_DDR)) {
+                       spin_lock_irqsave(&ppd->lflags_lock, flags);
+                       ppd->lflags &= ~(QIBL_IB_AUTONEG_INPROG |
+                                        QIBL_IB_AUTONEG_FAILED);
+                       spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+                       ppd->cpspec->autoneg_tries = 0;
+                       /* re-enable SDR, for next link down */
+                       set_7322_ibspeed_fast(ppd, ppd->link_speed_enabled);
+                       wake_up(&ppd->cpspec->autoneg_wait);
+                       symadj = 1;
+               } else if (ppd->lflags & QIBL_IB_AUTONEG_FAILED) {
+                       /*
+                        * Clear autoneg failure flag, and do setup
+                        * so we'll try next time link goes down and
+                        * back to INIT (possibly connected to a
+                        * different device).
+                        */
+                       spin_lock_irqsave(&ppd->lflags_lock, flags);
+                       ppd->lflags &= ~QIBL_IB_AUTONEG_FAILED;
+                       spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+                       ppd->cpspec->ibcctrl_b |= IBA7322_IBC_IBTA_1_2_MASK;
+                       symadj = 1;
+               }
+               if (!(ppd->lflags & QIBL_IB_AUTONEG_INPROG)) {
+                       symadj = 1;
+                       if (ppd->dd->cspec->r1 && ppd->cpspec->ipg_tries <= 10)
+                               try_7322_ipg(ppd);
+                       if (!ppd->cpspec->recovery_init)
+                               setup_7322_link_recovery(ppd, 0);
+                       ppd->cpspec->qdr_dfe_time = jiffies +
+                               msecs_to_jiffies(QDR_DFE_DISABLE_DELAY);
+               }
+               ppd->cpspec->ibmalfusesnap = 0;
+               ppd->cpspec->ibmalfsnap = read_7322_creg32_port(ppd,
+                       crp_errlink);
+       }
+       if (symadj) {
+               ppd->cpspec->iblnkdownsnap =
+                       read_7322_creg32_port(ppd, crp_iblinkdown);
+               if (ppd->cpspec->ibdeltainprog) {
+                       ppd->cpspec->ibdeltainprog = 0;
+                       ppd->cpspec->ibsymdelta += read_7322_creg32_port(ppd,
+                               crp_ibsymbolerr) - ppd->cpspec->ibsymsnap;
+                       ppd->cpspec->iblnkerrdelta += read_7322_creg32_port(ppd,
+                               crp_iblinkerrrecov) - ppd->cpspec->iblnkerrsnap;
+               }
+       } else if (!ibup && qib_compat_ddr_negotiate &&
+                  !ppd->cpspec->ibdeltainprog &&
+                       !(ppd->lflags & QIBL_IB_AUTONEG_INPROG)) {
+               ppd->cpspec->ibdeltainprog = 1;
+               ppd->cpspec->ibsymsnap = read_7322_creg32_port(ppd,
+                       crp_ibsymbolerr);
+               ppd->cpspec->iblnkerrsnap = read_7322_creg32_port(ppd,
+                       crp_iblinkerrrecov);
+       }
+
+       if (!ret)
+               qib_setup_7322_setextled(ppd, ibup);
+       return ret;
+}
+
+/*
+ * Does read/modify/write to appropriate registers to
+ * set output and direction bits selected by mask.
+ * these are in their canonical postions (e.g. lsb of
+ * dir will end up in D48 of extctrl on existing chips).
+ * returns contents of GP Inputs.
+ */
+static int gpio_7322_mod(struct qib_devdata *dd, u32 out, u32 dir, u32 mask)
+{
+       u64 read_val, new_out;
+       unsigned long flags;
+
+       if (mask) {
+               /* some bits being written, lock access to GPIO */
+               dir &= mask;
+               out &= mask;
+               spin_lock_irqsave(&dd->cspec->gpio_lock, flags);
+               dd->cspec->extctrl &= ~((u64)mask << SYM_LSB(EXTCtrl, GPIOOe));
+               dd->cspec->extctrl |= ((u64) dir << SYM_LSB(EXTCtrl, GPIOOe));
+               new_out = (dd->cspec->gpio_out & ~mask) | out;
+
+               qib_write_kreg(dd, kr_extctrl, dd->cspec->extctrl);
+               qib_write_kreg(dd, kr_gpio_out, new_out);
+               dd->cspec->gpio_out = new_out;
+               spin_unlock_irqrestore(&dd->cspec->gpio_lock, flags);
+       }
+       /*
+        * It is unlikely that a read at this time would get valid
+        * data on a pin whose direction line was set in the same
+        * call to this function. We include the read here because
+        * that allows us to potentially combine a change on one pin with
+        * a read on another, and because the old code did something like
+        * this.
+        */
+       read_val = qib_read_kreg64(dd, kr_extstatus);
+       return SYM_FIELD(read_val, EXTStatus, GPIOIn);
+}
+
+/* Enable writes to config EEPROM, if possible. Returns previous state */
+static int qib_7322_eeprom_wen(struct qib_devdata *dd, int wen)
+{
+       int prev_wen;
+       u32 mask;
+
+       mask = 1 << QIB_EEPROM_WEN_NUM;
+       prev_wen = ~gpio_7322_mod(dd, 0, 0, 0) >> QIB_EEPROM_WEN_NUM;
+       gpio_7322_mod(dd, wen ? 0 : mask, mask, mask);
+
+       return prev_wen & 1;
+}
+
+/*
+ * Read fundamental info we need to use the chip.  These are
+ * the registers that describe chip capabilities, and are
+ * saved in shadow registers.
+ */
+static void get_7322_chip_params(struct qib_devdata *dd)
+{
+       u64 val;
+       u32 piobufs;
+       int mtu;
+
+       dd->palign = qib_read_kreg32(dd, kr_pagealign);
+
+       dd->uregbase = qib_read_kreg32(dd, kr_userregbase);
+
+       dd->rcvtidcnt = qib_read_kreg32(dd, kr_rcvtidcnt);
+       dd->rcvtidbase = qib_read_kreg32(dd, kr_rcvtidbase);
+       dd->rcvegrbase = qib_read_kreg32(dd, kr_rcvegrbase);
+       dd->piobufbase = qib_read_kreg64(dd, kr_sendpiobufbase);
+       dd->pio2k_bufbase = dd->piobufbase & 0xffffffff;
+
+       val = qib_read_kreg64(dd, kr_sendpiobufcnt);
+       dd->piobcnt2k = val & ~0U;
+       dd->piobcnt4k = val >> 32;
+       val = qib_read_kreg64(dd, kr_sendpiosize);
+       dd->piosize2k = val & ~0U;
+       dd->piosize4k = val >> 32;
+
+       mtu = ib_mtu_enum_to_int(qib_ibmtu);
+       if (mtu == -1)
+               mtu = QIB_DEFAULT_MTU;
+       dd->pport[0].ibmtu = (u32)mtu;
+       dd->pport[1].ibmtu = (u32)mtu;
+
+       /* these may be adjusted in init_chip_wc_pat() */
+       dd->pio2kbase = (u32 __iomem *)
+               ((char __iomem *) dd->kregbase + dd->pio2k_bufbase);
+       dd->pio4kbase = (u32 __iomem *)
+               ((char __iomem *) dd->kregbase +
+                (dd->piobufbase >> 32));
+       /*
+        * 4K buffers take 2 pages; we use roundup just to be
+        * paranoid; we calculate it once here, rather than on
+        * ever buf allocate
+        */
+       dd->align4k = ALIGN(dd->piosize4k, dd->palign);
+
+       piobufs = dd->piobcnt4k + dd->piobcnt2k + NUM_VL15_BUFS;
+
+       dd->pioavregs = ALIGN(piobufs, sizeof(u64) * BITS_PER_BYTE / 2) /
+               (sizeof(u64) * BITS_PER_BYTE / 2);
+}
+
+/*
+ * The chip base addresses in cspec and cpspec have to be set
+ * after possible init_chip_wc_pat(), rather than in
+ * get_7322_chip_params(), so split out as separate function
+ */
+static void qib_7322_set_baseaddrs(struct qib_devdata *dd)
+{
+       u32 cregbase;
+       cregbase = qib_read_kreg32(dd, kr_counterregbase);
+
+       dd->cspec->cregbase = (u64 __iomem *)(cregbase +
+               (char __iomem *)dd->kregbase);
+
+       dd->egrtidbase = (u64 __iomem *)
+               ((char __iomem *) dd->kregbase + dd->rcvegrbase);
+
+       /* port registers are defined as relative to base of chip */
+       dd->pport[0].cpspec->kpregbase =
+               (u64 __iomem *)((char __iomem *)dd->kregbase);
+       dd->pport[1].cpspec->kpregbase =
+               (u64 __iomem *)(dd->palign +
+               (char __iomem *)dd->kregbase);
+       dd->pport[0].cpspec->cpregbase =
+               (u64 __iomem *)(qib_read_kreg_port(&dd->pport[0],
+               kr_counterregbase) + (char __iomem *)dd->kregbase);
+       dd->pport[1].cpspec->cpregbase =
+               (u64 __iomem *)(qib_read_kreg_port(&dd->pport[1],
+               kr_counterregbase) + (char __iomem *)dd->kregbase);
+}
+
+/*
+ * This is a fairly special-purpose observer, so we only support
+ * the port-specific parts of SendCtrl
+ */
+
+#define SENDCTRL_SHADOWED (SYM_MASK(SendCtrl_0, SendEnable) |          \
+                          SYM_MASK(SendCtrl_0, SDmaEnable) |           \
+                          SYM_MASK(SendCtrl_0, SDmaIntEnable) |        \
+                          SYM_MASK(SendCtrl_0, SDmaSingleDescriptor) | \
+                          SYM_MASK(SendCtrl_0, SDmaHalt) |             \
+                          SYM_MASK(SendCtrl_0, IBVLArbiterEn) |        \
+                          SYM_MASK(SendCtrl_0, ForceCreditUpToDate))
+
+static int sendctrl_hook(struct qib_devdata *dd,
+                        const struct diag_observer *op, u32 offs,
+                        u64 *data, u64 mask, int only_32)
+{
+       unsigned long flags;
+       unsigned idx;
+       unsigned pidx;
+       struct qib_pportdata *ppd = NULL;
+       u64 local_data, all_bits;
+
+       /*
+        * The fixed correspondence between Physical ports and pports is
+        * severed. We need to hunt for the ppd that corresponds
+        * to the offset we got. And we have to do that without admitting
+        * we know the stride, apparently.
+        */
+       for (pidx = 0; pidx < dd->num_pports; ++pidx) {
+               u64 __iomem *psptr;
+               u32 psoffs;
+
+               ppd = dd->pport + pidx;
+               if (!ppd->cpspec->kpregbase)
+                       continue;
+
+               psptr = ppd->cpspec->kpregbase + krp_sendctrl;
+               psoffs = (u32) (psptr - dd->kregbase) * sizeof(*psptr);
+               if (psoffs == offs)
+                       break;
+       }
+
+       /* If pport is not being managed by driver, just avoid shadows. */
+       if (pidx >= dd->num_pports)
+               ppd = NULL;
+
+       /* In any case, "idx" is flat index in kreg space */
+       idx = offs / sizeof(u64);
+
+       all_bits = ~0ULL;
+       if (only_32)
+               all_bits >>= 32;
+
+       spin_lock_irqsave(&dd->sendctrl_lock, flags);
+       if (!ppd || (mask & all_bits) != all_bits) {
+               /*
+                * At least some mask bits are zero, so we need
+                * to read. The judgement call is whether from
+                * reg or shadow. First-cut: read reg, and complain
+                * if any bits which should be shadowed are different
+                * from their shadowed value.
+                */
+               if (only_32)
+                       local_data = (u64)qib_read_kreg32(dd, idx);
+               else
+                       local_data = qib_read_kreg64(dd, idx);
+               *data = (local_data & ~mask) | (*data & mask);
+       }
+       if (mask) {
+               /*
+                * At least some mask bits are one, so we need
+                * to write, but only shadow some bits.
+                */
+               u64 sval, tval; /* Shadowed, transient */
+
+               /*
+                * New shadow val is bits we don't want to touch,
+                * ORed with bits we do, that are intended for shadow.
+                */
+               if (ppd) {
+                       sval = ppd->p_sendctrl & ~mask;
+                       sval |= *data & SENDCTRL_SHADOWED & mask;
+                       ppd->p_sendctrl = sval;
+               } else
+                       sval = *data & SENDCTRL_SHADOWED & mask;
+               tval = sval | (*data & ~SENDCTRL_SHADOWED & mask);
+               qib_write_kreg(dd, idx, tval);
+               qib_write_kreg(dd, kr_scratch, 0Ull);
+       }
+       spin_unlock_irqrestore(&dd->sendctrl_lock, flags);
+       return only_32 ? 4 : 8;
+}
+
+static const struct diag_observer sendctrl_0_observer = {
+       sendctrl_hook, KREG_IDX(SendCtrl_0) * sizeof(u64),
+       KREG_IDX(SendCtrl_0) * sizeof(u64)
+};
+
+static const struct diag_observer sendctrl_1_observer = {
+       sendctrl_hook, KREG_IDX(SendCtrl_1) * sizeof(u64),
+       KREG_IDX(SendCtrl_1) * sizeof(u64)
+};
+
+static ushort sdma_fetch_prio = 8;
+module_param_named(sdma_fetch_prio, sdma_fetch_prio, ushort, S_IRUGO);
+MODULE_PARM_DESC(sdma_fetch_prio, "SDMA descriptor fetch priority");
+
+/* Besides logging QSFP events, we set appropriate TxDDS values */
+static void init_txdds_table(struct qib_pportdata *ppd, int override);
+
+static void qsfp_7322_event(struct work_struct *work)
+{
+       struct qib_qsfp_data *qd;
+       struct qib_pportdata *ppd;
+       u64 pwrup;
+       int ret;
+       u32 le2;
+
+       qd = container_of(work, struct qib_qsfp_data, work);
+       ppd = qd->ppd;
+       pwrup = qd->t_insert + msecs_to_jiffies(QSFP_PWR_LAG_MSEC);
+
+       /*
+        * Some QSFP's not only do not respond until the full power-up
+        * time, but may behave badly if we try. So hold off responding
+        * to insertion.
+        */
+       while (1) {
+               u64 now = get_jiffies_64();
+               if (time_after64(now, pwrup))
+                       break;
+               msleep(1);
+       }
+       ret = qib_refresh_qsfp_cache(ppd, &qd->cache);
+       /*
+        * Need to change LE2 back to defaults if we couldn't
+        * read the cable type (to handle cable swaps), so do this
+        * even on failure to read cable information.  We don't
+        * get here for QME, so IS_QME check not needed here.
+        */
+       le2 = (!ret && qd->cache.atten[1] >= qib_long_atten &&
+              !ppd->dd->cspec->r1 && QSFP_IS_CU(qd->cache.tech)) ?
+               LE2_5m : LE2_DEFAULT;
+       ibsd_wr_allchans(ppd, 13, (le2 << 7), BMASK(9, 7));
+       init_txdds_table(ppd, 0);
+}
+
+/*
+ * There is little we can do but complain to the user if QSFP
+ * initialization fails.
+ */
+static void qib_init_7322_qsfp(struct qib_pportdata *ppd)
+{
+       unsigned long flags;
+       struct qib_qsfp_data *qd = &ppd->cpspec->qsfp_data;
+       struct qib_devdata *dd = ppd->dd;
+       u64 mod_prs_bit = QSFP_GPIO_MOD_PRS_N;
+
+       mod_prs_bit <<= (QSFP_GPIO_PORT2_SHIFT * ppd->hw_pidx);
+       qd->ppd = ppd;
+       qib_qsfp_init(qd, qsfp_7322_event);
+       spin_lock_irqsave(&dd->cspec->gpio_lock, flags);
+       dd->cspec->extctrl |= (mod_prs_bit << SYM_LSB(EXTCtrl, GPIOInvert));
+       dd->cspec->gpio_mask |= mod_prs_bit;
+       qib_write_kreg(dd, kr_extctrl, dd->cspec->extctrl);
+       qib_write_kreg(dd, kr_gpio_mask, dd->cspec->gpio_mask);
+       spin_unlock_irqrestore(&dd->cspec->gpio_lock, flags);
+}
+
+/*
+ * called at device initialization time, and also if the txselect
+ * module parameter is changed.  This is used for cables that don't
+ * have valid QSFP EEPROMs (not present, or attenuation is zero).
+ * We initialize to the default, then if there is a specific
+ * unit,port match, we use that (and set it immediately, for the
+ * current speed, if the link is at INIT or better).
+ * String format is "default# unit#,port#=# ... u,p=#", separators must
+ * be a SPACE character.  A newline terminates.  The u,p=# tuples may
+ * optionally have "u,p=#,#", where the final # is the H1 value
+ * The last specific match is used (actually, all are used, but last
+ * one is the one that winds up set); if none at all, fall back on default.
+ */
+static void set_no_qsfp_atten(struct qib_devdata *dd, int change)
+{
+       char *nxt, *str;
+       u32 pidx, unit, port, deflt, h1;
+       unsigned long val;
+       int any = 0, seth1;
+
+       str = txselect_list;
+
+       /* default number is validated in setup_txselect() */
+       deflt = simple_strtoul(str, &nxt, 0);
+       for (pidx = 0; pidx < dd->num_pports; ++pidx)
+               dd->pport[pidx].cpspec->no_eep = deflt;
+
+       while (*nxt && nxt[1]) {
+               str = ++nxt;
+               unit = simple_strtoul(str, &nxt, 0);
+               if (nxt == str || !*nxt || *nxt != ',') {
+                       while (*nxt && *nxt++ != ' ') /* skip to next, if any */
+                               ;
+                       continue;
+               }
+               str = ++nxt;
+               port = simple_strtoul(str, &nxt, 0);
+               if (nxt == str || *nxt != '=') {
+                       while (*nxt && *nxt++ != ' ') /* skip to next, if any */
+                               ;
+                       continue;
+               }
+               str = ++nxt;
+               val = simple_strtoul(str, &nxt, 0);
+               if (nxt == str) {
+                       while (*nxt && *nxt++ != ' ') /* skip to next, if any */
+                               ;
+                       continue;
+               }
+               if (val >= TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ)
+                       continue;
+               seth1 = 0;
+               h1 = 0; /* gcc thinks it might be used uninitted */
+               if (*nxt == ',' && nxt[1]) {
+                       str = ++nxt;
+                       h1 = (u32)simple_strtoul(str, &nxt, 0);
+                       if (nxt == str)
+                               while (*nxt && *nxt++ != ' ') /* skip */
+                                       ;
+                       else
+                               seth1 = 1;
+               }
+               for (pidx = 0; dd->unit == unit && pidx < dd->num_pports;
+                    ++pidx) {
+                       struct qib_pportdata *ppd = &dd->pport[pidx];
+
+                       if (ppd->port != port || !ppd->link_speed_supported)
+                               continue;
+                       ppd->cpspec->no_eep = val;
+                       /* now change the IBC and serdes, overriding generic */
+                       init_txdds_table(ppd, 1);
+                       any++;
+               }
+               if (*nxt == '\n')
+                       break; /* done */
+       }
+       if (change && !any) {
+               /* no specific setting, use the default.
+                * Change the IBC and serdes, but since it's
+                * general, don't override specific settings.
+                */
+               for (pidx = 0; pidx < dd->num_pports; ++pidx)
+                       if (dd->pport[pidx].link_speed_supported)
+                               init_txdds_table(&dd->pport[pidx], 0);
+       }
+}
+
+/* handle the txselect parameter changing */
+static int setup_txselect(const char *str, struct kernel_param *kp)
+{
+       struct qib_devdata *dd;
+       unsigned long val;
+       char *n;
+       if (strlen(str) >= MAX_ATTEN_LEN) {
+               printk(KERN_INFO QIB_DRV_NAME " txselect_values string "
+                      "too long\n");
+               return -ENOSPC;
+       }
+       val = simple_strtoul(str, &n, 0);
+       if (n == str || val >= (TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ)) {
+               printk(KERN_INFO QIB_DRV_NAME
+                      "txselect_values must start with a number < %d\n",
+                       TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ);
+               return -EINVAL;
+       }
+       strcpy(txselect_list, str);
+
+       list_for_each_entry(dd, &qib_dev_list, list)
+               if (dd->deviceid == PCI_DEVICE_ID_QLOGIC_IB_7322)
+                       set_no_qsfp_atten(dd, 1);
+       return 0;
+}
+
+/*
+ * Write the final few registers that depend on some of the
+ * init setup.  Done late in init, just before bringing up
+ * the serdes.
+ */
+static int qib_late_7322_initreg(struct qib_devdata *dd)
+{
+       int ret = 0, n;
+       u64 val;
+
+       qib_write_kreg(dd, kr_rcvhdrentsize, dd->rcvhdrentsize);
+       qib_write_kreg(dd, kr_rcvhdrsize, dd->rcvhdrsize);
+       qib_write_kreg(dd, kr_rcvhdrcnt, dd->rcvhdrcnt);
+       qib_write_kreg(dd, kr_sendpioavailaddr, dd->pioavailregs_phys);
+       val = qib_read_kreg64(dd, kr_sendpioavailaddr);
+       if (val != dd->pioavailregs_phys) {
+               qib_dev_err(dd, "Catastrophic software error, "
+                           "SendPIOAvailAddr written as %lx, "
+                           "read back as %llx\n",
+                           (unsigned long) dd->pioavailregs_phys,
+                           (unsigned long long) val);
+               ret = -EINVAL;
+       }
+
+       n = dd->piobcnt2k + dd->piobcnt4k + NUM_VL15_BUFS;
+       qib_7322_txchk_change(dd, 0, n, TXCHK_CHG_TYPE_KERN, NULL);
+       /* driver sends get pkey, lid, etc. checking also, to catch bugs */
+       qib_7322_txchk_change(dd, 0, n, TXCHK_CHG_TYPE_ENAB1, NULL);
+
+       qib_register_observer(dd, &sendctrl_0_observer);
+       qib_register_observer(dd, &sendctrl_1_observer);
+
+       dd->control &= ~QLOGIC_IB_C_SDMAFETCHPRIOEN;
+       qib_write_kreg(dd, kr_control, dd->control);
+       /*
+        * Set SendDmaFetchPriority and init Tx params, including
+        * QSFP handler on boards that have QSFP.
+        * First set our default attenuation entry for cables that
+        * don't have valid attenuation.
+        */
+       set_no_qsfp_atten(dd, 0);
+       for (n = 0; n < dd->num_pports; ++n) {
+               struct qib_pportdata *ppd = dd->pport + n;
+
+               qib_write_kreg_port(ppd, krp_senddmaprioritythld,
+                                   sdma_fetch_prio & 0xf);
+               /* Initialize qsfp if present on board. */
+               if (dd->flags & QIB_HAS_QSFP)
+                       qib_init_7322_qsfp(ppd);
+       }
+       dd->control |= QLOGIC_IB_C_SDMAFETCHPRIOEN;
+       qib_write_kreg(dd, kr_control, dd->control);
+
+       return ret;
+}
+
+/* per IB port errors.  */
+#define SENDCTRL_PIBP (MASK_ACROSS(0, 1) | MASK_ACROSS(3, 3) | \
+       MASK_ACROSS(8, 15))
+#define RCVCTRL_PIBP (MASK_ACROSS(0, 17) | MASK_ACROSS(39, 41))
+#define ERRS_PIBP (MASK_ACROSS(57, 58) | MASK_ACROSS(54, 54) | \
+       MASK_ACROSS(36, 49) | MASK_ACROSS(29, 34) | MASK_ACROSS(14, 17) | \
+       MASK_ACROSS(0, 11))
+
+/*
+ * Write the initialization per-port registers that need to be done at
+ * driver load and after reset completes (i.e., that aren't done as part
+ * of other init procedures called from qib_init.c).
+ * Some of these should be redundant on reset, but play safe.
+ */
+static void write_7322_init_portregs(struct qib_pportdata *ppd)
+{
+       u64 val;
+       int i;
+
+       if (!ppd->link_speed_supported) {
+               /* no buffer credits for this port */
+               for (i = 1; i < 8; i++)
+                       qib_write_kreg_port(ppd, krp_rxcreditvl0 + i, 0);
+               qib_write_kreg_port(ppd, krp_ibcctrl_b, 0);
+               qib_write_kreg(ppd->dd, kr_scratch, 0);
+               return;
+       }
+
+       /*
+        * Set the number of supported virtual lanes in IBC,
+        * for flow control packet handling on unsupported VLs
+        */
+       val = qib_read_kreg_port(ppd, krp_ibsdtestiftx);
+       val &= ~SYM_MASK(IB_SDTEST_IF_TX_0, VL_CAP);
+       val |= (u64)(ppd->vls_supported - 1) <<
+               SYM_LSB(IB_SDTEST_IF_TX_0, VL_CAP);
+       qib_write_kreg_port(ppd, krp_ibsdtestiftx, val);
+
+       qib_write_kreg_port(ppd, krp_rcvbthqp, QIB_KD_QP);
+
+       /* enable tx header checking */
+       qib_write_kreg_port(ppd, krp_sendcheckcontrol, IBA7322_SENDCHK_PKEY |
+                           IBA7322_SENDCHK_BTHQP | IBA7322_SENDCHK_SLID |
+                           IBA7322_SENDCHK_RAW_IPV6 | IBA7322_SENDCHK_MINSZ);
+
+       qib_write_kreg_port(ppd, krp_ncmodectrl,
+               SYM_MASK(IBNCModeCtrl_0, ScrambleCapLocal));
+
+       /*
+        * Unconditionally clear the bufmask bits.  If SDMA is
+        * enabled, we'll set them appropriately later.
+        */
+       qib_write_kreg_port(ppd, krp_senddmabufmask0, 0);
+       qib_write_kreg_port(ppd, krp_senddmabufmask1, 0);
+       qib_write_kreg_port(ppd, krp_senddmabufmask2, 0);
+       if (ppd->dd->cspec->r1)
+               ppd->p_sendctrl |= SYM_MASK(SendCtrl_0, ForceCreditUpToDate);
+}
+
+/*
+ * Write the initialization per-device registers that need to be done at
+ * driver load and after reset completes (i.e., that aren't done as part
+ * of other init procedures called from qib_init.c).  Also write per-port
+ * registers that are affected by overall device config, such as QP mapping
+ * Some of these should be redundant on reset, but play safe.
+ */
+static void write_7322_initregs(struct qib_devdata *dd)
+{
+       struct qib_pportdata *ppd;
+       int i, pidx;
+       u64 val;
+
+       /* Set Multicast QPs received by port 2 to map to context one. */
+       qib_write_kreg(dd, KREG_IDX(RcvQPMulticastContext_1), 1);
+
+       for (pidx = 0; pidx < dd->num_pports; ++pidx) {
+               unsigned n, regno;
+               unsigned long flags;
+
+               if (!dd->qpn_mask || !dd->pport[pidx].link_speed_supported)
+                       continue;
+
+               ppd = &dd->pport[pidx];
+
+               /* be paranoid against later code motion, etc. */
+               spin_lock_irqsave(&dd->cspec->rcvmod_lock, flags);
+               ppd->p_rcvctrl |= SYM_MASK(RcvCtrl_0, RcvQPMapEnable);
+               spin_unlock_irqrestore(&dd->cspec->rcvmod_lock, flags);
+
+               /* Initialize QP to context mapping */
+               regno = krp_rcvqpmaptable;
+               val = 0;
+               if (dd->num_pports > 1)
+                       n = dd->first_user_ctxt / dd->num_pports;
+               else
+                       n = dd->first_user_ctxt - 1;
+               for (i = 0; i < 32; ) {
+                       unsigned ctxt;
+
+                       if (dd->num_pports > 1)
+                               ctxt = (i % n) * dd->num_pports + pidx;
+                       else if (i % n)
+                               ctxt = (i % n) + 1;
+                       else
+                               ctxt = ppd->hw_pidx;
+                       val |= ctxt << (5 * (i % 6));
+                       i++;
+                       if (i % 6 == 0) {
+                               qib_write_kreg_port(ppd, regno, val);
+                               val = 0;
+                               regno++;
+                       }
+               }
+               qib_write_kreg_port(ppd, regno, val);
+       }
+
+       /*
+        * Setup up interrupt mitigation for kernel contexts, but
+        * not user contexts (user contexts use interrupts when
+        * stalled waiting for any packet, so want those interrupts
+        * right away).
+        */
+       for (i = 0; i < dd->first_user_ctxt; i++) {
+               dd->cspec->rcvavail_timeout[i] = rcv_int_timeout;
+               qib_write_kreg(dd, kr_rcvavailtimeout + i, rcv_int_timeout);
+       }
+
+       /*
+        * Initialize  as (disabled) rcvflow tables.  Application code
+        * will setup each flow as it uses the flow.
+        * Doesn't clear any of the error bits that might be set.
+        */
+       val = TIDFLOW_ERRBITS; /* these are W1C */
+       for (i = 0; i < dd->ctxtcnt; i++) {
+               int flow;
+               for (flow = 0; flow < NUM_TIDFLOWS_CTXT; flow++)
+                       qib_write_ureg(dd, ur_rcvflowtable+flow, val, i);
+       }
+
+       /*
+        * dual cards init to dual port recovery, single port cards to
+        * the one port.  Dual port cards may later adjust to 1 port,
+        * and then back to dual port if both ports are connected
+        * */
+       if (dd->num_pports)
+               setup_7322_link_recovery(dd->pport, dd->num_pports > 1);
+}
+
+static int qib_init_7322_variables(struct qib_devdata *dd)
+{
+       struct qib_pportdata *ppd;
+       unsigned features, pidx, sbufcnt;
+       int ret, mtu;
+       u32 sbufs, updthresh;
+
+       /* pport structs are contiguous, allocated after devdata */
+       ppd = (struct qib_pportdata *)(dd + 1);
+       dd->pport = ppd;
+       ppd[0].dd = dd;
+       ppd[1].dd = dd;
+
+       dd->cspec = (struct qib_chip_specific *)(ppd + 2);
+
+       ppd[0].cpspec = (struct qib_chippport_specific *)(dd->cspec + 1);
+       ppd[1].cpspec = &ppd[0].cpspec[1];
+       ppd[0].cpspec->ppd = &ppd[0]; /* for autoneg_7322_work() */
+       ppd[1].cpspec->ppd = &ppd[1]; /* for autoneg_7322_work() */
+
+       spin_lock_init(&dd->cspec->rcvmod_lock);
+       spin_lock_init(&dd->cspec->gpio_lock);
+
+       /* we haven't yet set QIB_PRESENT, so use read directly */
+       dd->revision = readq(&dd->kregbase[kr_revision]);
+
+       if ((dd->revision & 0xffffffffU) == 0xffffffffU) {
+               qib_dev_err(dd, "Revision register read failure, "
+                           "giving up initialization\n");
+               ret = -ENODEV;
+               goto bail;
+       }
+       dd->flags |= QIB_PRESENT;  /* now register routines work */
+
+       dd->majrev = (u8) SYM_FIELD(dd->revision, Revision_R, ChipRevMajor);
+       dd->minrev = (u8) SYM_FIELD(dd->revision, Revision_R, ChipRevMinor);
+       dd->cspec->r1 = dd->minrev == 1;
+
+       get_7322_chip_params(dd);
+       features = qib_7322_boardname(dd);
+
+       /* now that piobcnt2k and 4k set, we can allocate these */
+       sbufcnt = dd->piobcnt2k + dd->piobcnt4k +
+               NUM_VL15_BUFS + BITS_PER_LONG - 1;
+       sbufcnt /= BITS_PER_LONG;
+       dd->cspec->sendchkenable = kmalloc(sbufcnt *
+               sizeof(*dd->cspec->sendchkenable), GFP_KERNEL);
+       dd->cspec->sendgrhchk = kmalloc(sbufcnt *
+               sizeof(*dd->cspec->sendgrhchk), GFP_KERNEL);
+       dd->cspec->sendibchk = kmalloc(sbufcnt *
+               sizeof(*dd->cspec->sendibchk), GFP_KERNEL);
+       if (!dd->cspec->sendchkenable || !dd->cspec->sendgrhchk ||
+               !dd->cspec->sendibchk) {
+               qib_dev_err(dd, "Failed allocation for hdrchk bitmaps\n");
+               ret = -ENOMEM;
+               goto bail;
+       }
+
+       ppd = dd->pport;
+
+       /*
+        * GPIO bits for TWSI data and clock,
+        * used for serial EEPROM.
+        */
+       dd->gpio_sda_num = _QIB_GPIO_SDA_NUM;
+       dd->gpio_scl_num = _QIB_GPIO_SCL_NUM;
+       dd->twsi_eeprom_dev = QIB_TWSI_EEPROM_DEV;
+
+       dd->flags |= QIB_HAS_INTX | QIB_HAS_LINK_LATENCY |
+               QIB_NODMA_RTAIL | QIB_HAS_VLSUPP | QIB_HAS_HDRSUPP |
+               QIB_HAS_THRESH_UPDATE |
+               (sdma_idle_cnt ? QIB_HAS_SDMA_TIMEOUT : 0);
+       dd->flags |= qib_special_trigger ?
+               QIB_USE_SPCL_TRIG : QIB_HAS_SEND_DMA;
+
+       /*
+        * Setup initial values.  These may change when PAT is enabled, but
+        * we need these to do initial chip register accesses.
+        */
+       qib_7322_set_baseaddrs(dd);
+
+       mtu = ib_mtu_enum_to_int(qib_ibmtu);
+       if (mtu == -1)
+               mtu = QIB_DEFAULT_MTU;
+
+       dd->cspec->int_enable_mask = QIB_I_BITSEXTANT;
+       /* all hwerrors become interrupts, unless special purposed */
+       dd->cspec->hwerrmask = ~0ULL;
+       /*  link_recovery setup causes these errors, so ignore them,
+        *  other than clearing them when they occur */
+       dd->cspec->hwerrmask &=
+               ~(SYM_MASK(HwErrMask, IBSerdesPClkNotDetectMask_0) |
+                 SYM_MASK(HwErrMask, IBSerdesPClkNotDetectMask_1) |
+                 HWE_MASK(LATriggered));
+
+       for (pidx = 0; pidx < NUM_IB_PORTS; ++pidx) {
+               struct qib_chippport_specific *cp = ppd->cpspec;
+               ppd->link_speed_supported = features & PORT_SPD_CAP;
+               features >>=  PORT_SPD_CAP_SHIFT;
+               if (!ppd->link_speed_supported) {
+                       /* single port mode (7340, or configured) */
+                       dd->skip_kctxt_mask |= 1 << pidx;
+                       if (pidx == 0) {
+                               /* Make sure port is disabled. */
+                               qib_write_kreg_port(ppd, krp_rcvctrl, 0);
+                               qib_write_kreg_port(ppd, krp_ibcctrl_a, 0);
+                               ppd[0] = ppd[1];
+                               dd->cspec->hwerrmask &= ~(SYM_MASK(HwErrMask,
+                                                 IBSerdesPClkNotDetectMask_0)
+                                                 | SYM_MASK(HwErrMask,
+                                                 SDmaMemReadErrMask_0));
+                               dd->cspec->int_enable_mask &= ~(
+                                    SYM_MASK(IntMask, SDmaCleanupDoneMask_0) |
+                                    SYM_MASK(IntMask, SDmaIdleIntMask_0) |
+                                    SYM_MASK(IntMask, SDmaProgressIntMask_0) |
+                                    SYM_MASK(IntMask, SDmaIntMask_0) |
+                                    SYM_MASK(IntMask, ErrIntMask_0) |
+                                    SYM_MASK(IntMask, SendDoneIntMask_0));
+                       } else {
+                               /* Make sure port is disabled. */
+                               qib_write_kreg_port(ppd, krp_rcvctrl, 0);
+                               qib_write_kreg_port(ppd, krp_ibcctrl_a, 0);
+                               dd->cspec->hwerrmask &= ~(SYM_MASK(HwErrMask,
+                                                 IBSerdesPClkNotDetectMask_1)
+                                                 | SYM_MASK(HwErrMask,
+                                                 SDmaMemReadErrMask_1));
+                               dd->cspec->int_enable_mask &= ~(
+                                    SYM_MASK(IntMask, SDmaCleanupDoneMask_1) |
+                                    SYM_MASK(IntMask, SDmaIdleIntMask_1) |
+                                    SYM_MASK(IntMask, SDmaProgressIntMask_1) |
+                                    SYM_MASK(IntMask, SDmaIntMask_1) |
+                                    SYM_MASK(IntMask, ErrIntMask_1) |
+                                    SYM_MASK(IntMask, SendDoneIntMask_1));
+                       }
+                       continue;
+               }
+
+               dd->num_pports++;
+               qib_init_pportdata(ppd, dd, pidx, dd->num_pports);
+
+               ppd->link_width_supported = IB_WIDTH_1X | IB_WIDTH_4X;
+               ppd->link_width_enabled = IB_WIDTH_4X;
+               ppd->link_speed_enabled = ppd->link_speed_supported;
+               /*
+                * Set the initial values to reasonable default, will be set
+                * for real when link is up.
+                */
+               ppd->link_width_active = IB_WIDTH_4X;
+               ppd->link_speed_active = QIB_IB_SDR;
+               ppd->delay_mult = ib_rate_to_delay[IB_RATE_10_GBPS];
+               switch (qib_num_cfg_vls) {
+               case 1:
+                       ppd->vls_supported = IB_VL_VL0;
+                       break;
+               case 2:
+                       ppd->vls_supported = IB_VL_VL0_1;
+                       break;
+               default:
+                       qib_devinfo(dd->pcidev,
+                                   "Invalid num_vls %u, using 4 VLs\n",
+                                   qib_num_cfg_vls);
+                       qib_num_cfg_vls = 4;
+                       /* fall through */
+               case 4:
+                       ppd->vls_supported = IB_VL_VL0_3;
+                       break;
+               case 8:
+                       if (mtu <= 2048)
+                               ppd->vls_supported = IB_VL_VL0_7;
+                       else {
+                               qib_devinfo(dd->pcidev,
+                                           "Invalid num_vls %u for MTU %d "
+                                           ", using 4 VLs\n",
+                                           qib_num_cfg_vls, mtu);
+                               ppd->vls_supported = IB_VL_VL0_3;
+                               qib_num_cfg_vls = 4;
+                       }
+                       break;
+               }
+               ppd->vls_operational = ppd->vls_supported;
+
+               init_waitqueue_head(&cp->autoneg_wait);
+               INIT_DELAYED_WORK(&cp->autoneg_work,
+                                 autoneg_7322_work);
+               if (ppd->dd->cspec->r1)
+                       INIT_DELAYED_WORK(&cp->ipg_work, ipg_7322_work);
+
+               /*
+                * For Mez and similar cards, no qsfp info, so do
+                * the "cable info" setup here.  Can be overridden
+                * in adapter-specific routines.
+                */
+               if (!(ppd->dd->flags & QIB_HAS_QSFP)) {
+                       if (!IS_QMH(ppd->dd) && !IS_QME(ppd->dd))
+                               qib_devinfo(ppd->dd->pcidev, "IB%u:%u: "
+                                           "Unknown mezzanine card type\n",
+                                           dd->unit, ppd->port);
+                       cp->h1_val = IS_QMH(dd) ? H1_FORCE_QMH : H1_FORCE_QME;
+                       /*
+                        * Choose center value as default tx serdes setting
+                        * until changed through module parameter.
+                        */
+                       ppd->cpspec->no_eep = IS_QMH(dd) ?
+                               TXDDS_TABLE_SZ + 2 : TXDDS_TABLE_SZ + 4;
+               } else
+                       cp->h1_val = H1_FORCE_VAL;
+
+               /* Avoid writes to chip for mini_init */
+               if (!qib_mini_init)
+                       write_7322_init_portregs(ppd);
+
+               init_timer(&cp->chase_timer);
+               cp->chase_timer.function = reenable_chase;
+               cp->chase_timer.data = (unsigned long)ppd;
+
+               ppd++;
+       }
+
+       dd->rcvhdrentsize = QIB_RCVHDR_ENTSIZE;
+       dd->rcvhdrsize = QIB_DFLT_RCVHDRSIZE;
+       dd->rhf_offset = dd->rcvhdrentsize - sizeof(u64) / sizeof(u32);
+
+       /* we always allocate at least 2048 bytes for eager buffers */
+       dd->rcvegrbufsize = max(mtu, 2048);
+
+       qib_7322_tidtemplate(dd);
+
+       /*
+        * We can request a receive interrupt for 1 or
+        * more packets from current offset.
+        */
+       dd->rhdrhead_intr_off =
+               (u64) rcv_int_count << IBA7322_HDRHEAD_PKTINT_SHIFT;
+
+       /* setup the stats timer; the add_timer is done at end of init */
+       init_timer(&dd->stats_timer);
+       dd->stats_timer.function = qib_get_7322_faststats;
+       dd->stats_timer.data = (unsigned long) dd;
+
+       dd->ureg_align = 0x10000;  /* 64KB alignment */
+
+       dd->piosize2kmax_dwords = dd->piosize2k >> 2;
+
+       qib_7322_config_ctxts(dd);
+       qib_set_ctxtcnt(dd);
+
+       if (qib_wc_pat) {
+               ret = init_chip_wc_pat(dd, NUM_VL15_BUFS * dd->align4k);
+               if (ret)
+                       goto bail;
+       }
+       qib_7322_set_baseaddrs(dd); /* set chip access pointers now */
+
+       ret = 0;
+       if (qib_mini_init)
+               goto bail;
+       if (!dd->num_pports) {
+               qib_dev_err(dd, "No ports enabled, giving up initialization\n");
+               goto bail; /* no error, so can still figure out why err */
+       }
+
+       write_7322_initregs(dd);
+       ret = qib_create_ctxts(dd);
+       init_7322_cntrnames(dd);
+
+       updthresh = 8U; /* update threshold */
+
+       /* use all of 4KB buffers for the kernel SDMA, zero if !SDMA.
+        * reserve the update threshold amount for other kernel use, such
+        * as sending SMI, MAD, and ACKs, or 3, whichever is greater,
+        * unless we aren't enabling SDMA, in which case we want to use
+        * all the 4k bufs for the kernel.
+        * if this was less than the update threshold, we could wait
+        * a long time for an update.  Coded this way because we
+        * sometimes change the update threshold for various reasons,
+        * and we want this to remain robust.
+        */
+       if (dd->flags & QIB_HAS_SEND_DMA) {
+               dd->cspec->sdmabufcnt = dd->piobcnt4k;
+               sbufs = updthresh > 3 ? updthresh : 3;
+       } else {
+               dd->cspec->sdmabufcnt = 0;
+               sbufs = dd->piobcnt4k;
+       }
+       dd->cspec->lastbuf_for_pio = dd->piobcnt2k + dd->piobcnt4k -
+               dd->cspec->sdmabufcnt;
+       dd->lastctxt_piobuf = dd->cspec->lastbuf_for_pio - sbufs;
+       dd->cspec->lastbuf_for_pio--; /* range is <= , not < */
+       dd->pbufsctxt = (dd->cfgctxts > dd->first_user_ctxt) ?
+               dd->lastctxt_piobuf / (dd->cfgctxts - dd->first_user_ctxt) : 0;
+
+       /*
+        * If we have 16 user contexts, we will have 7 sbufs
+        * per context, so reduce the update threshold to match.  We
+        * want to update before we actually run out, at low pbufs/ctxt
+        * so give ourselves some margin.
+        */
+       if (dd->pbufsctxt >= 2 && dd->pbufsctxt - 2 < updthresh)
+               updthresh = dd->pbufsctxt - 2;
+       dd->cspec->updthresh_dflt = updthresh;
+       dd->cspec->updthresh = updthresh;
+
+       /* before full enable, no interrupts, no locking needed */
+       dd->sendctrl |= ((updthresh & SYM_RMASK(SendCtrl, AvailUpdThld))
+                            << SYM_LSB(SendCtrl, AvailUpdThld)) |
+                       SYM_MASK(SendCtrl, SendBufAvailPad64Byte);
+
+       dd->psxmitwait_supported = 1;
+       dd->psxmitwait_check_rate = QIB_7322_PSXMITWAIT_CHECK_RATE;
+bail:
+       if (!dd->ctxtcnt)
+               dd->ctxtcnt = 1; /* for other initialization code */
+
+       return ret;
+}
+
+static u32 __iomem *qib_7322_getsendbuf(struct qib_pportdata *ppd, u64 pbc,
+                                       u32 *pbufnum)
+{
+       u32 first, last, plen = pbc & QIB_PBC_LENGTH_MASK;
+       struct qib_devdata *dd = ppd->dd;
+
+       /* last is same for 2k and 4k, because we use 4k if all 2k busy */
+       if (pbc & PBC_7322_VL15_SEND) {
+               first = dd->piobcnt2k + dd->piobcnt4k + ppd->hw_pidx;
+               last = first;
+       } else {
+               if ((plen + 1) > dd->piosize2kmax_dwords)
+                       first = dd->piobcnt2k;
+               else
+                       first = 0;
+               last = dd->cspec->lastbuf_for_pio;
+       }
+       return qib_getsendbuf_range(dd, pbufnum, first, last);
+}
+
+static void qib_set_cntr_7322_sample(struct qib_pportdata *ppd, u32 intv,
+                                    u32 start)
+{
+       qib_write_kreg_port(ppd, krp_psinterval, intv);
+       qib_write_kreg_port(ppd, krp_psstart, start);
+}
+
+/*
+ * Must be called with sdma_lock held, or before init finished.
+ */
+static void qib_sdma_set_7322_desc_cnt(struct qib_pportdata *ppd, unsigned cnt)
+{
+       qib_write_kreg_port(ppd, krp_senddmadesccnt, cnt);
+}
+
+static struct sdma_set_state_action sdma_7322_action_table[] = {
+       [qib_sdma_state_s00_hw_down] = {
+               .go_s99_running_tofalse = 1,
+               .op_enable = 0,
+               .op_intenable = 0,
+               .op_halt = 0,
+               .op_drain = 0,
+       },
+       [qib_sdma_state_s10_hw_start_up_wait] = {
+               .op_enable = 0,
+               .op_intenable = 1,
+               .op_halt = 1,
+               .op_drain = 0,
+       },
+       [qib_sdma_state_s20_idle] = {
+               .op_enable = 1,
+               .op_intenable = 1,
+               .op_halt = 1,
+               .op_drain = 0,
+       },
+       [qib_sdma_state_s30_sw_clean_up_wait] = {
+               .op_enable = 0,
+               .op_intenable = 1,
+               .op_halt = 1,
+               .op_drain = 0,
+       },
+       [qib_sdma_state_s40_hw_clean_up_wait] = {
+               .op_enable = 1,
+               .op_intenable = 1,
+               .op_halt = 1,
+               .op_drain = 0,
+       },
+       [qib_sdma_state_s50_hw_halt_wait] = {
+               .op_enable = 1,
+               .op_intenable = 1,
+               .op_halt = 1,
+               .op_drain = 1,
+       },
+       [qib_sdma_state_s99_running] = {
+               .op_enable = 1,
+               .op_intenable = 1,
+               .op_halt = 0,
+               .op_drain = 0,
+               .go_s99_running_totrue = 1,
+       },
+};
+
+static void qib_7322_sdma_init_early(struct qib_pportdata *ppd)
+{
+       ppd->sdma_state.set_state_action = sdma_7322_action_table;
+}
+
+static int init_sdma_7322_regs(struct qib_pportdata *ppd)
+{
+       struct qib_devdata *dd = ppd->dd;
+       unsigned lastbuf, erstbuf;
+       u64 senddmabufmask[3] = { 0 };
+       int n, ret = 0;
+
+       qib_write_kreg_port(ppd, krp_senddmabase, ppd->sdma_descq_phys);
+       qib_sdma_7322_setlengen(ppd);
+       qib_sdma_update_7322_tail(ppd, 0); /* Set SendDmaTail */
+       qib_write_kreg_port(ppd, krp_senddmareloadcnt, sdma_idle_cnt);
+       qib_write_kreg_port(ppd, krp_senddmadesccnt, 0);
+       qib_write_kreg_port(ppd, krp_senddmaheadaddr, ppd->sdma_head_phys);
+
+       if (dd->num_pports)
+               n = dd->cspec->sdmabufcnt / dd->num_pports; /* no remainder */
+       else
+               n = dd->cspec->sdmabufcnt; /* failsafe for init */
+       erstbuf = (dd->piobcnt2k + dd->piobcnt4k) -
+               ((dd->num_pports == 1 || ppd->port == 2) ? n :
+               dd->cspec->sdmabufcnt);
+       lastbuf = erstbuf + n;
+
+       ppd->sdma_state.first_sendbuf = erstbuf;
+       ppd->sdma_state.last_sendbuf = lastbuf;
+       for (; erstbuf < lastbuf; ++erstbuf) {
+               unsigned word = erstbuf / BITS_PER_LONG;
+               unsigned bit = erstbuf & (BITS_PER_LONG - 1);
+
+               BUG_ON(word >= 3);
+               senddmabufmask[word] |= 1ULL << bit;
+       }
+       qib_write_kreg_port(ppd, krp_senddmabufmask0, senddmabufmask[0]);
+       qib_write_kreg_port(ppd, krp_senddmabufmask1, senddmabufmask[1]);
+       qib_write_kreg_port(ppd, krp_senddmabufmask2, senddmabufmask[2]);
+       return ret;
+}
+
+/* sdma_lock must be held */
+static u16 qib_sdma_7322_gethead(struct qib_pportdata *ppd)
+{
+       struct qib_devdata *dd = ppd->dd;
+       int sane;
+       int use_dmahead;
+       u16 swhead;
+       u16 swtail;
+       u16 cnt;
+       u16 hwhead;
+
+       use_dmahead = __qib_sdma_running(ppd) &&
+               (dd->flags & QIB_HAS_SDMA_TIMEOUT);
+retry:
+       hwhead = use_dmahead ?
+               (u16) le64_to_cpu(*ppd->sdma_head_dma) :
+               (u16) qib_read_kreg_port(ppd, krp_senddmahead);
+
+       swhead = ppd->sdma_descq_head;
+       swtail = ppd->sdma_descq_tail;
+       cnt = ppd->sdma_descq_cnt;
+
+       if (swhead < swtail)
+               /* not wrapped */
+               sane = (hwhead >= swhead) & (hwhead <= swtail);
+       else if (swhead > swtail)
+               /* wrapped around */
+               sane = ((hwhead >= swhead) && (hwhead < cnt)) ||
+                       (hwhead <= swtail);
+       else
+               /* empty */
+               sane = (hwhead == swhead);
+
+       if (unlikely(!sane)) {
+               if (use_dmahead) {
+                       /* try one more time, directly from the register */
+                       use_dmahead = 0;
+                       goto retry;
+               }
+               /* proceed as if no progress */
+               hwhead = swhead;
+       }
+
+       return hwhead;
+}
+
+static int qib_sdma_7322_busy(struct qib_pportdata *ppd)
+{
+       u64 hwstatus = qib_read_kreg_port(ppd, krp_senddmastatus);
+
+       return (hwstatus & SYM_MASK(SendDmaStatus_0, ScoreBoardDrainInProg)) ||
+              (hwstatus & SYM_MASK(SendDmaStatus_0, HaltInProg)) ||
+              !(hwstatus & SYM_MASK(SendDmaStatus_0, InternalSDmaHalt)) ||
+              !(hwstatus & SYM_MASK(SendDmaStatus_0, ScbEmpty));
+}
+
+/*
+ * Compute the amount of delay before sending the next packet if the
+ * port's send rate differs from the static rate set for the QP.
+ * The delay affects the next packet and the amount of the delay is
+ * based on the length of the this packet.
+ */
+static u32 qib_7322_setpbc_control(struct qib_pportdata *ppd, u32 plen,
+                                  u8 srate, u8 vl)
+{
+       u8 snd_mult = ppd->delay_mult;
+       u8 rcv_mult = ib_rate_to_delay[srate];
+       u32 ret;
+
+       ret = rcv_mult > snd_mult ? ((plen + 1) >> 1) * snd_mult : 0;
+
+       /* Indicate VL15, else set the VL in the control word */
+       if (vl == 15)
+               ret |= PBC_7322_VL15_SEND_CTRL;
+       else
+               ret |= vl << PBC_VL_NUM_LSB;
+       ret |= ((u32)(ppd->hw_pidx)) << PBC_PORT_SEL_LSB;
+
+       return ret;
+}
+
+/*
+ * Enable the per-port VL15 send buffers for use.
+ * They follow the rest of the buffers, without a config parameter.
+ * This was in initregs, but that is done before the shadow
+ * is set up, and this has to be done after the shadow is
+ * set up.
+ */
+static void qib_7322_initvl15_bufs(struct qib_devdata *dd)
+{
+       unsigned vl15bufs;
+
+       vl15bufs = dd->piobcnt2k + dd->piobcnt4k;
+       qib_chg_pioavailkernel(dd, vl15bufs, NUM_VL15_BUFS,
+                              TXCHK_CHG_TYPE_KERN, NULL);
+}
+
+static void qib_7322_init_ctxt(struct qib_ctxtdata *rcd)
+{
+       if (rcd->ctxt < NUM_IB_PORTS) {
+               if (rcd->dd->num_pports > 1) {
+                       rcd->rcvegrcnt = KCTXT0_EGRCNT / 2;
+                       rcd->rcvegr_tid_base = rcd->ctxt ? rcd->rcvegrcnt : 0;
+               } else {
+                       rcd->rcvegrcnt = KCTXT0_EGRCNT;
+                       rcd->rcvegr_tid_base = 0;
+               }
+       } else {
+               rcd->rcvegrcnt = rcd->dd->cspec->rcvegrcnt;
+               rcd->rcvegr_tid_base = KCTXT0_EGRCNT +
+                       (rcd->ctxt - NUM_IB_PORTS) * rcd->rcvegrcnt;
+       }
+}
+
+#define QTXSLEEPS 5000
+static void qib_7322_txchk_change(struct qib_devdata *dd, u32 start,
+                                 u32 len, u32 which, struct qib_ctxtdata *rcd)
+{
+       int i;
+       const int last = start + len - 1;
+       const int lastr = last / BITS_PER_LONG;
+       u32 sleeps = 0;
+       int wait = rcd != NULL;
+       unsigned long flags;
+
+       while (wait) {
+               unsigned long shadow;
+               int cstart, previ = -1;
+
+               /*
+                * when flipping from kernel to user, we can't change
+                * the checking type if the buffer is allocated to the
+                * driver.   It's OK the other direction, because it's
+                * from close, and we have just disarm'ed all the
+                * buffers.  All the kernel to kernel changes are also
+                * OK.
+                */
+               for (cstart = start; cstart <= last; cstart++) {
+                       i = ((2 * cstart) + QLOGIC_IB_SENDPIOAVAIL_BUSY_SHIFT)
+                               / BITS_PER_LONG;
+                       if (i != previ) {
+                               shadow = (unsigned long)
+                                       le64_to_cpu(dd->pioavailregs_dma[i]);
+                               previ = i;
+                       }
+                       if (test_bit(((2 * cstart) +
+                                     QLOGIC_IB_SENDPIOAVAIL_BUSY_SHIFT)
+                                    % BITS_PER_LONG, &shadow))
+                               break;
+               }
+
+               if (cstart > last)
+                       break;
+
+               if (sleeps == QTXSLEEPS)
+                       break;
+               /* make sure we see an updated copy next time around */
+               sendctrl_7322_mod(dd->pport, QIB_SENDCTRL_AVAIL_BLIP);
+               sleeps++;
+               msleep(1);
+       }
+
+       switch (which) {
+       case TXCHK_CHG_TYPE_DIS1:
+               /*
+                * disable checking on a range; used by diags; just
+                * one buffer, but still written generically
+                */
+               for (i = start; i <= last; i++)
+                       clear_bit(i, dd->cspec->sendchkenable);
+               break;
+
+       case TXCHK_CHG_TYPE_ENAB1:
+               /*
+                * (re)enable checking on a range; used by diags; just
+                * one buffer, but still written generically; read
+                * scratch to be sure buffer actually triggered, not
+                * just flushed from processor.
+                */
+               qib_read_kreg32(dd, kr_scratch);
+               for (i = start; i <= last; i++)
+                       set_bit(i, dd->cspec->sendchkenable);
+               break;
+
+       case TXCHK_CHG_TYPE_KERN:
+               /* usable by kernel */
+               for (i = start; i <= last; i++) {
+                       set_bit(i, dd->cspec->sendibchk);
+                       clear_bit(i, dd->cspec->sendgrhchk);
+               }
+               spin_lock_irqsave(&dd->uctxt_lock, flags);
+               /* see if we need to raise avail update threshold */
+               for (i = dd->first_user_ctxt;
+                    dd->cspec->updthresh != dd->cspec->updthresh_dflt
+                    && i < dd->cfgctxts; i++)
+                       if (dd->rcd[i] && dd->rcd[i]->subctxt_cnt &&
+                          ((dd->rcd[i]->piocnt / dd->rcd[i]->subctxt_cnt) - 1)
+                          < dd->cspec->updthresh_dflt)
+                               break;
+               spin_unlock_irqrestore(&dd->uctxt_lock, flags);
+               if (i == dd->cfgctxts) {
+                       spin_lock_irqsave(&dd->sendctrl_lock, flags);
+                       dd->cspec->updthresh = dd->cspec->updthresh_dflt;
+                       dd->sendctrl &= ~SYM_MASK(SendCtrl, AvailUpdThld);
+                       dd->sendctrl |= (dd->cspec->updthresh &
+                                        SYM_RMASK(SendCtrl, AvailUpdThld)) <<
+                                          SYM_LSB(SendCtrl, AvailUpdThld);
+                       spin_unlock_irqrestore(&dd->sendctrl_lock, flags);
+                       sendctrl_7322_mod(dd->pport, QIB_SENDCTRL_AVAIL_BLIP);
+               }
+               break;
+
+       case TXCHK_CHG_TYPE_USER:
+               /* for user process */
+               for (i = start; i <= last; i++) {
+                       clear_bit(i, dd->cspec->sendibchk);
+                       set_bit(i, dd->cspec->sendgrhchk);
+               }
+               spin_lock_irqsave(&dd->sendctrl_lock, flags);
+               if (rcd && rcd->subctxt_cnt && ((rcd->piocnt
+                       / rcd->subctxt_cnt) - 1) < dd->cspec->updthresh) {
+                       dd->cspec->updthresh = (rcd->piocnt /
+                                               rcd->subctxt_cnt) - 1;
+                       dd->sendctrl &= ~SYM_MASK(SendCtrl, AvailUpdThld);
+                       dd->sendctrl |= (dd->cspec->updthresh &
+                                       SYM_RMASK(SendCtrl, AvailUpdThld))
+                                       << SYM_LSB(SendCtrl, AvailUpdThld);
+                       spin_unlock_irqrestore(&dd->sendctrl_lock, flags);
+                       sendctrl_7322_mod(dd->pport, QIB_SENDCTRL_AVAIL_BLIP);
+               } else
+                       spin_unlock_irqrestore(&dd->sendctrl_lock, flags);
+               break;
+
+       default:
+               break;
+       }
+
+       for (i = start / BITS_PER_LONG; which >= 2 && i <= lastr; ++i)
+               qib_write_kreg(dd, kr_sendcheckmask + i,
+                              dd->cspec->sendchkenable[i]);
+
+       for (i = start / BITS_PER_LONG; which < 2 && i <= lastr; ++i) {
+               qib_write_kreg(dd, kr_sendgrhcheckmask + i,
+                              dd->cspec->sendgrhchk[i]);
+               qib_write_kreg(dd, kr_sendibpktmask + i,
+                              dd->cspec->sendibchk[i]);
+       }
+
+       /*
+        * Be sure whatever we did was seen by the chip and acted upon,
+        * before we return.  Mostly important for which >= 2.
+        */
+       qib_read_kreg32(dd, kr_scratch);
+}
+
+
+/* useful for trigger analyzers, etc. */
+static void writescratch(struct qib_devdata *dd, u32 val)
+{
+       qib_write_kreg(dd, kr_scratch, val);
+}
+
+/* Dummy for now, use chip regs soon */
+static int qib_7322_tempsense_rd(struct qib_devdata *dd, int regnum)
+{
+       return -ENXIO;
+}
+
+/**
+ * qib_init_iba7322_funcs - set up the chip-specific function pointers
+ * @dev: the pci_dev for qlogic_ib device
+ * @ent: pci_device_id struct for this dev
+ *
+ * Also allocates, inits, and returns the devdata struct for this
+ * device instance
+ *
+ * This is global, and is called directly at init to set up the
+ * chip-specific function pointers for later use.
+ */
+struct qib_devdata *qib_init_iba7322_funcs(struct pci_dev *pdev,
+                                          const struct pci_device_id *ent)
+{
+       struct qib_devdata *dd;
+       int ret, i;
+       u32 tabsize, actual_cnt = 0;
+
+       dd = qib_alloc_devdata(pdev,
+               NUM_IB_PORTS * sizeof(struct qib_pportdata) +
+               sizeof(struct qib_chip_specific) +
+               NUM_IB_PORTS * sizeof(struct qib_chippport_specific));
+       if (IS_ERR(dd))
+               goto bail;
+
+       dd->f_bringup_serdes    = qib_7322_bringup_serdes;
+       dd->f_cleanup           = qib_setup_7322_cleanup;
+       dd->f_clear_tids        = qib_7322_clear_tids;
+       dd->f_free_irq          = qib_7322_free_irq;
+       dd->f_get_base_info     = qib_7322_get_base_info;
+       dd->f_get_msgheader     = qib_7322_get_msgheader;
+       dd->f_getsendbuf        = qib_7322_getsendbuf;
+       dd->f_gpio_mod          = gpio_7322_mod;
+       dd->f_eeprom_wen        = qib_7322_eeprom_wen;
+       dd->f_hdrqempty         = qib_7322_hdrqempty;
+       dd->f_ib_updown         = qib_7322_ib_updown;
+       dd->f_init_ctxt         = qib_7322_init_ctxt;
+       dd->f_initvl15_bufs     = qib_7322_initvl15_bufs;
+       dd->f_intr_fallback     = qib_7322_intr_fallback;
+       dd->f_late_initreg      = qib_late_7322_initreg;
+       dd->f_setpbc_control    = qib_7322_setpbc_control;
+       dd->f_portcntr          = qib_portcntr_7322;
+       dd->f_put_tid           = qib_7322_put_tid;
+       dd->f_quiet_serdes      = qib_7322_mini_quiet_serdes;
+       dd->f_rcvctrl           = rcvctrl_7322_mod;
+       dd->f_read_cntrs        = qib_read_7322cntrs;
+       dd->f_read_portcntrs    = qib_read_7322portcntrs;
+       dd->f_reset             = qib_do_7322_reset;
+       dd->f_init_sdma_regs    = init_sdma_7322_regs;
+       dd->f_sdma_busy         = qib_sdma_7322_busy;
+       dd->f_sdma_gethead      = qib_sdma_7322_gethead;
+       dd->f_sdma_sendctrl     = qib_7322_sdma_sendctrl;
+       dd->f_sdma_set_desc_cnt = qib_sdma_set_7322_desc_cnt;
+       dd->f_sdma_update_tail  = qib_sdma_update_7322_tail;
+       dd->f_sendctrl          = sendctrl_7322_mod;
+       dd->f_set_armlaunch     = qib_set_7322_armlaunch;
+       dd->f_set_cntr_sample   = qib_set_cntr_7322_sample;
+       dd->f_iblink_state      = qib_7322_iblink_state;
+       dd->f_ibphys_portstate  = qib_7322_phys_portstate;
+       dd->f_get_ib_cfg        = qib_7322_get_ib_cfg;
+       dd->f_set_ib_cfg        = qib_7322_set_ib_cfg;
+       dd->f_set_ib_loopback   = qib_7322_set_loopback;
+       dd->f_get_ib_table      = qib_7322_get_ib_table;
+       dd->f_set_ib_table      = qib_7322_set_ib_table;
+       dd->f_set_intr_state    = qib_7322_set_intr_state;
+       dd->f_setextled         = qib_setup_7322_setextled;
+       dd->f_txchk_change      = qib_7322_txchk_change;
+       dd->f_update_usrhead    = qib_update_7322_usrhead;
+       dd->f_wantpiobuf_intr   = qib_wantpiobuf_7322_intr;
+       dd->f_xgxs_reset        = qib_7322_mini_pcs_reset;
+       dd->f_sdma_hw_clean_up  = qib_7322_sdma_hw_clean_up;
+       dd->f_sdma_hw_start_up  = qib_7322_sdma_hw_start_up;
+       dd->f_sdma_init_early   = qib_7322_sdma_init_early;
+       dd->f_writescratch      = writescratch;
+       dd->f_tempsense_rd      = qib_7322_tempsense_rd;
+       /*
+        * Do remaining PCIe setup and save PCIe values in dd.
+        * Any error printing is already done by the init code.
+        * On return, we have the chip mapped, but chip registers
+        * are not set up until start of qib_init_7322_variables.
+        */
+       ret = qib_pcie_ddinit(dd, pdev, ent);
+       if (ret < 0)
+               goto bail_free;
+
+       /* initialize chip-specific variables */
+       ret = qib_init_7322_variables(dd);
+       if (ret)
+               goto bail_cleanup;
+
+       if (qib_mini_init || !dd->num_pports)
+               goto bail;
+
+       /*
+        * Determine number of vectors we want; depends on port count
+        * and number of configured kernel receive queues actually used.
+        * Should also depend on whether sdma is enabled or not, but
+        * that's such a rare testing case it's not worth worrying about.
+        */
+       tabsize = dd->first_user_ctxt + ARRAY_SIZE(irq_table);
+       for (i = 0; i < tabsize; i++)
+               if ((i < ARRAY_SIZE(irq_table) &&
+                    irq_table[i].port <= dd->num_pports) ||
+                   (i >= ARRAY_SIZE(irq_table) &&
+                    dd->rcd[i - ARRAY_SIZE(irq_table)]))
+                       actual_cnt++;
+       tabsize = actual_cnt;
+       dd->cspec->msix_entries = kmalloc(tabsize *
+                       sizeof(struct msix_entry), GFP_KERNEL);
+       dd->cspec->msix_arg = kmalloc(tabsize *
+                       sizeof(void *), GFP_KERNEL);
+       if (!dd->cspec->msix_entries || !dd->cspec->msix_arg) {
+               qib_dev_err(dd, "No memory for MSIx table\n");
+               tabsize = 0;
+       }
+       for (i = 0; i < tabsize; i++)
+               dd->cspec->msix_entries[i].entry = i;
+
+       if (qib_pcie_params(dd, 8, &tabsize, dd->cspec->msix_entries))
+               qib_dev_err(dd, "Failed to setup PCIe or interrupts; "
+                           "continuing anyway\n");
+       /* may be less than we wanted, if not enough available */
+       dd->cspec->num_msix_entries = tabsize;
+
+       /* setup interrupt handler */
+       qib_setup_7322_interrupt(dd, 1);
+
+       /* clear diagctrl register, in case diags were running and crashed */
+       qib_write_kreg(dd, kr_hwdiagctrl, 0);
+
+       goto bail;
+
+bail_cleanup:
+       qib_pcie_ddcleanup(dd);
+bail_free:
+       qib_free_devdata(dd);
+       dd = ERR_PTR(ret);
+bail:
+       return dd;
+}
+
+/*
+ * Set the table entry at the specified index from the table specifed.
+ * There are 3 * TXDDS_TABLE_SZ entries in all per port, with the first
+ * TXDDS_TABLE_SZ for SDR, the next for DDR, and the last for QDR.
+ * 'idx' below addresses the correct entry, while its 4 LSBs select the
+ * corresponding entry (one of TXDDS_TABLE_SZ) from the selected table.
+ */
+#define DDS_ENT_AMP_LSB 14
+#define DDS_ENT_MAIN_LSB 9
+#define DDS_ENT_POST_LSB 5
+#define DDS_ENT_PRE_XTRA_LSB 3
+#define DDS_ENT_PRE_LSB 0
+
+/*
+ * Set one entry in the TxDDS table for spec'd port
+ * ridx picks one of the entries, while tp points
+ * to the appropriate table entry.
+ */
+static void set_txdds(struct qib_pportdata *ppd, int ridx,
+                     const struct txdds_ent *tp)
+{
+       struct qib_devdata *dd = ppd->dd;
+       u32 pack_ent;
+       int regidx;
+
+       /* Get correct offset in chip-space, and in source table */
+       regidx = KREG_IBPORT_IDX(IBSD_DDS_MAP_TABLE) + ridx;
+       /*
+        * We do not use qib_write_kreg_port() because it was intended
+        * only for registers in the lower "port specific" pages.
+        * So do index calculation  by hand.
+        */
+       if (ppd->hw_pidx)
+               regidx += (dd->palign / sizeof(u64));
+
+       pack_ent = tp->amp << DDS_ENT_AMP_LSB;
+       pack_ent |= tp->main << DDS_ENT_MAIN_LSB;
+       pack_ent |= tp->pre << DDS_ENT_PRE_LSB;
+       pack_ent |= tp->post << DDS_ENT_POST_LSB;
+       qib_write_kreg(dd, regidx, pack_ent);
+       /* Prevent back-to-back writes by hitting scratch */
+       qib_write_kreg(ppd->dd, kr_scratch, 0);
+}
+
+static const struct vendor_txdds_ent vendor_txdds[] = {
+       { /* Amphenol 1m 30awg NoEq */
+               { 0x41, 0x50, 0x48 }, "584470002       ",
+               { 10,  0,  0,  5 }, { 10,  0,  0,  9 }, {  7,  1,  0, 13 },
+       },
+       { /* Amphenol 3m 28awg NoEq */
+               { 0x41, 0x50, 0x48 }, "584470004       ",
+               {  0,  0,  0,  8 }, {  0,  0,  0, 11 }, {  0,  1,  7, 15 },
+       },
+       { /* Finisar 3m OM2 Optical */
+               { 0x00, 0x90, 0x65 }, "FCBG410QB1C03-QL",
+               {  0,  0,  0,  3 }, {  0,  0,  0,  4 }, {  0,  0,  0, 13 },
+       },
+       { /* Finisar 30m OM2 Optical */
+               { 0x00, 0x90, 0x65 }, "FCBG410QB1C30-QL",
+               {  0,  0,  0,  1 }, {  0,  0,  0,  5 }, {  0,  0,  0, 11 },
+       },
+       { /* Finisar Default OM2 Optical */
+               { 0x00, 0x90, 0x65 }, NULL,
+               {  0,  0,  0,  2 }, {  0,  0,  0,  5 }, {  0,  0,  0, 12 },
+       },
+       { /* Gore 1m 30awg NoEq */
+               { 0x00, 0x21, 0x77 }, "QSN3300-1       ",
+               {  0,  0,  0,  6 }, {  0,  0,  0,  9 }, {  0,  1,  0, 15 },
+       },
+       { /* Gore 2m 30awg NoEq */
+               { 0x00, 0x21, 0x77 }, "QSN3300-2       ",
+               {  0,  0,  0,  8 }, {  0,  0,  0, 10 }, {  0,  1,  7, 15 },
+       },
+       { /* Gore 1m 28awg NoEq */
+               { 0x00, 0x21, 0x77 }, "QSN3800-1       ",
+               {  0,  0,  0,  6 }, {  0,  0,  0,  8 }, {  0,  1,  0, 15 },
+       },
+       { /* Gore 3m 28awg NoEq */
+               { 0x00, 0x21, 0x77 }, "QSN3800-3       ",
+               {  0,  0,  0,  9 }, {  0,  0,  0, 13 }, {  0,  1,  7, 15 },
+       },
+       { /* Gore 5m 24awg Eq */
+               { 0x00, 0x21, 0x77 }, "QSN7000-5       ",
+               {  0,  0,  0,  7 }, {  0,  0,  0,  9 }, {  0,  1,  3, 15 },
+       },
+       { /* Gore 7m 24awg Eq */
+               { 0x00, 0x21, 0x77 }, "QSN7000-7       ",
+               {  0,  0,  0,  9 }, {  0,  0,  0, 11 }, {  0,  2,  6, 15 },
+       },
+       { /* Gore 5m 26awg Eq */
+               { 0x00, 0x21, 0x77 }, "QSN7600-5       ",
+               {  0,  0,  0,  8 }, {  0,  0,  0, 11 }, {  0,  1,  9, 13 },
+       },
+       { /* Gore 7m 26awg Eq */
+               { 0x00, 0x21, 0x77 }, "QSN7600-7       ",
+               {  0,  0,  0,  8 }, {  0,  0,  0, 11 }, {  10,  1,  8, 15 },
+       },
+       { /* Intersil 12m 24awg Active */
+               { 0x00, 0x30, 0xB4 }, "QLX4000CQSFP1224",
+               {  0,  0,  0,  2 }, {  0,  0,  0,  5 }, {  0,  3,  0,  9 },
+       },
+       { /* Intersil 10m 28awg Active */
+               { 0x00, 0x30, 0xB4 }, "QLX4000CQSFP1028",
+               {  0,  0,  0,  6 }, {  0,  0,  0,  4 }, {  0,  2,  0,  2 },
+       },
+       { /* Intersil 7m 30awg Active */
+               { 0x00, 0x30, 0xB4 }, "QLX4000CQSFP0730",
+               {  0,  0,  0,  6 }, {  0,  0,  0,  4 }, {  0,  1,  0,  3 },
+       },
+       { /* Intersil 5m 32awg Active */
+               { 0x00, 0x30, 0xB4 }, "QLX4000CQSFP0532",
+               {  0,  0,  0,  6 }, {  0,  0,  0,  6 }, {  0,  2,  0,  8 },
+       },
+       { /* Intersil Default Active */
+               { 0x00, 0x30, 0xB4 }, NULL,
+               {  0,  0,  0,  6 }, {  0,  0,  0,  5 }, {  0,  2,  0,  5 },
+       },
+       { /* Luxtera 20m Active Optical */
+               { 0x00, 0x25, 0x63 }, NULL,
+               {  0,  0,  0,  5 }, {  0,  0,  0,  8 }, {  0,  2,  0,  12 },
+       },
+       { /* Molex 1M Cu loopback */
+               { 0x00, 0x09, 0x3A }, "74763-0025      ",
+               {  2,  2,  6, 15 }, {  2,  2,  6, 15 }, {  2,  2,  6, 15 },
+       },
+       { /* Molex 2m 28awg NoEq */
+               { 0x00, 0x09, 0x3A }, "74757-2201      ",
+               {  0,  0,  0,  6 }, {  0,  0,  0,  9 }, {  0,  1,  1, 15 },
+       },
+};
+
+static const struct txdds_ent txdds_sdr[TXDDS_TABLE_SZ] = {
+       /* amp, pre, main, post */
+       {  2, 2, 15,  6 },      /* Loopback */
+       {  0, 0,  0,  1 },      /*  2 dB */
+       {  0, 0,  0,  2 },      /*  3 dB */
+       {  0, 0,  0,  3 },      /*  4 dB */
+       {  0, 0,  0,  4 },      /*  5 dB */
+       {  0, 0,  0,  5 },      /*  6 dB */
+       {  0, 0,  0,  6 },      /*  7 dB */
+       {  0, 0,  0,  7 },      /*  8 dB */
+       {  0, 0,  0,  8 },      /*  9 dB */
+       {  0, 0,  0,  9 },      /* 10 dB */
+       {  0, 0,  0, 10 },      /* 11 dB */
+       {  0, 0,  0, 11 },      /* 12 dB */
+       {  0, 0,  0, 12 },      /* 13 dB */
+       {  0, 0,  0, 13 },      /* 14 dB */
+       {  0, 0,  0, 14 },      /* 15 dB */
+       {  0, 0,  0, 15 },      /* 16 dB */
+};
+
+static const struct txdds_ent txdds_ddr[TXDDS_TABLE_SZ] = {
+       /* amp, pre, main, post */
+       {  2, 2, 15,  6 },      /* Loopback */
+       {  0, 0,  0,  8 },      /*  2 dB */
+       {  0, 0,  0,  8 },      /*  3 dB */
+       {  0, 0,  0,  9 },      /*  4 dB */
+       {  0, 0,  0,  9 },      /*  5 dB */
+       {  0, 0,  0, 10 },      /*  6 dB */
+       {  0, 0,  0, 10 },      /*  7 dB */
+       {  0, 0,  0, 11 },      /*  8 dB */
+       {  0, 0,  0, 11 },      /*  9 dB */
+       {  0, 0,  0, 12 },      /* 10 dB */
+       {  0, 0,  0, 12 },      /* 11 dB */
+       {  0, 0,  0, 13 },      /* 12 dB */
+       {  0, 0,  0, 13 },      /* 13 dB */
+       {  0, 0,  0, 14 },      /* 14 dB */
+       {  0, 0,  0, 14 },      /* 15 dB */
+       {  0, 0,  0, 15 },      /* 16 dB */
+};
+
+static const struct txdds_ent txdds_qdr[TXDDS_TABLE_SZ] = {
+       /* amp, pre, main, post */
+       {  2, 2, 15,  6 },      /* Loopback */
+       {  0, 1,  0,  7 },      /*  2 dB (also QMH7342) */
+       {  0, 1,  0,  9 },      /*  3 dB (also QMH7342) */
+       {  0, 1,  0, 11 },      /*  4 dB */
+       {  0, 1,  0, 13 },      /*  5 dB */
+       {  0, 1,  0, 15 },      /*  6 dB */
+       {  0, 1,  3, 15 },      /*  7 dB */
+       {  0, 1,  7, 15 },      /*  8 dB */
+       {  0, 1,  7, 15 },      /*  9 dB */
+       {  0, 1,  8, 15 },      /* 10 dB */
+       {  0, 1,  9, 15 },      /* 11 dB */
+       {  0, 1, 10, 15 },      /* 12 dB */
+       {  0, 2,  6, 15 },      /* 13 dB */
+       {  0, 2,  7, 15 },      /* 14 dB */
+       {  0, 2,  8, 15 },      /* 15 dB */
+       {  0, 2,  9, 15 },      /* 16 dB */
+};
+
+/*
+ * extra entries for use with txselect, for indices >= TXDDS_TABLE_SZ.
+ * These are mostly used for mez cards going through connectors
+ * and backplane traces, but can be used to add other "unusual"
+ * table values as well.
+ */
+static const struct txdds_ent txdds_extra_sdr[TXDDS_EXTRA_SZ] = {
+       /* amp, pre, main, post */
+       {  0, 0, 0,  1 },       /* QMH7342 backplane settings */
+       {  0, 0, 0,  1 },       /* QMH7342 backplane settings */
+       {  0, 0, 0,  2 },       /* QMH7342 backplane settings */
+       {  0, 0, 0,  2 },       /* QMH7342 backplane settings */
+       {  0, 0, 0, 11 },       /* QME7342 backplane settings */
+       {  0, 0, 0, 11 },       /* QME7342 backplane settings */
+       {  0, 0, 0, 11 },       /* QME7342 backplane settings */
+       {  0, 0, 0, 11 },       /* QME7342 backplane settings */
+       {  0, 0, 0, 11 },       /* QME7342 backplane settings */
+       {  0, 0, 0, 11 },       /* QME7342 backplane settings */
+       {  0, 0, 0, 11 },       /* QME7342 backplane settings */
+};
+
+static const struct txdds_ent txdds_extra_ddr[TXDDS_EXTRA_SZ] = {
+       /* amp, pre, main, post */
+       {  0, 0, 0,  7 },       /* QMH7342 backplane settings */
+       {  0, 0, 0,  7 },       /* QMH7342 backplane settings */
+       {  0, 0, 0,  8 },       /* QMH7342 backplane settings */
+       {  0, 0, 0,  8 },       /* QMH7342 backplane settings */
+       {  0, 0, 0, 13 },       /* QME7342 backplane settings */
+       {  0, 0, 0, 13 },       /* QME7342 backplane settings */
+       {  0, 0, 0, 13 },       /* QME7342 backplane settings */
+       {  0, 0, 0, 13 },       /* QME7342 backplane settings */
+       {  0, 0, 0, 13 },       /* QME7342 backplane settings */
+       {  0, 0, 0, 13 },       /* QME7342 backplane settings */
+       {  0, 0, 0, 13 },       /* QME7342 backplane settings */
+};
+
+static const struct txdds_ent txdds_extra_qdr[TXDDS_EXTRA_SZ] = {
+       /* amp, pre, main, post */
+       {  0, 1,  0,  4 },      /* QMH7342 backplane settings */
+       {  0, 1,  0,  5 },      /* QMH7342 backplane settings */
+       {  0, 1,  0,  6 },      /* QMH7342 backplane settings */
+       {  0, 1,  0,  8 },      /* QMH7342 backplane settings */
+       {  0, 1, 12, 10 },      /* QME7342 backplane setting */
+       {  0, 1, 12, 11 },      /* QME7342 backplane setting */
+       {  0, 1, 12, 12 },      /* QME7342 backplane setting */
+       {  0, 1, 12, 14 },      /* QME7342 backplane setting */
+       {  0, 1, 12,  6 },      /* QME7342 backplane setting */
+       {  0, 1, 12,  7 },      /* QME7342 backplane setting */
+       {  0, 1, 12,  8 },      /* QME7342 backplane setting */
+};
+
+static const struct txdds_ent *get_atten_table(const struct txdds_ent *txdds,
+                                              unsigned atten)
+{
+       /*
+        * The attenuation table starts at 2dB for entry 1,
+        * with entry 0 being the loopback entry.
+        */
+       if (atten <= 2)
+               atten = 1;
+       else if (atten > TXDDS_TABLE_SZ)
+               atten = TXDDS_TABLE_SZ - 1;
+       else
+               atten--;
+       return txdds + atten;
+}
+
+/*
+ * if override is set, the module parameter txselect has a value
+ * for this specific port, so use it, rather than our normal mechanism.
+ */
+static void find_best_ent(struct qib_pportdata *ppd,
+                         const struct txdds_ent **sdr_dds,
+                         const struct txdds_ent **ddr_dds,
+                         const struct txdds_ent **qdr_dds, int override)
+{
+       struct qib_qsfp_cache *qd = &ppd->cpspec->qsfp_data.cache;
+       int idx;
+
+       /* Search table of known cables */
+       for (idx = 0; !override && idx < ARRAY_SIZE(vendor_txdds); ++idx) {
+               const struct vendor_txdds_ent *v = vendor_txdds + idx;
+
+               if (!memcmp(v->oui, qd->oui, QSFP_VOUI_LEN) &&
+                   (!v->partnum ||
+                    !memcmp(v->partnum, qd->partnum, QSFP_PN_LEN))) {
+                       *sdr_dds = &v->sdr;
+                       *ddr_dds = &v->ddr;
+                       *qdr_dds = &v->qdr;
+                       return;
+               }
+       }
+
+       /* Lookup serdes setting by cable type and attenuation */
+       if (!override && QSFP_IS_ACTIVE(qd->tech)) {
+               *sdr_dds = txdds_sdr + ppd->dd->board_atten;
+               *ddr_dds = txdds_ddr + ppd->dd->board_atten;
+               *qdr_dds = txdds_qdr + ppd->dd->board_atten;
+               return;
+       }
+
+       if (!override && QSFP_HAS_ATTEN(qd->tech) && (qd->atten[0] ||
+                                                     qd->atten[1])) {
+               *sdr_dds = get_atten_table(txdds_sdr, qd->atten[0]);
+               *ddr_dds = get_atten_table(txdds_ddr, qd->atten[0]);
+               *qdr_dds = get_atten_table(txdds_qdr, qd->atten[1]);
+               return;
+       } else if (ppd->cpspec->no_eep < TXDDS_TABLE_SZ) {
+               /*
+                * If we have no (or incomplete) data from the cable
+                * EEPROM, or no QSFP, or override is set, use the
+                * module parameter value to index into the attentuation
+                * table.
+                */
+               idx = ppd->cpspec->no_eep;
+               *sdr_dds = &txdds_sdr[idx];
+               *ddr_dds = &txdds_ddr[idx];
+               *qdr_dds = &txdds_qdr[idx];
+       } else if (ppd->cpspec->no_eep < (TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ)) {
+               /* similar to above, but index into the "extra" table. */
+               idx = ppd->cpspec->no_eep - TXDDS_TABLE_SZ;
+               *sdr_dds = &txdds_extra_sdr[idx];
+               *ddr_dds = &txdds_extra_ddr[idx];
+               *qdr_dds = &txdds_extra_qdr[idx];
+       } else {
+               /* this shouldn't happen, it's range checked */
+               *sdr_dds = txdds_sdr + qib_long_atten;
+               *ddr_dds = txdds_ddr + qib_long_atten;
+               *qdr_dds = txdds_qdr + qib_long_atten;
+       }
+}
+
+static void init_txdds_table(struct qib_pportdata *ppd, int override)
+{
+       const struct txdds_ent *sdr_dds, *ddr_dds, *qdr_dds;
+       struct txdds_ent *dds;
+       int idx;
+       int single_ent = 0;
+
+       find_best_ent(ppd, &sdr_dds, &ddr_dds, &qdr_dds, override);
+
+       /* for mez cards or override, use the selected value for all entries */
+       if (!(ppd->dd->flags & QIB_HAS_QSFP) || override)
+               single_ent = 1;
+
+       /* Fill in the first entry with the best entry found. */
+       set_txdds(ppd, 0, sdr_dds);
+       set_txdds(ppd, TXDDS_TABLE_SZ, ddr_dds);
+       set_txdds(ppd, 2 * TXDDS_TABLE_SZ, qdr_dds);
+       if (ppd->lflags & (QIBL_LINKINIT | QIBL_LINKARMED |
+               QIBL_LINKACTIVE)) {
+               dds = (struct txdds_ent *)(ppd->link_speed_active ==
+                                          QIB_IB_QDR ?  qdr_dds :
+                                          (ppd->link_speed_active ==
+                                           QIB_IB_DDR ? ddr_dds : sdr_dds));
+               write_tx_serdes_param(ppd, dds);
+       }
+
+       /* Fill in the remaining entries with the default table values. */
+       for (idx = 1; idx < ARRAY_SIZE(txdds_sdr); ++idx) {
+               set_txdds(ppd, idx, single_ent ? sdr_dds : txdds_sdr + idx);
+               set_txdds(ppd, idx + TXDDS_TABLE_SZ,
+                         single_ent ? ddr_dds : txdds_ddr + idx);
+               set_txdds(ppd, idx + 2 * TXDDS_TABLE_SZ,
+                         single_ent ? qdr_dds : txdds_qdr + idx);
+       }
+}
+
+#define KR_AHB_ACC KREG_IDX(ahb_access_ctrl)
+#define KR_AHB_TRANS KREG_IDX(ahb_transaction_reg)
+#define AHB_TRANS_RDY SYM_MASK(ahb_transaction_reg, ahb_rdy)
+#define AHB_ADDR_LSB SYM_LSB(ahb_transaction_reg, ahb_address)
+#define AHB_DATA_LSB SYM_LSB(ahb_transaction_reg, ahb_data)
+#define AHB_WR SYM_MASK(ahb_transaction_reg, write_not_read)
+#define AHB_TRANS_TRIES 10
+
+/*
+ * The chan argument is 0=chan0, 1=chan1, 2=pll, 3=chan2, 4=chan4,
+ * 5=subsystem which is why most calls have "chan + chan >> 1"
+ * for the channel argument.
+ */
+static u32 ahb_mod(struct qib_devdata *dd, int quad, int chan, int addr,
+                   u32 data, u32 mask)
+{
+       u32 rd_data, wr_data, sz_mask;
+       u64 trans, acc, prev_acc;
+       u32 ret = 0xBAD0BAD;
+       int tries;
+
+       prev_acc = qib_read_kreg64(dd, KR_AHB_ACC);
+       /* From this point on, make sure we return access */
+       acc = (quad << 1) | 1;
+       qib_write_kreg(dd, KR_AHB_ACC, acc);
+
+       for (tries = 1; tries < AHB_TRANS_TRIES; ++tries) {
+               trans = qib_read_kreg64(dd, KR_AHB_TRANS);
+               if (trans & AHB_TRANS_RDY)
+                       break;
+       }
+       if (tries >= AHB_TRANS_TRIES) {
+               qib_dev_err(dd, "No ahb_rdy in %d tries\n", AHB_TRANS_TRIES);
+               goto bail;
+       }
+
+       /* If mask is not all 1s, we need to read, but different SerDes
+        * entities have different sizes
+        */
+       sz_mask = (1UL << ((quad == 1) ? 32 : 16)) - 1;
+       wr_data = data & mask & sz_mask;
+       if ((~mask & sz_mask) != 0) {
+               trans = ((chan << 6) | addr) << (AHB_ADDR_LSB + 1);
+               qib_write_kreg(dd, KR_AHB_TRANS, trans);
+
+               for (tries = 1; tries < AHB_TRANS_TRIES; ++tries) {
+                       trans = qib_read_kreg64(dd, KR_AHB_TRANS);
+                       if (trans & AHB_TRANS_RDY)
+                               break;
+               }
+               if (tries >= AHB_TRANS_TRIES) {
+                       qib_dev_err(dd, "No Rd ahb_rdy in %d tries\n",
+                                   AHB_TRANS_TRIES);
+                       goto bail;
+               }
+               /* Re-read in case host split reads and read data first */
+               trans = qib_read_kreg64(dd, KR_AHB_TRANS);
+               rd_data = (uint32_t)(trans >> AHB_DATA_LSB);
+               wr_data |= (rd_data & ~mask & sz_mask);
+       }
+
+       /* If mask is not zero, we need to write. */
+       if (mask & sz_mask) {
+               trans = ((chan << 6) | addr) << (AHB_ADDR_LSB + 1);
+               trans |= ((uint64_t)wr_data << AHB_DATA_LSB);
+               trans |= AHB_WR;
+               qib_write_kreg(dd, KR_AHB_TRANS, trans);
+
+               for (tries = 1; tries < AHB_TRANS_TRIES; ++tries) {
+                       trans = qib_read_kreg64(dd, KR_AHB_TRANS);
+                       if (trans & AHB_TRANS_RDY)
+                               break;
+               }
+               if (tries >= AHB_TRANS_TRIES) {
+                       qib_dev_err(dd, "No Wr ahb_rdy in %d tries\n",
+                                   AHB_TRANS_TRIES);
+                       goto bail;
+               }
+       }
+       ret = wr_data;
+bail:
+       qib_write_kreg(dd, KR_AHB_ACC, prev_acc);
+       return ret;
+}
+
+static void ibsd_wr_allchans(struct qib_pportdata *ppd, int addr, unsigned data,
+                            unsigned mask)
+{
+       struct qib_devdata *dd = ppd->dd;
+       int chan;
+       u32 rbc;
+
+       for (chan = 0; chan < SERDES_CHANS; ++chan) {
+               ahb_mod(dd, IBSD(ppd->hw_pidx), (chan + (chan >> 1)), addr,
+                       data, mask);
+               rbc = ahb_mod(dd, IBSD(ppd->hw_pidx), (chan + (chan >> 1)),
+                             addr, 0, 0);
+       }
+}
+
+static int serdes_7322_init(struct qib_pportdata *ppd)
+{
+       u64 data;
+       u32 le_val;
+
+       /*
+        * Initialize the Tx DDS tables.  Also done every QSFP event,
+        * for adapters with QSFP
+        */
+       init_txdds_table(ppd, 0);
+
+       /* ensure no tx overrides from earlier driver loads */
+       qib_write_kreg_port(ppd, krp_tx_deemph_override,
+               SYM_MASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
+               reset_tx_deemphasis_override));
+
+       /* Patch some SerDes defaults to "Better for IB" */
+       /* Timing Loop Bandwidth: cdr_timing[11:9] = 0 */
+       ibsd_wr_allchans(ppd, 2, 0, BMASK(11, 9));
+
+       /* Termination: rxtermctrl_r2d addr 11 bits [12:11] = 1 */
+       ibsd_wr_allchans(ppd, 11, (1 << 11), BMASK(12, 11));
+       /* Enable LE2: rxle2en_r2a addr 13 bit [6] = 1 */
+       ibsd_wr_allchans(ppd, 13, (1 << 6), (1 << 6));
+
+       /* May be overridden in qsfp_7322_event */
+       le_val = IS_QME(ppd->dd) ? LE2_QME : LE2_DEFAULT;
+       ibsd_wr_allchans(ppd, 13, (le_val << 7), BMASK(9, 7));
+
+       /* enable LE1 adaptation for all but QME, which is disabled */
+       le_val = IS_QME(ppd->dd) ? 0 : 1;
+       ibsd_wr_allchans(ppd, 13, (le_val << 5), (1 << 5));
+
+       /* Clear cmode-override, may be set from older driver */
+       ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 10, 0 << 14, 1 << 14);
+
+       /* Timing Recovery: rxtapsel addr 5 bits [9:8] = 0 */
+       ibsd_wr_allchans(ppd, 5, (0 << 8), BMASK(9, 8));
+
+       /* setup LoS params; these are subsystem, so chan == 5 */
+       /* LoS filter threshold_count on, ch 0-3, set to 8 */
+       ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 5, 8 << 11, BMASK(14, 11));
+       ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 7, 8 << 4, BMASK(7, 4));
+       ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 8, 8 << 11, BMASK(14, 11));
+       ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 10, 8 << 4, BMASK(7, 4));
+
+       /* LoS filter threshold_count off, ch 0-3, set to 4 */
+       ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 6, 4 << 0, BMASK(3, 0));
+       ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 7, 4 << 8, BMASK(11, 8));
+       ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 9, 4 << 0, BMASK(3, 0));
+       ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 10, 4 << 8, BMASK(11, 8));
+
+       /* LoS filter select enabled */
+       ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 9, 1 << 15, 1 << 15);
+
+       /* LoS target data:  SDR=4, DDR=2, QDR=1 */
+       ibsd_wr_allchans(ppd, 14, (1 << 3), BMASK(5, 3)); /* QDR */
+       ibsd_wr_allchans(ppd, 20, (2 << 10), BMASK(12, 10)); /* DDR */
+       ibsd_wr_allchans(ppd, 20, (4 << 13), BMASK(15, 13)); /* SDR */
+
+       data = qib_read_kreg_port(ppd, krp_serdesctrl);
+       qib_write_kreg_port(ppd, krp_serdesctrl, data |
+               SYM_MASK(IBSerdesCtrl_0, RXLOSEN));
+
+       /* rxbistena; set 0 to avoid effects of it switch later */
+       ibsd_wr_allchans(ppd, 9, 0 << 15, 1 << 15);
+
+       /* Configure 4 DFE taps, and only they adapt */
+       ibsd_wr_allchans(ppd, 16, 0 << 0, BMASK(1, 0));
+
+       /* gain hi stop 32 (22) (6:1) lo stop 7 (10:7) target 22 (13) (15:11) */
+       le_val = (ppd->dd->cspec->r1 || IS_QME(ppd->dd)) ? 0xb6c0 : 0x6bac;
+       ibsd_wr_allchans(ppd, 21, le_val, 0xfffe);
+
+       /*
+        * Set receive adaptation mode.  SDR and DDR adaptation are
+        * always on, and QDR is initially enabled; later disabled.
+        */
+       qib_write_kreg_port(ppd, krp_static_adapt_dis(0), 0ULL);
+       qib_write_kreg_port(ppd, krp_static_adapt_dis(1), 0ULL);
+       qib_write_kreg_port(ppd, krp_static_adapt_dis(2),
+                           ppd->dd->cspec->r1 ?
+                           QDR_STATIC_ADAPT_DOWN_R1 : QDR_STATIC_ADAPT_DOWN);
+       ppd->cpspec->qdr_dfe_on = 1;
+
+       /* FLoop LOS gate: PPM filter  enabled */
+       ibsd_wr_allchans(ppd, 38, 0 << 10, 1 << 10);
+
+       /* rx offset center enabled */
+       ibsd_wr_allchans(ppd, 12, 1 << 4, 1 << 4);
+
+       if (!ppd->dd->cspec->r1) {
+               ibsd_wr_allchans(ppd, 12, 1 << 12, 1 << 12);
+               ibsd_wr_allchans(ppd, 12, 2 << 8, 0x0f << 8);
+       }
+
+       /* Set the frequency loop bandwidth to 15 */
+       ibsd_wr_allchans(ppd, 2, 15 << 5, BMASK(8, 5));
+
+       return 0;
+}
+
+/* start adjust QMH serdes parameters */
+
+static void set_man_code(struct qib_pportdata *ppd, int chan, int code)
+{
+       ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), (chan + (chan >> 1)),
+               9, code << 9, 0x3f << 9);
+}
+
+static void set_man_mode_h1(struct qib_pportdata *ppd, int chan,
+       int enable, u32 tapenable)
+{
+       if (enable)
+               ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), (chan + (chan >> 1)),
+                       1, 3 << 10, 0x1f << 10);
+       else
+               ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), (chan + (chan >> 1)),
+                       1, 0, 0x1f << 10);
+}
+
+/* Set clock to 1, 0, 1, 0 */
+static void clock_man(struct qib_pportdata *ppd, int chan)
+{
+       ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), (chan + (chan >> 1)),
+               4, 0x4000, 0x4000);
+       ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), (chan + (chan >> 1)),
+               4, 0, 0x4000);
+       ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), (chan + (chan >> 1)),
+               4, 0x4000, 0x4000);
+       ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), (chan + (chan >> 1)),
+               4, 0, 0x4000);
+}
+
+/*
+ * write the current Tx serdes pre,post,main,amp settings into the serdes.
+ * The caller must pass the settings appropriate for the current speed,
+ * or not care if they are correct for the current speed.
+ */
+static void write_tx_serdes_param(struct qib_pportdata *ppd,
+                                 struct txdds_ent *txdds)
+{
+       u64 deemph;
+
+       deemph = qib_read_kreg_port(ppd, krp_tx_deemph_override);
+       /* field names for amp, main, post, pre, respectively */
+       deemph &= ~(SYM_MASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0, txampcntl_d2a) |
+                   SYM_MASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0, txc0_ena) |
+                   SYM_MASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0, txcp1_ena) |
+                   SYM_MASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0, txcn1_ena));
+
+       deemph |= SYM_MASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
+                          tx_override_deemphasis_select);
+       deemph |= (txdds->amp & SYM_RMASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
+                   txampcntl_d2a)) << SYM_LSB(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
+                                      txampcntl_d2a);
+       deemph |= (txdds->main & SYM_RMASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
+                    txc0_ena)) << SYM_LSB(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
+                                  txc0_ena);
+       deemph |= (txdds->post & SYM_RMASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
+                    txcp1_ena)) << SYM_LSB(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
+                                   txcp1_ena);
+       deemph |= (txdds->pre & SYM_RMASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
+                    txcn1_ena)) << SYM_LSB(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
+                                   txcn1_ena);
+       qib_write_kreg_port(ppd, krp_tx_deemph_override, deemph);
+}
+
+/*
+ * Set the parameters for mez cards on link bounce, so they are
+ * always exactly what was requested.  Similar logic to init_txdds
+ * but does just the serdes.
+ */
+static void adj_tx_serdes(struct qib_pportdata *ppd)
+{
+       const struct txdds_ent *sdr_dds, *ddr_dds, *qdr_dds;
+       struct txdds_ent *dds;
+
+       find_best_ent(ppd, &sdr_dds, &ddr_dds, &qdr_dds, 1);
+       dds = (struct txdds_ent *)(ppd->link_speed_active == QIB_IB_QDR ?
+               qdr_dds : (ppd->link_speed_active == QIB_IB_DDR ?
+                               ddr_dds : sdr_dds));
+       write_tx_serdes_param(ppd, dds);
+}
+
+/* set QDR forced value for H1, if needed */
+static void force_h1(struct qib_pportdata *ppd)
+{
+       int chan;
+
+       ppd->cpspec->qdr_reforce = 0;
+       if (!ppd->dd->cspec->r1)
+               return;
+
+       for (chan = 0; chan < SERDES_CHANS; chan++) {
+               set_man_mode_h1(ppd, chan, 1, 0);
+               set_man_code(ppd, chan, ppd->cpspec->h1_val);
+               clock_man(ppd, chan);
+               set_man_mode_h1(ppd, chan, 0, 0);
+       }
+}
+
+#define SJA_EN SYM_MASK(SPC_JTAG_ACCESS_REG, SPC_JTAG_ACCESS_EN)
+#define BISTEN_LSB SYM_LSB(SPC_JTAG_ACCESS_REG, bist_en)
+
+#define R_OPCODE_LSB 3
+#define R_OP_NOP 0
+#define R_OP_SHIFT 2
+#define R_OP_UPDATE 3
+#define R_TDI_LSB 2
+#define R_TDO_LSB 1
+#define R_RDY 1
+
+static int qib_r_grab(struct qib_devdata *dd)
+{
+       u64 val;
+       val = SJA_EN;
+       qib_write_kreg(dd, kr_r_access, val);
+       qib_read_kreg32(dd, kr_scratch);
+       return 0;
+}
+
+/* qib_r_wait_for_rdy() not only waits for the ready bit, it
+ * returns the current state of R_TDO
+ */
+static int qib_r_wait_for_rdy(struct qib_devdata *dd)
+{
+       u64 val;
+       int timeout;
+       for (timeout = 0; timeout < 100 ; ++timeout) {
+               val = qib_read_kreg32(dd, kr_r_access);
+               if (val & R_RDY)
+                       return (val >> R_TDO_LSB) & 1;
+       }
+       return -1;
+}
+
+static int qib_r_shift(struct qib_devdata *dd, int bisten,
+                      int len, u8 *inp, u8 *outp)
+{
+       u64 valbase, val;
+       int ret, pos;
+
+       valbase = SJA_EN | (bisten << BISTEN_LSB) |
+               (R_OP_SHIFT << R_OPCODE_LSB);
+       ret = qib_r_wait_for_rdy(dd);
+       if (ret < 0)
+               goto bail;
+       for (pos = 0; pos < len; ++pos) {
+               val = valbase;
+               if (outp) {
+                       outp[pos >> 3] &= ~(1 << (pos & 7));
+                       outp[pos >> 3] |= (ret << (pos & 7));
+               }
+               if (inp) {
+                       int tdi = inp[pos >> 3] >> (pos & 7);
+                       val |= ((tdi & 1) << R_TDI_LSB);
+               }
+               qib_write_kreg(dd, kr_r_access, val);
+               qib_read_kreg32(dd, kr_scratch);
+               ret = qib_r_wait_for_rdy(dd);
+               if (ret < 0)
+                       break;
+       }
+       /* Restore to NOP between operations. */
+       val =  SJA_EN | (bisten << BISTEN_LSB);
+       qib_write_kreg(dd, kr_r_access, val);
+       qib_read_kreg32(dd, kr_scratch);
+       ret = qib_r_wait_for_rdy(dd);
+
+       if (ret >= 0)
+               ret = pos;
+bail:
+       return ret;
+}
+
+static int qib_r_update(struct qib_devdata *dd, int bisten)
+{
+       u64 val;
+       int ret;
+
+       val = SJA_EN | (bisten << BISTEN_LSB) | (R_OP_UPDATE << R_OPCODE_LSB);
+       ret = qib_r_wait_for_rdy(dd);
+       if (ret >= 0) {
+               qib_write_kreg(dd, kr_r_access, val);
+               qib_read_kreg32(dd, kr_scratch);
+       }
+       return ret;
+}
+
+#define BISTEN_PORT_SEL 15
+#define LEN_PORT_SEL 625
+#define BISTEN_AT 17
+#define LEN_AT 156
+#define BISTEN_ETM 16
+#define LEN_ETM 632
+
+#define BIT2BYTE(x) (((x) +  BITS_PER_BYTE - 1) / BITS_PER_BYTE)
+
+/* these are common for all IB port use cases. */
+static u8 reset_at[BIT2BYTE(LEN_AT)] = {
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00,
+};
+static u8 reset_atetm[BIT2BYTE(LEN_ETM)] = {
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x80, 0xe3, 0x81, 0x73, 0x3c, 0x70, 0x8e,
+       0x07, 0xce, 0xf1, 0xc0, 0x39, 0x1e, 0x38, 0xc7, 0x03, 0xe7,
+       0x78, 0xe0, 0x1c, 0x0f, 0x9c, 0x7f, 0x80, 0x73, 0x0f, 0x70,
+       0xde, 0x01, 0xce, 0x39, 0xc0, 0xf9, 0x06, 0x38, 0xd7, 0x00,
+       0xe7, 0x19, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+};
+static u8 at[BIT2BYTE(LEN_AT)] = {
+       0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00,
+};
+
+/* used for IB1 or IB2, only one in use */
+static u8 atetm_1port[BIT2BYTE(LEN_ETM)] = {
+       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, 0x10, 0xf2, 0x80, 0x83, 0x1e, 0x38, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x50, 0xf4, 0x41, 0x00, 0x18, 0x78, 0xc8, 0x03,
+       0x07, 0x7b, 0xa0, 0x3e, 0x00, 0x02, 0x00, 0x00, 0x18, 0x00,
+       0x18, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00,
+};
+
+/* used when both IB1 and IB2 are in use */
+static u8 atetm_2port[BIT2BYTE(LEN_ETM)] = {
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79,
+       0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xf8, 0x80, 0x83, 0x1e, 0x38, 0xe0, 0x03, 0x05,
+       0x7b, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+       0xa2, 0x0f, 0x50, 0xf4, 0x41, 0x00, 0x18, 0x78, 0xd1, 0x07,
+       0x02, 0x7c, 0x80, 0x3e, 0x00, 0x02, 0x00, 0x00, 0x3e, 0x00,
+       0x02, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
+};
+
+/* used when only IB1 is in use */
+static u8 portsel_port1[BIT2BYTE(LEN_PORT_SEL)] = {
+       0x32, 0x65, 0xa4, 0x7b, 0x10, 0x98, 0xdc, 0xfe, 0x13, 0x13,
+       0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x73, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
+       0x13, 0x78, 0x78, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
+       0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x74, 0x32,
+       0x32, 0x32, 0x32, 0x32, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
+       0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
+       0x14, 0x14, 0x9f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+/* used when only IB2 is in use */
+static u8 portsel_port2[BIT2BYTE(LEN_PORT_SEL)] = {
+       0x32, 0x65, 0xa4, 0x7b, 0x10, 0x98, 0xdc, 0xfe, 0x39, 0x39,
+       0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x73, 0x32, 0x32, 0x32,
+       0x32, 0x32, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39,
+       0x39, 0x78, 0x78, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39,
+       0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x74, 0x32,
+       0x32, 0x32, 0x32, 0x32, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a,
+       0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a,
+       0x3a, 0x3a, 0x9f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
+};
+
+/* used when both IB1 and IB2 are in use */
+static u8 portsel_2port[BIT2BYTE(LEN_PORT_SEL)] = {
+       0x32, 0xba, 0x54, 0x76, 0x10, 0x98, 0xdc, 0xfe, 0x13, 0x13,
+       0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x73, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
+       0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
+       0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x74, 0x32,
+       0x32, 0x32, 0x32, 0x32, 0x14, 0x14, 0x14, 0x14, 0x14, 0x3a,
+       0x3a, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
+       0x14, 0x14, 0x9f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+/*
+ * Do setup to properly handle IB link recovery; if port is zero, we
+ * are initializing to cover both ports; otherwise we are initializing
+ * to cover a single port card, or the port has reached INIT and we may
+ * need to switch coverage types.
+ */
+static void setup_7322_link_recovery(struct qib_pportdata *ppd, u32 both)
+{
+       u8 *portsel, *etm;
+       struct qib_devdata *dd = ppd->dd;
+
+       if (!ppd->dd->cspec->r1)
+               return;
+       if (!both) {
+               dd->cspec->recovery_ports_initted++;
+               ppd->cpspec->recovery_init = 1;
+       }
+       if (!both && dd->cspec->recovery_ports_initted == 1) {
+               portsel = ppd->port == 1 ? portsel_port1 : portsel_port2;
+               etm = atetm_1port;
+       } else {
+               portsel = portsel_2port;
+               etm = atetm_2port;
+       }
+
+       if (qib_r_grab(dd) < 0 ||
+               qib_r_shift(dd, BISTEN_ETM, LEN_ETM, reset_atetm, NULL) < 0 ||
+               qib_r_update(dd, BISTEN_ETM) < 0 ||
+               qib_r_shift(dd, BISTEN_AT, LEN_AT, reset_at, NULL) < 0 ||
+               qib_r_update(dd, BISTEN_AT) < 0 ||
+               qib_r_shift(dd, BISTEN_PORT_SEL, LEN_PORT_SEL,
+                           portsel, NULL) < 0 ||
+               qib_r_update(dd, BISTEN_PORT_SEL) < 0 ||
+               qib_r_shift(dd, BISTEN_AT, LEN_AT, at, NULL) < 0 ||
+               qib_r_update(dd, BISTEN_AT) < 0 ||
+               qib_r_shift(dd, BISTEN_ETM, LEN_ETM, etm, NULL) < 0 ||
+               qib_r_update(dd, BISTEN_ETM) < 0)
+               qib_dev_err(dd, "Failed IB link recovery setup\n");
+}
+
+static void check_7322_rxe_status(struct qib_pportdata *ppd)
+{
+       struct qib_devdata *dd = ppd->dd;
+       u64 fmask;
+
+       if (dd->cspec->recovery_ports_initted != 1)
+               return; /* rest doesn't apply to dualport */
+       qib_write_kreg(dd, kr_control, dd->control |
+                      SYM_MASK(Control, FreezeMode));
+       (void)qib_read_kreg64(dd, kr_scratch);
+       udelay(3); /* ibcreset asserted 400ns, be sure that's over */
+       fmask = qib_read_kreg64(dd, kr_act_fmask);
+       if (!fmask) {
+               /*
+                * require a powercycle before we'll work again, and make
+                * sure we get no more interrupts, and don't turn off
+                * freeze.
+                */
+               ppd->dd->cspec->stay_in_freeze = 1;
+               qib_7322_set_intr_state(ppd->dd, 0);
+               qib_write_kreg(dd, kr_fmask, 0ULL);
+               qib_dev_err(dd, "HCA unusable until powercycled\n");
+               return; /* eventually reset */
+       }
+
+       qib_write_kreg(ppd->dd, kr_hwerrclear,
+           SYM_MASK(HwErrClear, IBSerdesPClkNotDetectClear_1));
+
+       /* don't do the full clear_freeze(), not needed for this */
+       qib_write_kreg(dd, kr_control, dd->control);
+       qib_read_kreg32(dd, kr_scratch);
+       /* take IBC out of reset */
+       if (ppd->link_speed_supported) {
+               ppd->cpspec->ibcctrl_a &=
+                       ~SYM_MASK(IBCCtrlA_0, IBStatIntReductionEn);
+               qib_write_kreg_port(ppd, krp_ibcctrl_a,
+                                   ppd->cpspec->ibcctrl_a);
+               qib_read_kreg32(dd, kr_scratch);
+               if (ppd->lflags & QIBL_IB_LINK_DISABLED)
+                       qib_set_ib_7322_lstate(ppd, 0,
+                               QLOGIC_IB_IBCC_LINKINITCMD_DISABLE);
+       }
+}
diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c
new file mode 100644 (file)
index 0000000..9b40f34
--- /dev/null
@@ -0,0 +1,1586 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009, 2010 QLogic Corporation.
+ * All rights reserved.
+ * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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/pci.h>
+#include <linux/netdevice.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/idr.h>
+
+#include "qib.h"
+#include "qib_common.h"
+
+/*
+ * min buffers we want to have per context, after driver
+ */
+#define QIB_MIN_USER_CTXT_BUFCNT 7
+
+#define QLOGIC_IB_R_SOFTWARE_MASK 0xFF
+#define QLOGIC_IB_R_SOFTWARE_SHIFT 24
+#define QLOGIC_IB_R_EMULATOR_MASK (1ULL<<62)
+
+/*
+ * Number of ctxts we are configured to use (to allow for more pio
+ * buffers per ctxt, etc.)  Zero means use chip value.
+ */
+ushort qib_cfgctxts;
+module_param_named(cfgctxts, qib_cfgctxts, ushort, S_IRUGO);
+MODULE_PARM_DESC(cfgctxts, "Set max number of contexts to use");
+
+/*
+ * If set, do not write to any regs if avoidable, hack to allow
+ * check for deranged default register values.
+ */
+ushort qib_mini_init;
+module_param_named(mini_init, qib_mini_init, ushort, S_IRUGO);
+MODULE_PARM_DESC(mini_init, "If set, do minimal diag init");
+
+unsigned qib_n_krcv_queues;
+module_param_named(krcvqs, qib_n_krcv_queues, uint, S_IRUGO);
+MODULE_PARM_DESC(krcvqs, "number of kernel receive queues per IB port");
+
+/*
+ * qib_wc_pat parameter:
+ *      0 is WC via MTRR
+ *      1 is WC via PAT
+ *      If PAT initialization fails, code reverts back to MTRR
+ */
+unsigned qib_wc_pat = 1; /* default (1) is to use PAT, not MTRR */
+module_param_named(wc_pat, qib_wc_pat, uint, S_IRUGO);
+MODULE_PARM_DESC(wc_pat, "enable write-combining via PAT mechanism");
+
+struct workqueue_struct *qib_wq;
+struct workqueue_struct *qib_cq_wq;
+
+static void verify_interrupt(unsigned long);
+
+static struct idr qib_unit_table;
+u32 qib_cpulist_count;
+unsigned long *qib_cpulist;
+
+/* set number of contexts we'll actually use */
+void qib_set_ctxtcnt(struct qib_devdata *dd)
+{
+       if (!qib_cfgctxts)
+               dd->cfgctxts = dd->ctxtcnt;
+       else if (qib_cfgctxts < dd->num_pports)
+               dd->cfgctxts = dd->ctxtcnt;
+       else if (qib_cfgctxts <= dd->ctxtcnt)
+               dd->cfgctxts = qib_cfgctxts;
+       else
+               dd->cfgctxts = dd->ctxtcnt;
+}
+
+/*
+ * Common code for creating the receive context array.
+ */
+int qib_create_ctxts(struct qib_devdata *dd)
+{
+       unsigned i;
+       int ret;
+
+       /*
+        * Allocate full ctxtcnt array, rather than just cfgctxts, because
+        * cleanup iterates across all possible ctxts.
+        */
+       dd->rcd = kzalloc(sizeof(*dd->rcd) * dd->ctxtcnt, GFP_KERNEL);
+       if (!dd->rcd) {
+               qib_dev_err(dd, "Unable to allocate ctxtdata array, "
+                           "failing\n");
+               ret = -ENOMEM;
+               goto done;
+       }
+
+       /* create (one or more) kctxt */
+       for (i = 0; i < dd->first_user_ctxt; ++i) {
+               struct qib_pportdata *ppd;
+               struct qib_ctxtdata *rcd;
+
+               if (dd->skip_kctxt_mask & (1 << i))
+                       continue;
+
+               ppd = dd->pport + (i % dd->num_pports);
+               rcd = qib_create_ctxtdata(ppd, i);
+               if (!rcd) {
+                       qib_dev_err(dd, "Unable to allocate ctxtdata"
+                                   " for Kernel ctxt, failing\n");
+                       ret = -ENOMEM;
+                       goto done;
+               }
+               rcd->pkeys[0] = QIB_DEFAULT_P_KEY;
+               rcd->seq_cnt = 1;
+       }
+       ret = 0;
+done:
+       return ret;
+}
+
+/*
+ * Common code for user and kernel context setup.
+ */
+struct qib_ctxtdata *qib_create_ctxtdata(struct qib_pportdata *ppd, u32 ctxt)
+{
+       struct qib_devdata *dd = ppd->dd;
+       struct qib_ctxtdata *rcd;
+
+       rcd = kzalloc(sizeof(*rcd), GFP_KERNEL);
+       if (rcd) {
+               INIT_LIST_HEAD(&rcd->qp_wait_list);
+               rcd->ppd = ppd;
+               rcd->dd = dd;
+               rcd->cnt = 1;
+               rcd->ctxt = ctxt;
+               dd->rcd[ctxt] = rcd;
+
+               dd->f_init_ctxt(rcd);
+
+               /*
+                * To avoid wasting a lot of memory, we allocate 32KB chunks
+                * of physically contiguous memory, advance through it until
+                * used up and then allocate more.  Of course, we need
+                * memory to store those extra pointers, now.  32KB seems to
+                * be the most that is "safe" under memory pressure
+                * (creating large files and then copying them over
+                * NFS while doing lots of MPI jobs).  The OOM killer can
+                * get invoked, even though we say we can sleep and this can
+                * cause significant system problems....
+                */
+               rcd->rcvegrbuf_size = 0x8000;
+               rcd->rcvegrbufs_perchunk =
+                       rcd->rcvegrbuf_size / dd->rcvegrbufsize;
+               rcd->rcvegrbuf_chunks = (rcd->rcvegrcnt +
+                       rcd->rcvegrbufs_perchunk - 1) /
+                       rcd->rcvegrbufs_perchunk;
+       }
+       return rcd;
+}
+
+/*
+ * Common code for initializing the physical port structure.
+ */
+void qib_init_pportdata(struct qib_pportdata *ppd, struct qib_devdata *dd,
+                       u8 hw_pidx, u8 port)
+{
+       ppd->dd = dd;
+       ppd->hw_pidx = hw_pidx;
+       ppd->port = port; /* IB port number, not index */
+
+       spin_lock_init(&ppd->sdma_lock);
+       spin_lock_init(&ppd->lflags_lock);
+       init_waitqueue_head(&ppd->state_wait);
+
+       init_timer(&ppd->symerr_clear_timer);
+       ppd->symerr_clear_timer.function = qib_clear_symerror_on_linkup;
+       ppd->symerr_clear_timer.data = (unsigned long)ppd;
+}
+
+static int init_pioavailregs(struct qib_devdata *dd)
+{
+       int ret, pidx;
+       u64 *status_page;
+
+       dd->pioavailregs_dma = dma_alloc_coherent(
+               &dd->pcidev->dev, PAGE_SIZE, &dd->pioavailregs_phys,
+               GFP_KERNEL);
+       if (!dd->pioavailregs_dma) {
+               qib_dev_err(dd, "failed to allocate PIOavail reg area "
+                           "in memory\n");
+               ret = -ENOMEM;
+               goto done;
+       }
+
+       /*
+        * We really want L2 cache aligned, but for current CPUs of
+        * interest, they are the same.
+        */
+       status_page = (u64 *)
+               ((char *) dd->pioavailregs_dma +
+                ((2 * L1_CACHE_BYTES +
+                  dd->pioavregs * sizeof(u64)) & ~L1_CACHE_BYTES));
+       /* device status comes first, for backwards compatibility */
+       dd->devstatusp = status_page;
+       *status_page++ = 0;
+       for (pidx = 0; pidx < dd->num_pports; ++pidx) {
+               dd->pport[pidx].statusp = status_page;
+               *status_page++ = 0;
+       }
+
+       /*
+        * Setup buffer to hold freeze and other messages, accessible to
+        * apps, following statusp.  This is per-unit, not per port.
+        */
+       dd->freezemsg = (char *) status_page;
+       *dd->freezemsg = 0;
+       /* length of msg buffer is "whatever is left" */
+       ret = (char *) status_page - (char *) dd->pioavailregs_dma;
+       dd->freezelen = PAGE_SIZE - ret;
+
+       ret = 0;
+
+done:
+       return ret;
+}
+
+/**
+ * init_shadow_tids - allocate the shadow TID array
+ * @dd: the qlogic_ib device
+ *
+ * allocate the shadow TID array, so we can qib_munlock previous
+ * entries.  It may make more sense to move the pageshadow to the
+ * ctxt data structure, so we only allocate memory for ctxts actually
+ * in use, since we at 8k per ctxt, now.
+ * We don't want failures here to prevent use of the driver/chip,
+ * so no return value.
+ */
+static void init_shadow_tids(struct qib_devdata *dd)
+{
+       struct page **pages;
+       dma_addr_t *addrs;
+
+       pages = vmalloc(dd->cfgctxts * dd->rcvtidcnt * sizeof(struct page *));
+       if (!pages) {
+               qib_dev_err(dd, "failed to allocate shadow page * "
+                           "array, no expected sends!\n");
+               goto bail;
+       }
+
+       addrs = vmalloc(dd->cfgctxts * dd->rcvtidcnt * sizeof(dma_addr_t));
+       if (!addrs) {
+               qib_dev_err(dd, "failed to allocate shadow dma handle "
+                           "array, no expected sends!\n");
+               goto bail_free;
+       }
+
+       memset(pages, 0, dd->cfgctxts * dd->rcvtidcnt * sizeof(struct page *));
+       memset(addrs, 0, dd->cfgctxts * dd->rcvtidcnt * sizeof(dma_addr_t));
+
+       dd->pageshadow = pages;
+       dd->physshadow = addrs;
+       return;
+
+bail_free:
+       vfree(pages);
+bail:
+       dd->pageshadow = NULL;
+}
+
+/*
+ * Do initialization for device that is only needed on
+ * first detect, not on resets.
+ */
+static int loadtime_init(struct qib_devdata *dd)
+{
+       int ret = 0;
+
+       if (((dd->revision >> QLOGIC_IB_R_SOFTWARE_SHIFT) &
+            QLOGIC_IB_R_SOFTWARE_MASK) != QIB_CHIP_SWVERSION) {
+               qib_dev_err(dd, "Driver only handles version %d, "
+                           "chip swversion is %d (%llx), failng\n",
+                           QIB_CHIP_SWVERSION,
+                           (int)(dd->revision >>
+                               QLOGIC_IB_R_SOFTWARE_SHIFT) &
+                           QLOGIC_IB_R_SOFTWARE_MASK,
+                           (unsigned long long) dd->revision);
+               ret = -ENOSYS;
+               goto done;
+       }
+
+       if (dd->revision & QLOGIC_IB_R_EMULATOR_MASK)
+               qib_devinfo(dd->pcidev, "%s", dd->boardversion);
+
+       spin_lock_init(&dd->pioavail_lock);
+       spin_lock_init(&dd->sendctrl_lock);
+       spin_lock_init(&dd->uctxt_lock);
+       spin_lock_init(&dd->qib_diag_trans_lock);
+       spin_lock_init(&dd->eep_st_lock);
+       mutex_init(&dd->eep_lock);
+
+       if (qib_mini_init)
+               goto done;
+
+       ret = init_pioavailregs(dd);
+       init_shadow_tids(dd);
+
+       qib_get_eeprom_info(dd);
+
+       /* setup time (don't start yet) to verify we got interrupt */
+       init_timer(&dd->intrchk_timer);
+       dd->intrchk_timer.function = verify_interrupt;
+       dd->intrchk_timer.data = (unsigned long) dd;
+
+done:
+       return ret;
+}
+
+/**
+ * init_after_reset - re-initialize after a reset
+ * @dd: the qlogic_ib device
+ *
+ * sanity check at least some of the values after reset, and
+ * ensure no receive or transmit (explictly, in case reset
+ * failed
+ */
+static int init_after_reset(struct qib_devdata *dd)
+{
+       int i;
+
+       /*
+        * Ensure chip does no sends or receives, tail updates, or
+        * pioavail updates while we re-initialize.  This is mostly
+        * for the driver data structures, not chip registers.
+        */
+       for (i = 0; i < dd->num_pports; ++i) {
+               /*
+                * ctxt == -1 means "all contexts". Only really safe for
+                * _dis_abling things, as here.
+                */
+               dd->f_rcvctrl(dd->pport + i, QIB_RCVCTRL_CTXT_DIS |
+                                 QIB_RCVCTRL_INTRAVAIL_DIS |
+                                 QIB_RCVCTRL_TAILUPD_DIS, -1);
+               /* Redundant across ports for some, but no big deal.  */
+               dd->f_sendctrl(dd->pport + i, QIB_SENDCTRL_SEND_DIS |
+                       QIB_SENDCTRL_AVAIL_DIS);
+       }
+
+       return 0;
+}
+
+static void enable_chip(struct qib_devdata *dd)
+{
+       u64 rcvmask;
+       int i;
+
+       /*
+        * Enable PIO send, and update of PIOavail regs to memory.
+        */
+       for (i = 0; i < dd->num_pports; ++i)
+               dd->f_sendctrl(dd->pport + i, QIB_SENDCTRL_SEND_ENB |
+                       QIB_SENDCTRL_AVAIL_ENB);
+       /*
+        * Enable kernel ctxts' receive and receive interrupt.
+        * Other ctxts done as user opens and inits them.
+        */
+       rcvmask = QIB_RCVCTRL_CTXT_ENB | QIB_RCVCTRL_INTRAVAIL_ENB;
+       rcvmask |= (dd->flags & QIB_NODMA_RTAIL) ?
+                 QIB_RCVCTRL_TAILUPD_DIS : QIB_RCVCTRL_TAILUPD_ENB;
+       for (i = 0; dd->rcd && i < dd->first_user_ctxt; ++i) {
+               struct qib_ctxtdata *rcd = dd->rcd[i];
+
+               if (rcd)
+                       dd->f_rcvctrl(rcd->ppd, rcvmask, i);
+       }
+}
+
+static void verify_interrupt(unsigned long opaque)
+{
+       struct qib_devdata *dd = (struct qib_devdata *) opaque;
+
+       if (!dd)
+               return; /* being torn down */
+
+       /*
+        * If we don't have a lid or any interrupts, let the user know and
+        * don't bother checking again.
+        */
+       if (dd->int_counter == 0) {
+               if (!dd->f_intr_fallback(dd))
+                       dev_err(&dd->pcidev->dev, "No interrupts detected, "
+                               "not usable.\n");
+               else /* re-arm the timer to see if fallback works */
+                       mod_timer(&dd->intrchk_timer, jiffies + HZ/2);
+       }
+}
+
+static void init_piobuf_state(struct qib_devdata *dd)
+{
+       int i, pidx;
+       u32 uctxts;
+
+       /*
+        * Ensure all buffers are free, and fifos empty.  Buffers
+        * are common, so only do once for port 0.
+        *
+        * After enable and qib_chg_pioavailkernel so we can safely
+        * enable pioavail updates and PIOENABLE.  After this, packets
+        * are ready and able to go out.
+        */
+       dd->f_sendctrl(dd->pport, QIB_SENDCTRL_DISARM_ALL);
+       for (pidx = 0; pidx < dd->num_pports; ++pidx)
+               dd->f_sendctrl(dd->pport + pidx, QIB_SENDCTRL_FLUSH);
+
+       /*
+        * If not all sendbufs are used, add the one to each of the lower
+        * numbered contexts.  pbufsctxt and lastctxt_piobuf are
+        * calculated in chip-specific code because it may cause some
+        * chip-specific adjustments to be made.
+        */
+       uctxts = dd->cfgctxts - dd->first_user_ctxt;
+       dd->ctxts_extrabuf = dd->pbufsctxt ?
+               dd->lastctxt_piobuf - (dd->pbufsctxt * uctxts) : 0;
+
+       /*
+        * Set up the shadow copies of the piobufavail registers,
+        * which we compare against the chip registers for now, and
+        * the in memory DMA'ed copies of the registers.
+        * By now pioavail updates to memory should have occurred, so
+        * copy them into our working/shadow registers; this is in
+        * case something went wrong with abort, but mostly to get the
+        * initial values of the generation bit correct.
+        */
+       for (i = 0; i < dd->pioavregs; i++) {
+               __le64 tmp;
+
+               tmp = dd->pioavailregs_dma[i];
+               /*
+                * Don't need to worry about pioavailkernel here
+                * because we will call qib_chg_pioavailkernel() later
+                * in initialization, to busy out buffers as needed.
+                */
+               dd->pioavailshadow[i] = le64_to_cpu(tmp);
+       }
+       while (i < ARRAY_SIZE(dd->pioavailshadow))
+               dd->pioavailshadow[i++] = 0; /* for debugging sanity */
+
+       /* after pioavailshadow is setup */
+       qib_chg_pioavailkernel(dd, 0, dd->piobcnt2k + dd->piobcnt4k,
+                              TXCHK_CHG_TYPE_KERN, NULL);
+       dd->f_initvl15_bufs(dd);
+}
+
+/**
+ * qib_init - do the actual initialization sequence on the chip
+ * @dd: the qlogic_ib device
+ * @reinit: reinitializing, so don't allocate new memory
+ *
+ * Do the actual initialization sequence on the chip.  This is done
+ * both from the init routine called from the PCI infrastructure, and
+ * when we reset the chip, or detect that it was reset internally,
+ * or it's administratively re-enabled.
+ *
+ * Memory allocation here and in called routines is only done in
+ * the first case (reinit == 0).  We have to be careful, because even
+ * without memory allocation, we need to re-write all the chip registers
+ * TIDs, etc. after the reset or enable has completed.
+ */
+int qib_init(struct qib_devdata *dd, int reinit)
+{
+       int ret = 0, pidx, lastfail = 0;
+       u32 portok = 0;
+       unsigned i;
+       struct qib_ctxtdata *rcd;
+       struct qib_pportdata *ppd;
+       unsigned long flags;
+
+       /* Set linkstate to unknown, so we can watch for a transition. */
+       for (pidx = 0; pidx < dd->num_pports; ++pidx) {
+               ppd = dd->pport + pidx;
+               spin_lock_irqsave(&ppd->lflags_lock, flags);
+               ppd->lflags &= ~(QIBL_LINKACTIVE | QIBL_LINKARMED |
+                                QIBL_LINKDOWN | QIBL_LINKINIT |
+                                QIBL_LINKV);
+               spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+       }
+
+       if (reinit)
+               ret = init_after_reset(dd);
+       else
+               ret = loadtime_init(dd);
+       if (ret)
+               goto done;
+
+       /* Bypass most chip-init, to get to device creation */
+       if (qib_mini_init)
+               return 0;
+
+       ret = dd->f_late_initreg(dd);
+       if (ret)
+               goto done;
+
+       /* dd->rcd can be NULL if early init failed */
+       for (i = 0; dd->rcd && i < dd->first_user_ctxt; ++i) {
+               /*
+                * Set up the (kernel) rcvhdr queue and egr TIDs.  If doing
+                * re-init, the simplest way to handle this is to free
+                * existing, and re-allocate.
+                * Need to re-create rest of ctxt 0 ctxtdata as well.
+                */
+               rcd = dd->rcd[i];
+               if (!rcd)
+                       continue;
+
+               lastfail = qib_create_rcvhdrq(dd, rcd);
+               if (!lastfail)
+                       lastfail = qib_setup_eagerbufs(rcd);
+               if (lastfail) {
+                       qib_dev_err(dd, "failed to allocate kernel ctxt's "
+                                   "rcvhdrq and/or egr bufs\n");
+                       continue;
+               }
+       }
+
+       for (pidx = 0; pidx < dd->num_pports; ++pidx) {
+               int mtu;
+               if (lastfail)
+                       ret = lastfail;
+               ppd = dd->pport + pidx;
+               mtu = ib_mtu_enum_to_int(qib_ibmtu);
+               if (mtu == -1) {
+                       mtu = QIB_DEFAULT_MTU;
+                       qib_ibmtu = 0; /* don't leave invalid value */
+               }
+               /* set max we can ever have for this driver load */
+               ppd->init_ibmaxlen = min(mtu > 2048 ?
+                                        dd->piosize4k : dd->piosize2k,
+                                        dd->rcvegrbufsize +
+                                        (dd->rcvhdrentsize << 2));
+               /*
+                * Have to initialize ibmaxlen, but this will normally
+                * change immediately in qib_set_mtu().
+                */
+               ppd->ibmaxlen = ppd->init_ibmaxlen;
+               qib_set_mtu(ppd, mtu);
+
+               spin_lock_irqsave(&ppd->lflags_lock, flags);
+               ppd->lflags |= QIBL_IB_LINK_DISABLED;
+               spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+
+               lastfail = dd->f_bringup_serdes(ppd);
+               if (lastfail) {
+                       qib_devinfo(dd->pcidev,
+                                "Failed to bringup IB port %u\n", ppd->port);
+                       lastfail = -ENETDOWN;
+                       continue;
+               }
+
+               /* let link come up, and enable IBC */
+               spin_lock_irqsave(&ppd->lflags_lock, flags);
+               ppd->lflags &= ~QIBL_IB_LINK_DISABLED;
+               spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+               portok++;
+       }
+
+       if (!portok) {
+               /* none of the ports initialized */
+               if (!ret && lastfail)
+                       ret = lastfail;
+               else if (!ret)
+                       ret = -ENETDOWN;
+               /* but continue on, so we can debug cause */
+       }
+
+       enable_chip(dd);
+
+       init_piobuf_state(dd);
+
+done:
+       if (!ret) {
+               /* chip is OK for user apps; mark it as initialized */
+               for (pidx = 0; pidx < dd->num_pports; ++pidx) {
+                       ppd = dd->pport + pidx;
+                       /*
+                        * Set status even if port serdes is not initialized
+                        * so that diags will work.
+                        */
+                       *ppd->statusp |= QIB_STATUS_CHIP_PRESENT |
+                               QIB_STATUS_INITTED;
+                       if (!ppd->link_speed_enabled)
+                               continue;
+                       if (dd->flags & QIB_HAS_SEND_DMA)
+                               ret = qib_setup_sdma(ppd);
+                       init_timer(&ppd->hol_timer);
+                       ppd->hol_timer.function = qib_hol_event;
+                       ppd->hol_timer.data = (unsigned long)ppd;
+                       ppd->hol_state = QIB_HOL_UP;
+               }
+
+               /* now we can enable all interrupts from the chip */
+               dd->f_set_intr_state(dd, 1);
+
+               /*
+                * Setup to verify we get an interrupt, and fallback
+                * to an alternate if necessary and possible.
+                */
+               mod_timer(&dd->intrchk_timer, jiffies + HZ/2);
+               /* start stats retrieval timer */
+               mod_timer(&dd->stats_timer, jiffies + HZ * ACTIVITY_TIMER);
+       }
+
+       /* if ret is non-zero, we probably should do some cleanup here... */
+       return ret;
+}
+
+/*
+ * These next two routines are placeholders in case we don't have per-arch
+ * code for controlling write combining.  If explicit control of write
+ * combining is not available, performance will probably be awful.
+ */
+
+int __attribute__((weak)) qib_enable_wc(struct qib_devdata *dd)
+{
+       return -EOPNOTSUPP;
+}
+
+void __attribute__((weak)) qib_disable_wc(struct qib_devdata *dd)
+{
+}
+
+static inline struct qib_devdata *__qib_lookup(int unit)
+{
+       return idr_find(&qib_unit_table, unit);
+}
+
+struct qib_devdata *qib_lookup(int unit)
+{
+       struct qib_devdata *dd;
+       unsigned long flags;
+
+       spin_lock_irqsave(&qib_devs_lock, flags);
+       dd = __qib_lookup(unit);
+       spin_unlock_irqrestore(&qib_devs_lock, flags);
+
+       return dd;
+}
+
+/*
+ * Stop the timers during unit shutdown, or after an error late
+ * in initialization.
+ */
+static void qib_stop_timers(struct qib_devdata *dd)
+{
+       struct qib_pportdata *ppd;
+       int pidx;
+
+       if (dd->stats_timer.data) {
+               del_timer_sync(&dd->stats_timer);
+               dd->stats_timer.data = 0;
+       }
+       if (dd->intrchk_timer.data) {
+               del_timer_sync(&dd->intrchk_timer);
+               dd->intrchk_timer.data = 0;
+       }
+       for (pidx = 0; pidx < dd->num_pports; ++pidx) {
+               ppd = dd->pport + pidx;
+               if (ppd->hol_timer.data)
+                       del_timer_sync(&ppd->hol_timer);
+               if (ppd->led_override_timer.data) {
+                       del_timer_sync(&ppd->led_override_timer);
+                       atomic_set(&ppd->led_override_timer_active, 0);
+               }
+               if (ppd->symerr_clear_timer.data)
+                       del_timer_sync(&ppd->symerr_clear_timer);
+       }
+}
+
+/**
+ * qib_shutdown_device - shut down a device
+ * @dd: the qlogic_ib device
+ *
+ * This is called to make the device quiet when we are about to
+ * unload the driver, and also when the device is administratively
+ * disabled.   It does not free any data structures.
+ * Everything it does has to be setup again by qib_init(dd, 1)
+ */
+static void qib_shutdown_device(struct qib_devdata *dd)
+{
+       struct qib_pportdata *ppd;
+       unsigned pidx;
+
+       for (pidx = 0; pidx < dd->num_pports; ++pidx) {
+               ppd = dd->pport + pidx;
+
+               spin_lock_irq(&ppd->lflags_lock);
+               ppd->lflags &= ~(QIBL_LINKDOWN | QIBL_LINKINIT |
+                                QIBL_LINKARMED | QIBL_LINKACTIVE |
+                                QIBL_LINKV);
+               spin_unlock_irq(&ppd->lflags_lock);
+               *ppd->statusp &= ~(QIB_STATUS_IB_CONF | QIB_STATUS_IB_READY);
+       }
+       dd->flags &= ~QIB_INITTED;
+
+       /* mask interrupts, but not errors */
+       dd->f_set_intr_state(dd, 0);
+
+       for (pidx = 0; pidx < dd->num_pports; ++pidx) {
+               ppd = dd->pport + pidx;
+               dd->f_rcvctrl(ppd, QIB_RCVCTRL_TAILUPD_DIS |
+                                  QIB_RCVCTRL_CTXT_DIS |
+                                  QIB_RCVCTRL_INTRAVAIL_DIS |
+                                  QIB_RCVCTRL_PKEY_ENB, -1);
+               /*
+                * Gracefully stop all sends allowing any in progress to
+                * trickle out first.
+                */
+               dd->f_sendctrl(ppd, QIB_SENDCTRL_CLEAR);
+       }
+
+       /*
+        * Enough for anything that's going to trickle out to have actually
+        * done so.
+        */
+       udelay(20);
+
+       for (pidx = 0; pidx < dd->num_pports; ++pidx) {
+               ppd = dd->pport + pidx;
+               dd->f_setextled(ppd, 0); /* make sure LEDs are off */
+
+               if (dd->flags & QIB_HAS_SEND_DMA)
+                       qib_teardown_sdma(ppd);
+
+               dd->f_sendctrl(ppd, QIB_SENDCTRL_AVAIL_DIS |
+                                   QIB_SENDCTRL_SEND_DIS);
+               /*
+                * Clear SerdesEnable.
+                * We can't count on interrupts since we are stopping.
+                */
+               dd->f_quiet_serdes(ppd);
+       }
+
+       qib_update_eeprom_log(dd);
+}
+
+/**
+ * qib_free_ctxtdata - free a context's allocated data
+ * @dd: the qlogic_ib device
+ * @rcd: the ctxtdata structure
+ *
+ * free up any allocated data for a context
+ * This should not touch anything that would affect a simultaneous
+ * re-allocation of context data, because it is called after qib_mutex
+ * is released (and can be called from reinit as well).
+ * It should never change any chip state, or global driver state.
+ */
+void qib_free_ctxtdata(struct qib_devdata *dd, struct qib_ctxtdata *rcd)
+{
+       if (!rcd)
+               return;
+
+       if (rcd->rcvhdrq) {
+               dma_free_coherent(&dd->pcidev->dev, rcd->rcvhdrq_size,
+                                 rcd->rcvhdrq, rcd->rcvhdrq_phys);
+               rcd->rcvhdrq = NULL;
+               if (rcd->rcvhdrtail_kvaddr) {
+                       dma_free_coherent(&dd->pcidev->dev, PAGE_SIZE,
+                                         rcd->rcvhdrtail_kvaddr,
+                                         rcd->rcvhdrqtailaddr_phys);
+                       rcd->rcvhdrtail_kvaddr = NULL;
+               }
+       }
+       if (rcd->rcvegrbuf) {
+               unsigned e;
+
+               for (e = 0; e < rcd->rcvegrbuf_chunks; e++) {
+                       void *base = rcd->rcvegrbuf[e];
+                       size_t size = rcd->rcvegrbuf_size;
+
+                       dma_free_coherent(&dd->pcidev->dev, size,
+                                         base, rcd->rcvegrbuf_phys[e]);
+               }
+               kfree(rcd->rcvegrbuf);
+               rcd->rcvegrbuf = NULL;
+               kfree(rcd->rcvegrbuf_phys);
+               rcd->rcvegrbuf_phys = NULL;
+               rcd->rcvegrbuf_chunks = 0;
+       }
+
+       kfree(rcd->tid_pg_list);
+       vfree(rcd->user_event_mask);
+       vfree(rcd->subctxt_uregbase);
+       vfree(rcd->subctxt_rcvegrbuf);
+       vfree(rcd->subctxt_rcvhdr_base);
+       kfree(rcd);
+}
+
+/*
+ * Perform a PIO buffer bandwidth write test, to verify proper system
+ * configuration.  Even when all the setup calls work, occasionally
+ * BIOS or other issues can prevent write combining from working, or
+ * can cause other bandwidth problems to the chip.
+ *
+ * This test simply writes the same buffer over and over again, and
+ * measures close to the peak bandwidth to the chip (not testing
+ * data bandwidth to the wire).   On chips that use an address-based
+ * trigger to send packets to the wire, this is easy.  On chips that
+ * use a count to trigger, we want to make sure that the packet doesn't
+ * go out on the wire, or trigger flow control checks.
+ */
+static void qib_verify_pioperf(struct qib_devdata *dd)
+{
+       u32 pbnum, cnt, lcnt;
+       u32 __iomem *piobuf;
+       u32 *addr;
+       u64 msecs, emsecs;
+
+       piobuf = dd->f_getsendbuf(dd->pport, 0ULL, &pbnum);
+       if (!piobuf) {
+               qib_devinfo(dd->pcidev,
+                        "No PIObufs for checking perf, skipping\n");
+               return;
+       }
+
+       /*
+        * Enough to give us a reasonable test, less than piobuf size, and
+        * likely multiple of store buffer length.
+        */
+       cnt = 1024;
+
+       addr = vmalloc(cnt);
+       if (!addr) {
+               qib_devinfo(dd->pcidev,
+                        "Couldn't get memory for checking PIO perf,"
+                        " skipping\n");
+               goto done;
+       }
+
+       preempt_disable();  /* we want reasonably accurate elapsed time */
+       msecs = 1 + jiffies_to_msecs(jiffies);
+       for (lcnt = 0; lcnt < 10000U; lcnt++) {
+               /* wait until we cross msec boundary */
+               if (jiffies_to_msecs(jiffies) >= msecs)
+                       break;
+               udelay(1);
+       }
+
+       dd->f_set_armlaunch(dd, 0);
+
+       /*
+        * length 0, no dwords actually sent
+        */
+       writeq(0, piobuf);
+       qib_flush_wc();
+
+       /*
+        * This is only roughly accurate, since even with preempt we
+        * still take interrupts that could take a while.   Running for
+        * >= 5 msec seems to get us "close enough" to accurate values.
+        */
+       msecs = jiffies_to_msecs(jiffies);
+       for (emsecs = lcnt = 0; emsecs <= 5UL; lcnt++) {
+               qib_pio_copy(piobuf + 64, addr, cnt >> 2);
+               emsecs = jiffies_to_msecs(jiffies) - msecs;
+       }
+
+       /* 1 GiB/sec, slightly over IB SDR line rate */
+       if (lcnt < (emsecs * 1024U))
+               qib_dev_err(dd,
+                           "Performance problem: bandwidth to PIO buffers is "
+                           "only %u MiB/sec\n",
+                           lcnt / (u32) emsecs);
+
+       preempt_enable();
+
+       vfree(addr);
+
+done:
+       /* disarm piobuf, so it's available again */
+       dd->f_sendctrl(dd->pport, QIB_SENDCTRL_DISARM_BUF(pbnum));
+       qib_sendbuf_done(dd, pbnum);
+       dd->f_set_armlaunch(dd, 1);
+}
+
+
+void qib_free_devdata(struct qib_devdata *dd)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&qib_devs_lock, flags);
+       idr_remove(&qib_unit_table, dd->unit);
+       list_del(&dd->list);
+       spin_unlock_irqrestore(&qib_devs_lock, flags);
+
+       ib_dealloc_device(&dd->verbs_dev.ibdev);
+}
+
+/*
+ * Allocate our primary per-unit data structure.  Must be done via verbs
+ * allocator, because the verbs cleanup process both does cleanup and
+ * free of the data structure.
+ * "extra" is for chip-specific data.
+ *
+ * Use the idr mechanism to get a unit number for this unit.
+ */
+struct qib_devdata *qib_alloc_devdata(struct pci_dev *pdev, size_t extra)
+{
+       unsigned long flags;
+       struct qib_devdata *dd;
+       int ret;
+
+       if (!idr_pre_get(&qib_unit_table, GFP_KERNEL)) {
+               dd = ERR_PTR(-ENOMEM);
+               goto bail;
+       }
+
+       dd = (struct qib_devdata *) ib_alloc_device(sizeof(*dd) + extra);
+       if (!dd) {
+               dd = ERR_PTR(-ENOMEM);
+               goto bail;
+       }
+
+       spin_lock_irqsave(&qib_devs_lock, flags);
+       ret = idr_get_new(&qib_unit_table, dd, &dd->unit);
+       if (ret >= 0)
+               list_add(&dd->list, &qib_dev_list);
+       spin_unlock_irqrestore(&qib_devs_lock, flags);
+
+       if (ret < 0) {
+               qib_early_err(&pdev->dev,
+                             "Could not allocate unit ID: error %d\n", -ret);
+               ib_dealloc_device(&dd->verbs_dev.ibdev);
+               dd = ERR_PTR(ret);
+               goto bail;
+       }
+
+       if (!qib_cpulist_count) {
+               u32 count = num_online_cpus();
+               qib_cpulist = kzalloc(BITS_TO_LONGS(count) *
+                                     sizeof(long), GFP_KERNEL);
+               if (qib_cpulist)
+                       qib_cpulist_count = count;
+               else
+                       qib_early_err(&pdev->dev, "Could not alloc cpulist "
+                                     "info, cpu affinity might be wrong\n");
+       }
+
+bail:
+       return dd;
+}
+
+/*
+ * Called from freeze mode handlers, and from PCI error
+ * reporting code.  Should be paranoid about state of
+ * system and data structures.
+ */
+void qib_disable_after_error(struct qib_devdata *dd)
+{
+       if (dd->flags & QIB_INITTED) {
+               u32 pidx;
+
+               dd->flags &= ~QIB_INITTED;
+               if (dd->pport)
+                       for (pidx = 0; pidx < dd->num_pports; ++pidx) {
+                               struct qib_pportdata *ppd;
+
+                               ppd = dd->pport + pidx;
+                               if (dd->flags & QIB_PRESENT) {
+                                       qib_set_linkstate(ppd,
+                                               QIB_IB_LINKDOWN_DISABLE);
+                                       dd->f_setextled(ppd, 0);
+                               }
+                               *ppd->statusp &= ~QIB_STATUS_IB_READY;
+                       }
+       }
+
+       /*
+        * Mark as having had an error for driver, and also
+        * for /sys and status word mapped to user programs.
+        * This marks unit as not usable, until reset.
+        */
+       if (dd->devstatusp)
+               *dd->devstatusp |= QIB_STATUS_HWERROR;
+}
+
+static void __devexit qib_remove_one(struct pci_dev *);
+static int __devinit qib_init_one(struct pci_dev *,
+                                 const struct pci_device_id *);
+
+#define DRIVER_LOAD_MSG "QLogic " QIB_DRV_NAME " loaded: "
+#define PFX QIB_DRV_NAME ": "
+
+static const struct pci_device_id qib_pci_tbl[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_PATHSCALE, PCI_DEVICE_ID_QLOGIC_IB_6120) },
+       { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_IB_7220) },
+       { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_IB_7322) },
+       { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, qib_pci_tbl);
+
+struct pci_driver qib_driver = {
+       .name = QIB_DRV_NAME,
+       .probe = qib_init_one,
+       .remove = __devexit_p(qib_remove_one),
+       .id_table = qib_pci_tbl,
+       .err_handler = &qib_pci_err_handler,
+};
+
+/*
+ * Do all the generic driver unit- and chip-independent memory
+ * allocation and initialization.
+ */
+static int __init qlogic_ib_init(void)
+{
+       int ret;
+
+       ret = qib_dev_init();
+       if (ret)
+               goto bail;
+
+       /*
+        * We create our own workqueue mainly because we want to be
+        * able to flush it when devices are being removed.  We can't
+        * use schedule_work()/flush_scheduled_work() because both
+        * unregister_netdev() and linkwatch_event take the rtnl lock,
+        * so flush_scheduled_work() can deadlock during device
+        * removal.
+        */
+       qib_wq = create_workqueue("qib");
+       if (!qib_wq) {
+               ret = -ENOMEM;
+               goto bail_dev;
+       }
+
+       qib_cq_wq = create_workqueue("qib_cq");
+       if (!qib_cq_wq) {
+               ret = -ENOMEM;
+               goto bail_wq;
+       }
+
+       /*
+        * These must be called before the driver is registered with
+        * the PCI subsystem.
+        */
+       idr_init(&qib_unit_table);
+       if (!idr_pre_get(&qib_unit_table, GFP_KERNEL)) {
+               printk(KERN_ERR QIB_DRV_NAME ": idr_pre_get() failed\n");
+               ret = -ENOMEM;
+               goto bail_cq_wq;
+       }
+
+       ret = pci_register_driver(&qib_driver);
+       if (ret < 0) {
+               printk(KERN_ERR QIB_DRV_NAME
+                      ": Unable to register driver: error %d\n", -ret);
+               goto bail_unit;
+       }
+
+       /* not fatal if it doesn't work */
+       if (qib_init_qibfs())
+               printk(KERN_ERR QIB_DRV_NAME ": Unable to register ipathfs\n");
+       goto bail; /* all OK */
+
+bail_unit:
+       idr_destroy(&qib_unit_table);
+bail_cq_wq:
+       destroy_workqueue(qib_cq_wq);
+bail_wq:
+       destroy_workqueue(qib_wq);
+bail_dev:
+       qib_dev_cleanup();
+bail:
+       return ret;
+}
+
+module_init(qlogic_ib_init);
+
+/*
+ * Do the non-unit driver cleanup, memory free, etc. at unload.
+ */
+static void __exit qlogic_ib_cleanup(void)
+{
+       int ret;
+
+       ret = qib_exit_qibfs();
+       if (ret)
+               printk(KERN_ERR QIB_DRV_NAME ": "
+                       "Unable to cleanup counter filesystem: "
+                       "error %d\n", -ret);
+
+       pci_unregister_driver(&qib_driver);
+
+       destroy_workqueue(qib_wq);
+       destroy_workqueue(qib_cq_wq);
+
+       qib_cpulist_count = 0;
+       kfree(qib_cpulist);
+
+       idr_destroy(&qib_unit_table);
+       qib_dev_cleanup();
+}
+
+module_exit(qlogic_ib_cleanup);
+
+/* this can only be called after a successful initialization */
+static void cleanup_device_data(struct qib_devdata *dd)
+{
+       int ctxt;
+       int pidx;
+       struct qib_ctxtdata **tmp;
+       unsigned long flags;
+
+       /* users can't do anything more with chip */
+       for (pidx = 0; pidx < dd->num_pports; ++pidx)
+               if (dd->pport[pidx].statusp)
+                       *dd->pport[pidx].statusp &= ~QIB_STATUS_CHIP_PRESENT;
+
+       if (!qib_wc_pat)
+               qib_disable_wc(dd);
+
+       if (dd->pioavailregs_dma) {
+               dma_free_coherent(&dd->pcidev->dev, PAGE_SIZE,
+                                 (void *) dd->pioavailregs_dma,
+                                 dd->pioavailregs_phys);
+               dd->pioavailregs_dma = NULL;
+       }
+
+       if (dd->pageshadow) {
+               struct page **tmpp = dd->pageshadow;
+               dma_addr_t *tmpd = dd->physshadow;
+               int i, cnt = 0;
+
+               for (ctxt = 0; ctxt < dd->cfgctxts; ctxt++) {
+                       int ctxt_tidbase = ctxt * dd->rcvtidcnt;
+                       int maxtid = ctxt_tidbase + dd->rcvtidcnt;
+
+                       for (i = ctxt_tidbase; i < maxtid; i++) {
+                               if (!tmpp[i])
+                                       continue;
+                               pci_unmap_page(dd->pcidev, tmpd[i],
+                                              PAGE_SIZE, PCI_DMA_FROMDEVICE);
+                               qib_release_user_pages(&tmpp[i], 1);
+                               tmpp[i] = NULL;
+                               cnt++;
+                       }
+               }
+
+               tmpp = dd->pageshadow;
+               dd->pageshadow = NULL;
+               vfree(tmpp);
+       }
+
+       /*
+        * Free any resources still in use (usually just kernel contexts)
+        * at unload; we do for ctxtcnt, because that's what we allocate.
+        * We acquire lock to be really paranoid that rcd isn't being
+        * accessed from some interrupt-related code (that should not happen,
+        * but best to be sure).
+        */
+       spin_lock_irqsave(&dd->uctxt_lock, flags);
+       tmp = dd->rcd;
+       dd->rcd = NULL;
+       spin_unlock_irqrestore(&dd->uctxt_lock, flags);
+       for (ctxt = 0; tmp && ctxt < dd->ctxtcnt; ctxt++) {
+               struct qib_ctxtdata *rcd = tmp[ctxt];
+
+               tmp[ctxt] = NULL; /* debugging paranoia */
+               qib_free_ctxtdata(dd, rcd);
+       }
+       kfree(tmp);
+       kfree(dd->boardname);
+}
+
+/*
+ * Clean up on unit shutdown, or error during unit load after
+ * successful initialization.
+ */
+static void qib_postinit_cleanup(struct qib_devdata *dd)
+{
+       /*
+        * Clean up chip-specific stuff.
+        * We check for NULL here, because it's outside
+        * the kregbase check, and we need to call it
+        * after the free_irq.  Thus it's possible that
+        * the function pointers were never initialized.
+        */
+       if (dd->f_cleanup)
+               dd->f_cleanup(dd);
+
+       qib_pcie_ddcleanup(dd);
+
+       cleanup_device_data(dd);
+
+       qib_free_devdata(dd);
+}
+
+static int __devinit qib_init_one(struct pci_dev *pdev,
+                                 const struct pci_device_id *ent)
+{
+       int ret, j, pidx, initfail;
+       struct qib_devdata *dd = NULL;
+
+       ret = qib_pcie_init(pdev, ent);
+       if (ret)
+               goto bail;
+
+       /*
+        * Do device-specific initialiation, function table setup, dd
+        * allocation, etc.
+        */
+       switch (ent->device) {
+       case PCI_DEVICE_ID_QLOGIC_IB_6120:
+#ifdef CONFIG_PCI_MSI
+               dd = qib_init_iba6120_funcs(pdev, ent);
+#else
+               qib_early_err(&pdev->dev, "QLogic PCIE device 0x%x cannot "
+                     "work if CONFIG_PCI_MSI is not enabled\n",
+                     ent->device);
+#endif
+               break;
+
+       case PCI_DEVICE_ID_QLOGIC_IB_7220:
+               dd = qib_init_iba7220_funcs(pdev, ent);
+               break;
+
+       case PCI_DEVICE_ID_QLOGIC_IB_7322:
+               dd = qib_init_iba7322_funcs(pdev, ent);
+               break;
+
+       default:
+               qib_early_err(&pdev->dev, "Failing on unknown QLogic "
+                             "deviceid 0x%x\n", ent->device);
+               ret = -ENODEV;
+       }
+
+       if (IS_ERR(dd))
+               ret = PTR_ERR(dd);
+       if (ret)
+               goto bail; /* error already printed */
+
+       /* do the generic initialization */
+       initfail = qib_init(dd, 0);
+
+       ret = qib_register_ib_device(dd);
+
+       /*
+        * Now ready for use.  this should be cleared whenever we
+        * detect a reset, or initiate one.  If earlier failure,
+        * we still create devices, so diags, etc. can be used
+        * to determine cause of problem.
+        */
+       if (!qib_mini_init && !initfail && !ret)
+               dd->flags |= QIB_INITTED;
+
+       j = qib_device_create(dd);
+       if (j)
+               qib_dev_err(dd, "Failed to create /dev devices: %d\n", -j);
+       j = qibfs_add(dd);
+       if (j)
+               qib_dev_err(dd, "Failed filesystem setup for counters: %d\n",
+                           -j);
+
+       if (qib_mini_init || initfail || ret) {
+               qib_stop_timers(dd);
+               for (pidx = 0; pidx < dd->num_pports; ++pidx)
+                       dd->f_quiet_serdes(dd->pport + pidx);
+               if (initfail)
+                       ret = initfail;
+               goto bail;
+       }
+
+       if (!qib_wc_pat) {
+               ret = qib_enable_wc(dd);
+               if (ret) {
+                       qib_dev_err(dd, "Write combining not enabled "
+                                   "(err %d): performance may be poor\n",
+                                   -ret);
+                       ret = 0;
+               }
+       }
+
+       qib_verify_pioperf(dd);
+bail:
+       return ret;
+}
+
+static void __devexit qib_remove_one(struct pci_dev *pdev)
+{
+       struct qib_devdata *dd = pci_get_drvdata(pdev);
+       int ret;
+
+       /* unregister from IB core */
+       qib_unregister_ib_device(dd);
+
+       /*
+        * Disable the IB link, disable interrupts on the device,
+        * clear dma engines, etc.
+        */
+       if (!qib_mini_init)
+               qib_shutdown_device(dd);
+
+       qib_stop_timers(dd);
+
+       /* wait until all of our (qsfp) schedule_work() calls complete */
+       flush_scheduled_work();
+
+       ret = qibfs_remove(dd);
+       if (ret)
+               qib_dev_err(dd, "Failed counters filesystem cleanup: %d\n",
+                           -ret);
+
+       qib_device_remove(dd);
+
+       qib_postinit_cleanup(dd);
+}
+
+/**
+ * qib_create_rcvhdrq - create a receive header queue
+ * @dd: the qlogic_ib device
+ * @rcd: the context data
+ *
+ * This must be contiguous memory (from an i/o perspective), and must be
+ * DMA'able (which means for some systems, it will go through an IOMMU,
+ * or be forced into a low address range).
+ */
+int qib_create_rcvhdrq(struct qib_devdata *dd, struct qib_ctxtdata *rcd)
+{
+       unsigned amt;
+
+       if (!rcd->rcvhdrq) {
+               dma_addr_t phys_hdrqtail;
+               gfp_t gfp_flags;
+
+               amt = ALIGN(dd->rcvhdrcnt * dd->rcvhdrentsize *
+                           sizeof(u32), PAGE_SIZE);
+               gfp_flags = (rcd->ctxt >= dd->first_user_ctxt) ?
+                       GFP_USER : GFP_KERNEL;
+               rcd->rcvhdrq = dma_alloc_coherent(
+                       &dd->pcidev->dev, amt, &rcd->rcvhdrq_phys,
+                       gfp_flags | __GFP_COMP);
+
+               if (!rcd->rcvhdrq) {
+                       qib_dev_err(dd, "attempt to allocate %d bytes "
+                                   "for ctxt %u rcvhdrq failed\n",
+                                   amt, rcd->ctxt);
+                       goto bail;
+               }
+
+               if (rcd->ctxt >= dd->first_user_ctxt) {
+                       rcd->user_event_mask = vmalloc_user(PAGE_SIZE);
+                       if (!rcd->user_event_mask)
+                               goto bail_free_hdrq;
+               }
+
+               if (!(dd->flags & QIB_NODMA_RTAIL)) {
+                       rcd->rcvhdrtail_kvaddr = dma_alloc_coherent(
+                               &dd->pcidev->dev, PAGE_SIZE, &phys_hdrqtail,
+                               gfp_flags);
+                       if (!rcd->rcvhdrtail_kvaddr)
+                               goto bail_free;
+                       rcd->rcvhdrqtailaddr_phys = phys_hdrqtail;
+               }
+
+               rcd->rcvhdrq_size = amt;
+       }
+
+       /* clear for security and sanity on each use */
+       memset(rcd->rcvhdrq, 0, rcd->rcvhdrq_size);
+       if (rcd->rcvhdrtail_kvaddr)
+               memset(rcd->rcvhdrtail_kvaddr, 0, PAGE_SIZE);
+       return 0;
+
+bail_free:
+       qib_dev_err(dd, "attempt to allocate 1 page for ctxt %u "
+                   "rcvhdrqtailaddr failed\n", rcd->ctxt);
+       vfree(rcd->user_event_mask);
+       rcd->user_event_mask = NULL;
+bail_free_hdrq:
+       dma_free_coherent(&dd->pcidev->dev, amt, rcd->rcvhdrq,
+                         rcd->rcvhdrq_phys);
+       rcd->rcvhdrq = NULL;
+bail:
+       return -ENOMEM;
+}
+
+/**
+ * allocate eager buffers, both kernel and user contexts.
+ * @rcd: the context we are setting up.
+ *
+ * Allocate the eager TID buffers and program them into hip.
+ * They are no longer completely contiguous, we do multiple allocation
+ * calls.  Otherwise we get the OOM code involved, by asking for too
+ * much per call, with disastrous results on some kernels.
+ */
+int qib_setup_eagerbufs(struct qib_ctxtdata *rcd)
+{
+       struct qib_devdata *dd = rcd->dd;
+       unsigned e, egrcnt, egrperchunk, chunk, egrsize, egroff;
+       size_t size;
+       gfp_t gfp_flags;
+
+       /*
+        * GFP_USER, but without GFP_FS, so buffer cache can be
+        * coalesced (we hope); otherwise, even at order 4,
+        * heavy filesystem activity makes these fail, and we can
+        * use compound pages.
+        */
+       gfp_flags = __GFP_WAIT | __GFP_IO | __GFP_COMP;
+
+       egrcnt = rcd->rcvegrcnt;
+       egroff = rcd->rcvegr_tid_base;
+       egrsize = dd->rcvegrbufsize;
+
+       chunk = rcd->rcvegrbuf_chunks;
+       egrperchunk = rcd->rcvegrbufs_perchunk;
+       size = rcd->rcvegrbuf_size;
+       if (!rcd->rcvegrbuf) {
+               rcd->rcvegrbuf =
+                       kzalloc(chunk * sizeof(rcd->rcvegrbuf[0]),
+                               GFP_KERNEL);
+               if (!rcd->rcvegrbuf)
+                       goto bail;
+       }
+       if (!rcd->rcvegrbuf_phys) {
+               rcd->rcvegrbuf_phys =
+                       kmalloc(chunk * sizeof(rcd->rcvegrbuf_phys[0]),
+                               GFP_KERNEL);
+               if (!rcd->rcvegrbuf_phys)
+                       goto bail_rcvegrbuf;
+       }
+       for (e = 0; e < rcd->rcvegrbuf_chunks; e++) {
+               if (rcd->rcvegrbuf[e])
+                       continue;
+               rcd->rcvegrbuf[e] =
+                       dma_alloc_coherent(&dd->pcidev->dev, size,
+                                          &rcd->rcvegrbuf_phys[e],
+                                          gfp_flags);
+               if (!rcd->rcvegrbuf[e])
+                       goto bail_rcvegrbuf_phys;
+       }
+
+       rcd->rcvegr_phys = rcd->rcvegrbuf_phys[0];
+
+       for (e = chunk = 0; chunk < rcd->rcvegrbuf_chunks; chunk++) {
+               dma_addr_t pa = rcd->rcvegrbuf_phys[chunk];
+               unsigned i;
+
+               for (i = 0; e < egrcnt && i < egrperchunk; e++, i++) {
+                       dd->f_put_tid(dd, e + egroff +
+                                         (u64 __iomem *)
+                                         ((char __iomem *)
+                                          dd->kregbase +
+                                          dd->rcvegrbase),
+                                         RCVHQ_RCV_TYPE_EAGER, pa);
+                       pa += egrsize;
+               }
+               cond_resched(); /* don't hog the cpu */
+       }
+
+       return 0;
+
+bail_rcvegrbuf_phys:
+       for (e = 0; e < rcd->rcvegrbuf_chunks && rcd->rcvegrbuf[e]; e++)
+               dma_free_coherent(&dd->pcidev->dev, size,
+                                 rcd->rcvegrbuf[e], rcd->rcvegrbuf_phys[e]);
+       kfree(rcd->rcvegrbuf_phys);
+       rcd->rcvegrbuf_phys = NULL;
+bail_rcvegrbuf:
+       kfree(rcd->rcvegrbuf);
+       rcd->rcvegrbuf = NULL;
+bail:
+       return -ENOMEM;
+}
+
+int init_chip_wc_pat(struct qib_devdata *dd, u32 vl15buflen)
+{
+       u64 __iomem *qib_kregbase = NULL;
+       void __iomem *qib_piobase = NULL;
+       u64 __iomem *qib_userbase = NULL;
+       u64 qib_kreglen;
+       u64 qib_pio2koffset = dd->piobufbase & 0xffffffff;
+       u64 qib_pio4koffset = dd->piobufbase >> 32;
+       u64 qib_pio2klen = dd->piobcnt2k * dd->palign;
+       u64 qib_pio4klen = dd->piobcnt4k * dd->align4k;
+       u64 qib_physaddr = dd->physaddr;
+       u64 qib_piolen;
+       u64 qib_userlen = 0;
+
+       /*
+        * Free the old mapping because the kernel will try to reuse the
+        * old mapping and not create a new mapping with the
+        * write combining attribute.
+        */
+       iounmap(dd->kregbase);
+       dd->kregbase = NULL;
+
+       /*
+        * Assumes chip address space looks like:
+        *      - kregs + sregs + cregs + uregs (in any order)
+        *      - piobufs (2K and 4K bufs in either order)
+        * or:
+        *      - kregs + sregs + cregs (in any order)
+        *      - piobufs (2K and 4K bufs in either order)
+        *      - uregs
+        */
+       if (dd->piobcnt4k == 0) {
+               qib_kreglen = qib_pio2koffset;
+               qib_piolen = qib_pio2klen;
+       } else if (qib_pio2koffset < qib_pio4koffset) {
+               qib_kreglen = qib_pio2koffset;
+               qib_piolen = qib_pio4koffset + qib_pio4klen - qib_kreglen;
+       } else {
+               qib_kreglen = qib_pio4koffset;
+               qib_piolen = qib_pio2koffset + qib_pio2klen - qib_kreglen;
+       }
+       qib_piolen += vl15buflen;
+       /* Map just the configured ports (not all hw ports) */
+       if (dd->uregbase > qib_kreglen)
+               qib_userlen = dd->ureg_align * dd->cfgctxts;
+
+       /* Sanity checks passed, now create the new mappings */
+       qib_kregbase = ioremap_nocache(qib_physaddr, qib_kreglen);
+       if (!qib_kregbase)
+               goto bail;
+
+       qib_piobase = ioremap_wc(qib_physaddr + qib_kreglen, qib_piolen);
+       if (!qib_piobase)
+               goto bail_kregbase;
+
+       if (qib_userlen) {
+               qib_userbase = ioremap_nocache(qib_physaddr + dd->uregbase,
+                                              qib_userlen);
+               if (!qib_userbase)
+                       goto bail_piobase;
+       }
+
+       dd->kregbase = qib_kregbase;
+       dd->kregend = (u64 __iomem *)
+               ((char __iomem *) qib_kregbase + qib_kreglen);
+       dd->piobase = qib_piobase;
+       dd->pio2kbase = (void __iomem *)
+               (((char __iomem *) dd->piobase) +
+                qib_pio2koffset - qib_kreglen);
+       if (dd->piobcnt4k)
+               dd->pio4kbase = (void __iomem *)
+                       (((char __iomem *) dd->piobase) +
+                        qib_pio4koffset - qib_kreglen);
+       if (qib_userlen)
+               /* ureg will now be accessed relative to dd->userbase */
+               dd->userbase = qib_userbase;
+       return 0;
+
+bail_piobase:
+       iounmap(qib_piobase);
+bail_kregbase:
+       iounmap(qib_kregbase);
+bail:
+       return -ENOMEM;
+}
diff --git a/drivers/infiniband/hw/qib/qib_intr.c b/drivers/infiniband/hw/qib/qib_intr.c
new file mode 100644 (file)
index 0000000..54a4082
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009, 2010 QLogic Corporation.
+ * All rights reserved.
+ * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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/pci.h>
+#include <linux/delay.h>
+
+#include "qib.h"
+#include "qib_common.h"
+
+/**
+ * qib_format_hwmsg - format a single hwerror message
+ * @msg message buffer
+ * @msgl length of message buffer
+ * @hwmsg message to add to message buffer
+ */
+static void qib_format_hwmsg(char *msg, size_t msgl, const char *hwmsg)
+{
+       strlcat(msg, "[", msgl);
+       strlcat(msg, hwmsg, msgl);
+       strlcat(msg, "]", msgl);
+}
+
+/**
+ * qib_format_hwerrors - format hardware error messages for display
+ * @hwerrs hardware errors bit vector
+ * @hwerrmsgs hardware error descriptions
+ * @nhwerrmsgs number of hwerrmsgs
+ * @msg message buffer
+ * @msgl message buffer length
+ */
+void qib_format_hwerrors(u64 hwerrs, const struct qib_hwerror_msgs *hwerrmsgs,
+                        size_t nhwerrmsgs, char *msg, size_t msgl)
+{
+       int i;
+
+       for (i = 0; i < nhwerrmsgs; i++)
+               if (hwerrs & hwerrmsgs[i].mask)
+                       qib_format_hwmsg(msg, msgl, hwerrmsgs[i].msg);
+}
+
+static void signal_ib_event(struct qib_pportdata *ppd, enum ib_event_type ev)
+{
+       struct ib_event event;
+       struct qib_devdata *dd = ppd->dd;
+
+       event.device = &dd->verbs_dev.ibdev;
+       event.element.port_num = ppd->port;
+       event.event = ev;
+       ib_dispatch_event(&event);
+}
+
+void qib_handle_e_ibstatuschanged(struct qib_pportdata *ppd, u64 ibcs)
+{
+       struct qib_devdata *dd = ppd->dd;
+       unsigned long flags;
+       u32 lstate;
+       u8 ltstate;
+       enum ib_event_type ev = 0;
+
+       lstate = dd->f_iblink_state(ibcs); /* linkstate */
+       ltstate = dd->f_ibphys_portstate(ibcs);
+
+       /*
+        * If linkstate transitions into INIT from any of the various down
+        * states, or if it transitions from any of the up (INIT or better)
+        * states into any of the down states (except link recovery), then
+        * call the chip-specific code to take appropriate actions.
+        */
+       if (lstate >= IB_PORT_INIT && (ppd->lflags & QIBL_LINKDOWN) &&
+           ltstate == IB_PHYSPORTSTATE_LINKUP) {
+               /* transitioned to UP */
+               if (dd->f_ib_updown(ppd, 1, ibcs))
+                       goto skip_ibchange; /* chip-code handled */
+       } else if (ppd->lflags & (QIBL_LINKINIT | QIBL_LINKARMED |
+                  QIBL_LINKACTIVE | QIBL_IB_FORCE_NOTIFY)) {
+               if (ltstate != IB_PHYSPORTSTATE_LINKUP &&
+                   ltstate <= IB_PHYSPORTSTATE_CFG_TRAIN &&
+                   dd->f_ib_updown(ppd, 0, ibcs))
+                       goto skip_ibchange; /* chip-code handled */
+               qib_set_uevent_bits(ppd, _QIB_EVENT_LINKDOWN_BIT);
+       }
+
+       if (lstate != IB_PORT_DOWN) {
+               /* lstate is INIT, ARMED, or ACTIVE */
+               if (lstate != IB_PORT_ACTIVE) {
+                       *ppd->statusp &= ~QIB_STATUS_IB_READY;
+                       if (ppd->lflags & QIBL_LINKACTIVE)
+                               ev = IB_EVENT_PORT_ERR;
+                       spin_lock_irqsave(&ppd->lflags_lock, flags);
+                       if (lstate == IB_PORT_ARMED) {
+                               ppd->lflags |= QIBL_LINKARMED | QIBL_LINKV;
+                               ppd->lflags &= ~(QIBL_LINKINIT |
+                                       QIBL_LINKDOWN | QIBL_LINKACTIVE);
+                       } else {
+                               ppd->lflags |= QIBL_LINKINIT | QIBL_LINKV;
+                               ppd->lflags &= ~(QIBL_LINKARMED |
+                                       QIBL_LINKDOWN | QIBL_LINKACTIVE);
+                       }
+                       spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+                       /* start a 75msec timer to clear symbol errors */
+                       mod_timer(&ppd->symerr_clear_timer,
+                                 msecs_to_jiffies(75));
+               } else if (ltstate == IB_PHYSPORTSTATE_LINKUP) {
+                       /* active, but not active defered */
+                       qib_hol_up(ppd); /* useful only for 6120 now */
+                       *ppd->statusp |=
+                               QIB_STATUS_IB_READY | QIB_STATUS_IB_CONF;
+                       qib_clear_symerror_on_linkup((unsigned long)ppd);
+                       spin_lock_irqsave(&ppd->lflags_lock, flags);
+                       ppd->lflags |= QIBL_LINKACTIVE | QIBL_LINKV;
+                       ppd->lflags &= ~(QIBL_LINKINIT |
+                               QIBL_LINKDOWN | QIBL_LINKARMED);
+                       spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+                       if (dd->flags & QIB_HAS_SEND_DMA)
+                               qib_sdma_process_event(ppd,
+                                       qib_sdma_event_e30_go_running);
+                       ev = IB_EVENT_PORT_ACTIVE;
+                       dd->f_setextled(ppd, 1);
+               }
+       } else { /* down */
+               if (ppd->lflags & QIBL_LINKACTIVE)
+                       ev = IB_EVENT_PORT_ERR;
+               spin_lock_irqsave(&ppd->lflags_lock, flags);
+               ppd->lflags |= QIBL_LINKDOWN | QIBL_LINKV;
+               ppd->lflags &= ~(QIBL_LINKINIT |
+                                QIBL_LINKACTIVE | QIBL_LINKARMED);
+               spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+               *ppd->statusp &= ~QIB_STATUS_IB_READY;
+       }
+
+skip_ibchange:
+       ppd->lastibcstat = ibcs;
+       if (ev)
+               signal_ib_event(ppd, ev);
+       return;
+}
+
+void qib_clear_symerror_on_linkup(unsigned long opaque)
+{
+       struct qib_pportdata *ppd = (struct qib_pportdata *)opaque;
+
+       if (ppd->lflags & QIBL_LINKACTIVE)
+               return;
+
+       ppd->ibport_data.z_symbol_error_counter =
+               ppd->dd->f_portcntr(ppd, QIBPORTCNTR_IBSYMBOLERR);
+}
+
+/*
+ * Handle receive interrupts for user ctxts; this means a user
+ * process was waiting for a packet to arrive, and didn't want
+ * to poll.
+ */
+void qib_handle_urcv(struct qib_devdata *dd, u64 ctxtr)
+{
+       struct qib_ctxtdata *rcd;
+       unsigned long flags;
+       int i;
+
+       spin_lock_irqsave(&dd->uctxt_lock, flags);
+       for (i = dd->first_user_ctxt; dd->rcd && i < dd->cfgctxts; i++) {
+               if (!(ctxtr & (1ULL << i)))
+                       continue;
+               rcd = dd->rcd[i];
+               if (!rcd || !rcd->cnt)
+                       continue;
+
+               if (test_and_clear_bit(QIB_CTXT_WAITING_RCV, &rcd->flag)) {
+                       wake_up_interruptible(&rcd->wait);
+                       dd->f_rcvctrl(rcd->ppd, QIB_RCVCTRL_INTRAVAIL_DIS,
+                                     rcd->ctxt);
+               } else if (test_and_clear_bit(QIB_CTXT_WAITING_URG,
+                                             &rcd->flag)) {
+                       rcd->urgent++;
+                       wake_up_interruptible(&rcd->wait);
+               }
+       }
+       spin_unlock_irqrestore(&dd->uctxt_lock, flags);
+}
+
+void qib_bad_intrstatus(struct qib_devdata *dd)
+{
+       static int allbits;
+
+       /* separate routine, for better optimization of qib_intr() */
+
+       /*
+        * We print the message and disable interrupts, in hope of
+        * having a better chance of debugging the problem.
+        */
+       qib_dev_err(dd, "Read of chip interrupt status failed"
+                   " disabling interrupts\n");
+       if (allbits++) {
+               /* disable interrupt delivery, something is very wrong */
+               if (allbits == 2)
+                       dd->f_set_intr_state(dd, 0);
+               if (allbits == 3) {
+                       qib_dev_err(dd, "2nd bad interrupt status, "
+                                   "unregistering interrupts\n");
+                       dd->flags |= QIB_BADINTR;
+                       dd->flags &= ~QIB_INITTED;
+                       dd->f_free_irq(dd);
+               }
+       }
+}
diff --git a/drivers/infiniband/hw/qib/qib_keys.c b/drivers/infiniband/hw/qib/qib_keys.c
new file mode 100644 (file)
index 0000000..4b80eb1
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 2006, 2007, 2009 QLogic Corporation. All rights reserved.
+ * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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 "qib.h"
+
+/**
+ * qib_alloc_lkey - allocate an lkey
+ * @rkt: lkey table in which to allocate the lkey
+ * @mr: memory region that this lkey protects
+ *
+ * Returns 1 if successful, otherwise returns 0.
+ */
+
+int qib_alloc_lkey(struct qib_lkey_table *rkt, struct qib_mregion *mr)
+{
+       unsigned long flags;
+       u32 r;
+       u32 n;
+       int ret;
+
+       spin_lock_irqsave(&rkt->lock, flags);
+
+       /* Find the next available LKEY */
+       r = rkt->next;
+       n = r;
+       for (;;) {
+               if (rkt->table[r] == NULL)
+                       break;
+               r = (r + 1) & (rkt->max - 1);
+               if (r == n) {
+                       spin_unlock_irqrestore(&rkt->lock, flags);
+                       ret = 0;
+                       goto bail;
+               }
+       }
+       rkt->next = (r + 1) & (rkt->max - 1);
+       /*
+        * Make sure lkey is never zero which is reserved to indicate an
+        * unrestricted LKEY.
+        */
+       rkt->gen++;
+       mr->lkey = (r << (32 - ib_qib_lkey_table_size)) |
+               ((((1 << (24 - ib_qib_lkey_table_size)) - 1) & rkt->gen)
+                << 8);
+       if (mr->lkey == 0) {
+               mr->lkey |= 1 << 8;
+               rkt->gen++;
+       }
+       rkt->table[r] = mr;
+       spin_unlock_irqrestore(&rkt->lock, flags);
+
+       ret = 1;
+
+bail:
+       return ret;
+}
+
+/**
+ * qib_free_lkey - free an lkey
+ * @rkt: table from which to free the lkey
+ * @lkey: lkey id to free
+ */
+int qib_free_lkey(struct qib_ibdev *dev, struct qib_mregion *mr)
+{
+       unsigned long flags;
+       u32 lkey = mr->lkey;
+       u32 r;
+       int ret;
+
+       spin_lock_irqsave(&dev->lk_table.lock, flags);
+       if (lkey == 0) {
+               if (dev->dma_mr && dev->dma_mr == mr) {
+                       ret = atomic_read(&dev->dma_mr->refcount);
+                       if (!ret)
+                               dev->dma_mr = NULL;
+               } else
+                       ret = 0;
+       } else {
+               r = lkey >> (32 - ib_qib_lkey_table_size);
+               ret = atomic_read(&dev->lk_table.table[r]->refcount);
+               if (!ret)
+                       dev->lk_table.table[r] = NULL;
+       }
+       spin_unlock_irqrestore(&dev->lk_table.lock, flags);
+
+       if (ret)
+               ret = -EBUSY;
+       return ret;
+}
+
+/**
+ * qib_lkey_ok - check IB SGE for validity and initialize
+ * @rkt: table containing lkey to check SGE against
+ * @isge: outgoing internal SGE
+ * @sge: SGE to check
+ * @acc: access flags
+ *
+ * Return 1 if valid and successful, otherwise returns 0.
+ *
+ * Check the IB SGE for validity and initialize our internal version
+ * of it.
+ */
+int qib_lkey_ok(struct qib_lkey_table *rkt, struct qib_pd *pd,
+               struct qib_sge *isge, struct ib_sge *sge, int acc)
+{
+       struct qib_mregion *mr;
+       unsigned n, m;
+       size_t off;
+       int ret = 0;
+       unsigned long flags;
+
+       /*
+        * We use LKEY == zero for kernel virtual addresses
+        * (see qib_get_dma_mr and qib_dma.c).
+        */
+       spin_lock_irqsave(&rkt->lock, flags);
+       if (sge->lkey == 0) {
+               struct qib_ibdev *dev = to_idev(pd->ibpd.device);
+
+               if (pd->user)
+                       goto bail;
+               if (!dev->dma_mr)
+                       goto bail;
+               atomic_inc(&dev->dma_mr->refcount);
+               isge->mr = dev->dma_mr;
+               isge->vaddr = (void *) sge->addr;
+               isge->length = sge->length;
+               isge->sge_length = sge->length;
+               isge->m = 0;
+               isge->n = 0;
+               goto ok;
+       }
+       mr = rkt->table[(sge->lkey >> (32 - ib_qib_lkey_table_size))];
+       if (unlikely(mr == NULL || mr->lkey != sge->lkey ||
+                    mr->pd != &pd->ibpd))
+               goto bail;
+
+       off = sge->addr - mr->user_base;
+       if (unlikely(sge->addr < mr->user_base ||
+                    off + sge->length > mr->length ||
+                    (mr->access_flags & acc) != acc))
+               goto bail;
+
+       off += mr->offset;
+       m = 0;
+       n = 0;
+       while (off >= mr->map[m]->segs[n].length) {
+               off -= mr->map[m]->segs[n].length;
+               n++;
+               if (n >= QIB_SEGSZ) {
+                       m++;
+                       n = 0;
+               }
+       }
+       atomic_inc(&mr->refcount);
+       isge->mr = mr;
+       isge->vaddr = mr->map[m]->segs[n].vaddr + off;
+       isge->length = mr->map[m]->segs[n].length - off;
+       isge->sge_length = sge->length;
+       isge->m = m;
+       isge->n = n;
+ok:
+       ret = 1;
+bail:
+       spin_unlock_irqrestore(&rkt->lock, flags);
+       return ret;
+}
+
+/**
+ * qib_rkey_ok - check the IB virtual address, length, and RKEY
+ * @dev: infiniband device
+ * @ss: SGE state
+ * @len: length of data
+ * @vaddr: virtual address to place data
+ * @rkey: rkey to check
+ * @acc: access flags
+ *
+ * Return 1 if successful, otherwise 0.
+ */
+int qib_rkey_ok(struct qib_qp *qp, struct qib_sge *sge,
+               u32 len, u64 vaddr, u32 rkey, int acc)
+{
+       struct qib_lkey_table *rkt = &to_idev(qp->ibqp.device)->lk_table;
+       struct qib_mregion *mr;
+       unsigned n, m;
+       size_t off;
+       int ret = 0;
+       unsigned long flags;
+
+       /*
+        * We use RKEY == zero for kernel virtual addresses
+        * (see qib_get_dma_mr and qib_dma.c).
+        */
+       spin_lock_irqsave(&rkt->lock, flags);
+       if (rkey == 0) {
+               struct qib_pd *pd = to_ipd(qp->ibqp.pd);
+               struct qib_ibdev *dev = to_idev(pd->ibpd.device);
+
+               if (pd->user)
+                       goto bail;
+               if (!dev->dma_mr)
+                       goto bail;
+               atomic_inc(&dev->dma_mr->refcount);
+               sge->mr = dev->dma_mr;
+               sge->vaddr = (void *) vaddr;
+               sge->length = len;
+               sge->sge_length = len;
+               sge->m = 0;
+               sge->n = 0;
+               goto ok;
+       }
+
+       mr = rkt->table[(rkey >> (32 - ib_qib_lkey_table_size))];
+       if (unlikely(mr == NULL || mr->lkey != rkey || qp->ibqp.pd != mr->pd))
+               goto bail;
+
+       off = vaddr - mr->iova;
+       if (unlikely(vaddr < mr->iova || off + len > mr->length ||
+                    (mr->access_flags & acc) == 0))
+               goto bail;
+
+       off += mr->offset;
+       m = 0;
+       n = 0;
+       while (off >= mr->map[m]->segs[n].length) {
+               off -= mr->map[m]->segs[n].length;
+               n++;
+               if (n >= QIB_SEGSZ) {
+                       m++;
+                       n = 0;
+               }
+       }
+       atomic_inc(&mr->refcount);
+       sge->mr = mr;
+       sge->vaddr = mr->map[m]->segs[n].vaddr + off;
+       sge->length = mr->map[m]->segs[n].length - off;
+       sge->sge_length = len;
+       sge->m = m;
+       sge->n = n;
+ok:
+       ret = 1;
+bail:
+       spin_unlock_irqrestore(&rkt->lock, flags);
+       return ret;
+}
+
+/*
+ * Initialize the memory region specified by the work reqeust.
+ */
+int qib_fast_reg_mr(struct qib_qp *qp, struct ib_send_wr *wr)
+{
+       struct qib_lkey_table *rkt = &to_idev(qp->ibqp.device)->lk_table;
+       struct qib_pd *pd = to_ipd(qp->ibqp.pd);
+       struct qib_mregion *mr;
+       u32 rkey = wr->wr.fast_reg.rkey;
+       unsigned i, n, m;
+       int ret = -EINVAL;
+       unsigned long flags;
+       u64 *page_list;
+       size_t ps;
+
+       spin_lock_irqsave(&rkt->lock, flags);
+       if (pd->user || rkey == 0)
+               goto bail;
+
+       mr = rkt->table[(rkey >> (32 - ib_qib_lkey_table_size))];
+       if (unlikely(mr == NULL || qp->ibqp.pd != mr->pd))
+               goto bail;
+
+       if (wr->wr.fast_reg.page_list_len > mr->max_segs)
+               goto bail;
+
+       ps = 1UL << wr->wr.fast_reg.page_shift;
+       if (wr->wr.fast_reg.length > ps * wr->wr.fast_reg.page_list_len)
+               goto bail;
+
+       mr->user_base = wr->wr.fast_reg.iova_start;
+       mr->iova = wr->wr.fast_reg.iova_start;
+       mr->lkey = rkey;
+       mr->length = wr->wr.fast_reg.length;
+       mr->access_flags = wr->wr.fast_reg.access_flags;
+       page_list = wr->wr.fast_reg.page_list->page_list;
+       m = 0;
+       n = 0;
+       for (i = 0; i < wr->wr.fast_reg.page_list_len; i++) {
+               mr->map[m]->segs[n].vaddr = (void *) page_list[i];
+               mr->map[m]->segs[n].length = ps;
+               if (++n == QIB_SEGSZ) {
+                       m++;
+                       n = 0;
+               }
+       }
+
+       ret = 0;
+bail:
+       spin_unlock_irqrestore(&rkt->lock, flags);
+       return ret;
+}
diff --git a/drivers/infiniband/hw/qib/qib_mad.c b/drivers/infiniband/hw/qib/qib_mad.c
new file mode 100644 (file)
index 0000000..94b0d1f
--- /dev/null
@@ -0,0 +1,2173 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009, 2010 QLogic Corporation.
+ * All rights reserved.
+ * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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 <rdma/ib_smi.h>
+
+#include "qib.h"
+#include "qib_mad.h"
+
+static int reply(struct ib_smp *smp)
+{
+       /*
+        * The verbs framework will handle the directed/LID route
+        * packet changes.
+        */
+       smp->method = IB_MGMT_METHOD_GET_RESP;
+       if (smp->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)
+               smp->status |= IB_SMP_DIRECTION;
+       return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
+}
+
+static void qib_send_trap(struct qib_ibport *ibp, void *data, unsigned len)
+{
+       struct ib_mad_send_buf *send_buf;
+       struct ib_mad_agent *agent;
+       struct ib_smp *smp;
+       int ret;
+       unsigned long flags;
+       unsigned long timeout;
+
+       agent = ibp->send_agent;
+       if (!agent)
+               return;
+
+       /* o14-3.2.1 */
+       if (!(ppd_from_ibp(ibp)->lflags & QIBL_LINKACTIVE))
+               return;
+
+       /* o14-2 */
+       if (ibp->trap_timeout && time_before(jiffies, ibp->trap_timeout))
+               return;
+
+       send_buf = ib_create_send_mad(agent, 0, 0, 0, IB_MGMT_MAD_HDR,
+                                     IB_MGMT_MAD_DATA, GFP_ATOMIC);
+       if (IS_ERR(send_buf))
+               return;
+
+       smp = send_buf->mad;
+       smp->base_version = IB_MGMT_BASE_VERSION;
+       smp->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
+       smp->class_version = 1;
+       smp->method = IB_MGMT_METHOD_TRAP;
+       ibp->tid++;
+       smp->tid = cpu_to_be64(ibp->tid);
+       smp->attr_id = IB_SMP_ATTR_NOTICE;
+       /* o14-1: smp->mkey = 0; */
+       memcpy(smp->data, data, len);
+
+       spin_lock_irqsave(&ibp->lock, flags);
+       if (!ibp->sm_ah) {
+               if (ibp->sm_lid != be16_to_cpu(IB_LID_PERMISSIVE)) {
+                       struct ib_ah *ah;
+                       struct ib_ah_attr attr;
+
+                       memset(&attr, 0, sizeof attr);
+                       attr.dlid = ibp->sm_lid;
+                       attr.port_num = ppd_from_ibp(ibp)->port;
+                       ah = ib_create_ah(ibp->qp0->ibqp.pd, &attr);
+                       if (IS_ERR(ah))
+                               ret = -EINVAL;
+                       else {
+                               send_buf->ah = ah;
+                               ibp->sm_ah = to_iah(ah);
+                               ret = 0;
+                       }
+               } else
+                       ret = -EINVAL;
+       } else {
+               send_buf->ah = &ibp->sm_ah->ibah;
+               ret = 0;
+       }
+       spin_unlock_irqrestore(&ibp->lock, flags);
+
+       if (!ret)
+               ret = ib_post_send_mad(send_buf, NULL);
+       if (!ret) {
+               /* 4.096 usec. */
+               timeout = (4096 * (1UL << ibp->subnet_timeout)) / 1000;
+               ibp->trap_timeout = jiffies + usecs_to_jiffies(timeout);
+       } else {
+               ib_free_send_mad(send_buf);
+               ibp->trap_timeout = 0;
+       }
+}
+
+/*
+ * Send a bad [PQ]_Key trap (ch. 14.3.8).
+ */
+void qib_bad_pqkey(struct qib_ibport *ibp, __be16 trap_num, u32 key, u32 sl,
+                  u32 qp1, u32 qp2, __be16 lid1, __be16 lid2)
+{
+       struct ib_mad_notice_attr data;
+
+       if (trap_num == IB_NOTICE_TRAP_BAD_PKEY)
+               ibp->pkey_violations++;
+       else
+               ibp->qkey_violations++;
+       ibp->n_pkt_drops++;
+
+       /* Send violation trap */
+       data.generic_type = IB_NOTICE_TYPE_SECURITY;
+       data.prod_type_msb = 0;
+       data.prod_type_lsb = IB_NOTICE_PROD_CA;
+       data.trap_num = trap_num;
+       data.issuer_lid = cpu_to_be16(ppd_from_ibp(ibp)->lid);
+       data.toggle_count = 0;
+       memset(&data.details, 0, sizeof data.details);
+       data.details.ntc_257_258.lid1 = lid1;
+       data.details.ntc_257_258.lid2 = lid2;
+       data.details.ntc_257_258.key = cpu_to_be32(key);
+       data.details.ntc_257_258.sl_qp1 = cpu_to_be32((sl << 28) | qp1);
+       data.details.ntc_257_258.qp2 = cpu_to_be32(qp2);
+
+       qib_send_trap(ibp, &data, sizeof data);
+}
+
+/*
+ * Send a bad M_Key trap (ch. 14.3.9).
+ */
+static void qib_bad_mkey(struct qib_ibport *ibp, struct ib_smp *smp)
+{
+       struct ib_mad_notice_attr data;
+
+       /* Send violation trap */
+       data.generic_type = IB_NOTICE_TYPE_SECURITY;
+       data.prod_type_msb = 0;
+       data.prod_type_lsb = IB_NOTICE_PROD_CA;
+       data.trap_num = IB_NOTICE_TRAP_BAD_MKEY;
+       data.issuer_lid = cpu_to_be16(ppd_from_ibp(ibp)->lid);
+       data.toggle_count = 0;
+       memset(&data.details, 0, sizeof data.details);
+       data.details.ntc_256.lid = data.issuer_lid;
+       data.details.ntc_256.method = smp->method;
+       data.details.ntc_256.attr_id = smp->attr_id;
+       data.details.ntc_256.attr_mod = smp->attr_mod;
+       data.details.ntc_256.mkey = smp->mkey;
+       if (smp->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) {
+               u8 hop_cnt;
+
+               data.details.ntc_256.dr_slid = smp->dr_slid;
+               data.details.ntc_256.dr_trunc_hop = IB_NOTICE_TRAP_DR_NOTICE;
+               hop_cnt = smp->hop_cnt;
+               if (hop_cnt > ARRAY_SIZE(data.details.ntc_256.dr_rtn_path)) {
+                       data.details.ntc_256.dr_trunc_hop |=
+                               IB_NOTICE_TRAP_DR_TRUNC;
+                       hop_cnt = ARRAY_SIZE(data.details.ntc_256.dr_rtn_path);
+               }
+               data.details.ntc_256.dr_trunc_hop |= hop_cnt;
+               memcpy(data.details.ntc_256.dr_rtn_path, smp->return_path,
+                      hop_cnt);
+       }
+
+       qib_send_trap(ibp, &data, sizeof data);
+}
+
+/*
+ * Send a Port Capability Mask Changed trap (ch. 14.3.11).
+ */
+void qib_cap_mask_chg(struct qib_ibport *ibp)
+{
+       struct ib_mad_notice_attr data;
+
+       data.generic_type = IB_NOTICE_TYPE_INFO;
+       data.prod_type_msb = 0;
+       data.prod_type_lsb = IB_NOTICE_PROD_CA;
+       data.trap_num = IB_NOTICE_TRAP_CAP_MASK_CHG;
+       data.issuer_lid = cpu_to_be16(ppd_from_ibp(ibp)->lid);
+       data.toggle_count = 0;
+       memset(&data.details, 0, sizeof data.details);
+       data.details.ntc_144.lid = data.issuer_lid;
+       data.details.ntc_144.new_cap_mask = cpu_to_be32(ibp->port_cap_flags);
+
+       qib_send_trap(ibp, &data, sizeof data);
+}
+
+/*
+ * Send a System Image GUID Changed trap (ch. 14.3.12).
+ */
+void qib_sys_guid_chg(struct qib_ibport *ibp)
+{
+       struct ib_mad_notice_attr data;
+
+       data.generic_type = IB_NOTICE_TYPE_INFO;
+       data.prod_type_msb = 0;
+       data.prod_type_lsb = IB_NOTICE_PROD_CA;
+       data.trap_num = IB_NOTICE_TRAP_SYS_GUID_CHG;
+       data.issuer_lid = cpu_to_be16(ppd_from_ibp(ibp)->lid);
+       data.toggle_count = 0;
+       memset(&data.details, 0, sizeof data.details);
+       data.details.ntc_145.lid = data.issuer_lid;
+       data.details.ntc_145.new_sys_guid = ib_qib_sys_image_guid;
+
+       qib_send_trap(ibp, &data, sizeof data);
+}
+
+/*
+ * Send a Node Description Changed trap (ch. 14.3.13).
+ */
+void qib_node_desc_chg(struct qib_ibport *ibp)
+{
+       struct ib_mad_notice_attr data;
+
+       data.generic_type = IB_NOTICE_TYPE_INFO;
+       data.prod_type_msb = 0;
+       data.prod_type_lsb = IB_NOTICE_PROD_CA;
+       data.trap_num = IB_NOTICE_TRAP_CAP_MASK_CHG;
+       data.issuer_lid = cpu_to_be16(ppd_from_ibp(ibp)->lid);
+       data.toggle_count = 0;
+       memset(&data.details, 0, sizeof data.details);
+       data.details.ntc_144.lid = data.issuer_lid;
+       data.details.ntc_144.local_changes = 1;
+       data.details.ntc_144.change_flags = IB_NOTICE_TRAP_NODE_DESC_CHG;
+
+       qib_send_trap(ibp, &data, sizeof data);
+}
+
+static int subn_get_nodedescription(struct ib_smp *smp,
+                                   struct ib_device *ibdev)
+{
+       if (smp->attr_mod)
+               smp->status |= IB_SMP_INVALID_FIELD;
+
+       memcpy(smp->data, ibdev->node_desc, sizeof(smp->data));
+
+       return reply(smp);
+}
+
+static int subn_get_nodeinfo(struct ib_smp *smp, struct ib_device *ibdev,
+                            u8 port)
+{
+       struct ib_node_info *nip = (struct ib_node_info *)&smp->data;
+       struct qib_devdata *dd = dd_from_ibdev(ibdev);
+       u32 vendor, majrev, minrev;
+       unsigned pidx = port - 1; /* IB number port from 1, hdw from 0 */
+
+       /* GUID 0 is illegal */
+       if (smp->attr_mod || pidx >= dd->num_pports ||
+           dd->pport[pidx].guid == 0)
+               smp->status |= IB_SMP_INVALID_FIELD;
+       else
+               nip->port_guid = dd->pport[pidx].guid;
+
+       nip->base_version = 1;
+       nip->class_version = 1;
+       nip->node_type = 1;     /* channel adapter */
+       nip->num_ports = ibdev->phys_port_cnt;
+       /* This is already in network order */
+       nip->sys_guid = ib_qib_sys_image_guid;
+       nip->node_guid = dd->pport->guid; /* Use first-port GUID as node */
+       nip->partition_cap = cpu_to_be16(qib_get_npkeys(dd));
+       nip->device_id = cpu_to_be16(dd->deviceid);
+       majrev = dd->majrev;
+       minrev = dd->minrev;
+       nip->revision = cpu_to_be32((majrev << 16) | minrev);
+       nip->local_port_num = port;
+       vendor = dd->vendorid;
+       nip->vendor_id[0] = QIB_SRC_OUI_1;
+       nip->vendor_id[1] = QIB_SRC_OUI_2;
+       nip->vendor_id[2] = QIB_SRC_OUI_3;
+
+       return reply(smp);
+}
+
+static int subn_get_guidinfo(struct ib_smp *smp, struct ib_device *ibdev,
+                            u8 port)
+{
+       struct qib_devdata *dd = dd_from_ibdev(ibdev);
+       u32 startgx = 8 * be32_to_cpu(smp->attr_mod);
+       __be64 *p = (__be64 *) smp->data;
+       unsigned pidx = port - 1; /* IB number port from 1, hdw from 0 */
+
+       /* 32 blocks of 8 64-bit GUIDs per block */
+
+       memset(smp->data, 0, sizeof(smp->data));
+
+       if (startgx == 0 && pidx < dd->num_pports) {
+               struct qib_pportdata *ppd = dd->pport + pidx;
+               struct qib_ibport *ibp = &ppd->ibport_data;
+               __be64 g = ppd->guid;
+               unsigned i;
+
+               /* GUID 0 is illegal */
+               if (g == 0)
+                       smp->status |= IB_SMP_INVALID_FIELD;
+               else {
+                       /* The first is a copy of the read-only HW GUID. */
+                       p[0] = g;
+                       for (i = 1; i < QIB_GUIDS_PER_PORT; i++)
+                               p[i] = ibp->guids[i - 1];
+               }
+       } else
+               smp->status |= IB_SMP_INVALID_FIELD;
+
+       return reply(smp);
+}
+
+static void set_link_width_enabled(struct qib_pportdata *ppd, u32 w)
+{
+       (void) ppd->dd->f_set_ib_cfg(ppd, QIB_IB_CFG_LWID_ENB, w);
+}
+
+static void set_link_speed_enabled(struct qib_pportdata *ppd, u32 s)
+{
+       (void) ppd->dd->f_set_ib_cfg(ppd, QIB_IB_CFG_SPD_ENB, s);
+}
+
+static int get_overrunthreshold(struct qib_pportdata *ppd)
+{
+       return ppd->dd->f_get_ib_cfg(ppd, QIB_IB_CFG_OVERRUN_THRESH);
+}
+
+/**
+ * set_overrunthreshold - set the overrun threshold
+ * @ppd: the physical port data
+ * @n: the new threshold
+ *
+ * Note that this will only take effect when the link state changes.
+ */
+static int set_overrunthreshold(struct qib_pportdata *ppd, unsigned n)
+{
+       (void) ppd->dd->f_set_ib_cfg(ppd, QIB_IB_CFG_OVERRUN_THRESH,
+                                        (u32)n);
+       return 0;
+}
+
+static int get_phyerrthreshold(struct qib_pportdata *ppd)
+{
+       return ppd->dd->f_get_ib_cfg(ppd, QIB_IB_CFG_PHYERR_THRESH);
+}
+
+/**
+ * set_phyerrthreshold - set the physical error threshold
+ * @ppd: the physical port data
+ * @n: the new threshold
+ *
+ * Note that this will only take effect when the link state changes.
+ */
+static int set_phyerrthreshold(struct qib_pportdata *ppd, unsigned n)
+{
+       (void) ppd->dd->f_set_ib_cfg(ppd, QIB_IB_CFG_PHYERR_THRESH,
+                                        (u32)n);
+       return 0;
+}
+
+/**
+ * get_linkdowndefaultstate - get the default linkdown state
+ * @ppd: the physical port data
+ *
+ * Returns zero if the default is POLL, 1 if the default is SLEEP.
+ */
+static int get_linkdowndefaultstate(struct qib_pportdata *ppd)
+{
+       return ppd->dd->f_get_ib_cfg(ppd, QIB_IB_CFG_LINKDEFAULT) ==
+               IB_LINKINITCMD_SLEEP;
+}
+
+static int check_mkey(struct qib_ibport *ibp, struct ib_smp *smp, int mad_flags)
+{
+       int ret = 0;
+
+       /* Is the mkey in the process of expiring? */
+       if (ibp->mkey_lease_timeout &&
+           time_after_eq(jiffies, ibp->mkey_lease_timeout)) {
+               /* Clear timeout and mkey protection field. */
+               ibp->mkey_lease_timeout = 0;
+               ibp->mkeyprot = 0;
+       }
+
+       /* M_Key checking depends on Portinfo:M_Key_protect_bits */
+       if ((mad_flags & IB_MAD_IGNORE_MKEY) == 0 && ibp->mkey != 0 &&
+           ibp->mkey != smp->mkey &&
+           (smp->method == IB_MGMT_METHOD_SET ||
+            smp->method == IB_MGMT_METHOD_TRAP_REPRESS ||
+            (smp->method == IB_MGMT_METHOD_GET && ibp->mkeyprot >= 2))) {
+               if (ibp->mkey_violations != 0xFFFF)
+                       ++ibp->mkey_violations;
+               if (!ibp->mkey_lease_timeout && ibp->mkey_lease_period)
+                       ibp->mkey_lease_timeout = jiffies +
+                               ibp->mkey_lease_period * HZ;
+               /* Generate a trap notice. */
+               qib_bad_mkey(ibp, smp);
+               ret = IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED;
+       } else if (ibp->mkey_lease_timeout)
+               ibp->mkey_lease_timeout = 0;
+
+       return ret;
+}
+
+static int subn_get_portinfo(struct ib_smp *smp, struct ib_device *ibdev,
+                            u8 port)
+{
+       struct qib_devdata *dd;
+       struct qib_pportdata *ppd;
+       struct qib_ibport *ibp;
+       struct ib_port_info *pip = (struct ib_port_info *)smp->data;
+       u16 lid;
+       u8 mtu;
+       int ret;
+       u32 state;
+       u32 port_num = be32_to_cpu(smp->attr_mod);
+
+       if (port_num == 0)
+               port_num = port;
+       else {
+               if (port_num > ibdev->phys_port_cnt) {
+                       smp->status |= IB_SMP_INVALID_FIELD;
+                       ret = reply(smp);
+                       goto bail;
+               }
+               if (port_num != port) {
+                       ibp = to_iport(ibdev, port_num);
+                       ret = check_mkey(ibp, smp, 0);
+                       if (ret)
+                               goto bail;
+               }
+       }
+
+       dd = dd_from_ibdev(ibdev);
+       /* IB numbers ports from 1, hdw from 0 */
+       ppd = dd->pport + (port_num - 1);
+       ibp = &ppd->ibport_data;
+
+       /* Clear all fields.  Only set the non-zero fields. */
+       memset(smp->data, 0, sizeof(smp->data));
+
+       /* Only return the mkey if the protection field allows it. */
+       if (smp->method == IB_MGMT_METHOD_SET || ibp->mkey == smp->mkey ||
+           ibp->mkeyprot == 0)
+               pip->mkey = ibp->mkey;
+       pip->gid_prefix = ibp->gid_prefix;
+       lid = ppd->lid;
+       pip->lid = lid ? cpu_to_be16(lid) : IB_LID_PERMISSIVE;
+       pip->sm_lid = cpu_to_be16(ibp->sm_lid);
+       pip->cap_mask = cpu_to_be32(ibp->port_cap_flags);
+       /* pip->diag_code; */
+       pip->mkey_lease_period = cpu_to_be16(ibp->mkey_lease_period);
+       pip->local_port_num = port;
+       pip->link_width_enabled = ppd->link_width_enabled;
+       pip->link_width_supported = ppd->link_width_supported;
+       pip->link_width_active = ppd->link_width_active;
+       state = dd->f_iblink_state(ppd->lastibcstat);
+       pip->linkspeed_portstate = ppd->link_speed_supported << 4 | state;
+
+       pip->portphysstate_linkdown =
+               (dd->f_ibphys_portstate(ppd->lastibcstat) << 4) |
+               (get_linkdowndefaultstate(ppd) ? 1 : 2);
+       pip->mkeyprot_resv_lmc = (ibp->mkeyprot << 6) | ppd->lmc;
+       pip->linkspeedactive_enabled = (ppd->link_speed_active << 4) |
+               ppd->link_speed_enabled;
+       switch (ppd->ibmtu) {
+       default: /* something is wrong; fall through */
+       case 4096:
+               mtu = IB_MTU_4096;
+               break;
+       case 2048:
+               mtu = IB_MTU_2048;
+               break;
+       case 1024:
+               mtu = IB_MTU_1024;
+               break;
+       case 512:
+               mtu = IB_MTU_512;
+               break;
+       case 256:
+               mtu = IB_MTU_256;
+               break;
+       }
+       pip->neighbormtu_mastersmsl = (mtu << 4) | ibp->sm_sl;
+       pip->vlcap_inittype = ppd->vls_supported << 4;  /* InitType = 0 */
+       pip->vl_high_limit = ibp->vl_high_limit;
+       pip->vl_arb_high_cap =
+               dd->f_get_ib_cfg(ppd, QIB_IB_CFG_VL_HIGH_CAP);
+       pip->vl_arb_low_cap =
+               dd->f_get_ib_cfg(ppd, QIB_IB_CFG_VL_LOW_CAP);
+       /* InitTypeReply = 0 */
+       pip->inittypereply_mtucap = qib_ibmtu ? qib_ibmtu : IB_MTU_4096;
+       /* HCAs ignore VLStallCount and HOQLife */
+       /* pip->vlstallcnt_hoqlife; */
+       pip->operationalvl_pei_peo_fpi_fpo =
+               dd->f_get_ib_cfg(ppd, QIB_IB_CFG_OP_VLS) << 4;
+       pip->mkey_violations = cpu_to_be16(ibp->mkey_violations);
+       /* P_KeyViolations are counted by hardware. */
+       pip->pkey_violations = cpu_to_be16(ibp->pkey_violations);
+       pip->qkey_violations = cpu_to_be16(ibp->qkey_violations);
+       /* Only the hardware GUID is supported for now */
+       pip->guid_cap = QIB_GUIDS_PER_PORT;
+       pip->clientrereg_resv_subnetto = ibp->subnet_timeout;
+       /* 32.768 usec. response time (guessing) */
+       pip->resv_resptimevalue = 3;
+       pip->localphyerrors_overrunerrors =
+               (get_phyerrthreshold(ppd) << 4) |
+               get_overrunthreshold(ppd);
+       /* pip->max_credit_hint; */
+       if (ibp->port_cap_flags & IB_PORT_LINK_LATENCY_SUP) {
+               u32 v;
+
+               v = dd->f_get_ib_cfg(ppd, QIB_IB_CFG_LINKLATENCY);
+               pip->link_roundtrip_latency[0] = v >> 16;
+               pip->link_roundtrip_latency[1] = v >> 8;
+               pip->link_roundtrip_latency[2] = v;
+       }
+
+       ret = reply(smp);
+
+bail:
+       return ret;
+}
+
+/**
+ * get_pkeys - return the PKEY table
+ * @dd: the qlogic_ib device
+ * @port: the IB port number
+ * @pkeys: the pkey table is placed here
+ */
+static int get_pkeys(struct qib_devdata *dd, u8 port, u16 *pkeys)
+{
+       struct qib_pportdata *ppd = dd->pport + port - 1;
+       /*
+        * always a kernel context, no locking needed.
+        * If we get here with ppd setup, no need to check
+        * that pd is valid.
+        */
+       struct qib_ctxtdata *rcd = dd->rcd[ppd->hw_pidx];
+
+       memcpy(pkeys, rcd->pkeys, sizeof(rcd->pkeys));
+
+       return 0;
+}
+
+static int subn_get_pkeytable(struct ib_smp *smp, struct ib_device *ibdev,
+                             u8 port)
+{
+       u32 startpx = 32 * (be32_to_cpu(smp->attr_mod) & 0xffff);
+       u16 *p = (u16 *) smp->data;
+       __be16 *q = (__be16 *) smp->data;
+
+       /* 64 blocks of 32 16-bit P_Key entries */
+
+       memset(smp->data, 0, sizeof(smp->data));
+       if (startpx == 0) {
+               struct qib_devdata *dd = dd_from_ibdev(ibdev);
+               unsigned i, n = qib_get_npkeys(dd);
+
+               get_pkeys(dd, port, p);
+
+               for (i = 0; i < n; i++)
+                       q[i] = cpu_to_be16(p[i]);
+       } else
+               smp->status |= IB_SMP_INVALID_FIELD;
+
+       return reply(smp);
+}
+
+static int subn_set_guidinfo(struct ib_smp *smp, struct ib_device *ibdev,
+                            u8 port)
+{
+       struct qib_devdata *dd = dd_from_ibdev(ibdev);
+       u32 startgx = 8 * be32_to_cpu(smp->attr_mod);
+       __be64 *p = (__be64 *) smp->data;
+       unsigned pidx = port - 1; /* IB number port from 1, hdw from 0 */
+
+       /* 32 blocks of 8 64-bit GUIDs per block */
+
+       if (startgx == 0 && pidx < dd->num_pports) {
+               struct qib_pportdata *ppd = dd->pport + pidx;
+               struct qib_ibport *ibp = &ppd->ibport_data;
+               unsigned i;
+
+               /* The first entry is read-only. */
+               for (i = 1; i < QIB_GUIDS_PER_PORT; i++)
+                       ibp->guids[i - 1] = p[i];
+       } else
+               smp->status |= IB_SMP_INVALID_FIELD;
+
+       /* The only GUID we support is the first read-only entry. */
+       return subn_get_guidinfo(smp, ibdev, port);
+}
+
+/**
+ * subn_set_portinfo - set port information
+ * @smp: the incoming SM packet
+ * @ibdev: the infiniband device
+ * @port: the port on the device
+ *
+ * Set Portinfo (see ch. 14.2.5.6).
+ */
+static int subn_set_portinfo(struct ib_smp *smp, struct ib_device *ibdev,
+                            u8 port)
+{
+       struct ib_port_info *pip = (struct ib_port_info *)smp->data;
+       struct ib_event event;
+       struct qib_devdata *dd;
+       struct qib_pportdata *ppd;
+       struct qib_ibport *ibp;
+       char clientrereg = 0;
+       unsigned long flags;
+       u16 lid, smlid;
+       u8 lwe;
+       u8 lse;
+       u8 state;
+       u8 vls;
+       u8 msl;
+       u16 lstate;
+       int ret, ore, mtu;
+       u32 port_num = be32_to_cpu(smp->attr_mod);
+
+       if (port_num == 0)
+               port_num = port;
+       else {
+               if (port_num > ibdev->phys_port_cnt)
+                       goto err;
+               /* Port attributes can only be set on the receiving port */
+               if (port_num != port)
+                       goto get_only;
+       }
+
+       dd = dd_from_ibdev(ibdev);
+       /* IB numbers ports from 1, hdw from 0 */
+       ppd = dd->pport + (port_num - 1);
+       ibp = &ppd->ibport_data;
+       event.device = ibdev;
+       event.element.port_num = port;
+
+       ibp->mkey = pip->mkey;
+       ibp->gid_prefix = pip->gid_prefix;
+       ibp->mkey_lease_period = be16_to_cpu(pip->mkey_lease_period);
+
+       lid = be16_to_cpu(pip->lid);
+       /* Must be a valid unicast LID address. */
+       if (lid == 0 || lid >= QIB_MULTICAST_LID_BASE)
+               goto err;
+       if (ppd->lid != lid || ppd->lmc != (pip->mkeyprot_resv_lmc & 7)) {
+               if (ppd->lid != lid)
+                       qib_set_uevent_bits(ppd, _QIB_EVENT_LID_CHANGE_BIT);
+               if (ppd->lmc != (pip->mkeyprot_resv_lmc & 7))
+                       qib_set_uevent_bits(ppd, _QIB_EVENT_LMC_CHANGE_BIT);
+               qib_set_lid(ppd, lid, pip->mkeyprot_resv_lmc & 7);
+               event.event = IB_EVENT_LID_CHANGE;
+               ib_dispatch_event(&event);
+       }
+
+       smlid = be16_to_cpu(pip->sm_lid);
+       msl = pip->neighbormtu_mastersmsl & 0xF;
+       /* Must be a valid unicast LID address. */
+       if (smlid == 0 || smlid >= QIB_MULTICAST_LID_BASE)
+               goto err;
+       if (smlid != ibp->sm_lid || msl != ibp->sm_sl) {
+               spin_lock_irqsave(&ibp->lock, flags);
+               if (ibp->sm_ah) {
+                       if (smlid != ibp->sm_lid)
+                               ibp->sm_ah->attr.dlid = smlid;
+                       if (msl != ibp->sm_sl)
+                               ibp->sm_ah->attr.sl = msl;
+               }
+               spin_unlock_irqrestore(&ibp->lock, flags);
+               if (smlid != ibp->sm_lid)
+                       ibp->sm_lid = smlid;
+               if (msl != ibp->sm_sl)
+                       ibp->sm_sl = msl;
+               event.event = IB_EVENT_SM_CHANGE;
+               ib_dispatch_event(&event);
+       }
+
+       /* Allow 1x or 4x to be set (see 14.2.6.6). */
+       lwe = pip->link_width_enabled;
+       if (lwe) {
+               if (lwe == 0xFF)
+                       lwe = ppd->link_width_supported;
+               else if (lwe >= 16 || (lwe & ~ppd->link_width_supported))
+                       goto err;
+               set_link_width_enabled(ppd, lwe);
+       }
+
+       lse = pip->linkspeedactive_enabled & 0xF;
+       if (lse) {
+               /*
+                * The IB 1.2 spec. only allows link speed values
+                * 1, 3, 5, 7, 15.  1.2.1 extended to allow specific
+                * speeds.
+                */
+               if (lse == 15)
+                       lse = ppd->link_speed_supported;
+               else if (lse >= 8 || (lse & ~ppd->link_speed_supported))
+                       goto err;
+               set_link_speed_enabled(ppd, lse);
+       }
+
+       /* Set link down default state. */
+       switch (pip->portphysstate_linkdown & 0xF) {
+       case 0: /* NOP */
+               break;
+       case 1: /* SLEEP */
+               (void) dd->f_set_ib_cfg(ppd, QIB_IB_CFG_LINKDEFAULT,
+                                       IB_LINKINITCMD_SLEEP);
+               break;
+       case 2: /* POLL */
+               (void) dd->f_set_ib_cfg(ppd, QIB_IB_CFG_LINKDEFAULT,
+                                       IB_LINKINITCMD_POLL);
+               break;
+       default:
+               goto err;
+       }
+
+       ibp->mkeyprot = pip->mkeyprot_resv_lmc >> 6;
+       ibp->vl_high_limit = pip->vl_high_limit;
+       (void) dd->f_set_ib_cfg(ppd, QIB_IB_CFG_VL_HIGH_LIMIT,
+                                   ibp->vl_high_limit);
+
+       mtu = ib_mtu_enum_to_int((pip->neighbormtu_mastersmsl >> 4) & 0xF);
+       if (mtu == -1)
+               goto err;
+       qib_set_mtu(ppd, mtu);
+
+       /* Set operational VLs */
+       vls = (pip->operationalvl_pei_peo_fpi_fpo >> 4) & 0xF;
+       if (vls) {
+               if (vls > ppd->vls_supported)
+                       goto err;
+               (void) dd->f_set_ib_cfg(ppd, QIB_IB_CFG_OP_VLS, vls);
+       }
+
+       if (pip->mkey_violations == 0)
+               ibp->mkey_violations = 0;
+
+       if (pip->pkey_violations == 0)
+               ibp->pkey_violations = 0;
+
+       if (pip->qkey_violations == 0)
+               ibp->qkey_violations = 0;
+
+       ore = pip->localphyerrors_overrunerrors;
+       if (set_phyerrthreshold(ppd, (ore >> 4) & 0xF))
+               goto err;
+
+       if (set_overrunthreshold(ppd, (ore & 0xF)))
+               goto err;
+
+       ibp->subnet_timeout = pip->clientrereg_resv_subnetto & 0x1F;
+
+       if (pip->clientrereg_resv_subnetto & 0x80) {
+               clientrereg = 1;
+               event.event = IB_EVENT_CLIENT_REREGISTER;
+               ib_dispatch_event(&event);
+       }
+
+       /*
+        * Do the port state change now that the other link parameters
+        * have been set.
+        * Changing the port physical state only makes sense if the link
+        * is down or is being set to down.
+        */
+       state = pip->linkspeed_portstate & 0xF;
+       lstate = (pip->portphysstate_linkdown >> 4) & 0xF;
+       if (lstate && !(state == IB_PORT_DOWN || state == IB_PORT_NOP))
+               goto err;
+
+       /*
+        * Only state changes of DOWN, ARM, and ACTIVE are valid
+        * and must be in the correct state to take effect (see 7.2.6).
+        */
+       switch (state) {
+       case IB_PORT_NOP:
+               if (lstate == 0)
+                       break;
+               /* FALLTHROUGH */
+       case IB_PORT_DOWN:
+               if (lstate == 0)
+                       lstate = QIB_IB_LINKDOWN_ONLY;
+               else if (lstate == 1)
+                       lstate = QIB_IB_LINKDOWN_SLEEP;
+               else if (lstate == 2)
+                       lstate = QIB_IB_LINKDOWN;
+               else if (lstate == 3)
+                       lstate = QIB_IB_LINKDOWN_DISABLE;
+               else
+                       goto err;
+               spin_lock_irqsave(&ppd->lflags_lock, flags);
+               ppd->lflags &= ~QIBL_LINKV;
+               spin_unlock_irqrestore(&ppd->lflags_lock, flags);
+               qib_set_linkstate(ppd, lstate);
+               /*
+                * Don't send a reply if the response would be sent
+                * through the disabled port.
+                */
+               if (lstate == QIB_IB_LINKDOWN_DISABLE && smp->hop_cnt) {
+                       ret = IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED;
+                       goto done;
+               }
+               qib_wait_linkstate(ppd, QIBL_LINKV, 10);
+               break;
+       case IB_PORT_ARMED:
+               qib_set_linkstate(ppd, QIB_IB_LINKARM);
+               break;
+       case IB_PORT_ACTIVE:
+               qib_set_linkstate(ppd, QIB_IB_LINKACTIVE);
+               break;
+       default:
+               /* XXX We have already partially updated our state! */
+               goto err;
+       }
+
+       ret = subn_get_portinfo(smp, ibdev, port);
+
+       if (clientrereg)
+               pip->clientrereg_resv_subnetto |= 0x80;
+
+       goto done;
+
+err:
+       smp->status |= IB_SMP_INVALID_FIELD;
+get_only:
+       ret = subn_get_portinfo(smp, ibdev, port);
+done:
+       return ret;
+}
+
+/**
+ * rm_pkey - decrecment the reference count for the given PKEY
+ * @dd: the qlogic_ib device
+ * @key: the PKEY index
+ *
+ * Return true if this was the last reference and the hardware table entry
+ * needs to be changed.
+ */
+static int rm_pkey(struct qib_pportdata *ppd, u16 key)
+{
+       int i;
+       int ret;
+
+       for (i = 0; i < ARRAY_SIZE(ppd->pkeys); i++) {
+               if (ppd->pkeys[i] != key)
+                       continue;
+               if (atomic_dec_and_test(&ppd->pkeyrefs[i])) {
+                       ppd->pkeys[i] = 0;
+                       ret = 1;
+                       goto bail;
+               }
+               break;
+       }
+
+       ret = 0;
+
+bail:
+       return ret;
+}
+
+/**
+ * add_pkey - add the given PKEY to the hardware table
+ * @dd: the qlogic_ib device
+ * @key: the PKEY
+ *
+ * Return an error code if unable to add the entry, zero if no change,
+ * or 1 if the hardware PKEY register needs to be updated.
+ */
+static int add_pkey(struct qib_pportdata *ppd, u16 key)
+{
+       int i;
+       u16 lkey = key & 0x7FFF;
+       int any = 0;
+       int ret;
+
+       if (lkey == 0x7FFF) {
+               ret = 0;
+               goto bail;
+       }
+
+       /* Look for an empty slot or a matching PKEY. */
+       for (i = 0; i < ARRAY_SIZE(ppd->pkeys); i++) {
+               if (!ppd->pkeys[i]) {
+                       any++;
+                       continue;
+               }
+               /* If it matches exactly, try to increment the ref count */
+               if (ppd->pkeys[i] == key) {
+                       if (atomic_inc_return(&ppd->pkeyrefs[i]) > 1) {
+                               ret = 0;
+                               goto bail;
+                       }
+                       /* Lost the race. Look for an empty slot below. */
+                       atomic_dec(&ppd->pkeyrefs[i]);
+                       any++;
+               }
+               /*
+                * It makes no sense to have both the limited and unlimited
+                * PKEY set at the same time since the unlimited one will
+                * disable the limited one.
+                */
+               if ((ppd->pkeys[i] & 0x7FFF) == lkey) {
+                       ret = -EEXIST;
+                       goto bail;
+               }
+       }
+       if (!any) {
+               ret = -EBUSY;
+               goto bail;
+       }
+       for (i = 0; i < ARRAY_SIZE(ppd->pkeys); i++) {
+               if (!ppd->pkeys[i] &&
+                   atomic_inc_return(&ppd->pkeyrefs[i]) == 1) {
+                       /* for qibstats, etc. */
+                       ppd->pkeys[i] = key;
+                       ret = 1;
+                       goto bail;
+               }
+       }
+       ret = -EBUSY;
+
+bail:
+       return ret;
+}
+
+/**
+ * set_pkeys - set the PKEY table for ctxt 0
+ * @dd: the qlogic_ib device
+ * @port: the IB port number
+ * @pkeys: the PKEY table
+ */
+static int set_pkeys(struct qib_devdata *dd, u8 port, u16 *pkeys)
+{
+       struct qib_pportdata *ppd;
+       struct qib_ctxtdata *rcd;
+       int i;
+       int changed = 0;
+
+       /*
+        * IB port one/two always maps to context zero/one,
+        * always a kernel context, no locking needed
+        * If we get here with ppd setup, no need to check
+        * that rcd is valid.
+        */
+       ppd = dd->pport + (port - 1);
+       rcd = dd->rcd[ppd->hw_pidx];
+
+       for (i = 0; i < ARRAY_SIZE(rcd->pkeys); i++) {
+               u16 key = pkeys[i];
+               u16 okey = rcd->pkeys[i];
+
+               if (key == okey)
+                       continue;
+               /*
+                * The value of this PKEY table entry is changing.
+                * Remove the old entry in the hardware's array of PKEYs.
+                */
+               if (okey & 0x7FFF)
+                       changed |= rm_pkey(ppd, okey);
+               if (key & 0x7FFF) {
+                       int ret = add_pkey(ppd, key);
+
+                       if (ret < 0)
+                               key = 0;
+                       else
+                               changed |= ret;
+               }
+               rcd->pkeys[i] = key;
+       }
+       if (changed) {
+               struct ib_event event;
+
+               (void) dd->f_set_ib_cfg(ppd, QIB_IB_CFG_PKEYS, 0);
+
+               event.event = IB_EVENT_PKEY_CHANGE;
+               event.device = &dd->verbs_dev.ibdev;
+               event.element.port_num = 1;
+               ib_dispatch_event(&event);
+       }
+       return 0;
+}
+
+static int subn_set_pkeytable(struct ib_smp *smp, struct ib_device *ibdev,
+                             u8 port)
+{
+       u32 startpx = 32 * (be32_to_cpu(smp->attr_mod) & 0xffff);
+       __be16 *p = (__be16 *) smp->data;
+       u16 *q = (u16 *) smp->data;
+       struct qib_devdata *dd = dd_from_ibdev(ibdev);
+       unsigned i, n = qib_get_npkeys(dd);
+
+       for (i = 0; i < n; i++)
+               q[i] = be16_to_cpu(p[i]);
+
+       if (startpx != 0 || set_pkeys(dd, port, q) != 0)
+               smp->status |= IB_SMP_INVALID_FIELD;
+
+       return subn_get_pkeytable(smp, ibdev, port);
+}
+
+static int subn_get_sl_to_vl(struct ib_smp *smp, struct ib_device *ibdev,
+                            u8 port)
+{
+       struct qib_ibport *ibp = to_iport(ibdev, port);
+       u8 *p = (u8 *) smp->data;
+       unsigned i;
+
+       memset(smp->data, 0, sizeof(smp->data));
+
+       if (!(ibp->port_cap_flags & IB_PORT_SL_MAP_SUP))
+               smp->status |= IB_SMP_UNSUP_METHOD;
+       else
+               for (i = 0; i < ARRAY_SIZE(ibp->sl_to_vl); i += 2)
+                       *p++ = (ibp->sl_to_vl[i] << 4) | ibp->sl_to_vl[i + 1];
+
+       return reply(smp);
+}
+
+static int subn_set_sl_to_vl(struct ib_smp *smp, struct ib_device *ibdev,
+                            u8 port)
+{
+       struct qib_ibport *ibp = to_iport(ibdev, port);
+       u8 *p = (u8 *) smp->data;
+       unsigned i;
+
+       if (!(ibp->port_cap_flags & IB_PORT_SL_MAP_SUP)) {
+               smp->status |= IB_SMP_UNSUP_METHOD;
+               return reply(smp);
+       }
+
+       for (i = 0; i < ARRAY_SIZE(ibp->sl_to_vl); i += 2, p++) {
+               ibp->sl_to_vl[i] = *p >> 4;
+               ibp->sl_to_vl[i + 1] = *p & 0xF;
+       }
+       qib_set_uevent_bits(ppd_from_ibp(to_iport(ibdev, port)),
+                           _QIB_EVENT_SL2VL_CHANGE_BIT);
+
+       return subn_get_sl_to_vl(smp, ibdev, port);
+}
+
+static int subn_get_vl_arb(struct ib_smp *smp, struct ib_device *ibdev,
+                          u8 port)
+{
+       unsigned which = be32_to_cpu(smp->attr_mod) >> 16;
+       struct qib_pportdata *ppd = ppd_from_ibp(to_iport(ibdev, port));
+
+       memset(smp->data, 0, sizeof(smp->data));
+
+       if (ppd->vls_supported == IB_VL_VL0)
+               smp->status |= IB_SMP_UNSUP_METHOD;
+       else if (which == IB_VLARB_LOWPRI_0_31)
+               (void) ppd->dd->f_get_ib_table(ppd, QIB_IB_TBL_VL_LOW_ARB,
+                                                  smp->data);
+       else if (which == IB_VLARB_HIGHPRI_0_31)
+               (void) ppd->dd->f_get_ib_table(ppd, QIB_IB_TBL_VL_HIGH_ARB,
+                                                  smp->data);
+       else
+               smp->status |= IB_SMP_INVALID_FIELD;
+
+       return reply(smp);
+}
+
+static int subn_set_vl_arb(struct ib_smp *smp, struct ib_device *ibdev,
+                          u8 port)
+{
+       unsigned which = be32_to_cpu(smp->attr_mod) >> 16;
+       struct qib_pportdata *ppd = ppd_from_ibp(to_iport(ibdev, port));
+
+       if (ppd->vls_supported == IB_VL_VL0)
+               smp->status |= IB_SMP_UNSUP_METHOD;
+       else if (which == IB_VLARB_LOWPRI_0_31)
+               (void) ppd->dd->f_set_ib_table(ppd, QIB_IB_TBL_VL_LOW_ARB,
+                                                  smp->data);
+       else if (which == IB_VLARB_HIGHPRI_0_31)
+               (void) ppd->dd->f_set_ib_table(ppd, QIB_IB_TBL_VL_HIGH_ARB,
+                                                  smp->data);
+       else
+               smp->status |= IB_SMP_INVALID_FIELD;
+
+       return subn_get_vl_arb(smp, ibdev, port);
+}
+
+static int subn_trap_repress(struct ib_smp *smp, struct ib_device *ibdev,
+                            u8 port)
+{
+       /*
+        * For now, we only send the trap once so no need to process this.
+        * o13-6, o13-7,
+        * o14-3.a4 The SMA shall not send any message in response to a valid
+        * SubnTrapRepress() message.
+        */
+       return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED;
+}
+
+static int pma_get_classportinfo(struct ib_perf *pmp,
+                                struct ib_device *ibdev)
+{
+       struct ib_pma_classportinfo *p =
+               (struct ib_pma_classportinfo *)pmp->data;
+       struct qib_devdata *dd = dd_from_ibdev(ibdev);
+
+       memset(pmp->data, 0, sizeof(pmp->data));
+
+       if (pmp->attr_mod != 0)
+               pmp->status |= IB_SMP_INVALID_FIELD;
+
+       /* Note that AllPortSelect is not valid */
+       p->base_version = 1;
+       p->class_version = 1;
+       p->cap_mask = IB_PMA_CLASS_CAP_EXT_WIDTH;
+       /*
+        * Set the most significant bit of CM2 to indicate support for
+        * congestion statistics
+        */
+       p->reserved[0] = dd->psxmitwait_supported << 7;
+       /*
+        * Expected response time is 4.096 usec. * 2^18 == 1.073741824 sec.
+        */
+       p->resp_time_value = 18;
+
+       return reply((struct ib_smp *) pmp);
+}
+
+static int pma_get_portsamplescontrol(struct ib_perf *pmp,
+                                     struct ib_device *ibdev, u8 port)
+{
+       struct ib_pma_portsamplescontrol *p =
+               (struct ib_pma_portsamplescontrol *)pmp->data;
+       struct qib_ibdev *dev = to_idev(ibdev);
+       struct qib_devdata *dd = dd_from_dev(dev);
+       struct qib_ibport *ibp = to_iport(ibdev, port);
+       struct qib_pportdata *ppd = ppd_from_ibp(ibp);
+       unsigned long flags;
+       u8 port_select = p->port_select;
+
+       memset(pmp->data, 0, sizeof(pmp->data));
+
+       p->port_select = port_select;
+       if (pmp->attr_mod != 0 || port_select != port) {
+               pmp->status |= IB_SMP_INVALID_FIELD;
+               goto bail;
+       }
+       spin_lock_irqsave(&ibp->lock, flags);
+       p->tick = dd->f_get_ib_cfg(ppd, QIB_IB_CFG_PMA_TICKS);
+       p->sample_status = dd->f_portcntr(ppd, QIBPORTCNTR_PSSTAT);
+       p->counter_width = 4;   /* 32 bit counters */
+       p->counter_mask0_9 = COUNTER_MASK0_9;
+       p->sample_start = cpu_to_be32(ibp->pma_sample_start);
+       p->sample_interval = cpu_to_be32(ibp->pma_sample_interval);
+       p->tag = cpu_to_be16(ibp->pma_tag);
+       p->counter_select[0] = ibp->pma_counter_select[0];
+       p->counter_select[1] = ibp->pma_counter_select[1];
+       p->counter_select[2] = ibp->pma_counter_select[2];
+       p->counter_select[3] = ibp->pma_counter_select[3];
+       p->counter_select[4] = ibp->pma_counter_select[4];
+       spin_unlock_irqrestore(&ibp->lock, flags);
+
+bail:
+       return reply((struct ib_smp *) pmp);
+}
+
+static int pma_set_portsamplescontrol(struct ib_perf *pmp,
+                                     struct ib_device *ibdev, u8 port)
+{
+       struct ib_pma_portsamplescontrol *p =
+               (struct ib_pma_portsamplescontrol *)pmp->data;
+       struct qib_ibdev *dev = to_idev(ibdev);
+       struct qib_devdata *dd = dd_from_dev(dev);
+       struct qib_ibport *ibp = to_iport(ibdev, port);
+       struct qib_pportdata *ppd = ppd_from_ibp(ibp);
+       unsigned long flags;
+       u8 status, xmit_flags;
+       int ret;
+
+       if (pmp->attr_mod != 0 || p->port_select != port) {
+               pmp->status |= IB_SMP_INVALID_FIELD;
+               ret = reply((struct ib_smp *) pmp);
+               goto bail;
+       }
+
+       spin_lock_irqsave(&ibp->lock, flags);
+
+       /* Port Sampling code owns the PS* HW counters */
+       xmit_flags = ppd->cong_stats.flags;
+       ppd->cong_stats.flags = IB_PMA_CONG_HW_CONTROL_SAMPLE;
+       status = dd->f_portcntr(ppd, QIBPORTCNTR_PSSTAT);
+       if (status == IB_PMA_SAMPLE_STATUS_DONE ||
+           (status == IB_PMA_SAMPLE_STATUS_RUNNING &&
+            xmit_flags == IB_PMA_CONG_HW_CONTROL_TIMER)) {
+               ibp->pma_sample_start = be32_to_cpu(p->sample_start);
+               ibp->pma_sample_interval = be32_to_cpu(p->sample_interval);
+               ibp->pma_tag = be16_to_cpu(p->tag);
+               ibp->pma_counter_select[0] = p->counter_select[0];
+               ibp->pma_counter_select[1] = p->counter_select[1];
+               ibp->pma_counter_select[2] = p->counter_select[2];
+               ibp->pma_counter_select[3] = p->counter_select[3];
+               ibp->pma_counter_select[4] = p->counter_select[4];
+               dd->f_set_cntr_sample(ppd, ibp->pma_sample_interval,
+                                     ibp->pma_sample_start);
+       }
+       spin_unlock_irqrestore(&ibp->lock, flags);
+
+       ret = pma_get_portsamplescontrol(pmp, ibdev, port);
+
+bail:
+       return ret;
+}
+
+static u64 get_counter(struct qib_ibport *ibp, struct qib_pportdata *ppd,
+                      __be16 sel)
+{
+       u64 ret;
+
+       switch (sel) {
+       case IB_PMA_PORT_XMIT_DATA:
+               ret = ppd->dd->f_portcntr(ppd, QIBPORTCNTR_PSXMITDATA);
+               break;
+       case IB_PMA_PORT_RCV_DATA:
+               ret = ppd->dd->f_portcntr(ppd, QIBPORTCNTR_PSRCVDATA);
+               break;
+       case IB_PMA_PORT_XMIT_PKTS:
+               ret = ppd->dd->f_portcntr(ppd, QIBPORTCNTR_PSXMITPKTS);
+               break;
+       case IB_PMA_PORT_RCV_PKTS:
+               ret = ppd->dd->f_portcntr(ppd, QIBPORTCNTR_PSRCVPKTS);
+               break;
+       case IB_PMA_PORT_XMIT_WAIT:
+               ret = ppd->dd->f_portcntr(ppd, QIBPORTCNTR_PSXMITWAIT);
+               break;
+       default:
+               ret = 0;
+       }
+
+       return ret;
+}
+
+/* This function assumes that the xmit_wait lock is already held */
+static u64 xmit_wait_get_value_delta(struct qib_pportdata *ppd)
+{
+       u32 delta;
+
+       delta = get_counter(&ppd->ibport_data, ppd,
+                           IB_PMA_PORT_XMIT_WAIT);
+       return ppd->cong_stats.counter + delta;
+}
+
+static void cache_hw_sample_counters(struct qib_pportdata *ppd)
+{
+       struct qib_ibport *ibp = &ppd->ibport_data;
+
+       ppd->cong_stats.counter_cache.psxmitdata =
+               get_counter(ibp, ppd, IB_PMA_PORT_XMIT_DATA);
+       ppd->cong_stats.counter_cache.psrcvdata =
+               get_counter(ibp, ppd, IB_PMA_PORT_RCV_DATA);
+       ppd->cong_stats.counter_cache.psxmitpkts =
+               get_counter(ibp, ppd, IB_PMA_PORT_XMIT_PKTS);
+       ppd->cong_stats.counter_cache.psrcvpkts =
+               get_counter(ibp, ppd, IB_PMA_PORT_RCV_PKTS);
+       ppd->cong_stats.counter_cache.psxmitwait =
+               get_counter(ibp, ppd, IB_PMA_PORT_XMIT_WAIT);
+}
+
+static u64 get_cache_hw_sample_counters(struct qib_pportdata *ppd,
+                                       __be16 sel)
+{
+       u64 ret;
+
+       switch (sel) {
+       case IB_PMA_PORT_XMIT_DATA:
+               ret = ppd->cong_stats.counter_cache.psxmitdata;
+               break;
+       case IB_PMA_PORT_RCV_DATA:
+               ret = ppd->cong_stats.counter_cache.psrcvdata;
+               break;
+       case IB_PMA_PORT_XMIT_PKTS:
+               ret = ppd->cong_stats.counter_cache.psxmitpkts;
+               break;
+       case IB_PMA_PORT_RCV_PKTS:
+               ret = ppd->cong_stats.counter_cache.psrcvpkts;
+               break;
+       case IB_PMA_PORT_XMIT_WAIT:
+               ret = ppd->cong_stats.counter_cache.psxmitwait;
+               break;
+       default:
+               ret = 0;
+       }
+
+       return ret;
+}
+
+static int pma_get_portsamplesresult(struct ib_perf *pmp,
+                                    struct ib_device *ibdev, u8 port)
+{
+       struct ib_pma_portsamplesresult *p =
+               (struct ib_pma_portsamplesresult *)pmp->data;
+       struct qib_ibdev *dev = to_idev(ibdev);
+       struct qib_devdata *dd = dd_from_dev(dev);
+       struct qib_ibport *ibp = to_iport(ibdev, port);
+       struct qib_pportdata *ppd = ppd_from_ibp(ibp);
+       unsigned long flags;
+       u8 status;
+       int i;
+
+       memset(pmp->data, 0, sizeof(pmp->data));
+       spin_lock_irqsave(&ibp->lock, flags);
+       p->tag = cpu_to_be16(ibp->pma_tag);
+       if (ppd->cong_stats.flags == IB_PMA_CONG_HW_CONTROL_TIMER)
+               p->sample_status = IB_PMA_SAMPLE_STATUS_DONE;
+       else {
+               status = dd->f_portcntr(ppd, QIBPORTCNTR_PSSTAT);
+               p->sample_status = cpu_to_be16(status);
+               if (status == IB_PMA_SAMPLE_STATUS_DONE) {
+                       cache_hw_sample_counters(ppd);
+                       ppd->cong_stats.counter =
+                               xmit_wait_get_value_delta(ppd);
+                       dd->f_set_cntr_sample(ppd,
+                                             QIB_CONG_TIMER_PSINTERVAL, 0);
+                       ppd->cong_stats.flags = IB_PMA_CONG_HW_CONTROL_TIMER;
+               }
+       }
+       for (i = 0; i < ARRAY_SIZE(ibp->pma_counter_select); i++)
+               p->counter[i] = cpu_to_be32(
+                       get_cache_hw_sample_counters(
+                               ppd, ibp->pma_counter_select[i]));
+       spin_unlock_irqrestore(&ibp->lock, flags);
+
+       return reply((struct ib_smp *) pmp);
+}
+
+static int pma_get_portsamplesresult_ext(struct ib_perf *pmp,
+                                        struct ib_device *ibdev, u8 port)
+{
+       struct ib_pma_portsamplesresult_ext *p =
+               (struct ib_pma_portsamplesresult_ext *)pmp->data;
+       struct qib_ibdev *dev = to_idev(ibdev);
+       struct qib_devdata *dd = dd_from_dev(dev);
+       struct qib_ibport *ibp = to_iport(ibdev, port);
+       struct qib_pportdata *ppd = ppd_from_ibp(ibp);
+       unsigned long flags;
+       u8 status;
+       int i;
+
+       /* Port Sampling code owns the PS* HW counters */
+       memset(pmp->data, 0, sizeof(pmp->data));
+       spin_lock_irqsave(&ibp->lock, flags);
+       p->tag = cpu_to_be16(ibp->pma_tag);
+       if (ppd->cong_stats.flags == IB_PMA_CONG_HW_CONTROL_TIMER)
+               p->sample_status = IB_PMA_SAMPLE_STATUS_DONE;
+       else {
+               status = dd->f_portcntr(ppd, QIBPORTCNTR_PSSTAT);
+               p->sample_status = cpu_to_be16(status);
+               /* 64 bits */
+               p->extended_width = cpu_to_be32(0x80000000);
+               if (status == IB_PMA_SAMPLE_STATUS_DONE) {
+                       cache_hw_sample_counters(ppd);
+                       ppd->cong_stats.counter =
+                               xmit_wait_get_value_delta(ppd);
+                       dd->f_set_cntr_sample(ppd,
+                                             QIB_CONG_TIMER_PSINTERVAL, 0);
+                       ppd->cong_stats.flags = IB_PMA_CONG_HW_CONTROL_TIMER;
+               }
+       }
+       for (i = 0; i < ARRAY_SIZE(ibp->pma_counter_select); i++)
+               p->counter[i] = cpu_to_be64(
+                       get_cache_hw_sample_counters(
+                               ppd, ibp->pma_counter_select[i]));
+       spin_unlock_irqrestore(&ibp->lock, flags);
+
+       return reply((struct ib_smp *) pmp);
+}
+
+static int pma_get_portcounters(struct ib_perf *pmp,
+                               struct ib_device *ibdev, u8 port)
+{
+       struct ib_pma_portcounters *p = (struct ib_pma_portcounters *)
+               pmp->data;
+       struct qib_ibport *ibp = to_iport(ibdev, port);
+       struct qib_pportdata *ppd = ppd_from_ibp(ibp);
+       struct qib_verbs_counters cntrs;
+       u8 port_select = p->port_select;
+
+       qib_get_counters(ppd, &cntrs);
+
+       /* Adjust counters for any resets done. */
+       cntrs.symbol_error_counter -= ibp->z_symbol_error_counter;
+       cntrs.link_error_recovery_counter -=
+               ibp->z_link_error_recovery_counter;
+       cntrs.link_downed_counter -= ibp->z_link_downed_counter;
+       cntrs.port_rcv_errors -= ibp->z_port_rcv_errors;
+       cntrs.port_rcv_remphys_errors -= ibp->z_port_rcv_remphys_errors;
+       cntrs.port_xmit_discards -= ibp->z_port_xmit_discards;
+       cntrs.port_xmit_data -= ibp->z_port_xmit_data;
+       cntrs.port_rcv_data -= ibp->z_port_rcv_data;
+       cntrs.port_xmit_packets -= ibp->z_port_xmit_packets;
+       cntrs.port_rcv_packets -= ibp->z_port_rcv_packets;
+       cntrs.local_link_integrity_errors -=
+               ibp->z_local_link_integrity_errors;
+       cntrs.excessive_buffer_overrun_errors -=
+               ibp->z_excessive_buffer_overrun_errors;
+       cntrs.vl15_dropped -= ibp->z_vl15_dropped;
+       cntrs.vl15_dropped += ibp->n_vl15_dropped;
+
+       memset(pmp->data, 0, sizeof(pmp->data));
+
+       p->port_select = port_select;
+       if (pmp->attr_mod != 0 || port_select != port)
+               pmp->status |= IB_SMP_INVALID_FIELD;
+
+       if (cntrs.symbol_error_counter > 0xFFFFUL)
+               p->symbol_error_counter = cpu_to_be16(0xFFFF);
+       else
+               p->symbol_error_counter =
+                       cpu_to_be16((u16)cntrs.symbol_error_counter);
+       if (cntrs.link_error_recovery_counter > 0xFFUL)
+               p->link_error_recovery_counter = 0xFF;
+       else
+               p->link_error_recovery_counter =
+                       (u8)cntrs.link_error_recovery_counter;
+       if (cntrs.link_downed_counter > 0xFFUL)
+               p->link_downed_counter = 0xFF;
+       else
+               p->link_downed_counter = (u8)cntrs.link_downed_counter;
+       if (cntrs.port_rcv_errors > 0xFFFFUL)
+               p->port_rcv_errors = cpu_to_be16(0xFFFF);
+       else
+               p->port_rcv_errors =
+                       cpu_to_be16((u16) cntrs.port_rcv_errors);
+       if (cntrs.port_rcv_remphys_errors > 0xFFFFUL)
+               p->port_rcv_remphys_errors = cpu_to_be16(0xFFFF);
+       else
+               p->port_rcv_remphys_errors =
+                       cpu_to_be16((u16)cntrs.port_rcv_remphys_errors);
+       if (cntrs.port_xmit_discards > 0xFFFFUL)
+               p->port_xmit_discards = cpu_to_be16(0xFFFF);
+       else
+               p->port_xmit_discards =
+                       cpu_to_be16((u16)cntrs.port_xmit_discards);
+       if (cntrs.local_link_integrity_errors > 0xFUL)
+               cntrs.local_link_integrity_errors = 0xFUL;
+       if (cntrs.excessive_buffer_overrun_errors > 0xFUL)
+               cntrs.excessive_buffer_overrun_errors = 0xFUL;
+       p->lli_ebor_errors = (cntrs.local_link_integrity_errors << 4) |
+               cntrs.excessive_buffer_overrun_errors;
+       if (cntrs.vl15_dropped > 0xFFFFUL)
+               p->vl15_dropped = cpu_to_be16(0xFFFF);
+       else
+               p->vl15_dropped = cpu_to_be16((u16)cntrs.vl15_dropped);
+       if (cntrs.port_xmit_data > 0xFFFFFFFFUL)
+               p->port_xmit_data = cpu_to_be32(0xFFFFFFFF);
+       else
+               p->port_xmit_data = cpu_to_be32((u32)cntrs.port_xmit_data);
+       if (cntrs.port_rcv_data > 0xFFFFFFFFUL)
+               p->port_rcv_data = cpu_to_be32(0xFFFFFFFF);
+       else
+               p->port_rcv_data = cpu_to_be32((u32)cntrs.port_rcv_data);
+       if (cntrs.port_xmit_packets > 0xFFFFFFFFUL)
+               p->port_xmit_packets = cpu_to_be32(0xFFFFFFFF);
+       else
+               p->port_xmit_packets =
+                       cpu_to_be32((u32)cntrs.port_xmit_packets);
+       if (cntrs.port_rcv_packets > 0xFFFFFFFFUL)
+               p->port_rcv_packets = cpu_to_be32(0xFFFFFFFF);
+       else
+               p->port_rcv_packets =
+                       cpu_to_be32((u32) cntrs.port_rcv_packets);
+
+       return reply((struct ib_smp *) pmp);
+}
+
+static int pma_get_portcounters_cong(struct ib_perf *pmp,
+                                    struct ib_device *ibdev, u8 port)
+{
+       /* Congestion PMA packets start at offset 24 not 64 */
+       struct ib_pma_portcounters_cong *p =
+               (struct ib_pma_portcounters_cong *)pmp->reserved;
+       struct qib_verbs_counters cntrs;
+       struct qib_ibport *ibp = to_iport(ibdev, port);
+       struct qib_pportdata *ppd = ppd_from_ibp(ibp);
+       struct qib_devdata *dd = dd_from_ppd(ppd);
+       u32 port_select = be32_to_cpu(pmp->attr_mod) & 0xFF;
+       u64 xmit_wait_counter;
+       unsigned long flags;
+
+       /*
+        * This check is performed only in the GET method because the
+        * SET method ends up calling this anyway.
+        */
+       if (!dd->psxmitwait_supported)
+               pmp->status |= IB_SMP_UNSUP_METH_ATTR;
+       if (port_select != port)
+               pmp->status |= IB_SMP_INVALID_FIELD;
+
+       qib_get_counters(ppd, &cntrs);
+       spin_lock_irqsave(&ppd->ibport_data.lock, flags);
+       xmit_wait_counter = xmit_wait_get_value_delta(ppd);
+       spin_unlock_irqrestore(&ppd->ibport_data.lock, flags);
+
+       /* Adjust counters for any resets done. */
+       cntrs.symbol_error_counter -= ibp->z_symbol_error_counter;
+       cntrs.link_error_recovery_counter -=
+               ibp->z_link_error_recovery_counter;
+       cntrs.link_downed_counter -= ibp->z_link_downed_counter;
+       cntrs.port_rcv_errors -= ibp->z_port_rcv_errors;
+       cntrs.port_rcv_remphys_errors -=
+               ibp->z_port_rcv_remphys_errors;
+       cntrs.port_xmit_discards -= ibp->z_port_xmit_discards;
+       cntrs.local_link_integrity_errors -=
+               ibp->z_local_link_integrity_errors;
+       cntrs.excessive_buffer_overrun_errors -=
+               ibp->z_excessive_buffer_overrun_errors;
+       cntrs.vl15_dropped -= ibp->z_vl15_dropped;
+       cntrs.vl15_dropped += ibp->n_vl15_dropped;
+       cntrs.port_xmit_data -= ibp->z_port_xmit_data;
+       cntrs.port_rcv_data -= ibp->z_port_rcv_data;
+       cntrs.port_xmit_packets -= ibp->z_port_xmit_packets;
+       cntrs.port_rcv_packets -= ibp->z_port_rcv_packets;
+
+       memset(pmp->reserved, 0, sizeof(pmp->reserved) +
+              sizeof(pmp->data));
+
+       /*
+        * Set top 3 bits to indicate interval in picoseconds in
+        * remaining bits.
+        */
+       p->port_check_rate =
+               cpu_to_be16((QIB_XMIT_RATE_PICO << 13) |
+                           (dd->psxmitwait_check_rate &
+                            ~(QIB_XMIT_RATE_PICO << 13)));
+       p->port_adr_events = cpu_to_be64(0);
+       p->port_xmit_wait = cpu_to_be64(xmit_wait_counter);
+       p->port_xmit_data = cpu_to_be64(cntrs.port_xmit_data);
+       p->port_rcv_data = cpu_to_be64(cntrs.port_rcv_data);
+       p->port_xmit_packets =
+               cpu_to_be64(cntrs.port_xmit_packets);
+       p->port_rcv_packets =
+               cpu_to_be64(cntrs.port_rcv_packets);
+       if (cntrs.symbol_error_counter > 0xFFFFUL)
+               p->symbol_error_counter = cpu_to_be16(0xFFFF);
+       else
+               p->symbol_error_counter =
+                       cpu_to_be16(
+                               (u16)cntrs.symbol_error_counter);
+       if (cntrs.link_error_recovery_counter > 0xFFUL)
+               p->link_error_recovery_counter = 0xFF;
+       else
+               p->link_error_recovery_counter =
+                       (u8)cntrs.link_error_recovery_counter;
+       if (cntrs.link_downed_counter > 0xFFUL)
+               p->link_downed_counter = 0xFF;
+       else
+               p->link_downed_counter =
+                       (u8)cntrs.link_downed_counter;
+       if (cntrs.port_rcv_errors > 0xFFFFUL)
+               p->port_rcv_errors = cpu_to_be16(0xFFFF);
+       else
+               p->port_rcv_errors =
+                       cpu_to_be16((u16) cntrs.port_rcv_errors);
+       if (cntrs.port_rcv_remphys_errors > 0xFFFFUL)
+               p->port_rcv_remphys_errors = cpu_to_be16(0xFFFF);
+       else
+               p->port_rcv_remphys_errors =
+                       cpu_to_be16(
+                               (u16)cntrs.port_rcv_remphys_errors);
+       if (cntrs.port_xmit_discards > 0xFFFFUL)
+               p->port_xmit_discards = cpu_to_be16(0xFFFF);
+       else
+               p->port_xmit_discards =
+                       cpu_to_be16((u16)cntrs.port_xmit_discards);
+       if (cntrs.local_link_integrity_errors > 0xFUL)
+               cntrs.local_link_integrity_errors = 0xFUL;
+       if (cntrs.excessive_buffer_overrun_errors > 0xFUL)
+               cntrs.excessive_buffer_overrun_errors = 0xFUL;
+       p->lli_ebor_errors = (cntrs.local_link_integrity_errors << 4) |
+               cntrs.excessive_buffer_overrun_errors;
+       if (cntrs.vl15_dropped > 0xFFFFUL)
+               p->vl15_dropped = cpu_to_be16(0xFFFF);
+       else
+               p->vl15_dropped = cpu_to_be16((u16)cntrs.vl15_dropped);
+
+       return reply((struct ib_smp *)pmp);
+}
+
+static int pma_get_portcounters_ext(struct ib_perf *pmp,
+                                   struct ib_device *ibdev, u8 port)
+{
+       struct ib_pma_portcounters_ext *p =
+               (struct ib_pma_portcounters_ext *)pmp->data;
+       struct qib_ibport *ibp = to_iport(ibdev, port);
+       struct qib_pportdata *ppd = ppd_from_ibp(ibp);
+       u64 swords, rwords, spkts, rpkts, xwait;
+       u8 port_select = p->port_select;
+
+       memset(pmp->data, 0, sizeof(pmp->data));
+
+       p->port_select = port_select;
+       if (pmp->attr_mod != 0 || port_select != port) {
+               pmp->status |= IB_SMP_INVALID_FIELD;
+               goto bail;
+       }
+
+       qib_snapshot_counters(ppd, &swords, &rwords, &spkts, &rpkts, &xwait);
+
+       /* Adjust counters for any resets done. */
+       swords -= ibp->z_port_xmit_data;
+       rwords -= ibp->z_port_rcv_data;
+       spkts -= ibp->z_port_xmit_packets;
+       rpkts -= ibp->z_port_rcv_packets;
+
+       p->port_xmit_data = cpu_to_be64(swords);
+       p->port_rcv_data = cpu_to_be64(rwords);
+       p->port_xmit_packets = cpu_to_be64(spkts);
+       p->port_rcv_packets = cpu_to_be64(rpkts);
+       p->port_unicast_xmit_packets = cpu_to_be64(ibp->n_unicast_xmit);
+       p->port_unicast_rcv_packets = cpu_to_be64(ibp->n_unicast_rcv);
+       p->port_multicast_xmit_packets = cpu_to_be64(ibp->n_multicast_xmit);
+       p->port_multicast_rcv_packets = cpu_to_be64(ibp->n_multicast_rcv);
+
+bail:
+       return reply((struct ib_smp *) pmp);
+}
+
+static int pma_set_portcounters(struct ib_perf *pmp,
+                               struct ib_device *ibdev, u8 port)
+{
+       struct ib_pma_portcounters *p = (struct ib_pma_portcounters *)
+               pmp->data;
+       struct qib_ibport *ibp = to_iport(ibdev, port);
+       struct qib_pportdata *ppd = ppd_from_ibp(ibp);
+       struct qib_verbs_counters cntrs;
+
+       /*
+        * Since the HW doesn't support clearing counters, we save the
+        * current count and subtract it from future responses.
+        */
+       qib_get_counters(ppd, &cntrs);
+
+       if (p->counter_select & IB_PMA_SEL_SYMBOL_ERROR)
+               ibp->z_symbol_error_counter = cntrs.symbol_error_counter;
+
+       if (p->counter_select & IB_PMA_SEL_LINK_ERROR_RECOVERY)
+               ibp->z_link_error_recovery_counter =
+                       cntrs.link_error_recovery_counter;
+
+       if (p->counter_select & IB_PMA_SEL_LINK_DOWNED)
+               ibp->z_link_downed_counter = cntrs.link_downed_counter;
+
+       if (p->counter_select & IB_PMA_SEL_PORT_RCV_ERRORS)
+               ibp->z_port_rcv_errors = cntrs.port_rcv_errors;
+
+       if (p->counter_select & IB_PMA_SEL_PORT_RCV_REMPHYS_ERRORS)
+               ibp->z_port_rcv_remphys_errors =
+                       cntrs.port_rcv_remphys_errors;
+
+       if (p->counter_select & IB_PMA_SEL_PORT_XMIT_DISCARDS)
+               ibp->z_port_xmit_discards = cntrs.port_xmit_discards;
+
+       if (p->counter_select & IB_PMA_SEL_LOCAL_LINK_INTEGRITY_ERRORS)
+               ibp->z_local_link_integrity_errors =
+                       cntrs.local_link_integrity_errors;
+
+       if (p->counter_select & IB_PMA_SEL_EXCESSIVE_BUFFER_OVERRUNS)
+               ibp->z_excessive_buffer_overrun_errors =
+                       cntrs.excessive_buffer_overrun_errors;
+
+       if (p->counter_select & IB_PMA_SEL_PORT_VL15_DROPPED) {
+               ibp->n_vl15_dropped = 0;
+               ibp->z_vl15_dropped = cntrs.vl15_dropped;
+       }
+
+       if (p->counter_select & IB_PMA_SEL_PORT_XMIT_DATA)
+               ibp->z_port_xmit_data = cntrs.port_xmit_data;
+
+       if (p->counter_select & IB_PMA_SEL_PORT_RCV_DATA)
+               ibp->z_port_rcv_data = cntrs.port_rcv_data;
+
+       if (p->counter_select & IB_PMA_SEL_PORT_XMIT_PACKETS)
+               ibp->z_port_xmit_packets = cntrs.port_xmit_packets;
+
+       if (p->counter_select & IB_PMA_SEL_PORT_RCV_PACKETS)
+               ibp->z_port_rcv_packets = cntrs.port_rcv_packets;
+
+       return pma_get_portcounters(pmp, ibdev, port);
+}
+
+static int pma_set_portcounters_cong(struct ib_perf *pmp,
+                                    struct ib_device *ibdev, u8 port)
+{
+       struct qib_ibport *ibp = to_iport(ibdev, port);
+       struct qib_pportdata *ppd = ppd_from_ibp(ibp);
+       struct qib_devdata *dd = dd_from_ppd(ppd);
+       struct qib_verbs_counters cntrs;
+       u32 counter_select = (be32_to_cpu(pmp->attr_mod) >> 24) & 0xFF;
+       int ret = 0;
+       unsigned long flags;
+
+       qib_get_counters(ppd, &cntrs);
+       /* Get counter values before we save them */
+       ret = pma_get_portcounters_cong(pmp, ibdev, port);
+
+       if (counter_select & IB_PMA_SEL_CONG_XMIT) {
+               spin_lock_irqsave(&ppd->ibport_data.lock, flags);
+               ppd->cong_stats.counter = 0;
+               dd->f_set_cntr_sample(ppd, QIB_CONG_TIMER_PSINTERVAL,
+                                     0x0);
+               spin_unlock_irqrestore(&ppd->ibport_data.lock, flags);
+       }
+       if (counter_select & IB_PMA_SEL_CONG_PORT_DATA) {
+               ibp->z_port_xmit_data = cntrs.port_xmit_data;
+               ibp->z_port_rcv_data = cntrs.port_rcv_data;
+               ibp->z_port_xmit_packets = cntrs.port_xmit_packets;
+               ibp->z_port_rcv_packets = cntrs.port_rcv_packets;
+       }
+       if (counter_select & IB_PMA_SEL_CONG_ALL) {
+               ibp->z_symbol_error_counter =
+                       cntrs.symbol_error_counter;
+               ibp->z_link_error_recovery_counter =
+                       cntrs.link_error_recovery_counter;
+               ibp->z_link_downed_counter =
+                       cntrs.link_downed_counter;
+               ibp->z_port_rcv_errors = cntrs.port_rcv_errors;
+               ibp->z_port_rcv_remphys_errors =
+                       cntrs.port_rcv_remphys_errors;
+               ibp->z_port_xmit_discards =
+                       cntrs.port_xmit_discards;
+               ibp->z_local_link_integrity_errors =
+                       cntrs.local_link_integrity_errors;
+               ibp->z_excessive_buffer_overrun_errors =
+                       cntrs.excessive_buffer_overrun_errors;
+               ibp->n_vl15_dropped = 0;
+               ibp->z_vl15_dropped = cntrs.vl15_dropped;
+       }
+
+       return ret;
+}
+
+static int pma_set_portcounters_ext(struct ib_perf *pmp,
+                                   struct ib_device *ibdev, u8 port)
+{
+       struct ib_pma_portcounters *p = (struct ib_pma_portcounters *)
+               pmp->data;
+       struct qib_ibport *ibp = to_iport(ibdev, port);
+       struct qib_pportdata *ppd = ppd_from_ibp(ibp);
+       u64 swords, rwords, spkts, rpkts, xwait;
+
+       qib_snapshot_counters(ppd, &swords, &rwords, &spkts, &rpkts, &xwait);
+
+       if (p->counter_select & IB_PMA_SELX_PORT_XMIT_DATA)
+               ibp->z_port_xmit_data = swords;
+
+       if (p->counter_select & IB_PMA_SELX_PORT_RCV_DATA)
+               ibp->z_port_rcv_data = rwords;
+
+       if (p->counter_select & IB_PMA_SELX_PORT_XMIT_PACKETS)
+               ibp->z_port_xmit_packets = spkts;
+
+       if (p->counter_select & IB_PMA_SELX_PORT_RCV_PACKETS)
+               ibp->z_port_rcv_packets = rpkts;
+
+       if (p->counter_select & IB_PMA_SELX_PORT_UNI_XMIT_PACKETS)
+               ibp->n_unicast_xmit = 0;
+
+       if (p->counter_select & IB_PMA_SELX_PORT_UNI_RCV_PACKETS)
+               ibp->n_unicast_rcv = 0;
+
+       if (p->counter_select & IB_PMA_SELX_PORT_MULTI_XMIT_PACKETS)
+               ibp->n_multicast_xmit = 0;
+
+       if (p->counter_select & IB_PMA_SELX_PORT_MULTI_RCV_PACKETS)
+               ibp->n_multicast_rcv = 0;
+
+       return pma_get_portcounters_ext(pmp, ibdev, port);
+}
+
+static int process_subn(struct ib_device *ibdev, int mad_flags,
+                       u8 port, struct ib_mad *in_mad,
+                       struct ib_mad *out_mad)
+{
+       struct ib_smp *smp = (struct ib_smp *)out_mad;
+       struct qib_ibport *ibp = to_iport(ibdev, port);
+       struct qib_pportdata *ppd = ppd_from_ibp(ibp);
+       int ret;
+
+       *out_mad = *in_mad;
+       if (smp->class_version != 1) {
+               smp->status |= IB_SMP_UNSUP_VERSION;
+               ret = reply(smp);
+               goto bail;
+       }
+
+       ret = check_mkey(ibp, smp, mad_flags);
+       if (ret) {
+               u32 port_num = be32_to_cpu(smp->attr_mod);
+
+               /*
+                * If this is a get/set portinfo, we already check the
+                * M_Key if the MAD is for another port and the M_Key
+                * is OK on the receiving port. This check is needed
+                * to increment the error counters when the M_Key
+                * fails to match on *both* ports.
+                */
+               if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO &&
+                   (smp->method == IB_MGMT_METHOD_GET ||
+                    smp->method == IB_MGMT_METHOD_SET) &&
+                   port_num && port_num <= ibdev->phys_port_cnt &&
+                   port != port_num)
+                       (void) check_mkey(to_iport(ibdev, port_num), smp, 0);
+               goto bail;
+       }
+
+       switch (smp->method) {
+       case IB_MGMT_METHOD_GET:
+               switch (smp->attr_id) {
+               case IB_SMP_ATTR_NODE_DESC:
+                       ret = subn_get_nodedescription(smp, ibdev);
+                       goto bail;
+               case IB_SMP_ATTR_NODE_INFO:
+                       ret = subn_get_nodeinfo(smp, ibdev, port);
+                       goto bail;
+               case IB_SMP_ATTR_GUID_INFO:
+                       ret = subn_get_guidinfo(smp, ibdev, port);
+                       goto bail;
+               case IB_SMP_ATTR_PORT_INFO:
+                       ret = subn_get_portinfo(smp, ibdev, port);
+                       goto bail;
+               case IB_SMP_ATTR_PKEY_TABLE:
+                       ret = subn_get_pkeytable(smp, ibdev, port);
+                       goto bail;
+               case IB_SMP_ATTR_SL_TO_VL_TABLE:
+                       ret = subn_get_sl_to_vl(smp, ibdev, port);
+                       goto bail;
+               case IB_SMP_ATTR_VL_ARB_TABLE:
+                       ret = subn_get_vl_arb(smp, ibdev, port);
+                       goto bail;
+               case IB_SMP_ATTR_SM_INFO:
+                       if (ibp->port_cap_flags & IB_PORT_SM_DISABLED) {
+                               ret = IB_MAD_RESULT_SUCCESS |
+                                       IB_MAD_RESULT_CONSUMED;
+                               goto bail;
+                       }
+                       if (ibp->port_cap_flags & IB_PORT_SM) {
+                               ret = IB_MAD_RESULT_SUCCESS;
+                               goto bail;
+                       }
+                       /* FALLTHROUGH */
+               default:
+                       smp->status |= IB_SMP_UNSUP_METH_ATTR;
+                       ret = reply(smp);
+                       goto bail;
+               }
+
+       case IB_MGMT_METHOD_SET:
+               switch (smp->attr_id) {
+               case IB_SMP_ATTR_GUID_INFO:
+                       ret = subn_set_guidinfo(smp, ibdev, port);
+                       goto bail;
+               case IB_SMP_ATTR_PORT_INFO:
+                       ret = subn_set_portinfo(smp, ibdev, port);
+                       goto bail;
+               case IB_SMP_ATTR_PKEY_TABLE:
+                       ret = subn_set_pkeytable(smp, ibdev, port);
+                       goto bail;
+               case IB_SMP_ATTR_SL_TO_VL_TABLE:
+                       ret = subn_set_sl_to_vl(smp, ibdev, port);
+                       goto bail;
+               case IB_SMP_ATTR_VL_ARB_TABLE:
+                       ret = subn_set_vl_arb(smp, ibdev, port);
+                       goto bail;
+               case IB_SMP_ATTR_SM_INFO:
+                       if (ibp->port_cap_flags & IB_PORT_SM_DISABLED) {
+                               ret = IB_MAD_RESULT_SUCCESS |
+                                       IB_MAD_RESULT_CONSUMED;
+                               goto bail;
+                       }
+                       if (ibp->port_cap_flags & IB_PORT_SM) {
+                               ret = IB_MAD_RESULT_SUCCESS;
+                               goto bail;
+                       }
+                       /* FALLTHROUGH */
+               default:
+                       smp->status |= IB_SMP_UNSUP_METH_ATTR;
+                       ret = reply(smp);
+                       goto bail;
+               }
+
+       case IB_MGMT_METHOD_TRAP_REPRESS:
+               if (smp->attr_id == IB_SMP_ATTR_NOTICE)
+                       ret = subn_trap_repress(smp, ibdev, port);
+               else {
+                       smp->status |= IB_SMP_UNSUP_METH_ATTR;
+                       ret = reply(smp);
+               }
+               goto bail;
+
+       case IB_MGMT_METHOD_TRAP:
+       case IB_MGMT_METHOD_REPORT:
+       case IB_MGMT_METHOD_REPORT_RESP:
+       case IB_MGMT_METHOD_GET_RESP:
+               /*
+                * The ib_mad module will call us to process responses
+                * before checking for other consumers.
+                * Just tell the caller to process it normally.
+                */
+               ret = IB_MAD_RESULT_SUCCESS;
+               goto bail;
+
+       case IB_MGMT_METHOD_SEND:
+               if (ib_get_smp_direction(smp) &&
+                   smp->attr_id == QIB_VENDOR_IPG) {
+                       ppd->dd->f_set_ib_cfg(ppd, QIB_IB_CFG_PORT,
+                                             smp->data[0]);
+                       ret = IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED;
+               } else
+                       ret = IB_MAD_RESULT_SUCCESS;
+               goto bail;
+
+       default:
+               smp->status |= IB_SMP_UNSUP_METHOD;
+               ret = reply(smp);
+       }
+
+bail:
+       return ret;
+}
+
+static int process_perf(struct ib_device *ibdev, u8 port,
+                       struct ib_mad *in_mad,
+                       struct ib_mad *out_mad)
+{
+       struct ib_perf *pmp = (struct ib_perf *)out_mad;
+       int ret;
+
+       *out_mad = *in_mad;
+       if (pmp->class_version != 1) {
+               pmp->status |= IB_SMP_UNSUP_VERSION;
+               ret = reply((struct ib_smp *) pmp);
+               goto bail;
+       }
+
+       switch (pmp->method) {
+       case IB_MGMT_METHOD_GET:
+               switch (pmp->attr_id) {
+               case IB_PMA_CLASS_PORT_INFO:
+                       ret = pma_get_classportinfo(pmp, ibdev);
+                       goto bail;
+               case IB_PMA_PORT_SAMPLES_CONTROL:
+                       ret = pma_get_portsamplescontrol(pmp, ibdev, port);
+                       goto bail;
+               case IB_PMA_PORT_SAMPLES_RESULT:
+                       ret = pma_get_portsamplesresult(pmp, ibdev, port);
+                       goto bail;
+               case IB_PMA_PORT_SAMPLES_RESULT_EXT:
+                       ret = pma_get_portsamplesresult_ext(pmp, ibdev, port);
+                       goto bail;
+               case IB_PMA_PORT_COUNTERS:
+                       ret = pma_get_portcounters(pmp, ibdev, port);
+                       goto bail;
+               case IB_PMA_PORT_COUNTERS_EXT:
+                       ret = pma_get_portcounters_ext(pmp, ibdev, port);
+                       goto bail;
+               case IB_PMA_PORT_COUNTERS_CONG:
+                       ret = pma_get_portcounters_cong(pmp, ibdev, port);
+                       goto bail;
+               default:
+                       pmp->status |= IB_SMP_UNSUP_METH_ATTR;
+                       ret = reply((struct ib_smp *) pmp);
+                       goto bail;
+               }
+
+       case IB_MGMT_METHOD_SET:
+               switch (pmp->attr_id) {
+               case IB_PMA_PORT_SAMPLES_CONTROL:
+                       ret = pma_set_portsamplescontrol(pmp, ibdev, port);
+                       goto bail;
+               case IB_PMA_PORT_COUNTERS:
+                       ret = pma_set_portcounters(pmp, ibdev, port);
+                       goto bail;
+               case IB_PMA_PORT_COUNTERS_EXT:
+                       ret = pma_set_portcounters_ext(pmp, ibdev, port);
+                       goto bail;
+               case IB_PMA_PORT_COUNTERS_CONG:
+                       ret = pma_set_portcounters_cong(pmp, ibdev, port);
+                       goto bail;
+               default:
+                       pmp->status |= IB_SMP_UNSUP_METH_ATTR;
+                       ret = reply((struct ib_smp *) pmp);
+                       goto bail;
+               }
+
+       case IB_MGMT_METHOD_TRAP:
+       case IB_MGMT_METHOD_GET_RESP:
+               /*
+                * The ib_mad module will call us to process responses
+                * before checking for other consumers.
+                * Just tell the caller to process it normally.
+                */
+               ret = IB_MAD_RESULT_SUCCESS;
+               goto bail;
+
+       default:
+               pmp->status |= IB_SMP_UNSUP_METHOD;
+               ret = reply((struct ib_smp *) pmp);
+       }
+
+bail:
+       return ret;
+}
+
+/**
+ * qib_process_mad - process an incoming MAD packet
+ * @ibdev: the infiniband device this packet came in on
+ * @mad_flags: MAD flags
+ * @port: the port number this packet came in on
+ * @in_wc: the work completion entry for this packet
+ * @in_grh: the global route header for this packet
+ * @in_mad: the incoming MAD
+ * @out_mad: any outgoing MAD reply
+ *
+ * Returns IB_MAD_RESULT_SUCCESS if this is a MAD that we are not
+ * interested in processing.
+ *
+ * Note that the verbs framework has already done the MAD sanity checks,
+ * and hop count/pointer updating for IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE
+ * MADs.
+ *
+ * This is called by the ib_mad module.
+ */
+int qib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port,
+                   struct ib_wc *in_wc, struct ib_grh *in_grh,
+                   struct ib_mad *in_mad, struct ib_mad *out_mad)
+{
+       int ret;
+
+       switch (in_mad->mad_hdr.mgmt_class) {
+       case IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE:
+       case IB_MGMT_CLASS_SUBN_LID_ROUTED:
+               ret = process_subn(ibdev, mad_flags, port, in_mad, out_mad);
+               goto bail;
+
+       case IB_MGMT_CLASS_PERF_MGMT:
+               ret = process_perf(ibdev, port, in_mad, out_mad);
+               goto bail;
+
+       default:
+               ret = IB_MAD_RESULT_SUCCESS;
+       }
+
+bail:
+       return ret;
+}
+
+static void send_handler(struct ib_mad_agent *agent,
+                        struct ib_mad_send_wc *mad_send_wc)
+{
+       ib_free_send_mad(mad_send_wc->send_buf);
+}
+
+static void xmit_wait_timer_func(unsigned long opaque)
+{
+       struct qib_pportdata *ppd = (struct qib_pportdata *)opaque;
+       struct qib_devdata *dd = dd_from_ppd(ppd);
+       unsigned long flags;
+       u8 status;
+
+       spin_lock_irqsave(&ppd->ibport_data.lock, flags);
+       if (ppd->cong_stats.flags == IB_PMA_CONG_HW_CONTROL_SAMPLE) {
+               status = dd->f_portcntr(ppd, QIBPORTCNTR_PSSTAT);
+               if (status == IB_PMA_SAMPLE_STATUS_DONE) {
+                       /* save counter cache */
+                       cache_hw_sample_counters(ppd);
+                       ppd->cong_stats.flags = IB_PMA_CONG_HW_CONTROL_TIMER;
+               } else
+                       goto done;
+       }
+       ppd->cong_stats.counter = xmit_wait_get_value_delta(ppd);
+       dd->f_set_cntr_sample(ppd, QIB_CONG_TIMER_PSINTERVAL, 0x0);
+done:
+       spin_unlock_irqrestore(&ppd->ibport_data.lock, flags);
+       mod_timer(&ppd->cong_stats.timer, jiffies + HZ);
+}
+
+int qib_create_agents(struct qib_ibdev *dev)
+{
+       struct qib_devdata *dd = dd_from_dev(dev);
+       struct ib_mad_agent *agent;
+       struct qib_ibport *ibp;
+       int p;
+       int ret;
+
+       for (p = 0; p < dd->num_pports; p++) {
+               ibp = &dd->pport[p].ibport_data;
+               agent = ib_register_mad_agent(&dev->ibdev, p + 1, IB_QPT_SMI,
+                                             NULL, 0, send_handler,
+                                             NULL, NULL);
+               if (IS_ERR(agent)) {
+                       ret = PTR_ERR(agent);
+                       goto err;
+               }
+
+               /* Initialize xmit_wait structure */
+               dd->pport[p].cong_stats.counter = 0;
+               init_timer(&dd->pport[p].cong_stats.timer);
+               dd->pport[p].cong_stats.timer.function = xmit_wait_timer_func;
+               dd->pport[p].cong_stats.timer.data =
+                       (unsigned long)(&dd->pport[p]);
+               dd->pport[p].cong_stats.timer.expires = 0;
+               add_timer(&dd->pport[p].cong_stats.timer);
+
+               ibp->send_agent = agent;
+       }
+
+       return 0;
+
+err:
+       for (p = 0; p < dd->num_pports; p++) {
+               ibp = &dd->pport[p].ibport_data;
+               if (ibp->send_agent) {
+                       agent = ibp->send_agent;
+                       ibp->send_agent = NULL;
+                       ib_unregister_mad_agent(agent);
+               }
+       }
+
+       return ret;
+}
+
+void qib_free_agents(struct qib_ibdev *dev)
+{
+       struct qib_devdata *dd = dd_from_dev(dev);
+       struct ib_mad_agent *agent;
+       struct qib_ibport *ibp;
+       int p;
+
+       for (p = 0; p < dd->num_pports; p++) {
+               ibp = &dd->pport[p].ibport_data;
+               if (ibp->send_agent) {
+                       agent = ibp->send_agent;
+                       ibp->send_agent = NULL;
+                       ib_unregister_mad_agent(agent);
+               }
+               if (ibp->sm_ah) {
+                       ib_destroy_ah(&ibp->sm_ah->ibah);
+                       ibp->sm_ah = NULL;
+               }
+               if (dd->pport[p].cong_stats.timer.data)
+                       del_timer_sync(&dd->pport[p].cong_stats.timer);
+       }
+}
diff --git a/drivers/infiniband/hw/qib/qib_mad.h b/drivers/infiniband/hw/qib/qib_mad.h
new file mode 100644 (file)
index 0000000..147aff9
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009, 2010 QLogic Corporation.
+ * All rights reserved.
+ * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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.
+ */
+
+#define IB_SMP_UNSUP_VERSION    cpu_to_be16(0x0004)
+#define IB_SMP_UNSUP_METHOD     cpu_to_be16(0x0008)
+#define IB_SMP_UNSUP_METH_ATTR  cpu_to_be16(0x000C)
+#define IB_SMP_INVALID_FIELD    cpu_to_be16(0x001C)
+
+struct ib_node_info {
+       u8 base_version;
+       u8 class_version;
+       u8 node_type;
+       u8 num_ports;
+       __be64 sys_guid;
+       __be64 node_guid;
+       __be64 port_guid;
+       __be16 partition_cap;
+       __be16 device_id;
+       __be32 revision;
+       u8 local_port_num;
+       u8 vendor_id[3];
+} __attribute__ ((packed));
+
+struct ib_mad_notice_attr {
+       u8 generic_type;
+       u8 prod_type_msb;
+       __be16 prod_type_lsb;
+       __be16 trap_num;
+       __be16 issuer_lid;
+       __be16 toggle_count;
+
+       union {
+               struct {
+                       u8      details[54];
+               } raw_data;
+
+               struct {
+                       __be16  reserved;
+                       __be16  lid;            /* where violation happened */
+                       u8      port_num;       /* where violation happened */
+               } __attribute__ ((packed)) ntc_129_131;
+
+               struct {
+                       __be16  reserved;
+                       __be16  lid;            /* LID where change occured */
+                       u8      reserved2;
+                       u8      local_changes;  /* low bit - local changes */
+                       __be32  new_cap_mask;   /* new capability mask */
+                       u8      reserved3;
+                       u8      change_flags;   /* low 3 bits only */
+               } __attribute__ ((packed)) ntc_144;
+
+               struct {
+                       __be16  reserved;
+                       __be16  lid;            /* lid where sys guid changed */
+                       __be16  reserved2;
+                       __be64  new_sys_guid;
+               } __attribute__ ((packed)) ntc_145;
+
+               struct {
+                       __be16  reserved;
+                       __be16  lid;
+                       __be16  dr_slid;
+                       u8      method;
+                       u8      reserved2;
+                       __be16  attr_id;
+                       __be32  attr_mod;
+                       __be64  mkey;
+                       u8      reserved3;
+                       u8      dr_trunc_hop;
+                       u8      dr_rtn_path[30];
+               } __attribute__ ((packed)) ntc_256;
+
+               struct {
+                       __be16          reserved;
+                       __be16          lid1;
+                       __be16          lid2;
+                       __be32          key;
+                       __be32          sl_qp1; /* SL: high 4 bits */
+                       __be32          qp2;    /* high 8 bits reserved */
+                       union ib_gid    gid1;
+                       union ib_gid    gid2;
+               } __attribute__ ((packed)) ntc_257_258;
+
+       } details;
+};
+
+/*
+ * Generic trap/notice types
+ */
+#define IB_NOTICE_TYPE_FATAL   0x80
+#define IB_NOTICE_TYPE_URGENT  0x81
+#define IB_NOTICE_TYPE_SECURITY        0x82
+#define IB_NOTICE_TYPE_SM      0x83
+#define IB_NOTICE_TYPE_INFO    0x84
+
+/*
+ * Generic trap/notice producers
+ */
+#define IB_NOTICE_PROD_CA              cpu_to_be16(1)
+#define IB_NOTICE_PROD_SWITCH          cpu_to_be16(2)
+#define IB_NOTICE_PROD_ROUTER          cpu_to_be16(3)
+#define IB_NOTICE_PROD_CLASS_MGR       cpu_to_be16(4)
+
+/*
+ * Generic trap/notice numbers
+ */
+#define IB_NOTICE_TRAP_LLI_THRESH      cpu_to_be16(129)
+#define IB_NOTICE_TRAP_EBO_THRESH      cpu_to_be16(130)
+#define IB_NOTICE_TRAP_FLOW_UPDATE     cpu_to_be16(131)
+#define IB_NOTICE_TRAP_CAP_MASK_CHG    cpu_to_be16(144)
+#define IB_NOTICE_TRAP_SYS_GUID_CHG    cpu_to_be16(145)
+#define IB_NOTICE_TRAP_BAD_MKEY                cpu_to_be16(256)
+#define IB_NOTICE_TRAP_BAD_PKEY                cpu_to_be16(257)
+#define IB_NOTICE_TRAP_BAD_QKEY                cpu_to_be16(258)
+
+/*
+ * Repress trap/notice flags
+ */
+#define IB_NOTICE_REPRESS_LLI_THRESH   (1 << 0)
+#define IB_NOTICE_REPRESS_EBO_THRESH   (1 << 1)
+#define IB_NOTICE_REPRESS_FLOW_UPDATE  (1 << 2)
+#define IB_NOTICE_REPRESS_CAP_MASK_CHG (1 << 3)
+#define IB_NOTICE_REPRESS_SYS_GUID_CHG (1 << 4)
+#define IB_NOTICE_REPRESS_BAD_MKEY     (1 << 5)
+#define IB_NOTICE_REPRESS_BAD_PKEY     (1 << 6)
+#define IB_NOTICE_REPRESS_BAD_QKEY     (1 << 7)
+
+/*
+ * Generic trap/notice other local changes flags (trap 144).
+ */
+#define IB_NOTICE_TRAP_LSE_CHG         0x04    /* Link Speed Enable changed */
+#define IB_NOTICE_TRAP_LWE_CHG         0x02    /* Link Width Enable changed */
+#define IB_NOTICE_TRAP_NODE_DESC_CHG   0x01
+
+/*
+ * Generic trap/notice M_Key volation flags in dr_trunc_hop (trap 256).
+ */
+#define IB_NOTICE_TRAP_DR_NOTICE       0x80
+#define IB_NOTICE_TRAP_DR_TRUNC                0x40
+
+struct ib_vl_weight_elem {
+       u8      vl;     /* Only low 4 bits, upper 4 bits reserved */
+       u8      weight;
+};
+
+#define IB_VLARB_LOWPRI_0_31    1
+#define IB_VLARB_LOWPRI_32_63   2
+#define IB_VLARB_HIGHPRI_0_31   3
+#define IB_VLARB_HIGHPRI_32_63  4
+
+/*
+ * PMA class portinfo capability mask bits
+ */
+#define IB_PMA_CLASS_CAP_ALLPORTSELECT  cpu_to_be16(1 << 8)
+#define IB_PMA_CLASS_CAP_EXT_WIDTH      cpu_to_be16(1 << 9)
+#define IB_PMA_CLASS_CAP_XMIT_WAIT      cpu_to_be16(1 << 12)
+
+#define IB_PMA_CLASS_PORT_INFO          cpu_to_be16(0x0001)
+#define IB_PMA_PORT_SAMPLES_CONTROL     cpu_to_be16(0x0010)
+#define IB_PMA_PORT_SAMPLES_RESULT      cpu_to_be16(0x0011)
+#define IB_PMA_PORT_COUNTERS            cpu_to_be16(0x0012)
+#define IB_PMA_PORT_COUNTERS_EXT        cpu_to_be16(0x001D)
+#define IB_PMA_PORT_SAMPLES_RESULT_EXT  cpu_to_be16(0x001E)
+#define IB_PMA_PORT_COUNTERS_CONG       cpu_to_be16(0xFF00)
+
+struct ib_perf {
+       u8 base_version;
+       u8 mgmt_class;
+       u8 class_version;
+       u8 method;
+       __be16 status;
+       __be16 unused;
+       __be64 tid;
+       __be16 attr_id;
+       __be16 resv;
+       __be32 attr_mod;
+       u8 reserved[40];
+       u8 data[192];
+} __attribute__ ((packed));
+
+struct ib_pma_classportinfo {
+       u8 base_version;
+       u8 class_version;
+       __be16 cap_mask;
+       u8 reserved[3];
+       u8 resp_time_value;     /* only lower 5 bits */
+       union ib_gid redirect_gid;
+       __be32 redirect_tc_sl_fl;       /* 8, 4, 20 bits respectively */
+       __be16 redirect_lid;
+       __be16 redirect_pkey;
+       __be32 redirect_qp;     /* only lower 24 bits */
+       __be32 redirect_qkey;
+       union ib_gid trap_gid;
+       __be32 trap_tc_sl_fl;   /* 8, 4, 20 bits respectively */
+       __be16 trap_lid;
+       __be16 trap_pkey;
+       __be32 trap_hl_qp;      /* 8, 24 bits respectively */
+       __be32 trap_qkey;
+} __attribute__ ((packed));
+
+struct ib_pma_portsamplescontrol {
+       u8 opcode;
+       u8 port_select;
+       u8 tick;
+       u8 counter_width;       /* only lower 3 bits */
+       __be32 counter_mask0_9; /* 2, 10 * 3, bits */
+       __be16 counter_mask10_14;       /* 1, 5 * 3, bits */
+       u8 sample_mechanisms;
+       u8 sample_status;       /* only lower 2 bits */
+       __be64 option_mask;
+       __be64 vendor_mask;
+       __be32 sample_start;
+       __be32 sample_interval;
+       __be16 tag;
+       __be16 counter_select[15];
+} __attribute__ ((packed));
+
+struct ib_pma_portsamplesresult {
+       __be16 tag;
+       __be16 sample_status;   /* only lower 2 bits */
+       __be32 counter[15];
+} __attribute__ ((packed));
+
+struct ib_pma_portsamplesresult_ext {
+       __be16 tag;
+       __be16 sample_status;   /* only lower 2 bits */
+       __be32 extended_width;  /* only upper 2 bits */
+       __be64 counter[15];
+} __attribute__ ((packed));
+
+struct ib_pma_portcounters {
+       u8 reserved;
+       u8 port_select;
+       __be16 counter_select;
+       __be16 symbol_error_counter;
+       u8 link_error_recovery_counter;
+       u8 link_downed_counter;
+       __be16 port_rcv_errors;
+       __be16 port_rcv_remphys_errors;
+       __be16 port_rcv_switch_relay_errors;
+       __be16 port_xmit_discards;
+       u8 port_xmit_constraint_errors;
+       u8 port_rcv_constraint_errors;
+       u8 reserved1;
+       u8 lli_ebor_errors;     /* 4, 4, bits */
+       __be16 reserved2;
+       __be16 vl15_dropped;
+       __be32 port_xmit_data;
+       __be32 port_rcv_data;
+       __be32 port_xmit_packets;
+       __be32 port_rcv_packets;
+} __attribute__ ((packed));
+
+struct ib_pma_portcounters_cong {
+       u8 reserved;
+       u8 reserved1;
+       __be16 port_check_rate;
+       __be16 symbol_error_counter;
+       u8 link_error_recovery_counter;
+       u8 link_downed_counter;
+       __be16 port_rcv_errors;
+       __be16 port_rcv_remphys_errors;
+       __be16 port_rcv_switch_relay_errors;
+       __be16 port_xmit_discards;
+       u8 port_xmit_constraint_errors;
+       u8 port_rcv_constraint_errors;
+       u8 reserved2;
+       u8 lli_ebor_errors;    /* 4, 4, bits */
+       __be16 reserved3;
+       __be16 vl15_dropped;
+       __be64 port_xmit_data;
+       __be64 port_rcv_data;
+       __be64 port_xmit_packets;
+       __be64 port_rcv_packets;
+       __be64 port_xmit_wait;
+       __be64 port_adr_events;
+} __attribute__ ((packed));
+
+#define IB_PMA_CONG_HW_CONTROL_TIMER            0x00
+#define IB_PMA_CONG_HW_CONTROL_SAMPLE           0x01
+
+#define QIB_XMIT_RATE_UNSUPPORTED               0x0
+#define QIB_XMIT_RATE_PICO                      0x7
+/* number of 4nsec cycles equaling 2secs */
+#define QIB_CONG_TIMER_PSINTERVAL               0x1DCD64EC
+
+#define IB_PMA_SEL_SYMBOL_ERROR                 cpu_to_be16(0x0001)
+#define IB_PMA_SEL_LINK_ERROR_RECOVERY          cpu_to_be16(0x0002)
+#define IB_PMA_SEL_LINK_DOWNED                  cpu_to_be16(0x0004)
+#define IB_PMA_SEL_PORT_RCV_ERRORS              cpu_to_be16(0x0008)
+#define IB_PMA_SEL_PORT_RCV_REMPHYS_ERRORS      cpu_to_be16(0x0010)
+#define IB_PMA_SEL_PORT_XMIT_DISCARDS           cpu_to_be16(0x0040)
+#define IB_PMA_SEL_LOCAL_LINK_INTEGRITY_ERRORS  cpu_to_be16(0x0200)
+#define IB_PMA_SEL_EXCESSIVE_BUFFER_OVERRUNS    cpu_to_be16(0x0400)
+#define IB_PMA_SEL_PORT_VL15_DROPPED            cpu_to_be16(0x0800)
+#define IB_PMA_SEL_PORT_XMIT_DATA               cpu_to_be16(0x1000)
+#define IB_PMA_SEL_PORT_RCV_DATA                cpu_to_be16(0x2000)
+#define IB_PMA_SEL_PORT_XMIT_PACKETS            cpu_to_be16(0x4000)
+#define IB_PMA_SEL_PORT_RCV_PACKETS             cpu_to_be16(0x8000)
+
+#define IB_PMA_SEL_CONG_ALL                     0x01
+#define IB_PMA_SEL_CONG_PORT_DATA               0x02
+#define IB_PMA_SEL_CONG_XMIT                    0x04
+#define IB_PMA_SEL_CONG_ROUTING                 0x08
+
+struct ib_pma_portcounters_ext {
+       u8 reserved;
+       u8 port_select;
+       __be16 counter_select;
+       __be32 reserved1;
+       __be64 port_xmit_data;
+       __be64 port_rcv_data;
+       __be64 port_xmit_packets;
+       __be64 port_rcv_packets;
+       __be64 port_unicast_xmit_packets;
+       __be64 port_unicast_rcv_packets;
+       __be64 port_multicast_xmit_packets;
+       __be64 port_multicast_rcv_packets;
+} __attribute__ ((packed));
+
+#define IB_PMA_SELX_PORT_XMIT_DATA              cpu_to_be16(0x0001)
+#define IB_PMA_SELX_PORT_RCV_DATA               cpu_to_be16(0x0002)
+#define IB_PMA_SELX_PORT_XMIT_PACKETS           cpu_to_be16(0x0004)
+#define IB_PMA_SELX_PORT_RCV_PACKETS            cpu_to_be16(0x0008)
+#define IB_PMA_SELX_PORT_UNI_XMIT_PACKETS       cpu_to_be16(0x0010)
+#define IB_PMA_SELX_PORT_UNI_RCV_PACKETS        cpu_to_be16(0x0020)
+#define IB_PMA_SELX_PORT_MULTI_XMIT_PACKETS     cpu_to_be16(0x0040)
+#define IB_PMA_SELX_PORT_MULTI_RCV_PACKETS      cpu_to_be16(0x0080)
+
+/*
+ * The PortSamplesControl.CounterMasks field is an array of 3 bit fields
+ * which specify the N'th counter's capabilities. See ch. 16.1.3.2.
+ * We support 5 counters which only count the mandatory quantities.
+ */
+#define COUNTER_MASK(q, n) (q << ((9 - n) * 3))
+#define COUNTER_MASK0_9 \
+       cpu_to_be32(COUNTER_MASK(1, 0) | \
+                   COUNTER_MASK(1, 1) | \
+                   COUNTER_MASK(1, 2) | \
+                   COUNTER_MASK(1, 3) | \
+                   COUNTER_MASK(1, 4))
diff --git a/drivers/infiniband/hw/qib/qib_mmap.c b/drivers/infiniband/hw/qib/qib_mmap.c
new file mode 100644 (file)
index 0000000..8b73a11
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <asm/pgtable.h>
+
+#include "qib_verbs.h"
+
+/**
+ * qib_release_mmap_info - free mmap info structure
+ * @ref: a pointer to the kref within struct qib_mmap_info
+ */
+void qib_release_mmap_info(struct kref *ref)
+{
+       struct qib_mmap_info *ip =
+               container_of(ref, struct qib_mmap_info, ref);
+       struct qib_ibdev *dev = to_idev(ip->context->device);
+
+       spin_lock_irq(&dev->pending_lock);
+       list_del(&ip->pending_mmaps);
+       spin_unlock_irq(&dev->pending_lock);
+
+       vfree(ip->obj);
+       kfree(ip);
+}
+
+/*
+ * open and close keep track of how many times the CQ is mapped,
+ * to avoid releasing it.
+ */
+static void qib_vma_open(struct vm_area_struct *vma)
+{
+       struct qib_mmap_info *ip = vma->vm_private_data;
+
+       kref_get(&ip->ref);
+}
+
+static void qib_vma_close(struct vm_area_struct *vma)
+{
+       struct qib_mmap_info *ip = vma->vm_private_data;
+
+       kref_put(&ip->ref, qib_release_mmap_info);
+}
+
+static struct vm_operations_struct qib_vm_ops = {
+       .open =     qib_vma_open,
+       .close =    qib_vma_close,
+};
+
+/**
+ * qib_mmap - create a new mmap region
+ * @context: the IB user context of the process making the mmap() call
+ * @vma: the VMA to be initialized
+ * Return zero if the mmap is OK. Otherwise, return an errno.
+ */
+int qib_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
+{
+       struct qib_ibdev *dev = to_idev(context->device);
+       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+       unsigned long size = vma->vm_end - vma->vm_start;
+       struct qib_mmap_info *ip, *pp;
+       int ret = -EINVAL;
+
+       /*
+        * Search the device's list of objects waiting for a mmap call.
+        * Normally, this list is very short since a call to create a
+        * CQ, QP, or SRQ is soon followed by a call to mmap().
+        */
+       spin_lock_irq(&dev->pending_lock);
+       list_for_each_entry_safe(ip, pp, &dev->pending_mmaps,
+                                pending_mmaps) {
+               /* Only the creator is allowed to mmap the object */
+               if (context != ip->context || (__u64) offset != ip->offset)
+                       continue;
+               /* Don't allow a mmap larger than the object. */
+               if (size > ip->size)
+                       break;
+
+               list_del_init(&ip->pending_mmaps);
+               spin_unlock_irq(&dev->pending_lock);
+
+               ret = remap_vmalloc_range(vma, ip->obj, 0);
+               if (ret)
+                       goto done;
+               vma->vm_ops = &qib_vm_ops;
+               vma->vm_private_data = ip;
+               qib_vma_open(vma);
+               goto done;
+       }
+       spin_unlock_irq(&dev->pending_lock);
+done:
+       return ret;
+}
+
+/*
+ * Allocate information for qib_mmap
+ */
+struct qib_mmap_info *qib_create_mmap_info(struct qib_ibdev *dev,
+                                          u32 size,
+                                          struct ib_ucontext *context,
+                                          void *obj) {
+       struct qib_mmap_info *ip;
+
+       ip = kmalloc(sizeof *ip, GFP_KERNEL);
+       if (!ip)
+               goto bail;
+
+       size = PAGE_ALIGN(size);
+
+       spin_lock_irq(&dev->mmap_offset_lock);
+       if (dev->mmap_offset == 0)
+               dev->mmap_offset = PAGE_SIZE;
+       ip->offset = dev->mmap_offset;
+       dev->mmap_offset += size;
+       spin_unlock_irq(&dev->mmap_offset_lock);
+
+       INIT_LIST_HEAD(&ip->pending_mmaps);
+       ip->size = size;
+       ip->context = context;
+       ip->obj = obj;
+       kref_init(&ip->ref);
+
+bail:
+       return ip;
+}
+
+void qib_update_mmap_info(struct qib_ibdev *dev, struct qib_mmap_info *ip,
+                         u32 size, void *obj)
+{
+       size = PAGE_ALIGN(size);
+
+       spin_lock_irq(&dev->mmap_offset_lock);
+       if (dev->mmap_offset == 0)
+               dev->mmap_offset = PAGE_SIZE;
+       ip->offset = dev->mmap_offset;
+       dev->mmap_offset += size;
+       spin_unlock_irq(&dev->mmap_offset_lock);
+
+       ip->size = size;
+       ip->obj = obj;
+}
diff --git a/drivers/infiniband/hw/qib/qib_mr.c b/drivers/infiniband/hw/qib/qib_mr.c
new file mode 100644 (file)
index 0000000..5f95f0f
--- /dev/null
@@ -0,0 +1,503 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved.
+ * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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 <rdma/ib_umem.h>
+#include <rdma/ib_smi.h>
+
+#include "qib.h"
+
+/* Fast memory region */
+struct qib_fmr {
+       struct ib_fmr ibfmr;
+       u8 page_shift;
+       struct qib_mregion mr;        /* must be last */
+};
+
+static inline struct qib_fmr *to_ifmr(struct ib_fmr *ibfmr)
+{
+       return container_of(ibfmr, struct qib_fmr, ibfmr);
+}
+
+/**
+ * qib_get_dma_mr - get a DMA memory region
+ * @pd: protection domain for this memory region
+ * @acc: access flags
+ *
+ * Returns the memory region on success, otherwise returns an errno.
+ * Note that all DMA addresses should be created via the
+ * struct ib_dma_mapping_ops functions (see qib_dma.c).
+ */
+struct ib_mr *qib_get_dma_mr(struct ib_pd *pd, int acc)
+{
+       struct qib_ibdev *dev = to_idev(pd->device);
+       struct qib_mr *mr;
+       struct ib_mr *ret;
+       unsigned long flags;
+
+       if (to_ipd(pd)->user) {
+               ret = ERR_PTR(-EPERM);
+               goto bail;
+       }
+
+       mr = kzalloc(sizeof *mr, GFP_KERNEL);
+       if (!mr) {
+               ret = ERR_PTR(-ENOMEM);
+               goto bail;
+       }
+
+       mr->mr.access_flags = acc;
+       atomic_set(&mr->mr.refcount, 0);
+
+       spin_lock_irqsave(&dev->lk_table.lock, flags);
+       if (!dev->dma_mr)
+               dev->dma_mr = &mr->mr;
+       spin_unlock_irqrestore(&dev->lk_table.lock, flags);
+
+       ret = &mr->ibmr;
+
+bail:
+       return ret;
+}
+
+static struct qib_mr *alloc_mr(int count, struct qib_lkey_table *lk_table)
+{
+       struct qib_mr *mr;
+       int m, i = 0;
+
+       /* Allocate struct plus pointers to first level page tables. */
+       m = (count + QIB_SEGSZ - 1) / QIB_SEGSZ;
+       mr = kmalloc(sizeof *mr + m * sizeof mr->mr.map[0], GFP_KERNEL);
+       if (!mr)
+               goto done;
+
+       /* Allocate first level page tables. */
+       for (; i < m; i++) {
+               mr->mr.map[i] = kmalloc(sizeof *mr->mr.map[0], GFP_KERNEL);
+               if (!mr->mr.map[i])
+                       goto bail;
+       }
+       mr->mr.mapsz = m;
+       mr->mr.max_segs = count;
+
+       /*
+        * ib_reg_phys_mr() will initialize mr->ibmr except for
+        * lkey and rkey.
+        */
+       if (!qib_alloc_lkey(lk_table, &mr->mr))
+               goto bail;
+       mr->ibmr.lkey = mr->mr.lkey;
+       mr->ibmr.rkey = mr->mr.lkey;
+
+       atomic_set(&mr->mr.refcount, 0);
+       goto done;
+
+bail:
+       while (i)
+               kfree(mr->mr.map[--i]);
+       kfree(mr);
+       mr = NULL;
+
+done:
+       return mr;
+}
+
+/**
+ * qib_reg_phys_mr - register a physical memory region
+ * @pd: protection domain for this memory region
+ * @buffer_list: pointer to the list of physical buffers to register
+ * @num_phys_buf: the number of physical buffers to register
+ * @iova_start: the starting address passed over IB which maps to this MR
+ *
+ * Returns the memory region on success, otherwise returns an errno.
+ */
+struct ib_mr *qib_reg_phys_mr(struct ib_pd *pd,
+                             struct ib_phys_buf *buffer_list,
+                             int num_phys_buf, int acc, u64 *iova_start)
+{
+       struct qib_mr *mr;
+       int n, m, i;
+       struct ib_mr *ret;
+
+       mr = alloc_mr(num_phys_buf, &to_idev(pd->device)->lk_table);
+       if (mr == NULL) {
+               ret = ERR_PTR(-ENOMEM);
+               goto bail;
+       }
+
+       mr->mr.pd = pd;
+       mr->mr.user_base = *iova_start;
+       mr->mr.iova = *iova_start;
+       mr->mr.length = 0;
+       mr->mr.offset = 0;
+       mr->mr.access_flags = acc;
+       mr->umem = NULL;
+
+       m = 0;
+       n = 0;
+       for (i = 0; i < num_phys_buf; i++) {
+               mr->mr.map[m]->segs[n].vaddr = (void *) buffer_list[i].addr;
+               mr->mr.map[m]->segs[n].length = buffer_list[i].size;
+               mr->mr.length += buffer_list[i].size;
+               n++;
+               if (n == QIB_SEGSZ) {
+                       m++;
+                       n = 0;
+               }
+       }
+
+       ret = &mr->ibmr;
+
+bail:
+       return ret;
+}
+
+/**
+ * qib_reg_user_mr - register a userspace memory region
+ * @pd: protection domain for this memory region
+ * @start: starting userspace address
+ * @length: length of region to register
+ * @virt_addr: virtual address to use (from HCA's point of view)
+ * @mr_access_flags: access flags for this memory region
+ * @udata: unused by the QLogic_IB driver
+ *
+ * Returns the memory region on success, otherwise returns an errno.
+ */
+struct ib_mr *qib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
+                             u64 virt_addr, int mr_access_flags,
+                             struct ib_udata *udata)
+{
+       struct qib_mr *mr;
+       struct ib_umem *umem;
+       struct ib_umem_chunk *chunk;
+       int n, m, i;
+       struct ib_mr *ret;
+
+       if (length == 0) {
+               ret = ERR_PTR(-EINVAL);
+               goto bail;
+       }
+
+       umem = ib_umem_get(pd->uobject->context, start, length,
+                          mr_access_flags, 0);
+       if (IS_ERR(umem))
+               return (void *) umem;
+
+       n = 0;
+       list_for_each_entry(chunk, &umem->chunk_list, list)
+               n += chunk->nents;
+
+       mr = alloc_mr(n, &to_idev(pd->device)->lk_table);
+       if (!mr) {
+               ret = ERR_PTR(-ENOMEM);
+               ib_umem_release(umem);
+               goto bail;
+       }
+
+       mr->mr.pd = pd;
+       mr->mr.user_base = start;
+       mr->mr.iova = virt_addr;
+       mr->mr.length = length;
+       mr->mr.offset = umem->offset;
+       mr->mr.access_flags = mr_access_flags;
+       mr->umem = umem;
+
+       m = 0;
+       n = 0;
+       list_for_each_entry(chunk, &umem->chunk_list, list) {
+               for (i = 0; i < chunk->nents; i++) {
+                       void *vaddr;
+
+                       vaddr = page_address(sg_page(&chunk->page_list[i]));
+                       if (!vaddr) {
+                               ret = ERR_PTR(-EINVAL);
+                               goto bail;
+                       }
+                       mr->mr.map[m]->segs[n].vaddr = vaddr;
+                       mr->mr.map[m]->segs[n].length = umem->page_size;
+                       n++;
+                       if (n == QIB_SEGSZ) {
+                               m++;
+                               n = 0;
+                       }
+               }
+       }
+       ret = &mr->ibmr;
+
+bail:
+       return ret;
+}
+
+/**
+ * qib_dereg_mr - unregister and free a memory region
+ * @ibmr: the memory region to free
+ *
+ * Returns 0 on success.
+ *
+ * Note that this is called to free MRs created by qib_get_dma_mr()
+ * or qib_reg_user_mr().
+ */
+int qib_dereg_mr(struct ib_mr *ibmr)
+{
+       struct qib_mr *mr = to_imr(ibmr);
+       struct qib_ibdev *dev = to_idev(ibmr->device);
+       int ret;
+       int i;
+
+       ret = qib_free_lkey(dev, &mr->mr);
+       if (ret)
+               return ret;
+
+       i = mr->mr.mapsz;
+       while (i)
+               kfree(mr->mr.map[--i]);
+       if (mr->umem)
+               ib_umem_release(mr->umem);
+       kfree(mr);
+       return 0;
+}
+
+/*
+ * Allocate a memory region usable with the
+ * IB_WR_FAST_REG_MR send work request.
+ *
+ * Return the memory region on success, otherwise return an errno.
+ */
+struct ib_mr *qib_alloc_fast_reg_mr(struct ib_pd *pd, int max_page_list_len)
+{
+       struct qib_mr *mr;
+
+       mr = alloc_mr(max_page_list_len, &to_idev(pd->device)->lk_table);
+       if (mr == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       mr->mr.pd = pd;
+       mr->mr.user_base = 0;
+       mr->mr.iova = 0;
+       mr->mr.length = 0;
+       mr->mr.offset = 0;
+       mr->mr.access_flags = 0;
+       mr->umem = NULL;
+
+       return &mr->ibmr;
+}
+
+struct ib_fast_reg_page_list *
+qib_alloc_fast_reg_page_list(struct ib_device *ibdev, int page_list_len)
+{
+       unsigned size = page_list_len * sizeof(u64);
+       struct ib_fast_reg_page_list *pl;
+
+       if (size > PAGE_SIZE)
+               return ERR_PTR(-EINVAL);
+
+       pl = kmalloc(sizeof *pl, GFP_KERNEL);
+       if (!pl)
+               return ERR_PTR(-ENOMEM);
+
+       pl->page_list = kmalloc(size, GFP_KERNEL);
+       if (!pl->page_list)
+               goto err_free;
+
+       return pl;
+
+err_free:
+       kfree(pl);
+       return ERR_PTR(-ENOMEM);
+}
+
+void qib_free_fast_reg_page_list(struct ib_fast_reg_page_list *pl)
+{
+       kfree(pl->page_list);
+       kfree(pl);
+}
+
+/**
+ * qib_alloc_fmr - allocate a fast memory region
+ * @pd: the protection domain for this memory region
+ * @mr_access_flags: access flags for this memory region
+ * @fmr_attr: fast memory region attributes
+ *
+ * Returns the memory region on success, otherwise returns an errno.
+ */
+struct ib_fmr *qib_alloc_fmr(struct ib_pd *pd, int mr_access_flags,
+                            struct ib_fmr_attr *fmr_attr)
+{
+       struct qib_fmr *fmr;
+       int m, i = 0;
+       struct ib_fmr *ret;
+
+       /* Allocate struct plus pointers to first level page tables. */
+       m = (fmr_attr->max_pages + QIB_SEGSZ - 1) / QIB_SEGSZ;
+       fmr = kmalloc(sizeof *fmr + m * sizeof fmr->mr.map[0], GFP_KERNEL);
+       if (!fmr)
+               goto bail;
+
+       /* Allocate first level page tables. */
+       for (; i < m; i++) {
+               fmr->mr.map[i] = kmalloc(sizeof *fmr->mr.map[0],
+                                        GFP_KERNEL);
+               if (!fmr->mr.map[i])
+                       goto bail;
+       }
+       fmr->mr.mapsz = m;
+
+       /*
+        * ib_alloc_fmr() will initialize fmr->ibfmr except for lkey &
+        * rkey.
+        */
+       if (!qib_alloc_lkey(&to_idev(pd->device)->lk_table, &fmr->mr))
+               goto bail;
+       fmr->ibfmr.rkey = fmr->mr.lkey;
+       fmr->ibfmr.lkey = fmr->mr.lkey;
+       /*
+        * Resources are allocated but no valid mapping (RKEY can't be
+        * used).
+        */
+       fmr->mr.pd = pd;
+       fmr->mr.user_base = 0;
+       fmr->mr.iova = 0;
+       fmr->mr.length = 0;
+       fmr->mr.offset = 0;
+       fmr->mr.access_flags = mr_access_flags;
+       fmr->mr.max_segs = fmr_attr->max_pages;
+       fmr->page_shift = fmr_attr->page_shift;
+
+       atomic_set(&fmr->mr.refcount, 0);
+       ret = &fmr->ibfmr;
+       goto done;
+
+bail:
+       while (i)
+               kfree(fmr->mr.map[--i]);
+       kfree(fmr);
+       ret = ERR_PTR(-ENOMEM);
+
+done:
+       return ret;
+}
+
+/**
+ * qib_map_phys_fmr - set up a fast memory region
+ * @ibmfr: the fast memory region to set up
+ * @page_list: the list of pages to associate with the fast memory region
+ * @list_len: the number of pages to associate with the fast memory region
+ * @iova: the virtual address of the start of the fast memory region
+ *
+ * This may be called from interrupt context.
+ */
+
+int qib_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list,
+                    int list_len, u64 iova)
+{
+       struct qib_fmr *fmr = to_ifmr(ibfmr);
+       struct qib_lkey_table *rkt;
+       unsigned long flags;
+       int m, n, i;
+       u32 ps;
+       int ret;
+
+       if (atomic_read(&fmr->mr.refcount))
+               return -EBUSY;
+
+       if (list_len > fmr->mr.max_segs) {
+               ret = -EINVAL;
+               goto bail;
+       }
+       rkt = &to_idev(ibfmr->device)->lk_table;
+       spin_lock_irqsave(&rkt->lock, flags);
+       fmr->mr.user_base = iova;
+       fmr->mr.iova = iova;
+       ps = 1 << fmr->page_shift;
+       fmr->mr.length = list_len * ps;
+       m = 0;
+       n = 0;
+       for (i = 0; i < list_len; i++) {
+               fmr->mr.map[m]->segs[n].vaddr = (void *) page_list[i];
+               fmr->mr.map[m]->segs[n].length = ps;
+               if (++n == QIB_SEGSZ) {
+                       m++;
+                       n = 0;
+               }
+       }
+       spin_unlock_irqrestore(&rkt->lock, flags);
+       ret = 0;
+
+bail:
+       return ret;
+}
+
+/**
+ * qib_unmap_fmr - unmap fast memory regions
+ * @fmr_list: the list of fast memory regions to unmap
+ *
+ * Returns 0 on success.
+ */
+int qib_unmap_fmr(struct list_head *fmr_list)
+{
+       struct qib_fmr *fmr;
+       struct qib_lkey_table *rkt;
+       unsigned long flags;
+
+       list_for_each_entry(fmr, fmr_list, ibfmr.list) {
+               rkt = &to_idev(fmr->ibfmr.device)->lk_table;
+               spin_lock_irqsave(&rkt->lock, flags);
+               fmr->mr.user_base = 0;
+               fmr->mr.iova = 0;
+               fmr->mr.length = 0;
+               spin_unlock_irqrestore(&rkt->lock, flags);
+       }
+       return 0;
+}
+
+/**
+ * qib_dealloc_fmr - deallocate a fast memory region
+ * @ibfmr: the fast memory region to deallocate
+ *
+ * Returns 0 on success.
+ */
+int qib_dealloc_fmr(struct ib_fmr *ibfmr)
+{
+       struct qib_fmr *fmr = to_ifmr(ibfmr);
+       int ret;
+       int i;
+
+       ret = qib_free_lkey(to_idev(ibfmr->device), &fmr->mr);
+       if (ret)
+               return ret;
+
+       i = fmr->mr.mapsz;
+       while (i)
+               kfree(fmr->mr.map[--i]);
+       kfree(fmr);
+       return 0;
+}
diff --git a/drivers/infiniband/hw/qib/qib_pcie.c b/drivers/infiniband/hw/qib/qib_pcie.c
new file mode 100644 (file)
index 0000000..c926bf4
--- /dev/null
@@ -0,0 +1,738 @@
+/*
+ * Copyright (c) 2008, 2009 QLogic Corporation. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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/pci.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/vmalloc.h>
+#include <linux/aer.h>
+
+#include "qib.h"
+
+/*
+ * This file contains PCIe utility routines that are common to the
+ * various QLogic InfiniPath adapters
+ */
+
+/*
+ * Code to adjust PCIe capabilities.
+ * To minimize the change footprint, we call it
+ * from qib_pcie_params, which every chip-specific
+ * file calls, even though this violates some
+ * expectations of harmlessness.
+ */
+static int qib_tune_pcie_caps(struct qib_devdata *);
+static int qib_tune_pcie_coalesce(struct qib_devdata *);
+
+/*
+ * Do all the common PCIe setup and initialization.
+ * devdata is not yet allocated, and is not allocated until after this
+ * routine returns success.  Therefore qib_dev_err() can't be used for error
+ * printing.
+ */
+int qib_pcie_init(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       int ret;
+
+       ret = pci_enable_device(pdev);
+       if (ret) {
+               /*
+                * This can happen (in theory) iff:
+                * We did a chip reset, and then failed to reprogram the
+                * BAR, or the chip reset due to an internal error.  We then
+                * unloaded the driver and reloaded it.
+                *
+                * Both reset cases set the BAR back to initial state.  For
+                * the latter case, the AER sticky error bit at offset 0x718
+                * should be set, but the Linux kernel doesn't yet know
+                * about that, it appears.  If the original BAR was retained
+                * in the kernel data structures, this may be OK.
+                */
+               qib_early_err(&pdev->dev, "pci enable failed: error %d\n",
+                             -ret);
+               goto done;
+       }
+
+       ret = pci_request_regions(pdev, QIB_DRV_NAME);
+       if (ret) {
+               qib_devinfo(pdev, "pci_request_regions fails: err %d\n", -ret);
+               goto bail;
+       }
+
+       ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+       if (ret) {
+               /*
+                * If the 64 bit setup fails, try 32 bit.  Some systems
+                * do not setup 64 bit maps on systems with 2GB or less
+                * memory installed.
+                */
+               ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+               if (ret) {
+                       qib_devinfo(pdev, "Unable to set DMA mask: %d\n", ret);
+                       goto bail;
+               }
+               ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+       } else
+               ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+       if (ret)
+               qib_early_err(&pdev->dev,
+                             "Unable to set DMA consistent mask: %d\n", ret);
+
+       pci_set_master(pdev);
+       ret = pci_enable_pcie_error_reporting(pdev);
+       if (ret)
+               qib_early_err(&pdev->dev,
+                             "Unable to enable pcie error reporting: %d\n",
+                             ret);
+       goto done;
+
+bail:
+       pci_disable_device(pdev);
+       pci_release_regions(pdev);
+done:
+       return ret;
+}
+
+/*
+ * Do remaining PCIe setup, once dd is allocated, and save away
+ * fields required to re-initialize after a chip reset, or for
+ * various other purposes
+ */
+int qib_pcie_ddinit(struct qib_devdata *dd, struct pci_dev *pdev,
+                   const struct pci_device_id *ent)
+{
+       unsigned long len;
+       resource_size_t addr;
+
+       dd->pcidev = pdev;
+       pci_set_drvdata(pdev, dd);
+
+       addr = pci_resource_start(pdev, 0);
+       len = pci_resource_len(pdev, 0);
+
+#if defined(__powerpc__)
+       /* There isn't a generic way to specify writethrough mappings */
+       dd->kregbase = __ioremap(addr, len, _PAGE_NO_CACHE | _PAGE_WRITETHRU);
+#else
+       dd->kregbase = ioremap_nocache(addr, len);
+#endif
+
+       if (!dd->kregbase)
+               return -ENOMEM;
+
+       dd->kregend = (u64 __iomem *)((void __iomem *) dd->kregbase + len);
+       dd->physaddr = addr;        /* used for io_remap, etc. */
+
+       /*
+        * Save BARs to rewrite after device reset.  Save all 64 bits of
+        * BAR, just in case.
+        */
+       dd->pcibar0 = addr;
+       dd->pcibar1 = addr >> 32;
+       dd->deviceid = ent->device; /* save for later use */
+       dd->vendorid = ent->vendor;
+
+       return 0;
+}
+
+/*
+ * Do PCIe cleanup, after chip-specific cleanup, etc.  Just prior
+ * to releasing the dd memory.
+ * void because none of the core pcie cleanup returns are void
+ */
+void qib_pcie_ddcleanup(struct qib_devdata *dd)
+{
+       u64 __iomem *base = (void __iomem *) dd->kregbase;
+
+       dd->kregbase = NULL;
+       iounmap(base);
+       if (dd->piobase)
+               iounmap(dd->piobase);
+       if (dd->userbase)
+               iounmap(dd->userbase);
+
+       pci_disable_device(dd->pcidev);
+       pci_release_regions(dd->pcidev);
+
+       pci_set_drvdata(dd->pcidev, NULL);
+}
+
+static void qib_msix_setup(struct qib_devdata *dd, int pos, u32 *msixcnt,
+                          struct msix_entry *msix_entry)
+{
+       int ret;
+       u32 tabsize = 0;
+       u16 msix_flags;
+
+       pci_read_config_word(dd->pcidev, pos + PCI_MSIX_FLAGS, &msix_flags);
+       tabsize = 1 + (msix_flags & PCI_MSIX_FLAGS_QSIZE);
+       if (tabsize > *msixcnt)
+               tabsize = *msixcnt;
+       ret = pci_enable_msix(dd->pcidev, msix_entry, tabsize);
+       if (ret > 0) {
+               tabsize = ret;
+               ret = pci_enable_msix(dd->pcidev, msix_entry, tabsize);
+       }
+       if (ret) {
+               qib_dev_err(dd, "pci_enable_msix %d vectors failed: %d, "
+                           "falling back to INTx\n", tabsize, ret);
+               tabsize = 0;
+       }
+       *msixcnt = tabsize;
+
+       if (ret)
+               qib_enable_intx(dd->pcidev);
+
+}
+
+/**
+ * We save the msi lo and hi values, so we can restore them after
+ * chip reset (the kernel PCI infrastructure doesn't yet handle that
+ * correctly.
+ */
+static int qib_msi_setup(struct qib_devdata *dd, int pos)
+{
+       struct pci_dev *pdev = dd->pcidev;
+       u16 control;
+       int ret;
+
+       ret = pci_enable_msi(pdev);
+       if (ret)
+               qib_dev_err(dd, "pci_enable_msi failed: %d, "
+                           "interrupts may not work\n", ret);
+       /* continue even if it fails, we may still be OK... */
+
+       pci_read_config_dword(pdev, pos + PCI_MSI_ADDRESS_LO,
+                             &dd->msi_lo);
+       pci_read_config_dword(pdev, pos + PCI_MSI_ADDRESS_HI,
+                             &dd->msi_hi);
+       pci_read_config_word(pdev, pos + PCI_MSI_FLAGS, &control);
+       /* now save the data (vector) info */
+       pci_read_config_word(pdev, pos + ((control & PCI_MSI_FLAGS_64BIT)
+                                   ? 12 : 8),
+                            &dd->msi_data);
+       return ret;
+}
+
+int qib_pcie_params(struct qib_devdata *dd, u32 minw, u32 *nent,
+                   struct msix_entry *entry)
+{
+       u16 linkstat, speed;
+       int pos = 0, pose, ret = 1;
+
+       pose = pci_find_capability(dd->pcidev, PCI_CAP_ID_EXP);
+       if (!pose) {
+               qib_dev_err(dd, "Can't find PCI Express capability!\n");
+               /* set up something... */
+               dd->lbus_width = 1;
+               dd->lbus_speed = 2500; /* Gen1, 2.5GHz */
+               goto bail;
+       }
+
+       pos = pci_find_capability(dd->pcidev, PCI_CAP_ID_MSIX);
+       if (nent && *nent && pos) {
+               qib_msix_setup(dd, pos, nent, entry);
+               ret = 0; /* did it, either MSIx or INTx */
+       } else {
+               pos = pci_find_capability(dd->pcidev, PCI_CAP_ID_MSI);
+               if (pos)
+                       ret = qib_msi_setup(dd, pos);
+               else
+                       qib_dev_err(dd, "No PCI MSI or MSIx capability!\n");
+       }
+       if (!pos)
+               qib_enable_intx(dd->pcidev);
+
+       pci_read_config_word(dd->pcidev, pose + PCI_EXP_LNKSTA, &linkstat);
+       /*
+        * speed is bits 0-3, linkwidth is bits 4-8
+        * no defines for them in headers
+        */
+       speed = linkstat & 0xf;
+       linkstat >>= 4;
+       linkstat &= 0x1f;
+       dd->lbus_width = linkstat;
+
+       switch (speed) {
+       case 1:
+               dd->lbus_speed = 2500; /* Gen1, 2.5GHz */
+               break;
+       case 2:
+               dd->lbus_speed = 5000; /* Gen1, 5GHz */
+               break;
+       default: /* not defined, assume gen1 */
+               dd->lbus_speed = 2500;
+               break;
+       }
+
+       /*
+        * Check against expected pcie width and complain if "wrong"
+        * on first initialization, not afterwards (i.e., reset).
+        */
+       if (minw && linkstat < minw)
+               qib_dev_err(dd,
+                           "PCIe width %u (x%u HCA), performance reduced\n",
+                           linkstat, minw);
+
+       qib_tune_pcie_caps(dd);
+
+       qib_tune_pcie_coalesce(dd);
+
+bail:
+       /* fill in string, even on errors */
+       snprintf(dd->lbus_info, sizeof(dd->lbus_info),
+                "PCIe,%uMHz,x%u\n", dd->lbus_speed, dd->lbus_width);
+       return ret;
+}
+
+/*
+ * Setup pcie interrupt stuff again after a reset.  I'd like to just call
+ * pci_enable_msi() again for msi, but when I do that,
+ * the MSI enable bit doesn't get set in the command word, and
+ * we switch to to a different interrupt vector, which is confusing,
+ * so I instead just do it all inline.  Perhaps somehow can tie this
+ * into the PCIe hotplug support at some point
+ */
+int qib_reinit_intr(struct qib_devdata *dd)
+{
+       int pos;
+       u16 control;
+       int ret = 0;
+
+       /* If we aren't using MSI, don't restore it */
+       if (!dd->msi_lo)
+               goto bail;
+
+       pos = pci_find_capability(dd->pcidev, PCI_CAP_ID_MSI);
+       if (!pos) {
+               qib_dev_err(dd, "Can't find MSI capability, "
+                           "can't restore MSI settings\n");
+               ret = 0;
+               /* nothing special for MSIx, just MSI */
+               goto bail;
+       }
+       pci_write_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_LO,
+                              dd->msi_lo);
+       pci_write_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_HI,
+                              dd->msi_hi);
+       pci_read_config_word(dd->pcidev, pos + PCI_MSI_FLAGS, &control);
+       if (!(control & PCI_MSI_FLAGS_ENABLE)) {
+               control |= PCI_MSI_FLAGS_ENABLE;
+               pci_write_config_word(dd->pcidev, pos + PCI_MSI_FLAGS,
+                                     control);
+       }
+       /* now rewrite the data (vector) info */
+       pci_write_config_word(dd->pcidev, pos +
+                             ((control & PCI_MSI_FLAGS_64BIT) ? 12 : 8),
+                             dd->msi_data);
+       ret = 1;
+bail:
+       if (!ret && (dd->flags & QIB_HAS_INTX)) {
+               qib_enable_intx(dd->pcidev);
+               ret = 1;
+       }
+
+       /* and now set the pci master bit again */
+       pci_set_master(dd->pcidev);
+
+       return ret;
+}
+
+/*
+ * Disable msi interrupt if enabled, and clear msi_lo.
+ * This is used primarily for the fallback to INTx, but
+ * is also used in reinit after reset, and during cleanup.
+ */
+void qib_nomsi(struct qib_devdata *dd)
+{
+       dd->msi_lo = 0;
+       pci_disable_msi(dd->pcidev);
+}
+
+/*
+ * Same as qib_nosmi, but for MSIx.
+ */
+void qib_nomsix(struct qib_devdata *dd)
+{
+       pci_disable_msix(dd->pcidev);
+}
+
+/*
+ * Similar to pci_intx(pdev, 1), except that we make sure
+ * msi(x) is off.
+ */
+void qib_enable_intx(struct pci_dev *pdev)
+{
+       u16 cw, new;
+       int pos;
+
+       /* first, turn on INTx */
+       pci_read_config_word(pdev, PCI_COMMAND, &cw);
+       new = cw & ~PCI_COMMAND_INTX_DISABLE;
+       if (new != cw)
+               pci_write_config_word(pdev, PCI_COMMAND, new);
+
+       pos = pci_find_capability(pdev, PCI_CAP_ID_MSI);
+       if (pos) {
+               /* then turn off MSI */
+               pci_read_config_word(pdev, pos + PCI_MSI_FLAGS, &cw);
+               new = cw & ~PCI_MSI_FLAGS_ENABLE;
+               if (new != cw)
+                       pci_write_config_word(pdev, pos + PCI_MSI_FLAGS, new);
+       }
+       pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
+       if (pos) {
+               /* then turn off MSIx */
+               pci_read_config_word(pdev, pos + PCI_MSIX_FLAGS, &cw);
+               new = cw & ~PCI_MSIX_FLAGS_ENABLE;
+               if (new != cw)
+                       pci_write_config_word(pdev, pos + PCI_MSIX_FLAGS, new);
+       }
+}
+
+/*
+ * These two routines are helper routines for the device reset code
+ * to move all the pcie code out of the chip-specific driver code.
+ */
+void qib_pcie_getcmd(struct qib_devdata *dd, u16 *cmd, u8 *iline, u8 *cline)
+{
+       pci_read_config_word(dd->pcidev, PCI_COMMAND, cmd);
+       pci_read_config_byte(dd->pcidev, PCI_INTERRUPT_LINE, iline);
+       pci_read_config_byte(dd->pcidev, PCI_CACHE_LINE_SIZE, cline);
+}
+
+void qib_pcie_reenable(struct qib_devdata *dd, u16 cmd, u8 iline, u8 cline)
+{
+       int r;
+       r = pci_write_config_dword(dd->pcidev, PCI_BASE_ADDRESS_0,
+                                  dd->pcibar0);
+       if (r)
+               qib_dev_err(dd, "rewrite of BAR0 failed: %d\n", r);
+       r = pci_write_config_dword(dd->pcidev, PCI_BASE_ADDRESS_1,
+                                  dd->pcibar1);
+       if (r)
+               qib_dev_err(dd, "rewrite of BAR1 failed: %d\n", r);
+       /* now re-enable memory access, and restore cosmetic settings */
+       pci_write_config_word(dd->pcidev, PCI_COMMAND, cmd);
+       pci_write_config_byte(dd->pcidev, PCI_INTERRUPT_LINE, iline);
+       pci_write_config_byte(dd->pcidev, PCI_CACHE_LINE_SIZE, cline);
+       r = pci_enable_device(dd->pcidev);
+       if (r)
+               qib_dev_err(dd, "pci_enable_device failed after "
+                           "reset: %d\n", r);
+}
+
+/* code to adjust PCIe capabilities. */
+
+static int fld2val(int wd, int mask)
+{
+       int lsbmask;
+
+       if (!mask)
+               return 0;
+       wd &= mask;
+       lsbmask = mask ^ (mask & (mask - 1));
+       wd /= lsbmask;
+       return wd;
+}
+
+static int val2fld(int wd, int mask)
+{
+       int lsbmask;
+
+       if (!mask)
+               return 0;
+       lsbmask = mask ^ (mask & (mask - 1));
+       wd *= lsbmask;
+       return wd;
+}
+
+static int qib_pcie_coalesce;
+module_param_named(pcie_coalesce, qib_pcie_coalesce, int, S_IRUGO);
+MODULE_PARM_DESC(pcie_coalesce, "tune PCIe colescing on some Intel chipsets");
+
+/*
+ * Enable PCIe completion and data coalescing, on Intel 5x00 and 7300
+ * chipsets.   This is known to be unsafe for some revisions of some
+ * of these chipsets, with some BIOS settings, and enabling it on those
+ * systems may result in the system crashing, and/or data corruption.
+ */
+static int qib_tune_pcie_coalesce(struct qib_devdata *dd)
+{
+       int r;
+       struct pci_dev *parent;
+       int ppos;
+       u16 devid;
+       u32 mask, bits, val;
+
+       if (!qib_pcie_coalesce)
+               return 0;
+
+       /* Find out supported and configured values for parent (root) */
+       parent = dd->pcidev->bus->self;
+       if (parent->bus->parent) {
+               qib_devinfo(dd->pcidev, "Parent not root\n");
+               return 1;
+       }
+       ppos = pci_find_capability(parent, PCI_CAP_ID_EXP);
+       if (!ppos)
+               return 1;
+       if (parent->vendor != 0x8086)
+               return 1;
+
+       /*
+        *  - bit 12: Max_rdcmp_Imt_EN: need to set to 1
+        *  - bit 11: COALESCE_FORCE: need to set to 0
+        *  - bit 10: COALESCE_EN: need to set to 1
+        *  (but limitations on some on some chipsets)
+        *
+        *  On the Intel 5000, 5100, and 7300 chipsets, there is
+        *  also: - bit 25:24: COALESCE_MODE, need to set to 0
+        */
+       devid = parent->device;
+       if (devid >= 0x25e2 && devid <= 0x25fa) {
+               u8 rev;
+
+               /* 5000 P/V/X/Z */
+               pci_read_config_byte(parent, PCI_REVISION_ID, &rev);
+               if (rev <= 0xb2)
+                       bits = 1U << 10;
+               else
+                       bits = 7U << 10;
+               mask = (3U << 24) | (7U << 10);
+       } else if (devid >= 0x65e2 && devid <= 0x65fa) {
+               /* 5100 */
+               bits = 1U << 10;
+               mask = (3U << 24) | (7U << 10);
+       } else if (devid >= 0x4021 && devid <= 0x402e) {
+               /* 5400 */
+               bits = 7U << 10;
+               mask = 7U << 10;
+       } else if (devid >= 0x3604 && devid <= 0x360a) {
+               /* 7300 */
+               bits = 7U << 10;
+               mask = (3U << 24) | (7U << 10);
+       } else {
+               /* not one of the chipsets that we know about */
+               return 1;
+       }
+       pci_read_config_dword(parent, 0x48, &val);
+       val &= ~mask;
+       val |= bits;
+       r = pci_write_config_dword(parent, 0x48, val);
+       return 0;
+}
+
+/*
+ * BIOS may not set PCIe bus-utilization parameters for best performance.
+ * Check and optionally adjust them to maximize our throughput.
+ */
+static int qib_pcie_caps;
+module_param_named(pcie_caps, qib_pcie_caps, int, S_IRUGO);
+MODULE_PARM_DESC(pcie_caps, "Max PCIe tuning: Payload (4lsb), ReadReq (D4..7)");
+
+static int qib_tune_pcie_caps(struct qib_devdata *dd)
+{
+       int ret = 1; /* Assume the worst */
+       struct pci_dev *parent;
+       int ppos, epos;
+       u16 pcaps, pctl, ecaps, ectl;
+       int rc_sup, ep_sup;
+       int rc_cur, ep_cur;
+
+       /* Find out supported and configured values for parent (root) */
+       parent = dd->pcidev->bus->self;
+       if (parent->bus->parent) {
+               qib_devinfo(dd->pcidev, "Parent not root\n");
+               goto bail;
+       }
+       ppos = pci_find_capability(parent, PCI_CAP_ID_EXP);
+       if (ppos) {
+               pci_read_config_word(parent, ppos + PCI_EXP_DEVCAP, &pcaps);
+               pci_read_config_word(parent, ppos + PCI_EXP_DEVCTL, &pctl);
+       } else
+               goto bail;
+       /* Find out supported and configured values for endpoint (us) */
+       epos = pci_find_capability(dd->pcidev, PCI_CAP_ID_EXP);
+       if (epos) {
+               pci_read_config_word(dd->pcidev, epos + PCI_EXP_DEVCAP, &ecaps);
+               pci_read_config_word(dd->pcidev, epos + PCI_EXP_DEVCTL, &ectl);
+       } else
+               goto bail;
+       ret = 0;
+       /* Find max payload supported by root, endpoint */
+       rc_sup = fld2val(pcaps, PCI_EXP_DEVCAP_PAYLOAD);
+       ep_sup = fld2val(ecaps, PCI_EXP_DEVCAP_PAYLOAD);
+       if (rc_sup > ep_sup)
+               rc_sup = ep_sup;
+
+       rc_cur = fld2val(pctl, PCI_EXP_DEVCTL_PAYLOAD);
+       ep_cur = fld2val(ectl, PCI_EXP_DEVCTL_PAYLOAD);
+
+       /* If Supported greater than limit in module param, limit it */
+       if (rc_sup > (qib_pcie_caps & 7))
+               rc_sup = qib_pcie_caps & 7;
+       /* If less than (allowed, supported), bump root payload */
+       if (rc_sup > rc_cur) {
+               rc_cur = rc_sup;
+               pctl = (pctl & ~PCI_EXP_DEVCTL_PAYLOAD) |
+                       val2fld(rc_cur, PCI_EXP_DEVCTL_PAYLOAD);
+               pci_write_config_word(parent, ppos + PCI_EXP_DEVCTL, pctl);
+       }
+       /* If less than (allowed, supported), bump endpoint payload */
+       if (rc_sup > ep_cur) {
+               ep_cur = rc_sup;
+               ectl = (ectl & ~PCI_EXP_DEVCTL_PAYLOAD) |
+                       val2fld(ep_cur, PCI_EXP_DEVCTL_PAYLOAD);
+               pci_write_config_word(dd->pcidev, epos + PCI_EXP_DEVCTL, ectl);
+       }
+
+       /*
+        * Now the Read Request size.
+        * No field for max supported, but PCIe spec limits it to 4096,
+        * which is code '5' (log2(4096) - 7)
+        */
+       rc_sup = 5;
+       if (rc_sup > ((qib_pcie_caps >> 4) & 7))
+               rc_sup = (qib_pcie_caps >> 4) & 7;
+       rc_cur = fld2val(pctl, PCI_EXP_DEVCTL_READRQ);
+       ep_cur = fld2val(ectl, PCI_EXP_DEVCTL_READRQ);
+
+       if (rc_sup > rc_cur) {
+               rc_cur = rc_sup;
+               pctl = (pctl & ~PCI_EXP_DEVCTL_READRQ) |
+                       val2fld(rc_cur, PCI_EXP_DEVCTL_READRQ);
+               pci_write_config_word(parent, ppos + PCI_EXP_DEVCTL, pctl);
+       }
+       if (rc_sup > ep_cur) {
+               ep_cur = rc_sup;
+               ectl = (ectl & ~PCI_EXP_DEVCTL_READRQ) |
+                       val2fld(ep_cur, PCI_EXP_DEVCTL_READRQ);
+               pci_write_config_word(dd->pcidev, epos + PCI_EXP_DEVCTL, ectl);
+       }
+bail:
+       return ret;
+}
+/* End of PCIe capability tuning */
+
+/*
+ * From here through qib_pci_err_handler definition is invoked via
+ * PCI error infrastructure, registered via pci
+ */
+static pci_ers_result_t
+qib_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
+{
+       struct qib_devdata *dd = pci_get_drvdata(pdev);
+       pci_ers_result_t ret = PCI_ERS_RESULT_RECOVERED;
+
+       switch (state) {
+       case pci_channel_io_normal:
+               qib_devinfo(pdev, "State Normal, ignoring\n");
+               break;
+
+       case pci_channel_io_frozen:
+               qib_devinfo(pdev, "State Frozen, requesting reset\n");
+               pci_disable_device(pdev);
+               ret = PCI_ERS_RESULT_NEED_RESET;
+               break;
+
+       case pci_channel_io_perm_failure:
+               qib_devinfo(pdev, "State Permanent Failure, disabling\n");
+               if (dd) {
+                       /* no more register accesses! */
+                       dd->flags &= ~QIB_PRESENT;
+                       qib_disable_after_error(dd);
+               }
+                /* else early, or other problem */
+               ret =  PCI_ERS_RESULT_DISCONNECT;
+               break;
+
+       default: /* shouldn't happen */
+               qib_devinfo(pdev, "QIB PCI errors detected (state %d)\n",
+                       state);
+               break;
+       }
+       return ret;
+}
+
+static pci_ers_result_t
+qib_pci_mmio_enabled(struct pci_dev *pdev)
+{
+       u64 words = 0U;
+       struct qib_devdata *dd = pci_get_drvdata(pdev);
+       pci_ers_result_t ret = PCI_ERS_RESULT_RECOVERED;
+
+       if (dd && dd->pport) {
+               words = dd->f_portcntr(dd->pport, QIBPORTCNTR_WORDRCV);
+               if (words == ~0ULL)
+                       ret = PCI_ERS_RESULT_NEED_RESET;
+       }
+       qib_devinfo(pdev, "QIB mmio_enabled function called, "
+                "read wordscntr %Lx, returning %d\n", words, ret);
+       return  ret;
+}
+
+static pci_ers_result_t
+qib_pci_slot_reset(struct pci_dev *pdev)
+{
+       qib_devinfo(pdev, "QIB link_reset function called, ignored\n");
+       return PCI_ERS_RESULT_CAN_RECOVER;
+}
+
+static pci_ers_result_t
+qib_pci_link_reset(struct pci_dev *pdev)
+{
+       qib_devinfo(pdev, "QIB link_reset function called, ignored\n");
+       return PCI_ERS_RESULT_CAN_RECOVER;
+}
+
+static void
+qib_pci_resume(struct pci_dev *pdev)
+{
+       struct qib_devdata *dd = pci_get_drvdata(pdev);
+       qib_devinfo(pdev, "QIB resume function called\n");
+       pci_cleanup_aer_uncorrect_error_status(pdev);
+       /*
+        * Running jobs will fail, since it's asynchronous
+        * unlike sysfs-requested reset.   Better than
+        * doing nothing.
+        */
+       qib_init(dd, 1); /* same as re-init after reset */
+}
+
+struct pci_error_handlers qib_pci_err_handler = {
+       .error_detected = qib_pci_error_detected,
+       .mmio_enabled = qib_pci_mmio_enabled,
+       .link_reset = qib_pci_link_reset,
+       .slot_reset = qib_pci_slot_reset,
+       .resume = qib_pci_resume,
+};
diff --git a/drivers/infiniband/hw/qib/qib_pio_copy.c b/drivers/infiniband/hw/qib/qib_pio_copy.c
new file mode 100644 (file)
index 0000000..10b8c44
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2009 QLogic Corporation. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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 "qib.h"
+
+/**
+ * qib_pio_copy - copy data to MMIO space, in multiples of 32-bits
+ * @to: destination, in MMIO space (must be 64-bit aligned)
+ * @from: source (must be 64-bit aligned)
+ * @count: number of 32-bit quantities to copy
+ *
+ * Copy data from kernel space to MMIO space, in multiples of 32 bits at a
+ * time.  Order of access is not guaranteed, nor is a memory barrier
+ * performed afterwards.
+ */
+void qib_pio_copy(void __iomem *to, const void *from, size_t count)
+{
+#ifdef CONFIG_64BIT
+       u64 __iomem *dst = to;
+       const u64 *src = from;
+       const u64 *end = src + (count >> 1);
+
+       while (src < end)
+               __raw_writeq(*src++, dst++);
+       if (count & 1)
+               __raw_writel(*(const u32 *)src, dst);
+#else
+       u32 __iomem *dst = to;
+       const u32 *src = from;
+       const u32 *end = src + count;
+
+       while (src < end)
+               __raw_writel(*src++, dst++);
+#endif
+}
diff --git a/drivers/infiniband/hw/qib/qib_qp.c b/drivers/infiniband/hw/qib/qib_qp.c
new file mode 100644 (file)
index 0000000..e0f65e3
--- /dev/null
@@ -0,0 +1,1255 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009, 2010 QLogic Corporation.
+ * All rights reserved.
+ * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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/err.h>
+#include <linux/vmalloc.h>
+
+#include "qib.h"
+
+#define BITS_PER_PAGE           (PAGE_SIZE*BITS_PER_BYTE)
+#define BITS_PER_PAGE_MASK      (BITS_PER_PAGE-1)
+
+static inline unsigned mk_qpn(struct qib_qpn_table *qpt,
+                             struct qpn_map *map, unsigned off)
+{
+       return (map - qpt->map) * BITS_PER_PAGE + off;
+}
+
+static inline unsigned find_next_offset(struct qib_qpn_table *qpt,
+                                       struct qpn_map *map, unsigned off,
+                                       unsigned r)
+{
+       if (qpt->mask) {
+               off++;
+               if ((off & qpt->mask) >> 1 != r)
+                       off = ((off & qpt->mask) ?
+                               (off | qpt->mask) + 1 : off) | (r << 1);
+       } else
+               off = find_next_zero_bit(map->page, BITS_PER_PAGE, off);
+       return off;
+}
+
+/*
+ * Convert the AETH credit code into the number of credits.
+ */
+static u32 credit_table[31] = {
+       0,                      /* 0 */
+       1,                      /* 1 */
+       2,                      /* 2 */
+       3,                      /* 3 */
+       4,                      /* 4 */
+       6,                      /* 5 */
+       8,                      /* 6 */
+       12,                     /* 7 */
+       16,                     /* 8 */
+       24,                     /* 9 */
+       32,                     /* A */
+       48,                     /* B */
+       64,                     /* C */
+       96,                     /* D */
+       128,                    /* E */
+       192,                    /* F */
+       256,                    /* 10 */
+       384,                    /* 11 */
+       512,                    /* 12 */
+       768,                    /* 13 */
+       1024,                   /* 14 */
+       1536,                   /* 15 */
+       2048,                   /* 16 */
+       3072,                   /* 17 */
+       4096,                   /* 18 */
+       6144,                   /* 19 */
+       8192,                   /* 1A */
+       12288,                  /* 1B */
+       16384,                  /* 1C */
+       24576,                  /* 1D */
+       32768                   /* 1E */
+};
+
+static void get_map_page(struct qib_qpn_table *qpt, struct qpn_map *map)
+{
+       unsigned long page = get_zeroed_page(GFP_KERNEL);
+
+       /*
+        * Free the page if someone raced with us installing it.
+        */
+
+       spin_lock(&qpt->lock);
+       if (map->page)
+               free_page(page);
+       else
+               map->page = (void *)page;
+       spin_unlock(&qpt->lock);
+}
+
+/*
+ * Allocate the next available QPN or
+ * zero/one for QP type IB_QPT_SMI/IB_QPT_GSI.
+ */
+static int alloc_qpn(struct qib_devdata *dd, struct qib_qpn_table *qpt,
+                    enum ib_qp_type type, u8 port)
+{
+       u32 i, offset, max_scan, qpn;
+       struct qpn_map *map;
+       u32 ret;
+       int r;
+
+       if (type == IB_QPT_SMI || type == IB_QPT_GSI) {
+               unsigned n;
+
+               ret = type == IB_QPT_GSI;
+               n = 1 << (ret + 2 * (port - 1));
+               spin_lock(&qpt->lock);
+               if (qpt->flags & n)
+                       ret = -EINVAL;
+               else
+                       qpt->flags |= n;
+               spin_unlock(&qpt->lock);
+               goto bail;
+       }
+
+       r = smp_processor_id();
+       if (r >= dd->n_krcv_queues)
+               r %= dd->n_krcv_queues;
+       qpn = qpt->last + 1;
+       if (qpn >= QPN_MAX)
+               qpn = 2;
+       if (qpt->mask && ((qpn & qpt->mask) >> 1) != r)
+               qpn = ((qpn & qpt->mask) ? (qpn | qpt->mask) + 1 : qpn) |
+                       (r << 1);
+       offset = qpn & BITS_PER_PAGE_MASK;
+       map = &qpt->map[qpn / BITS_PER_PAGE];
+       max_scan = qpt->nmaps - !offset;
+       for (i = 0;;) {
+               if (unlikely(!map->page)) {
+                       get_map_page(qpt, map);
+                       if (unlikely(!map->page))
+                               break;
+               }
+               do {
+                       if (!test_and_set_bit(offset, map->page)) {
+                               qpt->last = qpn;
+                               ret = qpn;
+                               goto bail;
+                       }
+                       offset = find_next_offset(qpt, map, offset, r);
+                       qpn = mk_qpn(qpt, map, offset);
+                       /*
+                        * This test differs from alloc_pidmap().
+                        * If find_next_offset() does find a zero
+                        * bit, we don't need to check for QPN
+                        * wrapping around past our starting QPN.
+                        * We just need to be sure we don't loop
+                        * forever.
+                        */
+               } while (offset < BITS_PER_PAGE && qpn < QPN_MAX);
+               /*
+                * In order to keep the number of pages allocated to a
+                * minimum, we scan the all existing pages before increasing
+                * the size of the bitmap table.
+                */
+               if (++i > max_scan) {
+                       if (qpt->nmaps == QPNMAP_ENTRIES)
+                               break;
+                       map = &qpt->map[qpt->nmaps++];
+                       offset = qpt->mask ? (r << 1) : 0;
+               } else if (map < &qpt->map[qpt->nmaps]) {
+                       ++map;
+                       offset = qpt->mask ? (r << 1) : 0;
+               } else {
+                       map = &qpt->map[0];
+                       offset = qpt->mask ? (r << 1) : 2;
+               }
+               qpn = mk_qpn(qpt, map, offset);
+       }
+
+       ret = -ENOMEM;
+
+bail:
+       return ret;
+}
+
+static void free_qpn(struct qib_qpn_table *qpt, u32 qpn)
+{
+       struct qpn_map *map;
+
+       map = qpt->map + qpn / BITS_PER_PAGE;
+       if (map->page)
+               clear_bit(qpn & BITS_PER_PAGE_MASK, map->page);
+}
+
+/*
+ * Put the QP into the hash table.
+ * The hash table holds a reference to the QP.
+ */
+static void insert_qp(struct qib_ibdev *dev, struct qib_qp *qp)
+{
+       struct qib_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num);
+       unsigned n = qp->ibqp.qp_num % dev->qp_table_size;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->qpt_lock, flags);
+
+       if (qp->ibqp.qp_num == 0)
+               ibp->qp0 = qp;
+       else if (qp->ibqp.qp_num == 1)
+               ibp->qp1 = qp;
+       else {
+               qp->next = dev->qp_table[n];
+               dev->qp_table[n] = qp;
+       }
+       atomic_inc(&qp->refcount);
+
+       spin_unlock_irqrestore(&dev->qpt_lock, flags);
+}
+
+/*
+ * Remove the QP from the table so it can't be found asynchronously by
+ * the receive interrupt routine.
+ */
+static void remove_qp(struct qib_ibdev *dev, struct qib_qp *qp)
+{
+       struct qib_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num);
+       struct qib_qp *q, **qpp;
+       unsigned long flags;
+
+       qpp = &dev->qp_table[qp->ibqp.qp_num % dev->qp_table_size];
+
+       spin_lock_irqsave(&dev->qpt_lock, flags);
+
+       if (ibp->qp0 == qp) {
+               ibp->qp0 = NULL;
+               atomic_dec(&qp->refcount);
+       } else if (ibp->qp1 == qp) {
+               ibp->qp1 = NULL;
+               atomic_dec(&qp->refcount);
+       } else
+               for (; (q = *qpp) != NULL; qpp = &q->next)
+                       if (q == qp) {
+                               *qpp = qp->next;
+                               qp->next = NULL;
+                               atomic_dec(&qp->refcount);
+                               break;
+                       }
+
+       spin_unlock_irqrestore(&dev->qpt_lock, flags);
+}
+
+/**
+ * qib_free_all_qps - check for QPs still in use
+ * @qpt: the QP table to empty
+ *
+ * There should not be any QPs still in use.
+ * Free memory for table.
+ */
+unsigned qib_free_all_qps(struct qib_devdata *dd)
+{
+       struct qib_ibdev *dev = &dd->verbs_dev;
+       unsigned long flags;
+       struct qib_qp *qp;
+       unsigned n, qp_inuse = 0;
+
+       for (n = 0; n < dd->num_pports; n++) {
+               struct qib_ibport *ibp = &dd->pport[n].ibport_data;
+
+               if (!qib_mcast_tree_empty(ibp))
+                       qp_inuse++;
+               if (ibp->qp0)
+                       qp_inuse++;
+               if (ibp->qp1)
+                       qp_inuse++;
+       }
+
+       spin_lock_irqsave(&dev->qpt_lock, flags);
+       for (n = 0; n < dev->qp_table_size; n++) {
+               qp = dev->qp_table[n];
+               dev->qp_table[n] = NULL;
+
+               for (; qp; qp = qp->next)
+                       qp_inuse++;
+       }
+       spin_unlock_irqrestore(&dev->qpt_lock, flags);
+
+       return qp_inuse;
+}
+
+/**
+ * qib_lookup_qpn - return the QP with the given QPN
+ * @qpt: the QP table
+ * @qpn: the QP number to look up
+ *
+ * The caller is responsible for decrementing the QP reference count
+ * when done.
+ */
+struct qib_qp *qib_lookup_qpn(struct qib_ibport *ibp, u32 qpn)
+{
+       struct qib_ibdev *dev = &ppd_from_ibp(ibp)->dd->verbs_dev;
+       unsigned long flags;
+       struct qib_qp *qp;
+
+       spin_lock_irqsave(&dev->qpt_lock, flags);
+
+       if (qpn == 0)
+               qp = ibp->qp0;
+       else if (qpn == 1)
+               qp = ibp->qp1;
+       else
+               for (qp = dev->qp_table[qpn % dev->qp_table_size]; qp;
+                    qp = qp->next)
+                       if (qp->ibqp.qp_num == qpn)
+                               break;
+       if (qp)
+               atomic_inc(&qp->refcount);
+
+       spin_unlock_irqrestore(&dev->qpt_lock, flags);
+       return qp;
+}
+
+/**
+ * qib_reset_qp - initialize the QP state to the reset state
+ * @qp: the QP to reset
+ * @type: the QP type
+ */
+static void qib_reset_qp(struct qib_qp *qp, enum ib_qp_type type)
+{
+       qp->remote_qpn = 0;
+       qp->qkey = 0;
+       qp->qp_access_flags = 0;
+       atomic_set(&qp->s_dma_busy, 0);
+       qp->s_flags &= QIB_S_SIGNAL_REQ_WR;
+       qp->s_hdrwords = 0;
+       qp->s_wqe = NULL;
+       qp->s_draining = 0;
+       qp->s_next_psn = 0;
+       qp->s_last_psn = 0;
+       qp->s_sending_psn = 0;
+       qp->s_sending_hpsn = 0;
+       qp->s_psn = 0;
+       qp->r_psn = 0;
+       qp->r_msn = 0;
+       if (type == IB_QPT_RC) {
+               qp->s_state = IB_OPCODE_RC_SEND_LAST;
+               qp->r_state = IB_OPCODE_RC_SEND_LAST;
+       } else {
+               qp->s_state = IB_OPCODE_UC_SEND_LAST;
+               qp->r_state = IB_OPCODE_UC_SEND_LAST;
+       }
+       qp->s_ack_state = IB_OPCODE_RC_ACKNOWLEDGE;
+       qp->r_nak_state = 0;
+       qp->r_aflags = 0;
+       qp->r_flags = 0;
+       qp->s_head = 0;
+       qp->s_tail = 0;
+       qp->s_cur = 0;
+       qp->s_acked = 0;
+       qp->s_last = 0;
+       qp->s_ssn = 1;
+       qp->s_lsn = 0;
+       qp->s_mig_state = IB_MIG_MIGRATED;
+       memset(qp->s_ack_queue, 0, sizeof(qp->s_ack_queue));
+       qp->r_head_ack_queue = 0;
+       qp->s_tail_ack_queue = 0;
+       qp->s_num_rd_atomic = 0;
+       if (qp->r_rq.wq) {
+               qp->r_rq.wq->head = 0;
+               qp->r_rq.wq->tail = 0;
+       }
+       qp->r_sge.num_sge = 0;
+}
+
+static void clear_mr_refs(struct qib_qp *qp, int clr_sends)
+{
+       unsigned n;
+
+       if (test_and_clear_bit(QIB_R_REWIND_SGE, &qp->r_aflags))
+               while (qp->s_rdma_read_sge.num_sge) {
+                       atomic_dec(&qp->s_rdma_read_sge.sge.mr->refcount);
+                       if (--qp->s_rdma_read_sge.num_sge)
+                               qp->s_rdma_read_sge.sge =
+                                       *qp->s_rdma_read_sge.sg_list++;
+               }
+
+       while (qp->r_sge.num_sge) {
+               atomic_dec(&qp->r_sge.sge.mr->refcount);
+               if (--qp->r_sge.num_sge)
+                       qp->r_sge.sge = *qp->r_sge.sg_list++;
+       }
+
+       if (clr_sends) {
+               while (qp->s_last != qp->s_head) {
+                       struct qib_swqe *wqe = get_swqe_ptr(qp, qp->s_last);
+                       unsigned i;
+
+                       for (i = 0; i < wqe->wr.num_sge; i++) {
+                               struct qib_sge *sge = &wqe->sg_list[i];
+
+                               atomic_dec(&sge->mr->refcount);
+                       }
+                       if (qp->ibqp.qp_type == IB_QPT_UD ||
+                           qp->ibqp.qp_type == IB_QPT_SMI ||
+                           qp->ibqp.qp_type == IB_QPT_GSI)
+                               atomic_dec(&to_iah(wqe->wr.wr.ud.ah)->refcount);
+                       if (++qp->s_last >= qp->s_size)
+                               qp->s_last = 0;
+               }
+               if (qp->s_rdma_mr) {
+                       atomic_dec(&qp->s_rdma_mr->refcount);
+                       qp->s_rdma_mr = NULL;
+               }
+       }
+
+       if (qp->ibqp.qp_type != IB_QPT_RC)
+               return;
+
+       for (n = 0; n < ARRAY_SIZE(qp->s_ack_queue); n++) {
+               struct qib_ack_entry *e = &qp->s_ack_queue[n];
+
+               if (e->opcode == IB_OPCODE_RC_RDMA_READ_REQUEST &&
+                   e->rdma_sge.mr) {
+                       atomic_dec(&e->rdma_sge.mr->refcount);
+                       e->rdma_sge.mr = NULL;
+               }
+       }
+}
+
+/**
+ * qib_error_qp - put a QP into the error state
+ * @qp: the QP to put into the error state
+ * @err: the receive completion error to signal if a RWQE is active
+ *
+ * Flushes both send and receive work queues.
+ * Returns true if last WQE event should be generated.
+ * The QP s_lock should be held and interrupts disabled.
+ * If we are already in error state, just return.
+ */
+int qib_error_qp(struct qib_qp *qp, enum ib_wc_status err)
+{
+       struct qib_ibdev *dev = to_idev(qp->ibqp.device);
+       struct ib_wc wc;
+       int ret = 0;
+
+       if (qp->state == IB_QPS_ERR || qp->state == IB_QPS_RESET)
+               goto bail;
+
+       qp->state = IB_QPS_ERR;
+
+       if (qp->s_flags & (QIB_S_TIMER | QIB_S_WAIT_RNR)) {
+               qp->s_flags &= ~(QIB_S_TIMER | QIB_S_WAIT_RNR);
+               del_timer(&qp->s_timer);
+       }
+       spin_lock(&dev->pending_lock);
+       if (!list_empty(&qp->iowait) && !(qp->s_flags & QIB_S_BUSY)) {
+               qp->s_flags &= ~QIB_S_ANY_WAIT_IO;
+               list_del_init(&qp->iowait);
+       }
+       spin_unlock(&dev->pending_lock);
+
+       if (!(qp->s_flags & QIB_S_BUSY)) {
+               qp->s_hdrwords = 0;
+               if (qp->s_rdma_mr) {
+                       atomic_dec(&qp->s_rdma_mr->refcount);
+                       qp->s_rdma_mr = NULL;
+               }
+               if (qp->s_tx) {
+                       qib_put_txreq(qp->s_tx);
+                       qp->s_tx = NULL;
+               }
+       }
+
+       /* Schedule the sending tasklet to drain the send work queue. */
+       if (qp->s_last != qp->s_head)
+               qib_schedule_send(qp);
+
+       clear_mr_refs(qp, 0);
+
+       memset(&wc, 0, sizeof(wc));
+       wc.qp = &qp->ibqp;
+       wc.opcode = IB_WC_RECV;
+
+       if (test_and_clear_bit(QIB_R_WRID_VALID, &qp->r_aflags)) {
+               wc.wr_id = qp->r_wr_id;
+               wc.status = err;
+               qib_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1);
+       }
+       wc.status = IB_WC_WR_FLUSH_ERR;
+
+       if (qp->r_rq.wq) {
+               struct qib_rwq *wq;
+               u32 head;
+               u32 tail;
+
+               spin_lock(&qp->r_rq.lock);
+
+               /* sanity check pointers before trusting them */
+               wq = qp->r_rq.wq;
+               head = wq->head;
+               if (head >= qp->r_rq.size)
+                       head = 0;
+               tail = wq->tail;
+               if (tail >= qp->r_rq.size)
+                       tail = 0;
+               while (tail != head) {
+                       wc.wr_id = get_rwqe_ptr(&qp->r_rq, tail)->wr_id;
+                       if (++tail >= qp->r_rq.size)
+                               tail = 0;
+                       qib_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1);
+               }
+               wq->tail = tail;
+
+               spin_unlock(&qp->r_rq.lock);
+       } else if (qp->ibqp.event_handler)
+               ret = 1;
+
+bail:
+       return ret;
+}
+
+/**
+ * qib_modify_qp - modify the attributes of a queue pair
+ * @ibqp: the queue pair who's attributes we're modifying
+ * @attr: the new attributes
+ * @attr_mask: the mask of attributes to modify
+ * @udata: user data for libibverbs.so
+ *
+ * Returns 0 on success, otherwise returns an errno.
+ */
+int qib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+                 int attr_mask, struct ib_udata *udata)
+{
+       struct qib_ibdev *dev = to_idev(ibqp->device);
+       struct qib_qp *qp = to_iqp(ibqp);
+       enum ib_qp_state cur_state, new_state;
+       struct ib_event ev;
+       int lastwqe = 0;
+       int mig = 0;
+       int ret;
+       u32 pmtu = 0; /* for gcc warning only */
+
+       spin_lock_irq(&qp->r_lock);
+       spin_lock(&qp->s_lock);
+
+       cur_state = attr_mask & IB_QP_CUR_STATE ?
+               attr->cur_qp_state : qp->state;
+       new_state = attr_mask & IB_QP_STATE ? attr->qp_state : cur_state;
+
+       if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type,
+                               attr_mask))
+               goto inval;
+
+       if (attr_mask & IB_QP_AV) {
+               if (attr->ah_attr.dlid >= QIB_MULTICAST_LID_BASE)
+                       goto inval;
+               if (qib_check_ah(qp->ibqp.device, &attr->ah_attr))
+                       goto inval;
+       }
+
+       if (attr_mask & IB_QP_ALT_PATH) {
+               if (attr->alt_ah_attr.dlid >= QIB_MULTICAST_LID_BASE)
+                       goto inval;
+               if (qib_check_ah(qp->ibqp.device, &attr->alt_ah_attr))
+                       goto inval;
+               if (attr->alt_pkey_index >= qib_get_npkeys(dd_from_dev(dev)))
+                       goto inval;
+       }
+
+       if (attr_mask & IB_QP_PKEY_INDEX)
+               if (attr->pkey_index >= qib_get_npkeys(dd_from_dev(dev)))
+                       goto inval;
+
+       if (attr_mask & IB_QP_MIN_RNR_TIMER)
+               if (attr->min_rnr_timer > 31)
+                       goto inval;
+
+       if (attr_mask & IB_QP_PORT)
+               if (qp->ibqp.qp_type == IB_QPT_SMI ||
+                   qp->ibqp.qp_type == IB_QPT_GSI ||
+                   attr->port_num == 0 ||
+                   attr->port_num > ibqp->device->phys_port_cnt)
+                       goto inval;
+
+       if (attr_mask & IB_QP_DEST_QPN)
+               if (attr->dest_qp_num > QIB_QPN_MASK)
+                       goto inval;
+
+       if (attr_mask & IB_QP_RETRY_CNT)
+               if (attr->retry_cnt > 7)
+                       goto inval;
+
+       if (attr_mask & IB_QP_RNR_RETRY)
+               if (attr->rnr_retry > 7)
+                       goto inval;
+
+       /*
+        * Don't allow invalid path_mtu values.  OK to set greater
+        * than the active mtu (or even the max_cap, if we have tuned
+        * that to a small mtu.  We'll set qp->path_mtu
+        * to the lesser of requested attribute mtu and active,
+        * for packetizing messages.
+        * Note that the QP port has to be set in INIT and MTU in RTR.
+        */
+       if (attr_mask & IB_QP_PATH_MTU) {
+               struct qib_devdata *dd = dd_from_dev(dev);
+               int mtu, pidx = qp->port_num - 1;
+
+               mtu = ib_mtu_enum_to_int(attr->path_mtu);
+               if (mtu == -1)
+                       goto inval;
+               if (mtu > dd->pport[pidx].ibmtu) {
+                       switch (dd->pport[pidx].ibmtu) {
+                       case 4096:
+                               pmtu = IB_MTU_4096;
+                               break;
+                       case 2048:
+                               pmtu = IB_MTU_2048;
+                               break;
+                       case 1024:
+                               pmtu = IB_MTU_1024;
+                               break;
+                       case 512:
+                               pmtu = IB_MTU_512;
+                               break;
+                       case 256:
+                               pmtu = IB_MTU_256;
+                               break;
+                       default:
+                               pmtu = IB_MTU_2048;
+                       }
+               } else
+                       pmtu = attr->path_mtu;
+       }
+
+       if (attr_mask & IB_QP_PATH_MIG_STATE) {
+               if (attr->path_mig_state == IB_MIG_REARM) {
+                       if (qp->s_mig_state == IB_MIG_ARMED)
+                               goto inval;
+                       if (new_state != IB_QPS_RTS)
+                               goto inval;
+               } else if (attr->path_mig_state == IB_MIG_MIGRATED) {
+                       if (qp->s_mig_state == IB_MIG_REARM)
+                               goto inval;
+                       if (new_state != IB_QPS_RTS && new_state != IB_QPS_SQD)
+                               goto inval;
+                       if (qp->s_mig_state == IB_MIG_ARMED)
+                               mig = 1;
+               } else
+                       goto inval;
+       }
+
+       if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
+               if (attr->max_dest_rd_atomic > QIB_MAX_RDMA_ATOMIC)
+                       goto inval;
+
+       switch (new_state) {
+       case IB_QPS_RESET:
+               if (qp->state != IB_QPS_RESET) {
+                       qp->state = IB_QPS_RESET;
+                       spin_lock(&dev->pending_lock);
+                       if (!list_empty(&qp->iowait))
+                               list_del_init(&qp->iowait);
+                       spin_unlock(&dev->pending_lock);
+                       qp->s_flags &= ~(QIB_S_TIMER | QIB_S_ANY_WAIT);
+                       spin_unlock(&qp->s_lock);
+                       spin_unlock_irq(&qp->r_lock);
+                       /* Stop the sending work queue and retry timer */
+                       cancel_work_sync(&qp->s_work);
+                       del_timer_sync(&qp->s_timer);
+                       wait_event(qp->wait_dma, !atomic_read(&qp->s_dma_busy));
+                       if (qp->s_tx) {
+                               qib_put_txreq(qp->s_tx);
+                               qp->s_tx = NULL;
+                       }
+                       remove_qp(dev, qp);
+                       wait_event(qp->wait, !atomic_read(&qp->refcount));
+                       spin_lock_irq(&qp->r_lock);
+                       spin_lock(&qp->s_lock);
+                       clear_mr_refs(qp, 1);
+                       qib_reset_qp(qp, ibqp->qp_type);
+               }
+               break;
+
+       case IB_QPS_RTR:
+               /* Allow event to retrigger if QP set to RTR more than once */
+               qp->r_flags &= ~QIB_R_COMM_EST;
+               qp->state = new_state;
+               break;
+
+       case IB_QPS_SQD:
+               qp->s_draining = qp->s_last != qp->s_cur;
+               qp->state = new_state;
+               break;
+
+       case IB_QPS_SQE:
+               if (qp->ibqp.qp_type == IB_QPT_RC)
+                       goto inval;
+               qp->state = new_state;
+               break;
+
+       case IB_QPS_ERR:
+               lastwqe = qib_error_qp(qp, IB_WC_WR_FLUSH_ERR);
+               break;
+
+       default:
+               qp->state = new_state;
+               break;
+       }
+
+       if (attr_mask & IB_QP_PKEY_INDEX)
+               qp->s_pkey_index = attr->pkey_index;
+
+       if (attr_mask & IB_QP_PORT)
+               qp->port_num = attr->port_num;
+
+       if (attr_mask & IB_QP_DEST_QPN)
+               qp->remote_qpn = attr->dest_qp_num;
+
+       if (attr_mask & IB_QP_SQ_PSN) {
+               qp->s_next_psn = attr->sq_psn & QIB_PSN_MASK;
+               qp->s_psn = qp->s_next_psn;
+               qp->s_sending_psn = qp->s_next_psn;
+               qp->s_last_psn = qp->s_next_psn - 1;
+               qp->s_sending_hpsn = qp->s_last_psn;
+       }
+
+       if (attr_mask & IB_QP_RQ_PSN)
+               qp->r_psn = attr->rq_psn & QIB_PSN_MASK;
+
+       if (attr_mask & IB_QP_ACCESS_FLAGS)
+               qp->qp_access_flags = attr->qp_access_flags;
+
+       if (attr_mask & IB_QP_AV) {
+               qp->remote_ah_attr = attr->ah_attr;
+               qp->s_srate = attr->ah_attr.static_rate;
+       }
+
+       if (attr_mask & IB_QP_ALT_PATH) {
+               qp->alt_ah_attr = attr->alt_ah_attr;
+               qp->s_alt_pkey_index = attr->alt_pkey_index;
+       }
+
+       if (attr_mask & IB_QP_PATH_MIG_STATE) {
+               qp->s_mig_state = attr->path_mig_state;
+               if (mig) {
+                       qp->remote_ah_attr = qp->alt_ah_attr;
+                       qp->port_num = qp->alt_ah_attr.port_num;
+                       qp->s_pkey_index = qp->s_alt_pkey_index;
+               }
+       }
+
+       if (attr_mask & IB_QP_PATH_MTU)
+               qp->path_mtu = pmtu;
+
+       if (attr_mask & IB_QP_RETRY_CNT) {
+               qp->s_retry_cnt = attr->retry_cnt;
+               qp->s_retry = attr->retry_cnt;
+       }
+
+       if (attr_mask & IB_QP_RNR_RETRY) {
+               qp->s_rnr_retry_cnt = attr->rnr_retry;
+               qp->s_rnr_retry = attr->rnr_retry;
+       }
+
+       if (attr_mask & IB_QP_MIN_RNR_TIMER)
+               qp->r_min_rnr_timer = attr->min_rnr_timer;
+
+       if (attr_mask & IB_QP_TIMEOUT)
+               qp->timeout = attr->timeout;
+
+       if (attr_mask & IB_QP_QKEY)
+               qp->qkey = attr->qkey;
+
+       if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
+               qp->r_max_rd_atomic = attr->max_dest_rd_atomic;
+
+       if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC)
+               qp->s_max_rd_atomic = attr->max_rd_atomic;
+
+       spin_unlock(&qp->s_lock);
+       spin_unlock_irq(&qp->r_lock);
+
+       if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT)
+               insert_qp(dev, qp);
+
+       if (lastwqe) {
+               ev.device = qp->ibqp.device;
+               ev.element.qp = &qp->ibqp;
+               ev.event = IB_EVENT_QP_LAST_WQE_REACHED;
+               qp->ibqp.event_handler(&ev, qp->ibqp.qp_context);
+       }
+       if (mig) {
+               ev.device = qp->ibqp.device;
+               ev.element.qp = &qp->ibqp;
+               ev.event = IB_EVENT_PATH_MIG;
+               qp->ibqp.event_handler(&ev, qp->ibqp.qp_context);
+       }
+       ret = 0;
+       goto bail;
+
+inval:
+       spin_unlock(&qp->s_lock);
+       spin_unlock_irq(&qp->r_lock);
+       ret = -EINVAL;
+
+bail:
+       return ret;
+}
+
+int qib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+                int attr_mask, struct ib_qp_init_attr *init_attr)
+{
+       struct qib_qp *qp = to_iqp(ibqp);
+
+       attr->qp_state = qp->state;
+       attr->cur_qp_state = attr->qp_state;
+       attr->path_mtu = qp->path_mtu;
+       attr->path_mig_state = qp->s_mig_state;
+       attr->qkey = qp->qkey;
+       attr->rq_psn = qp->r_psn & QIB_PSN_MASK;
+       attr->sq_psn = qp->s_next_psn & QIB_PSN_MASK;
+       attr->dest_qp_num = qp->remote_qpn;
+       attr->qp_access_flags = qp->qp_access_flags;
+       attr->cap.max_send_wr = qp->s_size - 1;
+       attr->cap.max_recv_wr = qp->ibqp.srq ? 0 : qp->r_rq.size - 1;
+       attr->cap.max_send_sge = qp->s_max_sge;
+       attr->cap.max_recv_sge = qp->r_rq.max_sge;
+       attr->cap.max_inline_data = 0;
+       attr->ah_attr = qp->remote_ah_attr;
+       attr->alt_ah_attr = qp->alt_ah_attr;
+       attr->pkey_index = qp->s_pkey_index;
+       attr->alt_pkey_index = qp->s_alt_pkey_index;
+       attr->en_sqd_async_notify = 0;
+       attr->sq_draining = qp->s_draining;
+       attr->max_rd_atomic = qp->s_max_rd_atomic;
+       attr->max_dest_rd_atomic = qp->r_max_rd_atomic;
+       attr->min_rnr_timer = qp->r_min_rnr_timer;
+       attr->port_num = qp->port_num;
+       attr->timeout = qp->timeout;
+       attr->retry_cnt = qp->s_retry_cnt;
+       attr->rnr_retry = qp->s_rnr_retry_cnt;
+       attr->alt_port_num = qp->alt_ah_attr.port_num;
+       attr->alt_timeout = qp->alt_timeout;
+
+       init_attr->event_handler = qp->ibqp.event_handler;
+       init_attr->qp_context = qp->ibqp.qp_context;
+       init_attr->send_cq = qp->ibqp.send_cq;
+       init_attr->recv_cq = qp->ibqp.recv_cq;
+       init_attr->srq = qp->ibqp.srq;
+       init_attr->cap = attr->cap;
+       if (qp->s_flags & QIB_S_SIGNAL_REQ_WR)
+               init_attr->sq_sig_type = IB_SIGNAL_REQ_WR;
+       else
+               init_attr->sq_sig_type = IB_SIGNAL_ALL_WR;
+       init_attr->qp_type = qp->ibqp.qp_type;
+       init_attr->port_num = qp->port_num;
+       return 0;
+}
+
+/**
+ * qib_compute_aeth - compute the AETH (syndrome + MSN)
+ * @qp: the queue pair to compute the AETH for
+ *
+ * Returns the AETH.
+ */
+__be32 qib_compute_aeth(struct qib_qp *qp)
+{
+       u32 aeth = qp->r_msn & QIB_MSN_MASK;
+
+       if (qp->ibqp.srq) {
+               /*
+                * Shared receive queues don't generate credits.
+                * Set the credit field to the invalid value.
+                */
+               aeth |= QIB_AETH_CREDIT_INVAL << QIB_AETH_CREDIT_SHIFT;
+       } else {
+               u32 min, max, x;
+               u32 credits;
+               struct qib_rwq *wq = qp->r_rq.wq;
+               u32 head;
+               u32 tail;
+
+               /* sanity check pointers before trusting them */
+               head = wq->head;
+               if (head >= qp->r_rq.size)
+                       head = 0;
+               tail = wq->tail;
+               if (tail >= qp->r_rq.size)
+                       tail = 0;
+               /*
+                * Compute the number of credits available (RWQEs).
+                * XXX Not holding the r_rq.lock here so there is a small
+                * chance that the pair of reads are not atomic.
+                */
+               credits = head - tail;
+               if ((int)credits < 0)
+                       credits += qp->r_rq.size;
+               /*
+                * Binary search the credit table to find the code to
+                * use.
+                */
+               min = 0;
+               max = 31;
+               for (;;) {
+                       x = (min + max) / 2;
+                       if (credit_table[x] == credits)
+                               break;
+                       if (credit_table[x] > credits)
+                               max = x;
+                       else if (min == x)
+                               break;
+                       else
+                               min = x;
+               }
+               aeth |= x << QIB_AETH_CREDIT_SHIFT;
+       }
+       return cpu_to_be32(aeth);
+}
+
+/**
+ * qib_create_qp - create a queue pair for a device
+ * @ibpd: the protection domain who's device we create the queue pair for
+ * @init_attr: the attributes of the queue pair
+ * @udata: user data for libibverbs.so
+ *
+ * Returns the queue pair on success, otherwise returns an errno.
+ *
+ * Called by the ib_create_qp() core verbs function.
+ */
+struct ib_qp *qib_create_qp(struct ib_pd *ibpd,
+                           struct ib_qp_init_attr *init_attr,
+                           struct ib_udata *udata)
+{
+       struct qib_qp *qp;
+       int err;
+       struct qib_swqe *swq = NULL;
+       struct qib_ibdev *dev;
+       struct qib_devdata *dd;
+       size_t sz;
+       size_t sg_list_sz;
+       struct ib_qp *ret;
+
+       if (init_attr->cap.max_send_sge > ib_qib_max_sges ||
+           init_attr->cap.max_send_wr > ib_qib_max_qp_wrs) {
+               ret = ERR_PTR(-EINVAL);
+               goto bail;
+       }
+
+       /* Check receive queue parameters if no SRQ is specified. */
+       if (!init_attr->srq) {
+               if (init_attr->cap.max_recv_sge > ib_qib_max_sges ||
+                   init_attr->cap.max_recv_wr > ib_qib_max_qp_wrs) {
+                       ret = ERR_PTR(-EINVAL);
+                       goto bail;
+               }
+               if (init_attr->cap.max_send_sge +
+                   init_attr->cap.max_send_wr +
+                   init_attr->cap.max_recv_sge +
+                   init_attr->cap.max_recv_wr == 0) {
+                       ret = ERR_PTR(-EINVAL);
+                       goto bail;
+               }
+       }
+
+       switch (init_attr->qp_type) {
+       case IB_QPT_SMI:
+       case IB_QPT_GSI:
+               if (init_attr->port_num == 0 ||
+                   init_attr->port_num > ibpd->device->phys_port_cnt) {
+                       ret = ERR_PTR(-EINVAL);
+                       goto bail;
+               }
+       case IB_QPT_UC:
+       case IB_QPT_RC:
+       case IB_QPT_UD:
+               sz = sizeof(struct qib_sge) *
+                       init_attr->cap.max_send_sge +
+                       sizeof(struct qib_swqe);
+               swq = vmalloc((init_attr->cap.max_send_wr + 1) * sz);
+               if (swq == NULL) {
+                       ret = ERR_PTR(-ENOMEM);
+                       goto bail;
+               }
+               sz = sizeof(*qp);
+               sg_list_sz = 0;
+               if (init_attr->srq) {
+                       struct qib_srq *srq = to_isrq(init_attr->srq);
+
+                       if (srq->rq.max_sge > 1)
+                               sg_list_sz = sizeof(*qp->r_sg_list) *
+                                       (srq->rq.max_sge - 1);
+               } else if (init_attr->cap.max_recv_sge > 1)
+                       sg_list_sz = sizeof(*qp->r_sg_list) *
+                               (init_attr->cap.max_recv_sge - 1);
+               qp = kzalloc(sz + sg_list_sz, GFP_KERNEL);
+               if (!qp) {
+                       ret = ERR_PTR(-ENOMEM);
+                       goto bail_swq;
+               }
+               if (init_attr->srq)
+                       sz = 0;
+               else {
+                       qp->r_rq.size = init_attr->cap.max_recv_wr + 1;
+                       qp->r_rq.max_sge = init_attr->cap.max_recv_sge;
+                       sz = (sizeof(struct ib_sge) * qp->r_rq.max_sge) +
+                               sizeof(struct qib_rwqe);
+                       qp->r_rq.wq = vmalloc_user(sizeof(struct qib_rwq) +
+                                                  qp->r_rq.size * sz);
+                       if (!qp->r_rq.wq) {
+                               ret = ERR_PTR(-ENOMEM);
+                               goto bail_qp;
+                       }
+               }
+
+               /*
+                * ib_create_qp() will initialize qp->ibqp
+                * except for qp->ibqp.qp_num.
+                */
+               spin_lock_init(&qp->r_lock);
+               spin_lock_init(&qp->s_lock);
+               spin_lock_init(&qp->r_rq.lock);
+               atomic_set(&qp->refcount, 0);
+               init_waitqueue_head(&qp->wait);
+               init_waitqueue_head(&qp->wait_dma);
+               init_timer(&qp->s_timer);
+               qp->s_timer.data = (unsigned long)qp;
+               INIT_WORK(&qp->s_work, qib_do_send);
+               INIT_LIST_HEAD(&qp->iowait);
+               INIT_LIST_HEAD(&qp->rspwait);
+               qp->state = IB_QPS_RESET;
+               qp->s_wq = swq;
+               qp->s_size = init_attr->cap.max_send_wr + 1;
+               qp->s_max_sge = init_attr->cap.max_send_sge;
+               if (init_attr->sq_sig_type == IB_SIGNAL_REQ_WR)
+                       qp->s_flags = QIB_S_SIGNAL_REQ_WR;
+               dev = to_idev(ibpd->device);
+               dd = dd_from_dev(dev);
+               err = alloc_qpn(dd, &dev->qpn_table, init_attr->qp_type,
+                               init_attr->port_num);
+               if (err < 0) {
+                       ret = ERR_PTR(err);
+                       vfree(qp->r_rq.wq);
+                       goto bail_qp;
+               }
+               qp->ibqp.qp_num = err;
+               qp->port_num = init_attr->port_num;
+               qp->processor_id = smp_processor_id();
+               qib_reset_qp(qp, init_attr->qp_type);
+               break;
+
+       default:
+               /* Don't support raw QPs */
+               ret = ERR_PTR(-ENOSYS);
+               goto bail;
+       }
+
+       init_attr->cap.max_inline_data = 0;
+
+       /*
+        * Return the address of the RWQ as the offset to mmap.
+        * See qib_mmap() for details.
+        */
+       if (udata && udata->outlen >= sizeof(__u64)) {
+               if (!qp->r_rq.wq) {
+                       __u64 offset = 0;
+
+                       err = ib_copy_to_udata(udata, &offset,
+                                              sizeof(offset));
+                       if (err) {
+                               ret = ERR_PTR(err);
+                               goto bail_ip;
+                       }
+               } else {
+                       u32 s = sizeof(struct qib_rwq) + qp->r_rq.size * sz;
+
+                       qp->ip = qib_create_mmap_info(dev, s,
+                                                     ibpd->uobject->context,
+                                                     qp->r_rq.wq);
+                       if (!qp->ip) {
+                               ret = ERR_PTR(-ENOMEM);
+                               goto bail_ip;
+                       }
+
+                       err = ib_copy_to_udata(udata, &(qp->ip->offset),
+                                              sizeof(qp->ip->offset));
+                       if (err) {
+                               ret = ERR_PTR(err);
+                               goto bail_ip;
+                       }
+               }
+       }
+
+       spin_lock(&dev->n_qps_lock);
+       if (dev->n_qps_allocated == ib_qib_max_qps) {
+               spin_unlock(&dev->n_qps_lock);
+               ret = ERR_PTR(-ENOMEM);
+               goto bail_ip;
+       }
+
+       dev->n_qps_allocated++;
+       spin_unlock(&dev->n_qps_lock);
+
+       if (qp->ip) {
+               spin_lock_irq(&dev->pending_lock);
+               list_add(&qp->ip->pending_mmaps, &dev->pending_mmaps);
+               spin_unlock_irq(&dev->pending_lock);
+       }
+
+       ret = &qp->ibqp;
+       goto bail;
+
+bail_ip:
+       if (qp->ip)
+               kref_put(&qp->ip->ref, qib_release_mmap_info);
+       else
+               vfree(qp->r_rq.wq);
+       free_qpn(&dev->qpn_table, qp->ibqp.qp_num);
+bail_qp:
+       kfree(qp);
+bail_swq:
+       vfree(swq);
+bail:
+       return ret;
+}
+
+/**
+ * qib_destroy_qp - destroy a queue pair
+ * @ibqp: the queue pair to destroy
+ *
+ * Returns 0 on success.
+ *
+ * Note that this can be called while the QP is actively sending or
+ * receiving!
+ */
+int qib_destroy_qp(struct ib_qp *ibqp)
+{
+       struct qib_qp *qp = to_iqp(ibqp);
+       struct qib_ibdev *dev = to_idev(ibqp->device);
+
+       /* Make sure HW and driver activity is stopped. */
+       spin_lock_irq(&qp->s_lock);
+       if (qp->state != IB_QPS_RESET) {
+               qp->state = IB_QPS_RESET;
+               spin_lock(&dev->pending_lock);
+               if (!list_empty(&qp->iowait))
+                       list_del_init(&qp->iowait);
+               spin_unlock(&dev->pending_lock);
+               qp->s_flags &= ~(QIB_S_TIMER | QIB_S_ANY_WAIT);
+               spin_unlock_irq(&qp->s_lock);
+               cancel_work_sync(&qp->s_work);
+               del_timer_sync(&qp->s_timer);
+               wait_event(qp->wait_dma, !atomic_read(&qp->s_dma_busy));
+               if (qp->s_tx) {
+                       qib_put_txreq(qp->s_tx);
+                       qp->s_tx = NULL;
+               }
+               remove_qp(dev, qp);
+               wait_event(qp->wait, !atomic_read(&qp->refcount));
+               clear_mr_refs(qp, 1);
+       } else
+               spin_unlock_irq(&qp->s_lock);
+
+       /* all user's cleaned up, mark it available */
+       free_qpn(&dev->qpn_table, qp->ibqp.qp_num);
+       spin_lock(&dev->n_qps_lock);
+       dev->n_qps_allocated--;
+       spin_unlock(&dev->n_qps_lock);
+
+       if (qp->ip)
+               kref_put(&qp->ip->ref, qib_release_mmap_info);
+       else
+               vfree(qp->r_rq.wq);
+       vfree(qp->s_wq);
+       kfree(qp);
+       return 0;
+}
+
+/**
+ * qib_init_qpn_table - initialize the QP number table for a device
+ * @qpt: the QPN table
+ */
+void qib_init_qpn_table(struct qib_devdata *dd, struct qib_qpn_table *qpt)
+{
+       spin_lock_init(&qpt->lock);
+       qpt->last = 1;          /* start with QPN 2 */
+       qpt->nmaps = 1;
+       qpt->mask = dd->qpn_mask;
+}
+
+/**
+ * qib_free_qpn_table - free the QP number table for a device
+ * @qpt: the QPN table
+ */
+void qib_free_qpn_table(struct qib_qpn_table *qpt)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(qpt->map); i++)
+               if (qpt->map[i].page)
+                       free_page((unsigned long) qpt->map[i].page);
+}
+
+/**
+ * qib_get_credit - flush the send work queue of a QP
+ * @qp: the qp who's send work queue to flush
+ * @aeth: the Acknowledge Extended Transport Header
+ *
+ * The QP s_lock should be held.
+ */
+void qib_get_credit(struct qib_qp *qp, u32 aeth)
+{
+       u32 credit = (aeth >> QIB_AETH_CREDIT_SHIFT) & QIB_AETH_CREDIT_MASK;
+
+       /*
+        * If the credit is invalid, we can send
+        * as many packets as we like.  Otherwise, we have to
+        * honor the credit field.
+        */
+       if (credit == QIB_AETH_CREDIT_INVAL) {
+               if (!(qp->s_flags & QIB_S_UNLIMITED_CREDIT)) {
+                       qp->s_flags |= QIB_S_UNLIMITED_CREDIT;
+                       if (qp->s_flags & QIB_S_WAIT_SSN_CREDIT) {
+                               qp->s_flags &= ~QIB_S_WAIT_SSN_CREDIT;
+                               qib_schedule_send(qp);
+                       }
+               }
+       } else if (!(qp->s_flags & QIB_S_UNLIMITED_CREDIT)) {
+               /* Compute new LSN (i.e., MSN + credit) */
+               credit = (aeth + credit_table[credit]) & QIB_MSN_MASK;
+               if (qib_cmp24(credit, qp->s_lsn) > 0) {
+                       qp->s_lsn = credit;
+                       if (qp->s_flags & QIB_S_WAIT_SSN_CREDIT) {
+                               qp->s_flags &= ~QIB_S_WAIT_SSN_CREDIT;
+                               qib_schedule_send(qp);
+                       }
+               }
+       }
+}
diff --git a/drivers/infiniband/hw/qib/qib_qsfp.c b/drivers/infiniband/hw/qib/qib_qsfp.c
new file mode 100644 (file)
index 0000000..35b3604
--- /dev/null
@@ -0,0 +1,564 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved.
+ * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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/delay.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+
+#include "qib.h"
+#include "qib_qsfp.h"
+
+/*
+ * QSFP support for ib_qib driver, using "Two Wire Serial Interface" driver
+ * in qib_twsi.c
+ */
+#define QSFP_MAX_RETRY 4
+
+static int qsfp_read(struct qib_pportdata *ppd, int addr, void *bp, int len)
+{
+       struct qib_devdata *dd = ppd->dd;
+       u32 out, mask;
+       int ret, cnt, pass = 0;
+       int stuck = 0;
+       u8 *buff = bp;
+
+       ret = mutex_lock_interruptible(&dd->eep_lock);
+       if (ret)
+               goto no_unlock;
+
+       if (dd->twsi_eeprom_dev == QIB_TWSI_NO_DEV) {
+               ret = -ENXIO;
+               goto bail;
+       }
+
+       /*
+        * We presume, if we are called at all, that this board has
+        * QSFP. This is on the same i2c chain as the legacy parts,
+        * but only responds if the module is selected via GPIO pins.
+        * Further, there are very long setup and hold requirements
+        * on MODSEL.
+        */
+       mask = QSFP_GPIO_MOD_SEL_N | QSFP_GPIO_MOD_RST_N | QSFP_GPIO_LP_MODE;
+       out = QSFP_GPIO_MOD_RST_N | QSFP_GPIO_LP_MODE;
+       if (ppd->hw_pidx) {
+               mask <<= QSFP_GPIO_PORT2_SHIFT;
+               out <<= QSFP_GPIO_PORT2_SHIFT;
+       }
+
+       dd->f_gpio_mod(dd, out, mask, mask);
+
+       /*
+        * Module could take up to 2 Msec to respond to MOD_SEL, and there
+        * is no way to tell if it is ready, so we must wait.
+        */
+       msleep(2);
+
+       /* Make sure TWSI bus is in sane state. */
+       ret = qib_twsi_reset(dd);
+       if (ret) {
+               qib_dev_porterr(dd, ppd->port,
+                               "QSFP interface Reset for read failed\n");
+               ret = -EIO;
+               stuck = 1;
+               goto deselect;
+       }
+
+       /* All QSFP modules are at A0 */
+
+       cnt = 0;
+       while (cnt < len) {
+               unsigned in_page;
+               int wlen = len - cnt;
+               in_page = addr % QSFP_PAGESIZE;
+               if ((in_page + wlen) > QSFP_PAGESIZE)
+                       wlen = QSFP_PAGESIZE - in_page;
+               ret = qib_twsi_blk_rd(dd, QSFP_DEV, addr, buff + cnt, wlen);
+               /* Some QSFP's fail first try. Retry as experiment */
+               if (ret && cnt == 0 && ++pass < QSFP_MAX_RETRY)
+                       continue;
+               if (ret) {
+                       /* qib_twsi_blk_rd() 1 for error, else 0 */
+                       ret = -EIO;
+                       goto deselect;
+               }
+               addr += wlen;
+               cnt += wlen;
+       }
+       ret = cnt;
+
+deselect:
+       /*
+        * Module could take up to 10 uSec after transfer before
+        * ready to respond to MOD_SEL negation, and there is no way
+        * to tell if it is ready, so we must wait.
+        */
+       udelay(10);
+       /* set QSFP MODSEL, RST. LP all high */
+       dd->f_gpio_mod(dd, mask, mask, mask);
+
+       /*
+        * Module could take up to 2 Msec to respond to MOD_SEL
+        * going away, and there is no way to tell if it is ready.
+        * so we must wait.
+        */
+       if (stuck)
+               qib_dev_err(dd, "QSFP interface bus stuck non-idle\n");
+
+       if (pass >= QSFP_MAX_RETRY && ret)
+               qib_dev_porterr(dd, ppd->port, "QSFP failed even retrying\n");
+       else if (pass)
+               qib_dev_porterr(dd, ppd->port, "QSFP retries: %d\n", pass);
+
+       msleep(2);
+
+bail:
+       mutex_unlock(&dd->eep_lock);
+
+no_unlock:
+       return ret;
+}
+
+/*
+ * qsfp_write
+ * We do not ordinarily write the QSFP, but this is needed to select
+ * the page on non-flat QSFPs, and possibly later unusual cases
+ */
+static int qib_qsfp_write(struct qib_pportdata *ppd, int addr, void *bp,
+                         int len)
+{
+       struct qib_devdata *dd = ppd->dd;
+       u32 out, mask;
+       int ret, cnt;
+       u8 *buff = bp;
+
+       ret = mutex_lock_interruptible(&dd->eep_lock);
+       if (ret)
+               goto no_unlock;
+
+       if (dd->twsi_eeprom_dev == QIB_TWSI_NO_DEV) {
+               ret = -ENXIO;
+               goto bail;
+       }
+
+       /*
+        * We presume, if we are called at all, that this board has
+        * QSFP. This is on the same i2c chain as the legacy parts,
+        * but only responds if the module is selected via GPIO pins.
+        * Further, there are very long setup and hold requirements
+        * on MODSEL.
+        */
+       mask = QSFP_GPIO_MOD_SEL_N | QSFP_GPIO_MOD_RST_N | QSFP_GPIO_LP_MODE;
+       out = QSFP_GPIO_MOD_RST_N | QSFP_GPIO_LP_MODE;
+       if (ppd->hw_pidx) {
+               mask <<= QSFP_GPIO_PORT2_SHIFT;
+               out <<= QSFP_GPIO_PORT2_SHIFT;
+       }
+       dd->f_gpio_mod(dd, out, mask, mask);
+
+       /*
+        * Module could take up to 2 Msec to respond to MOD_SEL,
+        * and there is no way to tell if it is ready, so we must wait.
+        */
+       msleep(2);
+
+       /* Make sure TWSI bus is in sane state. */
+       ret = qib_twsi_reset(dd);
+       if (ret) {
+               qib_dev_porterr(dd, ppd->port,
+                               "QSFP interface Reset for write failed\n");
+               ret = -EIO;
+               goto deselect;
+       }
+
+       /* All QSFP modules are at A0 */
+
+       cnt = 0;
+       while (cnt < len) {
+               unsigned in_page;
+               int wlen = len - cnt;
+               in_page = addr % QSFP_PAGESIZE;
+               if ((in_page + wlen) > QSFP_PAGESIZE)
+                       wlen = QSFP_PAGESIZE - in_page;
+               ret = qib_twsi_blk_wr(dd, QSFP_DEV, addr, buff + cnt, wlen);
+               if (ret) {
+                       /* qib_twsi_blk_wr() 1 for error, else 0 */
+                       ret = -EIO;
+                       goto deselect;
+               }
+               addr += wlen;
+               cnt += wlen;
+       }
+       ret = cnt;
+
+deselect:
+       /*
+        * Module could take up to 10 uSec after transfer before
+        * ready to respond to MOD_SEL negation, and there is no way
+        * to tell if it is ready, so we must wait.
+        */
+       udelay(10);
+       /* set QSFP MODSEL, RST, LP high */
+       dd->f_gpio_mod(dd, mask, mask, mask);
+       /*
+        * Module could take up to 2 Msec to respond to MOD_SEL
+        * going away, and there is no way to tell if it is ready.
+        * so we must wait.
+        */
+       msleep(2);
+
+bail:
+       mutex_unlock(&dd->eep_lock);
+
+no_unlock:
+       return ret;
+}
+
+/*
+ * For validation, we want to check the checksums, even of the
+ * fields we do not otherwise use. This function reads the bytes from
+ * <first> to <next-1> and returns the 8lsbs of the sum, or <0 for errors
+ */
+static int qsfp_cks(struct qib_pportdata *ppd, int first, int next)
+{
+       int ret;
+       u16 cks;
+       u8 bval;
+
+       cks = 0;
+       while (first < next) {
+               ret = qsfp_read(ppd, first, &bval, 1);
+               if (ret < 0)
+                       goto bail;
+               cks += bval;
+               ++first;
+       }
+       ret = cks & 0xFF;
+bail:
+       return ret;
+
+}
+
+int qib_refresh_qsfp_cache(struct qib_pportdata *ppd, struct qib_qsfp_cache *cp)
+{
+       int ret;
+       int idx;
+       u16 cks;
+       u32 mask;
+       u8 peek[4];
+
+       /* ensure sane contents on invalid reads, for cable swaps */
+       memset(cp, 0, sizeof(*cp));
+
+       mask = QSFP_GPIO_MOD_PRS_N;
+       if (ppd->hw_pidx)
+               mask <<= QSFP_GPIO_PORT2_SHIFT;
+
+       ret = ppd->dd->f_gpio_mod(ppd->dd, 0, 0, 0);
+       if (ret & mask) {
+               ret = -ENODEV;
+               goto bail;
+       }
+
+       ret = qsfp_read(ppd, 0, peek, 3);
+       if (ret < 0)
+               goto bail;
+       if ((peek[0] & 0xFE) != 0x0C)
+               qib_dev_porterr(ppd->dd, ppd->port,
+                               "QSFP byte0 is 0x%02X, S/B 0x0C/D\n", peek[0]);
+
+       if ((peek[2] & 2) == 0) {
+               /*
+                * If cable is paged, rather than "flat memory", we need to
+                * set the page to zero, Even if it already appears to be zero.
+                */
+               u8 poke = 0;
+               ret = qib_qsfp_write(ppd, 127, &poke, 1);
+               udelay(50);
+               if (ret != 1) {
+                       qib_dev_porterr(ppd->dd, ppd->port,
+                                       "Failed QSFP Page set\n");
+                       goto bail;
+               }
+       }
+
+       ret = qsfp_read(ppd, QSFP_MOD_ID_OFFS, &cp->id, 1);
+       if (ret < 0)
+               goto bail;
+       if ((cp->id & 0xFE) != 0x0C)
+               qib_dev_porterr(ppd->dd, ppd->port,
+                               "QSFP ID byte is 0x%02X, S/B 0x0C/D\n", cp->id);
+       cks = cp->id;
+
+       ret = qsfp_read(ppd, QSFP_MOD_PWR_OFFS, &cp->pwr, 1);
+       if (ret < 0)
+               goto bail;
+       cks += cp->pwr;
+
+       ret = qsfp_cks(ppd, QSFP_MOD_PWR_OFFS + 1, QSFP_MOD_LEN_OFFS);
+       if (ret < 0)
+               goto bail;
+       cks += ret;
+
+       ret = qsfp_read(ppd, QSFP_MOD_LEN_OFFS, &cp->len, 1);
+       if (ret < 0)
+               goto bail;
+       cks += cp->len;
+
+       ret = qsfp_read(ppd, QSFP_MOD_TECH_OFFS, &cp->tech, 1);
+       if (ret < 0)
+               goto bail;
+       cks += cp->tech;
+
+       ret = qsfp_read(ppd, QSFP_VEND_OFFS, &cp->vendor, QSFP_VEND_LEN);
+       if (ret < 0)
+               goto bail;
+       for (idx = 0; idx < QSFP_VEND_LEN; ++idx)
+               cks += cp->vendor[idx];
+
+       ret = qsfp_read(ppd, QSFP_IBXCV_OFFS, &cp->xt_xcv, 1);
+       if (ret < 0)
+               goto bail;
+       cks += cp->xt_xcv;
+
+       ret = qsfp_read(ppd, QSFP_VOUI_OFFS, &cp->oui, QSFP_VOUI_LEN);
+       if (ret < 0)
+               goto bail;
+       for (idx = 0; idx < QSFP_VOUI_LEN; ++idx)
+               cks += cp->oui[idx];
+
+       ret = qsfp_read(ppd, QSFP_PN_OFFS, &cp->partnum, QSFP_PN_LEN);
+       if (ret < 0)
+               goto bail;
+       for (idx = 0; idx < QSFP_PN_LEN; ++idx)
+               cks += cp->partnum[idx];
+
+       ret = qsfp_read(ppd, QSFP_REV_OFFS, &cp->rev, QSFP_REV_LEN);
+       if (ret < 0)
+               goto bail;
+       for (idx = 0; idx < QSFP_REV_LEN; ++idx)
+               cks += cp->rev[idx];
+
+       ret = qsfp_read(ppd, QSFP_ATTEN_OFFS, &cp->atten, QSFP_ATTEN_LEN);
+       if (ret < 0)
+               goto bail;
+       for (idx = 0; idx < QSFP_ATTEN_LEN; ++idx)
+               cks += cp->atten[idx];
+
+       ret = qsfp_cks(ppd, QSFP_ATTEN_OFFS + QSFP_ATTEN_LEN, QSFP_CC_OFFS);
+       if (ret < 0)
+               goto bail;
+       cks += ret;
+
+       cks &= 0xFF;
+       ret = qsfp_read(ppd, QSFP_CC_OFFS, &cp->cks1, 1);
+       if (ret < 0)
+               goto bail;
+       if (cks != cp->cks1)
+               qib_dev_porterr(ppd->dd, ppd->port,
+                               "QSFP cks1 is %02X, computed %02X\n", cp->cks1,
+                               cks);
+
+       /* Second checksum covers 192 to (serial, date, lot) */
+       ret = qsfp_cks(ppd, QSFP_CC_OFFS + 1, QSFP_SN_OFFS);
+       if (ret < 0)
+               goto bail;
+       cks = ret;
+
+       ret = qsfp_read(ppd, QSFP_SN_OFFS, &cp->serial, QSFP_SN_LEN);
+       if (ret < 0)
+               goto bail;
+       for (idx = 0; idx < QSFP_SN_LEN; ++idx)
+               cks += cp->serial[idx];
+
+       ret = qsfp_read(ppd, QSFP_DATE_OFFS, &cp->date, QSFP_DATE_LEN);
+       if (ret < 0)
+               goto bail;
+       for (idx = 0; idx < QSFP_DATE_LEN; ++idx)
+               cks += cp->date[idx];
+
+       ret = qsfp_read(ppd, QSFP_LOT_OFFS, &cp->lot, QSFP_LOT_LEN);
+       if (ret < 0)
+               goto bail;
+       for (idx = 0; idx < QSFP_LOT_LEN; ++idx)
+               cks += cp->lot[idx];
+
+       ret = qsfp_cks(ppd, QSFP_LOT_OFFS + QSFP_LOT_LEN, QSFP_CC_EXT_OFFS);
+       if (ret < 0)
+               goto bail;
+       cks += ret;
+
+       ret = qsfp_read(ppd, QSFP_CC_EXT_OFFS, &cp->cks2, 1);
+       if (ret < 0)
+               goto bail;
+       cks &= 0xFF;
+       if (cks != cp->cks2)
+               qib_dev_porterr(ppd->dd, ppd->port,
+                               "QSFP cks2 is %02X, computed %02X\n", cp->cks2,
+                               cks);
+       return 0;
+
+bail:
+       cp->id = 0;
+       return ret;
+}
+
+const char * const qib_qsfp_devtech[16] = {
+       "850nm VCSEL", "1310nm VCSEL", "1550nm VCSEL", "1310nm FP",
+       "1310nm DFB", "1550nm DFB", "1310nm EML", "1550nm EML",
+       "Cu Misc", "1490nm DFB", "Cu NoEq", "Cu Eq",
+       "Undef", "Cu Active BothEq", "Cu FarEq", "Cu NearEq"
+};
+
+#define QSFP_DUMP_CHUNK 16 /* Holds longest string */
+#define QSFP_DEFAULT_HDR_CNT 224
+
+static const char *pwr_codes = "1.5W2.0W2.5W3.5W";
+
+/*
+ * Initialize structures that control access to QSFP. Called once per port
+ * on cards that support QSFP.
+ */
+void qib_qsfp_init(struct qib_qsfp_data *qd,
+                  void (*fevent)(struct work_struct *))
+{
+       u32 mask, highs;
+       int pins;
+
+       struct qib_devdata *dd = qd->ppd->dd;
+
+       /* Initialize work struct for later QSFP events */
+       INIT_WORK(&qd->work, fevent);
+
+       /*
+        * Later, we may want more validation. For now, just set up pins and
+        * blip reset. If module is present, call qib_refresh_qsfp_cache(),
+        * to do further init.
+        */
+       mask = QSFP_GPIO_MOD_SEL_N | QSFP_GPIO_MOD_RST_N | QSFP_GPIO_LP_MODE;
+       highs = mask - QSFP_GPIO_MOD_RST_N;
+       if (qd->ppd->hw_pidx) {
+               mask <<= QSFP_GPIO_PORT2_SHIFT;
+               highs <<= QSFP_GPIO_PORT2_SHIFT;
+       }
+       dd->f_gpio_mod(dd, highs, mask, mask);
+       udelay(20); /* Generous RST dwell */
+
+       dd->f_gpio_mod(dd, mask, mask, mask);
+       /* Spec says module can take up to two seconds! */
+       mask = QSFP_GPIO_MOD_PRS_N;
+       if (qd->ppd->hw_pidx)
+               mask <<= QSFP_GPIO_PORT2_SHIFT;
+
+       /* Do not try to wait here. Better to let event handle it */
+       pins = dd->f_gpio_mod(dd, 0, 0, 0);
+       if (pins & mask)
+               goto bail;
+       /* We see a module, but it may be unwise to look yet. Just schedule */
+       qd->t_insert = get_jiffies_64();
+       schedule_work(&qd->work);
+bail:
+       return;
+}
+
+void qib_qsfp_deinit(struct qib_qsfp_data *qd)
+{
+       /*
+        * There is nothing to do here for now.  our
+        * work is scheduled with schedule_work(), and
+        * flush_scheduled_work() from remove_one will
+        * block until all work ssetup with schedule_work()
+        * completes.
+        */
+}
+
+int qib_qsfp_dump(struct qib_pportdata *ppd, char *buf, int len)
+{
+       struct qib_qsfp_cache cd;
+       u8 bin_buff[QSFP_DUMP_CHUNK];
+       char lenstr[6];
+       int sofar, ret;
+       int bidx = 0;
+
+       sofar = 0;
+       ret = qib_refresh_qsfp_cache(ppd, &cd);
+       if (ret < 0)
+               goto bail;
+
+       lenstr[0] = ' ';
+       lenstr[1] = '\0';
+       if (QSFP_IS_CU(cd.tech))
+               sprintf(lenstr, "%dM ", cd.len);
+
+       sofar += scnprintf(buf + sofar, len - sofar, "PWR:%.3sW\n", pwr_codes +
+                          (QSFP_PWR(cd.pwr) * 4));
+
+       sofar += scnprintf(buf + sofar, len - sofar, "TECH:%s%s\n", lenstr,
+                          qib_qsfp_devtech[cd.tech >> 4]);
+
+       sofar += scnprintf(buf + sofar, len - sofar, "Vendor:%.*s\n",
+                          QSFP_VEND_LEN, cd.vendor);
+
+       sofar += scnprintf(buf + sofar, len - sofar, "OUI:%06X\n",
+                          QSFP_OUI(cd.oui));
+
+       sofar += scnprintf(buf + sofar, len - sofar, "Part#:%.*s\n",
+                          QSFP_PN_LEN, cd.partnum);
+       sofar += scnprintf(buf + sofar, len - sofar, "Rev:%.*s\n",
+                          QSFP_REV_LEN, cd.rev);
+       if (QSFP_IS_CU(cd.tech))
+               sofar += scnprintf(buf + sofar, len - sofar, "Atten:%d, %d\n",
+                                  QSFP_ATTEN_SDR(cd.atten),
+                                  QSFP_ATTEN_DDR(cd.atten));
+       sofar += scnprintf(buf + sofar, len - sofar, "Serial:%.*s\n",
+                          QSFP_SN_LEN, cd.serial);
+       sofar += scnprintf(buf + sofar, len - sofar, "Date:%.*s\n",
+                          QSFP_DATE_LEN, cd.date);
+       sofar += scnprintf(buf + sofar, len - sofar, "Lot:%.*s\n",
+                          QSFP_LOT_LEN, cd.date);
+
+       while (bidx < QSFP_DEFAULT_HDR_CNT) {
+               int iidx;
+               ret = qsfp_read(ppd, bidx, bin_buff, QSFP_DUMP_CHUNK);
+               if (ret < 0)
+                       goto bail;
+               for (iidx = 0; iidx < ret; ++iidx) {
+                       sofar += scnprintf(buf + sofar, len-sofar, " %02X",
+                               bin_buff[iidx]);
+               }
+               sofar += scnprintf(buf + sofar, len - sofar, "\n");
+               bidx += QSFP_DUMP_CHUNK;
+       }
+       ret = sofar;
+bail:
+       return ret;
+}
diff --git a/drivers/infiniband/hw/qib/qib_qsfp.h b/drivers/infiniband/hw/qib/qib_qsfp.h
new file mode 100644 (file)
index 0000000..19b527b
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved.
+ * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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.
+ */
+/* QSFP support common definitions, for ib_qib driver */
+
+#define QSFP_DEV 0xA0
+#define QSFP_PWR_LAG_MSEC 2000
+
+/*
+ * Below are masks for various QSFP signals, for Port 1.
+ * Port2 equivalents are shifted by QSFP_GPIO_PORT2_SHIFT.
+ * _N means asserted low
+ */
+#define QSFP_GPIO_MOD_SEL_N (4)
+#define QSFP_GPIO_MOD_PRS_N (8)
+#define QSFP_GPIO_INT_N (0x10)
+#define QSFP_GPIO_MOD_RST_N (0x20)
+#define QSFP_GPIO_LP_MODE (0x40)
+#define QSFP_GPIO_PORT2_SHIFT 5
+
+#define QSFP_PAGESIZE 128
+/* Defined fields that QLogic requires of qualified cables */
+/* Byte 0 is Identifier, not checked */
+/* Byte 1 is reserved "status MSB" */
+/* Byte 2 is "status LSB" We only care that D2 "Flat Mem" is set. */
+/*
+ * Rest of first 128 not used, although 127 is reserved for page select
+ * if module is not "Flat memory".
+ */
+/* Byte 128 is Identifier: must be 0x0c for QSFP, or 0x0d for QSFP+ */
+#define QSFP_MOD_ID_OFFS 128
+/*
+ * Byte 129 is "Extended Identifier". We only care about D7,D6: Power class
+ *  0:1.5W, 1:2.0W, 2:2.5W, 3:3.5W
+ */
+#define QSFP_MOD_PWR_OFFS 129
+/* Byte 130 is Connector type. Not QLogic req'd */
+/* Bytes 131..138 are Transceiver types, bit maps for various tech, none IB */
+/* Byte 139 is encoding. code 0x01 is 8b10b. Not QLogic req'd */
+/* byte 140 is nominal bit-rate, in units of 100Mbits/sec Not QLogic req'd */
+/* Byte 141 is Extended Rate Select. Not QLogic req'd */
+/* Bytes 142..145 are lengths for various fiber types. Not QLogic req'd */
+/* Byte 146 is length for Copper. Units of 1 meter */
+#define QSFP_MOD_LEN_OFFS 146
+/*
+ * Byte 147 is Device technology. D0..3 not Qlogc req'd
+ * D4..7 select from 15 choices, translated by table:
+ */
+#define QSFP_MOD_TECH_OFFS 147
+extern const char *const qib_qsfp_devtech[16];
+/* Active Equalization includes fiber, copper full EQ, and copper near Eq */
+#define QSFP_IS_ACTIVE(tech) ((0xA2FF >> ((tech) >> 4)) & 1)
+/* Attenuation should be valid for copper other than full/near Eq */
+#define QSFP_HAS_ATTEN(tech) ((0x4D00 >> ((tech) >> 4)) & 1)
+/* Length is only valid if technology is "copper" */
+#define QSFP_IS_CU(tech) ((0xED00 >> ((tech) >> 4)) & 1)
+#define QSFP_TECH_1490 9
+
+#define QSFP_OUI(oui) (((unsigned)oui[0] << 16) | ((unsigned)oui[1] << 8) | \
+                       oui[2])
+#define QSFP_OUI_AMPHENOL 0x415048
+#define QSFP_OUI_FINISAR  0x009065
+#define QSFP_OUI_GORE     0x002177
+
+/* Bytes 148..163 are Vendor Name, Left-justified Blank-filled */
+#define QSFP_VEND_OFFS 148
+#define QSFP_VEND_LEN 16
+/* Byte 164 is IB Extended tranceiver codes Bits D0..3 are SDR,DDR,QDR,EDR */
+#define QSFP_IBXCV_OFFS 164
+/* Bytes 165..167 are Vendor OUI number */
+#define QSFP_VOUI_OFFS 165
+#define QSFP_VOUI_LEN 3
+/* Bytes 168..183 are Vendor Part Number, string */
+#define QSFP_PN_OFFS 168
+#define QSFP_PN_LEN 16
+/* Bytes 184,185 are Vendor Rev. Left Justified, Blank-filled */
+#define QSFP_REV_OFFS 184
+#define QSFP_REV_LEN 2
+/*
+ * Bytes 186,187 are Wavelength, if Optical. Not Qlogic req'd
+ *  If copper, they are attenuation in dB:
+ * Byte 186 is at 2.5Gb/sec (SDR), Byte 187 at 5.0Gb/sec (DDR)
+ */
+#define QSFP_ATTEN_OFFS 186
+#define QSFP_ATTEN_LEN 2
+/* Bytes 188,189 are Wavelength tolerance, not QLogic req'd */
+/* Byte 190 is Max Case Temp. Not QLogic req'd */
+/* Byte 191 is LSB of sum of bytes 128..190. Not QLogic req'd */
+#define QSFP_CC_OFFS 191
+/* Bytes 192..195 are Options implemented in qsfp. Not Qlogic req'd */
+/* Bytes 196..211 are Serial Number, String */
+#define QSFP_SN_OFFS 196
+#define QSFP_SN_LEN 16
+/* Bytes 212..219 are date-code YYMMDD (MM==1 for Jan) */
+#define QSFP_DATE_OFFS 212
+#define QSFP_DATE_LEN 6
+/* Bytes 218,219 are optional lot-code, string */
+#define QSFP_LOT_OFFS 218
+#define QSFP_LOT_LEN 2
+/* Bytes 220, 221 indicate monitoring options, Not QLogic req'd */
+/* Byte 223 is LSB of sum of bytes 192..222 */
+#define QSFP_CC_EXT_OFFS 223
+
+/*
+ * struct qib_qsfp_data encapsulates state of QSFP device for one port.
+ * it will be part of port-chip-specific data if a board supports QSFP.
+ *
+ * Since multiple board-types use QSFP, and their pport_data structs
+ * differ (in the chip-specific section), we need a pointer to its head.
+ *
+ * Avoiding premature optimization, we will have one work_struct per port,
+ * and let the (increasingly inaccurately named) eep_lock arbitrate
+ * access to common resources.
+ *
+ */
+
+/*
+ * Hold the parts of the onboard EEPROM that we care about, so we aren't
+ * coonstantly bit-boffing
+ */
+struct qib_qsfp_cache {
+       u8 id;  /* must be 0x0C or 0x0D; 0 indicates invalid EEPROM read */
+       u8 pwr; /* in D6,7 */
+       u8 len; /* in meters, Cu only */
+       u8 tech;
+       char vendor[QSFP_VEND_LEN];
+       u8 xt_xcv; /* Ext. tranceiver codes, 4 lsbs are IB speed supported */
+       u8 oui[QSFP_VOUI_LEN];
+       u8 partnum[QSFP_PN_LEN];
+       u8 rev[QSFP_REV_LEN];
+       u8 atten[QSFP_ATTEN_LEN];
+       u8 cks1;        /* Checksum of bytes 128..190 */
+       u8 serial[QSFP_SN_LEN];
+       u8 date[QSFP_DATE_LEN];
+       u8 lot[QSFP_LOT_LEN];
+       u8 cks2;        /* Checsum of bytes 192..222 */
+};
+
+#define QSFP_PWR(pbyte) (((pbyte) >> 6) & 3)
+#define QSFP_ATTEN_SDR(attenarray) (attenarray[0])
+#define QSFP_ATTEN_DDR(attenarray) (attenarray[1])
+
+struct qib_qsfp_data {
+       /* Helps to find our way */
+       struct qib_pportdata *ppd;
+       struct work_struct work;
+       struct qib_qsfp_cache cache;
+       u64 t_insert;
+};
+
+extern int qib_refresh_qsfp_cache(struct qib_pportdata *ppd,
+                                 struct qib_qsfp_cache *cp);
+extern void qib_qsfp_init(struct qib_qsfp_data *qd,
+                         void (*fevent)(struct work_struct *));
+extern void qib_qsfp_deinit(struct qib_qsfp_data *qd);
diff --git a/drivers/infiniband/hw/qib/qib_rc.c b/drivers/infiniband/hw/qib/qib_rc.c
new file mode 100644 (file)
index 0000000..40c0a37
--- /dev/null
@@ -0,0 +1,2288 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved.
+ * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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/io.h>
+
+#include "qib.h"
+
+/* cut down ridiculously long IB macro names */
+#define OP(x) IB_OPCODE_RC_##x
+
+static void rc_timeout(unsigned long arg);
+
+static u32 restart_sge(struct qib_sge_state *ss, struct qib_swqe *wqe,
+                      u32 psn, u32 pmtu)
+{
+       u32 len;
+
+       len = ((psn - wqe->psn) & QIB_PSN_MASK) * pmtu;
+       ss->sge = wqe->sg_list[0];
+       ss->sg_list = wqe->sg_list + 1;
+       ss->num_sge = wqe->wr.num_sge;
+       ss->total_len = wqe->length;
+       qib_skip_sge(ss, len, 0);
+       return wqe->length - len;
+}
+
+static void start_timer(struct qib_qp *qp)
+{
+       qp->s_flags |= QIB_S_TIMER;
+       qp->s_timer.function = rc_timeout;
+       /* 4.096 usec. * (1 << qp->timeout) */
+       qp->s_timer.expires = jiffies +
+               usecs_to_jiffies((4096UL * (1UL << qp->timeout)) / 1000UL);
+       add_timer(&qp->s_timer);
+}
+
+/**
+ * qib_make_rc_ack - construct a response packet (ACK, NAK, or RDMA read)
+ * @dev: the device for this QP
+ * @qp: a pointer to the QP
+ * @ohdr: a pointer to the IB header being constructed
+ * @pmtu: the path MTU
+ *
+ * Return 1 if constructed; otherwise, return 0.
+ * Note that we are in the responder's side of the QP context.
+ * Note the QP s_lock must be held.
+ */
+static int qib_make_rc_ack(struct qib_ibdev *dev, struct qib_qp *qp,
+                          struct qib_other_headers *ohdr, u32 pmtu)
+{
+       struct qib_ack_entry *e;
+       u32 hwords;
+       u32 len;
+       u32 bth0;
+       u32 bth2;
+
+       /* Don't send an ACK if we aren't supposed to. */
+       if (!(ib_qib_state_ops[qp->state] & QIB_PROCESS_RECV_OK))
+               goto bail;
+
+       /* header size in 32-bit words LRH+BTH = (8+12)/4. */
+       hwords = 5;
+
+       switch (qp->s_ack_state) {
+       case OP(RDMA_READ_RESPONSE_LAST):
+       case OP(RDMA_READ_RESPONSE_ONLY):
+               e = &qp->s_ack_queue[qp->s_tail_ack_queue];
+               if (e->rdma_sge.mr) {
+                       atomic_dec(&e->rdma_sge.mr->refcount);
+                       e->rdma_sge.mr = NULL;
+               }
+               /* FALLTHROUGH */
+       case OP(ATOMIC_ACKNOWLEDGE):
+               /*
+                * We can increment the tail pointer now that the last
+                * response has been sent instead of only being
+                * constructed.
+                */
+               if (++qp->s_tail_ack_queue > QIB_MAX_RDMA_ATOMIC)
+                       qp->s_tail_ack_queue = 0;
+               /* FALLTHROUGH */
+       case OP(SEND_ONLY):
+       case OP(ACKNOWLEDGE):
+               /* Check for no next entry in the queue. */
+               if (qp->r_head_ack_queue == qp->s_tail_ack_queue) {
+                       if (qp->s_flags & QIB_S_ACK_PENDING)
+                               goto normal;
+                       goto bail;
+               }
+
+               e = &qp->s_ack_queue[qp->s_tail_ack_queue];
+               if (e->opcode == OP(RDMA_READ_REQUEST)) {
+                       /*
+                        * If a RDMA read response is being resent and
+                        * we haven't seen the duplicate request yet,
+                        * then stop sending the remaining responses the
+                        * responder has seen until the requester resends it.
+                        */
+                       len = e->rdma_sge.sge_length;
+                       if (len && !e->rdma_sge.mr) {
+                               qp->s_tail_ack_queue = qp->r_head_ack_queue;
+                               goto bail;
+                       }
+                       /* Copy SGE state in case we need to resend */
+                       qp->s_rdma_mr = e->rdma_sge.mr;
+                       if (qp->s_rdma_mr)
+                               atomic_inc(&qp->s_rdma_mr->refcount);
+                       qp->s_ack_rdma_sge.sge = e->rdma_sge;
+                       qp->s_ack_rdma_sge.num_sge = 1;
+                       qp->s_cur_sge = &qp->s_ack_rdma_sge;
+                       if (len > pmtu) {
+                               len = pmtu;
+                               qp->s_ack_state = OP(RDMA_READ_RESPONSE_FIRST);
+                       } else {
+                               qp->s_ack_state = OP(RDMA_READ_RESPONSE_ONLY);
+                               e->sent = 1;
+                       }
+                       ohdr->u.aeth = qib_compute_aeth(qp);
+                       hwords++;
+                       qp->s_ack_rdma_psn = e->psn;
+                       bth2 = qp->s_ack_rdma_psn++ & QIB_PSN_MASK;
+               } else {
+                       /* COMPARE_SWAP or FETCH_ADD */
+                       qp->s_cur_sge = NULL;
+                       len = 0;
+                       qp->s_ack_state = OP(ATOMIC_ACKNOWLEDGE);
+                       ohdr->u.at.aeth = qib_compute_aeth(qp);
+                       ohdr->u.at.atomic_ack_eth[0] =
+                               cpu_to_be32(e->atomic_data >> 32);
+                       ohdr->u.at.atomic_ack_eth[1] =
+                               cpu_to_be32(e->atomic_data);
+                       hwords += sizeof(ohdr->u.at) / sizeof(u32);
+                       bth2 = e->psn & QIB_PSN_MASK;
+                       e->sent = 1;
+               }
+               bth0 = qp->s_ack_state << 24;
+               break;
+
+       case OP(RDMA_READ_RESPONSE_FIRST):
+               qp->s_ack_state = OP(RDMA_READ_RESPONSE_MIDDLE);
+               /* FALLTHROUGH */
+       case OP(RDMA_READ_RESPONSE_MIDDLE):
+               qp->s_cur_sge = &qp->s_ack_rdma_sge;
+               qp->s_rdma_mr = qp->s_ack_rdma_sge.sge.mr;
+               if (qp->s_rdma_mr)
+                       atomic_inc(&qp->s_rdma_mr->refcount);
+               len = qp->s_ack_rdma_sge.sge.sge_length;
+               if (len > pmtu)
+                       len = pmtu;
+               else {
+                       ohdr->u.aeth = qib_compute_aeth(qp);
+                       hwords++;
+                       qp->s_ack_state = OP(RDMA_READ_RESPONSE_LAST);
+                       e = &qp->s_ack_queue[qp->s_tail_ack_queue];
+                       e->sent = 1;
+               }
+               bth0 = qp->s_ack_state << 24;
+               bth2 = qp->s_ack_rdma_psn++ & QIB_PSN_MASK;
+               break;
+
+       default:
+normal:
+               /*
+                * Send a regular ACK.
+                * Set the s_ack_state so we wait until after sending
+                * the ACK before setting s_ack_state to ACKNOWLEDGE
+                * (see above).
+                */
+               qp->s_ack_state = OP(SEND_ONLY);
+               qp->s_flags &= ~QIB_S_ACK_PENDING;
+               qp->s_cur_sge = NULL;
+               if (qp->s_nak_state)
+                       ohdr->u.aeth =
+                               cpu_to_be32((qp->r_msn & QIB_MSN_MASK) |
+                                           (qp->s_nak_state <<
+                                            QIB_AETH_CREDIT_SHIFT));
+               else
+                       ohdr->u.aeth = qib_compute_aeth(qp);
+               hwords++;
+               len = 0;
+               bth0 = OP(ACKNOWLEDGE) << 24;
+               bth2 = qp->s_ack_psn & QIB_PSN_MASK;
+       }
+       qp->s_rdma_ack_cnt++;
+       qp->s_hdrwords = hwords;
+       qp->s_cur_size = len;
+       qib_make_ruc_header(qp, ohdr, bth0, bth2);
+       return 1;
+
+bail:
+       qp->s_ack_state = OP(ACKNOWLEDGE);
+       qp->s_flags &= ~(QIB_S_RESP_PENDING | QIB_S_ACK_PENDING);
+       return 0;
+}
+
+/**
+ * qib_make_rc_req - construct a request packet (SEND, RDMA r/w, ATOMIC)
+ * @qp: a pointer to the QP
+ *
+ * Return 1 if constructed; otherwise, return 0.
+ */
+int qib_make_rc_req(struct qib_qp *qp)
+{
+       struct qib_ibdev *dev = to_idev(qp->ibqp.device);
+       struct qib_other_headers *ohdr;
+       struct qib_sge_state *ss;
+       struct qib_swqe *wqe;
+       u32 hwords;
+       u32 len;
+       u32 bth0;
+       u32 bth2;
+       u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu);
+       char newreq;
+       unsigned long flags;
+       int ret = 0;
+       int delta;
+
+       ohdr = &qp->s_hdr.u.oth;
+       if (qp->remote_ah_attr.ah_flags & IB_AH_GRH)
+               ohdr = &qp->s_hdr.u.l.oth;
+
+       /*
+        * The lock is needed to synchronize between the sending tasklet,
+        * the receive interrupt handler, and timeout resends.
+        */
+       spin_lock_irqsave(&qp->s_lock, flags);
+
+       /* Sending responses has higher priority over sending requests. */
+       if ((qp->s_flags & QIB_S_RESP_PENDING) &&
+           qib_make_rc_ack(dev, qp, ohdr, pmtu))
+               goto done;
+
+       if (!(ib_qib_state_ops[qp->state] & QIB_PROCESS_SEND_OK)) {
+               if (!(ib_qib_state_ops[qp->state] & QIB_FLUSH_SEND))
+                       goto bail;
+               /* We are in the error state, flush the work request. */
+               if (qp->s_last == qp->s_head)
+                       goto bail;
+               /* If DMAs are in progress, we can't flush immediately. */
+               if (atomic_read(&qp->s_dma_busy)) {
+                       qp->s_flags |= QIB_S_WAIT_DMA;
+                       goto bail;
+               }
+               wqe = get_swqe_ptr(qp, qp->s_last);
+               while (qp->s_last != qp->s_acked) {
+                       qib_send_complete(qp, wqe, IB_WC_SUCCESS);
+                       if (++qp->s_last >= qp->s_size)
+                               qp->s_last = 0;
+                       wqe = get_swqe_ptr(qp, qp->s_last);
+               }
+               qib_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR);
+               goto done;
+       }
+
+       if (qp->s_flags & (QIB_S_WAIT_RNR | QIB_S_WAIT_ACK))
+               goto bail;
+
+       if (qib_cmp24(qp->s_psn, qp->s_sending_hpsn) <= 0) {
+               if (qib_cmp24(qp->s_sending_psn, qp->s_sending_hpsn) <= 0) {
+                       qp->s_flags |= QIB_S_WAIT_PSN;
+                       goto bail;
+               }
+               qp->s_sending_psn = qp->s_psn;
+               qp->s_sending_hpsn = qp->s_psn - 1;
+       }
+
+       /* header size in 32-bit words LRH+BTH = (8+12)/4. */
+       hwords = 5;
+       bth0 = 0;
+
+       /* Send a request. */
+       wqe = get_swqe_ptr(qp, qp->s_cur);
+       switch (qp->s_state) {
+       default:
+               if (!(ib_qib_state_ops[qp->state] & QIB_PROCESS_NEXT_SEND_OK))
+                       goto bail;
+               /*
+                * Resend an old request or start a new one.
+                *
+                * We keep track of the current SWQE so that
+                * we don't reset the "furthest progress" state
+                * if we need to back up.
+                */
+               newreq = 0;
+               if (qp->s_cur == qp->s_tail) {
+                       /* Check if send work queue is empty. */
+                       if (qp->s_tail == qp->s_head)
+                               goto bail;
+                       /*
+                        * If a fence is requested, wait for previous
+                        * RDMA read and atomic operations to finish.
+                        */
+                       if ((wqe->wr.send_flags & IB_SEND_FENCE) &&
+                           qp->s_num_rd_atomic) {
+                               qp->s_flags |= QIB_S_WAIT_FENCE;
+                               goto bail;
+                       }
+                       wqe->psn = qp->s_next_psn;
+                       newreq = 1;
+               }
+               /*
+                * Note that we have to be careful not to modify the
+                * original work request since we may need to resend
+                * it.
+                */
+               len = wqe->length;
+               ss = &qp->s_sge;
+               bth2 = qp->s_psn & QIB_PSN_MASK;
+               switch (wqe->wr.opcode) {
+               case IB_WR_SEND:
+               case IB_WR_SEND_WITH_IMM:
+                       /* If no credit, return. */
+                       if (!(qp->s_flags & QIB_S_UNLIMITED_CREDIT) &&
+                           qib_cmp24(wqe->ssn, qp->s_lsn + 1) > 0) {
+                               qp->s_flags |= QIB_S_WAIT_SSN_CREDIT;
+                               goto bail;
+                       }
+                       wqe->lpsn = wqe->psn;
+                       if (len > pmtu) {
+                               wqe->lpsn += (len - 1) / pmtu;
+                               qp->s_state = OP(SEND_FIRST);
+                               len = pmtu;
+                               break;
+                       }
+                       if (wqe->wr.opcode == IB_WR_SEND)
+                               qp->s_state = OP(SEND_ONLY);
+                       else {
+                               qp->s_state = OP(SEND_ONLY_WITH_IMMEDIATE);
+                               /* Immediate data comes after the BTH */
+                               ohdr->u.imm_data = wqe->wr.ex.imm_data;
+                               hwords += 1;
+                       }
+                       if (wqe->wr.send_flags & IB_SEND_SOLICITED)
+                               bth0 |= IB_BTH_SOLICITED;
+                       bth2 |= IB_BTH_REQ_ACK;
+                       if (++qp->s_cur == qp->s_size)
+                               qp->s_cur = 0;
+                       break;
+
+               case IB_WR_RDMA_WRITE:
+                       if (newreq && !(qp->s_flags & QIB_S_UNLIMITED_CREDIT))
+                               qp->s_lsn++;
+                       /* FALLTHROUGH */
+               case IB_WR_RDMA_WRITE_WITH_IMM:
+                       /* If no credit, return. */
+                       if (!(qp->s_flags & QIB_S_UNLIMITED_CREDIT) &&
+                           qib_cmp24(wqe->ssn, qp->s_lsn + 1) > 0) {
+                               qp->s_flags |= QIB_S_WAIT_SSN_CREDIT;
+                               goto bail;
+                       }
+                       ohdr->u.rc.reth.vaddr =
+                               cpu_to_be64(wqe->wr.wr.rdma.remote_addr);
+                       ohdr->u.rc.reth.rkey =
+                               cpu_to_be32(wqe->wr.wr.rdma.rkey);
+                       ohdr->u.rc.reth.length = cpu_to_be32(len);
+                       hwords += sizeof(struct ib_reth) / sizeof(u32);
+                       wqe->lpsn = wqe->psn;
+                       if (len > pmtu) {
+                               wqe->lpsn += (len - 1) / pmtu;
+                               qp->s_state = OP(RDMA_WRITE_FIRST);
+                               len = pmtu;
+                               break;
+                       }
+                       if (wqe->wr.opcode == IB_WR_RDMA_WRITE)
+                               qp->s_state = OP(RDMA_WRITE_ONLY);
+                       else {
+                               qp->s_state =
+                                       OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE);
+                               /* Immediate data comes after RETH */
+                               ohdr->u.rc.imm_data = wqe->wr.ex.imm_data;
+                               hwords += 1;
+                               if (wqe->wr.send_flags & IB_SEND_SOLICITED)
+                                       bth0 |= IB_BTH_SOLICITED;
+                       }
+                       bth2 |= IB_BTH_REQ_ACK;
+                       if (++qp->s_cur == qp->s_size)
+                               qp->s_cur = 0;
+                       break;
+
+               case IB_WR_RDMA_READ:
+                       /*
+                        * Don't allow more operations to be started
+                        * than the QP limits allow.
+                        */
+                       if (newreq) {
+                               if (qp->s_num_rd_atomic >=
+                                   qp->s_max_rd_atomic) {
+                                       qp->s_flags |= QIB_S_WAIT_RDMAR;
+                                       goto bail;
+                               }
+                               qp->s_num_rd_atomic++;
+                               if (!(qp->s_flags & QIB_S_UNLIMITED_CREDIT))
+                                       qp->s_lsn++;
+                               /*
+                                * Adjust s_next_psn to count the
+                                * expected number of responses.
+                                */
+                               if (len > pmtu)
+                                       qp->s_next_psn += (len - 1) / pmtu;
+                               wqe->lpsn = qp->s_next_psn++;
+                       }
+                       ohdr->u.rc.reth.vaddr =
+                               cpu_to_be64(wqe->wr.wr.rdma.remote_addr);
+                       ohdr->u.rc.reth.rkey =
+                               cpu_to_be32(wqe->wr.wr.rdma.rkey);
+                       ohdr->u.rc.reth.length = cpu_to_be32(len);
+                       qp->s_state = OP(RDMA_READ_REQUEST);
+                       hwords += sizeof(ohdr->u.rc.reth) / sizeof(u32);
+                       ss = NULL;
+                       len = 0;
+                       bth2 |= IB_BTH_REQ_ACK;
+                       if (++qp->s_cur == qp->s_size)
+                               qp->s_cur = 0;
+                       break;
+
+               case IB_WR_ATOMIC_CMP_AND_SWP:
+               case IB_WR_ATOMIC_FETCH_AND_ADD:
+                       /*
+                        * Don't allow more operations to be started
+                        * than the QP limits allow.
+                        */
+                       if (newreq) {
+                               if (qp->s_num_rd_atomic >=
+                                   qp->s_max_rd_atomic) {
+                                       qp->s_flags |= QIB_S_WAIT_RDMAR;
+                                       goto bail;
+                               }
+                               qp->s_num_rd_atomic++;
+                               if (!(qp->s_flags & QIB_S_UNLIMITED_CREDIT))
+                                       qp->s_lsn++;
+                               wqe->lpsn = wqe->psn;
+                       }
+                       if (wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
+                               qp->s_state = OP(COMPARE_SWAP);
+                               ohdr->u.atomic_eth.swap_data = cpu_to_be64(
+                                       wqe->wr.wr.atomic.swap);
+                               ohdr->u.atomic_eth.compare_data = cpu_to_be64(
+                                       wqe->wr.wr.atomic.compare_add);
+                       } else {
+                               qp->s_state = OP(FETCH_ADD);
+                               ohdr->u.atomic_eth.swap_data = cpu_to_be64(
+                                       wqe->wr.wr.atomic.compare_add);
+                               ohdr->u.atomic_eth.compare_data = 0;
+                       }
+                       ohdr->u.atomic_eth.vaddr[0] = cpu_to_be32(
+                               wqe->wr.wr.atomic.remote_addr >> 32);
+                       ohdr->u.atomic_eth.vaddr[1] = cpu_to_be32(
+                               wqe->wr.wr.atomic.remote_addr);
+                       ohdr->u.atomic_eth.rkey = cpu_to_be32(
+                               wqe->wr.wr.atomic.rkey);
+                       hwords += sizeof(struct ib_atomic_eth) / sizeof(u32);
+                       ss = NULL;
+                       len = 0;
+                       bth2 |= IB_BTH_REQ_ACK;
+                       if (++qp->s_cur == qp->s_size)
+                               qp->s_cur = 0;
+                       break;
+
+               default:
+                       goto bail;
+               }
+               qp->s_sge.sge = wqe->sg_list[0];
+               qp->s_sge.sg_list = wqe->sg_list + 1;
+               qp->s_sge.num_sge = wqe->wr.num_sge;
+               qp->s_sge.total_len = wqe->length;
+               qp->s_len = wqe->length;
+               if (newreq) {
+                       qp->s_tail++;
+                       if (qp->s_tail >= qp->s_size)
+                               qp->s_tail = 0;
+               }
+               if (wqe->wr.opcode == IB_WR_RDMA_READ)
+                       qp->s_psn = wqe->lpsn + 1;
+               else {
+                       qp->s_psn++;
+                       if (qib_cmp24(qp->s_psn, qp->s_next_psn) > 0)
+                               qp->s_next_psn = qp->s_psn;
+               }
+               break;
+
+       case OP(RDMA_READ_RESPONSE_FIRST):
+               /*
+                * qp->s_state is normally set to the opcode of the
+                * last packet constructed for new requests and therefore
+                * is never set to RDMA read response.
+                * RDMA_READ_RESPONSE_FIRST is used by the ACK processing
+                * thread to indicate a SEND needs to be restarted from an
+                * earlier PSN without interferring with the sending thread.
+                * See qib_restart_rc().
+                */
+               qp->s_len = restart_sge(&qp->s_sge, wqe, qp->s_psn, pmtu);
+               /* FALLTHROUGH */
+       case OP(SEND_FIRST):
+               qp->s_state = OP(SEND_MIDDLE);
+               /* FALLTHROUGH */
+       case OP(SEND_MIDDLE):
+               bth2 = qp->s_psn++ & QIB_PSN_MASK;
+               if (qib_cmp24(qp->s_psn, qp->s_next_psn) > 0)
+                       qp->s_next_psn = qp->s_psn;
+               ss = &qp->s_sge;
+               len = qp->s_len;
+               if (len > pmtu) {
+                       len = pmtu;
+                       break;
+               }
+               if (wqe->wr.opcode == IB_WR_SEND)
+                       qp->s_state = OP(SEND_LAST);
+               else {
+                       qp->s_state = OP(SEND_LAST_WITH_IMMEDIATE);
+                       /* Immediate data comes after the BTH */
+                       ohdr->u.imm_data = wqe->wr.ex.imm_data;
+                       hwords += 1;
+               }
+               if (wqe->wr.send_flags & IB_SEND_SOLICITED)
+                       bth0 |= IB_BTH_SOLICITED;
+               bth2 |= IB_BTH_REQ_ACK;
+               qp->s_cur++;
+               if (qp->s_cur >= qp->s_size)
+                       qp->s_cur = 0;
+               break;
+
+       case OP(RDMA_READ_RESPONSE_LAST):
+               /*
+                * qp->s_state is normally set to the opcode of the
+                * last packet constructed for new requests and therefore
+                * is never set to RDMA read response.
+                * RDMA_READ_RESPONSE_LAST is used by the ACK processing
+                * thread to indicate a RDMA write needs to be restarted from
+                * an earlier PSN without interferring with the sending thread.
+                * See qib_restart_rc().
+                */
+               qp->s_len = restart_sge(&qp->s_sge, wqe, qp->s_psn, pmtu);
+               /* FALLTHROUGH */
+       case OP(RDMA_WRITE_FIRST):
+               qp->s_state = OP(RDMA_WRITE_MIDDLE);
+               /* FALLTHROUGH */
+       case OP(RDMA_WRITE_MIDDLE):
+               bth2 = qp->s_psn++ & QIB_PSN_MASK;
+               if (qib_cmp24(qp->s_psn, qp->s_next_psn) > 0)
+                       qp->s_next_psn = qp->s_psn;
+               ss = &qp->s_sge;
+               len = qp->s_len;
+               if (len > pmtu) {
+                       len = pmtu;
+                       break;
+               }
+               if (wqe->wr.opcode == IB_WR_RDMA_WRITE)
+                       qp->s_state = OP(RDMA_WRITE_LAST);
+               else {
+                       qp->s_state = OP(RDMA_WRITE_LAST_WITH_IMMEDIATE);
+                       /* Immediate data comes after the BTH */
+                       ohdr->u.imm_data = wqe->wr.ex.imm_data;
+                       hwords += 1;
+                       if (wqe->wr.send_flags & IB_SEND_SOLICITED)
+                               bth0 |= IB_BTH_SOLICITED;
+               }
+               bth2 |= IB_BTH_REQ_ACK;
+               qp->s_cur++;
+               if (qp->s_cur >= qp->s_size)
+                       qp->s_cur = 0;
+               break;
+
+       case OP(RDMA_READ_RESPONSE_MIDDLE):
+               /*
+                * qp->s_state is normally set to the opcode of the
+                * last packet constructed for new requests and therefore
+                * is never set to RDMA read response.
+                * RDMA_READ_RESPONSE_MIDDLE is used by the ACK processing
+                * thread to indicate a RDMA read needs to be restarted from
+                * an earlier PSN without interferring with the sending thread.
+                * See qib_restart_rc().
+                */
+               len = ((qp->s_psn - wqe->psn) & QIB_PSN_MASK) * pmtu;
+               ohdr->u.rc.reth.vaddr =
+                       cpu_to_be64(wqe->wr.wr.rdma.remote_addr + len);
+               ohdr->u.rc.reth.rkey =
+                       cpu_to_be32(wqe->wr.wr.rdma.rkey);
+               ohdr->u.rc.reth.length = cpu_to_be32(wqe->length - len);
+               qp->s_state = OP(RDMA_READ_REQUEST);
+               hwords += sizeof(ohdr->u.rc.reth) / sizeof(u32);
+               bth2 = (qp->s_psn & QIB_PSN_MASK) | IB_BTH_REQ_ACK;
+               qp->s_psn = wqe->lpsn + 1;
+               ss = NULL;
+               len = 0;
+               qp->s_cur++;
+               if (qp->s_cur == qp->s_size)
+                       qp->s_cur = 0;
+               break;
+       }
+       qp->s_sending_hpsn = bth2;
+       delta = (((int) bth2 - (int) wqe->psn) << 8) >> 8;
+       if (delta && delta % QIB_PSN_CREDIT == 0)
+               bth2 |= IB_BTH_REQ_ACK;
+       if (qp->s_flags & QIB_S_SEND_ONE) {
+               qp->s_flags &= ~QIB_S_SEND_ONE;
+               qp->s_flags |= QIB_S_WAIT_ACK;
+               bth2 |= IB_BTH_REQ_ACK;
+       }
+       qp->s_len -= len;
+       qp->s_hdrwords = hwords;
+       qp->s_cur_sge = ss;
+       qp->s_cur_size = len;
+       qib_make_ruc_header(qp, ohdr, bth0 | (qp->s_state << 24), bth2);
+done:
+       ret = 1;
+       goto unlock;
+
+bail:
+       qp->s_flags &= ~QIB_S_BUSY;
+unlock:
+       spin_unlock_irqrestore(&qp->s_lock, flags);
+       return ret;
+}
+
+/**
+ * qib_send_rc_ack - Construct an ACK packet and send it
+ * @qp: a pointer to the QP
+ *
+ * This is called from qib_rc_rcv() and qib_kreceive().
+ * Note that RDMA reads and atomics are handled in the
+ * send side QP state and tasklet.
+ */
+void qib_send_rc_ack(struct qib_qp *qp)
+{
+       struct qib_devdata *dd = dd_from_ibdev(qp->ibqp.device);
+       struct qib_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num);
+       struct qib_pportdata *ppd = ppd_from_ibp(ibp);
+       u64 pbc;
+       u16 lrh0;
+       u32 bth0;
+       u32 hwords;
+       u32 pbufn;
+       u32 __iomem *piobuf;
+       struct qib_ib_header hdr;
+       struct qib_other_headers *ohdr;
+       u32 control;
+       unsigned long flags;
+
+       spin_lock_irqsave(&qp->s_lock, flags);
+
+       if (!(ib_qib_state_ops[qp->state] & QIB_PROCESS_RECV_OK))
+               goto unlock;
+
+       /* Don't send ACK or NAK if a RDMA read or atomic is pending. */
+       if ((qp->s_flags & QIB_S_RESP_PENDING) || qp->s_rdma_ack_cnt)
+               goto queue_ack;
+
+       /* Construct the header with s_lock held so APM doesn't change it. */
+       ohdr = &hdr.u.oth;
+       lrh0 = QIB_LRH_BTH;
+       /* header size in 32-bit words LRH+BTH+AETH = (8+12+4)/4. */
+       hwords = 6;
+       if (unlikely(qp->remote_ah_attr.ah_flags & IB_AH_GRH)) {
+               hwords += qib_make_grh(ibp, &hdr.u.l.grh,
+                                      &qp->remote_ah_attr.grh, hwords, 0);
+               ohdr = &hdr.u.l.oth;
+               lrh0 = QIB_LRH_GRH;
+       }
+       /* read pkey_index w/o lock (its atomic) */
+       bth0 = qib_get_pkey(ibp, qp->s_pkey_index) | (OP(ACKNOWLEDGE) << 24);
+       if (qp->s_mig_state == IB_MIG_MIGRATED)
+               bth0 |= IB_BTH_MIG_REQ;
+       if (qp->r_nak_state)
+               ohdr->u.aeth = cpu_to_be32((qp->r_msn & QIB_MSN_MASK) |
+                                           (qp->r_nak_state <<
+                                            QIB_AETH_CREDIT_SHIFT));
+       else
+               ohdr->u.aeth = qib_compute_aeth(qp);
+       lrh0 |= ibp->sl_to_vl[qp->remote_ah_attr.sl] << 12 |
+               qp->remote_ah_attr.sl << 4;
+       hdr.lrh[0] = cpu_to_be16(lrh0);
+       hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid);
+       hdr.lrh[2] = cpu_to_be16(hwords + SIZE_OF_CRC);
+       hdr.lrh[3] = cpu_to_be16(ppd->lid | qp->remote_ah_attr.src_path_bits);
+       ohdr->bth[0] = cpu_to_be32(bth0);
+       ohdr->bth[1] = cpu_to_be32(qp->remote_qpn);
+       ohdr->bth[2] = cpu_to_be32(qp->r_ack_psn & QIB_PSN_MASK);
+
+       spin_unlock_irqrestore(&qp->s_lock, flags);
+
+       /* Don't try to send ACKs if the link isn't ACTIVE */
+       if (!(ppd->lflags & QIBL_LINKACTIVE))
+               goto done;
+
+       control = dd->f_setpbc_control(ppd, hwords + SIZE_OF_CRC,
+                                      qp->s_srate, lrh0 >> 12);
+       /* length is + 1 for the control dword */
+       pbc = ((u64) control << 32) | (hwords + 1);
+
+       piobuf = dd->f_getsendbuf(ppd, pbc, &pbufn);
+       if (!piobuf) {
+               /*
+                * We are out of PIO buffers at the moment.
+                * Pass responsibility for sending the ACK to the
+                * send tasklet so that when a PIO buffer becomes
+                * available, the ACK is sent ahead of other outgoing
+                * packets.
+                */
+               spin_lock_irqsave(&qp->s_lock, flags);
+               goto queue_ack;
+       }
+
+       /*
+        * Write the pbc.
+        * We have to flush after the PBC for correctness
+        * on some cpus or WC buffer can be written out of order.
+        */
+       writeq(pbc, piobuf);
+
+       if (dd->flags & QIB_PIO_FLUSH_WC) {
+               u32 *hdrp = (u32 *) &hdr;
+
+               qib_flush_wc();
+               qib_pio_copy(piobuf + 2, hdrp, hwords - 1);
+               qib_flush_wc();
+               __raw_writel(hdrp[hwords - 1], piobuf + hwords + 1);
+       } else
+               qib_pio_copy(piobuf + 2, (u32 *) &hdr, hwords);
+
+       if (dd->flags & QIB_USE_SPCL_TRIG) {
+               u32 spcl_off = (pbufn >= dd->piobcnt2k) ? 2047 : 1023;
+
+               qib_flush_wc();
+               __raw_writel(0xaebecede, piobuf + spcl_off);
+       }
+
+       qib_flush_wc();
+       qib_sendbuf_done(dd, pbufn);
+
+       ibp->n_unicast_xmit++;
+       goto done;
+
+queue_ack:
+       if (ib_qib_state_ops[qp->state] & QIB_PROCESS_RECV_OK) {
+               ibp->n_rc_qacks++;
+               qp->s_flags |= QIB_S_ACK_PENDING | QIB_S_RESP_PENDING;
+               qp->s_nak_state = qp->r_nak_state;
+               qp->s_ack_psn = qp->r_ack_psn;
+
+               /* Schedule the send tasklet. */
+               qib_schedule_send(qp);
+       }
+unlock:
+       spin_unlock_irqrestore(&qp->s_lock, flags);
+done:
+       return;
+}
+
+/**
+ * reset_psn - reset the QP state to send starting from PSN
+ * @qp: the QP
+ * @psn: the packet sequence number to restart at
+ *
+ * This is called from qib_rc_rcv() to process an incoming RC ACK
+ * for the given QP.
+ * Called at interrupt level with the QP s_lock held.
+ */
+static void reset_psn(struct qib_qp *qp, u32 psn)
+{
+       u32 n = qp->s_acked;
+       struct qib_swqe *wqe = get_swqe_ptr(qp, n);
+       u32 opcode;
+
+       qp->s_cur = n;
+
+       /*
+        * If we are starting the request from the beginning,
+        * let the normal send code handle initialization.
+        */
+       if (qib_cmp24(psn, wqe->psn) <= 0) {
+               qp->s_state = OP(SEND_LAST);
+               goto done;
+       }
+
+       /* Find the work request opcode corresponding to the given PSN. */
+       opcode = wqe->wr.opcode;
+       for (;;) {
+               int diff;
+
+               if (++n == qp->s_size)
+                       n = 0;
+               if (n == qp->s_tail)
+                       break;
+               wqe = get_swqe_ptr(qp, n);
+               diff = qib_cmp24(psn, wqe->psn);
+               if (diff < 0)
+                       break;
+               qp->s_cur = n;
+               /*
+                * If we are starting the request from the beginning,
+                * let the normal send code handle initialization.
+                */
+               if (diff == 0) {
+                       qp->s_state = OP(SEND_LAST);
+                       goto done;
+               }
+               opcode = wqe->wr.opcode;
+       }
+
+       /*
+        * Set the state to restart in the middle of a request.
+        * Don't change the s_sge, s_cur_sge, or s_cur_size.
+        * See qib_make_rc_req().
+        */
+       switch (opcode) {
+       case IB_WR_SEND:
+       case IB_WR_SEND_WITH_IMM:
+               qp->s_state = OP(RDMA_READ_RESPONSE_FIRST);
+               break;
+
+       case IB_WR_RDMA_WRITE:
+       case IB_WR_RDMA_WRITE_WITH_IMM:
+               qp->s_state = OP(RDMA_READ_RESPONSE_LAST);
+               break;
+
+       case IB_WR_RDMA_READ:
+               qp->s_state = OP(RDMA_READ_RESPONSE_MIDDLE);
+               break;
+
+       default:
+               /*
+                * This case shouldn't happen since its only
+                * one PSN per req.
+                */
+               qp->s_state = OP(SEND_LAST);
+       }
+done:
+       qp->s_psn = psn;
+       /*
+        * Set QIB_S_WAIT_PSN as qib_rc_complete() may start the timer
+        * asynchronously before the send tasklet can get scheduled.
+        * Doing it in qib_make_rc_req() is too late.
+        */
+       if ((qib_cmp24(qp->s_psn, qp->s_sending_hpsn) <= 0) &&
+           (qib_cmp24(qp->s_sending_psn, qp->s_sending_hpsn) <= 0))
+               qp->s_flags |= QIB_S_WAIT_PSN;
+}
+
+/*
+ * Back up requester to resend the last un-ACKed request.
+ * The QP s_lock should be held and interrupts disabled.
+ */
+static void qib_restart_rc(struct qib_qp *qp, u32 psn, int wait)
+{
+       struct qib_swqe *wqe = get_swqe_ptr(qp, qp->s_acked);
+       struct qib_ibport *ibp;
+
+       if (qp->s_retry == 0) {
+               if (qp->s_mig_state == IB_MIG_ARMED) {
+                       qib_migrate_qp(qp);
+                       qp->s_retry = qp->s_retry_cnt;
+               } else if (qp->s_last == qp->s_acked) {
+                       qib_send_complete(qp, wqe, IB_WC_RETRY_EXC_ERR);
+                       qib_error_qp(qp, IB_WC_WR_FLUSH_ERR);
+                       return;
+               } else /* XXX need to handle delayed completion */
+                       return;
+       } else
+               qp->s_retry--;
+
+       ibp = to_iport(qp->ibqp.device, qp->port_num);
+       if (wqe->wr.opcode == IB_WR_RDMA_READ)
+               ibp->n_rc_resends++;
+       else
+               ibp->n_rc_resends += (qp->s_psn - psn) & QIB_PSN_MASK;
+
+       qp->s_flags &= ~(QIB_S_WAIT_FENCE | QIB_S_WAIT_RDMAR |
+                        QIB_S_WAIT_SSN_CREDIT | QIB_S_WAIT_PSN |
+                        QIB_S_WAIT_ACK);
+       if (wait)
+               qp->s_flags |= QIB_S_SEND_ONE;
+       reset_psn(qp, psn);
+}
+
+/*
+ * This is called from s_timer for missing responses.
+ */
+static void rc_timeout(unsigned long arg)
+{
+       struct qib_qp *qp = (struct qib_qp *)arg;
+       struct qib_ibport *ibp;
+       unsigned long flags;
+
+       spin_lock_irqsave(&qp->s_lock, flags);
+       if (qp->s_flags & QIB_S_TIMER) {
+               ibp = to_iport(qp->ibqp.device, qp->port_num);
+               ibp->n_rc_timeouts++;
+               qp->s_flags &= ~QIB_S_TIMER;
+               del_timer(&qp->s_timer);
+               qib_restart_rc(qp, qp->s_last_psn + 1, 1);
+               qib_schedule_send(qp);
+       }
+       spin_unlock_irqrestore(&qp->s_lock, flags);
+}
+
+/*
+ * This is called from s_timer for RNR timeouts.
+ */
+void qib_rc_rnr_retry(unsigned long arg)
+{
+       struct qib_qp *qp = (struct qib_qp *)arg;
+       unsigned long flags;
+
+       spin_lock_irqsave(&qp->s_lock, flags);
+       if (qp->s_flags & QIB_S_WAIT_RNR) {
+               qp->s_flags &= ~QIB_S_WAIT_RNR;
+               del_timer(&qp->s_timer);
+               qib_schedule_send(qp);
+       }
+       spin_unlock_irqrestore(&qp->s_lock, flags);
+}
+
+/*
+ * Set qp->s_sending_psn to the next PSN after the given one.
+ * This would be psn+1 except when RDMA reads are present.
+ */
+static void reset_sending_psn(struct qib_qp *qp, u32 psn)
+{
+       struct qib_swqe *wqe;
+       u32 n = qp->s_last;
+
+       /* Find the work request corresponding to the given PSN. */
+       for (;;) {
+               wqe = get_swqe_ptr(qp, n);
+               if (qib_cmp24(psn, wqe->lpsn) <= 0) {
+                       if (wqe->wr.opcode == IB_WR_RDMA_READ)
+                               qp->s_sending_psn = wqe->lpsn + 1;
+                       else
+                               qp->s_sending_psn = psn + 1;
+                       break;
+               }
+               if (++n == qp->s_size)
+                       n = 0;
+               if (n == qp->s_tail)
+                       break;
+       }
+}
+
+/*
+ * This should be called with the QP s_lock held and interrupts disabled.
+ */
+void qib_rc_send_complete(struct qib_qp *qp, struct qib_ib_header *hdr)
+{
+       struct qib_other_headers *ohdr;
+       struct qib_swqe *wqe;
+       struct ib_wc wc;
+       unsigned i;
+       u32 opcode;
+       u32 psn;
+
+       if (!(ib_qib_state_ops[qp->state] & QIB_PROCESS_OR_FLUSH_SEND))
+               return;
+
+       /* Find out where the BTH is */
+       if ((be16_to_cpu(hdr->lrh[0]) & 3) == QIB_LRH_BTH)
+               ohdr = &hdr->u.oth;
+       else
+               ohdr = &hdr->u.l.oth;
+
+       opcode = be32_to_cpu(ohdr->bth[0]) >> 24;
+       if (opcode >= OP(RDMA_READ_RESPONSE_FIRST) &&
+           opcode <= OP(ATOMIC_ACKNOWLEDGE)) {
+               WARN_ON(!qp->s_rdma_ack_cnt);
+               qp->s_rdma_ack_cnt--;
+               return;
+       }
+
+       psn = be32_to_cpu(ohdr->bth[2]);
+       reset_sending_psn(qp, psn);
+
+       /*
+        * Start timer after a packet requesting an ACK has been sent and
+        * there are still requests that haven't been acked.
+        */
+       if ((psn & IB_BTH_REQ_ACK) && qp->s_acked != qp->s_tail &&
+           !(qp->s_flags & (QIB_S_TIMER | QIB_S_WAIT_RNR | QIB_S_WAIT_PSN)))
+               start_timer(qp);
+
+       while (qp->s_last != qp->s_acked) {
+               wqe = get_swqe_ptr(qp, qp->s_last);
+               if (qib_cmp24(wqe->lpsn, qp->s_sending_psn) >= 0 &&
+                   qib_cmp24(qp->s_sending_psn, qp->s_sending_hpsn) <= 0)
+                       break;
+               for (i = 0; i < wqe->wr.num_sge; i++) {
+                       struct qib_sge *sge = &wqe->sg_list[i];
+
+                       atomic_dec(&sge->mr->refcount);
+               }
+               /* Post a send completion queue entry if requested. */
+               if (!(qp->s_flags & QIB_S_SIGNAL_REQ_WR) ||
+                   (wqe->wr.send_flags & IB_SEND_SIGNALED)) {
+                       memset(&wc, 0, sizeof wc);
+                       wc.wr_id = wqe->wr.wr_id;
+                       wc.status = IB_WC_SUCCESS;
+                       wc.opcode = ib_qib_wc_opcode[wqe->wr.opcode];
+                       wc.byte_len = wqe->length;
+                       wc.qp = &qp->ibqp;
+                       qib_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 0);
+               }
+               if (++qp->s_last >= qp->s_size)
+                       qp->s_last = 0;
+       }
+       /*
+        * If we were waiting for sends to complete before resending,
+        * and they are now complete, restart sending.
+        */
+       if (qp->s_flags & QIB_S_WAIT_PSN &&
+           qib_cmp24(qp->s_sending_psn, qp->s_sending_hpsn) > 0) {
+               qp->s_flags &= ~QIB_S_WAIT_PSN;
+               qp->s_sending_psn = qp->s_psn;
+               qp->s_sending_hpsn = qp->s_psn - 1;
+               qib_schedule_send(qp);
+       }
+}
+
+static inline void update_last_psn(struct qib_qp *qp, u32 psn)
+{
+       qp->s_last_psn = psn;
+}
+
+/*
+ * Generate a SWQE completion.
+ * This is similar to qib_send_complete but has to check to be sure
+ * that the SGEs are not being referenced if the SWQE is being resent.
+ */
+static struct qib_swqe *do_rc_completion(struct qib_qp *qp,
+                                        struct qib_swqe *wqe,
+                                        struct qib_ibport *ibp)
+{
+       struct ib_wc wc;
+       unsigned i;
+
+       /*
+        * Don't decrement refcount and don't generate a
+        * completion if the SWQE is being resent until the send
+        * is finished.
+        */
+       if (qib_cmp24(wqe->lpsn, qp->s_sending_psn) < 0 ||
+           qib_cmp24(qp->s_sending_psn, qp->s_sending_hpsn) > 0) {
+               for (i = 0; i < wqe->wr.num_sge; i++) {
+                       struct qib_sge *sge = &wqe->sg_list[i];
+
+                       atomic_dec(&sge->mr->refcount);
+               }
+               /* Post a send completion queue entry if requested. */
+               if (!(qp->s_flags & QIB_S_SIGNAL_REQ_WR) ||
+                   (wqe->wr.send_flags & IB_SEND_SIGNALED)) {
+                       memset(&wc, 0, sizeof wc);
+                       wc.wr_id = wqe->wr.wr_id;
+                       wc.status = IB_WC_SUCCESS;
+                       wc.opcode = ib_qib_wc_opcode[wqe->wr.opcode];
+                       wc.byte_len = wqe->length;
+                       wc.qp = &qp->ibqp;
+                       qib_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 0);
+               }
+               if (++qp->s_last >= qp->s_size)
+                       qp->s_last = 0;
+       } else
+               ibp->n_rc_delayed_comp++;
+
+       qp->s_retry = qp->s_retry_cnt;
+       update_last_psn(qp, wqe->lpsn);
+
+       /*
+        * If we are completing a request which is in the process of
+        * being resent, we can stop resending it since we know the
+        * responder has already seen it.
+        */
+       if (qp->s_acked == qp->s_cur) {
+               if (++qp->s_cur >= qp->s_size)
+                       qp->s_cur = 0;
+               qp->s_acked = qp->s_cur;
+               wqe = get_swqe_ptr(qp, qp->s_cur);
+               if (qp->s_acked != qp->s_tail) {
+                       qp->s_state = OP(SEND_LAST);
+                       qp->s_psn = wqe->psn;
+               }
+       } else {
+               if (++qp->s_acked >= qp->s_size)
+                       qp->s_acked = 0;
+               if (qp->state == IB_QPS_SQD && qp->s_acked == qp->s_cur)
+                       qp->s_draining = 0;
+               wqe = get_swqe_ptr(qp, qp->s_acked);
+       }
+       return wqe;
+}
+
+/**
+ * do_rc_ack - process an incoming RC ACK
+ * @qp: the QP the ACK came in on
+ * @psn: the packet sequence number of the ACK
+ * @opcode: the opcode of the request that resulted in the ACK
+ *
+ * This is called from qib_rc_rcv_resp() to process an incoming RC ACK
+ * for the given QP.
+ * Called at interrupt level with the QP s_lock held.
+ * Returns 1 if OK, 0 if current operation should be aborted (NAK).
+ */
+static int do_rc_ack(struct qib_qp *qp, u32 aeth, u32 psn, int opcode,
+                    u64 val, struct qib_ctxtdata *rcd)
+{
+       struct qib_ibport *ibp;
+       enum ib_wc_status status;
+       struct qib_swqe *wqe;
+       int ret = 0;
+       u32 ack_psn;
+       int diff;
+
+       /* Remove QP from retry timer */
+       if (qp->s_flags & (QIB_S_TIMER | QIB_S_WAIT_RNR)) {
+               qp->s_flags &= ~(QIB_S_TIMER | QIB_S_WAIT_RNR);
+               del_timer(&qp->s_timer);
+       }
+
+       /*
+        * Note that NAKs implicitly ACK outstanding SEND and RDMA write
+        * requests and implicitly NAK RDMA read and atomic requests issued
+        * before the NAK'ed request.  The MSN won't include the NAK'ed
+        * request but will include an ACK'ed request(s).
+        */
+       ack_psn = psn;
+       if (aeth >> 29)
+               ack_psn--;
+       wqe = get_swqe_ptr(qp, qp->s_acked);
+       ibp = to_iport(qp->ibqp.device, qp->port_num);
+
+       /*
+        * The MSN might be for a later WQE than the PSN indicates so
+        * only complete WQEs that the PSN finishes.
+        */
+       while ((diff = qib_cmp24(ack_psn, wqe->lpsn)) >= 0) {
+               /*
+                * RDMA_READ_RESPONSE_ONLY is a special case since
+                * we want to generate completion events for everything
+                * before the RDMA read, copy the data, then generate
+                * the completion for the read.
+                */
+               if (wqe->wr.opcode == IB_WR_RDMA_READ &&
+                   opcode == OP(RDMA_READ_RESPONSE_ONLY) &&
+                   diff == 0) {
+                       ret = 1;
+                       goto bail;
+               }
+               /*
+                * If this request is a RDMA read or atomic, and the ACK is
+                * for a later operation, this ACK NAKs the RDMA read or
+                * atomic.  In other words, only a RDMA_READ_LAST or ONLY
+                * can ACK a RDMA read and likewise for atomic ops.  Note
+                * that the NAK case can only happen if relaxed ordering is
+                * used and requests are sent after an RDMA read or atomic
+                * is sent but before the response is received.
+                */
+               if ((wqe->wr.opcode == IB_WR_RDMA_READ &&
+                    (opcode != OP(RDMA_READ_RESPONSE_LAST) || diff != 0)) ||
+                   ((wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP ||
+                     wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) &&
+                    (opcode != OP(ATOMIC_ACKNOWLEDGE) || diff != 0))) {
+                       /* Retry this request. */
+                       if (!(qp->r_flags & QIB_R_RDMAR_SEQ)) {
+                               qp->r_flags |= QIB_R_RDMAR_SEQ;
+                               qib_restart_rc(qp, qp->s_last_psn + 1, 0);
+                               if (list_empty(&qp->rspwait)) {
+                                       qp->r_flags |= QIB_R_RSP_SEND;
+                                       atomic_inc(&qp->refcount);
+                                       list_add_tail(&qp->rspwait,
+                                                     &rcd->qp_wait_list);
+                               }
+                       }
+                       /*
+                        * No need to process the ACK/NAK since we are
+                        * restarting an earlier request.
+                        */
+                       goto bail;
+               }
+               if (wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP ||
+                   wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) {
+                       u64 *vaddr = wqe->sg_list[0].vaddr;
+                       *vaddr = val;
+               }
+               if (qp->s_num_rd_atomic &&
+                   (wqe->wr.opcode == IB_WR_RDMA_READ ||
+                    wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP ||
+                    wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD)) {
+                       qp->s_num_rd_atomic--;
+                       /* Restart sending task if fence is complete */
+                       if ((qp->s_flags & QIB_S_WAIT_FENCE) &&
+                           !qp->s_num_rd_atomic) {
+                               qp->s_flags &= ~(QIB_S_WAIT_FENCE |
+                                                QIB_S_WAIT_ACK);
+                               qib_schedule_send(qp);
+                       } else if (qp->s_flags & QIB_S_WAIT_RDMAR) {
+                               qp->s_flags &= ~(QIB_S_WAIT_RDMAR |
+                                                QIB_S_WAIT_ACK);
+                               qib_schedule_send(qp);
+                       }
+               }
+               wqe = do_rc_completion(qp, wqe, ibp);
+               if (qp->s_acked == qp->s_tail)
+                       break;
+       }
+
+       switch (aeth >> 29) {
+       case 0:         /* ACK */
+               ibp->n_rc_acks++;
+               if (qp->s_acked != qp->s_tail) {
+                       /*
+                        * We are expecting more ACKs so
+                        * reset the retransmit timer.
+                        */
+                       start_timer(qp);
+                       /*
+                        * We can stop resending the earlier packets and
+                        * continue with the next packet the receiver wants.
+                        */
+                       if (qib_cmp24(qp->s_psn, psn) <= 0)
+                               reset_psn(qp, psn + 1);
+               } else if (qib_cmp24(qp->s_psn, psn) <= 0) {
+                       qp->s_state = OP(SEND_LAST);
+                       qp->s_psn = psn + 1;
+               }
+               if (qp->s_flags & QIB_S_WAIT_ACK) {
+                       qp->s_flags &= ~QIB_S_WAIT_ACK;
+                       qib_schedule_send(qp);
+               }
+               qib_get_credit(qp, aeth);
+               qp->s_rnr_retry = qp->s_rnr_retry_cnt;
+               qp->s_retry = qp->s_retry_cnt;
+               update_last_psn(qp, psn);
+               ret = 1;
+               goto bail;
+
+       case 1:         /* RNR NAK */
+               ibp->n_rnr_naks++;
+               if (qp->s_acked == qp->s_tail)
+                       goto bail;
+               if (qp->s_flags & QIB_S_WAIT_RNR)
+                       goto bail;
+               if (qp->s_rnr_retry == 0) {
+                       status = IB_WC_RNR_RETRY_EXC_ERR;
+                       goto class_b;
+               }
+               if (qp->s_rnr_retry_cnt < 7)
+                       qp->s_rnr_retry--;
+
+               /* The last valid PSN is the previous PSN. */
+               update_last_psn(qp, psn - 1);
+
+               ibp->n_rc_resends += (qp->s_psn - psn) & QIB_PSN_MASK;
+
+               reset_psn(qp, psn);
+
+               qp->s_flags &= ~(QIB_S_WAIT_SSN_CREDIT | QIB_S_WAIT_ACK);
+               qp->s_flags |= QIB_S_WAIT_RNR;
+               qp->s_timer.function = qib_rc_rnr_retry;
+               qp->s_timer.expires = jiffies + usecs_to_jiffies(
+                       ib_qib_rnr_table[(aeth >> QIB_AETH_CREDIT_SHIFT) &
+                                          QIB_AETH_CREDIT_MASK]);
+               add_timer(&qp->s_timer);
+               goto bail;
+
+       case 3:         /* NAK */
+               if (qp->s_acked == qp->s_tail)
+                       goto bail;
+               /* The last valid PSN is the previous PSN. */
+               update_last_psn(qp, psn - 1);
+               switch ((aeth >> QIB_AETH_CREDIT_SHIFT) &
+                       QIB_AETH_CREDIT_MASK) {
+               case 0: /* PSN sequence error */
+                       ibp->n_seq_naks++;
+                       /*
+                        * Back up to the responder's expected PSN.
+                        * Note that we might get a NAK in the middle of an
+                        * RDMA READ response which terminates the RDMA
+                        * READ.
+                        */
+                       qib_restart_rc(qp, psn, 0);
+                       qib_schedule_send(qp);
+                       break;
+
+               case 1: /* Invalid Request */
+                       status = IB_WC_REM_INV_REQ_ERR;
+                       ibp->n_other_naks++;
+                       goto class_b;
+
+               case 2: /* Remote Access Error */
+                       status = IB_WC_REM_ACCESS_ERR;
+                       ibp->n_other_naks++;
+                       goto class_b;
+
+               case 3: /* Remote Operation Error */
+                       status = IB_WC_REM_OP_ERR;
+                       ibp->n_other_naks++;
+class_b:
+                       if (qp->s_last == qp->s_acked) {
+                               qib_send_complete(qp, wqe, status);
+                               qib_error_qp(qp, IB_WC_WR_FLUSH_ERR);
+                       }
+                       break;
+
+               default:
+                       /* Ignore other reserved NAK error codes */
+                       goto reserved;
+               }
+               qp->s_retry = qp->s_retry_cnt;
+               qp->s_rnr_retry = qp->s_rnr_retry_cnt;
+               goto bail;
+
+       default:                /* 2: reserved */
+reserved:
+               /* Ignore reserved NAK codes. */
+               goto bail;
+       }
+
+bail:
+       return ret;
+}
+
+/*
+ * We have seen an out of sequence RDMA read middle or last packet.
+ * This ACKs SENDs and RDMA writes up to the first RDMA read or atomic SWQE.
+ */
+static void rdma_seq_err(struct qib_qp *qp, struct qib_ibport *ibp, u32 psn,
+                        struct qib_ctxtdata *rcd)
+{
+       struct qib_swqe *wqe;
+
+       /* Remove QP from retry timer */
+       if (qp->s_flags & (QIB_S_TIMER | QIB_S_WAIT_RNR)) {
+               qp->s_flags &= ~(QIB_S_TIMER | QIB_S_WAIT_RNR);
+               del_timer(&qp->s_timer);
+       }
+
+       wqe = get_swqe_ptr(qp, qp->s_acked);
+
+       while (qib_cmp24(psn, wqe->lpsn) > 0) {
+               if (wqe->wr.opcode == IB_WR_RDMA_READ ||
+                   wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP ||
+                   wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD)
+                       break;
+               wqe = do_rc_completion(qp, wqe, ibp);
+       }
+
+       ibp->n_rdma_seq++;
+       qp->r_flags |= QIB_R_RDMAR_SEQ;
+       qib_restart_rc(qp, qp->s_last_psn + 1, 0);
+       if (list_empty(&qp->rspwait)) {
+               qp->r_flags |= QIB_R_RSP_SEND;
+               atomic_inc(&qp->refcount);
+               list_add_tail(&qp->rspwait, &rcd->qp_wait_list);
+       }
+}
+
+/**
+ * qib_rc_rcv_resp - process an incoming RC response packet
+ * @ibp: the port this packet came in on
+ * @ohdr: the other headers for this packet
+ * @data: the packet data
+ * @tlen: the packet length
+ * @qp: the QP for this packet
+ * @opcode: the opcode for this packet
+ * @psn: the packet sequence number for this packet
+ * @hdrsize: the header length
+ * @pmtu: the path MTU
+ *
+ * This is called from qib_rc_rcv() to process an incoming RC response
+ * packet for the given QP.
+ * Called at interrupt level.
+ */
+static void qib_rc_rcv_resp(struct qib_ibport *ibp,
+                           struct qib_other_headers *ohdr,
+                           void *data, u32 tlen,
+                           struct qib_qp *qp,
+                           u32 opcode,
+                           u32 psn, u32 hdrsize, u32 pmtu,
+                           struct qib_ctxtdata *rcd)
+{
+       struct qib_swqe *wqe;
+       enum ib_wc_status status;
+       unsigned long flags;
+       int diff;
+       u32 pad;
+       u32 aeth;
+       u64 val;
+
+       spin_lock_irqsave(&qp->s_lock, flags);
+
+       /* Double check we can process this now that we hold the s_lock. */
+       if (!(ib_qib_state_ops[qp->state] & QIB_PROCESS_RECV_OK))
+               goto ack_done;
+
+       /* Ignore invalid responses. */
+       if (qib_cmp24(psn, qp->s_next_psn) >= 0)
+               goto ack_done;
+
+       /* Ignore duplicate responses. */
+       diff = qib_cmp24(psn, qp->s_last_psn);
+       if (unlikely(diff <= 0)) {
+               /* Update credits for "ghost" ACKs */
+               if (diff == 0 && opcode == OP(ACKNOWLEDGE)) {
+                       aeth = be32_to_cpu(ohdr->u.aeth);
+                       if ((aeth >> 29) == 0)
+                               qib_get_credit(qp, aeth);
+               }
+               goto ack_done;
+       }
+
+       /*
+        * Skip everything other than the PSN we expect, if we are waiting
+        * for a reply to a restarted RDMA read or atomic op.
+        */
+       if (qp->r_flags & QIB_R_RDMAR_SEQ) {
+               if (qib_cmp24(psn, qp->s_last_psn + 1) != 0)
+                       goto ack_done;
+               qp->r_flags &= ~QIB_R_RDMAR_SEQ;
+       }
+
+       if (unlikely(qp->s_acked == qp->s_tail))
+               goto ack_done;
+       wqe = get_swqe_ptr(qp, qp->s_acked);
+       status = IB_WC_SUCCESS;
+
+       switch (opcode) {
+       case OP(ACKNOWLEDGE):
+       case OP(ATOMIC_ACKNOWLEDGE):
+       case OP(RDMA_READ_RESPONSE_FIRST):
+               aeth = be32_to_cpu(ohdr->u.aeth);
+               if (opcode == OP(ATOMIC_ACKNOWLEDGE)) {
+                       __be32 *p = ohdr->u.at.atomic_ack_eth;
+
+                       val = ((u64) be32_to_cpu(p[0]) << 32) |
+                               be32_to_cpu(p[1]);
+               } else
+                       val = 0;
+               if (!do_rc_ack(qp, aeth, psn, opcode, val, rcd) ||
+                   opcode != OP(RDMA_READ_RESPONSE_FIRST))
+                       goto ack_done;
+               hdrsize += 4;
+               wqe = get_swqe_ptr(qp, qp->s_acked);
+               if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ))
+                       goto ack_op_err;
+               /*
+                * If this is a response to a resent RDMA read, we
+                * have to be careful to copy the data to the right
+                * location.
+                */
+               qp->s_rdma_read_len = restart_sge(&qp->s_rdma_read_sge,
+                                                 wqe, psn, pmtu);
+               goto read_middle;
+
+       case OP(RDMA_READ_RESPONSE_MIDDLE):
+               /* no AETH, no ACK */
+               if (unlikely(qib_cmp24(psn, qp->s_last_psn + 1)))
+                       goto ack_seq_err;
+               if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ))
+                       goto ack_op_err;
+read_middle:
+               if (unlikely(tlen != (hdrsize + pmtu + 4)))
+                       goto ack_len_err;
+               if (unlikely(pmtu >= qp->s_rdma_read_len))
+                       goto ack_len_err;
+
+               /*
+                * We got a response so update the timeout.
+                * 4.096 usec. * (1 << qp->timeout)
+                */
+               qp->s_flags |= QIB_S_TIMER;
+               mod_timer(&qp->s_timer, jiffies +
+                       usecs_to_jiffies((4096UL * (1UL << qp->timeout)) /
+                                        1000UL));
+               if (qp->s_flags & QIB_S_WAIT_ACK) {
+                       qp->s_flags &= ~QIB_S_WAIT_ACK;
+                       qib_schedule_send(qp);
+               }
+
+               if (opcode == OP(RDMA_READ_RESPONSE_MIDDLE))
+                       qp->s_retry = qp->s_retry_cnt;
+
+               /*
+                * Update the RDMA receive state but do the copy w/o
+                * holding the locks and blocking interrupts.
+                */
+               qp->s_rdma_read_len -= pmtu;
+               update_last_psn(qp, psn);
+               spin_unlock_irqrestore(&qp->s_lock, flags);
+               qib_copy_sge(&qp->s_rdma_read_sge, data, pmtu, 0);
+               goto bail;
+
+       case OP(RDMA_READ_RESPONSE_ONLY):
+               aeth = be32_to_cpu(ohdr->u.aeth);
+               if (!do_rc_ack(qp, aeth, psn, opcode, 0, rcd))
+                       goto ack_done;
+               /* Get the number of bytes the message was padded by. */
+               pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
+               /*
+                * Check that the data size is >= 0 && <= pmtu.
+                * Remember to account for the AETH header (4) and
+                * ICRC (4).
+                */
+               if (unlikely(tlen < (hdrsize + pad + 8)))
+                       goto ack_len_err;
+               /*
+                * If this is a response to a resent RDMA read, we
+                * have to be careful to copy the data to the right
+                * location.
+                */
+               wqe = get_swqe_ptr(qp, qp->s_acked);
+               qp->s_rdma_read_len = restart_sge(&qp->s_rdma_read_sge,
+                                                 wqe, psn, pmtu);
+               goto read_last;
+
+       case OP(RDMA_READ_RESPONSE_LAST):
+               /* ACKs READ req. */
+               if (unlikely(qib_cmp24(psn, qp->s_last_psn + 1)))
+                       goto ack_seq_err;
+               if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ))
+                       goto ack_op_err;
+               /* Get the number of bytes the message was padded by. */
+               pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
+               /*
+                * Check that the data size is >= 1 && <= pmtu.
+                * Remember to account for the AETH header (4) and
+                * ICRC (4).
+                */
+               if (unlikely(tlen <= (hdrsize + pad + 8)))
+                       goto ack_len_err;
+read_last:
+               tlen -= hdrsize + pad + 8;
+               if (unlikely(tlen != qp->s_rdma_read_len))
+                       goto ack_len_err;
+               aeth = be32_to_cpu(ohdr->u.aeth);
+               qib_copy_sge(&qp->s_rdma_read_sge, data, tlen, 0);
+               WARN_ON(qp->s_rdma_read_sge.num_sge);
+               (void) do_rc_ack(qp, aeth, psn,
+                                OP(RDMA_READ_RESPONSE_LAST), 0, rcd);
+               goto ack_done;
+       }
+
+ack_op_err:
+       status = IB_WC_LOC_QP_OP_ERR;
+       goto ack_err;
+
+ack_seq_err:
+       rdma_seq_err(qp, ibp, psn, rcd);
+       goto ack_done;
+
+ack_len_err:
+       status = IB_WC_LOC_LEN_ERR;
+ack_err:
+       if (qp->s_last == qp->s_acked) {
+               qib_send_complete(qp, wqe, status);
+               qib_error_qp(qp, IB_WC_WR_FLUSH_ERR);
+       }
+ack_done:
+       spin_unlock_irqrestore(&qp->s_lock, flags);
+bail:
+       return;
+}
+
+/**
+ * qib_rc_rcv_error - process an incoming duplicate or error RC packet
+ * @ohdr: the other headers for this packet
+ * @data: the packet data
+ * @qp: the QP for this packet
+ * @opcode: the opcode for this packet
+ * @psn: the packet sequence number for this packet
+ * @diff: the difference between the PSN and the expected PSN
+ *
+ * This is called from qib_rc_rcv() to process an unexpected
+ * incoming RC packet for the given QP.
+ * Called at interrupt level.
+ * Return 1 if no more processing is needed; otherwise return 0 to
+ * schedule a response to be sent.
+ */
+static int qib_rc_rcv_error(struct qib_other_headers *ohdr,
+                           void *data,
+                           struct qib_qp *qp,
+                           u32 opcode,
+                           u32 psn,
+                           int diff,
+                           struct qib_ctxtdata *rcd)
+{
+       struct qib_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num);
+       struct qib_ack_entry *e;
+       unsigned long flags;
+       u8 i, prev;
+       int old_req;
+
+       if (diff > 0) {
+               /*
+                * Packet sequence error.
+                * A NAK will ACK earlier sends and RDMA writes.
+                * Don't queue the NAK if we already sent one.
+                */
+               if (!qp->r_nak_state) {
+                       ibp->n_rc_seqnak++;
+                       qp->r_nak_state = IB_NAK_PSN_ERROR;
+                       /* Use the expected PSN. */
+                       qp->r_ack_psn = qp->r_psn;
+                       /*
+                        * Wait to send the sequence NAK until all packets
+                        * in the receive queue have been processed.
+                        * Otherwise, we end up propagating congestion.
+                        */
+                       if (list_empty(&qp->rspwait)) {
+                               qp->r_flags |= QIB_R_RSP_NAK;
+                               atomic_inc(&qp->refcount);
+                               list_add_tail(&qp->rspwait, &rcd->qp_wait_list);
+                       }
+               }
+               goto done;
+       }
+
+       /*
+        * Handle a duplicate request.  Don't re-execute SEND, RDMA
+        * write or atomic op.  Don't NAK errors, just silently drop
+        * the duplicate request.  Note that r_sge, r_len, and
+        * r_rcv_len may be in use so don't modify them.
+        *
+        * We are supposed to ACK the earliest duplicate PSN but we
+        * can coalesce an outstanding duplicate ACK.  We have to
+        * send the earliest so that RDMA reads can be restarted at
+        * the requester's expected PSN.
+        *
+        * First, find where this duplicate PSN falls within the
+        * ACKs previously sent.
+        * old_req is true if there is an older response that is scheduled
+        * to be sent before sending this one.
+        */
+       e = NULL;
+       old_req = 1;
+       ibp->n_rc_dupreq++;
+
+       spin_lock_irqsave(&qp->s_lock, flags);
+       /* Double check we can process this now that we hold the s_lock. */
+       if (!(ib_qib_state_ops[qp->state] & QIB_PROCESS_RECV_OK))
+               goto unlock_done;
+
+       for (i = qp->r_head_ack_queue; ; i = prev) {
+               if (i == qp->s_tail_ack_queue)
+                       old_req = 0;
+               if (i)
+                       prev = i - 1;
+               else
+                       prev = QIB_MAX_RDMA_ATOMIC;
+               if (prev == qp->r_head_ack_queue) {
+                       e = NULL;
+                       break;
+               }
+               e = &qp->s_ack_queue[prev];
+               if (!e->opcode) {
+                       e = NULL;
+                       break;
+               }
+               if (qib_cmp24(psn, e->psn) >= 0) {
+                       if (prev == qp->s_tail_ack_queue &&
+                           qib_cmp24(psn, e->lpsn) <= 0)
+                               old_req = 0;
+                       break;
+               }
+       }
+       switch (opcode) {
+       case OP(RDMA_READ_REQUEST): {
+               struct ib_reth *reth;
+               u32 offset;
+               u32 len;
+
+               /*
+                * If we didn't find the RDMA read request in the ack queue,
+                * we can ignore this request.
+                */
+               if (!e || e->opcode != OP(RDMA_READ_REQUEST))
+                       goto unlock_done;
+               /* RETH comes after BTH */
+               reth = &ohdr->u.rc.reth;
+               /*
+                * Address range must be a subset of the original
+                * request and start on pmtu boundaries.
+                * We reuse the old ack_queue slot since the requester
+                * should not back up and request an earlier PSN for the
+                * same request.
+                */
+               offset = ((psn - e->psn) & QIB_PSN_MASK) *
+                       ib_mtu_enum_to_int(qp->path_mtu);
+               len = be32_to_cpu(reth->length);
+               if (unlikely(offset + len != e->rdma_sge.sge_length))
+                       goto unlock_done;
+               if (e->rdma_sge.mr) {
+                       atomic_dec(&e->rdma_sge.mr->refcount);
+                       e->rdma_sge.mr = NULL;
+               }
+               if (len != 0) {
+                       u32 rkey = be32_to_cpu(reth->rkey);
+                       u64 vaddr = be64_to_cpu(reth->vaddr);
+                       int ok;
+
+                       ok = qib_rkey_ok(qp, &e->rdma_sge, len, vaddr, rkey,
+                                        IB_ACCESS_REMOTE_READ);
+                       if (unlikely(!ok))
+                               goto unlock_done;
+               } else {
+                       e->rdma_sge.vaddr = NULL;
+                       e->rdma_sge.length = 0;
+                       e->rdma_sge.sge_length = 0;
+               }
+               e->psn = psn;
+               if (old_req)
+                       goto unlock_done;
+               qp->s_tail_ack_queue = prev;
+               break;
+       }
+
+       case OP(COMPARE_SWAP):
+       case OP(FETCH_ADD): {
+               /*
+                * If we didn't find the atomic request in the ack queue
+                * or the send tasklet is already backed up to send an
+                * earlier entry, we can ignore this request.
+                */
+               if (!e || e->opcode != (u8) opcode || old_req)
+                       goto unlock_done;
+               qp->s_tail_ack_queue = prev;
+               break;
+       }
+
+       default:
+               /*
+                * Ignore this operation if it doesn't request an ACK
+                * or an earlier RDMA read or atomic is going to be resent.
+                */
+               if (!(psn & IB_BTH_REQ_ACK) || old_req)
+                       goto unlock_done;
+               /*
+                * Resend the most recent ACK if this request is
+                * after all the previous RDMA reads and atomics.
+                */
+               if (i == qp->r_head_ack_queue) {
+                       spin_unlock_irqrestore(&qp->s_lock, flags);
+                       qp->r_nak_state = 0;
+                       qp->r_ack_psn = qp->r_psn - 1;
+                       goto send_ack;
+               }
+               /*
+                * Try to send a simple ACK to work around a Mellanox bug
+                * which doesn't accept a RDMA read response or atomic
+                * response as an ACK for earlier SENDs or RDMA writes.
+                */
+               if (!(qp->s_flags & QIB_S_RESP_PENDING)) {
+                       spin_unlock_irqrestore(&qp->s_lock, flags);
+                       qp->r_nak_state = 0;
+                       qp->r_ack_psn = qp->s_ack_queue[i].psn - 1;
+                       goto send_ack;
+               }
+               /*
+                * Resend the RDMA read or atomic op which
+                * ACKs this duplicate request.
+                */
+               qp->s_tail_ack_queue = i;
+               break;
+       }
+       qp->s_ack_state = OP(ACKNOWLEDGE);
+       qp->s_flags |= QIB_S_RESP_PENDING;
+       qp->r_nak_state = 0;
+       qib_schedule_send(qp);
+
+unlock_done:
+       spin_unlock_irqrestore(&qp->s_lock, flags);
+done:
+       return 1;
+
+send_ack:
+       return 0;
+}
+
+void qib_rc_error(struct qib_qp *qp, enum ib_wc_status err)
+{
+       unsigned long flags;
+       int lastwqe;
+
+       spin_lock_irqsave(&qp->s_lock, flags);
+       lastwqe = qib_error_qp(qp, err);
+       spin_unlock_irqrestore(&qp->s_lock, flags);
+
+       if (lastwqe) {
+               struct ib_event ev;
+
+               ev.device = qp->ibqp.device;
+               ev.element.qp = &qp->ibqp;
+               ev.event = IB_EVENT_QP_LAST_WQE_REACHED;
+               qp->ibqp.event_handler(&ev, qp->ibqp.qp_context);
+       }
+}
+
+static inline void qib_update_ack_queue(struct qib_qp *qp, unsigned n)
+{
+       unsigned next;
+
+       next = n + 1;
+       if (next > QIB_MAX_RDMA_ATOMIC)
+               next = 0;
+       qp->s_tail_ack_queue = next;
+       qp->s_ack_state = OP(ACKNOWLEDGE);
+}
+
+/**
+ * qib_rc_rcv - process an incoming RC packet
+ * @rcd: the context pointer
+ * @hdr: the header of this packet
+ * @has_grh: true if the header has a GRH
+ * @data: the packet data
+ * @tlen: the packet length
+ * @qp: the QP for this packet
+ *
+ * This is called from qib_qp_rcv() to process an incoming RC packet
+ * for the given QP.
+ * Called at interrupt level.
+ */
+void qib_rc_rcv(struct qib_ctxtdata *rcd, struct qib_ib_header *hdr,
+               int has_grh, void *data, u32 tlen, struct qib_qp *qp)
+{
+       struct qib_ibport *ibp = &rcd->ppd->ibport_data;
+       struct qib_other_headers *ohdr;
+       u32 opcode;
+       u32 hdrsize;
+       u32 psn;
+       u32 pad;
+       struct ib_wc wc;
+       u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu);
+       int diff;
+       struct ib_reth *reth;
+       unsigned long flags;
+       int ret;
+
+       /* Check for GRH */
+       if (!has_grh) {
+               ohdr = &hdr->u.oth;
+               hdrsize = 8 + 12;       /* LRH + BTH */
+       } else {
+               ohdr = &hdr->u.l.oth;
+               hdrsize = 8 + 40 + 12;  /* LRH + GRH + BTH */
+       }
+
+       opcode = be32_to_cpu(ohdr->bth[0]);
+       spin_lock_irqsave(&qp->s_lock, flags);
+       if (qib_ruc_check_hdr(ibp, hdr, has_grh, qp, opcode))
+               goto sunlock;
+       spin_unlock_irqrestore(&qp->s_lock, flags);
+
+       psn = be32_to_cpu(ohdr->bth[2]);
+       opcode >>= 24;
+
+       /* Prevent simultaneous processing after APM on different CPUs */
+       spin_lock(&qp->r_lock);
+
+       /*
+        * Process responses (ACKs) before anything else.  Note that the
+        * packet sequence number will be for something in the send work
+        * queue rather than the expected receive packet sequence number.
+        * In other words, this QP is the requester.
+        */
+       if (opcode >= OP(RDMA_READ_RESPONSE_FIRST) &&
+           opcode <= OP(ATOMIC_ACKNOWLEDGE)) {
+               qib_rc_rcv_resp(ibp, ohdr, data, tlen, qp, opcode, psn,
+                               hdrsize, pmtu, rcd);
+               goto runlock;
+       }
+
+       /* Compute 24 bits worth of difference. */
+       diff = qib_cmp24(psn, qp->r_psn);
+       if (unlikely(diff)) {
+               if (qib_rc_rcv_error(ohdr, data, qp, opcode, psn, diff, rcd))
+                       goto runlock;
+               goto send_ack;
+       }
+
+       /* Check for opcode sequence errors. */
+       switch (qp->r_state) {
+       case OP(SEND_FIRST):
+       case OP(SEND_MIDDLE):
+               if (opcode == OP(SEND_MIDDLE) ||
+                   opcode == OP(SEND_LAST) ||
+                   opcode == OP(SEND_LAST_WITH_IMMEDIATE))
+                       break;
+               goto nack_inv;
+
+       case OP(RDMA_WRITE_FIRST):
+       case OP(RDMA_WRITE_MIDDLE):
+               if (opcode == OP(RDMA_WRITE_MIDDLE) ||
+                   opcode == OP(RDMA_WRITE_LAST) ||
+                   opcode == OP(RDMA_WRITE_LAST_WITH_IMMEDIATE))
+                       break;
+               goto nack_inv;
+
+       default:
+               if (opcode == OP(SEND_MIDDLE) ||
+                   opcode == OP(SEND_LAST) ||
+                   opcode == OP(SEND_LAST_WITH_IMMEDIATE) ||
+                   opcode == OP(RDMA_WRITE_MIDDLE) ||
+                   opcode == OP(RDMA_WRITE_LAST) ||
+                   opcode == OP(RDMA_WRITE_LAST_WITH_IMMEDIATE))
+                       goto nack_inv;
+               /*
+                * Note that it is up to the requester to not send a new
+                * RDMA read or atomic operation before receiving an ACK
+                * for the previous operation.
+                */
+               break;
+       }
+
+       memset(&wc, 0, sizeof wc);
+
+       if (qp->state == IB_QPS_RTR && !(qp->r_flags & QIB_R_COMM_EST)) {
+               qp->r_flags |= QIB_R_COMM_EST;
+               if (qp->ibqp.event_handler) {
+                       struct ib_event ev;
+
+                       ev.device = qp->ibqp.device;
+                       ev.element.qp = &qp->ibqp;
+                       ev.event = IB_EVENT_COMM_EST;
+                       qp->ibqp.event_handler(&ev, qp->ibqp.qp_context);
+               }
+       }
+
+       /* OK, process the packet. */
+       switch (opcode) {
+       case OP(SEND_FIRST):
+               ret = qib_get_rwqe(qp, 0);
+               if (ret < 0)
+                       goto nack_op_err;
+               if (!ret)
+                       goto rnr_nak;
+               qp->r_rcv_len = 0;
+               /* FALLTHROUGH */
+       case OP(SEND_MIDDLE):
+       case OP(RDMA_WRITE_MIDDLE):
+send_middle:
+               /* Check for invalid length PMTU or posted rwqe len. */
+               if (unlikely(tlen != (hdrsize + pmtu + 4)))
+                       goto nack_inv;
+               qp->r_rcv_len += pmtu;
+               if (unlikely(qp->r_rcv_len > qp->r_len))
+                       goto nack_inv;
+               qib_copy_sge(&qp->r_sge, data, pmtu, 1);
+               break;
+
+       case OP(RDMA_WRITE_LAST_WITH_IMMEDIATE):
+               /* consume RWQE */
+               ret = qib_get_rwqe(qp, 1);
+               if (ret < 0)
+                       goto nack_op_err;
+               if (!ret)
+                       goto rnr_nak;
+               goto send_last_imm;
+
+       case OP(SEND_ONLY):
+       case OP(SEND_ONLY_WITH_IMMEDIATE):
+               ret = qib_get_rwqe(qp, 0);
+               if (ret < 0)
+                       goto nack_op_err;
+               if (!ret)
+                       goto rnr_nak;
+               qp->r_rcv_len = 0;
+               if (opcode == OP(SEND_ONLY))
+                       goto send_last;
+               /* FALLTHROUGH */
+       case OP(SEND_LAST_WITH_IMMEDIATE):
+send_last_imm:
+               wc.ex.imm_data = ohdr->u.imm_data;
+               hdrsize += 4;
+               wc.wc_flags = IB_WC_WITH_IMM;
+               /* FALLTHROUGH */
+       case OP(SEND_LAST):
+       case OP(RDMA_WRITE_LAST):
+send_last:
+               /* Get the number of bytes the message was padded by. */
+               pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
+               /* Check for invalid length. */
+               /* XXX LAST len should be >= 1 */
+               if (unlikely(tlen < (hdrsize + pad + 4)))
+                       goto nack_inv;
+               /* Don't count the CRC. */
+               tlen -= (hdrsize + pad + 4);
+               wc.byte_len = tlen + qp->r_rcv_len;
+               if (unlikely(wc.byte_len > qp->r_len))
+                       goto nack_inv;
+               qib_copy_sge(&qp->r_sge, data, tlen, 1);
+               while (qp->r_sge.num_sge) {
+                       atomic_dec(&qp->r_sge.sge.mr->refcount);
+                       if (--qp->r_sge.num_sge)
+                               qp->r_sge.sge = *qp->r_sge.sg_list++;
+               }
+               qp->r_msn++;
+               if (!test_and_clear_bit(QIB_R_WRID_VALID, &qp->r_aflags))
+                       break;
+               wc.wr_id = qp->r_wr_id;
+               wc.status = IB_WC_SUCCESS;
+               if (opcode == OP(RDMA_WRITE_LAST_WITH_IMMEDIATE) ||
+                   opcode == OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE))
+                       wc.opcode = IB_WC_RECV_RDMA_WITH_IMM;
+               else
+                       wc.opcode = IB_WC_RECV;
+               wc.qp = &qp->ibqp;
+               wc.src_qp = qp->remote_qpn;
+               wc.slid = qp->remote_ah_attr.dlid;
+               wc.sl = qp->remote_ah_attr.sl;
+               /* Signal completion event if the solicited bit is set. */
+               qib_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,
+                            (ohdr->bth[0] &
+                             cpu_to_be32(IB_BTH_SOLICITED)) != 0);
+               break;
+
+       case OP(RDMA_WRITE_FIRST):
+       case OP(RDMA_WRITE_ONLY):
+       case OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE):
+               if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_WRITE)))
+                       goto nack_inv;
+               /* consume RWQE */
+               reth = &ohdr->u.rc.reth;
+               hdrsize += sizeof(*reth);
+               qp->r_len = be32_to_cpu(reth->length);
+               qp->r_rcv_len = 0;
+               qp->r_sge.sg_list = NULL;
+               if (qp->r_len != 0) {
+                       u32 rkey = be32_to_cpu(reth->rkey);
+                       u64 vaddr = be64_to_cpu(reth->vaddr);
+                       int ok;
+
+                       /* Check rkey & NAK */
+                       ok = qib_rkey_ok(qp, &qp->r_sge.sge, qp->r_len, vaddr,
+                                        rkey, IB_ACCESS_REMOTE_WRITE);
+                       if (unlikely(!ok))
+                               goto nack_acc;
+                       qp->r_sge.num_sge = 1;
+               } else {
+                       qp->r_sge.num_sge = 0;
+                       qp->r_sge.sge.mr = NULL;
+                       qp->r_sge.sge.vaddr = NULL;
+                       qp->r_sge.sge.length = 0;
+                       qp->r_sge.sge.sge_length = 0;
+               }
+               if (opcode == OP(RDMA_WRITE_FIRST))
+                       goto send_middle;
+               else if (opcode == OP(RDMA_WRITE_ONLY))
+                       goto send_last;
+               ret = qib_get_rwqe(qp, 1);
+               if (ret < 0)
+                       goto nack_op_err;
+               if (!ret)
+                       goto rnr_nak;
+               goto send_last_imm;
+
+       case OP(RDMA_READ_REQUEST): {
+               struct qib_ack_entry *e;
+               u32 len;
+               u8 next;
+
+               if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_READ)))
+                       goto nack_inv;
+               next = qp->r_head_ack_queue + 1;
+               /* s_ack_queue is size QIB_MAX_RDMA_ATOMIC+1 so use > not >= */
+               if (next > QIB_MAX_RDMA_ATOMIC)
+                       next = 0;
+               spin_lock_irqsave(&qp->s_lock, flags);
+               /* Double check we can process this while holding the s_lock. */
+               if (!(ib_qib_state_ops[qp->state] & QIB_PROCESS_RECV_OK))
+                       goto srunlock;
+               if (unlikely(next == qp->s_tail_ack_queue)) {
+                       if (!qp->s_ack_queue[next].sent)
+                               goto nack_inv_unlck;
+                       qib_update_ack_queue(qp, next);
+               }
+               e = &qp->s_ack_queue[qp->r_head_ack_queue];
+               if (e->opcode == OP(RDMA_READ_REQUEST) && e->rdma_sge.mr) {
+                       atomic_dec(&e->rdma_sge.mr->refcount);
+                       e->rdma_sge.mr = NULL;
+               }
+               reth = &ohdr->u.rc.reth;
+               len = be32_to_cpu(reth->length);
+               if (len) {
+                       u32 rkey = be32_to_cpu(reth->rkey);
+                       u64 vaddr = be64_to_cpu(reth->vaddr);
+                       int ok;
+
+                       /* Check rkey & NAK */
+                       ok = qib_rkey_ok(qp, &e->rdma_sge, len, vaddr,
+                                        rkey, IB_ACCESS_REMOTE_READ);
+                       if (unlikely(!ok))
+                               goto nack_acc_unlck;
+                       /*
+                        * Update the next expected PSN.  We add 1 later
+                        * below, so only add the remainder here.
+                        */
+                       if (len > pmtu)
+                               qp->r_psn += (len - 1) / pmtu;
+               } else {
+                       e->rdma_sge.mr = NULL;
+                       e->rdma_sge.vaddr = NULL;
+                       e->rdma_sge.length = 0;
+                       e->rdma_sge.sge_length = 0;
+               }
+               e->opcode = opcode;
+               e->sent = 0;
+               e->psn = psn;
+               e->lpsn = qp->r_psn;
+               /*
+                * We need to increment the MSN here instead of when we
+                * finish sending the result since a duplicate request would
+                * increment it more than once.
+                */
+               qp->r_msn++;
+               qp->r_psn++;
+               qp->r_state = opcode;
+               qp->r_nak_state = 0;
+               qp->r_head_ack_queue = next;
+
+               /* Schedule the send tasklet. */
+               qp->s_flags |= QIB_S_RESP_PENDING;
+               qib_schedule_send(qp);
+
+               goto srunlock;
+       }
+
+       case OP(COMPARE_SWAP):
+       case OP(FETCH_ADD): {
+               struct ib_atomic_eth *ateth;
+               struct qib_ack_entry *e;
+               u64 vaddr;
+               atomic64_t *maddr;
+               u64 sdata;
+               u32 rkey;
+               u8 next;
+
+               if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC)))
+                       goto nack_inv;
+               next = qp->r_head_ack_queue + 1;
+               if (next > QIB_MAX_RDMA_ATOMIC)
+                       next = 0;
+               spin_lock_irqsave(&qp->s_lock, flags);
+               /* Double check we can process this while holding the s_lock. */
+               if (!(ib_qib_state_ops[qp->state] & QIB_PROCESS_RECV_OK))
+                       goto srunlock;
+               if (unlikely(next == qp->s_tail_ack_queue)) {
+                       if (!qp->s_ack_queue[next].sent)
+                               goto nack_inv_unlck;
+                       qib_update_ack_queue(qp, next);
+               }
+               e = &qp->s_ack_queue[qp->r_head_ack_queue];
+               if (e->opcode == OP(RDMA_READ_REQUEST) && e->rdma_sge.mr) {
+                       atomic_dec(&e->rdma_sge.mr->refcount);
+                       e->rdma_sge.mr = NULL;
+               }
+               ateth = &ohdr->u.atomic_eth;
+               vaddr = ((u64) be32_to_cpu(ateth->vaddr[0]) << 32) |
+                       be32_to_cpu(ateth->vaddr[1]);
+               if (unlikely(vaddr & (sizeof(u64) - 1)))
+                       goto nack_inv_unlck;
+               rkey = be32_to_cpu(ateth->rkey);
+               /* Check rkey & NAK */
+               if (unlikely(!qib_rkey_ok(qp, &qp->r_sge.sge, sizeof(u64),
+                                         vaddr, rkey,
+                                         IB_ACCESS_REMOTE_ATOMIC)))
+                       goto nack_acc_unlck;
+               /* Perform atomic OP and save result. */
+               maddr = (atomic64_t *) qp->r_sge.sge.vaddr;
+               sdata = be64_to_cpu(ateth->swap_data);
+               e->atomic_data = (opcode == OP(FETCH_ADD)) ?
+                       (u64) atomic64_add_return(sdata, maddr) - sdata :
+                       (u64) cmpxchg((u64 *) qp->r_sge.sge.vaddr,
+                                     be64_to_cpu(ateth->compare_data),
+                                     sdata);
+               atomic_dec(&qp->r_sge.sge.mr->refcount);
+               qp->r_sge.num_sge = 0;
+               e->opcode = opcode;
+               e->sent = 0;
+               e->psn = psn;
+               e->lpsn = psn;
+               qp->r_msn++;
+               qp->r_psn++;
+               qp->r_state = opcode;
+               qp->r_nak_state = 0;
+               qp->r_head_ack_queue = next;
+
+               /* Schedule the send tasklet. */
+               qp->s_flags |= QIB_S_RESP_PENDING;
+               qib_schedule_send(qp);
+
+               goto srunlock;
+       }
+
+       default:
+               /* NAK unknown opcodes. */
+               goto nack_inv;
+       }
+       qp->r_psn++;
+       qp->r_state = opcode;
+       qp->r_ack_psn = psn;
+       qp->r_nak_state = 0;
+       /* Send an ACK if requested or required. */
+       if (psn & (1 << 31))
+               goto send_ack;
+       goto runlock;
+
+rnr_nak:
+       qp->r_nak_state = IB_RNR_NAK | qp->r_min_rnr_timer;
+       qp->r_ack_psn = qp->r_psn;
+       /* Queue RNR NAK for later */
+       if (list_empty(&qp->rspwait)) {
+               qp->r_flags |= QIB_R_RSP_NAK;
+               atomic_inc(&qp->refcount);
+               list_add_tail(&qp->rspwait, &rcd->qp_wait_list);
+       }
+       goto runlock;
+
+nack_op_err:
+       qib_rc_error(qp, IB_WC_LOC_QP_OP_ERR);
+       qp->r_nak_state = IB_NAK_REMOTE_OPERATIONAL_ERROR;
+       qp->r_ack_psn = qp->r_psn;
+       /* Queue NAK for later */
+       if (list_empty(&qp->rspwait)) {
+               qp->r_flags |= QIB_R_RSP_NAK;
+               atomic_inc(&qp->refcount);
+               list_add_tail(&qp->rspwait, &rcd->qp_wait_list);
+       }
+       goto runlock;
+
+nack_inv_unlck:
+       spin_unlock_irqrestore(&qp->s_lock, flags);
+nack_inv:
+       qib_rc_error(qp, IB_WC_LOC_QP_OP_ERR);
+       qp->r_nak_state = IB_NAK_INVALID_REQUEST;
+       qp->r_ack_psn = qp->r_psn;
+       /* Queue NAK for later */
+       if (list_empty(&qp->rspwait)) {
+               qp->r_flags |= QIB_R_RSP_NAK;
+               atomic_inc(&qp->refcount);
+               list_add_tail(&qp->rspwait, &rcd->qp_wait_list);
+       }
+       goto runlock;
+
+nack_acc_unlck:
+       spin_unlock_irqrestore(&qp->s_lock, flags);
+nack_acc:
+       qib_rc_error(qp, IB_WC_LOC_PROT_ERR);
+       qp->r_nak_state = IB_NAK_REMOTE_ACCESS_ERROR;
+       qp->r_ack_psn = qp->r_psn;
+send_ack:
+       qib_send_rc_ack(qp);
+runlock:
+       spin_unlock(&qp->r_lock);
+       return;
+
+srunlock:
+       spin_unlock_irqrestore(&qp->s_lock, flags);
+       spin_unlock(&qp->r_lock);
+       return;
+
+sunlock:
+       spin_unlock_irqrestore(&qp->s_lock, flags);
+}
diff --git a/drivers/infiniband/hw/qib/qib_ruc.c b/drivers/infiniband/hw/qib/qib_ruc.c
new file mode 100644 (file)
index 0000000..eb78d93
--- /dev/null
@@ -0,0 +1,817 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved.
+ * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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/spinlock.h>
+
+#include "qib.h"
+#include "qib_mad.h"
+
+/*
+ * Convert the AETH RNR timeout code into the number of microseconds.
+ */
+const u32 ib_qib_rnr_table[32] = {
+       655360, /* 00: 655.36 */
+       10,     /* 01:    .01 */
+       20,     /* 02     .02 */
+       30,     /* 03:    .03 */
+       40,     /* 04:    .04 */
+       60,     /* 05:    .06 */
+       80,     /* 06:    .08 */
+       120,    /* 07:    .12 */
+       160,    /* 08:    .16 */
+       240,    /* 09:    .24 */
+       320,    /* 0A:    .32 */
+       480,    /* 0B:    .48 */
+       640,    /* 0C:    .64 */
+       960,    /* 0D:    .96 */
+       1280,   /* 0E:   1.28 */
+       1920,   /* 0F:   1.92 */
+       2560,   /* 10:   2.56 */
+       3840,   /* 11:   3.84 */
+       5120,   /* 12:   5.12 */
+       7680,   /* 13:   7.68 */
+       10240,  /* 14:  10.24 */
+       15360,  /* 15:  15.36 */
+       20480,  /* 16:  20.48 */
+       30720,  /* 17:  30.72 */
+       40960,  /* 18:  40.96 */
+       61440,  /* 19:  61.44 */
+       81920,  /* 1A:  81.92 */
+       122880, /* 1B: 122.88 */
+       163840, /* 1C: 163.84 */
+       245760, /* 1D: 245.76 */
+       327680, /* 1E: 327.68 */
+       491520  /* 1F: 491.52 */
+};
+
+/*
+ * Validate a RWQE and fill in the SGE state.
+ * Return 1 if OK.
+ */
+static int qib_init_sge(struct qib_qp *qp, struct qib_rwqe *wqe)
+{
+       int i, j, ret;
+       struct ib_wc wc;
+       struct qib_lkey_table *rkt;
+       struct qib_pd *pd;
+       struct qib_sge_state *ss;
+
+       rkt = &to_idev(qp->ibqp.device)->lk_table;
+       pd = to_ipd(qp->ibqp.srq ? qp->ibqp.srq->pd : qp->ibqp.pd);
+       ss = &qp->r_sge;
+       ss->sg_list = qp->r_sg_list;
+       qp->r_len = 0;
+       for (i = j = 0; i < wqe->num_sge; i++) {
+               if (wqe->sg_list[i].length == 0)
+                       continue;
+               /* Check LKEY */
+               if (!qib_lkey_ok(rkt, pd, j ? &ss->sg_list[j - 1] : &ss->sge,
+                                &wqe->sg_list[i], IB_ACCESS_LOCAL_WRITE))
+                       goto bad_lkey;
+               qp->r_len += wqe->sg_list[i].length;
+               j++;
+       }
+       ss->num_sge = j;
+       ss->total_len = qp->r_len;
+       ret = 1;
+       goto bail;
+
+bad_lkey:
+       while (j) {
+               struct qib_sge *sge = --j ? &ss->sg_list[j - 1] : &ss->sge;
+
+               atomic_dec(&sge->mr->refcount);
+       }
+       ss->num_sge = 0;
+       memset(&wc, 0, sizeof(wc));
+       wc.wr_id = wqe->wr_id;
+       wc.status = IB_WC_LOC_PROT_ERR;
+       wc.opcode = IB_WC_RECV;
+       wc.qp = &qp->ibqp;
+       /* Signal solicited completion event. */
+       qib_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1);
+       ret = 0;
+bail:
+       return ret;
+}
+
+/**
+ * qib_get_rwqe - copy the next RWQE into the QP's RWQE
+ * @qp: the QP
+ * @wr_id_only: update qp->r_wr_id only, not qp->r_sge
+ *
+ * Return -1 if there is a local error, 0 if no RWQE is available,
+ * otherwise return 1.
+ *
+ * Can be called from interrupt level.
+ */
+int qib_get_rwqe(struct qib_qp *qp, int wr_id_only)
+{
+       unsigned long flags;
+       struct qib_rq *rq;
+       struct qib_rwq *wq;
+       struct qib_srq *srq;
+       struct qib_rwqe *wqe;
+       void (*handler)(struct ib_event *, void *);
+       u32 tail;
+       int ret;
+
+       if (qp->ibqp.srq) {
+               srq = to_isrq(qp->ibqp.srq);
+               handler = srq->ibsrq.event_handler;
+               rq = &srq->rq;
+       } else {
+               srq = NULL;
+               handler = NULL;
+               rq = &qp->r_rq;
+       }
+
+       spin_lock_irqsave(&rq->lock, flags);
+       if (!(ib_qib_state_ops[qp->state] & QIB_PROCESS_RECV_OK)) {
+               ret = 0;
+               goto unlock;
+       }
+
+       wq = rq->wq;
+       tail = wq->tail;
+       /* Validate tail before using it since it is user writable. */
+       if (tail >= rq->size)
+               tail = 0;
+       if (unlikely(tail == wq->head)) {
+               ret = 0;
+               goto unlock;
+       }
+       /* Make sure entry is read after head index is read. */
+       smp_rmb();
+       wqe = get_rwqe_ptr(rq, tail);
+       /*
+        * Even though we update the tail index in memory, the verbs
+        * consumer is not supposed to post more entries until a
+        * completion is generated.
+        */
+       if (++tail >= rq->size)
+               tail = 0;
+       wq->tail = tail;
+       if (!wr_id_only && !qib_init_sge(qp, wqe)) {
+               ret = -1;
+               goto unlock;
+       }
+       qp->r_wr_id = wqe->wr_id;
+
+       ret = 1;
+       set_bit(QIB_R_WRID_VALID, &qp->r_aflags);
+       if (handler) {
+               u32 n;
+
+               /*
+                * Validate head pointer value and compute
+                * the number of remaining WQEs.
+                */
+               n = wq->head;
+               if (n >= rq->size)
+                       n = 0;
+               if (n < tail)
+                       n += rq->size - tail;
+               else
+                       n -= tail;
+               if (n < srq->limit) {
+                       struct ib_event ev;
+
+                       srq->limit = 0;
+                       spin_unlock_irqrestore(&rq->lock, flags);
+                       ev.device = qp->ibqp.device;
+                       ev.element.srq = qp->ibqp.srq;
+                       ev.event = IB_EVENT_SRQ_LIMIT_REACHED;
+                       handler(&ev, srq->ibsrq.srq_context);
+                       goto bail;
+               }
+       }
+unlock:
+       spin_unlock_irqrestore(&rq->lock, flags);
+bail:
+       return ret;
+}
+
+/*
+ * Switch to alternate path.
+ * The QP s_lock should be held and interrupts disabled.
+ */
+void qib_migrate_qp(struct qib_qp *qp)
+{
+       struct ib_event ev;
+
+       qp->s_mig_state = IB_MIG_MIGRATED;
+       qp->remote_ah_attr = qp->alt_ah_attr;
+       qp->port_num = qp->alt_ah_attr.port_num;
+       qp->s_pkey_index = qp->s_alt_pkey_index;
+
+       ev.device = qp->ibqp.device;
+       ev.element.qp = &qp->ibqp;
+       ev.event = IB_EVENT_PATH_MIG;
+       qp->ibqp.event_handler(&ev, qp->ibqp.qp_context);
+}
+
+static __be64 get_sguid(struct qib_ibport *ibp, unsigned index)
+{
+       if (!index) {
+               struct qib_pportdata *ppd = ppd_from_ibp(ibp);
+
+               return ppd->guid;
+       } else
+               return ibp->guids[index - 1];
+}
+
+static int gid_ok(union ib_gid *gid, __be64 gid_prefix, __be64 id)
+{
+       return (gid->global.interface_id == id &&
+               (gid->global.subnet_prefix == gid_prefix ||
+                gid->global.subnet_prefix == IB_DEFAULT_GID_PREFIX));
+}
+
+/*
+ *
+ * This should be called with the QP s_lock held.
+ */
+int qib_ruc_check_hdr(struct qib_ibport *ibp, struct qib_ib_header *hdr,
+                     int has_grh, struct qib_qp *qp, u32 bth0)
+{
+       __be64 guid;
+
+       if (qp->s_mig_state == IB_MIG_ARMED && (bth0 & IB_BTH_MIG_REQ)) {
+               if (!has_grh) {
+                       if (qp->alt_ah_attr.ah_flags & IB_AH_GRH)
+                               goto err;
+               } else {
+                       if (!(qp->alt_ah_attr.ah_flags & IB_AH_GRH))
+                               goto err;
+                       guid = get_sguid(ibp, qp->alt_ah_attr.grh.sgid_index);
+                       if (!gid_ok(&hdr->u.l.grh.dgid, ibp->gid_prefix, guid))
+                               goto err;
+                       if (!gid_ok(&hdr->u.l.grh.sgid,
+                           qp->alt_ah_attr.grh.dgid.global.subnet_prefix,
+                           qp->alt_ah_attr.grh.dgid.global.interface_id))
+                               goto err;
+               }
+               if (!qib_pkey_ok((u16)bth0,
+                                qib_get_pkey(ibp, qp->s_alt_pkey_index))) {
+                       qib_bad_pqkey(ibp, IB_NOTICE_TRAP_BAD_PKEY,
+                                     (u16)bth0,
+                                     (be16_to_cpu(hdr->lrh[0]) >> 4) & 0xF,
+                                     0, qp->ibqp.qp_num,
+                                     hdr->lrh[3], hdr->lrh[1]);
+                       goto err;
+               }
+               /* Validate the SLID. See Ch. 9.6.1.5 and 17.2.8 */
+               if (be16_to_cpu(hdr->lrh[3]) != qp->alt_ah_attr.dlid ||
+                   ppd_from_ibp(ibp)->port != qp->alt_ah_attr.port_num)
+                       goto err;
+               qib_migrate_qp(qp);
+       } else {
+               if (!has_grh) {
+                       if (qp->remote_ah_attr.ah_flags & IB_AH_GRH)
+                               goto err;
+               } else {
+                       if (!(qp->remote_ah_attr.ah_flags & IB_AH_GRH))
+                               goto err;
+                       guid = get_sguid(ibp,
+                                        qp->remote_ah_attr.grh.sgid_index);
+                       if (!gid_ok(&hdr->u.l.grh.dgid, ibp->gid_prefix, guid))
+                               goto err;
+                       if (!gid_ok(&hdr->u.l.grh.sgid,
+                           qp->remote_ah_attr.grh.dgid.global.subnet_prefix,
+                           qp->remote_ah_attr.grh.dgid.global.interface_id))
+                               goto err;
+               }
+               if (!qib_pkey_ok((u16)bth0,
+                                qib_get_pkey(ibp, qp->s_pkey_index))) {
+                       qib_bad_pqkey(ibp, IB_NOTICE_TRAP_BAD_PKEY,
+                                     (u16)bth0,
+                                     (be16_to_cpu(hdr->lrh[0]) >> 4) & 0xF,
+                                     0, qp->ibqp.qp_num,
+                                     hdr->lrh[3], hdr->lrh[1]);
+                       goto err;
+               }
+               /* Validate the SLID. See Ch. 9.6.1.5 */
+               if (be16_to_cpu(hdr->lrh[3]) != qp->remote_ah_attr.dlid ||
+                   ppd_from_ibp(ibp)->port != qp->port_num)
+                       goto err;
+               if (qp->s_mig_state == IB_MIG_REARM &&
+                   !(bth0 & IB_BTH_MIG_REQ))
+                       qp->s_mig_state = IB_MIG_ARMED;
+       }
+
+       return 0;
+
+err:
+       return 1;
+}
+
+/**
+ * qib_ruc_loopback - handle UC and RC lookback requests
+ * @sqp: the sending QP
+ *
+ * This is called from qib_do_send() to
+ * forward a WQE addressed to the same HCA.
+ * Note that although we are single threaded due to the tasklet, we still
+ * have to protect against post_send().  We don't have to worry about
+ * receive interrupts since this is a connected protocol and all packets
+ * will pass through here.
+ */
+static void qib_ruc_loopback(struct qib_qp *sqp)
+{
+       struct qib_ibport *ibp = to_iport(sqp->ibqp.device, sqp->port_num);
+       struct qib_qp *qp;
+       struct qib_swqe *wqe;
+       struct qib_sge *sge;
+       unsigned long flags;
+       struct ib_wc wc;
+       u64 sdata;
+       atomic64_t *maddr;
+       enum ib_wc_status send_status;
+       int release;
+       int ret;
+
+       /*
+        * Note that we check the responder QP state after
+        * checking the requester's state.
+        */
+       qp = qib_lookup_qpn(ibp, sqp->remote_qpn);
+
+       spin_lock_irqsave(&sqp->s_lock, flags);
+
+       /* Return if we are already busy processing a work request. */
+       if ((sqp->s_flags & (QIB_S_BUSY | QIB_S_ANY_WAIT)) ||
+           !(ib_qib_state_ops[sqp->state] & QIB_PROCESS_OR_FLUSH_SEND))
+               goto unlock;
+
+       sqp->s_flags |= QIB_S_BUSY;
+
+again:
+       if (sqp->s_last == sqp->s_head)
+               goto clr_busy;
+       wqe = get_swqe_ptr(sqp, sqp->s_last);
+
+       /* Return if it is not OK to start a new work reqeust. */
+       if (!(ib_qib_state_ops[sqp->state] & QIB_PROCESS_NEXT_SEND_OK)) {
+               if (!(ib_qib_state_ops[sqp->state] & QIB_FLUSH_SEND))
+                       goto clr_busy;
+               /* We are in the error state, flush the work request. */
+               send_status = IB_WC_WR_FLUSH_ERR;
+               goto flush_send;
+       }
+
+       /*
+        * We can rely on the entry not changing without the s_lock
+        * being held until we update s_last.
+        * We increment s_cur to indicate s_last is in progress.
+        */
+       if (sqp->s_last == sqp->s_cur) {
+               if (++sqp->s_cur >= sqp->s_size)
+                       sqp->s_cur = 0;
+       }
+       spin_unlock_irqrestore(&sqp->s_lock, flags);
+
+       if (!qp || !(ib_qib_state_ops[qp->state] & QIB_PROCESS_RECV_OK) ||
+           qp->ibqp.qp_type != sqp->ibqp.qp_type) {
+               ibp->n_pkt_drops++;
+               /*
+                * For RC, the requester would timeout and retry so
+                * shortcut the timeouts and just signal too many retries.
+                */
+               if (sqp->ibqp.qp_type == IB_QPT_RC)
+                       send_status = IB_WC_RETRY_EXC_ERR;
+               else
+                       send_status = IB_WC_SUCCESS;
+               goto serr;
+       }
+
+       memset(&wc, 0, sizeof wc);
+       send_status = IB_WC_SUCCESS;
+
+       release = 1;
+       sqp->s_sge.sge = wqe->sg_list[0];
+       sqp->s_sge.sg_list = wqe->sg_list + 1;
+       sqp->s_sge.num_sge = wqe->wr.num_sge;
+       sqp->s_len = wqe->length;
+       switch (wqe->wr.opcode) {
+       case IB_WR_SEND_WITH_IMM:
+               wc.wc_flags = IB_WC_WITH_IMM;
+               wc.ex.imm_data = wqe->wr.ex.imm_data;
+               /* FALLTHROUGH */
+       case IB_WR_SEND:
+               ret = qib_get_rwqe(qp, 0);
+               if (ret < 0)
+                       goto op_err;
+               if (!ret)
+                       goto rnr_nak;
+               break;
+
+       case IB_WR_RDMA_WRITE_WITH_IMM:
+               if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_WRITE)))
+                       goto inv_err;
+               wc.wc_flags = IB_WC_WITH_IMM;
+               wc.ex.imm_data = wqe->wr.ex.imm_data;
+               ret = qib_get_rwqe(qp, 1);
+               if (ret < 0)
+                       goto op_err;
+               if (!ret)
+                       goto rnr_nak;
+               /* FALLTHROUGH */
+       case IB_WR_RDMA_WRITE:
+               if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_WRITE)))
+                       goto inv_err;
+               if (wqe->length == 0)
+                       break;
+               if (unlikely(!qib_rkey_ok(qp, &qp->r_sge.sge, wqe->length,
+                                         wqe->wr.wr.rdma.remote_addr,
+                                         wqe->wr.wr.rdma.rkey,
+                                         IB_ACCESS_REMOTE_WRITE)))
+                       goto acc_err;
+               qp->r_sge.sg_list = NULL;
+               qp->r_sge.num_sge = 1;
+               qp->r_sge.total_len = wqe->length;
+               break;
+
+       case IB_WR_RDMA_READ:
+               if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_READ)))
+                       goto inv_err;
+               if (unlikely(!qib_rkey_ok(qp, &sqp->s_sge.sge, wqe->length,
+                                         wqe->wr.wr.rdma.remote_addr,
+                                         wqe->wr.wr.rdma.rkey,
+                                         IB_ACCESS_REMOTE_READ)))
+                       goto acc_err;
+               release = 0;
+               sqp->s_sge.sg_list = NULL;
+               sqp->s_sge.num_sge = 1;
+               qp->r_sge.sge = wqe->sg_list[0];
+               qp->r_sge.sg_list = wqe->sg_list + 1;
+               qp->r_sge.num_sge = wqe->wr.num_sge;
+               qp->r_sge.total_len = wqe->length;
+               break;
+
+       case IB_WR_ATOMIC_CMP_AND_SWP:
+       case IB_WR_ATOMIC_FETCH_AND_ADD:
+               if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC)))
+                       goto inv_err;
+               if (unlikely(!qib_rkey_ok(qp, &qp->r_sge.sge, sizeof(u64),
+                                         wqe->wr.wr.atomic.remote_addr,
+                                         wqe->wr.wr.atomic.rkey,
+                                         IB_ACCESS_REMOTE_ATOMIC)))
+                       goto acc_err;
+               /* Perform atomic OP and save result. */
+               maddr = (atomic64_t *) qp->r_sge.sge.vaddr;
+               sdata = wqe->wr.wr.atomic.compare_add;
+               *(u64 *) sqp->s_sge.sge.vaddr =
+                       (wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) ?
+                       (u64) atomic64_add_return(sdata, maddr) - sdata :
+                       (u64) cmpxchg((u64 *) qp->r_sge.sge.vaddr,
+                                     sdata, wqe->wr.wr.atomic.swap);
+               atomic_dec(&qp->r_sge.sge.mr->refcount);
+               qp->r_sge.num_sge = 0;
+               goto send_comp;
+
+       default:
+               send_status = IB_WC_LOC_QP_OP_ERR;
+               goto serr;
+       }
+
+       sge = &sqp->s_sge.sge;
+       while (sqp->s_len) {
+               u32 len = sqp->s_len;
+
+               if (len > sge->length)
+                       len = sge->length;
+               if (len > sge->sge_length)
+                       len = sge->sge_length;
+               BUG_ON(len == 0);
+               qib_copy_sge(&qp->r_sge, sge->vaddr, len, release);
+               sge->vaddr += len;
+               sge->length -= len;
+               sge->sge_length -= len;
+               if (sge->sge_length == 0) {
+                       if (!release)
+                               atomic_dec(&sge->mr->refcount);
+                       if (--sqp->s_sge.num_sge)
+                               *sge = *sqp->s_sge.sg_list++;
+               } else if (sge->length == 0 && sge->mr->lkey) {
+                       if (++sge->n >= QIB_SEGSZ) {
+                               if (++sge->m >= sge->mr->mapsz)
+                                       break;
+                               sge->n = 0;
+                       }
+                       sge->vaddr =
+                               sge->mr->map[sge->m]->segs[sge->n].vaddr;
+                       sge->length =
+                               sge->mr->map[sge->m]->segs[sge->n].length;
+               }
+               sqp->s_len -= len;
+       }
+       if (release)
+               while (qp->r_sge.num_sge) {
+                       atomic_dec(&qp->r_sge.sge.mr->refcount);
+                       if (--qp->r_sge.num_sge)
+                               qp->r_sge.sge = *qp->r_sge.sg_list++;
+               }
+
+       if (!test_and_clear_bit(QIB_R_WRID_VALID, &qp->r_aflags))
+               goto send_comp;
+
+       if (wqe->wr.opcode == IB_WR_RDMA_WRITE_WITH_IMM)
+               wc.opcode = IB_WC_RECV_RDMA_WITH_IMM;
+       else
+               wc.opcode = IB_WC_RECV;
+       wc.wr_id = qp->r_wr_id;
+       wc.status = IB_WC_SUCCESS;
+       wc.byte_len = wqe->length;
+       wc.qp = &qp->ibqp;
+       wc.src_qp = qp->remote_qpn;
+       wc.slid = qp->remote_ah_attr.dlid;
+       wc.sl = qp->remote_ah_attr.sl;
+       wc.port_num = 1;
+       /* Signal completion event if the solicited bit is set. */
+       qib_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,
+                      wqe->wr.send_flags & IB_SEND_SOLICITED);
+
+send_comp:
+       spin_lock_irqsave(&sqp->s_lock, flags);
+       ibp->n_loop_pkts++;
+flush_send:
+       sqp->s_rnr_retry = sqp->s_rnr_retry_cnt;
+       qib_send_complete(sqp, wqe, send_status);
+       goto again;
+
+rnr_nak:
+       /* Handle RNR NAK */
+       if (qp->ibqp.qp_type == IB_QPT_UC)
+               goto send_comp;
+       ibp->n_rnr_naks++;
+       /*
+        * Note: we don't need the s_lock held since the BUSY flag
+        * makes this single threaded.
+        */
+       if (sqp->s_rnr_retry == 0) {
+               send_status = IB_WC_RNR_RETRY_EXC_ERR;
+               goto serr;
+       }
+       if (sqp->s_rnr_retry_cnt < 7)
+               sqp->s_rnr_retry--;
+       spin_lock_irqsave(&sqp->s_lock, flags);
+       if (!(ib_qib_state_ops[sqp->state] & QIB_PROCESS_RECV_OK))
+               goto clr_busy;
+       sqp->s_flags |= QIB_S_WAIT_RNR;
+       sqp->s_timer.function = qib_rc_rnr_retry;
+       sqp->s_timer.expires = jiffies +
+               usecs_to_jiffies(ib_qib_rnr_table[qp->r_min_rnr_timer]);
+       add_timer(&sqp->s_timer);
+       goto clr_busy;
+
+op_err:
+       send_status = IB_WC_REM_OP_ERR;
+       wc.status = IB_WC_LOC_QP_OP_ERR;
+       goto err;
+
+inv_err:
+       send_status = IB_WC_REM_INV_REQ_ERR;
+       wc.status = IB_WC_LOC_QP_OP_ERR;
+       goto err;
+
+acc_err:
+       send_status = IB_WC_REM_ACCESS_ERR;
+       wc.status = IB_WC_LOC_PROT_ERR;
+err:
+       /* responder goes to error state */
+       qib_rc_error(qp, wc.status);
+
+serr:
+       spin_lock_irqsave(&sqp->s_lock, flags);
+       qib_send_complete(sqp, wqe, send_status);
+       if (sqp->ibqp.qp_type == IB_QPT_RC) {
+               int lastwqe = qib_error_qp(sqp, IB_WC_WR_FLUSH_ERR);
+
+               sqp->s_flags &= ~QIB_S_BUSY;
+               spin_unlock_irqrestore(&sqp->s_lock, flags);
+               if (lastwqe) {
+                       struct ib_event ev;
+
+                       ev.device = sqp->ibqp.device;
+                       ev.element.qp = &sqp->ibqp;
+                       ev.event = IB_EVENT_QP_LAST_WQE_REACHED;
+                       sqp->ibqp.event_handler(&ev, sqp->ibqp.qp_context);
+               }
+               goto done;
+       }
+clr_busy:
+       sqp->s_flags &= ~QIB_S_BUSY;
+unlock:
+       spin_unlock_irqrestore(&sqp->s_lock, flags);
+done:
+       if (qp && atomic_dec_and_test(&qp->refcount))
+               wake_up(&qp->wait);
+}
+
+/**
+ * qib_make_grh - construct a GRH header
+ * @ibp: a pointer to the IB port
+ * @hdr: a pointer to the GRH header being constructed
+ * @grh: the global route address to send to
+ * @hwords: the number of 32 bit words of header being sent
+ * @nwords: the number of 32 bit words of data being sent
+ *
+ * Return the size of the header in 32 bit words.
+ */
+u32 qib_make_grh(struct qib_ibport *ibp, struct ib_grh *hdr,
+                struct ib_global_route *grh, u32 hwords, u32 nwords)
+{
+       hdr->version_tclass_flow =
+               cpu_to_be32((IB_GRH_VERSION << IB_GRH_VERSION_SHIFT) |
+                           (grh->traffic_class << IB_GRH_TCLASS_SHIFT) |
+                           (grh->flow_label << IB_GRH_FLOW_SHIFT));
+       hdr->paylen = cpu_to_be16((hwords - 2 + nwords + SIZE_OF_CRC) << 2);
+       /* next_hdr is defined by C8-7 in ch. 8.4.1 */
+       hdr->next_hdr = IB_GRH_NEXT_HDR;
+       hdr->hop_limit = grh->hop_limit;
+       /* The SGID is 32-bit aligned. */
+       hdr->sgid.global.subnet_prefix = ibp->gid_prefix;
+       hdr->sgid.global.interface_id = grh->sgid_index ?
+               ibp->guids[grh->sgid_index - 1] : ppd_from_ibp(ibp)->guid;
+       hdr->dgid = grh->dgid;
+
+       /* GRH header size in 32-bit words. */
+       return sizeof(struct ib_grh) / sizeof(u32);
+}
+
+void qib_make_ruc_header(struct qib_qp *qp, struct qib_other_headers *ohdr,
+                        u32 bth0, u32 bth2)
+{
+       struct qib_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num);
+       u16 lrh0;
+       u32 nwords;
+       u32 extra_bytes;
+
+       /* Construct the header. */
+       extra_bytes = -qp->s_cur_size & 3;
+       nwords = (qp->s_cur_size + extra_bytes) >> 2;
+       lrh0 = QIB_LRH_BTH;
+       if (unlikely(qp->remote_ah_attr.ah_flags & IB_AH_GRH)) {
+               qp->s_hdrwords += qib_make_grh(ibp, &qp->s_hdr.u.l.grh,
+                                              &qp->remote_ah_attr.grh,
+                                              qp->s_hdrwords, nwords);
+               lrh0 = QIB_LRH_GRH;
+       }
+       lrh0 |= ibp->sl_to_vl[qp->remote_ah_attr.sl] << 12 |
+               qp->remote_ah_attr.sl << 4;
+       qp->s_hdr.lrh[0] = cpu_to_be16(lrh0);
+       qp->s_hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid);
+       qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords + SIZE_OF_CRC);
+       qp->s_hdr.lrh[3] = cpu_to_be16(ppd_from_ibp(ibp)->lid |
+                                      qp->remote_ah_attr.src_path_bits);
+       bth0 |= qib_get_pkey(ibp, qp->s_pkey_index);
+       bth0 |= extra_bytes << 20;
+       if (qp->s_mig_state == IB_MIG_MIGRATED)
+               bth0 |= IB_BTH_MIG_REQ;
+       ohdr->bth[0] = cpu_to_be32(bth0);
+       ohdr->bth[1] = cpu_to_be32(qp->remote_qpn);
+       ohdr->bth[2] = cpu_to_be32(bth2);
+}
+
+/**
+ * qib_do_send - perform a send on a QP
+ * @work: contains a pointer to the QP
+ *
+ * Process entries in the send work queue until credit or queue is
+ * exhausted.  Only allow one CPU to send a packet per QP (tasklet).
+ * Otherwise, two threads could send packets out of order.
+ */
+void qib_do_send(struct work_struct *work)
+{
+       struct qib_qp *qp = container_of(work, struct qib_qp, s_work);
+       struct qib_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num);
+       struct qib_pportdata *ppd = ppd_from_ibp(ibp);
+       int (*make_req)(struct qib_qp *qp);
+       unsigned long flags;
+
+       if ((qp->ibqp.qp_type == IB_QPT_RC ||
+            qp->ibqp.qp_type == IB_QPT_UC) &&
+           (qp->remote_ah_attr.dlid & ~((1 << ppd->lmc) - 1)) == ppd->lid) {
+               qib_ruc_loopback(qp);
+               return;
+       }
+
+       if (qp->ibqp.qp_type == IB_QPT_RC)
+               make_req = qib_make_rc_req;
+       else if (qp->ibqp.qp_type == IB_QPT_UC)
+               make_req = qib_make_uc_req;
+       else
+               make_req = qib_make_ud_req;
+
+       spin_lock_irqsave(&qp->s_lock, flags);
+
+       /* Return if we are already busy processing a work request. */
+       if (!qib_send_ok(qp)) {
+               spin_unlock_irqrestore(&qp->s_lock, flags);
+               return;
+       }
+
+       qp->s_flags |= QIB_S_BUSY;
+
+       spin_unlock_irqrestore(&qp->s_lock, flags);
+
+       do {
+               /* Check for a constructed packet to be sent. */
+               if (qp->s_hdrwords != 0) {
+                       /*
+                        * If the packet cannot be sent now, return and
+                        * the send tasklet will be woken up later.
+                        */
+                       if (qib_verbs_send(qp, &qp->s_hdr, qp->s_hdrwords,
+                                          qp->s_cur_sge, qp->s_cur_size))
+                               break;
+                       /* Record that s_hdr is empty. */
+                       qp->s_hdrwords = 0;
+               }
+       } while (make_req(qp));
+}
+
+/*
+ * This should be called with s_lock held.
+ */
+void qib_send_complete(struct qib_qp *qp, struct qib_swqe *wqe,
+                      enum ib_wc_status status)
+{
+       u32 old_last, last;
+       unsigned i;
+
+       if (!(ib_qib_state_ops[qp->state] & QIB_PROCESS_OR_FLUSH_SEND))
+               return;
+
+       for (i = 0; i < wqe->wr.num_sge; i++) {
+               struct qib_sge *sge = &wqe->sg_list[i];
+
+               atomic_dec(&sge->mr->refcount);
+       }
+       if (qp->ibqp.qp_type == IB_QPT_UD ||
+           qp->ibqp.qp_type == IB_QPT_SMI ||
+           qp->ibqp.qp_type == IB_QPT_GSI)
+               atomic_dec(&to_iah(wqe->wr.wr.ud.ah)->refcount);
+
+       /* See ch. 11.2.4.1 and 10.7.3.1 */
+       if (!(qp->s_flags & QIB_S_SIGNAL_REQ_WR) ||
+           (wqe->wr.send_flags & IB_SEND_SIGNALED) ||
+           status != IB_WC_SUCCESS) {
+               struct ib_wc wc;
+
+               memset(&wc, 0, sizeof wc);
+               wc.wr_id = wqe->wr.wr_id;
+               wc.status = status;
+               wc.opcode = ib_qib_wc_opcode[wqe->wr.opcode];
+               wc.qp = &qp->ibqp;
+               if (status == IB_WC_SUCCESS)
+                       wc.byte_len = wqe->length;
+               qib_cq_enter(to_icq(qp->ibqp.send_cq), &wc,
+                            status != IB_WC_SUCCESS);
+       }
+
+       last = qp->s_last;
+       old_last = last;
+       if (++last >= qp->s_size)
+               last = 0;
+       qp->s_last = last;
+       if (qp->s_acked == old_last)
+               qp->s_acked = last;
+       if (qp->s_cur == old_last)
+               qp->s_cur = last;
+       if (qp->s_tail == old_last)
+               qp->s_tail = last;
+       if (qp->state == IB_QPS_SQD && last == qp->s_cur)
+               qp->s_draining = 0;
+}
similarity index 57%
rename from drivers/infiniband/hw/ipath/ipath_sd7220.c
rename to drivers/infiniband/hw/qib/qib_sd7220.c
index 2a68d9f624dd350f0eda45bcb51ca05717685d32..0aeed0e74cb67296ddccf38dd06679f8cb20cb15 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved.
+ * Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved.
  * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  */
 /*
  * This file contains all of the code that is specific to the SerDes
- * on the InfiniPath 7220 chip.
+ * on the QLogic_IB 7220 chip.
  */
 
 #include <linux/pci.h>
 #include <linux/delay.h>
 
-#include "ipath_kernel.h"
-#include "ipath_registers.h"
-#include "ipath_7220.h"
+#include "qib.h"
+#include "qib_7220.h"
+
+/*
+ * Same as in qib_iba7220.c, but just the registers needed here.
+ * Could move whole set to qib_7220.h, but decided better to keep
+ * local.
+ */
+#define KREG_IDX(regname) (QIB_7220_##regname##_OFFS / sizeof(u64))
+#define kr_hwerrclear KREG_IDX(HwErrClear)
+#define kr_hwerrmask KREG_IDX(HwErrMask)
+#define kr_hwerrstatus KREG_IDX(HwErrStatus)
+#define kr_ibcstatus KREG_IDX(IBCStatus)
+#define kr_ibserdesctrl KREG_IDX(IBSerDesCtrl)
+#define kr_scratch KREG_IDX(Scratch)
+#define kr_xgxs_cfg KREG_IDX(XGXSCfg)
+/* these are used only here, not in qib_iba7220.c */
+#define kr_ibsd_epb_access_ctrl KREG_IDX(ibsd_epb_access_ctrl)
+#define kr_ibsd_epb_transaction_reg KREG_IDX(ibsd_epb_transaction_reg)
+#define kr_pciesd_epb_transaction_reg KREG_IDX(pciesd_epb_transaction_reg)
+#define kr_pciesd_epb_access_ctrl KREG_IDX(pciesd_epb_access_ctrl)
+#define kr_serdes_ddsrxeq0 KREG_IDX(SerDes_DDSRXEQ0)
 
 /*
  * The IBSerDesMappTable is a memory that holds values to be stored in
- * various SerDes registers by IBC. It is not part of the normal kregs
- * map and is used in exactly one place, hence the #define below.
+ * various SerDes registers by IBC.
  */
-#define KR_IBSerDesMappTable (0x94000 / (sizeof(uint64_t)))
+#define kr_serdes_maptable KREG_IDX(IBSerDesMappTable)
 
 /*
  * Below used for sdnum parameter, selecting one of the two sections
 #define EPB_GLOBAL_WR (1U << (EPB_ADDR_SHF + 8))
 
 /* Forward declarations. */
-static int ipath_sd7220_reg_mod(struct ipath_devdata *dd, int sdnum, u32 loc,
-                               u32 data, u32 mask);
-static int ibsd_mod_allchnls(struct ipath_devdata *dd, int loc, int val,
+static int qib_sd7220_reg_mod(struct qib_devdata *dd, int sdnum, u32 loc,
+                             u32 data, u32 mask);
+static int ibsd_mod_allchnls(struct qib_devdata *dd, int loc, int val,
                             int mask);
-static int ipath_sd_trimdone_poll(struct ipath_devdata *dd);
-static void ipath_sd_trimdone_monitor(struct ipath_devdata *dd,
-                                     const char *where);
-static int ipath_sd_setvals(struct ipath_devdata *dd);
-static int ipath_sd_early(struct ipath_devdata *dd);
-static int ipath_sd_dactrim(struct ipath_devdata *dd);
-/* Set the registers that IBC may muck with to their default "preset" values */
-int ipath_sd7220_presets(struct ipath_devdata *dd);
-static int ipath_internal_presets(struct ipath_devdata *dd);
+static int qib_sd_trimdone_poll(struct qib_devdata *dd);
+static void qib_sd_trimdone_monitor(struct qib_devdata *dd, const char *where);
+static int qib_sd_setvals(struct qib_devdata *dd);
+static int qib_sd_early(struct qib_devdata *dd);
+static int qib_sd_dactrim(struct qib_devdata *dd);
+static int qib_internal_presets(struct qib_devdata *dd);
 /* Tweak the register (CMUCTRL5) that contains the TRIMSELF controls */
-static int ipath_sd_trimself(struct ipath_devdata *dd, int val);
-static int epb_access(struct ipath_devdata *dd, int sdnum, int claim);
-
-void ipath_set_relock_poll(struct ipath_devdata *dd, int ibup);
+static int qib_sd_trimself(struct qib_devdata *dd, int val);
+static int epb_access(struct qib_devdata *dd, int sdnum, int claim);
 
 /*
  * Below keeps track of whether the "once per power-on" initialization has
  * been done, because uC code Version 1.32.17 or higher allows the uC to
  * be reset at will, and Automatic Equalization may require it. So the
- * state of the reset "pin", as reflected in was_reset parameter to
- * ipath_sd7220_init() is no longer valid. Instead, we check for the
+ * state of the reset "pin", is no longer valid. Instead, we check for the
  * actual uC code having been loaded.
  */
-static int ipath_ibsd_ucode_loaded(struct ipath_devdata *dd)
+static int qib_ibsd_ucode_loaded(struct qib_pportdata *ppd)
 {
-       if (!dd->serdes_first_init_done && (ipath_sd7220_ib_vfy(dd) > 0))
-               dd->serdes_first_init_done = 1;
-       return dd->serdes_first_init_done;
+       struct qib_devdata *dd = ppd->dd;
+       if (!dd->cspec->serdes_first_init_done && (qib_sd7220_ib_vfy(dd) > 0))
+               dd->cspec->serdes_first_init_done = 1;
+       return dd->cspec->serdes_first_init_done;
 }
 
-/* repeat #define for local use. "Real" #define is in ipath_iba7220.c */
-#define INFINIPATH_HWE_IB_UC_MEMORYPARITYERR      0x0000004000000000ULL
+/* repeat #define for local use. "Real" #define is in qib_iba7220.c */
+#define QLOGIC_IB_HWE_IB_UC_MEMORYPARITYERR      0x0000004000000000ULL
 #define IB_MPREG5 (EPB_LOC(6, 0, 0xE) | (1L << EPB_IB_UC_CS_SHF))
 #define IB_MPREG6 (EPB_LOC(6, 0, 0xF) | (1U << EPB_IB_UC_CS_SHF))
 #define UC_PAR_CLR_D 8
@@ -114,25 +127,25 @@ static int ipath_ibsd_ucode_loaded(struct ipath_devdata *dd)
 #define IB_CTRL2(chn) (EPB_LOC(chn, 7, 3) | EPB_IB_QUAD0_CS)
 #define START_EQ1(chan) EPB_LOC(chan, 7, 0x27)
 
-void ipath_sd7220_clr_ibpar(struct ipath_devdata *dd)
+void qib_sd7220_clr_ibpar(struct qib_devdata *dd)
 {
        int ret;
 
        /* clear, then re-enable parity errs */
-       ret = ipath_sd7220_reg_mod(dd, IB_7220_SERDES, IB_MPREG6,
+       ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, IB_MPREG6,
                UC_PAR_CLR_D, UC_PAR_CLR_M);
        if (ret < 0) {
-               ipath_dev_err(dd, "Failed clearing IBSerDes Parity err\n");
+               qib_dev_err(dd, "Failed clearing IBSerDes Parity err\n");
                goto bail;
        }
-       ret = ipath_sd7220_reg_mod(dd, IB_7220_SERDES, IB_MPREG6, 0,
+       ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, IB_MPREG6, 0,
                UC_PAR_CLR_M);
 
-       ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
+       qib_read_kreg32(dd, kr_scratch);
        udelay(4);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear,
-               INFINIPATH_HWE_IB_UC_MEMORYPARITYERR);
-       ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
+       qib_write_kreg(dd, kr_hwerrclear,
+               QLOGIC_IB_HWE_IB_UC_MEMORYPARITYERR);
+       qib_read_kreg32(dd, kr_scratch);
 bail:
        return;
 }
@@ -146,7 +159,7 @@ bail:
 #define IB_PGUDP(chn) (EPB_LOC((chn), 2, 1) | EPB_IB_QUAD0_CS)
 #define IB_CMUDONE(chn) (EPB_LOC((chn), 7, 0xF) | EPB_IB_QUAD0_CS)
 
-static int ipath_resync_ibepb(struct ipath_devdata *dd)
+static int qib_resync_ibepb(struct qib_devdata *dd)
 {
        int ret, pat, tries, chn;
        u32 loc;
@@ -155,43 +168,42 @@ static int ipath_resync_ibepb(struct ipath_devdata *dd)
        chn = 0;
        for (tries = 0; tries < (4 * IBSD_RESYNC_TRIES); ++tries) {
                loc = IB_PGUDP(chn);
-               ret = ipath_sd7220_reg_mod(dd, IB_7220_SERDES, loc, 0, 0);
+               ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, loc, 0, 0);
                if (ret < 0) {
-                       ipath_dev_err(dd, "Failed read in resync\n");
+                       qib_dev_err(dd, "Failed read in resync\n");
                        continue;
                }
                if (ret != 0xF0 && ret != 0x55 && tries == 0)
-                       ipath_dev_err(dd, "unexpected pattern in resync\n");
+                       qib_dev_err(dd, "unexpected pattern in resync\n");
                pat = ret ^ 0xA5; /* alternate F0 and 55 */
-               ret = ipath_sd7220_reg_mod(dd, IB_7220_SERDES, loc, pat, 0xFF);
+               ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, loc, pat, 0xFF);
                if (ret < 0) {
-                       ipath_dev_err(dd, "Failed write in resync\n");
+                       qib_dev_err(dd, "Failed write in resync\n");
                        continue;
                }
-               ret = ipath_sd7220_reg_mod(dd, IB_7220_SERDES, loc, 0, 0);
+               ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, loc, 0, 0);
                if (ret < 0) {
-                       ipath_dev_err(dd, "Failed re-read in resync\n");
+                       qib_dev_err(dd, "Failed re-read in resync\n");
                        continue;
                }
                if (ret != pat) {
-                       ipath_dev_err(dd, "Failed compare1 in resync\n");
+                       qib_dev_err(dd, "Failed compare1 in resync\n");
                        continue;
                }
                loc = IB_CMUDONE(chn);
-               ret = ipath_sd7220_reg_mod(dd, IB_7220_SERDES, loc, 0, 0);
+               ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, loc, 0, 0);
                if (ret < 0) {
-                       ipath_dev_err(dd, "Failed CMUDONE rd in resync\n");
+                       qib_dev_err(dd, "Failed CMUDONE rd in resync\n");
                        continue;
                }
                if ((ret & 0x70) != ((chn << 4) | 0x40)) {
-                       ipath_dev_err(dd, "Bad CMUDONE value %02X, chn %d\n",
-                               ret, chn);
+                       qib_dev_err(dd, "Bad CMUDONE value %02X, chn %d\n",
+                                   ret, chn);
                        continue;
                }
                if (++chn == 4)
                        break;  /* Success */
        }
-       ipath_cdbg(VERBOSE, "Resync in %d tries\n", tries);
        return (ret > 0) ? 0 : ret;
 }
 
@@ -199,32 +211,32 @@ static int ipath_resync_ibepb(struct ipath_devdata *dd)
  * Localize the stuff that should be done to change IB uC reset
  * returns <0 for errors.
  */
-static int ipath_ibsd_reset(struct ipath_devdata *dd, int assert_rst)
+static int qib_ibsd_reset(struct qib_devdata *dd, int assert_rst)
 {
        u64 rst_val;
        int ret = 0;
        unsigned long flags;
 
-       rst_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibserdesctrl);
+       rst_val = qib_read_kreg64(dd, kr_ibserdesctrl);
        if (assert_rst) {
                /*
                 * Vendor recommends "interrupting" uC before reset, to
                 * minimize possible glitches.
                 */
-               spin_lock_irqsave(&dd->ipath_sdepb_lock, flags);
+               spin_lock_irqsave(&dd->cspec->sdepb_lock, flags);
                epb_access(dd, IB_7220_SERDES, 1);
                rst_val |= 1ULL;
                /* Squelch possible parity error from _asserting_ reset */
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
-                       dd->ipath_hwerrmask &
-                       ~INFINIPATH_HWE_IB_UC_MEMORYPARITYERR);
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_ibserdesctrl, rst_val);
+               qib_write_kreg(dd, kr_hwerrmask,
+                              dd->cspec->hwerrmask &
+                              ~QLOGIC_IB_HWE_IB_UC_MEMORYPARITYERR);
+               qib_write_kreg(dd, kr_ibserdesctrl, rst_val);
                /* flush write, delay to ensure it took effect */
-               ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
+               qib_read_kreg32(dd, kr_scratch);
                udelay(2);
                /* once it's reset, can remove interrupt */
                epb_access(dd, IB_7220_SERDES, -1);
-               spin_unlock_irqrestore(&dd->ipath_sdepb_lock, flags);
+               spin_unlock_irqrestore(&dd->cspec->sdepb_lock, flags);
        } else {
                /*
                 * Before we de-assert reset, we need to deal with
@@ -235,46 +247,46 @@ static int ipath_ibsd_reset(struct ipath_devdata *dd, int assert_rst)
                 */
                u64 val;
                rst_val &= ~(1ULL);
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
-                       dd->ipath_hwerrmask &
-                       ~INFINIPATH_HWE_IB_UC_MEMORYPARITYERR);
+               qib_write_kreg(dd, kr_hwerrmask,
+                              dd->cspec->hwerrmask &
+                              ~QLOGIC_IB_HWE_IB_UC_MEMORYPARITYERR);
 
-               ret = ipath_resync_ibepb(dd);
+               ret = qib_resync_ibepb(dd);
                if (ret < 0)
-                       ipath_dev_err(dd, "unable to re-sync IB EPB\n");
+                       qib_dev_err(dd, "unable to re-sync IB EPB\n");
 
                /* set uC control regs to suppress parity errs */
-               ret = ipath_sd7220_reg_mod(dd, IB_7220_SERDES, IB_MPREG5, 1, 1);
+               ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, IB_MPREG5, 1, 1);
                if (ret < 0)
                        goto bail;
                /* IB uC code past Version 1.32.17 allow suppression of wdog */
-               ret = ipath_sd7220_reg_mod(dd, IB_7220_SERDES, IB_MPREG6, 0x80,
+               ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, IB_MPREG6, 0x80,
                        0x80);
                if (ret < 0) {
-                       ipath_dev_err(dd, "Failed to set WDOG disable\n");
+                       qib_dev_err(dd, "Failed to set WDOG disable\n");
                        goto bail;
                }
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_ibserdesctrl, rst_val);
+               qib_write_kreg(dd, kr_ibserdesctrl, rst_val);
                /* flush write, delay for startup */
-               ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
+               qib_read_kreg32(dd, kr_scratch);
                udelay(1);
                /* clear, then re-enable parity errs */
-               ipath_sd7220_clr_ibpar(dd);
-               val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwerrstatus);
-               if (val & INFINIPATH_HWE_IB_UC_MEMORYPARITYERR) {
-                       ipath_dev_err(dd, "IBUC Parity still set after RST\n");
-                       dd->ipath_hwerrmask &=
-                               ~INFINIPATH_HWE_IB_UC_MEMORYPARITYERR;
+               qib_sd7220_clr_ibpar(dd);
+               val = qib_read_kreg64(dd, kr_hwerrstatus);
+               if (val & QLOGIC_IB_HWE_IB_UC_MEMORYPARITYERR) {
+                       qib_dev_err(dd, "IBUC Parity still set after RST\n");
+                       dd->cspec->hwerrmask &=
+                               ~QLOGIC_IB_HWE_IB_UC_MEMORYPARITYERR;
                }
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
-                       dd->ipath_hwerrmask);
+               qib_write_kreg(dd, kr_hwerrmask,
+                       dd->cspec->hwerrmask);
        }
 
 bail:
        return ret;
 }
 
-static void ipath_sd_trimdone_monitor(struct ipath_devdata *dd,
+static void qib_sd_trimdone_monitor(struct qib_devdata *dd,
        const char *where)
 {
        int ret, chn, baduns;
@@ -286,69 +298,71 @@ static void ipath_sd_trimdone_monitor(struct ipath_devdata *dd,
        /* give time for reset to settle out in EPB */
        udelay(2);
 
-       ret = ipath_resync_ibepb(dd);
+       ret = qib_resync_ibepb(dd);
        if (ret < 0)
-               ipath_dev_err(dd, "not able to re-sync IB EPB (%s)\n", where);
+               qib_dev_err(dd, "not able to re-sync IB EPB (%s)\n", where);
 
        /* Do "sacrificial read" to get EPB in sane state after reset */
-       ret = ipath_sd7220_reg_mod(dd, IB_7220_SERDES, IB_CTRL2(0), 0, 0);
+       ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, IB_CTRL2(0), 0, 0);
        if (ret < 0)
-               ipath_dev_err(dd, "Failed TRIMDONE 1st read, (%s)\n", where);
+               qib_dev_err(dd, "Failed TRIMDONE 1st read, (%s)\n", where);
 
        /* Check/show "summary" Trim-done bit in IBCStatus */
-       val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibcstatus);
-       if (val & (1ULL << 11))
-               ipath_cdbg(VERBOSE, "IBCS TRIMDONE set (%s)\n", where);
-       else
-               ipath_dev_err(dd, "IBCS TRIMDONE clear (%s)\n", where);
-
+       val = qib_read_kreg64(dd, kr_ibcstatus);
+       if (!(val & (1ULL << 11)))
+               qib_dev_err(dd, "IBCS TRIMDONE clear (%s)\n", where);
+       /*
+        * Do "dummy read/mod/wr" to get EPB in sane state after reset
+        * The default value for MPREG6 is 0.
+        */
        udelay(2);
 
-       ret = ipath_sd7220_reg_mod(dd, IB_7220_SERDES, IB_MPREG6, 0x80, 0x80);
+       ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, IB_MPREG6, 0x80, 0x80);
        if (ret < 0)
-               ipath_dev_err(dd, "Failed Dummy RMW, (%s)\n", where);
+               qib_dev_err(dd, "Failed Dummy RMW, (%s)\n", where);
        udelay(10);
 
        baduns = 0;
 
        for (chn = 3; chn >= 0; --chn) {
                /* Read CTRL reg for each channel to check TRIMDONE */
-               ret = ipath_sd7220_reg_mod(dd, IB_7220_SERDES,
+               ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES,
                        IB_CTRL2(chn), 0, 0);
                if (ret < 0)
-                       ipath_dev_err(dd, "Failed checking TRIMDONE, chn %d"
-                               " (%s)\n", chn, where);
+                       qib_dev_err(dd, "Failed checking TRIMDONE, chn %d"
+                                   " (%s)\n", chn, where);
 
                if (!(ret & 0x10)) {
                        int probe;
+
                        baduns |= (1 << chn);
-                       ipath_dev_err(dd, "TRIMDONE cleared on chn %d (%02X)."
+                       qib_dev_err(dd, "TRIMDONE cleared on chn %d (%02X)."
                                " (%s)\n", chn, ret, where);
-                       probe = ipath_sd7220_reg_mod(dd, IB_7220_SERDES,
+                       probe = qib_sd7220_reg_mod(dd, IB_7220_SERDES,
                                IB_PGUDP(0), 0, 0);
-                       ipath_dev_err(dd, "probe is %d (%02X)\n",
+                       qib_dev_err(dd, "probe is %d (%02X)\n",
                                probe, probe);
-                       probe = ipath_sd7220_reg_mod(dd, IB_7220_SERDES,
+                       probe = qib_sd7220_reg_mod(dd, IB_7220_SERDES,
                                IB_CTRL2(chn), 0, 0);
-                       ipath_dev_err(dd, "re-read: %d (%02X)\n",
+                       qib_dev_err(dd, "re-read: %d (%02X)\n",
                                probe, probe);
-                       ret = ipath_sd7220_reg_mod(dd, IB_7220_SERDES,
+                       ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES,
                                IB_CTRL2(chn), 0x10, 0x10);
                        if (ret < 0)
-                               ipath_dev_err(dd,
+                               qib_dev_err(dd,
                                        "Err on TRIMDONE rewrite1\n");
                }
        }
        for (chn = 3; chn >= 0; --chn) {
                /* Read CTRL reg for each channel to check TRIMDONE */
                if (baduns & (1 << chn)) {
-                       ipath_dev_err(dd,
+                       qib_dev_err(dd,
                                "Reseting TRIMDONE on chn %d (%s)\n",
                                chn, where);
-                       ret = ipath_sd7220_reg_mod(dd, IB_7220_SERDES,
+                       ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES,
                                IB_CTRL2(chn), 0x10, 0x10);
                        if (ret < 0)
-                               ipath_dev_err(dd, "Failed re-setting "
+                               qib_dev_err(dd, "Failed re-setting "
                                        "TRIMDONE, chn %d (%s)\n",
                                        chn, where);
                }
@@ -361,96 +375,86 @@ static void ipath_sd_trimdone_monitor(struct ipath_devdata *dd,
  * Post IB uC code version 1.32.17, was_reset being 1 is not really
  * informative, so we double-check.
  */
-int ipath_sd7220_init(struct ipath_devdata *dd, int was_reset)
+int qib_sd7220_init(struct qib_devdata *dd)
 {
        int ret = 1; /* default to failure */
-       int first_reset;
-       int val_stat;
+       int first_reset, was_reset;
 
+       /* SERDES MPU reset recorded in D0 */
+       was_reset = (qib_read_kreg64(dd, kr_ibserdesctrl) & 1);
        if (!was_reset) {
                /* entered with reset not asserted, we need to do it */
-               ipath_ibsd_reset(dd, 1);
-               ipath_sd_trimdone_monitor(dd, "Driver-reload");
+               qib_ibsd_reset(dd, 1);
+               qib_sd_trimdone_monitor(dd, "Driver-reload");
        }
-
        /* Substitute our deduced value for was_reset */
-       ret = ipath_ibsd_ucode_loaded(dd);
-       if (ret < 0) {
-               ret = 1;
-               goto done;
-       }
-       first_reset = !ret; /* First reset if IBSD uCode not yet loaded */
+       ret = qib_ibsd_ucode_loaded(dd->pport);
+       if (ret < 0)
+               goto bail;
 
+       first_reset = !ret; /* First reset if IBSD uCode not yet loaded */
        /*
         * Alter some regs per vendor latest doc, reset-defaults
         * are not right for IB.
         */
-       ret = ipath_sd_early(dd);
+       ret = qib_sd_early(dd);
        if (ret < 0) {
-               ipath_dev_err(dd, "Failed to set IB SERDES early defaults\n");
-               ret = 1;
-               goto done;
+               qib_dev_err(dd, "Failed to set IB SERDES early defaults\n");
+               goto bail;
        }
-
        /*
         * Set DAC manual trim IB.
         * We only do this once after chip has been reset (usually
         * same as once per system boot).
         */
        if (first_reset) {
-               ret = ipath_sd_dactrim(dd);
+               ret = qib_sd_dactrim(dd);
                if (ret < 0) {
-                       ipath_dev_err(dd, "Failed IB SERDES DAC trim\n");
-                       ret = 1;
-                       goto done;
+                       qib_dev_err(dd, "Failed IB SERDES DAC trim\n");
+                       goto bail;
                }
        }
-
        /*
         * Set various registers (DDS and RXEQ) that will be
         * controlled by IBC (in 1.2 mode) to reasonable preset values
         * Calling the "internal" version avoids the "check for needed"
         * and "trimdone monitor" that might be counter-productive.
         */
-       ret = ipath_internal_presets(dd);
+       ret = qib_internal_presets(dd);
        if (ret < 0) {
-               ipath_dev_err(dd, "Failed to set IB SERDES presets\n");
-               ret = 1;
-               goto done;
+               qib_dev_err(dd, "Failed to set IB SERDES presets\n");
+               goto bail;
        }
-       ret = ipath_sd_trimself(dd, 0x80);
+       ret = qib_sd_trimself(dd, 0x80);
        if (ret < 0) {
-               ipath_dev_err(dd, "Failed to set IB SERDES TRIMSELF\n");
-               ret = 1;
-               goto done;
+               qib_dev_err(dd, "Failed to set IB SERDES TRIMSELF\n");
+               goto bail;
        }
 
        /* Load image, then try to verify */
-       ret = 0;        /* Assume success */
+       ret = 0;        /* Assume success */
        if (first_reset) {
                int vfy;
                int trim_done;
-               ipath_dbg("SerDes uC was reset, reloading PRAM\n");
-               ret = ipath_sd7220_ib_load(dd);
+
+               ret = qib_sd7220_ib_load(dd);
                if (ret < 0) {
-                       ipath_dev_err(dd, "Failed to load IB SERDES image\n");
-                       ret = 1;
-                       goto done;
-               }
+                       qib_dev_err(dd, "Failed to load IB SERDES image\n");
+                       goto bail;
+               } else {
+                       /* Loaded image, try to verify */
+                       vfy = qib_sd7220_ib_vfy(dd);
+                       if (vfy != ret) {
+                               qib_dev_err(dd, "SERDES PRAM VFY failed\n");
+                               goto bail;
+                       } /* end if verified */
+               } /* end if loaded */
 
-               /* Loaded image, try to verify */
-               vfy = ipath_sd7220_ib_vfy(dd);
-               if (vfy != ret) {
-                       ipath_dev_err(dd, "SERDES PRAM VFY failed\n");
-                       ret = 1;
-                       goto done;
-               }
                /*
                 * Loaded and verified. Almost good...
                 * hold "success" in ret
                 */
                ret = 0;
-
                /*
                 * Prev steps all worked, continue bringup
                 * De-assert RESET to uC, only in first reset, to allow
@@ -461,45 +465,47 @@ int ipath_sd7220_init(struct ipath_devdata *dd, int was_reset)
                 */
                ret = ibsd_mod_allchnls(dd, START_EQ1(0), 0, 0x38);
                if (ret < 0) {
-                       ipath_dev_err(dd, "Failed clearing START_EQ1\n");
-                       ret = 1;
-                       goto done;
+                       qib_dev_err(dd, "Failed clearing START_EQ1\n");
+                       goto bail;
                }
 
-               ipath_ibsd_reset(dd, 0);
+               qib_ibsd_reset(dd, 0);
                /*
                 * If this is not the first reset, trimdone should be set
-                * already.
+                * already. We may need to check about this.
                 */
-               trim_done = ipath_sd_trimdone_poll(dd);
+               trim_done = qib_sd_trimdone_poll(dd);
                /*
                 * Whether or not trimdone succeeded, we need to put the
                 * uC back into reset to avoid a possible fight with the
                 * IBC state-machine.
                 */
-               ipath_ibsd_reset(dd, 1);
+               qib_ibsd_reset(dd, 1);
 
                if (!trim_done) {
-                       ipath_dev_err(dd, "No TRIMDONE seen\n");
-                       ret = 1;
-                       goto done;
+                       qib_dev_err(dd, "No TRIMDONE seen\n");
+                       goto bail;
                }
-
-               ipath_sd_trimdone_monitor(dd, "First-reset");
+               /*
+                * DEBUG: check each time we reset if trimdone bits have
+                * gotten cleared, and re-set them.
+                */
+               qib_sd_trimdone_monitor(dd, "First-reset");
                /* Remember so we do not re-do the load, dactrim, etc. */
-               dd->serdes_first_init_done = 1;
+               dd->cspec->serdes_first_init_done = 1;
        }
        /*
-        * Setup for channel training and load values for
+        * setup for channel training and load values for
         * RxEq and DDS in tables used by IBC in IB1.2 mode
         */
-
-       val_stat = ipath_sd_setvals(dd);
-       if (val_stat < 0)
-               ret = 1;
+       ret = 0;
+       if (qib_sd_setvals(dd) >= 0)
+               goto done;
+bail:
+       ret = 1;
 done:
        /* start relock timer regardless, but start at 1 second */
-       ipath_set_relock_poll(dd, -1);
+       set_7220_relock_poll(dd, -1);
        return ret;
 }
 
@@ -517,7 +523,7 @@ done:
  * the "claim" parameter is >0 to claim, <0 to release, 0 to query.
  * Returns <0 for errors, >0 if we had ownership, else 0.
  */
-static int epb_access(struct ipath_devdata *dd, int sdnum, int claim)
+static int epb_access(struct qib_devdata *dd, int sdnum, int claim)
 {
        u16 acc;
        u64 accval;
@@ -525,28 +531,30 @@ static int epb_access(struct ipath_devdata *dd, int sdnum, int claim)
        u64 oct_sel = 0;
 
        switch (sdnum) {
-       case IB_7220_SERDES :
+       case IB_7220_SERDES:
                /*
                 * The IB SERDES "ownership" is fairly simple. A single each
                 * request/grant.
                 */
-               acc = dd->ipath_kregs->kr_ib_epbacc;
+               acc = kr_ibsd_epb_access_ctrl;
                break;
-       case PCIE_SERDES0 :
-       case PCIE_SERDES1 :
+
+       case PCIE_SERDES0:
+       case PCIE_SERDES1:
                /* PCIe SERDES has two "octants", need to select which */
-               acc = dd->ipath_kregs->kr_pcie_epbacc;
+               acc = kr_pciesd_epb_access_ctrl;
                oct_sel = (2 << (sdnum - PCIE_SERDES0));
                break;
-       default :
+
+       default:
                return 0;
        }
 
        /* Make sure any outstanding transaction was seen */
-       ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
+       qib_read_kreg32(dd, kr_scratch);
        udelay(15);
 
-       accval = ipath_read_kreg32(dd, acc);
+       accval = qib_read_kreg32(dd, acc);
 
        owned = !!(accval & EPB_ACC_GNT);
        if (claim < 0) {
@@ -557,22 +565,22 @@ static int epb_access(struct ipath_devdata *dd, int sdnum, int claim)
                 * Both should be clear
                 */
                u64 newval = 0;
-               ipath_write_kreg(dd, acc, newval);
+               qib_write_kreg(dd, acc, newval);
                /* First read after write is not trustworthy */
-               pollval = ipath_read_kreg32(dd, acc);
+               pollval = qib_read_kreg32(dd, acc);
                udelay(5);
-               pollval = ipath_read_kreg32(dd, acc);
+               pollval = qib_read_kreg32(dd, acc);
                if (pollval & EPB_ACC_GNT)
                        owned = -1;
        } else if (claim > 0) {
                /* Need to claim */
                u64 pollval;
                u64 newval = EPB_ACC_REQ | oct_sel;
-               ipath_write_kreg(dd, acc, newval);
+               qib_write_kreg(dd, acc, newval);
                /* First read after write is not trustworthy */
-               pollval = ipath_read_kreg32(dd, acc);
+               pollval = qib_read_kreg32(dd, acc);
                udelay(5);
-               pollval = ipath_read_kreg32(dd, acc);
+               pollval = qib_read_kreg32(dd, acc);
                if (!(pollval & EPB_ACC_GNT))
                        owned = -1;
        }
@@ -582,18 +590,17 @@ static int epb_access(struct ipath_devdata *dd, int sdnum, int claim)
 /*
  * Lemma to deal with race condition of write..read to epb regs
  */
-static int epb_trans(struct ipath_devdata *dd, u16 reg, u64 i_val, u64 *o_vp)
+static int epb_trans(struct qib_devdata *dd, u16 reg, u64 i_val, u64 *o_vp)
 {
        int tries;
        u64 transval;
 
-
-       ipath_write_kreg(dd, reg, i_val);
+       qib_write_kreg(dd, reg, i_val);
        /* Throw away first read, as RDY bit may be stale */
-       transval = ipath_read_kreg64(dd, reg);
+       transval = qib_read_kreg64(dd, reg);
 
        for (tries = EPB_TRANS_TRIES; tries; --tries) {
-               transval = ipath_read_kreg32(dd, reg);
+               transval = qib_read_kreg32(dd, reg);
                if (transval & EPB_TRANS_RDY)
                        break;
                udelay(5);
@@ -606,21 +613,20 @@ static int epb_trans(struct ipath_devdata *dd, u16 reg, u64 i_val, u64 *o_vp)
 }
 
 /**
- *
- * ipath_sd7220_reg_mod - modify SERDES register
- * @dd: the infinipath device
+ * qib_sd7220_reg_mod - modify SERDES register
+ * @dd: the qlogic_ib device
  * @sdnum: which SERDES to access
  * @loc: location - channel, element, register, as packed by EPB_LOC() macro.
  * @wd: Write Data - value to set in register
  * @mask: ones where data should be spliced into reg.
  *
- * Basic register read/modify/write, with un-needed accesses elided. That is,
+ * Basic register read/modify/write, with un-needed acesses elided. That is,
  * a mask of zero will prevent write, while a mask of 0xFF will prevent read.
  * returns current (presumed, if a write was done) contents of selected
  * register, or <0 if errors.
  */
-static int ipath_sd7220_reg_mod(struct ipath_devdata *dd, int sdnum, u32 loc,
-                               u32 wd, u32 mask)
+static int qib_sd7220_reg_mod(struct qib_devdata *dd, int sdnum, u32 loc,
+                             u32 wd, u32 mask)
 {
        u16 trans;
        u64 transval;
@@ -629,14 +635,16 @@ static int ipath_sd7220_reg_mod(struct ipath_devdata *dd, int sdnum, u32 loc,
        unsigned long flags;
 
        switch (sdnum) {
-       case IB_7220_SERDES :
-               trans = dd->ipath_kregs->kr_ib_epbtrans;
+       case IB_7220_SERDES:
+               trans = kr_ibsd_epb_transaction_reg;
                break;
-       case PCIE_SERDES0 :
-       case PCIE_SERDES1 :
-               trans = dd->ipath_kregs->kr_pcie_epbtrans;
+
+       case PCIE_SERDES0:
+       case PCIE_SERDES1:
+               trans = kr_pciesd_epb_transaction_reg;
                break;
-       default :
+
+       default:
                return -1;
        }
 
@@ -644,23 +652,23 @@ static int ipath_sd7220_reg_mod(struct ipath_devdata *dd, int sdnum, u32 loc,
         * All access is locked in software (vs other host threads) and
         * hardware (vs uC access).
         */
-       spin_lock_irqsave(&dd->ipath_sdepb_lock, flags);
+       spin_lock_irqsave(&dd->cspec->sdepb_lock, flags);
 
        owned = epb_access(dd, sdnum, 1);
        if (owned < 0) {
-               spin_unlock_irqrestore(&dd->ipath_sdepb_lock, flags);
+               spin_unlock_irqrestore(&dd->cspec->sdepb_lock, flags);
                return -1;
        }
        ret = 0;
        for (tries = EPB_TRANS_TRIES; tries; --tries) {
-               transval = ipath_read_kreg32(dd, trans);
+               transval = qib_read_kreg32(dd, trans);
                if (transval & EPB_TRANS_RDY)
                        break;
                udelay(5);
        }
 
        if (tries > 0) {
-               tries = 1;      /* to make read-skip work */
+               tries = 1;      /* to make read-skip work */
                if (mask != 0xFF) {
                        /*
                         * Not a pure write, so need to read.
@@ -688,7 +696,7 @@ static int ipath_sd7220_reg_mod(struct ipath_devdata *dd, int sdnum, u32 loc,
        else
                ret = transval & EPB_DATA_MASK;
 
-       spin_unlock_irqrestore(&dd->ipath_sdepb_lock, flags);
+       spin_unlock_irqrestore(&dd->cspec->sdepb_lock, flags);
        if (tries <= 0)
                ret = -1;
        return ret;
@@ -707,7 +715,7 @@ static int ipath_sd7220_reg_mod(struct ipath_devdata *dd, int sdnum, u32 loc,
 #define EPB_RAMDATA EPB_LOC(6, 0, 5)
 
 /* Transfer date to/from uC Program RAM of IB or PCIe SerDes */
-static int ipath_sd7220_ram_xfer(struct ipath_devdata *dd, int sdnum, u32 loc,
+static int qib_sd7220_ram_xfer(struct qib_devdata *dd, int sdnum, u32 loc,
                               u8 *buf, int cnt, int rd_notwr)
 {
        u16 trans;
@@ -723,29 +731,28 @@ static int ipath_sd7220_ram_xfer(struct ipath_devdata *dd, int sdnum, u32 loc,
 
        /* Pick appropriate transaction reg and "Chip select" for this serdes */
        switch (sdnum) {
-       case IB_7220_SERDES :
+       case IB_7220_SERDES:
                csbit = 1ULL << EPB_IB_UC_CS_SHF;
-               trans = dd->ipath_kregs->kr_ib_epbtrans;
+               trans = kr_ibsd_epb_transaction_reg;
                break;
-       case PCIE_SERDES0 :
-       case PCIE_SERDES1 :
+
+       case PCIE_SERDES0:
+       case PCIE_SERDES1:
                /* PCIe SERDES has uC "chip select" in different bit, too */
                csbit = 1ULL << EPB_PCIE_UC_CS_SHF;
-               trans = dd->ipath_kregs->kr_pcie_epbtrans;
+               trans = kr_pciesd_epb_transaction_reg;
                break;
-       default :
+
+       default:
                return -1;
        }
 
        op = rd_notwr ? "Rd" : "Wr";
-       spin_lock_irqsave(&dd->ipath_sdepb_lock, flags);
+       spin_lock_irqsave(&dd->cspec->sdepb_lock, flags);
 
        owned = epb_access(dd, sdnum, 1);
        if (owned < 0) {
-               spin_unlock_irqrestore(&dd->ipath_sdepb_lock, flags);
-               ipath_dbg("Could not get %s access to %s EPB: %X, loc %X\n",
-                       op, (sdnum == IB_7220_SERDES) ? "IB" : "PCIe",
-                       owned, loc);
+               spin_unlock_irqrestore(&dd->cspec->sdepb_lock, flags);
                return -1;
        }
 
@@ -758,16 +765,14 @@ static int ipath_sd7220_ram_xfer(struct ipath_devdata *dd, int sdnum, u32 loc,
         */
        addr = loc & 0x1FFF;
        for (tries = EPB_TRANS_TRIES; tries; --tries) {
-               transval = ipath_read_kreg32(dd, trans);
+               transval = qib_read_kreg32(dd, trans);
                if (transval & EPB_TRANS_RDY)
                        break;
                udelay(5);
        }
 
        sofar = 0;
-       if (tries <= 0)
-               ipath_dbg("No initial RDY on EPB access request\n");
-       else {
+       if (tries > 0) {
                /*
                 * Every "memory" access is doubly-indirect.
                 * We set two bytes of address, then read/write
@@ -778,8 +783,6 @@ static int ipath_sd7220_ram_xfer(struct ipath_devdata *dd, int sdnum, u32 loc,
                transval = csbit | EPB_UC_CTL |
                        (rd_notwr ? EPB_ROM_R : EPB_ROM_W);
                tries = epb_trans(dd, trans, transval, &transval);
-               if (tries <= 0)
-                       ipath_dbg("No EPB response to uC %s cmd\n", op);
                while (tries > 0 && sofar < cnt) {
                        if (!sofar) {
                                /* Only set address at start of chunk */
@@ -787,18 +790,14 @@ static int ipath_sd7220_ram_xfer(struct ipath_devdata *dd, int sdnum, u32 loc,
                                transval = csbit | EPB_MADDRH | addrbyte;
                                tries = epb_trans(dd, trans, transval,
                                                  &transval);
-                               if (tries <= 0) {
-                                       ipath_dbg("No EPB response ADDRH\n");
+                               if (tries <= 0)
                                        break;
-                               }
                                addrbyte = (addr + sofar) & 0xFF;
                                transval = csbit | EPB_MADDRL | addrbyte;
                                tries = epb_trans(dd, trans, transval,
                                                 &transval);
-                               if (tries <= 0) {
-                                       ipath_dbg("No EPB response ADDRL\n");
+                               if (tries <= 0)
                                        break;
-                               }
                        }
 
                        if (rd_notwr)
@@ -806,10 +805,8 @@ static int ipath_sd7220_ram_xfer(struct ipath_devdata *dd, int sdnum, u32 loc,
                        else
                                transval = csbit | EPB_ROMDATA | buf[sofar];
                        tries = epb_trans(dd, trans, transval, &transval);
-                       if (tries <= 0) {
-                               ipath_dbg("No EPB response DATA\n");
+                       if (tries <= 0)
                                break;
-                       }
                        if (rd_notwr)
                                buf[sofar] = transval & EPB_DATA_MASK;
                        ++sofar;
@@ -817,8 +814,6 @@ static int ipath_sd7220_ram_xfer(struct ipath_devdata *dd, int sdnum, u32 loc,
                /* Finally, clear control-bit for Read or Write */
                transval = csbit | EPB_UC_CTL;
                tries = epb_trans(dd, trans, transval, &transval);
-               if (tries <= 0)
-                       ipath_dbg("No EPB response to drop of uC %s cmd\n", op);
        }
 
        ret = sofar;
@@ -826,18 +821,16 @@ static int ipath_sd7220_ram_xfer(struct ipath_devdata *dd, int sdnum, u32 loc,
        if (epb_access(dd, sdnum, -1) < 0)
                ret = -1;
 
-       spin_unlock_irqrestore(&dd->ipath_sdepb_lock, flags);
-       if (tries <= 0) {
-               ipath_dbg("SERDES PRAM %s failed after %d bytes\n", op, sofar);
+       spin_unlock_irqrestore(&dd->cspec->sdepb_lock, flags);
+       if (tries <= 0)
                ret = -1;
-       }
        return ret;
 }
 
 #define PROG_CHUNK 64
 
-int ipath_sd7220_prog_ld(struct ipath_devdata *dd, int sdnum,
-       u8 *img, int len, int offset)
+int qib_sd7220_prog_ld(struct qib_devdata *dd, int sdnum,
+                      u8 *img, int len, int offset)
 {
        int cnt, sofar, req;
 
@@ -846,7 +839,7 @@ int ipath_sd7220_prog_ld(struct ipath_devdata *dd, int sdnum,
                req = len - sofar;
                if (req > PROG_CHUNK)
                        req = PROG_CHUNK;
-               cnt = ipath_sd7220_ram_xfer(dd, sdnum, offset + sofar,
+               cnt = qib_sd7220_ram_xfer(dd, sdnum, offset + sofar,
                                          img + sofar, req, 0);
                if (cnt < req) {
                        sofar = -1;
@@ -860,8 +853,8 @@ int ipath_sd7220_prog_ld(struct ipath_devdata *dd, int sdnum,
 #define VFY_CHUNK 64
 #define SD_PRAM_ERROR_LIMIT 42
 
-int ipath_sd7220_prog_vfy(struct ipath_devdata *dd, int sdnum,
-       const u8 *img, int len, int offset)
+int qib_sd7220_prog_vfy(struct qib_devdata *dd, int sdnum,
+                       const u8 *img, int len, int offset)
 {
        int cnt, sofar, req, idx, errors;
        unsigned char readback[VFY_CHUNK];
@@ -872,7 +865,7 @@ int ipath_sd7220_prog_vfy(struct ipath_devdata *dd, int sdnum,
                req = len - sofar;
                if (req > VFY_CHUNK)
                        req = VFY_CHUNK;
-               cnt = ipath_sd7220_ram_xfer(dd, sdnum, sofar + offset,
+               cnt = qib_sd7220_ram_xfer(dd, sdnum, sofar + offset,
                                          readback, req, 1);
                if (cnt < req) {
                        /* failed in read itself */
@@ -888,11 +881,13 @@ int ipath_sd7220_prog_vfy(struct ipath_devdata *dd, int sdnum,
        return errors ? -errors : sofar;
 }
 
-/* IRQ not set up at this point in init, so we poll. */
+/*
+ * IRQ not set up at this point in init, so we poll.
+ */
 #define IB_SERDES_TRIM_DONE (1ULL << 11)
 #define TRIM_TMO (30)
 
-static int ipath_sd_trimdone_poll(struct ipath_devdata *dd)
+static int qib_sd_trimdone_poll(struct qib_devdata *dd)
 {
        int trim_tmo, ret;
        uint64_t val;
@@ -903,16 +898,15 @@ static int ipath_sd_trimdone_poll(struct ipath_devdata *dd)
         */
        ret = 0;
        for (trim_tmo = 0; trim_tmo < TRIM_TMO; ++trim_tmo) {
-               val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibcstatus);
+               val = qib_read_kreg64(dd, kr_ibcstatus);
                if (val & IB_SERDES_TRIM_DONE) {
-                       ipath_cdbg(VERBOSE, "TRIMDONE after %d\n", trim_tmo);
                        ret = 1;
                        break;
                }
                msleep(10);
        }
        if (trim_tmo >= TRIM_TMO) {
-               ipath_dev_err(dd, "No TRIMDONE in %d tries\n", trim_tmo);
+               qib_dev_err(dd, "No TRIMDONE in %d tries\n", trim_tmo);
                ret = 0;
        }
        return ret;
@@ -964,8 +958,7 @@ static struct dds_init {
 };
 
 /*
- * Next, values related to Receive Equalization.
- * In comments, FDR (Full) is IB DDR, HDR (Half) is IB SDR
+ * Now the RXEQ section of the table.
  */
 /* Hardware packs an element number and register address thus: */
 #define RXEQ_INIT_RDESC(elt, addr) (((elt) & 0xF) | ((addr) << 4))
@@ -981,23 +974,23 @@ static struct dds_init {
 #define RXEQ_SDR_ZCNT 23
 
 static struct rxeq_init {
-       u16 rdesc;      /* in form used in SerDesDDSRXEQ */
+       u16 rdesc;      /* in form used in SerDesDDSRXEQ */
        u8  rdata[4];
 } rxeq_init_vals[] = {
        /* Set Rcv Eq. to Preset node */
        RXEQ_VAL_ALL(7, 0x27, 0x10),
        /* Set DFELTHFDR/HDR thresholds */
-       RXEQ_VAL(7, 8,    0, 0, 0, 0), /* FDR */
+       RXEQ_VAL(7, 8,    0, 0, 0, 0), /* FDR, was 0, 1, 2, 3 */
        RXEQ_VAL(7, 0x21, 0, 0, 0, 0), /* HDR */
-       /* Set TLTHFDR/HDR threshold */
-       RXEQ_VAL(7, 9,    2, 2, 2, 2), /* FDR */
-       RXEQ_VAL(7, 0x23, 2, 2, 2, 2), /* HDR */
+       /* Set TLTHFDR/HDR theshold */
+       RXEQ_VAL(7, 9,    2, 2, 2, 2), /* FDR, was 0, 2, 4, 6 */
+       RXEQ_VAL(7, 0x23, 2, 2, 2, 2), /* HDR, was  0, 1, 2, 3 */
        /* Set Preamp setting 2 (ZFR/ZCNT) */
-       RXEQ_VAL(7, 0x1B, 12, 12, 12, 12), /* FDR */
-       RXEQ_VAL(7, 0x1C, 12, 12, 12, 12), /* HDR */
+       RXEQ_VAL(7, 0x1B, 12, 12, 12, 12), /* FDR, was 12, 16, 20, 24 */
+       RXEQ_VAL(7, 0x1C, 12, 12, 12, 12), /* HDR, was 12, 16, 20, 24 */
        /* Set Preamp DC gain and Setting 1 (GFR/GHR) */
-       RXEQ_VAL(7, 0x1E, 0x10, 0x10, 0x10, 0x10), /* FDR */
-       RXEQ_VAL(7, 0x1F, 0x10, 0x10, 0x10, 0x10), /* HDR */
+       RXEQ_VAL(7, 0x1E, 16, 16, 16, 16), /* FDR, was 16, 17, 18, 20 */
+       RXEQ_VAL(7, 0x1F, 16, 16, 16, 16), /* HDR, was 16, 17, 18, 20 */
        /* Toggle RELOCK (in VCDL_CTRL0) to lock to data */
        RXEQ_VAL_ALL(6, 6, 0x20), /* Set D5 High */
        RXEQ_VAL_ALL(6, 6, 0), /* Set D5 Low */
@@ -1007,27 +1000,27 @@ static struct rxeq_init {
 #define DDS_ROWS (16)
 #define RXEQ_ROWS ARRAY_SIZE(rxeq_init_vals)
 
-static int ipath_sd_setvals(struct ipath_devdata *dd)
+static int qib_sd_setvals(struct qib_devdata *dd)
 {
        int idx, midx;
-       int min_idx;     /* Minimum index for this portion of table */
+       int min_idx;     /* Minimum index for this portion of table */
        uint32_t dds_reg_map;
        u64 __iomem *taddr, *iaddr;
        uint64_t data;
        uint64_t sdctl;
 
-       taddr = dd->ipath_kregbase + KR_IBSerDesMappTable;
-       iaddr = dd->ipath_kregbase + dd->ipath_kregs->kr_ib_ddsrxeq;
+       taddr = dd->kregbase + kr_serdes_maptable;
+       iaddr = dd->kregbase + kr_serdes_ddsrxeq0;
 
        /*
         * Init the DDS section of the table.
         * Each "row" of the table provokes NUM_DDS_REG writes, to the
         * registers indicated in DDS_REG_MAP.
         */
-       sdctl = ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibserdesctrl);
+       sdctl = qib_read_kreg64(dd, kr_ibserdesctrl);
        sdctl = (sdctl & ~(0x1f << 8)) | (NUM_DDS_REGS << 8);
        sdctl = (sdctl & ~(0x1f << 13)) | (RXEQ_ROWS << 13);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_ibserdesctrl, sdctl);
+       qib_write_kreg(dd, kr_ibserdesctrl, sdctl);
 
        /*
         * Iterate down table within loop for each register to store.
@@ -1037,21 +1030,21 @@ static int ipath_sd_setvals(struct ipath_devdata *dd)
                data = ((dds_reg_map & 0xF) << 4) | TX_FAST_ELT;
                writeq(data, iaddr + idx);
                mmiowb();
-               ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
+               qib_read_kreg32(dd, kr_scratch);
                dds_reg_map >>= 4;
                for (midx = 0; midx < DDS_ROWS; ++midx) {
                        u64 __iomem *daddr = taddr + ((midx << 4) + idx);
                        data = dds_init_vals[midx].reg_vals[idx];
                        writeq(data, daddr);
                        mmiowb();
-                       ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
+                       qib_read_kreg32(dd, kr_scratch);
                } /* End inner for (vals for this reg, each row) */
        } /* end outer for (regs to be stored) */
 
        /*
-        * Init the RXEQ section of the table. As explained above the table
-        * rxeq_init_vals[], this runs in a different order, as the pattern
-        * of register references is more complex, but there are only
+        * Init the RXEQ section of the table.
+        * This runs in a different order, as the pattern of
+        * register references is more complex, but there are only
         * four "data" values per register.
         */
        min_idx = idx; /* RXEQ indices pick up where DDS left off */
@@ -1066,13 +1059,13 @@ static int ipath_sd_setvals(struct ipath_devdata *dd)
                /* Store the next RXEQ register address */
                writeq(rxeq_init_vals[idx].rdesc, iaddr + didx);
                mmiowb();
-               ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
+               qib_read_kreg32(dd, kr_scratch);
                /* Iterate through RXEQ values */
                for (vidx = 0; vidx < 4; vidx++) {
                        data = rxeq_init_vals[idx].rdata[vidx];
                        writeq(data, taddr + (vidx << 6) + idx);
                        mmiowb();
-                       ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
+                       qib_read_kreg32(dd, kr_scratch);
                }
        } /* end outer for (Reg-writes for RXEQ) */
        return 0;
@@ -1085,33 +1078,18 @@ static int ipath_sd_setvals(struct ipath_devdata *dd)
 #define VCDL_CTRL2(chan) EPB_LOC(chan, 6, 8)
 #define START_EQ2(chan) EPB_LOC(chan, 7, 0x28)
 
-static int ibsd_sto_noisy(struct ipath_devdata *dd, int loc, int val, int mask)
-{
-       int ret = -1;
-       int sloc; /* shifted loc, for messages */
-
-       loc |= (1U << EPB_IB_QUAD0_CS_SHF);
-       sloc = loc >> EPB_ADDR_SHF;
-
-       ret = ipath_sd7220_reg_mod(dd, IB_7220_SERDES, loc, val, mask);
-       if (ret < 0)
-               ipath_dev_err(dd, "Write failed: elt %d,"
-                       " addr 0x%X, chnl %d, val 0x%02X, mask 0x%02X\n",
-                       (sloc & 0xF), (sloc >> 9) & 0x3f, (sloc >> 4) & 7,
-                       val & 0xFF, mask & 0xFF);
-       return ret;
-}
-
 /*
  * Repeat a "store" across all channels of the IB SerDes.
  * Although nominally it inherits the "read value" of the last
  * channel it modified, the only really useful return is <0 for
  * failure, >= 0 for success. The parameter 'loc' is assumed to
- * be the location for the channel-0 copy of the register to
- * be modified.
+ * be the location in some channel of the register to be modified
+ * The caller can specify use of the "gang write" option of EPB,
+ * in which case we use the specified channel data for any fields
+ * not explicitely written.
  */
-static int ibsd_mod_allchnls(struct ipath_devdata *dd, int loc, int val,
-       int mask)
+static int ibsd_mod_allchnls(struct qib_devdata *dd, int loc, int val,
+                            int mask)
 {
        int ret = -1;
        int chnl;
@@ -1126,24 +1104,27 @@ static int ibsd_mod_allchnls(struct ipath_devdata *dd, int loc, int val,
                loc |= (1U << EPB_IB_QUAD0_CS_SHF);
                chnl = (loc >> (4 + EPB_ADDR_SHF)) & 7;
                if (mask != 0xFF) {
-                       ret = ipath_sd7220_reg_mod(dd, IB_7220_SERDES,
-                               loc & ~EPB_GLOBAL_WR, 0, 0);
+                       ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES,
+                                                loc & ~EPB_GLOBAL_WR, 0, 0);
                        if (ret < 0) {
                                int sloc = loc >> EPB_ADDR_SHF;
-                               ipath_dev_err(dd, "pre-read failed: elt %d,"
-                                       " addr 0x%X, chnl %d\n", (sloc & 0xF),
-                                       (sloc >> 9) & 0x3f, chnl);
+
+                               qib_dev_err(dd, "pre-read failed: elt %d,"
+                                           " addr 0x%X, chnl %d\n",
+                                           (sloc & 0xF),
+                                           (sloc >> 9) & 0x3f, chnl);
                                return ret;
                        }
                        val = (ret & ~mask) | (val & mask);
                }
                loc &=  ~(7 << (4+EPB_ADDR_SHF));
-               ret = ipath_sd7220_reg_mod(dd, IB_7220_SERDES, loc, val, 0xFF);
+               ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, loc, val, 0xFF);
                if (ret < 0) {
                        int sloc = loc >> EPB_ADDR_SHF;
-                       ipath_dev_err(dd, "Global WR failed: elt %d,"
-                               " addr 0x%X, val %02X\n",
-                               (sloc & 0xF), (sloc >> 9) & 0x3f, val);
+
+                       qib_dev_err(dd, "Global WR failed: elt %d,"
+                                   " addr 0x%X, val %02X\n",
+                                   (sloc & 0xF), (sloc >> 9) & 0x3f, val);
                }
                return ret;
        }
@@ -1151,16 +1132,17 @@ static int ibsd_mod_allchnls(struct ipath_devdata *dd, int loc, int val,
        loc &=  ~(7 << (4+EPB_ADDR_SHF));
        loc |= (1U << EPB_IB_QUAD0_CS_SHF);
        for (chnl = 0; chnl < 4; ++chnl) {
-               int cloc;
-               cloc = loc | (chnl << (4+EPB_ADDR_SHF));
-               ret = ipath_sd7220_reg_mod(dd, IB_7220_SERDES, cloc, val, mask);
+               int cloc = loc | (chnl << (4+EPB_ADDR_SHF));
+
+               ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, cloc, val, mask);
                if (ret < 0) {
                        int sloc = loc >> EPB_ADDR_SHF;
-                       ipath_dev_err(dd, "Write failed: elt %d,"
-                               " addr 0x%X, chnl %d, val 0x%02X,"
-                               " mask 0x%02X\n",
-                               (sloc & 0xF), (sloc >> 9) & 0x3f, chnl,
-                               val & 0xFF, mask & 0xFF);
+
+                       qib_dev_err(dd, "Write failed: elt %d,"
+                                   " addr 0x%X, chnl %d, val 0x%02X,"
+                                   " mask 0x%02X\n",
+                                   (sloc & 0xF), (sloc >> 9) & 0x3f, chnl,
+                                   val & 0xFF, mask & 0xFF);
                        break;
                }
        }
@@ -1171,7 +1153,7 @@ static int ibsd_mod_allchnls(struct ipath_devdata *dd, int loc, int val,
  * Set the Tx values normally modified by IBC in IB1.2 mode to default
  * values, as gotten from first row of init table.
  */
-static int set_dds_vals(struct ipath_devdata *dd, struct dds_init *ddi)
+static int set_dds_vals(struct qib_devdata *dd, struct dds_init *ddi)
 {
        int ret;
        int idx, reg, data;
@@ -1194,7 +1176,7 @@ static int set_dds_vals(struct ipath_devdata *dd, struct dds_init *ddi)
  * Set the Rx values normally modified by IBC in IB1.2 mode to default
  * values, as gotten from selected column of init table.
  */
-static int set_rxeq_vals(struct ipath_devdata *dd, int vsel)
+static int set_rxeq_vals(struct qib_devdata *dd, int vsel)
 {
        int ret;
        int ridx;
@@ -1202,6 +1184,7 @@ static int set_rxeq_vals(struct ipath_devdata *dd, int vsel)
 
        for (ridx = 0; ridx < cnt; ++ridx) {
                int elt, reg, val, loc;
+
                elt = rxeq_init_vals[ridx].rdesc & 0xF;
                reg = rxeq_init_vals[ridx].rdesc >> 4;
                loc = EPB_LOC(0, elt, reg);
@@ -1217,83 +1200,66 @@ static int set_rxeq_vals(struct ipath_devdata *dd, int vsel)
 /*
  * Set the default values (row 0) for DDR Driver Demphasis.
  * we do this initially and whenever we turn off IB-1.2
+ *
  * The "default" values for Rx equalization are also stored to
  * SerDes registers. Formerly (and still default), we used set 2.
  * For experimenting with cables and link-partners, we allow changing
  * that via a module parameter.
  */
-static unsigned ipath_rxeq_set = 2;
-module_param_named(rxeq_default_set, ipath_rxeq_set, uint,
-       S_IWUSR | S_IRUGO);
+static unsigned qib_rxeq_set = 2;
+module_param_named(rxeq_default_set, qib_rxeq_set, uint,
+                  S_IWUSR | S_IRUGO);
 MODULE_PARM_DESC(rxeq_default_set,
-       "Which set [0..3] of Rx Equalization values is default");
+                "Which set [0..3] of Rx Equalization values is default");
 
-static int ipath_internal_presets(struct ipath_devdata *dd)
+static int qib_internal_presets(struct qib_devdata *dd)
 {
        int ret = 0;
 
        ret = set_dds_vals(dd, dds_init_vals + DDS_3M);
 
        if (ret < 0)
-               ipath_dev_err(dd, "Failed to set default DDS values\n");
-       ret = set_rxeq_vals(dd, ipath_rxeq_set & 3);
+               qib_dev_err(dd, "Failed to set default DDS values\n");
+       ret = set_rxeq_vals(dd, qib_rxeq_set & 3);
        if (ret < 0)
-               ipath_dev_err(dd, "Failed to set default RXEQ values\n");
+               qib_dev_err(dd, "Failed to set default RXEQ values\n");
        return ret;
 }
 
-int ipath_sd7220_presets(struct ipath_devdata *dd)
+int qib_sd7220_presets(struct qib_devdata *dd)
 {
        int ret = 0;
 
-       if (!dd->ipath_presets_needed)
+       if (!dd->cspec->presets_needed)
                return ret;
-       dd->ipath_presets_needed = 0;
+       dd->cspec->presets_needed = 0;
        /* Assert uC reset, so we don't clash with it. */
-       ipath_ibsd_reset(dd, 1);
+       qib_ibsd_reset(dd, 1);
        udelay(2);
-       ipath_sd_trimdone_monitor(dd, "link-down");
+       qib_sd_trimdone_monitor(dd, "link-down");
 
-       ret = ipath_internal_presets(dd);
-return ret;
+       ret = qib_internal_presets(dd);
+       return ret;
 }
 
-static int ipath_sd_trimself(struct ipath_devdata *dd, int val)
+static int qib_sd_trimself(struct qib_devdata *dd, int val)
 {
-       return ibsd_sto_noisy(dd, CMUCTRL5, val, 0xFF);
+       int loc = CMUCTRL5 | (1U << EPB_IB_QUAD0_CS_SHF);
+
+       return qib_sd7220_reg_mod(dd, IB_7220_SERDES, loc, val, 0xFF);
 }
 
-static int ipath_sd_early(struct ipath_devdata *dd)
+static int qib_sd_early(struct qib_devdata *dd)
 {
-       int ret = -1; /* Default failed */
-       int chnl;
+       int ret;
 
-       for (chnl = 0; chnl < 4; ++chnl) {
-               ret = ibsd_sto_noisy(dd, RXHSCTRL0(chnl), 0xD4, 0xFF);
-               if (ret < 0)
-                       goto bail;
-       }
-       for (chnl = 0; chnl < 4; ++chnl) {
-               ret = ibsd_sto_noisy(dd, VCDL_DAC2(chnl), 0x2D, 0xFF);
-               if (ret < 0)
-                       goto bail;
-       }
-       /* more fine-tuning of what will be default */
-       for (chnl = 0; chnl < 4; ++chnl) {
-               ret = ibsd_sto_noisy(dd, VCDL_CTRL2(chnl), 3, 0xF);
-               if (ret < 0)
-                       goto bail;
-       }
-       for (chnl = 0; chnl < 4; ++chnl) {
-               ret = ibsd_sto_noisy(dd, START_EQ1(chnl), 0x10, 0xFF);
-               if (ret < 0)
-                       goto bail;
-       }
-       for (chnl = 0; chnl < 4; ++chnl) {
-               ret = ibsd_sto_noisy(dd, START_EQ2(chnl), 0x30, 0xFF);
-               if (ret < 0)
-                       goto bail;
-       }
+       ret = ibsd_mod_allchnls(dd, RXHSCTRL0(0) | EPB_GLOBAL_WR, 0xD4, 0xFF);
+       if (ret < 0)
+               goto bail;
+       ret = ibsd_mod_allchnls(dd, START_EQ1(0) | EPB_GLOBAL_WR, 0x10, 0xFF);
+       if (ret < 0)
+               goto bail;
+       ret = ibsd_mod_allchnls(dd, START_EQ2(0) | EPB_GLOBAL_WR, 0x30, 0xFF);
 bail:
        return ret;
 }
@@ -1302,50 +1268,53 @@ bail:
 #define LDOUTCTRL1(chnl) EPB_LOC(chnl, 7, 6)
 #define RXHSSTATUS(chnl) EPB_LOC(chnl, 6, 0xF)
 
-static int ipath_sd_dactrim(struct ipath_devdata *dd)
+static int qib_sd_dactrim(struct qib_devdata *dd)
 {
-       int ret = -1; /* Default failed */
-       int chnl;
+       int ret;
+
+       ret = ibsd_mod_allchnls(dd, VCDL_DAC2(0) | EPB_GLOBAL_WR, 0x2D, 0xFF);
+       if (ret < 0)
+               goto bail;
+
+       /* more fine-tuning of what will be default */
+       ret = ibsd_mod_allchnls(dd, VCDL_CTRL2(0), 3, 0xF);
+       if (ret < 0)
+               goto bail;
+
+       ret = ibsd_mod_allchnls(dd, BACTRL(0) | EPB_GLOBAL_WR, 0x40, 0xFF);
+       if (ret < 0)
+               goto bail;
+
+       ret = ibsd_mod_allchnls(dd, LDOUTCTRL1(0) | EPB_GLOBAL_WR, 0x04, 0xFF);
+       if (ret < 0)
+               goto bail;
+
+       ret = ibsd_mod_allchnls(dd, RXHSSTATUS(0) | EPB_GLOBAL_WR, 0x04, 0xFF);
+       if (ret < 0)
+               goto bail;
 
-       for (chnl = 0; chnl < 4; ++chnl) {
-               ret = ibsd_sto_noisy(dd, BACTRL(chnl), 0x40, 0xFF);
-               if (ret < 0)
-                       goto bail;
-       }
-       for (chnl = 0; chnl < 4; ++chnl) {
-               ret = ibsd_sto_noisy(dd, LDOUTCTRL1(chnl), 0x04, 0xFF);
-               if (ret < 0)
-                       goto bail;
-       }
-       for (chnl = 0; chnl < 4; ++chnl) {
-               ret = ibsd_sto_noisy(dd, RXHSSTATUS(chnl), 0x04, 0xFF);
-               if (ret < 0)
-                       goto bail;
-       }
        /*
-        * delay for max possible number of steps, with slop.
+        * Delay for max possible number of steps, with slop.
         * Each step is about 4usec.
         */
        udelay(415);
-       for (chnl = 0; chnl < 4; ++chnl) {
-               ret = ibsd_sto_noisy(dd, LDOUTCTRL1(chnl), 0x00, 0xFF);
-               if (ret < 0)
-                       goto bail;
-       }
+
+       ret = ibsd_mod_allchnls(dd, LDOUTCTRL1(0) | EPB_GLOBAL_WR, 0x00, 0xFF);
+
 bail:
        return ret;
 }
 
 #define RELOCK_FIRST_MS 3
 #define RXLSPPM(chan) EPB_LOC(chan, 0, 2)
-void ipath_toggle_rclkrls(struct ipath_devdata *dd)
+void toggle_7220_rclkrls(struct qib_devdata *dd)
 {
        int loc = RXLSPPM(0) | EPB_GLOBAL_WR;
        int ret;
 
        ret = ibsd_mod_allchnls(dd, loc, 0, 0x80);
        if (ret < 0)
-               ipath_dev_err(dd, "RCLKRLS failed to clear D7\n");
+               qib_dev_err(dd, "RCLKRLS failed to clear D7\n");
        else {
                udelay(1);
                ibsd_mod_allchnls(dd, loc, 0x80, 0x80);
@@ -1354,109 +1323,91 @@ void ipath_toggle_rclkrls(struct ipath_devdata *dd)
        udelay(1);
        ret = ibsd_mod_allchnls(dd, loc, 0, 0x80);
        if (ret < 0)
-               ipath_dev_err(dd, "RCLKRLS failed to clear D7\n");
+               qib_dev_err(dd, "RCLKRLS failed to clear D7\n");
        else {
                udelay(1);
                ibsd_mod_allchnls(dd, loc, 0x80, 0x80);
        }
        /* Now reset xgxs and IBC to complete the recovery */
-       dd->ipath_f_xgxs_reset(dd);
+       dd->f_xgxs_reset(dd->pport);
 }
 
 /*
  * Shut down the timer that polls for relock occasions, if needed
- * this is "hooked" from ipath_7220_quiet_serdes(), which is called
- * just before ipath_shutdown_device() in ipath_driver.c shuts down all
+ * this is "hooked" from qib_7220_quiet_serdes(), which is called
+ * just before qib_shutdown_device() in qib_driver.c shuts down all
  * the other timers
  */
-void ipath_shutdown_relock_poll(struct ipath_devdata *dd)
+void shutdown_7220_relock_poll(struct qib_devdata *dd)
 {
-       struct ipath_relock *irp = &dd->ipath_relock_singleton;
-       if (atomic_read(&irp->ipath_relock_timer_active)) {
-               del_timer_sync(&irp->ipath_relock_timer);
-               atomic_set(&irp->ipath_relock_timer_active, 0);
-       }
+       if (dd->cspec->relock_timer_active)
+               del_timer_sync(&dd->cspec->relock_timer);
 }
 
-static unsigned ipath_relock_by_timer = 1;
-module_param_named(relock_by_timer, ipath_relock_by_timer, uint,
-       S_IWUSR | S_IRUGO);
+static unsigned qib_relock_by_timer = 1;
+module_param_named(relock_by_timer, qib_relock_by_timer, uint,
+                  S_IWUSR | S_IRUGO);
 MODULE_PARM_DESC(relock_by_timer, "Allow relock attempt if link not up");
 
-static void ipath_run_relock(unsigned long opaque)
+static void qib_run_relock(unsigned long opaque)
 {
-       struct ipath_devdata *dd = (struct ipath_devdata *)opaque;
-       struct ipath_relock *irp = &dd->ipath_relock_singleton;
-       u64 val, ltstate;
-
-       if (!(dd->ipath_flags & IPATH_INITTED)) {
-               /* Not yet up, just reenable the timer for later */
-               irp->ipath_relock_interval = HZ;
-               mod_timer(&irp->ipath_relock_timer, jiffies + HZ);
-               return;
-       }
+       struct qib_devdata *dd = (struct qib_devdata *)opaque;
+       struct qib_pportdata *ppd = dd->pport;
+       struct qib_chip_specific *cs = dd->cspec;
+       int timeoff;
 
        /*
-        * Check link-training state for "stuck" state.
+        * Check link-training state for "stuck" state, when down.
         * if found, try relock and schedule another try at
         * exponentially growing delay, maxed at one second.
         * if not stuck, our work is done.
         */
-       val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibcstatus);
-       ltstate = ipath_ib_linktrstate(dd, val);
-
-       if (ltstate <= INFINIPATH_IBCS_LT_STATE_CFGWAITRMT
-               && ltstate != INFINIPATH_IBCS_LT_STATE_LINKUP) {
-               int timeoff;
-               /* Not up yet. Try again, if allowed by module-param */
-               if (ipath_relock_by_timer) {
-                       if (dd->ipath_flags & IPATH_IB_AUTONEG_INPROG)
-                               ipath_cdbg(VERBOSE, "Skip RELOCK in AUTONEG\n");
-                       else if (!(dd->ipath_flags & IPATH_IB_LINK_DISABLED)) {
-                               ipath_cdbg(VERBOSE, "RELOCK\n");
-                               ipath_toggle_rclkrls(dd);
-                       }
+       if ((dd->flags & QIB_INITTED) && !(ppd->lflags &
+           (QIBL_IB_AUTONEG_INPROG | QIBL_LINKINIT | QIBL_LINKARMED |
+            QIBL_LINKACTIVE))) {
+               if (qib_relock_by_timer) {
+                       if (!(ppd->lflags & QIBL_IB_LINK_DISABLED))
+                               toggle_7220_rclkrls(dd);
                }
                /* re-set timer for next check */
-               timeoff = irp->ipath_relock_interval << 1;
+               timeoff = cs->relock_interval << 1;
                if (timeoff > HZ)
                        timeoff = HZ;
-               irp->ipath_relock_interval = timeoff;
-
-               mod_timer(&irp->ipath_relock_timer, jiffies + timeoff);
-       } else {
-               /* Up, so no more need to check so often */
-               mod_timer(&irp->ipath_relock_timer, jiffies + HZ);
-       }
+               cs->relock_interval = timeoff;
+       } else
+               timeoff = HZ;
+       mod_timer(&cs->relock_timer, jiffies + timeoff);
 }
 
-void ipath_set_relock_poll(struct ipath_devdata *dd, int ibup)
+void set_7220_relock_poll(struct qib_devdata *dd, int ibup)
 {
-       struct ipath_relock *irp = &dd->ipath_relock_singleton;
+       struct qib_chip_specific *cs = dd->cspec;
 
-       if (ibup > 0) {
-               /* we are now up, so relax timer to 1 second interval */
-               if (atomic_read(&irp->ipath_relock_timer_active))
-                       mod_timer(&irp->ipath_relock_timer, jiffies + HZ);
+       if (ibup) {
+               /* We are now up, relax timer to 1 second interval */
+               if (cs->relock_timer_active) {
+                       cs->relock_interval = HZ;
+                       mod_timer(&cs->relock_timer, jiffies + HZ);
+               }
        } else {
                /* Transition to down, (re-)set timer to short interval. */
-               int timeout;
-               timeout = (HZ * ((ibup == -1) ? 1000 : RELOCK_FIRST_MS))/1000;
+               unsigned int timeout;
+
+               timeout = msecs_to_jiffies(RELOCK_FIRST_MS);
                if (timeout == 0)
                        timeout = 1;
                /* If timer has not yet been started, do so. */
-               if (atomic_inc_return(&irp->ipath_relock_timer_active) == 1) {
-                       init_timer(&irp->ipath_relock_timer);
-                       irp->ipath_relock_timer.function = ipath_run_relock;
-                       irp->ipath_relock_timer.data = (unsigned long) dd;
-                       irp->ipath_relock_interval = timeout;
-                       irp->ipath_relock_timer.expires = jiffies + timeout;
-                       add_timer(&irp->ipath_relock_timer);
+               if (!cs->relock_timer_active) {
+                       cs->relock_timer_active = 1;
+                       init_timer(&cs->relock_timer);
+                       cs->relock_timer.function = qib_run_relock;
+                       cs->relock_timer.data = (unsigned long) dd;
+                       cs->relock_interval = timeout;
+                       cs->relock_timer.expires = jiffies + timeout;
+                       add_timer(&cs->relock_timer);
                } else {
-                       irp->ipath_relock_interval = timeout;
-                       mod_timer(&irp->ipath_relock_timer, jiffies + timeout);
-                       atomic_dec(&irp->ipath_relock_timer_active);
+                       cs->relock_interval = timeout;
+                       mod_timer(&cs->relock_timer, jiffies + timeout);
                }
        }
 }
-
similarity index 99%
rename from drivers/infiniband/hw/ipath/ipath_sd7220_img.c
rename to drivers/infiniband/hw/qib/qib_sd7220_img.c
index 5ef59da9270a0345203feeb1c480a83e23e7fad8..a1118fbd2370a3b4e15503abd40e3642c909ffce 100644 (file)
 #include <linux/pci.h>
 #include <linux/delay.h>
 
-#include "ipath_kernel.h"
-#include "ipath_registers.h"
-#include "ipath_7220.h"
+#include "qib.h"
+#include "qib_7220.h"
 
-static unsigned char ipath_sd7220_ib_img[] = {
+static unsigned char qib_sd7220_ib_img[] = {
 /*0000*/0x02, 0x0A, 0x29, 0x02, 0x0A, 0x87, 0xE5, 0xE6,
        0x30, 0xE6, 0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F,
 /*0010*/0x00, 0xE5, 0xE2, 0x30, 0xE4, 0x04, 0x7E, 0x01,
@@ -1069,14 +1068,14 @@ static unsigned char ipath_sd7220_ib_img[] = {
        0x01, 0x20, 0x11, 0x00, 0x04, 0x20, 0x00, 0x81
 };
 
-int ipath_sd7220_ib_load(struct ipath_devdata *dd)
+int qib_sd7220_ib_load(struct qib_devdata *dd)
 {
-       return ipath_sd7220_prog_ld(dd, IB_7220_SERDES, ipath_sd7220_ib_img,
-               sizeof(ipath_sd7220_ib_img), 0);
+       return qib_sd7220_prog_ld(dd, IB_7220_SERDES, qib_sd7220_ib_img,
+               sizeof(qib_sd7220_ib_img), 0);
 }
 
-int ipath_sd7220_ib_vfy(struct ipath_devdata *dd)
+int qib_sd7220_ib_vfy(struct qib_devdata *dd)
 {
-       return ipath_sd7220_prog_vfy(dd, IB_7220_SERDES, ipath_sd7220_ib_img,
-               sizeof(ipath_sd7220_ib_img), 0);
+       return qib_sd7220_prog_vfy(dd, IB_7220_SERDES, qib_sd7220_ib_img,
+               sizeof(qib_sd7220_ib_img), 0);
 }
diff --git a/drivers/infiniband/hw/qib/qib_sdma.c b/drivers/infiniband/hw/qib/qib_sdma.c
new file mode 100644 (file)
index 0000000..b845688
--- /dev/null
@@ -0,0 +1,973 @@
+/*
+ * Copyright (c) 2007, 2008, 2009, 2010 QLogic Corporation. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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/spinlock.h>
+#include <linux/netdevice.h>
+
+#include "qib.h"
+#include "qib_common.h"
+
+/* default pio off, sdma on */
+static ushort sdma_descq_cnt = 256;
+module_param_named(sdma_descq_cnt, sdma_descq_cnt, ushort, S_IRUGO);
+MODULE_PARM_DESC(sdma_descq_cnt, "Number of SDMA descq entries");
+
+/*
+ * Bits defined in the send DMA descriptor.
+ */
+#define SDMA_DESC_LAST          (1ULL << 11)
+#define SDMA_DESC_FIRST         (1ULL << 12)
+#define SDMA_DESC_DMA_HEAD      (1ULL << 13)
+#define SDMA_DESC_USE_LARGE_BUF (1ULL << 14)
+#define SDMA_DESC_INTR          (1ULL << 15)
+#define SDMA_DESC_COUNT_LSB     16
+#define SDMA_DESC_GEN_LSB       30
+
+char *qib_sdma_state_names[] = {
+       [qib_sdma_state_s00_hw_down]          = "s00_HwDown",
+       [qib_sdma_state_s10_hw_start_up_wait] = "s10_HwStartUpWait",
+       [qib_sdma_state_s20_idle]             = "s20_Idle",
+       [qib_sdma_state_s30_sw_clean_up_wait] = "s30_SwCleanUpWait",
+       [qib_sdma_state_s40_hw_clean_up_wait] = "s40_HwCleanUpWait",
+       [qib_sdma_state_s50_hw_halt_wait]     = "s50_HwHaltWait",
+       [qib_sdma_state_s99_running]          = "s99_Running",
+};
+
+char *qib_sdma_event_names[] = {
+       [qib_sdma_event_e00_go_hw_down]   = "e00_GoHwDown",
+       [qib_sdma_event_e10_go_hw_start]  = "e10_GoHwStart",
+       [qib_sdma_event_e20_hw_started]   = "e20_HwStarted",
+       [qib_sdma_event_e30_go_running]   = "e30_GoRunning",
+       [qib_sdma_event_e40_sw_cleaned]   = "e40_SwCleaned",
+       [qib_sdma_event_e50_hw_cleaned]   = "e50_HwCleaned",
+       [qib_sdma_event_e60_hw_halted]    = "e60_HwHalted",
+       [qib_sdma_event_e70_go_idle]      = "e70_GoIdle",
+       [qib_sdma_event_e7220_err_halted] = "e7220_ErrHalted",
+       [qib_sdma_event_e7322_err_halted] = "e7322_ErrHalted",
+       [qib_sdma_event_e90_timer_tick]   = "e90_TimerTick",
+};
+
+/* declare all statics here rather than keep sorting */
+static int alloc_sdma(struct qib_pportdata *);
+static void sdma_complete(struct kref *);
+static void sdma_finalput(struct qib_sdma_state *);
+static void sdma_get(struct qib_sdma_state *);
+static void sdma_put(struct qib_sdma_state *);
+static void sdma_set_state(struct qib_pportdata *, enum qib_sdma_states);
+static void sdma_start_sw_clean_up(struct qib_pportdata *);
+static void sdma_sw_clean_up_task(unsigned long);
+static void unmap_desc(struct qib_pportdata *, unsigned);
+
+static void sdma_get(struct qib_sdma_state *ss)
+{
+       kref_get(&ss->kref);
+}
+
+static void sdma_complete(struct kref *kref)
+{
+       struct qib_sdma_state *ss =
+               container_of(kref, struct qib_sdma_state, kref);
+
+       complete(&ss->comp);
+}
+
+static void sdma_put(struct qib_sdma_state *ss)
+{
+       kref_put(&ss->kref, sdma_complete);
+}
+
+static void sdma_finalput(struct qib_sdma_state *ss)
+{
+       sdma_put(ss);
+       wait_for_completion(&ss->comp);
+}
+
+/*
+ * Complete all the sdma requests on the active list, in the correct
+ * order, and with appropriate processing.   Called when cleaning up
+ * after sdma shutdown, and when new sdma requests are submitted for
+ * a link that is down.   This matches what is done for requests
+ * that complete normally, it's just the full list.
+ *
+ * Must be called with sdma_lock held
+ */
+static void clear_sdma_activelist(struct qib_pportdata *ppd)
+{
+       struct qib_sdma_txreq *txp, *txp_next;
+
+       list_for_each_entry_safe(txp, txp_next, &ppd->sdma_activelist, list) {
+               list_del_init(&txp->list);
+               if (txp->flags & QIB_SDMA_TXREQ_F_FREEDESC) {
+                       unsigned idx;
+
+                       idx = txp->start_idx;
+                       while (idx != txp->next_descq_idx) {
+                               unmap_desc(ppd, idx);
+                               if (++idx == ppd->sdma_descq_cnt)
+                                       idx = 0;
+                       }
+               }
+               if (txp->callback)
+                       (*txp->callback)(txp, QIB_SDMA_TXREQ_S_ABORTED);
+       }
+}
+
+static void sdma_sw_clean_up_task(unsigned long opaque)
+{
+       struct qib_pportdata *ppd = (struct qib_pportdata *) opaque;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ppd->sdma_lock, flags);
+
+       /*
+        * At this point, the following should always be true:
+        * - We are halted, so no more descriptors are getting retired.
+        * - We are not running, so no one is submitting new work.
+        * - Only we can send the e40_sw_cleaned, so we can't start
+        *   running again until we say so.  So, the active list and
+        *   descq are ours to play with.
+        */
+
+       /* Process all retired requests. */
+       qib_sdma_make_progress(ppd);
+
+       clear_sdma_activelist(ppd);
+
+       /*
+        * Resync count of added and removed.  It is VERY important that
+        * sdma_descq_removed NEVER decrement - user_sdma depends on it.
+        */
+       ppd->sdma_descq_removed = ppd->sdma_descq_added;
+
+       /*
+        * Reset our notion of head and tail.
+        * Note that the HW registers will be reset when switching states
+        * due to calling __qib_sdma_process_event() below.
+        */
+       ppd->sdma_descq_tail = 0;
+       ppd->sdma_descq_head = 0;
+       ppd->sdma_head_dma[0] = 0;
+       ppd->sdma_generation = 0;
+
+       __qib_sdma_process_event(ppd, qib_sdma_event_e40_sw_cleaned);
+
+       spin_unlock_irqrestore(&ppd->sdma_lock, flags);
+}
+
+/*
+ * This is called when changing to state qib_sdma_state_s10_hw_start_up_wait
+ * as a result of send buffer errors or send DMA descriptor errors.
+ * We want to disarm the buffers in these cases.
+ */
+static void sdma_hw_start_up(struct qib_pportdata *ppd)
+{
+       struct qib_sdma_state *ss = &ppd->sdma_state;
+       unsigned bufno;
+
+       for (bufno = ss->first_sendbuf; bufno < ss->last_sendbuf; ++bufno)
+               ppd->dd->f_sendctrl(ppd, QIB_SENDCTRL_DISARM_BUF(bufno));
+
+       ppd->dd->f_sdma_hw_start_up(ppd);
+}
+
+static void sdma_sw_tear_down(struct qib_pportdata *ppd)
+{
+       struct qib_sdma_state *ss = &ppd->sdma_state;
+
+       /* Releasing this reference means the state machine has stopped. */
+       sdma_put(ss);
+}
+
+static void sdma_start_sw_clean_up(struct qib_pportdata *ppd)
+{
+       tasklet_hi_schedule(&ppd->sdma_sw_clean_up_task);
+}
+
+static void sdma_set_state(struct qib_pportdata *ppd,
+       enum qib_sdma_states next_state)
+{
+       struct qib_sdma_state *ss = &ppd->sdma_state;
+       struct sdma_set_state_action *action = ss->set_state_action;
+       unsigned op = 0;
+
+       /* debugging bookkeeping */
+       ss->previous_state = ss->current_state;
+       ss->previous_op = ss->current_op;
+
+       ss->current_state = next_state;
+
+       if (action[next_state].op_enable)
+               op |= QIB_SDMA_SENDCTRL_OP_ENABLE;
+
+       if (action[next_state].op_intenable)
+               op |= QIB_SDMA_SENDCTRL_OP_INTENABLE;
+
+       if (action[next_state].op_halt)
+               op |= QIB_SDMA_SENDCTRL_OP_HALT;
+
+       if (action[next_state].op_drain)
+               op |= QIB_SDMA_SENDCTRL_OP_DRAIN;
+
+       if (action[next_state].go_s99_running_tofalse)
+               ss->go_s99_running = 0;
+
+       if (action[next_state].go_s99_running_totrue)
+               ss->go_s99_running = 1;
+
+       ss->current_op = op;
+
+       ppd->dd->f_sdma_sendctrl(ppd, ss->current_op);
+}
+
+static void unmap_desc(struct qib_pportdata *ppd, unsigned head)
+{
+       __le64 *descqp = &ppd->sdma_descq[head].qw[0];
+       u64 desc[2];
+       dma_addr_t addr;
+       size_t len;
+
+       desc[0] = le64_to_cpu(descqp[0]);
+       desc[1] = le64_to_cpu(descqp[1]);
+
+       addr = (desc[1] << 32) | (desc[0] >> 32);
+       len = (desc[0] >> 14) & (0x7ffULL << 2);
+       dma_unmap_single(&ppd->dd->pcidev->dev, addr, len, DMA_TO_DEVICE);
+}
+
+static int alloc_sdma(struct qib_pportdata *ppd)
+{
+       ppd->sdma_descq_cnt = sdma_descq_cnt;
+       if (!ppd->sdma_descq_cnt)
+               ppd->sdma_descq_cnt = 256;
+
+       /* Allocate memory for SendDMA descriptor FIFO */
+       ppd->sdma_descq = dma_alloc_coherent(&ppd->dd->pcidev->dev,
+               ppd->sdma_descq_cnt * sizeof(u64[2]), &ppd->sdma_descq_phys,
+               GFP_KERNEL);
+
+       if (!ppd->sdma_descq) {
+               qib_dev_err(ppd->dd, "failed to allocate SendDMA descriptor "
+                           "FIFO memory\n");
+               goto bail;
+       }
+
+       /* Allocate memory for DMA of head register to memory */
+       ppd->sdma_head_dma = dma_alloc_coherent(&ppd->dd->pcidev->dev,
+               PAGE_SIZE, &ppd->sdma_head_phys, GFP_KERNEL);
+       if (!ppd->sdma_head_dma) {
+               qib_dev_err(ppd->dd, "failed to allocate SendDMA "
+                           "head memory\n");
+               goto cleanup_descq;
+       }
+       ppd->sdma_head_dma[0] = 0;
+       return 0;
+
+cleanup_descq:
+       dma_free_coherent(&ppd->dd->pcidev->dev,
+               ppd->sdma_descq_cnt * sizeof(u64[2]), (void *)ppd->sdma_descq,
+               ppd->sdma_descq_phys);
+       ppd->sdma_descq = NULL;
+       ppd->sdma_descq_phys = 0;
+bail:
+       ppd->sdma_descq_cnt = 0;
+       return -ENOMEM;
+}
+
+static void free_sdma(struct qib_pportdata *ppd)
+{
+       struct qib_devdata *dd = ppd->dd;
+
+       if (ppd->sdma_head_dma) {
+               dma_free_coherent(&dd->pcidev->dev, PAGE_SIZE,
+                                 (void *)ppd->sdma_head_dma,
+                                 ppd->sdma_head_phys);
+               ppd->sdma_head_dma = NULL;
+               ppd->sdma_head_phys = 0;
+       }
+
+       if (ppd->sdma_descq) {
+               dma_free_coherent(&dd->pcidev->dev,
+                                 ppd->sdma_descq_cnt * sizeof(u64[2]),
+                                 ppd->sdma_descq, ppd->sdma_descq_phys);
+               ppd->sdma_descq = NULL;
+               ppd->sdma_descq_phys = 0;
+       }
+}
+
+static inline void make_sdma_desc(struct qib_pportdata *ppd,
+                                 u64 *sdmadesc, u64 addr, u64 dwlen,
+                                 u64 dwoffset)
+{
+
+       WARN_ON(addr & 3);
+       /* SDmaPhyAddr[47:32] */
+       sdmadesc[1] = addr >> 32;
+       /* SDmaPhyAddr[31:0] */
+       sdmadesc[0] = (addr & 0xfffffffcULL) << 32;
+       /* SDmaGeneration[1:0] */
+       sdmadesc[0] |= (ppd->sdma_generation & 3ULL) <<
+               SDMA_DESC_GEN_LSB;
+       /* SDmaDwordCount[10:0] */
+       sdmadesc[0] |= (dwlen & 0x7ffULL) << SDMA_DESC_COUNT_LSB;
+       /* SDmaBufOffset[12:2] */
+       sdmadesc[0] |= dwoffset & 0x7ffULL;
+}
+
+/* sdma_lock must be held */
+int qib_sdma_make_progress(struct qib_pportdata *ppd)
+{
+       struct list_head *lp = NULL;
+       struct qib_sdma_txreq *txp = NULL;
+       struct qib_devdata *dd = ppd->dd;
+       int progress = 0;
+       u16 hwhead;
+       u16 idx = 0;
+
+       hwhead = dd->f_sdma_gethead(ppd);
+
+       /* The reason for some of the complexity of this code is that
+        * not all descriptors have corresponding txps.  So, we have to
+        * be able to skip over descs until we wander into the range of
+        * the next txp on the list.
+        */
+
+       if (!list_empty(&ppd->sdma_activelist)) {
+               lp = ppd->sdma_activelist.next;
+               txp = list_entry(lp, struct qib_sdma_txreq, list);
+               idx = txp->start_idx;
+       }
+
+       while (ppd->sdma_descq_head != hwhead) {
+               /* if desc is part of this txp, unmap if needed */
+               if (txp && (txp->flags & QIB_SDMA_TXREQ_F_FREEDESC) &&
+                   (idx == ppd->sdma_descq_head)) {
+                       unmap_desc(ppd, ppd->sdma_descq_head);
+                       if (++idx == ppd->sdma_descq_cnt)
+                               idx = 0;
+               }
+
+               /* increment dequed desc count */
+               ppd->sdma_descq_removed++;
+
+               /* advance head, wrap if needed */
+               if (++ppd->sdma_descq_head == ppd->sdma_descq_cnt)
+                       ppd->sdma_descq_head = 0;
+
+               /* if now past this txp's descs, do the callback */
+               if (txp && txp->next_descq_idx == ppd->sdma_descq_head) {
+                       /* remove from active list */
+                       list_del_init(&txp->list);
+                       if (txp->callback)
+                               (*txp->callback)(txp, QIB_SDMA_TXREQ_S_OK);
+                       /* see if there is another txp */
+                       if (list_empty(&ppd->sdma_activelist))
+                               txp = NULL;
+                       else {
+                               lp = ppd->sdma_activelist.next;
+                               txp = list_entry(lp, struct qib_sdma_txreq,
+                                       list);
+                               idx = txp->start_idx;
+                       }
+               }
+               progress = 1;
+       }
+       if (progress)
+               qib_verbs_sdma_desc_avail(ppd, qib_sdma_descq_freecnt(ppd));
+       return progress;
+}
+
+/*
+ * This is called from interrupt context.
+ */
+void qib_sdma_intr(struct qib_pportdata *ppd)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ppd->sdma_lock, flags);
+
+       __qib_sdma_intr(ppd);
+
+       spin_unlock_irqrestore(&ppd->sdma_lock, flags);
+}
+
+void __qib_sdma_intr(struct qib_pportdata *ppd)
+{
+       if (__qib_sdma_running(ppd))
+               qib_sdma_make_progress(ppd);
+}
+
+int qib_setup_sdma(struct qib_pportdata *ppd)
+{
+       struct qib_devdata *dd = ppd->dd;
+       unsigned long flags;
+       int ret = 0;
+
+       ret = alloc_sdma(ppd);
+       if (ret)
+               goto bail;
+
+       /* set consistent sdma state */
+       ppd->dd->f_sdma_init_early(ppd);
+       spin_lock_irqsave(&ppd->sdma_lock, flags);
+       sdma_set_state(ppd, qib_sdma_state_s00_hw_down);
+       spin_unlock_irqrestore(&ppd->sdma_lock, flags);
+
+       /* set up reference counting */
+       kref_init(&ppd->sdma_state.kref);
+       init_completion(&ppd->sdma_state.comp);
+
+       ppd->sdma_generation = 0;
+       ppd->sdma_descq_head = 0;
+       ppd->sdma_descq_removed = 0;
+       ppd->sdma_descq_added = 0;
+
+       INIT_LIST_HEAD(&ppd->sdma_activelist);
+
+       tasklet_init(&ppd->sdma_sw_clean_up_task, sdma_sw_clean_up_task,
+               (unsigned long)ppd);
+
+       ret = dd->f_init_sdma_regs(ppd);
+       if (ret)
+               goto bail_alloc;
+
+       qib_sdma_process_event(ppd, qib_sdma_event_e10_go_hw_start);
+
+       return 0;
+
+bail_alloc:
+       qib_teardown_sdma(ppd);
+bail:
+       return ret;
+}
+
+void qib_teardown_sdma(struct qib_pportdata *ppd)
+{
+       qib_sdma_process_event(ppd, qib_sdma_event_e00_go_hw_down);
+
+       /*
+        * This waits for the state machine to exit so it is not
+        * necessary to kill the sdma_sw_clean_up_task to make sure
+        * it is not running.
+        */
+       sdma_finalput(&ppd->sdma_state);
+
+       free_sdma(ppd);
+}
+
+int qib_sdma_running(struct qib_pportdata *ppd)
+{
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&ppd->sdma_lock, flags);
+       ret = __qib_sdma_running(ppd);
+       spin_unlock_irqrestore(&ppd->sdma_lock, flags);
+
+       return ret;
+}
+
+/*
+ * Complete a request when sdma not running; likely only request
+ * but to simplify the code, always queue it, then process the full
+ * activelist.  We process the entire list to ensure that this particular
+ * request does get it's callback, but in the correct order.
+ * Must be called with sdma_lock held
+ */
+static void complete_sdma_err_req(struct qib_pportdata *ppd,
+                                 struct qib_verbs_txreq *tx)
+{
+       atomic_inc(&tx->qp->s_dma_busy);
+       /* no sdma descriptors, so no unmap_desc */
+       tx->txreq.start_idx = 0;
+       tx->txreq.next_descq_idx = 0;
+       list_add_tail(&tx->txreq.list, &ppd->sdma_activelist);
+       clear_sdma_activelist(ppd);
+}
+
+/*
+ * This function queues one IB packet onto the send DMA queue per call.
+ * The caller is responsible for checking:
+ * 1) The number of send DMA descriptor entries is less than the size of
+ *    the descriptor queue.
+ * 2) The IB SGE addresses and lengths are 32-bit aligned
+ *    (except possibly the last SGE's length)
+ * 3) The SGE addresses are suitable for passing to dma_map_single().
+ */
+int qib_sdma_verbs_send(struct qib_pportdata *ppd,
+                       struct qib_sge_state *ss, u32 dwords,
+                       struct qib_verbs_txreq *tx)
+{
+       unsigned long flags;
+       struct qib_sge *sge;
+       struct qib_qp *qp;
+       int ret = 0;
+       u16 tail;
+       __le64 *descqp;
+       u64 sdmadesc[2];
+       u32 dwoffset;
+       dma_addr_t addr;
+
+       spin_lock_irqsave(&ppd->sdma_lock, flags);
+
+retry:
+       if (unlikely(!__qib_sdma_running(ppd))) {
+               complete_sdma_err_req(ppd, tx);
+               goto unlock;
+       }
+
+       if (tx->txreq.sg_count > qib_sdma_descq_freecnt(ppd)) {
+               if (qib_sdma_make_progress(ppd))
+                       goto retry;
+               if (ppd->dd->flags & QIB_HAS_SDMA_TIMEOUT)
+                       ppd->dd->f_sdma_set_desc_cnt(ppd,
+                                       ppd->sdma_descq_cnt / 2);
+               goto busy;
+       }
+
+       dwoffset = tx->hdr_dwords;
+       make_sdma_desc(ppd, sdmadesc, (u64) tx->txreq.addr, dwoffset, 0);
+
+       sdmadesc[0] |= SDMA_DESC_FIRST;
+       if (tx->txreq.flags & QIB_SDMA_TXREQ_F_USELARGEBUF)
+               sdmadesc[0] |= SDMA_DESC_USE_LARGE_BUF;
+
+       /* write to the descq */
+       tail = ppd->sdma_descq_tail;
+       descqp = &ppd->sdma_descq[tail].qw[0];
+       *descqp++ = cpu_to_le64(sdmadesc[0]);
+       *descqp++ = cpu_to_le64(sdmadesc[1]);
+
+       /* increment the tail */
+       if (++tail == ppd->sdma_descq_cnt) {
+               tail = 0;
+               descqp = &ppd->sdma_descq[0].qw[0];
+               ++ppd->sdma_generation;
+       }
+
+       tx->txreq.start_idx = tail;
+
+       sge = &ss->sge;
+       while (dwords) {
+               u32 dw;
+               u32 len;
+
+               len = dwords << 2;
+               if (len > sge->length)
+                       len = sge->length;
+               if (len > sge->sge_length)
+                       len = sge->sge_length;
+               BUG_ON(len == 0);
+               dw = (len + 3) >> 2;
+               addr = dma_map_single(&ppd->dd->pcidev->dev, sge->vaddr,
+                                     dw << 2, DMA_TO_DEVICE);
+               if (dma_mapping_error(&ppd->dd->pcidev->dev, addr))
+                       goto unmap;
+               sdmadesc[0] = 0;
+               make_sdma_desc(ppd, sdmadesc, (u64) addr, dw, dwoffset);
+               /* SDmaUseLargeBuf has to be set in every descriptor */
+               if (tx->txreq.flags & QIB_SDMA_TXREQ_F_USELARGEBUF)
+                       sdmadesc[0] |= SDMA_DESC_USE_LARGE_BUF;
+               /* write to the descq */
+               *descqp++ = cpu_to_le64(sdmadesc[0]);
+               *descqp++ = cpu_to_le64(sdmadesc[1]);
+
+               /* increment the tail */
+               if (++tail == ppd->sdma_descq_cnt) {
+                       tail = 0;
+                       descqp = &ppd->sdma_descq[0].qw[0];
+                       ++ppd->sdma_generation;
+               }
+               sge->vaddr += len;
+               sge->length -= len;
+               sge->sge_length -= len;
+               if (sge->sge_length == 0) {
+                       if (--ss->num_sge)
+                               *sge = *ss->sg_list++;
+               } else if (sge->length == 0 && sge->mr->lkey) {
+                       if (++sge->n >= QIB_SEGSZ) {
+                               if (++sge->m >= sge->mr->mapsz)
+                                       break;
+                               sge->n = 0;
+                       }
+                       sge->vaddr =
+                               sge->mr->map[sge->m]->segs[sge->n].vaddr;
+                       sge->length =
+                               sge->mr->map[sge->m]->segs[sge->n].length;
+               }
+
+               dwoffset += dw;
+               dwords -= dw;
+       }
+
+       if (!tail)
+               descqp = &ppd->sdma_descq[ppd->sdma_descq_cnt].qw[0];
+       descqp -= 2;
+       descqp[0] |= cpu_to_le64(SDMA_DESC_LAST);
+       if (tx->txreq.flags & QIB_SDMA_TXREQ_F_HEADTOHOST)
+               descqp[0] |= cpu_to_le64(SDMA_DESC_DMA_HEAD);
+       if (tx->txreq.flags & QIB_SDMA_TXREQ_F_INTREQ)
+               descqp[0] |= cpu_to_le64(SDMA_DESC_INTR);
+
+       atomic_inc(&tx->qp->s_dma_busy);
+       tx->txreq.next_descq_idx = tail;
+       ppd->dd->f_sdma_update_tail(ppd, tail);
+       ppd->sdma_descq_added += tx->txreq.sg_count;
+       list_add_tail(&tx->txreq.list, &ppd->sdma_activelist);
+       goto unlock;
+
+unmap:
+       for (;;) {
+               if (!tail)
+                       tail = ppd->sdma_descq_cnt - 1;
+               else
+                       tail--;
+               if (tail == ppd->sdma_descq_tail)
+                       break;
+               unmap_desc(ppd, tail);
+       }
+       qp = tx->qp;
+       qib_put_txreq(tx);
+       spin_lock(&qp->s_lock);
+       if (qp->ibqp.qp_type == IB_QPT_RC) {
+               /* XXX what about error sending RDMA read responses? */
+               if (ib_qib_state_ops[qp->state] & QIB_PROCESS_RECV_OK)
+                       qib_error_qp(qp, IB_WC_GENERAL_ERR);
+       } else if (qp->s_wqe)
+               qib_send_complete(qp, qp->s_wqe, IB_WC_GENERAL_ERR);
+       spin_unlock(&qp->s_lock);
+       /* return zero to process the next send work request */
+       goto unlock;
+
+busy:
+       qp = tx->qp;
+       spin_lock(&qp->s_lock);
+       if (ib_qib_state_ops[qp->state] & QIB_PROCESS_RECV_OK) {
+               struct qib_ibdev *dev;
+
+               /*
+                * If we couldn't queue the DMA request, save the info
+                * and try again later rather than destroying the
+                * buffer and undoing the side effects of the copy.
+                */
+               tx->ss = ss;
+               tx->dwords = dwords;
+               qp->s_tx = tx;
+               dev = &ppd->dd->verbs_dev;
+               spin_lock(&dev->pending_lock);
+               if (list_empty(&qp->iowait)) {
+                       struct qib_ibport *ibp;
+
+                       ibp = &ppd->ibport_data;
+                       ibp->n_dmawait++;
+                       qp->s_flags |= QIB_S_WAIT_DMA_DESC;
+                       list_add_tail(&qp->iowait, &dev->dmawait);
+               }
+               spin_unlock(&dev->pending_lock);
+               qp->s_flags &= ~QIB_S_BUSY;
+               spin_unlock(&qp->s_lock);
+               ret = -EBUSY;
+       } else {
+               spin_unlock(&qp->s_lock);
+               qib_put_txreq(tx);
+       }
+unlock:
+       spin_unlock_irqrestore(&ppd->sdma_lock, flags);
+       return ret;
+}
+
+void qib_sdma_process_event(struct qib_pportdata *ppd,
+       enum qib_sdma_events event)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ppd->sdma_lock, flags);
+
+       __qib_sdma_process_event(ppd, event);
+
+       if (ppd->sdma_state.current_state == qib_sdma_state_s99_running)
+               qib_verbs_sdma_desc_avail(ppd, qib_sdma_descq_freecnt(ppd));
+
+       spin_unlock_irqrestore(&ppd->sdma_lock, flags);
+}
+
+void __qib_sdma_process_event(struct qib_pportdata *ppd,
+       enum qib_sdma_events event)
+{
+       struct qib_sdma_state *ss = &ppd->sdma_state;
+
+       switch (ss->current_state) {
+       case qib_sdma_state_s00_hw_down:
+               switch (event) {
+               case qib_sdma_event_e00_go_hw_down:
+                       break;
+               case qib_sdma_event_e30_go_running:
+                       /*
+                        * If down, but running requested (usually result
+                        * of link up, then we need to start up.
+                        * This can happen when hw down is requested while
+                        * bringing the link up with traffic active on
+                        * 7220, e.g. */
+                       ss->go_s99_running = 1;
+                       /* fall through and start dma engine */
+               case qib_sdma_event_e10_go_hw_start:
+                       /* This reference means the state machine is started */
+                       sdma_get(&ppd->sdma_state);
+                       sdma_set_state(ppd,
+                                      qib_sdma_state_s10_hw_start_up_wait);
+                       break;
+               case qib_sdma_event_e20_hw_started:
+                       break;
+               case qib_sdma_event_e40_sw_cleaned:
+                       sdma_sw_tear_down(ppd);
+                       break;
+               case qib_sdma_event_e50_hw_cleaned:
+                       break;
+               case qib_sdma_event_e60_hw_halted:
+                       break;
+               case qib_sdma_event_e70_go_idle:
+                       break;
+               case qib_sdma_event_e7220_err_halted:
+                       break;
+               case qib_sdma_event_e7322_err_halted:
+                       break;
+               case qib_sdma_event_e90_timer_tick:
+                       break;
+               }
+               break;
+
+       case qib_sdma_state_s10_hw_start_up_wait:
+               switch (event) {
+               case qib_sdma_event_e00_go_hw_down:
+                       sdma_set_state(ppd, qib_sdma_state_s00_hw_down);
+                       sdma_sw_tear_down(ppd);
+                       break;
+               case qib_sdma_event_e10_go_hw_start:
+                       break;
+               case qib_sdma_event_e20_hw_started:
+                       sdma_set_state(ppd, ss->go_s99_running ?
+                                      qib_sdma_state_s99_running :
+                                      qib_sdma_state_s20_idle);
+                       break;
+               case qib_sdma_event_e30_go_running:
+                       ss->go_s99_running = 1;
+                       break;
+               case qib_sdma_event_e40_sw_cleaned:
+                       break;
+               case qib_sdma_event_e50_hw_cleaned:
+                       break;
+               case qib_sdma_event_e60_hw_halted:
+                       break;
+               case qib_sdma_event_e70_go_idle:
+                       ss->go_s99_running = 0;
+                       break;
+               case qib_sdma_event_e7220_err_halted:
+                       break;
+               case qib_sdma_event_e7322_err_halted:
+                       break;
+               case qib_sdma_event_e90_timer_tick:
+                       break;
+               }
+               break;
+
+       case qib_sdma_state_s20_idle:
+               switch (event) {
+               case qib_sdma_event_e00_go_hw_down:
+                       sdma_set_state(ppd, qib_sdma_state_s00_hw_down);
+                       sdma_sw_tear_down(ppd);
+                       break;
+               case qib_sdma_event_e10_go_hw_start:
+                       break;
+               case qib_sdma_event_e20_hw_started:
+                       break;
+               case qib_sdma_event_e30_go_running:
+                       sdma_set_state(ppd, qib_sdma_state_s99_running);
+                       ss->go_s99_running = 1;
+                       break;
+               case qib_sdma_event_e40_sw_cleaned:
+                       break;
+               case qib_sdma_event_e50_hw_cleaned:
+                       break;
+               case qib_sdma_event_e60_hw_halted:
+                       break;
+               case qib_sdma_event_e70_go_idle:
+                       break;
+               case qib_sdma_event_e7220_err_halted:
+                       break;
+               case qib_sdma_event_e7322_err_halted:
+                       break;
+               case qib_sdma_event_e90_timer_tick:
+                       break;
+               }
+               break;
+
+       case qib_sdma_state_s30_sw_clean_up_wait:
+               switch (event) {
+               case qib_sdma_event_e00_go_hw_down:
+                       sdma_set_state(ppd, qib_sdma_state_s00_hw_down);
+                       break;
+               case qib_sdma_event_e10_go_hw_start:
+                       break;
+               case qib_sdma_event_e20_hw_started:
+                       break;
+               case qib_sdma_event_e30_go_running:
+                       ss->go_s99_running = 1;
+                       break;
+               case qib_sdma_event_e40_sw_cleaned:
+                       sdma_set_state(ppd,
+                                      qib_sdma_state_s10_hw_start_up_wait);
+                       sdma_hw_start_up(ppd);
+                       break;
+               case qib_sdma_event_e50_hw_cleaned:
+                       break;
+               case qib_sdma_event_e60_hw_halted:
+                       break;
+               case qib_sdma_event_e70_go_idle:
+                       ss->go_s99_running = 0;
+                       break;
+               case qib_sdma_event_e7220_err_halted:
+                       break;
+               case qib_sdma_event_e7322_err_halted:
+                       break;
+               case qib_sdma_event_e90_timer_tick:
+                       break;
+               }
+               break;
+
+       case qib_sdma_state_s40_hw_clean_up_wait:
+               switch (event) {
+               case qib_sdma_event_e00_go_hw_down:
+                       sdma_set_state(ppd, qib_sdma_state_s00_hw_down);
+                       sdma_start_sw_clean_up(ppd);
+                       break;
+               case qib_sdma_event_e10_go_hw_start:
+                       break;
+               case qib_sdma_event_e20_hw_started:
+                       break;
+               case qib_sdma_event_e30_go_running:
+                       ss->go_s99_running = 1;
+                       break;
+               case qib_sdma_event_e40_sw_cleaned:
+                       break;
+               case qib_sdma_event_e50_hw_cleaned:
+                       sdma_set_state(ppd,
+                                      qib_sdma_state_s30_sw_clean_up_wait);
+                       sdma_start_sw_clean_up(ppd);
+                       break;
+               case qib_sdma_event_e60_hw_halted:
+                       break;
+               case qib_sdma_event_e70_go_idle:
+                       ss->go_s99_running = 0;
+                       break;
+               case qib_sdma_event_e7220_err_halted:
+                       break;
+               case qib_sdma_event_e7322_err_halted:
+                       break;
+               case qib_sdma_event_e90_timer_tick:
+                       break;
+               }
+               break;
+
+       case qib_sdma_state_s50_hw_halt_wait:
+               switch (event) {
+               case qib_sdma_event_e00_go_hw_down:
+                       sdma_set_state(ppd, qib_sdma_state_s00_hw_down);
+                       sdma_start_sw_clean_up(ppd);
+                       break;
+               case qib_sdma_event_e10_go_hw_start:
+                       break;
+               case qib_sdma_event_e20_hw_started:
+                       break;
+               case qib_sdma_event_e30_go_running:
+                       ss->go_s99_running = 1;
+                       break;
+               case qib_sdma_event_e40_sw_cleaned:
+                       break;
+               case qib_sdma_event_e50_hw_cleaned:
+                       break;
+               case qib_sdma_event_e60_hw_halted:
+                       sdma_set_state(ppd,
+                                      qib_sdma_state_s40_hw_clean_up_wait);
+                       ppd->dd->f_sdma_hw_clean_up(ppd);
+                       break;
+               case qib_sdma_event_e70_go_idle:
+                       ss->go_s99_running = 0;
+                       break;
+               case qib_sdma_event_e7220_err_halted:
+                       break;
+               case qib_sdma_event_e7322_err_halted:
+                       break;
+               case qib_sdma_event_e90_timer_tick:
+                       break;
+               }
+               break;
+
+       case qib_sdma_state_s99_running:
+               switch (event) {
+               case qib_sdma_event_e00_go_hw_down:
+                       sdma_set_state(ppd, qib_sdma_state_s00_hw_down);
+                       sdma_start_sw_clean_up(ppd);
+                       break;
+               case qib_sdma_event_e10_go_hw_start:
+                       break;
+               case qib_sdma_event_e20_hw_started:
+                       break;
+               case qib_sdma_event_e30_go_running:
+                       break;
+               case qib_sdma_event_e40_sw_cleaned:
+                       break;
+               case qib_sdma_event_e50_hw_cleaned:
+                       break;
+               case qib_sdma_event_e60_hw_halted:
+                       sdma_set_state(ppd,
+                                      qib_sdma_state_s30_sw_clean_up_wait);
+                       sdma_start_sw_clean_up(ppd);
+                       break;
+               case qib_sdma_event_e70_go_idle:
+                       sdma_set_state(ppd, qib_sdma_state_s50_hw_halt_wait);
+                       ss->go_s99_running = 0;
+                       break;
+               case qib_sdma_event_e7220_err_halted:
+                       sdma_set_state(ppd,
+                                      qib_sdma_state_s30_sw_clean_up_wait);
+                       sdma_start_sw_clean_up(ppd);
+                       break;
+               case qib_sdma_event_e7322_err_halted:
+                       sdma_set_state(ppd, qib_sdma_state_s50_hw_halt_wait);
+                       break;
+               case qib_sdma_event_e90_timer_tick:
+                       break;
+               }
+               break;
+       }
+
+       ss->last_event = event;
+}
diff --git a/drivers/infiniband/hw/qib/qib_srq.c b/drivers/infiniband/hw/qib/qib_srq.c
new file mode 100644 (file)
index 0000000..c3ec8ef
--- /dev/null
@@ -0,0 +1,375 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved.
+ * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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/err.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#include "qib_verbs.h"
+
+/**
+ * qib_post_srq_receive - post a receive on a shared receive queue
+ * @ibsrq: the SRQ to post the receive on
+ * @wr: the list of work requests to post
+ * @bad_wr: A pointer to the first WR to cause a problem is put here
+ *
+ * This may be called from interrupt context.
+ */
+int qib_post_srq_receive(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
+                        struct ib_recv_wr **bad_wr)
+{
+       struct qib_srq *srq = to_isrq(ibsrq);
+       struct qib_rwq *wq;
+       unsigned long flags;
+       int ret;
+
+       for (; wr; wr = wr->next) {
+               struct qib_rwqe *wqe;
+               u32 next;
+               int i;
+
+               if ((unsigned) wr->num_sge > srq->rq.max_sge) {
+                       *bad_wr = wr;
+                       ret = -EINVAL;
+                       goto bail;
+               }
+
+               spin_lock_irqsave(&srq->rq.lock, flags);
+               wq = srq->rq.wq;
+               next = wq->head + 1;
+               if (next >= srq->rq.size)
+                       next = 0;
+               if (next == wq->tail) {
+                       spin_unlock_irqrestore(&srq->rq.lock, flags);
+                       *bad_wr = wr;
+                       ret = -ENOMEM;
+                       goto bail;
+               }
+
+               wqe = get_rwqe_ptr(&srq->rq, wq->head);
+               wqe->wr_id = wr->wr_id;
+               wqe->num_sge = wr->num_sge;
+               for (i = 0; i < wr->num_sge; i++)
+                       wqe->sg_list[i] = wr->sg_list[i];
+               /* Make sure queue entry is written before the head index. */
+               smp_wmb();
+               wq->head = next;
+               spin_unlock_irqrestore(&srq->rq.lock, flags);
+       }
+       ret = 0;
+
+bail:
+       return ret;
+}
+
+/**
+ * qib_create_srq - create a shared receive queue
+ * @ibpd: the protection domain of the SRQ to create
+ * @srq_init_attr: the attributes of the SRQ
+ * @udata: data from libibverbs when creating a user SRQ
+ */
+struct ib_srq *qib_create_srq(struct ib_pd *ibpd,
+                             struct ib_srq_init_attr *srq_init_attr,
+                             struct ib_udata *udata)
+{
+       struct qib_ibdev *dev = to_idev(ibpd->device);
+       struct qib_srq *srq;
+       u32 sz;
+       struct ib_srq *ret;
+
+       if (srq_init_attr->attr.max_sge == 0 ||
+           srq_init_attr->attr.max_sge > ib_qib_max_srq_sges ||
+           srq_init_attr->attr.max_wr == 0 ||
+           srq_init_attr->attr.max_wr > ib_qib_max_srq_wrs) {
+               ret = ERR_PTR(-EINVAL);
+               goto done;
+       }
+
+       srq = kmalloc(sizeof(*srq), GFP_KERNEL);
+       if (!srq) {
+               ret = ERR_PTR(-ENOMEM);
+               goto done;
+       }
+
+       /*
+        * Need to use vmalloc() if we want to support large #s of entries.
+        */
+       srq->rq.size = srq_init_attr->attr.max_wr + 1;
+       srq->rq.max_sge = srq_init_attr->attr.max_sge;
+       sz = sizeof(struct ib_sge) * srq->rq.max_sge +
+               sizeof(struct qib_rwqe);
+       srq->rq.wq = vmalloc_user(sizeof(struct qib_rwq) + srq->rq.size * sz);
+       if (!srq->rq.wq) {
+               ret = ERR_PTR(-ENOMEM);
+               goto bail_srq;
+       }
+
+       /*
+        * Return the address of the RWQ as the offset to mmap.
+        * See qib_mmap() for details.
+        */
+       if (udata && udata->outlen >= sizeof(__u64)) {
+               int err;
+               u32 s = sizeof(struct qib_rwq) + srq->rq.size * sz;
+
+               srq->ip =
+                   qib_create_mmap_info(dev, s, ibpd->uobject->context,
+                                        srq->rq.wq);
+               if (!srq->ip) {
+                       ret = ERR_PTR(-ENOMEM);
+                       goto bail_wq;
+               }
+
+               err = ib_copy_to_udata(udata, &srq->ip->offset,
+                                      sizeof(srq->ip->offset));
+               if (err) {
+                       ret = ERR_PTR(err);
+                       goto bail_ip;
+               }
+       } else
+               srq->ip = NULL;
+
+       /*
+        * ib_create_srq() will initialize srq->ibsrq.
+        */
+       spin_lock_init(&srq->rq.lock);
+       srq->rq.wq->head = 0;
+       srq->rq.wq->tail = 0;
+       srq->limit = srq_init_attr->attr.srq_limit;
+
+       spin_lock(&dev->n_srqs_lock);
+       if (dev->n_srqs_allocated == ib_qib_max_srqs) {
+               spin_unlock(&dev->n_srqs_lock);
+               ret = ERR_PTR(-ENOMEM);
+               goto bail_ip;
+       }
+
+       dev->n_srqs_allocated++;
+       spin_unlock(&dev->n_srqs_lock);
+
+       if (srq->ip) {
+               spin_lock_irq(&dev->pending_lock);
+               list_add(&srq->ip->pending_mmaps, &dev->pending_mmaps);
+               spin_unlock_irq(&dev->pending_lock);
+       }
+
+       ret = &srq->ibsrq;
+       goto done;
+
+bail_ip:
+       kfree(srq->ip);
+bail_wq:
+       vfree(srq->rq.wq);
+bail_srq:
+       kfree(srq);
+done:
+       return ret;
+}
+
+/**
+ * qib_modify_srq - modify a shared receive queue
+ * @ibsrq: the SRQ to modify
+ * @attr: the new attributes of the SRQ
+ * @attr_mask: indicates which attributes to modify
+ * @udata: user data for libibverbs.so
+ */
+int qib_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
+                  enum ib_srq_attr_mask attr_mask,
+                  struct ib_udata *udata)
+{
+       struct qib_srq *srq = to_isrq(ibsrq);
+       struct qib_rwq *wq;
+       int ret = 0;
+
+       if (attr_mask & IB_SRQ_MAX_WR) {
+               struct qib_rwq *owq;
+               struct qib_rwqe *p;
+               u32 sz, size, n, head, tail;
+
+               /* Check that the requested sizes are below the limits. */
+               if ((attr->max_wr > ib_qib_max_srq_wrs) ||
+                   ((attr_mask & IB_SRQ_LIMIT) ?
+                    attr->srq_limit : srq->limit) > attr->max_wr) {
+                       ret = -EINVAL;
+                       goto bail;
+               }
+
+               sz = sizeof(struct qib_rwqe) +
+                       srq->rq.max_sge * sizeof(struct ib_sge);
+               size = attr->max_wr + 1;
+               wq = vmalloc_user(sizeof(struct qib_rwq) + size * sz);
+               if (!wq) {
+                       ret = -ENOMEM;
+                       goto bail;
+               }
+
+               /* Check that we can write the offset to mmap. */
+               if (udata && udata->inlen >= sizeof(__u64)) {
+                       __u64 offset_addr;
+                       __u64 offset = 0;
+
+                       ret = ib_copy_from_udata(&offset_addr, udata,
+                                                sizeof(offset_addr));
+                       if (ret)
+                               goto bail_free;
+                       udata->outbuf =
+                               (void __user *) (unsigned long) offset_addr;
+                       ret = ib_copy_to_udata(udata, &offset,
+                                              sizeof(offset));
+                       if (ret)
+                               goto bail_free;
+               }
+
+               spin_lock_irq(&srq->rq.lock);
+               /*
+                * validate head and tail pointer values and compute
+                * the number of remaining WQEs.
+                */
+               owq = srq->rq.wq;
+               head = owq->head;
+               tail = owq->tail;
+               if (head >= srq->rq.size || tail >= srq->rq.size) {
+                       ret = -EINVAL;
+                       goto bail_unlock;
+               }
+               n = head;
+               if (n < tail)
+                       n += srq->rq.size - tail;
+               else
+                       n -= tail;
+               if (size <= n) {
+                       ret = -EINVAL;
+                       goto bail_unlock;
+               }
+               n = 0;
+               p = wq->wq;
+               while (tail != head) {
+                       struct qib_rwqe *wqe;
+                       int i;
+
+                       wqe = get_rwqe_ptr(&srq->rq, tail);
+                       p->wr_id = wqe->wr_id;
+                       p->num_sge = wqe->num_sge;
+                       for (i = 0; i < wqe->num_sge; i++)
+                               p->sg_list[i] = wqe->sg_list[i];
+                       n++;
+                       p = (struct qib_rwqe *)((char *) p + sz);
+                       if (++tail >= srq->rq.size)
+                               tail = 0;
+               }
+               srq->rq.wq = wq;
+               srq->rq.size = size;
+               wq->head = n;
+               wq->tail = 0;
+               if (attr_mask & IB_SRQ_LIMIT)
+                       srq->limit = attr->srq_limit;
+               spin_unlock_irq(&srq->rq.lock);
+
+               vfree(owq);
+
+               if (srq->ip) {
+                       struct qib_mmap_info *ip = srq->ip;
+                       struct qib_ibdev *dev = to_idev(srq->ibsrq.device);
+                       u32 s = sizeof(struct qib_rwq) + size * sz;
+
+                       qib_update_mmap_info(dev, ip, s, wq);
+
+                       /*
+                        * Return the offset to mmap.
+                        * See qib_mmap() for details.
+                        */
+                       if (udata && udata->inlen >= sizeof(__u64)) {
+                               ret = ib_copy_to_udata(udata, &ip->offset,
+                                                      sizeof(ip->offset));
+                               if (ret)
+                                       goto bail;
+                       }
+
+                       /*
+                        * Put user mapping info onto the pending list
+                        * unless it already is on the list.
+                        */
+                       spin_lock_irq(&dev->pending_lock);
+                       if (list_empty(&ip->pending_mmaps))
+                               list_add(&ip->pending_mmaps,
+                                        &dev->pending_mmaps);
+                       spin_unlock_irq(&dev->pending_lock);
+               }
+       } else if (attr_mask & IB_SRQ_LIMIT) {
+               spin_lock_irq(&srq->rq.lock);
+               if (attr->srq_limit >= srq->rq.size)
+                       ret = -EINVAL;
+               else
+                       srq->limit = attr->srq_limit;
+               spin_unlock_irq(&srq->rq.lock);
+       }
+       goto bail;
+
+bail_unlock:
+       spin_unlock_irq(&srq->rq.lock);
+bail_free:
+       vfree(wq);
+bail:
+       return ret;
+}
+
+int qib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr)
+{
+       struct qib_srq *srq = to_isrq(ibsrq);
+
+       attr->max_wr = srq->rq.size - 1;
+       attr->max_sge = srq->rq.max_sge;
+       attr->srq_limit = srq->limit;
+       return 0;
+}
+
+/**
+ * qib_destroy_srq - destroy a shared receive queue
+ * @ibsrq: the SRQ to destroy
+ */
+int qib_destroy_srq(struct ib_srq *ibsrq)
+{
+       struct qib_srq *srq = to_isrq(ibsrq);
+       struct qib_ibdev *dev = to_idev(ibsrq->device);
+
+       spin_lock(&dev->n_srqs_lock);
+       dev->n_srqs_allocated--;
+       spin_unlock(&dev->n_srqs_lock);
+       if (srq->ip)
+               kref_put(&srq->ip->ref, qib_release_mmap_info);
+       else
+               vfree(srq->rq.wq);
+       kfree(srq);
+
+       return 0;
+}
diff --git a/drivers/infiniband/hw/qib/qib_sysfs.c b/drivers/infiniband/hw/qib/qib_sysfs.c
new file mode 100644 (file)
index 0000000..dab4d9f
--- /dev/null
@@ -0,0 +1,691 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved.
+ * Copyright (c) 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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/ctype.h>
+
+#include "qib.h"
+
+/**
+ * qib_parse_ushort - parse an unsigned short value in an arbitrary base
+ * @str: the string containing the number
+ * @valp: where to put the result
+ *
+ * Returns the number of bytes consumed, or negative value on error.
+ */
+static int qib_parse_ushort(const char *str, unsigned short *valp)
+{
+       unsigned long val;
+       char *end;
+       int ret;
+
+       if (!isdigit(str[0])) {
+               ret = -EINVAL;
+               goto bail;
+       }
+
+       val = simple_strtoul(str, &end, 0);
+
+       if (val > 0xffff) {
+               ret = -EINVAL;
+               goto bail;
+       }
+
+       *valp = val;
+
+       ret = end + 1 - str;
+       if (ret == 0)
+               ret = -EINVAL;
+
+bail:
+       return ret;
+}
+
+/* start of per-port functions */
+/*
+ * Get/Set heartbeat enable. OR of 1=enabled, 2=auto
+ */
+static ssize_t show_hrtbt_enb(struct qib_pportdata *ppd, char *buf)
+{
+       struct qib_devdata *dd = ppd->dd;
+       int ret;
+
+       ret = dd->f_get_ib_cfg(ppd, QIB_IB_CFG_HRTBT);
+       ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
+       return ret;
+}
+
+static ssize_t store_hrtbt_enb(struct qib_pportdata *ppd, const char *buf,
+                              size_t count)
+{
+       struct qib_devdata *dd = ppd->dd;
+       int ret;
+       u16 val;
+
+       ret = qib_parse_ushort(buf, &val);
+
+       /*
+        * Set the "intentional" heartbeat enable per either of
+        * "Enable" and "Auto", as these are normally set together.
+        * This bit is consulted when leaving loopback mode,
+        * because entering loopback mode overrides it and automatically
+        * disables heartbeat.
+        */
+       if (ret >= 0)
+               ret = dd->f_set_ib_cfg(ppd, QIB_IB_CFG_HRTBT, val);
+       if (ret < 0)
+               qib_dev_err(dd, "attempt to set invalid Heartbeat enable\n");
+       return ret < 0 ? ret : count;
+}
+
+static ssize_t store_loopback(struct qib_pportdata *ppd, const char *buf,
+                             size_t count)
+{
+       struct qib_devdata *dd = ppd->dd;
+       int ret = count, r;
+
+       r = dd->f_set_ib_loopback(ppd, buf);
+       if (r < 0)
+               ret = r;
+
+       return ret;
+}
+
+static ssize_t store_led_override(struct qib_pportdata *ppd, const char *buf,
+                                 size_t count)
+{
+       struct qib_devdata *dd = ppd->dd;
+       int ret;
+       u16 val;
+
+       ret = qib_parse_ushort(buf, &val);
+       if (ret > 0)
+               qib_set_led_override(ppd, val);
+       else
+               qib_dev_err(dd, "attempt to set invalid LED override\n");
+       return ret < 0 ? ret : count;
+}
+
+static ssize_t show_status(struct qib_pportdata *ppd, char *buf)
+{
+       ssize_t ret;
+
+       if (!ppd->statusp)
+               ret = -EINVAL;
+       else
+               ret = scnprintf(buf, PAGE_SIZE, "0x%llx\n",
+                               (unsigned long long) *(ppd->statusp));
+       return ret;
+}
+
+/*
+ * For userland compatibility, these offsets must remain fixed.
+ * They are strings for QIB_STATUS_*
+ */
+static const char *qib_status_str[] = {
+       "Initted",
+       "",
+       "",
+       "",
+       "",
+       "Present",
+       "IB_link_up",
+       "IB_configured",
+       "",
+       "Fatal_Hardware_Error",
+       NULL,
+};
+
+static ssize_t show_status_str(struct qib_pportdata *ppd, char *buf)
+{
+       int i, any;
+       u64 s;
+       ssize_t ret;
+
+       if (!ppd->statusp) {
+               ret = -EINVAL;
+               goto bail;
+       }
+
+       s = *(ppd->statusp);
+       *buf = '\0';
+       for (any = i = 0; s && qib_status_str[i]; i++) {
+               if (s & 1) {
+                       /* if overflow */
+                       if (any && strlcat(buf, " ", PAGE_SIZE) >= PAGE_SIZE)
+                               break;
+                       if (strlcat(buf, qib_status_str[i], PAGE_SIZE) >=
+                                       PAGE_SIZE)
+                               break;
+                       any = 1;
+               }
+               s >>= 1;
+       }
+       if (any)
+               strlcat(buf, "\n", PAGE_SIZE);
+
+       ret = strlen(buf);
+
+bail:
+       return ret;
+}
+
+/* end of per-port functions */
+
+/*
+ * Start of per-port file structures and support code
+ * Because we are fitting into other infrastructure, we have to supply the
+ * full set of kobject/sysfs_ops structures and routines.
+ */
+#define QIB_PORT_ATTR(name, mode, show, store) \
+       static struct qib_port_attr qib_port_attr_##name = \
+               __ATTR(name, mode, show, store)
+
+struct qib_port_attr {
+       struct attribute attr;
+       ssize_t (*show)(struct qib_pportdata *, char *);
+       ssize_t (*store)(struct qib_pportdata *, const char *, size_t);
+};
+
+QIB_PORT_ATTR(loopback, S_IWUSR, NULL, store_loopback);
+QIB_PORT_ATTR(led_override, S_IWUSR, NULL, store_led_override);
+QIB_PORT_ATTR(hrtbt_enable, S_IWUSR | S_IRUGO, show_hrtbt_enb,
+             store_hrtbt_enb);
+QIB_PORT_ATTR(status, S_IRUGO, show_status, NULL);
+QIB_PORT_ATTR(status_str, S_IRUGO, show_status_str, NULL);
+
+static struct attribute *port_default_attributes[] = {
+       &qib_port_attr_loopback.attr,
+       &qib_port_attr_led_override.attr,
+       &qib_port_attr_hrtbt_enable.attr,
+       &qib_port_attr_status.attr,
+       &qib_port_attr_status_str.attr,
+       NULL
+};
+
+static ssize_t qib_portattr_show(struct kobject *kobj,
+       struct attribute *attr, char *buf)
+{
+       struct qib_port_attr *pattr =
+               container_of(attr, struct qib_port_attr, attr);
+       struct qib_pportdata *ppd =
+               container_of(kobj, struct qib_pportdata, pport_kobj);
+
+       return pattr->show(ppd, buf);
+}
+
+static ssize_t qib_portattr_store(struct kobject *kobj,
+       struct attribute *attr, const char *buf, size_t len)
+{
+       struct qib_port_attr *pattr =
+               container_of(attr, struct qib_port_attr, attr);
+       struct qib_pportdata *ppd =
+               container_of(kobj, struct qib_pportdata, pport_kobj);
+
+       return pattr->store(ppd, buf, len);
+}
+
+static void qib_port_release(struct kobject *kobj)
+{
+       /* nothing to do since memory is freed by qib_free_devdata() */
+}
+
+static const struct sysfs_ops qib_port_ops = {
+       .show = qib_portattr_show,
+       .store = qib_portattr_store,
+};
+
+static struct kobj_type qib_port_ktype = {
+       .release = qib_port_release,
+       .sysfs_ops = &qib_port_ops,
+       .default_attrs = port_default_attributes
+};
+
+/* Start sl2vl */
+
+#define QIB_SL2VL_ATTR(N) \
+       static struct qib_sl2vl_attr qib_sl2vl_attr_##N = { \
+               .attr = { .name = __stringify(N), .mode = 0444 }, \
+               .sl = N \
+       }
+
+struct qib_sl2vl_attr {
+       struct attribute attr;
+       int sl;
+};
+
+QIB_SL2VL_ATTR(0);
+QIB_SL2VL_ATTR(1);
+QIB_SL2VL_ATTR(2);
+QIB_SL2VL_ATTR(3);
+QIB_SL2VL_ATTR(4);
+QIB_SL2VL_ATTR(5);
+QIB_SL2VL_ATTR(6);
+QIB_SL2VL_ATTR(7);
+QIB_SL2VL_ATTR(8);
+QIB_SL2VL_ATTR(9);
+QIB_SL2VL_ATTR(10);
+QIB_SL2VL_ATTR(11);
+QIB_SL2VL_ATTR(12);
+QIB_SL2VL_ATTR(13);
+QIB_SL2VL_ATTR(14);
+QIB_SL2VL_ATTR(15);
+
+static struct attribute *sl2vl_default_attributes[] = {
+       &qib_sl2vl_attr_0.attr,
+       &qib_sl2vl_attr_1.attr,
+       &qib_sl2vl_attr_2.attr,
+       &qib_sl2vl_attr_3.attr,
+       &qib_sl2vl_attr_4.attr,
+       &qib_sl2vl_attr_5.attr,
+       &qib_sl2vl_attr_6.attr,
+       &qib_sl2vl_attr_7.attr,
+       &qib_sl2vl_attr_8.attr,
+       &qib_sl2vl_attr_9.attr,
+       &qib_sl2vl_attr_10.attr,
+       &qib_sl2vl_attr_11.attr,
+       &qib_sl2vl_attr_12.attr,
+       &qib_sl2vl_attr_13.attr,
+       &qib_sl2vl_attr_14.attr,
+       &qib_sl2vl_attr_15.attr,
+       NULL
+};
+
+static ssize_t sl2vl_attr_show(struct kobject *kobj, struct attribute *attr,
+                              char *buf)
+{
+       struct qib_sl2vl_attr *sattr =
+               container_of(attr, struct qib_sl2vl_attr, attr);
+       struct qib_pportdata *ppd =
+               container_of(kobj, struct qib_pportdata, sl2vl_kobj);
+       struct qib_ibport *qibp = &ppd->ibport_data;
+
+       return sprintf(buf, "%u\n", qibp->sl_to_vl[sattr->sl]);
+}
+
+static const struct sysfs_ops qib_sl2vl_ops = {
+       .show = sl2vl_attr_show,
+};
+
+static struct kobj_type qib_sl2vl_ktype = {
+       .release = qib_port_release,
+       .sysfs_ops = &qib_sl2vl_ops,
+       .default_attrs = sl2vl_default_attributes
+};
+
+/* End sl2vl */
+
+/* Start diag_counters */
+
+#define QIB_DIAGC_ATTR(N) \
+       static struct qib_diagc_attr qib_diagc_attr_##N = { \
+               .attr = { .name = __stringify(N), .mode = 0444 }, \
+               .counter = offsetof(struct qib_ibport, n_##N) \
+       }
+
+struct qib_diagc_attr {
+       struct attribute attr;
+       size_t counter;
+};
+
+QIB_DIAGC_ATTR(rc_resends);
+QIB_DIAGC_ATTR(rc_acks);
+QIB_DIAGC_ATTR(rc_qacks);
+QIB_DIAGC_ATTR(rc_delayed_comp);
+QIB_DIAGC_ATTR(seq_naks);
+QIB_DIAGC_ATTR(rdma_seq);
+QIB_DIAGC_ATTR(rnr_naks);
+QIB_DIAGC_ATTR(other_naks);
+QIB_DIAGC_ATTR(rc_timeouts);
+QIB_DIAGC_ATTR(loop_pkts);
+QIB_DIAGC_ATTR(pkt_drops);
+QIB_DIAGC_ATTR(dmawait);
+QIB_DIAGC_ATTR(unaligned);
+QIB_DIAGC_ATTR(rc_dupreq);
+QIB_DIAGC_ATTR(rc_seqnak);
+
+static struct attribute *diagc_default_attributes[] = {
+       &qib_diagc_attr_rc_resends.attr,
+       &qib_diagc_attr_rc_acks.attr,
+       &qib_diagc_attr_rc_qacks.attr,
+       &qib_diagc_attr_rc_delayed_comp.attr,
+       &qib_diagc_attr_seq_naks.attr,
+       &qib_diagc_attr_rdma_seq.attr,
+       &qib_diagc_attr_rnr_naks.attr,
+       &qib_diagc_attr_other_naks.attr,
+       &qib_diagc_attr_rc_timeouts.attr,
+       &qib_diagc_attr_loop_pkts.attr,
+       &qib_diagc_attr_pkt_drops.attr,
+       &qib_diagc_attr_dmawait.attr,
+       &qib_diagc_attr_unaligned.attr,
+       &qib_diagc_attr_rc_dupreq.attr,
+       &qib_diagc_attr_rc_seqnak.attr,
+       NULL
+};
+
+static ssize_t diagc_attr_show(struct kobject *kobj, struct attribute *attr,
+                              char *buf)
+{
+       struct qib_diagc_attr *dattr =
+               container_of(attr, struct qib_diagc_attr, attr);
+       struct qib_pportdata *ppd =
+               container_of(kobj, struct qib_pportdata, diagc_kobj);
+       struct qib_ibport *qibp = &ppd->ibport_data;
+
+       return sprintf(buf, "%u\n", *(u32 *)((char *)qibp + dattr->counter));
+}
+
+static const struct sysfs_ops qib_diagc_ops = {
+       .show = diagc_attr_show,
+};
+
+static struct kobj_type qib_diagc_ktype = {
+       .release = qib_port_release,
+       .sysfs_ops = &qib_diagc_ops,
+       .default_attrs = diagc_default_attributes
+};
+
+/* End diag_counters */
+
+/* end of per-port file structures and support code */
+
+/*
+ * Start of per-unit (or driver, in some cases, but replicated
+ * per unit) functions (these get a device *)
+ */
+static ssize_t show_rev(struct device *device, struct device_attribute *attr,
+                       char *buf)
+{
+       struct qib_ibdev *dev =
+               container_of(device, struct qib_ibdev, ibdev.dev);
+
+       return sprintf(buf, "%x\n", dd_from_dev(dev)->minrev);
+}
+
+static ssize_t show_hca(struct device *device, struct device_attribute *attr,
+                       char *buf)
+{
+       struct qib_ibdev *dev =
+               container_of(device, struct qib_ibdev, ibdev.dev);
+       struct qib_devdata *dd = dd_from_dev(dev);
+       int ret;
+
+       if (!dd->boardname)
+               ret = -EINVAL;
+       else
+               ret = scnprintf(buf, PAGE_SIZE, "%s\n", dd->boardname);
+       return ret;
+}
+
+static ssize_t show_version(struct device *device,
+                           struct device_attribute *attr, char *buf)
+{
+       /* The string printed here is already newline-terminated. */
+       return scnprintf(buf, PAGE_SIZE, "%s", (char *)ib_qib_version);
+}
+
+static ssize_t show_boardversion(struct device *device,
+                                struct device_attribute *attr, char *buf)
+{
+       struct qib_ibdev *dev =
+               container_of(device, struct qib_ibdev, ibdev.dev);
+       struct qib_devdata *dd = dd_from_dev(dev);
+
+       /* The string printed here is already newline-terminated. */
+       return scnprintf(buf, PAGE_SIZE, "%s", dd->boardversion);
+}
+
+
+static ssize_t show_localbus_info(struct device *device,
+                                 struct device_attribute *attr, char *buf)
+{
+       struct qib_ibdev *dev =
+               container_of(device, struct qib_ibdev, ibdev.dev);
+       struct qib_devdata *dd = dd_from_dev(dev);
+
+       /* The string printed here is already newline-terminated. */
+       return scnprintf(buf, PAGE_SIZE, "%s", dd->lbus_info);
+}
+
+
+static ssize_t show_nctxts(struct device *device,
+                          struct device_attribute *attr, char *buf)
+{
+       struct qib_ibdev *dev =
+               container_of(device, struct qib_ibdev, ibdev.dev);
+       struct qib_devdata *dd = dd_from_dev(dev);
+
+       /* Return the number of user ports (contexts) available. */
+       return scnprintf(buf, PAGE_SIZE, "%u\n", dd->cfgctxts -
+               dd->first_user_ctxt);
+}
+
+static ssize_t show_serial(struct device *device,
+                          struct device_attribute *attr, char *buf)
+{
+       struct qib_ibdev *dev =
+               container_of(device, struct qib_ibdev, ibdev.dev);
+       struct qib_devdata *dd = dd_from_dev(dev);
+
+       buf[sizeof dd->serial] = '\0';
+       memcpy(buf, dd->serial, sizeof dd->serial);
+       strcat(buf, "\n");
+       return strlen(buf);
+}
+
+static ssize_t store_chip_reset(struct device *device,
+                               struct device_attribute *attr, const char *buf,
+                               size_t count)
+{
+       struct qib_ibdev *dev =
+               container_of(device, struct qib_ibdev, ibdev.dev);
+       struct qib_devdata *dd = dd_from_dev(dev);
+       int ret;
+
+       if (count < 5 || memcmp(buf, "reset", 5) || !dd->diag_client) {
+               ret = -EINVAL;
+               goto bail;
+       }
+
+       ret = qib_reset_device(dd->unit);
+bail:
+       return ret < 0 ? ret : count;
+}
+
+static ssize_t show_logged_errs(struct device *device,
+                               struct device_attribute *attr, char *buf)
+{
+       struct qib_ibdev *dev =
+               container_of(device, struct qib_ibdev, ibdev.dev);
+       struct qib_devdata *dd = dd_from_dev(dev);
+       int idx, count;
+
+       /* force consistency with actual EEPROM */
+       if (qib_update_eeprom_log(dd) != 0)
+               return -ENXIO;
+
+       count = 0;
+       for (idx = 0; idx < QIB_EEP_LOG_CNT; ++idx) {
+               count += scnprintf(buf + count, PAGE_SIZE - count, "%d%c",
+                                  dd->eep_st_errs[idx],
+                                  idx == (QIB_EEP_LOG_CNT - 1) ? '\n' : ' ');
+       }
+
+       return count;
+}
+
+/*
+ * Dump tempsense regs. in decimal, to ease shell-scripts.
+ */
+static ssize_t show_tempsense(struct device *device,
+                             struct device_attribute *attr, char *buf)
+{
+       struct qib_ibdev *dev =
+               container_of(device, struct qib_ibdev, ibdev.dev);
+       struct qib_devdata *dd = dd_from_dev(dev);
+       int ret;
+       int idx;
+       u8 regvals[8];
+
+       ret = -ENXIO;
+       for (idx = 0; idx < 8; ++idx) {
+               if (idx == 6)
+                       continue;
+               ret = dd->f_tempsense_rd(dd, idx);
+               if (ret < 0)
+                       break;
+               regvals[idx] = ret;
+       }
+       if (idx == 8)
+               ret = scnprintf(buf, PAGE_SIZE, "%d %d %02X %02X %d %d\n",
+                               *(signed char *)(regvals),
+                               *(signed char *)(regvals + 1),
+                               regvals[2], regvals[3],
+                               *(signed char *)(regvals + 5),
+                               *(signed char *)(regvals + 7));
+       return ret;
+}
+
+/*
+ * end of per-unit (or driver, in some cases, but replicated
+ * per unit) functions
+ */
+
+/* start of per-unit file structures and support code */
+static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
+static DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL);
+static DEVICE_ATTR(board_id, S_IRUGO, show_hca, NULL);
+static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
+static DEVICE_ATTR(nctxts, S_IRUGO, show_nctxts, NULL);
+static DEVICE_ATTR(serial, S_IRUGO, show_serial, NULL);
+static DEVICE_ATTR(boardversion, S_IRUGO, show_boardversion, NULL);
+static DEVICE_ATTR(logged_errors, S_IRUGO, show_logged_errs, NULL);
+static DEVICE_ATTR(tempsense, S_IRUGO, show_tempsense, NULL);
+static DEVICE_ATTR(localbus_info, S_IRUGO, show_localbus_info, NULL);
+static DEVICE_ATTR(chip_reset, S_IWUSR, NULL, store_chip_reset);
+
+static struct device_attribute *qib_attributes[] = {
+       &dev_attr_hw_rev,
+       &dev_attr_hca_type,
+       &dev_attr_board_id,
+       &dev_attr_version,
+       &dev_attr_nctxts,
+       &dev_attr_serial,
+       &dev_attr_boardversion,
+       &dev_attr_logged_errors,
+       &dev_attr_tempsense,
+       &dev_attr_localbus_info,
+       &dev_attr_chip_reset,
+};
+
+int qib_create_port_files(struct ib_device *ibdev, u8 port_num,
+                         struct kobject *kobj)
+{
+       struct qib_pportdata *ppd;
+       struct qib_devdata *dd = dd_from_ibdev(ibdev);
+       int ret;
+
+       if (!port_num || port_num > dd->num_pports) {
+               qib_dev_err(dd, "Skipping infiniband class with "
+                           "invalid port %u\n", port_num);
+               ret = -ENODEV;
+               goto bail;
+       }
+       ppd = &dd->pport[port_num - 1];
+
+       ret = kobject_init_and_add(&ppd->pport_kobj, &qib_port_ktype, kobj,
+                                  "linkcontrol");
+       if (ret) {
+               qib_dev_err(dd, "Skipping linkcontrol sysfs info, "
+                           "(err %d) port %u\n", ret, port_num);
+               goto bail;
+       }
+       kobject_uevent(&ppd->pport_kobj, KOBJ_ADD);
+
+       ret = kobject_init_and_add(&ppd->sl2vl_kobj, &qib_sl2vl_ktype, kobj,
+                                  "sl2vl");
+       if (ret) {
+               qib_dev_err(dd, "Skipping sl2vl sysfs info, "
+                           "(err %d) port %u\n", ret, port_num);
+               goto bail_sl;
+       }
+       kobject_uevent(&ppd->sl2vl_kobj, KOBJ_ADD);
+
+       ret = kobject_init_and_add(&ppd->diagc_kobj, &qib_diagc_ktype, kobj,
+                                  "diag_counters");
+       if (ret) {
+               qib_dev_err(dd, "Skipping diag_counters sysfs info, "
+                           "(err %d) port %u\n", ret, port_num);
+               goto bail_diagc;
+       }
+       kobject_uevent(&ppd->diagc_kobj, KOBJ_ADD);
+
+       return 0;
+
+bail_diagc:
+       kobject_put(&ppd->sl2vl_kobj);
+bail_sl:
+       kobject_put(&ppd->pport_kobj);
+bail:
+       return ret;
+}
+
+/*
+ * Register and create our files in /sys/class/infiniband.
+ */
+int qib_verbs_register_sysfs(struct qib_devdata *dd)
+{
+       struct ib_device *dev = &dd->verbs_dev.ibdev;
+       int i, ret;
+
+       for (i = 0; i < ARRAY_SIZE(qib_attributes); ++i) {
+               ret = device_create_file(&dev->dev, qib_attributes[i]);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * Unregister and remove our files in /sys/class/infiniband.
+ */
+void qib_verbs_unregister_sysfs(struct qib_devdata *dd)
+{
+       struct qib_pportdata *ppd;
+       int i;
+
+       for (i = 0; i < dd->num_pports; i++) {
+               ppd = &dd->pport[i];
+               kobject_put(&ppd->pport_kobj);
+               kobject_put(&ppd->sl2vl_kobj);
+       }
+}
diff --git a/drivers/infiniband/hw/qib/qib_twsi.c b/drivers/infiniband/hw/qib/qib_twsi.c
new file mode 100644 (file)
index 0000000..6f31ca5
--- /dev/null
@@ -0,0 +1,498 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved.
+ * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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/delay.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+
+#include "qib.h"
+
+/*
+ * QLogic_IB "Two Wire Serial Interface" driver.
+ * Originally written for a not-quite-i2c serial eeprom, which is
+ * still used on some supported boards. Later boards have added a
+ * variety of other uses, most board-specific, so teh bit-boffing
+ * part has been split off to this file, while the other parts
+ * have been moved to chip-specific files.
+ *
+ * We have also dropped all pretense of fully generic (e.g. pretend
+ * we don't know whether '1' is the higher voltage) interface, as
+ * the restrictions of the generic i2c interface (e.g. no access from
+ * driver itself) make it unsuitable for this use.
+ */
+
+#define READ_CMD 1
+#define WRITE_CMD 0
+
+/**
+ * i2c_wait_for_writes - wait for a write
+ * @dd: the qlogic_ib device
+ *
+ * We use this instead of udelay directly, so we can make sure
+ * that previous register writes have been flushed all the way
+ * to the chip.  Since we are delaying anyway, the cost doesn't
+ * hurt, and makes the bit twiddling more regular
+ */
+static void i2c_wait_for_writes(struct qib_devdata *dd)
+{
+       /*
+        * implicit read of EXTStatus is as good as explicit
+        * read of scratch, if all we want to do is flush
+        * writes.
+        */
+       dd->f_gpio_mod(dd, 0, 0, 0);
+       rmb(); /* inlined, so prevent compiler reordering */
+}
+
+/*
+ * QSFP modules are allowed to hold SCL low for 500uSec. Allow twice that
+ * for "almost compliant" modules
+ */
+#define SCL_WAIT_USEC 1000
+
+/* BUF_WAIT is time bus must be free between STOP or ACK and to next START.
+ * Should be 20, but some chips need more.
+ */
+#define TWSI_BUF_WAIT_USEC 60
+
+static void scl_out(struct qib_devdata *dd, u8 bit)
+{
+       u32 mask;
+
+       udelay(1);
+
+       mask = 1UL << dd->gpio_scl_num;
+
+       /* SCL is meant to be bare-drain, so never set "OUT", just DIR */
+       dd->f_gpio_mod(dd, 0, bit ? 0 : mask, mask);
+
+       /*
+        * Allow for slow slaves by simple
+        * delay for falling edge, sampling on rise.
+        */
+       if (!bit)
+               udelay(2);
+       else {
+               int rise_usec;
+               for (rise_usec = SCL_WAIT_USEC; rise_usec > 0; rise_usec -= 2) {
+                       if (mask & dd->f_gpio_mod(dd, 0, 0, 0))
+                               break;
+                       udelay(2);
+               }
+               if (rise_usec <= 0)
+                       qib_dev_err(dd, "SCL interface stuck low > %d uSec\n",
+                                   SCL_WAIT_USEC);
+       }
+       i2c_wait_for_writes(dd);
+}
+
+static void sda_out(struct qib_devdata *dd, u8 bit)
+{
+       u32 mask;
+
+       mask = 1UL << dd->gpio_sda_num;
+
+       /* SDA is meant to be bare-drain, so never set "OUT", just DIR */
+       dd->f_gpio_mod(dd, 0, bit ? 0 : mask, mask);
+
+       i2c_wait_for_writes(dd);
+       udelay(2);
+}
+
+static u8 sda_in(struct qib_devdata *dd, int wait)
+{
+       int bnum;
+       u32 read_val, mask;
+
+       bnum = dd->gpio_sda_num;
+       mask = (1UL << bnum);
+       /* SDA is meant to be bare-drain, so never set "OUT", just DIR */
+       dd->f_gpio_mod(dd, 0, 0, mask);
+       read_val = dd->f_gpio_mod(dd, 0, 0, 0);
+       if (wait)
+               i2c_wait_for_writes(dd);
+       return (read_val & mask) >> bnum;
+}
+
+/**
+ * i2c_ackrcv - see if ack following write is true
+ * @dd: the qlogic_ib device
+ */
+static int i2c_ackrcv(struct qib_devdata *dd)
+{
+       u8 ack_received;
+
+       /* AT ENTRY SCL = LOW */
+       /* change direction, ignore data */
+       ack_received = sda_in(dd, 1);
+       scl_out(dd, 1);
+       ack_received = sda_in(dd, 1) == 0;
+       scl_out(dd, 0);
+       return ack_received;
+}
+
+static void stop_cmd(struct qib_devdata *dd);
+
+/**
+ * rd_byte - read a byte, sending STOP on last, else ACK
+ * @dd: the qlogic_ib device
+ *
+ * Returns byte shifted out of device
+ */
+static int rd_byte(struct qib_devdata *dd, int last)
+{
+       int bit_cntr, data;
+
+       data = 0;
+
+       for (bit_cntr = 7; bit_cntr >= 0; --bit_cntr) {
+               data <<= 1;
+               scl_out(dd, 1);
+               data |= sda_in(dd, 0);
+               scl_out(dd, 0);
+       }
+       if (last) {
+               scl_out(dd, 1);
+               stop_cmd(dd);
+       } else {
+               sda_out(dd, 0);
+               scl_out(dd, 1);
+               scl_out(dd, 0);
+               sda_out(dd, 1);
+       }
+       return data;
+}
+
+/**
+ * wr_byte - write a byte, one bit at a time
+ * @dd: the qlogic_ib device
+ * @data: the byte to write
+ *
+ * Returns 0 if we got the following ack, otherwise 1
+ */
+static int wr_byte(struct qib_devdata *dd, u8 data)
+{
+       int bit_cntr;
+       u8 bit;
+
+       for (bit_cntr = 7; bit_cntr >= 0; bit_cntr--) {
+               bit = (data >> bit_cntr) & 1;
+               sda_out(dd, bit);
+               scl_out(dd, 1);
+               scl_out(dd, 0);
+       }
+       return (!i2c_ackrcv(dd)) ? 1 : 0;
+}
+
+/*
+ * issue TWSI start sequence:
+ * (both clock/data high, clock high, data low while clock is high)
+ */
+static void start_seq(struct qib_devdata *dd)
+{
+       sda_out(dd, 1);
+       scl_out(dd, 1);
+       sda_out(dd, 0);
+       udelay(1);
+       scl_out(dd, 0);
+}
+
+/**
+ * stop_seq - transmit the stop sequence
+ * @dd: the qlogic_ib device
+ *
+ * (both clock/data low, clock high, data high while clock is high)
+ */
+static void stop_seq(struct qib_devdata *dd)
+{
+       scl_out(dd, 0);
+       sda_out(dd, 0);
+       scl_out(dd, 1);
+       sda_out(dd, 1);
+}
+
+/**
+ * stop_cmd - transmit the stop condition
+ * @dd: the qlogic_ib device
+ *
+ * (both clock/data low, clock high, data high while clock is high)
+ */
+static void stop_cmd(struct qib_devdata *dd)
+{
+       stop_seq(dd);
+       udelay(TWSI_BUF_WAIT_USEC);
+}
+
+/**
+ * qib_twsi_reset - reset I2C communication
+ * @dd: the qlogic_ib device
+ */
+
+int qib_twsi_reset(struct qib_devdata *dd)
+{
+       int clock_cycles_left = 9;
+       int was_high = 0;
+       u32 pins, mask;
+
+       /* Both SCL and SDA should be high. If not, there
+        * is something wrong.
+        */
+       mask = (1UL << dd->gpio_scl_num) | (1UL << dd->gpio_sda_num);
+
+       /*
+        * Force pins to desired innocuous state.
+        * This is the default power-on state with out=0 and dir=0,
+        * So tri-stated and should be floating high (barring HW problems)
+        */
+       dd->f_gpio_mod(dd, 0, 0, mask);
+
+       /*
+        * Clock nine times to get all listeners into a sane state.
+        * If SDA does not go high at any point, we are wedged.
+        * One vendor recommends then issuing START followed by STOP.
+        * we cannot use our "normal" functions to do that, because
+        * if SCL drops between them, another vendor's part will
+        * wedge, dropping SDA and keeping it low forever, at the end of
+        * the next transaction (even if it was not the device addressed).
+        * So our START and STOP take place with SCL held high.
+        */
+       while (clock_cycles_left--) {
+               scl_out(dd, 0);
+               scl_out(dd, 1);
+               /* Note if SDA is high, but keep clocking to sync slave */
+               was_high |= sda_in(dd, 0);
+       }
+
+       if (was_high) {
+               /*
+                * We saw a high, which we hope means the slave is sync'd.
+                * Issue START, STOP, pause for T_BUF.
+                */
+
+               pins = dd->f_gpio_mod(dd, 0, 0, 0);
+               if ((pins & mask) != mask)
+                       qib_dev_err(dd, "GPIO pins not at rest: %d\n",
+                                   pins & mask);
+               /* Drop SDA to issue START */
+               udelay(1); /* Guarantee .6 uSec setup */
+               sda_out(dd, 0);
+               udelay(1); /* Guarantee .6 uSec hold */
+               /* At this point, SCL is high, SDA low. Raise SDA for STOP */
+               sda_out(dd, 1);
+               udelay(TWSI_BUF_WAIT_USEC);
+       }
+
+       return !was_high;
+}
+
+#define QIB_TWSI_START 0x100
+#define QIB_TWSI_STOP 0x200
+
+/* Write byte to TWSI, optionally prefixed with START or suffixed with
+ * STOP.
+ * returns 0 if OK (ACK received), else != 0
+ */
+static int qib_twsi_wr(struct qib_devdata *dd, int data, int flags)
+{
+       int ret = 1;
+       if (flags & QIB_TWSI_START)
+               start_seq(dd);
+
+       ret = wr_byte(dd, data); /* Leaves SCL low (from i2c_ackrcv()) */
+
+       if (flags & QIB_TWSI_STOP)
+               stop_cmd(dd);
+       return ret;
+}
+
+/* Added functionality for IBA7220-based cards */
+#define QIB_TEMP_DEV 0x98
+
+/*
+ * qib_twsi_blk_rd
+ * Formerly called qib_eeprom_internal_read, and only used for eeprom,
+ * but now the general interface for data transfer from twsi devices.
+ * One vestige of its former role is that it recognizes a device
+ * QIB_TWSI_NO_DEV and does the correct operation for the legacy part,
+ * which responded to all TWSI device codes, interpreting them as
+ * address within device. On all other devices found on board handled by
+ * this driver, the device is followed by a one-byte "address" which selects
+ * the "register" or "offset" within the device from which data should
+ * be read.
+ */
+int qib_twsi_blk_rd(struct qib_devdata *dd, int dev, int addr,
+                   void *buffer, int len)
+{
+       int ret;
+       u8 *bp = buffer;
+
+       ret = 1;
+
+       if (dev == QIB_TWSI_NO_DEV) {
+               /* legacy not-really-I2C */
+               addr = (addr << 1) | READ_CMD;
+               ret = qib_twsi_wr(dd, addr, QIB_TWSI_START);
+       } else {
+               /* Actual I2C */
+               ret = qib_twsi_wr(dd, dev | WRITE_CMD, QIB_TWSI_START);
+               if (ret) {
+                       stop_cmd(dd);
+                       ret = 1;
+                       goto bail;
+               }
+               /*
+                * SFF spec claims we do _not_ stop after the addr
+                * but simply issue a start with the "read" dev-addr.
+                * Since we are implicitely waiting for ACK here,
+                * we need t_buf (nominally 20uSec) before that start,
+                * and cannot rely on the delay built in to the STOP
+                */
+               ret = qib_twsi_wr(dd, addr, 0);
+               udelay(TWSI_BUF_WAIT_USEC);
+
+               if (ret) {
+                       qib_dev_err(dd,
+                               "Failed to write interface read addr %02X\n",
+                               addr);
+                       ret = 1;
+                       goto bail;
+               }
+               ret = qib_twsi_wr(dd, dev | READ_CMD, QIB_TWSI_START);
+       }
+       if (ret) {
+               stop_cmd(dd);
+               ret = 1;
+               goto bail;
+       }
+
+       /*
+        * block devices keeps clocking data out as long as we ack,
+        * automatically incrementing the address. Some have "pages"
+        * whose boundaries will not be crossed, but the handling
+        * of these is left to the caller, who is in a better
+        * position to know.
+        */
+       while (len-- > 0) {
+               /*
+                * Get and store data, sending ACK if length remaining,
+                * else STOP
+                */
+               *bp++ = rd_byte(dd, !len);
+       }
+
+       ret = 0;
+
+bail:
+       return ret;
+}
+
+/*
+ * qib_twsi_blk_wr
+ * Formerly called qib_eeprom_internal_write, and only used for eeprom,
+ * but now the general interface for data transfer to twsi devices.
+ * One vestige of its former role is that it recognizes a device
+ * QIB_TWSI_NO_DEV and does the correct operation for the legacy part,
+ * which responded to all TWSI device codes, interpreting them as
+ * address within device. On all other devices found on board handled by
+ * this driver, the device is followed by a one-byte "address" which selects
+ * the "register" or "offset" within the device to which data should
+ * be written.
+ */
+int qib_twsi_blk_wr(struct qib_devdata *dd, int dev, int addr,
+                   const void *buffer, int len)
+{
+       int sub_len;
+       const u8 *bp = buffer;
+       int max_wait_time, i;
+       int ret;
+       ret = 1;
+
+       while (len > 0) {
+               if (dev == QIB_TWSI_NO_DEV) {
+                       if (qib_twsi_wr(dd, (addr << 1) | WRITE_CMD,
+                                       QIB_TWSI_START)) {
+                               goto failed_write;
+                       }
+               } else {
+                       /* Real I2C */
+                       if (qib_twsi_wr(dd, dev | WRITE_CMD, QIB_TWSI_START))
+                               goto failed_write;
+                       ret = qib_twsi_wr(dd, addr, 0);
+                       if (ret) {
+                               qib_dev_err(dd, "Failed to write interface"
+                                           " write addr %02X\n", addr);
+                               goto failed_write;
+                       }
+               }
+
+               sub_len = min(len, 4);
+               addr += sub_len;
+               len -= sub_len;
+
+               for (i = 0; i < sub_len; i++)
+                       if (qib_twsi_wr(dd, *bp++, 0))
+                               goto failed_write;
+
+               stop_cmd(dd);
+
+               /*
+                * Wait for write complete by waiting for a successful
+                * read (the chip replies with a zero after the write
+                * cmd completes, and before it writes to the eeprom.
+                * The startcmd for the read will fail the ack until
+                * the writes have completed.   We do this inline to avoid
+                * the debug prints that are in the real read routine
+                * if the startcmd fails.
+                * We also use the proper device address, so it doesn't matter
+                * whether we have real eeprom_dev. Legacy likes any address.
+                */
+               max_wait_time = 100;
+               while (qib_twsi_wr(dd, dev | READ_CMD, QIB_TWSI_START)) {
+                       stop_cmd(dd);
+                       if (!--max_wait_time)
+                               goto failed_write;
+               }
+               /* now read (and ignore) the resulting byte */
+               rd_byte(dd, 1);
+       }
+
+       ret = 0;
+       goto bail;
+
+failed_write:
+       stop_cmd(dd);
+       ret = 1;
+
+bail:
+       return ret;
+}
diff --git a/drivers/infiniband/hw/qib/qib_tx.c b/drivers/infiniband/hw/qib/qib_tx.c
new file mode 100644 (file)
index 0000000..f7eb1dd
--- /dev/null
@@ -0,0 +1,557 @@
+/*
+ * Copyright (c) 2008, 2009, 2010 QLogic Corporation. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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/spinlock.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/vmalloc.h>
+
+#include "qib.h"
+
+static unsigned qib_hol_timeout_ms = 3000;
+module_param_named(hol_timeout_ms, qib_hol_timeout_ms, uint, S_IRUGO);
+MODULE_PARM_DESC(hol_timeout_ms,
+                "duration of user app suspension after link failure");
+
+unsigned qib_sdma_fetch_arb = 1;
+module_param_named(fetch_arb, qib_sdma_fetch_arb, uint, S_IRUGO);
+MODULE_PARM_DESC(fetch_arb, "IBA7220: change SDMA descriptor arbitration");
+
+/**
+ * qib_disarm_piobufs - cancel a range of PIO buffers
+ * @dd: the qlogic_ib device
+ * @first: the first PIO buffer to cancel
+ * @cnt: the number of PIO buffers to cancel
+ *
+ * Cancel a range of PIO buffers. Used at user process close,
+ * in case it died while writing to a PIO buffer.
+ */
+void qib_disarm_piobufs(struct qib_devdata *dd, unsigned first, unsigned cnt)
+{
+       unsigned long flags;
+       unsigned i;
+       unsigned last;
+
+       last = first + cnt;
+       spin_lock_irqsave(&dd->pioavail_lock, flags);
+       for (i = first; i < last; i++) {
+               __clear_bit(i, dd->pio_need_disarm);
+               dd->f_sendctrl(dd->pport, QIB_SENDCTRL_DISARM_BUF(i));
+       }
+       spin_unlock_irqrestore(&dd->pioavail_lock, flags);
+}
+
+/*
+ * This is called by a user process when it sees the DISARM_BUFS event
+ * bit is set.
+ */
+int qib_disarm_piobufs_ifneeded(struct qib_ctxtdata *rcd)
+{
+       struct qib_devdata *dd = rcd->dd;
+       unsigned i;
+       unsigned last;
+       unsigned n = 0;
+
+       last = rcd->pio_base + rcd->piocnt;
+       /*
+        * Don't need uctxt_lock here, since user has called in to us.
+        * Clear at start in case more interrupts set bits while we
+        * are disarming
+        */
+       if (rcd->user_event_mask) {
+               /*
+                * subctxt_cnt is 0 if not shared, so do base
+                * separately, first, then remaining subctxt, if any
+                */
+               clear_bit(_QIB_EVENT_DISARM_BUFS_BIT, &rcd->user_event_mask[0]);
+               for (i = 1; i < rcd->subctxt_cnt; i++)
+                       clear_bit(_QIB_EVENT_DISARM_BUFS_BIT,
+                                 &rcd->user_event_mask[i]);
+       }
+       spin_lock_irq(&dd->pioavail_lock);
+       for (i = rcd->pio_base; i < last; i++) {
+               if (__test_and_clear_bit(i, dd->pio_need_disarm)) {
+                       n++;
+                       dd->f_sendctrl(rcd->ppd, QIB_SENDCTRL_DISARM_BUF(i));
+               }
+       }
+       spin_unlock_irq(&dd->pioavail_lock);
+       return 0;
+}
+
+static struct qib_pportdata *is_sdma_buf(struct qib_devdata *dd, unsigned i)
+{
+       struct qib_pportdata *ppd;
+       unsigned pidx;
+
+       for (pidx = 0; pidx < dd->num_pports; pidx++) {
+               ppd = dd->pport + pidx;
+               if (i >= ppd->sdma_state.first_sendbuf &&
+                   i < ppd->sdma_state.last_sendbuf)
+                       return ppd;
+       }
+       return NULL;
+}
+
+/*
+ * Return true if send buffer is being used by a user context.
+ * Sets  _QIB_EVENT_DISARM_BUFS_BIT in user_event_mask as a side effect
+ */
+static int find_ctxt(struct qib_devdata *dd, unsigned bufn)
+{
+       struct qib_ctxtdata *rcd;
+       unsigned ctxt;
+       int ret = 0;
+
+       spin_lock(&dd->uctxt_lock);
+       for (ctxt = dd->first_user_ctxt; ctxt < dd->cfgctxts; ctxt++) {
+               rcd = dd->rcd[ctxt];
+               if (!rcd || bufn < rcd->pio_base ||
+                   bufn >= rcd->pio_base + rcd->piocnt)
+                       continue;
+               if (rcd->user_event_mask) {
+                       int i;
+                       /*
+                        * subctxt_cnt is 0 if not shared, so do base
+                        * separately, first, then remaining subctxt, if any
+                        */
+                       set_bit(_QIB_EVENT_DISARM_BUFS_BIT,
+                               &rcd->user_event_mask[0]);
+                       for (i = 1; i < rcd->subctxt_cnt; i++)
+                               set_bit(_QIB_EVENT_DISARM_BUFS_BIT,
+                                       &rcd->user_event_mask[i]);
+               }
+               ret = 1;
+               break;
+       }
+       spin_unlock(&dd->uctxt_lock);
+
+       return ret;
+}
+
+/*
+ * Disarm a set of send buffers.  If the buffer might be actively being
+ * written to, mark the buffer to be disarmed later when it is not being
+ * written to.
+ *
+ * This should only be called from the IRQ error handler.
+ */
+void qib_disarm_piobufs_set(struct qib_devdata *dd, unsigned long *mask,
+                           unsigned cnt)
+{
+       struct qib_pportdata *ppd, *pppd[dd->num_pports];
+       unsigned i;
+       unsigned long flags;
+
+       for (i = 0; i < dd->num_pports; i++)
+               pppd[i] = NULL;
+
+       for (i = 0; i < cnt; i++) {
+               int which;
+               if (!test_bit(i, mask))
+                       continue;
+               /*
+                * If the buffer is owned by the DMA hardware,
+                * reset the DMA engine.
+                */
+               ppd = is_sdma_buf(dd, i);
+               if (ppd) {
+                       pppd[ppd->port] = ppd;
+                       continue;
+               }
+               /*
+                * If the kernel is writing the buffer or the buffer is
+                * owned by a user process, we can't clear it yet.
+                */
+               spin_lock_irqsave(&dd->pioavail_lock, flags);
+               if (test_bit(i, dd->pio_writing) ||
+                   (!test_bit(i << 1, dd->pioavailkernel) &&
+                    find_ctxt(dd, i))) {
+                       __set_bit(i, dd->pio_need_disarm);
+                       which = 0;
+               } else {
+                       which = 1;
+                       dd->f_sendctrl(dd->pport, QIB_SENDCTRL_DISARM_BUF(i));
+               }
+               spin_unlock_irqrestore(&dd->pioavail_lock, flags);
+       }
+
+       /* do cancel_sends once per port that had sdma piobufs in error */
+       for (i = 0; i < dd->num_pports; i++)
+               if (pppd[i])
+                       qib_cancel_sends(pppd[i]);
+}
+
+/**
+ * update_send_bufs - update shadow copy of the PIO availability map
+ * @dd: the qlogic_ib device
+ *
+ * called whenever our local copy indicates we have run out of send buffers
+ */
+static void update_send_bufs(struct qib_devdata *dd)
+{
+       unsigned long flags;
+       unsigned i;
+       const unsigned piobregs = dd->pioavregs;
+
+       /*
+        * If the generation (check) bits have changed, then we update the
+        * busy bit for the corresponding PIO buffer.  This algorithm will
+        * modify positions to the value they already have in some cases
+        * (i.e., no change), but it's faster than changing only the bits
+        * that have changed.
+        *
+        * We would like to do this atomicly, to avoid spinlocks in the
+        * critical send path, but that's not really possible, given the
+        * type of changes, and that this routine could be called on
+        * multiple cpu's simultaneously, so we lock in this routine only,
+        * to avoid conflicting updates; all we change is the shadow, and
+        * it's a single 64 bit memory location, so by definition the update
+        * is atomic in terms of what other cpu's can see in testing the
+        * bits.  The spin_lock overhead isn't too bad, since it only
+        * happens when all buffers are in use, so only cpu overhead, not
+        * latency or bandwidth is affected.
+        */
+       if (!dd->pioavailregs_dma)
+               return;
+       spin_lock_irqsave(&dd->pioavail_lock, flags);
+       for (i = 0; i < piobregs; i++) {
+               u64 pchbusy, pchg, piov, pnew;
+
+               piov = le64_to_cpu(dd->pioavailregs_dma[i]);
+               pchg = dd->pioavailkernel[i] &
+                       ~(dd->pioavailshadow[i] ^ piov);
+               pchbusy = pchg << QLOGIC_IB_SENDPIOAVAIL_BUSY_SHIFT;
+               if (pchg && (pchbusy & dd->pioavailshadow[i])) {
+                       pnew = dd->pioavailshadow[i] & ~pchbusy;
+                       pnew |= piov & pchbusy;
+                       dd->pioavailshadow[i] = pnew;
+               }
+       }
+       spin_unlock_irqrestore(&dd->pioavail_lock, flags);
+}
+
+/*
+ * Debugging code and stats updates if no pio buffers available.
+ */
+static noinline void no_send_bufs(struct qib_devdata *dd)
+{
+       dd->upd_pio_shadow = 1;
+
+       /* not atomic, but if we lose a stat count in a while, that's OK */
+       qib_stats.sps_nopiobufs++;
+}
+
+/*
+ * Common code for normal driver send buffer allocation, and reserved
+ * allocation.
+ *
+ * Do appropriate marking as busy, etc.
+ * Returns buffer pointer if one is found, otherwise NULL.
+ */
+u32 __iomem *qib_getsendbuf_range(struct qib_devdata *dd, u32 *pbufnum,
+                                 u32 first, u32 last)
+{
+       unsigned i, j, updated = 0;
+       unsigned nbufs;
+       unsigned long flags;
+       unsigned long *shadow = dd->pioavailshadow;
+       u32 __iomem *buf;
+
+       if (!(dd->flags & QIB_PRESENT))
+               return NULL;
+
+       nbufs = last - first + 1; /* number in range to check */
+       if (dd->upd_pio_shadow) {
+               /*
+                * Minor optimization.  If we had no buffers on last call,
+                * start out by doing the update; continue and do scan even
+                * if no buffers were updated, to be paranoid.
+                */
+               update_send_bufs(dd);
+               updated++;
+       }
+       i = first;
+rescan:
+       /*
+        * While test_and_set_bit() is atomic, we do that and then the
+        * change_bit(), and the pair is not.  See if this is the cause
+        * of the remaining armlaunch errors.
+        */
+       spin_lock_irqsave(&dd->pioavail_lock, flags);
+       for (j = 0; j < nbufs; j++, i++) {
+               if (i > last)
+                       i = first;
+               if (__test_and_set_bit((2 * i) + 1, shadow))
+                       continue;
+               /* flip generation bit */
+               __change_bit(2 * i, shadow);
+               /* remember that the buffer can be written to now */
+               __set_bit(i, dd->pio_writing);
+               break;
+       }
+       spin_unlock_irqrestore(&dd->pioavail_lock, flags);
+
+       if (j == nbufs) {
+               if (!updated) {
+                       /*
+                        * First time through; shadow exhausted, but may be
+                        * buffers available, try an update and then rescan.
+                        */
+                       update_send_bufs(dd);
+                       updated++;
+                       i = first;
+                       goto rescan;
+               }
+               no_send_bufs(dd);
+               buf = NULL;
+       } else {
+               if (i < dd->piobcnt2k)
+                       buf = (u32 __iomem *)(dd->pio2kbase +
+                               i * dd->palign);
+               else
+                       buf = (u32 __iomem *)(dd->pio4kbase +
+                               (i - dd->piobcnt2k) * dd->align4k);
+               if (pbufnum)
+                       *pbufnum = i;
+               dd->upd_pio_shadow = 0;
+       }
+
+       return buf;
+}
+
+/*
+ * Record that the caller is finished writing to the buffer so we don't
+ * disarm it while it is being written and disarm it now if needed.
+ */
+void qib_sendbuf_done(struct qib_devdata *dd, unsigned n)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&dd->pioavail_lock, flags);
+       __clear_bit(n, dd->pio_writing);
+       if (__test_and_clear_bit(n, dd->pio_need_disarm))
+               dd->f_sendctrl(dd->pport, QIB_SENDCTRL_DISARM_BUF(n));
+       spin_unlock_irqrestore(&dd->pioavail_lock, flags);
+}
+
+/**
+ * qib_chg_pioavailkernel - change which send buffers are available for kernel
+ * @dd: the qlogic_ib device
+ * @start: the starting send buffer number
+ * @len: the number of send buffers
+ * @avail: true if the buffers are available for kernel use, false otherwise
+ */
+void qib_chg_pioavailkernel(struct qib_devdata *dd, unsigned start,
+       unsigned len, u32 avail, struct qib_ctxtdata *rcd)
+{
+       unsigned long flags;
+       unsigned end;
+       unsigned ostart = start;
+
+       /* There are two bits per send buffer (busy and generation) */
+       start *= 2;
+       end = start + len * 2;
+
+       spin_lock_irqsave(&dd->pioavail_lock, flags);
+       /* Set or clear the busy bit in the shadow. */
+       while (start < end) {
+               if (avail) {
+                       unsigned long dma;
+                       int i;
+
+                       /*
+                        * The BUSY bit will never be set, because we disarm
+                        * the user buffers before we hand them back to the
+                        * kernel.  We do have to make sure the generation
+                        * bit is set correctly in shadow, since it could
+                        * have changed many times while allocated to user.
+                        * We can't use the bitmap functions on the full
+                        * dma array because it is always little-endian, so
+                        * we have to flip to host-order first.
+                        * BITS_PER_LONG is slightly wrong, since it's
+                        * always 64 bits per register in chip...
+                        * We only work on 64 bit kernels, so that's OK.
+                        */
+                       i = start / BITS_PER_LONG;
+                       __clear_bit(QLOGIC_IB_SENDPIOAVAIL_BUSY_SHIFT + start,
+                                   dd->pioavailshadow);
+                       dma = (unsigned long)
+                               le64_to_cpu(dd->pioavailregs_dma[i]);
+                       if (test_bit((QLOGIC_IB_SENDPIOAVAIL_CHECK_SHIFT +
+                                     start) % BITS_PER_LONG, &dma))
+                               __set_bit(QLOGIC_IB_SENDPIOAVAIL_CHECK_SHIFT +
+                                         start, dd->pioavailshadow);
+                       else
+                               __clear_bit(QLOGIC_IB_SENDPIOAVAIL_CHECK_SHIFT
+                                           + start, dd->pioavailshadow);
+                       __set_bit(start, dd->pioavailkernel);
+               } else {
+                       __set_bit(start + QLOGIC_IB_SENDPIOAVAIL_BUSY_SHIFT,
+                                 dd->pioavailshadow);
+                       __clear_bit(start, dd->pioavailkernel);
+               }
+               start += 2;
+       }
+
+       spin_unlock_irqrestore(&dd->pioavail_lock, flags);
+
+       dd->f_txchk_change(dd, ostart, len, avail, rcd);
+}
+
+/*
+ * Flush all sends that might be in the ready to send state, as well as any
+ * that are in the process of being sent.  Used whenever we need to be
+ * sure the send side is idle.  Cleans up all buffer state by canceling
+ * all pio buffers, and issuing an abort, which cleans up anything in the
+ * launch fifo.  The cancel is superfluous on some chip versions, but
+ * it's safer to always do it.
+ * PIOAvail bits are updated by the chip as if a normal send had happened.
+ */
+void qib_cancel_sends(struct qib_pportdata *ppd)
+{
+       struct qib_devdata *dd = ppd->dd;
+       struct qib_ctxtdata *rcd;
+       unsigned long flags;
+       unsigned ctxt;
+       unsigned i;
+       unsigned last;
+
+       /*
+        * Tell PSM to disarm buffers again before trying to reuse them.
+        * We need to be sure the rcd doesn't change out from under us
+        * while we do so.  We hold the two locks sequentially.  We might
+        * needlessly set some need_disarm bits as a result, if the
+        * context is closed after we release the uctxt_lock, but that's
+        * fairly benign, and safer than nesting the locks.
+        */
+       for (ctxt = dd->first_user_ctxt; ctxt < dd->cfgctxts; ctxt++) {
+               spin_lock_irqsave(&dd->uctxt_lock, flags);
+               rcd = dd->rcd[ctxt];
+               if (rcd && rcd->ppd == ppd) {
+                       last = rcd->pio_base + rcd->piocnt;
+                       if (rcd->user_event_mask) {
+                               /*
+                                * subctxt_cnt is 0 if not shared, so do base
+                                * separately, first, then remaining subctxt,
+                                * if any
+                                */
+                               set_bit(_QIB_EVENT_DISARM_BUFS_BIT,
+                                       &rcd->user_event_mask[0]);
+                               for (i = 1; i < rcd->subctxt_cnt; i++)
+                                       set_bit(_QIB_EVENT_DISARM_BUFS_BIT,
+                                               &rcd->user_event_mask[i]);
+                       }
+                       i = rcd->pio_base;
+                       spin_unlock_irqrestore(&dd->uctxt_lock, flags);
+                       spin_lock_irqsave(&dd->pioavail_lock, flags);
+                       for (; i < last; i++)
+                               __set_bit(i, dd->pio_need_disarm);
+                       spin_unlock_irqrestore(&dd->pioavail_lock, flags);
+               } else
+                       spin_unlock_irqrestore(&dd->uctxt_lock, flags);
+       }
+
+       if (!(dd->flags & QIB_HAS_SEND_DMA))
+               dd->f_sendctrl(ppd, QIB_SENDCTRL_DISARM_ALL |
+                                   QIB_SENDCTRL_FLUSH);
+}
+
+/*
+ * Force an update of in-memory copy of the pioavail registers, when
+ * needed for any of a variety of reasons.
+ * If already off, this routine is a nop, on the assumption that the
+ * caller (or set of callers) will "do the right thing".
+ * This is a per-device operation, so just the first port.
+ */
+void qib_force_pio_avail_update(struct qib_devdata *dd)
+{
+       dd->f_sendctrl(dd->pport, QIB_SENDCTRL_AVAIL_BLIP);
+}
+
+void qib_hol_down(struct qib_pportdata *ppd)
+{
+       /*
+        * Cancel sends when the link goes DOWN so that we aren't doing it
+        * at INIT when we might be trying to send SMI packets.
+        */
+       if (!(ppd->lflags & QIBL_IB_AUTONEG_INPROG))
+               qib_cancel_sends(ppd);
+}
+
+/*
+ * Link is at INIT.
+ * We start the HoL timer so we can detect stuck packets blocking SMP replies.
+ * Timer may already be running, so use mod_timer, not add_timer.
+ */
+void qib_hol_init(struct qib_pportdata *ppd)
+{
+       if (ppd->hol_state != QIB_HOL_INIT) {
+               ppd->hol_state = QIB_HOL_INIT;
+               mod_timer(&ppd->hol_timer,
+                         jiffies + msecs_to_jiffies(qib_hol_timeout_ms));
+       }
+}
+
+/*
+ * Link is up, continue any user processes, and ensure timer
+ * is a nop, if running.  Let timer keep running, if set; it
+ * will nop when it sees the link is up.
+ */
+void qib_hol_up(struct qib_pportdata *ppd)
+{
+       ppd->hol_state = QIB_HOL_UP;
+}
+
+/*
+ * This is only called via the timer.
+ */
+void qib_hol_event(unsigned long opaque)
+{
+       struct qib_pportdata *ppd = (struct qib_pportdata *)opaque;
+
+       /* If hardware error, etc, skip. */
+       if (!(ppd->dd->flags & QIB_INITTED))
+               return;
+
+       if (ppd->hol_state != QIB_HOL_UP) {
+               /*
+                * Try to flush sends in case a stuck packet is blocking
+                * SMP replies.
+                */
+               qib_hol_down(ppd);
+               mod_timer(&ppd->hol_timer,
+                         jiffies + msecs_to_jiffies(qib_hol_timeout_ms));
+       }
+}
diff --git a/drivers/infiniband/hw/qib/qib_uc.c b/drivers/infiniband/hw/qib/qib_uc.c
new file mode 100644 (file)
index 0000000..6c7fe78
--- /dev/null
@@ -0,0 +1,555 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009, 2010 QLogic Corporation.
+ * All rights reserved.
+ * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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 "qib.h"
+
+/* cut down ridiculously long IB macro names */
+#define OP(x) IB_OPCODE_UC_##x
+
+/**
+ * qib_make_uc_req - construct a request packet (SEND, RDMA write)
+ * @qp: a pointer to the QP
+ *
+ * Return 1 if constructed; otherwise, return 0.
+ */
+int qib_make_uc_req(struct qib_qp *qp)
+{
+       struct qib_other_headers *ohdr;
+       struct qib_swqe *wqe;
+       unsigned long flags;
+       u32 hwords;
+       u32 bth0;
+       u32 len;
+       u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu);
+       int ret = 0;
+
+       spin_lock_irqsave(&qp->s_lock, flags);
+
+       if (!(ib_qib_state_ops[qp->state] & QIB_PROCESS_SEND_OK)) {
+               if (!(ib_qib_state_ops[qp->state] & QIB_FLUSH_SEND))
+                       goto bail;
+               /* We are in the error state, flush the work request. */
+               if (qp->s_last == qp->s_head)
+                       goto bail;
+               /* If DMAs are in progress, we can't flush immediately. */
+               if (atomic_read(&qp->s_dma_busy)) {
+                       qp->s_flags |= QIB_S_WAIT_DMA;
+                       goto bail;
+               }
+               wqe = get_swqe_ptr(qp, qp->s_last);
+               qib_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR);
+               goto done;
+       }
+
+       ohdr = &qp->s_hdr.u.oth;
+       if (qp->remote_ah_attr.ah_flags & IB_AH_GRH)
+               ohdr = &qp->s_hdr.u.l.oth;
+
+       /* header size in 32-bit words LRH+BTH = (8+12)/4. */
+       hwords = 5;
+       bth0 = 0;
+
+       /* Get the next send request. */
+       wqe = get_swqe_ptr(qp, qp->s_cur);
+       qp->s_wqe = NULL;
+       switch (qp->s_state) {
+       default:
+               if (!(ib_qib_state_ops[qp->state] &
+                   QIB_PROCESS_NEXT_SEND_OK))
+                       goto bail;
+               /* Check if send work queue is empty. */
+               if (qp->s_cur == qp->s_head)
+                       goto bail;
+               /*
+                * Start a new request.
+                */
+               wqe->psn = qp->s_next_psn;
+               qp->s_psn = qp->s_next_psn;
+               qp->s_sge.sge = wqe->sg_list[0];
+               qp->s_sge.sg_list = wqe->sg_list + 1;
+               qp->s_sge.num_sge = wqe->wr.num_sge;
+               qp->s_sge.total_len = wqe->length;
+               len = wqe->length;
+               qp->s_len = len;
+               switch (wqe->wr.opcode) {
+               case IB_WR_SEND:
+               case IB_WR_SEND_WITH_IMM:
+                       if (len > pmtu) {
+                               qp->s_state = OP(SEND_FIRST);
+                               len = pmtu;
+                               break;
+                       }
+                       if (wqe->wr.opcode == IB_WR_SEND)
+                               qp->s_state = OP(SEND_ONLY);
+                       else {
+                               qp->s_state =
+                                       OP(SEND_ONLY_WITH_IMMEDIATE);
+                               /* Immediate data comes after the BTH */
+                               ohdr->u.imm_data = wqe->wr.ex.imm_data;
+                               hwords += 1;
+                       }
+                       if (wqe->wr.send_flags & IB_SEND_SOLICITED)
+                               bth0 |= IB_BTH_SOLICITED;
+                       qp->s_wqe = wqe;
+                       if (++qp->s_cur >= qp->s_size)
+                               qp->s_cur = 0;
+                       break;
+
+               case IB_WR_RDMA_WRITE:
+               case IB_WR_RDMA_WRITE_WITH_IMM:
+                       ohdr->u.rc.reth.vaddr =
+                               cpu_to_be64(wqe->wr.wr.rdma.remote_addr);
+                       ohdr->u.rc.reth.rkey =
+                               cpu_to_be32(wqe->wr.wr.rdma.rkey);
+                       ohdr->u.rc.reth.length = cpu_to_be32(len);
+                       hwords += sizeof(struct ib_reth) / 4;
+                       if (len > pmtu) {
+                               qp->s_state = OP(RDMA_WRITE_FIRST);
+                               len = pmtu;
+                               break;
+                       }
+                       if (wqe->wr.opcode == IB_WR_RDMA_WRITE)
+                               qp->s_state = OP(RDMA_WRITE_ONLY);
+                       else {
+                               qp->s_state =
+                                       OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE);
+                               /* Immediate data comes after the RETH */
+                               ohdr->u.rc.imm_data = wqe->wr.ex.imm_data;
+                               hwords += 1;
+                               if (wqe->wr.send_flags & IB_SEND_SOLICITED)
+                                       bth0 |= IB_BTH_SOLICITED;
+                       }
+                       qp->s_wqe = wqe;
+                       if (++qp->s_cur >= qp->s_size)
+                               qp->s_cur = 0;
+                       break;
+
+               default:
+                       goto bail;
+               }
+               break;
+
+       case OP(SEND_FIRST):
+               qp->s_state = OP(SEND_MIDDLE);
+               /* FALLTHROUGH */
+       case OP(SEND_MIDDLE):
+               len = qp->s_len;
+               if (len > pmtu) {
+                       len = pmtu;
+                       break;
+               }
+               if (wqe->wr.opcode == IB_WR_SEND)
+                       qp->s_state = OP(SEND_LAST);
+               else {
+                       qp->s_state = OP(SEND_LAST_WITH_IMMEDIATE);
+                       /* Immediate data comes after the BTH */
+                       ohdr->u.imm_data = wqe->wr.ex.imm_data;
+                       hwords += 1;
+               }
+               if (wqe->wr.send_flags & IB_SEND_SOLICITED)
+                       bth0 |= IB_BTH_SOLICITED;
+               qp->s_wqe = wqe;
+               if (++qp->s_cur >= qp->s_size)
+                       qp->s_cur = 0;
+               break;
+
+       case OP(RDMA_WRITE_FIRST):
+               qp->s_state = OP(RDMA_WRITE_MIDDLE);
+               /* FALLTHROUGH */
+       case OP(RDMA_WRITE_MIDDLE):
+               len = qp->s_len;
+               if (len > pmtu) {
+                       len = pmtu;
+                       break;
+               }
+               if (wqe->wr.opcode == IB_WR_RDMA_WRITE)
+                       qp->s_state = OP(RDMA_WRITE_LAST);
+               else {
+                       qp->s_state =
+                               OP(RDMA_WRITE_LAST_WITH_IMMEDIATE);
+                       /* Immediate data comes after the BTH */
+                       ohdr->u.imm_data = wqe->wr.ex.imm_data;
+                       hwords += 1;
+                       if (wqe->wr.send_flags & IB_SEND_SOLICITED)
+                               bth0 |= IB_BTH_SOLICITED;
+               }
+               qp->s_wqe = wqe;
+               if (++qp->s_cur >= qp->s_size)
+                       qp->s_cur = 0;
+               break;
+       }
+       qp->s_len -= len;
+       qp->s_hdrwords = hwords;
+       qp->s_cur_sge = &qp->s_sge;
+       qp->s_cur_size = len;
+       qib_make_ruc_header(qp, ohdr, bth0 | (qp->s_state << 24),
+                           qp->s_next_psn++ & QIB_PSN_MASK);
+done:
+       ret = 1;
+       goto unlock;
+
+bail:
+       qp->s_flags &= ~QIB_S_BUSY;
+unlock:
+       spin_unlock_irqrestore(&qp->s_lock, flags);
+       return ret;
+}
+
+/**
+ * qib_uc_rcv - handle an incoming UC packet
+ * @ibp: the port the packet came in on
+ * @hdr: the header of the packet
+ * @has_grh: true if the packet has a GRH
+ * @data: the packet data
+ * @tlen: the length of the packet
+ * @qp: the QP for this packet.
+ *
+ * This is called from qib_qp_rcv() to process an incoming UC packet
+ * for the given QP.
+ * Called at interrupt level.
+ */
+void qib_uc_rcv(struct qib_ibport *ibp, struct qib_ib_header *hdr,
+               int has_grh, void *data, u32 tlen, struct qib_qp *qp)
+{
+       struct qib_other_headers *ohdr;
+       unsigned long flags;
+       u32 opcode;
+       u32 hdrsize;
+       u32 psn;
+       u32 pad;
+       struct ib_wc wc;
+       u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu);
+       struct ib_reth *reth;
+       int ret;
+
+       /* Check for GRH */
+       if (!has_grh) {
+               ohdr = &hdr->u.oth;
+               hdrsize = 8 + 12;       /* LRH + BTH */
+       } else {
+               ohdr = &hdr->u.l.oth;
+               hdrsize = 8 + 40 + 12;  /* LRH + GRH + BTH */
+       }
+
+       opcode = be32_to_cpu(ohdr->bth[0]);
+       spin_lock_irqsave(&qp->s_lock, flags);
+       if (qib_ruc_check_hdr(ibp, hdr, has_grh, qp, opcode))
+               goto sunlock;
+       spin_unlock_irqrestore(&qp->s_lock, flags);
+
+       psn = be32_to_cpu(ohdr->bth[2]);
+       opcode >>= 24;
+       memset(&wc, 0, sizeof wc);
+
+       /* Prevent simultaneous processing after APM on different CPUs */
+       spin_lock(&qp->r_lock);
+
+       /* Compare the PSN verses the expected PSN. */
+       if (unlikely(qib_cmp24(psn, qp->r_psn) != 0)) {
+               /*
+                * Handle a sequence error.
+                * Silently drop any current message.
+                */
+               qp->r_psn = psn;
+inv:
+               if (qp->r_state == OP(SEND_FIRST) ||
+                   qp->r_state == OP(SEND_MIDDLE)) {
+                       set_bit(QIB_R_REWIND_SGE, &qp->r_aflags);
+                       qp->r_sge.num_sge = 0;
+               } else
+                       while (qp->r_sge.num_sge) {
+                               atomic_dec(&qp->r_sge.sge.mr->refcount);
+                               if (--qp->r_sge.num_sge)
+                                       qp->r_sge.sge = *qp->r_sge.sg_list++;
+                       }
+               qp->r_state = OP(SEND_LAST);
+               switch (opcode) {
+               case OP(SEND_FIRST):
+               case OP(SEND_ONLY):
+               case OP(SEND_ONLY_WITH_IMMEDIATE):
+                       goto send_first;
+
+               case OP(RDMA_WRITE_FIRST):
+               case OP(RDMA_WRITE_ONLY):
+               case OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE):
+                       goto rdma_first;
+
+               default:
+                       goto drop;
+               }
+       }
+
+       /* Check for opcode sequence errors. */
+       switch (qp->r_state) {
+       case OP(SEND_FIRST):
+       case OP(SEND_MIDDLE):
+               if (opcode == OP(SEND_MIDDLE) ||
+                   opcode == OP(SEND_LAST) ||
+                   opcode == OP(SEND_LAST_WITH_IMMEDIATE))
+                       break;
+               goto inv;
+
+       case OP(RDMA_WRITE_FIRST):
+       case OP(RDMA_WRITE_MIDDLE):
+               if (opcode == OP(RDMA_WRITE_MIDDLE) ||
+                   opcode == OP(RDMA_WRITE_LAST) ||
+                   opcode == OP(RDMA_WRITE_LAST_WITH_IMMEDIATE))
+                       break;
+               goto inv;
+
+       default:
+               if (opcode == OP(SEND_FIRST) ||
+                   opcode == OP(SEND_ONLY) ||
+                   opcode == OP(SEND_ONLY_WITH_IMMEDIATE) ||
+                   opcode == OP(RDMA_WRITE_FIRST) ||
+                   opcode == OP(RDMA_WRITE_ONLY) ||
+                   opcode == OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE))
+                       break;
+               goto inv;
+       }
+
+       if (qp->state == IB_QPS_RTR && !(qp->r_flags & QIB_R_COMM_EST)) {
+               qp->r_flags |= QIB_R_COMM_EST;
+               if (qp->ibqp.event_handler) {
+                       struct ib_event ev;
+
+                       ev.device = qp->ibqp.device;
+                       ev.element.qp = &qp->ibqp;
+                       ev.event = IB_EVENT_COMM_EST;
+                       qp->ibqp.event_handler(&ev, qp->ibqp.qp_context);
+               }
+       }
+
+       /* OK, process the packet. */
+       switch (opcode) {
+       case OP(SEND_FIRST):
+       case OP(SEND_ONLY):
+       case OP(SEND_ONLY_WITH_IMMEDIATE):
+send_first:
+               if (test_and_clear_bit(QIB_R_REWIND_SGE, &qp->r_aflags))
+                       qp->r_sge = qp->s_rdma_read_sge;
+               else {
+                       ret = qib_get_rwqe(qp, 0);
+                       if (ret < 0)
+                               goto op_err;
+                       if (!ret)
+                               goto drop;
+                       /*
+                        * qp->s_rdma_read_sge will be the owner
+                        * of the mr references.
+                        */
+                       qp->s_rdma_read_sge = qp->r_sge;
+               }
+               qp->r_rcv_len = 0;
+               if (opcode == OP(SEND_ONLY))
+                       goto send_last;
+               else if (opcode == OP(SEND_ONLY_WITH_IMMEDIATE))
+                       goto send_last_imm;
+               /* FALLTHROUGH */
+       case OP(SEND_MIDDLE):
+               /* Check for invalid length PMTU or posted rwqe len. */
+               if (unlikely(tlen != (hdrsize + pmtu + 4)))
+                       goto rewind;
+               qp->r_rcv_len += pmtu;
+               if (unlikely(qp->r_rcv_len > qp->r_len))
+                       goto rewind;
+               qib_copy_sge(&qp->r_sge, data, pmtu, 0);
+               break;
+
+       case OP(SEND_LAST_WITH_IMMEDIATE):
+send_last_imm:
+               wc.ex.imm_data = ohdr->u.imm_data;
+               hdrsize += 4;
+               wc.wc_flags = IB_WC_WITH_IMM;
+               /* FALLTHROUGH */
+       case OP(SEND_LAST):
+send_last:
+               /* Get the number of bytes the message was padded by. */
+               pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
+               /* Check for invalid length. */
+               /* XXX LAST len should be >= 1 */
+               if (unlikely(tlen < (hdrsize + pad + 4)))
+                       goto rewind;
+               /* Don't count the CRC. */
+               tlen -= (hdrsize + pad + 4);
+               wc.byte_len = tlen + qp->r_rcv_len;
+               if (unlikely(wc.byte_len > qp->r_len))
+                       goto rewind;
+               wc.opcode = IB_WC_RECV;
+last_imm:
+               qib_copy_sge(&qp->r_sge, data, tlen, 0);
+               while (qp->s_rdma_read_sge.num_sge) {
+                       atomic_dec(&qp->s_rdma_read_sge.sge.mr->refcount);
+                       if (--qp->s_rdma_read_sge.num_sge)
+                               qp->s_rdma_read_sge.sge =
+                                       *qp->s_rdma_read_sge.sg_list++;
+               }
+               wc.wr_id = qp->r_wr_id;
+               wc.status = IB_WC_SUCCESS;
+               wc.qp = &qp->ibqp;
+               wc.src_qp = qp->remote_qpn;
+               wc.slid = qp->remote_ah_attr.dlid;
+               wc.sl = qp->remote_ah_attr.sl;
+               /* Signal completion event if the solicited bit is set. */
+               qib_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,
+                            (ohdr->bth[0] &
+                               cpu_to_be32(IB_BTH_SOLICITED)) != 0);
+               break;
+
+       case OP(RDMA_WRITE_FIRST):
+       case OP(RDMA_WRITE_ONLY):
+       case OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE): /* consume RWQE */
+rdma_first:
+               if (unlikely(!(qp->qp_access_flags &
+                              IB_ACCESS_REMOTE_WRITE))) {
+                       goto drop;
+               }
+               reth = &ohdr->u.rc.reth;
+               hdrsize += sizeof(*reth);
+               qp->r_len = be32_to_cpu(reth->length);
+               qp->r_rcv_len = 0;
+               qp->r_sge.sg_list = NULL;
+               if (qp->r_len != 0) {
+                       u32 rkey = be32_to_cpu(reth->rkey);
+                       u64 vaddr = be64_to_cpu(reth->vaddr);
+                       int ok;
+
+                       /* Check rkey */
+                       ok = qib_rkey_ok(qp, &qp->r_sge.sge, qp->r_len,
+                                        vaddr, rkey, IB_ACCESS_REMOTE_WRITE);
+                       if (unlikely(!ok))
+                               goto drop;
+                       qp->r_sge.num_sge = 1;
+               } else {
+                       qp->r_sge.num_sge = 0;
+                       qp->r_sge.sge.mr = NULL;
+                       qp->r_sge.sge.vaddr = NULL;
+                       qp->r_sge.sge.length = 0;
+                       qp->r_sge.sge.sge_length = 0;
+               }
+               if (opcode == OP(RDMA_WRITE_ONLY))
+                       goto rdma_last;
+               else if (opcode == OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE))
+                       goto rdma_last_imm;
+               /* FALLTHROUGH */
+       case OP(RDMA_WRITE_MIDDLE):
+               /* Check for invalid length PMTU or posted rwqe len. */
+               if (unlikely(tlen != (hdrsize + pmtu + 4)))
+                       goto drop;
+               qp->r_rcv_len += pmtu;
+               if (unlikely(qp->r_rcv_len > qp->r_len))
+                       goto drop;
+               qib_copy_sge(&qp->r_sge, data, pmtu, 1);
+               break;
+
+       case OP(RDMA_WRITE_LAST_WITH_IMMEDIATE):
+rdma_last_imm:
+               wc.ex.imm_data = ohdr->u.imm_data;
+               hdrsize += 4;
+               wc.wc_flags = IB_WC_WITH_IMM;
+
+               /* Get the number of bytes the message was padded by. */
+               pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
+               /* Check for invalid length. */
+               /* XXX LAST len should be >= 1 */
+               if (unlikely(tlen < (hdrsize + pad + 4)))
+                       goto drop;
+               /* Don't count the CRC. */
+               tlen -= (hdrsize + pad + 4);
+               if (unlikely(tlen + qp->r_rcv_len != qp->r_len))
+                       goto drop;
+               if (test_and_clear_bit(QIB_R_REWIND_SGE, &qp->r_aflags))
+                       while (qp->s_rdma_read_sge.num_sge) {
+                               atomic_dec(&qp->s_rdma_read_sge.sge.mr->
+                                          refcount);
+                               if (--qp->s_rdma_read_sge.num_sge)
+                                       qp->s_rdma_read_sge.sge =
+                                               *qp->s_rdma_read_sge.sg_list++;
+                       }
+               else {
+                       ret = qib_get_rwqe(qp, 1);
+                       if (ret < 0)
+                               goto op_err;
+                       if (!ret)
+                               goto drop;
+               }
+               wc.byte_len = qp->r_len;
+               wc.opcode = IB_WC_RECV_RDMA_WITH_IMM;
+               goto last_imm;
+
+       case OP(RDMA_WRITE_LAST):
+rdma_last:
+               /* Get the number of bytes the message was padded by. */
+               pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
+               /* Check for invalid length. */
+               /* XXX LAST len should be >= 1 */
+               if (unlikely(tlen < (hdrsize + pad + 4)))
+                       goto drop;
+               /* Don't count the CRC. */
+               tlen -= (hdrsize + pad + 4);
+               if (unlikely(tlen + qp->r_rcv_len != qp->r_len))
+                       goto drop;
+               qib_copy_sge(&qp->r_sge, data, tlen, 1);
+               while (qp->r_sge.num_sge) {
+                       atomic_dec(&qp->r_sge.sge.mr->refcount);
+                       if (--qp->r_sge.num_sge)
+                               qp->r_sge.sge = *qp->r_sge.sg_list++;
+               }
+               break;
+
+       default:
+               /* Drop packet for unknown opcodes. */
+               goto drop;
+       }
+       qp->r_psn++;
+       qp->r_state = opcode;
+       spin_unlock(&qp->r_lock);
+       return;
+
+rewind:
+       set_bit(QIB_R_REWIND_SGE, &qp->r_aflags);
+       qp->r_sge.num_sge = 0;
+drop:
+       ibp->n_pkt_drops++;
+       spin_unlock(&qp->r_lock);
+       return;
+
+op_err:
+       qib_rc_error(qp, IB_WC_LOC_QP_OP_ERR);
+       spin_unlock(&qp->r_lock);
+       return;
+
+sunlock:
+       spin_unlock_irqrestore(&qp->s_lock, flags);
+}
diff --git a/drivers/infiniband/hw/qib/qib_ud.c b/drivers/infiniband/hw/qib/qib_ud.c
new file mode 100644 (file)
index 0000000..c838cda
--- /dev/null
@@ -0,0 +1,607 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved.
+ * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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 <rdma/ib_smi.h>
+
+#include "qib.h"
+#include "qib_mad.h"
+
+/**
+ * qib_ud_loopback - handle send on loopback QPs
+ * @sqp: the sending QP
+ * @swqe: the send work request
+ *
+ * This is called from qib_make_ud_req() to forward a WQE addressed
+ * to the same HCA.
+ * Note that the receive interrupt handler may be calling qib_ud_rcv()
+ * while this is being called.
+ */
+static void qib_ud_loopback(struct qib_qp *sqp, struct qib_swqe *swqe)
+{
+       struct qib_ibport *ibp = to_iport(sqp->ibqp.device, sqp->port_num);
+       struct qib_pportdata *ppd;
+       struct qib_qp *qp;
+       struct ib_ah_attr *ah_attr;
+       unsigned long flags;
+       struct qib_sge_state ssge;
+       struct qib_sge *sge;
+       struct ib_wc wc;
+       u32 length;
+
+       qp = qib_lookup_qpn(ibp, swqe->wr.wr.ud.remote_qpn);
+       if (!qp) {
+               ibp->n_pkt_drops++;
+               return;
+       }
+       if (qp->ibqp.qp_type != sqp->ibqp.qp_type ||
+           !(ib_qib_state_ops[qp->state] & QIB_PROCESS_RECV_OK)) {
+               ibp->n_pkt_drops++;
+               goto drop;
+       }
+
+       ah_attr = &to_iah(swqe->wr.wr.ud.ah)->attr;
+       ppd = ppd_from_ibp(ibp);
+
+       if (qp->ibqp.qp_num > 1) {
+               u16 pkey1;
+               u16 pkey2;
+               u16 lid;
+
+               pkey1 = qib_get_pkey(ibp, sqp->s_pkey_index);
+               pkey2 = qib_get_pkey(ibp, qp->s_pkey_index);
+               if (unlikely(!qib_pkey_ok(pkey1, pkey2))) {
+                       lid = ppd->lid | (ah_attr->src_path_bits &
+                                         ((1 << ppd->lmc) - 1));
+                       qib_bad_pqkey(ibp, IB_NOTICE_TRAP_BAD_PKEY, pkey1,
+                                     ah_attr->sl,
+                                     sqp->ibqp.qp_num, qp->ibqp.qp_num,
+                                     cpu_to_be16(lid),
+                                     cpu_to_be16(ah_attr->dlid));
+                       goto drop;
+               }
+       }
+
+       /*
+        * Check that the qkey matches (except for QP0, see 9.6.1.4.1).
+        * Qkeys with the high order bit set mean use the
+        * qkey from the QP context instead of the WR (see 10.2.5).
+        */
+       if (qp->ibqp.qp_num) {
+               u32 qkey;
+
+               qkey = (int)swqe->wr.wr.ud.remote_qkey < 0 ?
+                       sqp->qkey : swqe->wr.wr.ud.remote_qkey;
+               if (unlikely(qkey != qp->qkey)) {
+                       u16 lid;
+
+                       lid = ppd->lid | (ah_attr->src_path_bits &
+                                         ((1 << ppd->lmc) - 1));
+                       qib_bad_pqkey(ibp, IB_NOTICE_TRAP_BAD_QKEY, qkey,
+                                     ah_attr->sl,
+                                     sqp->ibqp.qp_num, qp->ibqp.qp_num,
+                                     cpu_to_be16(lid),
+                                     cpu_to_be16(ah_attr->dlid));
+                       goto drop;
+               }
+       }
+
+       /*
+        * A GRH is expected to preceed the data even if not
+        * present on the wire.
+        */
+       length = swqe->length;
+       memset(&wc, 0, sizeof wc);
+       wc.byte_len = length + sizeof(struct ib_grh);
+
+       if (swqe->wr.opcode == IB_WR_SEND_WITH_IMM) {
+               wc.wc_flags = IB_WC_WITH_IMM;
+               wc.ex.imm_data = swqe->wr.ex.imm_data;
+       }
+
+       spin_lock_irqsave(&qp->r_lock, flags);
+
+       /*
+        * Get the next work request entry to find where to put the data.
+        */
+       if (qp->r_flags & QIB_R_REUSE_SGE)
+               qp->r_flags &= ~QIB_R_REUSE_SGE;
+       else {
+               int ret;
+
+               ret = qib_get_rwqe(qp, 0);
+               if (ret < 0) {
+                       qib_rc_error(qp, IB_WC_LOC_QP_OP_ERR);
+                       goto bail_unlock;
+               }
+               if (!ret) {
+                       if (qp->ibqp.qp_num == 0)
+                               ibp->n_vl15_dropped++;
+                       goto bail_unlock;
+               }
+       }
+       /* Silently drop packets which are too big. */
+       if (unlikely(wc.byte_len > qp->r_len)) {
+               qp->r_flags |= QIB_R_REUSE_SGE;
+               ibp->n_pkt_drops++;
+               goto bail_unlock;
+       }
+
+       if (ah_attr->ah_flags & IB_AH_GRH) {
+               qib_copy_sge(&qp->r_sge, &ah_attr->grh,
+                            sizeof(struct ib_grh), 1);
+               wc.wc_flags |= IB_WC_GRH;
+       } else
+               qib_skip_sge(&qp->r_sge, sizeof(struct ib_grh), 1);
+       ssge.sg_list = swqe->sg_list + 1;
+       ssge.sge = *swqe->sg_list;
+       ssge.num_sge = swqe->wr.num_sge;
+       sge = &ssge.sge;
+       while (length) {
+               u32 len = sge->length;
+
+               if (len > length)
+                       len = length;
+               if (len > sge->sge_length)
+                       len = sge->sge_length;
+               BUG_ON(len == 0);
+               qib_copy_sge(&qp->r_sge, sge->vaddr, len, 1);
+               sge->vaddr += len;
+               sge->length -= len;
+               sge->sge_length -= len;
+               if (sge->sge_length == 0) {
+                       if (--ssge.num_sge)
+                               *sge = *ssge.sg_list++;
+               } else if (sge->length == 0 && sge->mr->lkey) {
+                       if (++sge->n >= QIB_SEGSZ) {
+                               if (++sge->m >= sge->mr->mapsz)
+                                       break;
+                               sge->n = 0;
+                       }
+                       sge->vaddr =
+                               sge->mr->map[sge->m]->segs[sge->n].vaddr;
+                       sge->length =
+                               sge->mr->map[sge->m]->segs[sge->n].length;
+               }
+               length -= len;
+       }
+       while (qp->r_sge.num_sge) {
+               atomic_dec(&qp->r_sge.sge.mr->refcount);
+               if (--qp->r_sge.num_sge)
+                       qp->r_sge.sge = *qp->r_sge.sg_list++;
+       }
+       if (!test_and_clear_bit(QIB_R_WRID_VALID, &qp->r_aflags))
+               goto bail_unlock;
+       wc.wr_id = qp->r_wr_id;
+       wc.status = IB_WC_SUCCESS;
+       wc.opcode = IB_WC_RECV;
+       wc.qp = &qp->ibqp;
+       wc.src_qp = sqp->ibqp.qp_num;
+       wc.pkey_index = qp->ibqp.qp_type == IB_QPT_GSI ?
+               swqe->wr.wr.ud.pkey_index : 0;
+       wc.slid = ppd->lid | (ah_attr->src_path_bits & ((1 << ppd->lmc) - 1));
+       wc.sl = ah_attr->sl;
+       wc.dlid_path_bits = ah_attr->dlid & ((1 << ppd->lmc) - 1);
+       wc.port_num = qp->port_num;
+       /* Signal completion event if the solicited bit is set. */
+       qib_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,
+                    swqe->wr.send_flags & IB_SEND_SOLICITED);
+       ibp->n_loop_pkts++;
+bail_unlock:
+       spin_unlock_irqrestore(&qp->r_lock, flags);
+drop:
+       if (atomic_dec_and_test(&qp->refcount))
+               wake_up(&qp->wait);
+}
+
+/**
+ * qib_make_ud_req - construct a UD request packet
+ * @qp: the QP
+ *
+ * Return 1 if constructed; otherwise, return 0.
+ */
+int qib_make_ud_req(struct qib_qp *qp)
+{
+       struct qib_other_headers *ohdr;
+       struct ib_ah_attr *ah_attr;
+       struct qib_pportdata *ppd;
+       struct qib_ibport *ibp;
+       struct qib_swqe *wqe;
+       unsigned long flags;
+       u32 nwords;
+       u32 extra_bytes;
+       u32 bth0;
+       u16 lrh0;
+       u16 lid;
+       int ret = 0;
+       int next_cur;
+
+       spin_lock_irqsave(&qp->s_lock, flags);
+
+       if (!(ib_qib_state_ops[qp->state] & QIB_PROCESS_NEXT_SEND_OK)) {
+               if (!(ib_qib_state_ops[qp->state] & QIB_FLUSH_SEND))
+                       goto bail;
+               /* We are in the error state, flush the work request. */
+               if (qp->s_last == qp->s_head)
+                       goto bail;
+               /* If DMAs are in progress, we can't flush immediately. */
+               if (atomic_read(&qp->s_dma_busy)) {
+                       qp->s_flags |= QIB_S_WAIT_DMA;
+                       goto bail;
+               }
+               wqe = get_swqe_ptr(qp, qp->s_last);
+               qib_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR);
+               goto done;
+       }
+
+       if (qp->s_cur == qp->s_head)
+               goto bail;
+
+       wqe = get_swqe_ptr(qp, qp->s_cur);
+       next_cur = qp->s_cur + 1;
+       if (next_cur >= qp->s_size)
+               next_cur = 0;
+
+       /* Construct the header. */
+       ibp = to_iport(qp->ibqp.device, qp->port_num);
+       ppd = ppd_from_ibp(ibp);
+       ah_attr = &to_iah(wqe->wr.wr.ud.ah)->attr;
+       if (ah_attr->dlid >= QIB_MULTICAST_LID_BASE) {
+               if (ah_attr->dlid != QIB_PERMISSIVE_LID)
+                       ibp->n_multicast_xmit++;
+               else
+                       ibp->n_unicast_xmit++;
+       } else {
+               ibp->n_unicast_xmit++;
+               lid = ah_attr->dlid & ~((1 << ppd->lmc) - 1);
+               if (unlikely(lid == ppd->lid)) {
+                       /*
+                        * If DMAs are in progress, we can't generate
+                        * a completion for the loopback packet since
+                        * it would be out of order.
+                        * XXX Instead of waiting, we could queue a
+                        * zero length descriptor so we get a callback.
+                        */
+                       if (atomic_read(&qp->s_dma_busy)) {
+                               qp->s_flags |= QIB_S_WAIT_DMA;
+                               goto bail;
+                       }
+                       qp->s_cur = next_cur;
+                       spin_unlock_irqrestore(&qp->s_lock, flags);
+                       qib_ud_loopback(qp, wqe);
+                       spin_lock_irqsave(&qp->s_lock, flags);
+                       qib_send_complete(qp, wqe, IB_WC_SUCCESS);
+                       goto done;
+               }
+       }
+
+       qp->s_cur = next_cur;
+       extra_bytes = -wqe->length & 3;
+       nwords = (wqe->length + extra_bytes) >> 2;
+
+       /* header size in 32-bit words LRH+BTH+DETH = (8+12+8)/4. */
+       qp->s_hdrwords = 7;
+       qp->s_cur_size = wqe->length;
+       qp->s_cur_sge = &qp->s_sge;
+       qp->s_srate = ah_attr->static_rate;
+       qp->s_wqe = wqe;
+       qp->s_sge.sge = wqe->sg_list[0];
+       qp->s_sge.sg_list = wqe->sg_list + 1;
+       qp->s_sge.num_sge = wqe->wr.num_sge;
+       qp->s_sge.total_len = wqe->length;
+
+       if (ah_attr->ah_flags & IB_AH_GRH) {
+               /* Header size in 32-bit words. */
+               qp->s_hdrwords += qib_make_grh(ibp, &qp->s_hdr.u.l.grh,
+                                              &ah_attr->grh,
+                                              qp->s_hdrwords, nwords);
+               lrh0 = QIB_LRH_GRH;
+               ohdr = &qp->s_hdr.u.l.oth;
+               /*
+                * Don't worry about sending to locally attached multicast
+                * QPs.  It is unspecified by the spec. what happens.
+                */
+       } else {
+               /* Header size in 32-bit words. */
+               lrh0 = QIB_LRH_BTH;
+               ohdr = &qp->s_hdr.u.oth;
+       }
+       if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM) {
+               qp->s_hdrwords++;
+               ohdr->u.ud.imm_data = wqe->wr.ex.imm_data;
+               bth0 = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE << 24;
+       } else
+               bth0 = IB_OPCODE_UD_SEND_ONLY << 24;
+       lrh0 |= ah_attr->sl << 4;
+       if (qp->ibqp.qp_type == IB_QPT_SMI)
+               lrh0 |= 0xF000; /* Set VL (see ch. 13.5.3.1) */
+       else
+               lrh0 |= ibp->sl_to_vl[ah_attr->sl] << 12;
+       qp->s_hdr.lrh[0] = cpu_to_be16(lrh0);
+       qp->s_hdr.lrh[1] = cpu_to_be16(ah_attr->dlid);  /* DEST LID */
+       qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords + SIZE_OF_CRC);
+       lid = ppd->lid;
+       if (lid) {
+               lid |= ah_attr->src_path_bits & ((1 << ppd->lmc) - 1);
+               qp->s_hdr.lrh[3] = cpu_to_be16(lid);
+       } else
+               qp->s_hdr.lrh[3] = IB_LID_PERMISSIVE;
+       if (wqe->wr.send_flags & IB_SEND_SOLICITED)
+               bth0 |= IB_BTH_SOLICITED;
+       bth0 |= extra_bytes << 20;
+       bth0 |= qp->ibqp.qp_type == IB_QPT_SMI ? QIB_DEFAULT_P_KEY :
+               qib_get_pkey(ibp, qp->ibqp.qp_type == IB_QPT_GSI ?
+                            wqe->wr.wr.ud.pkey_index : qp->s_pkey_index);
+       ohdr->bth[0] = cpu_to_be32(bth0);
+       /*
+        * Use the multicast QP if the destination LID is a multicast LID.
+        */
+       ohdr->bth[1] = ah_attr->dlid >= QIB_MULTICAST_LID_BASE &&
+               ah_attr->dlid != QIB_PERMISSIVE_LID ?
+               cpu_to_be32(QIB_MULTICAST_QPN) :
+               cpu_to_be32(wqe->wr.wr.ud.remote_qpn);
+       ohdr->bth[2] = cpu_to_be32(qp->s_next_psn++ & QIB_PSN_MASK);
+       /*
+        * Qkeys with the high order bit set mean use the
+        * qkey from the QP context instead of the WR (see 10.2.5).
+        */
+       ohdr->u.ud.deth[0] = cpu_to_be32((int)wqe->wr.wr.ud.remote_qkey < 0 ?
+                                        qp->qkey : wqe->wr.wr.ud.remote_qkey);
+       ohdr->u.ud.deth[1] = cpu_to_be32(qp->ibqp.qp_num);
+
+done:
+       ret = 1;
+       goto unlock;
+
+bail:
+       qp->s_flags &= ~QIB_S_BUSY;
+unlock:
+       spin_unlock_irqrestore(&qp->s_lock, flags);
+       return ret;
+}
+
+static unsigned qib_lookup_pkey(struct qib_ibport *ibp, u16 pkey)
+{
+       struct qib_pportdata *ppd = ppd_from_ibp(ibp);
+       struct qib_devdata *dd = ppd->dd;
+       unsigned ctxt = ppd->hw_pidx;
+       unsigned i;
+
+       pkey &= 0x7fff; /* remove limited/full membership bit */
+
+       for (i = 0; i < ARRAY_SIZE(dd->rcd[ctxt]->pkeys); ++i)
+               if ((dd->rcd[ctxt]->pkeys[i] & 0x7fff) == pkey)
+                       return i;
+
+       /*
+        * Should not get here, this means hardware failed to validate pkeys.
+        * Punt and return index 0.
+        */
+       return 0;
+}
+
+/**
+ * qib_ud_rcv - receive an incoming UD packet
+ * @ibp: the port the packet came in on
+ * @hdr: the packet header
+ * @has_grh: true if the packet has a GRH
+ * @data: the packet data
+ * @tlen: the packet length
+ * @qp: the QP the packet came on
+ *
+ * This is called from qib_qp_rcv() to process an incoming UD packet
+ * for the given QP.
+ * Called at interrupt level.
+ */
+void qib_ud_rcv(struct qib_ibport *ibp, struct qib_ib_header *hdr,
+               int has_grh, void *data, u32 tlen, struct qib_qp *qp)
+{
+       struct qib_other_headers *ohdr;
+       int opcode;
+       u32 hdrsize;
+       u32 pad;
+       struct ib_wc wc;
+       u32 qkey;
+       u32 src_qp;
+       u16 dlid;
+
+       /* Check for GRH */
+       if (!has_grh) {
+               ohdr = &hdr->u.oth;
+               hdrsize = 8 + 12 + 8;   /* LRH + BTH + DETH */
+       } else {
+               ohdr = &hdr->u.l.oth;
+               hdrsize = 8 + 40 + 12 + 8; /* LRH + GRH + BTH + DETH */
+       }
+       qkey = be32_to_cpu(ohdr->u.ud.deth[0]);
+       src_qp = be32_to_cpu(ohdr->u.ud.deth[1]) & QIB_QPN_MASK;
+
+       /* Get the number of bytes the message was padded by. */
+       pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
+       if (unlikely(tlen < (hdrsize + pad + 4))) {
+               /* Drop incomplete packets. */
+               ibp->n_pkt_drops++;
+               goto bail;
+       }
+       tlen -= hdrsize + pad + 4;
+
+       /*
+        * Check that the permissive LID is only used on QP0
+        * and the QKEY matches (see 9.6.1.4.1 and 9.6.1.5.1).
+        */
+       if (qp->ibqp.qp_num) {
+               if (unlikely(hdr->lrh[1] == IB_LID_PERMISSIVE ||
+                            hdr->lrh[3] == IB_LID_PERMISSIVE)) {
+                       ibp->n_pkt_drops++;
+                       goto bail;
+               }
+               if (qp->ibqp.qp_num > 1) {
+                       u16 pkey1, pkey2;
+
+                       pkey1 = be32_to_cpu(ohdr->bth[0]);
+                       pkey2 = qib_get_pkey(ibp, qp->s_pkey_index);
+                       if (unlikely(!qib_pkey_ok(pkey1, pkey2))) {
+                               qib_bad_pqkey(ibp, IB_NOTICE_TRAP_BAD_PKEY,
+                                             pkey1,
+                                             (be16_to_cpu(hdr->lrh[0]) >> 4) &
+                                               0xF,
+                                             src_qp, qp->ibqp.qp_num,
+                                             hdr->lrh[3], hdr->lrh[1]);
+                               goto bail;
+                       }
+               }
+               if (unlikely(qkey != qp->qkey)) {
+                       qib_bad_pqkey(ibp, IB_NOTICE_TRAP_BAD_QKEY, qkey,
+                                     (be16_to_cpu(hdr->lrh[0]) >> 4) & 0xF,
+                                     src_qp, qp->ibqp.qp_num,
+                                     hdr->lrh[3], hdr->lrh[1]);
+                       goto bail;
+               }
+               /* Drop invalid MAD packets (see 13.5.3.1). */
+               if (unlikely(qp->ibqp.qp_num == 1 &&
+                            (tlen != 256 ||
+                             (be16_to_cpu(hdr->lrh[0]) >> 12) == 15))) {
+                       ibp->n_pkt_drops++;
+                       goto bail;
+               }
+       } else {
+               struct ib_smp *smp;
+
+               /* Drop invalid MAD packets (see 13.5.3.1). */
+               if (tlen != 256 || (be16_to_cpu(hdr->lrh[0]) >> 12) != 15) {
+                       ibp->n_pkt_drops++;
+                       goto bail;
+               }
+               smp = (struct ib_smp *) data;
+               if ((hdr->lrh[1] == IB_LID_PERMISSIVE ||
+                    hdr->lrh[3] == IB_LID_PERMISSIVE) &&
+                   smp->mgmt_class != IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) {
+                       ibp->n_pkt_drops++;
+                       goto bail;
+               }
+       }
+
+       /*
+        * The opcode is in the low byte when its in network order
+        * (top byte when in host order).
+        */
+       opcode = be32_to_cpu(ohdr->bth[0]) >> 24;
+       if (qp->ibqp.qp_num > 1 &&
+           opcode == IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE) {
+               wc.ex.imm_data = ohdr->u.ud.imm_data;
+               wc.wc_flags = IB_WC_WITH_IMM;
+               hdrsize += sizeof(u32);
+       } else if (opcode == IB_OPCODE_UD_SEND_ONLY) {
+               wc.ex.imm_data = 0;
+               wc.wc_flags = 0;
+       } else {
+               ibp->n_pkt_drops++;
+               goto bail;
+       }
+
+       /*
+        * A GRH is expected to preceed the data even if not
+        * present on the wire.
+        */
+       wc.byte_len = tlen + sizeof(struct ib_grh);
+
+       /*
+        * We need to serialize getting a receive work queue entry and
+        * generating a completion for it against QPs sending to this QP
+        * locally.
+        */
+       spin_lock(&qp->r_lock);
+
+       /*
+        * Get the next work request entry to find where to put the data.
+        */
+       if (qp->r_flags & QIB_R_REUSE_SGE)
+               qp->r_flags &= ~QIB_R_REUSE_SGE;
+       else {
+               int ret;
+
+               ret = qib_get_rwqe(qp, 0);
+               if (ret < 0) {
+                       qib_rc_error(qp, IB_WC_LOC_QP_OP_ERR);
+                       goto bail_unlock;
+               }
+               if (!ret) {
+                       if (qp->ibqp.qp_num == 0)
+                               ibp->n_vl15_dropped++;
+                       goto bail_unlock;
+               }
+       }
+       /* Silently drop packets which are too big. */
+       if (unlikely(wc.byte_len > qp->r_len)) {
+               qp->r_flags |= QIB_R_REUSE_SGE;
+               ibp->n_pkt_drops++;
+               goto bail_unlock;
+       }
+       if (has_grh) {
+               qib_copy_sge(&qp->r_sge, &hdr->u.l.grh,
+                            sizeof(struct ib_grh), 1);
+               wc.wc_flags |= IB_WC_GRH;
+       } else
+               qib_skip_sge(&qp->r_sge, sizeof(struct ib_grh), 1);
+       qib_copy_sge(&qp->r_sge, data, wc.byte_len - sizeof(struct ib_grh), 1);
+       while (qp->r_sge.num_sge) {
+               atomic_dec(&qp->r_sge.sge.mr->refcount);
+               if (--qp->r_sge.num_sge)
+                       qp->r_sge.sge = *qp->r_sge.sg_list++;
+       }
+       if (!test_and_clear_bit(QIB_R_WRID_VALID, &qp->r_aflags))
+               goto bail_unlock;
+       wc.wr_id = qp->r_wr_id;
+       wc.status = IB_WC_SUCCESS;
+       wc.opcode = IB_WC_RECV;
+       wc.vendor_err = 0;
+       wc.qp = &qp->ibqp;
+       wc.src_qp = src_qp;
+       wc.pkey_index = qp->ibqp.qp_type == IB_QPT_GSI ?
+               qib_lookup_pkey(ibp, be32_to_cpu(ohdr->bth[0])) : 0;
+       wc.slid = be16_to_cpu(hdr->lrh[3]);
+       wc.sl = (be16_to_cpu(hdr->lrh[0]) >> 4) & 0xF;
+       dlid = be16_to_cpu(hdr->lrh[1]);
+       /*
+        * Save the LMC lower bits if the destination LID is a unicast LID.
+        */
+       wc.dlid_path_bits = dlid >= QIB_MULTICAST_LID_BASE ? 0 :
+               dlid & ((1 << ppd_from_ibp(ibp)->lmc) - 1);
+       wc.port_num = qp->port_num;
+       /* Signal completion event if the solicited bit is set. */
+       qib_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,
+                    (ohdr->bth[0] &
+                       cpu_to_be32(IB_BTH_SOLICITED)) != 0);
+bail_unlock:
+       spin_unlock(&qp->r_lock);
+bail:;
+}
diff --git a/drivers/infiniband/hw/qib/qib_user_pages.c b/drivers/infiniband/hw/qib/qib_user_pages.c
new file mode 100644 (file)
index 0000000..d7a26c1
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved.
+ * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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/mm.h>
+#include <linux/device.h>
+
+#include "qib.h"
+
+static void __qib_release_user_pages(struct page **p, size_t num_pages,
+                                    int dirty)
+{
+       size_t i;
+
+       for (i = 0; i < num_pages; i++) {
+               if (dirty)
+                       set_page_dirty_lock(p[i]);
+               put_page(p[i]);
+       }
+}
+
+/*
+ * Call with current->mm->mmap_sem held.
+ */
+static int __get_user_pages(unsigned long start_page, size_t num_pages,
+                           struct page **p, struct vm_area_struct **vma)
+{
+       unsigned long lock_limit;
+       size_t got;
+       int ret;
+
+       lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
+
+       if (num_pages > lock_limit && !capable(CAP_IPC_LOCK)) {
+               ret = -ENOMEM;
+               goto bail;
+       }
+
+       for (got = 0; got < num_pages; got += ret) {
+               ret = get_user_pages(current, current->mm,
+                                    start_page + got * PAGE_SIZE,
+                                    num_pages - got, 1, 1,
+                                    p + got, vma);
+               if (ret < 0)
+                       goto bail_release;
+       }
+
+       current->mm->locked_vm += num_pages;
+
+       ret = 0;
+       goto bail;
+
+bail_release:
+       __qib_release_user_pages(p, got, 0);
+bail:
+       return ret;
+}
+
+/**
+ * qib_map_page - a safety wrapper around pci_map_page()
+ *
+ * A dma_addr of all 0's is interpreted by the chip as "disabled".
+ * Unfortunately, it can also be a valid dma_addr returned on some
+ * architectures.
+ *
+ * The powerpc iommu assigns dma_addrs in ascending order, so we don't
+ * have to bother with retries or mapping a dummy page to insure we
+ * don't just get the same mapping again.
+ *
+ * I'm sure we won't be so lucky with other iommu's, so FIXME.
+ */
+dma_addr_t qib_map_page(struct pci_dev *hwdev, struct page *page,
+                       unsigned long offset, size_t size, int direction)
+{
+       dma_addr_t phys;
+
+       phys = pci_map_page(hwdev, page, offset, size, direction);
+
+       if (phys == 0) {
+               pci_unmap_page(hwdev, phys, size, direction);
+               phys = pci_map_page(hwdev, page, offset, size, direction);
+               /*
+                * FIXME: If we get 0 again, we should keep this page,
+                * map another, then free the 0 page.
+                */
+       }
+
+       return phys;
+}
+
+/**
+ * qib_get_user_pages - lock user pages into memory
+ * @start_page: the start page
+ * @num_pages: the number of pages
+ * @p: the output page structures
+ *
+ * This function takes a given start page (page aligned user virtual
+ * address) and pins it and the following specified number of pages.  For
+ * now, num_pages is always 1, but that will probably change at some point
+ * (because caller is doing expected sends on a single virtually contiguous
+ * buffer, so we can do all pages at once).
+ */
+int qib_get_user_pages(unsigned long start_page, size_t num_pages,
+                      struct page **p)
+{
+       int ret;
+
+       down_write(&current->mm->mmap_sem);
+
+       ret = __get_user_pages(start_page, num_pages, p, NULL);
+
+       up_write(&current->mm->mmap_sem);
+
+       return ret;
+}
+
+void qib_release_user_pages(struct page **p, size_t num_pages)
+{
+       if (current->mm) /* during close after signal, mm can be NULL */
+               down_write(&current->mm->mmap_sem);
+
+       __qib_release_user_pages(p, num_pages, 1);
+
+       if (current->mm) {
+               current->mm->locked_vm -= num_pages;
+               up_write(&current->mm->mmap_sem);
+       }
+}
diff --git a/drivers/infiniband/hw/qib/qib_user_sdma.c b/drivers/infiniband/hw/qib/qib_user_sdma.c
new file mode 100644 (file)
index 0000000..4c19e06
--- /dev/null
@@ -0,0 +1,897 @@
+/*
+ * Copyright (c) 2007, 2008, 2009 QLogic Corporation. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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/mm.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/dmapool.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/highmem.h>
+#include <linux/io.h>
+#include <linux/uio.h>
+#include <linux/rbtree.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+
+#include "qib.h"
+#include "qib_user_sdma.h"
+
+/* minimum size of header */
+#define QIB_USER_SDMA_MIN_HEADER_LENGTH 64
+/* expected size of headers (for dma_pool) */
+#define QIB_USER_SDMA_EXP_HEADER_LENGTH 64
+/* attempt to drain the queue for 5secs */
+#define QIB_USER_SDMA_DRAIN_TIMEOUT 500
+
+struct qib_user_sdma_pkt {
+       u8 naddr;               /* dimension of addr (1..3) ... */
+       u32 counter;            /* sdma pkts queued counter for this entry */
+       u64 added;              /* global descq number of entries */
+
+       struct {
+               u32 offset;                     /* offset for kvaddr, addr */
+               u32 length;                     /* length in page */
+               u8  put_page;                   /* should we put_page? */
+               u8  dma_mapped;                 /* is page dma_mapped? */
+               struct page *page;              /* may be NULL (coherent mem) */
+               void *kvaddr;                   /* FIXME: only for pio hack */
+               dma_addr_t addr;
+       } addr[4];   /* max pages, any more and we coalesce */
+       struct list_head list;  /* list element */
+};
+
+struct qib_user_sdma_queue {
+       /*
+        * pkts sent to dma engine are queued on this
+        * list head.  the type of the elements of this
+        * list are struct qib_user_sdma_pkt...
+        */
+       struct list_head sent;
+
+       /* headers with expected length are allocated from here... */
+       char header_cache_name[64];
+       struct dma_pool *header_cache;
+
+       /* packets are allocated from the slab cache... */
+       char pkt_slab_name[64];
+       struct kmem_cache *pkt_slab;
+
+       /* as packets go on the queued queue, they are counted... */
+       u32 counter;
+       u32 sent_counter;
+
+       /* dma page table */
+       struct rb_root dma_pages_root;
+
+       /* protect everything above... */
+       struct mutex lock;
+};
+
+struct qib_user_sdma_queue *
+qib_user_sdma_queue_create(struct device *dev, int unit, int ctxt, int sctxt)
+{
+       struct qib_user_sdma_queue *pq =
+               kmalloc(sizeof(struct qib_user_sdma_queue), GFP_KERNEL);
+
+       if (!pq)
+               goto done;
+
+       pq->counter = 0;
+       pq->sent_counter = 0;
+       INIT_LIST_HEAD(&pq->sent);
+
+       mutex_init(&pq->lock);
+
+       snprintf(pq->pkt_slab_name, sizeof(pq->pkt_slab_name),
+                "qib-user-sdma-pkts-%u-%02u.%02u", unit, ctxt, sctxt);
+       pq->pkt_slab = kmem_cache_create(pq->pkt_slab_name,
+                                        sizeof(struct qib_user_sdma_pkt),
+                                        0, 0, NULL);
+
+       if (!pq->pkt_slab)
+               goto err_kfree;
+
+       snprintf(pq->header_cache_name, sizeof(pq->header_cache_name),
+                "qib-user-sdma-headers-%u-%02u.%02u", unit, ctxt, sctxt);
+       pq->header_cache = dma_pool_create(pq->header_cache_name,
+                                          dev,
+                                          QIB_USER_SDMA_EXP_HEADER_LENGTH,
+                                          4, 0);
+       if (!pq->header_cache)
+               goto err_slab;
+
+       pq->dma_pages_root = RB_ROOT;
+
+       goto done;
+
+err_slab:
+       kmem_cache_destroy(pq->pkt_slab);
+err_kfree:
+       kfree(pq);
+       pq = NULL;
+
+done:
+       return pq;
+}
+
+static void qib_user_sdma_init_frag(struct qib_user_sdma_pkt *pkt,
+                                   int i, size_t offset, size_t len,
+                                   int put_page, int dma_mapped,
+                                   struct page *page,
+                                   void *kvaddr, dma_addr_t dma_addr)
+{
+       pkt->addr[i].offset = offset;
+       pkt->addr[i].length = len;
+       pkt->addr[i].put_page = put_page;
+       pkt->addr[i].dma_mapped = dma_mapped;
+       pkt->addr[i].page = page;
+       pkt->addr[i].kvaddr = kvaddr;
+       pkt->addr[i].addr = dma_addr;
+}
+
+static void qib_user_sdma_init_header(struct qib_user_sdma_pkt *pkt,
+                                     u32 counter, size_t offset,
+                                     size_t len, int dma_mapped,
+                                     struct page *page,
+                                     void *kvaddr, dma_addr_t dma_addr)
+{
+       pkt->naddr = 1;
+       pkt->counter = counter;
+       qib_user_sdma_init_frag(pkt, 0, offset, len, 0, dma_mapped, page,
+                               kvaddr, dma_addr);
+}
+
+/* we've too many pages in the iovec, coalesce to a single page */
+static int qib_user_sdma_coalesce(const struct qib_devdata *dd,
+                                 struct qib_user_sdma_pkt *pkt,
+                                 const struct iovec *iov,
+                                 unsigned long niov)
+{
+       int ret = 0;
+       struct page *page = alloc_page(GFP_KERNEL);
+       void *mpage_save;
+       char *mpage;
+       int i;
+       int len = 0;
+       dma_addr_t dma_addr;
+
+       if (!page) {
+               ret = -ENOMEM;
+               goto done;
+       }
+
+       mpage = kmap(page);
+       mpage_save = mpage;
+       for (i = 0; i < niov; i++) {
+               int cfur;
+
+               cfur = copy_from_user(mpage,
+                                     iov[i].iov_base, iov[i].iov_len);
+               if (cfur) {
+                       ret = -EFAULT;
+                       goto free_unmap;
+               }
+
+               mpage += iov[i].iov_len;
+               len += iov[i].iov_len;
+       }
+
+       dma_addr = dma_map_page(&dd->pcidev->dev, page, 0, len,
+                               DMA_TO_DEVICE);
+       if (dma_mapping_error(&dd->pcidev->dev, dma_addr)) {
+               ret = -ENOMEM;
+               goto free_unmap;
+       }
+
+       qib_user_sdma_init_frag(pkt, 1, 0, len, 0, 1, page, mpage_save,
+                               dma_addr);
+       pkt->naddr = 2;
+
+       goto done;
+
+free_unmap:
+       kunmap(page);
+       __free_page(page);
+done:
+       return ret;
+}
+
+/*
+ * How many pages in this iovec element?
+ */
+static int qib_user_sdma_num_pages(const struct iovec *iov)
+{
+       const unsigned long addr  = (unsigned long) iov->iov_base;
+       const unsigned long  len  = iov->iov_len;
+       const unsigned long spage = addr & PAGE_MASK;
+       const unsigned long epage = (addr + len - 1) & PAGE_MASK;
+
+       return 1 + ((epage - spage) >> PAGE_SHIFT);
+}
+
+/*
+ * Truncate length to page boundry.
+ */
+static int qib_user_sdma_page_length(unsigned long addr, unsigned long len)
+{
+       const unsigned long offset = addr & ~PAGE_MASK;
+
+       return ((offset + len) > PAGE_SIZE) ? (PAGE_SIZE - offset) : len;
+}
+
+static void qib_user_sdma_free_pkt_frag(struct device *dev,
+                                       struct qib_user_sdma_queue *pq,
+                                       struct qib_user_sdma_pkt *pkt,
+                                       int frag)
+{
+       const int i = frag;
+
+       if (pkt->addr[i].page) {
+               if (pkt->addr[i].dma_mapped)
+                       dma_unmap_page(dev,
+                                      pkt->addr[i].addr,
+                                      pkt->addr[i].length,
+                                      DMA_TO_DEVICE);
+
+               if (pkt->addr[i].kvaddr)
+                       kunmap(pkt->addr[i].page);
+
+               if (pkt->addr[i].put_page)
+                       put_page(pkt->addr[i].page);
+               else
+                       __free_page(pkt->addr[i].page);
+       } else if (pkt->addr[i].kvaddr)
+               /* free coherent mem from cache... */
+               dma_pool_free(pq->header_cache,
+                             pkt->addr[i].kvaddr, pkt->addr[i].addr);
+}
+
+/* return number of pages pinned... */
+static int qib_user_sdma_pin_pages(const struct qib_devdata *dd,
+                                  struct qib_user_sdma_pkt *pkt,
+                                  unsigned long addr, int tlen, int npages)
+{
+       struct page *pages[2];
+       int j;
+       int ret;
+
+       ret = get_user_pages(current, current->mm, addr,
+                            npages, 0, 1, pages, NULL);
+
+       if (ret != npages) {
+               int i;
+
+               for (i = 0; i < ret; i++)
+                       put_page(pages[i]);
+
+               ret = -ENOMEM;
+               goto done;
+       }
+
+       for (j = 0; j < npages; j++) {
+               /* map the pages... */
+               const int flen = qib_user_sdma_page_length(addr, tlen);
+               dma_addr_t dma_addr =
+                       dma_map_page(&dd->pcidev->dev,
+                                    pages[j], 0, flen, DMA_TO_DEVICE);
+               unsigned long fofs = addr & ~PAGE_MASK;
+
+               if (dma_mapping_error(&dd->pcidev->dev, dma_addr)) {
+                       ret = -ENOMEM;
+                       goto done;
+               }
+
+               qib_user_sdma_init_frag(pkt, pkt->naddr, fofs, flen, 1, 1,
+                                       pages[j], kmap(pages[j]), dma_addr);
+
+               pkt->naddr++;
+               addr += flen;
+               tlen -= flen;
+       }
+
+done:
+       return ret;
+}
+
+static int qib_user_sdma_pin_pkt(const struct qib_devdata *dd,
+                                struct qib_user_sdma_queue *pq,
+                                struct qib_user_sdma_pkt *pkt,
+                                const struct iovec *iov,
+                                unsigned long niov)
+{
+       int ret = 0;
+       unsigned long idx;
+
+       for (idx = 0; idx < niov; idx++) {
+               const int npages = qib_user_sdma_num_pages(iov + idx);
+               const unsigned long addr = (unsigned long) iov[idx].iov_base;
+
+               ret = qib_user_sdma_pin_pages(dd, pkt, addr,
+                                             iov[idx].iov_len, npages);
+               if (ret < 0)
+                       goto free_pkt;
+       }
+
+       goto done;
+
+free_pkt:
+       for (idx = 0; idx < pkt->naddr; idx++)
+               qib_user_sdma_free_pkt_frag(&dd->pcidev->dev, pq, pkt, idx);
+
+done:
+       return ret;
+}
+
+static int qib_user_sdma_init_payload(const struct qib_devdata *dd,
+                                     struct qib_user_sdma_queue *pq,
+                                     struct qib_user_sdma_pkt *pkt,
+                                     const struct iovec *iov,
+                                     unsigned long niov, int npages)
+{
+       int ret = 0;
+
+       if (npages >= ARRAY_SIZE(pkt->addr))
+               ret = qib_user_sdma_coalesce(dd, pkt, iov, niov);
+       else
+               ret = qib_user_sdma_pin_pkt(dd, pq, pkt, iov, niov);
+
+       return ret;
+}
+
+/* free a packet list -- return counter value of last packet */
+static void qib_user_sdma_free_pkt_list(struct device *dev,
+                                       struct qib_user_sdma_queue *pq,
+                                       struct list_head *list)
+{
+       struct qib_user_sdma_pkt *pkt, *pkt_next;
+
+       list_for_each_entry_safe(pkt, pkt_next, list, list) {
+               int i;
+
+               for (i = 0; i < pkt->naddr; i++)
+                       qib_user_sdma_free_pkt_frag(dev, pq, pkt, i);
+
+               kmem_cache_free(pq->pkt_slab, pkt);
+       }
+}
+
+/*
+ * copy headers, coalesce etc -- pq->lock must be held
+ *
+ * we queue all the packets to list, returning the
+ * number of bytes total.  list must be empty initially,
+ * as, if there is an error we clean it...
+ */
+static int qib_user_sdma_queue_pkts(const struct qib_devdata *dd,
+                                   struct qib_user_sdma_queue *pq,
+                                   struct list_head *list,
+                                   const struct iovec *iov,
+                                   unsigned long niov,
+                                   int maxpkts)
+{
+       unsigned long idx = 0;
+       int ret = 0;
+       int npkts = 0;
+       struct page *page = NULL;
+       __le32 *pbc;
+       dma_addr_t dma_addr;
+       struct qib_user_sdma_pkt *pkt = NULL;
+       size_t len;
+       size_t nw;
+       u32 counter = pq->counter;
+       int dma_mapped = 0;
+
+       while (idx < niov && npkts < maxpkts) {
+               const unsigned long addr = (unsigned long) iov[idx].iov_base;
+               const unsigned long idx_save = idx;
+               unsigned pktnw;
+               unsigned pktnwc;
+               int nfrags = 0;
+               int npages = 0;
+               int cfur;
+
+               dma_mapped = 0;
+               len = iov[idx].iov_len;
+               nw = len >> 2;
+               page = NULL;
+
+               pkt = kmem_cache_alloc(pq->pkt_slab, GFP_KERNEL);
+               if (!pkt) {
+                       ret = -ENOMEM;
+                       goto free_list;
+               }
+
+               if (len < QIB_USER_SDMA_MIN_HEADER_LENGTH ||
+                   len > PAGE_SIZE || len & 3 || addr & 3) {
+                       ret = -EINVAL;
+                       goto free_pkt;
+               }
+
+               if (len == QIB_USER_SDMA_EXP_HEADER_LENGTH)
+                       pbc = dma_pool_alloc(pq->header_cache, GFP_KERNEL,
+                                            &dma_addr);
+               else
+                       pbc = NULL;
+
+               if (!pbc) {
+                       page = alloc_page(GFP_KERNEL);
+                       if (!page) {
+                               ret = -ENOMEM;
+                               goto free_pkt;
+                       }
+                       pbc = kmap(page);
+               }
+
+               cfur = copy_from_user(pbc, iov[idx].iov_base, len);
+               if (cfur) {
+                       ret = -EFAULT;
+                       goto free_pbc;
+               }
+
+               /*
+                * This assignment is a bit strange.  it's because the
+                * the pbc counts the number of 32 bit words in the full
+                * packet _except_ the first word of the pbc itself...
+                */
+               pktnwc = nw - 1;
+
+               /*
+                * pktnw computation yields the number of 32 bit words
+                * that the caller has indicated in the PBC.  note that
+                * this is one less than the total number of words that
+                * goes to the send DMA engine as the first 32 bit word
+                * of the PBC itself is not counted.  Armed with this count,
+                * we can verify that the packet is consistent with the
+                * iovec lengths.
+                */
+               pktnw = le32_to_cpu(*pbc) & QIB_PBC_LENGTH_MASK;
+               if (pktnw < pktnwc || pktnw > pktnwc + (PAGE_SIZE >> 2)) {
+                       ret = -EINVAL;
+                       goto free_pbc;
+               }
+
+               idx++;
+               while (pktnwc < pktnw && idx < niov) {
+                       const size_t slen = iov[idx].iov_len;
+                       const unsigned long faddr =
+                               (unsigned long) iov[idx].iov_base;
+
+                       if (slen & 3 || faddr & 3 || !slen ||
+                           slen > PAGE_SIZE) {
+                               ret = -EINVAL;
+                               goto free_pbc;
+                       }
+
+                       npages++;
+                       if ((faddr & PAGE_MASK) !=
+                           ((faddr + slen - 1) & PAGE_MASK))
+                               npages++;
+
+                       pktnwc += slen >> 2;
+                       idx++;
+                       nfrags++;
+               }
+
+               if (pktnwc != pktnw) {
+                       ret = -EINVAL;
+                       goto free_pbc;
+               }
+
+               if (page) {
+                       dma_addr = dma_map_page(&dd->pcidev->dev,
+                                               page, 0, len, DMA_TO_DEVICE);
+                       if (dma_mapping_error(&dd->pcidev->dev, dma_addr)) {
+                               ret = -ENOMEM;
+                               goto free_pbc;
+                       }
+
+                       dma_mapped = 1;
+               }
+
+               qib_user_sdma_init_header(pkt, counter, 0, len, dma_mapped,
+                                         page, pbc, dma_addr);
+
+               if (nfrags) {
+                       ret = qib_user_sdma_init_payload(dd, pq, pkt,
+                                                        iov + idx_save + 1,
+                                                        nfrags, npages);
+                       if (ret < 0)
+                               goto free_pbc_dma;
+               }
+
+               counter++;
+               npkts++;
+
+               list_add_tail(&pkt->list, list);
+       }
+
+       ret = idx;
+       goto done;
+
+free_pbc_dma:
+       if (dma_mapped)
+               dma_unmap_page(&dd->pcidev->dev, dma_addr, len, DMA_TO_DEVICE);
+free_pbc:
+       if (page) {
+               kunmap(page);
+               __free_page(page);
+       } else
+               dma_pool_free(pq->header_cache, pbc, dma_addr);
+free_pkt:
+       kmem_cache_free(pq->pkt_slab, pkt);
+free_list:
+       qib_user_sdma_free_pkt_list(&dd->pcidev->dev, pq, list);
+done:
+       return ret;
+}
+
+static void qib_user_sdma_set_complete_counter(struct qib_user_sdma_queue *pq,
+                                              u32 c)
+{
+       pq->sent_counter = c;
+}
+
+/* try to clean out queue -- needs pq->lock */
+static int qib_user_sdma_queue_clean(struct qib_pportdata *ppd,
+                                    struct qib_user_sdma_queue *pq)
+{
+       struct qib_devdata *dd = ppd->dd;
+       struct list_head free_list;
+       struct qib_user_sdma_pkt *pkt;
+       struct qib_user_sdma_pkt *pkt_prev;
+       int ret = 0;
+
+       INIT_LIST_HEAD(&free_list);
+
+       list_for_each_entry_safe(pkt, pkt_prev, &pq->sent, list) {
+               s64 descd = ppd->sdma_descq_removed - pkt->added;
+
+               if (descd < 0)
+                       break;
+
+               list_move_tail(&pkt->list, &free_list);
+
+               /* one more packet cleaned */
+               ret++;
+       }
+
+       if (!list_empty(&free_list)) {
+               u32 counter;
+
+               pkt = list_entry(free_list.prev,
+                                struct qib_user_sdma_pkt, list);
+               counter = pkt->counter;
+
+               qib_user_sdma_free_pkt_list(&dd->pcidev->dev, pq, &free_list);
+               qib_user_sdma_set_complete_counter(pq, counter);
+       }
+
+       return ret;
+}
+
+void qib_user_sdma_queue_destroy(struct qib_user_sdma_queue *pq)
+{
+       if (!pq)
+               return;
+
+       kmem_cache_destroy(pq->pkt_slab);
+       dma_pool_destroy(pq->header_cache);
+       kfree(pq);
+}
+
+/* clean descriptor queue, returns > 0 if some elements cleaned */
+static int qib_user_sdma_hwqueue_clean(struct qib_pportdata *ppd)
+{
+       int ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ppd->sdma_lock, flags);
+       ret = qib_sdma_make_progress(ppd);
+       spin_unlock_irqrestore(&ppd->sdma_lock, flags);
+
+       return ret;
+}
+
+/* we're in close, drain packets so that we can cleanup successfully... */
+void qib_user_sdma_queue_drain(struct qib_pportdata *ppd,
+                              struct qib_user_sdma_queue *pq)
+{
+       struct qib_devdata *dd = ppd->dd;
+       int i;
+
+       if (!pq)
+               return;
+
+       for (i = 0; i < QIB_USER_SDMA_DRAIN_TIMEOUT; i++) {
+               mutex_lock(&pq->lock);
+               if (list_empty(&pq->sent)) {
+                       mutex_unlock(&pq->lock);
+                       break;
+               }
+               qib_user_sdma_hwqueue_clean(ppd);
+               qib_user_sdma_queue_clean(ppd, pq);
+               mutex_unlock(&pq->lock);
+               msleep(10);
+       }
+
+       if (!list_empty(&pq->sent)) {
+               struct list_head free_list;
+
+               qib_dev_err(dd, "user sdma lists not empty: forcing!\n");
+               INIT_LIST_HEAD(&free_list);
+               mutex_lock(&pq->lock);
+               list_splice_init(&pq->sent, &free_list);
+               qib_user_sdma_free_pkt_list(&dd->pcidev->dev, pq, &free_list);
+               mutex_unlock(&pq->lock);
+       }
+}
+
+static inline __le64 qib_sdma_make_desc0(struct qib_pportdata *ppd,
+                                        u64 addr, u64 dwlen, u64 dwoffset)
+{
+       u8 tmpgen;
+
+       tmpgen = ppd->sdma_generation;
+
+       return cpu_to_le64(/* SDmaPhyAddr[31:0] */
+                          ((addr & 0xfffffffcULL) << 32) |
+                          /* SDmaGeneration[1:0] */
+                          ((tmpgen & 3ULL) << 30) |
+                          /* SDmaDwordCount[10:0] */
+                          ((dwlen & 0x7ffULL) << 16) |
+                          /* SDmaBufOffset[12:2] */
+                          (dwoffset & 0x7ffULL));
+}
+
+static inline __le64 qib_sdma_make_first_desc0(__le64 descq)
+{
+       return descq | cpu_to_le64(1ULL << 12);
+}
+
+static inline __le64 qib_sdma_make_last_desc0(__le64 descq)
+{
+                                             /* last */  /* dma head */
+       return descq | cpu_to_le64(1ULL << 11 | 1ULL << 13);
+}
+
+static inline __le64 qib_sdma_make_desc1(u64 addr)
+{
+       /* SDmaPhyAddr[47:32] */
+       return cpu_to_le64(addr >> 32);
+}
+
+static void qib_user_sdma_send_frag(struct qib_pportdata *ppd,
+                                   struct qib_user_sdma_pkt *pkt, int idx,
+                                   unsigned ofs, u16 tail)
+{
+       const u64 addr = (u64) pkt->addr[idx].addr +
+               (u64) pkt->addr[idx].offset;
+       const u64 dwlen = (u64) pkt->addr[idx].length / 4;
+       __le64 *descqp;
+       __le64 descq0;
+
+       descqp = &ppd->sdma_descq[tail].qw[0];
+
+       descq0 = qib_sdma_make_desc0(ppd, addr, dwlen, ofs);
+       if (idx == 0)
+               descq0 = qib_sdma_make_first_desc0(descq0);
+       if (idx == pkt->naddr - 1)
+               descq0 = qib_sdma_make_last_desc0(descq0);
+
+       descqp[0] = descq0;
+       descqp[1] = qib_sdma_make_desc1(addr);
+}
+
+/* pq->lock must be held, get packets on the wire... */
+static int qib_user_sdma_push_pkts(struct qib_pportdata *ppd,
+                                  struct qib_user_sdma_queue *pq,
+                                  struct list_head *pktlist)
+{
+       struct qib_devdata *dd = ppd->dd;
+       int ret = 0;
+       unsigned long flags;
+       u16 tail;
+       u8 generation;
+       u64 descq_added;
+
+       if (list_empty(pktlist))
+               return 0;
+
+       if (unlikely(!(ppd->lflags & QIBL_LINKACTIVE)))
+               return -ECOMM;
+
+       spin_lock_irqsave(&ppd->sdma_lock, flags);
+
+       /* keep a copy for restoring purposes in case of problems */
+       generation = ppd->sdma_generation;
+       descq_added = ppd->sdma_descq_added;
+
+       if (unlikely(!__qib_sdma_running(ppd))) {
+               ret = -ECOMM;
+               goto unlock;
+       }
+
+       tail = ppd->sdma_descq_tail;
+       while (!list_empty(pktlist)) {
+               struct qib_user_sdma_pkt *pkt =
+                       list_entry(pktlist->next, struct qib_user_sdma_pkt,
+                                  list);
+               int i;
+               unsigned ofs = 0;
+               u16 dtail = tail;
+
+               if (pkt->naddr > qib_sdma_descq_freecnt(ppd))
+                       goto unlock_check_tail;
+
+               for (i = 0; i < pkt->naddr; i++) {
+                       qib_user_sdma_send_frag(ppd, pkt, i, ofs, tail);
+                       ofs += pkt->addr[i].length >> 2;
+
+                       if (++tail == ppd->sdma_descq_cnt) {
+                               tail = 0;
+                               ++ppd->sdma_generation;
+                       }
+               }
+
+               if ((ofs << 2) > ppd->ibmaxlen) {
+                       ret = -EMSGSIZE;
+                       goto unlock;
+               }
+
+               /*
+                * If the packet is >= 2KB mtu equivalent, we have to use
+                * the large buffers, and have to mark each descriptor as
+                * part of a large buffer packet.
+                */
+               if (ofs > dd->piosize2kmax_dwords) {
+                       for (i = 0; i < pkt->naddr; i++) {
+                               ppd->sdma_descq[dtail].qw[0] |=
+                                       cpu_to_le64(1ULL << 14);
+                               if (++dtail == ppd->sdma_descq_cnt)
+                                       dtail = 0;
+                       }
+               }
+
+               ppd->sdma_descq_added += pkt->naddr;
+               pkt->added = ppd->sdma_descq_added;
+               list_move_tail(&pkt->list, &pq->sent);
+               ret++;
+       }
+
+unlock_check_tail:
+       /* advance the tail on the chip if necessary */
+       if (ppd->sdma_descq_tail != tail)
+               dd->f_sdma_update_tail(ppd, tail);
+
+unlock:
+       if (unlikely(ret < 0)) {
+               ppd->sdma_generation = generation;
+               ppd->sdma_descq_added = descq_added;
+       }
+       spin_unlock_irqrestore(&ppd->sdma_lock, flags);
+
+       return ret;
+}
+
+int qib_user_sdma_writev(struct qib_ctxtdata *rcd,
+                        struct qib_user_sdma_queue *pq,
+                        const struct iovec *iov,
+                        unsigned long dim)
+{
+       struct qib_devdata *dd = rcd->dd;
+       struct qib_pportdata *ppd = rcd->ppd;
+       int ret = 0;
+       struct list_head list;
+       int npkts = 0;
+
+       INIT_LIST_HEAD(&list);
+
+       mutex_lock(&pq->lock);
+
+       /* why not -ECOMM like qib_user_sdma_push_pkts() below? */
+       if (!qib_sdma_running(ppd))
+               goto done_unlock;
+
+       if (ppd->sdma_descq_added != ppd->sdma_descq_removed) {
+               qib_user_sdma_hwqueue_clean(ppd);
+               qib_user_sdma_queue_clean(ppd, pq);
+       }
+
+       while (dim) {
+               const int mxp = 8;
+
+               down_write(&current->mm->mmap_sem);
+               ret = qib_user_sdma_queue_pkts(dd, pq, &list, iov, dim, mxp);
+               up_write(&current->mm->mmap_sem);
+
+               if (ret <= 0)
+                       goto done_unlock;
+               else {
+                       dim -= ret;
+                       iov += ret;
+               }
+
+               /* force packets onto the sdma hw queue... */
+               if (!list_empty(&list)) {
+                       /*
+                        * Lazily clean hw queue.  the 4 is a guess of about
+                        * how many sdma descriptors a packet will take (it
+                        * doesn't have to be perfect).
+                        */
+                       if (qib_sdma_descq_freecnt(ppd) < ret * 4) {
+                               qib_user_sdma_hwqueue_clean(ppd);
+                               qib_user_sdma_queue_clean(ppd, pq);
+                       }
+
+                       ret = qib_user_sdma_push_pkts(ppd, pq, &list);
+                       if (ret < 0)
+                               goto done_unlock;
+                       else {
+                               npkts += ret;
+                               pq->counter += ret;
+
+                               if (!list_empty(&list))
+                                       goto done_unlock;
+                       }
+               }
+       }
+
+done_unlock:
+       if (!list_empty(&list))
+               qib_user_sdma_free_pkt_list(&dd->pcidev->dev, pq, &list);
+       mutex_unlock(&pq->lock);
+
+       return (ret < 0) ? ret : npkts;
+}
+
+int qib_user_sdma_make_progress(struct qib_pportdata *ppd,
+                               struct qib_user_sdma_queue *pq)
+{
+       int ret = 0;
+
+       mutex_lock(&pq->lock);
+       qib_user_sdma_hwqueue_clean(ppd);
+       ret = qib_user_sdma_queue_clean(ppd, pq);
+       mutex_unlock(&pq->lock);
+
+       return ret;
+}
+
+u32 qib_user_sdma_complete_counter(const struct qib_user_sdma_queue *pq)
+{
+       return pq ? pq->sent_counter : 0;
+}
+
+u32 qib_user_sdma_inflight_counter(struct qib_user_sdma_queue *pq)
+{
+       return pq ? pq->counter : 0;
+}
diff --git a/drivers/infiniband/hw/qib/qib_user_sdma.h b/drivers/infiniband/hw/qib/qib_user_sdma.h
new file mode 100644 (file)
index 0000000..ce8cbaf
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2007, 2008 QLogic Corporation. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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/device.h>
+
+struct qib_user_sdma_queue;
+
+struct qib_user_sdma_queue *
+qib_user_sdma_queue_create(struct device *dev, int unit, int port, int sport);
+void qib_user_sdma_queue_destroy(struct qib_user_sdma_queue *pq);
+
+int qib_user_sdma_writev(struct qib_ctxtdata *pd,
+                        struct qib_user_sdma_queue *pq,
+                        const struct iovec *iov,
+                        unsigned long dim);
+
+int qib_user_sdma_make_progress(struct qib_pportdata *ppd,
+                               struct qib_user_sdma_queue *pq);
+
+void qib_user_sdma_queue_drain(struct qib_pportdata *ppd,
+                              struct qib_user_sdma_queue *pq);
+
+u32 qib_user_sdma_complete_counter(const struct qib_user_sdma_queue *pq);
+u32 qib_user_sdma_inflight_counter(struct qib_user_sdma_queue *pq);
diff --git a/drivers/infiniband/hw/qib/qib_verbs.c b/drivers/infiniband/hw/qib/qib_verbs.c
new file mode 100644 (file)
index 0000000..cda8f41
--- /dev/null
@@ -0,0 +1,2248 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009, 2010 QLogic Corporation.
+ * All rights reserved.
+ * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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 <rdma/ib_mad.h>
+#include <rdma/ib_user_verbs.h>
+#include <linux/io.h>
+#include <linux/utsname.h>
+#include <linux/rculist.h>
+#include <linux/mm.h>
+
+#include "qib.h"
+#include "qib_common.h"
+
+static unsigned int ib_qib_qp_table_size = 251;
+module_param_named(qp_table_size, ib_qib_qp_table_size, uint, S_IRUGO);
+MODULE_PARM_DESC(qp_table_size, "QP table size");
+
+unsigned int ib_qib_lkey_table_size = 16;
+module_param_named(lkey_table_size, ib_qib_lkey_table_size, uint,
+                  S_IRUGO);
+MODULE_PARM_DESC(lkey_table_size,
+                "LKEY table size in bits (2^n, 1 <= n <= 23)");
+
+static unsigned int ib_qib_max_pds = 0xFFFF;
+module_param_named(max_pds, ib_qib_max_pds, uint, S_IRUGO);
+MODULE_PARM_DESC(max_pds,
+                "Maximum number of protection domains to support");
+
+static unsigned int ib_qib_max_ahs = 0xFFFF;
+module_param_named(max_ahs, ib_qib_max_ahs, uint, S_IRUGO);
+MODULE_PARM_DESC(max_ahs, "Maximum number of address handles to support");
+
+unsigned int ib_qib_max_cqes = 0x2FFFF;
+module_param_named(max_cqes, ib_qib_max_cqes, uint, S_IRUGO);
+MODULE_PARM_DESC(max_cqes,
+                "Maximum number of completion queue entries to support");
+
+unsigned int ib_qib_max_cqs = 0x1FFFF;
+module_param_named(max_cqs, ib_qib_max_cqs, uint, S_IRUGO);
+MODULE_PARM_DESC(max_cqs, "Maximum number of completion queues to support");
+
+unsigned int ib_qib_max_qp_wrs = 0x3FFF;
+module_param_named(max_qp_wrs, ib_qib_max_qp_wrs, uint, S_IRUGO);
+MODULE_PARM_DESC(max_qp_wrs, "Maximum number of QP WRs to support");
+
+unsigned int ib_qib_max_qps = 16384;
+module_param_named(max_qps, ib_qib_max_qps, uint, S_IRUGO);
+MODULE_PARM_DESC(max_qps, "Maximum number of QPs to support");
+
+unsigned int ib_qib_max_sges = 0x60;
+module_param_named(max_sges, ib_qib_max_sges, uint, S_IRUGO);
+MODULE_PARM_DESC(max_sges, "Maximum number of SGEs to support");
+
+unsigned int ib_qib_max_mcast_grps = 16384;
+module_param_named(max_mcast_grps, ib_qib_max_mcast_grps, uint, S_IRUGO);
+MODULE_PARM_DESC(max_mcast_grps,
+                "Maximum number of multicast groups to support");
+
+unsigned int ib_qib_max_mcast_qp_attached = 16;
+module_param_named(max_mcast_qp_attached, ib_qib_max_mcast_qp_attached,
+                  uint, S_IRUGO);
+MODULE_PARM_DESC(max_mcast_qp_attached,
+                "Maximum number of attached QPs to support");
+
+unsigned int ib_qib_max_srqs = 1024;
+module_param_named(max_srqs, ib_qib_max_srqs, uint, S_IRUGO);
+MODULE_PARM_DESC(max_srqs, "Maximum number of SRQs to support");
+
+unsigned int ib_qib_max_srq_sges = 128;
+module_param_named(max_srq_sges, ib_qib_max_srq_sges, uint, S_IRUGO);
+MODULE_PARM_DESC(max_srq_sges, "Maximum number of SRQ SGEs to support");
+
+unsigned int ib_qib_max_srq_wrs = 0x1FFFF;
+module_param_named(max_srq_wrs, ib_qib_max_srq_wrs, uint, S_IRUGO);
+MODULE_PARM_DESC(max_srq_wrs, "Maximum number of SRQ WRs support");
+
+static unsigned int ib_qib_disable_sma;
+module_param_named(disable_sma, ib_qib_disable_sma, uint, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(disable_sma, "Disable the SMA");
+
+/*
+ * Note that it is OK to post send work requests in the SQE and ERR
+ * states; qib_do_send() will process them and generate error
+ * completions as per IB 1.2 C10-96.
+ */
+const int ib_qib_state_ops[IB_QPS_ERR + 1] = {
+       [IB_QPS_RESET] = 0,
+       [IB_QPS_INIT] = QIB_POST_RECV_OK,
+       [IB_QPS_RTR] = QIB_POST_RECV_OK | QIB_PROCESS_RECV_OK,
+       [IB_QPS_RTS] = QIB_POST_RECV_OK | QIB_PROCESS_RECV_OK |
+           QIB_POST_SEND_OK | QIB_PROCESS_SEND_OK |
+           QIB_PROCESS_NEXT_SEND_OK,
+       [IB_QPS_SQD] = QIB_POST_RECV_OK | QIB_PROCESS_RECV_OK |
+           QIB_POST_SEND_OK | QIB_PROCESS_SEND_OK,
+       [IB_QPS_SQE] = QIB_POST_RECV_OK | QIB_PROCESS_RECV_OK |
+           QIB_POST_SEND_OK | QIB_FLUSH_SEND,
+       [IB_QPS_ERR] = QIB_POST_RECV_OK | QIB_FLUSH_RECV |
+           QIB_POST_SEND_OK | QIB_FLUSH_SEND,
+};
+
+struct qib_ucontext {
+       struct ib_ucontext ibucontext;
+};
+
+static inline struct qib_ucontext *to_iucontext(struct ib_ucontext
+                                                 *ibucontext)
+{
+       return container_of(ibucontext, struct qib_ucontext, ibucontext);
+}
+
+/*
+ * Translate ib_wr_opcode into ib_wc_opcode.
+ */
+const enum ib_wc_opcode ib_qib_wc_opcode[] = {
+       [IB_WR_RDMA_WRITE] = IB_WC_RDMA_WRITE,
+       [IB_WR_RDMA_WRITE_WITH_IMM] = IB_WC_RDMA_WRITE,
+       [IB_WR_SEND] = IB_WC_SEND,
+       [IB_WR_SEND_WITH_IMM] = IB_WC_SEND,
+       [IB_WR_RDMA_READ] = IB_WC_RDMA_READ,
+       [IB_WR_ATOMIC_CMP_AND_SWP] = IB_WC_COMP_SWAP,
+       [IB_WR_ATOMIC_FETCH_AND_ADD] = IB_WC_FETCH_ADD
+};
+
+/*
+ * System image GUID.
+ */
+__be64 ib_qib_sys_image_guid;
+
+/**
+ * qib_copy_sge - copy data to SGE memory
+ * @ss: the SGE state
+ * @data: the data to copy
+ * @length: the length of the data
+ */
+void qib_copy_sge(struct qib_sge_state *ss, void *data, u32 length, int release)
+{
+       struct qib_sge *sge = &ss->sge;
+
+       while (length) {
+               u32 len = sge->length;
+
+               if (len > length)
+                       len = length;
+               if (len > sge->sge_length)
+                       len = sge->sge_length;
+               BUG_ON(len == 0);
+               memcpy(sge->vaddr, data, len);
+               sge->vaddr += len;
+               sge->length -= len;
+               sge->sge_length -= len;
+               if (sge->sge_length == 0) {
+                       if (release)
+                               atomic_dec(&sge->mr->refcount);
+                       if (--ss->num_sge)
+                               *sge = *ss->sg_list++;
+               } else if (sge->length == 0 && sge->mr->lkey) {
+                       if (++sge->n >= QIB_SEGSZ) {
+                               if (++sge->m >= sge->mr->mapsz)
+                                       break;
+                               sge->n = 0;
+                       }
+                       sge->vaddr =
+                               sge->mr->map[sge->m]->segs[sge->n].vaddr;
+                       sge->length =
+                               sge->mr->map[sge->m]->segs[sge->n].length;
+               }
+               data += len;
+               length -= len;
+       }
+}
+
+/**
+ * qib_skip_sge - skip over SGE memory - XXX almost dup of prev func
+ * @ss: the SGE state
+ * @length: the number of bytes to skip
+ */
+void qib_skip_sge(struct qib_sge_state *ss, u32 length, int release)
+{
+       struct qib_sge *sge = &ss->sge;
+
+       while (length) {
+               u32 len = sge->length;
+
+               if (len > length)
+                       len = length;
+               if (len > sge->sge_length)
+                       len = sge->sge_length;
+               BUG_ON(len == 0);
+               sge->vaddr += len;
+               sge->length -= len;
+               sge->sge_length -= len;
+               if (sge->sge_length == 0) {
+                       if (release)
+                               atomic_dec(&sge->mr->refcount);
+                       if (--ss->num_sge)
+                               *sge = *ss->sg_list++;
+               } else if (sge->length == 0 && sge->mr->lkey) {
+                       if (++sge->n >= QIB_SEGSZ) {
+                               if (++sge->m >= sge->mr->mapsz)
+                                       break;
+                               sge->n = 0;
+                       }
+                       sge->vaddr =
+                               sge->mr->map[sge->m]->segs[sge->n].vaddr;
+                       sge->length =
+                               sge->mr->map[sge->m]->segs[sge->n].length;
+               }
+               length -= len;
+       }
+}
+
+/*
+ * Count the number of DMA descriptors needed to send length bytes of data.
+ * Don't modify the qib_sge_state to get the count.
+ * Return zero if any of the segments is not aligned.
+ */
+static u32 qib_count_sge(struct qib_sge_state *ss, u32 length)
+{
+       struct qib_sge *sg_list = ss->sg_list;
+       struct qib_sge sge = ss->sge;
+       u8 num_sge = ss->num_sge;
+       u32 ndesc = 1;  /* count the header */
+
+       while (length) {
+               u32 len = sge.length;
+
+               if (len > length)
+                       len = length;
+               if (len > sge.sge_length)
+                       len = sge.sge_length;
+               BUG_ON(len == 0);
+               if (((long) sge.vaddr & (sizeof(u32) - 1)) ||
+                   (len != length && (len & (sizeof(u32) - 1)))) {
+                       ndesc = 0;
+                       break;
+               }
+               ndesc++;
+               sge.vaddr += len;
+               sge.length -= len;
+               sge.sge_length -= len;
+               if (sge.sge_length == 0) {
+                       if (--num_sge)
+                               sge = *sg_list++;
+               } else if (sge.length == 0 && sge.mr->lkey) {
+                       if (++sge.n >= QIB_SEGSZ) {
+                               if (++sge.m >= sge.mr->mapsz)
+                                       break;
+                               sge.n = 0;
+                       }
+                       sge.vaddr =
+                               sge.mr->map[sge.m]->segs[sge.n].vaddr;
+                       sge.length =
+                               sge.mr->map[sge.m]->segs[sge.n].length;
+               }
+               length -= len;
+       }
+       return ndesc;
+}
+
+/*
+ * Copy from the SGEs to the data buffer.
+ */
+static void qib_copy_from_sge(void *data, struct qib_sge_state *ss, u32 length)
+{
+       struct qib_sge *sge = &ss->sge;
+
+       while (length) {
+               u32 len = sge->length;
+
+               if (len > length)
+                       len = length;
+               if (len > sge->sge_length)
+                       len = sge->sge_length;
+               BUG_ON(len == 0);
+               memcpy(data, sge->vaddr, len);
+               sge->vaddr += len;
+               sge->length -= len;
+               sge->sge_length -= len;
+               if (sge->sge_length == 0) {
+                       if (--ss->num_sge)
+                               *sge = *ss->sg_list++;
+               } else if (sge->length == 0 && sge->mr->lkey) {
+                       if (++sge->n >= QIB_SEGSZ) {
+                               if (++sge->m >= sge->mr->mapsz)
+                                       break;
+                               sge->n = 0;
+                       }
+                       sge->vaddr =
+                               sge->mr->map[sge->m]->segs[sge->n].vaddr;
+                       sge->length =
+                               sge->mr->map[sge->m]->segs[sge->n].length;
+               }
+               data += len;
+               length -= len;
+       }
+}
+
+/**
+ * qib_post_one_send - post one RC, UC, or UD send work request
+ * @qp: the QP to post on
+ * @wr: the work request to send
+ */
+static int qib_post_one_send(struct qib_qp *qp, struct ib_send_wr *wr)
+{
+       struct qib_swqe *wqe;
+       u32 next;
+       int i;
+       int j;
+       int acc;
+       int ret;
+       unsigned long flags;
+       struct qib_lkey_table *rkt;
+       struct qib_pd *pd;
+
+       spin_lock_irqsave(&qp->s_lock, flags);
+
+       /* Check that state is OK to post send. */
+       if (unlikely(!(ib_qib_state_ops[qp->state] & QIB_POST_SEND_OK)))
+               goto bail_inval;
+
+       /* IB spec says that num_sge == 0 is OK. */
+       if (wr->num_sge > qp->s_max_sge)
+               goto bail_inval;
+
+       /*
+        * Don't allow RDMA reads or atomic operations on UC or
+        * undefined operations.
+        * Make sure buffer is large enough to hold the result for atomics.
+        */
+       if (wr->opcode == IB_WR_FAST_REG_MR) {
+               if (qib_fast_reg_mr(qp, wr))
+                       goto bail_inval;
+       } else if (qp->ibqp.qp_type == IB_QPT_UC) {
+               if ((unsigned) wr->opcode >= IB_WR_RDMA_READ)
+                       goto bail_inval;
+       } else if (qp->ibqp.qp_type != IB_QPT_RC) {
+               /* Check IB_QPT_SMI, IB_QPT_GSI, IB_QPT_UD opcode */
+               if (wr->opcode != IB_WR_SEND &&
+                   wr->opcode != IB_WR_SEND_WITH_IMM)
+                       goto bail_inval;
+               /* Check UD destination address PD */
+               if (qp->ibqp.pd != wr->wr.ud.ah->pd)
+                       goto bail_inval;
+       } else if ((unsigned) wr->opcode > IB_WR_ATOMIC_FETCH_AND_ADD)
+               goto bail_inval;
+       else if (wr->opcode >= IB_WR_ATOMIC_CMP_AND_SWP &&
+                  (wr->num_sge == 0 ||
+                   wr->sg_list[0].length < sizeof(u64) ||
+                   wr->sg_list[0].addr & (sizeof(u64) - 1)))
+               goto bail_inval;
+       else if (wr->opcode >= IB_WR_RDMA_READ && !qp->s_max_rd_atomic)
+               goto bail_inval;
+
+       next = qp->s_head + 1;
+       if (next >= qp->s_size)
+               next = 0;
+       if (next == qp->s_last) {
+               ret = -ENOMEM;
+               goto bail;
+       }
+
+       rkt = &to_idev(qp->ibqp.device)->lk_table;
+       pd = to_ipd(qp->ibqp.pd);
+       wqe = get_swqe_ptr(qp, qp->s_head);
+       wqe->wr = *wr;
+       wqe->length = 0;
+       j = 0;
+       if (wr->num_sge) {
+               acc = wr->opcode >= IB_WR_RDMA_READ ?
+                       IB_ACCESS_LOCAL_WRITE : 0;
+               for (i = 0; i < wr->num_sge; i++) {
+                       u32 length = wr->sg_list[i].length;
+                       int ok;
+
+                       if (length == 0)
+                               continue;
+                       ok = qib_lkey_ok(rkt, pd, &wqe->sg_list[j],
+                                        &wr->sg_list[i], acc);
+                       if (!ok)
+                               goto bail_inval_free;
+                       wqe->length += length;
+                       j++;
+               }
+               wqe->wr.num_sge = j;
+       }
+       if (qp->ibqp.qp_type == IB_QPT_UC ||
+           qp->ibqp.qp_type == IB_QPT_RC) {
+               if (wqe->length > 0x80000000U)
+                       goto bail_inval_free;
+       } else if (wqe->length > (dd_from_ibdev(qp->ibqp.device)->pport +
+                                 qp->port_num - 1)->ibmtu)
+               goto bail_inval_free;
+       else
+               atomic_inc(&to_iah(wr->wr.ud.ah)->refcount);
+       wqe->ssn = qp->s_ssn++;
+       qp->s_head = next;
+
+       ret = 0;
+       goto bail;
+
+bail_inval_free:
+       while (j) {
+               struct qib_sge *sge = &wqe->sg_list[--j];
+
+               atomic_dec(&sge->mr->refcount);
+       }
+bail_inval:
+       ret = -EINVAL;
+bail:
+       spin_unlock_irqrestore(&qp->s_lock, flags);
+       return ret;
+}
+
+/**
+ * qib_post_send - post a send on a QP
+ * @ibqp: the QP to post the send on
+ * @wr: the list of work requests to post
+ * @bad_wr: the first bad WR is put here
+ *
+ * This may be called from interrupt context.
+ */
+static int qib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
+                        struct ib_send_wr **bad_wr)
+{
+       struct qib_qp *qp = to_iqp(ibqp);
+       int err = 0;
+
+       for (; wr; wr = wr->next) {
+               err = qib_post_one_send(qp, wr);
+               if (err) {
+                       *bad_wr = wr;
+                       goto bail;
+               }
+       }
+
+       /* Try to do the send work in the caller's context. */
+       qib_do_send(&qp->s_work);
+
+bail:
+       return err;
+}
+
+/**
+ * qib_post_receive - post a receive on a QP
+ * @ibqp: the QP to post the receive on
+ * @wr: the WR to post
+ * @bad_wr: the first bad WR is put here
+ *
+ * This may be called from interrupt context.
+ */
+static int qib_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
+                           struct ib_recv_wr **bad_wr)
+{
+       struct qib_qp *qp = to_iqp(ibqp);
+       struct qib_rwq *wq = qp->r_rq.wq;
+       unsigned long flags;
+       int ret;
+
+       /* Check that state is OK to post receive. */
+       if (!(ib_qib_state_ops[qp->state] & QIB_POST_RECV_OK) || !wq) {
+               *bad_wr = wr;
+               ret = -EINVAL;
+               goto bail;
+       }
+
+       for (; wr; wr = wr->next) {
+               struct qib_rwqe *wqe;
+               u32 next;
+               int i;
+
+               if ((unsigned) wr->num_sge > qp->r_rq.max_sge) {
+                       *bad_wr = wr;
+                       ret = -EINVAL;
+                       goto bail;
+               }
+
+               spin_lock_irqsave(&qp->r_rq.lock, flags);
+               next = wq->head + 1;
+               if (next >= qp->r_rq.size)
+                       next = 0;
+               if (next == wq->tail) {
+                       spin_unlock_irqrestore(&qp->r_rq.lock, flags);
+                       *bad_wr = wr;
+                       ret = -ENOMEM;
+                       goto bail;
+               }
+
+               wqe = get_rwqe_ptr(&qp->r_rq, wq->head);
+               wqe->wr_id = wr->wr_id;
+               wqe->num_sge = wr->num_sge;
+               for (i = 0; i < wr->num_sge; i++)
+                       wqe->sg_list[i] = wr->sg_list[i];
+               /* Make sure queue entry is written before the head index. */
+               smp_wmb();
+               wq->head = next;
+               spin_unlock_irqrestore(&qp->r_rq.lock, flags);
+       }
+       ret = 0;
+
+bail:
+       return ret;
+}
+
+/**
+ * qib_qp_rcv - processing an incoming packet on a QP
+ * @rcd: the context pointer
+ * @hdr: the packet header
+ * @has_grh: true if the packet has a GRH
+ * @data: the packet data
+ * @tlen: the packet length
+ * @qp: the QP the packet came on
+ *
+ * This is called from qib_ib_rcv() to process an incoming packet
+ * for the given QP.
+ * Called at interrupt level.
+ */
+static void qib_qp_rcv(struct qib_ctxtdata *rcd, struct qib_ib_header *hdr,
+                      int has_grh, void *data, u32 tlen, struct qib_qp *qp)
+{
+       struct qib_ibport *ibp = &rcd->ppd->ibport_data;
+
+       /* Check for valid receive state. */
+       if (!(ib_qib_state_ops[qp->state] & QIB_PROCESS_RECV_OK)) {
+               ibp->n_pkt_drops++;
+               return;
+       }
+
+       switch (qp->ibqp.qp_type) {
+       case IB_QPT_SMI:
+       case IB_QPT_GSI:
+               if (ib_qib_disable_sma)
+                       break;
+               /* FALLTHROUGH */
+       case IB_QPT_UD:
+               qib_ud_rcv(ibp, hdr, has_grh, data, tlen, qp);
+               break;
+
+       case IB_QPT_RC:
+               qib_rc_rcv(rcd, hdr, has_grh, data, tlen, qp);
+               break;
+
+       case IB_QPT_UC:
+               qib_uc_rcv(ibp, hdr, has_grh, data, tlen, qp);
+               break;
+
+       default:
+               break;
+       }
+}
+
+/**
+ * qib_ib_rcv - process an incoming packet
+ * @rcd: the context pointer
+ * @rhdr: the header of the packet
+ * @data: the packet payload
+ * @tlen: the packet length
+ *
+ * This is called from qib_kreceive() to process an incoming packet at
+ * interrupt level. Tlen is the length of the header + data + CRC in bytes.
+ */
+void qib_ib_rcv(struct qib_ctxtdata *rcd, void *rhdr, void *data, u32 tlen)
+{
+       struct qib_pportdata *ppd = rcd->ppd;
+       struct qib_ibport *ibp = &ppd->ibport_data;
+       struct qib_ib_header *hdr = rhdr;
+       struct qib_other_headers *ohdr;
+       struct qib_qp *qp;
+       u32 qp_num;
+       int lnh;
+       u8 opcode;
+       u16 lid;
+
+       /* 24 == LRH+BTH+CRC */
+       if (unlikely(tlen < 24))
+               goto drop;
+
+       /* Check for a valid destination LID (see ch. 7.11.1). */
+       lid = be16_to_cpu(hdr->lrh[1]);
+       if (lid < QIB_MULTICAST_LID_BASE) {
+               lid &= ~((1 << ppd->lmc) - 1);
+               if (unlikely(lid != ppd->lid))
+                       goto drop;
+       }
+
+       /* Check for GRH */
+       lnh = be16_to_cpu(hdr->lrh[0]) & 3;
+       if (lnh == QIB_LRH_BTH)
+               ohdr = &hdr->u.oth;
+       else if (lnh == QIB_LRH_GRH) {
+               u32 vtf;
+
+               ohdr = &hdr->u.l.oth;
+               if (hdr->u.l.grh.next_hdr != IB_GRH_NEXT_HDR)
+                       goto drop;
+               vtf = be32_to_cpu(hdr->u.l.grh.version_tclass_flow);
+               if ((vtf >> IB_GRH_VERSION_SHIFT) != IB_GRH_VERSION)
+                       goto drop;
+       } else
+               goto drop;
+
+       opcode = be32_to_cpu(ohdr->bth[0]) >> 24;
+       ibp->opstats[opcode & 0x7f].n_bytes += tlen;
+       ibp->opstats[opcode & 0x7f].n_packets++;
+
+       /* Get the destination QP number. */
+       qp_num = be32_to_cpu(ohdr->bth[1]) & QIB_QPN_MASK;
+       if (qp_num == QIB_MULTICAST_QPN) {
+               struct qib_mcast *mcast;
+               struct qib_mcast_qp *p;
+
+               if (lnh != QIB_LRH_GRH)
+                       goto drop;
+               mcast = qib_mcast_find(ibp, &hdr->u.l.grh.dgid);
+               if (mcast == NULL)
+                       goto drop;
+               ibp->n_multicast_rcv++;
+               list_for_each_entry_rcu(p, &mcast->qp_list, list)
+                       qib_qp_rcv(rcd, hdr, 1, data, tlen, p->qp);
+               /*
+                * Notify qib_multicast_detach() if it is waiting for us
+                * to finish.
+                */
+               if (atomic_dec_return(&mcast->refcount) <= 1)
+                       wake_up(&mcast->wait);
+       } else {
+               qp = qib_lookup_qpn(ibp, qp_num);
+               if (!qp)
+                       goto drop;
+               ibp->n_unicast_rcv++;
+               qib_qp_rcv(rcd, hdr, lnh == QIB_LRH_GRH, data, tlen, qp);
+               /*
+                * Notify qib_destroy_qp() if it is waiting
+                * for us to finish.
+                */
+               if (atomic_dec_and_test(&qp->refcount))
+                       wake_up(&qp->wait);
+       }
+       return;
+
+drop:
+       ibp->n_pkt_drops++;
+}
+
+/*
+ * This is called from a timer to check for QPs
+ * which need kernel memory in order to send a packet.
+ */
+static void mem_timer(unsigned long data)
+{
+       struct qib_ibdev *dev = (struct qib_ibdev *) data;
+       struct list_head *list = &dev->memwait;
+       struct qib_qp *qp = NULL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->pending_lock, flags);
+       if (!list_empty(list)) {
+               qp = list_entry(list->next, struct qib_qp, iowait);
+               list_del_init(&qp->iowait);
+               atomic_inc(&qp->refcount);
+               if (!list_empty(list))
+                       mod_timer(&dev->mem_timer, jiffies + 1);
+       }
+       spin_unlock_irqrestore(&dev->pending_lock, flags);
+
+       if (qp) {
+               spin_lock_irqsave(&qp->s_lock, flags);
+               if (qp->s_flags & QIB_S_WAIT_KMEM) {
+                       qp->s_flags &= ~QIB_S_WAIT_KMEM;
+                       qib_schedule_send(qp);
+               }
+               spin_unlock_irqrestore(&qp->s_lock, flags);
+               if (atomic_dec_and_test(&qp->refcount))
+                       wake_up(&qp->wait);
+       }
+}
+
+static void update_sge(struct qib_sge_state *ss, u32 length)
+{
+       struct qib_sge *sge = &ss->sge;
+
+       sge->vaddr += length;
+       sge->length -= length;
+       sge->sge_length -= length;
+       if (sge->sge_length == 0) {
+               if (--ss->num_sge)
+                       *sge = *ss->sg_list++;
+       } else if (sge->length == 0 && sge->mr->lkey) {
+               if (++sge->n >= QIB_SEGSZ) {
+                       if (++sge->m >= sge->mr->mapsz)
+                               return;
+                       sge->n = 0;
+               }
+               sge->vaddr = sge->mr->map[sge->m]->segs[sge->n].vaddr;
+               sge->length = sge->mr->map[sge->m]->segs[sge->n].length;
+       }
+}
+
+#ifdef __LITTLE_ENDIAN
+static inline u32 get_upper_bits(u32 data, u32 shift)
+{
+       return data >> shift;
+}
+
+static inline u32 set_upper_bits(u32 data, u32 shift)
+{
+       return data << shift;
+}
+
+static inline u32 clear_upper_bytes(u32 data, u32 n, u32 off)
+{
+       data <<= ((sizeof(u32) - n) * BITS_PER_BYTE);
+       data >>= ((sizeof(u32) - n - off) * BITS_PER_BYTE);
+       return data;
+}
+#else
+static inline u32 get_upper_bits(u32 data, u32 shift)
+{
+       return data << shift;
+}
+
+static inline u32 set_upper_bits(u32 data, u32 shift)
+{
+       return data >> shift;
+}
+
+static inline u32 clear_upper_bytes(u32 data, u32 n, u32 off)
+{
+       data >>= ((sizeof(u32) - n) * BITS_PER_BYTE);
+       data <<= ((sizeof(u32) - n - off) * BITS_PER_BYTE);
+       return data;
+}
+#endif
+
+static void copy_io(u32 __iomem *piobuf, struct qib_sge_state *ss,
+                   u32 length, unsigned flush_wc)
+{
+       u32 extra = 0;
+       u32 data = 0;
+       u32 last;
+
+       while (1) {
+               u32 len = ss->sge.length;
+               u32 off;
+
+               if (len > length)
+                       len = length;
+               if (len > ss->sge.sge_length)
+                       len = ss->sge.sge_length;
+               BUG_ON(len == 0);
+               /* If the source address is not aligned, try to align it. */
+               off = (unsigned long)ss->sge.vaddr & (sizeof(u32) - 1);
+               if (off) {
+                       u32 *addr = (u32 *)((unsigned long)ss->sge.vaddr &
+                                           ~(sizeof(u32) - 1));
+                       u32 v = get_upper_bits(*addr, off * BITS_PER_BYTE);
+                       u32 y;
+
+                       y = sizeof(u32) - off;
+                       if (len > y)
+                               len = y;
+                       if (len + extra >= sizeof(u32)) {
+                               data |= set_upper_bits(v, extra *
+                                                      BITS_PER_BYTE);
+                               len = sizeof(u32) - extra;
+                               if (len == length) {
+                                       last = data;
+                                       break;
+                               }
+                               __raw_writel(data, piobuf);
+                               piobuf++;
+                               extra = 0;
+                               data = 0;
+                       } else {
+                               /* Clear unused upper bytes */
+                               data |= clear_upper_bytes(v, len, extra);
+                               if (len == length) {
+                                       last = data;
+                                       break;
+                               }
+                               extra += len;
+                       }
+               } else if (extra) {
+                       /* Source address is aligned. */
+                       u32 *addr = (u32 *) ss->sge.vaddr;
+                       int shift = extra * BITS_PER_BYTE;
+                       int ushift = 32 - shift;
+                       u32 l = len;
+
+                       while (l >= sizeof(u32)) {
+                               u32 v = *addr;
+
+                               data |= set_upper_bits(v, shift);
+                               __raw_writel(data, piobuf);
+                               data = get_upper_bits(v, ushift);
+                               piobuf++;
+                               addr++;
+                               l -= sizeof(u32);
+                       }
+                       /*
+                        * We still have 'extra' number of bytes leftover.
+                        */
+                       if (l) {
+                               u32 v = *addr;
+
+                               if (l + extra >= sizeof(u32)) {
+                                       data |= set_upper_bits(v, shift);
+                                       len -= l + extra - sizeof(u32);
+                                       if (len == length) {
+                                               last = data;
+                                               break;
+                                       }
+                                       __raw_writel(data, piobuf);
+                                       piobuf++;
+                                       extra = 0;
+                                       data = 0;
+                               } else {
+                                       /* Clear unused upper bytes */
+                                       data |= clear_upper_bytes(v, l, extra);
+                                       if (len == length) {
+                                               last = data;
+                                               break;
+                                       }
+                                       extra += l;
+                               }
+                       } else if (len == length) {
+                               last = data;
+                               break;
+                       }
+               } else if (len == length) {
+                       u32 w;
+
+                       /*
+                        * Need to round up for the last dword in the
+                        * packet.
+                        */
+                       w = (len + 3) >> 2;
+                       qib_pio_copy(piobuf, ss->sge.vaddr, w - 1);
+                       piobuf += w - 1;
+                       last = ((u32 *) ss->sge.vaddr)[w - 1];
+                       break;
+               } else {
+                       u32 w = len >> 2;
+
+                       qib_pio_copy(piobuf, ss->sge.vaddr, w);
+                       piobuf += w;
+
+                       extra = len & (sizeof(u32) - 1);
+                       if (extra) {
+                               u32 v = ((u32 *) ss->sge.vaddr)[w];
+
+                               /* Clear unused upper bytes */
+                               data = clear_upper_bytes(v, extra, 0);
+                       }
+               }
+               update_sge(ss, len);
+               length -= len;
+       }
+       /* Update address before sending packet. */
+       update_sge(ss, length);
+       if (flush_wc) {
+               /* must flush early everything before trigger word */
+               qib_flush_wc();
+               __raw_writel(last, piobuf);
+               /* be sure trigger word is written */
+               qib_flush_wc();
+       } else
+               __raw_writel(last, piobuf);
+}
+
+static struct qib_verbs_txreq *get_txreq(struct qib_ibdev *dev,
+                                        struct qib_qp *qp, int *retp)
+{
+       struct qib_verbs_txreq *tx;
+       unsigned long flags;
+
+       spin_lock_irqsave(&qp->s_lock, flags);
+       spin_lock(&dev->pending_lock);
+
+       if (!list_empty(&dev->txreq_free)) {
+               struct list_head *l = dev->txreq_free.next;
+
+               list_del(l);
+               tx = list_entry(l, struct qib_verbs_txreq, txreq.list);
+               *retp = 0;
+       } else {
+               if (ib_qib_state_ops[qp->state] & QIB_PROCESS_RECV_OK &&
+                   list_empty(&qp->iowait)) {
+                       dev->n_txwait++;
+                       qp->s_flags |= QIB_S_WAIT_TX;
+                       list_add_tail(&qp->iowait, &dev->txwait);
+               }
+               tx = NULL;
+               qp->s_flags &= ~QIB_S_BUSY;
+               *retp = -EBUSY;
+       }
+
+       spin_unlock(&dev->pending_lock);
+       spin_unlock_irqrestore(&qp->s_lock, flags);
+
+       return tx;
+}
+
+void qib_put_txreq(struct qib_verbs_txreq *tx)
+{
+       struct qib_ibdev *dev;
+       struct qib_qp *qp;
+       unsigned long flags;
+
+       qp = tx->qp;
+       dev = to_idev(qp->ibqp.device);
+
+       if (atomic_dec_and_test(&qp->refcount))
+               wake_up(&qp->wait);
+       if (tx->mr) {
+               atomic_dec(&tx->mr->refcount);
+               tx->mr = NULL;
+       }
+       if (tx->txreq.flags & QIB_SDMA_TXREQ_F_FREEBUF) {
+               tx->txreq.flags &= ~QIB_SDMA_TXREQ_F_FREEBUF;
+               dma_unmap_single(&dd_from_dev(dev)->pcidev->dev,
+                                tx->txreq.addr, tx->hdr_dwords << 2,
+                                DMA_TO_DEVICE);
+               kfree(tx->align_buf);
+       }
+
+       spin_lock_irqsave(&dev->pending_lock, flags);
+
+       /* Put struct back on free list */
+       list_add(&tx->txreq.list, &dev->txreq_free);
+
+       if (!list_empty(&dev->txwait)) {
+               /* Wake up first QP wanting a free struct */
+               qp = list_entry(dev->txwait.next, struct qib_qp, iowait);
+               list_del_init(&qp->iowait);
+               atomic_inc(&qp->refcount);
+               spin_unlock_irqrestore(&dev->pending_lock, flags);
+
+               spin_lock_irqsave(&qp->s_lock, flags);
+               if (qp->s_flags & QIB_S_WAIT_TX) {
+                       qp->s_flags &= ~QIB_S_WAIT_TX;
+                       qib_schedule_send(qp);
+               }
+               spin_unlock_irqrestore(&qp->s_lock, flags);
+
+               if (atomic_dec_and_test(&qp->refcount))
+                       wake_up(&qp->wait);
+       } else
+               spin_unlock_irqrestore(&dev->pending_lock, flags);
+}
+
+/*
+ * This is called when there are send DMA descriptors that might be
+ * available.
+ *
+ * This is called with ppd->sdma_lock held.
+ */
+void qib_verbs_sdma_desc_avail(struct qib_pportdata *ppd, unsigned avail)
+{
+       struct qib_qp *qp, *nqp;
+       struct qib_qp *qps[20];
+       struct qib_ibdev *dev;
+       unsigned i, n;
+
+       n = 0;
+       dev = &ppd->dd->verbs_dev;
+       spin_lock(&dev->pending_lock);
+
+       /* Search wait list for first QP wanting DMA descriptors. */
+       list_for_each_entry_safe(qp, nqp, &dev->dmawait, iowait) {
+               if (qp->port_num != ppd->port)
+                       continue;
+               if (n == ARRAY_SIZE(qps))
+                       break;
+               if (qp->s_tx->txreq.sg_count > avail)
+                       break;
+               avail -= qp->s_tx->txreq.sg_count;
+               list_del_init(&qp->iowait);
+               atomic_inc(&qp->refcount);
+               qps[n++] = qp;
+       }
+
+       spin_unlock(&dev->pending_lock);
+
+       for (i = 0; i < n; i++) {
+               qp = qps[i];
+               spin_lock(&qp->s_lock);
+               if (qp->s_flags & QIB_S_WAIT_DMA_DESC) {
+                       qp->s_flags &= ~QIB_S_WAIT_DMA_DESC;
+                       qib_schedule_send(qp);
+               }
+               spin_unlock(&qp->s_lock);
+               if (atomic_dec_and_test(&qp->refcount))
+                       wake_up(&qp->wait);
+       }
+}
+
+/*
+ * This is called with ppd->sdma_lock held.
+ */
+static void sdma_complete(struct qib_sdma_txreq *cookie, int status)
+{
+       struct qib_verbs_txreq *tx =
+               container_of(cookie, struct qib_verbs_txreq, txreq);
+       struct qib_qp *qp = tx->qp;
+
+       spin_lock(&qp->s_lock);
+       if (tx->wqe)
+               qib_send_complete(qp, tx->wqe, IB_WC_SUCCESS);
+       else if (qp->ibqp.qp_type == IB_QPT_RC) {
+               struct qib_ib_header *hdr;
+
+               if (tx->txreq.flags & QIB_SDMA_TXREQ_F_FREEBUF)
+                       hdr = &tx->align_buf->hdr;
+               else {
+                       struct qib_ibdev *dev = to_idev(qp->ibqp.device);
+
+                       hdr = &dev->pio_hdrs[tx->hdr_inx].hdr;
+               }
+               qib_rc_send_complete(qp, hdr);
+       }
+       if (atomic_dec_and_test(&qp->s_dma_busy)) {
+               if (qp->state == IB_QPS_RESET)
+                       wake_up(&qp->wait_dma);
+               else if (qp->s_flags & QIB_S_WAIT_DMA) {
+                       qp->s_flags &= ~QIB_S_WAIT_DMA;
+                       qib_schedule_send(qp);
+               }
+       }
+       spin_unlock(&qp->s_lock);
+
+       qib_put_txreq(tx);
+}
+
+static int wait_kmem(struct qib_ibdev *dev, struct qib_qp *qp)
+{
+       unsigned long flags;
+       int ret = 0;
+
+       spin_lock_irqsave(&qp->s_lock, flags);
+       if (ib_qib_state_ops[qp->state] & QIB_PROCESS_RECV_OK) {
+               spin_lock(&dev->pending_lock);
+               if (list_empty(&qp->iowait)) {
+                       if (list_empty(&dev->memwait))
+                               mod_timer(&dev->mem_timer, jiffies + 1);
+                       qp->s_flags |= QIB_S_WAIT_KMEM;
+                       list_add_tail(&qp->iowait, &dev->memwait);
+               }
+               spin_unlock(&dev->pending_lock);
+               qp->s_flags &= ~QIB_S_BUSY;
+               ret = -EBUSY;
+       }
+       spin_unlock_irqrestore(&qp->s_lock, flags);
+
+       return ret;
+}
+
+static int qib_verbs_send_dma(struct qib_qp *qp, struct qib_ib_header *hdr,
+                             u32 hdrwords, struct qib_sge_state *ss, u32 len,
+                             u32 plen, u32 dwords)
+{
+       struct qib_ibdev *dev = to_idev(qp->ibqp.device);
+       struct qib_devdata *dd = dd_from_dev(dev);
+       struct qib_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num);
+       struct qib_pportdata *ppd = ppd_from_ibp(ibp);
+       struct qib_verbs_txreq *tx;
+       struct qib_pio_header *phdr;
+       u32 control;
+       u32 ndesc;
+       int ret;
+
+       tx = qp->s_tx;
+       if (tx) {
+               qp->s_tx = NULL;
+               /* resend previously constructed packet */
+               ret = qib_sdma_verbs_send(ppd, tx->ss, tx->dwords, tx);
+               goto bail;
+       }
+
+       tx = get_txreq(dev, qp, &ret);
+       if (!tx)
+               goto bail;
+
+       control = dd->f_setpbc_control(ppd, plen, qp->s_srate,
+                                      be16_to_cpu(hdr->lrh[0]) >> 12);
+       tx->qp = qp;
+       atomic_inc(&qp->refcount);
+       tx->wqe = qp->s_wqe;
+       tx->mr = qp->s_rdma_mr;
+       if (qp->s_rdma_mr)
+               qp->s_rdma_mr = NULL;
+       tx->txreq.callback = sdma_complete;
+       if (dd->flags & QIB_HAS_SDMA_TIMEOUT)
+               tx->txreq.flags = QIB_SDMA_TXREQ_F_HEADTOHOST;
+       else
+               tx->txreq.flags = QIB_SDMA_TXREQ_F_INTREQ;
+       if (plen + 1 > dd->piosize2kmax_dwords)
+               tx->txreq.flags |= QIB_SDMA_TXREQ_F_USELARGEBUF;
+
+       if (len) {
+               /*
+                * Don't try to DMA if it takes more descriptors than
+                * the queue holds.
+                */
+               ndesc = qib_count_sge(ss, len);
+               if (ndesc >= ppd->sdma_descq_cnt)
+                       ndesc = 0;
+       } else
+               ndesc = 1;
+       if (ndesc) {
+               phdr = &dev->pio_hdrs[tx->hdr_inx];
+               phdr->pbc[0] = cpu_to_le32(plen);
+               phdr->pbc[1] = cpu_to_le32(control);
+               memcpy(&phdr->hdr, hdr, hdrwords << 2);
+               tx->txreq.flags |= QIB_SDMA_TXREQ_F_FREEDESC;
+               tx->txreq.sg_count = ndesc;
+               tx->txreq.addr = dev->pio_hdrs_phys +
+                       tx->hdr_inx * sizeof(struct qib_pio_header);
+               tx->hdr_dwords = hdrwords + 2; /* add PBC length */
+               ret = qib_sdma_verbs_send(ppd, ss, dwords, tx);
+               goto bail;
+       }
+
+       /* Allocate a buffer and copy the header and payload to it. */
+       tx->hdr_dwords = plen + 1;
+       phdr = kmalloc(tx->hdr_dwords << 2, GFP_ATOMIC);
+       if (!phdr)
+               goto err_tx;
+       phdr->pbc[0] = cpu_to_le32(plen);
+       phdr->pbc[1] = cpu_to_le32(control);
+       memcpy(&phdr->hdr, hdr, hdrwords << 2);
+       qib_copy_from_sge((u32 *) &phdr->hdr + hdrwords, ss, len);
+
+       tx->txreq.addr = dma_map_single(&dd->pcidev->dev, phdr,
+                                       tx->hdr_dwords << 2, DMA_TO_DEVICE);
+       if (dma_mapping_error(&dd->pcidev->dev, tx->txreq.addr))
+               goto map_err;
+       tx->align_buf = phdr;
+       tx->txreq.flags |= QIB_SDMA_TXREQ_F_FREEBUF;
+       tx->txreq.sg_count = 1;
+       ret = qib_sdma_verbs_send(ppd, NULL, 0, tx);
+       goto unaligned;
+
+map_err:
+       kfree(phdr);
+err_tx:
+       qib_put_txreq(tx);
+       ret = wait_kmem(dev, qp);
+unaligned:
+       ibp->n_unaligned++;
+bail:
+       return ret;
+}
+
+/*
+ * If we are now in the error state, return zero to flush the
+ * send work request.
+ */
+static int no_bufs_available(struct qib_qp *qp)
+{
+       struct qib_ibdev *dev = to_idev(qp->ibqp.device);
+       struct qib_devdata *dd;
+       unsigned long flags;
+       int ret = 0;
+
+       /*
+        * Note that as soon as want_buffer() is called and
+        * possibly before it returns, qib_ib_piobufavail()
+        * could be called. Therefore, put QP on the I/O wait list before
+        * enabling the PIO avail interrupt.
+        */
+       spin_lock_irqsave(&qp->s_lock, flags);
+       if (ib_qib_state_ops[qp->state] & QIB_PROCESS_RECV_OK) {
+               spin_lock(&dev->pending_lock);
+               if (list_empty(&qp->iowait)) {
+                       dev->n_piowait++;
+                       qp->s_flags |= QIB_S_WAIT_PIO;
+                       list_add_tail(&qp->iowait, &dev->piowait);
+                       dd = dd_from_dev(dev);
+                       dd->f_wantpiobuf_intr(dd, 1);
+               }
+               spin_unlock(&dev->pending_lock);
+               qp->s_flags &= ~QIB_S_BUSY;
+               ret = -EBUSY;
+       }
+       spin_unlock_irqrestore(&qp->s_lock, flags);
+       return ret;
+}
+
+static int qib_verbs_send_pio(struct qib_qp *qp, struct qib_ib_header *ibhdr,
+                             u32 hdrwords, struct qib_sge_state *ss, u32 len,
+                             u32 plen, u32 dwords)
+{
+       struct qib_devdata *dd = dd_from_ibdev(qp->ibqp.device);
+       struct qib_pportdata *ppd = dd->pport + qp->port_num - 1;
+       u32 *hdr = (u32 *) ibhdr;
+       u32 __iomem *piobuf_orig;
+       u32 __iomem *piobuf;
+       u64 pbc;
+       unsigned long flags;
+       unsigned flush_wc;
+       u32 control;
+       u32 pbufn;
+
+       control = dd->f_setpbc_control(ppd, plen, qp->s_srate,
+               be16_to_cpu(ibhdr->lrh[0]) >> 12);
+       pbc = ((u64) control << 32) | plen;
+       piobuf = dd->f_getsendbuf(ppd, pbc, &pbufn);
+       if (unlikely(piobuf == NULL))
+               return no_bufs_available(qp);
+
+       /*
+        * Write the pbc.
+        * We have to flush after the PBC for correctness on some cpus
+        * or WC buffer can be written out of order.
+        */
+       writeq(pbc, piobuf);
+       piobuf_orig = piobuf;
+       piobuf += 2;
+
+       flush_wc = dd->flags & QIB_PIO_FLUSH_WC;
+       if (len == 0) {
+               /*
+                * If there is just the header portion, must flush before
+                * writing last word of header for correctness, and after
+                * the last header word (trigger word).
+                */
+               if (flush_wc) {
+                       qib_flush_wc();
+                       qib_pio_copy(piobuf, hdr, hdrwords - 1);
+                       qib_flush_wc();
+                       __raw_writel(hdr[hdrwords - 1], piobuf + hdrwords - 1);
+                       qib_flush_wc();
+               } else
+                       qib_pio_copy(piobuf, hdr, hdrwords);
+               goto done;
+       }
+
+       if (flush_wc)
+               qib_flush_wc();
+       qib_pio_copy(piobuf, hdr, hdrwords);
+       piobuf += hdrwords;
+
+       /* The common case is aligned and contained in one segment. */
+       if (likely(ss->num_sge == 1 && len <= ss->sge.length &&
+                  !((unsigned long)ss->sge.vaddr & (sizeof(u32) - 1)))) {
+               u32 *addr = (u32 *) ss->sge.vaddr;
+
+               /* Update address before sending packet. */
+               update_sge(ss, len);
+               if (flush_wc) {
+                       qib_pio_copy(piobuf, addr, dwords - 1);
+                       /* must flush early everything before trigger word */
+                       qib_flush_wc();
+                       __raw_writel(addr[dwords - 1], piobuf + dwords - 1);
+                       /* be sure trigger word is written */
+                       qib_flush_wc();
+               } else
+                       qib_pio_copy(piobuf, addr, dwords);
+               goto done;
+       }
+       copy_io(piobuf, ss, len, flush_wc);
+done:
+       if (dd->flags & QIB_USE_SPCL_TRIG) {
+               u32 spcl_off = (pbufn >= dd->piobcnt2k) ? 2047 : 1023;
+               qib_flush_wc();
+               __raw_writel(0xaebecede, piobuf_orig + spcl_off);
+       }
+       qib_sendbuf_done(dd, pbufn);
+       if (qp->s_rdma_mr) {
+               atomic_dec(&qp->s_rdma_mr->refcount);
+               qp->s_rdma_mr = NULL;
+       }
+       if (qp->s_wqe) {
+               spin_lock_irqsave(&qp->s_lock, flags);
+               qib_send_complete(qp, qp->s_wqe, IB_WC_SUCCESS);
+               spin_unlock_irqrestore(&qp->s_lock, flags);
+       } else if (qp->ibqp.qp_type == IB_QPT_RC) {
+               spin_lock_irqsave(&qp->s_lock, flags);
+               qib_rc_send_complete(qp, ibhdr);
+               spin_unlock_irqrestore(&qp->s_lock, flags);
+       }
+       return 0;
+}
+
+/**
+ * qib_verbs_send - send a packet
+ * @qp: the QP to send on
+ * @hdr: the packet header
+ * @hdrwords: the number of 32-bit words in the header
+ * @ss: the SGE to send
+ * @len: the length of the packet in bytes
+ *
+ * Return zero if packet is sent or queued OK.
+ * Return non-zero and clear qp->s_flags QIB_S_BUSY otherwise.
+ */
+int qib_verbs_send(struct qib_qp *qp, struct qib_ib_header *hdr,
+                  u32 hdrwords, struct qib_sge_state *ss, u32 len)
+{
+       struct qib_devdata *dd = dd_from_ibdev(qp->ibqp.device);
+       u32 plen;
+       int ret;
+       u32 dwords = (len + 3) >> 2;
+
+       /*
+        * Calculate the send buffer trigger address.
+        * The +1 counts for the pbc control dword following the pbc length.
+        */
+       plen = hdrwords + dwords + 1;
+
+       /*
+        * VL15 packets (IB_QPT_SMI) will always use PIO, so we
+        * can defer SDMA restart until link goes ACTIVE without
+        * worrying about just how we got there.
+        */
+       if (qp->ibqp.qp_type == IB_QPT_SMI ||
+           !(dd->flags & QIB_HAS_SEND_DMA))
+               ret = qib_verbs_send_pio(qp, hdr, hdrwords, ss, len,
+                                        plen, dwords);
+       else
+               ret = qib_verbs_send_dma(qp, hdr, hdrwords, ss, len,
+                                        plen, dwords);
+
+       return ret;
+}
+
+int qib_snapshot_counters(struct qib_pportdata *ppd, u64 *swords,
+                         u64 *rwords, u64 *spkts, u64 *rpkts,
+                         u64 *xmit_wait)
+{
+       int ret;
+       struct qib_devdata *dd = ppd->dd;
+
+       if (!(dd->flags & QIB_PRESENT)) {
+               /* no hardware, freeze, etc. */
+               ret = -EINVAL;
+               goto bail;
+       }
+       *swords = dd->f_portcntr(ppd, QIBPORTCNTR_WORDSEND);
+       *rwords = dd->f_portcntr(ppd, QIBPORTCNTR_WORDRCV);
+       *spkts = dd->f_portcntr(ppd, QIBPORTCNTR_PKTSEND);
+       *rpkts = dd->f_portcntr(ppd, QIBPORTCNTR_PKTRCV);
+       *xmit_wait = dd->f_portcntr(ppd, QIBPORTCNTR_SENDSTALL);
+
+       ret = 0;
+
+bail:
+       return ret;
+}
+
+/**
+ * qib_get_counters - get various chip counters
+ * @dd: the qlogic_ib device
+ * @cntrs: counters are placed here
+ *
+ * Return the counters needed by recv_pma_get_portcounters().
+ */
+int qib_get_counters(struct qib_pportdata *ppd,
+                    struct qib_verbs_counters *cntrs)
+{
+       int ret;
+
+       if (!(ppd->dd->flags & QIB_PRESENT)) {
+               /* no hardware, freeze, etc. */
+               ret = -EINVAL;
+               goto bail;
+       }
+       cntrs->symbol_error_counter =
+               ppd->dd->f_portcntr(ppd, QIBPORTCNTR_IBSYMBOLERR);
+       cntrs->link_error_recovery_counter =
+               ppd->dd->f_portcntr(ppd, QIBPORTCNTR_IBLINKERRRECOV);
+       /*
+        * The link downed counter counts when the other side downs the
+        * connection.  We add in the number of times we downed the link
+        * due to local link integrity errors to compensate.
+        */
+       cntrs->link_downed_counter =
+               ppd->dd->f_portcntr(ppd, QIBPORTCNTR_IBLINKDOWN);
+       cntrs->port_rcv_errors =
+               ppd->dd->f_portcntr(ppd, QIBPORTCNTR_RXDROPPKT) +
+               ppd->dd->f_portcntr(ppd, QIBPORTCNTR_RCVOVFL) +
+               ppd->dd->f_portcntr(ppd, QIBPORTCNTR_ERR_RLEN) +
+               ppd->dd->f_portcntr(ppd, QIBPORTCNTR_INVALIDRLEN) +
+               ppd->dd->f_portcntr(ppd, QIBPORTCNTR_ERRLINK) +
+               ppd->dd->f_portcntr(ppd, QIBPORTCNTR_ERRICRC) +
+               ppd->dd->f_portcntr(ppd, QIBPORTCNTR_ERRVCRC) +
+               ppd->dd->f_portcntr(ppd, QIBPORTCNTR_ERRLPCRC) +
+               ppd->dd->f_portcntr(ppd, QIBPORTCNTR_BADFORMAT);
+       cntrs->port_rcv_errors +=
+               ppd->dd->f_portcntr(ppd, QIBPORTCNTR_RXLOCALPHYERR);
+       cntrs->port_rcv_errors +=
+               ppd->dd->f_portcntr(ppd, QIBPORTCNTR_RXVLERR);
+       cntrs->port_rcv_remphys_errors =
+               ppd->dd->f_portcntr(ppd, QIBPORTCNTR_RCVEBP);
+       cntrs->port_xmit_discards =
+               ppd->dd->f_portcntr(ppd, QIBPORTCNTR_UNSUPVL);
+       cntrs->port_xmit_data = ppd->dd->f_portcntr(ppd,
+                       QIBPORTCNTR_WORDSEND);
+       cntrs->port_rcv_data = ppd->dd->f_portcntr(ppd,
+                       QIBPORTCNTR_WORDRCV);
+       cntrs->port_xmit_packets = ppd->dd->f_portcntr(ppd,
+                       QIBPORTCNTR_PKTSEND);
+       cntrs->port_rcv_packets = ppd->dd->f_portcntr(ppd,
+                       QIBPORTCNTR_PKTRCV);
+       cntrs->local_link_integrity_errors =
+               ppd->dd->f_portcntr(ppd, QIBPORTCNTR_LLI);
+       cntrs->excessive_buffer_overrun_errors =
+               ppd->dd->f_portcntr(ppd, QIBPORTCNTR_EXCESSBUFOVFL);
+       cntrs->vl15_dropped =
+               ppd->dd->f_portcntr(ppd, QIBPORTCNTR_VL15PKTDROP);
+
+       ret = 0;
+
+bail:
+       return ret;
+}
+
+/**
+ * qib_ib_piobufavail - callback when a PIO buffer is available
+ * @dd: the device pointer
+ *
+ * This is called from qib_intr() at interrupt level when a PIO buffer is
+ * available after qib_verbs_send() returned an error that no buffers were
+ * available. Disable the interrupt if there are no more QPs waiting.
+ */
+void qib_ib_piobufavail(struct qib_devdata *dd)
+{
+       struct qib_ibdev *dev = &dd->verbs_dev;
+       struct list_head *list;
+       struct qib_qp *qps[5];
+       struct qib_qp *qp;
+       unsigned long flags;
+       unsigned i, n;
+
+       list = &dev->piowait;
+       n = 0;
+
+       /*
+        * Note: checking that the piowait list is empty and clearing
+        * the buffer available interrupt needs to be atomic or we
+        * could end up with QPs on the wait list with the interrupt
+        * disabled.
+        */
+       spin_lock_irqsave(&dev->pending_lock, flags);
+       while (!list_empty(list)) {
+               if (n == ARRAY_SIZE(qps))
+                       goto full;
+               qp = list_entry(list->next, struct qib_qp, iowait);
+               list_del_init(&qp->iowait);
+               atomic_inc(&qp->refcount);
+               qps[n++] = qp;
+       }
+       dd->f_wantpiobuf_intr(dd, 0);
+full:
+       spin_unlock_irqrestore(&dev->pending_lock, flags);
+
+       for (i = 0; i < n; i++) {
+               qp = qps[i];
+
+               spin_lock_irqsave(&qp->s_lock, flags);
+               if (qp->s_flags & QIB_S_WAIT_PIO) {
+                       qp->s_flags &= ~QIB_S_WAIT_PIO;
+                       qib_schedule_send(qp);
+               }
+               spin_unlock_irqrestore(&qp->s_lock, flags);
+
+               /* Notify qib_destroy_qp() if it is waiting. */
+               if (atomic_dec_and_test(&qp->refcount))
+                       wake_up(&qp->wait);
+       }
+}
+
+static int qib_query_device(struct ib_device *ibdev,
+                           struct ib_device_attr *props)
+{
+       struct qib_devdata *dd = dd_from_ibdev(ibdev);
+       struct qib_ibdev *dev = to_idev(ibdev);
+
+       memset(props, 0, sizeof(*props));
+
+       props->device_cap_flags = IB_DEVICE_BAD_PKEY_CNTR |
+               IB_DEVICE_BAD_QKEY_CNTR | IB_DEVICE_SHUTDOWN_PORT |
+               IB_DEVICE_SYS_IMAGE_GUID | IB_DEVICE_RC_RNR_NAK_GEN |
+               IB_DEVICE_PORT_ACTIVE_EVENT | IB_DEVICE_SRQ_RESIZE;
+       props->page_size_cap = PAGE_SIZE;
+       props->vendor_id =
+               QIB_SRC_OUI_1 << 16 | QIB_SRC_OUI_2 << 8 | QIB_SRC_OUI_3;
+       props->vendor_part_id = dd->deviceid;
+       props->hw_ver = dd->minrev;
+       props->sys_image_guid = ib_qib_sys_image_guid;
+       props->max_mr_size = ~0ULL;
+       props->max_qp = ib_qib_max_qps;
+       props->max_qp_wr = ib_qib_max_qp_wrs;
+       props->max_sge = ib_qib_max_sges;
+       props->max_cq = ib_qib_max_cqs;
+       props->max_ah = ib_qib_max_ahs;
+       props->max_cqe = ib_qib_max_cqes;
+       props->max_mr = dev->lk_table.max;
+       props->max_fmr = dev->lk_table.max;
+       props->max_map_per_fmr = 32767;
+       props->max_pd = ib_qib_max_pds;
+       props->max_qp_rd_atom = QIB_MAX_RDMA_ATOMIC;
+       props->max_qp_init_rd_atom = 255;
+       /* props->max_res_rd_atom */
+       props->max_srq = ib_qib_max_srqs;
+       props->max_srq_wr = ib_qib_max_srq_wrs;
+       props->max_srq_sge = ib_qib_max_srq_sges;
+       /* props->local_ca_ack_delay */
+       props->atomic_cap = IB_ATOMIC_GLOB;
+       props->max_pkeys = qib_get_npkeys(dd);
+       props->max_mcast_grp = ib_qib_max_mcast_grps;
+       props->max_mcast_qp_attach = ib_qib_max_mcast_qp_attached;
+       props->max_total_mcast_qp_attach = props->max_mcast_qp_attach *
+               props->max_mcast_grp;
+
+       return 0;
+}
+
+static int qib_query_port(struct ib_device *ibdev, u8 port,
+                         struct ib_port_attr *props)
+{
+       struct qib_devdata *dd = dd_from_ibdev(ibdev);
+       struct qib_ibport *ibp = to_iport(ibdev, port);
+       struct qib_pportdata *ppd = ppd_from_ibp(ibp);
+       enum ib_mtu mtu;
+       u16 lid = ppd->lid;
+
+       memset(props, 0, sizeof(*props));
+       props->lid = lid ? lid : be16_to_cpu(IB_LID_PERMISSIVE);
+       props->lmc = ppd->lmc;
+       props->sm_lid = ibp->sm_lid;
+       props->sm_sl = ibp->sm_sl;
+       props->state = dd->f_iblink_state(ppd->lastibcstat);
+       props->phys_state = dd->f_ibphys_portstate(ppd->lastibcstat);
+       props->port_cap_flags = ibp->port_cap_flags;
+       props->gid_tbl_len = QIB_GUIDS_PER_PORT;
+       props->max_msg_sz = 0x80000000;
+       props->pkey_tbl_len = qib_get_npkeys(dd);
+       props->bad_pkey_cntr = ibp->pkey_violations;
+       props->qkey_viol_cntr = ibp->qkey_violations;
+       props->active_width = ppd->link_width_active;
+       /* See rate_show() */
+       props->active_speed = ppd->link_speed_active;
+       props->max_vl_num = qib_num_vls(ppd->vls_supported);
+       props->init_type_reply = 0;
+
+       props->max_mtu = qib_ibmtu ? qib_ibmtu : IB_MTU_4096;
+       switch (ppd->ibmtu) {
+       case 4096:
+               mtu = IB_MTU_4096;
+               break;
+       case 2048:
+               mtu = IB_MTU_2048;
+               break;
+       case 1024:
+               mtu = IB_MTU_1024;
+               break;
+       case 512:
+               mtu = IB_MTU_512;
+               break;
+       case 256:
+               mtu = IB_MTU_256;
+               break;
+       default:
+               mtu = IB_MTU_2048;
+       }
+       props->active_mtu = mtu;
+       props->subnet_timeout = ibp->subnet_timeout;
+
+       return 0;
+}
+
+static int qib_modify_device(struct ib_device *device,
+                            int device_modify_mask,
+                            struct ib_device_modify *device_modify)
+{
+       struct qib_devdata *dd = dd_from_ibdev(device);
+       unsigned i;
+       int ret;
+
+       if (device_modify_mask & ~(IB_DEVICE_MODIFY_SYS_IMAGE_GUID |
+                                  IB_DEVICE_MODIFY_NODE_DESC)) {
+               ret = -EOPNOTSUPP;
+               goto bail;
+       }
+
+       if (device_modify_mask & IB_DEVICE_MODIFY_NODE_DESC) {
+               memcpy(device->node_desc, device_modify->node_desc, 64);
+               for (i = 0; i < dd->num_pports; i++) {
+                       struct qib_ibport *ibp = &dd->pport[i].ibport_data;
+
+                       qib_node_desc_chg(ibp);
+               }
+       }
+
+       if (device_modify_mask & IB_DEVICE_MODIFY_SYS_IMAGE_GUID) {
+               ib_qib_sys_image_guid =
+                       cpu_to_be64(device_modify->sys_image_guid);
+               for (i = 0; i < dd->num_pports; i++) {
+                       struct qib_ibport *ibp = &dd->pport[i].ibport_data;
+
+                       qib_sys_guid_chg(ibp);
+               }
+       }
+
+       ret = 0;
+
+bail:
+       return ret;
+}
+
+static int qib_modify_port(struct ib_device *ibdev, u8 port,
+                          int port_modify_mask, struct ib_port_modify *props)
+{
+       struct qib_ibport *ibp = to_iport(ibdev, port);
+       struct qib_pportdata *ppd = ppd_from_ibp(ibp);
+
+       ibp->port_cap_flags |= props->set_port_cap_mask;
+       ibp->port_cap_flags &= ~props->clr_port_cap_mask;
+       if (props->set_port_cap_mask || props->clr_port_cap_mask)
+               qib_cap_mask_chg(ibp);
+       if (port_modify_mask & IB_PORT_SHUTDOWN)
+               qib_set_linkstate(ppd, QIB_IB_LINKDOWN);
+       if (port_modify_mask & IB_PORT_RESET_QKEY_CNTR)
+               ibp->qkey_violations = 0;
+       return 0;
+}
+
+static int qib_query_gid(struct ib_device *ibdev, u8 port,
+                        int index, union ib_gid *gid)
+{
+       struct qib_devdata *dd = dd_from_ibdev(ibdev);
+       int ret = 0;
+
+       if (!port || port > dd->num_pports)
+               ret = -EINVAL;
+       else {
+               struct qib_ibport *ibp = to_iport(ibdev, port);
+               struct qib_pportdata *ppd = ppd_from_ibp(ibp);
+
+               gid->global.subnet_prefix = ibp->gid_prefix;
+               if (index == 0)
+                       gid->global.interface_id = ppd->guid;
+               else if (index < QIB_GUIDS_PER_PORT)
+                       gid->global.interface_id = ibp->guids[index - 1];
+               else
+                       ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static struct ib_pd *qib_alloc_pd(struct ib_device *ibdev,
+                                 struct ib_ucontext *context,
+                                 struct ib_udata *udata)
+{
+       struct qib_ibdev *dev = to_idev(ibdev);
+       struct qib_pd *pd;
+       struct ib_pd *ret;
+
+       /*
+        * This is actually totally arbitrary.  Some correctness tests
+        * assume there's a maximum number of PDs that can be allocated.
+        * We don't actually have this limit, but we fail the test if
+        * we allow allocations of more than we report for this value.
+        */
+
+       pd = kmalloc(sizeof *pd, GFP_KERNEL);
+       if (!pd) {
+               ret = ERR_PTR(-ENOMEM);
+               goto bail;
+       }
+
+       spin_lock(&dev->n_pds_lock);
+       if (dev->n_pds_allocated == ib_qib_max_pds) {
+               spin_unlock(&dev->n_pds_lock);
+               kfree(pd);
+               ret = ERR_PTR(-ENOMEM);
+               goto bail;
+       }
+
+       dev->n_pds_allocated++;
+       spin_unlock(&dev->n_pds_lock);
+
+       /* ib_alloc_pd() will initialize pd->ibpd. */
+       pd->user = udata != NULL;
+
+       ret = &pd->ibpd;
+
+bail:
+       return ret;
+}
+
+static int qib_dealloc_pd(struct ib_pd *ibpd)
+{
+       struct qib_pd *pd = to_ipd(ibpd);
+       struct qib_ibdev *dev = to_idev(ibpd->device);
+
+       spin_lock(&dev->n_pds_lock);
+       dev->n_pds_allocated--;
+       spin_unlock(&dev->n_pds_lock);
+
+       kfree(pd);
+
+       return 0;
+}
+
+int qib_check_ah(struct ib_device *ibdev, struct ib_ah_attr *ah_attr)
+{
+       /* A multicast address requires a GRH (see ch. 8.4.1). */
+       if (ah_attr->dlid >= QIB_MULTICAST_LID_BASE &&
+           ah_attr->dlid != QIB_PERMISSIVE_LID &&
+           !(ah_attr->ah_flags & IB_AH_GRH))
+               goto bail;
+       if ((ah_attr->ah_flags & IB_AH_GRH) &&
+           ah_attr->grh.sgid_index >= QIB_GUIDS_PER_PORT)
+               goto bail;
+       if (ah_attr->dlid == 0)
+               goto bail;
+       if (ah_attr->port_num < 1 ||
+           ah_attr->port_num > ibdev->phys_port_cnt)
+               goto bail;
+       if (ah_attr->static_rate != IB_RATE_PORT_CURRENT &&
+           ib_rate_to_mult(ah_attr->static_rate) < 0)
+               goto bail;
+       if (ah_attr->sl > 15)
+               goto bail;
+       return 0;
+bail:
+       return -EINVAL;
+}
+
+/**
+ * qib_create_ah - create an address handle
+ * @pd: the protection domain
+ * @ah_attr: the attributes of the AH
+ *
+ * This may be called from interrupt context.
+ */
+static struct ib_ah *qib_create_ah(struct ib_pd *pd,
+                                  struct ib_ah_attr *ah_attr)
+{
+       struct qib_ah *ah;
+       struct ib_ah *ret;
+       struct qib_ibdev *dev = to_idev(pd->device);
+       unsigned long flags;
+
+       if (qib_check_ah(pd->device, ah_attr)) {
+               ret = ERR_PTR(-EINVAL);
+               goto bail;
+       }
+
+       ah = kmalloc(sizeof *ah, GFP_ATOMIC);
+       if (!ah) {
+               ret = ERR_PTR(-ENOMEM);
+               goto bail;
+       }
+
+       spin_lock_irqsave(&dev->n_ahs_lock, flags);
+       if (dev->n_ahs_allocated == ib_qib_max_ahs) {
+               spin_unlock_irqrestore(&dev->n_ahs_lock, flags);
+               kfree(ah);
+               ret = ERR_PTR(-ENOMEM);
+               goto bail;
+       }
+
+       dev->n_ahs_allocated++;
+       spin_unlock_irqrestore(&dev->n_ahs_lock, flags);
+
+       /* ib_create_ah() will initialize ah->ibah. */
+       ah->attr = *ah_attr;
+       atomic_set(&ah->refcount, 0);
+
+       ret = &ah->ibah;
+
+bail:
+       return ret;
+}
+
+/**
+ * qib_destroy_ah - destroy an address handle
+ * @ibah: the AH to destroy
+ *
+ * This may be called from interrupt context.
+ */
+static int qib_destroy_ah(struct ib_ah *ibah)
+{
+       struct qib_ibdev *dev = to_idev(ibah->device);
+       struct qib_ah *ah = to_iah(ibah);
+       unsigned long flags;
+
+       if (atomic_read(&ah->refcount) != 0)
+               return -EBUSY;
+
+       spin_lock_irqsave(&dev->n_ahs_lock, flags);
+       dev->n_ahs_allocated--;
+       spin_unlock_irqrestore(&dev->n_ahs_lock, flags);
+
+       kfree(ah);
+
+       return 0;
+}
+
+static int qib_modify_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr)
+{
+       struct qib_ah *ah = to_iah(ibah);
+
+       if (qib_check_ah(ibah->device, ah_attr))
+               return -EINVAL;
+
+       ah->attr = *ah_attr;
+
+       return 0;
+}
+
+static int qib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr)
+{
+       struct qib_ah *ah = to_iah(ibah);
+
+       *ah_attr = ah->attr;
+
+       return 0;
+}
+
+/**
+ * qib_get_npkeys - return the size of the PKEY table for context 0
+ * @dd: the qlogic_ib device
+ */
+unsigned qib_get_npkeys(struct qib_devdata *dd)
+{
+       return ARRAY_SIZE(dd->rcd[0]->pkeys);
+}
+
+/*
+ * Return the indexed PKEY from the port PKEY table.
+ * No need to validate rcd[ctxt]; the port is setup if we are here.
+ */
+unsigned qib_get_pkey(struct qib_ibport *ibp, unsigned index)
+{
+       struct qib_pportdata *ppd = ppd_from_ibp(ibp);
+       struct qib_devdata *dd = ppd->dd;
+       unsigned ctxt = ppd->hw_pidx;
+       unsigned ret;
+
+       /* dd->rcd null if mini_init or some init failures */
+       if (!dd->rcd || index >= ARRAY_SIZE(dd->rcd[ctxt]->pkeys))
+               ret = 0;
+       else
+               ret = dd->rcd[ctxt]->pkeys[index];
+
+       return ret;
+}
+
+static int qib_query_pkey(struct ib_device *ibdev, u8 port, u16 index,
+                         u16 *pkey)
+{
+       struct qib_devdata *dd = dd_from_ibdev(ibdev);
+       int ret;
+
+       if (index >= qib_get_npkeys(dd)) {
+               ret = -EINVAL;
+               goto bail;
+       }
+
+       *pkey = qib_get_pkey(to_iport(ibdev, port), index);
+       ret = 0;
+
+bail:
+       return ret;
+}
+
+/**
+ * qib_alloc_ucontext - allocate a ucontest
+ * @ibdev: the infiniband device
+ * @udata: not used by the QLogic_IB driver
+ */
+
+static struct ib_ucontext *qib_alloc_ucontext(struct ib_device *ibdev,
+                                             struct ib_udata *udata)
+{
+       struct qib_ucontext *context;
+       struct ib_ucontext *ret;
+
+       context = kmalloc(sizeof *context, GFP_KERNEL);
+       if (!context) {
+               ret = ERR_PTR(-ENOMEM);
+               goto bail;
+       }
+
+       ret = &context->ibucontext;
+
+bail:
+       return ret;
+}
+
+static int qib_dealloc_ucontext(struct ib_ucontext *context)
+{
+       kfree(to_iucontext(context));
+       return 0;
+}
+
+static void init_ibport(struct qib_pportdata *ppd)
+{
+       struct qib_verbs_counters cntrs;
+       struct qib_ibport *ibp = &ppd->ibport_data;
+
+       spin_lock_init(&ibp->lock);
+       /* Set the prefix to the default value (see ch. 4.1.1) */
+       ibp->gid_prefix = IB_DEFAULT_GID_PREFIX;
+       ibp->sm_lid = be16_to_cpu(IB_LID_PERMISSIVE);
+       ibp->port_cap_flags = IB_PORT_SYS_IMAGE_GUID_SUP |
+               IB_PORT_CLIENT_REG_SUP | IB_PORT_SL_MAP_SUP |
+               IB_PORT_TRAP_SUP | IB_PORT_AUTO_MIGR_SUP |
+               IB_PORT_DR_NOTICE_SUP | IB_PORT_CAP_MASK_NOTICE_SUP |
+               IB_PORT_OTHER_LOCAL_CHANGES_SUP;
+       if (ppd->dd->flags & QIB_HAS_LINK_LATENCY)
+               ibp->port_cap_flags |= IB_PORT_LINK_LATENCY_SUP;
+       ibp->pma_counter_select[0] = IB_PMA_PORT_XMIT_DATA;
+       ibp->pma_counter_select[1] = IB_PMA_PORT_RCV_DATA;
+       ibp->pma_counter_select[2] = IB_PMA_PORT_XMIT_PKTS;
+       ibp->pma_counter_select[3] = IB_PMA_PORT_RCV_PKTS;
+       ibp->pma_counter_select[4] = IB_PMA_PORT_XMIT_WAIT;
+
+       /* Snapshot current HW counters to "clear" them. */
+       qib_get_counters(ppd, &cntrs);
+       ibp->z_symbol_error_counter = cntrs.symbol_error_counter;
+       ibp->z_link_error_recovery_counter =
+               cntrs.link_error_recovery_counter;
+       ibp->z_link_downed_counter = cntrs.link_downed_counter;
+       ibp->z_port_rcv_errors = cntrs.port_rcv_errors;
+       ibp->z_port_rcv_remphys_errors = cntrs.port_rcv_remphys_errors;
+       ibp->z_port_xmit_discards = cntrs.port_xmit_discards;
+       ibp->z_port_xmit_data = cntrs.port_xmit_data;
+       ibp->z_port_rcv_data = cntrs.port_rcv_data;
+       ibp->z_port_xmit_packets = cntrs.port_xmit_packets;
+       ibp->z_port_rcv_packets = cntrs.port_rcv_packets;
+       ibp->z_local_link_integrity_errors =
+               cntrs.local_link_integrity_errors;
+       ibp->z_excessive_buffer_overrun_errors =
+               cntrs.excessive_buffer_overrun_errors;
+       ibp->z_vl15_dropped = cntrs.vl15_dropped;
+}
+
+/**
+ * qib_register_ib_device - register our device with the infiniband core
+ * @dd: the device data structure
+ * Return the allocated qib_ibdev pointer or NULL on error.
+ */
+int qib_register_ib_device(struct qib_devdata *dd)
+{
+       struct qib_ibdev *dev = &dd->verbs_dev;
+       struct ib_device *ibdev = &dev->ibdev;
+       struct qib_pportdata *ppd = dd->pport;
+       unsigned i, lk_tab_size;
+       int ret;
+
+       dev->qp_table_size = ib_qib_qp_table_size;
+       dev->qp_table = kzalloc(dev->qp_table_size * sizeof *dev->qp_table,
+                               GFP_KERNEL);
+       if (!dev->qp_table) {
+               ret = -ENOMEM;
+               goto err_qpt;
+       }
+
+       for (i = 0; i < dd->num_pports; i++)
+               init_ibport(ppd + i);
+
+       /* Only need to initialize non-zero fields. */
+       spin_lock_init(&dev->qpt_lock);
+       spin_lock_init(&dev->n_pds_lock);
+       spin_lock_init(&dev->n_ahs_lock);
+       spin_lock_init(&dev->n_cqs_lock);
+       spin_lock_init(&dev->n_qps_lock);
+       spin_lock_init(&dev->n_srqs_lock);
+       spin_lock_init(&dev->n_mcast_grps_lock);
+       init_timer(&dev->mem_timer);
+       dev->mem_timer.function = mem_timer;
+       dev->mem_timer.data = (unsigned long) dev;
+
+       qib_init_qpn_table(dd, &dev->qpn_table);
+
+       /*
+        * The top ib_qib_lkey_table_size bits are used to index the
+        * table.  The lower 8 bits can be owned by the user (copied from
+        * the LKEY).  The remaining bits act as a generation number or tag.
+        */
+       spin_lock_init(&dev->lk_table.lock);
+       dev->lk_table.max = 1 << ib_qib_lkey_table_size;
+       lk_tab_size = dev->lk_table.max * sizeof(*dev->lk_table.table);
+       dev->lk_table.table = (struct qib_mregion **)
+               __get_free_pages(GFP_KERNEL, get_order(lk_tab_size));
+       if (dev->lk_table.table == NULL) {
+               ret = -ENOMEM;
+               goto err_lk;
+       }
+       memset(dev->lk_table.table, 0, lk_tab_size);
+       INIT_LIST_HEAD(&dev->pending_mmaps);
+       spin_lock_init(&dev->pending_lock);
+       dev->mmap_offset = PAGE_SIZE;
+       spin_lock_init(&dev->mmap_offset_lock);
+       INIT_LIST_HEAD(&dev->piowait);
+       INIT_LIST_HEAD(&dev->dmawait);
+       INIT_LIST_HEAD(&dev->txwait);
+       INIT_LIST_HEAD(&dev->memwait);
+       INIT_LIST_HEAD(&dev->txreq_free);
+
+       if (ppd->sdma_descq_cnt) {
+               dev->pio_hdrs = dma_alloc_coherent(&dd->pcidev->dev,
+                                               ppd->sdma_descq_cnt *
+                                               sizeof(struct qib_pio_header),
+                                               &dev->pio_hdrs_phys,
+                                               GFP_KERNEL);
+               if (!dev->pio_hdrs) {
+                       ret = -ENOMEM;
+                       goto err_hdrs;
+               }
+       }
+
+       for (i = 0; i < ppd->sdma_descq_cnt; i++) {
+               struct qib_verbs_txreq *tx;
+
+               tx = kzalloc(sizeof *tx, GFP_KERNEL);
+               if (!tx) {
+                       ret = -ENOMEM;
+                       goto err_tx;
+               }
+               tx->hdr_inx = i;
+               list_add(&tx->txreq.list, &dev->txreq_free);
+       }
+
+       /*
+        * The system image GUID is supposed to be the same for all
+        * IB HCAs in a single system but since there can be other
+        * device types in the system, we can't be sure this is unique.
+        */
+       if (!ib_qib_sys_image_guid)
+               ib_qib_sys_image_guid = ppd->guid;
+
+       strlcpy(ibdev->name, "qib%d", IB_DEVICE_NAME_MAX);
+       ibdev->owner = THIS_MODULE;
+       ibdev->node_guid = ppd->guid;
+       ibdev->uverbs_abi_ver = QIB_UVERBS_ABI_VERSION;
+       ibdev->uverbs_cmd_mask =
+               (1ull << IB_USER_VERBS_CMD_GET_CONTEXT)         |
+               (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE)        |
+               (1ull << IB_USER_VERBS_CMD_QUERY_PORT)          |
+               (1ull << IB_USER_VERBS_CMD_ALLOC_PD)            |
+               (1ull << IB_USER_VERBS_CMD_DEALLOC_PD)          |
+               (1ull << IB_USER_VERBS_CMD_CREATE_AH)           |
+               (1ull << IB_USER_VERBS_CMD_MODIFY_AH)           |
+               (1ull << IB_USER_VERBS_CMD_QUERY_AH)            |
+               (1ull << IB_USER_VERBS_CMD_DESTROY_AH)          |
+               (1ull << IB_USER_VERBS_CMD_REG_MR)              |
+               (1ull << IB_USER_VERBS_CMD_DEREG_MR)            |
+               (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) |
+               (1ull << IB_USER_VERBS_CMD_CREATE_CQ)           |
+               (1ull << IB_USER_VERBS_CMD_RESIZE_CQ)           |
+               (1ull << IB_USER_VERBS_CMD_DESTROY_CQ)          |
+               (1ull << IB_USER_VERBS_CMD_POLL_CQ)             |
+               (1ull << IB_USER_VERBS_CMD_REQ_NOTIFY_CQ)       |
+               (1ull << IB_USER_VERBS_CMD_CREATE_QP)           |
+               (1ull << IB_USER_VERBS_CMD_QUERY_QP)            |
+               (1ull << IB_USER_VERBS_CMD_MODIFY_QP)           |
+               (1ull << IB_USER_VERBS_CMD_DESTROY_QP)          |
+               (1ull << IB_USER_VERBS_CMD_POST_SEND)           |
+               (1ull << IB_USER_VERBS_CMD_POST_RECV)           |
+               (1ull << IB_USER_VERBS_CMD_ATTACH_MCAST)        |
+               (1ull << IB_USER_VERBS_CMD_DETACH_MCAST)        |
+               (1ull << IB_USER_VERBS_CMD_CREATE_SRQ)          |
+               (1ull << IB_USER_VERBS_CMD_MODIFY_SRQ)          |
+               (1ull << IB_USER_VERBS_CMD_QUERY_SRQ)           |
+               (1ull << IB_USER_VERBS_CMD_DESTROY_SRQ)         |
+               (1ull << IB_USER_VERBS_CMD_POST_SRQ_RECV);
+       ibdev->node_type = RDMA_NODE_IB_CA;
+       ibdev->phys_port_cnt = dd->num_pports;
+       ibdev->num_comp_vectors = 1;
+       ibdev->dma_device = &dd->pcidev->dev;
+       ibdev->query_device = qib_query_device;
+       ibdev->modify_device = qib_modify_device;
+       ibdev->query_port = qib_query_port;
+       ibdev->modify_port = qib_modify_port;
+       ibdev->query_pkey = qib_query_pkey;
+       ibdev->query_gid = qib_query_gid;
+       ibdev->alloc_ucontext = qib_alloc_ucontext;
+       ibdev->dealloc_ucontext = qib_dealloc_ucontext;
+       ibdev->alloc_pd = qib_alloc_pd;
+       ibdev->dealloc_pd = qib_dealloc_pd;
+       ibdev->create_ah = qib_create_ah;
+       ibdev->destroy_ah = qib_destroy_ah;
+       ibdev->modify_ah = qib_modify_ah;
+       ibdev->query_ah = qib_query_ah;
+       ibdev->create_srq = qib_create_srq;
+       ibdev->modify_srq = qib_modify_srq;
+       ibdev->query_srq = qib_query_srq;
+       ibdev->destroy_srq = qib_destroy_srq;
+       ibdev->create_qp = qib_create_qp;
+       ibdev->modify_qp = qib_modify_qp;
+       ibdev->query_qp = qib_query_qp;
+       ibdev->destroy_qp = qib_destroy_qp;
+       ibdev->post_send = qib_post_send;
+       ibdev->post_recv = qib_post_receive;
+       ibdev->post_srq_recv = qib_post_srq_receive;
+       ibdev->create_cq = qib_create_cq;
+       ibdev->destroy_cq = qib_destroy_cq;
+       ibdev->resize_cq = qib_resize_cq;
+       ibdev->poll_cq = qib_poll_cq;
+       ibdev->req_notify_cq = qib_req_notify_cq;
+       ibdev->get_dma_mr = qib_get_dma_mr;
+       ibdev->reg_phys_mr = qib_reg_phys_mr;
+       ibdev->reg_user_mr = qib_reg_user_mr;
+       ibdev->dereg_mr = qib_dereg_mr;
+       ibdev->alloc_fast_reg_mr = qib_alloc_fast_reg_mr;
+       ibdev->alloc_fast_reg_page_list = qib_alloc_fast_reg_page_list;
+       ibdev->free_fast_reg_page_list = qib_free_fast_reg_page_list;
+       ibdev->alloc_fmr = qib_alloc_fmr;
+       ibdev->map_phys_fmr = qib_map_phys_fmr;
+       ibdev->unmap_fmr = qib_unmap_fmr;
+       ibdev->dealloc_fmr = qib_dealloc_fmr;
+       ibdev->attach_mcast = qib_multicast_attach;
+       ibdev->detach_mcast = qib_multicast_detach;
+       ibdev->process_mad = qib_process_mad;
+       ibdev->mmap = qib_mmap;
+       ibdev->dma_ops = &qib_dma_mapping_ops;
+
+       snprintf(ibdev->node_desc, sizeof(ibdev->node_desc),
+                QIB_IDSTR " %s", init_utsname()->nodename);
+
+       ret = ib_register_device(ibdev, qib_create_port_files);
+       if (ret)
+               goto err_reg;
+
+       ret = qib_create_agents(dev);
+       if (ret)
+               goto err_agents;
+
+       if (qib_verbs_register_sysfs(dd))
+               goto err_class;
+
+       goto bail;
+
+err_class:
+       qib_free_agents(dev);
+err_agents:
+       ib_unregister_device(ibdev);
+err_reg:
+err_tx:
+       while (!list_empty(&dev->txreq_free)) {
+               struct list_head *l = dev->txreq_free.next;
+               struct qib_verbs_txreq *tx;
+
+               list_del(l);
+               tx = list_entry(l, struct qib_verbs_txreq, txreq.list);
+               kfree(tx);
+       }
+       if (ppd->sdma_descq_cnt)
+               dma_free_coherent(&dd->pcidev->dev,
+                                 ppd->sdma_descq_cnt *
+                                       sizeof(struct qib_pio_header),
+                                 dev->pio_hdrs, dev->pio_hdrs_phys);
+err_hdrs:
+       free_pages((unsigned long) dev->lk_table.table, get_order(lk_tab_size));
+err_lk:
+       kfree(dev->qp_table);
+err_qpt:
+       qib_dev_err(dd, "cannot register verbs: %d!\n", -ret);
+bail:
+       return ret;
+}
+
+void qib_unregister_ib_device(struct qib_devdata *dd)
+{
+       struct qib_ibdev *dev = &dd->verbs_dev;
+       struct ib_device *ibdev = &dev->ibdev;
+       u32 qps_inuse;
+       unsigned lk_tab_size;
+
+       qib_verbs_unregister_sysfs(dd);
+
+       qib_free_agents(dev);
+
+       ib_unregister_device(ibdev);
+
+       if (!list_empty(&dev->piowait))
+               qib_dev_err(dd, "piowait list not empty!\n");
+       if (!list_empty(&dev->dmawait))
+               qib_dev_err(dd, "dmawait list not empty!\n");
+       if (!list_empty(&dev->txwait))
+               qib_dev_err(dd, "txwait list not empty!\n");
+       if (!list_empty(&dev->memwait))
+               qib_dev_err(dd, "memwait list not empty!\n");
+       if (dev->dma_mr)
+               qib_dev_err(dd, "DMA MR not NULL!\n");
+
+       qps_inuse = qib_free_all_qps(dd);
+       if (qps_inuse)
+               qib_dev_err(dd, "QP memory leak! %u still in use\n",
+                           qps_inuse);
+
+       del_timer_sync(&dev->mem_timer);
+       qib_free_qpn_table(&dev->qpn_table);
+       while (!list_empty(&dev->txreq_free)) {
+               struct list_head *l = dev->txreq_free.next;
+               struct qib_verbs_txreq *tx;
+
+               list_del(l);
+               tx = list_entry(l, struct qib_verbs_txreq, txreq.list);
+               kfree(tx);
+       }
+       if (dd->pport->sdma_descq_cnt)
+               dma_free_coherent(&dd->pcidev->dev,
+                                 dd->pport->sdma_descq_cnt *
+                                       sizeof(struct qib_pio_header),
+                                 dev->pio_hdrs, dev->pio_hdrs_phys);
+       lk_tab_size = dev->lk_table.max * sizeof(*dev->lk_table.table);
+       free_pages((unsigned long) dev->lk_table.table,
+                  get_order(lk_tab_size));
+       kfree(dev->qp_table);
+}
diff --git a/drivers/infiniband/hw/qib/qib_verbs.h b/drivers/infiniband/hw/qib/qib_verbs.h
new file mode 100644 (file)
index 0000000..bd57c12
--- /dev/null
@@ -0,0 +1,1100 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009, 2010 QLogic Corporation.
+ * All rights reserved.
+ * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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 QIB_VERBS_H
+#define QIB_VERBS_H
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/kref.h>
+#include <linux/workqueue.h>
+#include <rdma/ib_pack.h>
+#include <rdma/ib_user_verbs.h>
+
+struct qib_ctxtdata;
+struct qib_pportdata;
+struct qib_devdata;
+struct qib_verbs_txreq;
+
+#define QIB_MAX_RDMA_ATOMIC     16
+#define QIB_GUIDS_PER_PORT     5
+
+#define QPN_MAX                 (1 << 24)
+#define QPNMAP_ENTRIES          (QPN_MAX / PAGE_SIZE / BITS_PER_BYTE)
+
+/*
+ * Increment this value if any changes that break userspace ABI
+ * compatibility are made.
+ */
+#define QIB_UVERBS_ABI_VERSION       2
+
+/*
+ * Define an ib_cq_notify value that is not valid so we know when CQ
+ * notifications are armed.
+ */
+#define IB_CQ_NONE      (IB_CQ_NEXT_COMP + 1)
+
+#define IB_SEQ_NAK     (3 << 29)
+
+/* AETH NAK opcode values */
+#define IB_RNR_NAK                      0x20
+#define IB_NAK_PSN_ERROR                0x60
+#define IB_NAK_INVALID_REQUEST          0x61
+#define IB_NAK_REMOTE_ACCESS_ERROR      0x62
+#define IB_NAK_REMOTE_OPERATIONAL_ERROR 0x63
+#define IB_NAK_INVALID_RD_REQUEST       0x64
+
+/* Flags for checking QP state (see ib_qib_state_ops[]) */
+#define QIB_POST_SEND_OK                0x01
+#define QIB_POST_RECV_OK                0x02
+#define QIB_PROCESS_RECV_OK             0x04
+#define QIB_PROCESS_SEND_OK             0x08
+#define QIB_PROCESS_NEXT_SEND_OK        0x10
+#define QIB_FLUSH_SEND                 0x20
+#define QIB_FLUSH_RECV                 0x40
+#define QIB_PROCESS_OR_FLUSH_SEND \
+       (QIB_PROCESS_SEND_OK | QIB_FLUSH_SEND)
+
+/* IB Performance Manager status values */
+#define IB_PMA_SAMPLE_STATUS_DONE       0x00
+#define IB_PMA_SAMPLE_STATUS_STARTED    0x01
+#define IB_PMA_SAMPLE_STATUS_RUNNING    0x02
+
+/* Mandatory IB performance counter select values. */
+#define IB_PMA_PORT_XMIT_DATA   cpu_to_be16(0x0001)
+#define IB_PMA_PORT_RCV_DATA    cpu_to_be16(0x0002)
+#define IB_PMA_PORT_XMIT_PKTS   cpu_to_be16(0x0003)
+#define IB_PMA_PORT_RCV_PKTS    cpu_to_be16(0x0004)
+#define IB_PMA_PORT_XMIT_WAIT   cpu_to_be16(0x0005)
+
+#define QIB_VENDOR_IPG         cpu_to_be16(0xFFA0)
+
+#define IB_BTH_REQ_ACK         (1 << 31)
+#define IB_BTH_SOLICITED       (1 << 23)
+#define IB_BTH_MIG_REQ         (1 << 22)
+
+/* XXX Should be defined in ib_verbs.h enum ib_port_cap_flags */
+#define IB_PORT_OTHER_LOCAL_CHANGES_SUP (1 << 26)
+
+#define IB_GRH_VERSION         6
+#define IB_GRH_VERSION_MASK    0xF
+#define IB_GRH_VERSION_SHIFT   28
+#define IB_GRH_TCLASS_MASK     0xFF
+#define IB_GRH_TCLASS_SHIFT    20
+#define IB_GRH_FLOW_MASK       0xFFFFF
+#define IB_GRH_FLOW_SHIFT      0
+#define IB_GRH_NEXT_HDR                0x1B
+
+#define IB_DEFAULT_GID_PREFIX  cpu_to_be64(0xfe80000000000000ULL)
+
+/* Values for set/get portinfo VLCap OperationalVLs */
+#define IB_VL_VL0       1
+#define IB_VL_VL0_1     2
+#define IB_VL_VL0_3     3
+#define IB_VL_VL0_7     4
+#define IB_VL_VL0_14    5
+
+static inline int qib_num_vls(int vls)
+{
+       switch (vls) {
+       default:
+       case IB_VL_VL0:
+               return 1;
+       case IB_VL_VL0_1:
+               return 2;
+       case IB_VL_VL0_3:
+               return 4;
+       case IB_VL_VL0_7:
+               return 8;
+       case IB_VL_VL0_14:
+               return 15;
+       }
+}
+
+struct ib_reth {
+       __be64 vaddr;
+       __be32 rkey;
+       __be32 length;
+} __attribute__ ((packed));
+
+struct ib_atomic_eth {
+       __be32 vaddr[2];        /* unaligned so access as 2 32-bit words */
+       __be32 rkey;
+       __be64 swap_data;
+       __be64 compare_data;
+} __attribute__ ((packed));
+
+struct qib_other_headers {
+       __be32 bth[3];
+       union {
+               struct {
+                       __be32 deth[2];
+                       __be32 imm_data;
+               } ud;
+               struct {
+                       struct ib_reth reth;
+                       __be32 imm_data;
+               } rc;
+               struct {
+                       __be32 aeth;
+                       __be32 atomic_ack_eth[2];
+               } at;
+               __be32 imm_data;
+               __be32 aeth;
+               struct ib_atomic_eth atomic_eth;
+       } u;
+} __attribute__ ((packed));
+
+/*
+ * Note that UD packets with a GRH header are 8+40+12+8 = 68 bytes
+ * long (72 w/ imm_data).  Only the first 56 bytes of the IB header
+ * will be in the eager header buffer.  The remaining 12 or 16 bytes
+ * are in the data buffer.
+ */
+struct qib_ib_header {
+       __be16 lrh[4];
+       union {
+               struct {
+                       struct ib_grh grh;
+                       struct qib_other_headers oth;
+               } l;
+               struct qib_other_headers oth;
+       } u;
+} __attribute__ ((packed));
+
+struct qib_pio_header {
+       __le32 pbc[2];
+       struct qib_ib_header hdr;
+} __attribute__ ((packed));
+
+/*
+ * There is one struct qib_mcast for each multicast GID.
+ * All attached QPs are then stored as a list of
+ * struct qib_mcast_qp.
+ */
+struct qib_mcast_qp {
+       struct list_head list;
+       struct qib_qp *qp;
+};
+
+struct qib_mcast {
+       struct rb_node rb_node;
+       union ib_gid mgid;
+       struct list_head qp_list;
+       wait_queue_head_t wait;
+       atomic_t refcount;
+       int n_attached;
+};
+
+/* Protection domain */
+struct qib_pd {
+       struct ib_pd ibpd;
+       int user;               /* non-zero if created from user space */
+};
+
+/* Address Handle */
+struct qib_ah {
+       struct ib_ah ibah;
+       struct ib_ah_attr attr;
+       atomic_t refcount;
+};
+
+/*
+ * This structure is used by qib_mmap() to validate an offset
+ * when an mmap() request is made.  The vm_area_struct then uses
+ * this as its vm_private_data.
+ */
+struct qib_mmap_info {
+       struct list_head pending_mmaps;
+       struct ib_ucontext *context;
+       void *obj;
+       __u64 offset;
+       struct kref ref;
+       unsigned size;
+};
+
+/*
+ * This structure is used to contain the head pointer, tail pointer,
+ * and completion queue entries as a single memory allocation so
+ * it can be mmap'ed into user space.
+ */
+struct qib_cq_wc {
+       u32 head;               /* index of next entry to fill */
+       u32 tail;               /* index of next ib_poll_cq() entry */
+       union {
+               /* these are actually size ibcq.cqe + 1 */
+               struct ib_uverbs_wc uqueue[0];
+               struct ib_wc kqueue[0];
+       };
+};
+
+/*
+ * The completion queue structure.
+ */
+struct qib_cq {
+       struct ib_cq ibcq;
+       struct work_struct comptask;
+       spinlock_t lock; /* protect changes in this struct */
+       u8 notify;
+       u8 triggered;
+       struct qib_cq_wc *queue;
+       struct qib_mmap_info *ip;
+};
+
+/*
+ * A segment is a linear region of low physical memory.
+ * XXX Maybe we should use phys addr here and kmap()/kunmap().
+ * Used by the verbs layer.
+ */
+struct qib_seg {
+       void *vaddr;
+       size_t length;
+};
+
+/* The number of qib_segs that fit in a page. */
+#define QIB_SEGSZ     (PAGE_SIZE / sizeof(struct qib_seg))
+
+struct qib_segarray {
+       struct qib_seg segs[QIB_SEGSZ];
+};
+
+struct qib_mregion {
+       struct ib_pd *pd;       /* shares refcnt of ibmr.pd */
+       u64 user_base;          /* User's address for this region */
+       u64 iova;               /* IB start address of this region */
+       size_t length;
+       u32 lkey;
+       u32 offset;             /* offset (bytes) to start of region */
+       int access_flags;
+       u32 max_segs;           /* number of qib_segs in all the arrays */
+       u32 mapsz;              /* size of the map array */
+       atomic_t refcount;
+       struct qib_segarray *map[0];    /* the segments */
+};
+
+/*
+ * These keep track of the copy progress within a memory region.
+ * Used by the verbs layer.
+ */
+struct qib_sge {
+       struct qib_mregion *mr;
+       void *vaddr;            /* kernel virtual address of segment */
+       u32 sge_length;         /* length of the SGE */
+       u32 length;             /* remaining length of the segment */
+       u16 m;                  /* current index: mr->map[m] */
+       u16 n;                  /* current index: mr->map[m]->segs[n] */
+};
+
+/* Memory region */
+struct qib_mr {
+       struct ib_mr ibmr;
+       struct ib_umem *umem;
+       struct qib_mregion mr;  /* must be last */
+};
+
+/*
+ * Send work request queue entry.
+ * The size of the sg_list is determined when the QP is created and stored
+ * in qp->s_max_sge.
+ */
+struct qib_swqe {
+       struct ib_send_wr wr;   /* don't use wr.sg_list */
+       u32 psn;                /* first packet sequence number */
+       u32 lpsn;               /* last packet sequence number */
+       u32 ssn;                /* send sequence number */
+       u32 length;             /* total length of data in sg_list */
+       struct qib_sge sg_list[0];
+};
+
+/*
+ * Receive work request queue entry.
+ * The size of the sg_list is determined when the QP (or SRQ) is created
+ * and stored in qp->r_rq.max_sge (or srq->rq.max_sge).
+ */
+struct qib_rwqe {
+       u64 wr_id;
+       u8 num_sge;
+       struct ib_sge sg_list[0];
+};
+
+/*
+ * This structure is used to contain the head pointer, tail pointer,
+ * and receive work queue entries as a single memory allocation so
+ * it can be mmap'ed into user space.
+ * Note that the wq array elements are variable size so you can't
+ * just index into the array to get the N'th element;
+ * use get_rwqe_ptr() instead.
+ */
+struct qib_rwq {
+       u32 head;               /* new work requests posted to the head */
+       u32 tail;               /* receives pull requests from here. */
+       struct qib_rwqe wq[0];
+};
+
+struct qib_rq {
+       struct qib_rwq *wq;
+       spinlock_t lock; /* protect changes in this struct */
+       u32 size;               /* size of RWQE array */
+       u8 max_sge;
+};
+
+struct qib_srq {
+       struct ib_srq ibsrq;
+       struct qib_rq rq;
+       struct qib_mmap_info *ip;
+       /* send signal when number of RWQEs < limit */
+       u32 limit;
+};
+
+struct qib_sge_state {
+       struct qib_sge *sg_list;      /* next SGE to be used if any */
+       struct qib_sge sge;   /* progress state for the current SGE */
+       u32 total_len;
+       u8 num_sge;
+};
+
+/*
+ * This structure holds the information that the send tasklet needs
+ * to send a RDMA read response or atomic operation.
+ */
+struct qib_ack_entry {
+       u8 opcode;
+       u8 sent;
+       u32 psn;
+       u32 lpsn;
+       union {
+               struct qib_sge rdma_sge;
+               u64 atomic_data;
+       };
+};
+
+/*
+ * Variables prefixed with s_ are for the requester (sender).
+ * Variables prefixed with r_ are for the responder (receiver).
+ * Variables prefixed with ack_ are for responder replies.
+ *
+ * Common variables are protected by both r_rq.lock and s_lock in that order
+ * which only happens in modify_qp() or changing the QP 'state'.
+ */
+struct qib_qp {
+       struct ib_qp ibqp;
+       struct qib_qp *next;            /* link list for QPN hash table */
+       struct qib_qp *timer_next;      /* link list for qib_ib_timer() */
+       struct list_head iowait;        /* link for wait PIO buf */
+       struct list_head rspwait;       /* link for waititing to respond */
+       struct ib_ah_attr remote_ah_attr;
+       struct ib_ah_attr alt_ah_attr;
+       struct qib_ib_header s_hdr;     /* next packet header to send */
+       atomic_t refcount;
+       wait_queue_head_t wait;
+       wait_queue_head_t wait_dma;
+       struct timer_list s_timer;
+       struct work_struct s_work;
+       struct qib_mmap_info *ip;
+       struct qib_sge_state *s_cur_sge;
+       struct qib_verbs_txreq *s_tx;
+       struct qib_mregion *s_rdma_mr;
+       struct qib_sge_state s_sge;     /* current send request data */
+       struct qib_ack_entry s_ack_queue[QIB_MAX_RDMA_ATOMIC + 1];
+       struct qib_sge_state s_ack_rdma_sge;
+       struct qib_sge_state s_rdma_read_sge;
+       struct qib_sge_state r_sge;     /* current receive data */
+       spinlock_t r_lock;      /* used for APM */
+       spinlock_t s_lock;
+       atomic_t s_dma_busy;
+       unsigned processor_id;  /* Processor ID QP is bound to */
+       u32 s_flags;
+       u32 s_cur_size;         /* size of send packet in bytes */
+       u32 s_len;              /* total length of s_sge */
+       u32 s_rdma_read_len;    /* total length of s_rdma_read_sge */
+       u32 s_next_psn;         /* PSN for next request */
+       u32 s_last_psn;         /* last response PSN processed */
+       u32 s_sending_psn;      /* lowest PSN that is being sent */
+       u32 s_sending_hpsn;     /* highest PSN that is being sent */
+       u32 s_psn;              /* current packet sequence number */
+       u32 s_ack_rdma_psn;     /* PSN for sending RDMA read responses */
+       u32 s_ack_psn;          /* PSN for acking sends and RDMA writes */
+       u32 s_rnr_timeout;      /* number of milliseconds for RNR timeout */
+       u32 r_ack_psn;          /* PSN for next ACK or atomic ACK */
+       u64 r_wr_id;            /* ID for current receive WQE */
+       unsigned long r_aflags;
+       u32 r_len;              /* total length of r_sge */
+       u32 r_rcv_len;          /* receive data len processed */
+       u32 r_psn;              /* expected rcv packet sequence number */
+       u32 r_msn;              /* message sequence number */
+       u16 s_hdrwords;         /* size of s_hdr in 32 bit words */
+       u16 s_rdma_ack_cnt;
+       u8 state;               /* QP state */
+       u8 s_state;             /* opcode of last packet sent */
+       u8 s_ack_state;         /* opcode of packet to ACK */
+       u8 s_nak_state;         /* non-zero if NAK is pending */
+       u8 r_state;             /* opcode of last packet received */
+       u8 r_nak_state;         /* non-zero if NAK is pending */
+       u8 r_min_rnr_timer;     /* retry timeout value for RNR NAKs */
+       u8 r_flags;
+       u8 r_max_rd_atomic;     /* max number of RDMA read/atomic to receive */
+       u8 r_head_ack_queue;    /* index into s_ack_queue[] */
+       u8 qp_access_flags;
+       u8 s_max_sge;           /* size of s_wq->sg_list */
+       u8 s_retry_cnt;         /* number of times to retry */
+       u8 s_rnr_retry_cnt;
+       u8 s_retry;             /* requester retry counter */
+       u8 s_rnr_retry;         /* requester RNR retry counter */
+       u8 s_pkey_index;        /* PKEY index to use */
+       u8 s_alt_pkey_index;    /* Alternate path PKEY index to use */
+       u8 s_max_rd_atomic;     /* max number of RDMA read/atomic to send */
+       u8 s_num_rd_atomic;     /* number of RDMA read/atomic pending */
+       u8 s_tail_ack_queue;    /* index into s_ack_queue[] */
+       u8 s_srate;
+       u8 s_draining;
+       u8 s_mig_state;
+       u8 timeout;             /* Timeout for this QP */
+       u8 alt_timeout;         /* Alternate path timeout for this QP */
+       u8 port_num;
+       enum ib_mtu path_mtu;
+       u32 remote_qpn;
+       u32 qkey;               /* QKEY for this QP (for UD or RD) */
+       u32 s_size;             /* send work queue size */
+       u32 s_head;             /* new entries added here */
+       u32 s_tail;             /* next entry to process */
+       u32 s_cur;              /* current work queue entry */
+       u32 s_acked;            /* last un-ACK'ed entry */
+       u32 s_last;             /* last completed entry */
+       u32 s_ssn;              /* SSN of tail entry */
+       u32 s_lsn;              /* limit sequence number (credit) */
+       struct qib_swqe *s_wq;  /* send work queue */
+       struct qib_swqe *s_wqe;
+       struct qib_rq r_rq;             /* receive work queue */
+       struct qib_sge r_sg_list[0];    /* verified SGEs */
+};
+
+/*
+ * Atomic bit definitions for r_aflags.
+ */
+#define QIB_R_WRID_VALID        0
+#define QIB_R_REWIND_SGE        1
+
+/*
+ * Bit definitions for r_flags.
+ */
+#define QIB_R_REUSE_SGE 0x01
+#define QIB_R_RDMAR_SEQ 0x02
+#define QIB_R_RSP_NAK   0x04
+#define QIB_R_RSP_SEND  0x08
+#define QIB_R_COMM_EST  0x10
+
+/*
+ * Bit definitions for s_flags.
+ *
+ * QIB_S_SIGNAL_REQ_WR - set if QP send WRs contain completion signaled
+ * QIB_S_BUSY - send tasklet is processing the QP
+ * QIB_S_TIMER - the RC retry timer is active
+ * QIB_S_ACK_PENDING - an ACK is waiting to be sent after RDMA read/atomics
+ * QIB_S_WAIT_FENCE - waiting for all prior RDMA read or atomic SWQEs
+ *                         before processing the next SWQE
+ * QIB_S_WAIT_RDMAR - waiting for a RDMA read or atomic SWQE to complete
+ *                         before processing the next SWQE
+ * QIB_S_WAIT_RNR - waiting for RNR timeout
+ * QIB_S_WAIT_SSN_CREDIT - waiting for RC credits to process next SWQE
+ * QIB_S_WAIT_DMA - waiting for send DMA queue to drain before generating
+ *                  next send completion entry not via send DMA
+ * QIB_S_WAIT_PIO - waiting for a send buffer to be available
+ * QIB_S_WAIT_TX - waiting for a struct qib_verbs_txreq to be available
+ * QIB_S_WAIT_DMA_DESC - waiting for DMA descriptors to be available
+ * QIB_S_WAIT_KMEM - waiting for kernel memory to be available
+ * QIB_S_WAIT_PSN - waiting for a packet to exit the send DMA queue
+ * QIB_S_WAIT_ACK - waiting for an ACK packet before sending more requests
+ * QIB_S_SEND_ONE - send one packet, request ACK, then wait for ACK
+ */
+#define QIB_S_SIGNAL_REQ_WR    0x0001
+#define QIB_S_BUSY             0x0002
+#define QIB_S_TIMER            0x0004
+#define QIB_S_RESP_PENDING     0x0008
+#define QIB_S_ACK_PENDING      0x0010
+#define QIB_S_WAIT_FENCE       0x0020
+#define QIB_S_WAIT_RDMAR       0x0040
+#define QIB_S_WAIT_RNR         0x0080
+#define QIB_S_WAIT_SSN_CREDIT  0x0100
+#define QIB_S_WAIT_DMA         0x0200
+#define QIB_S_WAIT_PIO         0x0400
+#define QIB_S_WAIT_TX          0x0800
+#define QIB_S_WAIT_DMA_DESC    0x1000
+#define QIB_S_WAIT_KMEM                0x2000
+#define QIB_S_WAIT_PSN         0x4000
+#define QIB_S_WAIT_ACK         0x8000
+#define QIB_S_SEND_ONE         0x10000
+#define QIB_S_UNLIMITED_CREDIT 0x20000
+
+/*
+ * Wait flags that would prevent any packet type from being sent.
+ */
+#define QIB_S_ANY_WAIT_IO (QIB_S_WAIT_PIO | QIB_S_WAIT_TX | \
+       QIB_S_WAIT_DMA_DESC | QIB_S_WAIT_KMEM)
+
+/*
+ * Wait flags that would prevent send work requests from making progress.
+ */
+#define QIB_S_ANY_WAIT_SEND (QIB_S_WAIT_FENCE | QIB_S_WAIT_RDMAR | \
+       QIB_S_WAIT_RNR | QIB_S_WAIT_SSN_CREDIT | QIB_S_WAIT_DMA | \
+       QIB_S_WAIT_PSN | QIB_S_WAIT_ACK)
+
+#define QIB_S_ANY_WAIT (QIB_S_ANY_WAIT_IO | QIB_S_ANY_WAIT_SEND)
+
+#define QIB_PSN_CREDIT  16
+
+/*
+ * Since struct qib_swqe is not a fixed size, we can't simply index into
+ * struct qib_qp.s_wq.  This function does the array index computation.
+ */
+static inline struct qib_swqe *get_swqe_ptr(struct qib_qp *qp,
+                                             unsigned n)
+{
+       return (struct qib_swqe *)((char *)qp->s_wq +
+                                    (sizeof(struct qib_swqe) +
+                                     qp->s_max_sge *
+                                     sizeof(struct qib_sge)) * n);
+}
+
+/*
+ * Since struct qib_rwqe is not a fixed size, we can't simply index into
+ * struct qib_rwq.wq.  This function does the array index computation.
+ */
+static inline struct qib_rwqe *get_rwqe_ptr(struct qib_rq *rq, unsigned n)
+{
+       return (struct qib_rwqe *)
+               ((char *) rq->wq->wq +
+                (sizeof(struct qib_rwqe) +
+                 rq->max_sge * sizeof(struct ib_sge)) * n);
+}
+
+/*
+ * QPN-map pages start out as NULL, they get allocated upon
+ * first use and are never deallocated. This way,
+ * large bitmaps are not allocated unless large numbers of QPs are used.
+ */
+struct qpn_map {
+       void *page;
+};
+
+struct qib_qpn_table {
+       spinlock_t lock; /* protect changes in this struct */
+       unsigned flags;         /* flags for QP0/1 allocated for each port */
+       u32 last;               /* last QP number allocated */
+       u32 nmaps;              /* size of the map table */
+       u16 limit;
+       u16 mask;
+       /* bit map of free QP numbers other than 0/1 */
+       struct qpn_map map[QPNMAP_ENTRIES];
+};
+
+struct qib_lkey_table {
+       spinlock_t lock; /* protect changes in this struct */
+       u32 next;               /* next unused index (speeds search) */
+       u32 gen;                /* generation count */
+       u32 max;                /* size of the table */
+       struct qib_mregion **table;
+};
+
+struct qib_opcode_stats {
+       u64 n_packets;          /* number of packets */
+       u64 n_bytes;            /* total number of bytes */
+};
+
+struct qib_ibport {
+       struct qib_qp *qp0;
+       struct qib_qp *qp1;
+       struct ib_mad_agent *send_agent;        /* agent for SMI (traps) */
+       struct qib_ah *sm_ah;
+       struct qib_ah *smi_ah;
+       struct rb_root mcast_tree;
+       spinlock_t lock;                /* protect changes in this struct */
+
+       /* non-zero when timer is set */
+       unsigned long mkey_lease_timeout;
+       unsigned long trap_timeout;
+       __be64 gid_prefix;      /* in network order */
+       __be64 mkey;
+       __be64 guids[QIB_GUIDS_PER_PORT - 1];   /* writable GUIDs */
+       u64 tid;                /* TID for traps */
+       u64 n_unicast_xmit;     /* total unicast packets sent */
+       u64 n_unicast_rcv;      /* total unicast packets received */
+       u64 n_multicast_xmit;   /* total multicast packets sent */
+       u64 n_multicast_rcv;    /* total multicast packets received */
+       u64 z_symbol_error_counter;             /* starting count for PMA */
+       u64 z_link_error_recovery_counter;      /* starting count for PMA */
+       u64 z_link_downed_counter;              /* starting count for PMA */
+       u64 z_port_rcv_errors;                  /* starting count for PMA */
+       u64 z_port_rcv_remphys_errors;          /* starting count for PMA */
+       u64 z_port_xmit_discards;               /* starting count for PMA */
+       u64 z_port_xmit_data;                   /* starting count for PMA */
+       u64 z_port_rcv_data;                    /* starting count for PMA */
+       u64 z_port_xmit_packets;                /* starting count for PMA */
+       u64 z_port_rcv_packets;                 /* starting count for PMA */
+       u32 z_local_link_integrity_errors;      /* starting count for PMA */
+       u32 z_excessive_buffer_overrun_errors;  /* starting count for PMA */
+       u32 z_vl15_dropped;                     /* starting count for PMA */
+       u32 n_rc_resends;
+       u32 n_rc_acks;
+       u32 n_rc_qacks;
+       u32 n_rc_delayed_comp;
+       u32 n_seq_naks;
+       u32 n_rdma_seq;
+       u32 n_rnr_naks;
+       u32 n_other_naks;
+       u32 n_loop_pkts;
+       u32 n_pkt_drops;
+       u32 n_vl15_dropped;
+       u32 n_rc_timeouts;
+       u32 n_dmawait;
+       u32 n_unaligned;
+       u32 n_rc_dupreq;
+       u32 n_rc_seqnak;
+       u32 port_cap_flags;
+       u32 pma_sample_start;
+       u32 pma_sample_interval;
+       __be16 pma_counter_select[5];
+       u16 pma_tag;
+       u16 pkey_violations;
+       u16 qkey_violations;
+       u16 mkey_violations;
+       u16 mkey_lease_period;
+       u16 sm_lid;
+       u16 repress_traps;
+       u8 sm_sl;
+       u8 mkeyprot;
+       u8 subnet_timeout;
+       u8 vl_high_limit;
+       u8 sl_to_vl[16];
+
+       struct qib_opcode_stats opstats[128];
+};
+
+struct qib_ibdev {
+       struct ib_device ibdev;
+       struct list_head pending_mmaps;
+       spinlock_t mmap_offset_lock; /* protect mmap_offset */
+       u32 mmap_offset;
+       struct qib_mregion *dma_mr;
+
+       /* QP numbers are shared by all IB ports */
+       struct qib_qpn_table qpn_table;
+       struct qib_lkey_table lk_table;
+       struct list_head piowait;       /* list for wait PIO buf */
+       struct list_head dmawait;       /* list for wait DMA */
+       struct list_head txwait;        /* list for wait qib_verbs_txreq */
+       struct list_head memwait;       /* list for wait kernel memory */
+       struct list_head txreq_free;
+       struct timer_list mem_timer;
+       struct qib_qp **qp_table;
+       struct qib_pio_header *pio_hdrs;
+       dma_addr_t pio_hdrs_phys;
+       /* list of QPs waiting for RNR timer */
+       spinlock_t pending_lock; /* protect wait lists, PMA counters, etc. */
+       unsigned qp_table_size; /* size of the hash table */
+       spinlock_t qpt_lock;
+
+       u32 n_piowait;
+       u32 n_txwait;
+
+       u32 n_pds_allocated;    /* number of PDs allocated for device */
+       spinlock_t n_pds_lock;
+       u32 n_ahs_allocated;    /* number of AHs allocated for device */
+       spinlock_t n_ahs_lock;
+       u32 n_cqs_allocated;    /* number of CQs allocated for device */
+       spinlock_t n_cqs_lock;
+       u32 n_qps_allocated;    /* number of QPs allocated for device */
+       spinlock_t n_qps_lock;
+       u32 n_srqs_allocated;   /* number of SRQs allocated for device */
+       spinlock_t n_srqs_lock;
+       u32 n_mcast_grps_allocated; /* number of mcast groups allocated */
+       spinlock_t n_mcast_grps_lock;
+};
+
+struct qib_verbs_counters {
+       u64 symbol_error_counter;
+       u64 link_error_recovery_counter;
+       u64 link_downed_counter;
+       u64 port_rcv_errors;
+       u64 port_rcv_remphys_errors;
+       u64 port_xmit_discards;
+       u64 port_xmit_data;
+       u64 port_rcv_data;
+       u64 port_xmit_packets;
+       u64 port_rcv_packets;
+       u32 local_link_integrity_errors;
+       u32 excessive_buffer_overrun_errors;
+       u32 vl15_dropped;
+};
+
+static inline struct qib_mr *to_imr(struct ib_mr *ibmr)
+{
+       return container_of(ibmr, struct qib_mr, ibmr);
+}
+
+static inline struct qib_pd *to_ipd(struct ib_pd *ibpd)
+{
+       return container_of(ibpd, struct qib_pd, ibpd);
+}
+
+static inline struct qib_ah *to_iah(struct ib_ah *ibah)
+{
+       return container_of(ibah, struct qib_ah, ibah);
+}
+
+static inline struct qib_cq *to_icq(struct ib_cq *ibcq)
+{
+       return container_of(ibcq, struct qib_cq, ibcq);
+}
+
+static inline struct qib_srq *to_isrq(struct ib_srq *ibsrq)
+{
+       return container_of(ibsrq, struct qib_srq, ibsrq);
+}
+
+static inline struct qib_qp *to_iqp(struct ib_qp *ibqp)
+{
+       return container_of(ibqp, struct qib_qp, ibqp);
+}
+
+static inline struct qib_ibdev *to_idev(struct ib_device *ibdev)
+{
+       return container_of(ibdev, struct qib_ibdev, ibdev);
+}
+
+/*
+ * Send if not busy or waiting for I/O and either
+ * a RC response is pending or we can process send work requests.
+ */
+static inline int qib_send_ok(struct qib_qp *qp)
+{
+       return !(qp->s_flags & (QIB_S_BUSY | QIB_S_ANY_WAIT_IO)) &&
+               (qp->s_hdrwords || (qp->s_flags & QIB_S_RESP_PENDING) ||
+                !(qp->s_flags & QIB_S_ANY_WAIT_SEND));
+}
+
+extern struct workqueue_struct *qib_wq;
+extern struct workqueue_struct *qib_cq_wq;
+
+/*
+ * This must be called with s_lock held.
+ */
+static inline void qib_schedule_send(struct qib_qp *qp)
+{
+       if (qib_send_ok(qp)) {
+               if (qp->processor_id == smp_processor_id())
+                       queue_work(qib_wq, &qp->s_work);
+               else
+                       queue_work_on(qp->processor_id,
+                                     qib_wq, &qp->s_work);
+       }
+}
+
+static inline int qib_pkey_ok(u16 pkey1, u16 pkey2)
+{
+       u16 p1 = pkey1 & 0x7FFF;
+       u16 p2 = pkey2 & 0x7FFF;
+
+       /*
+        * Low 15 bits must be non-zero and match, and
+        * one of the two must be a full member.
+        */
+       return p1 && p1 == p2 && ((__s16)pkey1 < 0 || (__s16)pkey2 < 0);
+}
+
+void qib_bad_pqkey(struct qib_ibport *ibp, __be16 trap_num, u32 key, u32 sl,
+                  u32 qp1, u32 qp2, __be16 lid1, __be16 lid2);
+void qib_cap_mask_chg(struct qib_ibport *ibp);
+void qib_sys_guid_chg(struct qib_ibport *ibp);
+void qib_node_desc_chg(struct qib_ibport *ibp);
+int qib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
+                   struct ib_wc *in_wc, struct ib_grh *in_grh,
+                   struct ib_mad *in_mad, struct ib_mad *out_mad);
+int qib_create_agents(struct qib_ibdev *dev);
+void qib_free_agents(struct qib_ibdev *dev);
+
+/*
+ * Compare the lower 24 bits of the two values.
+ * Returns an integer <, ==, or > than zero.
+ */
+static inline int qib_cmp24(u32 a, u32 b)
+{
+       return (((int) a) - ((int) b)) << 8;
+}
+
+struct qib_mcast *qib_mcast_find(struct qib_ibport *ibp, union ib_gid *mgid);
+
+int qib_snapshot_counters(struct qib_pportdata *ppd, u64 *swords,
+                         u64 *rwords, u64 *spkts, u64 *rpkts,
+                         u64 *xmit_wait);
+
+int qib_get_counters(struct qib_pportdata *ppd,
+                    struct qib_verbs_counters *cntrs);
+
+int qib_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid);
+
+int qib_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid);
+
+int qib_mcast_tree_empty(struct qib_ibport *ibp);
+
+__be32 qib_compute_aeth(struct qib_qp *qp);
+
+struct qib_qp *qib_lookup_qpn(struct qib_ibport *ibp, u32 qpn);
+
+struct ib_qp *qib_create_qp(struct ib_pd *ibpd,
+                           struct ib_qp_init_attr *init_attr,
+                           struct ib_udata *udata);
+
+int qib_destroy_qp(struct ib_qp *ibqp);
+
+int qib_error_qp(struct qib_qp *qp, enum ib_wc_status err);
+
+int qib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+                 int attr_mask, struct ib_udata *udata);
+
+int qib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+                int attr_mask, struct ib_qp_init_attr *init_attr);
+
+unsigned qib_free_all_qps(struct qib_devdata *dd);
+
+void qib_init_qpn_table(struct qib_devdata *dd, struct qib_qpn_table *qpt);
+
+void qib_free_qpn_table(struct qib_qpn_table *qpt);
+
+void qib_get_credit(struct qib_qp *qp, u32 aeth);
+
+unsigned qib_pkt_delay(u32 plen, u8 snd_mult, u8 rcv_mult);
+
+void qib_verbs_sdma_desc_avail(struct qib_pportdata *ppd, unsigned avail);
+
+void qib_put_txreq(struct qib_verbs_txreq *tx);
+
+int qib_verbs_send(struct qib_qp *qp, struct qib_ib_header *hdr,
+                  u32 hdrwords, struct qib_sge_state *ss, u32 len);
+
+void qib_copy_sge(struct qib_sge_state *ss, void *data, u32 length,
+                 int release);
+
+void qib_skip_sge(struct qib_sge_state *ss, u32 length, int release);
+
+void qib_uc_rcv(struct qib_ibport *ibp, struct qib_ib_header *hdr,
+               int has_grh, void *data, u32 tlen, struct qib_qp *qp);
+
+void qib_rc_rcv(struct qib_ctxtdata *rcd, struct qib_ib_header *hdr,
+               int has_grh, void *data, u32 tlen, struct qib_qp *qp);
+
+int qib_check_ah(struct ib_device *ibdev, struct ib_ah_attr *ah_attr);
+
+void qib_rc_rnr_retry(unsigned long arg);
+
+void qib_rc_send_complete(struct qib_qp *qp, struct qib_ib_header *hdr);
+
+void qib_rc_error(struct qib_qp *qp, enum ib_wc_status err);
+
+int qib_post_ud_send(struct qib_qp *qp, struct ib_send_wr *wr);
+
+void qib_ud_rcv(struct qib_ibport *ibp, struct qib_ib_header *hdr,
+               int has_grh, void *data, u32 tlen, struct qib_qp *qp);
+
+int qib_alloc_lkey(struct qib_lkey_table *rkt, struct qib_mregion *mr);
+
+int qib_free_lkey(struct qib_ibdev *dev, struct qib_mregion *mr);
+
+int qib_lkey_ok(struct qib_lkey_table *rkt, struct qib_pd *pd,
+               struct qib_sge *isge, struct ib_sge *sge, int acc);
+
+int qib_rkey_ok(struct qib_qp *qp, struct qib_sge *sge,
+               u32 len, u64 vaddr, u32 rkey, int acc);
+
+int qib_post_srq_receive(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
+                        struct ib_recv_wr **bad_wr);
+
+struct ib_srq *qib_create_srq(struct ib_pd *ibpd,
+                             struct ib_srq_init_attr *srq_init_attr,
+                             struct ib_udata *udata);
+
+int qib_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
+                  enum ib_srq_attr_mask attr_mask,
+                  struct ib_udata *udata);
+
+int qib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr);
+
+int qib_destroy_srq(struct ib_srq *ibsrq);
+
+void qib_cq_enter(struct qib_cq *cq, struct ib_wc *entry, int sig);
+
+int qib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry);
+
+struct ib_cq *qib_create_cq(struct ib_device *ibdev, int entries,
+                           int comp_vector, struct ib_ucontext *context,
+                           struct ib_udata *udata);
+
+int qib_destroy_cq(struct ib_cq *ibcq);
+
+int qib_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags notify_flags);
+
+int qib_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata);
+
+struct ib_mr *qib_get_dma_mr(struct ib_pd *pd, int acc);
+
+struct ib_mr *qib_reg_phys_mr(struct ib_pd *pd,
+                             struct ib_phys_buf *buffer_list,
+                             int num_phys_buf, int acc, u64 *iova_start);
+
+struct ib_mr *qib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
+                             u64 virt_addr, int mr_access_flags,
+                             struct ib_udata *udata);
+
+int qib_dereg_mr(struct ib_mr *ibmr);
+
+struct ib_mr *qib_alloc_fast_reg_mr(struct ib_pd *pd, int max_page_list_len);
+
+struct ib_fast_reg_page_list *qib_alloc_fast_reg_page_list(
+                               struct ib_device *ibdev, int page_list_len);
+
+void qib_free_fast_reg_page_list(struct ib_fast_reg_page_list *pl);
+
+int qib_fast_reg_mr(struct qib_qp *qp, struct ib_send_wr *wr);
+
+struct ib_fmr *qib_alloc_fmr(struct ib_pd *pd, int mr_access_flags,
+                            struct ib_fmr_attr *fmr_attr);
+
+int qib_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list,
+                    int list_len, u64 iova);
+
+int qib_unmap_fmr(struct list_head *fmr_list);
+
+int qib_dealloc_fmr(struct ib_fmr *ibfmr);
+
+void qib_release_mmap_info(struct kref *ref);
+
+struct qib_mmap_info *qib_create_mmap_info(struct qib_ibdev *dev, u32 size,
+                                          struct ib_ucontext *context,
+                                          void *obj);
+
+void qib_update_mmap_info(struct qib_ibdev *dev, struct qib_mmap_info *ip,
+                         u32 size, void *obj);
+
+int qib_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
+
+int qib_get_rwqe(struct qib_qp *qp, int wr_id_only);
+
+void qib_migrate_qp(struct qib_qp *qp);
+
+int qib_ruc_check_hdr(struct qib_ibport *ibp, struct qib_ib_header *hdr,
+                     int has_grh, struct qib_qp *qp, u32 bth0);
+
+u32 qib_make_grh(struct qib_ibport *ibp, struct ib_grh *hdr,
+                struct ib_global_route *grh, u32 hwords, u32 nwords);
+
+void qib_make_ruc_header(struct qib_qp *qp, struct qib_other_headers *ohdr,
+                        u32 bth0, u32 bth2);
+
+void qib_do_send(struct work_struct *work);
+
+void qib_send_complete(struct qib_qp *qp, struct qib_swqe *wqe,
+                      enum ib_wc_status status);
+
+void qib_send_rc_ack(struct qib_qp *qp);
+
+int qib_make_rc_req(struct qib_qp *qp);
+
+int qib_make_uc_req(struct qib_qp *qp);
+
+int qib_make_ud_req(struct qib_qp *qp);
+
+int qib_register_ib_device(struct qib_devdata *);
+
+void qib_unregister_ib_device(struct qib_devdata *);
+
+void qib_ib_rcv(struct qib_ctxtdata *, void *, void *, u32);
+
+void qib_ib_piobufavail(struct qib_devdata *);
+
+unsigned qib_get_npkeys(struct qib_devdata *);
+
+unsigned qib_get_pkey(struct qib_ibport *, unsigned);
+
+extern const enum ib_wc_opcode ib_qib_wc_opcode[];
+
+/*
+ * Below  HCA-independent IB PhysPortState values, returned
+ * by the f_ibphys_portstate() routine.
+ */
+#define IB_PHYSPORTSTATE_SLEEP 1
+#define IB_PHYSPORTSTATE_POLL 2
+#define IB_PHYSPORTSTATE_DISABLED 3
+#define IB_PHYSPORTSTATE_CFG_TRAIN 4
+#define IB_PHYSPORTSTATE_LINKUP 5
+#define IB_PHYSPORTSTATE_LINK_ERR_RECOVER 6
+#define IB_PHYSPORTSTATE_CFG_DEBOUNCE 8
+#define IB_PHYSPORTSTATE_CFG_IDLE 0xB
+#define IB_PHYSPORTSTATE_RECOVERY_RETRAIN 0xC
+#define IB_PHYSPORTSTATE_RECOVERY_WAITRMT 0xE
+#define IB_PHYSPORTSTATE_RECOVERY_IDLE 0xF
+#define IB_PHYSPORTSTATE_CFG_ENH 0x10
+#define IB_PHYSPORTSTATE_CFG_WAIT_ENH 0x13
+
+extern const int ib_qib_state_ops[];
+
+extern __be64 ib_qib_sys_image_guid;    /* in network order */
+
+extern unsigned int ib_qib_lkey_table_size;
+
+extern unsigned int ib_qib_max_cqes;
+
+extern unsigned int ib_qib_max_cqs;
+
+extern unsigned int ib_qib_max_qp_wrs;
+
+extern unsigned int ib_qib_max_qps;
+
+extern unsigned int ib_qib_max_sges;
+
+extern unsigned int ib_qib_max_mcast_grps;
+
+extern unsigned int ib_qib_max_mcast_qp_attached;
+
+extern unsigned int ib_qib_max_srqs;
+
+extern unsigned int ib_qib_max_srq_sges;
+
+extern unsigned int ib_qib_max_srq_wrs;
+
+extern const u32 ib_qib_rnr_table[];
+
+extern struct ib_dma_mapping_ops qib_dma_mapping_ops;
+
+#endif                          /* QIB_VERBS_H */
diff --git a/drivers/infiniband/hw/qib/qib_verbs_mcast.c b/drivers/infiniband/hw/qib/qib_verbs_mcast.c
new file mode 100644 (file)
index 0000000..dabb697
--- /dev/null
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved.
+ * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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/rculist.h>
+
+#include "qib.h"
+
+/**
+ * qib_mcast_qp_alloc - alloc a struct to link a QP to mcast GID struct
+ * @qp: the QP to link
+ */
+static struct qib_mcast_qp *qib_mcast_qp_alloc(struct qib_qp *qp)
+{
+       struct qib_mcast_qp *mqp;
+
+       mqp = kmalloc(sizeof *mqp, GFP_KERNEL);
+       if (!mqp)
+               goto bail;
+
+       mqp->qp = qp;
+       atomic_inc(&qp->refcount);
+
+bail:
+       return mqp;
+}
+
+static void qib_mcast_qp_free(struct qib_mcast_qp *mqp)
+{
+       struct qib_qp *qp = mqp->qp;
+
+       /* Notify qib_destroy_qp() if it is waiting. */
+       if (atomic_dec_and_test(&qp->refcount))
+               wake_up(&qp->wait);
+
+       kfree(mqp);
+}
+
+/**
+ * qib_mcast_alloc - allocate the multicast GID structure
+ * @mgid: the multicast GID
+ *
+ * A list of QPs will be attached to this structure.
+ */
+static struct qib_mcast *qib_mcast_alloc(union ib_gid *mgid)
+{
+       struct qib_mcast *mcast;
+
+       mcast = kmalloc(sizeof *mcast, GFP_KERNEL);
+       if (!mcast)
+               goto bail;
+
+       mcast->mgid = *mgid;
+       INIT_LIST_HEAD(&mcast->qp_list);
+       init_waitqueue_head(&mcast->wait);
+       atomic_set(&mcast->refcount, 0);
+       mcast->n_attached = 0;
+
+bail:
+       return mcast;
+}
+
+static void qib_mcast_free(struct qib_mcast *mcast)
+{
+       struct qib_mcast_qp *p, *tmp;
+
+       list_for_each_entry_safe(p, tmp, &mcast->qp_list, list)
+               qib_mcast_qp_free(p);
+
+       kfree(mcast);
+}
+
+/**
+ * qib_mcast_find - search the global table for the given multicast GID
+ * @ibp: the IB port structure
+ * @mgid: the multicast GID to search for
+ *
+ * Returns NULL if not found.
+ *
+ * The caller is responsible for decrementing the reference count if found.
+ */
+struct qib_mcast *qib_mcast_find(struct qib_ibport *ibp, union ib_gid *mgid)
+{
+       struct rb_node *n;
+       unsigned long flags;
+       struct qib_mcast *mcast;
+
+       spin_lock_irqsave(&ibp->lock, flags);
+       n = ibp->mcast_tree.rb_node;
+       while (n) {
+               int ret;
+
+               mcast = rb_entry(n, struct qib_mcast, rb_node);
+
+               ret = memcmp(mgid->raw, mcast->mgid.raw,
+                            sizeof(union ib_gid));
+               if (ret < 0)
+                       n = n->rb_left;
+               else if (ret > 0)
+                       n = n->rb_right;
+               else {
+                       atomic_inc(&mcast->refcount);
+                       spin_unlock_irqrestore(&ibp->lock, flags);
+                       goto bail;
+               }
+       }
+       spin_unlock_irqrestore(&ibp->lock, flags);
+
+       mcast = NULL;
+
+bail:
+       return mcast;
+}
+
+/**
+ * qib_mcast_add - insert mcast GID into table and attach QP struct
+ * @mcast: the mcast GID table
+ * @mqp: the QP to attach
+ *
+ * Return zero if both were added.  Return EEXIST if the GID was already in
+ * the table but the QP was added.  Return ESRCH if the QP was already
+ * attached and neither structure was added.
+ */
+static int qib_mcast_add(struct qib_ibdev *dev, struct qib_ibport *ibp,
+                        struct qib_mcast *mcast, struct qib_mcast_qp *mqp)
+{
+       struct rb_node **n = &ibp->mcast_tree.rb_node;
+       struct rb_node *pn = NULL;
+       int ret;
+
+       spin_lock_irq(&ibp->lock);
+
+       while (*n) {
+               struct qib_mcast *tmcast;
+               struct qib_mcast_qp *p;
+
+               pn = *n;
+               tmcast = rb_entry(pn, struct qib_mcast, rb_node);
+
+               ret = memcmp(mcast->mgid.raw, tmcast->mgid.raw,
+                            sizeof(union ib_gid));
+               if (ret < 0) {
+                       n = &pn->rb_left;
+                       continue;
+               }
+               if (ret > 0) {
+                       n = &pn->rb_right;
+                       continue;
+               }
+
+               /* Search the QP list to see if this is already there. */
+               list_for_each_entry_rcu(p, &tmcast->qp_list, list) {
+                       if (p->qp == mqp->qp) {
+                               ret = ESRCH;
+                               goto bail;
+                       }
+               }
+               if (tmcast->n_attached == ib_qib_max_mcast_qp_attached) {
+                       ret = ENOMEM;
+                       goto bail;
+               }
+
+               tmcast->n_attached++;
+
+               list_add_tail_rcu(&mqp->list, &tmcast->qp_list);
+               ret = EEXIST;
+               goto bail;
+       }
+
+       spin_lock(&dev->n_mcast_grps_lock);
+       if (dev->n_mcast_grps_allocated == ib_qib_max_mcast_grps) {
+               spin_unlock(&dev->n_mcast_grps_lock);
+               ret = ENOMEM;
+               goto bail;
+       }
+
+       dev->n_mcast_grps_allocated++;
+       spin_unlock(&dev->n_mcast_grps_lock);
+
+       mcast->n_attached++;
+
+       list_add_tail_rcu(&mqp->list, &mcast->qp_list);
+
+       atomic_inc(&mcast->refcount);
+       rb_link_node(&mcast->rb_node, pn, n);
+       rb_insert_color(&mcast->rb_node, &ibp->mcast_tree);
+
+       ret = 0;
+
+bail:
+       spin_unlock_irq(&ibp->lock);
+
+       return ret;
+}
+
+int qib_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
+{
+       struct qib_qp *qp = to_iqp(ibqp);
+       struct qib_ibdev *dev = to_idev(ibqp->device);
+       struct qib_ibport *ibp;
+       struct qib_mcast *mcast;
+       struct qib_mcast_qp *mqp;
+       int ret;
+
+       if (ibqp->qp_num <= 1 || qp->state == IB_QPS_RESET) {
+               ret = -EINVAL;
+               goto bail;
+       }
+
+       /*
+        * Allocate data structures since its better to do this outside of
+        * spin locks and it will most likely be needed.
+        */
+       mcast = qib_mcast_alloc(gid);
+       if (mcast == NULL) {
+               ret = -ENOMEM;
+               goto bail;
+       }
+       mqp = qib_mcast_qp_alloc(qp);
+       if (mqp == NULL) {
+               qib_mcast_free(mcast);
+               ret = -ENOMEM;
+               goto bail;
+       }
+       ibp = to_iport(ibqp->device, qp->port_num);
+       switch (qib_mcast_add(dev, ibp, mcast, mqp)) {
+       case ESRCH:
+               /* Neither was used: OK to attach the same QP twice. */
+               qib_mcast_qp_free(mqp);
+               qib_mcast_free(mcast);
+               break;
+
+       case EEXIST:            /* The mcast wasn't used */
+               qib_mcast_free(mcast);
+               break;
+
+       case ENOMEM:
+               /* Exceeded the maximum number of mcast groups. */
+               qib_mcast_qp_free(mqp);
+               qib_mcast_free(mcast);
+               ret = -ENOMEM;
+               goto bail;
+
+       default:
+               break;
+       }
+
+       ret = 0;
+
+bail:
+       return ret;
+}
+
+int qib_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
+{
+       struct qib_qp *qp = to_iqp(ibqp);
+       struct qib_ibdev *dev = to_idev(ibqp->device);
+       struct qib_ibport *ibp = to_iport(ibqp->device, qp->port_num);
+       struct qib_mcast *mcast = NULL;
+       struct qib_mcast_qp *p, *tmp;
+       struct rb_node *n;
+       int last = 0;
+       int ret;
+
+       if (ibqp->qp_num <= 1 || qp->state == IB_QPS_RESET) {
+               ret = -EINVAL;
+               goto bail;
+       }
+
+       spin_lock_irq(&ibp->lock);
+
+       /* Find the GID in the mcast table. */
+       n = ibp->mcast_tree.rb_node;
+       while (1) {
+               if (n == NULL) {
+                       spin_unlock_irq(&ibp->lock);
+                       ret = -EINVAL;
+                       goto bail;
+               }
+
+               mcast = rb_entry(n, struct qib_mcast, rb_node);
+               ret = memcmp(gid->raw, mcast->mgid.raw,
+                            sizeof(union ib_gid));
+               if (ret < 0)
+                       n = n->rb_left;
+               else if (ret > 0)
+                       n = n->rb_right;
+               else
+                       break;
+       }
+
+       /* Search the QP list. */
+       list_for_each_entry_safe(p, tmp, &mcast->qp_list, list) {
+               if (p->qp != qp)
+                       continue;
+               /*
+                * We found it, so remove it, but don't poison the forward
+                * link until we are sure there are no list walkers.
+                */
+               list_del_rcu(&p->list);
+               mcast->n_attached--;
+
+               /* If this was the last attached QP, remove the GID too. */
+               if (list_empty(&mcast->qp_list)) {
+                       rb_erase(&mcast->rb_node, &ibp->mcast_tree);
+                       last = 1;
+               }
+               break;
+       }
+
+       spin_unlock_irq(&ibp->lock);
+
+       if (p) {
+               /*
+                * Wait for any list walkers to finish before freeing the
+                * list element.
+                */
+               wait_event(mcast->wait, atomic_read(&mcast->refcount) <= 1);
+               qib_mcast_qp_free(p);
+       }
+       if (last) {
+               atomic_dec(&mcast->refcount);
+               wait_event(mcast->wait, !atomic_read(&mcast->refcount));
+               qib_mcast_free(mcast);
+               spin_lock_irq(&dev->n_mcast_grps_lock);
+               dev->n_mcast_grps_allocated--;
+               spin_unlock_irq(&dev->n_mcast_grps_lock);
+       }
+
+       ret = 0;
+
+bail:
+       return ret;
+}
+
+int qib_mcast_tree_empty(struct qib_ibport *ibp)
+{
+       return ibp->mcast_tree.rb_node == NULL;
+}
similarity index 57%
rename from drivers/infiniband/hw/ipath/ipath_7220.h
rename to drivers/infiniband/hw/qib/qib_wc_ppc64.c
index 74fa5cc5131d03916b316a1f933ac9c52f376f84..673cf4c22ebdf776931db04af334364d52663ee9 100644 (file)
@@ -1,7 +1,5 @@
-#ifndef _IPATH_7220_H
-#define _IPATH_7220_H
 /*
- * Copyright (c) 2007 QLogic Corporation. All rights reserved.
+ * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
  */
 
 /*
- * This header file provides the declarations and common definitions
- * for (mostly) manipulation of the SerDes blocks within the IBA7220.
- * the functions declared should only be called from within other
- * 7220-related files such as ipath_iba7220.c or ipath_sd7220.c.
+ * This file is conditionally built on PowerPC only.  Otherwise weak symbol
+ * versions of the functions exported from here are used.
  */
-int ipath_sd7220_presets(struct ipath_devdata *dd);
-int ipath_sd7220_init(struct ipath_devdata *dd, int was_reset);
-int ipath_sd7220_prog_ld(struct ipath_devdata *dd, int sdnum, u8 *img,
-       int len, int offset);
-int ipath_sd7220_prog_vfy(struct ipath_devdata *dd, int sdnum, const u8 *img,
-       int len, int offset);
-/*
- * Below used for sdnum parameter, selecting one of the two sections
- * used for PCIe, or the single SerDes used for IB, which is the
- * only one currently used
- */
-#define IB_7220_SERDES 2
 
-int ipath_sd7220_ib_load(struct ipath_devdata *dd);
-int ipath_sd7220_ib_vfy(struct ipath_devdata *dd);
+#include "qib.h"
 
-#endif /* _IPATH_7220_H */
+/**
+ * qib_enable_wc - enable write combining for MMIO writes to the device
+ * @dd: qlogic_ib device
+ *
+ * Nothing to do on PowerPC, so just return without error.
+ */
+int qib_enable_wc(struct qib_devdata *dd)
+{
+       return 0;
+}
+
+/**
+ * qib_unordered_wc - indicate whether write combining is unordered
+ *
+ * Because our performance depends on our ability to do write
+ * combining mmio writes in the most efficient way, we need to
+ * know if we are on a processor that may reorder stores when
+ * write combining.
+ */
+int qib_unordered_wc(void)
+{
+       return 1;
+}
diff --git a/drivers/infiniband/hw/qib/qib_wc_x86_64.c b/drivers/infiniband/hw/qib/qib_wc_x86_64.c
new file mode 100644 (file)
index 0000000..561b8bc
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved.
+ * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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.
+ */
+
+/*
+ * This file is conditionally built on x86_64 only.  Otherwise weak symbol
+ * versions of the functions exported from here are used.
+ */
+
+#include <linux/pci.h>
+#include <asm/mtrr.h>
+#include <asm/processor.h>
+
+#include "qib.h"
+
+/**
+ * qib_enable_wc - enable write combining for MMIO writes to the device
+ * @dd: qlogic_ib device
+ *
+ * This routine is x86_64-specific; it twiddles the CPU's MTRRs to enable
+ * write combining.
+ */
+int qib_enable_wc(struct qib_devdata *dd)
+{
+       int ret = 0;
+       u64 pioaddr, piolen;
+       unsigned bits;
+       const unsigned long addr = pci_resource_start(dd->pcidev, 0);
+       const size_t len = pci_resource_len(dd->pcidev, 0);
+
+       /*
+        * Set the PIO buffers to be WCCOMB, so we get HT bursts to the
+        * chip.  Linux (possibly the hardware) requires it to be on a power
+        * of 2 address matching the length (which has to be a power of 2).
+        * For rev1, that means the base address, for rev2, it will be just
+        * the PIO buffers themselves.
+        * For chips with two sets of buffers, the calculations are
+        * somewhat more complicated; we need to sum, and the piobufbase
+        * register has both offsets, 2K in low 32 bits, 4K in high 32 bits.
+        * The buffers are still packed, so a single range covers both.
+        */
+       if (dd->piobcnt2k && dd->piobcnt4k) {
+               /* 2 sizes for chip */
+               unsigned long pio2kbase, pio4kbase;
+               pio2kbase = dd->piobufbase & 0xffffffffUL;
+               pio4kbase = (dd->piobufbase >> 32) & 0xffffffffUL;
+               if (pio2kbase < pio4kbase) {
+                       /* all current chips */
+                       pioaddr = addr + pio2kbase;
+                       piolen = pio4kbase - pio2kbase +
+                               dd->piobcnt4k * dd->align4k;
+               } else {
+                       pioaddr = addr + pio4kbase;
+                       piolen = pio2kbase - pio4kbase +
+                               dd->piobcnt2k * dd->palign;
+               }
+       } else {  /* single buffer size (2K, currently) */
+               pioaddr = addr + dd->piobufbase;
+               piolen = dd->piobcnt2k * dd->palign +
+                       dd->piobcnt4k * dd->align4k;
+       }
+
+       for (bits = 0; !(piolen & (1ULL << bits)); bits++)
+               /* do nothing */ ;
+
+       if (piolen != (1ULL << bits)) {
+               piolen >>= bits;
+               while (piolen >>= 1)
+                       bits++;
+               piolen = 1ULL << (bits + 1);
+       }
+       if (pioaddr & (piolen - 1)) {
+               u64 atmp;
+               atmp = pioaddr & ~(piolen - 1);
+               if (atmp < addr || (atmp + piolen) > (addr + len)) {
+                       qib_dev_err(dd, "No way to align address/size "
+                                   "(%llx/%llx), no WC mtrr\n",
+                                   (unsigned long long) atmp,
+                                   (unsigned long long) piolen << 1);
+                       ret = -ENODEV;
+               } else {
+                       pioaddr = atmp;
+                       piolen <<= 1;
+               }
+       }
+
+       if (!ret) {
+               int cookie;
+
+               cookie = mtrr_add(pioaddr, piolen, MTRR_TYPE_WRCOMB, 0);
+               if (cookie < 0) {
+                       {
+                               qib_devinfo(dd->pcidev,
+                                        "mtrr_add()  WC for PIO bufs "
+                                        "failed (%d)\n",
+                                        cookie);
+                               ret = -EINVAL;
+                       }
+               } else {
+                       dd->wc_cookie = cookie;
+                       dd->wc_base = (unsigned long) pioaddr;
+                       dd->wc_len = (unsigned long) piolen;
+               }
+       }
+
+       return ret;
+}
+
+/**
+ * qib_disable_wc - disable write combining for MMIO writes to the device
+ * @dd: qlogic_ib device
+ */
+void qib_disable_wc(struct qib_devdata *dd)
+{
+       if (dd->wc_cookie) {
+               int r;
+
+               r = mtrr_del(dd->wc_cookie, dd->wc_base,
+                            dd->wc_len);
+               if (r < 0)
+                       qib_devinfo(dd->pcidev,
+                                "mtrr_del(%lx, %lx, %lx) failed: %d\n",
+                                dd->wc_cookie, dd->wc_base,
+                                dd->wc_len, r);
+               dd->wc_cookie = 0; /* even on failure */
+       }
+}
+
+/**
+ * qib_unordered_wc - indicate whether write combining is ordered
+ *
+ * Because our performance depends on our ability to do write combining mmio
+ * writes in the most efficient way, we need to know if we are on an Intel
+ * or AMD x86_64 processor.  AMD x86_64 processors flush WC buffers out in
+ * the order completed, and so no special flushing is required to get
+ * correct ordering.  Intel processors, however, will flush write buffers
+ * out in "random" orders, and so explicit ordering is needed at times.
+ */
+int qib_unordered_wc(void)
+{
+       return boot_cpu_data.x86_vendor != X86_VENDOR_AMD;
+}
index 423e0e6031ab5010e542555b10bc539683efaae6..34157bb97ed6440695dcafb072ca3f8419cb5d0b 100644 (file)
@@ -47,15 +47,15 @@ struct joydev {
        struct mutex mutex;
        struct device dev;
 
-       struct js_corr corr[ABS_MAX + 1];
+       struct js_corr corr[ABS_CNT];
        struct JS_DATA_SAVE_TYPE glue;
        int nabs;
        int nkey;
        __u16 keymap[KEY_MAX - BTN_MISC + 1];
        __u16 keypam[KEY_MAX - BTN_MISC + 1];
-       __u8 absmap[ABS_MAX + 1];
-       __u8 abspam[ABS_MAX + 1];
-       __s16 abs[ABS_MAX + 1];
+       __u8 absmap[ABS_CNT];
+       __u8 abspam[ABS_CNT];
+       __s16 abs[ABS_CNT];
 };
 
 struct joydev_client {
@@ -826,7 +826,7 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
        joydev->handle.handler = handler;
        joydev->handle.private = joydev;
 
-       for (i = 0; i < ABS_MAX + 1; i++)
+       for (i = 0; i < ABS_CNT; i++)
                if (test_bit(i, dev->absbit)) {
                        joydev->absmap[i] = joydev->nabs;
                        joydev->abspam[joydev->nabs] = i;
index 35149ec455a9fa3770a33ae2e1c61e2d6fb06a02..79172af164f25a5ccd913f32225dcd5e60c22760 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/keyboard.h>
+#include <linux/platform_device.h>
 
 #include <asm/amigaints.h>
 #include <asm/amigahw.h>
@@ -154,10 +155,9 @@ static const char *amikbd_messages[8] = {
        [7] = KERN_WARNING "amikbd: keyboard interrupt\n"
 };
 
-static struct input_dev *amikbd_dev;
-
-static irqreturn_t amikbd_interrupt(int irq, void *dummy)
+static irqreturn_t amikbd_interrupt(int irq, void *data)
 {
+       struct input_dev *dev = data;
        unsigned char scancode, down;
 
        scancode = ~ciaa.sdr;           /* get and invert scancode (keyboard is active low) */
@@ -170,47 +170,42 @@ static irqreturn_t amikbd_interrupt(int irq, void *dummy)
 
        if (scancode < 0x78) {          /* scancodes < 0x78 are keys */
                if (scancode == 98) {   /* CapsLock is a toggle switch key on Amiga */
-                       input_report_key(amikbd_dev, scancode, 1);
-                       input_report_key(amikbd_dev, scancode, 0);
+                       input_report_key(dev, scancode, 1);
+                       input_report_key(dev, scancode, 0);
                } else {
-                       input_report_key(amikbd_dev, scancode, down);
+                       input_report_key(dev, scancode, down);
                }
 
-               input_sync(amikbd_dev);
+               input_sync(dev);
        } else                          /* scancodes >= 0x78 are error codes */
                printk(amikbd_messages[scancode - 0x78]);
 
        return IRQ_HANDLED;
 }
 
-static int __init amikbd_init(void)
+static int __init amikbd_probe(struct platform_device *pdev)
 {
+       struct input_dev *dev;
        int i, j, err;
 
-       if (!AMIGAHW_PRESENT(AMI_KEYBOARD))
-               return -ENODEV;
-
-       if (!request_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100, "amikeyb"))
-               return -EBUSY;
-
-       amikbd_dev = input_allocate_device();
-       if (!amikbd_dev) {
-               printk(KERN_ERR "amikbd: not enough memory for input device\n");
-               err = -ENOMEM;
-               goto fail1;
+       dev = input_allocate_device();
+       if (!dev) {
+               dev_err(&pdev->dev, "Not enough memory for input device\n");
+               return -ENOMEM;
        }
 
-       amikbd_dev->name = "Amiga Keyboard";
-       amikbd_dev->phys = "amikbd/input0";
-       amikbd_dev->id.bustype = BUS_AMIGA;
-       amikbd_dev->id.vendor = 0x0001;
-       amikbd_dev->id.product = 0x0001;
-       amikbd_dev->id.version = 0x0100;
+       dev->name = pdev->name;
+       dev->phys = "amikbd/input0";
+       dev->id.bustype = BUS_AMIGA;
+       dev->id.vendor = 0x0001;
+       dev->id.product = 0x0001;
+       dev->id.version = 0x0100;
+       dev->dev.parent = &pdev->dev;
 
-       amikbd_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+       dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
 
        for (i = 0; i < 0x78; i++)
-               set_bit(i, amikbd_dev->keybit);
+               set_bit(i, dev->keybit);
 
        for (i = 0; i < MAX_NR_KEYMAPS; i++) {
                static u_short temp_map[NR_KEYS] __initdata;
@@ -229,30 +224,54 @@ static int __init amikbd_init(void)
                memcpy(key_maps[i], temp_map, sizeof(temp_map));
        }
        ciaa.cra &= ~0x41;       /* serial data in, turn off TA */
-       if (request_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt, 0, "amikbd",
-                       amikbd_interrupt)) {
-               err = -EBUSY;
+       err = request_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt, 0, "amikbd",
+                         dev);
+       if (err)
                goto fail2;
-       }
 
-       err = input_register_device(amikbd_dev);
+       err = input_register_device(dev);
        if (err)
                goto fail3;
 
+       platform_set_drvdata(pdev, dev);
+
        return 0;
 
- fail3:        free_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt);
- fail2:        input_free_device(amikbd_dev);
- fail1:        release_mem_region(CIAA_PHYSADDR - 1 + 0xb00, 0x100);
+ fail3:        free_irq(IRQ_AMIGA_CIAA_SP, dev);
+ fail2:        input_free_device(dev);
        return err;
 }
 
-static void __exit amikbd_exit(void)
+static int __exit amikbd_remove(struct platform_device *pdev)
+{
+       struct input_dev *dev = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+       free_irq(IRQ_AMIGA_CIAA_SP, dev);
+       input_unregister_device(dev);
+       return 0;
+}
+
+static struct platform_driver amikbd_driver = {
+       .remove = __exit_p(amikbd_remove),
+       .driver   = {
+               .name   = "amiga-keyboard",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init amikbd_init(void)
 {
-       free_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt);
-       input_unregister_device(amikbd_dev);
-       release_mem_region(CIAA_PHYSADDR - 1 + 0xb00, 0x100);
+       return platform_driver_probe(&amikbd_driver, amikbd_probe);
 }
 
 module_init(amikbd_init);
+
+static void __exit amikbd_exit(void)
+{
+       platform_driver_unregister(&amikbd_driver);
+}
+
 module_exit(amikbd_exit);
+
+MODULE_ALIAS("platform:amiga-keyboard");
index 48cdabec372a0b8e6344749deebef3bb7876db44..c44b9eafc556e48c114780e0dc7ed6af1e144cda 100644 (file)
@@ -80,6 +80,16 @@ config INPUT_M68K_BEEP
        tristate "M68k Beeper support"
        depends on M68K
 
+config INPUT_MAX8925_ONKEY
+       tristate "MAX8925 ONKEY support"
+       depends on MFD_MAX8925
+       help
+         Support the ONKEY of MAX8925 PMICs as an input device
+         reporting power button status.
+
+         To compile this driver as a module, choose M here: the module
+         will be called max8925_onkey.
+
 config INPUT_APANEL
        tristate "Fujitsu Lifebook Application Panel buttons"
        depends on X86 && I2C && LEDS_CLASS
index f9f577031e0688d93554f0796ebc83ddc280ff51..71fe57d8023ff834284afc91ad57fcd08c97606e 100644 (file)
@@ -20,6 +20,7 @@ obj-$(CONFIG_HP_SDC_RTC)              += hp_sdc_rtc.o
 obj-$(CONFIG_INPUT_IXP4XX_BEEPER)      += ixp4xx-beeper.o
 obj-$(CONFIG_INPUT_KEYSPAN_REMOTE)     += keyspan_remote.o
 obj-$(CONFIG_INPUT_M68K_BEEP)          += m68kspkr.o
+obj-$(CONFIG_INPUT_MAX8925_ONKEY)      += max8925_onkey.o
 obj-$(CONFIG_INPUT_PCAP)               += pcap_keys.o
 obj-$(CONFIG_INPUT_PCF50633_PMU)       += pcf50633-input.o
 obj-$(CONFIG_INPUT_PCF8574)            += pcf8574_keypad.o
index ad730e15afc0c7ce8f2cb30b13f12e2cc34aec3a..e00a1cc79c0a448d5b344612ee9c7354b86c342c 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/proc_fs.h>
 #include <linux/poll.h>
 #include <linux/rtc.h>
+#include <linux/smp_lock.h>
 #include <linux/semaphore.h>
 
 MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
@@ -64,8 +65,8 @@ static DECLARE_WAIT_QUEUE_HEAD(hp_sdc_rtc_wait);
 static ssize_t hp_sdc_rtc_read(struct file *file, char __user *buf,
                               size_t count, loff_t *ppos);
 
-static int hp_sdc_rtc_ioctl(struct inode *inode, struct file *file,
-                           unsigned int cmd, unsigned long arg);
+static long hp_sdc_rtc_unlocked_ioctl(struct file *file,
+                                     unsigned int cmd, unsigned long arg);
 
 static unsigned int hp_sdc_rtc_poll(struct file *file, poll_table *wait);
 
@@ -512,7 +513,7 @@ static int hp_sdc_rtc_read_proc(char *page, char **start, off_t off,
         return len;
 }
 
-static int hp_sdc_rtc_ioctl(struct inode *inode, struct file *file, 
+static int hp_sdc_rtc_ioctl(struct file *file, 
                            unsigned int cmd, unsigned long arg)
 {
 #if 1
@@ -659,14 +660,27 @@ static int hp_sdc_rtc_ioctl(struct inode *inode, struct file *file,
 #endif
 }
 
+static long hp_sdc_rtc_unlocked_ioctl(struct file *file,
+                                     unsigned int cmd, unsigned long arg)
+{
+       int ret;
+
+       lock_kernel();
+       ret = hp_sdc_rtc_ioctl(file, cmd, arg);
+       unlock_kernel();
+
+       return ret;
+}
+
+
 static const struct file_operations hp_sdc_rtc_fops = {
-        .owner =       THIS_MODULE,
-        .llseek =      no_llseek,
-        .read =                hp_sdc_rtc_read,
-        .poll =                hp_sdc_rtc_poll,
-        .ioctl =       hp_sdc_rtc_ioctl,
-        .open =                hp_sdc_rtc_open,
-        .fasync =      hp_sdc_rtc_fasync,
+        .owner =               THIS_MODULE,
+        .llseek =              no_llseek,
+        .read =                        hp_sdc_rtc_read,
+        .poll =                        hp_sdc_rtc_poll,
+        .unlocked_ioctl =      hp_sdc_rtc_ioctl,
+        .open =                        hp_sdc_rtc_open,
+        .fasync =              hp_sdc_rtc_fasync,
 };
 
 static struct miscdevice hp_sdc_rtc_dev = {
diff --git a/drivers/input/misc/max8925_onkey.c b/drivers/input/misc/max8925_onkey.c
new file mode 100644 (file)
index 0000000..80af446
--- /dev/null
@@ -0,0 +1,148 @@
+/**
+ * max8925_onkey.c - MAX8925 ONKEY driver
+ *
+ * Copyright (C) 2009 Marvell International Ltd.
+ *      Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * 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 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/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/max8925.h>
+#include <linux/slab.h>
+
+#define HARDRESET_EN           (1 << 7)
+#define PWREN_EN               (1 << 7)
+
+struct max8925_onkey_info {
+       struct input_dev        *idev;
+       struct i2c_client       *i2c;
+       int                     irq;
+};
+
+/*
+ * MAX8925 gives us an interrupt when ONKEY is held for 3 seconds.
+ * max8925_set_bits() operates I2C bus and may sleep. So implement
+ * it in thread IRQ handler.
+ */
+static irqreturn_t max8925_onkey_handler(int irq, void *data)
+{
+       struct max8925_onkey_info *info = data;
+
+       input_report_key(info->idev, KEY_POWER, 1);
+       input_sync(info->idev);
+
+       /* Enable hardreset to halt if system isn't shutdown on time */
+       max8925_set_bits(info->i2c, MAX8925_SYSENSEL,
+                        HARDRESET_EN, HARDRESET_EN);
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit max8925_onkey_probe(struct platform_device *pdev)
+{
+       struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
+       struct max8925_onkey_info *info;
+       int error;
+
+       info = kzalloc(sizeof(struct max8925_onkey_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       info->i2c = chip->i2c;
+       info->irq = chip->irq_base + MAX8925_IRQ_GPM_SW_3SEC;
+
+       info->idev = input_allocate_device();
+       if (!info->idev) {
+               dev_err(chip->dev, "Failed to allocate input dev\n");
+               error = -ENOMEM;
+               goto out_input;
+       }
+
+       info->idev->name = "max8925_on";
+       info->idev->phys = "max8925_on/input0";
+       info->idev->id.bustype = BUS_I2C;
+       info->idev->dev.parent = &pdev->dev;
+       info->idev->evbit[0] = BIT_MASK(EV_KEY);
+       info->idev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);
+
+       error = request_threaded_irq(info->irq, NULL, max8925_onkey_handler,
+                                    IRQF_ONESHOT, "onkey", info);
+       if (error < 0) {
+               dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
+                       info->irq, error);
+               goto out_irq;
+       }
+
+       error = input_register_device(info->idev);
+       if (error) {
+               dev_err(chip->dev, "Can't register input device: %d\n", error);
+               goto out;
+       }
+
+       platform_set_drvdata(pdev, info);
+
+       return 0;
+
+out:
+       free_irq(info->irq, info);
+out_irq:
+       input_free_device(info->idev);
+out_input:
+       kfree(info);
+       return error;
+}
+
+static int __devexit max8925_onkey_remove(struct platform_device *pdev)
+{
+       struct max8925_onkey_info *info = platform_get_drvdata(pdev);
+
+       free_irq(info->irq, info);
+       input_unregister_device(info->idev);
+       kfree(info);
+
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver max8925_onkey_driver = {
+       .driver         = {
+               .name   = "max8925-onkey",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = max8925_onkey_probe,
+       .remove         = __devexit_p(max8925_onkey_remove),
+};
+
+static int __init max8925_onkey_init(void)
+{
+       return platform_driver_register(&max8925_onkey_driver);
+}
+module_init(max8925_onkey_init);
+
+static void __exit max8925_onkey_exit(void)
+{
+       platform_driver_unregister(&max8925_onkey_driver);
+}
+module_exit(max8925_onkey_exit);
+
+MODULE_DESCRIPTION("Maxim MAX8925 ONKEY driver");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_LICENSE("GPL");
index 0d45422f8095040f9354b3fe40d4a520218e7c88..1dacae4b43f0f32671e42934919526c5502a4dcf 100644 (file)
@@ -259,8 +259,11 @@ static const struct of_device_id bbc_beep_match[] = {
 };
 
 static struct of_platform_driver bbc_beep_driver = {
-       .name           = "bbcbeep",
-       .match_table    = bbc_beep_match,
+       .driver = {
+               .name = "bbcbeep",
+               .owner = THIS_MODULE,
+               .of_match_table = bbc_beep_match,
+       },
        .probe          = bbc_beep_probe,
        .remove         = __devexit_p(bbc_remove),
        .shutdown       = sparcspkr_shutdown,
@@ -338,8 +341,11 @@ static const struct of_device_id grover_beep_match[] = {
 };
 
 static struct of_platform_driver grover_beep_driver = {
-       .name           = "groverbeep",
-       .match_table    = grover_beep_match,
+       .driver = {
+               .name = "groverbeep",
+               .owner = THIS_MODULE,
+               .of_match_table = grover_beep_match,
+       },
        .probe          = grover_beep_probe,
        .remove         = __devexit_p(grover_remove),
        .shutdown       = sparcspkr_shutdown,
index fee9eac8e04ab830fbfb4fab89ef79b10138187a..4f9b2afc24e820d75b819555f7f667f94bd73f69 100644 (file)
@@ -90,8 +90,8 @@ static void vibra_disable(struct vibra_info *info)
        twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
                         (reg & ~TWL4030_VIBRA_EN), TWL4030_REG_VIBRA_CTL);
 
-       twl4030_codec_disable_resource(TWL4030_CODEC_RES_POWER);
        twl4030_codec_disable_resource(TWL4030_CODEC_RES_APLL);
+       twl4030_codec_disable_resource(TWL4030_CODEC_RES_POWER);
 
        info->enabled = false;
 }
index 1477466076ad1764989f82387cc737fd453181ab..b71eb55f2dbc97dafd4a769fc61f346e69a5e0af 100644 (file)
@@ -300,7 +300,7 @@ static int uinput_validate_absbits(struct input_dev *dev)
        unsigned int cnt;
        int retval = 0;
 
-       for (cnt = 0; cnt < ABS_MAX + 1; cnt++) {
+       for (cnt = 0; cnt < ABS_CNT; cnt++) {
                if (!test_bit(cnt, dev->absbit))
                        continue;
 
@@ -387,7 +387,7 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu
        dev->id.product = user_dev->id.product;
        dev->id.version = user_dev->id.version;
 
-       size = sizeof(int) * (ABS_MAX + 1);
+       size = sizeof(int) * ABS_CNT;
        memcpy(dev->absmax, user_dev->absmax, size);
        memcpy(dev->absmin, user_dev->absmin, size);
        memcpy(dev->absfuzz, user_dev->absfuzz, size);
index a185ac78a42ca441a193229f2bd04ccf7cfd8079..ff5f61a0fd3ad1eb071e600e5e37fb15fb4ca61a 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/input.h>
 #include <linux/interrupt.h>
+#include <linux/platform_device.h>
 
 #include <asm/irq.h>
 #include <asm/setup.h>
@@ -34,10 +35,10 @@ MODULE_DESCRIPTION("Amiga mouse driver");
 MODULE_LICENSE("GPL");
 
 static int amimouse_lastx, amimouse_lasty;
-static struct input_dev *amimouse_dev;
 
-static irqreturn_t amimouse_interrupt(int irq, void *dummy)
+static irqreturn_t amimouse_interrupt(int irq, void *data)
 {
+       struct input_dev *dev = data;
        unsigned short joy0dat, potgor;
        int nx, ny, dx, dy;
 
@@ -59,14 +60,14 @@ static irqreturn_t amimouse_interrupt(int irq, void *dummy)
 
        potgor = amiga_custom.potgor;
 
-       input_report_rel(amimouse_dev, REL_X, dx);
-       input_report_rel(amimouse_dev, REL_Y, dy);
+       input_report_rel(dev, REL_X, dx);
+       input_report_rel(dev, REL_Y, dy);
 
-       input_report_key(amimouse_dev, BTN_LEFT,   ciaa.pra & 0x40);
-       input_report_key(amimouse_dev, BTN_MIDDLE, potgor & 0x0100);
-       input_report_key(amimouse_dev, BTN_RIGHT,  potgor & 0x0400);
+       input_report_key(dev, BTN_LEFT,   ciaa.pra & 0x40);
+       input_report_key(dev, BTN_MIDDLE, potgor & 0x0100);
+       input_report_key(dev, BTN_RIGHT,  potgor & 0x0400);
 
-       input_sync(amimouse_dev);
+       input_sync(dev);
 
        return IRQ_HANDLED;
 }
@@ -74,63 +75,90 @@ static irqreturn_t amimouse_interrupt(int irq, void *dummy)
 static int amimouse_open(struct input_dev *dev)
 {
        unsigned short joy0dat;
+       int error;
 
        joy0dat = amiga_custom.joy0dat;
 
        amimouse_lastx = joy0dat & 0xff;
        amimouse_lasty = joy0dat >> 8;
 
-       if (request_irq(IRQ_AMIGA_VERTB, amimouse_interrupt, 0, "amimouse", amimouse_interrupt)) {
-                printk(KERN_ERR "amimouse.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
-                return -EBUSY;
-        }
+       error = request_irq(IRQ_AMIGA_VERTB, amimouse_interrupt, 0, "amimouse",
+                           dev);
+       if (error)
+               dev_err(&dev->dev, "Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
 
-        return 0;
+       return error;
 }
 
 static void amimouse_close(struct input_dev *dev)
 {
-       free_irq(IRQ_AMIGA_VERTB, amimouse_interrupt);
+       free_irq(IRQ_AMIGA_VERTB, dev);
 }
 
-static int __init amimouse_init(void)
+static int __init amimouse_probe(struct platform_device *pdev)
 {
        int err;
+       struct input_dev *dev;
 
-       if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_MOUSE))
-               return -ENODEV;
-
-       amimouse_dev = input_allocate_device();
-       if (!amimouse_dev)
+       dev = input_allocate_device();
+       if (!dev)
                return -ENOMEM;
 
-       amimouse_dev->name = "Amiga mouse";
-       amimouse_dev->phys = "amimouse/input0";
-       amimouse_dev->id.bustype = BUS_AMIGA;
-       amimouse_dev->id.vendor = 0x0001;
-       amimouse_dev->id.product = 0x0002;
-       amimouse_dev->id.version = 0x0100;
+       dev->name = pdev->name;
+       dev->phys = "amimouse/input0";
+       dev->id.bustype = BUS_AMIGA;
+       dev->id.vendor = 0x0001;
+       dev->id.product = 0x0002;
+       dev->id.version = 0x0100;
 
-       amimouse_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
-       amimouse_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
-       amimouse_dev->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) |
+       dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+       dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
+       dev->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) |
                BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
-       amimouse_dev->open = amimouse_open;
-       amimouse_dev->close = amimouse_close;
+       dev->open = amimouse_open;
+       dev->close = amimouse_close;
+       dev->dev.parent = &pdev->dev;
 
-       err = input_register_device(amimouse_dev);
+       err = input_register_device(dev);
        if (err) {
-               input_free_device(amimouse_dev);
+               input_free_device(dev);
                return err;
        }
 
+       platform_set_drvdata(pdev, dev);
+
        return 0;
 }
 
-static void __exit amimouse_exit(void)
+static int __exit amimouse_remove(struct platform_device *pdev)
 {
-        input_unregister_device(amimouse_dev);
+       struct input_dev *dev = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+       input_unregister_device(dev);
+       return 0;
+}
+
+static struct platform_driver amimouse_driver = {
+       .remove = __exit_p(amimouse_remove),
+       .driver   = {
+               .name   = "amiga-mouse",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init amimouse_init(void)
+{
+       return platform_driver_probe(&amimouse_driver, amimouse_probe);
 }
 
 module_init(amimouse_init);
+
+static void __exit amimouse_exit(void)
+{
+       platform_driver_unregister(&amimouse_driver);
+}
+
 module_exit(amimouse_exit);
+
+MODULE_ALIAS("platform:amiga-mouse");
index 5071af2c06040f3032d85f4f44be9be5f0202319..04e32f2d1241eacc9cfc6716fb22441d2dbd2a3e 100644 (file)
@@ -51,7 +51,7 @@ static inline void i8042_write_command(int val)
 
 static int __devinit sparc_i8042_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;
 
        dp = dp->child;
        while (dp) {
@@ -96,8 +96,11 @@ static const struct of_device_id sparc_i8042_match[] = {
 MODULE_DEVICE_TABLE(of, sparc_i8042_match);
 
 static struct of_platform_driver sparc_i8042_driver = {
-       .name           = "i8042",
-       .match_table    = sparc_i8042_match,
+       .driver = {
+               .name = "i8042",
+               .owner = THIS_MODULE,
+               .of_match_table = sparc_i8042_match,
+       },
        .probe          = sparc_i8042_probe,
        .remove         = __devexit_p(sparc_i8042_remove),
 };
index f84f8e32e3f1789fac1655752eeb051b3139cb93..e2c028d2638fce0e49d41912f91f1a3260cb16a0 100644 (file)
@@ -244,17 +244,17 @@ static int __devinit xps2_of_probe(struct of_device *ofdev,
        int error;
 
        dev_info(dev, "Device Tree Probing \'%s\'\n",
-                       ofdev->node->name);
+                       ofdev->dev.of_node->name);
 
        /* Get iospace for the device */
-       error = of_address_to_resource(ofdev->node, 0, &r_mem);
+       error = of_address_to_resource(ofdev->dev.of_node, 0, &r_mem);
        if (error) {
                dev_err(dev, "invalid address\n");
                return error;
        }
 
        /* Get IRQ for the device */
-       if (of_irq_to_resource(ofdev->node, 0, &r_irq) == NO_IRQ) {
+       if (of_irq_to_resource(ofdev->dev.of_node, 0, &r_irq) == NO_IRQ) {
                dev_err(dev, "no IRQ found\n");
                return -ENODEV;
        }
@@ -342,7 +342,7 @@ static int __devexit xps2_of_remove(struct of_device *of_dev)
        iounmap(drvdata->base_address);
 
        /* Get iospace of the device */
-       if (of_address_to_resource(of_dev->node, 0, &r_mem))
+       if (of_address_to_resource(of_dev->dev.of_node, 0, &r_mem))
                dev_err(dev, "invalid address\n");
        else
                release_mem_region(r_mem.start, resource_size(&r_mem));
@@ -362,8 +362,11 @@ static const struct of_device_id xps2_of_match[] __devinitconst = {
 MODULE_DEVICE_TABLE(of, xps2_of_match);
 
 static struct of_platform_driver xps2_of_driver = {
-       .name           = DRIVER_NAME,
-       .match_table    = xps2_of_match,
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = xps2_of_match,
+       },
        .probe          = xps2_of_probe,
        .remove         = __devexit_p(xps2_of_remove),
 };
index 532279cda0e4989de8aa45e3791f920d5c82c92b..634f6f6b9b1349a27bcca9a056ca27a1b5151abc 100644 (file)
@@ -1163,8 +1163,8 @@ static int __devinit ads7846_probe(struct spi_device *spi)
 
        ts->reg = regulator_get(&spi->dev, "vcc");
        if (IS_ERR(ts->reg)) {
-               dev_err(&spi->dev, "unable to get regulator: %ld\n",
-                       PTR_ERR(ts->reg));
+               err = PTR_ERR(ts->reg);
+               dev_err(&spi->dev, "unable to get regulator: %ld\n", err);
                goto err_free_gpio;
        }
 
index e0b7c834111d37467b1b6454828f5ad071ddcae9..ac5d0f9b0cb14bac59636f3ae01315a517070567 100644 (file)
@@ -413,6 +413,8 @@ static struct dev_pm_ops s3c_ts_pmops = {
 #endif
 
 static struct platform_device_id s3cts_driver_ids[] = {
+       { "s3c2410-ts", 0 },
+       { "s3c2440-ts", 0 },
        { "s3c64xx-ts", FEAT_PEN_IRQ },
        { }
 };
index 29a8bbf3f086d658d6ab7b36c9c126532695640a..567d57215c28e14bbe78621d1add3b2d1204ff2f 100644 (file)
@@ -857,6 +857,11 @@ static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt)
        if ((pkt[0] & 0xe0) != 0xe0)
                return 0;
 
+       if (be16_to_cpu(packet->data_len) > 0xff)
+               packet->data_len = cpu_to_be16(be16_to_cpu(packet->data_len) - 0x100);
+       if (be16_to_cpu(packet->x_len) > 0xff)
+               packet->x_len = cpu_to_be16(be16_to_cpu(packet->x_len) - 0x80);
+
        /* send ACK */
        ret = usb_submit_urb(priv->ack, GFP_ATOMIC);
 
@@ -1112,7 +1117,7 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
 
 #ifdef CONFIG_TOUCHSCREEN_USB_NEXIO
        [DEVTYPE_NEXIO] = {
-               .rept_size      = 128,
+               .rept_size      = 1024,
                .irq_always     = true,
                .read_data      = nexio_read_data,
                .init           = nexio_init,
index ee5837522f5abff83922ed1dbb417f81e8e5d951..0cabe31f26df3f5929842f28b63b0784e5c8c05c 100644 (file)
@@ -787,8 +787,7 @@ capi_poll(struct file *file, poll_table * wait)
 }
 
 static int
-capi_ioctl(struct inode *inode, struct file *file,
-          unsigned int cmd, unsigned long arg)
+capi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        struct capidev *cdev = file->private_data;
        capi_ioctl_struct data;
@@ -981,6 +980,18 @@ register_out:
        }
 }
 
+static long
+capi_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       int ret;
+
+       lock_kernel();
+       ret = capi_ioctl(file, cmd, arg);
+       unlock_kernel();
+
+       return ret;
+}
+
 static int capi_open(struct inode *inode, struct file *file)
 {
        struct capidev *cdev;
@@ -1026,7 +1037,7 @@ static const struct file_operations capi_fops =
        .read           = capi_read,
        .write          = capi_write,
        .poll           = capi_poll,
-       .ioctl          = capi_ioctl,
+       .unlocked_ioctl = capi_unlocked_ioctl,
        .open           = capi_open,
        .release        = capi_release,
 };
index bd00dceacaf0d6cac10a1ab8da423264f706a313..bde3c88b8b270e0ca527849b0f58c9647bfb67ad 100644 (file)
@@ -1147,6 +1147,12 @@ load_unlock_out:
                if (ctr->state == CAPI_CTR_DETECTED)
                        goto reset_unlock_out;
 
+               if (ctr->reset_ctr == NULL) {
+                       printk(KERN_DEBUG "kcapi: reset: no reset function\n");
+                       retval = -ESRCH;
+                       goto reset_unlock_out;
+               }
+
                ctr->reset_ctr(ctr);
 
                retval = wait_on_ctr_state(ctr, CAPI_CTR_DETECTED);
index 964a55fb148608b57f99b30db5b2c859654e7cf6..8f78f15c8ef78798f06a6e4a076a718829b7999c 100644 (file)
@@ -169,17 +169,6 @@ static inline void ignore_cstruct_param(struct cardstate *cs, _cstruct param,
                         msgname, paramname);
 }
 
-/*
- * convert hex to binary
- */
-static inline u8 hex2bin(char c)
-{
-       int result = c & 0x0f;
-       if (c & 0x40)
-               result += 9;
-       return result;
-}
-
 /*
  * convert an IE from Gigaset hex string to ETSI binary representation
  * including length byte
@@ -191,7 +180,7 @@ static int encode_ie(char *in, u8 *out, int maxlen)
        while (*in) {
                if (!isxdigit(in[0]) || !isxdigit(in[1]) || l >= maxlen)
                        return -1;
-               out[++l] = (hex2bin(in[0]) << 4) + hex2bin(in[1]);
+               out[++l] = (hex_to_bin(in[0]) << 4) + hex_to_bin(in[1]);
                in += 2;
        }
        out[0] = l;
@@ -932,30 +921,6 @@ void gigaset_isdn_stop(struct cardstate *cs)
  * ============================
  */
 
-/*
- * load firmware
- */
-static int gigaset_load_firmware(struct capi_ctr *ctr, capiloaddata *data)
-{
-       struct cardstate *cs = ctr->driverdata;
-
-       /* AVM specific operation, not needed for Gigaset -- ignore */
-       dev_notice(cs->dev, "load_firmware ignored\n");
-
-       return 0;
-}
-
-/*
- * reset (deactivate) controller
- */
-static void gigaset_reset_ctr(struct capi_ctr *ctr)
-{
-       struct cardstate *cs = ctr->driverdata;
-
-       /* AVM specific operation, not needed for Gigaset -- ignore */
-       dev_notice(cs->dev, "reset_ctr ignored\n");
-}
-
 /*
  * register CAPI application
  */
@@ -2213,8 +2178,8 @@ int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid)
        iif->ctr.driverdata    = cs;
        strncpy(iif->ctr.name, isdnid, sizeof(iif->ctr.name));
        iif->ctr.driver_name   = "gigaset";
-       iif->ctr.load_firmware = gigaset_load_firmware;
-       iif->ctr.reset_ctr     = gigaset_reset_ctr;
+       iif->ctr.load_firmware = NULL;
+       iif->ctr.reset_ctr     = NULL;
        iif->ctr.register_appl = gigaset_register_appl;
        iif->ctr.release_appl  = gigaset_release_appl;
        iif->ctr.send_message  = gigaset_send_message;
index 1925118122f877bdb2313d64f7fc8478e678e141..8b0a7d86b30ff1dc62bb769973b511fde7fb03d9 100644 (file)
@@ -74,9 +74,10 @@ static struct pnp_device_id fcpnp_ids[] __devinitdata = {
                .id             = "AVM0900",
                .driver_data    = (unsigned long) "Fritz!Card PnP",
        },
+       { .id = "" }
 };
 
-MODULE_DEVICE_TABLE(isapnp, fcpnp_ids);
+MODULE_DEVICE_TABLE(pnp, fcpnp_ids);
 #endif
 
 static int protocol = 2;       /* EURO-ISDN Default */
index 70044ee4b2280f37a58151d995d90170f582f9fa..a44cdb492ea999568695428b9a8353090cea0e24 100644 (file)
@@ -1272,9 +1272,9 @@ isdn_poll(struct file *file, poll_table * wait)
 
 
 static int
-isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+isdn_ioctl(struct file *file, uint cmd, ulong arg)
 {
-       uint minor = iminor(inode);
+       uint minor = iminor(file->f_path.dentry->d_inode);
        isdn_ctrl c;
        int drvidx;
        int chidx;
@@ -1722,6 +1722,18 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
 #undef cfg
 }
 
+static long
+isdn_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       int ret;
+
+       lock_kernel();
+       ret = isdn_ioctl(file, cmd, arg);
+       unlock_kernel();
+
+       return ret;
+}
+
 /*
  * Open the device code.
  */
@@ -1838,7 +1850,7 @@ static const struct file_operations isdn_fops =
        .read           = isdn_read,
        .write          = isdn_write,
        .poll           = isdn_poll,
-       .ioctl          = isdn_ioctl,
+       .unlocked_ioctl = isdn_unlocked_ioctl,
        .open           = isdn_open,
        .release        = isdn_close,
 };
index 8785004e85e09759a5b9db53bd81225a7e0f5342..81048b8ed8ad97b7890f631155c77264c35fd98d 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/miscdevice.h>
 #include <linux/module.h>
 #include <linux/mISDNif.h>
+#include <linux/smp_lock.h>
 #include "core.h"
 
 static u_int   *debug;
@@ -97,8 +98,6 @@ mISDN_read(struct file *filep, char __user *buf, size_t count, loff_t *off)
        if (*debug & DEBUG_TIMER)
                printk(KERN_DEBUG "%s(%p, %p, %d, %p)\n", __func__,
                        filep, buf, (int)count, off);
-       if (*off != filep->f_pos)
-               return -ESPIPE;
 
        if (list_empty(&dev->expired) && (dev->work == 0)) {
                if (filep->f_flags & O_NONBLOCK)
@@ -215,9 +214,8 @@ unlock:
        return ret;
 }
 
-static int
-mISDN_ioctl(struct inode *inode, struct file *filep, unsigned int cmd,
-    unsigned long arg)
+static long
+mISDN_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
 {
        struct mISDNtimerdev    *dev = filep->private_data;
        int                     id, tout, ret = 0;
@@ -226,6 +224,7 @@ mISDN_ioctl(struct inode *inode, struct file *filep, unsigned int cmd,
        if (*debug & DEBUG_TIMER)
                printk(KERN_DEBUG "%s(%p, %x, %lx)\n", __func__,
                    filep, cmd, arg);
+       lock_kernel();
        switch (cmd) {
        case IMADDTIMER:
                if (get_user(tout, (int __user *)arg)) {
@@ -257,13 +256,14 @@ mISDN_ioctl(struct inode *inode, struct file *filep, unsigned int cmd,
        default:
                ret = -EINVAL;
        }
+       unlock_kernel();
        return ret;
 }
 
 static const struct file_operations mISDN_fops = {
        .read           = mISDN_read,
        .poll           = mISDN_poll,
-       .ioctl          = mISDN_ioctl,
+       .unlocked_ioctl = mISDN_ioctl,
        .open           = mISDN_open,
        .release        = mISDN_close,
 };
index 505eb64c329cb67605cd6a69f4c70256fc6332f2..81bf25e67ce1668b88a6af271c994dde5e25cbe5 100644 (file)
@@ -21,7 +21,7 @@ comment "LED drivers"
 
 config LEDS_88PM860X
        tristate "LED Support for Marvell 88PM860x PMIC"
-       depends on LEDS_CLASS && MFD_88PM860X
+       depends on MFD_88PM860X
        help
          This option enables support for on-chip LED drivers found on Marvell
          Semiconductor 88PM8606 PMIC.
@@ -67,6 +67,16 @@ config LEDS_NET48XX
          This option enables support for the Soekris net4801 and net4826 error
          LED.
 
+config LEDS_NET5501
+       tristate "LED Support for Soekris net5501 series Error LED"
+       depends on LEDS_TRIGGERS
+       depends on X86 && LEDS_GPIO_PLATFORM && GPIO_CS5535
+       select LEDS_TRIGGER_DEFAULT_ON
+       default n
+       help
+         Add support for the Soekris net5501 board (detection, error led
+         and GPIO).
+
 config LEDS_FSG
        tristate "LED Support for the Freecom FSG-3"
        depends on MACH_FSG
@@ -285,6 +295,13 @@ config LEDS_DELL_NETBOOKS
          This adds support for the Latitude 2100 and similar
          notebooks that have an external LED.
 
+config LEDS_MC13783
+       tristate "LED Support for MC13783 PMIC"
+       depends on MFD_MC13783
+       help
+         This option enable support for on-chip LED drivers found
+         on Freescale Semiconductor MC13783 PMIC.
+
 config LEDS_TRIGGERS
        bool "LED Trigger support"
        help
index 0cd8b9957380d01f58acbf8aa28163fd1f1650fc..2493de4993741d8f59b006292e75c97d245baf9a 100644 (file)
@@ -13,6 +13,7 @@ obj-$(CONFIG_LEDS_MIKROTIK_RB532)     += leds-rb532.o
 obj-$(CONFIG_LEDS_S3C24XX)             += leds-s3c24xx.o
 obj-$(CONFIG_LEDS_AMS_DELTA)           += leds-ams-delta.o
 obj-$(CONFIG_LEDS_NET48XX)             += leds-net48xx.o
+obj-$(CONFIG_LEDS_NET5501)             += leds-net5501.o
 obj-$(CONFIG_LEDS_WRAP)                        += leds-wrap.o
 obj-$(CONFIG_LEDS_ALIX2)               += leds-alix2.o
 obj-$(CONFIG_LEDS_H1940)               += leds-h1940.o
@@ -35,6 +36,7 @@ obj-$(CONFIG_LEDS_INTEL_SS4200)               += leds-ss4200.o
 obj-$(CONFIG_LEDS_LT3593)              += leds-lt3593.o
 obj-$(CONFIG_LEDS_ADP5520)             += leds-adp5520.o
 obj-$(CONFIG_LEDS_DELL_NETBOOKS)       += dell-led.o
+obj-$(CONFIG_LEDS_MC13783)             += leds-mc13783.o
 
 # LED SPI Drivers
 obj-$(CONFIG_LEDS_DAC124S085)          += leds-dac124s085.o
index 69e7d86a5143e36d2db68275214e4af539777be4..2606600765079f946501717888a411eef20ac3fd 100644 (file)
@@ -74,7 +74,7 @@ static ssize_t led_max_brightness_show(struct device *dev,
 
 static struct device_attribute led_class_attrs[] = {
        __ATTR(brightness, 0644, led_brightness_show, led_brightness_store),
-       __ATTR(max_brightness, 0644, led_max_brightness_show, NULL),
+       __ATTR(max_brightness, 0444, led_max_brightness_show, NULL),
 #ifdef CONFIG_LEDS_TRIGGERS
        __ATTR(trigger, 0644, led_trigger_show, led_trigger_store),
 #endif
index 16a60c06c96c62c7bd6eb4d87fac77d46af1b66a..b7677106cff8041035be46fdc03442acd727f0cb 100644 (file)
@@ -256,8 +256,10 @@ static int pm860x_led_probe(struct platform_device *pdev)
        if (pdev->dev.parent->platform_data) {
                pm860x_pdata = pdev->dev.parent->platform_data;
                pdata = pm860x_pdata->led;
-       } else
-               pdata = NULL;
+       } else {
+               dev_err(&pdev->dev, "missing platform data\n");
+               return -EINVAL;
+       }
 
        data = kzalloc(sizeof(struct pm860x_led), GFP_KERNEL);
        if (data == NULL)
@@ -268,8 +270,11 @@ static int pm860x_led_probe(struct platform_device *pdev)
        data->i2c = (chip->id == CHIP_PM8606) ? chip->client : chip->companion;
        data->iset = pdata->iset;
        data->port = __check_device(pdata, data->name);
-       if (data->port < 0)
+       if (data->port < 0) {
+               dev_err(&pdev->dev, "check device failed\n");
+               kfree(data);
                return -EINVAL;
+       }
 
        data->current_brightness = 0;
        data->cdev.name = data->name;
index c6e4b772b7575206f9cb9a093b682f5060d2df82..cc22eeefa10bb1845b700771cf4b4317e05f0ba2 100644 (file)
@@ -26,7 +26,8 @@ struct gpio_led_data {
        u8 new_level;
        u8 can_sleep;
        u8 active_low;
-       int (*platform_gpio_blink_set)(unsigned gpio,
+       u8 blinking;
+       int (*platform_gpio_blink_set)(unsigned gpio, int state,
                        unsigned long *delay_on, unsigned long *delay_off);
 };
 
@@ -35,7 +36,13 @@ static void gpio_led_work(struct work_struct *work)
        struct gpio_led_data    *led_dat =
                container_of(work, struct gpio_led_data, work);
 
-       gpio_set_value_cansleep(led_dat->gpio, led_dat->new_level);
+       if (led_dat->blinking) {
+               led_dat->platform_gpio_blink_set(led_dat->gpio,
+                                                led_dat->new_level,
+                                                NULL, NULL);
+               led_dat->blinking = 0;
+       } else
+               gpio_set_value_cansleep(led_dat->gpio, led_dat->new_level);
 }
 
 static void gpio_led_set(struct led_classdev *led_cdev,
@@ -60,8 +67,14 @@ static void gpio_led_set(struct led_classdev *led_cdev,
        if (led_dat->can_sleep) {
                led_dat->new_level = level;
                schedule_work(&led_dat->work);
-       } else
-               gpio_set_value(led_dat->gpio, level);
+       } else {
+               if (led_dat->blinking) {
+                       led_dat->platform_gpio_blink_set(led_dat->gpio, level,
+                                                        NULL, NULL);
+                       led_dat->blinking = 0;
+               } else
+                       gpio_set_value(led_dat->gpio, level);
+       }
 }
 
 static int gpio_blink_set(struct led_classdev *led_cdev,
@@ -70,12 +83,14 @@ static int gpio_blink_set(struct led_classdev *led_cdev,
        struct gpio_led_data *led_dat =
                container_of(led_cdev, struct gpio_led_data, cdev);
 
-       return led_dat->platform_gpio_blink_set(led_dat->gpio, delay_on, delay_off);
+       led_dat->blinking = 1;
+       return led_dat->platform_gpio_blink_set(led_dat->gpio, GPIO_LED_BLINK,
+                                               delay_on, delay_off);
 }
 
 static int __devinit create_gpio_led(const struct gpio_led *template,
        struct gpio_led_data *led_dat, struct device *parent,
-       int (*blink_set)(unsigned, unsigned long *, unsigned long *))
+       int (*blink_set)(unsigned, int, unsigned long *, unsigned long *))
 {
        int ret, state;
 
@@ -97,6 +112,7 @@ static int __devinit create_gpio_led(const struct gpio_led *template,
        led_dat->gpio = template->gpio;
        led_dat->can_sleep = gpio_cansleep(template->gpio);
        led_dat->active_low = template->active_low;
+       led_dat->blinking = 0;
        if (blink_set) {
                led_dat->platform_gpio_blink_set = blink_set;
                led_dat->cdev.blink_set = gpio_blink_set;
@@ -113,7 +129,7 @@ static int __devinit create_gpio_led(const struct gpio_led *template,
        ret = gpio_direction_output(led_dat->gpio, led_dat->active_low ^ state);
        if (ret < 0)
                goto err;
-
+               
        INIT_WORK(&led_dat->work, gpio_led_work);
 
        ret = led_classdev_register(parent, &led_dat->cdev);
@@ -211,7 +227,7 @@ struct gpio_led_of_platform_data {
 static int __devinit of_gpio_leds_probe(struct of_device *ofdev,
                                        const struct of_device_id *match)
 {
-       struct device_node *np = ofdev->node, *child;
+       struct device_node *np = ofdev->dev.of_node, *child;
        struct gpio_led_of_platform_data *pdata;
        int count = 0, ret;
 
@@ -291,8 +307,8 @@ static struct of_platform_driver of_gpio_leds_driver = {
        .driver = {
                .name = "of_gpio_leds",
                .owner = THIS_MODULE,
+               .of_match_table = of_gpio_leds_match,
        },
-       .match_table = of_gpio_leds_match,
        .probe = of_gpio_leds_probe,
        .remove = __devexit_p(of_gpio_leds_remove),
 };
index 8d5ecceba1813f4a6de912c21c7cffe95ca965c1..932a58da76c4e97cba12a3c7b657b72dafa70e86 100644 (file)
@@ -379,6 +379,7 @@ static int __devinit lp3944_probe(struct i2c_client *client,
 {
        struct lp3944_platform_data *lp3944_pdata = client->dev.platform_data;
        struct lp3944_data *data;
+       int err;
 
        if (lp3944_pdata == NULL) {
                dev_err(&client->dev, "no platform data\n");
@@ -401,9 +402,13 @@ static int __devinit lp3944_probe(struct i2c_client *client,
 
        mutex_init(&data->lock);
 
-       dev_info(&client->dev, "lp3944 enabled\n");
+       err = lp3944_configure(client, data, lp3944_pdata);
+       if (err < 0) {
+               kfree(data);
+               return err;
+       }
 
-       lp3944_configure(client, data, lp3944_pdata);
+       dev_info(&client->dev, "lp3944 enabled\n");
        return 0;
 }
 
diff --git a/drivers/leds/leds-mc13783.c b/drivers/leds/leds-mc13783.c
new file mode 100644 (file)
index 0000000..f05bb08
--- /dev/null
@@ -0,0 +1,403 @@
+/*
+ * LEDs driver for Freescale MC13783
+ *
+ * Copyright (C) 2010 Philippe Rétornaz
+ *
+ * Based on leds-da903x:
+ * Copyright (C) 2008 Compulab, Ltd.
+ *      Mike Rapoport <mike@compulab.co.il>
+ *
+ * Copyright (C) 2006-2008 Marvell International Ltd.
+ *      Eric Miao <eric.miao@marvell.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/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/workqueue.h>
+#include <linux/mfd/mc13783.h>
+#include <linux/slab.h>
+
+struct mc13783_led {
+       struct led_classdev     cdev;
+       struct work_struct      work;
+       struct mc13783          *master;
+       enum led_brightness     new_brightness;
+       int                     id;
+};
+
+#define MC13783_REG_LED_CONTROL_0      51
+#define MC13783_LED_C0_ENABLE_BIT      (1 << 0)
+#define MC13783_LED_C0_TRIODE_MD_BIT   (1 << 7)
+#define MC13783_LED_C0_TRIODE_AD_BIT   (1 << 8)
+#define MC13783_LED_C0_TRIODE_KP_BIT   (1 << 9)
+#define MC13783_LED_C0_BOOST_BIT       (1 << 10)
+#define MC13783_LED_C0_ABMODE_MASK     0x7
+#define MC13783_LED_C0_ABMODE          11
+#define MC13783_LED_C0_ABREF_MASK      0x3
+#define MC13783_LED_C0_ABREF           14
+
+#define MC13783_REG_LED_CONTROL_1      52
+#define MC13783_LED_C1_TC1HALF_BIT     (1 << 18)
+
+#define MC13783_REG_LED_CONTROL_2      53
+#define MC13783_LED_C2_BL_P_MASK       0xf
+#define MC13783_LED_C2_MD_P            9
+#define MC13783_LED_C2_AD_P            13
+#define MC13783_LED_C2_KP_P            17
+#define MC13783_LED_C2_BL_C_MASK       0x7
+#define MC13783_LED_C2_MD_C            0
+#define MC13783_LED_C2_AD_C            3
+#define MC13783_LED_C2_KP_C            6
+
+#define MC13783_REG_LED_CONTROL_3      54
+#define MC13783_LED_C3_TC_P            6
+#define MC13783_LED_C3_TC_P_MASK       0x1f
+
+#define MC13783_REG_LED_CONTROL_4      55
+#define MC13783_REG_LED_CONTROL_5      56
+
+#define MC13783_LED_Cx_PERIOD          21
+#define MC13783_LED_Cx_PERIOD_MASK     0x3
+#define MC13783_LED_Cx_SLEWLIM_BIT      (1 << 23)
+#define MC13783_LED_Cx_TRIODE_TC_BIT   (1 << 23)
+#define MC13783_LED_Cx_TC_C_MASK       0x3
+
+static void mc13783_led_work(struct work_struct *work)
+{
+       struct mc13783_led *led = container_of(work, struct mc13783_led, work);
+       int reg = 0;
+       int mask = 0;
+       int value = 0;
+       int bank, off, shift;
+
+       switch (led->id) {
+       case MC13783_LED_MD:
+               reg = MC13783_REG_LED_CONTROL_2;
+               mask = MC13783_LED_C2_BL_P_MASK << MC13783_LED_C2_MD_P;
+               value = (led->new_brightness >> 4) << MC13783_LED_C2_MD_P;
+               break;
+       case MC13783_LED_AD:
+               reg = MC13783_REG_LED_CONTROL_2;
+               mask = MC13783_LED_C2_BL_P_MASK << MC13783_LED_C2_AD_P;
+               value = (led->new_brightness >> 4) << MC13783_LED_C2_AD_P;
+               break;
+       case MC13783_LED_KP:
+               reg = MC13783_REG_LED_CONTROL_2;
+               mask = MC13783_LED_C2_BL_P_MASK << MC13783_LED_C2_KP_P;
+               value = (led->new_brightness >> 4) << MC13783_LED_C2_KP_P;
+               break;
+       case MC13783_LED_R1:
+       case MC13783_LED_G1:
+       case MC13783_LED_B1:
+       case MC13783_LED_R2:
+       case MC13783_LED_G2:
+       case MC13783_LED_B2:
+       case MC13783_LED_R3:
+       case MC13783_LED_G3:
+       case MC13783_LED_B3:
+               off = led->id - MC13783_LED_R1;
+               bank = off/3;
+               reg = MC13783_REG_LED_CONTROL_3 + off/3;
+               shift = (off - bank * 3) * 5 + MC13783_LED_C3_TC_P;
+               value = (led->new_brightness >> 3) << shift;
+               mask = MC13783_LED_C3_TC_P_MASK << shift;
+               break;
+       }
+
+       mc13783_lock(led->master);
+
+       mc13783_reg_rmw(led->master, reg, mask, value);
+
+       mc13783_unlock(led->master);
+}
+
+static void mc13783_led_set(struct led_classdev *led_cdev,
+                          enum led_brightness value)
+{
+       struct mc13783_led *led;
+
+       led = container_of(led_cdev, struct mc13783_led, cdev);
+       led->new_brightness = value;
+       schedule_work(&led->work);
+}
+
+static int __devinit mc13783_led_setup(struct mc13783_led *led, int max_current)
+{
+       int shift = 0;
+       int mask = 0;
+       int value = 0;
+       int reg = 0;
+       int ret, bank;
+
+       switch (led->id) {
+       case MC13783_LED_MD:
+               shift = MC13783_LED_C2_MD_C;
+               mask = MC13783_LED_C2_BL_C_MASK;
+               value = max_current & MC13783_LED_C2_BL_C_MASK;
+               reg = MC13783_REG_LED_CONTROL_2;
+               break;
+       case MC13783_LED_AD:
+               shift = MC13783_LED_C2_AD_C;
+               mask = MC13783_LED_C2_BL_C_MASK;
+               value = max_current & MC13783_LED_C2_BL_C_MASK;
+               reg = MC13783_REG_LED_CONTROL_2;
+               break;
+       case MC13783_LED_KP:
+               shift = MC13783_LED_C2_KP_C;
+               mask = MC13783_LED_C2_BL_C_MASK;
+               value = max_current & MC13783_LED_C2_BL_C_MASK;
+               reg = MC13783_REG_LED_CONTROL_2;
+               break;
+       case MC13783_LED_R1:
+       case MC13783_LED_G1:
+       case MC13783_LED_B1:
+       case MC13783_LED_R2:
+       case MC13783_LED_G2:
+       case MC13783_LED_B2:
+       case MC13783_LED_R3:
+       case MC13783_LED_G3:
+       case MC13783_LED_B3:
+               bank = (led->id - MC13783_LED_R1)/3;
+               reg = MC13783_REG_LED_CONTROL_3 + bank;
+               shift = ((led->id - MC13783_LED_R1) - bank * 3) * 2;
+               mask = MC13783_LED_Cx_TC_C_MASK;
+               value = max_current & MC13783_LED_Cx_TC_C_MASK;
+               break;
+       }
+
+       mc13783_lock(led->master);
+
+       ret = mc13783_reg_rmw(led->master, reg, mask << shift,
+                                               value << shift);
+
+       mc13783_unlock(led->master);
+       return ret;
+}
+
+static int __devinit mc13783_leds_prepare(struct platform_device *pdev)
+{
+       struct mc13783_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
+       struct mc13783 *dev = dev_get_drvdata(pdev->dev.parent);
+       int ret = 0;
+       int reg = 0;
+
+       mc13783_lock(dev);
+
+       if (pdata->flags & MC13783_LED_TC1HALF)
+               reg |= MC13783_LED_C1_TC1HALF_BIT;
+
+       if (pdata->flags & MC13783_LED_SLEWLIMTC)
+               reg |= MC13783_LED_Cx_SLEWLIM_BIT;
+
+       ret = mc13783_reg_write(dev, MC13783_REG_LED_CONTROL_1, reg);
+       if (ret)
+               goto out;
+
+       reg = (pdata->bl_period & MC13783_LED_Cx_PERIOD_MASK) <<
+                                                       MC13783_LED_Cx_PERIOD;
+
+       if (pdata->flags & MC13783_LED_SLEWLIMBL)
+               reg |= MC13783_LED_Cx_SLEWLIM_BIT;
+
+       ret = mc13783_reg_write(dev, MC13783_REG_LED_CONTROL_2, reg);
+       if (ret)
+               goto out;
+
+       reg = (pdata->tc1_period & MC13783_LED_Cx_PERIOD_MASK) <<
+                                                       MC13783_LED_Cx_PERIOD;
+
+       if (pdata->flags & MC13783_LED_TRIODE_TC1)
+               reg |= MC13783_LED_Cx_TRIODE_TC_BIT;
+
+       ret = mc13783_reg_write(dev, MC13783_REG_LED_CONTROL_3, reg);
+       if (ret)
+               goto out;
+
+       reg = (pdata->tc2_period & MC13783_LED_Cx_PERIOD_MASK) <<
+                                                       MC13783_LED_Cx_PERIOD;
+
+       if (pdata->flags & MC13783_LED_TRIODE_TC2)
+               reg |= MC13783_LED_Cx_TRIODE_TC_BIT;
+
+       ret = mc13783_reg_write(dev, MC13783_REG_LED_CONTROL_4, reg);
+       if (ret)
+               goto out;
+
+       reg = (pdata->tc3_period & MC13783_LED_Cx_PERIOD_MASK) <<
+                                                       MC13783_LED_Cx_PERIOD;
+
+       if (pdata->flags & MC13783_LED_TRIODE_TC3)
+               reg |= MC13783_LED_Cx_TRIODE_TC_BIT;;
+
+       ret = mc13783_reg_write(dev, MC13783_REG_LED_CONTROL_5, reg);
+       if (ret)
+               goto out;
+
+       reg = MC13783_LED_C0_ENABLE_BIT;
+       if (pdata->flags & MC13783_LED_TRIODE_MD)
+               reg |= MC13783_LED_C0_TRIODE_MD_BIT;
+       if (pdata->flags & MC13783_LED_TRIODE_AD)
+               reg |= MC13783_LED_C0_TRIODE_AD_BIT;
+       if (pdata->flags & MC13783_LED_TRIODE_KP)
+               reg |= MC13783_LED_C0_TRIODE_KP_BIT;
+       if (pdata->flags & MC13783_LED_BOOST_EN)
+               reg |= MC13783_LED_C0_BOOST_BIT;
+
+       reg |= (pdata->abmode & MC13783_LED_C0_ABMODE_MASK) <<
+                                                       MC13783_LED_C0_ABMODE;
+       reg |= (pdata->abref & MC13783_LED_C0_ABREF_MASK) <<
+                                                       MC13783_LED_C0_ABREF;
+
+       ret = mc13783_reg_write(dev, MC13783_REG_LED_CONTROL_0, reg);
+
+out:
+       mc13783_unlock(dev);
+       return ret;
+}
+
+static int __devinit mc13783_led_probe(struct platform_device *pdev)
+{
+       struct mc13783_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
+       struct mc13783_led_platform_data *led_cur;
+       struct mc13783_led *led, *led_dat;
+       int ret, i;
+       int init_led = 0;
+
+       if (pdata == NULL) {
+               dev_err(&pdev->dev, "missing platform data\n");
+               return -ENODEV;
+       }
+
+       if (pdata->num_leds < 1 || pdata->num_leds > MC13783_LED_MAX) {
+               dev_err(&pdev->dev, "Invalid led count %d\n", pdata->num_leds);
+               return -EINVAL;
+       }
+
+       led = kzalloc(sizeof(*led) * pdata->num_leds, GFP_KERNEL);
+       if (led == NULL) {
+               dev_err(&pdev->dev, "failed to alloc memory\n");
+               return -ENOMEM;
+       }
+
+       ret = mc13783_leds_prepare(pdev);
+       if (ret) {
+               dev_err(&pdev->dev, "unable to init led driver\n");
+               goto err_free;
+       }
+
+       for (i = 0; i < pdata->num_leds; i++) {
+               led_dat = &led[i];
+               led_cur = &pdata->led[i];
+
+               if (led_cur->id > MC13783_LED_MAX || led_cur->id < 0) {
+                       dev_err(&pdev->dev, "invalid id %d\n", led_cur->id);
+                       ret = -EINVAL;
+                       goto err_register;
+               }
+
+               if (init_led & (1 << led_cur->id)) {
+                       dev_err(&pdev->dev, "led %d already initialized\n",
+                                       led_cur->id);
+                       ret = -EINVAL;
+                       goto err_register;
+               }
+
+               init_led |= 1 << led_cur->id;
+               led_dat->cdev.name = led_cur->name;
+               led_dat->cdev.default_trigger = led_cur->default_trigger;
+               led_dat->cdev.brightness_set = mc13783_led_set;
+               led_dat->cdev.brightness = LED_OFF;
+               led_dat->id = led_cur->id;
+               led_dat->master = dev_get_drvdata(pdev->dev.parent);
+
+               INIT_WORK(&led_dat->work, mc13783_led_work);
+
+               ret = led_classdev_register(pdev->dev.parent, &led_dat->cdev);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to register led %d\n",
+                                       led_dat->id);
+                       goto err_register;
+               }
+
+               ret = mc13783_led_setup(led_dat, led_cur->max_current);
+               if (ret) {
+                       dev_err(&pdev->dev, "unable to init led %d\n",
+                                       led_dat->id);
+                       i++;
+                       goto err_register;
+               }
+       }
+
+       platform_set_drvdata(pdev, led);
+       return 0;
+
+err_register:
+       for (i = i - 1; i >= 0; i--) {
+               led_classdev_unregister(&led[i].cdev);
+               cancel_work_sync(&led[i].work);
+       }
+
+err_free:
+       kfree(led);
+       return ret;
+}
+
+static int __devexit mc13783_led_remove(struct platform_device *pdev)
+{
+       struct mc13783_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
+       struct mc13783_led *led = platform_get_drvdata(pdev);
+       struct mc13783 *dev = dev_get_drvdata(pdev->dev.parent);
+       int i;
+
+       for (i = 0; i < pdata->num_leds; i++) {
+               led_classdev_unregister(&led[i].cdev);
+               cancel_work_sync(&led[i].work);
+       }
+
+       mc13783_lock(dev);
+
+       mc13783_reg_write(dev, MC13783_REG_LED_CONTROL_0, 0);
+       mc13783_reg_write(dev, MC13783_REG_LED_CONTROL_1, 0);
+       mc13783_reg_write(dev, MC13783_REG_LED_CONTROL_2, 0);
+       mc13783_reg_write(dev, MC13783_REG_LED_CONTROL_3, 0);
+       mc13783_reg_write(dev, MC13783_REG_LED_CONTROL_4, 0);
+       mc13783_reg_write(dev, MC13783_REG_LED_CONTROL_5, 0);
+
+       mc13783_unlock(dev);
+
+       kfree(led);
+       return 0;
+}
+
+static struct platform_driver mc13783_led_driver = {
+       .driver = {
+               .name   = "mc13783-led",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = mc13783_led_probe,
+       .remove         = __devexit_p(mc13783_led_remove),
+};
+
+static int __init mc13783_led_init(void)
+{
+       return platform_driver_register(&mc13783_led_driver);
+}
+module_init(mc13783_led_init);
+
+static void __exit mc13783_led_exit(void)
+{
+       platform_driver_unregister(&mc13783_led_driver);
+}
+module_exit(mc13783_led_exit);
+
+MODULE_DESCRIPTION("LEDs driver for Freescale MC13783 PMIC");
+MODULE_AUTHOR("Philippe Retornaz <philippe.retornaz@epfl.ch>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:mc13783-led");
diff --git a/drivers/leds/leds-net5501.c b/drivers/leds/leds-net5501.c
new file mode 100644 (file)
index 0000000..3063f59
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Soekris board support code
+ *
+ * Copyright (C) 2008-2009 Tower Technologies
+ * Written by Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/string.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#include <asm/geode.h>
+
+static struct gpio_led net5501_leds[] = {
+       {
+               .name = "error",
+               .gpio = 6,
+               .default_trigger = "default-on",
+       },
+};
+
+static struct gpio_led_platform_data net5501_leds_data = {
+       .num_leds = ARRAY_SIZE(net5501_leds),
+       .leds = net5501_leds,
+};
+
+static struct platform_device net5501_leds_dev = {
+       .name = "leds-gpio",
+       .id = -1,
+       .dev.platform_data = &net5501_leds_data,
+};
+
+static void __init init_net5501(void)
+{
+       platform_device_register(&net5501_leds_dev);
+}
+
+struct soekris_board {
+       u16     offset;
+       char    *sig;
+       u8      len;
+       void    (*init)(void);
+};
+
+static struct soekris_board __initdata boards[] = {
+       { 0xb7b, "net5501", 7, init_net5501 },  /* net5501 v1.33/1.33c */
+       { 0xb1f, "net5501", 7, init_net5501 },  /* net5501 v1.32i */
+};
+
+static int __init soekris_init(void)
+{
+       int i;
+       unsigned char *rombase, *bios;
+
+       if (!is_geode())
+               return 0;
+
+       rombase = ioremap(0xffff0000, 0xffff);
+       if (!rombase) {
+               printk(KERN_INFO "Soekris net5501 LED driver failed to get rombase");
+               return 0;
+       }
+
+       bios = rombase + 0x20;  /* null terminated */
+
+       if (strncmp(bios, "comBIOS", 7))
+               goto unmap;
+
+       for (i = 0; i < ARRAY_SIZE(boards); i++) {
+               unsigned char *model = rombase + boards[i].offset;
+
+               if (strncmp(model, boards[i].sig, boards[i].len) == 0) {
+                       printk(KERN_INFO "Soekris %s: %s\n", model, bios);
+
+                       if (boards[i].init)
+                               boards[i].init();
+                       break;
+               }
+       }
+
+unmap:
+       iounmap(rombase);
+       return 0;
+}
+
+arch_initcall(soekris_init);
index 51477ec7139179dd2dec53795de21273453f2c1c..a688293abd0b43a0f9e8135d0ce4d43812307f0a 100644 (file)
@@ -534,7 +534,7 @@ static int __init nas_gpio_init(void)
        set_power_light_amber_noblink();
        return 0;
 out_err:
-       for (; i >= 0; i--)
+       for (i--; i >= 0; i--)
                unregister_nasgpio_led(i);
        pci_unregister_driver(&nas_gpio_pci_driver);
        return ret;
index 26a303a1d1abd4bc885de4be79d46798f98a0afc..97147804a49cefc2e6b8864da44be7de13ca0832 100644 (file)
@@ -39,14 +39,12 @@ static struct macio_chip      *macio_on_hold;
 
 static int macio_bus_match(struct device *dev, struct device_driver *drv) 
 {
-       struct macio_dev * macio_dev = to_macio_device(dev);
-       struct macio_driver * macio_drv = to_macio_driver(drv);
-       const struct of_device_id * matches = macio_drv->match_table;
+       const struct of_device_id * matches = drv->of_match_table;
 
        if (!matches) 
                return 0;
 
-       return of_match_device(matches, &macio_dev->ofdev) != NULL;
+       return of_match_device(matches, dev) != NULL;
 }
 
 struct macio_dev *macio_dev_get(struct macio_dev *dev)
@@ -84,7 +82,7 @@ static int macio_device_probe(struct device *dev)
 
        macio_dev_get(macio_dev);
 
-       match = of_match_device(drv->match_table, &macio_dev->ofdev);
+       match = of_match_device(drv->driver.of_match_table, dev);
        if (match)
                error = drv->probe(macio_dev, match);
        if (error)
@@ -248,7 +246,7 @@ static void macio_create_fixup_irq(struct macio_dev *dev, int index,
 
 static void macio_add_missing_resources(struct macio_dev *dev)
 {
-       struct device_node *np = dev->ofdev.node;
+       struct device_node *np = dev->ofdev.dev.of_node;
        unsigned int irq_base;
 
        /* Gatwick has some missing interrupts on child nodes */
@@ -289,7 +287,7 @@ static void macio_add_missing_resources(struct macio_dev *dev)
 
 static void macio_setup_interrupts(struct macio_dev *dev)
 {
-       struct device_node *np = dev->ofdev.node;
+       struct device_node *np = dev->ofdev.dev.of_node;
        unsigned int irq;
        int i = 0, j = 0;
 
@@ -317,7 +315,7 @@ static void macio_setup_interrupts(struct macio_dev *dev)
 static void macio_setup_resources(struct macio_dev *dev,
                                  struct resource *parent_res)
 {
-       struct device_node *np = dev->ofdev.node;
+       struct device_node *np = dev->ofdev.dev.of_node;
        struct resource r;
        int index;
 
@@ -373,9 +371,9 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip,
 
        dev->bus = &chip->lbus;
        dev->media_bay = in_bay;
-       dev->ofdev.node = np;
-       dev->ofdev.dma_mask = 0xffffffffUL;
-       dev->ofdev.dev.dma_mask = &dev->ofdev.dma_mask;
+       dev->ofdev.dev.of_node = np;
+       dev->ofdev.archdata.dma_mask = 0xffffffffUL;
+       dev->ofdev.dev.dma_mask = &dev->ofdev.archdata.dma_mask;
        dev->ofdev.dev.parent = parent;
        dev->ofdev.dev.bus = &macio_bus_type;
        dev->ofdev.dev.release = macio_release_dev;
@@ -494,9 +492,9 @@ static void macio_pci_add_devices(struct macio_chip *chip)
        }
 
        /* Add media bay devices if any */
+       pnode = mbdev->ofdev.dev.of_node;
        if (mbdev)
-               for (np = NULL; (np = of_get_next_child(mbdev->ofdev.node, np))
-                            != NULL;) {
+               for (np = NULL; (np = of_get_next_child(pnode, np)) != NULL;) {
                        if (macio_skip_device(np))
                                continue;
                        of_node_get(np);
@@ -506,9 +504,9 @@ static void macio_pci_add_devices(struct macio_chip *chip)
                }
 
        /* Add serial ports if any */
+       pnode = sdev->ofdev.dev.of_node;
        if (sdev) {
-               for (np = NULL; (np = of_get_next_child(sdev->ofdev.node, np))
-                            != NULL;) {
+               for (np = NULL; (np = of_get_next_child(pnode, np)) != NULL;) {
                        if (macio_skip_device(np))
                                continue;
                        of_node_get(np);
index 9e9453b584250f61b6a741861df2608e27cfb63e..6999ce59fd1091ddd8e9b46f2ced859275deab1c 100644 (file)
@@ -9,7 +9,7 @@ field##_show (struct device *dev, struct device_attribute *attr,        \
               char *buf)                                               \
 {                                                                      \
        struct macio_dev *mdev = to_macio_device (dev);                 \
-       return sprintf (buf, format_string, mdev->ofdev.node->field);   \
+       return sprintf (buf, format_string, mdev->ofdev.dev.of_node->field); \
 }
 
 static ssize_t
@@ -21,7 +21,7 @@ compatible_show (struct device *dev, struct device_attribute *attr, char *buf)
        int length = 0;
 
        of = &to_macio_device (dev)->ofdev;
-       compat = of_get_property(of->node, "compatible", &cplen);
+       compat = of_get_property(of->dev.of_node, "compatible", &cplen);
        if (!compat) {
                *buf = '\0';
                return 0;
@@ -58,7 +58,7 @@ static ssize_t devspec_show(struct device *dev,
        struct of_device *ofdev;
 
        ofdev = to_of_device(dev);
-       return sprintf(buf, "%s\n", ofdev->node->full_name);
+       return sprintf(buf, "%s\n", ofdev->dev.of_node->full_name);
 }
 
 macio_config_of_attr (name, "%s\n");
index 08002b88f342deb961d18b20994a838bbf76bac9..288acce76b74ec36d8324d2284439c9592cbd3c7 100644 (file)
@@ -564,7 +564,7 @@ static int __devinit media_bay_attach(struct macio_dev *mdev, const struct of_de
        unsigned long base;
        int i;
 
-       ofnode = mdev->ofdev.node;
+       ofnode = mdev->ofdev.dev.of_node;
 
        if (macio_resource_count(mdev) < 1)
                return -ENODEV;
index c876349c32de5c0d8318db1bcacabf53ef2ed133..a271c8218d82b00c3311c3c77d26f135ce5791ec 100644 (file)
@@ -100,7 +100,7 @@ const struct file_operations nvram_fops = {
        .llseek         = nvram_llseek,
        .read           = read_nvram,
        .write          = write_nvram,
-       .ioctl          = nvram_ioctl,
+       .unlocked_ioctl = nvram_ioctl,
 };
 
 static struct miscdevice nvram_dev = {
index 7c54d80c4fb2309e1873cd52981fe7ff186853b5..12946c5f583f53526654b58a41138595f0f0afc9 100644 (file)
@@ -375,7 +375,7 @@ static int __devinit rackmeter_probe(struct macio_dev* mdev,
        pr_debug("rackmeter_probe()\n");
 
        /* Get i2s-a node */
-       while ((i2s = of_get_next_child(mdev->ofdev.node, i2s)) != NULL)
+       while ((i2s = of_get_next_child(mdev->ofdev.dev.of_node, i2s)) != NULL)
               if (strcmp(i2s->name, "i2s-a") == 0)
                       break;
        if (i2s == NULL) {
@@ -431,7 +431,7 @@ static int __devinit rackmeter_probe(struct macio_dev* mdev,
            of_address_to_resource(i2s, 1, &rdma)) {
                printk(KERN_ERR
                       "rackmeter: found match but lacks resources: %s",
-                      mdev->ofdev.node->full_name);
+                      mdev->ofdev.dev.of_node->full_name);
                rc = -ENXIO;
                goto bail_free;
        }
index c9da5c4c167d9ea1dbaa995ceb854acfd6001840..2506c957712e894479e48ced054b5eb4bf532873 100644 (file)
@@ -671,8 +671,11 @@ static const struct of_device_id smu_platform_match[] =
 
 static struct of_platform_driver smu_of_platform_driver =
 {
-       .name           = "smu",
-       .match_table    = smu_platform_match,
+       .driver = {
+               .name = "smu",
+               .owner = THIS_MODULE,
+               .of_match_table = smu_platform_match,
+       },
        .probe          = smu_platform_probe,
 };
 
index b18fa948f3d1be64c3f3df73cbc715596fb05de7..e60605bd0ea980a5928d0349df3fdb29eb09bb0c 100644 (file)
@@ -2215,7 +2215,7 @@ static int fcu_of_probe(struct of_device* dev, const struct of_device_id *match)
        state = state_detached;
 
        /* Lookup the fans in the device tree */
-       fcu_lookup_fans(dev->node);
+       fcu_lookup_fans(dev->dev.of_node);
 
        /* Add the driver */
        return i2c_add_driver(&therm_pm72_driver);
@@ -2238,8 +2238,11 @@ static const struct of_device_id fcu_match[] =
 
 static struct of_platform_driver fcu_of_platform_driver = 
 {
-       .name           = "temperature",
-       .match_table    = fcu_match,
+       .driver = {
+               .name = "temperature",
+               .owner = THIS_MODULE,
+               .of_match_table = fcu_match,
+       },
        .probe          = fcu_of_probe,
        .remove         = fcu_of_remove
 };
index 0839770e4ec54faa6c742c4c7f06ac81fecb7080..5c9367acf0cf2c6a3411fe691f12540caab7ffd7 100644 (file)
@@ -463,8 +463,11 @@ static const struct of_device_id therm_of_match[] = {{
 };
 
 static struct of_platform_driver therm_of_driver = {
-       .name           = "temperature",
-       .match_table    = therm_of_match,
+       .driver = {
+               .name = "temperature",
+               .owner = THIS_MODULE,
+               .of_match_table = therm_of_match,
+       },
        .probe          = therm_of_probe,
        .remove         = therm_of_remove,
 };
index 42764849eb787c42fe38315333e0d6bbcd544287..3d4fc0f7b00ba384d168214436c91103bb125419 100644 (file)
@@ -2273,8 +2273,7 @@ static int register_pmu_pm_ops(void)
 device_initcall(register_pmu_pm_ops);
 #endif
 
-static int
-pmu_ioctl(struct inode * inode, struct file *filp,
+static int pmu_ioctl(struct file *filp,
                     u_int cmd, u_long arg)
 {
        __u32 __user *argp = (__u32 __user *)arg;
@@ -2337,11 +2336,23 @@ pmu_ioctl(struct inode * inode, struct file *filp,
        return error;
 }
 
+static long pmu_unlocked_ioctl(struct file *filp,
+                              u_int cmd, u_long arg)
+{
+       int ret;
+
+       lock_kernel();
+       ret = pmu_ioctl(filp, cmd, arg);
+       unlock_kernel();
+
+       return ret;
+}
+
 static const struct file_operations pmu_device_fops = {
        .read           = pmu_read,
        .write          = pmu_write,
        .poll           = pmu_fpoll,
-       .ioctl          = pmu_ioctl,
+       .unlocked_ioctl = pmu_unlocked_ioctl,
        .open           = pmu_open,
        .release        = pmu_release,
 };
index 23d1d54b12a4b76a3d6b126a4c57c68a2b0ea6c7..1742435ce3ae3080f9ee4f489bc03e5ba827bb52 100644 (file)
@@ -1699,7 +1699,7 @@ int bitmap_create(mddev_t *mddev)
                 * and bypass the page cache, we must sync the file
                 * first.
                 */
-               vfs_fsync(file, file->f_dentry, 1);
+               vfs_fsync(file, 1);
        }
        /* read superblock from bitmap file (this sets mddev->bitmap_info.chunksize) */
        if (!mddev->bitmap_info.external)
index 9ea17d6c799bac62fa348a043469246f5ef6dbb6..d2c0f94fa37d7a708b1c6854e7be3b1d3b60162f 100644 (file)
@@ -4645,7 +4645,7 @@ static int raid456_cpu_notify(struct notifier_block *nfb, unsigned long action,
                        kfree(percpu->scribble);
                        pr_err("%s: failed memory allocation for cpu%ld\n",
                               __func__, cpu);
-                       return NOTIFY_BAD;
+                       return notifier_from_errno(-ENOMEM);
                }
                break;
        case CPU_DEAD:
index 9ddc57909d492199097bdb184f2184dff7c1fbde..425862ffb2856b1e3b9019816ef6b003e7053f3f 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/module.h>
+#include <linux/smp_lock.h>
 #include <linux/poll.h>
 #include <linux/ioctl.h>
 #include <linux/wait.h>
@@ -963,7 +964,7 @@ dvb_demux_read(struct file *file, char __user *buf, size_t count,
        return ret;
 }
 
-static int dvb_demux_do_ioctl(struct inode *inode, struct file *file,
+static int dvb_demux_do_ioctl(struct file *file,
                              unsigned int cmd, void *parg)
 {
        struct dmxdev_filter *dmxdevfilter = file->private_data;
@@ -1084,10 +1085,16 @@ static int dvb_demux_do_ioctl(struct inode *inode, struct file *file,
        return ret;
 }
 
-static int dvb_demux_ioctl(struct inode *inode, struct file *file,
-                          unsigned int cmd, unsigned long arg)
+static long dvb_demux_ioctl(struct file *file, unsigned int cmd,
+                           unsigned long arg)
 {
-       return dvb_usercopy(inode, file, cmd, arg, dvb_demux_do_ioctl);
+       int ret;
+
+       lock_kernel();
+       ret = dvb_usercopy(file, cmd, arg, dvb_demux_do_ioctl);
+       unlock_kernel();
+
+       return ret;
 }
 
 static unsigned int dvb_demux_poll(struct file *file, poll_table *wait)
@@ -1139,7 +1146,7 @@ static int dvb_demux_release(struct inode *inode, struct file *file)
 static const struct file_operations dvb_demux_fops = {
        .owner = THIS_MODULE,
        .read = dvb_demux_read,
-       .ioctl = dvb_demux_ioctl,
+       .unlocked_ioctl = dvb_demux_ioctl,
        .open = dvb_demux_open,
        .release = dvb_demux_release,
        .poll = dvb_demux_poll,
@@ -1152,7 +1159,7 @@ static struct dvb_device dvbdev_demux = {
        .fops = &dvb_demux_fops
 };
 
-static int dvb_dvr_do_ioctl(struct inode *inode, struct file *file,
+static int dvb_dvr_do_ioctl(struct file *file,
                            unsigned int cmd, void *parg)
 {
        struct dvb_device *dvbdev = file->private_data;
@@ -1176,10 +1183,16 @@ static int dvb_dvr_do_ioctl(struct inode *inode, struct file *file,
        return ret;
 }
 
-static int dvb_dvr_ioctl(struct inode *inode, struct file *file,
+static long dvb_dvr_ioctl(struct file *file,
                         unsigned int cmd, unsigned long arg)
 {
-       return dvb_usercopy(inode, file, cmd, arg, dvb_dvr_do_ioctl);
+       int ret;
+
+       lock_kernel();
+       ret = dvb_usercopy(file, cmd, arg, dvb_dvr_do_ioctl);
+       unlock_kernel();
+
+       return ret;
 }
 
 static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait)
@@ -1208,7 +1221,7 @@ static const struct file_operations dvb_dvr_fops = {
        .owner = THIS_MODULE,
        .read = dvb_dvr_read,
        .write = dvb_dvr_write,
-       .ioctl = dvb_dvr_ioctl,
+       .unlocked_ioctl = dvb_dvr_ioctl,
        .open = dvb_dvr_open,
        .release = dvb_dvr_release,
        .poll = dvb_dvr_poll,
index cb22da53bfb0fb126a7760a58b95339b0ae76a5a..ef259a0718ac3176befc7e283f67145f5d0d4d0c 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 #include <linux/sched.h>
+#include <linux/smp_lock.h>
 #include <linux/kthread.h>
 
 #include "dvb_ca_en50221.h"
@@ -1181,7 +1182,7 @@ static int dvb_ca_en50221_thread(void *data)
  *
  * @return 0 on success, <0 on error.
  */
-static int dvb_ca_en50221_io_do_ioctl(struct inode *inode, struct file *file,
+static int dvb_ca_en50221_io_do_ioctl(struct file *file,
                                      unsigned int cmd, void *parg)
 {
        struct dvb_device *dvbdev = file->private_data;
@@ -1255,10 +1256,16 @@ static int dvb_ca_en50221_io_do_ioctl(struct inode *inode, struct file *file,
  *
  * @return 0 on success, <0 on error.
  */
-static int dvb_ca_en50221_io_ioctl(struct inode *inode, struct file *file,
-                                  unsigned int cmd, unsigned long arg)
+static long dvb_ca_en50221_io_ioctl(struct file *file,
+                                   unsigned int cmd, unsigned long arg)
 {
-       return dvb_usercopy(inode, file, cmd, arg, dvb_ca_en50221_io_do_ioctl);
+       int ret;
+
+       lock_kernel();
+       ret = dvb_usercopy(file, cmd, arg, dvb_ca_en50221_io_do_ioctl);
+       unlock_kernel();
+
+       return ret;
 }
 
 
@@ -1611,7 +1618,7 @@ static const struct file_operations dvb_ca_fops = {
        .owner = THIS_MODULE,
        .read = dvb_ca_en50221_io_read,
        .write = dvb_ca_en50221_io_write,
-       .ioctl = dvb_ca_en50221_io_ioctl,
+       .unlocked_ioctl = dvb_ca_en50221_io_ioctl,
        .open = dvb_ca_en50221_io_open,
        .release = dvb_ca_en50221_io_release,
        .poll = dvb_ca_en50221_io_poll,
index 6932def4d26622bf68aae3879e07219145fec9b1..44ae89ecef94ba4701ad2cb600e42c3d7e5e7692 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/list.h>
 #include <linux/freezer.h>
 #include <linux/jiffies.h>
+#include <linux/smp_lock.h>
 #include <linux/kthread.h>
 #include <asm/processor.h>
 
@@ -1195,14 +1196,14 @@ static void dtv_property_cache_submit(struct dvb_frontend *fe)
        }
 }
 
-static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file,
+static int dvb_frontend_ioctl_legacy(struct file *file,
                        unsigned int cmd, void *parg);
-static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file,
+static int dvb_frontend_ioctl_properties(struct file *file,
                        unsigned int cmd, void *parg);
 
 static int dtv_property_process_get(struct dvb_frontend *fe,
                                    struct dtv_property *tvp,
-                                   struct inode *inode, struct file *file)
+                                   struct file *file)
 {
        int r = 0;
 
@@ -1335,7 +1336,6 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
 
 static int dtv_property_process_set(struct dvb_frontend *fe,
                                    struct dtv_property *tvp,
-                                   struct inode *inode,
                                    struct file *file)
 {
        int r = 0;
@@ -1366,7 +1366,7 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
                dprintk("%s() Finalised property cache\n", __func__);
                dtv_property_cache_submit(fe);
 
-               r |= dvb_frontend_ioctl_legacy(inode, file, FE_SET_FRONTEND,
+               r |= dvb_frontend_ioctl_legacy(file, FE_SET_FRONTEND,
                        &fepriv->parameters);
                break;
        case DTV_FREQUENCY:
@@ -1398,12 +1398,12 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
                break;
        case DTV_VOLTAGE:
                fe->dtv_property_cache.voltage = tvp->u.data;
-               r = dvb_frontend_ioctl_legacy(inode, file, FE_SET_VOLTAGE,
+               r = dvb_frontend_ioctl_legacy(file, FE_SET_VOLTAGE,
                        (void *)fe->dtv_property_cache.voltage);
                break;
        case DTV_TONE:
                fe->dtv_property_cache.sectone = tvp->u.data;
-               r = dvb_frontend_ioctl_legacy(inode, file, FE_SET_TONE,
+               r = dvb_frontend_ioctl_legacy(file, FE_SET_TONE,
                        (void *)fe->dtv_property_cache.sectone);
                break;
        case DTV_CODE_RATE_HP:
@@ -1487,7 +1487,7 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
        return r;
 }
 
-static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
+static int dvb_frontend_ioctl(struct file *file,
                        unsigned int cmd, void *parg)
 {
        struct dvb_device *dvbdev = file->private_data;
@@ -1509,17 +1509,17 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
                return -ERESTARTSYS;
 
        if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY))
-               err = dvb_frontend_ioctl_properties(inode, file, cmd, parg);
+               err = dvb_frontend_ioctl_properties(file, cmd, parg);
        else {
                fe->dtv_property_cache.state = DTV_UNDEFINED;
-               err = dvb_frontend_ioctl_legacy(inode, file, cmd, parg);
+               err = dvb_frontend_ioctl_legacy(file, cmd, parg);
        }
 
        up(&fepriv->sem);
        return err;
 }
 
-static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file,
+static int dvb_frontend_ioctl_properties(struct file *file,
                        unsigned int cmd, void *parg)
 {
        struct dvb_device *dvbdev = file->private_data;
@@ -1555,7 +1555,7 @@ static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file,
                }
 
                for (i = 0; i < tvps->num; i++) {
-                       (tvp + i)->result = dtv_property_process_set(fe, tvp + i, inode, file);
+                       (tvp + i)->result = dtv_property_process_set(fe, tvp + i, file);
                        err |= (tvp + i)->result;
                }
 
@@ -1587,7 +1587,7 @@ static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file,
                }
 
                for (i = 0; i < tvps->num; i++) {
-                       (tvp + i)->result = dtv_property_process_get(fe, tvp + i, inode, file);
+                       (tvp + i)->result = dtv_property_process_get(fe, tvp + i, file);
                        err |= (tvp + i)->result;
                }
 
@@ -1604,7 +1604,7 @@ out:
        return err;
 }
 
-static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file,
+static int dvb_frontend_ioctl_legacy(struct file *file,
                        unsigned int cmd, void *parg)
 {
        struct dvb_device *dvbdev = file->private_data;
@@ -2031,7 +2031,7 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
 
 static const struct file_operations dvb_frontend_fops = {
        .owner          = THIS_MODULE,
-       .ioctl          = dvb_generic_ioctl,
+       .unlocked_ioctl = dvb_generic_ioctl,
        .poll           = dvb_frontend_poll,
        .open           = dvb_frontend_open,
        .release        = dvb_frontend_release
index cccea412088b29c0717cdcdaab349c092bf4cd01..f6dac2bb0ac658c2f14fa39d65644ecb117d3547 100644 (file)
@@ -59,6 +59,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/dvb/net.h>
+#include <linux/smp_lock.h>
 #include <linux/uio.h>
 #include <asm/uaccess.h>
 #include <linux/crc32.h>
@@ -1329,7 +1330,7 @@ static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned long num)
        return 0;
 }
 
-static int dvb_net_do_ioctl(struct inode *inode, struct file *file,
+static int dvb_net_do_ioctl(struct file *file,
                  unsigned int cmd, void *parg)
 {
        struct dvb_device *dvbdev = file->private_data;
@@ -1431,10 +1432,16 @@ static int dvb_net_do_ioctl(struct inode *inode, struct file *file,
        return 0;
 }
 
-static int dvb_net_ioctl(struct inode *inode, struct file *file,
+static long dvb_net_ioctl(struct file *file,
              unsigned int cmd, unsigned long arg)
 {
-       return dvb_usercopy(inode, file, cmd, arg, dvb_net_do_ioctl);
+       int ret;
+
+       lock_kernel();
+       ret = dvb_usercopy(file, cmd, arg, dvb_net_do_ioctl);
+       unlock_kernel();
+
+       return ret;
 }
 
 static int dvb_net_close(struct inode *inode, struct file *file)
@@ -1455,7 +1462,7 @@ static int dvb_net_close(struct inode *inode, struct file *file)
 
 static const struct file_operations dvb_net_fops = {
        .owner = THIS_MODULE,
-       .ioctl = dvb_net_ioctl,
+       .unlocked_ioctl = dvb_net_ioctl,
        .open = dvb_generic_open,
        .release = dvb_net_close,
 };
index 94159b90f733ec7587e952cc8599dbebbd355190..b915c39d782f1edc994472d8788aaedc0b722b8c 100644 (file)
@@ -154,10 +154,11 @@ int dvb_generic_release(struct inode *inode, struct file *file)
 EXPORT_SYMBOL(dvb_generic_release);
 
 
-int dvb_generic_ioctl(struct inode *inode, struct file *file,
-                     unsigned int cmd, unsigned long arg)
+long dvb_generic_ioctl(struct file *file,
+                      unsigned int cmd, unsigned long arg)
 {
        struct dvb_device *dvbdev = file->private_data;
+       int ret;
 
        if (!dvbdev)
                return -ENODEV;
@@ -165,7 +166,11 @@ int dvb_generic_ioctl(struct inode *inode, struct file *file,
        if (!dvbdev->kernel_ioctl)
                return -EINVAL;
 
-       return dvb_usercopy (inode, file, cmd, arg, dvbdev->kernel_ioctl);
+       lock_kernel();
+       ret = dvb_usercopy(file, cmd, arg, dvbdev->kernel_ioctl);
+       unlock_kernel();
+
+       return ret;
 }
 EXPORT_SYMBOL(dvb_generic_ioctl);
 
@@ -377,9 +382,9 @@ EXPORT_SYMBOL(dvb_unregister_adapter);
    define this as video_usercopy(). this will introduce a dependecy
    to the v4l "videodev.o" module, which is unnecessary for some
    cards (ie. the budget dvb-cards don't need the v4l module...) */
-int dvb_usercopy(struct inode *inode, struct file *file,
+int dvb_usercopy(struct file *file,
                     unsigned int cmd, unsigned long arg,
-                    int (*func)(struct inode *inode, struct file *file,
+                    int (*func)(struct file *file,
                     unsigned int cmd, void *arg))
 {
        char    sbuf[128];
@@ -416,7 +421,7 @@ int dvb_usercopy(struct inode *inode, struct file *file,
        }
 
        /* call driver */
-       if ((err = func(inode, file, cmd, parg)) == -ENOIOCTLCMD)
+       if ((err = func(file, cmd, parg)) == -ENOIOCTLCMD)
                err = -EINVAL;
 
        if (err < 0)
index f7b499d4a3c0a3d3adf126a7b3e27097f70863fb..fcc6ae98745e018588d21d83af953c6765aad85c 100644 (file)
@@ -116,8 +116,7 @@ struct dvb_device {
 
        wait_queue_head_t         wait_queue;
        /* don't really need those !? -- FIXME: use video_usercopy  */
-       int (*kernel_ioctl)(struct inode *inode, struct file *file,
-                           unsigned int cmd, void *arg);
+       int (*kernel_ioctl)(struct file *file, unsigned int cmd, void *arg);
 
        void *priv;
 };
@@ -138,17 +137,15 @@ extern void dvb_unregister_device (struct dvb_device *dvbdev);
 
 extern int dvb_generic_open (struct inode *inode, struct file *file);
 extern int dvb_generic_release (struct inode *inode, struct file *file);
-extern int dvb_generic_ioctl (struct inode *inode, struct file *file,
+extern long dvb_generic_ioctl (struct file *file,
                              unsigned int cmd, unsigned long arg);
 
 /* we don't mess with video_usercopy() any more,
 we simply define out own dvb_usercopy(), which will hopefully become
 generic_usercopy()  someday... */
 
-extern int dvb_usercopy(struct inode *inode, struct file *file,
-                           unsigned int cmd, unsigned long arg,
-                           int (*func)(struct inode *inode, struct file *file,
-                           unsigned int cmd, void *arg));
+extern int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
+                           int (*func)(struct file *file, unsigned int cmd, void *arg));
 
 /** generic DVB attach function. */
 #ifdef CONFIG_MEDIA_ATTACH
index 853e04b7cb361d45257f80dcafdcf121cd340c63..d3c2cf60de7613ff7ba44a93c811d7273d5cff07 100644 (file)
@@ -175,8 +175,7 @@ static int fdtv_ca_send_msg(struct firedtv *fdtv, void *arg)
        return err;
 }
 
-static int fdtv_ca_ioctl(struct inode *inode, struct file *file,
-                           unsigned int cmd, void *arg)
+static int fdtv_ca_ioctl(struct file *file, unsigned int cmd, void *arg)
 {
        struct dvb_device *dvbdev = file->private_data;
        struct firedtv *fdtv = dvbdev->priv;
@@ -217,7 +216,7 @@ static unsigned int fdtv_ca_io_poll(struct file *file, poll_table *wait)
 
 static const struct file_operations fdtv_ca_fops = {
        .owner          = THIS_MODULE,
-       .ioctl          = dvb_generic_ioctl,
+       .unlocked_ioctl = dvb_generic_ioctl,
        .open           = dvb_generic_open,
        .release        = dvb_generic_release,
        .poll           = fdtv_ca_io_poll,
index 38915591c6e52402938ac193c27739b174ad32f0..a6be529eec5ca72e3dd8f965e334b956b4911557 100644 (file)
@@ -708,7 +708,7 @@ static void gpioirq(unsigned long cookie)
 
 
 #ifdef CONFIG_DVB_AV7110_OSD
-static int dvb_osd_ioctl(struct inode *inode, struct file *file,
+static int dvb_osd_ioctl(struct file *file,
                         unsigned int cmd, void *parg)
 {
        struct dvb_device *dvbdev = file->private_data;
@@ -727,7 +727,7 @@ static int dvb_osd_ioctl(struct inode *inode, struct file *file,
 
 static const struct file_operations dvb_osd_fops = {
        .owner          = THIS_MODULE,
-       .ioctl          = dvb_generic_ioctl,
+       .unlocked_ioctl = dvb_generic_ioctl,
        .open           = dvb_generic_open,
        .release        = dvb_generic_release,
 };
index 53884814161c2a064853de36a8557b14b04aad75..13efba942dac42579eafb43870ee3fc5d85082c9 100644 (file)
@@ -1089,7 +1089,7 @@ static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len
 }
 
 
-static int dvb_video_ioctl(struct inode *inode, struct file *file,
+static int dvb_video_ioctl(struct file *file,
                           unsigned int cmd, void *parg)
 {
        struct dvb_device *dvbdev = file->private_data;
@@ -1297,7 +1297,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
        return ret;
 }
 
-static int dvb_audio_ioctl(struct inode *inode, struct file *file,
+static int dvb_audio_ioctl(struct file *file,
                           unsigned int cmd, void *parg)
 {
        struct dvb_device *dvbdev = file->private_data;
@@ -1517,7 +1517,7 @@ static int dvb_audio_release(struct inode *inode, struct file *file)
 static const struct file_operations dvb_video_fops = {
        .owner          = THIS_MODULE,
        .write          = dvb_video_write,
-       .ioctl          = dvb_generic_ioctl,
+       .unlocked_ioctl = dvb_generic_ioctl,
        .open           = dvb_video_open,
        .release        = dvb_video_release,
        .poll           = dvb_video_poll,
@@ -1535,7 +1535,7 @@ static struct dvb_device dvbdev_video = {
 static const struct file_operations dvb_audio_fops = {
        .owner          = THIS_MODULE,
        .write          = dvb_audio_write,
-       .ioctl          = dvb_generic_ioctl,
+       .unlocked_ioctl = dvb_generic_ioctl,
        .open           = dvb_audio_open,
        .release        = dvb_audio_release,
        .poll           = dvb_audio_poll,
index ac7779c45c5b15e561d70ecc23e3de5b270ff5f5..4eba35a018e3de051db314ea573e9400ff2fd816 100644 (file)
@@ -248,8 +248,7 @@ static unsigned int dvb_ca_poll (struct file *file, poll_table *wait)
        return mask;
 }
 
-static int dvb_ca_ioctl(struct inode *inode, struct file *file,
-                unsigned int cmd, void *parg)
+static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg)
 {
        struct dvb_device *dvbdev = file->private_data;
        struct av7110 *av7110 = dvbdev->priv;
@@ -350,7 +349,7 @@ static const struct file_operations dvb_ca_fops = {
        .owner          = THIS_MODULE,
        .read           = dvb_ca_read,
        .write          = dvb_ca_write,
-       .ioctl          = dvb_generic_ioctl,
+       .unlocked_ioctl = dvb_generic_ioctl,
        .open           = dvb_ca_open,
        .release        = dvb_generic_release,
        .poll           = dvb_ca_poll,
index 7bd4c0fc23ccbf94558a747562b2ec830dfa346a..5c53624e0e87b44affc26c4eae7dc619c5082a99 100644 (file)
@@ -2570,9 +2570,7 @@ mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i)
 }
 
 /**
- * mptscsih_set_scsi_lookup
- *
- * writes a scmd entry into the ScsiLookup[] array list
+ * mptscsih_set_scsi_lookup - write a scmd entry into the ScsiLookup[] array list
  *
  * @ioc: Pointer to MPT_ADAPTER structure
  * @i: index into the array
@@ -2735,7 +2733,7 @@ mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
 
 
 /**
- *     mptscsih_get_completion_code -
+ *     mptscsih_get_completion_code - get completion code from MPT request
  *     @ioc: Pointer to MPT_ADAPTER structure
  *     @req: Pointer to original MPT request frame
  *     @reply: Pointer to MPT reply frame (NULL if TurboReply)
index d33693c133689522e5ca74e8de41c8aaa7c42066..c4b117f5fb70959df600a2153ac7d961a692488c 100644 (file)
@@ -186,14 +186,9 @@ static int i2o_cfg_parms(unsigned long arg, unsigned int type)
        if (!dev)
                return -ENXIO;
 
-       ops = kmalloc(kcmd.oplen, GFP_KERNEL);
-       if (!ops)
-               return -ENOMEM;
-
-       if (copy_from_user(ops, kcmd.opbuf, kcmd.oplen)) {
-               kfree(ops);
-               return -EFAULT;
-       }
+       ops = memdup_user(kcmd.opbuf, kcmd.oplen);
+       if (IS_ERR(ops))
+               return PTR_ERR(ops);
 
        /*
         * It's possible to have a _very_ large table
index 6a14d2b1ccf02e3bfe6701bf086ba500c9e98d6b..405d2d5183cf626c2bdd1d771f7173466f5636bb 100644 (file)
@@ -173,33 +173,35 @@ static struct resource regulator_resources[] = {
        PM8607_REG_RESOURCE(LDO9,  LDO9),
        PM8607_REG_RESOURCE(LDO10, LDO10),
        PM8607_REG_RESOURCE(LDO12, LDO12),
+       PM8607_REG_RESOURCE(VIBRATOR_SET, VIBRATOR_SET),
        PM8607_REG_RESOURCE(LDO14, LDO14),
 };
 
-#define PM8607_REG_DEVS(_name, _id)                                    \
+#define PM8607_REG_DEVS(_id)                                           \
 {                                                                      \
-       .name           = "88pm8607-" #_name,                           \
+       .name           = "88pm860x-regulator",                         \
        .num_resources  = 1,                                            \
        .resources      = &regulator_resources[PM8607_ID_##_id],        \
        .id             = PM8607_ID_##_id,                              \
 }
 
 static struct mfd_cell regulator_devs[] = {
-       PM8607_REG_DEVS(buck1, BUCK1),
-       PM8607_REG_DEVS(buck2, BUCK2),
-       PM8607_REG_DEVS(buck3, BUCK3),
-       PM8607_REG_DEVS(ldo1,  LDO1),
-       PM8607_REG_DEVS(ldo2,  LDO2),
-       PM8607_REG_DEVS(ldo3,  LDO3),
-       PM8607_REG_DEVS(ldo4,  LDO4),
-       PM8607_REG_DEVS(ldo5,  LDO5),
-       PM8607_REG_DEVS(ldo6,  LDO6),
-       PM8607_REG_DEVS(ldo7,  LDO7),
-       PM8607_REG_DEVS(ldo8,  LDO8),
-       PM8607_REG_DEVS(ldo9,  LDO9),
-       PM8607_REG_DEVS(ldo10, LDO10),
-       PM8607_REG_DEVS(ldo12, LDO12),
-       PM8607_REG_DEVS(ldo14, LDO14),
+       PM8607_REG_DEVS(BUCK1),
+       PM8607_REG_DEVS(BUCK2),
+       PM8607_REG_DEVS(BUCK3),
+       PM8607_REG_DEVS(LDO1),
+       PM8607_REG_DEVS(LDO2),
+       PM8607_REG_DEVS(LDO3),
+       PM8607_REG_DEVS(LDO4),
+       PM8607_REG_DEVS(LDO5),
+       PM8607_REG_DEVS(LDO6),
+       PM8607_REG_DEVS(LDO7),
+       PM8607_REG_DEVS(LDO8),
+       PM8607_REG_DEVS(LDO9),
+       PM8607_REG_DEVS(LDO10),
+       PM8607_REG_DEVS(LDO12),
+       PM8607_REG_DEVS(LDO13),
+       PM8607_REG_DEVS(LDO14),
 };
 
 struct pm860x_irq_data {
index de3e74cde51c425625b56e16a40db92ee14b91dd..3c6a9860dd9c2945d5722afe21e057efbbfc21e7 100644 (file)
@@ -49,6 +49,7 @@ config MFD_SH_MOBILE_SDHI
        bool "Support for SuperH Mobile SDHI"
        depends on SUPERH || ARCH_SHMOBILE
        select MFD_CORE
+       select TMIO_MMC_DMA
         ---help---
          This driver supports the SDHI hardware block found in many
          SuperH Mobile SoCs.
@@ -162,6 +163,11 @@ config MFD_TMIO
        bool
        default n
 
+config TMIO_MMC_DMA
+       bool
+       select DMA_ENGINE
+       select DMADEVICES
+
 config MFD_T7L66XB
        bool "Support Toshiba T7L66XB"
        depends on ARM && HAVE_CLK
index 1f68ecadddc24a17ab37d37e6aa6e28cb32dd3d9..fecf38a4f02543a601083bbfdd3a972f1da05963 100644 (file)
@@ -679,6 +679,10 @@ err_revision:
        if (pdata->flags & MC13783_USE_TOUCHSCREEN)
                mc13783_add_subdevice(mc13783, "mc13783-ts");
 
+       if (pdata->flags & MC13783_USE_LED)
+               mc13783_add_subdevice_pdata(mc13783, "mc13783-led",
+                                       pdata->leds, sizeof(*pdata->leds));
+
        return 0;
 }
 
index 63a614d696c1994ab037320b5d8fdbb51e7125c1..dc95ddb708f1f19278c0c0f7f70f45ea903d9071 100644 (file)
@@ -620,6 +620,9 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
                                                &pcf->mbc_pdev);
        pcf50633_client_dev_register(pcf, "pcf50633-adc",
                                                &pcf->adc_pdev);
+       pcf50633_client_dev_register(pcf, "pcf50633-backlight",
+                                               &pcf->bl_pdev);
+
 
        for (i = 0; i < PCF50633_NUM_REGULATORS; i++) {
                struct platform_device *pdev;
index 497f91b6138edc4dba97ff82c9c1845a83ca6454..cd164595f08a0cedfc7335a3033fe7a0980ca025 100644 (file)
 #include <linux/mfd/core.h>
 #include <linux/mfd/tmio.h>
 #include <linux/mfd/sh_mobile_sdhi.h>
+#include <linux/sh_dma.h>
 
 struct sh_mobile_sdhi {
        struct clk *clk;
        struct tmio_mmc_data mmc_data;
        struct mfd_cell cell_mmc;
+       struct sh_dmae_slave param_tx;
+       struct sh_dmae_slave param_rx;
+       struct tmio_mmc_dma dma_priv;
 };
 
 static struct resource sh_mobile_sdhi_resources[] = {
@@ -64,6 +68,8 @@ static void sh_mobile_sdhi_set_pwr(struct platform_device *tmio, int state)
 static int __init sh_mobile_sdhi_probe(struct platform_device *pdev)
 {
        struct sh_mobile_sdhi *priv;
+       struct tmio_mmc_data *mmc_data;
+       struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
        struct resource *mem;
        char clk_name[8];
        int ret, irq;
@@ -85,6 +91,8 @@ static int __init sh_mobile_sdhi_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
+       mmc_data = &priv->mmc_data;
+
        snprintf(clk_name, sizeof(clk_name), "sdhi%d", pdev->id);
        priv->clk = clk_get(&pdev->dev, clk_name);
        if (IS_ERR(priv->clk)) {
@@ -96,12 +104,24 @@ static int __init sh_mobile_sdhi_probe(struct platform_device *pdev)
 
        clk_enable(priv->clk);
 
-       priv->mmc_data.hclk = clk_get_rate(priv->clk);
-       priv->mmc_data.set_pwr = sh_mobile_sdhi_set_pwr;
-       priv->mmc_data.capabilities = MMC_CAP_MMC_HIGHSPEED;
+       mmc_data->hclk = clk_get_rate(priv->clk);
+       mmc_data->set_pwr = sh_mobile_sdhi_set_pwr;
+       mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED;
+       if (p) {
+               mmc_data->flags = p->tmio_flags;
+               mmc_data->ocr_mask = p->tmio_ocr_mask;
+       }
+
+       if (p && p->dma_slave_tx >= 0 && p->dma_slave_rx >= 0) {
+               priv->param_tx.slave_id = p->dma_slave_tx;
+               priv->param_rx.slave_id = p->dma_slave_rx;
+               priv->dma_priv.chan_priv_tx = &priv->param_tx;
+               priv->dma_priv.chan_priv_rx = &priv->param_rx;
+               mmc_data->dma = &priv->dma_priv;
+       }
 
        memcpy(&priv->cell_mmc, &sh_mobile_sdhi_cell, sizeof(priv->cell_mmc));
-       priv->cell_mmc.driver_data = &priv->mmc_data;
+       priv->cell_mmc.driver_data = mmc_data;
        priv->cell_mmc.platform_data = &priv->cell_mmc;
        priv->cell_mmc.data_size = sizeof(priv->cell_mmc);
 
index 0d0d625fece28849e985487fdebb9607c0c372cc..26386a92f5aafbb614c3308d7c03c05f638cfc15 100644 (file)
@@ -14,11 +14,17 @@ menuconfig MISC_DEVICES
 if MISC_DEVICES
 
 config AD525X_DPOT
-       tristate "Analog Devices AD525x Digital Potentiometers"
-       depends on I2C && SYSFS
+       tristate "Analog Devices Digital Potentiometers"
+       depends on (I2C || SPI) && SYSFS
        help
          If you say yes here, you get support for the Analog Devices
-         AD5258, AD5259, AD5251, AD5252, AD5253, AD5254 and AD5255
+         AD5258, AD5259, AD5251, AD5252, AD5253, AD5254, AD5255
+         AD5160, AD5161, AD5162, AD5165, AD5200, AD5201, AD5203,
+         AD5204, AD5206, AD5207, AD5231, AD5232, AD5233, AD5235,
+         AD5260, AD5262, AD5263, AD5290, AD5291, AD5292, AD5293,
+         AD7376, AD8400, AD8402, AD8403, ADN2850, AD5241, AD5242,
+         AD5243, AD5245, AD5246, AD5247, AD5248, AD5280, AD5282,
+         ADN2860, AD5273, AD5171, AD5170, AD5172, AD5173
          digital potentiometer chips.
 
          See Documentation/misc-devices/ad525x_dpot.txt for the
@@ -27,6 +33,26 @@ config AD525X_DPOT
          This driver can also be built as a module.  If so, the module
          will be called ad525x_dpot.
 
+config AD525X_DPOT_I2C
+       tristate "support I2C bus connection"
+       depends on AD525X_DPOT && I2C
+       help
+         Say Y here if you have a digital potentiometers hooked to an I2C bus.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ad525x_dpot-i2c.
+
+config AD525X_DPOT_SPI
+       tristate "support SPI bus connection"
+       depends on AD525X_DPOT && SPI_MASTER
+       help
+         Say Y here if you have a digital potentiometers hooked to an SPI bus.
+
+         If unsure, say N (but it's safe to say "Y").
+
+         To compile this driver as a module, choose M here: the
+         module will be called ad525x_dpot-spi.
+
 config ATMEL_PWM
        tristate "Atmel AT32/AT91 PWM support"
        depends on AVR32 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9
index f12dc3e544029b63a85ec2c3e97e80f601487422..6ed06a19474acc23de3b93b732ecce25b9a55c40 100644 (file)
@@ -4,6 +4,8 @@
 
 obj-$(CONFIG_IBM_ASM)          += ibmasm/
 obj-$(CONFIG_AD525X_DPOT)      += ad525x_dpot.o
+obj-$(CONFIG_AD525X_DPOT_I2C)  += ad525x_dpot-i2c.o
+obj-$(CONFIG_AD525X_DPOT_SPI)  += ad525x_dpot-spi.o
 obj-$(CONFIG_ATMEL_PWM)                += atmel_pwm.o
 obj-$(CONFIG_ATMEL_SSC)                += atmel-ssc.o
 obj-$(CONFIG_ATMEL_TCLIB)      += atmel_tclib.o
diff --git a/drivers/misc/ad525x_dpot-i2c.c b/drivers/misc/ad525x_dpot-i2c.c
new file mode 100644 (file)
index 0000000..374352a
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Driver for the Analog Devices digital potentiometers (I2C bus)
+ *
+ * Copyright (C) 2010 Michael Hennerich, Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+
+#include "ad525x_dpot.h"
+
+/* ------------------------------------------------------------------------- */
+/* I2C bus functions */
+static int write_d8(void *client, u8 val)
+{
+       return i2c_smbus_write_byte(client, val);
+}
+
+static int write_r8d8(void *client, u8 reg, u8 val)
+{
+       return i2c_smbus_write_byte_data(client, reg, val);
+}
+
+static int write_r8d16(void *client, u8 reg, u16 val)
+{
+       return i2c_smbus_write_word_data(client, reg, val);
+}
+
+static int read_d8(void *client)
+{
+       return i2c_smbus_read_byte(client);
+}
+
+static int read_r8d8(void *client, u8 reg)
+{
+       return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int read_r8d16(void *client, u8 reg)
+{
+       return i2c_smbus_read_word_data(client, reg);
+}
+
+static const struct ad_dpot_bus_ops bops = {
+       .read_d8        = read_d8,
+       .read_r8d8      = read_r8d8,
+       .read_r8d16     = read_r8d16,
+       .write_d8       = write_d8,
+       .write_r8d8     = write_r8d8,
+       .write_r8d16    = write_r8d16,
+};
+
+static int __devinit ad_dpot_i2c_probe(struct i2c_client *client,
+                                     const struct i2c_device_id *id)
+{
+       struct ad_dpot_bus_data bdata = {
+               .client = client,
+               .bops = &bops,
+       };
+
+       struct ad_dpot_id dpot_id = {
+               .name = (char *) &id->name,
+               .devid = id->driver_data,
+       };
+
+       if (!i2c_check_functionality(client->adapter,
+                                    I2C_FUNC_SMBUS_WORD_DATA)) {
+               dev_err(&client->dev, "SMBUS Word Data not Supported\n");
+               return -EIO;
+       }
+
+       return ad_dpot_probe(&client->dev, &bdata, &dpot_id);
+}
+
+static int __devexit ad_dpot_i2c_remove(struct i2c_client *client)
+{
+       return ad_dpot_remove(&client->dev);
+}
+
+static const struct i2c_device_id ad_dpot_id[] = {
+       {"ad5258", AD5258_ID},
+       {"ad5259", AD5259_ID},
+       {"ad5251", AD5251_ID},
+       {"ad5252", AD5252_ID},
+       {"ad5253", AD5253_ID},
+       {"ad5254", AD5254_ID},
+       {"ad5255", AD5255_ID},
+       {"ad5241", AD5241_ID},
+       {"ad5242", AD5242_ID},
+       {"ad5243", AD5243_ID},
+       {"ad5245", AD5245_ID},
+       {"ad5246", AD5246_ID},
+       {"ad5247", AD5247_ID},
+       {"ad5248", AD5248_ID},
+       {"ad5280", AD5280_ID},
+       {"ad5282", AD5282_ID},
+       {"adn2860", ADN2860_ID},
+       {"ad5273", AD5273_ID},
+       {"ad5171", AD5171_ID},
+       {"ad5170", AD5170_ID},
+       {"ad5172", AD5172_ID},
+       {"ad5173", AD5173_ID},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, ad_dpot_id);
+
+static struct i2c_driver ad_dpot_i2c_driver = {
+       .driver = {
+               .name   = "ad_dpot",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = ad_dpot_i2c_probe,
+       .remove         = __devexit_p(ad_dpot_i2c_remove),
+       .id_table       = ad_dpot_id,
+};
+
+static int __init ad_dpot_i2c_init(void)
+{
+       return i2c_add_driver(&ad_dpot_i2c_driver);
+}
+module_init(ad_dpot_i2c_init);
+
+static void __exit ad_dpot_i2c_exit(void)
+{
+       i2c_del_driver(&ad_dpot_i2c_driver);
+}
+module_exit(ad_dpot_i2c_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("digital potentiometer I2C bus driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("i2c:ad_dpot");
diff --git a/drivers/misc/ad525x_dpot-spi.c b/drivers/misc/ad525x_dpot-spi.c
new file mode 100644 (file)
index 0000000..b8c6df9
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Driver for the Analog Devices digital potentiometers (SPI bus)
+ *
+ * Copyright (C) 2010 Michael Hennerich, Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/spi/spi.h>
+#include <linux/module.h>
+
+#include "ad525x_dpot.h"
+
+static const struct ad_dpot_id ad_dpot_spi_devlist[] = {
+       {.name = "ad5160", .devid = AD5160_ID},
+       {.name = "ad5161", .devid = AD5161_ID},
+       {.name = "ad5162", .devid = AD5162_ID},
+       {.name = "ad5165", .devid = AD5165_ID},
+       {.name = "ad5200", .devid = AD5200_ID},
+       {.name = "ad5201", .devid = AD5201_ID},
+       {.name = "ad5203", .devid = AD5203_ID},
+       {.name = "ad5204", .devid = AD5204_ID},
+       {.name = "ad5206", .devid = AD5206_ID},
+       {.name = "ad5207", .devid = AD5207_ID},
+       {.name = "ad5231", .devid = AD5231_ID},
+       {.name = "ad5232", .devid = AD5232_ID},
+       {.name = "ad5233", .devid = AD5233_ID},
+       {.name = "ad5235", .devid = AD5235_ID},
+       {.name = "ad5260", .devid = AD5260_ID},
+       {.name = "ad5262", .devid = AD5262_ID},
+       {.name = "ad5263", .devid = AD5263_ID},
+       {.name = "ad5290", .devid = AD5290_ID},
+       {.name = "ad5291", .devid = AD5291_ID},
+       {.name = "ad5292", .devid = AD5292_ID},
+       {.name = "ad5293", .devid = AD5293_ID},
+       {.name = "ad7376", .devid = AD7376_ID},
+       {.name = "ad8400", .devid = AD8400_ID},
+       {.name = "ad8402", .devid = AD8402_ID},
+       {.name = "ad8403", .devid = AD8403_ID},
+       {.name = "adn2850", .devid = ADN2850_ID},
+       {}
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* SPI bus functions */
+static int write8(void *client, u8 val)
+{
+       u8 data = val;
+       return spi_write(client, &data, 1);
+}
+
+static int write16(void *client, u8 reg, u8 val)
+{
+       u8 data[2] = {reg, val};
+       return spi_write(client, data, 1);
+}
+
+static int write24(void *client, u8 reg, u16 val)
+{
+       u8 data[3] = {reg, val >> 8, val};
+       return spi_write(client, data, 1);
+}
+
+static int read8(void *client)
+{
+       int ret;
+       u8 data;
+       ret = spi_read(client, &data, 1);
+       if (ret < 0)
+               return ret;
+
+       return data;
+}
+
+static int read16(void *client, u8 reg)
+{
+       int ret;
+       u8 buf_rx[2];
+
+       write16(client, reg, 0);
+       ret = spi_read(client, buf_rx, 2);
+       if (ret < 0)
+               return ret;
+
+       return (buf_rx[0] << 8) |  buf_rx[1];
+}
+
+static int read24(void *client, u8 reg)
+{
+       int ret;
+       u8 buf_rx[3];
+
+       write24(client, reg, 0);
+       ret = spi_read(client, buf_rx, 3);
+       if (ret < 0)
+               return ret;
+
+       return (buf_rx[1] << 8) |  buf_rx[2];
+}
+
+static const struct ad_dpot_bus_ops bops = {
+       .read_d8        = read8,
+       .read_r8d8      = read16,
+       .read_r8d16     = read24,
+       .write_d8       = write8,
+       .write_r8d8     = write16,
+       .write_r8d16    = write24,
+};
+
+static const struct ad_dpot_id *dpot_match_id(const struct ad_dpot_id *id,
+                                               char *name)
+{
+       while (id->name && id->name[0]) {
+               if (strcmp(name, id->name) == 0)
+                       return id;
+               id++;
+       }
+       return NULL;
+}
+
+static int __devinit ad_dpot_spi_probe(struct spi_device *spi)
+{
+       char *name = spi->dev.platform_data;
+       const struct ad_dpot_id *dpot_id;
+
+       struct ad_dpot_bus_data bdata = {
+               .client = spi,
+               .bops = &bops,
+       };
+
+       dpot_id = dpot_match_id(ad_dpot_spi_devlist, name);
+
+       if (dpot_id == NULL) {
+               dev_err(&spi->dev, "%s not in supported device list", name);
+               return -ENODEV;
+       }
+
+       return ad_dpot_probe(&spi->dev, &bdata, dpot_id);
+}
+
+static int __devexit ad_dpot_spi_remove(struct spi_device *spi)
+{
+       return ad_dpot_remove(&spi->dev);
+}
+
+static struct spi_driver ad_dpot_spi_driver = {
+       .driver = {
+               .name   = "ad_dpot",
+               .bus    = &spi_bus_type,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = ad_dpot_spi_probe,
+       .remove         = __devexit_p(ad_dpot_spi_remove),
+};
+
+static int __init ad_dpot_spi_init(void)
+{
+       return spi_register_driver(&ad_dpot_spi_driver);
+}
+module_init(ad_dpot_spi_init);
+
+static void __exit ad_dpot_spi_exit(void)
+{
+       spi_unregister_driver(&ad_dpot_spi_driver);
+}
+module_exit(ad_dpot_spi_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("digital potentiometer SPI bus driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:ad_dpot");
index 30a59f2bacd2a58f61abb25a4bfcbc28c046f61a..5e6fa8449e8b7bba11c2aca88fce59f34b80277e 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * ad525x_dpot: Driver for the Analog Devices AD525x digital potentiometers
- * Copyright (c) 2009 Analog Devices, Inc.
+ * ad525x_dpot: Driver for the Analog Devices digital potentiometers
+ * Copyright (c) 2009-2010 Analog Devices, Inc.
  * Author: Michael Hennerich <hennerich@blackfin.uclinux.org>
  *
  * DEVID               #Wipers         #Positions      Resistor Options (kOhm)
  * AD5255              3               512             25, 250
  * AD5253              4               64              1, 10, 50, 100
  * AD5254              4               256             1, 10, 50, 100
+ * AD5160              1               256             5, 10, 50, 100
+ * AD5161              1               256             5, 10, 50, 100
+ * AD5162              2               256             2.5, 10, 50, 100
+ * AD5165              1               256             100
+ * AD5200              1               256             10, 50
+ * AD5201              1               33              10, 50
+ * AD5203              4               64              10, 100
+ * AD5204              4               256             10, 50, 100
+ * AD5206              6               256             10, 50, 100
+ * AD5207              2               256             10, 50, 100
+ * AD5231              1               1024            10, 50, 100
+ * AD5232              2               256             10, 50, 100
+ * AD5233              4               64              10, 50, 100
+ * AD5235              2               1024            25, 250
+ * AD5260              1               256             20, 50, 200
+ * AD5262              2               256             20, 50, 200
+ * AD5263              4               256             20, 50, 200
+ * AD5290              1               256             10, 50, 100
+ * AD5291              1               256             20
+ * AD5292              1               1024            20
+ * AD5293              1               1024            20
+ * AD7376              1               128             10, 50, 100, 1M
+ * AD8400              1               256             1, 10, 50, 100
+ * AD8402              2               256             1, 10, 50, 100
+ * AD8403              4               256             1, 10, 50, 100
+ * ADN2850             3               512             25, 250
+ * AD5241              1               256             10, 100, 1M
+ * AD5246              1               128             5, 10, 50, 100
+ * AD5247              1               128             5, 10, 50, 100
+ * AD5245              1               256             5, 10, 50, 100
+ * AD5243              2               256             2.5, 10, 50, 100
+ * AD5248              2               256             2.5, 10, 50, 100
+ * AD5242              2               256             20, 50, 200
+ * AD5280              1               256             20, 50, 200
+ * AD5282              2               256             20, 50, 200
+ * ADN2860             3               512             25, 250
+ * AD5273              1               64              1, 10, 50, 100 (OTP)
+ * AD5171              1               64              5, 10, 50, 100 (OTP)
+ * AD5170              1               256             2.5, 10, 50, 100 (OTP)
+ * AD5172              2               256             2.5, 10, 50, 100 (OTP)
+ * AD5173              2               256             2.5, 10, 50, 100 (OTP)
  *
  * See Documentation/misc-devices/ad525x_dpot.txt for more info.
  *
 #include <linux/device.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
 #include <linux/delay.h>
+#include <linux/slab.h>
 
-#define DRIVER_NAME                    "ad525x_dpot"
-#define DRIVER_VERSION                 "0.1"
-
-enum dpot_devid {
-       AD5258_ID,
-       AD5259_ID,
-       AD5251_ID,
-       AD5252_ID,
-       AD5253_ID,
-       AD5254_ID,
-       AD5255_ID,
-};
+#define DRIVER_VERSION                 "0.2"
 
-#define AD5258_MAX_POSITION            64
-#define AD5259_MAX_POSITION            256
-#define AD5251_MAX_POSITION            64
-#define AD5252_MAX_POSITION            256
-#define AD5253_MAX_POSITION            64
-#define AD5254_MAX_POSITION            256
-#define AD5255_MAX_POSITION            512
-
-#define AD525X_RDAC0           0
-#define AD525X_RDAC1           1
-#define AD525X_RDAC2           2
-#define AD525X_RDAC3           3
-
-#define AD525X_REG_TOL         0x18
-#define AD525X_TOL_RDAC0       (AD525X_REG_TOL | AD525X_RDAC0)
-#define AD525X_TOL_RDAC1       (AD525X_REG_TOL | AD525X_RDAC1)
-#define AD525X_TOL_RDAC2       (AD525X_REG_TOL | AD525X_RDAC2)
-#define AD525X_TOL_RDAC3       (AD525X_REG_TOL | AD525X_RDAC3)
-
-/* RDAC-to-EEPROM Interface Commands */
-#define AD525X_I2C_RDAC                (0x00 << 5)
-#define AD525X_I2C_EEPROM      (0x01 << 5)
-#define AD525X_I2C_CMD         (0x80)
-
-#define AD525X_DEC_ALL_6DB     (AD525X_I2C_CMD | (0x4 << 3))
-#define AD525X_INC_ALL_6DB     (AD525X_I2C_CMD | (0x9 << 3))
-#define AD525X_DEC_ALL         (AD525X_I2C_CMD | (0x6 << 3))
-#define AD525X_INC_ALL         (AD525X_I2C_CMD | (0xB << 3))
-
-static s32 ad525x_read(struct i2c_client *client, u8 reg);
-static s32 ad525x_write(struct i2c_client *client, u8 reg, u8 value);
+#include "ad525x_dpot.h"
 
 /*
  * Client data (each client gets its own)
  */
 
 struct dpot_data {
+       struct ad_dpot_bus_data bdata;
        struct mutex update_lock;
        unsigned rdac_mask;
        unsigned max_pos;
-       unsigned devid;
+       unsigned long devid;
+       unsigned uid;
+       unsigned feat;
+       unsigned wipers;
+       u16 rdac_cache[MAX_RDACS];
+       DECLARE_BITMAP(otp_en_mask, MAX_RDACS);
 };
 
+static inline int dpot_read_d8(struct dpot_data *dpot)
+{
+       return dpot->bdata.bops->read_d8(dpot->bdata.client);
+}
+
+static inline int dpot_read_r8d8(struct dpot_data *dpot, u8 reg)
+{
+       return dpot->bdata.bops->read_r8d8(dpot->bdata.client, reg);
+}
+
+static inline int dpot_read_r8d16(struct dpot_data *dpot, u8 reg)
+{
+       return dpot->bdata.bops->read_r8d16(dpot->bdata.client, reg);
+}
+
+static inline int dpot_write_d8(struct dpot_data *dpot, u8 val)
+{
+       return dpot->bdata.bops->write_d8(dpot->bdata.client, val);
+}
+
+static inline int dpot_write_r8d8(struct dpot_data *dpot, u8 reg, u16 val)
+{
+       return dpot->bdata.bops->write_r8d8(dpot->bdata.client, reg, val);
+}
+
+static inline int dpot_write_r8d16(struct dpot_data *dpot, u8 reg, u16 val)
+{
+       return dpot->bdata.bops->write_r8d16(dpot->bdata.client, reg, val);
+}
+
+static s32 dpot_read_spi(struct dpot_data *dpot, u8 reg)
+{
+       unsigned ctrl = 0;
+
+       if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD))) {
+
+               if (dpot->feat & F_RDACS_WONLY)
+                       return dpot->rdac_cache[reg & DPOT_RDAC_MASK];
+
+               if (dpot->uid == DPOT_UID(AD5291_ID) ||
+                       dpot->uid == DPOT_UID(AD5292_ID) ||
+                       dpot->uid == DPOT_UID(AD5293_ID))
+                       return dpot_read_r8d8(dpot,
+                               DPOT_AD5291_READ_RDAC << 2);
+
+               ctrl = DPOT_SPI_READ_RDAC;
+       } else if (reg & DPOT_ADDR_EEPROM) {
+               ctrl = DPOT_SPI_READ_EEPROM;
+       }
+
+       if (dpot->feat & F_SPI_16BIT)
+               return dpot_read_r8d8(dpot, ctrl);
+       else if (dpot->feat & F_SPI_24BIT)
+               return dpot_read_r8d16(dpot, ctrl);
+
+       return -EFAULT;
+}
+
+static s32 dpot_read_i2c(struct dpot_data *dpot, u8 reg)
+{
+       unsigned ctrl = 0;
+       switch (dpot->uid) {
+       case DPOT_UID(AD5246_ID):
+       case DPOT_UID(AD5247_ID):
+               return dpot_read_d8(dpot);
+       case DPOT_UID(AD5245_ID):
+       case DPOT_UID(AD5241_ID):
+       case DPOT_UID(AD5242_ID):
+       case DPOT_UID(AD5243_ID):
+       case DPOT_UID(AD5248_ID):
+       case DPOT_UID(AD5280_ID):
+       case DPOT_UID(AD5282_ID):
+               ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
+                       0 : DPOT_AD5291_RDAC_AB;
+               return dpot_read_r8d8(dpot, ctrl);
+       case DPOT_UID(AD5170_ID):
+       case DPOT_UID(AD5171_ID):
+       case DPOT_UID(AD5273_ID):
+                       return dpot_read_d8(dpot);
+       case DPOT_UID(AD5172_ID):
+       case DPOT_UID(AD5173_ID):
+               ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
+                       0 : DPOT_AD5272_3_A0;
+               return dpot_read_r8d8(dpot, ctrl);
+       default:
+               if ((reg & DPOT_REG_TOL) || (dpot->max_pos > 256))
+                       return dpot_read_r8d16(dpot, (reg & 0xF8) |
+                                       ((reg & 0x7) << 1));
+               else
+                       return dpot_read_r8d8(dpot, reg);
+       }
+}
+
+static s32 dpot_read(struct dpot_data *dpot, u8 reg)
+{
+       if (dpot->feat & F_SPI)
+               return dpot_read_spi(dpot, reg);
+       else
+               return dpot_read_i2c(dpot, reg);
+}
+
+static s32 dpot_write_spi(struct dpot_data *dpot, u8 reg, u16 value)
+{
+       unsigned val = 0;
+
+       if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD))) {
+               if (dpot->feat & F_RDACS_WONLY)
+                       dpot->rdac_cache[reg & DPOT_RDAC_MASK] = value;
+
+               if (dpot->feat & F_AD_APPDATA) {
+                       if (dpot->feat & F_SPI_8BIT) {
+                               val = ((reg & DPOT_RDAC_MASK) <<
+                                       DPOT_MAX_POS(dpot->devid)) |
+                                       value;
+                               return dpot_write_d8(dpot, val);
+                       } else if (dpot->feat & F_SPI_16BIT) {
+                               val = ((reg & DPOT_RDAC_MASK) <<
+                                       DPOT_MAX_POS(dpot->devid)) |
+                                       value;
+                               return dpot_write_r8d8(dpot, val >> 8,
+                                       val & 0xFF);
+                       } else
+                               BUG();
+               } else {
+                       if (dpot->uid == DPOT_UID(AD5291_ID) ||
+                               dpot->uid == DPOT_UID(AD5292_ID) ||
+                               dpot->uid == DPOT_UID(AD5293_ID))
+                               return dpot_write_r8d8(dpot,
+                                       (DPOT_AD5291_RDAC << 2) |
+                                       (value >> 8), value & 0xFF);
+
+                       val = DPOT_SPI_RDAC | (reg & DPOT_RDAC_MASK);
+               }
+       } else if (reg & DPOT_ADDR_EEPROM) {
+               val = DPOT_SPI_EEPROM | (reg & DPOT_RDAC_MASK);
+       } else if (reg & DPOT_ADDR_CMD) {
+               switch (reg) {
+               case DPOT_DEC_ALL_6DB:
+                       val = DPOT_SPI_DEC_ALL_6DB;
+                       break;
+               case DPOT_INC_ALL_6DB:
+                       val = DPOT_SPI_INC_ALL_6DB;
+                       break;
+               case DPOT_DEC_ALL:
+                       val = DPOT_SPI_DEC_ALL;
+                       break;
+               case DPOT_INC_ALL:
+                       val = DPOT_SPI_INC_ALL;
+                       break;
+               }
+       } else
+               BUG();
+
+       if (dpot->feat & F_SPI_16BIT)
+               return dpot_write_r8d8(dpot, val, value);
+       else if (dpot->feat & F_SPI_24BIT)
+               return dpot_write_r8d16(dpot, val, value);
+
+       return -EFAULT;
+}
+
+static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value)
+{
+       /* Only write the instruction byte for certain commands */
+       unsigned tmp = 0, ctrl = 0;
+
+       switch (dpot->uid) {
+       case DPOT_UID(AD5246_ID):
+       case DPOT_UID(AD5247_ID):
+               return dpot_write_d8(dpot, value);
+               break;
+
+       case DPOT_UID(AD5245_ID):
+       case DPOT_UID(AD5241_ID):
+       case DPOT_UID(AD5242_ID):
+       case DPOT_UID(AD5243_ID):
+       case DPOT_UID(AD5248_ID):
+       case DPOT_UID(AD5280_ID):
+       case DPOT_UID(AD5282_ID):
+               ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
+                       0 : DPOT_AD5291_RDAC_AB;
+               return dpot_write_r8d8(dpot, ctrl, value);
+               break;
+       case DPOT_UID(AD5171_ID):
+       case DPOT_UID(AD5273_ID):
+               if (reg & DPOT_ADDR_OTP) {
+                       tmp = dpot_read_d8(dpot);
+                       if (tmp >> 6) /* Ready to Program? */
+                               return -EFAULT;
+                       ctrl = DPOT_AD5273_FUSE;
+               }
+               return dpot_write_r8d8(dpot, ctrl, value);
+               break;
+       case DPOT_UID(AD5172_ID):
+       case DPOT_UID(AD5173_ID):
+               ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
+                       0 : DPOT_AD5272_3_A0;
+               if (reg & DPOT_ADDR_OTP) {
+                       tmp = dpot_read_r8d16(dpot, ctrl);
+                       if (tmp >> 14) /* Ready to Program? */
+                               return -EFAULT;
+                       ctrl |= DPOT_AD5270_2_3_FUSE;
+               }
+               return dpot_write_r8d8(dpot, ctrl, value);
+               break;
+       case DPOT_UID(AD5170_ID):
+               if (reg & DPOT_ADDR_OTP) {
+                       tmp = dpot_read_r8d16(dpot, tmp);
+                       if (tmp >> 14) /* Ready to Program? */
+                               return -EFAULT;
+                       ctrl = DPOT_AD5270_2_3_FUSE;
+               }
+               return dpot_write_r8d8(dpot, ctrl, value);
+               break;
+       default:
+               if (reg & DPOT_ADDR_CMD)
+                       return dpot_write_d8(dpot, reg);
+
+               if (dpot->max_pos > 256)
+                       return dpot_write_r8d16(dpot, (reg & 0xF8) |
+                                               ((reg & 0x7) << 1), value);
+               else
+                       /* All other registers require instruction + data bytes */
+                       return dpot_write_r8d8(dpot, reg, value);
+       }
+}
+
+
+static s32 dpot_write(struct dpot_data *dpot, u8 reg, u16 value)
+{
+       if (dpot->feat & F_SPI)
+               return dpot_write_spi(dpot, reg, value);
+       else
+               return dpot_write_i2c(dpot, reg, value);
+}
+
 /* sysfs functions */
 
 static ssize_t sysfs_show_reg(struct device *dev,
-                             struct device_attribute *attr, char *buf, u32 reg)
+                             struct device_attribute *attr,
+                             char *buf, u32 reg)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct dpot_data *data = i2c_get_clientdata(client);
+       struct dpot_data *data = dev_get_drvdata(dev);
        s32 value;
 
+       if (reg & DPOT_ADDR_OTP_EN)
+               return sprintf(buf, "%s\n",
+                       test_bit(DPOT_RDAC_MASK & reg, data->otp_en_mask) ?
+                       "enabled" : "disabled");
+
+
        mutex_lock(&data->update_lock);
-       value = ad525x_read(client, reg);
+       value = dpot_read(data, reg);
        mutex_unlock(&data->update_lock);
 
        if (value < 0)
@@ -111,7 +358,7 @@ static ssize_t sysfs_show_reg(struct device *dev,
         * datasheet (Rev. A) for more details.
         */
 
-       if (reg & AD525X_REG_TOL)
+       if (reg & DPOT_REG_TOL)
                return sprintf(buf, "0x%04x\n", value & 0xFFFF);
        else
                return sprintf(buf, "%u\n", value & data->rdac_mask);
@@ -121,11 +368,23 @@ static ssize_t sysfs_set_reg(struct device *dev,
                             struct device_attribute *attr,
                             const char *buf, size_t count, u32 reg)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct dpot_data *data = i2c_get_clientdata(client);
+       struct dpot_data *data = dev_get_drvdata(dev);
        unsigned long value;
        int err;
 
+       if (reg & DPOT_ADDR_OTP_EN) {
+               if (!strncmp(buf, "enabled", sizeof("enabled")))
+                       set_bit(DPOT_RDAC_MASK & reg, data->otp_en_mask);
+               else
+                       clear_bit(DPOT_RDAC_MASK & reg, data->otp_en_mask);
+
+               return count;
+       }
+
+       if ((reg & DPOT_ADDR_OTP) &&
+               !test_bit(DPOT_RDAC_MASK & reg, data->otp_en_mask))
+               return -EPERM;
+
        err = strict_strtoul(buf, 10, &value);
        if (err)
                return err;
@@ -134,9 +393,11 @@ static ssize_t sysfs_set_reg(struct device *dev,
                value = data->rdac_mask;
 
        mutex_lock(&data->update_lock);
-       ad525x_write(client, reg, value);
-       if (reg & AD525X_I2C_EEPROM)
+       dpot_write(data, reg, value);
+       if (reg & DPOT_ADDR_EEPROM)
                msleep(26);     /* Sleep while the EEPROM updates */
+       else if (reg & DPOT_ADDR_OTP)
+               msleep(400);    /* Sleep while the OTP updates */
        mutex_unlock(&data->update_lock);
 
        return count;
@@ -146,11 +407,10 @@ static ssize_t sysfs_do_cmd(struct device *dev,
                            struct device_attribute *attr,
                            const char *buf, size_t count, u32 reg)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct dpot_data *data = i2c_get_clientdata(client);
+       struct dpot_data *data = dev_get_drvdata(dev);
 
        mutex_lock(&data->update_lock);
-       ad525x_write(client, reg, 0);
+       dpot_write(data, reg, 0);
        mutex_unlock(&data->update_lock);
 
        return count;
@@ -158,244 +418,131 @@ static ssize_t sysfs_do_cmd(struct device *dev,
 
 /* ------------------------------------------------------------------------- */
 
-static ssize_t show_rdac0(struct device *dev,
-                         struct device_attribute *attr, char *buf)
-{
-       return sysfs_show_reg(dev, attr, buf, AD525X_I2C_RDAC | AD525X_RDAC0);
-}
-
-static ssize_t set_rdac0(struct device *dev,
-                        struct device_attribute *attr,
-                        const char *buf, size_t count)
-{
-       return sysfs_set_reg(dev, attr, buf, count,
-                            AD525X_I2C_RDAC | AD525X_RDAC0);
-}
-
-static DEVICE_ATTR(rdac0, S_IWUSR | S_IRUGO, show_rdac0, set_rdac0);
-
-static ssize_t show_eeprom0(struct device *dev,
-                           struct device_attribute *attr, char *buf)
-{
-       return sysfs_show_reg(dev, attr, buf, AD525X_I2C_EEPROM | AD525X_RDAC0);
-}
-
-static ssize_t set_eeprom0(struct device *dev,
-                          struct device_attribute *attr,
-                          const char *buf, size_t count)
-{
-       return sysfs_set_reg(dev, attr, buf, count,
-                            AD525X_I2C_EEPROM | AD525X_RDAC0);
-}
-
-static DEVICE_ATTR(eeprom0, S_IWUSR | S_IRUGO, show_eeprom0, set_eeprom0);
-
-static ssize_t show_tolerance0(struct device *dev,
-                              struct device_attribute *attr, char *buf)
-{
-       return sysfs_show_reg(dev, attr, buf,
-                             AD525X_I2C_EEPROM | AD525X_TOL_RDAC0);
-}
-
-static DEVICE_ATTR(tolerance0, S_IRUGO, show_tolerance0, NULL);
-
-/* ------------------------------------------------------------------------- */
-
-static ssize_t show_rdac1(struct device *dev,
-                         struct device_attribute *attr, char *buf)
-{
-       return sysfs_show_reg(dev, attr, buf, AD525X_I2C_RDAC | AD525X_RDAC1);
-}
-
-static ssize_t set_rdac1(struct device *dev,
-                        struct device_attribute *attr,
-                        const char *buf, size_t count)
-{
-       return sysfs_set_reg(dev, attr, buf, count,
-                            AD525X_I2C_RDAC | AD525X_RDAC1);
-}
-
-static DEVICE_ATTR(rdac1, S_IWUSR | S_IRUGO, show_rdac1, set_rdac1);
-
-static ssize_t show_eeprom1(struct device *dev,
-                           struct device_attribute *attr, char *buf)
-{
-       return sysfs_show_reg(dev, attr, buf, AD525X_I2C_EEPROM | AD525X_RDAC1);
-}
-
-static ssize_t set_eeprom1(struct device *dev,
-                          struct device_attribute *attr,
-                          const char *buf, size_t count)
-{
-       return sysfs_set_reg(dev, attr, buf, count,
-                            AD525X_I2C_EEPROM | AD525X_RDAC1);
-}
-
-static DEVICE_ATTR(eeprom1, S_IWUSR | S_IRUGO, show_eeprom1, set_eeprom1);
-
-static ssize_t show_tolerance1(struct device *dev,
-                              struct device_attribute *attr, char *buf)
-{
-       return sysfs_show_reg(dev, attr, buf,
-                             AD525X_I2C_EEPROM | AD525X_TOL_RDAC1);
-}
-
-static DEVICE_ATTR(tolerance1, S_IRUGO, show_tolerance1, NULL);
-
-/* ------------------------------------------------------------------------- */
-
-static ssize_t show_rdac2(struct device *dev,
-                         struct device_attribute *attr, char *buf)
-{
-       return sysfs_show_reg(dev, attr, buf, AD525X_I2C_RDAC | AD525X_RDAC2);
-}
-
-static ssize_t set_rdac2(struct device *dev,
-                        struct device_attribute *attr,
-                        const char *buf, size_t count)
-{
-       return sysfs_set_reg(dev, attr, buf, count,
-                            AD525X_I2C_RDAC | AD525X_RDAC2);
-}
-
-static DEVICE_ATTR(rdac2, S_IWUSR | S_IRUGO, show_rdac2, set_rdac2);
-
-static ssize_t show_eeprom2(struct device *dev,
-                           struct device_attribute *attr, char *buf)
-{
-       return sysfs_show_reg(dev, attr, buf, AD525X_I2C_EEPROM | AD525X_RDAC2);
-}
-
-static ssize_t set_eeprom2(struct device *dev,
-                          struct device_attribute *attr,
-                          const char *buf, size_t count)
-{
-       return sysfs_set_reg(dev, attr, buf, count,
-                            AD525X_I2C_EEPROM | AD525X_RDAC2);
-}
-
-static DEVICE_ATTR(eeprom2, S_IWUSR | S_IRUGO, show_eeprom2, set_eeprom2);
-
-static ssize_t show_tolerance2(struct device *dev,
-                              struct device_attribute *attr, char *buf)
-{
-       return sysfs_show_reg(dev, attr, buf,
-                             AD525X_I2C_EEPROM | AD525X_TOL_RDAC2);
-}
-
-static DEVICE_ATTR(tolerance2, S_IRUGO, show_tolerance2, NULL);
-
-/* ------------------------------------------------------------------------- */
-
-static ssize_t show_rdac3(struct device *dev,
-                         struct device_attribute *attr, char *buf)
-{
-       return sysfs_show_reg(dev, attr, buf, AD525X_I2C_RDAC | AD525X_RDAC3);
-}
-
-static ssize_t set_rdac3(struct device *dev,
-                        struct device_attribute *attr,
-                        const char *buf, size_t count)
-{
-       return sysfs_set_reg(dev, attr, buf, count,
-                            AD525X_I2C_RDAC | AD525X_RDAC3);
-}
-
-static DEVICE_ATTR(rdac3, S_IWUSR | S_IRUGO, show_rdac3, set_rdac3);
-
-static ssize_t show_eeprom3(struct device *dev,
-                           struct device_attribute *attr, char *buf)
-{
-       return sysfs_show_reg(dev, attr, buf, AD525X_I2C_EEPROM | AD525X_RDAC3);
-}
-
-static ssize_t set_eeprom3(struct device *dev,
-                          struct device_attribute *attr,
-                          const char *buf, size_t count)
-{
-       return sysfs_set_reg(dev, attr, buf, count,
-                            AD525X_I2C_EEPROM | AD525X_RDAC3);
-}
+#define DPOT_DEVICE_SHOW(_name, _reg) static ssize_t \
+show_##_name(struct device *dev, \
+                         struct device_attribute *attr, char *buf) \
+{ \
+       return sysfs_show_reg(dev, attr, buf, _reg); \
+}
+
+#define DPOT_DEVICE_SET(_name, _reg) static ssize_t \
+set_##_name(struct device *dev, \
+                        struct device_attribute *attr, \
+                        const char *buf, size_t count) \
+{ \
+       return sysfs_set_reg(dev, attr, buf, count, _reg); \
+}
+
+#define DPOT_DEVICE_SHOW_SET(name, reg) \
+DPOT_DEVICE_SHOW(name, reg) \
+DPOT_DEVICE_SET(name, reg) \
+static DEVICE_ATTR(name, S_IWUSR | S_IRUGO, show_##name, set_##name);
+
+#define DPOT_DEVICE_SHOW_ONLY(name, reg) \
+DPOT_DEVICE_SHOW(name, reg) \
+static DEVICE_ATTR(name, S_IWUSR | S_IRUGO, show_##name, NULL);
+
+DPOT_DEVICE_SHOW_SET(rdac0, DPOT_ADDR_RDAC | DPOT_RDAC0);
+DPOT_DEVICE_SHOW_SET(eeprom0, DPOT_ADDR_EEPROM | DPOT_RDAC0);
+DPOT_DEVICE_SHOW_ONLY(tolerance0, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC0);
+DPOT_DEVICE_SHOW_SET(otp0, DPOT_ADDR_OTP | DPOT_RDAC0);
+DPOT_DEVICE_SHOW_SET(otp0en, DPOT_ADDR_OTP_EN | DPOT_RDAC0);
+
+DPOT_DEVICE_SHOW_SET(rdac1, DPOT_ADDR_RDAC | DPOT_RDAC1);
+DPOT_DEVICE_SHOW_SET(eeprom1, DPOT_ADDR_EEPROM | DPOT_RDAC1);
+DPOT_DEVICE_SHOW_ONLY(tolerance1, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC1);
+DPOT_DEVICE_SHOW_SET(otp1, DPOT_ADDR_OTP | DPOT_RDAC1);
+DPOT_DEVICE_SHOW_SET(otp1en, DPOT_ADDR_OTP_EN | DPOT_RDAC1);
+
+DPOT_DEVICE_SHOW_SET(rdac2, DPOT_ADDR_RDAC | DPOT_RDAC2);
+DPOT_DEVICE_SHOW_SET(eeprom2, DPOT_ADDR_EEPROM | DPOT_RDAC2);
+DPOT_DEVICE_SHOW_ONLY(tolerance2, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC2);
+DPOT_DEVICE_SHOW_SET(otp2, DPOT_ADDR_OTP | DPOT_RDAC2);
+DPOT_DEVICE_SHOW_SET(otp2en, DPOT_ADDR_OTP_EN | DPOT_RDAC2);
+
+DPOT_DEVICE_SHOW_SET(rdac3, DPOT_ADDR_RDAC | DPOT_RDAC3);
+DPOT_DEVICE_SHOW_SET(eeprom3, DPOT_ADDR_EEPROM | DPOT_RDAC3);
+DPOT_DEVICE_SHOW_ONLY(tolerance3, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC3);
+DPOT_DEVICE_SHOW_SET(otp3, DPOT_ADDR_OTP | DPOT_RDAC3);
+DPOT_DEVICE_SHOW_SET(otp3en, DPOT_ADDR_OTP_EN | DPOT_RDAC3);
+
+DPOT_DEVICE_SHOW_SET(rdac4, DPOT_ADDR_RDAC | DPOT_RDAC4);
+DPOT_DEVICE_SHOW_SET(eeprom4, DPOT_ADDR_EEPROM | DPOT_RDAC4);
+DPOT_DEVICE_SHOW_ONLY(tolerance4, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC4);
+DPOT_DEVICE_SHOW_SET(otp4, DPOT_ADDR_OTP | DPOT_RDAC4);
+DPOT_DEVICE_SHOW_SET(otp4en, DPOT_ADDR_OTP_EN | DPOT_RDAC4);
+
+DPOT_DEVICE_SHOW_SET(rdac5, DPOT_ADDR_RDAC | DPOT_RDAC5);
+DPOT_DEVICE_SHOW_SET(eeprom5, DPOT_ADDR_EEPROM | DPOT_RDAC5);
+DPOT_DEVICE_SHOW_ONLY(tolerance5, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC5);
+DPOT_DEVICE_SHOW_SET(otp5, DPOT_ADDR_OTP | DPOT_RDAC5);
+DPOT_DEVICE_SHOW_SET(otp5en, DPOT_ADDR_OTP_EN | DPOT_RDAC5);
+
+static const struct attribute *dpot_attrib_wipers[] = {
+       &dev_attr_rdac0.attr,
+       &dev_attr_rdac1.attr,
+       &dev_attr_rdac2.attr,
+       &dev_attr_rdac3.attr,
+       &dev_attr_rdac4.attr,
+       &dev_attr_rdac5.attr,
+       NULL
+};
 
-static DEVICE_ATTR(eeprom3, S_IWUSR | S_IRUGO, show_eeprom3, set_eeprom3);
+static const struct attribute *dpot_attrib_eeprom[] = {
+       &dev_attr_eeprom0.attr,
+       &dev_attr_eeprom1.attr,
+       &dev_attr_eeprom2.attr,
+       &dev_attr_eeprom3.attr,
+       &dev_attr_eeprom4.attr,
+       &dev_attr_eeprom5.attr,
+       NULL
+};
 
-static ssize_t show_tolerance3(struct device *dev,
-                              struct device_attribute *attr, char *buf)
-{
-       return sysfs_show_reg(dev, attr, buf,
-                             AD525X_I2C_EEPROM | AD525X_TOL_RDAC3);
-}
+static const struct attribute *dpot_attrib_otp[] = {
+       &dev_attr_otp0.attr,
+       &dev_attr_otp1.attr,
+       &dev_attr_otp2.attr,
+       &dev_attr_otp3.attr,
+       &dev_attr_otp4.attr,
+       &dev_attr_otp5.attr,
+       NULL
+};
 
-static DEVICE_ATTR(tolerance3, S_IRUGO, show_tolerance3, NULL);
-
-static struct attribute *ad525x_attributes_wipers[4][4] = {
-       {
-               &dev_attr_rdac0.attr,
-               &dev_attr_eeprom0.attr,
-               &dev_attr_tolerance0.attr,
-               NULL
-       }, {
-               &dev_attr_rdac1.attr,
-               &dev_attr_eeprom1.attr,
-               &dev_attr_tolerance1.attr,
-               NULL
-       }, {
-               &dev_attr_rdac2.attr,
-               &dev_attr_eeprom2.attr,
-               &dev_attr_tolerance2.attr,
-               NULL
-       }, {
-               &dev_attr_rdac3.attr,
-               &dev_attr_eeprom3.attr,
-               &dev_attr_tolerance3.attr,
-               NULL
-       }
+static const struct attribute *dpot_attrib_otp_en[] = {
+       &dev_attr_otp0en.attr,
+       &dev_attr_otp1en.attr,
+       &dev_attr_otp2en.attr,
+       &dev_attr_otp3en.attr,
+       &dev_attr_otp4en.attr,
+       &dev_attr_otp5en.attr,
+       NULL
 };
 
-static const struct attribute_group ad525x_group_wipers[] = {
-       {.attrs = ad525x_attributes_wipers[AD525X_RDAC0]},
-       {.attrs = ad525x_attributes_wipers[AD525X_RDAC1]},
-       {.attrs = ad525x_attributes_wipers[AD525X_RDAC2]},
-       {.attrs = ad525x_attributes_wipers[AD525X_RDAC3]},
+static const struct attribute *dpot_attrib_tolerance[] = {
+       &dev_attr_tolerance0.attr,
+       &dev_attr_tolerance1.attr,
+       &dev_attr_tolerance2.attr,
+       &dev_attr_tolerance3.attr,
+       &dev_attr_tolerance4.attr,
+       &dev_attr_tolerance5.attr,
+       NULL
 };
 
 /* ------------------------------------------------------------------------- */
 
-static ssize_t set_inc_all(struct device *dev,
-                          struct device_attribute *attr,
-                          const char *buf, size_t count)
-{
-       return sysfs_do_cmd(dev, attr, buf, count, AD525X_INC_ALL);
-}
+#define DPOT_DEVICE_DO_CMD(_name, _cmd) static ssize_t \
+set_##_name(struct device *dev, \
+                        struct device_attribute *attr, \
+                        const char *buf, size_t count) \
+{ \
+       return sysfs_do_cmd(dev, attr, buf, count, _cmd); \
+} \
+static DEVICE_ATTR(_name, S_IWUSR | S_IRUGO, NULL, set_##_name);
 
-static DEVICE_ATTR(inc_all, S_IWUSR, NULL, set_inc_all);
-
-static ssize_t set_dec_all(struct device *dev,
-                          struct device_attribute *attr,
-                          const char *buf, size_t count)
-{
-       return sysfs_do_cmd(dev, attr, buf, count, AD525X_DEC_ALL);
-}
-
-static DEVICE_ATTR(dec_all, S_IWUSR, NULL, set_dec_all);
-
-static ssize_t set_inc_all_6db(struct device *dev,
-                              struct device_attribute *attr,
-                              const char *buf, size_t count)
-{
-       return sysfs_do_cmd(dev, attr, buf, count, AD525X_INC_ALL_6DB);
-}
-
-static DEVICE_ATTR(inc_all_6db, S_IWUSR, NULL, set_inc_all_6db);
-
-static ssize_t set_dec_all_6db(struct device *dev,
-                              struct device_attribute *attr,
-                              const char *buf, size_t count)
-{
-       return sysfs_do_cmd(dev, attr, buf, count, AD525X_DEC_ALL_6DB);
-}
-
-static DEVICE_ATTR(dec_all_6db, S_IWUSR, NULL, set_dec_all_6db);
+DPOT_DEVICE_DO_CMD(inc_all, DPOT_INC_ALL);
+DPOT_DEVICE_DO_CMD(dec_all, DPOT_DEC_ALL);
+DPOT_DEVICE_DO_CMD(inc_all_6db, DPOT_INC_ALL_6DB);
+DPOT_DEVICE_DO_CMD(dec_all_6db, DPOT_DEC_ALL_6DB);
 
 static struct attribute *ad525x_attributes_commands[] = {
        &dev_attr_inc_all.attr,
@@ -409,74 +556,56 @@ static const struct attribute_group ad525x_group_commands = {
        .attrs = ad525x_attributes_commands,
 };
 
-/* ------------------------------------------------------------------------- */
-
-/* i2c device functions */
+__devinit int ad_dpot_add_files(struct device *dev,
+               unsigned features, unsigned rdac)
+{
+       int err = sysfs_create_file(&dev->kobj,
+               dpot_attrib_wipers[rdac]);
+       if (features & F_CMD_EEP)
+               err |= sysfs_create_file(&dev->kobj,
+                       dpot_attrib_eeprom[rdac]);
+       if (features & F_CMD_TOL)
+               err |= sysfs_create_file(&dev->kobj,
+                       dpot_attrib_tolerance[rdac]);
+       if (features & F_CMD_OTP) {
+               err |= sysfs_create_file(&dev->kobj,
+                       dpot_attrib_otp_en[rdac]);
+               err |= sysfs_create_file(&dev->kobj,
+                       dpot_attrib_otp[rdac]);
+       }
 
-/**
- * ad525x_read - return the value contained in the specified register
- * on the AD5258 device.
- * @client: value returned from i2c_new_device()
- * @reg: the register to read
- *
- * If the tolerance register is specified, 2 bytes are returned.
- * Otherwise, 1 byte is returned.  A negative value indicates an error
- * occurred while reading the register.
- */
-static s32 ad525x_read(struct i2c_client *client, u8 reg)
-{
-       struct dpot_data *data = i2c_get_clientdata(client);
+       if (err)
+               dev_err(dev, "failed to register sysfs hooks for RDAC%d\n",
+                       rdac);
 
-       if ((reg & AD525X_REG_TOL) || (data->max_pos > 256))
-               return i2c_smbus_read_word_data(client, (reg & 0xF8) |
-                                               ((reg & 0x7) << 1));
-       else
-               return i2c_smbus_read_byte_data(client, reg);
+       return err;
 }
 
-/**
- * ad525x_write - store the given value in the specified register on
- * the AD5258 device.
- * @client: value returned from i2c_new_device()
- * @reg: the register to write
- * @value: the byte to store in the register
- *
- * For certain instructions that do not require a data byte, "NULL"
- * should be specified for the "value" parameter.  These instructions
- * include NOP, RESTORE_FROM_EEPROM, and STORE_TO_EEPROM.
- *
- * A negative return value indicates an error occurred while reading
- * the register.
- */
-static s32 ad525x_write(struct i2c_client *client, u8 reg, u8 value)
-{
-       struct dpot_data *data = i2c_get_clientdata(client);
-
-       /* Only write the instruction byte for certain commands */
-       if (reg & AD525X_I2C_CMD)
-               return i2c_smbus_write_byte(client, reg);
-
-       if (data->max_pos > 256)
-               return i2c_smbus_write_word_data(client, (reg & 0xF8) |
-                                               ((reg & 0x7) << 1), value);
-       else
-               /* All other registers require instruction + data bytes */
-               return i2c_smbus_write_byte_data(client, reg, value);
+inline void ad_dpot_remove_files(struct device *dev,
+               unsigned features, unsigned rdac)
+{
+       sysfs_remove_file(&dev->kobj,
+               dpot_attrib_wipers[rdac]);
+       if (features & F_CMD_EEP)
+               sysfs_remove_file(&dev->kobj,
+                       dpot_attrib_eeprom[rdac]);
+       if (features & F_CMD_TOL)
+               sysfs_remove_file(&dev->kobj,
+                       dpot_attrib_tolerance[rdac]);
+       if (features & F_CMD_OTP) {
+               sysfs_remove_file(&dev->kobj,
+                       dpot_attrib_otp_en[rdac]);
+               sysfs_remove_file(&dev->kobj,
+                       dpot_attrib_otp[rdac]);
+       }
 }
 
-static int ad525x_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+__devinit int ad_dpot_probe(struct device *dev,
+               struct ad_dpot_bus_data *bdata, const struct ad_dpot_id *id)
 {
-       struct device *dev = &client->dev;
-       struct dpot_data *data;
-       int err = 0;
 
-       dev_dbg(dev, "%s\n", __func__);
-
-       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) {
-               dev_err(dev, "missing I2C functionality for this driver\n");
-               goto exit;
-       }
+       struct dpot_data *data;
+       int i, err = 0;
 
        data = kzalloc(sizeof(struct dpot_data), GFP_KERNEL);
        if (!data) {
@@ -484,183 +613,74 @@ static int ad525x_probe(struct i2c_client *client,
                goto exit;
        }
 
-       i2c_set_clientdata(client, data);
+       dev_set_drvdata(dev, data);
        mutex_init(&data->update_lock);
 
-       switch (id->driver_data) {
-       case AD5258_ID:
-               data->max_pos = AD5258_MAX_POSITION;
-               err = sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC0]);
-               break;
-       case AD5259_ID:
-               data->max_pos = AD5259_MAX_POSITION;
-               err = sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC0]);
-               break;
-       case AD5251_ID:
-               data->max_pos = AD5251_MAX_POSITION;
-               err = sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC1]);
-               err |= sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC3]);
-               err |= sysfs_create_group(&dev->kobj, &ad525x_group_commands);
-               break;
-       case AD5252_ID:
-               data->max_pos = AD5252_MAX_POSITION;
-               err = sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC1]);
-               err |= sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC3]);
-               err |= sysfs_create_group(&dev->kobj, &ad525x_group_commands);
-               break;
-       case AD5253_ID:
-               data->max_pos = AD5253_MAX_POSITION;
-               err = sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC0]);
-               err |= sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC1]);
-               err |= sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC2]);
-               err |= sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC3]);
-               err |= sysfs_create_group(&dev->kobj, &ad525x_group_commands);
-               break;
-       case AD5254_ID:
-               data->max_pos = AD5254_MAX_POSITION;
-               err = sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC0]);
-               err |= sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC1]);
-               err |= sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC2]);
-               err |= sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC3]);
-               err |= sysfs_create_group(&dev->kobj, &ad525x_group_commands);
-               break;
-       case AD5255_ID:
-               data->max_pos = AD5255_MAX_POSITION;
-               err = sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC0]);
-               err |= sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC1]);
-               err |= sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC2]);
-               err |= sysfs_create_group(&dev->kobj, &ad525x_group_commands);
-               break;
-       default:
-               err = -ENODEV;
-               goto exit_free;
-       }
+       data->bdata = *bdata;
+       data->devid = id->devid;
+
+       data->max_pos = 1 << DPOT_MAX_POS(data->devid);
+       data->rdac_mask = data->max_pos - 1;
+       data->feat = DPOT_FEAT(data->devid);
+       data->uid = DPOT_UID(data->devid);
+       data->wipers = DPOT_WIPERS(data->devid);
+
+       for (i = DPOT_RDAC0; i < MAX_RDACS; i++)
+               if (data->wipers & (1 << i)) {
+                       err = ad_dpot_add_files(dev, data->feat, i);
+                       if (err)
+                               goto exit_remove_files;
+                       /* power-up midscale */
+                       if (data->feat & F_RDACS_WONLY)
+                               data->rdac_cache[i] = data->max_pos / 2;
+               }
+
+       if (data->feat & F_CMD_INC)
+               err = sysfs_create_group(&dev->kobj, &ad525x_group_commands);
 
        if (err) {
                dev_err(dev, "failed to register sysfs hooks\n");
                goto exit_free;
        }
 
-       data->devid = id->driver_data;
-       data->rdac_mask = data->max_pos - 1;
-
        dev_info(dev, "%s %d-Position Digital Potentiometer registered\n",
                 id->name, data->max_pos);
 
        return 0;
 
+exit_remove_files:
+       for (i = DPOT_RDAC0; i < MAX_RDACS; i++)
+               if (data->wipers & (1 << i))
+                       ad_dpot_remove_files(dev, data->feat, i);
+
 exit_free:
        kfree(data);
-       i2c_set_clientdata(client, NULL);
+       dev_set_drvdata(dev, NULL);
 exit:
-       dev_err(dev, "failed to create client\n");
+       dev_err(dev, "failed to create client for %s ID 0x%lX\n",
+                       id->name, id->devid);
        return err;
 }
+EXPORT_SYMBOL(ad_dpot_probe);
 
-static int __devexit ad525x_remove(struct i2c_client *client)
+__devexit int ad_dpot_remove(struct device *dev)
 {
-       struct dpot_data *data = i2c_get_clientdata(client);
-       struct device *dev = &client->dev;
-
-       switch (data->devid) {
-       case AD5258_ID:
-       case AD5259_ID:
-               sysfs_remove_group(&dev->kobj,
-                                  &ad525x_group_wipers[AD525X_RDAC0]);
-               break;
-       case AD5251_ID:
-       case AD5252_ID:
-               sysfs_remove_group(&dev->kobj,
-                                  &ad525x_group_wipers[AD525X_RDAC1]);
-               sysfs_remove_group(&dev->kobj,
-                                  &ad525x_group_wipers[AD525X_RDAC3]);
-               sysfs_remove_group(&dev->kobj, &ad525x_group_commands);
-               break;
-       case AD5253_ID:
-       case AD5254_ID:
-               sysfs_remove_group(&dev->kobj,
-                                  &ad525x_group_wipers[AD525X_RDAC0]);
-               sysfs_remove_group(&dev->kobj,
-                                  &ad525x_group_wipers[AD525X_RDAC1]);
-               sysfs_remove_group(&dev->kobj,
-                                  &ad525x_group_wipers[AD525X_RDAC2]);
-               sysfs_remove_group(&dev->kobj,
-                                  &ad525x_group_wipers[AD525X_RDAC3]);
-               sysfs_remove_group(&dev->kobj, &ad525x_group_commands);
-               break;
-       case AD5255_ID:
-               sysfs_remove_group(&dev->kobj,
-                                  &ad525x_group_wipers[AD525X_RDAC0]);
-               sysfs_remove_group(&dev->kobj,
-                                  &ad525x_group_wipers[AD525X_RDAC1]);
-               sysfs_remove_group(&dev->kobj,
-                                  &ad525x_group_wipers[AD525X_RDAC2]);
-               sysfs_remove_group(&dev->kobj, &ad525x_group_commands);
-               break;
-       }
+       struct dpot_data *data = dev_get_drvdata(dev);
+       int i;
+
+       for (i = DPOT_RDAC0; i < MAX_RDACS; i++)
+               if (data->wipers & (1 << i))
+                       ad_dpot_remove_files(dev, data->feat, i);
 
-       i2c_set_clientdata(client, NULL);
        kfree(data);
 
        return 0;
 }
+EXPORT_SYMBOL(ad_dpot_remove);
 
-static const struct i2c_device_id ad525x_idtable[] = {
-       {"ad5258", AD5258_ID},
-       {"ad5259", AD5259_ID},
-       {"ad5251", AD5251_ID},
-       {"ad5252", AD5252_ID},
-       {"ad5253", AD5253_ID},
-       {"ad5254", AD5254_ID},
-       {"ad5255", AD5255_ID},
-       {}
-};
-
-MODULE_DEVICE_TABLE(i2c, ad525x_idtable);
-
-static struct i2c_driver ad525x_driver = {
-       .driver = {
-                  .owner = THIS_MODULE,
-                  .name = DRIVER_NAME,
-                  },
-       .id_table = ad525x_idtable,
-       .probe = ad525x_probe,
-       .remove = __devexit_p(ad525x_remove),
-};
-
-static int __init ad525x_init(void)
-{
-       return i2c_add_driver(&ad525x_driver);
-}
-
-module_init(ad525x_init);
-
-static void __exit ad525x_exit(void)
-{
-       i2c_del_driver(&ad525x_driver);
-}
-
-module_exit(ad525x_exit);
 
 MODULE_AUTHOR("Chris Verges <chrisv@cyberswitching.com>, "
-             "Michael Hennerich <hennerich@blackfin.uclinux.org>");
-MODULE_DESCRIPTION("AD5258/9 digital potentiometer driver");
+             "Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Digital potentiometer driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/misc/ad525x_dpot.h b/drivers/misc/ad525x_dpot.h
new file mode 100644 (file)
index 0000000..78b89fd
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * Driver for the Analog Devices digital potentiometers
+ *
+ * Copyright (C) 2010 Michael Hennerich, Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _AD_DPOT_H_
+#define _AD_DPOT_H_
+
+#include <linux/types.h>
+
+#define DPOT_CONF(features, wipers, max_pos, uid) \
+               (((features) << 18) | (((wipers) & 0xFF) << 10) | \
+               ((max_pos & 0xF) << 6) | (uid & 0x3F))
+
+#define DPOT_UID(conf)         (conf & 0x3F)
+#define DPOT_MAX_POS(conf)     ((conf >> 6) & 0xF)
+#define DPOT_WIPERS(conf)      ((conf >> 10) & 0xFF)
+#define DPOT_FEAT(conf)                (conf >> 18)
+
+#define BRDAC0                 (1 << 0)
+#define BRDAC1                 (1 << 1)
+#define BRDAC2                 (1 << 2)
+#define BRDAC3                 (1 << 3)
+#define BRDAC4                 (1 << 4)
+#define BRDAC5                 (1 << 5)
+#define MAX_RDACS              6
+
+#define F_CMD_INC              (1 << 0)        /* Features INC/DEC ALL, 6dB */
+#define F_CMD_EEP              (1 << 1)        /* Features EEPROM */
+#define F_CMD_OTP              (1 << 2)        /* Features OTP */
+#define F_CMD_TOL              (1 << 3)        /* RDACS feature Tolerance REG */
+#define F_RDACS_RW             (1 << 4)        /* RDACS are Read/Write  */
+#define F_RDACS_WONLY          (1 << 5)        /* RDACS are Write only */
+#define F_AD_APPDATA           (1 << 6)        /* RDAC Address append to data */
+#define F_SPI_8BIT             (1 << 7)        /* All SPI XFERS are 8-bit */
+#define F_SPI_16BIT            (1 << 8)        /* All SPI XFERS are 16-bit */
+#define F_SPI_24BIT            (1 << 9)        /* All SPI XFERS are 24-bit */
+
+#define F_RDACS_RW_TOL (F_RDACS_RW | F_CMD_EEP | F_CMD_TOL)
+#define F_RDACS_RW_EEP (F_RDACS_RW | F_CMD_EEP)
+#define F_SPI          (F_SPI_8BIT | F_SPI_16BIT | F_SPI_24BIT)
+
+enum dpot_devid {
+       AD5258_ID = DPOT_CONF(F_RDACS_RW_TOL, BRDAC0, 6, 0), /* I2C */
+       AD5259_ID = DPOT_CONF(F_RDACS_RW_TOL, BRDAC0, 8, 1),
+       AD5251_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC,
+                       BRDAC0 | BRDAC3, 6, 2),
+       AD5252_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC,
+                       BRDAC0 | BRDAC3, 8, 3),
+       AD5253_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC,
+                       BRDAC0 | BRDAC1 | BRDAC2 | BRDAC3, 6, 4),
+       AD5254_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC,
+                       BRDAC0 | BRDAC1 | BRDAC2 | BRDAC3, 8, 5),
+       AD5255_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC,
+                       BRDAC0 | BRDAC1 | BRDAC2, 9, 6),
+       AD5160_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
+                       BRDAC0, 8, 7), /* SPI */
+       AD5161_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
+                       BRDAC0, 8, 8),
+       AD5162_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_16BIT,
+                       BRDAC0 | BRDAC1, 8, 9),
+       AD5165_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
+                       BRDAC0, 8, 10),
+       AD5200_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
+                       BRDAC0, 8, 11),
+       AD5201_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
+                       BRDAC0, 5, 12),
+       AD5203_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
+                       BRDAC0 | BRDAC1 | BRDAC2 | BRDAC3, 6, 13),
+       AD5204_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_16BIT,
+                       BRDAC0 | BRDAC1 | BRDAC2 | BRDAC3, 8, 14),
+       AD5206_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_16BIT,
+                       BRDAC0 | BRDAC1 | BRDAC2 | BRDAC3 | BRDAC4 | BRDAC5,
+                       8, 15),
+       AD5207_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_16BIT,
+                       BRDAC0 | BRDAC1, 8, 16),
+       AD5231_ID = DPOT_CONF(F_RDACS_RW_EEP | F_CMD_INC | F_SPI_24BIT,
+                       BRDAC0, 10, 17),
+       AD5232_ID = DPOT_CONF(F_RDACS_RW_EEP | F_CMD_INC | F_SPI_16BIT,
+                       BRDAC0 | BRDAC1, 8, 18),
+       AD5233_ID = DPOT_CONF(F_RDACS_RW_EEP | F_CMD_INC | F_SPI_16BIT,
+                       BRDAC0 | BRDAC1 | BRDAC2 | BRDAC3, 6, 19),
+       AD5235_ID = DPOT_CONF(F_RDACS_RW_EEP | F_CMD_INC | F_SPI_24BIT,
+                       BRDAC0 | BRDAC1, 10, 20),
+       AD5260_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
+                       BRDAC0, 8, 21),
+       AD5262_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_16BIT,
+                       BRDAC0 | BRDAC1, 8, 22),
+       AD5263_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_16BIT,
+                       BRDAC0 | BRDAC1 | BRDAC2 | BRDAC3, 8, 23),
+       AD5290_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
+                       BRDAC0, 8, 24),
+       AD5291_ID = DPOT_CONF(F_RDACS_RW | F_SPI_16BIT, BRDAC0, 8, 25),
+       AD5292_ID = DPOT_CONF(F_RDACS_RW | F_SPI_16BIT, BRDAC0, 10, 26),
+       AD5293_ID = DPOT_CONF(F_RDACS_RW | F_SPI_16BIT, BRDAC0, 10, 27),
+       AD7376_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
+                       BRDAC0, 7, 28),
+       AD8400_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
+                       BRDAC0, 8, 29),
+       AD8402_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_16BIT,
+                       BRDAC0 | BRDAC1, 8, 30),
+       AD8403_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_16BIT,
+                       BRDAC0 | BRDAC1 | BRDAC2, 8, 31),
+       ADN2850_ID = DPOT_CONF(F_RDACS_RW_EEP | F_CMD_INC | F_SPI_24BIT,
+                       BRDAC0 | BRDAC1, 10, 32),
+       AD5241_ID = DPOT_CONF(F_RDACS_RW, BRDAC0, 8, 33),
+       AD5242_ID = DPOT_CONF(F_RDACS_RW, BRDAC0 | BRDAC1, 8, 34),
+       AD5243_ID = DPOT_CONF(F_RDACS_RW, BRDAC0 | BRDAC1, 8, 35),
+       AD5245_ID = DPOT_CONF(F_RDACS_RW, BRDAC0, 8, 36),
+       AD5246_ID = DPOT_CONF(F_RDACS_RW, BRDAC0, 7, 37),
+       AD5247_ID = DPOT_CONF(F_RDACS_RW, BRDAC0, 7, 38),
+       AD5248_ID = DPOT_CONF(F_RDACS_RW, BRDAC0 | BRDAC1, 8, 39),
+       AD5280_ID = DPOT_CONF(F_RDACS_RW, BRDAC0, 8, 40),
+       AD5282_ID = DPOT_CONF(F_RDACS_RW, BRDAC0 | BRDAC1, 8, 41),
+       ADN2860_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC,
+                       BRDAC0 | BRDAC1 | BRDAC2, 9, 42),
+       AD5273_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0, 6, 43),
+       AD5171_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0, 6, 44),
+       AD5170_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0, 8, 45),
+       AD5172_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0 | BRDAC1, 8, 46),
+       AD5173_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0 | BRDAC1, 8, 47),
+};
+
+#define DPOT_RDAC0             0
+#define DPOT_RDAC1             1
+#define DPOT_RDAC2             2
+#define DPOT_RDAC3             3
+#define DPOT_RDAC4             4
+#define DPOT_RDAC5             5
+
+#define DPOT_RDAC_MASK         0x1F
+
+#define DPOT_REG_TOL           0x18
+#define DPOT_TOL_RDAC0         (DPOT_REG_TOL | DPOT_RDAC0)
+#define DPOT_TOL_RDAC1         (DPOT_REG_TOL | DPOT_RDAC1)
+#define DPOT_TOL_RDAC2         (DPOT_REG_TOL | DPOT_RDAC2)
+#define DPOT_TOL_RDAC3         (DPOT_REG_TOL | DPOT_RDAC3)
+#define DPOT_TOL_RDAC4         (DPOT_REG_TOL | DPOT_RDAC4)
+#define DPOT_TOL_RDAC5         (DPOT_REG_TOL | DPOT_RDAC5)
+
+/* RDAC-to-EEPROM Interface Commands */
+#define DPOT_ADDR_RDAC         (0x0 << 5)
+#define DPOT_ADDR_EEPROM       (0x1 << 5)
+#define DPOT_ADDR_OTP          (0x1 << 6)
+#define DPOT_ADDR_CMD          (0x1 << 7)
+#define DPOT_ADDR_OTP_EN       (0x1 << 9)
+
+#define DPOT_DEC_ALL_6DB       (DPOT_ADDR_CMD | (0x4 << 3))
+#define DPOT_INC_ALL_6DB       (DPOT_ADDR_CMD | (0x9 << 3))
+#define DPOT_DEC_ALL           (DPOT_ADDR_CMD | (0x6 << 3))
+#define DPOT_INC_ALL           (DPOT_ADDR_CMD | (0xB << 3))
+
+#define DPOT_SPI_RDAC          0xB0
+#define DPOT_SPI_EEPROM                0x30
+#define DPOT_SPI_READ_RDAC     0xA0
+#define DPOT_SPI_READ_EEPROM   0x90
+#define DPOT_SPI_DEC_ALL_6DB   0x50
+#define DPOT_SPI_INC_ALL_6DB   0xD0
+#define DPOT_SPI_DEC_ALL       0x70
+#define DPOT_SPI_INC_ALL       0xF0
+
+/* AD5291/2/3 use special commands */
+#define DPOT_AD5291_RDAC       0x01
+#define DPOT_AD5291_READ_RDAC  0x02
+
+/* AD524x use special commands */
+#define DPOT_AD5291_RDAC_AB    0x80
+
+#define DPOT_AD5273_FUSE       0x80
+#define DPOT_AD5270_2_3_FUSE   0x20
+#define DPOT_AD5270_2_3_OW     0x08
+#define DPOT_AD5272_3_A0       0x08
+#define DPOT_AD5270_2FUSE      0x80
+
+struct dpot_data;
+
+struct ad_dpot_bus_ops {
+       int (*read_d8) (void *client);
+       int (*read_r8d8) (void *client, u8 reg);
+       int (*read_r8d16) (void *client, u8 reg);
+       int (*write_d8) (void *client, u8 val);
+       int (*write_r8d8) (void *client, u8 reg, u8 val);
+       int (*write_r8d16) (void *client, u8 reg, u16 val);
+};
+
+struct ad_dpot_bus_data {
+       void *client;
+       const struct ad_dpot_bus_ops *bops;
+};
+
+struct ad_dpot_id {
+       char *name;
+       unsigned long devid;
+};
+
+int ad_dpot_probe(struct device *dev, struct ad_dpot_bus_data *bdata, const struct ad_dpot_id *id);
+int ad_dpot_remove(struct device *dev);
+
+#endif
index 31a991161f0a0f984ab73354d1281ccf8aa4943b..5bfb2a2041b8a8f4854fbaf7351e8a1739ea5db0 100644 (file)
@@ -75,6 +75,9 @@ enum ctype {
        UNALIGNED_LOAD_STORE_WRITE,
        OVERWRITE_ALLOCATION,
        WRITE_AFTER_FREE,
+       SOFTLOCKUP,
+       HARDLOCKUP,
+       HUNG_TASK,
 };
 
 static char* cp_name[] = {
@@ -99,6 +102,9 @@ static char* cp_type[] = {
        "UNALIGNED_LOAD_STORE_WRITE",
        "OVERWRITE_ALLOCATION",
        "WRITE_AFTER_FREE",
+       "SOFTLOCKUP",
+       "HARDLOCKUP",
+       "HUNG_TASK",
 };
 
 static struct jprobe lkdtm;
@@ -320,6 +326,20 @@ static void lkdtm_do_action(enum ctype which)
                memset(data, 0x78, len);
                break;
        }
+       case SOFTLOCKUP:
+               preempt_disable();
+               for (;;)
+                       cpu_relax();
+               break;
+       case HARDLOCKUP:
+               local_irq_disable();
+               for (;;)
+                       cpu_relax();
+               break;
+       case HUNG_TASK:
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule();
+               break;
        case NONE:
        default:
                break;
index 3168ebd616b2aefe0646514171e7c3d553a70fcc..569e94da844cd3f1ffe022f8e4885752096bdec4 100644 (file)
@@ -1252,9 +1252,8 @@ EXPORT_SYMBOL(mmc_card_can_sleep);
 /**
  *     mmc_suspend_host - suspend a host
  *     @host: mmc host
- *     @state: suspend mode (PM_SUSPEND_xxx)
  */
-int mmc_suspend_host(struct mmc_host *host, pm_message_t state)
+int mmc_suspend_host(struct mmc_host *host)
 {
        int err = 0;
 
index 0d96080d44b098431af53b15764c0f8e6fdd1e81..63772e7e7608c5f2d1c8229b5978e1c55fd0b796 100644 (file)
@@ -79,8 +79,6 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
         * we cannot use the retries field in mmc_command.
         */
        for (i = 0;i <= retries;i++) {
-               memset(&mrq, 0, sizeof(struct mmc_request));
-
                err = mmc_app_cmd(host, card);
                if (err) {
                        /* no point in retrying; no APP commands allowed */
index 2dd4cfe7ca17d8da17ef24fe6f89932e2771e755..b9dee28ee7d03a7ca1588037beedcb585880ccb9 100644 (file)
@@ -295,6 +295,12 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
 
        card->type = MMC_TYPE_SDIO;
 
+       /*
+        * Call the optional HC's init_card function to handle quirks.
+        */
+       if (host->ops->init_card)
+               host->ops->init_card(host, card);
+
        /*
         * For native busses:  set card RCA and quit open drain mode.
         */
index ff27c8c713554024dd0b2530cda395dd2d296b94..0f687cdeb064ac917d778a35f9bc5c756f1da89e 100644 (file)
@@ -405,6 +405,36 @@ void sdio_writeb(struct sdio_func *func, u8 b, unsigned int addr, int *err_ret)
 }
 EXPORT_SYMBOL_GPL(sdio_writeb);
 
+/**
+ *     sdio_writeb_readb - write and read a byte from SDIO function
+ *     @func: SDIO function to access
+ *     @write_byte: byte to write
+ *     @addr: address to write to
+ *     @err_ret: optional status value from transfer
+ *
+ *     Performs a RAW (Read after Write) operation as defined by SDIO spec -
+ *     single byte is written to address space of a given SDIO function and
+ *     response is read back from the same address, both using single request.
+ *     If there is a problem with the operation, 0xff is returned and
+ *     @err_ret will contain the error code.
+ */
+u8 sdio_writeb_readb(struct sdio_func *func, u8 write_byte,
+       unsigned int addr, int *err_ret)
+{
+       int ret;
+       u8 val;
+
+       ret = mmc_io_rw_direct(func->card, 1, func->num, addr,
+                       write_byte, &val);
+       if (err_ret)
+               *err_ret = ret;
+       if (ret)
+               val = 0xff;
+
+       return val;
+}
+EXPORT_SYMBOL_GPL(sdio_writeb_readb);
+
 /**
  *     sdio_memcpy_fromio - read a chunk of memory from a SDIO function
  *     @func: SDIO function to access
index 2e13b94769fdce2747590ce8f2da89d6a58eff79..e171e77f6129d8b80829099fabe0bdd1a8e25f71 100644 (file)
@@ -136,6 +136,18 @@ config MMC_SDHCI_S3C
 
          If unsure, say N.
 
+config MMC_SDHCI_SPEAR
+       tristate "SDHCI support on ST SPEAr platform"
+       depends on MMC_SDHCI && PLAT_SPEAR
+       help
+         This selects the Secure Digital Host Controller Interface (SDHCI)
+         often referrered to as the HSMMC block in some of the ST SPEAR range
+         of SoC
+
+         If you have a controller with this interface, say Y or M here.
+
+         If unsure, say N.
+
 config MMC_SDHCI_S3C_DMA
        bool "DMA support on S3C SDHCI"
        depends on MMC_SDHCI_S3C && EXPERIMENTAL
@@ -412,3 +424,11 @@ config SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND
        depends on SDH_BFIN
        help
          If you say yes here SD-Cards may work on the EZkit.
+
+config MMC_SH_MMCIF
+       tristate "SuperH Internal MMCIF support"
+       depends on MMC_BLOCK && (SUPERH || ARCH_SHMOBILE)
+       help
+         This selects the MMC Host Interface controler (MMCIF).
+
+         This driver supports MMCIF in sh7724/sh7757/sh7372.
index f4803977dfceb2b8f71d4514e0af8c115c923aee..e30c2ee488942c711713647e731d888af5619d64 100644 (file)
@@ -14,6 +14,7 @@ obj-$(CONFIG_MMC_SDHCI)               += sdhci.o
 obj-$(CONFIG_MMC_SDHCI_PCI)    += sdhci-pci.o
 obj-$(CONFIG_MMC_SDHCI_PLTFM)  += sdhci-pltfm.o
 obj-$(CONFIG_MMC_SDHCI_S3C)    += sdhci-s3c.o
+obj-$(CONFIG_MMC_SDHCI_SPEAR)  += sdhci-spear.o
 obj-$(CONFIG_MMC_WBSD)         += wbsd.o
 obj-$(CONFIG_MMC_AU1X)         += au1xmmc.o
 obj-$(CONFIG_MMC_OMAP)         += omap.o
@@ -34,6 +35,7 @@ obj-$(CONFIG_MMC_TMIO)                += tmio_mmc.o
 obj-$(CONFIG_MMC_CB710)        += cb710-mmc.o
 obj-$(CONFIG_MMC_VIA_SDMMC)    += via-sdmmc.o
 obj-$(CONFIG_SDH_BFIN)         += bfin_sdh.o
+obj-$(CONFIG_MMC_SH_MMCIF)     += sh_mmcif.o
 
 obj-$(CONFIG_MMC_SDHCI_OF)     += sdhci-of.o
 sdhci-of-y                             := sdhci-of-core.o
index 336d9f553f3e85ae6240b5a22c83ae0eb33fe3b0..5f3a599ead07bbdfae11f7abc0198285e743db81 100644 (file)
@@ -1157,7 +1157,7 @@ static int at91_mci_suspend(struct platform_device *pdev, pm_message_t state)
                enable_irq_wake(host->board->det_pin);
 
        if (mmc)
-               ret = mmc_suspend_host(mmc, state);
+               ret = mmc_suspend_host(mmc);
 
        return ret;
 }
index df0e8a88d85ffec1f725fe25b48239f1a6c0fd57..95ef864ad8f9f13e73bbb04c64f966e02a772672 100644 (file)
@@ -173,6 +173,7 @@ struct atmel_mci {
  * @mmc: The mmc_host representing this slot.
  * @host: The MMC controller this slot is using.
  * @sdc_reg: Value of SDCR to be written before using this slot.
+ * @sdio_irq: SDIO irq mask for this slot.
  * @mrq: mmc_request currently being processed or waiting to be
  *     processed, or NULL when the slot is idle.
  * @queue_node: List node for placing this node in the @queue list of
@@ -191,6 +192,7 @@ struct atmel_mci_slot {
        struct atmel_mci        *host;
 
        u32                     sdc_reg;
+       u32                     sdio_irq;
 
        struct mmc_request      *mrq;
        struct list_head        queue_node;
@@ -792,7 +794,7 @@ static void atmci_start_request(struct atmel_mci *host,
        mci_writel(host, SDCR, slot->sdc_reg);
 
        iflags = mci_readl(host, IMR);
-       if (iflags)
+       if (iflags & ~(MCI_SDIOIRQA | MCI_SDIOIRQB))
                dev_warn(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n",
                                iflags);
 
@@ -952,10 +954,21 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                if (mci_has_rwproof())
                        host->mode_reg |= (MCI_MR_WRPROOF | MCI_MR_RDPROOF);
 
-               if (list_empty(&host->queue))
+               if (atmci_is_mci2()) {
+                       /* setup High Speed mode in relation with card capacity */
+                       if (ios->timing == MMC_TIMING_SD_HS)
+                               host->cfg_reg |= MCI_CFG_HSMODE;
+                       else
+                               host->cfg_reg &= ~MCI_CFG_HSMODE;
+               }
+
+               if (list_empty(&host->queue)) {
                        mci_writel(host, MR, host->mode_reg);
-               else
+                       if (atmci_is_mci2())
+                               mci_writel(host, CFG, host->cfg_reg);
+               } else {
                        host->need_clock_update = true;
+               }
 
                spin_unlock_bh(&host->lock);
        } else {
@@ -1030,11 +1043,23 @@ static int atmci_get_cd(struct mmc_host *mmc)
        return present;
 }
 
+static void atmci_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+       struct atmel_mci_slot   *slot = mmc_priv(mmc);
+       struct atmel_mci        *host = slot->host;
+
+       if (enable)
+               mci_writel(host, IER, slot->sdio_irq);
+       else
+               mci_writel(host, IDR, slot->sdio_irq);
+}
+
 static const struct mmc_host_ops atmci_ops = {
        .request        = atmci_request,
        .set_ios        = atmci_set_ios,
        .get_ro         = atmci_get_ro,
        .get_cd         = atmci_get_cd,
+       .enable_sdio_irq = atmci_enable_sdio_irq,
 };
 
 /* Called with host->lock held */
@@ -1052,8 +1077,11 @@ static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq)
         * necessary if set_ios() is called when a different slot is
         * busy transfering data.
         */
-       if (host->need_clock_update)
+       if (host->need_clock_update) {
                mci_writel(host, MR, host->mode_reg);
+               if (atmci_is_mci2())
+                       mci_writel(host, CFG, host->cfg_reg);
+       }
 
        host->cur_slot->mrq = NULL;
        host->mrq = NULL;
@@ -1483,6 +1511,19 @@ static void atmci_cmd_interrupt(struct atmel_mci *host, u32 status)
        tasklet_schedule(&host->tasklet);
 }
 
+static void atmci_sdio_interrupt(struct atmel_mci *host, u32 status)
+{
+       int     i;
+
+       for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) {
+               struct atmel_mci_slot *slot = host->slot[i];
+               if (slot && (status & slot->sdio_irq)) {
+                       mmc_signal_sdio_irq(slot->mmc);
+               }
+       }
+}
+
+
 static irqreturn_t atmci_interrupt(int irq, void *dev_id)
 {
        struct atmel_mci        *host = dev_id;
@@ -1522,6 +1563,10 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
 
                if (pending & MCI_CMDRDY)
                        atmci_cmd_interrupt(host, status);
+
+               if (pending & (MCI_SDIOIRQA | MCI_SDIOIRQB))
+                       atmci_sdio_interrupt(host, status);
+
        } while (pass_count++ < 5);
 
        return pass_count ? IRQ_HANDLED : IRQ_NONE;
@@ -1544,7 +1589,7 @@ static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id)
 
 static int __init atmci_init_slot(struct atmel_mci *host,
                struct mci_slot_pdata *slot_data, unsigned int id,
-               u32 sdc_reg)
+               u32 sdc_reg, u32 sdio_irq)
 {
        struct mmc_host                 *mmc;
        struct atmel_mci_slot           *slot;
@@ -1560,11 +1605,16 @@ static int __init atmci_init_slot(struct atmel_mci *host,
        slot->wp_pin = slot_data->wp_pin;
        slot->detect_is_active_high = slot_data->detect_is_active_high;
        slot->sdc_reg = sdc_reg;
+       slot->sdio_irq = sdio_irq;
 
        mmc->ops = &atmci_ops;
        mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512);
        mmc->f_max = host->bus_hz / 2;
        mmc->ocr_avail  = MMC_VDD_32_33 | MMC_VDD_33_34;
+       if (sdio_irq)
+               mmc->caps |= MMC_CAP_SDIO_IRQ;
+       if (atmci_is_mci2())
+               mmc->caps |= MMC_CAP_SD_HIGHSPEED;
        if (slot_data->bus_width >= 4)
                mmc->caps |= MMC_CAP_4_BIT_DATA;
 
@@ -1753,13 +1803,13 @@ static int __init atmci_probe(struct platform_device *pdev)
        ret = -ENODEV;
        if (pdata->slot[0].bus_width) {
                ret = atmci_init_slot(host, &pdata->slot[0],
-                               0, MCI_SDCSEL_SLOT_A);
+                               0, MCI_SDCSEL_SLOT_A, MCI_SDIOIRQA);
                if (!ret)
                        nr_slots++;
        }
        if (pdata->slot[1].bus_width) {
                ret = atmci_init_slot(host, &pdata->slot[1],
-                               1, MCI_SDCSEL_SLOT_B);
+                               1, MCI_SDCSEL_SLOT_B, MCI_SDIOIRQB);
                if (!ret)
                        nr_slots++;
        }
index f5834449400e0b06d6cd4d60f85c9ce4d303705a..c8da5d30a861b5b7a294945f59aae0d80968c128 100644 (file)
@@ -1142,7 +1142,7 @@ static int au1xmmc_suspend(struct platform_device *pdev, pm_message_t state)
        struct au1xmmc_host *host = platform_get_drvdata(pdev);
        int ret;
 
-       ret = mmc_suspend_host(host->mmc, state);
+       ret = mmc_suspend_host(host->mmc);
        if (ret)
                return ret;
 
index 6919e844072c9dbf683359764ea6fe55a763906b..4b0e677d7295091dbd4772054a8c06e20a4d3184 100644 (file)
@@ -576,7 +576,7 @@ static int sdh_suspend(struct platform_device *dev, pm_message_t state)
        int ret = 0;
 
        if (mmc)
-               ret = mmc_suspend_host(mmc, state);
+               ret = mmc_suspend_host(mmc);
 
        bfin_write_SDH_PWR_CTL(bfin_read_SDH_PWR_CTL() & ~PWR_ON);
        peripheral_free_list(drv_data->pin_req);
index 92a324f7417c3eb0a710a19fcd47b1f792b067f7..ca3bdc831900be8b0f39457a495081534907c3b5 100644 (file)
@@ -675,7 +675,7 @@ static int cb710_mmc_suspend(struct platform_device *pdev, pm_message_t state)
        struct mmc_host *mmc = cb710_slot_to_mmc(slot);
        int err;
 
-       err = mmc_suspend_host(mmc, state);
+       err = mmc_suspend_host(mmc);
        if (err)
                return err;
 
index 3bd0ba294e9de667a56c2abf3915f77d43ad8b1b..33d9f1b00862f805aca98acf72c497d91239be02 100644 (file)
 
 /*
  * One scatterlist dma "segment" is at most MAX_CCNT rw_threshold units,
- * and we handle up to NR_SG segments.  MMC_BLOCK_BOUNCE kicks in only
+ * and we handle up to MAX_NR_SG segments.  MMC_BLOCK_BOUNCE kicks in only
  * for drivers with max_hw_segs == 1, making the segments bigger (64KB)
- * than the page or two that's otherwise typical.  NR_SG == 16 gives at
- * least the same throughput boost, using EDMA transfer linkage instead
- * of spending CPU time copying pages.
+ * than the page or two that's otherwise typical. nr_sg (passed from
+ * platform data) == 16 gives at least the same throughput boost, using
+ * EDMA transfer linkage instead of spending CPU time copying pages.
  */
 #define MAX_CCNT       ((1 << 16) - 1)
 
-#define NR_SG          16
+#define MAX_NR_SG      16
 
 static unsigned rw_threshold = 32;
 module_param(rw_threshold, uint, S_IRUGO);
@@ -171,6 +171,7 @@ struct mmc_davinci_host {
 #define DAVINCI_MMC_DATADIR_READ       1
 #define DAVINCI_MMC_DATADIR_WRITE      2
        unsigned char data_dir;
+       unsigned char suspended;
 
        /* buffer is used during PIO of one scatterlist segment, and
         * is updated along with buffer_bytes_left.  bytes_left applies
@@ -192,7 +193,7 @@ struct mmc_davinci_host {
        struct edmacc_param     tx_template;
        struct edmacc_param     rx_template;
        unsigned                n_link;
-       u32                     links[NR_SG - 1];
+       u32                     links[MAX_NR_SG - 1];
 
        /* For PIO we walk scatterlists one segment at a time. */
        unsigned int            sg_len;
@@ -202,6 +203,8 @@ struct mmc_davinci_host {
        u8 version;
        /* for ns in one cycle calculation */
        unsigned ns_in_one_cycle;
+       /* Number of sg segments */
+       u8 nr_sg;
 #ifdef CONFIG_CPU_FREQ
        struct notifier_block   freq_transition;
 #endif
@@ -568,6 +571,7 @@ davinci_release_dma_channels(struct mmc_davinci_host *host)
 
 static int __init davinci_acquire_dma_channels(struct mmc_davinci_host *host)
 {
+       u32 link_size;
        int r, i;
 
        /* Acquire master DMA write channel */
@@ -593,7 +597,8 @@ static int __init davinci_acquire_dma_channels(struct mmc_davinci_host *host)
        /* Allocate parameter RAM slots, which will later be bound to a
         * channel as needed to handle a scatterlist.
         */
-       for (i = 0; i < ARRAY_SIZE(host->links); i++) {
+       link_size = min_t(unsigned, host->nr_sg, ARRAY_SIZE(host->links));
+       for (i = 0; i < link_size; i++) {
                r = edma_alloc_slot(EDMA_CTLR(host->txdma), EDMA_SLOT_ANY);
                if (r < 0) {
                        dev_dbg(mmc_dev(host->mmc), "dma PaRAM alloc --> %d\n",
@@ -905,19 +910,26 @@ static void mmc_davinci_cmd_done(struct mmc_davinci_host *host,
        }
 }
 
-static void
-davinci_abort_data(struct mmc_davinci_host *host, struct mmc_data *data)
+static inline void mmc_davinci_reset_ctrl(struct mmc_davinci_host *host,
+                                                               int val)
 {
        u32 temp;
 
-       /* reset command and data state machines */
        temp = readl(host->base + DAVINCI_MMCCTL);
-       writel(temp | MMCCTL_CMDRST | MMCCTL_DATRST,
-               host->base + DAVINCI_MMCCTL);
+       if (val)        /* reset */
+               temp |= MMCCTL_CMDRST | MMCCTL_DATRST;
+       else            /* enable */
+               temp &= ~(MMCCTL_CMDRST | MMCCTL_DATRST);
 
-       temp &= ~(MMCCTL_CMDRST | MMCCTL_DATRST);
-       udelay(10);
        writel(temp, host->base + DAVINCI_MMCCTL);
+       udelay(10);
+}
+
+static void
+davinci_abort_data(struct mmc_davinci_host *host, struct mmc_data *data)
+{
+       mmc_davinci_reset_ctrl(host, 1);
+       mmc_davinci_reset_ctrl(host, 0);
 }
 
 static irqreturn_t mmc_davinci_irq(int irq, void *dev_id)
@@ -1121,15 +1133,8 @@ static inline void mmc_davinci_cpufreq_deregister(struct mmc_davinci_host *host)
 #endif
 static void __init init_mmcsd_host(struct mmc_davinci_host *host)
 {
-       /* DAT line portion is diabled and in reset state */
-       writel(readl(host->base + DAVINCI_MMCCTL) | MMCCTL_DATRST,
-               host->base + DAVINCI_MMCCTL);
-
-       /* CMD line portion is diabled and in reset state */
-       writel(readl(host->base + DAVINCI_MMCCTL) | MMCCTL_CMDRST,
-               host->base + DAVINCI_MMCCTL);
 
-       udelay(10);
+       mmc_davinci_reset_ctrl(host, 1);
 
        writel(0, host->base + DAVINCI_MMCCLK);
        writel(MMCCLK_CLKEN, host->base + DAVINCI_MMCCLK);
@@ -1137,12 +1142,7 @@ static void __init init_mmcsd_host(struct mmc_davinci_host *host)
        writel(0x1FFF, host->base + DAVINCI_MMCTOR);
        writel(0xFFFF, host->base + DAVINCI_MMCTOD);
 
-       writel(readl(host->base + DAVINCI_MMCCTL) & ~MMCCTL_DATRST,
-               host->base + DAVINCI_MMCCTL);
-       writel(readl(host->base + DAVINCI_MMCCTL) & ~MMCCTL_CMDRST,
-               host->base + DAVINCI_MMCCTL);
-
-       udelay(10);
+       mmc_davinci_reset_ctrl(host, 0);
 }
 
 static int __init davinci_mmcsd_probe(struct platform_device *pdev)
@@ -1202,6 +1202,12 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
 
        init_mmcsd_host(host);
 
+       if (pdata->nr_sg)
+               host->nr_sg = pdata->nr_sg - 1;
+
+       if (host->nr_sg > MAX_NR_SG || !host->nr_sg)
+               host->nr_sg = MAX_NR_SG;
+
        host->use_dma = use_dma;
        host->irq = irq;
 
@@ -1327,32 +1333,65 @@ static int __exit davinci_mmcsd_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM
-static int davinci_mmcsd_suspend(struct platform_device *pdev, pm_message_t msg)
+static int davinci_mmcsd_suspend(struct device *dev)
 {
+       struct platform_device *pdev = to_platform_device(dev);
        struct mmc_davinci_host *host = platform_get_drvdata(pdev);
+       int ret;
 
-       return mmc_suspend_host(host->mmc, msg);
+       mmc_host_enable(host->mmc);
+       ret = mmc_suspend_host(host->mmc);
+       if (!ret) {
+               writel(0, host->base + DAVINCI_MMCIM);
+               mmc_davinci_reset_ctrl(host, 1);
+               mmc_host_disable(host->mmc);
+               clk_disable(host->clk);
+               host->suspended = 1;
+       } else {
+               host->suspended = 0;
+               mmc_host_disable(host->mmc);
+       }
+
+       return ret;
 }
 
-static int davinci_mmcsd_resume(struct platform_device *pdev)
+static int davinci_mmcsd_resume(struct device *dev)
 {
+       struct platform_device *pdev = to_platform_device(dev);
        struct mmc_davinci_host *host = platform_get_drvdata(pdev);
+       int ret;
+
+       if (!host->suspended)
+               return 0;
 
-       return mmc_resume_host(host->mmc);
+       clk_enable(host->clk);
+       mmc_host_enable(host->mmc);
+
+       mmc_davinci_reset_ctrl(host, 0);
+       ret = mmc_resume_host(host->mmc);
+       if (!ret)
+               host->suspended = 0;
+
+       return ret;
 }
+
+static const struct dev_pm_ops davinci_mmcsd_pm = {
+       .suspend        = davinci_mmcsd_suspend,
+       .resume         = davinci_mmcsd_resume,
+};
+
+#define davinci_mmcsd_pm_ops (&davinci_mmcsd_pm)
 #else
-#define davinci_mmcsd_suspend  NULL
-#define davinci_mmcsd_resume   NULL
+#define davinci_mmcsd_pm_ops NULL
 #endif
 
 static struct platform_driver davinci_mmcsd_driver = {
        .driver         = {
                .name   = "davinci_mmc",
                .owner  = THIS_MODULE,
+               .pm     = davinci_mmcsd_pm_ops,
        },
        .remove         = __exit_p(davinci_mmcsd_remove),
-       .suspend        = davinci_mmcsd_suspend,
-       .resume         = davinci_mmcsd_resume,
 };
 
 static int __init davinci_mmcsd_init(void)
index bf98d7cc928aa3e605c81bbe488bf248ebdd2c86..9a68ff4353a2e83878fce5429afe9351140daf57 100644 (file)
@@ -1115,7 +1115,7 @@ static int imxmci_suspend(struct platform_device *dev, pm_message_t state)
        int ret = 0;
 
        if (mmc)
-               ret = mmc_suspend_host(mmc, state);
+               ret = mmc_suspend_host(mmc);
 
        return ret;
 }
index ff115d92088811fbe544220cd9800da07f58cd4b..4917af96bae1d0be7472e32bf13784ec5ffb4412 100644 (file)
@@ -824,7 +824,7 @@ static int mmci_suspend(struct amba_device *dev, pm_message_t state)
        if (mmc) {
                struct mmci_host *host = mmc_priv(mmc);
 
-               ret = mmc_suspend_host(mmc, state);
+               ret = mmc_suspend_host(mmc);
                if (ret == 0)
                        writel(0, host->base + MMCIMASK0);
        }
index 61f1d27fed3fe7b1b510c7cfc7d49883b8ad581a..24e09454e52238c87c6b00dfdaee00196f4ac6eb 100644 (file)
@@ -1327,7 +1327,7 @@ msmsdcc_suspend(struct platform_device *dev, pm_message_t state)
                        disable_irq(host->stat_irq);
 
                if (mmc->card && mmc->card->type != MMC_TYPE_SDIO)
-                       rc = mmc_suspend_host(mmc, state);
+                       rc = mmc_suspend_host(mmc);
                if (!rc)
                        msmsdcc_writel(host, 0, MMCIMASK0);
                if (host->clks_on)
index 34e23489811ae74ea14594f1af1cb84f7a6e6b58..366eefa77c5a4b96f2a1c8ce9f822ff053aecb1c 100644 (file)
@@ -865,7 +865,7 @@ static int mvsd_suspend(struct platform_device *dev, pm_message_t state)
        int ret = 0;
 
        if (mmc)
-               ret = mmc_suspend_host(mmc, state);
+               ret = mmc_suspend_host(mmc);
 
        return ret;
 }
index 2df90412abb5b6ef369ee5648fc4451ce4428f57..d9d4a72e0ec792d42386d21afcf327fa5b59f69c 100644 (file)
@@ -119,6 +119,7 @@ struct mxcmci_host {
        int                     detect_irq;
        int                     dma;
        int                     do_dma;
+       int                     use_sdio;
        unsigned int            power_mode;
        struct imxmmc_platform_data *pdata;
 
@@ -138,6 +139,7 @@ struct mxcmci_host {
        int                     clock;
 
        struct work_struct      datawork;
+       spinlock_t              lock;
 };
 
 static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios);
@@ -151,6 +153,8 @@ static void mxcmci_softreset(struct mxcmci_host *host)
 {
        int i;
 
+       dev_dbg(mmc_dev(host->mmc), "mxcmci_softreset\n");
+
        /* reset sequence */
        writew(STR_STP_CLK_RESET, host->base + MMC_REG_STR_STP_CLK);
        writew(STR_STP_CLK_RESET | STR_STP_CLK_START_CLK,
@@ -224,6 +228,9 @@ 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;
+       unsigned long flags;
+
        WARN_ON(host->cmd != NULL);
        host->cmd = cmd;
 
@@ -247,12 +254,16 @@ static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd,
                return -EINVAL;
        }
 
+       int_cntr = INT_END_CMD_RES_EN;
+
        if (mxcmci_use_dma(host))
-               writel(INT_READ_OP_EN | INT_WRITE_OP_DONE_EN |
-                               INT_END_CMD_RES_EN,
-                               host->base + MMC_REG_INT_CNTR);
-       else
-               writel(INT_END_CMD_RES_EN, host->base + MMC_REG_INT_CNTR);
+               int_cntr |= INT_READ_OP_EN | INT_WRITE_OP_DONE_EN;
+
+       spin_lock_irqsave(&host->lock, flags);
+       if (host->use_sdio)
+               int_cntr |= INT_SDIO_IRQ_EN;
+       writel(int_cntr, host->base + MMC_REG_INT_CNTR);
+       spin_unlock_irqrestore(&host->lock, flags);
 
        writew(cmd->opcode, host->base + MMC_REG_CMD);
        writel(cmd->arg, host->base + MMC_REG_ARG);
@@ -264,7 +275,14 @@ 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)
 {
-       writel(0, host->base + MMC_REG_INT_CNTR);
+       u32 int_cntr = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&host->lock, flags);
+       if (host->use_sdio)
+               int_cntr |= INT_SDIO_IRQ_EN;
+       writel(int_cntr, host->base + MMC_REG_INT_CNTR);
+       spin_unlock_irqrestore(&host->lock, flags);
 
        host->req = NULL;
        host->cmd = NULL;
@@ -290,16 +308,25 @@ static int mxcmci_finish_data(struct mxcmci_host *host, unsigned int stat)
                dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n",
                                stat);
                if (stat & STATUS_CRC_READ_ERR) {
+                       dev_err(mmc_dev(host->mmc), "%s: -EILSEQ\n", __func__);
                        data->error = -EILSEQ;
                } else if (stat & STATUS_CRC_WRITE_ERR) {
                        u32 err_code = (stat >> 9) & 0x3;
-                       if (err_code == 2) /* No CRC response */
+                       if (err_code == 2) { /* No CRC response */
+                               dev_err(mmc_dev(host->mmc),
+                                       "%s: No CRC -ETIMEDOUT\n", __func__);
                                data->error = -ETIMEDOUT;
-                       else
+                       } else {
+                               dev_err(mmc_dev(host->mmc),
+                                       "%s: -EILSEQ\n", __func__);
                                data->error = -EILSEQ;
+                       }
                } else if (stat & STATUS_TIME_OUT_READ) {
+                       dev_err(mmc_dev(host->mmc),
+                               "%s: read -ETIMEDOUT\n", __func__);
                        data->error = -ETIMEDOUT;
                } else {
+                       dev_err(mmc_dev(host->mmc), "%s: -EIO\n", __func__);
                        data->error = -EIO;
                }
        } else {
@@ -433,8 +460,6 @@ static int mxcmci_transfer_data(struct mxcmci_host *host)
        struct scatterlist *sg;
        int stat, i;
 
-       host->datasize = 0;
-
        host->data = data;
        host->datasize = 0;
 
@@ -464,6 +489,9 @@ static void mxcmci_datawork(struct work_struct *work)
        struct mxcmci_host *host = container_of(work, struct mxcmci_host,
                                                  datawork);
        int datastat = mxcmci_transfer_data(host);
+
+       writel(STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE,
+               host->base + MMC_REG_STATUS);
        mxcmci_finish_data(host, datastat);
 
        if (host->req->stop) {
@@ -523,15 +551,35 @@ static void mxcmci_cmd_done(struct mxcmci_host *host, unsigned int stat)
 static irqreturn_t mxcmci_irq(int irq, void *devid)
 {
        struct mxcmci_host *host = devid;
+       unsigned long flags;
+       bool sdio_irq;
        u32 stat;
 
        stat = readl(host->base + MMC_REG_STATUS);
-       writel(stat, host->base + MMC_REG_STATUS);
+       writel(stat & ~(STATUS_SDIO_INT_ACTIVE | STATUS_DATA_TRANS_DONE |
+                       STATUS_WRITE_OP_DONE), host->base + MMC_REG_STATUS);
 
        dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat);
 
+       spin_lock_irqsave(&host->lock, flags);
+       sdio_irq = (stat & STATUS_SDIO_INT_ACTIVE) && host->use_sdio;
+       spin_unlock_irqrestore(&host->lock, flags);
+
+#ifdef HAS_DMA
+       if (mxcmci_use_dma(host) &&
+           (stat & (STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE)))
+               writel(STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE,
+                       host->base + MMC_REG_STATUS);
+#endif
+
+       if (sdio_irq) {
+               writel(STATUS_SDIO_INT_ACTIVE, host->base + MMC_REG_STATUS);
+               mmc_signal_sdio_irq(host->mmc);
+       }
+
        if (stat & STATUS_END_CMD_RESP)
                mxcmci_cmd_done(host, stat);
+
 #ifdef HAS_DMA
        if (mxcmci_use_dma(host) &&
                  (stat & (STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE)))
@@ -668,11 +716,46 @@ static int mxcmci_get_ro(struct mmc_host *mmc)
        return -ENOSYS;
 }
 
+static void mxcmci_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+       struct mxcmci_host *host = mmc_priv(mmc);
+       unsigned long flags;
+       u32 int_cntr;
+
+       spin_lock_irqsave(&host->lock, flags);
+       host->use_sdio = enable;
+       int_cntr = readl(host->base + MMC_REG_INT_CNTR);
+
+       if (enable)
+               int_cntr |= INT_SDIO_IRQ_EN;
+       else
+               int_cntr &= ~INT_SDIO_IRQ_EN;
+
+       writel(int_cntr, host->base + MMC_REG_INT_CNTR);
+       spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void mxcmci_init_card(struct mmc_host *host, struct mmc_card *card)
+{
+       /*
+        * MX3 SoCs have a silicon bug which corrupts CRC calculation of
+        * multi-block transfers when connected SDIO peripheral doesn't
+        * drive the BUSY line as required by the specs.
+        * One way to prevent this is to only allow 1-bit transfers.
+        */
+
+       if (cpu_is_mx3() && card->type == MMC_TYPE_SDIO)
+               host->caps &= ~MMC_CAP_4_BIT_DATA;
+       else
+               host->caps |= MMC_CAP_4_BIT_DATA;
+}
 
 static const struct mmc_host_ops mxcmci_ops = {
-       .request        = mxcmci_request,
-       .set_ios        = mxcmci_set_ios,
-       .get_ro         = mxcmci_get_ro,
+       .request                = mxcmci_request,
+       .set_ios                = mxcmci_set_ios,
+       .get_ro                 = mxcmci_get_ro,
+       .enable_sdio_irq        = mxcmci_enable_sdio_irq,
+       .init_card              = mxcmci_init_card,
 };
 
 static int mxcmci_probe(struct platform_device *pdev)
@@ -700,7 +783,7 @@ static int mxcmci_probe(struct platform_device *pdev)
        }
 
        mmc->ops = &mxcmci_ops;
-       mmc->caps = MMC_CAP_4_BIT_DATA;
+       mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
 
        /* MMC core transfer sizes tunable parameters */
        mmc->max_hw_segs = 64;
@@ -719,6 +802,7 @@ static int mxcmci_probe(struct platform_device *pdev)
 
        host->mmc = mmc;
        host->pdata = pdev->dev.platform_data;
+       spin_lock_init(&host->lock);
 
        if (host->pdata && host->pdata->ocr_avail)
                mmc->ocr_avail = host->pdata->ocr_avail;
@@ -848,7 +932,7 @@ static int mxcmci_suspend(struct platform_device *dev, pm_message_t state)
        int ret = 0;
 
        if (mmc)
-               ret = mmc_suspend_host(mmc, state);
+               ret = mmc_suspend_host(mmc);
 
        return ret;
 }
index bb6cc54b558ee235f17b28990f5e80da8304f2b6..1247e5de9faa84afb6f2b9be923fcd5ce5053f97 100644 (file)
@@ -64,7 +64,7 @@ static int of_mmc_spi_get_ro(struct device *dev)
 struct mmc_spi_platform_data *mmc_spi_get_pdata(struct spi_device *spi)
 {
        struct device *dev = &spi->dev;
-       struct device_node *np = dev_archdata_get_node(&dev->archdata);
+       struct device_node *np = dev->of_node;
        struct of_mmc_spi *oms;
        const u32 *voltage_ranges;
        int num_ranges;
@@ -135,7 +135,7 @@ EXPORT_SYMBOL(mmc_spi_get_pdata);
 void mmc_spi_put_pdata(struct spi_device *spi)
 {
        struct device *dev = &spi->dev;
-       struct device_node *np = dev_archdata_get_node(&dev->archdata);
+       struct device_node *np = dev->of_node;
        struct of_mmc_spi *oms = to_of_mmc_spi(dev);
        int i;
 
index 84d280406341f1bf071e07430e6118766cea87c5..2b281680e3206da99f9e991d69f12c5edef92754 100644 (file)
 #include <plat/fpga.h>
 
 #define        OMAP_MMC_REG_CMD        0x00
-#define        OMAP_MMC_REG_ARGL       0x04
-#define        OMAP_MMC_REG_ARGH       0x08
-#define        OMAP_MMC_REG_CON        0x0c
-#define        OMAP_MMC_REG_STAT       0x10
-#define        OMAP_MMC_REG_IE         0x14
-#define        OMAP_MMC_REG_CTO        0x18
-#define        OMAP_MMC_REG_DTO        0x1c
-#define        OMAP_MMC_REG_DATA       0x20
-#define        OMAP_MMC_REG_BLEN       0x24
-#define        OMAP_MMC_REG_NBLK       0x28
-#define        OMAP_MMC_REG_BUF        0x2c
-#define OMAP_MMC_REG_SDIO      0x34
-#define        OMAP_MMC_REG_REV        0x3c
-#define        OMAP_MMC_REG_RSP0       0x40
-#define        OMAP_MMC_REG_RSP1       0x44
-#define        OMAP_MMC_REG_RSP2       0x48
-#define        OMAP_MMC_REG_RSP3       0x4c
-#define        OMAP_MMC_REG_RSP4       0x50
-#define        OMAP_MMC_REG_RSP5       0x54
-#define        OMAP_MMC_REG_RSP6       0x58
-#define        OMAP_MMC_REG_RSP7       0x5c
-#define        OMAP_MMC_REG_IOSR       0x60
-#define        OMAP_MMC_REG_SYSC       0x64
-#define        OMAP_MMC_REG_SYSS       0x68
+#define        OMAP_MMC_REG_ARGL       0x01
+#define        OMAP_MMC_REG_ARGH       0x02
+#define        OMAP_MMC_REG_CON        0x03
+#define        OMAP_MMC_REG_STAT       0x04
+#define        OMAP_MMC_REG_IE         0x05
+#define        OMAP_MMC_REG_CTO        0x06
+#define        OMAP_MMC_REG_DTO        0x07
+#define        OMAP_MMC_REG_DATA       0x08
+#define        OMAP_MMC_REG_BLEN       0x09
+#define        OMAP_MMC_REG_NBLK       0x0a
+#define        OMAP_MMC_REG_BUF        0x0b
+#define        OMAP_MMC_REG_SDIO       0x0d
+#define        OMAP_MMC_REG_REV        0x0f
+#define        OMAP_MMC_REG_RSP0       0x10
+#define        OMAP_MMC_REG_RSP1       0x11
+#define        OMAP_MMC_REG_RSP2       0x12
+#define        OMAP_MMC_REG_RSP3       0x13
+#define        OMAP_MMC_REG_RSP4       0x14
+#define        OMAP_MMC_REG_RSP5       0x15
+#define        OMAP_MMC_REG_RSP6       0x16
+#define        OMAP_MMC_REG_RSP7       0x17
+#define        OMAP_MMC_REG_IOSR       0x18
+#define        OMAP_MMC_REG_SYSC       0x19
+#define        OMAP_MMC_REG_SYSS       0x1a
 
 #define        OMAP_MMC_STAT_CARD_ERR          (1 << 14)
 #define        OMAP_MMC_STAT_CARD_IRQ          (1 << 13)
@@ -78,8 +78,9 @@
 #define        OMAP_MMC_STAT_CARD_BUSY         (1 <<  2)
 #define        OMAP_MMC_STAT_END_OF_CMD        (1 <<  0)
 
-#define OMAP_MMC_READ(host, reg)       __raw_readw((host)->virt_base + OMAP_MMC_REG_##reg)
-#define OMAP_MMC_WRITE(host, reg, val) __raw_writew((val), (host)->virt_base + OMAP_MMC_REG_##reg)
+#define OMAP_MMC_REG(host, reg)                (OMAP_MMC_REG_##reg << (host)->reg_shift)
+#define OMAP_MMC_READ(host, reg)       __raw_readw((host)->virt_base + OMAP_MMC_REG(host, reg))
+#define OMAP_MMC_WRITE(host, reg, val) __raw_writew((val), (host)->virt_base + OMAP_MMC_REG(host, reg))
 
 /*
  * Command types
@@ -133,6 +134,7 @@ struct mmc_omap_host {
        int                     irq;
        unsigned char           bus_mode;
        unsigned char           hw_bus_mode;
+       unsigned int            reg_shift;
 
        struct work_struct      cmd_abort_work;
        unsigned                abort:1;
@@ -680,9 +682,9 @@ mmc_omap_xfer_data(struct mmc_omap_host *host, int write)
        host->data->bytes_xfered += n;
 
        if (write) {
-               __raw_writesw(host->virt_base + OMAP_MMC_REG_DATA, host->buffer, n);
+               __raw_writesw(host->virt_base + OMAP_MMC_REG(host, DATA), host->buffer, n);
        } else {
-               __raw_readsw(host->virt_base + OMAP_MMC_REG_DATA, host->buffer, n);
+               __raw_readsw(host->virt_base + OMAP_MMC_REG(host, DATA), host->buffer, n);
        }
 }
 
@@ -900,7 +902,7 @@ mmc_omap_prepare_dma(struct mmc_omap_host *host, struct mmc_data *data)
        int dst_port = 0;
        int sync_dev = 0;
 
-       data_addr = host->phys_base + OMAP_MMC_REG_DATA;
+       data_addr = host->phys_base + OMAP_MMC_REG(host, DATA);
        frame = data->blksz;
        count = sg_dma_len(sg);
 
@@ -1493,6 +1495,8 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
                }
        }
 
+       host->reg_shift = (cpu_is_omap7xx() ? 1 : 2);
+
        return 0;
 
 err_plat_cleanup:
@@ -1557,7 +1561,7 @@ static int mmc_omap_suspend(struct platform_device *pdev, pm_message_t mesg)
                struct mmc_omap_slot *slot;
 
                slot = host->slots[i];
-               ret = mmc_suspend_host(slot->mmc, mesg);
+               ret = mmc_suspend_host(slot->mmc);
                if (ret < 0) {
                        while (--i >= 0) {
                                slot = host->slots[i];
index e9caf694c59e200e57eed9cc1cc29847139cf9b4..b032828c61263028963bd412a7455546d5e86ce7 100644 (file)
@@ -157,12 +157,10 @@ struct omap_hsmmc_host {
         */
        struct  regulator       *vcc;
        struct  regulator       *vcc_aux;
-       struct  semaphore       sem;
        struct  work_struct     mmc_carddetect_work;
        void    __iomem         *base;
        resource_size_t         mapbase;
        spinlock_t              irq_lock; /* Prevent races with irq handler */
-       unsigned long           flags;
        unsigned int            id;
        unsigned int            dma_len;
        unsigned int            dma_sg_idx;
@@ -183,6 +181,7 @@ struct omap_hsmmc_host {
        int                     protect_card;
        int                     reqs_blocked;
        int                     use_reg;
+       int                     req_in_progress;
 
        struct  omap_mmc_platform_data  *pdata;
 };
@@ -524,6 +523,27 @@ static void omap_hsmmc_stop_clock(struct omap_hsmmc_host *host)
                dev_dbg(mmc_dev(host->mmc), "MMC Clock is not stoped\n");
 }
 
+static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host)
+{
+       unsigned int irq_mask;
+
+       if (host->use_dma)
+               irq_mask = INT_EN_MASK & ~(BRR_ENABLE | BWR_ENABLE);
+       else
+               irq_mask = INT_EN_MASK;
+
+       OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
+       OMAP_HSMMC_WRITE(host->base, ISE, irq_mask);
+       OMAP_HSMMC_WRITE(host->base, IE, irq_mask);
+}
+
+static void omap_hsmmc_disable_irq(struct omap_hsmmc_host *host)
+{
+       OMAP_HSMMC_WRITE(host->base, ISE, 0);
+       OMAP_HSMMC_WRITE(host->base, IE, 0);
+       OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
+}
+
 #ifdef CONFIG_PM
 
 /*
@@ -592,9 +612,7 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
                && time_before(jiffies, timeout))
                ;
 
-       OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
-       OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
-       OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
+       omap_hsmmc_disable_irq(host);
 
        /* Do not initialize card-specific things if the power is off */
        if (host->power_mode == MMC_POWER_OFF)
@@ -697,6 +715,8 @@ static void send_init_stream(struct omap_hsmmc_host *host)
                return;
 
        disable_irq(host->irq);
+
+       OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
        OMAP_HSMMC_WRITE(host->base, CON,
                OMAP_HSMMC_READ(host->base, CON) | INIT_STREAM);
        OMAP_HSMMC_WRITE(host->base, CMD, INIT_STREAM_CMD);
@@ -762,17 +782,7 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
                mmc_hostname(host->mmc), cmd->opcode, cmd->arg);
        host->cmd = cmd;
 
-       /*
-        * Clear status bits and enable interrupts
-        */
-       OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
-       OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
-
-       if (host->use_dma)
-               OMAP_HSMMC_WRITE(host->base, IE,
-                                INT_EN_MASK & ~(BRR_ENABLE | BWR_ENABLE));
-       else
-               OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
+       omap_hsmmc_enable_irq(host);
 
        host->response_busy = 0;
        if (cmd->flags & MMC_RSP_PRESENT) {
@@ -806,13 +816,7 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
        if (host->use_dma)
                cmdreg |= DMA_EN;
 
-       /*
-        * In an interrupt context (i.e. STOP command), the spinlock is unlocked
-        * by the interrupt handler, otherwise (i.e. for a new request) it is
-        * unlocked here.
-        */
-       if (!in_interrupt())
-               spin_unlock_irqrestore(&host->irq_lock, host->flags);
+       host->req_in_progress = 1;
 
        OMAP_HSMMC_WRITE(host->base, ARG, cmd->arg);
        OMAP_HSMMC_WRITE(host->base, CMD, cmdreg);
@@ -827,6 +831,23 @@ omap_hsmmc_get_dma_dir(struct omap_hsmmc_host *host, struct mmc_data *data)
                return DMA_FROM_DEVICE;
 }
 
+static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_request *mrq)
+{
+       int dma_ch;
+
+       spin_lock(&host->irq_lock);
+       host->req_in_progress = 0;
+       dma_ch = host->dma_ch;
+       spin_unlock(&host->irq_lock);
+
+       omap_hsmmc_disable_irq(host);
+       /* Do not complete the request if DMA is still in progress */
+       if (mrq->data && host->use_dma && dma_ch != -1)
+               return;
+       host->mrq = NULL;
+       mmc_request_done(host->mmc, mrq);
+}
+
 /*
  * Notify the transfer complete to MMC core
  */
@@ -843,25 +864,19 @@ omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data)
                        return;
                }
 
-               host->mrq = NULL;
-               mmc_request_done(host->mmc, mrq);
+               omap_hsmmc_request_done(host, mrq);
                return;
        }
 
        host->data = NULL;
 
-       if (host->use_dma && host->dma_ch != -1)
-               dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len,
-                       omap_hsmmc_get_dma_dir(host, data));
-
        if (!data->error)
                data->bytes_xfered += data->blocks * (data->blksz);
        else
                data->bytes_xfered = 0;
 
        if (!data->stop) {
-               host->mrq = NULL;
-               mmc_request_done(host->mmc, data->mrq);
+               omap_hsmmc_request_done(host, data->mrq);
                return;
        }
        omap_hsmmc_start_command(host, data->stop, NULL);
@@ -887,10 +902,8 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd)
                        cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP10);
                }
        }
-       if ((host->data == NULL && !host->response_busy) || cmd->error) {
-               host->mrq = NULL;
-               mmc_request_done(host->mmc, cmd->mrq);
-       }
+       if ((host->data == NULL && !host->response_busy) || cmd->error)
+               omap_hsmmc_request_done(host, cmd->mrq);
 }
 
 /*
@@ -898,14 +911,19 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd)
  */
 static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno)
 {
+       int dma_ch;
+
        host->data->error = errno;
 
-       if (host->use_dma && host->dma_ch != -1) {
+       spin_lock(&host->irq_lock);
+       dma_ch = host->dma_ch;
+       host->dma_ch = -1;
+       spin_unlock(&host->irq_lock);
+
+       if (host->use_dma && dma_ch != -1) {
                dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, host->dma_len,
                        omap_hsmmc_get_dma_dir(host, host->data));
-               omap_free_dma(host->dma_ch);
-               host->dma_ch = -1;
-               up(&host->sem);
+               omap_free_dma(dma_ch);
        }
        host->data = NULL;
 }
@@ -967,28 +985,21 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host,
                        __func__);
 }
 
-/*
- * MMC controller IRQ handler
- */
-static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id)
+static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
 {
-       struct omap_hsmmc_host *host = dev_id;
        struct mmc_data *data;
-       int end_cmd = 0, end_trans = 0, status;
-
-       spin_lock(&host->irq_lock);
-
-       if (host->mrq == NULL) {
-               OMAP_HSMMC_WRITE(host->base, STAT,
-                       OMAP_HSMMC_READ(host->base, STAT));
-               /* Flush posted write */
-               OMAP_HSMMC_READ(host->base, STAT);
-               spin_unlock(&host->irq_lock);
-               return IRQ_HANDLED;
+       int end_cmd = 0, end_trans = 0;
+
+       if (!host->req_in_progress) {
+               do {
+                       OMAP_HSMMC_WRITE(host->base, STAT, status);
+                       /* Flush posted write */
+                       status = OMAP_HSMMC_READ(host->base, STAT);
+               } while (status & INT_EN_MASK);
+               return;
        }
 
        data = host->data;
-       status = OMAP_HSMMC_READ(host->base, STAT);
        dev_dbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
 
        if (status & ERR) {
@@ -1041,15 +1052,27 @@ static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id)
        }
 
        OMAP_HSMMC_WRITE(host->base, STAT, status);
-       /* Flush posted write */
-       OMAP_HSMMC_READ(host->base, STAT);
 
        if (end_cmd || ((status & CC) && host->cmd))
                omap_hsmmc_cmd_done(host, host->cmd);
        if ((end_trans || (status & TC)) && host->mrq)
                omap_hsmmc_xfer_done(host, data);
+}
 
-       spin_unlock(&host->irq_lock);
+/*
+ * MMC controller IRQ handler
+ */
+static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id)
+{
+       struct omap_hsmmc_host *host = dev_id;
+       int status;
+
+       status = OMAP_HSMMC_READ(host->base, STAT);
+       do {
+               omap_hsmmc_do_irq(host, status);
+               /* Flush posted write */
+               status = OMAP_HSMMC_READ(host->base, STAT);
+       } while (status & INT_EN_MASK);
 
        return IRQ_HANDLED;
 }
@@ -1244,31 +1267,47 @@ static void omap_hsmmc_config_dma_params(struct omap_hsmmc_host *host,
 /*
  * DMA call back function
  */
-static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *data)
+static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data)
 {
-       struct omap_hsmmc_host *host = data;
+       struct omap_hsmmc_host *host = cb_data;
+       struct mmc_data *data = host->mrq->data;
+       int dma_ch, req_in_progress;
 
        if (ch_status & OMAP2_DMA_MISALIGNED_ERR_IRQ)
                dev_dbg(mmc_dev(host->mmc), "MISALIGNED_ADRS_ERR\n");
 
-       if (host->dma_ch < 0)
+       spin_lock(&host->irq_lock);
+       if (host->dma_ch < 0) {
+               spin_unlock(&host->irq_lock);
                return;
+       }
 
        host->dma_sg_idx++;
        if (host->dma_sg_idx < host->dma_len) {
                /* Fire up the next transfer. */
-               omap_hsmmc_config_dma_params(host, host->data,
-                                          host->data->sg + host->dma_sg_idx);
+               omap_hsmmc_config_dma_params(host, data,
+                                          data->sg + host->dma_sg_idx);
+               spin_unlock(&host->irq_lock);
                return;
        }
 
-       omap_free_dma(host->dma_ch);
+       dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len,
+               omap_hsmmc_get_dma_dir(host, data));
+
+       req_in_progress = host->req_in_progress;
+       dma_ch = host->dma_ch;
        host->dma_ch = -1;
-       /*
-        * DMA Callback: run in interrupt context.
-        * mutex_unlock will throw a kernel warning if used.
-        */
-       up(&host->sem);
+       spin_unlock(&host->irq_lock);
+
+       omap_free_dma(dma_ch);
+
+       /* If DMA has finished after TC, complete the request */
+       if (!req_in_progress) {
+               struct mmc_request *mrq = host->mrq;
+
+               host->mrq = NULL;
+               mmc_request_done(host->mmc, mrq);
+       }
 }
 
 /*
@@ -1277,7 +1316,7 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *data)
 static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host,
                                        struct mmc_request *req)
 {
-       int dma_ch = 0, ret = 0, err = 1, i;
+       int dma_ch = 0, ret = 0, i;
        struct mmc_data *data = req->data;
 
        /* Sanity check: all the SG entries must be aligned by block size. */
@@ -1294,23 +1333,7 @@ static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host,
                 */
                return -EINVAL;
 
-       /*
-        * If for some reason the DMA transfer is still active,
-        * we wait for timeout period and free the dma
-        */
-       if (host->dma_ch != -1) {
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(100);
-               if (down_trylock(&host->sem)) {
-                       omap_free_dma(host->dma_ch);
-                       host->dma_ch = -1;
-                       up(&host->sem);
-                       return err;
-               }
-       } else {
-               if (down_trylock(&host->sem))
-                       return err;
-       }
+       BUG_ON(host->dma_ch != -1);
 
        ret = omap_request_dma(omap_hsmmc_get_dma_sync_dev(host, data),
                               "MMC/SD", omap_hsmmc_dma_cb, host, &dma_ch);
@@ -1410,37 +1433,27 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
        struct omap_hsmmc_host *host = mmc_priv(mmc);
        int err;
 
-       /*
-        * Prevent races with the interrupt handler because of unexpected
-        * interrupts, but not if we are already in interrupt context i.e.
-        * retries.
-        */
-       if (!in_interrupt()) {
-               spin_lock_irqsave(&host->irq_lock, host->flags);
-               /*
-                * Protect the card from I/O if there is a possibility
-                * it can be removed.
-                */
-               if (host->protect_card) {
-                       if (host->reqs_blocked < 3) {
-                               /*
-                                * Ensure the controller is left in a consistent
-                                * state by resetting the command and data state
-                                * machines.
-                                */
-                               omap_hsmmc_reset_controller_fsm(host, SRD);
-                               omap_hsmmc_reset_controller_fsm(host, SRC);
-                               host->reqs_blocked += 1;
-                       }
-                       req->cmd->error = -EBADF;
-                       if (req->data)
-                               req->data->error = -EBADF;
-                       spin_unlock_irqrestore(&host->irq_lock, host->flags);
-                       mmc_request_done(mmc, req);
-                       return;
-               } else if (host->reqs_blocked)
-                       host->reqs_blocked = 0;
-       }
+       BUG_ON(host->req_in_progress);
+       BUG_ON(host->dma_ch != -1);
+       if (host->protect_card) {
+               if (host->reqs_blocked < 3) {
+                       /*
+                        * Ensure the controller is left in a consistent
+                        * state by resetting the command and data state
+                        * machines.
+                        */
+                       omap_hsmmc_reset_controller_fsm(host, SRD);
+                       omap_hsmmc_reset_controller_fsm(host, SRC);
+                       host->reqs_blocked += 1;
+               }
+               req->cmd->error = -EBADF;
+               if (req->data)
+                       req->data->error = -EBADF;
+               req->cmd->retries = 0;
+               mmc_request_done(mmc, req);
+               return;
+       } else if (host->reqs_blocked)
+               host->reqs_blocked = 0;
        WARN_ON(host->mrq != NULL);
        host->mrq = req;
        err = omap_hsmmc_prepare_data(host, req);
@@ -1449,8 +1462,6 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
                if (req->data)
                        req->data->error = err;
                host->mrq = NULL;
-               if (!in_interrupt())
-                       spin_unlock_irqrestore(&host->irq_lock, host->flags);
                mmc_request_done(mmc, req);
                return;
        }
@@ -2019,7 +2030,6 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
        mmc->f_min      = 400000;
        mmc->f_max      = 52000000;
 
-       sema_init(&host->sem, 1);
        spin_lock_init(&host->irq_lock);
 
        host->iclk = clk_get(&pdev->dev, "ick");
@@ -2162,8 +2172,7 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
                }
        }
 
-       OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
-       OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
+       omap_hsmmc_disable_irq(host);
 
        mmc_host_lazy_disable(host->mmc);
 
@@ -2258,10 +2267,12 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM
-static int omap_hsmmc_suspend(struct platform_device *pdev, pm_message_t state)
+static int omap_hsmmc_suspend(struct device *dev)
 {
        int ret = 0;
+       struct platform_device *pdev = to_platform_device(dev);
        struct omap_hsmmc_host *host = platform_get_drvdata(pdev);
+       pm_message_t state = PMSG_SUSPEND; /* unused by MMC core */
 
        if (host && host->suspended)
                return 0;
@@ -2281,12 +2292,9 @@ static int omap_hsmmc_suspend(struct platform_device *pdev, pm_message_t state)
                }
                cancel_work_sync(&host->mmc_carddetect_work);
                mmc_host_enable(host->mmc);
-               ret = mmc_suspend_host(host->mmc, state);
+               ret = mmc_suspend_host(host->mmc);
                if (ret == 0) {
-                       OMAP_HSMMC_WRITE(host->base, ISE, 0);
-                       OMAP_HSMMC_WRITE(host->base, IE, 0);
-
-
+                       omap_hsmmc_disable_irq(host);
                        OMAP_HSMMC_WRITE(host->base, HCTL,
                                OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP);
                        mmc_host_disable(host->mmc);
@@ -2310,9 +2318,10 @@ static int omap_hsmmc_suspend(struct platform_device *pdev, pm_message_t state)
 }
 
 /* Routine to resume the MMC device */
-static int omap_hsmmc_resume(struct platform_device *pdev)
+static int omap_hsmmc_resume(struct device *dev)
 {
        int ret = 0;
+       struct platform_device *pdev = to_platform_device(dev);
        struct omap_hsmmc_host *host = platform_get_drvdata(pdev);
 
        if (host && !host->suspended)
@@ -2363,13 +2372,17 @@ clk_en_err:
 #define omap_hsmmc_resume              NULL
 #endif
 
-static struct platform_driver omap_hsmmc_driver = {
-       .remove         = omap_hsmmc_remove,
+static struct dev_pm_ops omap_hsmmc_dev_pm_ops = {
        .suspend        = omap_hsmmc_suspend,
        .resume         = omap_hsmmc_resume,
+};
+
+static struct platform_driver omap_hsmmc_driver = {
+       .remove         = omap_hsmmc_remove,
        .driver         = {
                .name = DRIVER_NAME,
                .owner = THIS_MODULE,
+               .pm = &omap_hsmmc_dev_pm_ops,
        },
 };
 
index e4f00e70a749db8fb88aefc6ac580df99b4769ff..0a4e43f371408733f43ba9fae73be7647222b5b6 100644 (file)
@@ -813,7 +813,7 @@ static int pxamci_suspend(struct device *dev)
        int ret = 0;
 
        if (mmc)
-               ret = mmc_suspend_host(mmc, PMSG_SUSPEND);
+               ret = mmc_suspend_host(mmc);
 
        return ret;
 }
index 2fdf7689ae6c3a2bdb2c876f0299b2c7e9009edf..2e16e0a90a5e1a5d8d3d7487727baa39d701b8fb 100644 (file)
@@ -1881,9 +1881,8 @@ MODULE_DEVICE_TABLE(platform, s3cmci_driver_ids);
 static int s3cmci_suspend(struct device *dev)
 {
        struct mmc_host *mmc = platform_get_drvdata(to_platform_device(dev));
-       struct pm_message event = { PM_EVENT_SUSPEND };
 
-       return mmc_suspend_host(mmc, event);
+       return mmc_suspend_host(mmc);
 }
 
 static int s3cmci_resume(struct device *dev)
index 55e33135edb4dbc60b800e9207b7ae1b0e3b8139..a2e9820cd42f75e9de5942eb4ef7c0f37cbc0db5 100644 (file)
@@ -89,7 +89,7 @@ static int sdhci_of_suspend(struct of_device *ofdev, pm_message_t state)
 {
        struct sdhci_host *host = dev_get_drvdata(&ofdev->dev);
 
-       return mmc_suspend_host(host->mmc, state);
+       return mmc_suspend_host(host->mmc);
 }
 
 static int sdhci_of_resume(struct of_device *ofdev)
@@ -118,7 +118,7 @@ static bool __devinit sdhci_of_wp_inverted(struct device_node *np)
 static int __devinit sdhci_of_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 sdhci_of_data *sdhci_of_data = match->data;
        struct sdhci_host *host;
        struct sdhci_of_host *of_host;
@@ -205,8 +205,11 @@ static const struct of_device_id sdhci_of_match[] = {
 MODULE_DEVICE_TABLE(of, sdhci_of_match);
 
 static struct of_platform_driver sdhci_of_driver = {
-       .driver.name = "sdhci-of",
-       .match_table = sdhci_of_match,
+       .driver = {
+               .name = "sdhci-of",
+               .owner = THIS_MODULE,
+               .of_match_table = sdhci_of_match,
+       },
        .probe = sdhci_of_probe,
        .remove = __devexit_p(sdhci_of_remove),
        .suspend = sdhci_of_suspend,
index d5b11a17e64805c7e5e8531d192afdd0230a1805..c8623de13af33d1b44cc701b1a52eb4ea13dda26 100644 (file)
@@ -129,12 +129,12 @@ struct sdhci_of_data sdhci_esdhc = {
                  SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET |
                  SDHCI_QUIRK_NO_CARD_NO_RESET,
        .ops = {
-               .readl = sdhci_be32bs_readl,
-               .readw = esdhc_readw,
-               .readb = sdhci_be32bs_readb,
-               .writel = sdhci_be32bs_writel,
-               .writew = esdhc_writew,
-               .writeb = esdhc_writeb,
+               .read_l = sdhci_be32bs_readl,
+               .read_w = esdhc_readw,
+               .read_b = sdhci_be32bs_readb,
+               .write_l = sdhci_be32bs_writel,
+               .write_w = esdhc_writew,
+               .write_b = esdhc_writeb,
                .set_clock = esdhc_set_clock,
                .enable_dma = esdhc_enable_dma,
                .get_max_clock = esdhc_get_max_clock,
index 35117f3ed7576fe79a5e6f9263fdcc951f806d7e..68ddb7546ae238e2064efe320baeadca698f1922 100644 (file)
@@ -55,11 +55,11 @@ struct sdhci_of_data sdhci_hlwd = {
        .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR |
                  SDHCI_QUIRK_32BIT_DMA_SIZE,
        .ops = {
-               .readl = sdhci_be32bs_readl,
-               .readw = sdhci_be32bs_readw,
-               .readb = sdhci_be32bs_readb,
-               .writel = sdhci_hlwd_writel,
-               .writew = sdhci_hlwd_writew,
-               .writeb = sdhci_hlwd_writeb,
+               .read_l = sdhci_be32bs_readl,
+               .read_w = sdhci_be32bs_readw,
+               .read_b = sdhci_be32bs_readb,
+               .write_l = sdhci_hlwd_writel,
+               .write_w = sdhci_hlwd_writew,
+               .write_b = sdhci_hlwd_writeb,
        },
 };
index 6701af629c30e3b8c0fb86c606f546cddf7519b7..65483fdea45b56ba431bd5a37a3891bdeed708c8 100644 (file)
@@ -628,7 +628,7 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot(
        host = sdhci_alloc_host(&pdev->dev, sizeof(struct sdhci_pci_slot));
        if (IS_ERR(host)) {
                dev_err(&pdev->dev, "cannot allocate host\n");
-               return ERR_PTR(PTR_ERR(host));
+               return ERR_CAST(host);
        }
 
        slot = sdhci_priv(host);
index 297f40ae6ad5623f2695c16c4a5db4886931b791..b6ee0d71969898257cf625b6b21cc37b3426a9f6 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/mmc/host.h>
 
 #include <linux/io.h>
+#include <linux/sdhci-pltfm.h>
 
 #include "sdhci.h"
 
@@ -49,19 +50,18 @@ static struct sdhci_ops sdhci_pltfm_ops = {
 
 static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
 {
+       struct sdhci_pltfm_data *pdata = pdev->dev.platform_data;
        struct sdhci_host *host;
        struct resource *iomem;
        int ret;
 
-       BUG_ON(pdev == NULL);
-
        iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!iomem) {
                ret = -ENOMEM;
                goto err;
        }
 
-       if (resource_size(iomem) != 0x100)
+       if (resource_size(iomem) < 0x100)
                dev_err(&pdev->dev, "Invalid iomem size. You may "
                        "experience problems.\n");
 
@@ -76,7 +76,12 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
        }
 
        host->hw_name = "platform";
-       host->ops = &sdhci_pltfm_ops;
+       if (pdata && pdata->ops)
+               host->ops = pdata->ops;
+       else
+               host->ops = &sdhci_pltfm_ops;
+       if (pdata)
+               host->quirks = pdata->quirks;
        host->irq = platform_get_irq(pdev, 0);
 
        if (!request_mem_region(iomem->start, resource_size(iomem),
@@ -93,6 +98,12 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
                goto err_remap;
        }
 
+       if (pdata && pdata->init) {
+               ret = pdata->init(host);
+               if (ret)
+                       goto err_plat_init;
+       }
+
        ret = sdhci_add_host(host);
        if (ret)
                goto err_add_host;
@@ -102,6 +113,9 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
        return 0;
 
 err_add_host:
+       if (pdata && pdata->exit)
+               pdata->exit(host);
+err_plat_init:
        iounmap(host->ioaddr);
 err_remap:
        release_mem_region(iomem->start, resource_size(iomem));
@@ -114,6 +128,7 @@ err:
 
 static int __devexit sdhci_pltfm_remove(struct platform_device *pdev)
 {
+       struct sdhci_pltfm_data *pdata = pdev->dev.platform_data;
        struct sdhci_host *host = platform_get_drvdata(pdev);
        struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        int dead;
@@ -125,6 +140,8 @@ static int __devexit sdhci_pltfm_remove(struct platform_device *pdev)
                dead = 1;
 
        sdhci_remove_host(host, dead);
+       if (pdata && pdata->exit)
+               pdata->exit(host);
        iounmap(host->ioaddr);
        release_mem_region(iomem->start, resource_size(iomem));
        sdhci_free_host(host);
@@ -165,4 +182,3 @@ MODULE_DESCRIPTION("Secure Digital Host Controller Interface platform driver");
 MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:sdhci");
-
index 2136794c0cfaf66fed55c5433f8e4bc574e19604..af217924a76eb94511fddf7789d5d1a458a2c21b 100644 (file)
@@ -317,12 +317,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
        host->irq = irq;
 
        /* Setup quirks for the controller */
-
-       /* Currently with ADMA enabled we are getting some length
-        * interrupts that are not being dealt with, do disable
-        * ADMA until this is sorted out. */
-       host->quirks |= SDHCI_QUIRK_BROKEN_ADMA;
-       host->quirks |= SDHCI_QUIRK_32BIT_ADMA_SIZE;
+       host->quirks |= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC;
 
 #ifndef CONFIG_MMC_SDHCI_S3C_DMA
 
@@ -330,9 +325,6 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
         * support as well. */
        host->quirks |= SDHCI_QUIRK_BROKEN_DMA;
 
-       /* PIO currently has problems with multi-block IO */
-       host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK;
-
 #endif /* CONFIG_MMC_SDHCI_S3C_DMA */
 
        /* It seems we do not get an DATA transfer complete on non-busy
diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c
new file mode 100644 (file)
index 0000000..d70c54c
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * drivers/mmc/host/sdhci-spear.c
+ *
+ * Support of SDHCI platform devices for spear soc family
+ *
+ * Copyright (C) 2010 ST Microelectronics
+ * Viresh Kumar<viresh.kumar@st.com>
+ *
+ * Inspired by sdhci-pltfm.c
+ *
+ * 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/highmem.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sdhci-spear.h>
+#include <linux/io.h>
+#include "sdhci.h"
+
+struct spear_sdhci {
+       struct clk *clk;
+       struct sdhci_plat_data *data;
+};
+
+/* sdhci ops */
+static struct sdhci_ops sdhci_pltfm_ops = {
+       /* Nothing to do for now. */
+};
+
+/* gpio card detection interrupt handler */
+static irqreturn_t sdhci_gpio_irq(int irq, void *dev_id)
+{
+       struct platform_device *pdev = dev_id;
+       struct sdhci_host *host = platform_get_drvdata(pdev);
+       struct spear_sdhci *sdhci = dev_get_platdata(&pdev->dev);
+       unsigned long gpio_irq_type;
+       int val;
+
+       val = gpio_get_value(sdhci->data->card_int_gpio);
+
+       /* val == 1 -> card removed, val == 0 -> card inserted */
+       /* if card removed - set irq for low level, else vice versa */
+       gpio_irq_type = val ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH;
+       set_irq_type(irq, gpio_irq_type);
+
+       if (sdhci->data->card_power_gpio >= 0) {
+               if (!sdhci->data->power_always_enb) {
+                       /* if card inserted, give power, otherwise remove it */
+                       val = sdhci->data->power_active_high ? !val : val ;
+                       gpio_set_value(sdhci->data->card_power_gpio, val);
+               }
+       }
+
+       /* inform sdhci driver about card insertion/removal */
+       tasklet_schedule(&host->card_tasklet);
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit sdhci_probe(struct platform_device *pdev)
+{
+       struct sdhci_host *host;
+       struct resource *iomem;
+       struct spear_sdhci *sdhci;
+       int ret;
+
+       BUG_ON(pdev == NULL);
+
+       iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!iomem) {
+               ret = -ENOMEM;
+               dev_dbg(&pdev->dev, "memory resource not defined\n");
+               goto err;
+       }
+
+       if (!request_mem_region(iomem->start, resource_size(iomem),
+                               "spear-sdhci")) {
+               ret = -EBUSY;
+               dev_dbg(&pdev->dev, "cannot request region\n");
+               goto err;
+       }
+
+       sdhci = kzalloc(sizeof(*sdhci), GFP_KERNEL);
+       if (!sdhci) {
+               ret = -ENOMEM;
+               dev_dbg(&pdev->dev, "cannot allocate memory for sdhci\n");
+               goto err_kzalloc;
+       }
+
+       /* clk enable */
+       sdhci->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(sdhci->clk)) {
+               ret = PTR_ERR(sdhci->clk);
+               dev_dbg(&pdev->dev, "Error getting clock\n");
+               goto err_clk_get;
+       }
+
+       ret = clk_enable(sdhci->clk);
+       if (ret) {
+               dev_dbg(&pdev->dev, "Error enabling clock\n");
+               goto err_clk_enb;
+       }
+
+       /* overwrite platform_data */
+       sdhci->data = dev_get_platdata(&pdev->dev);
+       pdev->dev.platform_data = sdhci;
+
+       if (pdev->dev.parent)
+               host = sdhci_alloc_host(pdev->dev.parent, 0);
+       else
+               host = sdhci_alloc_host(&pdev->dev, 0);
+
+       if (IS_ERR(host)) {
+               ret = PTR_ERR(host);
+               dev_dbg(&pdev->dev, "error allocating host\n");
+               goto err_alloc_host;
+       }
+
+       host->hw_name = "sdhci";
+       host->ops = &sdhci_pltfm_ops;
+       host->irq = platform_get_irq(pdev, 0);
+       host->quirks = SDHCI_QUIRK_BROKEN_ADMA;
+
+       host->ioaddr = ioremap(iomem->start, resource_size(iomem));
+       if (!host->ioaddr) {
+               ret = -ENOMEM;
+               dev_dbg(&pdev->dev, "failed to remap registers\n");
+               goto err_ioremap;
+       }
+
+       ret = sdhci_add_host(host);
+       if (ret) {
+               dev_dbg(&pdev->dev, "error adding host\n");
+               goto err_add_host;
+       }
+
+       platform_set_drvdata(pdev, host);
+
+       /*
+        * It is optional to use GPIOs for sdhci Power control & sdhci card
+        * interrupt detection. If sdhci->data is NULL, then use original sdhci
+        * lines otherwise GPIO lines.
+        * If GPIO is selected for power control, then power should be disabled
+        * after card removal and should be enabled when card insertion
+        * interrupt occurs
+        */
+       if (!sdhci->data)
+               return 0;
+
+       if (sdhci->data->card_power_gpio >= 0) {
+               int val = 0;
+
+               ret = gpio_request(sdhci->data->card_power_gpio, "sdhci");
+               if (ret < 0) {
+                       dev_dbg(&pdev->dev, "gpio request fail: %d\n",
+                                       sdhci->data->card_power_gpio);
+                       goto err_pgpio_request;
+               }
+
+               if (sdhci->data->power_always_enb)
+                       val = sdhci->data->power_active_high;
+               else
+                       val = !sdhci->data->power_active_high;
+
+               ret = gpio_direction_output(sdhci->data->card_power_gpio, val);
+               if (ret) {
+                       dev_dbg(&pdev->dev, "gpio set direction fail: %d\n",
+                                       sdhci->data->card_power_gpio);
+                       goto err_pgpio_direction;
+               }
+
+               gpio_set_value(sdhci->data->card_power_gpio, 1);
+       }
+
+       if (sdhci->data->card_int_gpio >= 0) {
+               ret = gpio_request(sdhci->data->card_int_gpio, "sdhci");
+               if (ret < 0) {
+                       dev_dbg(&pdev->dev, "gpio request fail: %d\n",
+                                       sdhci->data->card_int_gpio);
+                       goto err_igpio_request;
+               }
+
+               ret = gpio_direction_input(sdhci->data->card_int_gpio);
+               if (ret) {
+                       dev_dbg(&pdev->dev, "gpio set direction fail: %d\n",
+                                       sdhci->data->card_int_gpio);
+                       goto err_igpio_direction;
+               }
+               ret = request_irq(gpio_to_irq(sdhci->data->card_int_gpio),
+                               sdhci_gpio_irq, IRQF_TRIGGER_LOW,
+                               mmc_hostname(host->mmc), pdev);
+               if (ret) {
+                       dev_dbg(&pdev->dev, "gpio request irq fail: %d\n",
+                                       sdhci->data->card_int_gpio);
+                       goto err_igpio_request_irq;
+               }
+
+       }
+
+       return 0;
+
+err_igpio_request_irq:
+err_igpio_direction:
+       if (sdhci->data->card_int_gpio >= 0)
+               gpio_free(sdhci->data->card_int_gpio);
+err_igpio_request:
+err_pgpio_direction:
+       if (sdhci->data->card_power_gpio >= 0)
+               gpio_free(sdhci->data->card_power_gpio);
+err_pgpio_request:
+       platform_set_drvdata(pdev, NULL);
+       sdhci_remove_host(host, 1);
+err_add_host:
+       iounmap(host->ioaddr);
+err_ioremap:
+       sdhci_free_host(host);
+err_alloc_host:
+       clk_disable(sdhci->clk);
+err_clk_enb:
+       clk_put(sdhci->clk);
+err_clk_get:
+       kfree(sdhci);
+err_kzalloc:
+       release_mem_region(iomem->start, resource_size(iomem));
+err:
+       dev_err(&pdev->dev, "spear-sdhci probe failed: %d\n", ret);
+       return ret;
+}
+
+static int __devexit sdhci_remove(struct platform_device *pdev)
+{
+       struct sdhci_host *host = platform_get_drvdata(pdev);
+       struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       struct spear_sdhci *sdhci = dev_get_platdata(&pdev->dev);
+       int dead;
+       u32 scratch;
+
+       if (sdhci->data) {
+               if (sdhci->data->card_int_gpio >= 0) {
+                       free_irq(gpio_to_irq(sdhci->data->card_int_gpio), pdev);
+                       gpio_free(sdhci->data->card_int_gpio);
+               }
+
+               if (sdhci->data->card_power_gpio >= 0)
+                       gpio_free(sdhci->data->card_power_gpio);
+       }
+
+       platform_set_drvdata(pdev, NULL);
+       dead = 0;
+       scratch = readl(host->ioaddr + SDHCI_INT_STATUS);
+       if (scratch == (u32)-1)
+               dead = 1;
+
+       sdhci_remove_host(host, dead);
+       iounmap(host->ioaddr);
+       sdhci_free_host(host);
+       clk_disable(sdhci->clk);
+       clk_put(sdhci->clk);
+       kfree(sdhci);
+       if (iomem)
+               release_mem_region(iomem->start, resource_size(iomem));
+
+       return 0;
+}
+
+static struct platform_driver sdhci_driver = {
+       .driver = {
+               .name   = "sdhci",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = sdhci_probe,
+       .remove         = __devexit_p(sdhci_remove),
+};
+
+static int __init sdhci_init(void)
+{
+       return platform_driver_register(&sdhci_driver);
+}
+module_init(sdhci_init);
+
+static void __exit sdhci_exit(void)
+{
+       platform_driver_unregister(&sdhci_driver);
+}
+module_exit(sdhci_exit);
+
+MODULE_DESCRIPTION("SPEAr Secure Digital Host Controller Interface driver");
+MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>");
+MODULE_LICENSE("GPL v2");
index 9d4fdfa685e57521a711c29904c100a66df4cd48..c6d1bd8d4ac43d917e2772f2242dcdea03aa6040 100644 (file)
@@ -496,12 +496,22 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
                WARN_ON((desc - host->adma_desc) > (128 * 2 + 1) * 4);
        }
 
-       /*
-        * Add a terminating entry.
-        */
+       if (host->quirks & SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC) {
+               /*
+               * Mark the last descriptor as the terminating descriptor
+               */
+               if (desc != host->adma_desc) {
+                       desc -= 8;
+                       desc[0] |= 0x2; /* end */
+               }
+       } else {
+               /*
+               * Add a terminating entry.
+               */
 
-       /* nop, end, valid */
-       sdhci_set_adma_desc(desc, 0, 0, 0x3);
+               /* nop, end, valid */
+               sdhci_set_adma_desc(desc, 0, 0, 0x3);
+       }
 
        /*
         * Resync align buffer as we might have changed it.
@@ -1587,7 +1597,7 @@ int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state)
 
        sdhci_disable_card_detection(host);
 
-       ret = mmc_suspend_host(host->mmc, state);
+       ret = mmc_suspend_host(host->mmc);
        if (ret)
                return ret;
 
@@ -1744,7 +1754,8 @@ int sdhci_add_host(struct sdhci_host *host)
        host->max_clk =
                (caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT;
        host->max_clk *= 1000000;
-       if (host->max_clk == 0) {
+       if (host->max_clk == 0 || host->quirks &
+                       SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN) {
                if (!host->ops->get_max_clock) {
                        printk(KERN_ERR
                               "%s: Hardware doesn't specify base clock "
index 842f46f9428469657679e45c1b5b1dc8097c694f..c8468134adc95db0dbfd5ec901ebf96930c22b84 100644 (file)
 #define  SDHCI_INT_DATA_MASK   (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \
                SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \
                SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \
-               SDHCI_INT_DATA_END_BIT | SDHCI_ADMA_ERROR)
+               SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR)
 #define SDHCI_INT_ALL_MASK     ((unsigned int)-1)
 
 #define SDHCI_ACMD12_ERR       0x3C
@@ -236,6 +236,10 @@ struct sdhci_host {
 #define SDHCI_QUIRK_DELAY_AFTER_POWER                  (1<<23)
 /* Controller uses SDCLK instead of TMCLK for data timeouts */
 #define SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK            (1<<24)
+/* Controller reports wrong base clock capability */
+#define SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN              (1<<25)
+/* Controller cannot support End Attribute in NOP ADMA descriptor */
+#define SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC              (1<<26)
 
        int                     irq;            /* Device IRQ */
        void __iomem *          ioaddr;         /* Mapped address */
@@ -294,12 +298,12 @@ struct sdhci_host {
 
 struct sdhci_ops {
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
-       u32             (*readl)(struct sdhci_host *host, int reg);
-       u16             (*readw)(struct sdhci_host *host, int reg);
-       u8              (*readb)(struct sdhci_host *host, int reg);
-       void            (*writel)(struct sdhci_host *host, u32 val, int reg);
-       void            (*writew)(struct sdhci_host *host, u16 val, int reg);
-       void            (*writeb)(struct sdhci_host *host, u8 val, int reg);
+       u32             (*read_l)(struct sdhci_host *host, int reg);
+       u16             (*read_w)(struct sdhci_host *host, int reg);
+       u8              (*read_b)(struct sdhci_host *host, int reg);
+       void            (*write_l)(struct sdhci_host *host, u32 val, int reg);
+       void            (*write_w)(struct sdhci_host *host, u16 val, int reg);
+       void            (*write_b)(struct sdhci_host *host, u8 val, int reg);
 #endif
 
        void    (*set_clock)(struct sdhci_host *host, unsigned int clock);
@@ -314,48 +318,48 @@ struct sdhci_ops {
 
 static inline void sdhci_writel(struct sdhci_host *host, u32 val, int reg)
 {
-       if (unlikely(host->ops->writel))
-               host->ops->writel(host, val, reg);
+       if (unlikely(host->ops->write_l))
+               host->ops->write_l(host, val, reg);
        else
                writel(val, host->ioaddr + reg);
 }
 
 static inline void sdhci_writew(struct sdhci_host *host, u16 val, int reg)
 {
-       if (unlikely(host->ops->writew))
-               host->ops->writew(host, val, reg);
+       if (unlikely(host->ops->write_w))
+               host->ops->write_w(host, val, reg);
        else
                writew(val, host->ioaddr + reg);
 }
 
 static inline void sdhci_writeb(struct sdhci_host *host, u8 val, int reg)
 {
-       if (unlikely(host->ops->writeb))
-               host->ops->writeb(host, val, reg);
+       if (unlikely(host->ops->write_b))
+               host->ops->write_b(host, val, reg);
        else
                writeb(val, host->ioaddr + reg);
 }
 
 static inline u32 sdhci_readl(struct sdhci_host *host, int reg)
 {
-       if (unlikely(host->ops->readl))
-               return host->ops->readl(host, reg);
+       if (unlikely(host->ops->read_l))
+               return host->ops->read_l(host, reg);
        else
                return readl(host->ioaddr + reg);
 }
 
 static inline u16 sdhci_readw(struct sdhci_host *host, int reg)
 {
-       if (unlikely(host->ops->readw))
-               return host->ops->readw(host, reg);
+       if (unlikely(host->ops->read_w))
+               return host->ops->read_w(host, reg);
        else
                return readw(host->ioaddr + reg);
 }
 
 static inline u8 sdhci_readb(struct sdhci_host *host, int reg)
 {
-       if (unlikely(host->ops->readb))
-               return host->ops->readb(host, reg);
+       if (unlikely(host->ops->read_b))
+               return host->ops->read_b(host, reg);
        else
                return readb(host->ioaddr + reg);
 }
index cb41e9c3ac07cce58a2d96c00bff6cda57ec5c55..e7507af3856e24c9cfef86443e6f5a2cc30ac47c 100644 (file)
@@ -519,7 +519,7 @@ static int sdricoh_pcmcia_suspend(struct pcmcia_device *link)
 {
        struct mmc_host *mmc = link->priv;
        dev_dbg(&link->dev, "suspend\n");
-       mmc_suspend_host(mmc, PMSG_SUSPEND);
+       mmc_suspend_host(mmc);
        return 0;
 }
 
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
new file mode 100644 (file)
index 0000000..eb97830
--- /dev/null
@@ -0,0 +1,965 @@
+/*
+ * MMCIF eMMC driver.
+ *
+ * Copyright (C) 2010 Renesas Solutions Corp.
+ * Yusuke Goda <yusuke.goda.sx@renesas.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.
+ *
+ *
+ * TODO
+ *  1. DMA
+ *  2. Power management
+ *  3. Handle MMC errors better
+ *
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/core.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sdio.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/mmc/sh_mmcif.h>
+
+#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))
+#define CMD_SET_RTYP_6B                ((0 << 23) | (1 << 22)) /* R1/R1b/R3/R4/R5 */
+#define CMD_SET_RTYP_17B       ((1 << 23) | (0 << 22)) /* R2 */
+#define CMD_SET_RBSY           (1 << 21) /* R1b */
+#define CMD_SET_CCSEN          (1 << 20)
+#define CMD_SET_WDAT           (1 << 19) /* 1: on data, 0: no data */
+#define CMD_SET_DWEN           (1 << 18) /* 1: write, 0: read */
+#define CMD_SET_CMLTE          (1 << 17) /* 1: multi block trans, 0: single */
+#define CMD_SET_CMD12EN                (1 << 16) /* 1: CMD12 auto issue */
+#define CMD_SET_RIDXC_INDEX    ((0 << 15) | (0 << 14)) /* index check */
+#define CMD_SET_RIDXC_BITS     ((0 << 15) | (1 << 14)) /* check bits check */
+#define CMD_SET_RIDXC_NO       ((1 << 15) | (0 << 14)) /* no check */
+#define CMD_SET_CRC7C          ((0 << 13) | (0 << 12)) /* CRC7 check*/
+#define CMD_SET_CRC7C_BITS     ((0 << 13) | (1 << 12)) /* check bits check*/
+#define CMD_SET_CRC7C_INTERNAL ((1 << 13) | (0 << 12)) /* internal CRC7 check*/
+#define CMD_SET_CRC16C         (1 << 10) /* 0: CRC16 check*/
+#define CMD_SET_CRCSTE         (1 << 8) /* 1: not receive CRC status */
+#define CMD_SET_TBIT           (1 << 7) /* 1: tran mission bit "Low" */
+#define CMD_SET_OPDM           (1 << 6) /* 1: open/drain */
+#define CMD_SET_CCSH           (1 << 5)
+#define CMD_SET_DATW_1         ((0 << 1) | (0 << 0)) /* 1bit */
+#define CMD_SET_DATW_4         ((0 << 1) | (1 << 0)) /* 4bit */
+#define CMD_SET_DATW_8         ((1 << 1) | (0 << 0)) /* 8bit */
+
+/* CE_CMD_CTRL */
+#define CMD_CTRL_BREAK         (1 << 0)
+
+/* CE_BLOCK_SET */
+#define BLOCK_SIZE_MASK                0x0000ffff
+
+/* CE_CLK_CTRL */
+#define CLK_ENABLE             (1 << 24) /* 1: output mmc clock */
+#define CLK_CLEAR              ((1 << 19) | (1 << 18) | (1 << 17) | (1 << 16))
+#define CLK_SUP_PCLK           ((1 << 19) | (1 << 18) | (1 << 17) | (1 << 16))
+#define SRSPTO_256             ((1 << 13) | (0 << 12)) /* resp timeout */
+#define SRBSYTO_29             ((1 << 11) | (1 << 10) |        \
+                                (1 << 9) | (1 << 8)) /* resp busy timeout */
+#define SRWDTO_29              ((1 << 7) | (1 << 6) |          \
+                                (1 << 5) | (1 << 4)) /* read/write timeout */
+#define SCCSTO_29              ((1 << 3) | (1 << 2) |          \
+                                (1 << 1) | (1 << 0)) /* ccs timeout */
+
+/* CE_BUF_ACC */
+#define BUF_ACC_DMAWEN         (1 << 25)
+#define BUF_ACC_DMAREN         (1 << 24)
+#define BUF_ACC_BUSW_32                (0 << 17)
+#define BUF_ACC_BUSW_16                (1 << 17)
+#define BUF_ACC_ATYP           (1 << 16)
+
+/* CE_INT */
+#define INT_CCSDE              (1 << 29)
+#define INT_CMD12DRE           (1 << 26)
+#define INT_CMD12RBE           (1 << 25)
+#define INT_CMD12CRE           (1 << 24)
+#define INT_DTRANE             (1 << 23)
+#define INT_BUFRE              (1 << 22)
+#define INT_BUFWEN             (1 << 21)
+#define INT_BUFREN             (1 << 20)
+#define INT_CCSRCV             (1 << 19)
+#define INT_RBSYE              (1 << 17)
+#define INT_CRSPE              (1 << 16)
+#define INT_CMDVIO             (1 << 15)
+#define INT_BUFVIO             (1 << 14)
+#define INT_WDATERR            (1 << 11)
+#define INT_RDATERR            (1 << 10)
+#define INT_RIDXERR            (1 << 9)
+#define INT_RSPERR             (1 << 8)
+#define INT_CCSTO              (1 << 5)
+#define INT_CRCSTO             (1 << 4)
+#define INT_WDATTO             (1 << 3)
+#define INT_RDATTO             (1 << 2)
+#define INT_RBSYTO             (1 << 1)
+#define INT_RSPTO              (1 << 0)
+#define INT_ERR_STS            (INT_CMDVIO | INT_BUFVIO | INT_WDATERR |  \
+                                INT_RDATERR | INT_RIDXERR | INT_RSPERR | \
+                                INT_CCSTO | INT_CRCSTO | INT_WDATTO |    \
+                                INT_RDATTO | INT_RBSYTO | INT_RSPTO)
+
+/* CE_INT_MASK */
+#define MASK_ALL               0x00000000
+#define MASK_MCCSDE            (1 << 29)
+#define MASK_MCMD12DRE         (1 << 26)
+#define MASK_MCMD12RBE         (1 << 25)
+#define MASK_MCMD12CRE         (1 << 24)
+#define MASK_MDTRANE           (1 << 23)
+#define MASK_MBUFRE            (1 << 22)
+#define MASK_MBUFWEN           (1 << 21)
+#define MASK_MBUFREN           (1 << 20)
+#define MASK_MCCSRCV           (1 << 19)
+#define MASK_MRBSYE            (1 << 17)
+#define MASK_MCRSPE            (1 << 16)
+#define MASK_MCMDVIO           (1 << 15)
+#define MASK_MBUFVIO           (1 << 14)
+#define MASK_MWDATERR          (1 << 11)
+#define MASK_MRDATERR          (1 << 10)
+#define MASK_MRIDXERR          (1 << 9)
+#define MASK_MRSPERR           (1 << 8)
+#define MASK_MCCSTO            (1 << 5)
+#define MASK_MCRCSTO           (1 << 4)
+#define MASK_MWDATTO           (1 << 3)
+#define MASK_MRDATTO           (1 << 2)
+#define MASK_MRBSYTO           (1 << 1)
+#define MASK_MRSPTO            (1 << 0)
+
+/* CE_HOST_STS1 */
+#define STS1_CMDSEQ            (1 << 31)
+
+/* CE_HOST_STS2 */
+#define STS2_CRCSTE            (1 << 31)
+#define STS2_CRC16E            (1 << 30)
+#define STS2_AC12CRCE          (1 << 29)
+#define STS2_RSPCRC7E          (1 << 28)
+#define STS2_CRCSTEBE          (1 << 27)
+#define STS2_RDATEBE           (1 << 26)
+#define STS2_AC12REBE          (1 << 25)
+#define STS2_RSPEBE            (1 << 24)
+#define STS2_AC12IDXE          (1 << 23)
+#define STS2_RSPIDXE           (1 << 22)
+#define STS2_CCSTO             (1 << 15)
+#define STS2_RDATTO            (1 << 14)
+#define STS2_DATBSYTO          (1 << 13)
+#define STS2_CRCSTTO           (1 << 12)
+#define STS2_AC12BSYTO         (1 << 11)
+#define STS2_RSPBSYTO          (1 << 10)
+#define STS2_AC12RSPTO         (1 << 9)
+#define STS2_RSPTO             (1 << 8)
+#define STS2_CRC_ERR           (STS2_CRCSTE | STS2_CRC16E |            \
+                                STS2_AC12CRCE | STS2_RSPCRC7E | STS2_CRCSTEBE)
+#define STS2_TIMEOUT_ERR       (STS2_CCSTO | STS2_RDATTO |             \
+                                STS2_DATBSYTO | STS2_CRCSTTO |         \
+                                STS2_AC12BSYTO | STS2_RSPBSYTO |       \
+                                STS2_AC12RSPTO | STS2_RSPTO)
+
+/* CE_VERSION */
+#define SOFT_RST_ON            (1 << 31)
+#define SOFT_RST_OFF           (0 << 31)
+
+#define CLKDEV_EMMC_DATA       52000000 /* 52MHz */
+#define CLKDEV_MMC_DATA                20000000 /* 20MHz */
+#define CLKDEV_INIT            400000   /* 400 KHz */
+
+struct sh_mmcif_host {
+       struct mmc_host *mmc;
+       struct mmc_data *data;
+       struct mmc_command *cmd;
+       struct platform_device *pd;
+       struct clk *hclk;
+       unsigned int clk;
+       int bus_width;
+       u16 wait_int;
+       u16 sd_error;
+       long timeout;
+       void __iomem *addr;
+       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);
+}
+
+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);
+}
+
+
+static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk)
+{
+       struct sh_mmcif_plat_data *p = host->pd->dev.platform_data;
+
+       sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE);
+       sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR);
+
+       if (!clk)
+               return;
+       if (p->sup_pclk && clk == host->clk)
+               sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_SUP_PCLK);
+       else
+               sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR &
+                       (ilog2(__rounddown_pow_of_two(host->clk / clk)) << 16));
+
+       sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE);
+}
+
+static void sh_mmcif_sync_reset(struct sh_mmcif_host *host)
+{
+       u32 tmp;
+
+       tmp = 0x010f0000 & sh_mmcif_readl(host, 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_bitset(host, MMCIF_CE_CLK_CTRL, tmp |
+               SRSPTO_256 | SRBSYTO_29 | SRWDTO_29 | SCCSTO_29);
+       /* byte swap on */
+       sh_mmcif_bitset(host, MMCIF_CE_BUF_ACC, BUF_ACC_ATYP);
+}
+
+static int sh_mmcif_error_manage(struct sh_mmcif_host *host)
+{
+       u32 state1, state2;
+       int ret, timeout = 10000000;
+
+       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));
+
+       if (state1 & STS1_CMDSEQ) {
+               sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, CMD_CTRL_BREAK);
+               sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, ~CMD_CTRL_BREAK);
+               while (1) {
+                       timeout--;
+                       if (timeout < 0) {
+                               pr_err(DRIVER_NAME": Forceed end of " \
+                                       "command sequence timeout err\n");
+                               return -EIO;
+                       }
+                       if (!(sh_mmcif_readl(host, MMCIF_CE_HOST_STS1)
+                                                               & STS1_CMDSEQ))
+                               break;
+                       mdelay(1);
+               }
+               sh_mmcif_sync_reset(host);
+               pr_debug(DRIVER_NAME": Forced end of command sequence\n");
+               return -EIO;
+       }
+
+       if (state2 & STS2_CRC_ERR) {
+               pr_debug(DRIVER_NAME": Happened CRC error\n");
+               ret = -EIO;
+       } else if (state2 & STS2_TIMEOUT_ERR) {
+               pr_debug(DRIVER_NAME": Happened Timeout error\n");
+               ret = -ETIMEDOUT;
+       } else {
+               pr_debug(DRIVER_NAME": Happened End/Index error\n");
+               ret = -EIO;
+       }
+       return ret;
+}
+
+static int sh_mmcif_single_read(struct sh_mmcif_host *host,
+                                       struct mmc_request *mrq)
+{
+       struct mmc_data *data = mrq->data;
+       long time;
+       u32 blocksize, i, *p = sg_virt(data->sg);
+
+       host->wait_int = 0;
+
+       /* buf read enable */
+       sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
+       time = wait_event_interruptible_timeout(host->intr_wait,
+                       host->wait_int == 1 ||
+                       host->sd_error == 1, host->timeout);
+       if (host->wait_int != 1 && (time == 0 || host->sd_error != 0))
+               return sh_mmcif_error_manage(host);
+
+       host->wait_int = 0;
+       blocksize = (BLOCK_SIZE_MASK &
+                       sh_mmcif_readl(host, MMCIF_CE_BLOCK_SET)) + 3;
+       for (i = 0; i < blocksize / 4; i++)
+               *p++ = sh_mmcif_readl(host, MMCIF_CE_DATA);
+
+       /* buffer read end */
+       sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFRE);
+       time = wait_event_interruptible_timeout(host->intr_wait,
+                       host->wait_int == 1 ||
+                       host->sd_error == 1, host->timeout);
+       if (host->wait_int != 1 && (time == 0 || host->sd_error != 0))
+               return sh_mmcif_error_manage(host);
+
+       host->wait_int = 0;
+       return 0;
+}
+
+static int sh_mmcif_multi_read(struct sh_mmcif_host *host,
+                                       struct mmc_request *mrq)
+{
+       struct mmc_data *data = mrq->data;
+       long time;
+       u32 blocksize, i, j, sec, *p;
+
+       blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host, MMCIF_CE_BLOCK_SET);
+       for (j = 0; j < data->sg_len; j++) {
+               p = sg_virt(data->sg);
+               host->wait_int = 0;
+               for (sec = 0; sec < data->sg->length / blocksize; sec++) {
+                       sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
+                       /* buf read enable */
+                       time = wait_event_interruptible_timeout(host->intr_wait,
+                               host->wait_int == 1 ||
+                               host->sd_error == 1, host->timeout);
+
+                       if (host->wait_int != 1 &&
+                           (time == 0 || host->sd_error != 0))
+                               return sh_mmcif_error_manage(host);
+
+                       host->wait_int = 0;
+                       for (i = 0; i < blocksize / 4; i++)
+                               *p++ = sh_mmcif_readl(host, MMCIF_CE_DATA);
+               }
+               if (j < data->sg_len - 1)
+                       data->sg++;
+       }
+       return 0;
+}
+
+static int sh_mmcif_single_write(struct sh_mmcif_host *host,
+                                       struct mmc_request *mrq)
+{
+       struct mmc_data *data = mrq->data;
+       long time;
+       u32 blocksize, i, *p = sg_virt(data->sg);
+
+       host->wait_int = 0;
+       sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
+
+       /* buf write enable */
+       time = wait_event_interruptible_timeout(host->intr_wait,
+                       host->wait_int == 1 ||
+                       host->sd_error == 1, host->timeout);
+       if (host->wait_int != 1 && (time == 0 || host->sd_error != 0))
+               return sh_mmcif_error_manage(host);
+
+       host->wait_int = 0;
+       blocksize = (BLOCK_SIZE_MASK &
+                       sh_mmcif_readl(host, MMCIF_CE_BLOCK_SET)) + 3;
+       for (i = 0; i < blocksize / 4; i++)
+               sh_mmcif_writel(host, MMCIF_CE_DATA, *p++);
+
+       /* buffer write end */
+       sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MDTRANE);
+
+       time = wait_event_interruptible_timeout(host->intr_wait,
+                       host->wait_int == 1 ||
+                       host->sd_error == 1, host->timeout);
+       if (host->wait_int != 1 && (time == 0 || host->sd_error != 0))
+               return sh_mmcif_error_manage(host);
+
+       host->wait_int = 0;
+       return 0;
+}
+
+static int sh_mmcif_multi_write(struct sh_mmcif_host *host,
+                                               struct mmc_request *mrq)
+{
+       struct mmc_data *data = mrq->data;
+       long time;
+       u32 i, sec, j, blocksize, *p;
+
+       blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host, MMCIF_CE_BLOCK_SET);
+
+       for (j = 0; j < data->sg_len; j++) {
+               p = sg_virt(data->sg);
+               host->wait_int = 0;
+               for (sec = 0; sec < data->sg->length / blocksize; sec++) {
+                       sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
+                       /* buf write enable*/
+                       time = wait_event_interruptible_timeout(host->intr_wait,
+                               host->wait_int == 1 ||
+                               host->sd_error == 1, host->timeout);
+
+                       if (host->wait_int != 1 &&
+                           (time == 0 || host->sd_error != 0))
+                               return sh_mmcif_error_manage(host);
+
+                       host->wait_int = 0;
+                       for (i = 0; i < blocksize / 4; i++)
+                               sh_mmcif_writel(host, MMCIF_CE_DATA, *p++);
+               }
+               if (j < data->sg_len - 1)
+                       data->sg++;
+       }
+       return 0;
+}
+
+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);
+       } else
+               cmd->resp[0] = sh_mmcif_readl(host, 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);
+}
+
+static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
+               struct mmc_request *mrq, struct mmc_command *cmd, u32 opc)
+{
+       u32 tmp = 0;
+
+       /* Response Type check */
+       switch (mmc_resp_type(cmd)) {
+       case MMC_RSP_NONE:
+               tmp |= CMD_SET_RTYP_NO;
+               break;
+       case MMC_RSP_R1:
+       case MMC_RSP_R1B:
+       case MMC_RSP_R3:
+               tmp |= CMD_SET_RTYP_6B;
+               break;
+       case MMC_RSP_R2:
+               tmp |= CMD_SET_RTYP_17B;
+               break;
+       default:
+               pr_err(DRIVER_NAME": Not support type response.\n");
+               break;
+       }
+       switch (opc) {
+       /* RBSY */
+       case MMC_SWITCH:
+       case MMC_STOP_TRANSMISSION:
+       case MMC_SET_WRITE_PROT:
+       case MMC_CLR_WRITE_PROT:
+       case MMC_ERASE:
+       case MMC_GEN_CMD:
+               tmp |= CMD_SET_RBSY;
+               break;
+       }
+       /* WDAT / DATW */
+       if (host->data) {
+               tmp |= CMD_SET_WDAT;
+               switch (host->bus_width) {
+               case MMC_BUS_WIDTH_1:
+                       tmp |= CMD_SET_DATW_1;
+                       break;
+               case MMC_BUS_WIDTH_4:
+                       tmp |= CMD_SET_DATW_4;
+                       break;
+               case MMC_BUS_WIDTH_8:
+                       tmp |= CMD_SET_DATW_8;
+                       break;
+               default:
+                       pr_err(DRIVER_NAME": Not support bus width.\n");
+                       break;
+               }
+       }
+       /* DWEN */
+       if (opc == MMC_WRITE_BLOCK || opc == MMC_WRITE_MULTIPLE_BLOCK)
+               tmp |= CMD_SET_DWEN;
+       /* CMLTE/CMD12EN */
+       if (opc == MMC_READ_MULTIPLE_BLOCK || opc == MMC_WRITE_MULTIPLE_BLOCK) {
+               tmp |= CMD_SET_CMLTE | CMD_SET_CMD12EN;
+               sh_mmcif_bitset(host, MMCIF_CE_BLOCK_SET,
+                                       mrq->data->blocks << 16);
+       }
+       /* RIDXC[1:0] check bits */
+       if (opc == MMC_SEND_OP_COND || opc == MMC_ALL_SEND_CID ||
+           opc == MMC_SEND_CSD || opc == MMC_SEND_CID)
+               tmp |= CMD_SET_RIDXC_BITS;
+       /* RCRC7C[1:0] check bits */
+       if (opc == MMC_SEND_OP_COND)
+               tmp |= CMD_SET_CRC7C_BITS;
+       /* RCRC7C[1:0] internal CRC7 */
+       if (opc == MMC_ALL_SEND_CID ||
+               opc == MMC_SEND_CSD || opc == MMC_SEND_CID)
+               tmp |= CMD_SET_CRC7C_INTERNAL;
+
+       return opc = ((opc << 24) | tmp);
+}
+
+static u32 sh_mmcif_data_trans(struct sh_mmcif_host *host,
+                               struct mmc_request *mrq, u32 opc)
+{
+       u32 ret;
+
+       switch (opc) {
+       case MMC_READ_MULTIPLE_BLOCK:
+               ret = sh_mmcif_multi_read(host, mrq);
+               break;
+       case MMC_WRITE_MULTIPLE_BLOCK:
+               ret = sh_mmcif_multi_write(host, mrq);
+               break;
+       case MMC_WRITE_BLOCK:
+               ret = sh_mmcif_single_write(host, mrq);
+               break;
+       case MMC_READ_SINGLE_BLOCK:
+       case MMC_SEND_EXT_CSD:
+               ret = sh_mmcif_single_read(host, mrq);
+               break;
+       default:
+               pr_err(DRIVER_NAME": NOT SUPPORT CMD = d'%08d\n", opc);
+               ret = -EINVAL;
+               break;
+       }
+       return ret;
+}
+
+static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
+                       struct mmc_request *mrq, struct mmc_command *cmd)
+{
+       long time;
+       int ret = 0, mask = 0;
+       u32 opc = cmd->opcode;
+
+       host->cmd = cmd;
+
+       switch (opc) {
+       /* respons busy check */
+       case MMC_SWITCH:
+       case MMC_STOP_TRANSMISSION:
+       case MMC_SET_WRITE_PROT:
+       case MMC_CLR_WRITE_PROT:
+       case MMC_ERASE:
+       case MMC_GEN_CMD:
+               mask = MASK_MRBSYE;
+               break;
+       default:
+               mask = MASK_MCRSPE;
+               break;
+       }
+       mask |= MASK_MCMDVIO | MASK_MBUFVIO | MASK_MWDATERR |
+               MASK_MRDATERR | MASK_MRIDXERR | MASK_MRSPERR |
+               MASK_MCCSTO | MASK_MCRCSTO | MASK_MWDATTO |
+               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);
+       }
+       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);
+       /* set arg */
+       sh_mmcif_writel(host, MMCIF_CE_ARG, cmd->arg);
+       host->wait_int = 0;
+       /* set cmd */
+       sh_mmcif_writel(host, MMCIF_CE_CMD_SET, opc);
+
+       time = wait_event_interruptible_timeout(host->intr_wait,
+               host->wait_int == 1 || host->sd_error == 1, host->timeout);
+       if (host->wait_int != 1 && time == 0) {
+               cmd->error = sh_mmcif_error_manage(host);
+               return;
+       }
+       if (host->sd_error) {
+               switch (cmd->opcode) {
+               case MMC_ALL_SEND_CID:
+               case MMC_SELECT_CARD:
+               case MMC_APP_CMD:
+                       cmd->error = -ETIMEDOUT;
+                       break;
+               default:
+                       pr_debug("%s: Cmd(d'%d) err\n",
+                                       DRIVER_NAME, cmd->opcode);
+                       cmd->error = sh_mmcif_error_manage(host);
+                       break;
+               }
+               host->sd_error = 0;
+               host->wait_int = 0;
+               return;
+       }
+       if (!(cmd->flags & MMC_RSP_PRESENT)) {
+               cmd->error = ret;
+               host->wait_int = 0;
+               return;
+       }
+       if (host->wait_int == 1) {
+               sh_mmcif_get_response(host, cmd);
+               host->wait_int = 0;
+       }
+       if (host->data) {
+               ret = sh_mmcif_data_trans(host, mrq, cmd->opcode);
+               if (ret < 0)
+                       mrq->data->bytes_xfered = 0;
+               else
+                       mrq->data->bytes_xfered =
+                               mrq->data->blocks * mrq->data->blksz;
+       }
+       cmd->error = ret;
+}
+
+static void sh_mmcif_stop_cmd(struct sh_mmcif_host *host,
+               struct mmc_request *mrq, struct mmc_command *cmd)
+{
+       long time;
+
+       if (mrq->cmd->opcode == MMC_READ_MULTIPLE_BLOCK)
+               sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12DRE);
+       else if (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK)
+               sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE);
+       else {
+               pr_err(DRIVER_NAME": not support stop cmd\n");
+               cmd->error = sh_mmcif_error_manage(host);
+               return;
+       }
+
+       time = wait_event_interruptible_timeout(host->intr_wait,
+                       host->wait_int == 1 ||
+                       host->sd_error == 1, host->timeout);
+       if (host->wait_int != 1 && (time == 0 || host->sd_error != 0)) {
+               cmd->error = sh_mmcif_error_manage(host);
+               return;
+       }
+       sh_mmcif_get_cmd12response(host, cmd);
+       host->wait_int = 0;
+       cmd->error = 0;
+}
+
+static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+       struct sh_mmcif_host *host = mmc_priv(mmc);
+
+       switch (mrq->cmd->opcode) {
+       /* MMCIF does not support SD/SDIO command */
+       case SD_IO_SEND_OP_COND:
+       case MMC_APP_CMD:
+               mrq->cmd->error = -ETIMEDOUT;
+               mmc_request_done(mmc, mrq);
+               return;
+       case MMC_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */
+               if (!mrq->data) {
+                       /* send_if_cond cmd (not support) */
+                       mrq->cmd->error = -ETIMEDOUT;
+                       mmc_request_done(mmc, mrq);
+                       return;
+               }
+               break;
+       default:
+               break;
+       }
+       host->data = mrq->data;
+       sh_mmcif_start_cmd(host, mrq, mrq->cmd);
+       host->data = NULL;
+
+       if (mrq->cmd->error != 0) {
+               mmc_request_done(mmc, mrq);
+               return;
+       }
+       if (mrq->stop)
+               sh_mmcif_stop_cmd(host, mrq, mrq->stop);
+       mmc_request_done(mmc, mrq);
+}
+
+static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct sh_mmcif_host *host = mmc_priv(mmc);
+       struct sh_mmcif_plat_data *p = host->pd->dev.platform_data;
+
+       if (ios->power_mode == MMC_POWER_OFF) {
+               /* clock stop */
+               sh_mmcif_clock_control(host, 0);
+               if (p->down_pwr)
+                       p->down_pwr(host->pd);
+               return;
+       } else if (ios->power_mode == MMC_POWER_UP) {
+               if (p->set_pwr)
+                       p->set_pwr(host->pd, ios->power_mode);
+       }
+
+       if (ios->clock)
+               sh_mmcif_clock_control(host, ios->clock);
+
+       host->bus_width = ios->bus_width;
+}
+
+static struct mmc_host_ops sh_mmcif_ops = {
+       .request        = sh_mmcif_request,
+       .set_ios        = sh_mmcif_set_ios,
+};
+
+static void sh_mmcif_detect(struct mmc_host *mmc)
+{
+       mmc_detect_change(mmc, 0);
+}
+
+static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
+{
+       struct sh_mmcif_host *host = dev_id;
+       u32 state = 0;
+       int err = 0;
+
+       state = sh_mmcif_readl(host, MMCIF_CE_INT);
+
+       if (state & INT_RBSYE) {
+               sh_mmcif_writel(host, 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_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCRSPE);
+       } else if (state & INT_BUFREN) {
+               sh_mmcif_writel(host, 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_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
+       } else if (state & INT_CMD12DRE) {
+               sh_mmcif_writel(host, 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_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFRE);
+       } else if (state & INT_DTRANE) {
+               sh_mmcif_writel(host, 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,
+                               ~(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_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_bitclr(host, MMCIF_CE_INT_MASK, state);
+               err = 1;
+       }
+       if (err) {
+               host->sd_error = 1;
+               pr_debug("%s: int err state = %08x\n", DRIVER_NAME, state);
+       }
+       host->wait_int = 1;
+       wake_up(&host->intr_wait);
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit sh_mmcif_probe(struct platform_device *pdev)
+{
+       int ret = 0, irq[2];
+       struct mmc_host *mmc;
+       struct sh_mmcif_host *host = NULL;
+       struct sh_mmcif_plat_data *pd = NULL;
+       struct resource *res;
+       void __iomem *reg;
+       char clk_name[8];
+
+       irq[0] = platform_get_irq(pdev, 0);
+       irq[1] = platform_get_irq(pdev, 1);
+       if (irq[0] < 0 || irq[1] < 0) {
+               pr_err(DRIVER_NAME": Get irq error\n");
+               return -ENXIO;
+       }
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "platform_get_resource error.\n");
+               return -ENXIO;
+       }
+       reg = ioremap(res->start, resource_size(res));
+       if (!reg) {
+               dev_err(&pdev->dev, "ioremap error.\n");
+               return -ENOMEM;
+       }
+       pd = (struct sh_mmcif_plat_data *)(pdev->dev.platform_data);
+       if (!pd) {
+               dev_err(&pdev->dev, "sh_mmcif plat data error.\n");
+               ret = -ENXIO;
+               goto clean_up;
+       }
+       mmc = mmc_alloc_host(sizeof(struct sh_mmcif_host), &pdev->dev);
+       if (!mmc) {
+               ret = -ENOMEM;
+               goto clean_up;
+       }
+       host            = mmc_priv(mmc);
+       host->mmc       = mmc;
+       host->addr      = reg;
+       host->timeout   = 1000;
+
+       snprintf(clk_name, sizeof(clk_name), "mmc%d", pdev->id);
+       host->hclk = clk_get(&pdev->dev, clk_name);
+       if (IS_ERR(host->hclk)) {
+               dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
+               ret = PTR_ERR(host->hclk);
+               goto clean_up1;
+       }
+       clk_enable(host->hclk);
+       host->clk = clk_get_rate(host->hclk);
+       host->pd = pdev;
+
+       init_waitqueue_head(&host->intr_wait);
+
+       mmc->ops = &sh_mmcif_ops;
+       mmc->f_max = host->clk;
+       /* close to 400KHz */
+       if (mmc->f_max < 51200000)
+               mmc->f_min = mmc->f_max / 128;
+       else if (mmc->f_max < 102400000)
+               mmc->f_min = mmc->f_max / 256;
+       else
+               mmc->f_min = mmc->f_max / 512;
+       if (pd->ocr)
+               mmc->ocr_avail = pd->ocr;
+       mmc->caps = MMC_CAP_MMC_HIGHSPEED;
+       if (pd->caps)
+               mmc->caps |= pd->caps;
+       mmc->max_phys_segs = 128;
+       mmc->max_hw_segs = 128;
+       mmc->max_blk_size = 512;
+       mmc->max_blk_count = 65535;
+       mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
+       mmc->max_seg_size = mmc->max_req_size;
+
+       sh_mmcif_sync_reset(host);
+       platform_set_drvdata(pdev, host);
+       mmc_add_host(mmc);
+
+       ret = request_irq(irq[0], sh_mmcif_intr, 0, "sh_mmc:error", host);
+       if (ret) {
+               pr_err(DRIVER_NAME": request_irq error (sh_mmc:error)\n");
+               goto clean_up2;
+       }
+       ret = request_irq(irq[1], sh_mmcif_intr, 0, "sh_mmc:int", host);
+       if (ret) {
+               free_irq(irq[0], host);
+               pr_err(DRIVER_NAME": request_irq error (sh_mmc:int)\n");
+               goto clean_up2;
+       }
+
+       sh_mmcif_writel(host, 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);
+       return ret;
+
+clean_up2:
+       clk_disable(host->hclk);
+clean_up1:
+       mmc_free_host(mmc);
+clean_up:
+       if (reg)
+               iounmap(reg);
+       return ret;
+}
+
+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);
+
+       irq[0] = platform_get_irq(pdev, 0);
+       irq[1] = platform_get_irq(pdev, 1);
+
+       if (host->addr)
+               iounmap(host->addr);
+
+       platform_set_drvdata(pdev, NULL);
+       mmc_remove_host(host->mmc);
+
+       free_irq(irq[0], host);
+       free_irq(irq[1], host);
+
+       clk_disable(host->hclk);
+       mmc_free_host(host->mmc);
+
+       return 0;
+}
+
+static struct platform_driver sh_mmcif_driver = {
+       .probe          = sh_mmcif_probe,
+       .remove         = sh_mmcif_remove,
+       .driver         = {
+               .name   = DRIVER_NAME,
+       },
+};
+
+static int __init sh_mmcif_init(void)
+{
+       return platform_driver_register(&sh_mmcif_driver);
+}
+
+static void __exit sh_mmcif_exit(void)
+{
+       platform_driver_unregister(&sh_mmcif_driver);
+}
+
+module_init(sh_mmcif_init);
+module_exit(sh_mmcif_exit);
+
+
+MODULE_DESCRIPTION("SuperH on-chip MMC/eMMC interface driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS(DRIVER_NAME);
+MODULE_AUTHOR("Yusuke Goda <yusuke.goda.sx@renesas.com>");
index 82554ddec6b3cb6b3d3e0a438fdbc2bceeb3561e..cec99958b65286b3768fb3e5c06e91140909bbf5 100644 (file)
@@ -1032,7 +1032,7 @@ static void tifm_sd_remove(struct tifm_dev *sock)
 
 static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state)
 {
-       return mmc_suspend_host(tifm_get_drvdata(sock), state);
+       return mmc_suspend_host(tifm_get_drvdata(sock));
 }
 
 static int tifm_sd_resume(struct tifm_dev *sock)
index b2b577f6afd402b593a525e34c4bcd6dd5a17be9..ee7d0a5a51c496cb92b04e7b9bc8172f8a233875 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/irq.h>
 #include <linux/device.h>
 #include <linux/delay.h>
+#include <linux/dmaengine.h>
 #include <linux/mmc/host.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/tmio.h>
@@ -131,8 +132,8 @@ tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command *cmd)
 
        host->cmd = cmd;
 
-/* FIXME - this seems to be ok comented out but the spec suggest this bit should
- *         be set when issuing app commands.
+/* FIXME - this seems to be ok commented out but the spec suggest this bit
+ *         should be set when issuing app commands.
  *     if(cmd->flags & MMC_FLAG_ACMD)
  *             c |= APP_CMD;
  */
@@ -155,12 +156,12 @@ tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command *cmd)
        return 0;
 }
 
-/* This chip always returns (at least?) as much data as you ask for.
+/*
+ * This chip always returns (at least?) as much data as you ask for.
  * I'm unsure what happens if you ask for less than a block. This should be
  * looked into to ensure that a funny length read doesnt hose the controller.
- *
  */
-static inline void tmio_mmc_pio_irq(struct tmio_mmc_host *host)
+static void tmio_mmc_pio_irq(struct tmio_mmc_host *host)
 {
        struct mmc_data *data = host->data;
        unsigned short *buf;
@@ -180,7 +181,7 @@ static inline void tmio_mmc_pio_irq(struct tmio_mmc_host *host)
                count = data->blksz;
 
        pr_debug("count: %08x offset: %08x flags %08x\n",
-           count, host->sg_off, data->flags);
+                count, host->sg_off, data->flags);
 
        /* Transfer the data */
        if (data->flags & MMC_DATA_READ)
@@ -198,7 +199,7 @@ static inline void tmio_mmc_pio_irq(struct tmio_mmc_host *host)
        return;
 }
 
-static inline void tmio_mmc_data_irq(struct tmio_mmc_host *host)
+static void tmio_mmc_do_data_irq(struct tmio_mmc_host *host)
 {
        struct mmc_data *data = host->data;
        struct mmc_command *stop;
@@ -206,7 +207,7 @@ static inline void tmio_mmc_data_irq(struct tmio_mmc_host *host)
        host->data = NULL;
 
        if (!data) {
-               pr_debug("Spurious data end IRQ\n");
+               dev_warn(&host->pdev->dev, "Spurious data end IRQ\n");
                return;
        }
        stop = data->stop;
@@ -219,7 +220,8 @@ static inline void tmio_mmc_data_irq(struct tmio_mmc_host *host)
 
        pr_debug("Completed data request\n");
 
-       /*FIXME - other drivers allow an optional stop command of any given type
+       /*
+        * FIXME: other drivers allow an optional stop command of any given type
         *        which we dont do, as the chip can auto generate them.
         *        Perhaps we can be smarter about when to use auto CMD12 and
         *        only issue the auto request when we know this is the desired
@@ -227,10 +229,17 @@ static inline void tmio_mmc_data_irq(struct tmio_mmc_host *host)
         *        upper layers expect. For now, we do what works.
         */
 
-       if (data->flags & MMC_DATA_READ)
-               disable_mmc_irqs(host, TMIO_MASK_READOP);
-       else
-               disable_mmc_irqs(host, TMIO_MASK_WRITEOP);
+       if (data->flags & MMC_DATA_READ) {
+               if (!host->chan_rx)
+                       disable_mmc_irqs(host, TMIO_MASK_READOP);
+               dev_dbg(&host->pdev->dev, "Complete Rx request %p\n",
+                       host->mrq);
+       } else {
+               if (!host->chan_tx)
+                       disable_mmc_irqs(host, TMIO_MASK_WRITEOP);
+               dev_dbg(&host->pdev->dev, "Complete Tx request %p\n",
+                       host->mrq);
+       }
 
        if (stop) {
                if (stop->opcode == 12 && !stop->arg)
@@ -242,7 +251,35 @@ static inline void tmio_mmc_data_irq(struct tmio_mmc_host *host)
        tmio_mmc_finish_request(host);
 }
 
-static inline void tmio_mmc_cmd_irq(struct tmio_mmc_host *host,
+static void tmio_mmc_data_irq(struct tmio_mmc_host *host)
+{
+       struct mmc_data *data = host->data;
+
+       if (!data)
+               return;
+
+       if (host->chan_tx && (data->flags & MMC_DATA_WRITE)) {
+               /*
+                * Has all data been written out yet? Testing on SuperH showed,
+                * that in most cases the first interrupt comes already with the
+                * BUSY status bit clear, but on some operations, like mount or
+                * in the beginning of a write / sync / umount, there is one
+                * DATAEND interrupt with the BUSY bit set, in this cases
+                * waiting for one more interrupt fixes the problem.
+                */
+               if (!(sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_CMD_BUSY)) {
+                       disable_mmc_irqs(host, TMIO_STAT_DATAEND);
+                       tasklet_schedule(&host->dma_complete);
+               }
+       } else if (host->chan_rx && (data->flags & MMC_DATA_READ)) {
+               disable_mmc_irqs(host, TMIO_STAT_DATAEND);
+               tasklet_schedule(&host->dma_complete);
+       } else {
+               tmio_mmc_do_data_irq(host);
+       }
+}
+
+static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host,
        unsigned int stat)
 {
        struct mmc_command *cmd = host->cmd;
@@ -282,10 +319,16 @@ static inline void tmio_mmc_cmd_irq(struct tmio_mmc_host *host,
         * If theres no data or we encountered an error, finish now.
         */
        if (host->data && !cmd->error) {
-               if (host->data->flags & MMC_DATA_READ)
-                       enable_mmc_irqs(host, TMIO_MASK_READOP);
-               else
-                       enable_mmc_irqs(host, TMIO_MASK_WRITEOP);
+               if (host->data->flags & MMC_DATA_READ) {
+                       if (!host->chan_rx)
+                               enable_mmc_irqs(host, TMIO_MASK_READOP);
+               } else {
+                       struct dma_chan *chan = host->chan_tx;
+                       if (!chan)
+                               enable_mmc_irqs(host, TMIO_MASK_WRITEOP);
+                       else
+                               tasklet_schedule(&host->dma_issue);
+               }
        } else {
                tmio_mmc_finish_request(host);
        }
@@ -293,7 +336,6 @@ static inline void tmio_mmc_cmd_irq(struct tmio_mmc_host *host,
        return;
 }
 
-
 static irqreturn_t tmio_mmc_irq(int irq, void *devid)
 {
        struct tmio_mmc_host *host = devid;
@@ -311,7 +353,7 @@ static irqreturn_t tmio_mmc_irq(int irq, void *devid)
        if (!ireg) {
                disable_mmc_irqs(host, status & ~irq_mask);
 
-               pr_debug("tmio_mmc: Spurious irq, disabling! "
+               pr_warning("tmio_mmc: Spurious irq, disabling! "
                        "0x%08x 0x%08x 0x%08x\n", status, irq_mask, ireg);
                pr_debug_status(status);
 
@@ -363,16 +405,265 @@ out:
        return IRQ_HANDLED;
 }
 
+#ifdef CONFIG_TMIO_MMC_DMA
+static void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable)
+{
+#if defined(CONFIG_SUPERH) || defined(CONFIG_ARCH_SHMOBILE)
+       /* Switch DMA mode on or off - SuperH specific? */
+       sd_ctrl_write16(host, 0xd8, enable ? 2 : 0);
+#endif
+}
+
+static void tmio_dma_complete(void *arg)
+{
+       struct tmio_mmc_host *host = arg;
+
+       dev_dbg(&host->pdev->dev, "Command completed\n");
+
+       if (!host->data)
+               dev_warn(&host->pdev->dev, "NULL data in DMA completion!\n");
+       else
+               enable_mmc_irqs(host, TMIO_STAT_DATAEND);
+}
+
+static int tmio_mmc_start_dma_rx(struct tmio_mmc_host *host)
+{
+       struct scatterlist *sg = host->sg_ptr;
+       struct dma_async_tx_descriptor *desc = NULL;
+       struct dma_chan *chan = host->chan_rx;
+       int ret;
+
+       ret = dma_map_sg(&host->pdev->dev, sg, host->sg_len, DMA_FROM_DEVICE);
+       if (ret > 0) {
+               host->dma_sglen = ret;
+               desc = chan->device->device_prep_slave_sg(chan, sg, ret,
+                       DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       }
+
+       if (desc) {
+               host->desc = desc;
+               desc->callback = tmio_dma_complete;
+               desc->callback_param = host;
+               host->cookie = desc->tx_submit(desc);
+               if (host->cookie < 0) {
+                       host->desc = NULL;
+                       ret = host->cookie;
+               } else {
+                       chan->device->device_issue_pending(chan);
+               }
+       }
+       dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n",
+               __func__, host->sg_len, ret, host->cookie, host->mrq);
+
+       if (!host->desc) {
+               /* DMA failed, fall back to PIO */
+               if (ret >= 0)
+                       ret = -EIO;
+               host->chan_rx = NULL;
+               dma_release_channel(chan);
+               /* Free the Tx channel too */
+               chan = host->chan_tx;
+               if (chan) {
+                       host->chan_tx = NULL;
+                       dma_release_channel(chan);
+               }
+               dev_warn(&host->pdev->dev,
+                        "DMA failed: %d, falling back to PIO\n", ret);
+               tmio_mmc_enable_dma(host, false);
+               reset(host);
+               /* Fail this request, let above layers recover */
+               host->mrq->cmd->error = ret;
+               tmio_mmc_finish_request(host);
+       }
+
+       dev_dbg(&host->pdev->dev, "%s(): desc %p, cookie %d, sg[%d]\n", __func__,
+               desc, host->cookie, host->sg_len);
+
+       return ret > 0 ? 0 : ret;
+}
+
+static int tmio_mmc_start_dma_tx(struct tmio_mmc_host *host)
+{
+       struct scatterlist *sg = host->sg_ptr;
+       struct dma_async_tx_descriptor *desc = NULL;
+       struct dma_chan *chan = host->chan_tx;
+       int ret;
+
+       ret = dma_map_sg(&host->pdev->dev, sg, host->sg_len, DMA_TO_DEVICE);
+       if (ret > 0) {
+               host->dma_sglen = ret;
+               desc = chan->device->device_prep_slave_sg(chan, sg, ret,
+                       DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       }
+
+       if (desc) {
+               host->desc = desc;
+               desc->callback = tmio_dma_complete;
+               desc->callback_param = host;
+               host->cookie = desc->tx_submit(desc);
+               if (host->cookie < 0) {
+                       host->desc = NULL;
+                       ret = host->cookie;
+               }
+       }
+       dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n",
+               __func__, host->sg_len, ret, host->cookie, host->mrq);
+
+       if (!host->desc) {
+               /* DMA failed, fall back to PIO */
+               if (ret >= 0)
+                       ret = -EIO;
+               host->chan_tx = NULL;
+               dma_release_channel(chan);
+               /* Free the Rx channel too */
+               chan = host->chan_rx;
+               if (chan) {
+                       host->chan_rx = NULL;
+                       dma_release_channel(chan);
+               }
+               dev_warn(&host->pdev->dev,
+                        "DMA failed: %d, falling back to PIO\n", ret);
+               tmio_mmc_enable_dma(host, false);
+               reset(host);
+               /* Fail this request, let above layers recover */
+               host->mrq->cmd->error = ret;
+               tmio_mmc_finish_request(host);
+       }
+
+       dev_dbg(&host->pdev->dev, "%s(): desc %p, cookie %d\n", __func__,
+               desc, host->cookie);
+
+       return ret > 0 ? 0 : ret;
+}
+
+static int tmio_mmc_start_dma(struct tmio_mmc_host *host,
+                              struct mmc_data *data)
+{
+       if (data->flags & MMC_DATA_READ) {
+               if (host->chan_rx)
+                       return tmio_mmc_start_dma_rx(host);
+       } else {
+               if (host->chan_tx)
+                       return tmio_mmc_start_dma_tx(host);
+       }
+
+       return 0;
+}
+
+static void tmio_issue_tasklet_fn(unsigned long priv)
+{
+       struct tmio_mmc_host *host = (struct tmio_mmc_host *)priv;
+       struct dma_chan *chan = host->chan_tx;
+
+       chan->device->device_issue_pending(chan);
+}
+
+static void tmio_tasklet_fn(unsigned long arg)
+{
+       struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg;
+
+       if (host->data->flags & MMC_DATA_READ)
+               dma_unmap_sg(&host->pdev->dev, host->sg_ptr, host->dma_sglen,
+                            DMA_FROM_DEVICE);
+       else
+               dma_unmap_sg(&host->pdev->dev, host->sg_ptr, host->dma_sglen,
+                            DMA_TO_DEVICE);
+
+       tmio_mmc_do_data_irq(host);
+}
+
+/* It might be necessary to make filter MFD specific */
+static bool tmio_mmc_filter(struct dma_chan *chan, void *arg)
+{
+       dev_dbg(chan->device->dev, "%s: slave data %p\n", __func__, arg);
+       chan->private = arg;
+       return true;
+}
+
+static void tmio_mmc_request_dma(struct tmio_mmc_host *host,
+                                struct tmio_mmc_data *pdata)
+{
+       host->cookie = -EINVAL;
+       host->desc = NULL;
+
+       /* We can only either use DMA for both Tx and Rx or not use it at all */
+       if (pdata->dma) {
+               dma_cap_mask_t mask;
+
+               dma_cap_zero(mask);
+               dma_cap_set(DMA_SLAVE, mask);
+
+               host->chan_tx = dma_request_channel(mask, tmio_mmc_filter,
+                                                   pdata->dma->chan_priv_tx);
+               dev_dbg(&host->pdev->dev, "%s: TX: got channel %p\n", __func__,
+                       host->chan_tx);
+
+               if (!host->chan_tx)
+                       return;
+
+               host->chan_rx = dma_request_channel(mask, tmio_mmc_filter,
+                                                   pdata->dma->chan_priv_rx);
+               dev_dbg(&host->pdev->dev, "%s: RX: got channel %p\n", __func__,
+                       host->chan_rx);
+
+               if (!host->chan_rx) {
+                       dma_release_channel(host->chan_tx);
+                       host->chan_tx = NULL;
+                       return;
+               }
+
+               tasklet_init(&host->dma_complete, tmio_tasklet_fn, (unsigned long)host);
+               tasklet_init(&host->dma_issue, tmio_issue_tasklet_fn, (unsigned long)host);
+
+               tmio_mmc_enable_dma(host, true);
+       }
+}
+
+static void tmio_mmc_release_dma(struct tmio_mmc_host *host)
+{
+       if (host->chan_tx) {
+               struct dma_chan *chan = host->chan_tx;
+               host->chan_tx = NULL;
+               dma_release_channel(chan);
+       }
+       if (host->chan_rx) {
+               struct dma_chan *chan = host->chan_rx;
+               host->chan_rx = NULL;
+               dma_release_channel(chan);
+       }
+
+       host->cookie = -EINVAL;
+       host->desc = NULL;
+}
+#else
+static int tmio_mmc_start_dma(struct tmio_mmc_host *host,
+                              struct mmc_data *data)
+{
+       return 0;
+}
+
+static void tmio_mmc_request_dma(struct tmio_mmc_host *host,
+                                struct tmio_mmc_data *pdata)
+{
+       host->chan_tx = NULL;
+       host->chan_rx = NULL;
+}
+
+static void tmio_mmc_release_dma(struct tmio_mmc_host *host)
+{
+}
+#endif
+
 static int tmio_mmc_start_data(struct tmio_mmc_host *host,
        struct mmc_data *data)
 {
        pr_debug("setup data transfer: blocksize %08x  nr_blocks %d\n",
-           data->blksz, data->blocks);
+                data->blksz, data->blocks);
 
        /* Hardware cannot perform 1 and 2 byte requests in 4 bit mode */
        if (data->blksz < 4 && host->mmc->ios.bus_width == MMC_BUS_WIDTH_4) {
-               printk(KERN_ERR "%s: %d byte block unsupported in 4 bit mode\n",
-                       mmc_hostname(host->mmc), data->blksz);
+               pr_err("%s: %d byte block unsupported in 4 bit mode\n",
+                      mmc_hostname(host->mmc), data->blksz);
                return -EINVAL;
        }
 
@@ -383,7 +674,7 @@ static int tmio_mmc_start_data(struct tmio_mmc_host *host,
        sd_ctrl_write16(host, CTL_SD_XFER_LEN, data->blksz);
        sd_ctrl_write16(host, CTL_XFER_BLK_COUNT, data->blocks);
 
-       return 0;
+       return tmio_mmc_start_dma(host, data);
 }
 
 /* Process requests from the MMC layer */
@@ -404,7 +695,6 @@ static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
        }
 
        ret = tmio_mmc_start_command(host, mrq->cmd);
-
        if (!ret)
                return;
 
@@ -458,11 +748,14 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 static int tmio_mmc_get_ro(struct mmc_host *mmc)
 {
        struct tmio_mmc_host *host = mmc_priv(mmc);
+       struct mfd_cell *cell = host->pdev->dev.platform_data;
+       struct tmio_mmc_data *pdata = cell->driver_data;
 
-       return (sd_ctrl_read16(host, CTL_STATUS) & TMIO_STAT_WRPROTECT) ? 0 : 1;
+       return ((pdata->flags & TMIO_MMC_WRPROTECT_DISABLE) ||
+               (sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT)) ? 0 : 1;
 }
 
-static struct mmc_host_ops tmio_mmc_ops = {
+static const struct mmc_host_ops tmio_mmc_ops = {
        .request        = tmio_mmc_request,
        .set_ios        = tmio_mmc_set_ios,
        .get_ro         = tmio_mmc_get_ro,
@@ -475,7 +768,7 @@ static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state)
        struct mmc_host *mmc = platform_get_drvdata(dev);
        int ret;
 
-       ret = mmc_suspend_host(mmc, state);
+       ret = mmc_suspend_host(mmc);
 
        /* Tell MFD core it can disable us now.*/
        if (!ret && cell->disable)
@@ -515,6 +808,7 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
        struct tmio_mmc_host *host;
        struct mmc_host *mmc;
        int ret = -EINVAL;
+       u32 irq_mask = TMIO_MASK_CMD;
 
        if (dev->num_resources != 2)
                goto out;
@@ -553,7 +847,10 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
        mmc->caps |= pdata->capabilities;
        mmc->f_max = pdata->hclk;
        mmc->f_min = mmc->f_max / 512;
-       mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+       if (pdata->ocr_mask)
+               mmc->ocr_avail = pdata->ocr_mask;
+       else
+               mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
 
        /* Tell the MFD core we are ready to be enabled */
        if (cell->enable) {
@@ -578,13 +875,20 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
        if (ret)
                goto cell_disable;
 
+       /* See if we also get DMA */
+       tmio_mmc_request_dma(host, pdata);
+
        mmc_add_host(mmc);
 
-       printk(KERN_INFO "%s at 0x%08lx irq %d\n", mmc_hostname(host->mmc),
-              (unsigned long)host->ctl, host->irq);
+       pr_info("%s at 0x%08lx irq %d\n", mmc_hostname(host->mmc),
+               (unsigned long)host->ctl, host->irq);
 
        /* Unmask the IRQs we want to know about */
-       enable_mmc_irqs(host, TMIO_MASK_IRQ);
+       if (!host->chan_rx)
+               irq_mask |= TMIO_MASK_READOP;
+       if (!host->chan_tx)
+               irq_mask |= TMIO_MASK_WRITEOP;
+       enable_mmc_irqs(host, irq_mask);
 
        return 0;
 
@@ -609,6 +913,7 @@ static int __devexit tmio_mmc_remove(struct platform_device *dev)
        if (mmc) {
                struct tmio_mmc_host *host = mmc_priv(mmc);
                mmc_remove_host(mmc);
+               tmio_mmc_release_dma(host);
                free_irq(host->irq, host);
                if (cell->disable)
                        cell->disable(dev);
index dafecfbcd91a2e6045655af41c793c27c8b93f4c..64f7d5dfc106ac7b39e37842c5eca9a898dbbb06 100644 (file)
@@ -10,6 +10,8 @@
  */
 
 #include <linux/highmem.h>
+#include <linux/interrupt.h>
+#include <linux/dmaengine.h>
 
 #define CTL_SD_CMD 0x00
 #define CTL_ARG_REG 0x04
@@ -106,6 +108,17 @@ struct tmio_mmc_host {
        unsigned int            sg_off;
 
        struct platform_device *pdev;
+
+       /* DMA support */
+       struct dma_chan         *chan_rx;
+       struct dma_chan         *chan_tx;
+       struct tasklet_struct   dma_complete;
+       struct tasklet_struct   dma_issue;
+#ifdef CONFIG_TMIO_MMC_DMA
+       struct dma_async_tx_descriptor *desc;
+       unsigned int            dma_sglen;
+       dma_cookie_t            cookie;
+#endif
 };
 
 #include <linux/io.h>
index 632858a94376b0b04c2d4a61fe79ad0f99b11760..19f2d72dbca58c4b8e4ecaad1d029029b3e43cf3 100644 (file)
@@ -1280,7 +1280,7 @@ static int via_sd_suspend(struct pci_dev *pcidev, pm_message_t state)
        via_save_pcictrlreg(host);
        via_save_sdcreg(host);
 
-       ret = mmc_suspend_host(host->mmc, state);
+       ret = mmc_suspend_host(host->mmc);
 
        pci_save_state(pcidev);
        pci_enable_wake(pcidev, pci_choose_state(pcidev, state), 0);
index 69efe01eece829cb2f0011b8771471d91245818a..0012f5d13d28715c0ecd4404e28a8f9502e3a085 100644 (file)
@@ -1819,7 +1819,7 @@ static int wbsd_suspend(struct wbsd_host *host, pm_message_t state)
 {
        BUG_ON(host == NULL);
 
-       return mmc_suspend_host(host->mmc, state);
+       return mmc_suspend_host(host->mmc);
 }
 
 static int wbsd_resume(struct wbsd_host *host)
index 36dbcee1ac29aa8c67416b7041cb08d1550e15cf..ba124baa646d7af1fe54cf958d2e26c2af5a00d9 100644 (file)
@@ -143,7 +143,7 @@ static int of_flash_remove(struct of_device *dev)
 static struct mtd_info * __devinit obsolete_probe(struct of_device *dev,
                                                  struct map_info *map)
 {
-       struct device_node *dp = dev->node;
+       struct device_node *dp = dev->dev.of_node;
        const char *of_probe;
        struct mtd_info *mtd;
        static const char *rom_probe_types[]
@@ -221,7 +221,7 @@ static int __devinit of_flash_probe(struct of_device *dev,
 #ifdef CONFIG_MTD_PARTITIONS
        const char **part_probe_types;
 #endif
-       struct device_node *dp = dev->node;
+       struct device_node *dp = dev->dev.of_node;
        struct resource res;
        struct of_flash *info;
        const char *probe_type = match->data;
@@ -245,7 +245,7 @@ static int __devinit of_flash_probe(struct of_device *dev,
        p = of_get_property(dp, "reg", &count);
        if (count % reg_tuple_size != 0) {
                dev_err(&dev->dev, "Malformed reg property on %s\n",
-                               dev->node->full_name);
+                               dev->dev.of_node->full_name);
                err = -EINVAL;
                goto err_flash_remove;
        }
@@ -418,8 +418,11 @@ static struct of_device_id of_flash_match[] = {
 MODULE_DEVICE_TABLE(of, of_flash_match);
 
 static struct of_platform_driver of_flash_driver = {
-       .name           = "of-flash",
-       .match_table    = of_flash_match,
+       .driver = {
+               .name = "of-flash",
+               .owner = THIS_MODULE,
+               .of_match_table = of_flash_match,
+       },
        .probe          = of_flash_probe,
        .remove         = of_flash_remove,
 };
index fadc4c45b455aaabfab873d35c09a1e7c05c1960..0391c2527bd77ac075bf3a2fbc694b49cc5af939 100644 (file)
@@ -110,7 +110,7 @@ int uflash_devinit(struct of_device *op, struct device_node *dp)
 
 static int __devinit uflash_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;
 
        /* Flashprom must have the "user" property in order to
         * be used by this driver.
@@ -149,8 +149,11 @@ static const struct of_device_id uflash_match[] = {
 MODULE_DEVICE_TABLE(of, uflash_match);
 
 static struct of_platform_driver uflash_driver = {
-       .name           = DRIVER_NAME,
-       .match_table    = uflash_match,
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = uflash_match,
+       },
        .probe          = uflash_probe,
        .remove         = __devexit_p(uflash_remove),
 };
index 8bb5e4a663284b5e0fbbf1e617ec80813d3d71c9..000d65ea55a42bf495ba773dca6c66f99f0d3136 100644 (file)
@@ -468,8 +468,7 @@ static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start,
        return ret;
 }
 
-static int mtd_ioctl(struct inode *inode, struct file *file,
-                    u_int cmd, u_long arg)
+static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)
 {
        struct mtd_file_info *mfi = file->private_data;
        struct mtd_info *mtd = mfi->mtd;
@@ -840,6 +839,17 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
        return ret;
 } /* memory_ioctl */
 
+static long mtd_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
+{
+       int ret;
+
+       lock_kernel();
+       ret = mtd_ioctl(file, cmd, arg);
+       unlock_kernel();
+
+       return ret;
+}
+
 #ifdef CONFIG_COMPAT
 
 struct mtd_oob_buf32 {
@@ -854,7 +864,6 @@ struct mtd_oob_buf32 {
 static long mtd_compat_ioctl(struct file *file, unsigned int cmd,
        unsigned long arg)
 {
-       struct inode *inode = file->f_path.dentry->d_inode;
        struct mtd_file_info *mfi = file->private_data;
        struct mtd_info *mtd = mfi->mtd;
        void __user *argp = compat_ptr(arg);
@@ -892,7 +901,7 @@ static long mtd_compat_ioctl(struct file *file, unsigned int cmd,
                break;
        }
        default:
-               ret = mtd_ioctl(inode, file, cmd, (unsigned long)argp);
+               ret = mtd_ioctl(file, cmd, (unsigned long)argp);
        }
 
        unlock_kernel();
@@ -960,7 +969,7 @@ static const struct file_operations mtd_fops = {
        .llseek         = mtd_lseek,
        .read           = mtd_read,
        .write          = mtd_write,
-       .ioctl          = mtd_ioctl,
+       .unlocked_ioctl = mtd_unlocked_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = mtd_compat_ioctl,
 #endif
index 3f38fb8e66668c37f36a86d29fb7c08766e752e6..5084cc51794421c10eb2067dc151a22511b12968 100644 (file)
@@ -1030,14 +1030,14 @@ static int __devinit fsl_elbc_ctrl_probe(struct of_device *ofdev,
        init_waitqueue_head(&ctrl->controller.wq);
        init_waitqueue_head(&ctrl->irq_wait);
 
-       ctrl->regs = of_iomap(ofdev->node, 0);
+       ctrl->regs = of_iomap(ofdev->dev.of_node, 0);
        if (!ctrl->regs) {
                dev_err(&ofdev->dev, "failed to get memory region\n");
                ret = -ENODEV;
                goto err;
        }
 
-       ctrl->irq = of_irq_to_resource(ofdev->node, 0, NULL);
+       ctrl->irq = of_irq_to_resource(ofdev->dev.of_node, 0, NULL);
        if (ctrl->irq == NO_IRQ) {
                dev_err(&ofdev->dev, "failed to get irq resource\n");
                ret = -ENODEV;
@@ -1058,7 +1058,7 @@ static int __devinit fsl_elbc_ctrl_probe(struct of_device *ofdev,
                goto err;
        }
 
-       for_each_child_of_node(ofdev->node, child)
+       for_each_child_of_node(ofdev->dev.of_node, child)
                if (of_device_is_compatible(child, "fsl,elbc-fcm-nand"))
                        fsl_elbc_chip_probe(ctrl, child);
 
@@ -1078,9 +1078,10 @@ static const struct of_device_id fsl_elbc_match[] = {
 
 static struct of_platform_driver fsl_elbc_ctrl_driver = {
        .driver = {
-               .name   = "fsl-elbc",
+               .name = "fsl-elbc",
+               .owner = THIS_MODULE,
+               .of_match_table = fsl_elbc_match,
        },
-       .match_table = fsl_elbc_match,
        .probe = fsl_elbc_ctrl_probe,
        .remove = fsl_elbc_ctrl_remove,
 };
index 2d215ccb564d7961ac7c502900a72265b777d4c8..00aea6f7d1f1bc6bbf8bfae8080bce0b01c633e7 100644 (file)
@@ -360,8 +360,11 @@ static const struct of_device_id of_fun_match[] = {
 MODULE_DEVICE_TABLE(of, of_fun_match);
 
 static struct of_platform_driver of_fun_driver = {
-       .name           = "fsl,upm-nand",
-       .match_table    = of_fun_match,
+       .driver = {
+               .name = "fsl,upm-nand",
+               .owner = THIS_MODULE,
+               .of_match_table = of_fun_match,
+       },
        .probe          = fun_probe,
        .remove         = __devexit_p(fun_remove),
 };
index b983cae8c298288a2d2942e4170114f047182559..98fd2bdf8be15df36be2dd264e56ea27282bd20b 100644 (file)
@@ -239,14 +239,14 @@ static int __devinit ndfc_probe(struct of_device *ofdev,
        dev_set_drvdata(&ofdev->dev, ndfc);
 
        /* Read the reg property to get the chip select */
-       reg = of_get_property(ofdev->node, "reg", &len);
+       reg = of_get_property(ofdev->dev.of_node, "reg", &len);
        if (reg == NULL || len != 12) {
                dev_err(&ofdev->dev, "unable read reg property (%d)\n", len);
                return -ENOENT;
        }
        ndfc->chip_select = reg[0];
 
-       ndfc->ndfcbase = of_iomap(ofdev->node, 0);
+       ndfc->ndfcbase = of_iomap(ofdev->dev.of_node, 0);
        if (!ndfc->ndfcbase) {
                dev_err(&ofdev->dev, "failed to get memory\n");
                return -EIO;
@@ -255,20 +255,20 @@ static int __devinit ndfc_probe(struct of_device *ofdev,
        ccr = NDFC_CCR_BS(ndfc->chip_select);
 
        /* It is ok if ccr does not exist - just default to 0 */
-       reg = of_get_property(ofdev->node, "ccr", NULL);
+       reg = of_get_property(ofdev->dev.of_node, "ccr", NULL);
        if (reg)
                ccr |= *reg;
 
        out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
 
        /* Set the bank settings if given */
-       reg = of_get_property(ofdev->node, "bank-settings", NULL);
+       reg = of_get_property(ofdev->dev.of_node, "bank-settings", NULL);
        if (reg) {
                int offset = NDFC_BCFG0 + (ndfc->chip_select << 2);
                out_be32(ndfc->ndfcbase + offset, *reg);
        }
 
-       err = ndfc_chip_init(ndfc, ofdev->node);
+       err = ndfc_chip_init(ndfc, ofdev->dev.of_node);
        if (err) {
                iounmap(ndfc->ndfcbase);
                return err;
@@ -294,9 +294,10 @@ MODULE_DEVICE_TABLE(of, ndfc_match);
 
 static struct of_platform_driver ndfc_driver = {
        .driver = {
-               .name   = "ndfc",
+               .name = "ndfc",
+               .owner = THIS_MODULE,
+               .of_match_table = ndfc_match,
        },
-       .match_table = ndfc_match,
        .probe = ndfc_probe,
        .remove = __devexit_p(ndfc_remove),
 };
index 090a05c12cbe0db0c67659a0abb39354aa0e11ff..f02af24d033a73341b7490acec7f2255e8ed67c9 100644 (file)
@@ -93,7 +93,7 @@ static int __devinit pasemi_nand_probe(struct of_device *ofdev,
                                      const struct of_device_id *match)
 {
        struct pci_dev *pdev;
-       struct device_node *np = ofdev->node;
+       struct device_node *np = ofdev->dev.of_node;
        struct resource res;
        struct nand_chip *chip;
        int err = 0;
@@ -221,8 +221,11 @@ MODULE_DEVICE_TABLE(of, pasemi_nand_match);
 
 static struct of_platform_driver pasemi_nand_driver =
 {
-       .name           = (char*)driver_name,
-       .match_table    = pasemi_nand_match,
+       .driver = {
+               .name = (char*)driver_name,
+               .owner = THIS_MODULE,
+               .of_match_table = pasemi_nand_match,
+       },
        .probe          = pasemi_nand_probe,
        .remove         = pasemi_nand_remove,
 };
index b37cbde6e7dbfb0981b00d6934fdd397023020d1..884852dc7eb44b29d1788fb43db7c3f6846c6936 100644 (file)
@@ -301,8 +301,11 @@ static const struct of_device_id socrates_nand_match[] =
 MODULE_DEVICE_TABLE(of, socrates_nand_match);
 
 static struct of_platform_driver socrates_nand_driver = {
-       .name           = "socrates_nand",
-       .match_table    = socrates_nand_match,
+       .driver = {
+               .name = "socrates_nand",
+               .owner = THIS_MODULE,
+               .of_match_table = socrates_nand_match,
+       },
        .probe          = socrates_nand_probe,
        .remove         = __devexit_p(socrates_nand_remove),
 };
index 72ebb3f06b86b835658870247cdf582b61724704..4dfa6b90c21c30566d35939d7d3837327495f208 100644 (file)
@@ -189,8 +189,7 @@ static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin)
        return new_offset;
 }
 
-static int vol_cdev_fsync(struct file *file, struct dentry *dentry,
-                         int datasync)
+static int vol_cdev_fsync(struct file *file, int datasync)
 {
        struct ubi_volume_desc *desc = file->private_data;
        struct ubi_device *ubi = desc->vol->ubi;
index 82eaf65d2d8580f66ec83e3fdd2082e492c57a33..ea9b7a098c9bd75e2023fe7e5164f4baf7a86fee 100644 (file)
@@ -551,8 +551,7 @@ static irqreturn_t el16_interrupt(int irq, void *dev_id)
        void __iomem *shmem;
 
        if (dev == NULL) {
-               pr_err("%s: net_interrupt(): irq %d for unknown device.\n",
-                       dev->name, irq);
+               pr_err("net_interrupt(): irq %d for unknown device.\n", irq);
                return IRQ_NONE;
        }
 
index 373c1a563474d9540c43ae315bcab0185b813ddd..b46be490cd2aab76bf5cf84a496d18632b10cb59 100644 (file)
@@ -283,6 +283,8 @@ struct be_adapter {
        u8 port_type;
        u8 transceiver;
        u8 generation;          /* BladeEngine ASIC generation */
+       u32 flash_status;
+       struct completion flash_compl;
 
        bool sriov_enabled;
        u32 vf_if_handle[BE_MAX_VF];
index e79bf8b9af3bc5e0a3034d9b3c9ab7d6f9dfef39..9d11dbf5e4da2d96d941a48c2af51d8bae9bdb57 100644 (file)
@@ -59,6 +59,13 @@ static int be_mcc_compl_process(struct be_adapter *adapter,
 
        compl_status = (compl->status >> CQE_STATUS_COMPL_SHIFT) &
                                CQE_STATUS_COMPL_MASK;
+
+       if ((compl->tag0 == OPCODE_COMMON_WRITE_FLASHROM) &&
+               (compl->tag1 == CMD_SUBSYSTEM_COMMON)) {
+               adapter->flash_status = compl_status;
+               complete(&adapter->flash_compl);
+       }
+
        if (compl_status == MCC_STATUS_SUCCESS) {
                if (compl->tag0 == OPCODE_ETH_GET_STATISTICS) {
                        struct be_cmd_resp_get_stats *resp =
@@ -287,7 +294,7 @@ int be_cmd_POST(struct be_adapter *adapter)
                } else {
                        return 0;
                }
-       } while (timeout < 20);
+       } while (timeout < 40);
 
        dev_err(&adapter->pdev->dev, "POST timeout; stage=0x%x\n", stage);
        return -1;
@@ -1417,6 +1424,7 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd,
        int status;
 
        spin_lock_bh(&adapter->mcc_lock);
+       adapter->flash_status = 0;
 
        wrb = wrb_from_mccq(adapter);
        if (!wrb) {
@@ -1428,6 +1436,7 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd,
 
        be_wrb_hdr_prepare(wrb, cmd->size, false, 1,
                        OPCODE_COMMON_WRITE_FLASHROM);
+       wrb->tag1 = CMD_SUBSYSTEM_COMMON;
 
        be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
                OPCODE_COMMON_WRITE_FLASHROM, cmd->size);
@@ -1439,10 +1448,16 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd,
        req->params.op_code = cpu_to_le32(flash_opcode);
        req->params.data_buf_size = cpu_to_le32(buf_size);
 
-       status = be_mcc_notify_wait(adapter);
+       be_mcc_notify(adapter);
+       spin_unlock_bh(&adapter->mcc_lock);
+
+       if (!wait_for_completion_timeout(&adapter->flash_compl,
+                       msecs_to_jiffies(12000)))
+               status = -1;
+       else
+               status = adapter->flash_status;
 
 err:
-       spin_unlock_bh(&adapter->mcc_lock);
        return status;
 }
 
index 058d7f95f5ae17df77c65c473a9683d4ec2a737a..54b14272f333330edc9cddbce502d7e0068103ba 100644 (file)
@@ -1861,7 +1861,7 @@ static int be_setup(struct be_adapter *adapter)
                                goto if_destroy;
                        }
                        vf++;
-               } while (vf < num_vfs);
+               }
        } else if (!be_physfn(adapter)) {
                status = be_cmd_mac_addr_query(adapter, mac,
                        MAC_ADDRESS_TYPE_NETWORK, false, adapter->if_handle);
@@ -2319,6 +2319,7 @@ static int be_ctrl_init(struct be_adapter *adapter)
        spin_lock_init(&adapter->mcc_lock);
        spin_lock_init(&adapter->mcc_cq_lock);
 
+       init_completion(&adapter->flash_compl);
        pci_save_state(adapter->pdev);
        return 0;
 
@@ -2487,10 +2488,6 @@ static int __devinit be_probe(struct pci_dev *pdev,
                status = be_cmd_POST(adapter);
                if (status)
                        goto ctrl_clean;
-
-               status = be_cmd_reset_function(adapter);
-               if (status)
-                       goto ctrl_clean;
        }
 
        /* tell fw we're ready to fire cmds */
@@ -2498,6 +2495,12 @@ static int __devinit be_probe(struct pci_dev *pdev,
        if (status)
                goto ctrl_clean;
 
+       if (be_physfn(adapter)) {
+               status = be_cmd_reset_function(adapter);
+               if (status)
+                       goto ctrl_clean;
+       }
+
        status = be_stats_init(adapter);
        if (status)
                goto ctrl_clean;
index 39a54bad397f7212b22340187a73325f20b7ab9d..368f33313fb6619635383ca9799ae7cf8d5e6376 100644 (file)
@@ -1626,6 +1626,7 @@ static int __devinit bfin_mii_bus_probe(struct platform_device *pdev)
        return 0;
 
 out_err_mdiobus_register:
+       kfree(miibus->irq);
        mdiobus_free(miibus);
 out_err_alloc:
        peripheral_free_list(pin_req);
@@ -1638,6 +1639,7 @@ static int __devexit bfin_mii_bus_remove(struct platform_device *pdev)
        struct mii_bus *miibus = platform_get_drvdata(pdev);
        platform_set_drvdata(pdev, NULL);
        mdiobus_unregister(miibus);
+       kfree(miibus->irq);
        mdiobus_free(miibus);
        peripheral_free_list(pin_req);
        return 0;
index 225fd147774aa1f8c37ea452f46d1e558a317316..8af8442c694a69c2e4e5dea49ebcd7d13a4e92de 100644 (file)
@@ -392,15 +392,17 @@ static struct of_device_id __devinitdata mpc5xxx_can_table[] = {
 };
 
 static struct of_platform_driver mpc5xxx_can_driver = {
-       .owner = THIS_MODULE,
-       .name = "mpc5xxx_can",
+       .driver = {
+               .name = "mpc5xxx_can",
+               .owner = THIS_MODULE,
+               .of_match_table = mpc5xxx_can_table,
+       },
        .probe = mpc5xxx_can_probe,
        .remove = __devexit_p(mpc5xxx_can_remove),
 #ifdef CONFIG_PM
        .suspend = mpc5xxx_can_suspend,
        .resume = mpc5xxx_can_resume,
 #endif
-       .match_table = mpc5xxx_can_table,
 };
 
 static int __init mpc5xxx_can_init(void)
index 85f7cbfe8e5fbfe4ec54e6290a78372f0b576533..0a8de01d52f7a1e2c1267701bb8d9e2437ad7fd6 100644 (file)
@@ -599,6 +599,8 @@ struct net_device *alloc_sja1000dev(int sizeof_priv)
        priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
                CAN_CTRLMODE_BERR_REPORTING;
 
+       spin_lock_init(&priv->cmdreg_lock);
+
        if (sizeof_priv)
                priv->priv = (void *)priv + sizeof(struct sja1000_priv);
 
index 34e79efbd2fca7413924a8e47abde8b47baa82bb..ac1a83d7c2044fdd20c5b42063de62231b7d2725 100644 (file)
@@ -71,7 +71,7 @@ static int __devexit sja1000_ofp_remove(struct of_device *ofdev)
 {
        struct net_device *dev = dev_get_drvdata(&ofdev->dev);
        struct sja1000_priv *priv = netdev_priv(dev);
-       struct device_node *np = ofdev->node;
+       struct device_node *np = ofdev->dev.of_node;
        struct resource res;
 
        dev_set_drvdata(&ofdev->dev, NULL);
@@ -90,7 +90,7 @@ static int __devexit sja1000_ofp_remove(struct of_device *ofdev)
 static int __devinit sja1000_ofp_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 net_device *dev;
        struct sja1000_priv *priv;
        struct resource res;
@@ -215,11 +215,13 @@ static struct of_device_id __devinitdata sja1000_ofp_table[] = {
 MODULE_DEVICE_TABLE(of, sja1000_ofp_table);
 
 static struct of_platform_driver sja1000_ofp_driver = {
-       .owner = THIS_MODULE,
-       .name = DRV_NAME,
+       .driver = {
+               .owner = THIS_MODULE,
+               .name = DRV_NAME,
+               .of_match_table = sja1000_ofp_table,
+       },
        .probe = sja1000_ofp_probe,
        .remove = __devexit_p(sja1000_ofp_remove),
-       .match_table = sja1000_ofp_table,
 };
 
 static int __init sja1000_ofp_init(void)
index be90d3598bcab522889767495506490cf409a35e..fe925663d39a535a5c9d2c6f65866c3f2f29e6d7 100644 (file)
@@ -3367,13 +3367,9 @@ static int cnic_cm_shutdown(struct cnic_dev *dev)
 
 static void cnic_init_context(struct cnic_dev *dev, u32 cid)
 {
-       struct cnic_local *cp = dev->cnic_priv;
        u32 cid_addr;
        int i;
 
-       if (CHIP_NUM(cp) == CHIP_NUM_5709)
-               return;
-
        cid_addr = GET_CID_ADDR(cid);
 
        for (i = 0; i < CTX_SIZE; i += 4)
@@ -3530,14 +3526,11 @@ static void cnic_init_bnx2_tx_ring(struct cnic_dev *dev)
 
        sb_id = cp->status_blk_num;
        tx_cid = 20;
-       cnic_init_context(dev, tx_cid);
-       cnic_init_context(dev, tx_cid + 1);
        cp->tx_cons_ptr = &s_blk->status_tx_quick_consumer_index2;
        if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) {
                struct status_block_msix *sblk = cp->status_blk.bnx2;
 
                tx_cid = TX_TSS_CID + sb_id - 1;
-               cnic_init_context(dev, tx_cid);
                CNIC_WR(dev, BNX2_TSCH_TSS_CFG, (sb_id << 24) |
                        (TX_TSS_CID << 7));
                cp->tx_cons_ptr = &sblk->status_tx_quick_consumer_index;
@@ -3556,6 +3549,9 @@ static void cnic_init_bnx2_tx_ring(struct cnic_dev *dev)
                offset2 = BNX2_L2CTX_TBDR_BHADDR_HI_XI;
                offset3 = BNX2_L2CTX_TBDR_BHADDR_LO_XI;
        } else {
+               cnic_init_context(dev, tx_cid);
+               cnic_init_context(dev, tx_cid + 1);
+
                offset0 = BNX2_L2CTX_TYPE;
                offset1 = BNX2_L2CTX_CMD_TYPE;
                offset2 = BNX2_L2CTX_TBDR_BHADDR_HI;
index 110c62072e6f8ca626ff79623570c0f6e60b40fa..0c55177db046ddf6ce4bb0a684dea0fed459b201 100644 (file)
@@ -12,8 +12,8 @@
 #ifndef CNIC_IF_H
 #define CNIC_IF_H
 
-#define CNIC_MODULE_VERSION    "2.1.1"
-#define CNIC_MODULE_RELDATE    "Feb 22, 2010"
+#define CNIC_MODULE_VERSION    "2.1.2"
+#define CNIC_MODULE_RELDATE    "May 26, 2010"
 
 #define CNIC_ULP_RDMA          0
 #define CNIC_ULP_ISCSI         1
index 02698a1c80b057a4f57eba4e5e72f40c2c7da293..f547894ff48fc3a02317548dafe8ec900e5044e2 100644 (file)
@@ -122,8 +122,11 @@ static struct of_device_id ehea_device_table[] = {
 MODULE_DEVICE_TABLE(of, ehea_device_table);
 
 static struct of_platform_driver ehea_driver = {
-       .name = "ehea",
-       .match_table = ehea_device_table,
+       .driver = {
+               .name = "ehea",
+               .owner = THIS_MODULE,
+               .of_match_table = ehea_device_table,
+       },
        .probe = ehea_probe_adapter,
        .remove = ehea_remove,
 };
@@ -3050,7 +3053,7 @@ static DEVICE_ATTR(log_port_id, S_IRUSR | S_IRGRP | S_IROTH, ehea_show_port_id,
 static void __devinit logical_port_release(struct device *dev)
 {
        struct ehea_port *port = container_of(dev, struct ehea_port, ofdev.dev);
-       of_node_put(port->ofdev.node);
+       of_node_put(port->ofdev.dev.of_node);
 }
 
 static struct device *ehea_register_port(struct ehea_port *port,
@@ -3058,7 +3061,7 @@ static struct device *ehea_register_port(struct ehea_port *port,
 {
        int ret;
 
-       port->ofdev.node = of_node_get(dn);
+       port->ofdev.dev.of_node = of_node_get(dn);
        port->ofdev.dev.parent = &port->adapter->ofdev->dev;
        port->ofdev.dev.bus = &ibmebus_bus_type;
 
@@ -3225,7 +3228,7 @@ static int ehea_setup_ports(struct ehea_adapter *adapter)
        const u32 *dn_log_port_id;
        int i = 0;
 
-       lhea_dn = adapter->ofdev->node;
+       lhea_dn = adapter->ofdev->dev.of_node;
        while ((eth_dn = of_get_next_child(lhea_dn, eth_dn))) {
 
                dn_log_port_id = of_get_property(eth_dn, "ibm,hea-port-no",
@@ -3264,7 +3267,7 @@ static struct device_node *ehea_get_eth_dn(struct ehea_adapter *adapter,
        struct device_node *eth_dn = NULL;
        const u32 *dn_log_port_id;
 
-       lhea_dn = adapter->ofdev->node;
+       lhea_dn = adapter->ofdev->dev.of_node;
        while ((eth_dn = of_get_next_child(lhea_dn, eth_dn))) {
 
                dn_log_port_id = of_get_property(eth_dn, "ibm,hea-port-no",
@@ -3394,7 +3397,7 @@ static int __devinit ehea_probe_adapter(struct of_device *dev,
        const u64 *adapter_handle;
        int ret;
 
-       if (!dev || !dev->node) {
+       if (!dev || !dev->dev.of_node) {
                ehea_error("Invalid ibmebus device probed");
                return -EINVAL;
        }
@@ -3410,14 +3413,14 @@ static int __devinit ehea_probe_adapter(struct of_device *dev,
 
        adapter->ofdev = dev;
 
-       adapter_handle = of_get_property(dev->node, "ibm,hea-handle",
+       adapter_handle = of_get_property(dev->dev.of_node, "ibm,hea-handle",
                                         NULL);
        if (adapter_handle)
                adapter->handle = *adapter_handle;
 
        if (!adapter->handle) {
                dev_err(&dev->dev, "failed getting handle for adapter"
-                       " '%s'\n", dev->node->full_name);
+                       " '%s'\n", dev->dev.of_node->full_name);
                ret = -ENODEV;
                goto out_free_ad;
        }
index e125113759a5e1a09e6851b3a145f4042d0b0040..6586b5c7e4b617066bea1d652f175b51b5f9d6f4 100644 (file)
@@ -1034,9 +1034,10 @@ static int enic_set_port_profile(struct enic *enic, u8 request, u8 *mac,
 {
        struct vic_provinfo *vp;
        u8 oui[3] = VIC_PROVINFO_CISCO_OUI;
-       unsigned short *uuid;
+       u8 *uuid;
        char uuid_str[38];
-       static char *uuid_fmt = "%04X%04X-%04X-%04X-%04X-%04X%04X%04X";
+       static char *uuid_fmt = "%02X%02X%02X%02X-%02X%02X-%02X%02X-"
+               "%02X%02X-%02X%02X%02X%02X%0X%02X";
        int err;
 
        if (!name)
@@ -1058,20 +1059,24 @@ static int enic_set_port_profile(struct enic *enic, u8 request, u8 *mac,
                ETH_ALEN, mac);
 
        if (instance_uuid) {
-               uuid = (unsigned short *)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[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 (host_uuid) {
-               uuid = (unsigned short *)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[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);
@@ -1127,6 +1132,14 @@ static int enic_set_vf_port(struct net_device *netdev, int vf,
        switch (request) {
        case PORT_REQUEST_ASSOCIATE:
 
+               /* If the interface mac addr hasn't been assigned,
+                * assign a random mac addr before setting port-
+                * profile.
+                */
+
+               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]);
 
index 14cbde5cf68e52546d0b2f4c0e42f26fa95b89f5..6ed2df14ec8490eba68ed4b7f8af104830fe4949 100644 (file)
@@ -174,6 +174,7 @@ MODULE_PARM_DESC(buffer_size, "DMA buffer allocation size");
  * @iobase:    pointer to I/O memory region
  * @membase:   pointer to buffer memory region
  * @dma_alloc: dma allocated buffer size
+ * @io_region_size:    I/O memory region size
  * @num_tx:    number of send buffers
  * @cur_tx:    last send buffer written
  * @dty_tx:    last buffer actually sent
@@ -193,6 +194,7 @@ struct ethoc {
        void __iomem *iobase;
        void __iomem *membase;
        int dma_alloc;
+       resource_size_t io_region_size;
 
        unsigned int num_tx;
        unsigned int cur_tx;
@@ -943,6 +945,7 @@ static int ethoc_probe(struct platform_device *pdev)
        priv = netdev_priv(netdev);
        priv->netdev = netdev;
        priv->dma_alloc = 0;
+       priv->io_region_size = mmio->end - mmio->start + 1;
 
        priv->iobase = devm_ioremap_nocache(&pdev->dev, netdev->base_addr,
                        resource_size(mmio));
@@ -1047,20 +1050,34 @@ static int ethoc_probe(struct platform_device *pdev)
        ret = register_netdev(netdev);
        if (ret < 0) {
                dev_err(&netdev->dev, "failed to register interface\n");
-               goto error;
+               goto error2;
        }
 
        goto out;
 
+error2:
+       netif_napi_del(&priv->napi);
 error:
        mdiobus_unregister(priv->mdio);
 free_mdio:
        kfree(priv->mdio->irq);
        mdiobus_free(priv->mdio);
 free:
-       if (priv->dma_alloc)
-               dma_free_coherent(NULL, priv->dma_alloc, priv->membase,
-                       netdev->mem_start);
+       if (priv) {
+               if (priv->dma_alloc)
+                       dma_free_coherent(NULL, priv->dma_alloc, priv->membase,
+                                         netdev->mem_start);
+               else if (priv->membase)
+                       devm_iounmap(&pdev->dev, priv->membase);
+               if (priv->iobase)
+                       devm_iounmap(&pdev->dev, priv->iobase);
+       }
+       if (mem)
+               devm_release_mem_region(&pdev->dev, mem->start,
+                                       mem->end - mem->start + 1);
+       if (mmio)
+               devm_release_mem_region(&pdev->dev, mmio->start,
+                                       mmio->end - mmio->start + 1);
        free_netdev(netdev);
 out:
        return ret;
@@ -1078,6 +1095,7 @@ static int ethoc_remove(struct platform_device *pdev)
        platform_set_drvdata(pdev, NULL);
 
        if (netdev) {
+               netif_napi_del(&priv->napi);
                phy_disconnect(priv->phy);
                priv->phy = NULL;
 
@@ -1089,6 +1107,14 @@ static int ethoc_remove(struct platform_device *pdev)
                if (priv->dma_alloc)
                        dma_free_coherent(NULL, priv->dma_alloc, priv->membase,
                                netdev->mem_start);
+               else {
+                       devm_iounmap(&pdev->dev, priv->membase);
+                       devm_release_mem_region(&pdev->dev, netdev->mem_start,
+                               netdev->mem_end - netdev->mem_start + 1);
+               }
+               devm_iounmap(&pdev->dev, priv->iobase);
+               devm_release_mem_region(&pdev->dev, netdev->base_addr,
+                       priv->io_region_size);
                unregister_netdev(netdev);
                free_netdev(netdev);
        }
index 42d9ac9ba3958aa3b4b6a7210bb96cb51aa3dd52..ddf7a86cd4661f0cdfa438d7a2a9dae6db68acec 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/clk.h>
 #include <linux/platform_device.h>
 #include <linux/phy.h>
+#include <linux/fec.h>
 
 #include <asm/cacheflush.h>
 
@@ -182,6 +183,7 @@ struct fec_enet_private {
        struct  phy_device *phy_dev;
        int     mii_timeout;
        uint    phy_speed;
+       phy_interface_t phy_interface;
        int     index;
        int     link;
        int     full_duplex;
@@ -679,6 +681,8 @@ static int fec_enet_mii_probe(struct net_device *dev)
        struct phy_device *phy_dev = NULL;
        int phy_addr;
 
+       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]) {
@@ -709,6 +713,11 @@ static int fec_enet_mii_probe(struct net_device *dev)
        fep->link = 0;
        fep->full_duplex = 0;
 
+       printk(KERN_INFO "%s: Freescale FEC PHY driver [%s] "
+               "(mii_bus:phy_addr=%s, irq=%d)\n", dev->name,
+               fep->phy_dev->drv->name, dev_name(&fep->phy_dev->dev),
+               fep->phy_dev->irq);
+
        return 0;
 }
 
@@ -754,13 +763,8 @@ static int fec_enet_mii_init(struct platform_device *pdev)
        if (mdiobus_register(fep->mii_bus))
                goto err_out_free_mdio_irq;
 
-       if (fec_enet_mii_probe(dev) != 0)
-               goto err_out_unregister_bus;
-
        return 0;
 
-err_out_unregister_bus:
-       mdiobus_unregister(fep->mii_bus);
 err_out_free_mdio_irq:
        kfree(fep->mii_bus->irq);
 err_out_free_mdiobus:
@@ -913,7 +917,12 @@ fec_enet_open(struct net_device *dev)
        if (ret)
                return ret;
 
-       /* schedule a link state check */
+       /* Probe and connect to PHY when open the interface */
+       ret = fec_enet_mii_probe(dev);
+       if (ret) {
+               fec_enet_free_buffers(dev);
+               return ret;
+       }
        phy_start(fep->phy_dev);
        netif_start_queue(dev);
        fep->opened = 1;
@@ -927,10 +936,12 @@ fec_enet_close(struct net_device *dev)
 
        /* Don't know what to do yet. */
        fep->opened = 0;
-       phy_stop(fep->phy_dev);
        netif_stop_queue(dev);
        fec_stop(dev);
 
+       if (fep->phy_dev)
+               phy_disconnect(fep->phy_dev);
+
         fec_enet_free_buffers(dev);
 
        return 0;
@@ -1191,6 +1202,21 @@ fec_restart(struct net_device *dev, int duplex)
        /* Set MII speed */
        writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
 
+#ifdef FEC_MIIGSK_ENR
+       if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) {
+               /* disable the gasket and wait */
+               writel(0, fep->hwp + FEC_MIIGSK_ENR);
+               while (readl(fep->hwp + FEC_MIIGSK_ENR) & 4)
+                       udelay(1);
+
+               /* configure the gasket: RMII, 50 MHz, no loopback, no echo */
+               writel(1, fep->hwp + FEC_MIIGSK_CFGR);
+
+               /* re-enable the gasket */
+               writel(2, fep->hwp + FEC_MIIGSK_ENR);
+       }
+#endif
+
        /* And last, enable the transmit and receive processing */
        writel(2, fep->hwp + FEC_ECNTRL);
        writel(0, fep->hwp + FEC_R_DES_ACTIVE);
@@ -1226,6 +1252,7 @@ static int __devinit
 fec_probe(struct platform_device *pdev)
 {
        struct fec_enet_private *fep;
+       struct fec_platform_data *pdata;
        struct net_device *ndev;
        int i, irq, ret = 0;
        struct resource *r;
@@ -1259,6 +1286,10 @@ fec_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, ndev);
 
+       pdata = pdev->dev.platform_data;
+       if (pdata)
+               fep->phy_interface = pdata->phy;
+
        /* This device has up to three irqs on some platforms */
        for (i = 0; i < 3; i++) {
                irq = platform_get_irq(pdev, i);
@@ -1294,11 +1325,6 @@ fec_probe(struct platform_device *pdev)
        if (ret)
                goto failed_register;
 
-       printk(KERN_INFO "%s: Freescale FEC PHY driver [%s] "
-               "(mii_bus:phy_addr=%s, irq=%d)\n", ndev->name,
-               fep->phy_dev->drv->name, dev_name(&fep->phy_dev->dev),
-               fep->phy_dev->irq);
-
        return 0;
 
 failed_register:
index cc47f3f057c7464b2f5096e7810bad46c9362cf7..2c48b25668d56f7247707b8a8fadff476713ad22 100644 (file)
@@ -43,6 +43,8 @@
 #define FEC_R_DES_START                0x180 /* Receive descriptor ring */
 #define FEC_X_DES_START                0x184 /* Transmit descriptor ring */
 #define FEC_R_BUFF_SIZE                0x188 /* Maximum receive buff size */
+#define FEC_MIIGSK_CFGR                0x300 /* MIIGSK Configuration reg */
+#define FEC_MIIGSK_ENR         0x308 /* MIIGSK Enable reg */
 
 #else
 
index 221f440c10f4b59c49232283dae0fbbd48920856..25e6cc6840b1ecf1993630d2f1b5acf19a3675b6 100644 (file)
@@ -871,7 +871,7 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
        priv->ndev = ndev;
 
        /* Reserve FEC control zone */
-       rv = of_address_to_resource(op->node, 0, &mem);
+       rv = of_address_to_resource(op->dev.of_node, 0, &mem);
        if (rv) {
                printk(KERN_ERR DRIVER_NAME ": "
                                "Error while parsing device node resource\n" );
@@ -919,7 +919,7 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
 
        /* Get the IRQ we need one by one */
                /* Control */
-       ndev->irq = irq_of_parse_and_map(op->node, 0);
+       ndev->irq = irq_of_parse_and_map(op->dev.of_node, 0);
 
                /* RX */
        priv->r_irq = bcom_get_task_irq(priv->rx_dmatsk);
@@ -942,20 +942,20 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
        /* Start with safe defaults for link connection */
        priv->speed = 100;
        priv->duplex = DUPLEX_HALF;
-       priv->mdio_speed = ((mpc5xxx_get_bus_frequency(op->node) >> 20) / 5) << 1;
+       priv->mdio_speed = ((mpc5xxx_get_bus_frequency(op->dev.of_node) >> 20) / 5) << 1;
 
        /* The current speed preconfigures the speed of the MII link */
-       prop = of_get_property(op->node, "current-speed", &prop_size);
+       prop = of_get_property(op->dev.of_node, "current-speed", &prop_size);
        if (prop && (prop_size >= sizeof(u32) * 2)) {
                priv->speed = prop[0];
                priv->duplex = prop[1] ? DUPLEX_FULL : DUPLEX_HALF;
        }
 
        /* If there is a phy handle, then get the PHY node */
-       priv->phy_node = of_parse_phandle(op->node, "phy-handle", 0);
+       priv->phy_node = of_parse_phandle(op->dev.of_node, "phy-handle", 0);
 
        /* the 7-wire property means don't use MII mode */
-       if (of_find_property(op->node, "fsl,7-wire-mode", NULL)) {
+       if (of_find_property(op->dev.of_node, "fsl,7-wire-mode", NULL)) {
                priv->seven_wire_mode = 1;
                dev_info(&ndev->dev, "using 7-wire PHY mode\n");
        }
@@ -1063,9 +1063,11 @@ static struct of_device_id mpc52xx_fec_match[] = {
 MODULE_DEVICE_TABLE(of, mpc52xx_fec_match);
 
 static struct of_platform_driver mpc52xx_fec_driver = {
-       .owner          = THIS_MODULE,
-       .name           = DRIVER_NAME,
-       .match_table    = mpc52xx_fec_match,
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = mpc52xx_fec_match,
+       },
        .probe          = mpc52xx_fec_probe,
        .remove         = mpc52xx_fec_remove,
 #ifdef CONFIG_PM
index 7658a082e390cd4c8d86c066cdf0d76aa1d72d80..006f64d9f96a695e6fbde63b0269121da323df0b 100644 (file)
@@ -66,7 +66,7 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of,
                const struct of_device_id *match)
 {
        struct device *dev = &of->dev;
-       struct device_node *np = of->node;
+       struct device_node *np = of->dev.of_node;
        struct mii_bus *bus;
        struct mpc52xx_fec_mdio_priv *priv;
        struct resource res = {};
@@ -107,7 +107,7 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of,
 
        /* set MII speed */
        out_be32(&priv->regs->mii_speed,
-               ((mpc5xxx_get_bus_frequency(of->node) >> 20) / 5) << 1);
+               ((mpc5xxx_get_bus_frequency(of->dev.of_node) >> 20) / 5) << 1);
 
        err = of_mdiobus_register(bus, np);
        if (err)
@@ -159,10 +159,13 @@ static struct of_device_id mpc52xx_fec_mdio_match[] = {
 MODULE_DEVICE_TABLE(of, mpc52xx_fec_mdio_match);
 
 struct of_platform_driver mpc52xx_fec_mdio_driver = {
-       .name = "mpc5200b-fec-phy",
+       .driver = {
+               .name = "mpc5200b-fec-phy",
+               .owner = THIS_MODULE,
+               .of_match_table = mpc52xx_fec_mdio_match,
+       },
        .probe = mpc52xx_fec_mdio_probe,
        .remove = mpc52xx_fec_mdio_remove,
-       .match_table = mpc52xx_fec_mdio_match,
 };
 
 /* let fec driver call it, since this has to be registered before it */
index 0fb0fefcb7874f5ba159be21a73db0fb3d710523..309a0eaddd815739d33c196d94ce3aad770cec34 100644 (file)
@@ -1013,7 +1013,7 @@ static int __devinit fs_enet_probe(struct of_device *ofdev,
                return -ENOMEM;
 
        if (!IS_FEC(match)) {
-               data = of_get_property(ofdev->node, "fsl,cpm-command", &len);
+               data = of_get_property(ofdev->dev.of_node, "fsl,cpm-command", &len);
                if (!data || len != 4)
                        goto out_free_fpi;
 
@@ -1025,8 +1025,8 @@ static int __devinit fs_enet_probe(struct of_device *ofdev,
        fpi->rx_copybreak = 240;
        fpi->use_napi = 1;
        fpi->napi_weight = 17;
-       fpi->phy_node = of_parse_phandle(ofdev->node, "phy-handle", 0);
-       if ((!fpi->phy_node) && (!of_get_property(ofdev->node, "fixed-link",
+       fpi->phy_node = of_parse_phandle(ofdev->dev.of_node, "phy-handle", 0);
+       if ((!fpi->phy_node) && (!of_get_property(ofdev->dev.of_node, "fixed-link",
                                                  NULL)))
                goto out_free_fpi;
 
@@ -1059,7 +1059,7 @@ static int __devinit fs_enet_probe(struct of_device *ofdev,
        spin_lock_init(&fep->lock);
        spin_lock_init(&fep->tx_lock);
 
-       mac_addr = of_get_mac_address(ofdev->node);
+       mac_addr = of_get_mac_address(ofdev->dev.of_node);
        if (mac_addr)
                memcpy(ndev->dev_addr, mac_addr, 6);
 
@@ -1156,8 +1156,11 @@ static struct of_device_id fs_enet_match[] = {
 MODULE_DEVICE_TABLE(of, fs_enet_match);
 
 static struct of_platform_driver fs_enet_driver = {
-       .name   = "fs_enet",
-       .match_table = fs_enet_match,
+       .driver = {
+               .owner = THIS_MODULE,
+               .name = "fs_enet",
+               .of_match_table = fs_enet_match,
+       },
        .probe = fs_enet_probe,
        .remove = fs_enet_remove,
 };
index 714da967fa19bde3162c5be324bd48fcd19e926f..5d45084b287d13afa6d24dcfc02d18f56afb0ce1 100644 (file)
@@ -88,19 +88,19 @@ static int do_pd_setup(struct fs_enet_private *fep)
        struct fs_platform_info *fpi = fep->fpi;
        int ret = -EINVAL;
 
-       fep->interrupt = of_irq_to_resource(ofdev->node, 0, NULL);
+       fep->interrupt = of_irq_to_resource(ofdev->dev.of_node, 0, NULL);
        if (fep->interrupt == NO_IRQ)
                goto out;
 
-       fep->fcc.fccp = of_iomap(ofdev->node, 0);
+       fep->fcc.fccp = of_iomap(ofdev->dev.of_node, 0);
        if (!fep->fcc.fccp)
                goto out;
 
-       fep->fcc.ep = of_iomap(ofdev->node, 1);
+       fep->fcc.ep = of_iomap(ofdev->dev.of_node, 1);
        if (!fep->fcc.ep)
                goto out_fccp;
 
-       fep->fcc.fcccp = of_iomap(ofdev->node, 2);
+       fep->fcc.fcccp = of_iomap(ofdev->dev.of_node, 2);
        if (!fep->fcc.fcccp)
                goto out_ep;
 
index 7eff92ef01da4de9e28857cfbe0a5c69f4789b41..7ca1642276d02e44949a966f3107c7b36c82ea03 100644 (file)
@@ -98,11 +98,11 @@ static int do_pd_setup(struct fs_enet_private *fep)
 {
        struct of_device *ofdev = to_of_device(fep->dev);
 
-       fep->interrupt = of_irq_to_resource(ofdev->node, 0, NULL);
+       fep->interrupt = of_irq_to_resource(ofdev->dev.of_node, 0, NULL);
        if (fep->interrupt == NO_IRQ)
                return -EINVAL;
 
-       fep->fec.fecp = of_iomap(ofdev->node, 0);
+       fep->fec.fecp = of_iomap(ofdev->dev.of_node, 0);
        if (!fep->fcc.fccp)
                return -EINVAL;
 
index 7f0591e43cd992feac439dbdd83bbb7a9ae17d42..a3c44544846d5ab2ef1a54e205c51e4e79310688 100644 (file)
@@ -98,15 +98,15 @@ static int do_pd_setup(struct fs_enet_private *fep)
 {
        struct of_device *ofdev = to_of_device(fep->dev);
 
-       fep->interrupt = of_irq_to_resource(ofdev->node, 0, NULL);
+       fep->interrupt = of_irq_to_resource(ofdev->dev.of_node, 0, NULL);
        if (fep->interrupt == NO_IRQ)
                return -EINVAL;
 
-       fep->scc.sccp = of_iomap(ofdev->node, 0);
+       fep->scc.sccp = of_iomap(ofdev->dev.of_node, 0);
        if (!fep->scc.sccp)
                return -EINVAL;
 
-       fep->scc.ep = of_iomap(ofdev->node, 1);
+       fep->scc.ep = of_iomap(ofdev->dev.of_node, 1);
        if (!fep->scc.ep) {
                iounmap(fep->scc.sccp);
                return -EINVAL;
index 24ff9f43a62b4e6378da3f231b280e75258bfce9..0f90685d3d19472e3bc0dc9b05ed5872a5fa9f63 100644 (file)
@@ -224,8 +224,11 @@ static struct of_device_id fs_enet_mdio_bb_match[] = {
 MODULE_DEVICE_TABLE(of, fs_enet_mdio_bb_match);
 
 static struct of_platform_driver fs_enet_bb_mdio_driver = {
-       .name = "fsl-bb-mdio",
-       .match_table = fs_enet_mdio_bb_match,
+       .driver = {
+               .name = "fsl-bb-mdio",
+               .owner = THIS_MODULE,
+               .of_match_table = fs_enet_mdio_bb_match,
+       },
        .probe = fs_enet_mdio_probe,
        .remove = fs_enet_mdio_remove,
 };
index 5944b65082cb2a11ef13b16f2cb12c853b9b65c3..bddffd169b93888cfab8d97f05de9136063a81cb 100644 (file)
@@ -124,7 +124,7 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
        new_bus->write = &fs_enet_fec_mii_write;
        new_bus->reset = &fs_enet_fec_mii_reset;
 
-       ret = of_address_to_resource(ofdev->node, 0, &res);
+       ret = of_address_to_resource(ofdev->dev.of_node, 0, &res);
        if (ret)
                goto out_res;
 
@@ -135,7 +135,7 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
                goto out_fec;
 
        if (get_bus_freq) {
-               clock = get_bus_freq(ofdev->node);
+               clock = get_bus_freq(ofdev->dev.of_node);
                if (!clock) {
                        /* Use maximum divider if clock is unknown */
                        dev_warn(&ofdev->dev, "could not determine IPS clock\n");
@@ -172,7 +172,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;
 
@@ -222,8 +222,11 @@ static struct of_device_id fs_enet_mdio_fec_match[] = {
 MODULE_DEVICE_TABLE(of, fs_enet_mdio_fec_match);
 
 static struct of_platform_driver fs_enet_fec_mdio_driver = {
-       .name = "fsl-fec-mdio",
-       .match_table = fs_enet_mdio_fec_match,
+       .driver = {
+               .name = "fsl-fec-mdio",
+               .owner = THIS_MODULE,
+               .of_match_table = fs_enet_mdio_fec_match,
+       },
        .probe = fs_enet_mdio_probe,
        .remove = fs_enet_mdio_remove,
 };
index ff028f59b9306c086f03df626e5cecf31d131a22..b4c41d72c423ef79e004bd901f23ef03f96e311f 100644 (file)
@@ -267,7 +267,7 @@ static int get_ucc_id_for_range(u64 start, u64 end, u32 *ucc_id)
 static int fsl_pq_mdio_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 device_node *tbi;
        struct fsl_pq_mdio_priv *priv;
        struct fsl_pq_mdio __iomem *regs = NULL;
@@ -471,10 +471,13 @@ static struct of_device_id fsl_pq_mdio_match[] = {
 MODULE_DEVICE_TABLE(of, fsl_pq_mdio_match);
 
 static struct of_platform_driver fsl_pq_mdio_driver = {
-       .name = "fsl-pq_mdio",
+       .driver = {
+               .name = "fsl-pq_mdio",
+               .owner = THIS_MODULE,
+               .of_match_table = fsl_pq_mdio_match,
+       },
        .probe = fsl_pq_mdio_probe,
        .remove = fsl_pq_mdio_remove,
-       .match_table = fsl_pq_mdio_match,
 };
 
 int __init fsl_pq_mdio_init(void)
index c6791cd4ee0537503a70f4cbd2d0a005725c863d..1830f3199cb523080b1a880dd5e834ad9fb8d99a 100644 (file)
@@ -608,7 +608,7 @@ static int gfar_of_init(struct of_device *ofdev, struct net_device **pdev)
        int err = 0, i;
        struct net_device *dev = NULL;
        struct gfar_private *priv = NULL;
-       struct device_node *np = ofdev->node;
+       struct device_node *np = ofdev->dev.of_node;
        struct device_node *child = NULL;
        const u32 *stash;
        const u32 *stash_len;
@@ -646,7 +646,7 @@ static int gfar_of_init(struct of_device *ofdev, struct net_device **pdev)
                return -ENOMEM;
 
        priv = netdev_priv(dev);
-       priv->node = ofdev->node;
+       priv->node = ofdev->dev.of_node;
        priv->ndev = dev;
 
        dev->num_tx_queues = num_tx_qs;
@@ -939,7 +939,7 @@ static int gfar_probe(struct of_device *ofdev,
        priv = netdev_priv(dev);
        priv->ndev = dev;
        priv->ofdev = ofdev;
-       priv->node = ofdev->node;
+       priv->node = ofdev->dev.of_node;
        SET_NETDEV_DEV(dev, &ofdev->dev);
 
        spin_lock_init(&priv->bflock);
@@ -3167,12 +3167,14 @@ MODULE_DEVICE_TABLE(of, gfar_match);
 
 /* Structure for a device driver */
 static struct of_platform_driver gfar_driver = {
-       .name = "fsl-gianfar",
-       .match_table = gfar_match,
-
+       .driver = {
+               .name = "fsl-gianfar",
+               .owner = THIS_MODULE,
+               .pm = GFAR_PM_OPS,
+               .of_match_table = gfar_match,
+       },
        .probe = gfar_probe,
        .remove = gfar_remove,
-       .driver.pm = GFAR_PM_OPS,
 };
 
 static int __init gfar_init(void)
index fd491e409488e0ea0b8947c36f24f4810b012c03..f37a4c143ddddf985556018dc5e21288e23f3207 100644 (file)
@@ -1499,7 +1499,8 @@ static int __devinit greth_of_probe(struct of_device *ofdev, const struct of_dev
        if (i == 6) {
                const unsigned char *addr;
                int len;
-               addr = of_get_property(ofdev->node, "local-mac-address", &len);
+               addr = of_get_property(ofdev->dev.of_node, "local-mac-address",
+                                       &len);
                if (addr != NULL && len == 6) {
                        for (i = 0; i < 6; i++)
                                macaddr[i] = (unsigned int) addr[i];
index 694132e04af697a4b78518708d0e6471046223bc..4e7d1d0a23401d3d3601ac671d5ba1d60aac7399 100644 (file)
@@ -1151,8 +1151,7 @@ static int __init yam_init_driver(void)
                dev = alloc_netdev(sizeof(struct yam_port), name,
                                   yam_setup);
                if (!dev) {
-                       printk(KERN_ERR "yam: cannot allocate net device %s\n",
-                              dev->name);
+                       pr_err("yam: cannot allocate net device\n");
                        err = -ENOMEM;
                        goto error;
                }
index 2484e9e6c1edd0f7dd06026d4111b6dadab7ea12..b150c102ca5ace67ce0fb988266ba88b13023cbe 100644 (file)
@@ -136,7 +136,8 @@ static inline void emac_report_timeout_error(struct emac_instance *dev,
                                  EMAC_FTR_440EP_PHY_CLK_FIX))
                DBG(dev, "%s" NL, error);
        else if (net_ratelimit())
-               printk(KERN_ERR "%s: %s\n", dev->ofdev->node->full_name, error);
+               printk(KERN_ERR "%s: %s\n", dev->ofdev->dev.of_node->full_name,
+                       error);
 }
 
 /* EMAC PHY clock workaround:
@@ -2185,7 +2186,7 @@ static void emac_ethtool_get_drvinfo(struct net_device *ndev,
        strcpy(info->version, DRV_VERSION);
        info->fw_version[0] = '\0';
        sprintf(info->bus_info, "PPC 4xx EMAC-%d %s",
-               dev->cell_index, dev->ofdev->node->full_name);
+               dev->cell_index, dev->ofdev->dev.of_node->full_name);
        info->regdump_len = emac_ethtool_get_regs_len(ndev);
 }
 
@@ -2379,7 +2380,7 @@ static int __devinit emac_read_uint_prop(struct device_node *np, const char *nam
 
 static int __devinit emac_init_phy(struct emac_instance *dev)
 {
-       struct device_node *np = dev->ofdev->node;
+       struct device_node *np = dev->ofdev->dev.of_node;
        struct net_device *ndev = dev->ndev;
        u32 phy_map, adv;
        int i;
@@ -2514,7 +2515,7 @@ static int __devinit emac_init_phy(struct emac_instance *dev)
 
 static int __devinit emac_init_config(struct emac_instance *dev)
 {
-       struct device_node *np = dev->ofdev->node;
+       struct device_node *np = dev->ofdev->dev.of_node;
        const void *p;
        unsigned int plen;
        const char *pm, *phy_modes[] = {
@@ -2723,7 +2724,7 @@ static int __devinit emac_probe(struct of_device *ofdev,
 {
        struct net_device *ndev;
        struct emac_instance *dev;
-       struct device_node *np = ofdev->node;
+       struct device_node *np = ofdev->dev.of_node;
        struct device_node **blist = NULL;
        int err, i;
 
@@ -2810,7 +2811,7 @@ static int __devinit emac_probe(struct of_device *ofdev,
        err = mal_register_commac(dev->mal, &dev->commac);
        if (err) {
                printk(KERN_ERR "%s: failed to register with mal %s!\n",
-                      np->full_name, dev->mal_dev->node->full_name);
+                      np->full_name, dev->mal_dev->dev.of_node->full_name);
                goto err_rel_deps;
        }
        dev->rx_skb_size = emac_rx_skb_size(ndev->mtu);
@@ -2995,9 +2996,11 @@ static struct of_device_id emac_match[] =
 MODULE_DEVICE_TABLE(of, emac_match);
 
 static struct of_platform_driver emac_driver = {
-       .name = "emac",
-       .match_table = emac_match,
-
+       .driver = {
+               .name = "emac",
+               .owner = THIS_MODULE,
+               .of_match_table = emac_match,
+       },
        .probe = emac_probe,
        .remove = emac_remove,
 };
index 775c850a425a311e9341718fa85b302641fb942b..3995fafc1e08bb3adb8658bd4d0098c4aff09f60 100644 (file)
@@ -33,7 +33,7 @@ static void emac_desc_dump(struct emac_instance *p)
        int i;
        printk("** EMAC %s TX BDs **\n"
               " tx_cnt = %d tx_slot = %d ack_slot = %d\n",
-              p->ofdev->node->full_name,
+              p->ofdev->dev.of_node->full_name,
               p->tx_cnt, p->tx_slot, p->ack_slot);
        for (i = 0; i < NUM_TX_BUFF / 2; ++i)
                printk
@@ -49,7 +49,7 @@ static void emac_desc_dump(struct emac_instance *p)
        printk("** EMAC %s RX BDs **\n"
               " rx_slot = %d flags = 0x%lx rx_skb_size = %d rx_sync_size = %d\n"
               " rx_sg_skb = 0x%p\n",
-              p->ofdev->node->full_name,
+              p->ofdev->dev.of_node->full_name,
               p->rx_slot, p->commac.flags, p->rx_skb_size,
               p->rx_sync_size, p->rx_sg_skb);
        for (i = 0; i < NUM_RX_BUFF / 2; ++i)
@@ -77,7 +77,8 @@ static void emac_mac_dump(struct emac_instance *dev)
               "MR0 = 0x%08x MR1 = 0x%08x TMR0 = 0x%08x TMR1 = 0x%08x\n"
               "RMR = 0x%08x ISR = 0x%08x ISER = 0x%08x\n"
               "IAR = %04x%08x VTPID = 0x%04x VTCI = 0x%04x\n",
-              dev->ofdev->node->full_name, in_be32(&p->mr0), in_be32(&p->mr1),
+              dev->ofdev->dev.of_node->full_name,
+              in_be32(&p->mr0), in_be32(&p->mr1),
               in_be32(&p->tmr0), in_be32(&p->tmr1),
               in_be32(&p->rmr), in_be32(&p->isr), in_be32(&p->iser),
               in_be32(&p->iahr), in_be32(&p->ialr), in_be32(&p->vtpid),
@@ -128,7 +129,7 @@ static void emac_mal_dump(struct mal_instance *mal)
               "CFG = 0x%08x ESR = 0x%08x IER = 0x%08x\n"
               "TX|CASR = 0x%08x CARR = 0x%08x EOBISR = 0x%08x DEIR = 0x%08x\n"
               "RX|CASR = 0x%08x CARR = 0x%08x EOBISR = 0x%08x DEIR = 0x%08x\n",
-              mal->ofdev->node->full_name,
+              mal->ofdev->dev.of_node->full_name,
               get_mal_dcrn(mal, MAL_CFG), get_mal_dcrn(mal, MAL_ESR),
               get_mal_dcrn(mal, MAL_IER),
               get_mal_dcrn(mal, MAL_TXCASR), get_mal_dcrn(mal, MAL_TXCARR),
index b631842ec8d00a2cd861bde288cd7c768bc141d0..e596c77ccdf7ea54e1fb64054bc89f1b3ac07a6b 100644 (file)
@@ -53,8 +53,8 @@ extern void emac_dbg_dump_all(void);
 
 #endif
 
-#define EMAC_DBG(dev, name, fmt, arg...) \
-       printk(KERN_DEBUG #name "%s: " fmt, dev->ofdev->node->full_name, ## arg)
+#define EMAC_DBG(d, name, fmt, arg...) \
+       printk(KERN_DEBUG #name "%s: " fmt, d->ofdev->dev.of_node->full_name, ## arg)
 
 #if DBG_LEVEL > 0
 #  define DBG(d,f,x...)                EMAC_DBG(d, emac, f, ##x)
index 5b3d94419fe6aa1ba94c2e1c8e00cc30f925ccdc..fcff9e0bd3827396546398c5f5feb2cc4269c90f 100644 (file)
@@ -538,11 +538,11 @@ static int __devinit mal_probe(struct of_device *ofdev,
        }
        mal->index = index;
        mal->ofdev = ofdev;
-       mal->version = of_device_is_compatible(ofdev->node, "ibm,mcmal2") ? 2 : 1;
+       mal->version = of_device_is_compatible(ofdev->dev.of_node, "ibm,mcmal2") ? 2 : 1;
 
        MAL_DBG(mal, "probe" NL);
 
-       prop = of_get_property(ofdev->node, "num-tx-chans", NULL);
+       prop = of_get_property(ofdev->dev.of_node, "num-tx-chans", NULL);
        if (prop == NULL) {
                printk(KERN_ERR
                       "mal%d: can't find MAL num-tx-chans property!\n",
@@ -552,7 +552,7 @@ static int __devinit mal_probe(struct of_device *ofdev,
        }
        mal->num_tx_chans = prop[0];
 
-       prop = of_get_property(ofdev->node, "num-rx-chans", NULL);
+       prop = of_get_property(ofdev->dev.of_node, "num-rx-chans", NULL);
        if (prop == NULL) {
                printk(KERN_ERR
                       "mal%d: can't find MAL num-rx-chans property!\n",
@@ -562,14 +562,14 @@ static int __devinit mal_probe(struct of_device *ofdev,
        }
        mal->num_rx_chans = prop[0];
 
-       dcr_base = dcr_resource_start(ofdev->node, 0);
+       dcr_base = dcr_resource_start(ofdev->dev.of_node, 0);
        if (dcr_base == 0) {
                printk(KERN_ERR
                       "mal%d: can't find DCR resource!\n", index);
                err = -ENODEV;
                goto fail;
        }
-       mal->dcr_host = dcr_map(ofdev->node, dcr_base, 0x100);
+       mal->dcr_host = dcr_map(ofdev->dev.of_node, dcr_base, 0x100);
        if (!DCR_MAP_OK(mal->dcr_host)) {
                printk(KERN_ERR
                       "mal%d: failed to map DCRs !\n", index);
@@ -577,28 +577,28 @@ static int __devinit mal_probe(struct of_device *ofdev,
                goto fail;
        }
 
-       if (of_device_is_compatible(ofdev->node, "ibm,mcmal-405ez")) {
+       if (of_device_is_compatible(ofdev->dev.of_node, "ibm,mcmal-405ez")) {
 #if defined(CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT) && \
                defined(CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR)
                mal->features |= (MAL_FTR_CLEAR_ICINTSTAT |
                                MAL_FTR_COMMON_ERR_INT);
 #else
                printk(KERN_ERR "%s: Support for 405EZ not enabled!\n",
-                               ofdev->node->full_name);
+                               ofdev->dev.of_node->full_name);
                err = -ENODEV;
                goto fail;
 #endif
        }
 
-       mal->txeob_irq = irq_of_parse_and_map(ofdev->node, 0);
-       mal->rxeob_irq = irq_of_parse_and_map(ofdev->node, 1);
-       mal->serr_irq = irq_of_parse_and_map(ofdev->node, 2);
+       mal->txeob_irq = irq_of_parse_and_map(ofdev->dev.of_node, 0);
+       mal->rxeob_irq = irq_of_parse_and_map(ofdev->dev.of_node, 1);
+       mal->serr_irq = irq_of_parse_and_map(ofdev->dev.of_node, 2);
 
        if (mal_has_feature(mal, MAL_FTR_COMMON_ERR_INT)) {
                mal->txde_irq = mal->rxde_irq = mal->serr_irq;
        } else {
-               mal->txde_irq = irq_of_parse_and_map(ofdev->node, 3);
-               mal->rxde_irq = irq_of_parse_and_map(ofdev->node, 4);
+               mal->txde_irq = irq_of_parse_and_map(ofdev->dev.of_node, 3);
+               mal->rxde_irq = irq_of_parse_and_map(ofdev->dev.of_node, 4);
        }
 
        if (mal->txeob_irq == NO_IRQ || mal->rxeob_irq == NO_IRQ ||
@@ -629,7 +629,7 @@ static int __devinit mal_probe(struct of_device *ofdev,
        /* Current Axon is not happy with priority being non-0, it can
         * deadlock, fix it up here
         */
-       if (of_device_is_compatible(ofdev->node, "ibm,mcmal-axon"))
+       if (of_device_is_compatible(ofdev->dev.of_node, "ibm,mcmal-axon"))
                cfg &= ~(MAL2_CFG_RPP_10 | MAL2_CFG_WPP_10);
 
        /* Apply configuration */
@@ -701,7 +701,7 @@ static int __devinit mal_probe(struct of_device *ofdev,
 
        printk(KERN_INFO
               "MAL v%d %s, %d TX channels, %d RX channels\n",
-              mal->version, ofdev->node->full_name,
+              mal->version, ofdev->dev.of_node->full_name,
               mal->num_tx_chans, mal->num_rx_chans);
 
        /* Advertise this instance to the rest of the world */
@@ -790,9 +790,11 @@ static struct of_device_id mal_platform_match[] =
 };
 
 static struct of_platform_driver mal_of_driver = {
-       .name = "mcmal",
-       .match_table = mal_platform_match,
-
+       .driver = {
+               .name = "mcmal",
+               .owner = THIS_MODULE,
+               .of_match_table = mal_platform_match,
+       },
        .probe = mal_probe,
        .remove = mal_remove,
 };
index 5b90d34c845502dc789b4c87b6bc35e9f2a89f64..108919bcdf137959d9bb2b5957607132ebabb407 100644 (file)
@@ -103,7 +103,7 @@ int __devinit rgmii_attach(struct of_device *ofdev, int input, int mode)
        /* Check if we need to attach to a RGMII */
        if (input < 0 || !rgmii_valid_mode(mode)) {
                printk(KERN_ERR "%s: unsupported settings !\n",
-                      ofdev->node->full_name);
+                      ofdev->dev.of_node->full_name);
                return -ENODEV;
        }
 
@@ -113,7 +113,7 @@ int __devinit rgmii_attach(struct of_device *ofdev, int input, int mode)
        out_be32(&p->fer, in_be32(&p->fer) | rgmii_mode_mask(mode, input));
 
        printk(KERN_NOTICE "%s: input %d in %s mode\n",
-              ofdev->node->full_name, input, rgmii_mode_name(mode));
+              ofdev->dev.of_node->full_name, input, rgmii_mode_name(mode));
 
        ++dev->users;
 
@@ -231,7 +231,7 @@ void *rgmii_dump_regs(struct of_device *ofdev, void *buf)
 static int __devinit rgmii_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 rgmii_instance *dev;
        struct resource regs;
        int rc;
@@ -264,11 +264,11 @@ static int __devinit rgmii_probe(struct of_device *ofdev,
        }
 
        /* Check for RGMII flags */
-       if (of_get_property(ofdev->node, "has-mdio", NULL))
+       if (of_get_property(ofdev->dev.of_node, "has-mdio", NULL))
                dev->flags |= EMAC_RGMII_FLAG_HAS_MDIO;
 
        /* CAB lacks the right properties, fix this up */
-       if (of_device_is_compatible(ofdev->node, "ibm,rgmii-axon"))
+       if (of_device_is_compatible(ofdev->dev.of_node, "ibm,rgmii-axon"))
                dev->flags |= EMAC_RGMII_FLAG_HAS_MDIO;
 
        DBG2(dev, " Boot FER = 0x%08x, SSR = 0x%08x\n",
@@ -279,7 +279,7 @@ static int __devinit rgmii_probe(struct of_device *ofdev,
 
        printk(KERN_INFO
               "RGMII %s initialized with%s MDIO support\n",
-              ofdev->node->full_name,
+              ofdev->dev.of_node->full_name,
               (dev->flags & EMAC_RGMII_FLAG_HAS_MDIO) ? "" : "out");
 
        wmb();
@@ -319,9 +319,11 @@ static struct of_device_id rgmii_match[] =
 };
 
 static struct of_platform_driver rgmii_driver = {
-       .name = "emac-rgmii",
-       .match_table = rgmii_match,
-
+       .driver = {
+               .name = "emac-rgmii",
+               .owner = THIS_MODULE,
+               .of_match_table = rgmii_match,
+       },
        .probe = rgmii_probe,
        .remove = rgmii_remove,
 };
index 30173a9fb557d930f543d0c237f3fff0a5cb777b..044637144c4349b4291351fc38772b17f0355830 100644 (file)
@@ -57,7 +57,8 @@ void tah_reset(struct of_device *ofdev)
                --n;
 
        if (unlikely(!n))
-               printk(KERN_ERR "%s: reset timeout\n", ofdev->node->full_name);
+               printk(KERN_ERR "%s: reset timeout\n",
+                       ofdev->dev.of_node->full_name);
 
        /* 10KB TAH TX FIFO accomodates the max MTU of 9000 */
        out_be32(&p->mr,
@@ -89,7 +90,7 @@ void *tah_dump_regs(struct of_device *ofdev, void *buf)
 static int __devinit tah_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 tah_instance *dev;
        struct resource regs;
        int rc;
@@ -127,7 +128,7 @@ static int __devinit tah_probe(struct of_device *ofdev,
        tah_reset(ofdev);
 
        printk(KERN_INFO
-              "TAH %s initialized\n", ofdev->node->full_name);
+              "TAH %s initialized\n", ofdev->dev.of_node->full_name);
        wmb();
 
        return 0;
@@ -165,9 +166,11 @@ static struct of_device_id tah_match[] =
 };
 
 static struct of_platform_driver tah_driver = {
-       .name = "emac-tah",
-       .match_table = tah_match,
-
+       .driver = {
+               .name = "emac-tah",
+               .owner = THIS_MODULE,
+               .of_match_table = tah_match,
+       },
        .probe = tah_probe,
        .remove = tah_remove,
 };
index 1f038f808ab32512fdb78ae01b4f54f9f152d5a2..046dcd069c4556c2cddf68eb772577b3ca6e00ff 100644 (file)
@@ -121,13 +121,14 @@ int __devinit zmii_attach(struct of_device *ofdev, int input, int *mode)
                        dev->mode = *mode;
 
                printk(KERN_NOTICE "%s: bridge in %s mode\n",
-                      ofdev->node->full_name, zmii_mode_name(dev->mode));
+                      ofdev->dev.of_node->full_name,
+                      zmii_mode_name(dev->mode));
        } else {
                /* All inputs must use the same mode */
                if (*mode != PHY_MODE_NA && *mode != dev->mode) {
                        printk(KERN_ERR
                               "%s: invalid mode %d specified for input %d\n",
-                              ofdev->node->full_name, *mode, input);
+                              ofdev->dev.of_node->full_name, *mode, input);
                        mutex_unlock(&dev->lock);
                        return -EINVAL;
                }
@@ -233,7 +234,7 @@ void *zmii_dump_regs(struct of_device *ofdev, void *buf)
 static int __devinit zmii_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 zmii_instance *dev;
        struct resource regs;
        int rc;
@@ -273,7 +274,7 @@ static int __devinit zmii_probe(struct of_device *ofdev,
        out_be32(&dev->base->fer, 0);
 
        printk(KERN_INFO
-              "ZMII %s initialized\n", ofdev->node->full_name);
+              "ZMII %s initialized\n", ofdev->dev.of_node->full_name);
        wmb();
        dev_set_drvdata(&ofdev->dev, dev);
 
@@ -312,9 +313,11 @@ static struct of_device_id zmii_match[] =
 };
 
 static struct of_platform_driver zmii_driver = {
-       .name = "emac-zmii",
-       .match_table = zmii_match,
-
+       .driver = {
+               .name = "emac-zmii",
+               .owner = THIS_MODULE,
+               .of_match_table = zmii_match,
+       },
        .probe = zmii_probe,
        .remove = zmii_remove,
 };
index 911c082cee5acfa258211b117c1f018bcd9dbb49..f940dfa1f7f84e713033057605bfb069618ec0bb 100644 (file)
@@ -107,8 +107,12 @@ static int bfin_sir_set_speed(struct bfin_sir_port *port, int speed)
        case 57600:
        case 115200:
 
-               quot = (port->clk + (8 * speed)) / (16 * speed)\
-                                               - ANOMALY_05000230;
+               /*
+                * IRDA is not affected by anomaly 05000230, so there is no
+                * need to tweak the divisor like he UART driver (which will
+                * slightly speed up the baud rate on us).
+                */
+               quot = (port->clk + (8 * speed)) / (16 * speed);
 
                do {
                        udelay(utime);
index d0ea3d6dea95f6f26b2fe3f9534c8b445c810cc6..ffae480587ae909fa482dda292f8802ca15565c8 100644 (file)
@@ -360,6 +360,7 @@ struct ixgbe_adapter {
        u32 flags2;
 #define IXGBE_FLAG2_RSC_CAPABLE                 (u32)(1)
 #define IXGBE_FLAG2_RSC_ENABLED                 (u32)(1 << 1)
+#define IXGBE_FLAG2_TEMP_SENSOR_CAPABLE         (u32)(1 << 2)
 /* default to trying for four seconds */
 #define IXGBE_TRY_LINK_TIMEOUT (4 * HZ)
 
@@ -407,6 +408,8 @@ struct ixgbe_adapter {
        u16 eeprom_version;
 
        int node;
+       struct work_struct check_overtemp_task;
+       u32 interrupt_event;
 
        /* SR-IOV */
        DECLARE_BITMAP(active_vfs, IXGBE_MAX_VF_FUNCTIONS);
index f2b7ff44215b52b3f9608d6593d22792273727f5..9c02d6014cc43856fa405d8b0c0cc140aef63dde 100644 (file)
@@ -1236,6 +1236,7 @@ static struct ixgbe_phy_operations phy_ops_82598 = {
        .setup_link             = &ixgbe_setup_phy_link_generic,
        .setup_link_speed       = &ixgbe_setup_phy_link_speed_generic,
        .read_i2c_eeprom        = &ixgbe_read_i2c_eeprom_82598,
+       .check_overtemp   = &ixgbe_tn_check_overtemp,
 };
 
 struct ixgbe_info ixgbe_82598_info = {
index e9706eb8e4ff58fdb805e12094438a3e14437bb9..a4e2901f2f08e5bc585fb5889c174d754a2672e3 100644 (file)
@@ -2395,6 +2395,7 @@ static struct ixgbe_phy_operations phy_ops_82599 = {
        .write_i2c_byte         = &ixgbe_write_i2c_byte_generic,
        .read_i2c_eeprom        = &ixgbe_read_i2c_eeprom_generic,
        .write_i2c_eeprom       = &ixgbe_write_i2c_eeprom_generic,
+       .check_overtemp         = &ixgbe_tn_check_overtemp,
 };
 
 struct ixgbe_info ixgbe_82599_info = {
index 9551cbb7bf01f532e3a5705f9e54e45d0cf8ae6e..d571d101de08fb4c183af77cb9b64d10904d10a7 100644 (file)
@@ -108,6 +108,8 @@ static DEFINE_PCI_DEVICE_TABLE(ixgbe_pci_tbl) = {
         board_82599 },
        {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_CX4),
         board_82599 },
+       {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_T3_LOM),
+        board_82599 },
        {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_COMBO_BACKPLANE),
         board_82599 },
 
@@ -1618,6 +1620,48 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector)
        }
 }
 
+/**
+ * ixgbe_check_overtemp_task - worker thread to check over tempurature
+ * @work: pointer to work_struct containing our data
+ **/
+static void ixgbe_check_overtemp_task(struct work_struct *work)
+{
+       struct ixgbe_adapter *adapter = container_of(work,
+                                                    struct ixgbe_adapter,
+                                                    check_overtemp_task);
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 eicr = adapter->interrupt_event;
+
+       if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) {
+               switch (hw->device_id) {
+               case IXGBE_DEV_ID_82599_T3_LOM: {
+                       u32 autoneg;
+                       bool link_up = false;
+
+                       if (hw->mac.ops.check_link)
+                               hw->mac.ops.check_link(hw, &autoneg, &link_up, false);
+
+                       if (((eicr & IXGBE_EICR_GPI_SDP0) && (!link_up)) ||
+                           (eicr & IXGBE_EICR_LSC))
+                               /* Check if this is due to overtemp */
+                               if (hw->phy.ops.check_overtemp(hw) == IXGBE_ERR_OVERTEMP)
+                                       break;
+                       }
+                       return;
+               default:
+                       if (!(eicr & IXGBE_EICR_GPI_SDP0))
+                               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");
+               /* write to clear the interrupt */
+               IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0);
+       }
+}
+
 static void ixgbe_check_fan_failure(struct ixgbe_adapter *adapter, u32 eicr)
 {
        struct ixgbe_hw *hw = &adapter->hw;
@@ -1689,6 +1733,10 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data)
 
        if (hw->mac.type == ixgbe_mac_82599EB) {
                ixgbe_check_sfp_event(adapter, eicr);
+               adapter->interrupt_event = eicr;
+               if ((adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) &&
+                   ((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC)))
+                       schedule_work(&adapter->check_overtemp_task);
 
                /* Handle Flow Director Full threshold interrupt */
                if (eicr & IXGBE_EICR_FLOW_DIR) {
@@ -2190,6 +2238,8 @@ static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter)
        u32 mask;
 
        mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE);
+       if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE)
+               mask |= IXGBE_EIMS_GPI_SDP0;
        if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE)
                mask |= IXGBE_EIMS_GPI_SDP1;
        if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
@@ -2250,6 +2300,9 @@ static irqreturn_t ixgbe_intr(int irq, void *data)
                ixgbe_check_sfp_event(adapter, eicr);
 
        ixgbe_check_fan_failure(adapter, eicr);
+       if ((adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) &&
+           ((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC)))
+               schedule_work(&adapter->check_overtemp_task);
 
        if (napi_schedule_prep(&(q_vector->napi))) {
                adapter->tx_ring[0]->total_packets = 0;
@@ -3265,6 +3318,13 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
                IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE);
        }
 
+       /* Enable Thermal over heat sensor interrupt */
+       if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) {
+               gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
+               gpie |= IXGBE_SDP0_GPIEN;
+               IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
+       }
+
        /* Enable fan failure interrupt if media type is copper */
        if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) {
                gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
@@ -3666,6 +3726,9 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
            adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)
                cancel_work_sync(&adapter->fdir_reinit_task);
 
+       if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE)
+               cancel_work_sync(&adapter->check_overtemp_task);
+
        /* disable transmits in the hardware now that interrupts are off */
        for (i = 0; i < adapter->num_tx_queues; i++) {
                j = adapter->tx_ring[i]->reg_idx;
@@ -4645,6 +4708,8 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
                adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82599;
                adapter->flags2 |= IXGBE_FLAG2_RSC_CAPABLE;
                adapter->flags2 |= IXGBE_FLAG2_RSC_ENABLED;
+               if (hw->device_id == IXGBE_DEV_ID_82599_T3_LOM)
+                       adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_CAPABLE;
                if (dev->features & NETIF_F_NTUPLE) {
                        /* Flow Director perfect filter enabled */
                        adapter->flags |= IXGBE_FLAG_FDIR_PERFECT_CAPABLE;
@@ -6561,7 +6626,9 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
        }
 
        /* reset_hw fills in the perm_addr as well */
+       hw->phy.reset_if_overtemp = true;
        err = hw->mac.ops.reset_hw(hw);
+       hw->phy.reset_if_overtemp = false;
        if (err == IXGBE_ERR_SFP_NOT_PRESENT &&
            hw->mac.type == ixgbe_mac_82598EB) {
                /*
@@ -6730,6 +6797,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
            adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)
                INIT_WORK(&adapter->fdir_reinit_task, ixgbe_fdir_reinit_task);
 
+       if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE)
+               INIT_WORK(&adapter->check_overtemp_task, ixgbe_check_overtemp_task);
 #ifdef CONFIG_IXGBE_DCA
        if (dca_add_requester(&pdev->dev) == 0) {
                adapter->flags |= IXGBE_FLAG_DCA_ENABLED;
index 22d21af1478326b7c332f72b7c2759566addb43c..09e1911ff510474ecda600446a51330d057647e3 100644 (file)
@@ -135,6 +135,11 @@ static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id)
  **/
 s32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw)
 {
+       /* Don't reset PHY if it's shut down due to overtemp. */
+       if (!hw->phy.reset_if_overtemp &&
+           (IXGBE_ERR_OVERTEMP == hw->phy.ops.check_overtemp(hw)))
+               return 0;
+
        /*
         * Perform soft PHY reset to the PHY_XS.
         * This will cause a soft reset to the PHY
@@ -1345,3 +1350,28 @@ s32 ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw *hw,
        return status;
 }
 
+/**
+ *  ixgbe_tn_check_overtemp - Checks if an overtemp occured.
+ *  @hw: pointer to hardware structure
+ *
+ *  Checks if the LASI temp alarm status was triggered due to overtemp
+ **/
+s32 ixgbe_tn_check_overtemp(struct ixgbe_hw *hw)
+{
+       s32 status = 0;
+       u16 phy_data = 0;
+
+       if (hw->device_id != IXGBE_DEV_ID_82599_T3_LOM)
+               goto out;
+
+       /* Check that the LASI temp alarm status was triggered */
+       hw->phy.ops.read_reg(hw, IXGBE_TN_LASI_STATUS_REG,
+                            MDIO_MMD_PMAPMD, &phy_data);
+
+       if (!(phy_data & IXGBE_TN_LASI_STATUS_TEMP_ALARM))
+               goto out;
+
+       status = IXGBE_ERR_OVERTEMP;
+out:
+       return status;
+}
index c9c545941407fa5f09964c20040f52b5b78bef2f..ef4ba834c593e81220dfa78a9174646cb4289502 100644 (file)
@@ -80,6 +80,8 @@
 #define IXGBE_I2C_T_SU_STO  4
 #define IXGBE_I2C_T_BUF     5
 
+#define IXGBE_TN_LASI_STATUS_REG        0x9005
+#define IXGBE_TN_LASI_STATUS_TEMP_ALARM 0x0008
 
 s32 ixgbe_init_phy_ops_generic(struct ixgbe_hw *hw);
 s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw);
@@ -106,6 +108,7 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw);
 s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
                                         u16 *list_offset,
                                         u16 *data_offset);
+s32 ixgbe_tn_check_overtemp(struct ixgbe_hw *hw);
 s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
                                 u8 dev_addr, u8 *data);
 s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
index 39b9be897439b1d745e7c739c5c0089d0b43bf0c..2eb6e151016cac10ca15eadfd9311283361e09b9 100644 (file)
@@ -51,6 +51,7 @@
 #define IXGBE_DEV_ID_82599_KX4           0x10F7
 #define IXGBE_DEV_ID_82599_KX4_MEZZ      0x1514
 #define IXGBE_DEV_ID_82599_KR            0x1517
+#define IXGBE_DEV_ID_82599_T3_LOM        0x151C
 #define IXGBE_DEV_ID_82599_CX4           0x10F9
 #define IXGBE_DEV_ID_82599_SFP           0x10FB
 #define IXGBE_DEV_ID_82599_SFP_EM        0x1507
@@ -2470,6 +2471,7 @@ struct ixgbe_phy_operations {
        s32 (*write_i2c_byte)(struct ixgbe_hw *, u8, u8, u8);
        s32 (*read_i2c_eeprom)(struct ixgbe_hw *, u8 , u8 *);
        s32 (*write_i2c_eeprom)(struct ixgbe_hw *, u8, u8);
+       s32 (*check_overtemp)(struct ixgbe_hw *);
 };
 
 struct ixgbe_eeprom_info {
@@ -2518,6 +2520,7 @@ struct ixgbe_phy_info {
        enum ixgbe_smart_speed          smart_speed;
        bool                            smart_speed_active;
        bool                            multispeed_fiber;
+       bool                            reset_if_overtemp;
 };
 
 #include "ixgbe_mbx.h"
@@ -2605,6 +2608,7 @@ struct ixgbe_info {
 #define IXGBE_ERR_FDIR_REINIT_FAILED            -23
 #define IXGBE_ERR_EEPROM_VERSION                -24
 #define IXGBE_ERR_NO_SPACE                      -25
+#define IXGBE_ERR_OVERTEMP                      -26
 #define IXGBE_NOT_IMPLEMENTED                   0x7FFFFFFF
 
 #endif /* _IXGBE_TYPE_H_ */
index c03358434acb8f513464764b1a1ec147add0b681..522abe2ff25a2dc5430a333b1599a9b7c9eb3213 100644 (file)
@@ -295,6 +295,10 @@ This option defaults to enabled (set) */
 
 #define MULTICAST_CAM_TABLE_NUM 4
 
+/* TEMAC Synthesis features */
+#define TEMAC_FEATURE_RX_CSUM  (1 << 0)
+#define TEMAC_FEATURE_TX_CSUM  (1 << 1)
+
 /* TX/RX CURDESC_PTR points to first descriptor */
 /* TX/RX TAILDESC_PTR points to last descriptor in linked list */
 
@@ -353,6 +357,7 @@ struct temac_local {
        struct mutex indirect_mutex;
        u32 options;                    /* Current options word */
        int last_link;
+       unsigned int temac_features;
 
        /* Buffer descriptors */
        struct cdmac_bd *tx_bd_v;
index b59b24d667f0a0a4d9b3f823961506465a191b44..52dcc84956477059e44161a00fea68fa5f2e5c1c 100644 (file)
@@ -245,7 +245,7 @@ static int temac_dma_bd_init(struct net_device *ndev)
                                          CHNL_CTRL_IRQ_COAL_EN);
        /* 0x10220483 */
        /* 0x00100483 */
-       lp->dma_out(lp, RX_CHNL_CTRL, 0xff010000 |
+       lp->dma_out(lp, RX_CHNL_CTRL, 0xff070000 |
                                          CHNL_CTRL_IRQ_EN |
                                          CHNL_CTRL_IRQ_DLY_EN |
                                          CHNL_CTRL_IRQ_COAL_EN |
@@ -574,6 +574,10 @@ static void temac_start_xmit_done(struct net_device *ndev)
                if (cur_p->app4)
                        dev_kfree_skb_irq((struct sk_buff *)cur_p->app4);
                cur_p->app0 = 0;
+               cur_p->app1 = 0;
+               cur_p->app2 = 0;
+               cur_p->app3 = 0;
+               cur_p->app4 = 0;
 
                ndev->stats.tx_packets++;
                ndev->stats.tx_bytes += cur_p->len;
@@ -589,6 +593,29 @@ static void temac_start_xmit_done(struct net_device *ndev)
        netif_wake_queue(ndev);
 }
 
+static inline int temac_check_tx_bd_space(struct temac_local *lp, int num_frag)
+{
+       struct cdmac_bd *cur_p;
+       int tail;
+
+       tail = lp->tx_bd_tail;
+       cur_p = &lp->tx_bd_v[tail];
+
+       do {
+               if (cur_p->app0)
+                       return NETDEV_TX_BUSY;
+
+               tail++;
+               if (tail >= TX_BD_NUM)
+                       tail = 0;
+
+               cur_p = &lp->tx_bd_v[tail];
+               num_frag--;
+       } while (num_frag >= 0);
+
+       return 0;
+}
+
 static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
        struct temac_local *lp = netdev_priv(ndev);
@@ -603,7 +630,7 @@ static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        start_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail;
        cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
 
-       if (cur_p->app0 & STS_CTRL_APP0_CMPLT) {
+       if (temac_check_tx_bd_space(lp, num_frag)) {
                if (!netif_queue_stopped(ndev)) {
                        netif_stop_queue(ndev);
                        return NETDEV_TX_BUSY;
@@ -613,29 +640,14 @@ static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 
        cur_p->app0 = 0;
        if (skb->ip_summed == CHECKSUM_PARTIAL) {
-               const struct iphdr *ip = ip_hdr(skb);
-               int length = 0, start = 0, insert = 0;
-
-               switch (ip->protocol) {
-               case IPPROTO_TCP:
-                       start = sizeof(struct iphdr) + ETH_HLEN;
-                       insert = sizeof(struct iphdr) + ETH_HLEN + 16;
-                       length = ip->tot_len - sizeof(struct iphdr);
-                       break;
-               case IPPROTO_UDP:
-                       start = sizeof(struct iphdr) + ETH_HLEN;
-                       insert = sizeof(struct iphdr) + ETH_HLEN + 6;
-                       length = ip->tot_len - sizeof(struct iphdr);
-                       break;
-               default:
-                       break;
-               }
-               cur_p->app1 = ((start << 16) | insert);
-               cur_p->app2 = csum_tcpudp_magic(ip->saddr, ip->daddr,
-                                               length, ip->protocol, 0);
-               skb->data[insert] = 0;
-               skb->data[insert + 1] = 0;
+               unsigned int csum_start_off = skb_transport_offset(skb);
+               unsigned int csum_index_off = csum_start_off + skb->csum_offset;
+
+               cur_p->app0 |= 1; /* TX Checksum Enabled */
+               cur_p->app1 = (csum_start_off << 16) | csum_index_off;
+               cur_p->app2 = 0;  /* initial checksum seed */
        }
+
        cur_p->app0 |= STS_CTRL_APP0_SOP;
        cur_p->len = skb_headlen(skb);
        cur_p->phys = dma_map_single(ndev->dev.parent, skb->data, skb->len,
@@ -699,6 +711,15 @@ static void ll_temac_recv(struct net_device *ndev)
                skb->protocol = eth_type_trans(skb, ndev);
                skb->ip_summed = CHECKSUM_NONE;
 
+               /* if we're doing rx csum offload, set it up */
+               if (((lp->temac_features & TEMAC_FEATURE_RX_CSUM) != 0) &&
+                       (skb->protocol == __constant_htons(ETH_P_IP)) &&
+                       (skb->len > 64)) {
+
+                       skb->csum = cur_p->app3 & 0xFFFF;
+                       skb->ip_summed = CHECKSUM_COMPLETE;
+               }
+
                netif_rx(skb);
 
                ndev->stats.rx_packets++;
@@ -883,6 +904,7 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match)
        struct temac_local *lp;
        struct net_device *ndev;
        const void *addr;
+       __be32 *p;
        int size, rc = 0;
 
        /* Init network device structure */
@@ -920,14 +942,26 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match)
        mutex_init(&lp->indirect_mutex);
 
        /* map device registers */
-       lp->regs = of_iomap(op->node, 0);
+       lp->regs = of_iomap(op->dev.of_node, 0);
        if (!lp->regs) {
                dev_err(&op->dev, "could not map temac regs.\n");
                goto nodev;
        }
 
+       /* Setup checksum offload, but default to off if not specified */
+       lp->temac_features = 0;
+       p = (__be32 *)of_get_property(op->dev.of_node, "xlnx,txcsum", NULL);
+       if (p && be32_to_cpu(*p)) {
+               lp->temac_features |= TEMAC_FEATURE_TX_CSUM;
+               /* Can checksum TCP/UDP over IPv4. */
+               ndev->features |= NETIF_F_IP_CSUM;
+       }
+       p = (__be32 *)of_get_property(op->dev.of_node, "xlnx,rxcsum", NULL);
+       if (p && be32_to_cpu(*p))
+               lp->temac_features |= TEMAC_FEATURE_RX_CSUM;
+
        /* Find the DMA node, map the DMA registers, and decode the DMA IRQs */
-       np = of_parse_phandle(op->node, "llink-connected", 0);
+       np = of_parse_phandle(op->dev.of_node, "llink-connected", 0);
        if (!np) {
                dev_err(&op->dev, "could not find DMA node\n");
                goto nodev;
@@ -950,7 +984,7 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match)
 
        lp->rx_irq = irq_of_parse_and_map(np, 0);
        lp->tx_irq = irq_of_parse_and_map(np, 1);
-       if (!lp->rx_irq || !lp->tx_irq) {
+       if ((lp->rx_irq == NO_IRQ) || (lp->tx_irq == NO_IRQ)) {
                dev_err(&op->dev, "could not determine irqs\n");
                rc = -ENOMEM;
                goto nodev;
@@ -959,7 +993,7 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match)
        of_node_put(np); /* Finished with the DMA node; drop the reference */
 
        /* Retrieve the MAC address */
-       addr = of_get_property(op->node, "local-mac-address", &size);
+       addr = of_get_property(op->dev.of_node, "local-mac-address", &size);
        if ((!addr) || (size != 6)) {
                dev_err(&op->dev, "could not find MAC address\n");
                rc = -ENODEV;
@@ -967,11 +1001,11 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match)
        }
        temac_set_mac_address(ndev, (void *)addr);
 
-       rc = temac_mdio_setup(lp, op->node);
+       rc = temac_mdio_setup(lp, op->dev.of_node);
        if (rc)
                dev_warn(&op->dev, "error registering MDIO bus\n");
 
-       lp->phy_node = of_parse_phandle(op->node, "phy-handle", 0);
+       lp->phy_node = of_parse_phandle(op->dev.of_node, "phy-handle", 0);
        if (lp->phy_node)
                dev_dbg(lp->dev, "using PHY node %s (%p)\n", np->full_name, np);
 
@@ -1024,12 +1058,12 @@ static struct of_device_id temac_of_match[] __devinitdata = {
 MODULE_DEVICE_TABLE(of, temac_of_match);
 
 static struct of_platform_driver temac_of_driver = {
-       .match_table = temac_of_match,
        .probe = temac_of_probe,
        .remove = __devexit_p(temac_of_remove),
        .driver = {
                .owner = THIS_MODULE,
                .name = "xilinx_temac",
+               .of_match_table = temac_of_match,
        },
 };
 
index 4e238afab4a3b999d2e4af9ee178b6d593c4a9ed..87e8d4cb40579a8947419446012b38896b29064c 100644 (file)
@@ -634,11 +634,18 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
 
        err = register_netdevice(dev);
        if (err < 0)
-               return err;
+               goto destroy_port;
 
        list_add_tail(&vlan->list, &port->vlans);
        netif_stacked_transfer_operstate(lowerdev, dev);
+
        return 0;
+
+destroy_port:
+       if (list_empty(&port->vlans))
+               macvlan_port_destroy(lowerdev);
+
+       return err;
 }
 EXPORT_SYMBOL_GPL(macvlan_common_newlink);
 
index 57288ca1395f1e6b0974655396afb5341566b37a..b07e4dee80aada693e46e0a4cabca678f8500ad8 100644 (file)
@@ -163,28 +163,30 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages,
                        ret = mlx4_alloc_icm_pages(&chunk->mem[chunk->npages],
                                                   cur_order, gfp_mask);
 
-               if (!ret) {
-                       ++chunk->npages;
-
-                       if (coherent)
-                               ++chunk->nsg;
-                       else if (chunk->npages == MLX4_ICM_CHUNK_LEN) {
-                               chunk->nsg = pci_map_sg(dev->pdev, chunk->mem,
-                                                       chunk->npages,
-                                                       PCI_DMA_BIDIRECTIONAL);
+               if (ret) {
+                       if (--cur_order < 0)
+                               goto fail;
+                       else
+                               continue;
+               }
 
-                               if (chunk->nsg <= 0)
-                                       goto fail;
+               ++chunk->npages;
 
-                               chunk = NULL;
-                       }
+               if (coherent)
+                       ++chunk->nsg;
+               else if (chunk->npages == MLX4_ICM_CHUNK_LEN) {
+                       chunk->nsg = pci_map_sg(dev->pdev, chunk->mem,
+                                               chunk->npages,
+                                               PCI_DMA_BIDIRECTIONAL);
 
-                       npages -= 1 << cur_order;
-               } else {
-                       --cur_order;
-                       if (cur_order < 0)
+                       if (chunk->nsg <= 0)
                                goto fail;
                }
+
+               if (chunk->npages == MLX4_ICM_CHUNK_LEN)
+                       chunk = NULL;
+
+               npages -= 1 << cur_order;
        }
 
        if (!coherent && chunk) {
index 3898108f98ce6c7d6bd096a868080def27501223..1a57c3da1f498bb5d21531879ae2d9df941324dd 100644 (file)
@@ -928,7 +928,7 @@ static const struct net_device_ops myri_ops = {
 
 static int __devinit myri_sbus_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;
        static unsigned version_printed;
        struct net_device *dev;
        struct myri_eth *mp;
@@ -1161,8 +1161,11 @@ static const struct of_device_id myri_sbus_match[] = {
 MODULE_DEVICE_TABLE(of, myri_sbus_match);
 
 static struct of_platform_driver myri_sbus_driver = {
-       .name           = "myri",
-       .match_table    = myri_sbus_match,
+       .driver = {
+               .name = "myri",
+               .owner = THIS_MODULE,
+               .of_match_table = myri_sbus_match,
+       },
        .probe          = myri_sbus_probe,
        .remove         = __devexit_p(myri_sbus_remove),
 };
index 30abb4e436f16ed70b3aa85487d59441fad6a313..63e8e3893bd6cb9d05ad674a036c1b3f49e82aad 100644 (file)
@@ -9115,7 +9115,7 @@ static int __devinit niu_n2_irq_init(struct niu *np, u8 *ldg_num_map)
        const u32 *int_prop;
        int i;
 
-       int_prop = of_get_property(op->node, "interrupts", NULL);
+       int_prop = of_get_property(op->dev.of_node, "interrupts", NULL);
        if (!int_prop)
                return -ENODEV;
 
@@ -9266,7 +9266,7 @@ static int __devinit niu_get_of_props(struct niu *np)
        int prop_len;
 
        if (np->parent->plat_type == PLAT_TYPE_NIU)
-               dp = np->op->node;
+               dp = np->op->dev.of_node;
        else
                dp = pci_device_to_OF_node(np->pdev);
 
@@ -10083,10 +10083,10 @@ static int __devinit niu_of_probe(struct of_device *op,
 
        niu_driver_version();
 
-       reg = of_get_property(op->node, "reg", NULL);
+       reg = of_get_property(op->dev.of_node, "reg", NULL);
        if (!reg) {
                dev_err(&op->dev, "%s: No 'reg' property, aborting\n",
-                       op->node->full_name);
+                       op->dev.of_node->full_name);
                return -ENODEV;
        }
 
@@ -10099,7 +10099,7 @@ static int __devinit niu_of_probe(struct of_device *op,
        np = netdev_priv(dev);
 
        memset(&parent_id, 0, sizeof(parent_id));
-       parent_id.of = of_get_parent(op->node);
+       parent_id.of = of_get_parent(op->dev.of_node);
 
        np->parent = niu_get_parent(np, &parent_id,
                                    PLAT_TYPE_NIU);
@@ -10234,8 +10234,11 @@ static const struct of_device_id niu_match[] = {
 MODULE_DEVICE_TABLE(of, niu_match);
 
 static struct of_platform_driver niu_of_driver = {
-       .name           = "niu",
-       .match_table    = niu_match,
+       .driver = {
+               .name = "niu",
+               .owner = THIS_MODULE,
+               .of_match_table = niu_match,
+       },
        .probe          = niu_of_probe,
        .remove         = __devexit_p(niu_of_remove),
 };
index 35897134a5dd34c210e72229136e50c7a44a0040..fc5fef2a81752c17249c66609923eddb5af046da 100644 (file)
@@ -199,12 +199,12 @@ static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
        if (!pdata)
                return -ENOMEM;
 
-       ret = of_get_gpio(ofdev->node, 0);
+       ret = of_get_gpio(ofdev->dev.of_node, 0);
        if (ret < 0)
                goto out_free;
        pdata->mdc = ret;
 
-       ret = of_get_gpio(ofdev->node, 1);
+       ret = of_get_gpio(ofdev->dev.of_node, 1);
        if (ret < 0)
                goto out_free;
        pdata->mdio = ret;
@@ -213,7 +213,7 @@ static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
        if (!new_bus)
                goto out_free;
 
-       ret = of_mdiobus_register(new_bus, ofdev->node);
+       ret = of_mdiobus_register(new_bus, ofdev->dev.of_node);
        if (ret)
                mdio_gpio_bus_deinit(&ofdev->dev);
 
@@ -241,8 +241,11 @@ static struct of_device_id mdio_ofgpio_match[] = {
 MODULE_DEVICE_TABLE(of, mdio_ofgpio_match);
 
 static struct of_platform_driver mdio_ofgpio_driver = {
-       .name = "mdio-gpio",
-       .match_table = mdio_ofgpio_match,
+       .driver = {
+               .name = "mdio-gpio",
+               .owner = THIS_MODULE,
+               .of_match_table = mdio_ofgpio_match,
+       },
        .probe = mdio_ofgpio_probe,
        .remove = __devexit_p(mdio_ofgpio_remove),
 };
index 5441688daba70c6ad61f825fd911966041907c29..c5f8eb102bf76de12c86d2665b19b1c7fcb8d8b0 100644 (file)
@@ -2926,5 +2926,5 @@ EXPORT_SYMBOL(ppp_output_wakeup);
 EXPORT_SYMBOL(ppp_register_compressor);
 EXPORT_SYMBOL(ppp_unregister_compressor);
 MODULE_LICENSE("GPL");
-MODULE_ALIAS_CHARDEV_MAJOR(PPP_MAJOR);
-MODULE_ALIAS("/dev/ppp");
+MODULE_ALIAS_CHARDEV(PPP_MAJOR, 0);
+MODULE_ALIAS("devname:ppp");
index b1b93ff2351f70e7902cf2840885285570799355..805b64d1e893564bfc7aa1b3957c1df606dcf46a 100644 (file)
@@ -289,6 +289,7 @@ static void pppoe_flush_dev(struct net_device *dev)
        struct pppoe_net *pn;
        int i;
 
+       pn = pppoe_pernet(dev_net(dev));
        write_lock_bh(&pn->hash_lock);
        for (i = 0; i < PPPOE_HASH_SIZE; i++) {
                struct pppox_sock *po = pn->hash_table[i];
index 586ed0915a293f25d6dd5d6cd1fee28e6ece283e..501a55ffce570d5e9920efb6933346705473e872 100644 (file)
@@ -1294,6 +1294,9 @@ static int sh_mdio_release(struct net_device *ndev)
        /* remove mdio bus info from net_device */
        dev_set_drvdata(&ndev->dev, NULL);
 
+       /* free interrupts memory */
+       kfree(bus->irq);
+
        /* free bitbang info */
        free_mdio_bitbang(bus);
 
index 4591fe9bf0b9dd5fe875f5e6aecc5f877b0cc119..367e96f317d4d4df298a59945a2d3e3ca7ea9e73 100644 (file)
@@ -1131,8 +1131,8 @@ static int __devinit bigmac_ether_init(struct of_device *op,
                goto fail_and_cleanup;
 
        /* Get supported SBUS burst sizes. */
-       bsizes = of_getintprop_default(qec_op->node, "burst-sizes", 0xff);
-       bsizes_more = of_getintprop_default(qec_op->node, "burst-sizes", 0xff);
+       bsizes = of_getintprop_default(qec_op->dev.of_node, "burst-sizes", 0xff);
+       bsizes_more = of_getintprop_default(qec_op->dev.of_node, "burst-sizes", 0xff);
 
        bsizes &= 0xff;
        if (bsizes_more != 0xff)
@@ -1184,7 +1184,7 @@ static int __devinit bigmac_ether_init(struct of_device *op,
        }
 
        /* Get the board revision of this BigMAC. */
-       bp->board_rev = of_getintprop_default(bp->bigmac_op->node,
+       bp->board_rev = of_getintprop_default(bp->bigmac_op->dev.of_node,
                                              "board-version", 1);
 
        /* Init auto-negotiation timer state. */
@@ -1290,8 +1290,11 @@ static const struct of_device_id bigmac_sbus_match[] = {
 MODULE_DEVICE_TABLE(of, bigmac_sbus_match);
 
 static struct of_platform_driver bigmac_sbus_driver = {
-       .name           = "sunbmac",
-       .match_table    = bigmac_sbus_match,
+       .driver = {
+               .name = "sunbmac",
+               .owner = THIS_MODULE,
+               .of_match_table = bigmac_sbus_match,
+       },
        .probe          = bigmac_sbus_probe,
        .remove         = __devexit_p(bigmac_sbus_remove),
 };
index 915c5909c7a8bb90e4c6fe22617f5dbee032552c..3d9650b8d38fab26fce127f52d7a09ad1170ff6d 100644 (file)
@@ -2481,7 +2481,7 @@ static void hme_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info
        else {
                const struct linux_prom_registers *regs;
                struct of_device *op = hp->happy_dev;
-               regs = of_get_property(op->node, "regs", NULL);
+               regs = of_get_property(op->dev.of_node, "regs", NULL);
                if (regs)
                        sprintf(info->bus_info, "SBUS:%d",
                                regs->which_io);
@@ -2641,14 +2641,14 @@ static const struct net_device_ops hme_netdev_ops = {
 #ifdef CONFIG_SBUS
 static int __devinit happy_meal_sbus_probe_one(struct of_device *op, int is_qfe)
 {
-       struct device_node *dp = op->node, *sbus_dp;
+       struct device_node *dp = op->dev.of_node, *sbus_dp;
        struct quattro *qp = NULL;
        struct happy_meal *hp;
        struct net_device *dev;
        int i, qfe_slot = -1;
        int err = -ENODEV;
 
-       sbus_dp = to_of_device(op->dev.parent)->node;
+       sbus_dp = to_of_device(op->dev.parent)->dev.of_node;
 
        /* We can match PCI devices too, do not accept those here. */
        if (strcmp(sbus_dp->name, "sbus"))
@@ -3237,7 +3237,7 @@ static void happy_meal_pci_exit(void)
 #ifdef CONFIG_SBUS
 static int __devinit hme_sbus_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;
        const char *model = of_get_property(dp, "model", NULL);
        int is_qfe = (match->data != NULL);
 
@@ -3291,8 +3291,11 @@ static const struct of_device_id hme_sbus_match[] = {
 MODULE_DEVICE_TABLE(of, hme_sbus_match);
 
 static struct of_platform_driver hme_sbus_driver = {
-       .name           = "hme",
-       .match_table    = hme_sbus_match,
+       .driver = {
+               .name = "hme",
+               .owner = THIS_MODULE,
+               .of_match_table = hme_sbus_match,
+       },
        .probe          = hme_sbus_probe,
        .remove         = __devexit_p(hme_sbus_remove),
 };
index 386af7bbe6783914f3fd683bc12d28a84b770e1a..7d9c33dd9d1acf8efc6e9925787678f050a0b80c 100644 (file)
@@ -1323,7 +1323,7 @@ static int __devinit sparc_lance_probe_one(struct of_device *op,
                                           struct of_device *ledma,
                                           struct of_device *lebuffer)
 {
-       struct device_node *dp = op->node;
+       struct device_node *dp = op->dev.of_node;
        static unsigned version_printed;
        struct lance_private *lp;
        struct net_device *dev;
@@ -1410,7 +1410,7 @@ static int __devinit sparc_lance_probe_one(struct of_device *op,
 
        lp->burst_sizes = 0;
        if (lp->ledma) {
-               struct device_node *ledma_dp = ledma->node;
+               struct device_node *ledma_dp = ledma->dev.of_node;
                struct device_node *sbus_dp;
                unsigned int sbmask;
                const char *prop;
@@ -1506,7 +1506,7 @@ fail:
 static int __devinit sunlance_sbus_probe(struct of_device *op, const struct of_device_id *match)
 {
        struct of_device *parent = to_of_device(op->dev.parent);
-       struct device_node *parent_dp = parent->node;
+       struct device_node *parent_dp = parent->dev.of_node;
        int err;
 
        if (!strcmp(parent_dp->name, "ledma")) {
@@ -1545,8 +1545,11 @@ static const struct of_device_id sunlance_sbus_match[] = {
 MODULE_DEVICE_TABLE(of, sunlance_sbus_match);
 
 static struct of_platform_driver sunlance_sbus_driver = {
-       .name           = "sunlance",
-       .match_table    = sunlance_sbus_match,
+       .driver = {
+               .name = "sunlance",
+               .owner = THIS_MODULE,
+               .of_match_table = sunlance_sbus_match,
+       },
        .probe          = sunlance_sbus_probe,
        .remove         = __devexit_p(sunlance_sbus_remove),
 };
index a7542d25c8451f31b0420e586fd96b74e77eced4..72b579c8d8127d4d18c006c22ca631b2be06fe06 100644 (file)
@@ -695,7 +695,7 @@ static void qe_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
        strcpy(info->version, "3.0");
 
        op = qep->op;
-       regs = of_get_property(op->node, "reg", NULL);
+       regs = of_get_property(op->dev.of_node, "reg", NULL);
        if (regs)
                sprintf(info->bus_info, "SBUS:%d", regs->which_io);
 
@@ -799,7 +799,7 @@ static struct sunqec * __devinit get_qec(struct of_device *child)
                        if (qec_global_reset(qecp->gregs))
                                goto fail;
 
-                       qecp->qec_bursts = qec_get_burst(op->node);
+                       qecp->qec_bursts = qec_get_burst(op->dev.of_node);
 
                        qec_init_once(qecp, op);
 
@@ -857,7 +857,7 @@ static int __devinit qec_ether_init(struct of_device *op)
 
        res = -ENODEV;
 
-       i = of_getintprop_default(op->node, "channel#", -1);
+       i = of_getintprop_default(op->dev.of_node, "channel#", -1);
        if (i == -1)
                goto fail;
        qe->channel = i;
@@ -977,8 +977,11 @@ static const struct of_device_id qec_sbus_match[] = {
 MODULE_DEVICE_TABLE(of, qec_sbus_match);
 
 static struct of_platform_driver qec_sbus_driver = {
-       .name           = "qec",
-       .match_table    = qec_sbus_match,
+       .driver = {
+               .name = "qec",
+               .owner = THIS_MODULE,
+               .of_match_table = qec_sbus_match,
+       },
        .probe          = qec_sbus_probe,
        .remove         = __devexit_p(qec_sbus_remove),
 };
index 97b25533e5fb1dd741bc7a2541ed598014707a99..6ad6fe706312ff4c2cff31034b37428275e2f230 100644 (file)
@@ -526,6 +526,8 @@ static inline struct sk_buff *tun_alloc_skb(struct tun_struct *tun,
        struct sk_buff *skb;
        int err;
 
+       sock_update_classid(sk);
+
        /* Under a page?  Don't bother with paged skb. */
        if (prepad + len < PAGE_SIZE || !linear)
                linear = len;
@@ -1649,3 +1651,4 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION);
 MODULE_AUTHOR(DRV_COPYRIGHT);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_MISCDEV(TUN_MINOR);
+MODULE_ALIAS("devname:net/tun");
index 932602db54b39c09b1c7bbb9e62e6a663c356903..4a34833b85ddad284c1f19efff1bf9d23ed7f7e1 100644 (file)
@@ -3719,7 +3719,7 @@ static const struct net_device_ops ucc_geth_netdev_ops = {
 static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *match)
 {
        struct device *device = &ofdev->dev;
-       struct device_node *np = ofdev->node;
+       struct device_node *np = ofdev->dev.of_node;
        struct net_device *dev = NULL;
        struct ucc_geth_private *ugeth = NULL;
        struct ucc_geth_info *ug_info;
@@ -3963,8 +3963,11 @@ static struct of_device_id ucc_geth_match[] = {
 MODULE_DEVICE_TABLE(of, ucc_geth_match);
 
 static struct of_platform_driver ucc_geth_driver = {
-       .name           = DRV_NAME,
-       .match_table    = ucc_geth_match,
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = ucc_geth_match,
+       },
        .probe          = ucc_geth_probe,
        .remove         = ucc_geth_remove,
        .suspend        = ucc_geth_suspend,
index 31b73310ec77db754d458fedeabd6ecea81ab4d1..1f802e90474c3ccd342a70fb8b7352cadedf6bcd 100644 (file)
@@ -322,7 +322,7 @@ static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
                size = (u16) (header & 0x0000ffff);
 
                if ((skb->len) - ((size + 1) & 0xfffe) == 0) {
-                       u8 alignment = (u32)skb->data & 0x3;
+                       u8 alignment = (unsigned long)skb->data & 0x3;
                        if (alignment != 0x2) {
                                /*
                                 * not 16bit aligned so use the room provided by
@@ -351,7 +351,7 @@ static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
                }
                ax_skb = skb_clone(skb, GFP_ATOMIC);
                if (ax_skb) {
-                       u8 alignment = (u32)packet & 0x3;
+                       u8 alignment = (unsigned long)packet & 0x3;
                        ax_skb->len = size;
 
                        if (alignment != 0x2) {
index 9964df199511879b4f5d73c0ca36014da972009e..0a3c41faea9c2118dd28f6c558c939002c34d135 100644 (file)
@@ -475,6 +475,9 @@ static const struct usb_device_id hso_ids[] = {
        {USB_DEVICE(0x0af0, 0x8302)},
        {USB_DEVICE(0x0af0, 0x8304)},
        {USB_DEVICE(0x0af0, 0x8400)},
+       {USB_DEVICE(0x0af0, 0x8600)},
+       {USB_DEVICE(0x0af0, 0x8800)},
+       {USB_DEVICE(0x0af0, 0x8900)},
        {USB_DEVICE(0x0af0, 0xd035)},
        {USB_DEVICE(0x0af0, 0xd055)},
        {USB_DEVICE(0x0af0, 0xd155)},
index b0a85d0387962b6ce2394637f9ae6dbbac5f6684..78eb3190b9b1343bee9e1cd786090c395ebd0877 100644 (file)
@@ -122,7 +122,7 @@ static void skb_xmit_done(struct virtqueue *svq)
        struct virtnet_info *vi = svq->vdev->priv;
 
        /* Suppress further interrupts. */
-       svq->vq_ops->disable_cb(svq);
+       virtqueue_disable_cb(svq);
 
        /* We were probably waiting for more output buffers. */
        netif_wake_queue(vi->dev);
@@ -210,7 +210,7 @@ static int receive_mergeable(struct virtnet_info *vi, struct sk_buff *skb)
                        return -EINVAL;
                }
 
-               page = vi->rvq->vq_ops->get_buf(vi->rvq, &len);
+               page = virtqueue_get_buf(vi->rvq, &len);
                if (!page) {
                        pr_debug("%s: rx error: %d buffers missing\n",
                                 skb->dev->name, hdr->mhdr.num_buffers);
@@ -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 = vi->rvq->vq_ops->add_buf(vi->rvq, vi->rx_sg, 0, 2, skb);
+       err = virtqueue_add_buf(vi->rvq, vi->rx_sg, 0, 2, skb);
        if (err < 0)
                dev_kfree_skb(skb);
 
@@ -385,7 +385,7 @@ static int add_recvbuf_big(struct virtnet_info *vi, gfp_t gfp)
 
        /* chain first in list head */
        first->private = (unsigned long)list;
-       err = vi->rvq->vq_ops->add_buf(vi->rvq, vi->rx_sg, 0, MAX_SKB_FRAGS + 2,
+       err = virtqueue_add_buf(vi->rvq, vi->rx_sg, 0, MAX_SKB_FRAGS + 2,
                                       first);
        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 = vi->rvq->vq_ops->add_buf(vi->rvq, vi->rx_sg, 0, 1, page);
+       err = virtqueue_add_buf(vi->rvq, vi->rx_sg, 0, 1, page);
        if (err < 0)
                give_pages(vi, page);
 
@@ -433,7 +433,7 @@ static bool try_fill_recv(struct virtnet_info *vi, gfp_t gfp)
        } while (err > 0);
        if (unlikely(vi->num > vi->max))
                vi->max = vi->num;
-       vi->rvq->vq_ops->kick(vi->rvq);
+       virtqueue_kick(vi->rvq);
        return !oom;
 }
 
@@ -442,7 +442,7 @@ static void skb_recv_done(struct virtqueue *rvq)
        struct virtnet_info *vi = rvq->vdev->priv;
        /* Schedule NAPI, Suppress further interrupts if successful. */
        if (napi_schedule_prep(&vi->napi)) {
-               rvq->vq_ops->disable_cb(rvq);
+               virtqueue_disable_cb(rvq);
                __napi_schedule(&vi->napi);
        }
 }
@@ -471,7 +471,7 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
 
 again:
        while (received < budget &&
-              (buf = vi->rvq->vq_ops->get_buf(vi->rvq, &len)) != NULL) {
+              (buf = virtqueue_get_buf(vi->rvq, &len)) != NULL) {
                receive_buf(vi->dev, buf, len);
                --vi->num;
                received++;
@@ -485,9 +485,9 @@ again:
        /* Out of packets? */
        if (received < budget) {
                napi_complete(napi);
-               if (unlikely(!vi->rvq->vq_ops->enable_cb(vi->rvq)) &&
+               if (unlikely(!virtqueue_enable_cb(vi->rvq)) &&
                    napi_schedule_prep(napi)) {
-                       vi->rvq->vq_ops->disable_cb(vi->rvq);
+                       virtqueue_disable_cb(vi->rvq);
                        __napi_schedule(napi);
                        goto again;
                }
@@ -501,7 +501,7 @@ static unsigned int free_old_xmit_skbs(struct virtnet_info *vi)
        struct sk_buff *skb;
        unsigned int len, tot_sgs = 0;
 
-       while ((skb = vi->svq->vq_ops->get_buf(vi->svq, &len)) != NULL) {
+       while ((skb = virtqueue_get_buf(vi->svq, &len)) != NULL) {
                pr_debug("Sent skb %p\n", skb);
                vi->dev->stats.tx_bytes += skb->len;
                vi->dev->stats.tx_packets++;
@@ -554,7 +554,7 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb)
                sg_set_buf(vi->tx_sg, &hdr->hdr, sizeof hdr->hdr);
 
        hdr->num_sg = skb_to_sgvec(skb, vi->tx_sg + 1, 0, skb->len) + 1;
-       return vi->svq->vq_ops->add_buf(vi->svq, vi->tx_sg, hdr->num_sg,
+       return virtqueue_add_buf(vi->svq, vi->tx_sg, hdr->num_sg,
                                        0, skb);
 }
 
@@ -574,14 +574,14 @@ again:
        if (unlikely(capacity < 0)) {
                netif_stop_queue(dev);
                dev_warn(&dev->dev, "Unexpected full queue\n");
-               if (unlikely(!vi->svq->vq_ops->enable_cb(vi->svq))) {
-                       vi->svq->vq_ops->disable_cb(vi->svq);
+               if (unlikely(!virtqueue_enable_cb(vi->svq))) {
+                       virtqueue_disable_cb(vi->svq);
                        netif_start_queue(dev);
                        goto again;
                }
                return NETDEV_TX_BUSY;
        }
-       vi->svq->vq_ops->kick(vi->svq);
+       virtqueue_kick(vi->svq);
 
        /* Don't wait up for transmitted skbs to be freed. */
        skb_orphan(skb);
@@ -591,12 +591,12 @@ again:
         * before it gets out of hand.  Naturally, this wastes entries. */
        if (capacity < 2+MAX_SKB_FRAGS) {
                netif_stop_queue(dev);
-               if (unlikely(!vi->svq->vq_ops->enable_cb(vi->svq))) {
+               if (unlikely(!virtqueue_enable_cb(vi->svq))) {
                        /* More just got used, free them then recheck. */
                        capacity += free_old_xmit_skbs(vi);
                        if (capacity >= 2+MAX_SKB_FRAGS) {
                                netif_start_queue(dev);
-                               vi->svq->vq_ops->disable_cb(vi->svq);
+                               virtqueue_disable_cb(vi->svq);
                        }
                }
        }
@@ -641,7 +641,7 @@ static int virtnet_open(struct net_device *dev)
         * now.  virtnet_poll wants re-enable the queue, so we disable here.
         * We synchronize against interrupts via NAPI_STATE_SCHED */
        if (napi_schedule_prep(&vi->napi)) {
-               vi->rvq->vq_ops->disable_cb(vi->rvq);
+               virtqueue_disable_cb(vi->rvq);
                __napi_schedule(&vi->napi);
        }
        return 0;
@@ -678,15 +678,15 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
                sg_set_buf(&sg[i + 1], sg_virt(s), s->length);
        sg_set_buf(&sg[out + in - 1], &status, sizeof(status));
 
-       BUG_ON(vi->cvq->vq_ops->add_buf(vi->cvq, sg, out, in, vi) < 0);
+       BUG_ON(virtqueue_add_buf(vi->cvq, sg, out, in, vi) < 0);
 
-       vi->cvq->vq_ops->kick(vi->cvq);
+       virtqueue_kick(vi->cvq);
 
        /*
         * Spin for a response, the kick causes an ioport write, trapping
         * into the hypervisor, so the request should be handled immediately.
         */
-       while (!vi->cvq->vq_ops->get_buf(vi->cvq, &tmp))
+       while (!virtqueue_get_buf(vi->cvq, &tmp))
                cpu_relax();
 
        return status == VIRTIO_NET_OK;
@@ -1003,13 +1003,13 @@ static void free_unused_bufs(struct virtnet_info *vi)
 {
        void *buf;
        while (1) {
-               buf = vi->svq->vq_ops->detach_unused_buf(vi->svq);
+               buf = virtqueue_detach_unused_buf(vi->svq);
                if (!buf)
                        break;
                dev_kfree_skb(buf);
        }
        while (1) {
-               buf = vi->rvq->vq_ops->detach_unused_buf(vi->rvq);
+               buf = virtqueue_detach_unused_buf(vi->rvq);
                if (!buf)
                        break;
                if (vi->mergeable_rx_bufs || vi->big_packets)
index 6537593fae66cfc6cfc02c4b5dc95c7b35d4e572..8cc9e319f4356da8904cbf4e7a495d59eba94645 100644 (file)
@@ -1027,12 +1027,12 @@ void i2400m_rx_edata(struct i2400m *i2400m, struct sk_buff *skb_rx,
                ro_sn = (reorder >> I2400M_RO_SN_SHIFT) & I2400M_RO_SN;
 
                spin_lock_irqsave(&i2400m->rx_lock, flags);
-               roq = &i2400m->rx_roq[ro_cin];
-               if (roq == NULL) {
+               if (i2400m->rx_roq == NULL) {
                        kfree_skb(skb); /* rx_roq is already destroyed */
                        spin_unlock_irqrestore(&i2400m->rx_lock, flags);
                        goto error;
                }
+               roq = &i2400m->rx_roq[ro_cin];
                kref_get(&i2400m->rx_roq_refcount);
                spin_unlock_irqrestore(&i2400m->rx_lock, flags);
 
index a441aad922c254f50e06ebe99949cf4b8162ab87..3b7ab20a5c54ca77fcbf04db0e0095ebc1ef5c5c 100644 (file)
@@ -5162,13 +5162,6 @@ static void proc_SSID_on_close(struct inode *inode, struct file *file)
        enable_MAC(ai, 1);
 }
 
-static inline u8 hexVal(char c) {
-       if (c>='0' && c<='9') return c -= '0';
-       if (c>='a' && c<='f') return c -= 'a'-10;
-       if (c>='A' && c<='F') return c -= 'A'-10;
-       return 0;
-}
-
 static void proc_APList_on_close( struct inode *inode, struct file *file ) {
        struct proc_data *data = (struct proc_data *)file->private_data;
        struct proc_dir_entry *dp = PDE(inode);
@@ -5188,11 +5181,11 @@ static void proc_APList_on_close( struct inode *inode, struct file *file ) {
                        switch(j%3) {
                        case 0:
                                APList_rid.ap[i][j/3]=
-                                       hexVal(data->wbuffer[j+i*6*3])<<4;
+                                       hex_to_bin(data->wbuffer[j+i*6*3])<<4;
                                break;
                        case 1:
                                APList_rid.ap[i][j/3]|=
-                                       hexVal(data->wbuffer[j+i*6*3]);
+                                       hex_to_bin(data->wbuffer[j+i*6*3]);
                                break;
                        }
                }
@@ -5340,10 +5333,10 @@ static void proc_wepkey_on_close( struct inode *inode, struct file *file ) {
        for( i = 0; i < 16*3 && data->wbuffer[i+j]; i++ ) {
                switch(i%3) {
                case 0:
-                       key[i/3] = hexVal(data->wbuffer[i+j])<<4;
+                       key[i/3] = hex_to_bin(data->wbuffer[i+j])<<4;
                        break;
                case 1:
-                       key[i/3] |= hexVal(data->wbuffer[i+j]);
+                       key[i/3] |= hex_to_bin(data->wbuffer[i+j]);
                        break;
                }
        }
index 5f04cf38a5bc95548b07069bda31818a2438aa93..cc6d41dec332091eeef2c9a0b7905f2e26c95cfe 100644 (file)
@@ -1214,6 +1214,7 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
        struct ath5k_hw *ah = sc->ah;
        struct sk_buff *skb = bf->skb;
        struct ath5k_desc *ds;
+       int ret;
 
        if (!skb) {
                skb = ath5k_rx_skb_alloc(sc, &bf->skbaddr);
@@ -1240,9 +1241,9 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
        ds = bf->desc;
        ds->ds_link = bf->daddr;        /* link to self */
        ds->ds_data = bf->skbaddr;
-       ah->ah_setup_rx_desc(ah, ds,
-               skb_tailroom(skb),      /* buffer size */
-               0);
+       ret = ah->ah_setup_rx_desc(ah, ds, ah->common.rx_bufsize, 0);
+       if (ret)
+               return ret;
 
        if (sc->rxlink != NULL)
                *sc->rxlink = bf->daddr;
index c8a4558f79ba0573a674829b53d6cfef2258e347..f43d85a302c461e52080a8f8021e835d5874b8d3 100644 (file)
@@ -76,22 +76,13 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
        ds = bf->bf_desc;
        flags = ATH9K_TXDESC_NOACK;
 
-       if (((sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) ||
-            (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) &&
-           (ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)) {
-               ds->ds_link = bf->bf_daddr; /* self-linked */
-               flags |= ATH9K_TXDESC_VEOL;
-               /* Let hardware handle antenna switching. */
-               antenna = 0;
-       } else {
-               ds->ds_link = 0;
-               /*
-                * Switch antenna every beacon.
-                * Should only switch every beacon period, not for every SWBA
-                * XXX assumes two antennae
-                */
-               antenna = ((sc->beacon.ast_be_xmit / sc->nbcnvifs) & 1 ? 2 : 1);
-       }
+       ds->ds_link = 0;
+       /*
+        * Switch antenna every beacon.
+        * Should only switch every beacon period, not for every SWBA
+        * XXX assumes two antennae
+        */
+       antenna = ((sc->beacon.ast_be_xmit / sc->nbcnvifs) & 1 ? 2 : 1);
 
        sband = &sc->sbands[common->hw->conf.channel->band];
        rate = sband->bitrates[rateidx].hw_value;
@@ -215,36 +206,6 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
        return bf;
 }
 
-/*
- * Startup beacon transmission for adhoc mode when they are sent entirely
- * by the hardware using the self-linked descriptor + veol trick.
-*/
-static void ath_beacon_start_adhoc(struct ath_softc *sc,
-                                  struct ieee80211_vif *vif)
-{
-       struct ath_hw *ah = sc->sc_ah;
-       struct ath_common *common = ath9k_hw_common(ah);
-       struct ath_buf *bf;
-       struct ath_vif *avp;
-       struct sk_buff *skb;
-
-       avp = (void *)vif->drv_priv;
-
-       if (avp->av_bcbuf == NULL)
-               return;
-
-       bf = avp->av_bcbuf;
-       skb = bf->bf_mpdu;
-
-       ath_beacon_setup(sc, avp, bf, 0);
-
-       /* NB: caller is known to have already stopped tx dma */
-       ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bf->bf_daddr);
-       ath9k_hw_txstart(ah, sc->beacon.beaconq);
-       ath_print(common, ATH_DBG_BEACON, "TXDP%u = %llx (%p)\n",
-                 sc->beacon.beaconq, ito64(bf->bf_daddr), bf->bf_desc);
-}
-
 int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif)
 {
        struct ath_softc *sc = aphy->sc;
@@ -265,7 +226,8 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif)
                list_del(&avp->av_bcbuf->list);
 
                if (sc->sc_ah->opmode == NL80211_IFTYPE_AP ||
-                   !(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)) {
+                   sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC ||
+                   sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT) {
                        int slot;
                        /*
                         * Assign the vif to a beacon xmit slot. As
@@ -274,17 +236,11 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif)
                        avp->av_bslot = 0;
                        for (slot = 0; slot < ATH_BCBUF; slot++)
                                if (sc->beacon.bslot[slot] == NULL) {
-                                       /*
-                                        * XXX hack, space out slots to better
-                                        * deal with misses
-                                        */
-                                       if (slot+1 < ATH_BCBUF &&
-                                           sc->beacon.bslot[slot+1] == NULL) {
-                                               avp->av_bslot = slot+1;
-                                               break;
-                                       }
                                        avp->av_bslot = slot;
+
                                        /* NB: keep looking for a double slot */
+                                       if (slot == 0 || !sc->beacon.bslot[slot-1])
+                                               break;
                                }
                        BUG_ON(sc->beacon.bslot[avp->av_bslot] != NULL);
                        sc->beacon.bslot[avp->av_bslot] = vif;
@@ -721,8 +677,7 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
         * self-linked tx descriptor and let the hardware deal with things.
         */
        intval |= ATH9K_BEACON_ENA;
-       if (!(ah->caps.hw_caps & ATH9K_HW_CAP_VEOL))
-               ah->imask |= ATH9K_INT_SWBA;
+       ah->imask |= ATH9K_INT_SWBA;
 
        ath_beaconq_config(sc);
 
@@ -732,10 +687,6 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
        ath9k_beacon_init(sc, nexttbtt, intval);
        sc->beacon.bmisscnt = 0;
        ath9k_hw_set_interrupts(ah, ah->imask);
-
-       /* FIXME: Handle properly when vif is NULL */
-       if (vif && ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)
-               ath_beacon_start_adhoc(sc, vif);
 }
 
 void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
index 46dc41a16faa23e9edbb213c55d39523c6fb0a41..77b359162d6cad0a408754fff4cc8b9af64d3063 100644 (file)
@@ -107,12 +107,14 @@ static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev,
 static void hif_usb_tx_cb(struct urb *urb)
 {
        struct tx_buf *tx_buf = (struct tx_buf *) urb->context;
-       struct hif_device_usb *hif_dev = tx_buf->hif_dev;
+       struct hif_device_usb *hif_dev;
        struct sk_buff *skb;
 
-       if (!hif_dev || !tx_buf)
+       if (!tx_buf || !tx_buf->hif_dev)
                return;
 
+       hif_dev = tx_buf->hif_dev;
+
        switch (urb->status) {
        case 0:
                break;
@@ -607,6 +609,10 @@ static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev)
 
        return 0;
 err:
+       if (tx_buf) {
+               kfree(tx_buf->buf);
+               kfree(tx_buf);
+       }
        ath9k_hif_usb_dealloc_tx_urbs(hif_dev);
        return -ENOMEM;
 }
index ad556aa8da39064704a151e3e0550f202986dd33..c251603ab032f3668acaa9e5f8ce5bac63b1082f 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
 #include <linux/leds.h>
+#include <linux/slab.h>
 #include <net/mac80211.h>
 
 #include "common.h"
index 893b552981a07494413288064dd9601be1e3373e..abfa0493236f5a8c5f785d0126a26c9c0cba45bc 100644 (file)
@@ -752,7 +752,6 @@ static int ath_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;
 
@@ -776,30 +775,9 @@ static int ath_key_config(struct ath_common *common,
        memcpy(hk.kv_val, key->key, key->keylen);
 
        if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
-
-               if (key->ap_addr) {
-                       /*
-                        * Group keys on hardware that supports multicast frame
-                        * key search use a mac that is the sender's address with
-                        * the high bit set instead of the app-specified address.
-                        */
-                       memcpy(gmac, key->ap_addr, ETH_ALEN);
-                       gmac[0] |= 0x80;
-                       mac = gmac;
-
-                       if (key->alg == ALG_TKIP)
-                               idx = ath_reserve_key_cache_slot_tkip(common);
-                       else
-                               idx = ath_reserve_key_cache_slot(common);
-                       if (idx < 0)
-                               mac = NULL; /* no free key cache entries */
-               }
-
-               if (!mac) {
-                       /* For now, use the default keys for broadcast keys. This may
-                        * need to change with virtual interfaces. */
-                       idx = key->keyidx;
-               }
+               /* 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;
index 257b10ba6f57e2b4c7e99872ef046709ba7c668f..1ec836cf1c0da8defa709b6ba983cac744ba9799 100644 (file)
@@ -28,7 +28,6 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
        { PCI_VDEVICE(ATHEROS, 0x002C) }, /* PCI-E 802.11n bonded out */
        { PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI   */
        { PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */
-       { PCI_VDEVICE(ATHEROS, 0x0030) }, /* PCI-E  AR9300 */
        { 0 }
 };
 
index ba139132c85f9013fb062154f6fa37a5d3e73bef..ca6065b71b46fb463c914f61061304177f693d2c 100644 (file)
 
 #define SKB_CB_ATHBUF(__skb)   (*((struct ath_buf **)__skb->cb))
 
+static inline bool ath9k_check_auto_sleep(struct ath_softc *sc)
+{
+       return sc->ps_enabled &&
+              (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP);
+}
+
 static struct ieee80211_hw * ath_get_virt_hw(struct ath_softc *sc,
                                             struct ieee80211_hdr *hdr)
 {
@@ -616,8 +622,8 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
        hdr = (struct ieee80211_hdr *)skb->data;
 
        /* Process Beacon and CAB receive in PS state */
-       if ((sc->ps_flags & PS_WAIT_FOR_BEACON) &&
-           ieee80211_is_beacon(hdr->frame_control))
+       if (((sc->ps_flags & PS_WAIT_FOR_BEACON) || ath9k_check_auto_sleep(sc))
+           && ieee80211_is_beacon(hdr->frame_control))
                ath_rx_ps_beacon(sc, skb);
        else if ((sc->ps_flags & PS_WAIT_FOR_CAB) &&
                 (ieee80211_is_data(hdr->frame_control) ||
@@ -932,9 +938,10 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
                        sc->rx.rxotherant = 0;
                }
 
-               if (unlikely(sc->ps_flags & (PS_WAIT_FOR_BEACON |
-                                            PS_WAIT_FOR_CAB |
-                                            PS_WAIT_FOR_PSPOLL_DATA)))
+               if (unlikely(ath9k_check_auto_sleep(sc) ||
+                            (sc->ps_flags & (PS_WAIT_FOR_BEACON |
+                                             PS_WAIT_FOR_CAB |
+                                             PS_WAIT_FOR_PSPOLL_DATA))))
                        ath_rx_ps(sc, skb);
 
                ath_rx_send_to_mac80211(hw, sc, skb, rxs);
index a273e373b7b068651ea63f615a234aee91587718..c92b2c0cbd9130ee1ba35a1ac160dfd5f0baa0ca 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/module.h>
 #include <linux/etherdevice.h>
 #include <linux/sched.h>
+#include <linux/gfp.h>
 #include <net/mac80211.h>
 
 #include "iwl-dev.h"
index 107e173112f65ab9a2b1b66d22108edc148d5fc6..5d3f51ff2f0d075ad6ef81c022a687651afd2e07 100644 (file)
@@ -376,6 +376,11 @@ void iwl_bg_start_internal_scan(struct work_struct *work)
 
        mutex_lock(&priv->mutex);
 
+       if (priv->is_internal_short_scan == true) {
+               IWL_DEBUG_SCAN(priv, "Internal scan already in progress\n");
+               goto unlock;
+       }
+
        if (!iwl_is_ready_rf(priv)) {
                IWL_DEBUG_SCAN(priv, "not ready or exit pending\n");
                goto unlock;
@@ -497,17 +502,27 @@ void iwl_bg_scan_completed(struct work_struct *work)
 {
        struct iwl_priv *priv =
            container_of(work, struct iwl_priv, scan_completed);
+       bool internal = false;
 
        IWL_DEBUG_SCAN(priv, "SCAN complete scan\n");
 
        cancel_delayed_work(&priv->scan_check);
 
-       if (!priv->is_internal_short_scan)
-               ieee80211_scan_completed(priv->hw, false);
-       else {
+       mutex_lock(&priv->mutex);
+       if (priv->is_internal_short_scan) {
                priv->is_internal_short_scan = false;
                IWL_DEBUG_SCAN(priv, "internal short scan completed\n");
+               internal = true;
        }
+       mutex_unlock(&priv->mutex);
+
+       /*
+        * Do not hold mutex here since this will cause mac80211 to call
+        * into driver again into functions that will attempt to take
+        * mutex.
+        */
+       if (!internal)
+               ieee80211_scan_completed(priv->hw, false);
 
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
index 85ed235ac901c446f9efdb924d6f02009b81f706..83a26361a9b56b35d4364c93b9f9df32905c8cc6 100644 (file)
@@ -431,7 +431,7 @@ int iwl_add_bssid_station(struct iwl_priv *priv, const u8 *addr, bool init_rs,
        struct iwl_link_quality_cmd *link_cmd;
        unsigned long flags;
 
-       if (*sta_id_r)
+       if (sta_id_r)
                *sta_id_r = IWL_INVALID_STATION;
 
        ret = iwl_add_station_common(priv, addr, 0, NULL, &sta_id);
index 2d2890878deae2162abf5dea253821f09f55e461..4bd61ee627c08f49f0b2519e16c7a74f31cf27ca 100644 (file)
@@ -2572,14 +2572,18 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev)
 
 static void rndis_wlan_do_link_down_work(struct usbnet *usbdev)
 {
-       union iwreq_data evt;
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
 
-       netif_carrier_off(usbdev->net);
+       if (priv->connected) {
+               priv->connected = false;
+               memset(priv->bssid, 0, ETH_ALEN);
+
+               deauthenticate(usbdev);
 
-       evt.data.flags = 0;
-       evt.data.length = 0;
-       memset(evt.ap_addr.sa_data, 0, ETH_ALEN);
-       wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL);
+               cfg80211_disconnected(usbdev->net, 0, NULL, 0, GFP_KERNEL);
+       }
+
+       netif_carrier_off(usbdev->net);
 }
 
 static void rndis_wlan_worker(struct work_struct *work)
index 4ba7b038928fa1a0108c84319f2aa85b2a6054c6..ad2c98af7e9d62090dd54837206d07bcd23675a6 100644 (file)
@@ -926,7 +926,7 @@ static void rt2400pci_disable_radio(struct rt2x00_dev *rt2x00dev)
 static int rt2400pci_set_state(struct rt2x00_dev *rt2x00dev,
                               enum dev_state state)
 {
-       u32 reg;
+       u32 reg, reg2;
        unsigned int i;
        char put_to_sleep;
        char bbp_state;
@@ -947,11 +947,12 @@ static int rt2400pci_set_state(struct rt2x00_dev *rt2x00dev,
         * device has entered the correct state.
         */
        for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-               rt2x00pci_register_read(rt2x00dev, PWRCSR1, &reg);
-               bbp_state = rt2x00_get_field32(reg, PWRCSR1_BBP_CURR_STATE);
-               rf_state = rt2x00_get_field32(reg, PWRCSR1_RF_CURR_STATE);
+               rt2x00pci_register_read(rt2x00dev, PWRCSR1, &reg2);
+               bbp_state = rt2x00_get_field32(reg2, PWRCSR1_BBP_CURR_STATE);
+               rf_state = rt2x00_get_field32(reg2, PWRCSR1_RF_CURR_STATE);
                if (bbp_state == state && rf_state == state)
                        return 0;
+               rt2x00pci_register_write(rt2x00dev, PWRCSR1, reg);
                msleep(10);
        }
 
index 89d132d4af1276e11ccf451004c00a3aa6e71fb2..41da3d218c65e343b5ded898ad5cee89257e4201 100644 (file)
@@ -1084,7 +1084,7 @@ static void rt2500pci_disable_radio(struct rt2x00_dev *rt2x00dev)
 static int rt2500pci_set_state(struct rt2x00_dev *rt2x00dev,
                               enum dev_state state)
 {
-       u32 reg;
+       u32 reg, reg2;
        unsigned int i;
        char put_to_sleep;
        char bbp_state;
@@ -1105,11 +1105,12 @@ static int rt2500pci_set_state(struct rt2x00_dev *rt2x00dev,
         * device has entered the correct state.
         */
        for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-               rt2x00pci_register_read(rt2x00dev, PWRCSR1, &reg);
-               bbp_state = rt2x00_get_field32(reg, PWRCSR1_BBP_CURR_STATE);
-               rf_state = rt2x00_get_field32(reg, PWRCSR1_RF_CURR_STATE);
+               rt2x00pci_register_read(rt2x00dev, PWRCSR1, &reg2);
+               bbp_state = rt2x00_get_field32(reg2, PWRCSR1_BBP_CURR_STATE);
+               rf_state = rt2x00_get_field32(reg2, PWRCSR1_RF_CURR_STATE);
                if (bbp_state == state && rf_state == state)
                        return 0;
+               rt2x00pci_register_write(rt2x00dev, PWRCSR1, reg);
                msleep(10);
        }
 
index 0f8b84b7224cace0167ebe5b0065da28af08986c..699161327d656feb56cb7c74d081e17e277a9394 100644 (file)
@@ -413,7 +413,7 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
         */
        rt2x00_desc_read(txi, 0, &word);
        rt2x00_set_field32(&word, TXINFO_W0_USB_DMA_TX_PKT_LEN,
-                          skb->len + TXWI_DESC_SIZE);
+                          skb->len - TXINFO_DESC_SIZE);
        rt2x00_set_field32(&word, TXINFO_W0_WIV,
                           !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags));
        rt2x00_set_field32(&word, TXINFO_W0_QSEL, 2);
index a016f7ccde29a1c347e72a3c82750fff0c700390..f71eee67f977de43e0c2aa61b0355ff29dc8d3ae 100644 (file)
@@ -206,7 +206,7 @@ void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev)
        /*
         * Free irq line.
         */
-       free_irq(to_pci_dev(rt2x00dev->dev)->irq, rt2x00dev);
+       free_irq(rt2x00dev->irq, rt2x00dev);
 
        /*
         * Free DMA
index 2e3076f67535502b93bfbf7cde4b4cc2267521c0..6a74baf4e934b97e4ac3978341736790f18fb6e3 100644 (file)
@@ -1689,7 +1689,7 @@ static void rt61pci_disable_radio(struct rt2x00_dev *rt2x00dev)
 
 static int rt61pci_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state)
 {
-       u32 reg;
+       u32 reg, reg2;
        unsigned int i;
        char put_to_sleep;
 
@@ -1706,10 +1706,11 @@ static int rt61pci_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state)
         * device has entered the correct state.
         */
        for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-               rt2x00pci_register_read(rt2x00dev, MAC_CSR12, &reg);
-               state = rt2x00_get_field32(reg, MAC_CSR12_BBP_CURRENT_STATE);
+               rt2x00pci_register_read(rt2x00dev, MAC_CSR12, &reg2);
+               state = rt2x00_get_field32(reg2, MAC_CSR12_BBP_CURRENT_STATE);
                if (state == !put_to_sleep)
                        return 0;
+               rt2x00pci_register_write(rt2x00dev, MAC_CSR12, reg);
                msleep(10);
        }
 
index e35bd19c3c5aeb09ffec25549bf4ef0d07064385..6e0d82efe9241802d8fdea54eacfe9f686437f0d 100644 (file)
@@ -1366,7 +1366,7 @@ static void rt73usb_disable_radio(struct rt2x00_dev *rt2x00dev)
 
 static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state)
 {
-       u32 reg;
+       u32 reg, reg2;
        unsigned int i;
        char put_to_sleep;
 
@@ -1383,10 +1383,11 @@ static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state)
         * device has entered the correct state.
         */
        for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-               rt2x00usb_register_read(rt2x00dev, MAC_CSR12, &reg);
-               state = rt2x00_get_field32(reg, MAC_CSR12_BBP_CURRENT_STATE);
+               rt2x00usb_register_read(rt2x00dev, MAC_CSR12, &reg2);
+               state = rt2x00_get_field32(reg2, MAC_CSR12_BBP_CURRENT_STATE);
                if (state == !put_to_sleep)
                        return 0;
+               rt2x00usb_register_write(rt2x00dev, MAC_CSR12, reg);
                msleep(10);
        }
 
index 57f4bfd959c8d46519fbe375901d3d2f3de2864f..b98fb643fab0cd674fd33e9b3969e95cab4ea0ef 100644 (file)
@@ -113,6 +113,8 @@ static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length)
        wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len,
                     beacon ? "beacon" : "");
 
+       skb_trim(skb, skb->len - desc->pad_len);
+
        memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
        ieee80211_rx_ni(wl->hw, skb);
 }
index a7db68d37ee98c3e3359507ad31630110a55d8f4..d04c5b262050a9aefef0f48cde2bfa2f700510a7 100644 (file)
@@ -1088,7 +1088,7 @@ static void xemaclite_remove_ndev(struct net_device *ndev)
  */
 static bool get_bool(struct of_device *ofdev, const char *s)
 {
-       u32 *p = (u32 *)of_get_property(ofdev->node, s, NULL);
+       u32 *p = (u32 *)of_get_property(ofdev->dev.of_node, s, NULL);
 
        if (p) {
                return (bool)*p;
@@ -1130,14 +1130,14 @@ static int __devinit xemaclite_of_probe(struct of_device *ofdev,
        dev_info(dev, "Device Tree Probing\n");
 
        /* Get iospace for the device */
-       rc = of_address_to_resource(ofdev->node, 0, &r_mem);
+       rc = of_address_to_resource(ofdev->dev.of_node, 0, &r_mem);
        if (rc) {
                dev_err(dev, "invalid address\n");
                return rc;
        }
 
        /* Get IRQ for the device */
-       rc = of_irq_to_resource(ofdev->node, 0, &r_irq);
+       rc = of_irq_to_resource(ofdev->dev.of_node, 0, &r_irq);
        if (rc == NO_IRQ) {
                dev_err(dev, "no IRQ found\n");
                return rc;
@@ -1182,7 +1182,7 @@ static int __devinit xemaclite_of_probe(struct of_device *ofdev,
        lp->next_rx_buf_to_use = 0x0;
        lp->tx_ping_pong = get_bool(ofdev, "xlnx,tx-ping-pong");
        lp->rx_ping_pong = get_bool(ofdev, "xlnx,rx-ping-pong");
-       mac_address = of_get_mac_address(ofdev->node);
+       mac_address = of_get_mac_address(ofdev->dev.of_node);
 
        if (mac_address)
                /* Set the MAC address. */
@@ -1197,7 +1197,7 @@ static int __devinit xemaclite_of_probe(struct of_device *ofdev,
        /* Set the MAC address in the EmacLite device */
        xemaclite_update_address(lp, ndev->dev_addr);
 
-       lp->phy_node = of_parse_phandle(ofdev->node, "phy-handle", 0);
+       lp->phy_node = of_parse_phandle(ofdev->dev.of_node, "phy-handle", 0);
        rc = xemaclite_mdio_setup(lp, &ofdev->dev);
        if (rc)
                dev_warn(&ofdev->dev, "error registering MDIO bus\n");
@@ -1291,8 +1291,11 @@ static struct of_device_id xemaclite_of_match[] __devinitdata = {
 MODULE_DEVICE_TABLE(of, xemaclite_of_match);
 
 static struct of_platform_driver xemaclite_of_driver = {
-       .name           = DRIVER_NAME,
-       .match_table    = xemaclite_of_match,
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = xemaclite_of_match,
+       },
        .probe          = xemaclite_of_probe,
        .remove         = __devexit_p(xemaclite_of_remove),
 };
index 224ae6bc67b6bb7b5b893192b7170cc6be8ef29c..7d18f8e0b013199c2e1bfd886b8dd6b93c639f7e 100644 (file)
@@ -10,8 +10,7 @@
 #include <asm/errno.h>
 
 /**
- * of_match_device - Tell if an of_device structure has a matching
- * of_match structure
+ * of_match_device - Tell if a struct device matches an of_device_id list
  * @ids: array of of device match structures to search in
  * @dev: the of device structure to match against
  *
  * system is in its list of supported devices.
  */
 const struct of_device_id *of_match_device(const struct of_device_id *matches,
-                                       const struct of_device *dev)
+                                          const struct device *dev)
 {
-       if (!dev->node)
+       if (!dev->of_node)
                return NULL;
-       return of_match_node(matches, dev->node);
+       return of_match_node(matches, dev->of_node);
 }
 EXPORT_SYMBOL(of_match_device);
 
@@ -54,7 +53,7 @@ static ssize_t devspec_show(struct device *dev,
        struct of_device *ofdev;
 
        ofdev = to_of_device(dev);
-       return sprintf(buf, "%s\n", ofdev->node->full_name);
+       return sprintf(buf, "%s\n", ofdev->dev.of_node->full_name);
 }
 
 static ssize_t name_show(struct device *dev,
@@ -63,7 +62,7 @@ static ssize_t name_show(struct device *dev,
        struct of_device *ofdev;
 
        ofdev = to_of_device(dev);
-       return sprintf(buf, "%s\n", ofdev->node->name);
+       return sprintf(buf, "%s\n", ofdev->dev.of_node->name);
 }
 
 static ssize_t modalias_show(struct device *dev,
@@ -97,14 +96,14 @@ void of_release_dev(struct device *dev)
        struct of_device *ofdev;
 
        ofdev = to_of_device(dev);
-       of_node_put(ofdev->node);
+       of_node_put(ofdev->dev.of_node);
        kfree(ofdev);
 }
 EXPORT_SYMBOL(of_release_dev);
 
 int of_device_register(struct of_device *ofdev)
 {
-       BUG_ON(ofdev->node == NULL);
+       BUG_ON(ofdev->dev.of_node == NULL);
 
        device_initialize(&ofdev->dev);
 
@@ -112,7 +111,7 @@ int of_device_register(struct of_device *ofdev)
         * the parent. If there is no parent defined, set the node
         * explicitly */
        if (!ofdev->dev.parent)
-               set_dev_node(&ofdev->dev, of_node_to_nid(ofdev->node));
+               set_dev_node(&ofdev->dev, of_node_to_nid(ofdev->dev.of_node));
 
        return device_add(&ofdev->dev);
 }
@@ -132,11 +131,11 @@ ssize_t of_device_get_modalias(struct of_device *ofdev,
        ssize_t tsize, csize, repend;
 
        /* Name & Type */
-       csize = snprintf(str, len, "of:N%sT%s",
-                               ofdev->node->name, ofdev->node->type);
+       csize = snprintf(str, len, "of:N%sT%s", ofdev->dev.of_node->name,
+                        ofdev->dev.of_node->type);
 
        /* Get compatible property if any */
-       compat = of_get_property(ofdev->node, "compatible", &cplen);
+       compat = of_get_property(ofdev->dev.of_node, "compatible", &cplen);
        if (!compat)
                return csize;
 
index dee4fb56b094106381dc891d94bdc47341480131..b6987bba85566d6df8f3afdd8187599cb3618758 100644 (file)
@@ -556,6 +556,21 @@ void __init unflatten_device_tree(void)
 
        pr_debug(" -> unflatten_device_tree()\n");
 
+       if (!initial_boot_params) {
+               pr_debug("No device tree pointer\n");
+               return;
+       }
+
+       pr_debug("Unflattening device tree:\n");
+       pr_debug("magic: %08x\n", be32_to_cpu(initial_boot_params->magic));
+       pr_debug("size: %08x\n", be32_to_cpu(initial_boot_params->totalsize));
+       pr_debug("version: %08x\n", be32_to_cpu(initial_boot_params->version));
+
+       if (be32_to_cpu(initial_boot_params->magic) != OF_DT_HEADER) {
+               pr_err("Invalid device tree blob header\n");
+               return;
+       }
+
        /* First pass, scan for size */
        start = ((unsigned long)initial_boot_params) +
                be32_to_cpu(initial_boot_params->off_dt_struct);
index a3a708e590d00eabbd2ce62105d2bd4c06bbd922..ab6522c8e4fe801fc5ae8fefb782fdc0869a77fa 100644 (file)
@@ -42,7 +42,7 @@ void of_register_i2c_devices(struct i2c_adapter *adap,
 
                info.addr = be32_to_cpup(addr);
 
-               dev_archdata_set_node(&dev_ad, node);
+               info.of_node = node;
                info.archdata = &dev_ad;
 
                request_module("%s", info.type);
@@ -68,7 +68,7 @@ EXPORT_SYMBOL(of_register_i2c_devices);
 
 static int of_dev_node_match(struct device *dev, void *data)
 {
-        return dev_archdata_get_node(&dev->archdata) == data;
+        return dev->of_node == data;
 }
 
 /* must call put_device() when done with returned i2c_client device */
index b4748337223b43d28aa7fb11d7eb788ec29d6da4..42a6715f8e84287ed2eef40382dc7bc89e181fbf 100644 (file)
@@ -79,7 +79,7 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
                /* Associate the OF node with the device structure so it
                 * can be looked up later */
                of_node_get(child);
-               dev_archdata_set_node(&phy->dev.archdata, child);
+               phy->dev.of_node = child;
 
                /* All data is now stored in the phy struct; register it */
                rc = phy_device_register(phy);
@@ -100,7 +100,7 @@ EXPORT_SYMBOL(of_mdiobus_register);
 /* Helper function for of_phy_find_device */
 static int of_phy_match(struct device *dev, void *phy_np)
 {
-       return dev_archdata_get_node(&dev->archdata) == phy_np;
+       return dev->of_node == phy_np;
 }
 
 /**
@@ -166,7 +166,7 @@ struct phy_device *of_phy_connect_fixed_link(struct net_device *dev,
        if (!dev->dev.parent)
                return NULL;
 
-       net_np = dev_archdata_get_node(&dev->dev.parent->archdata);
+       net_np = dev->dev.parent->of_node;
        if (!net_np)
                return NULL;
 
index f65f48b9844885c9708596c73aa4f7eeefba1904..5fed7e3c7da341362a1c7bdf08f53b5e4b11c60a 100644 (file)
@@ -79,7 +79,7 @@ void of_register_spi_devices(struct spi_master *master, struct device_node *np)
 
                /* Store a pointer to the node in the device structure */
                of_node_get(nc);
-               spi->dev.archdata.of_node = nc;
+               spi->dev.of_node = nc;
 
                /* Register the new device */
                request_module(spi->modalias);
index d58ade170c4b27fd50bf5abc471eac618c4eea3e..7dacc1ebe91e013cadbc77ca57cf729f34585ef5 100644 (file)
@@ -21,14 +21,12 @@ extern struct device_attribute of_platform_device_attrs[];
 
 static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
 {
-       struct of_device *of_dev = to_of_device(dev);
-       struct of_platform_driver *of_drv = to_of_platform_driver(drv);
-       const struct of_device_id *matches = of_drv->match_table;
+       const struct of_device_id *matches = drv->of_match_table;
 
        if (!matches)
                return 0;
 
-       return of_match_device(matches, of_dev) != NULL;
+       return of_match_device(matches, dev) != NULL;
 }
 
 static int of_platform_device_probe(struct device *dev)
@@ -46,7 +44,7 @@ static int of_platform_device_probe(struct device *dev)
 
        of_dev_get(of_dev);
 
-       match = of_match_device(drv->match_table, of_dev);
+       match = of_match_device(drv->driver.of_match_table, dev);
        if (match)
                error = drv->probe(of_dev, match);
        if (error)
@@ -386,11 +384,6 @@ int of_bus_type_init(struct bus_type *bus, const char *name)
 
 int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus)
 {
-       /* initialize common driver fields */
-       if (!drv->driver.name)
-               drv->driver.name = drv->name;
-       if (!drv->driver.owner)
-               drv->driver.owner = drv->owner;
        drv->driver.bus = bus;
 
        /* register with core */
index 1586e1caa2f56a790c550a535bd17702d6230c72..8bef6d60f88b6f10a683ffae201530123c5c49e9 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/parport.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
 #include <asm/setup.h>
 #include <asm/amigahw.h>
 #include <asm/irq.h>
@@ -31,7 +33,6 @@
 #define DPRINTK(x...)  do { } while (0)
 #endif
 
-static struct parport *this_port = NULL;
 
 static void amiga_write_data(struct parport *p, unsigned char data)
 {
@@ -227,18 +228,11 @@ static struct parport_operations pp_amiga_ops = {
 
 /* ----------- Initialisation code --------------------------------- */
 
-static int __init parport_amiga_init(void)
+static int __init amiga_parallel_probe(struct platform_device *pdev)
 {
        struct parport *p;
        int err;
 
-       if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_PARALLEL))
-               return -ENODEV;
-
-       err = -EBUSY;
-       if (!request_mem_region(CIAA_PHYSADDR-1+0x100, 0x100, "parallel"))
-               goto out_mem;
-
        ciaa.ddrb = 0xff;
        ciab.ddra &= 0xf8;
        mb();
@@ -246,41 +240,63 @@ static int __init parport_amiga_init(void)
        p = parport_register_port((unsigned long)&ciaa.prb, IRQ_AMIGA_CIAA_FLG,
                                   PARPORT_DMA_NONE, &pp_amiga_ops);
        if (!p)
-               goto out_port;
+               return -EBUSY;
 
-       err = request_irq(IRQ_AMIGA_CIAA_FLG, parport_irq_handler, 0, p->name, p);
+       err = request_irq(IRQ_AMIGA_CIAA_FLG, parport_irq_handler, 0, p->name,
+                         p);
        if (err)
                goto out_irq;
 
-       this_port = p;
        printk(KERN_INFO "%s: Amiga built-in port using irq\n", p->name);
        /* XXX: set operating mode */
        parport_announce_port(p);
 
+       platform_set_drvdata(pdev, p);
+
        return 0;
 
 out_irq:
        parport_put_port(p);
-out_port:
-       release_mem_region(CIAA_PHYSADDR-1+0x100, 0x100);
-out_mem:
        return err;
 }
 
-static void __exit parport_amiga_exit(void)
+static int __exit amiga_parallel_remove(struct platform_device *pdev)
+{
+       struct parport *port = platform_get_drvdata(pdev);
+
+       parport_remove_port(port);
+       if (port->irq != PARPORT_IRQ_NONE)
+               free_irq(IRQ_AMIGA_CIAA_FLG, port);
+       parport_put_port(port);
+       platform_set_drvdata(pdev, NULL);
+       return 0;
+}
+
+static struct platform_driver amiga_parallel_driver = {
+       .remove = __exit_p(amiga_parallel_remove),
+       .driver   = {
+               .name   = "amiga-parallel",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init amiga_parallel_init(void)
+{
+       return platform_driver_probe(&amiga_parallel_driver,
+                                    amiga_parallel_probe);
+}
+
+module_init(amiga_parallel_init);
+
+static void __exit amiga_parallel_exit(void)
 {
-       parport_remove_port(this_port);
-       if (this_port->irq != PARPORT_IRQ_NONE)
-               free_irq(IRQ_AMIGA_CIAA_FLG, this_port);
-       parport_put_port(this_port);
-       release_mem_region(CIAA_PHYSADDR-1+0x100, 0x100);
+       platform_driver_unregister(&amiga_parallel_driver);
 }
 
+module_exit(amiga_parallel_exit);
 
 MODULE_AUTHOR("Joerg Dorchain <joerg@dorchain.net>");
 MODULE_DESCRIPTION("Parport Driver for Amiga builtin Port");
 MODULE_SUPPORTED_DEVICE("Amiga builtin Parallel Port");
 MODULE_LICENSE("GPL");
-
-module_init(parport_amiga_init)
-module_exit(parport_amiga_exit)
+MODULE_ALIAS("platform:amiga-parallel");
index 065f229580d5cfc3acd8d740597bb638c558a889..9a5b4b89416146827467946e77e96c36ac391c68 100644 (file)
@@ -382,8 +382,11 @@ static const struct of_device_id bpp_match[] = {
 MODULE_DEVICE_TABLE(of, bpp_match);
 
 static struct of_platform_driver bpp_sbus_driver = {
-       .name           = "bpp",
-       .match_table    = bpp_match,
+       .driver = {
+               .name = "bpp",
+               .owner = THIS_MODULE,
+               .of_match_table = bpp_match,
+       },
        .probe          = bpp_probe,
        .remove         = __devexit_p(bpp_remove),
 };
index 7858a117e80b04aab04bd112ed383a66d2e40a40..34ef70d562b2ea18256e3555639f972497481af7 100644 (file)
@@ -19,7 +19,7 @@ config PCI_MSI
           by using the 'pci=nomsi' option.  This disables MSI for the
           entire system.
 
-          If you don't know what to do here, say N.
+          If you don't know what to do here, say Y.
 
 config PCI_DEBUG
        bool "PCI Debugging"
index 2f646fe1260f3831b13036cdfd5b26cb56078c8e..531bc697d800910087d8ff2f125a00c03dd4abc9 100644 (file)
@@ -13,7 +13,7 @@
  * configuration space.
  */
 
-static DEFINE_SPINLOCK(pci_lock);
+static DEFINE_RAW_SPINLOCK(pci_lock);
 
 /*
  *  Wrappers for all PCI configuration access functions.  They just check
@@ -33,10 +33,10 @@ int pci_bus_read_config_##size \
        unsigned long flags;                                            \
        u32 data = 0;                                                   \
        if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER;       \
-       spin_lock_irqsave(&pci_lock, flags);                            \
+       raw_spin_lock_irqsave(&pci_lock, flags);                        \
        res = bus->ops->read(bus, devfn, pos, len, &data);              \
        *value = (type)data;                                            \
-       spin_unlock_irqrestore(&pci_lock, flags);                       \
+       raw_spin_unlock_irqrestore(&pci_lock, flags);           \
        return res;                                                     \
 }
 
@@ -47,9 +47,9 @@ int pci_bus_write_config_##size \
        int res;                                                        \
        unsigned long flags;                                            \
        if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER;       \
-       spin_lock_irqsave(&pci_lock, flags);                            \
+       raw_spin_lock_irqsave(&pci_lock, flags);                        \
        res = bus->ops->write(bus, devfn, pos, len, value);             \
-       spin_unlock_irqrestore(&pci_lock, flags);                       \
+       raw_spin_unlock_irqrestore(&pci_lock, flags);           \
        return res;                                                     \
 }
 
@@ -79,10 +79,10 @@ struct pci_ops *pci_bus_set_ops(struct pci_bus *bus, struct pci_ops *ops)
        struct pci_ops *old_ops;
        unsigned long flags;
 
-       spin_lock_irqsave(&pci_lock, flags);
+       raw_spin_lock_irqsave(&pci_lock, flags);
        old_ops = bus->ops;
        bus->ops = ops;
-       spin_unlock_irqrestore(&pci_lock, flags);
+       raw_spin_unlock_irqrestore(&pci_lock, flags);
        return old_ops;
 }
 EXPORT_SYMBOL(pci_bus_set_ops);
@@ -136,9 +136,9 @@ static noinline void pci_wait_ucfg(struct pci_dev *dev)
        __add_wait_queue(&pci_ucfg_wait, &wait);
        do {
                set_current_state(TASK_UNINTERRUPTIBLE);
-               spin_unlock_irq(&pci_lock);
+               raw_spin_unlock_irq(&pci_lock);
                schedule();
-               spin_lock_irq(&pci_lock);
+               raw_spin_lock_irq(&pci_lock);
        } while (dev->block_ucfg_access);
        __remove_wait_queue(&pci_ucfg_wait, &wait);
 }
@@ -150,11 +150,11 @@ int pci_user_read_config_##size                                           \
        int ret = 0;                                                    \
        u32 data = -1;                                                  \
        if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER;       \
-       spin_lock_irq(&pci_lock);                                       \
+       raw_spin_lock_irq(&pci_lock);                           \
        if (unlikely(dev->block_ucfg_access)) pci_wait_ucfg(dev);       \
        ret = dev->bus->ops->read(dev->bus, dev->devfn,                 \
                                        pos, sizeof(type), &data);      \
-       spin_unlock_irq(&pci_lock);                                     \
+       raw_spin_unlock_irq(&pci_lock);                         \
        *val = (type)data;                                              \
        return ret;                                                     \
 }
@@ -165,11 +165,11 @@ int pci_user_write_config_##size                                  \
 {                                                                      \
        int ret = -EIO;                                                 \
        if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER;       \
-       spin_lock_irq(&pci_lock);                                       \
+       raw_spin_lock_irq(&pci_lock);                           \
        if (unlikely(dev->block_ucfg_access)) pci_wait_ucfg(dev);       \
        ret = dev->bus->ops->write(dev->bus, dev->devfn,                \
                                        pos, sizeof(type), val);        \
-       spin_unlock_irq(&pci_lock);                                     \
+       raw_spin_unlock_irq(&pci_lock);                         \
        return ret;                                                     \
 }
 
@@ -220,8 +220,13 @@ static int pci_vpd_pci22_wait(struct pci_dev *dev)
                        return 0;
                }
 
-               if (time_after(jiffies, timeout))
+               if (time_after(jiffies, timeout)) {
+                       dev_printk(KERN_DEBUG, &dev->dev,
+                                  "vpd r/w failed.  This is likely a firmware "
+                                  "bug on this device.  Contact the card "
+                                  "vendor for a firmware update.");
                        return -ETIMEDOUT;
+               }
                if (fatal_signal_pending(current))
                        return -EINTR;
                if (!cond_resched())
@@ -396,10 +401,10 @@ void pci_block_user_cfg_access(struct pci_dev *dev)
        unsigned long flags;
        int was_blocked;
 
-       spin_lock_irqsave(&pci_lock, flags);
+       raw_spin_lock_irqsave(&pci_lock, flags);
        was_blocked = dev->block_ucfg_access;
        dev->block_ucfg_access = 1;
-       spin_unlock_irqrestore(&pci_lock, flags);
+       raw_spin_unlock_irqrestore(&pci_lock, flags);
 
        /* If we BUG() inside the pci_lock, we're guaranteed to hose
         * the machine */
@@ -417,7 +422,7 @@ void pci_unblock_user_cfg_access(struct pci_dev *dev)
 {
        unsigned long flags;
 
-       spin_lock_irqsave(&pci_lock, flags);
+       raw_spin_lock_irqsave(&pci_lock, flags);
 
        /* This indicates a problem in the caller, but we don't need
         * to kill them, unlike a double-block above. */
@@ -425,6 +430,6 @@ void pci_unblock_user_cfg_access(struct pci_dev *dev)
 
        dev->block_ucfg_access = 0;
        wake_up_all(&pci_ucfg_wait);
-       spin_unlock_irqrestore(&pci_lock, flags);
+       raw_spin_unlock_irqrestore(&pci_lock, flags);
 }
 EXPORT_SYMBOL_GPL(pci_unblock_user_cfg_access);
index 33ead97f0c4b24e2e030ae913bef26cdf435d533..0a19708074c2b5265379ec816e777771823ab861 100644 (file)
@@ -131,9 +131,10 @@ static int __init dmar_parse_dev_scope(void *start, void *end, int *cnt,
                if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT ||
                    scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE)
                        (*cnt)++;
-               else
+               else if (scope->entry_type != ACPI_DMAR_SCOPE_TYPE_IOAPIC) {
                        printk(KERN_WARNING PREFIX
-                               "Unsupported device scope\n");
+                              "Unsupported device scope\n");
+               }
                start += scope->length;
        }
        if (*cnt == 0)
@@ -309,6 +310,8 @@ int dmar_find_matched_atsr_unit(struct pci_dev *dev)
        struct acpi_dmar_atsr *atsr;
        struct dmar_atsr_unit *atsru;
 
+       dev = pci_physfn(dev);
+
        list_for_each_entry(atsru, &dmar_atsr_units, list) {
                atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
                if (atsr->segment == pci_domain_nr(dev->bus))
@@ -358,12 +361,14 @@ dmar_parse_one_rhsa(struct acpi_dmar_header *header)
                        return 0;
                }
        }
-       WARN(1, "Your BIOS is broken; RHSA refers to non-existent DMAR unit at %llx\n"
-            "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
-            drhd->reg_base_addr,
-            dmi_get_system_info(DMI_BIOS_VENDOR),
-            dmi_get_system_info(DMI_BIOS_VERSION),
-            dmi_get_system_info(DMI_PRODUCT_VERSION));
+       WARN_TAINT(
+               1, TAINT_FIRMWARE_WORKAROUND,
+               "Your BIOS is broken; RHSA refers to non-existent DMAR unit at %llx\n"
+               "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
+               drhd->reg_base_addr,
+               dmi_get_system_info(DMI_BIOS_VENDOR),
+               dmi_get_system_info(DMI_BIOS_VERSION),
+               dmi_get_system_info(DMI_PRODUCT_VERSION));
 
        return 0;
 }
@@ -507,7 +512,7 @@ parse_dmar_table(void)
        return ret;
 }
 
-int dmar_pci_device_match(struct pci_dev *devices[], int cnt,
+static int dmar_pci_device_match(struct pci_dev *devices[], int cnt,
                          struct pci_dev *dev)
 {
        int index;
@@ -530,6 +535,8 @@ dmar_find_matched_drhd_unit(struct pci_dev *dev)
        struct dmar_drhd_unit *dmaru = NULL;
        struct acpi_dmar_hardware_unit *drhd;
 
+       dev = pci_physfn(dev);
+
        list_for_each_entry(dmaru, &dmar_drhd_units, list) {
                drhd = container_of(dmaru->hdr,
                                    struct acpi_dmar_hardware_unit,
@@ -614,7 +621,17 @@ int __init dmar_table_init(void)
        return 0;
 }
 
-static int bios_warned;
+static void warn_invalid_dmar(u64 addr, const char *message)
+{
+       WARN_TAINT_ONCE(
+               1, TAINT_FIRMWARE_WORKAROUND,
+               "Your BIOS is broken; DMAR reported at address %llx%s!\n"
+               "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
+               addr, message,
+               dmi_get_system_info(DMI_BIOS_VENDOR),
+               dmi_get_system_info(DMI_BIOS_VERSION),
+               dmi_get_system_info(DMI_PRODUCT_VERSION));
+}
 
 int __init check_zero_address(void)
 {
@@ -640,13 +657,7 @@ int __init check_zero_address(void)
 
                        drhd = (void *)entry_header;
                        if (!drhd->address) {
-                               /* Promote an attitude of violence to a BIOS engineer today */
-                               WARN(1, "Your BIOS is broken; DMAR reported at address zero!\n"
-                                    "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
-                                    dmi_get_system_info(DMI_BIOS_VENDOR),
-                                    dmi_get_system_info(DMI_BIOS_VERSION),
-                                    dmi_get_system_info(DMI_PRODUCT_VERSION));
-                               bios_warned = 1;
+                               warn_invalid_dmar(0, "");
                                goto failed;
                        }
 
@@ -659,14 +670,8 @@ int __init check_zero_address(void)
                        ecap = dmar_readq(addr + DMAR_ECAP_REG);
                        early_iounmap(addr, VTD_PAGE_SIZE);
                        if (cap == (uint64_t)-1 && ecap == (uint64_t)-1) {
-                               /* Promote an attitude of violence to a BIOS engineer today */
-                               WARN(1, "Your BIOS is broken; DMAR reported at address %llx returns all ones!\n"
-                                    "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
-                                     drhd->address,
-                                     dmi_get_system_info(DMI_BIOS_VENDOR),
-                                     dmi_get_system_info(DMI_BIOS_VERSION),
-                                     dmi_get_system_info(DMI_PRODUCT_VERSION));
-                               bios_warned = 1;
+                               warn_invalid_dmar(drhd->address,
+                                                 " returns all ones");
                                goto failed;
                        }
                }
@@ -731,14 +736,7 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
        int msagaw = 0;
 
        if (!drhd->reg_base_addr) {
-               if (!bios_warned) {
-                       WARN(1, "Your BIOS is broken; DMAR reported at address zero!\n"
-                            "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
-                            dmi_get_system_info(DMI_BIOS_VENDOR),
-                            dmi_get_system_info(DMI_BIOS_VERSION),
-                            dmi_get_system_info(DMI_PRODUCT_VERSION));
-                       bios_warned = 1;
-               }
+               warn_invalid_dmar(0, "");
                return -EINVAL;
        }
 
@@ -758,16 +756,7 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
        iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG);
 
        if (iommu->cap == (uint64_t)-1 && iommu->ecap == (uint64_t)-1) {
-               if (!bios_warned) {
-                       /* Promote an attitude of violence to a BIOS engineer today */
-                       WARN(1, "Your BIOS is broken; DMAR reported at address %llx returns all ones!\n"
-                            "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
-                            drhd->reg_base_addr,
-                            dmi_get_system_info(DMI_BIOS_VENDOR),
-                            dmi_get_system_info(DMI_BIOS_VERSION),
-                            dmi_get_system_info(DMI_PRODUCT_VERSION));
-                       bios_warned = 1;
-               }
+               warn_invalid_dmar(drhd->reg_base_addr, " returns all ones");
                goto err_unmap;
        }
 
@@ -806,7 +795,8 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
        }
 
        ver = readl(iommu->reg + DMAR_VER_REG);
-       pr_info("IOMMU %llx: ver %d:%d cap %llx ecap %llx\n",
+       pr_info("IOMMU %d: reg_base_addr %llx ver %d:%d cap %llx ecap %llx\n",
+               iommu->seq_id,
                (unsigned long long)drhd->reg_base_addr,
                DMAR_VER_MAJOR(ver), DMAR_VER_MINOR(ver),
                (unsigned long long)iommu->cap,
@@ -1457,9 +1447,11 @@ int dmar_reenable_qi(struct intel_iommu *iommu)
 /*
  * Check interrupt remapping support in DMAR table description.
  */
-int dmar_ir_support(void)
+int __init dmar_ir_support(void)
 {
        struct acpi_table_dmar *dmar;
        dmar = (struct acpi_table_dmar *)dmar_tbl;
+       if (!dmar)
+               return 0;
        return dmar->flags & 0x1;
 }
index 6644337d63d68249b1bca0241e188db08dbabe5e..b3e5580c837b782ed3cf86108b82ee3e4c5473e6 100644 (file)
@@ -1075,13 +1075,12 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        /* make our own copy of the pci bus structure,
         * as we like tweaking it a lot */
-       ctrl->pci_bus = kmalloc(sizeof(*ctrl->pci_bus), GFP_KERNEL);
+       ctrl->pci_bus = kmemdup(pdev->bus, sizeof(*ctrl->pci_bus), GFP_KERNEL);
        if (!ctrl->pci_bus) {
                err("out of memory\n");
                rc = -ENOMEM;
                goto err_free_ctrl;
        }
-       memcpy(ctrl->pci_bus, pdev->bus, sizeof(*ctrl->pci_bus));
 
        ctrl->bus = pdev->bus->number;
        ctrl->rev = pdev->revision;
index 0a16444c14c9d46d80ad391d5759cc27e0ab19f9..2fce726758d2f1bc0c5d24dff8ca3690707c4a56 100644 (file)
@@ -84,12 +84,6 @@ int pciehp_configure_device(struct slot *p_slot)
                dev = pci_get_slot(parent, PCI_DEVFN(0, fn));
                if (!dev)
                        continue;
-               if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
-                       ctrl_err(ctrl, "Cannot hot-add display device %s\n",
-                                pci_name(dev));
-                       pci_dev_put(dev);
-                       continue;
-               }
                if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
                                (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) {
                        pciehp_add_bridge(dev);
@@ -133,15 +127,9 @@ int pciehp_unconfigure_device(struct slot *p_slot)
                presence = 0;
 
        for (j = 0; j < 8; j++) {
-               struct pci_devtemp = pci_get_slot(parent, PCI_DEVFN(0, j));
+               struct pci_dev *temp = pci_get_slot(parent, PCI_DEVFN(0, j));
                if (!temp)
                        continue;
-               if ((temp->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
-                       ctrl_err(ctrl, "Cannot remove display device %s\n",
-                                pci_name(temp));
-                       pci_dev_put(temp);
-                       continue;
-               }
                if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE && presence) {
                        pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl);
                        if (bctl & PCI_BRIDGE_CTL_VGA) {
@@ -149,7 +137,8 @@ int pciehp_unconfigure_device(struct slot *p_slot)
                                         "Cannot remove display device %s\n",
                                         pci_name(temp));
                                pci_dev_put(temp);
-                               continue;
+                               rc = EINVAL;
+                               break;
                        }
                }
                pci_remove_bus_device(temp);
index 371dc564e2e46c744ac48dc9fd08c361dee0c34b..796828fce34cb5b918a485de903d3af18971ed38 100644 (file)
@@ -491,13 +491,11 @@ static void domain_update_iommu_coherency(struct dmar_domain *domain)
 
        domain->iommu_coherency = 1;
 
-       i = find_first_bit(&domain->iommu_bmp, g_num_of_iommus);
-       for (; i < g_num_of_iommus; ) {
+       for_each_set_bit(i, &domain->iommu_bmp, g_num_of_iommus) {
                if (!ecap_coherent(g_iommus[i]->ecap)) {
                        domain->iommu_coherency = 0;
                        break;
                }
-               i = find_next_bit(&domain->iommu_bmp, g_num_of_iommus, i+1);
        }
 }
 
@@ -507,13 +505,11 @@ static void domain_update_iommu_snooping(struct dmar_domain *domain)
 
        domain->iommu_snooping = 1;
 
-       i = find_first_bit(&domain->iommu_bmp, g_num_of_iommus);
-       for (; i < g_num_of_iommus; ) {
+       for_each_set_bit(i, &domain->iommu_bmp, g_num_of_iommus) {
                if (!ecap_sc_support(g_iommus[i]->ecap)) {
                        domain->iommu_snooping = 0;
                        break;
                }
-               i = find_next_bit(&domain->iommu_bmp, g_num_of_iommus, i+1);
        }
 }
 
@@ -1068,7 +1064,7 @@ static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
 }
 
 static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
-                                 unsigned long pfn, unsigned int pages)
+                                 unsigned long pfn, unsigned int pages, int map)
 {
        unsigned int mask = ilog2(__roundup_pow_of_two(pages));
        uint64_t addr = (uint64_t)pfn << VTD_PAGE_SHIFT;
@@ -1089,10 +1085,10 @@ static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
                                                DMA_TLB_PSI_FLUSH);
 
        /*
-        * In caching mode, domain ID 0 is reserved for non-present to present
-        * mapping flush. Device IOTLB doesn't need to be flushed in this case.
+        * In caching mode, changes of pages from non-present to present require
+        * flush. However, device IOTLB doesn't need to be flushed in this case.
         */
-       if (!cap_caching_mode(iommu->cap) || did)
+       if (!cap_caching_mode(iommu->cap) || !map)
                iommu_flush_dev_iotlb(iommu->domains[did], addr, mask);
 }
 
@@ -1154,7 +1150,8 @@ static int iommu_init_domains(struct intel_iommu *iommu)
        unsigned long nlongs;
 
        ndomains = cap_ndoms(iommu->cap);
-       pr_debug("Number of Domains supportd <%ld>\n", ndomains);
+       pr_debug("IOMMU %d: Number of Domains supportd <%ld>\n", iommu->seq_id,
+                       ndomains);
        nlongs = BITS_TO_LONGS(ndomains);
 
        spin_lock_init(&iommu->lock);
@@ -1194,8 +1191,7 @@ void free_dmar_iommu(struct intel_iommu *iommu)
        unsigned long flags;
 
        if ((iommu->domains) && (iommu->domain_ids)) {
-               i = find_first_bit(iommu->domain_ids, cap_ndoms(iommu->cap));
-               for (; i < cap_ndoms(iommu->cap); ) {
+               for_each_set_bit(i, iommu->domain_ids, cap_ndoms(iommu->cap)) {
                        domain = iommu->domains[i];
                        clear_bit(i, iommu->domain_ids);
 
@@ -1207,9 +1203,6 @@ void free_dmar_iommu(struct intel_iommu *iommu)
                                        domain_exit(domain);
                        }
                        spin_unlock_irqrestore(&domain->iommu_lock, flags);
-
-                       i = find_next_bit(iommu->domain_ids,
-                               cap_ndoms(iommu->cap), i+1);
                }
        }
 
@@ -1292,14 +1285,11 @@ static void iommu_detach_domain(struct dmar_domain *domain,
 
        spin_lock_irqsave(&iommu->lock, flags);
        ndomains = cap_ndoms(iommu->cap);
-       num = find_first_bit(iommu->domain_ids, ndomains);
-       for (; num < ndomains; ) {
+       for_each_set_bit(num, iommu->domain_ids, ndomains) {
                if (iommu->domains[num] == domain) {
                        found = 1;
                        break;
                }
-               num = find_next_bit(iommu->domain_ids,
-                                   cap_ndoms(iommu->cap), num+1);
        }
 
        if (found) {
@@ -1485,15 +1475,12 @@ static int domain_context_mapping_one(struct dmar_domain *domain, int segment,
 
                /* find an available domain id for this device in iommu */
                ndomains = cap_ndoms(iommu->cap);
-               num = find_first_bit(iommu->domain_ids, ndomains);
-               for (; num < ndomains; ) {
+               for_each_set_bit(num, iommu->domain_ids, ndomains) {
                        if (iommu->domains[num] == domain) {
                                id = num;
                                found = 1;
                                break;
                        }
-                       num = find_next_bit(iommu->domain_ids,
-                                           cap_ndoms(iommu->cap), num+1);
                }
 
                if (found == 0) {
@@ -1558,7 +1545,7 @@ static int domain_context_mapping_one(struct dmar_domain *domain, int segment,
                                           (((u16)bus) << 8) | devfn,
                                           DMA_CCMD_MASK_NOBIT,
                                           DMA_CCMD_DEVICE_INVL);
-               iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_DSI_FLUSH);
+               iommu->flush.flush_iotlb(iommu, domain->id, 0, 0, DMA_TLB_DSI_FLUSH);
        } else {
                iommu_flush_write_buffer(iommu);
        }
@@ -2333,14 +2320,16 @@ int __init init_dmars(void)
                         */
                        iommu->flush.flush_context = __iommu_flush_context;
                        iommu->flush.flush_iotlb = __iommu_flush_iotlb;
-                       printk(KERN_INFO "IOMMU 0x%Lx: using Register based "
+                       printk(KERN_INFO "IOMMU %d 0x%Lx: using Register based "
                               "invalidation\n",
+                               iommu->seq_id,
                               (unsigned long long)drhd->reg_base_addr);
                } else {
                        iommu->flush.flush_context = qi_flush_context;
                        iommu->flush.flush_iotlb = qi_flush_iotlb;
-                       printk(KERN_INFO "IOMMU 0x%Lx: using Queued "
+                       printk(KERN_INFO "IOMMU %d 0x%Lx: using Queued "
                               "invalidation\n",
+                               iommu->seq_id,
                               (unsigned long long)drhd->reg_base_addr);
                }
        }
@@ -2621,7 +2610,7 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
 
        /* it's a non-present to present mapping. Only flush if caching mode */
        if (cap_caching_mode(iommu->cap))
-               iommu_flush_iotlb_psi(iommu, 0, mm_to_dma_pfn(iova->pfn_lo), size);
+               iommu_flush_iotlb_psi(iommu, domain->id, mm_to_dma_pfn(iova->pfn_lo), size, 1);
        else
                iommu_flush_write_buffer(iommu);
 
@@ -2661,15 +2650,24 @@ static void flush_unmaps(void)
                if (!deferred_flush[i].next)
                        continue;
 
-               iommu->flush.flush_iotlb(iommu, 0, 0, 0,
+               /* In caching mode, global flushes turn emulation expensive */
+               if (!cap_caching_mode(iommu->cap))
+                       iommu->flush.flush_iotlb(iommu, 0, 0, 0,
                                         DMA_TLB_GLOBAL_FLUSH);
                for (j = 0; j < deferred_flush[i].next; j++) {
                        unsigned long mask;
                        struct iova *iova = deferred_flush[i].iova[j];
-
-                       mask = ilog2(mm_to_dma_pfn(iova->pfn_hi - iova->pfn_lo + 1));
-                       iommu_flush_dev_iotlb(deferred_flush[i].domain[j],
-                                       (uint64_t)iova->pfn_lo << PAGE_SHIFT, mask);
+                       struct dmar_domain *domain = deferred_flush[i].domain[j];
+
+                       /* On real hardware multiple invalidations are expensive */
+                       if (cap_caching_mode(iommu->cap))
+                               iommu_flush_iotlb_psi(iommu, domain->id,
+                               iova->pfn_lo, iova->pfn_hi - iova->pfn_lo + 1, 0);
+                       else {
+                               mask = ilog2(mm_to_dma_pfn(iova->pfn_hi - iova->pfn_lo + 1));
+                               iommu_flush_dev_iotlb(deferred_flush[i].domain[j],
+                                               (uint64_t)iova->pfn_lo << PAGE_SHIFT, mask);
+                       }
                        __free_iova(&deferred_flush[i].domain[j]->iovad, iova);
                }
                deferred_flush[i].next = 0;
@@ -2750,7 +2748,7 @@ static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
 
        if (intel_iommu_strict) {
                iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
-                                     last_pfn - start_pfn + 1);
+                                     last_pfn - start_pfn + 1, 0);
                /* free iova */
                __free_iova(&domain->iovad, iova);
        } else {
@@ -2840,7 +2838,7 @@ static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
 
        if (intel_iommu_strict) {
                iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
-                                     last_pfn - start_pfn + 1);
+                                     last_pfn - start_pfn + 1, 0);
                /* free iova */
                __free_iova(&domain->iovad, iova);
        } else {
@@ -2874,7 +2872,6 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int ne
        struct dmar_domain *domain;
        size_t size = 0;
        int prot = 0;
-       size_t offset_pfn = 0;
        struct iova *iova = NULL;
        int ret;
        struct scatterlist *sg;
@@ -2928,7 +2925,7 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int ne
 
        /* it's a non-present to present mapping. Only flush if caching mode */
        if (cap_caching_mode(iommu->cap))
-               iommu_flush_iotlb_psi(iommu, 0, start_vpfn, offset_pfn);
+               iommu_flush_iotlb_psi(iommu, domain->id, start_vpfn, size, 1);
        else
                iommu_flush_write_buffer(iommu);
 
@@ -3436,22 +3433,6 @@ static void vm_domain_remove_all_dev_info(struct dmar_domain *domain)
 /* domain id for virtual machine, it won't be set in context */
 static unsigned long vm_domid;
 
-static int vm_domain_min_agaw(struct dmar_domain *domain)
-{
-       int i;
-       int min_agaw = domain->agaw;
-
-       i = find_first_bit(&domain->iommu_bmp, g_num_of_iommus);
-       for (; i < g_num_of_iommus; ) {
-               if (min_agaw > g_iommus[i]->agaw)
-                       min_agaw = g_iommus[i]->agaw;
-
-               i = find_next_bit(&domain->iommu_bmp, g_num_of_iommus, i+1);
-       }
-
-       return min_agaw;
-}
-
 static struct dmar_domain *iommu_alloc_vm_domain(void)
 {
        struct dmar_domain *domain;
@@ -3512,8 +3493,7 @@ static void iommu_free_vm_domain(struct dmar_domain *domain)
                iommu = drhd->iommu;
 
                ndomains = cap_ndoms(iommu->cap);
-               i = find_first_bit(iommu->domain_ids, ndomains);
-               for (; i < ndomains; ) {
+               for_each_set_bit(i, iommu->domain_ids, ndomains) {
                        if (iommu->domains[i] == domain) {
                                spin_lock_irqsave(&iommu->lock, flags);
                                clear_bit(i, iommu->domain_ids);
@@ -3521,7 +3501,6 @@ static void iommu_free_vm_domain(struct dmar_domain *domain)
                                spin_unlock_irqrestore(&iommu->lock, flags);
                                break;
                        }
-                       i = find_next_bit(iommu->domain_ids, ndomains, i+1);
                }
        }
 }
@@ -3582,7 +3561,6 @@ static int intel_iommu_attach_device(struct iommu_domain *domain,
        struct pci_dev *pdev = to_pci_dev(dev);
        struct intel_iommu *iommu;
        int addr_width;
-       u64 end;
 
        /* normally pdev is not mapped */
        if (unlikely(domain_context_mapped(pdev))) {
@@ -3605,14 +3583,30 @@ static int intel_iommu_attach_device(struct iommu_domain *domain,
 
        /* check if this iommu agaw is sufficient for max mapped address */
        addr_width = agaw_to_width(iommu->agaw);
-       end = DOMAIN_MAX_ADDR(addr_width);
-       end = end & VTD_PAGE_MASK;
-       if (end < dmar_domain->max_addr) {
-               printk(KERN_ERR "%s: iommu agaw (%d) is not "
+       if (addr_width > cap_mgaw(iommu->cap))
+               addr_width = cap_mgaw(iommu->cap);
+
+       if (dmar_domain->max_addr > (1LL << addr_width)) {
+               printk(KERN_ERR "%s: iommu width (%d) is not "
                       "sufficient for the mapped address (%llx)\n",
-                      __func__, iommu->agaw, dmar_domain->max_addr);
+                      __func__, addr_width, dmar_domain->max_addr);
                return -EFAULT;
        }
+       dmar_domain->gaw = addr_width;
+
+       /*
+        * Knock out extra levels of page tables if necessary
+        */
+       while (iommu->agaw < dmar_domain->agaw) {
+               struct dma_pte *pte;
+
+               pte = dmar_domain->pgd;
+               if (dma_pte_present(pte)) {
+                       free_pgtable_page(dmar_domain->pgd);
+                       dmar_domain->pgd = (struct dma_pte *)dma_pte_addr(pte);
+               }
+               dmar_domain->agaw--;
+       }
 
        return domain_add_dev_info(dmar_domain, pdev, CONTEXT_TT_MULTI_LEVEL);
 }
@@ -3632,7 +3626,6 @@ static int intel_iommu_map(struct iommu_domain *domain,
 {
        struct dmar_domain *dmar_domain = domain->priv;
        u64 max_addr;
-       int addr_width;
        int prot = 0;
        size_t size;
        int ret;
@@ -3647,18 +3640,14 @@ static int intel_iommu_map(struct iommu_domain *domain,
        size     = PAGE_SIZE << gfp_order;
        max_addr = iova + size;
        if (dmar_domain->max_addr < max_addr) {
-               int min_agaw;
                u64 end;
 
                /* check if minimum agaw is sufficient for mapped address */
-               min_agaw = vm_domain_min_agaw(dmar_domain);
-               addr_width = agaw_to_width(min_agaw);
-               end = DOMAIN_MAX_ADDR(addr_width);
-               end = end & VTD_PAGE_MASK;
+               end = __DOMAIN_MAX_ADDR(dmar_domain->gaw) + 1;
                if (end < max_addr) {
-                       printk(KERN_ERR "%s: iommu agaw (%d) is not "
+                       printk(KERN_ERR "%s: iommu width (%d) is not "
                               "sufficient for the mapped address (%llx)\n",
-                              __func__, min_agaw, max_addr);
+                              __func__, dmar_domain->gaw, max_addr);
                        return -EFAULT;
                }
                dmar_domain->max_addr = max_addr;
index 6ee98a56946fff4a887b80f39c281ac495eb479b..1315ac688aa267d9aa504f4d2874b9aa930b4bc8 100644 (file)
@@ -832,9 +832,9 @@ static int ir_parse_ioapic_hpet_scope(struct acpi_dmar_header *header,
                                return -1;
                        }
 
-                       printk(KERN_INFO "IOAPIC id %d under DRHD base"
-                              " 0x%Lx\n", scope->enumeration_id,
-                              drhd->address);
+                       printk(KERN_INFO "IOAPIC id %d under DRHD base "
+                              " 0x%Lx IOMMU %d\n", scope->enumeration_id,
+                              drhd->address, iommu->seq_id);
 
                        ir_parse_one_ioapic_scope(scope, iommu);
                } else if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_HPET) {
index 6309c5a2528f1912bddabaabc6b870ed271a54e7..afd2fbf7d797185f9e645ff85f7450edc7039889 100644 (file)
@@ -979,7 +979,12 @@ static ssize_t reset_store(struct device *dev,
 
        if (val != 1)
                return -EINVAL;
-       return pci_reset_function(pdev);
+
+       result = pci_reset_function(pdev);
+       if (result < 0)
+               return result;
+
+       return count;
 }
 
 static struct device_attribute reset_attr = __ATTR(reset, 0200, NULL, reset_store);
@@ -1030,6 +1035,39 @@ error:
        return retval;
 }
 
+static void pci_remove_slot_links(struct pci_dev *dev)
+{
+       char func[10];
+       struct pci_slot *slot;
+
+       sysfs_remove_link(&dev->dev.kobj, "slot");
+       list_for_each_entry(slot, &dev->bus->slots, list) {
+               if (slot->number != PCI_SLOT(dev->devfn))
+                       continue;
+               snprintf(func, 10, "function%d", PCI_FUNC(dev->devfn));
+               sysfs_remove_link(&slot->kobj, func);
+       }
+}
+
+static int pci_create_slot_links(struct pci_dev *dev)
+{
+       int result = 0;
+       char func[10];
+       struct pci_slot *slot;
+
+       list_for_each_entry(slot, &dev->bus->slots, list) {
+               if (slot->number != PCI_SLOT(dev->devfn))
+                       continue;
+               result = sysfs_create_link(&dev->dev.kobj, &slot->kobj, "slot");
+               if (result)
+                       goto out;
+               snprintf(func, 10, "function%d", PCI_FUNC(dev->devfn));
+               result = sysfs_create_link(&slot->kobj, &dev->dev.kobj, func);
+       }
+out:
+       return result;
+}
+
 int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
 {
        int retval;
@@ -1092,6 +1130,8 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
        if (retval)
                goto err_vga_file;
 
+       pci_create_slot_links(pdev);
+
        return 0;
 
 err_vga_file:
@@ -1141,6 +1181,8 @@ void pci_remove_sysfs_dev_files(struct pci_dev *pdev)
        if (!sysfs_initialized)
                return;
 
+       pci_remove_slot_links(pdev);
+
        pci_remove_capabilities_sysfs(pdev);
 
        if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE)
index 1df7c508814ecb596685e8e8c27fcda2282006cc..60f30e7f1c8c1c81d874204103b58443d63c3416 100644 (file)
@@ -1193,7 +1193,7 @@ void pci_disable_enabled_device(struct pci_dev *dev)
  * anymore.  This only involves disabling PCI bus-mastering, if active.
  *
  * Note we don't actually disable the device until all callers of
- * pci_device_enable() have called pci_device_disable().
+ * pci_enable_device() have called pci_disable_device().
  */
 void
 pci_disable_device(struct pci_dev *dev)
@@ -1631,7 +1631,6 @@ void pci_pm_init(struct pci_dev *dev)
                 * let the user space enable it to wake up the system as needed.
                 */
                device_set_wakeup_capable(&dev->dev, true);
-               device_set_wakeup_enable(&dev->dev, false);
                /* Disable the PME# generation functionality */
                pci_pme_active(dev, false);
        } else {
@@ -1655,7 +1654,6 @@ void platform_pci_wakeup_init(struct pci_dev *dev)
                return;
 
        device_set_wakeup_capable(&dev->dev, true);
-       device_set_wakeup_enable(&dev->dev, false);
        platform_pci_sleep_wake(dev, false);
 }
 
index f8f425b8731ddb91f8663069da23495bf75befcb..909924692b8aeeb7a49c103cd31d2159e347eb9f 100644 (file)
@@ -168,7 +168,7 @@ static u32 *find_pci_config_dword(struct aer_error *err, int where,
                target = &err->root_status;
                rw1cs = 1;
                break;
-       case PCI_ERR_ROOT_COR_SRC:
+       case PCI_ERR_ROOT_ERR_SRC:
                target = &err->source_id;
                break;
        }
index 7a711ee314b7f6a6c3da38b4b47082c859e8dfa2..484cc55194b8841809218cb15d5f2ccccdffd582 100644 (file)
@@ -72,13 +72,120 @@ void pci_no_aer(void)
        pcie_aer_disable = 1;   /* has priority over 'forceload' */
 }
 
+static int set_device_error_reporting(struct pci_dev *dev, void *data)
+{
+       bool enable = *((bool *)data);
+
+       if ((dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) ||
+           (dev->pcie_type == PCI_EXP_TYPE_UPSTREAM) ||
+           (dev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM)) {
+               if (enable)
+                       pci_enable_pcie_error_reporting(dev);
+               else
+                       pci_disable_pcie_error_reporting(dev);
+       }
+
+       if (enable)
+               pcie_set_ecrc_checking(dev);
+
+       return 0;
+}
+
+/**
+ * set_downstream_devices_error_reporting - enable/disable the error reporting  bits on the root port and its downstream ports.
+ * @dev: pointer to root port's pci_dev data structure
+ * @enable: true = enable error reporting, false = disable error reporting.
+ */
+static void set_downstream_devices_error_reporting(struct pci_dev *dev,
+                                                  bool enable)
+{
+       set_device_error_reporting(dev, &enable);
+
+       if (!dev->subordinate)
+               return;
+       pci_walk_bus(dev->subordinate, set_device_error_reporting, &enable);
+}
+
+/**
+ * aer_enable_rootport - enable Root Port's interrupts when receiving messages
+ * @rpc: pointer to a Root Port data structure
+ *
+ * Invoked when PCIe bus loads AER service driver.
+ */
+static void aer_enable_rootport(struct aer_rpc *rpc)
+{
+       struct pci_dev *pdev = rpc->rpd->port;
+       int pos, aer_pos;
+       u16 reg16;
+       u32 reg32;
+
+       pos = pci_pcie_cap(pdev);
+       /* Clear PCIe Capability's Device Status */
+       pci_read_config_word(pdev, pos+PCI_EXP_DEVSTA, &reg16);
+       pci_write_config_word(pdev, pos+PCI_EXP_DEVSTA, reg16);
+
+       /* Disable system error generation in response to error messages */
+       pci_read_config_word(pdev, pos + PCI_EXP_RTCTL, &reg16);
+       reg16 &= ~(SYSTEM_ERROR_INTR_ON_MESG_MASK);
+       pci_write_config_word(pdev, pos + PCI_EXP_RTCTL, reg16);
+
+       aer_pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
+       /* Clear error status */
+       pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, &reg32);
+       pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, reg32);
+       pci_read_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, &reg32);
+       pci_write_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, reg32);
+       pci_read_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, &reg32);
+       pci_write_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, reg32);
+
+       /*
+        * Enable error reporting for the root port device and downstream port
+        * devices.
+        */
+       set_downstream_devices_error_reporting(pdev, true);
+
+       /* Enable Root Port's interrupt in response to error messages */
+       pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_COMMAND, &reg32);
+       reg32 |= ROOT_PORT_INTR_ON_MESG_MASK;
+       pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_COMMAND, reg32);
+}
+
+/**
+ * aer_disable_rootport - disable Root Port's interrupts when receiving messages
+ * @rpc: pointer to a Root Port data structure
+ *
+ * Invoked when PCIe bus unloads AER service driver.
+ */
+static void aer_disable_rootport(struct aer_rpc *rpc)
+{
+       struct pci_dev *pdev = rpc->rpd->port;
+       u32 reg32;
+       int pos;
+
+       /*
+        * Disable error reporting for the root port device and downstream port
+        * devices.
+        */
+       set_downstream_devices_error_reporting(pdev, false);
+
+       pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
+       /* Disable Root's interrupt in response to error messages */
+       pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, &reg32);
+       reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK;
+       pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, reg32);
+
+       /* Clear Root's error status reg */
+       pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, &reg32);
+       pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, reg32);
+}
+
 /**
  * aer_irq - Root Port's ISR
  * @irq: IRQ assigned to Root Port
  * @context: pointer to Root Port data structure
  *
  * Invoked when Root Port detects AER messages.
- **/
+ */
 irqreturn_t aer_irq(int irq, void *context)
 {
        unsigned int status, id;
@@ -97,13 +204,13 @@ irqreturn_t aer_irq(int irq, void *context)
 
        /* Read error status */
        pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, &status);
-       if (!(status & ROOT_ERR_STATUS_MASKS)) {
+       if (!(status & (PCI_ERR_ROOT_UNCOR_RCV|PCI_ERR_ROOT_COR_RCV))) {
                spin_unlock_irqrestore(&rpc->e_lock, flags);
                return IRQ_NONE;
        }
 
        /* Read error source and clear error status */
-       pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_COR_SRC, &id);
+       pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_ERR_SRC, &id);
        pci_write_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, status);
 
        /* Store error source for later DPC handler */
@@ -135,7 +242,7 @@ EXPORT_SYMBOL_GPL(aer_irq);
  * @dev: pointer to the pcie_dev data structure
  *
  * Invoked when Root Port's AER service is loaded.
- **/
+ */
 static struct aer_rpc *aer_alloc_rpc(struct pcie_device *dev)
 {
        struct aer_rpc *rpc;
@@ -144,15 +251,11 @@ static struct aer_rpc *aer_alloc_rpc(struct pcie_device *dev)
        if (!rpc)
                return NULL;
 
-       /*
-        * Initialize Root lock access, e_lock, to Root Error Status Reg,
-        * Root Error ID Reg, and Root error producer/consumer index.
-        */
+       /* Initialize Root lock access, e_lock, to Root Error Status Reg */
        spin_lock_init(&rpc->e_lock);
 
        rpc->rpd = dev;
        INIT_WORK(&rpc->dpc_handler, aer_isr);
-       rpc->prod_idx = rpc->cons_idx = 0;
        mutex_init(&rpc->rpc_mutex);
        init_waitqueue_head(&rpc->wait_release);
 
@@ -167,7 +270,7 @@ static struct aer_rpc *aer_alloc_rpc(struct pcie_device *dev)
  * @dev: pointer to the pcie_dev data structure
  *
  * Invoked when PCI Express bus unloads or AER probe fails.
- **/
+ */
 static void aer_remove(struct pcie_device *dev)
 {
        struct aer_rpc *rpc = get_service_data(dev);
@@ -179,7 +282,8 @@ static void aer_remove(struct pcie_device *dev)
 
                wait_event(rpc->wait_release, rpc->prod_idx == rpc->cons_idx);
 
-               aer_delete_rootport(rpc);
+               aer_disable_rootport(rpc);
+               kfree(rpc);
                set_service_data(dev, NULL);
        }
 }
@@ -190,7 +294,7 @@ static void aer_remove(struct pcie_device *dev)
  * @id: pointer to the service id data structure
  *
  * Invoked when PCI Express bus loads AER service driver.
- **/
+ */
 static int __devinit aer_probe(struct pcie_device *dev)
 {
        int status;
@@ -230,47 +334,30 @@ static int __devinit aer_probe(struct pcie_device *dev)
  * @dev: pointer to Root Port's pci_dev data structure
  *
  * Invoked by Port Bus driver when performing link reset at Root Port.
- **/
+ */
 static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
 {
-       u16 p2p_ctrl;
-       u32 status;
+       u32 reg32;
        int pos;
 
        pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
 
        /* Disable Root's interrupt in response to error messages */
-       pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, 0);
-
-       /* Assert Secondary Bus Reset */
-       pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &p2p_ctrl);
-       p2p_ctrl |= PCI_BRIDGE_CTL_BUS_RESET;
-       pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
-
-       /*
-        * we should send hot reset message for 2ms to allow it time to
-        * propogate to all downstream ports
-        */
-       msleep(2);
-
-       /* De-assert Secondary Bus Reset */
-       p2p_ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
-       pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
+       pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, &reg32);
+       reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK;
+       pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32);
 
-       /*
-        * System software must wait for at least 100ms from the end
-        * of a reset of one or more device before it is permitted
-        * to issue Configuration Requests to those devices.
-        */
-       msleep(200);
+       aer_do_secondary_bus_reset(dev);
        dev_printk(KERN_DEBUG, &dev->dev, "Root Port link has been reset\n");
 
+       /* Clear Root Error Status */
+       pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &reg32);
+       pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, reg32);
+
        /* Enable Root Port's interrupt in response to error messages */
-       pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &status);
-       pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, status);
-       pci_write_config_dword(dev,
-               pos + PCI_ERR_ROOT_COMMAND,
-               ROOT_PORT_INTR_ON_MESG_MASK);
+       pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, &reg32);
+       reg32 |= ROOT_PORT_INTR_ON_MESG_MASK;
+       pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32);
 
        return PCI_ERS_RESULT_RECOVERED;
 }
@@ -281,7 +368,7 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
  * @error: error severity being notified by port bus
  *
  * Invoked by Port Bus driver during error recovery.
- **/
+ */
 static pci_ers_result_t aer_error_detected(struct pci_dev *dev,
                        enum pci_channel_state error)
 {
@@ -294,7 +381,7 @@ static pci_ers_result_t aer_error_detected(struct pci_dev *dev,
  * @dev: pointer to Root Port's pci_dev data structure
  *
  * Invoked by Port Bus driver during nonfatal recovery.
- **/
+ */
 static void aer_error_resume(struct pci_dev *dev)
 {
        int pos;
@@ -321,7 +408,7 @@ static void aer_error_resume(struct pci_dev *dev)
  * aer_service_init - register AER root service driver
  *
  * Invoked when AER root service driver is loaded.
- **/
+ */
 static int __init aer_service_init(void)
 {
        if (pcie_aer_disable)
@@ -335,7 +422,7 @@ static int __init aer_service_init(void)
  * aer_service_exit - unregister AER root service driver
  *
  * Invoked when AER root service driver is unloaded.
- **/
+ */
 static void __exit aer_service_exit(void)
 {
        pcie_port_service_unregister(&aerdriver);
index bd833ea3ba495e77040a754f203ad42f68f709ea..80c11d1314999c77f9666dd6f892610b90e07bd0 100644 (file)
@@ -17,9 +17,6 @@
 #define AER_FATAL                      1
 #define AER_CORRECTABLE                        2
 
-/* Root Error Status Register Bits */
-#define ROOT_ERR_STATUS_MASKS          0x0f
-
 #define SYSTEM_ERROR_INTR_ON_MESG_MASK (PCI_EXP_RTCTL_SECEE|   \
                                        PCI_EXP_RTCTL_SENFEE|   \
                                        PCI_EXP_RTCTL_SEFEE)
@@ -117,8 +114,7 @@ static inline pci_ers_result_t merge_result(enum pci_ers_result orig,
 }
 
 extern struct bus_type pcie_port_bus_type;
-extern void aer_enable_rootport(struct aer_rpc *rpc);
-extern void aer_delete_rootport(struct aer_rpc *rpc);
+extern void aer_do_secondary_bus_reset(struct pci_dev *dev);
 extern int aer_init(struct pcie_device *dev);
 extern void aer_isr(struct work_struct *work);
 extern void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
@@ -134,4 +130,21 @@ static inline int aer_osc_setup(struct pcie_device *pciedev)
 }
 #endif
 
+#ifdef CONFIG_ACPI_APEI
+extern int pcie_aer_get_firmware_first(struct pci_dev *pci_dev);
+#else
+static inline int pcie_aer_get_firmware_first(struct pci_dev *pci_dev)
+{
+       if (pci_dev->__aer_firmware_first_valid)
+               return pci_dev->__aer_firmware_first;
+       return 0;
+}
+#endif
+
+static inline void pcie_aer_force_firmware_first(struct pci_dev *pci_dev,
+                                                int enable)
+{
+       pci_dev->__aer_firmware_first = !!enable;
+       pci_dev->__aer_firmware_first_valid = 1;
+}
 #endif /* _AERDRV_H_ */
index 04814087658d32a27ed6cd5dc8571b2ee077e59f..f278d7b0d95d32b636260cddbe763aa109fbfacf 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/acpi.h>
 #include <linux/pci-acpi.h>
 #include <linux/delay.h>
+#include <acpi/apei.h>
 #include "aerdrv.h"
 
 /**
@@ -53,3 +54,79 @@ int aer_osc_setup(struct pcie_device *pciedev)
 
        return 0;
 }
+
+#ifdef CONFIG_ACPI_APEI
+static inline int hest_match_pci(struct acpi_hest_aer_common *p,
+                                struct pci_dev *pci)
+{
+       return  (0           == pci_domain_nr(pci->bus) &&
+                p->bus      == pci->bus->number &&
+                p->device   == PCI_SLOT(pci->devfn) &&
+                p->function == PCI_FUNC(pci->devfn));
+}
+
+struct aer_hest_parse_info {
+       struct pci_dev *pci_dev;
+       int firmware_first;
+};
+
+static int aer_hest_parse(struct acpi_hest_header *hest_hdr, void *data)
+{
+       struct aer_hest_parse_info *info = data;
+       struct acpi_hest_aer_common *p;
+       u8 pcie_type = 0;
+       u8 bridge = 0;
+       int ff = 0;
+
+       switch (hest_hdr->type) {
+       case ACPI_HEST_TYPE_AER_ROOT_PORT:
+               pcie_type = PCI_EXP_TYPE_ROOT_PORT;
+               break;
+       case ACPI_HEST_TYPE_AER_ENDPOINT:
+               pcie_type = PCI_EXP_TYPE_ENDPOINT;
+               break;
+       case ACPI_HEST_TYPE_AER_BRIDGE:
+               if ((info->pci_dev->class >> 16) == PCI_BASE_CLASS_BRIDGE)
+                       bridge = 1;
+               break;
+       default:
+               return 0;
+       }
+
+       p = (struct acpi_hest_aer_common *)(hest_hdr + 1);
+       if (p->flags & ACPI_HEST_GLOBAL) {
+               if ((info->pci_dev->is_pcie &&
+                    info->pci_dev->pcie_type == pcie_type) || bridge)
+                       ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST);
+       } else
+               if (hest_match_pci(p, info->pci_dev))
+                       ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST);
+       info->firmware_first = ff;
+
+       return 0;
+}
+
+static void aer_set_firmware_first(struct pci_dev *pci_dev)
+{
+       int rc;
+       struct aer_hest_parse_info info = {
+               .pci_dev        = pci_dev,
+               .firmware_first = 0,
+       };
+
+       rc = apei_hest_parse(aer_hest_parse, &info);
+
+       if (rc)
+               pci_dev->__aer_firmware_first = 0;
+       else
+               pci_dev->__aer_firmware_first = info.firmware_first;
+       pci_dev->__aer_firmware_first_valid = 1;
+}
+
+int pcie_aer_get_firmware_first(struct pci_dev *dev)
+{
+       if (!dev->__aer_firmware_first_valid)
+               aer_set_firmware_first(dev);
+       return dev->__aer_firmware_first;
+}
+#endif
index aceb04b67b60f55979258256e84e93209faf3f24..8af4f619bba2ceb8871e4b34674ab0678c988c4b 100644 (file)
@@ -36,7 +36,7 @@ int pci_enable_pcie_error_reporting(struct pci_dev *dev)
        u16 reg16 = 0;
        int pos;
 
-       if (dev->aer_firmware_first)
+       if (pcie_aer_get_firmware_first(dev))
                return -EIO;
 
        pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
@@ -47,13 +47,12 @@ int pci_enable_pcie_error_reporting(struct pci_dev *dev)
        if (!pos)
                return -EIO;
 
-       pci_read_config_word(dev, pos+PCI_EXP_DEVCTL, &reg16);
-       reg16 = reg16 |
-               PCI_EXP_DEVCTL_CERE |
+       pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &reg16);
+       reg16 |= (PCI_EXP_DEVCTL_CERE |
                PCI_EXP_DEVCTL_NFERE |
                PCI_EXP_DEVCTL_FERE |
-               PCI_EXP_DEVCTL_URRE;
-       pci_write_config_word(dev, pos+PCI_EXP_DEVCTL, reg16);
+               PCI_EXP_DEVCTL_URRE);
+       pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, reg16);
 
        return 0;
 }
@@ -64,19 +63,19 @@ int pci_disable_pcie_error_reporting(struct pci_dev *dev)
        u16 reg16 = 0;
        int pos;
 
-       if (dev->aer_firmware_first)
+       if (pcie_aer_get_firmware_first(dev))
                return -EIO;
 
        pos = pci_pcie_cap(dev);
        if (!pos)
                return -EIO;
 
-       pci_read_config_word(dev, pos+PCI_EXP_DEVCTL, &reg16);
-       reg16 = reg16 & ~(PCI_EXP_DEVCTL_CERE |
-                       PCI_EXP_DEVCTL_NFERE |
-                       PCI_EXP_DEVCTL_FERE |
-                       PCI_EXP_DEVCTL_URRE);
-       pci_write_config_word(dev, pos+PCI_EXP_DEVCTL, reg16);
+       pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &reg16);
+       reg16 &= ~(PCI_EXP_DEVCTL_CERE |
+               PCI_EXP_DEVCTL_NFERE |
+               PCI_EXP_DEVCTL_FERE |
+               PCI_EXP_DEVCTL_URRE);
+       pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, reg16);
 
        return 0;
 }
@@ -99,99 +98,46 @@ int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev)
 }
 EXPORT_SYMBOL_GPL(pci_cleanup_aer_uncorrect_error_status);
 
-static int set_device_error_reporting(struct pci_dev *dev, void *data)
-{
-       bool enable = *((bool *)data);
-
-       if ((dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) ||
-           (dev->pcie_type == PCI_EXP_TYPE_UPSTREAM) ||
-           (dev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM)) {
-               if (enable)
-                       pci_enable_pcie_error_reporting(dev);
-               else
-                       pci_disable_pcie_error_reporting(dev);
-       }
-
-       if (enable)
-               pcie_set_ecrc_checking(dev);
-
-       return 0;
-}
-
 /**
- * set_downstream_devices_error_reporting - enable/disable the error reporting  bits on the root port and its downstream ports.
- * @dev: pointer to root port's pci_dev data structure
- * @enable: true = enable error reporting, false = disable error reporting.
+ * add_error_device - list device to be handled
+ * @e_info: pointer to error info
+ * @dev: pointer to pci_dev to be added
  */
-static void set_downstream_devices_error_reporting(struct pci_dev *dev,
-                                                  bool enable)
-{
-       set_device_error_reporting(dev, &enable);
-
-       if (!dev->subordinate)
-               return;
-       pci_walk_bus(dev->subordinate, set_device_error_reporting, &enable);
-}
-
-static inline int compare_device_id(struct pci_dev *dev,
-                       struct aer_err_info *e_info)
-{
-       if (e_info->id == ((dev->bus->number << 8) | dev->devfn)) {
-               /*
-                * Device ID match
-                */
-               return 1;
-       }
-
-       return 0;
-}
-
 static int add_error_device(struct aer_err_info *e_info, struct pci_dev *dev)
 {
        if (e_info->error_dev_num < AER_MAX_MULTI_ERR_DEVICES) {
                e_info->dev[e_info->error_dev_num] = dev;
                e_info->error_dev_num++;
-               return 1;
+               return 0;
        }
-
-       return 0;
+       return -ENOSPC;
 }
 
-
 #define        PCI_BUS(x)      (((x) >> 8) & 0xff)
 
-static int find_device_iter(struct pci_dev *dev, void *data)
+/**
+ * is_error_source - check whether the device is source of reported error
+ * @dev: pointer to pci_dev to be checked
+ * @e_info: pointer to reported error info
+ */
+static bool is_error_source(struct pci_dev *dev, struct aer_err_info *e_info)
 {
        int pos;
-       u32 status;
-       u32 mask;
+       u32 status, mask;
        u16 reg16;
-       int result;
-       struct aer_err_info *e_info = (struct aer_err_info *)data;
 
        /*
         * When bus id is equal to 0, it might be a bad id
         * reported by root port.
         */
        if (!nosourceid && (PCI_BUS(e_info->id) != 0)) {
-               result = compare_device_id(dev, e_info);
-               if (result)
-                       add_error_device(e_info, dev);
+               /* Device ID match? */
+               if (e_info->id == ((dev->bus->number << 8) | dev->devfn))
+                       return true;
 
-               /*
-                * If there is no multiple error, we stop
-                * or continue based on the id comparing.
-                */
+               /* Continue id comparing if there is no multiple error */
                if (!e_info->multi_error_valid)
-                       return result;
-
-               /*
-                * If there are multiple errors and id does match,
-                * We need continue to search other devices under
-                * the root port. Return 0 means that.
-                */
-               if (result)
-                       return 0;
+                       return false;
        }
 
        /*
@@ -200,71 +146,94 @@ static int find_device_iter(struct pci_dev *dev, void *data)
         *      2) bus id is equal to 0. Some ports might lose the bus
         *              id of error source id;
         *      3) There are multiple errors and prior id comparing fails;
-        * We check AER status registers to find the initial reporter.
+        * We check AER status registers to find possible reporter.
         */
        if (atomic_read(&dev->enable_cnt) == 0)
-               return 0;
+               return false;
        pos = pci_pcie_cap(dev);
        if (!pos)
-               return 0;
+               return false;
+
        /* Check if AER is enabled */
-       pci_read_config_word(dev, pos+PCI_EXP_DEVCTL, &reg16);
+       pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &reg16);
        if (!(reg16 & (
                PCI_EXP_DEVCTL_CERE |
                PCI_EXP_DEVCTL_NFERE |
                PCI_EXP_DEVCTL_FERE |
                PCI_EXP_DEVCTL_URRE)))
-               return 0;
+               return false;
        pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
        if (!pos)
-               return 0;
+               return false;
 
-       status = 0;
-       mask = 0;
+       /* Check if error is recorded */
        if (e_info->severity == AER_CORRECTABLE) {
                pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &status);
                pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, &mask);
-               if (status & ~mask) {
-                       add_error_device(e_info, dev);
-                       goto added;
-               }
        } else {
                pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
                pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, &mask);
-               if (status & ~mask) {
-                       add_error_device(e_info, dev);
-                       goto added;
-               }
        }
+       if (status & ~mask)
+               return true;
 
-       return 0;
+       return false;
+}
 
-added:
-       if (e_info->multi_error_valid)
-               return 0;
-       else
-               return 1;
+static int find_device_iter(struct pci_dev *dev, void *data)
+{
+       struct aer_err_info *e_info = (struct aer_err_info *)data;
+
+       if (is_error_source(dev, e_info)) {
+               /* List this device */
+               if (add_error_device(e_info, dev)) {
+                       /* We cannot handle more... Stop iteration */
+                       /* TODO: Should print error message here? */
+                       return 1;
+               }
+
+               /* If there is only a single error, stop iteration */
+               if (!e_info->multi_error_valid)
+                       return 1;
+       }
+       return 0;
 }
 
 /**
  * find_source_device - search through device hierarchy for source device
  * @parent: pointer to Root Port pci_dev data structure
- * @err_info: including detailed error information such like id
+ * @e_info: including detailed error information such like id
  *
- * Invoked when error is detected at the Root Port.
+ * Return true if found.
+ *
+ * Invoked by DPC when error is detected at the Root Port.
+ * Caller of this function must set id, severity, and multi_error_valid of
+ * struct aer_err_info pointed by @e_info properly.  This function must fill
+ * e_info->error_dev_num and e_info->dev[], based on the given information.
  */
-static void find_source_device(struct pci_dev *parent,
+static bool find_source_device(struct pci_dev *parent,
                struct aer_err_info *e_info)
 {
        struct pci_dev *dev = parent;
        int result;
 
+       /* Must reset in this function */
+       e_info->error_dev_num = 0;
+
        /* Is Root Port an agent that sends error message? */
        result = find_device_iter(dev, e_info);
        if (result)
-               return;
+               return true;
 
        pci_walk_bus(parent->subordinate, find_device_iter, e_info);
+
+       if (!e_info->error_dev_num) {
+               dev_printk(KERN_DEBUG, &parent->dev,
+                               "can't find device of ID%04x\n",
+                               e_info->id);
+               return false;
+       }
+       return true;
 }
 
 static int report_error_detected(struct pci_dev *dev, void *data)
@@ -403,43 +372,77 @@ static pci_ers_result_t broadcast_error_message(struct pci_dev *dev,
        return result_data.result;
 }
 
-struct find_aer_service_data {
-       struct pcie_port_service_driver *aer_driver;
-       int is_downstream;
-};
-
-static int find_aer_service_iter(struct device *device, void *data)
+/**
+ * aer_do_secondary_bus_reset - perform secondary bus reset
+ * @dev: pointer to bridge's pci_dev data structure
+ *
+ * Invoked when performing link reset at Root Port or Downstream Port.
+ */
+void aer_do_secondary_bus_reset(struct pci_dev *dev)
 {
-       struct device_driver *driver;
-       struct pcie_port_service_driver *service_driver;
-       struct find_aer_service_data *result;
+       u16 p2p_ctrl;
+
+       /* Assert Secondary Bus Reset */
+       pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &p2p_ctrl);
+       p2p_ctrl |= PCI_BRIDGE_CTL_BUS_RESET;
+       pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
+
+       /*
+        * we should send hot reset message for 2ms to allow it time to
+        * propagate to all downstream ports
+        */
+       msleep(2);
+
+       /* De-assert Secondary Bus Reset */
+       p2p_ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
+       pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
+
+       /*
+        * System software must wait for at least 100ms from the end
+        * of a reset of one or more device before it is permitted
+        * to issue Configuration Requests to those devices.
+        */
+       msleep(200);
+}
 
-       result = (struct find_aer_service_data *) data;
+/**
+ * default_downstream_reset_link - default reset function for Downstream Port
+ * @dev: pointer to downstream port's pci_dev data structure
+ *
+ * Invoked when performing link reset at Downstream Port w/ no aer driver.
+ */
+static pci_ers_result_t default_downstream_reset_link(struct pci_dev *dev)
+{
+       aer_do_secondary_bus_reset(dev);
+       dev_printk(KERN_DEBUG, &dev->dev,
+               "Downstream Port link has been reset\n");
+       return PCI_ERS_RESULT_RECOVERED;
+}
 
-       if (device->bus == &pcie_port_bus_type) {
-               struct pcie_device *pcie = to_pcie_device(device);
+static int find_aer_service_iter(struct device *device, void *data)
+{
+       struct pcie_port_service_driver *service_driver, **drv;
 
-               if (pcie->port->pcie_type == PCI_EXP_TYPE_DOWNSTREAM)
-                       result->is_downstream = 1;
+       drv = (struct pcie_port_service_driver **) data;
 
-               driver = device->driver;
-               if (driver) {
-                       service_driver = to_service_driver(driver);
-                       if (service_driver->service == PCIE_PORT_SERVICE_AER) {
-                               result->aer_driver = service_driver;
-                               return 1;
-                       }
+       if (device->bus == &pcie_port_bus_type && device->driver) {
+               service_driver = to_service_driver(device->driver);
+               if (service_driver->service == PCIE_PORT_SERVICE_AER) {
+                       *drv = service_driver;
+                       return 1;
                }
        }
 
        return 0;
 }
 
-static void find_aer_service(struct pci_dev *dev,
-               struct find_aer_service_data *data)
+static struct pcie_port_service_driver *find_aer_service(struct pci_dev *dev)
 {
-       int retval;
-       retval = device_for_each_child(&dev->dev, data, find_aer_service_iter);
+       struct pcie_port_service_driver *drv = NULL;
+
+       device_for_each_child(&dev->dev, &drv, find_aer_service_iter);
+
+       return drv;
 }
 
 static pci_ers_result_t reset_link(struct pcie_device *aerdev,
@@ -447,38 +450,34 @@ static pci_ers_result_t reset_link(struct pcie_device *aerdev,
 {
        struct pci_dev *udev;
        pci_ers_result_t status;
-       struct find_aer_service_data data;
+       struct pcie_port_service_driver *driver;
 
-       if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE)
+       if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE) {
+               /* Reset this port for all subordinates */
                udev = dev;
-       else
+       } else {
+               /* Reset the upstream component (likely downstream port) */
                udev = dev->bus->self;
+       }
 
-       data.is_downstream = 0;
-       data.aer_driver = NULL;
-       find_aer_service(udev, &data);
+       /* Use the aer driver of the component firstly */
+       driver = find_aer_service(udev);
 
-       /*
-        * Use the aer driver of the error agent firstly.
-        * If it hasn't the aer driver, use the root port's
-        */
-       if (!data.aer_driver || !data.aer_driver->reset_link) {
-               if (data.is_downstream &&
-                       aerdev->device.driver &&
-                       to_service_driver(aerdev->device.driver)->reset_link) {
-                       data.aer_driver =
-                               to_service_driver(aerdev->device.driver);
-               } else {
-                       dev_printk(KERN_DEBUG, &dev->dev, "no link-reset "
-                                  "support\n");
-                       return PCI_ERS_RESULT_DISCONNECT;
-               }
+       if (driver && driver->reset_link) {
+               status = driver->reset_link(udev);
+       } else if (udev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM) {
+               status = default_downstream_reset_link(udev);
+       } else {
+               dev_printk(KERN_DEBUG, &dev->dev,
+                       "no link-reset support at upstream device %s\n",
+                       pci_name(udev));
+               return PCI_ERS_RESULT_DISCONNECT;
        }
 
-       status = data.aer_driver->reset_link(udev);
        if (status != PCI_ERS_RESULT_RECOVERED) {
-               dev_printk(KERN_DEBUG, &dev->dev, "link reset at upstream "
-                          "device %s failed\n", pci_name(udev));
+               dev_printk(KERN_DEBUG, &dev->dev,
+                       "link reset at upstream device %s failed\n",
+                       pci_name(udev));
                return PCI_ERS_RESULT_DISCONNECT;
        }
 
@@ -495,8 +494,7 @@ static pci_ers_result_t reset_link(struct pcie_device *aerdev,
  * error detected message to all downstream drivers within a hierarchy in
  * question and return the returned code.
  */
-static pci_ers_result_t do_recovery(struct pcie_device *aerdev,
-               struct pci_dev *dev,
+static void do_recovery(struct pcie_device *aerdev, struct pci_dev *dev,
                int severity)
 {
        pci_ers_result_t status, result = PCI_ERS_RESULT_RECOVERED;
@@ -514,10 +512,8 @@ static pci_ers_result_t do_recovery(struct pcie_device *aerdev,
 
        if (severity == AER_FATAL) {
                result = reset_link(aerdev, dev);
-               if (result != PCI_ERS_RESULT_RECOVERED) {
-                       /* TODO: Should panic here? */
-                       return result;
-               }
+               if (result != PCI_ERS_RESULT_RECOVERED)
+                       goto failed;
        }
 
        if (status == PCI_ERS_RESULT_CAN_RECOVER)
@@ -538,13 +534,22 @@ static pci_ers_result_t do_recovery(struct pcie_device *aerdev,
                                report_slot_reset);
        }
 
-       if (status == PCI_ERS_RESULT_RECOVERED)
-               broadcast_error_message(dev,
+       if (status != PCI_ERS_RESULT_RECOVERED)
+               goto failed;
+
+       broadcast_error_message(dev,
                                state,
                                "resume",
                                report_resume);
 
-       return status;
+       dev_printk(KERN_DEBUG, &dev->dev,
+               "AER driver successfully recovered\n");
+       return;
+
+failed:
+       /* TODO: Should kernel panic here? */
+       dev_printk(KERN_DEBUG, &dev->dev,
+               "AER driver didn't recover\n");
 }
 
 /**
@@ -559,7 +564,6 @@ static void handle_error_source(struct pcie_device *aerdev,
        struct pci_dev *dev,
        struct aer_err_info *info)
 {
-       pci_ers_result_t status = 0;
        int pos;
 
        if (info->severity == AER_CORRECTABLE) {
@@ -571,114 +575,8 @@ static void handle_error_source(struct pcie_device *aerdev,
                if (pos)
                        pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS,
                                        info->status);
-       } else {
-               status = do_recovery(aerdev, dev, info->severity);
-               if (status == PCI_ERS_RESULT_RECOVERED) {
-                       dev_printk(KERN_DEBUG, &dev->dev, "AER driver "
-                                  "successfully recovered\n");
-               } else {
-                       /* TODO: Should kernel panic here? */
-                       dev_printk(KERN_DEBUG, &dev->dev, "AER driver didn't "
-                                  "recover\n");
-               }
-       }
-}
-
-/**
- * aer_enable_rootport - enable Root Port's interrupts when receiving messages
- * @rpc: pointer to a Root Port data structure
- *
- * Invoked when PCIe bus loads AER service driver.
- */
-void aer_enable_rootport(struct aer_rpc *rpc)
-{
-       struct pci_dev *pdev = rpc->rpd->port;
-       int pos, aer_pos;
-       u16 reg16;
-       u32 reg32;
-
-       pos = pci_pcie_cap(pdev);
-       /* Clear PCIe Capability's Device Status */
-       pci_read_config_word(pdev, pos+PCI_EXP_DEVSTA, &reg16);
-       pci_write_config_word(pdev, pos+PCI_EXP_DEVSTA, reg16);
-
-       /* Disable system error generation in response to error messages */
-       pci_read_config_word(pdev, pos + PCI_EXP_RTCTL, &reg16);
-       reg16 &= ~(SYSTEM_ERROR_INTR_ON_MESG_MASK);
-       pci_write_config_word(pdev, pos + PCI_EXP_RTCTL, reg16);
-
-       aer_pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
-       /* Clear error status */
-       pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, &reg32);
-       pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, reg32);
-       pci_read_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, &reg32);
-       pci_write_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, reg32);
-       pci_read_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, &reg32);
-       pci_write_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, reg32);
-
-       /*
-        * Enable error reporting for the root port device and downstream port
-        * devices.
-        */
-       set_downstream_devices_error_reporting(pdev, true);
-
-       /* Enable Root Port's interrupt in response to error messages */
-       pci_write_config_dword(pdev,
-               aer_pos + PCI_ERR_ROOT_COMMAND,
-               ROOT_PORT_INTR_ON_MESG_MASK);
-}
-
-/**
- * disable_root_aer - disable Root Port's interrupts when receiving messages
- * @rpc: pointer to a Root Port data structure
- *
- * Invoked when PCIe bus unloads AER service driver.
- */
-static void disable_root_aer(struct aer_rpc *rpc)
-{
-       struct pci_dev *pdev = rpc->rpd->port;
-       u32 reg32;
-       int pos;
-
-       /*
-        * Disable error reporting for the root port device and downstream port
-        * devices.
-        */
-       set_downstream_devices_error_reporting(pdev, false);
-
-       pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
-       /* Disable Root's interrupt in response to error messages */
-       pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, 0);
-
-       /* Clear Root's error status reg */
-       pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, &reg32);
-       pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, reg32);
-}
-
-/**
- * get_e_source - retrieve an error source
- * @rpc: pointer to the root port which holds an error
- *
- * Invoked by DPC handler to consume an error.
- */
-static struct aer_err_source *get_e_source(struct aer_rpc *rpc)
-{
-       struct aer_err_source *e_source;
-       unsigned long flags;
-
-       /* Lock access to Root error producer/consumer index */
-       spin_lock_irqsave(&rpc->e_lock, flags);
-       if (rpc->prod_idx == rpc->cons_idx) {
-               spin_unlock_irqrestore(&rpc->e_lock, flags);
-               return NULL;
-       }
-       e_source = &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 e_source;
+       } else
+               do_recovery(aerdev, dev, info->severity);
 }
 
 /**
@@ -687,11 +585,14 @@ static struct aer_err_source *get_e_source(struct aer_rpc *rpc)
  * @info: pointer to structure to store the error record
  *
  * Return 1 on success, 0 on error.
+ *
+ * Note that @info is reused among all error devices. Clear fields properly.
  */
 static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
 {
        int pos, temp;
 
+       /* Must reset in this function */
        info->status = 0;
        info->tlp_header_valid = 0;
 
@@ -744,12 +645,6 @@ static inline void aer_process_err_devices(struct pcie_device *p_device,
 {
        int i;
 
-       if (!e_info->dev[0]) {
-               dev_printk(KERN_DEBUG, &p_device->port->dev,
-                               "can't find device of ID%04x\n",
-                               e_info->id);
-       }
-
        /* Report all before handle them, not to lost records by reset etc. */
        for (i = 0; i < e_info->error_dev_num && e_info->dev[i]; i++) {
                if (get_device_error_info(e_info->dev[i], e_info))
@@ -770,11 +665,10 @@ static void aer_isr_one_error(struct pcie_device *p_device,
                struct aer_err_source *e_src)
 {
        struct aer_err_info *e_info;
-       int i;
 
        /* struct aer_err_info might be big, so we allocate it with slab */
        e_info = kmalloc(sizeof(struct aer_err_info), GFP_KERNEL);
-       if (e_info == NULL) {
+       if (!e_info) {
                dev_printk(KERN_DEBUG, &p_device->port->dev,
                        "Can't allocate mem when processing AER errors\n");
                return;
@@ -784,36 +678,71 @@ static void aer_isr_one_error(struct pcie_device *p_device,
         * There is a possibility that both correctable error and
         * uncorrectable error being logged. Report correctable error first.
         */
-       for (i = 1; i & ROOT_ERR_STATUS_MASKS ; i <<= 2) {
-               if (i > 4)
-                       break;
-               if (!(e_src->status & i))
-                       continue;
-
-               memset(e_info, 0, sizeof(struct aer_err_info));
-
-               /* Init comprehensive error information */
-               if (i & PCI_ERR_ROOT_COR_RCV) {
-                       e_info->id = ERR_COR_ID(e_src->id);
-                       e_info->severity = AER_CORRECTABLE;
-               } else {
-                       e_info->id = ERR_UNCOR_ID(e_src->id);
-                       e_info->severity = ((e_src->status >> 6) & 1);
-               }
-               if (e_src->status &
-                       (PCI_ERR_ROOT_MULTI_COR_RCV |
-                        PCI_ERR_ROOT_MULTI_UNCOR_RCV))
+       if (e_src->status & PCI_ERR_ROOT_COR_RCV) {
+               e_info->id = ERR_COR_ID(e_src->id);
+               e_info->severity = AER_CORRECTABLE;
+
+               if (e_src->status & PCI_ERR_ROOT_MULTI_COR_RCV)
                        e_info->multi_error_valid = 1;
+               else
+                       e_info->multi_error_valid = 0;
+
+               aer_print_port_info(p_device->port, e_info);
+
+               if (find_source_device(p_device->port, e_info))
+                       aer_process_err_devices(p_device, e_info);
+       }
+
+       if (e_src->status & PCI_ERR_ROOT_UNCOR_RCV) {
+               e_info->id = ERR_UNCOR_ID(e_src->id);
+
+               if (e_src->status & PCI_ERR_ROOT_FATAL_RCV)
+                       e_info->severity = AER_FATAL;
+               else
+                       e_info->severity = AER_NONFATAL;
+
+               if (e_src->status & PCI_ERR_ROOT_MULTI_UNCOR_RCV)
+                       e_info->multi_error_valid = 1;
+               else
+                       e_info->multi_error_valid = 0;
 
                aer_print_port_info(p_device->port, e_info);
 
-               find_source_device(p_device->port, e_info);
-               aer_process_err_devices(p_device, e_info);
+               if (find_source_device(p_device->port, e_info))
+                       aer_process_err_devices(p_device, e_info);
        }
 
        kfree(e_info);
 }
 
+/**
+ * get_e_source - retrieve an error source
+ * @rpc: pointer to the root port which holds an error
+ * @e_src: pointer to store retrieved error source
+ *
+ * Return 1 if an error source is retrieved, otherwise 0.
+ *
+ * Invoked by DPC handler to consume an error.
+ */
+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;
+       }
+       spin_unlock_irqrestore(&rpc->e_lock, flags);
+
+       return ret;
+}
+
 /**
  * aer_isr - consume errors detected by root port
  * @work: definition of this work item
@@ -824,33 +753,16 @@ void aer_isr(struct work_struct *work)
 {
        struct aer_rpc *rpc = container_of(work, struct aer_rpc, dpc_handler);
        struct pcie_device *p_device = rpc->rpd;
-       struct aer_err_source *e_src;
+       struct aer_err_source e_src;
 
        mutex_lock(&rpc->rpc_mutex);
-       e_src = get_e_source(rpc);
-       while (e_src) {
-               aer_isr_one_error(p_device, e_src);
-               e_src = get_e_source(rpc);
-       }
+       while (get_e_source(rpc, &e_src))
+               aer_isr_one_error(p_device, &e_src);
        mutex_unlock(&rpc->rpc_mutex);
 
        wake_up(&rpc->wait_release);
 }
 
-/**
- * aer_delete_rootport - disable root port aer and delete service data
- * @rpc: pointer to a root port device being deleted
- *
- * Invoked when AER service unloaded on a specific Root Port
- */
-void aer_delete_rootport(struct aer_rpc *rpc)
-{
-       /* Disable root port AER itself */
-       disable_root_aer(rpc);
-
-       kfree(rpc);
-}
-
 /**
  * aer_init - provide AER initialization
  * @dev: pointer to AER pcie device
@@ -859,7 +771,7 @@ void aer_delete_rootport(struct aer_rpc *rpc)
  */
 int aer_init(struct pcie_device *dev)
 {
-       if (dev->port->aer_firmware_first) {
+       if (pcie_aer_get_firmware_first(dev->port)) {
                dev_printk(KERN_DEBUG, &dev->device,
                           "PCIe errors handled by platform firmware.\n");
                goto out;
@@ -873,7 +785,7 @@ out:
        if (forceload) {
                dev_printk(KERN_DEBUG, &dev->device,
                           "aerdrv forceload requested.\n");
-               dev->port->aer_firmware_first = 0;
+               pcie_aer_force_firmware_first(dev->port, 0);
                return 0;
        }
        return -ENXIO;
index c82548afcd5cbc4781b1fbf0784c0012475689bb..f4adba2d1dd3e6671b08c3a3ccb156a841829dfa 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/module.h>
 #include <linux/cpumask.h>
 #include <linux/pci-aspm.h>
-#include <acpi/acpi_hest.h>
 #include "pci.h"
 
 #define CARDBUS_LATENCY_TIMER  176     /* secondary latency timer */
@@ -904,12 +903,6 @@ void set_pcie_hotplug_bridge(struct pci_dev *pdev)
                pdev->is_hotplug_bridge = 1;
 }
 
-static void set_pci_aer_firmware_first(struct pci_dev *pdev)
-{
-       if (acpi_hest_firmware_first_pci(pdev))
-               pdev->aer_firmware_first = 1;
-}
-
 #define LEGACY_IO_RESOURCE     (IORESOURCE_IO | IORESOURCE_PCI_FIXED)
 
 /**
@@ -939,7 +932,6 @@ int pci_setup_device(struct pci_dev *dev)
        dev->multifunction = !!(hdr_type & 0x80);
        dev->error_state = pci_channel_io_normal;
        set_pcie_port_type(dev);
-       set_pci_aer_firmware_first(dev);
 
        list_for_each_entry(slot, &dev->bus->slots, list)
                if (PCI_SLOT(dev->devfn) == slot->number)
index 27c0e6eb7136030b8c419e91e2c3dae595322a0c..b7512cf08c58ea665c2b4afce6aaac7ca9ddf13a 100644 (file)
@@ -2127,6 +2127,7 @@ 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);
 
 /* Go through the list of Hypertransport capabilities and
  * return 1 if a HT MSI capability is found and enabled */
@@ -2218,15 +2219,16 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS,
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8132_BRIDGE,
                         ht_enable_msi_mapping);
 
-/* The P5N32-SLI Premium motherboard from Asus has a problem with msi
+/* The P5N32-SLI motherboards from Asus have a problem with msi
  * for the MCP55 NIC. It is not yet determined whether the msi problem
  * also affects other devices. As for now, turn off msi for this device.
  */
 static void __devinit nvenet_msi_disable(struct pci_dev *dev)
 {
-       if (dmi_name_in_vendors("P5N32-SLI PREMIUM")) {
+       if (dmi_name_in_vendors("P5N32-SLI PREMIUM") ||
+           dmi_name_in_vendors("P5N32-E SLI")) {
                dev_info(&dev->dev,
-                        "Disabling msi for MCP55 NIC on P5N32-SLI Premium\n");
+                        "Disabling msi for MCP55 NIC on P5N32-SLI\n");
                dev->no_msi = 1;
        }
 }
@@ -2552,6 +2554,19 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1518, quirk_i82576_sriov);
 
 #endif /* CONFIG_PCI_IOV */
 
+/* Allow manual resource allocation for PCI hotplug bridges
+ * via pci=hpmemsize=nnM and pci=hpiosize=nnM parameters. For
+ * some PCI-PCI hotplug bridges, like PLX 6254 (former HINT HB6),
+ * kernel fails to allocate resources when hotplug device is 
+ * inserted and PCI bus is rescanned.
+ */
+static void __devinit quirk_hotplug_bridge(struct pci_dev *dev)
+{
+       dev->is_hotplug_bridge = 1;
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_HINT, 0x0020, quirk_hotplug_bridge);
+
 /*
  * This is a quirk for the Ricoh MMC controller found as a part of
  * some mulifunction chips.
index 659eaa0fc48facf81dad9c0b5c430498e01398e3..e0189cf7c5587ac2d182e7e55a20892c272631b4 100644 (file)
@@ -97,6 +97,50 @@ static ssize_t cur_speed_read_file(struct pci_slot *slot, char *buf)
        return bus_speed_read(slot->bus->cur_bus_speed, buf);
 }
 
+static void remove_sysfs_files(struct pci_slot *slot)
+{
+       char func[10];
+       struct list_head *tmp;
+
+       list_for_each(tmp, &slot->bus->devices) {
+               struct pci_dev *dev = pci_dev_b(tmp);
+               if (PCI_SLOT(dev->devfn) != slot->number)
+                       continue;
+               sysfs_remove_link(&dev->dev.kobj, "slot");
+
+               snprintf(func, 10, "function%d", PCI_FUNC(dev->devfn));
+               sysfs_remove_link(&slot->kobj, func);
+       }
+}
+
+static int create_sysfs_files(struct pci_slot *slot)
+{
+       int result;
+       char func[10];
+       struct list_head *tmp;
+
+       list_for_each(tmp, &slot->bus->devices) {
+               struct pci_dev *dev = pci_dev_b(tmp);
+               if (PCI_SLOT(dev->devfn) != slot->number)
+                       continue;
+
+               result = sysfs_create_link(&dev->dev.kobj, &slot->kobj, "slot");
+               if (result)
+                       goto fail;
+
+               snprintf(func, 10, "function%d", PCI_FUNC(dev->devfn));
+               result = sysfs_create_link(&slot->kobj, &dev->dev.kobj, func);
+               if (result)
+                       goto fail;
+       }
+
+       return 0;
+
+fail:
+       remove_sysfs_files(slot);
+       return result;
+}
+
 static void pci_slot_release(struct kobject *kobj)
 {
        struct pci_dev *dev;
@@ -109,6 +153,8 @@ static void pci_slot_release(struct kobject *kobj)
                if (PCI_SLOT(dev->devfn) == slot->number)
                        dev->slot = NULL;
 
+       remove_sysfs_files(slot);
+
        list_del(&slot->list);
 
        kfree(slot);
@@ -300,6 +346,8 @@ placeholder:
        INIT_LIST_HEAD(&slot->list);
        list_add(&slot->list, &parent->slots);
 
+       create_sysfs_files(slot);
+
        list_for_each_entry(dev, &parent->devices, bus_list)
                if (PCI_SLOT(dev->devfn) == slot_nr)
                        dev->slot = slot;
index 2e59fe947d28095c15fb96327499e07edd8b32ea..f94d8281cfb04df3fd06582c61e1e2f654c877dd 100644 (file)
@@ -185,7 +185,7 @@ static int __devinit electra_cf_probe(struct of_device *ofdev,
                                      const struct of_device_id *match)
 {
        struct device *device = &ofdev->dev;
-       struct device_node *np = ofdev->node;
+       struct device_node *np = ofdev->dev.of_node;
        struct electra_cf_socket   *cf;
        struct resource mem, io;
        int status;
@@ -357,8 +357,11 @@ static const struct of_device_id electra_cf_match[] = {
 MODULE_DEVICE_TABLE(of, electra_cf_match);
 
 static struct of_platform_driver electra_cf_driver = {
-       .name      = (char *)driver_name,
-       .match_table    = electra_cf_match,
+       .driver = {
+               .name = (char *)driver_name,
+               .owner = THIS_MODULE,
+               .of_match_table = electra_cf_match,
+       },
        .probe    = electra_cf_probe,
        .remove   = electra_cf_remove,
 };
index 41cc954a5ffee1dd2a87bd4374bd69f22ddb4f9e..1a648b90b634890512ffb95560c1944d5d7a214a 100644 (file)
@@ -1298,8 +1298,11 @@ static const struct of_device_id m8xx_pcmcia_match[] = {
 MODULE_DEVICE_TABLE(of, m8xx_pcmcia_match);
 
 static struct of_platform_driver m8xx_pcmcia_driver = {
-       .name = driver_name,
-       .match_table = m8xx_pcmcia_match,
+       .driver = {
+               .name = driver_name,
+               .owner = THIS_MODULE,
+               .match_table = m8xx_pcmcia_match,
+       },
        .probe = m8xx_probe,
        .remove = m8xx_remove,
 };
index ef0c5f13369111d380da217d840bf3323618abb4..d007a2a03830c815d507383c5556ca9a6d37a412 100644 (file)
@@ -813,8 +813,7 @@ static u_int ds_poll(struct file *file, poll_table *wait)
 
 /*====================================================================*/
 
-static int ds_ioctl(struct inode *inode, struct file *file,
-                   u_int cmd, u_long arg)
+static int ds_ioctl(struct file *file, u_int cmd, u_long arg)
 {
     struct pcmcia_socket *s;
     void __user *uarg = (char __user *)arg;
@@ -1021,13 +1020,25 @@ free_out:
     return err;
 } /* ds_ioctl */
 
+static long ds_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       int ret;
+
+       lock_kernel();
+       ret = ds_ioctl(file, cmd, arg);
+       unlock_kernel();
+
+       return ret;
+}
+
+
 /*====================================================================*/
 
 static const struct file_operations ds_fops = {
        .owner          = THIS_MODULE,
        .open           = ds_open,
        .release        = ds_release,
-       .ioctl          = ds_ioctl,
+       .unlocked_ioctl = ds_unlocked_ioctl,
        .read           = ds_read,
        .write          = ds_write,
        .poll           = ds_poll,
index 6c3320d7505533804881a56fb349534b4eea0e4c..3e1b8a288719d2047e911025e9fc6c1c8714d578 100644 (file)
@@ -390,6 +390,7 @@ config EEEPC_WMI
        depends on ACPI_WMI
        depends on INPUT
        depends on EXPERIMENTAL
+       depends on BACKLIGHT_CLASS_DEVICE
        select INPUT_SPARSEKMAP
        ---help---
          Say Y here if you want to support WMI-based hotkeys on Eee PC laptops.
@@ -527,4 +528,13 @@ config ACPI_CMPC
          keys as input device, backlight device, tablet and accelerometer
          devices.
 
+config INTEL_SCU_IPC
+       bool "Intel SCU IPC Support"
+       depends on X86_MRST
+       default y
+       ---help---
+         IPC is used to bridge the communications between kernel and SCU on
+         some embedded Intel x86 platforms. This is not needed for PC-type
+         machines.
+
 endif # X86_PLATFORM_DEVICES
index a906490e3530a91f44b41b571af0b9737d85feae..8770bfe71431ec6435feacd02b4d2211741b7a39 100644 (file)
@@ -25,3 +25,4 @@ obj-$(CONFIG_ACPI_ASUS)               += asus_acpi.o
 obj-$(CONFIG_TOPSTAR_LAPTOP)   += topstar-laptop.o
 obj-$(CONFIG_ACPI_TOSHIBA)     += toshiba_acpi.o
 obj-$(CONFIG_TOSHIBA_BT_RFKILL)        += toshiba_bluetooth.o
+obj-$(CONFIG_INTEL_SCU_IPC)    += intel_scu_ipc.o
index 7f9e5ddc949841ba3c80d15aa75d94a60e9385c0..3bf399fe2bbc14bb2e61051fdac4aa7d28c53bb9 100644 (file)
@@ -24,6 +24,7 @@
 #include <acpi/acpi_drivers.h>
 #include <linux/backlight.h>
 #include <linux/input.h>
+#include <linux/rfkill.h>
 
 MODULE_LICENSE("GPL");
 
@@ -37,7 +38,7 @@ struct cmpc_accel {
 
 #define CMPC_ACCEL_HID         "ACCE0000"
 #define CMPC_TABLET_HID                "TBLT0000"
-#define CMPC_BL_HID            "IPML200"
+#define CMPC_IPML_HID  "IPML200"
 #define CMPC_KEYS_HID          "FnBT0000"
 
 /*
@@ -461,43 +462,168 @@ static const struct backlight_ops cmpc_bl_ops = {
        .update_status = cmpc_bl_update_status
 };
 
-static int cmpc_bl_add(struct acpi_device *acpi)
+/*
+ * RFKILL code.
+ */
+
+static acpi_status cmpc_get_rfkill_wlan(acpi_handle handle,
+                                       unsigned long long *value)
 {
-       struct backlight_properties props;
+       union acpi_object param;
+       struct acpi_object_list input;
+       unsigned long long output;
+       acpi_status status;
+
+       param.type = ACPI_TYPE_INTEGER;
+       param.integer.value = 0xC1;
+       input.count = 1;
+       input.pointer = &param;
+       status = acpi_evaluate_integer(handle, "GRDI", &input, &output);
+       if (ACPI_SUCCESS(status))
+               *value = output;
+       return status;
+}
+
+static acpi_status cmpc_set_rfkill_wlan(acpi_handle handle,
+                                       unsigned long long value)
+{
+       union acpi_object param[2];
+       struct acpi_object_list input;
+       acpi_status status;
+       unsigned long long output;
+
+       param[0].type = ACPI_TYPE_INTEGER;
+       param[0].integer.value = 0xC1;
+       param[1].type = ACPI_TYPE_INTEGER;
+       param[1].integer.value = value;
+       input.count = 2;
+       input.pointer = param;
+       status = acpi_evaluate_integer(handle, "GWRI", &input, &output);
+       return status;
+}
+
+static void cmpc_rfkill_query(struct rfkill *rfkill, void *data)
+{
+       acpi_status status;
+       acpi_handle handle;
+       unsigned long long state;
+       bool blocked;
+
+       handle = data;
+       status = cmpc_get_rfkill_wlan(handle, &state);
+       if (ACPI_SUCCESS(status)) {
+               blocked = state & 1 ? false : true;
+               rfkill_set_sw_state(rfkill, blocked);
+       }
+}
+
+static int cmpc_rfkill_block(void *data, bool blocked)
+{
+       acpi_status status;
+       acpi_handle handle;
+       unsigned long long state;
+
+       handle = data;
+       status = cmpc_get_rfkill_wlan(handle, &state);
+       if (ACPI_FAILURE(status))
+               return -ENODEV;
+       if (blocked)
+               state &= ~1;
+       else
+               state |= 1;
+       status = cmpc_set_rfkill_wlan(handle, state);
+       if (ACPI_FAILURE(status))
+               return -ENODEV;
+       return 0;
+}
+
+static const struct rfkill_ops cmpc_rfkill_ops = {
+       .query = cmpc_rfkill_query,
+       .set_block = cmpc_rfkill_block,
+};
+
+/*
+ * Common backlight and rfkill code.
+ */
+
+struct ipml200_dev {
        struct backlight_device *bd;
+       struct rfkill *rf;
+};
+
+static int cmpc_ipml_add(struct acpi_device *acpi)
+{
+       int retval;
+       struct ipml200_dev *ipml;
+       struct backlight_properties props;
+
+       ipml = kmalloc(sizeof(*ipml), GFP_KERNEL);
+       if (ipml == NULL)
+               return -ENOMEM;
 
        memset(&props, 0, sizeof(struct backlight_properties));
        props.max_brightness = 7;
-       bd = backlight_device_register("cmpc_bl", &acpi->dev, acpi->handle,
-                                      &cmpc_bl_ops, &props);
-       if (IS_ERR(bd))
-               return PTR_ERR(bd);
-       dev_set_drvdata(&acpi->dev, bd);
+       ipml->bd = backlight_device_register("cmpc_bl", &acpi->dev,
+                                            acpi->handle, &cmpc_bl_ops,
+                                            &props);
+       if (IS_ERR(ipml->bd)) {
+               retval = PTR_ERR(ipml->bd);
+               goto out_bd;
+       }
+
+       ipml->rf = rfkill_alloc("cmpc_rfkill", &acpi->dev, RFKILL_TYPE_WLAN,
+                               &cmpc_rfkill_ops, acpi->handle);
+       /* rfkill_alloc may fail if RFKILL is disabled. We should still work
+        * anyway. */
+       if (!IS_ERR(ipml->rf)) {
+               retval = rfkill_register(ipml->rf);
+               if (retval) {
+                       rfkill_destroy(ipml->rf);
+                       ipml->rf = NULL;
+               }
+       } else {
+               ipml->rf = NULL;
+       }
+
+       dev_set_drvdata(&acpi->dev, ipml);
        return 0;
+
+out_bd:
+       kfree(ipml);
+       return retval;
 }
 
-static int cmpc_bl_remove(struct acpi_device *acpi, int type)
+static int cmpc_ipml_remove(struct acpi_device *acpi, int type)
 {
-       struct backlight_device *bd;
+       struct ipml200_dev *ipml;
+
+       ipml = dev_get_drvdata(&acpi->dev);
+
+       backlight_device_unregister(ipml->bd);
+
+       if (ipml->rf) {
+               rfkill_unregister(ipml->rf);
+               rfkill_destroy(ipml->rf);
+       }
+
+       kfree(ipml);
 
-       bd = dev_get_drvdata(&acpi->dev);
-       backlight_device_unregister(bd);
        return 0;
 }
 
-static const struct acpi_device_id cmpc_bl_device_ids[] = {
-       {CMPC_BL_HID, 0},
+static const struct acpi_device_id cmpc_ipml_device_ids[] = {
+       {CMPC_IPML_HID, 0},
        {"", 0}
 };
 
-static struct acpi_driver cmpc_bl_acpi_driver = {
+static struct acpi_driver cmpc_ipml_acpi_driver = {
        .owner = THIS_MODULE,
        .name = "cmpc",
        .class = "cmpc",
-       .ids = cmpc_bl_device_ids,
+       .ids = cmpc_ipml_device_ids,
        .ops = {
-               .add = cmpc_bl_add,
-               .remove = cmpc_bl_remove
+               .add = cmpc_ipml_add,
+               .remove = cmpc_ipml_remove
        }
 };
 
@@ -580,7 +706,7 @@ static int cmpc_init(void)
        if (r)
                goto failed_keys;
 
-       r = acpi_bus_register_driver(&cmpc_bl_acpi_driver);
+       r = acpi_bus_register_driver(&cmpc_ipml_acpi_driver);
        if (r)
                goto failed_bl;
 
@@ -598,7 +724,7 @@ failed_accel:
        acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
 
 failed_tablet:
-       acpi_bus_unregister_driver(&cmpc_bl_acpi_driver);
+       acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver);
 
 failed_bl:
        acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
@@ -611,7 +737,7 @@ static void cmpc_exit(void)
 {
        acpi_bus_unregister_driver(&cmpc_accel_acpi_driver);
        acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
-       acpi_bus_unregister_driver(&cmpc_bl_acpi_driver);
+       acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver);
        acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
 }
 
@@ -621,7 +747,7 @@ module_exit(cmpc_exit);
 static const struct acpi_device_id cmpc_device_ids[] = {
        {CMPC_ACCEL_HID, 0},
        {CMPC_TABLET_HID, 0},
-       {CMPC_BL_HID, 0},
+       {CMPC_IPML_HID, 0},
        {CMPC_KEYS_HID, 0},
        {"", 0}
 };
index b227eb469f49ba60667900ad24a2fccc4d8eb583..9dc50fbf3d0bc787989fe0621dd24e413e55aea6 100644 (file)
@@ -206,7 +206,7 @@ static int eeepc_wmi_backlight_notify(struct eeepc_wmi *eeepc, int code)
 {
        struct backlight_device *bd = eeepc->backlight_device;
        int old = bd->props.brightness;
-       int new;
+       int new = old;
 
        if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX)
                new = code - NOTIFY_BRNUP_MIN + 1;
index 47b4fd75aa344966b3933af9ca7b09acf7eee613..e325aeb37d2ef0b158ff6960ab7ecc17c0b738c2 100644 (file)
@@ -1090,10 +1090,9 @@ static int __init fujitsu_init(void)
        if (acpi_disabled)
                return -ENODEV;
 
-       fujitsu = kmalloc(sizeof(struct fujitsu_t), GFP_KERNEL);
+       fujitsu = kzalloc(sizeof(struct fujitsu_t), GFP_KERNEL);
        if (!fujitsu)
                return -ENOMEM;
-       memset(fujitsu, 0, sizeof(struct fujitsu_t));
        fujitsu->keycode1 = KEY_PROG1;
        fujitsu->keycode2 = KEY_PROG2;
        fujitsu->keycode3 = KEY_PROG3;
@@ -1150,12 +1149,11 @@ static int __init fujitsu_init(void)
 
        /* Register hotkey driver */
 
-       fujitsu_hotkey = kmalloc(sizeof(struct fujitsu_hotkey_t), GFP_KERNEL);
+       fujitsu_hotkey = kzalloc(sizeof(struct fujitsu_hotkey_t), GFP_KERNEL);
        if (!fujitsu_hotkey) {
                ret = -ENOMEM;
                goto fail_hotkey;
        }
-       memset(fujitsu_hotkey, 0, sizeof(struct fujitsu_hotkey_t));
 
        result = acpi_bus_register_driver(&acpi_fujitsu_hotkey_driver);
        if (result < 0) {
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c
new file mode 100644 (file)
index 0000000..576c3ed
--- /dev/null
@@ -0,0 +1,829 @@
+/*
+ * intel_scu_ipc.c: Driver for the Intel SCU IPC mechanism
+ *
+ * (C) Copyright 2008-2010 Intel Corporation
+ * Author: Sreedhara DS (sreedhara.ds@intel.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.
+ *
+ * SCU runing in ARC processor communicates with other entity running in IA
+ * core through IPC mechanism which in turn messaging between IA core ad SCU.
+ * SCU has two IPC mechanism IPC-1 and IPC-2. IPC-1 is used between IA32 and
+ * SCU where IPC-2 is used between P-Unit and SCU. This driver delas with
+ * IPC-1 Driver provides an API for power control unit registers (e.g. MSIC)
+ * along with other APIs.
+ */
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/sysdev.h>
+#include <linux/pm.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <asm/setup.h>
+#include <asm/intel_scu_ipc.h>
+
+/* IPC defines the following message types */
+#define IPCMSG_WATCHDOG_TIMER 0xF8 /* Set Kernel Watchdog Threshold */
+#define IPCMSG_BATTERY        0xEF /* Coulomb Counter Accumulator */
+#define IPCMSG_FW_UPDATE      0xFE /* Firmware update */
+#define IPCMSG_PCNTRL         0xFF /* Power controller unit read/write */
+#define IPCMSG_FW_REVISION    0xF4 /* Get firmware revision */
+
+/* Command id associated with message IPCMSG_PCNTRL */
+#define IPC_CMD_PCNTRL_W      0 /* Register write */
+#define IPC_CMD_PCNTRL_R      1 /* Register read */
+#define IPC_CMD_PCNTRL_M      2 /* Register read-modify-write */
+
+/* Miscelaneous Command ids */
+#define IPC_CMD_INDIRECT_RD   2 /* 32bit indirect read */
+#define IPC_CMD_INDIRECT_WR   5 /* 32bit indirect write */
+
+/*
+ * IPC register summary
+ *
+ * IPC register blocks are memory mapped at fixed address of 0xFF11C000
+ * To read or write information to the SCU, driver writes to IPC-1 memory
+ * mapped registers (base address 0xFF11C000). The following is the IPC
+ * mechanism
+ *
+ * 1. IA core cDMI interface claims this transaction and converts it to a
+ *    Transaction Layer Packet (TLP) message which is sent across the cDMI.
+ *
+ * 2. South Complex cDMI block receives this message and writes it to
+ *    the IPC-1 register block, causing an interrupt to the SCU
+ *
+ * 3. SCU firmware decodes this interrupt and IPC message and the appropriate
+ *    message handler is called within firmware.
+ */
+
+#define IPC_BASE_ADDR     0xFF11C000   /* IPC1 base register address */
+#define IPC_MAX_ADDR      0x100                /* Maximum IPC regisers */
+#define IPC_WWBUF_SIZE    16           /* IPC Write buffer Size */
+#define IPC_RWBUF_SIZE    16           /* IPC Read buffer Size */
+#define IPC_I2C_BASE      0xFF12B000   /* I2C control register base address */
+#define IPC_I2C_MAX_ADDR  0x10         /* Maximum I2C regisers */
+
+static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id);
+static void ipc_remove(struct pci_dev *pdev);
+
+struct intel_scu_ipc_dev {
+       struct pci_dev *pdev;
+       void __iomem *ipc_base;
+       void __iomem *i2c_base;
+};
+
+static struct intel_scu_ipc_dev  ipcdev; /* Only one for now */
+
+static int platform = 1;
+module_param(platform, int, 0);
+MODULE_PARM_DESC(platform, "1 for moorestown platform");
+
+
+
+
+/*
+ * IPC Read Buffer (Read Only):
+ * 16 byte buffer for receiving data from SCU, if IPC command
+ * processing results in response data
+ */
+#define IPC_READ_BUFFER                0x90
+
+#define IPC_I2C_CNTRL_ADDR     0
+#define I2C_DATA_ADDR          0x04
+
+static DEFINE_MUTEX(ipclock); /* lock used to prevent multiple call to SCU */
+
+/*
+ * Command Register (Write Only):
+ * A write to this register results in an interrupt to the SCU core processor
+ * Format:
+ * |rfu2(8) | size(8) | command id(4) | rfu1(3) | ioc(1) | command(8)|
+ */
+static inline void ipc_command(u32 cmd) /* Send ipc command */
+{
+       writel(cmd, ipcdev.ipc_base);
+}
+
+/*
+ * IPC Write Buffer (Write Only):
+ * 16-byte buffer for sending data associated with IPC command to
+ * SCU. Size of the data is specified in the IPC_COMMAND_REG register
+ */
+static inline void ipc_data_writel(u32 data, u32 offset) /* Write ipc data */
+{
+       writel(data, ipcdev.ipc_base + 0x80 + offset);
+}
+
+/*
+ * IPC destination Pointer (Write Only):
+ * Use content as pointer for destination write
+ */
+static inline void ipc_write_dptr(u32 data) /* Write dptr data */
+{
+       writel(data, ipcdev.ipc_base + 0x0C);
+}
+
+/*
+ * IPC Source Pointer (Write Only):
+ * Use content as pointer for read location
+*/
+static inline void ipc_write_sptr(u32 data) /* Write dptr data */
+{
+       writel(data, ipcdev.ipc_base + 0x08);
+}
+
+/*
+ * Status Register (Read Only):
+ * Driver will read this register to get the ready/busy status of the IPC
+ * block and error status of the IPC command that was just processed by SCU
+ * Format:
+ * |rfu3(8)|error code(8)|initiator id(8)|cmd id(4)|rfu1(2)|error(1)|busy(1)|
+ */
+
+static inline u8 ipc_read_status(void)
+{
+       return __raw_readl(ipcdev.ipc_base + 0x04);
+}
+
+static inline u8 ipc_data_readb(u32 offset) /* Read ipc byte data */
+{
+       return readb(ipcdev.ipc_base + IPC_READ_BUFFER + offset);
+}
+
+static inline u8 ipc_data_readl(u32 offset) /* Read ipc u32 data */
+{
+       return readl(ipcdev.ipc_base + IPC_READ_BUFFER + offset);
+}
+
+static inline int busy_loop(void) /* Wait till scu status is busy */
+{
+       u32 status = 0;
+       u32 loop_count = 0;
+
+       status = ipc_read_status();
+       while (status & 1) {
+               udelay(1); /* scu processing time is in few u secods */
+               status = ipc_read_status();
+               loop_count++;
+               /* break if scu doesn't reset busy bit after huge retry */
+               if (loop_count > 100000) {
+                       dev_err(&ipcdev.pdev->dev, "IPC timed out");
+                       return -ETIMEDOUT;
+               }
+       }
+       return (status >> 1) & 1;
+}
+
+/* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */
+static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id)
+{
+       int nc;
+       u32 offset = 0;
+       u32 err = 0;
+       u8 cbuf[IPC_WWBUF_SIZE] = { '\0' };
+       u32 *wbuf = (u32 *)&cbuf;
+
+       mutex_lock(&ipclock);
+       if (ipcdev.pdev == NULL) {
+               mutex_unlock(&ipclock);
+               return -ENODEV;
+       }
+
+       if (platform == 1) {
+               /* Entry is 4 bytes for read/write, 5 bytes for read modify */
+               for (nc = 0; nc < count; nc++) {
+                       cbuf[offset] = addr[nc];
+                       cbuf[offset + 1] = addr[nc] >> 8;
+                       if (id != IPC_CMD_PCNTRL_R)
+                               cbuf[offset + 2] = data[nc];
+                       if (id == IPC_CMD_PCNTRL_M) {
+                               cbuf[offset + 3] = data[nc + 1];
+                               offset += 1;
+                       }
+                       offset += 3;
+               }
+               for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
+                       ipc_data_writel(wbuf[nc], offset); /* Write wbuff */
+
+       } else {
+               for (nc = 0, offset = 0; nc < count; nc++, offset += 2)
+                       ipc_data_writel(addr[nc], offset); /* Write addresses */
+               if (id != IPC_CMD_PCNTRL_R) {
+                       for (nc = 0; nc < count; nc++, offset++)
+                               ipc_data_writel(data[nc], offset); /* Write data */
+                       if (id == IPC_CMD_PCNTRL_M)
+                               ipc_data_writel(data[nc + 1], offset); /* Mask value*/
+               }
+       }
+
+       if (id != IPC_CMD_PCNTRL_M)
+               ipc_command((count * 3) << 16 |  id << 12 | 0 << 8 | op);
+       else
+               ipc_command((count * 4) << 16 |  id << 12 | 0 << 8 | op);
+
+       err = busy_loop();
+
+       if (id == IPC_CMD_PCNTRL_R) { /* Read rbuf */
+               /* Workaround: values are read as 0 without memcpy_fromio */
+               memcpy_fromio(cbuf, ipcdev.ipc_base + IPC_READ_BUFFER, 16);
+               if (platform == 1) {
+                       for (nc = 0, offset = 2; nc < count; nc++, offset += 3)
+                               data[nc] = ipc_data_readb(offset);
+               } else {
+                       for (nc = 0; nc < count; nc++)
+                               data[nc] = ipc_data_readb(nc);
+               }
+       }
+       mutex_unlock(&ipclock);
+       return err;
+}
+
+/**
+ *     intel_scu_ipc_ioread8           -       read a word via the SCU
+ *     @addr: register on SCU
+ *     @data: return pointer for read byte
+ *
+ *     Read a single register. Returns 0 on success or an error code. All
+ *     locking between SCU accesses is handled for the caller.
+ *
+ *     This function may sleep.
+ */
+int intel_scu_ipc_ioread8(u16 addr, u8 *data)
+{
+       return pwr_reg_rdwr(&addr, data, 1, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_R);
+}
+EXPORT_SYMBOL(intel_scu_ipc_ioread8);
+
+/**
+ *     intel_scu_ipc_ioread16          -       read a word via the SCU
+ *     @addr: register on SCU
+ *     @data: return pointer for read word
+ *
+ *     Read a register pair. Returns 0 on success or an error code. All
+ *     locking between SCU accesses is handled for the caller.
+ *
+ *     This function may sleep.
+ */
+int intel_scu_ipc_ioread16(u16 addr, u16 *data)
+{
+       u16 x[2] = {addr, addr + 1 };
+       return pwr_reg_rdwr(x, (u8 *)data, 2, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_R);
+}
+EXPORT_SYMBOL(intel_scu_ipc_ioread16);
+
+/**
+ *     intel_scu_ipc_ioread32          -       read a dword via the SCU
+ *     @addr: register on SCU
+ *     @data: return pointer for read dword
+ *
+ *     Read four registers. Returns 0 on success or an error code. All
+ *     locking between SCU accesses is handled for the caller.
+ *
+ *     This function may sleep.
+ */
+int intel_scu_ipc_ioread32(u16 addr, u32 *data)
+{
+       u16 x[4] = {addr, addr + 1, addr + 2, addr + 3};
+       return pwr_reg_rdwr(x, (u8 *)data, 4, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_R);
+}
+EXPORT_SYMBOL(intel_scu_ipc_ioread32);
+
+/**
+ *     intel_scu_ipc_iowrite8          -       write a byte via the SCU
+ *     @addr: register on SCU
+ *     @data: byte to write
+ *
+ *     Write a single register. Returns 0 on success or an error code. All
+ *     locking between SCU accesses is handled for the caller.
+ *
+ *     This function may sleep.
+ */
+int intel_scu_ipc_iowrite8(u16 addr, u8 data)
+{
+       return pwr_reg_rdwr(&addr, &data, 1, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_W);
+}
+EXPORT_SYMBOL(intel_scu_ipc_iowrite8);
+
+/**
+ *     intel_scu_ipc_iowrite16         -       write a word via the SCU
+ *     @addr: register on SCU
+ *     @data: word to write
+ *
+ *     Write two registers. Returns 0 on success or an error code. All
+ *     locking between SCU accesses is handled for the caller.
+ *
+ *     This function may sleep.
+ */
+int intel_scu_ipc_iowrite16(u16 addr, u16 data)
+{
+       u16 x[2] = {addr, addr + 1 };
+       return pwr_reg_rdwr(x, (u8 *)&data, 2, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_W);
+}
+EXPORT_SYMBOL(intel_scu_ipc_iowrite16);
+
+/**
+ *     intel_scu_ipc_iowrite32         -       write a dword via the SCU
+ *     @addr: register on SCU
+ *     @data: dword to write
+ *
+ *     Write four registers. Returns 0 on success or an error code. All
+ *     locking between SCU accesses is handled for the caller.
+ *
+ *     This function may sleep.
+ */
+int intel_scu_ipc_iowrite32(u16 addr, u32 data)
+{
+       u16 x[4] = {addr, addr + 1, addr + 2, addr + 3};
+       return pwr_reg_rdwr(x, (u8 *)&data, 4, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_W);
+}
+EXPORT_SYMBOL(intel_scu_ipc_iowrite32);
+
+/**
+ *     intel_scu_ipc_readvv            -       read a set of registers
+ *     @addr: register list
+ *     @data: bytes to return
+ *     @len: length of array
+ *
+ *     Read registers. Returns 0 on success or an error code. All
+ *     locking between SCU accesses is handled for the caller.
+ *
+ *     The largest array length permitted by the hardware is 5 items.
+ *
+ *     This function may sleep.
+ */
+int intel_scu_ipc_readv(u16 *addr, u8 *data, int len)
+{
+       return pwr_reg_rdwr(addr, data, len, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_R);
+}
+EXPORT_SYMBOL(intel_scu_ipc_readv);
+
+/**
+ *     intel_scu_ipc_writev            -       write a set of registers
+ *     @addr: register list
+ *     @data: bytes to write
+ *     @len: length of array
+ *
+ *     Write registers. Returns 0 on success or an error code. All
+ *     locking between SCU accesses is handled for the caller.
+ *
+ *     The largest array length permitted by the hardware is 5 items.
+ *
+ *     This function may sleep.
+ *
+ */
+int intel_scu_ipc_writev(u16 *addr, u8 *data, int len)
+{
+       return pwr_reg_rdwr(addr, data, len, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_W);
+}
+EXPORT_SYMBOL(intel_scu_ipc_writev);
+
+
+/**
+ *     intel_scu_ipc_update_register   -       r/m/w a register
+ *     @addr: register address
+ *     @bits: bits to update
+ *     @mask: mask of bits to update
+ *
+ *     Read-modify-write power control unit register. The first data argument
+ *     must be register value and second is mask value
+ *     mask is a bitmap that indicates which bits to update.
+ *     0 = masked. Don't modify this bit, 1 = modify this bit.
+ *     returns 0 on success or an error code.
+ *
+ *     This function may sleep. Locking between SCU accesses is handled
+ *     for the caller.
+ */
+int intel_scu_ipc_update_register(u16 addr, u8 bits, u8 mask)
+{
+       u8 data[2] = { bits, mask };
+       return pwr_reg_rdwr(&addr, data, 1, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_M);
+}
+EXPORT_SYMBOL(intel_scu_ipc_update_register);
+
+/**
+ *     intel_scu_ipc_register_read     -       32bit indirect read
+ *     @addr: register address
+ *     @value: 32bit value return
+ *
+ *     Performs IA 32 bit indirect read, returns 0 on success, or an
+ *     error code.
+ *
+ *     Can be used when SCCB(System Controller Configuration Block) register
+ *     HRIM(Honor Restricted IPC Messages) is set (bit 23)
+ *
+ *     This function may sleep. Locking for SCU accesses is handled for
+ *     the caller.
+ */
+int intel_scu_ipc_register_read(u32 addr, u32 *value)
+{
+       u32 err = 0;
+
+       mutex_lock(&ipclock);
+       if (ipcdev.pdev == NULL) {
+               mutex_unlock(&ipclock);
+               return -ENODEV;
+       }
+       ipc_write_sptr(addr);
+       ipc_command(4 << 16 | IPC_CMD_INDIRECT_RD);
+       err = busy_loop();
+       *value = ipc_data_readl(0);
+       mutex_unlock(&ipclock);
+       return err;
+}
+EXPORT_SYMBOL(intel_scu_ipc_register_read);
+
+/**
+ *     intel_scu_ipc_register_write    -       32bit indirect write
+ *     @addr: register address
+ *     @value: 32bit value to write
+ *
+ *     Performs IA 32 bit indirect write, returns 0 on success, or an
+ *     error code.
+ *
+ *     Can be used when SCCB(System Controller Configuration Block) register
+ *     HRIM(Honor Restricted IPC Messages) is set (bit 23)
+ *
+ *     This function may sleep. Locking for SCU accesses is handled for
+ *     the caller.
+ */
+int intel_scu_ipc_register_write(u32 addr, u32 value)
+{
+       u32 err = 0;
+
+       mutex_lock(&ipclock);
+       if (ipcdev.pdev == NULL) {
+               mutex_unlock(&ipclock);
+               return -ENODEV;
+       }
+       ipc_write_dptr(addr);
+       ipc_data_writel(value, 0);
+       ipc_command(4 << 16 | IPC_CMD_INDIRECT_WR);
+       err = busy_loop();
+       mutex_unlock(&ipclock);
+       return err;
+}
+EXPORT_SYMBOL(intel_scu_ipc_register_write);
+
+/**
+ *     intel_scu_ipc_simple_command    -       send a simple command
+ *     @cmd: command
+ *     @sub: sub type
+ *
+ *     Issue a simple command to the SCU. Do not use this interface if
+ *     you must then access data as any data values may be overwritten
+ *     by another SCU access by the time this function returns.
+ *
+ *     This function may sleep. Locking for SCU accesses is handled for
+ *     the caller.
+ */
+int intel_scu_ipc_simple_command(int cmd, int sub)
+{
+       u32 err = 0;
+
+       mutex_lock(&ipclock);
+       if (ipcdev.pdev == NULL) {
+               mutex_unlock(&ipclock);
+               return -ENODEV;
+       }
+       ipc_command(cmd << 12 | sub);
+       err = busy_loop();
+       mutex_unlock(&ipclock);
+       return err;
+}
+EXPORT_SYMBOL(intel_scu_ipc_simple_command);
+
+/**
+ *     intel_scu_ipc_command   -       command with data
+ *     @cmd: command
+ *     @sub: sub type
+ *     @in: input data
+ *     @inlen: input length
+ *     @out: output data
+ *     @outlein: output length
+ *
+ *     Issue a command to the SCU which involves data transfers. Do the
+ *     data copies under the lock but leave it for the caller to interpret
+ */
+
+int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,
+                                                       u32 *out, int outlen)
+{
+       u32 err = 0;
+       int i = 0;
+
+       mutex_lock(&ipclock);
+       if (ipcdev.pdev == NULL) {
+               mutex_unlock(&ipclock);
+               return -ENODEV;
+       }
+
+       for (i = 0; i < inlen; i++)
+               ipc_data_writel(*in++, 4 * i);
+
+       ipc_command(cmd << 12 | sub);
+       err = busy_loop();
+
+       for (i = 0; i < outlen; i++)
+               *out++ = ipc_data_readl(4 * i);
+
+       mutex_unlock(&ipclock);
+       return err;
+}
+EXPORT_SYMBOL(intel_scu_ipc_command);
+
+/*I2C commands */
+#define IPC_I2C_WRITE 1 /* I2C Write command */
+#define IPC_I2C_READ  2 /* I2C Read command */
+
+/**
+ *     intel_scu_ipc_i2c_cntrl         -       I2C read/write operations
+ *     @addr: I2C address + command bits
+ *     @data: data to read/write
+ *
+ *     Perform an an I2C read/write operation via the SCU. All locking is
+ *     handled for the caller. This function may sleep.
+ *
+ *     Returns an error code or 0 on success.
+ *
+ *     This has to be in the IPC driver for the locking.
+ */
+int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data)
+{
+       u32 cmd = 0;
+
+       mutex_lock(&ipclock);
+       cmd = (addr >> 24) & 0xFF;
+       if (cmd == IPC_I2C_READ) {
+               writel(addr, ipcdev.i2c_base + IPC_I2C_CNTRL_ADDR);
+               /* Write not getting updated without delay */
+               mdelay(1);
+               *data = readl(ipcdev.i2c_base + I2C_DATA_ADDR);
+       } else if (cmd == IPC_I2C_WRITE) {
+               writel(addr, ipcdev.i2c_base + I2C_DATA_ADDR);
+               mdelay(1);
+               writel(addr, ipcdev.i2c_base + IPC_I2C_CNTRL_ADDR);
+       } else {
+               dev_err(&ipcdev.pdev->dev,
+                       "intel_scu_ipc: I2C INVALID_CMD = 0x%x\n", cmd);
+
+               mutex_unlock(&ipclock);
+               return -1;
+       }
+       mutex_unlock(&ipclock);
+       return 0;
+}
+EXPORT_SYMBOL(intel_scu_ipc_i2c_cntrl);
+
+#define IPC_FW_LOAD_ADDR 0xFFFC0000 /* Storage location for FW image */
+#define IPC_FW_UPDATE_MBOX_ADDR 0xFFFFDFF4 /* Mailbox between ipc and scu */
+#define IPC_MAX_FW_SIZE 262144 /* 256K storage size for loading the FW image */
+#define IPC_FW_MIP_HEADER_SIZE 2048 /* Firmware MIP header size */
+/* IPC inform SCU to get ready for update process */
+#define IPC_CMD_FW_UPDATE_READY  0x10FE
+/* IPC inform SCU to go for update process */
+#define IPC_CMD_FW_UPDATE_GO     0x20FE
+/* Status code for fw update */
+#define IPC_FW_UPDATE_SUCCESS  0x444f4e45 /* Status code 'DONE' */
+#define IPC_FW_UPDATE_BADN     0x4241444E /* Status code 'BADN' */
+#define IPC_FW_TXHIGH          0x54784849 /* Status code 'IPC_FW_TXHIGH' */
+#define IPC_FW_TXLOW           0x54784c4f /* Status code 'IPC_FW_TXLOW' */
+
+struct fw_update_mailbox {
+       u32    status;
+       u32    scu_flag;
+       u32    driver_flag;
+};
+
+
+/**
+ *     intel_scu_ipc_fw_update -        Firmware update utility
+ *     @buffer: firmware buffer
+ *     @length: size of firmware buffer
+ *
+ *     This function provides an interface to load the firmware into
+ *     the SCU. Returns 0 on success or -1 on failure
+ */
+int intel_scu_ipc_fw_update(u8 *buffer, u32 length)
+{
+       void __iomem *fw_update_base;
+       struct fw_update_mailbox __iomem *mailbox = NULL;
+       int retry_cnt = 0;
+       u32 status;
+
+       mutex_lock(&ipclock);
+       fw_update_base = ioremap_nocache(IPC_FW_LOAD_ADDR, (128*1024));
+       if (fw_update_base == NULL) {
+               mutex_unlock(&ipclock);
+               return -ENOMEM;
+       }
+       mailbox = ioremap_nocache(IPC_FW_UPDATE_MBOX_ADDR,
+                                       sizeof(struct fw_update_mailbox));
+       if (mailbox == NULL) {
+               iounmap(fw_update_base);
+               mutex_unlock(&ipclock);
+               return -ENOMEM;
+       }
+
+       ipc_command(IPC_CMD_FW_UPDATE_READY);
+
+       /* Intitialize mailbox */
+       writel(0, &mailbox->status);
+       writel(0, &mailbox->scu_flag);
+       writel(0, &mailbox->driver_flag);
+
+       /* Driver copies the 2KB MIP header to SRAM at 0xFFFC0000*/
+       memcpy_toio(fw_update_base, buffer, 0x800);
+
+       /* Driver sends "FW Update" IPC command (CMD_ID 0xFE; MSG_ID 0x02).
+       * Upon receiving this command, SCU will write the 2K MIP header
+       * from 0xFFFC0000 into NAND.
+       * SCU will write a status code into the Mailbox, and then set scu_flag.
+       */
+
+       ipc_command(IPC_CMD_FW_UPDATE_GO);
+
+       /*Driver stalls until scu_flag is set */
+       while (readl(&mailbox->scu_flag) != 1) {
+               rmb();
+               mdelay(1);
+       }
+
+       /* Driver checks Mailbox status.
+        * If the status is 'BADN', then abort (bad NAND).
+        * If the status is 'IPC_FW_TXLOW', then continue.
+        */
+       while (readl(&mailbox->status) != IPC_FW_TXLOW) {
+               rmb();
+               mdelay(10);
+       }
+       mdelay(10);
+
+update_retry:
+       if (retry_cnt > 5)
+               goto update_end;
+
+       if (readl(&mailbox->status) != IPC_FW_TXLOW)
+               goto update_end;
+       buffer = buffer + 0x800;
+       memcpy_toio(fw_update_base, buffer, 0x20000);
+       writel(1, &mailbox->driver_flag);
+       while (readl(&mailbox->scu_flag) == 1) {
+               rmb();
+               mdelay(1);
+       }
+
+       /* check for 'BADN' */
+       if (readl(&mailbox->status) == IPC_FW_UPDATE_BADN)
+               goto update_end;
+
+       while (readl(&mailbox->status) != IPC_FW_TXHIGH) {
+               rmb();
+               mdelay(10);
+       }
+       mdelay(10);
+
+       if (readl(&mailbox->status) != IPC_FW_TXHIGH)
+               goto update_end;
+
+       buffer = buffer + 0x20000;
+       memcpy_toio(fw_update_base, buffer, 0x20000);
+       writel(0, &mailbox->driver_flag);
+
+       while (mailbox->scu_flag == 0) {
+               rmb();
+               mdelay(1);
+       }
+
+       /* check for 'BADN' */
+       if (readl(&mailbox->status) == IPC_FW_UPDATE_BADN)
+               goto update_end;
+
+       if (readl(&mailbox->status) == IPC_FW_TXLOW) {
+               ++retry_cnt;
+               goto update_retry;
+       }
+
+update_end:
+       status = readl(&mailbox->status);
+
+       iounmap(fw_update_base);
+       iounmap(mailbox);
+       mutex_unlock(&ipclock);
+
+       if (status == IPC_FW_UPDATE_SUCCESS)
+               return 0;
+       return -1;
+}
+EXPORT_SYMBOL(intel_scu_ipc_fw_update);
+
+/*
+ * Interrupt handler gets called when ioc bit of IPC_COMMAND_REG set to 1
+ * When ioc bit is set to 1, caller api must wait for interrupt handler called
+ * which in turn unlocks the caller api. Currently this is not used
+ *
+ * This is edge triggered so we need take no action to clear anything
+ */
+static irqreturn_t ioc(int irq, void *dev_id)
+{
+       return IRQ_HANDLED;
+}
+
+/**
+ *     ipc_probe       -       probe an Intel SCU IPC
+ *     @dev: the PCI device matching
+ *     @id: entry in the match table
+ *
+ *     Enable and install an intel SCU IPC. This appears in the PCI space
+ *     but uses some hard coded addresses as well.
+ */
+static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+       int err;
+       resource_size_t pci_resource;
+
+       if (ipcdev.pdev)                /* We support only one SCU */
+               return -EBUSY;
+
+       ipcdev.pdev = pci_dev_get(dev);
+
+       err = pci_enable_device(dev);
+       if (err)
+               return err;
+
+       err = pci_request_regions(dev, "intel_scu_ipc");
+       if (err)
+               return err;
+
+       pci_resource = pci_resource_start(dev, 0);
+       if (!pci_resource)
+               return -ENOMEM;
+
+       if (request_irq(dev->irq, ioc, 0, "intel_scu_ipc", &ipcdev))
+               return -EBUSY;
+
+       ipcdev.ipc_base = ioremap_nocache(IPC_BASE_ADDR, IPC_MAX_ADDR);
+       if (!ipcdev.ipc_base)
+               return -ENOMEM;
+
+       ipcdev.i2c_base = ioremap_nocache(IPC_I2C_BASE, IPC_I2C_MAX_ADDR);
+       if (!ipcdev.i2c_base) {
+               iounmap(ipcdev.ipc_base);
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+/**
+ *     ipc_remove      -       remove a bound IPC device
+ *     @pdev: PCI device
+ *
+ *     In practice the SCU is not removable but this function is also
+ *     called for each device on a module unload or cleanup which is the
+ *     path that will get used.
+ *
+ *     Free up the mappings and release the PCI resources
+ */
+static void ipc_remove(struct pci_dev *pdev)
+{
+       free_irq(pdev->irq, &ipcdev);
+       pci_release_regions(pdev);
+       pci_dev_put(ipcdev.pdev);
+       iounmap(ipcdev.ipc_base);
+       iounmap(ipcdev.i2c_base);
+       ipcdev.pdev = NULL;
+}
+
+static const struct pci_device_id pci_ids[] = {
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080e)},
+       { 0,}
+};
+MODULE_DEVICE_TABLE(pci, pci_ids);
+
+static struct pci_driver ipc_driver = {
+       .name = "intel_scu_ipc",
+       .id_table = pci_ids,
+       .probe = ipc_probe,
+       .remove = ipc_remove,
+};
+
+
+static int __init intel_scu_ipc_init(void)
+{
+       return  pci_register_driver(&ipc_driver);
+}
+
+static void __exit intel_scu_ipc_exit(void)
+{
+       pci_unregister_driver(&ipc_driver);
+}
+
+MODULE_AUTHOR("Sreedhara DS <sreedhara.ds@intel.com>");
+MODULE_DESCRIPTION("Intel SCU IPC driver");
+MODULE_LICENSE("GPL");
+
+module_init(intel_scu_ipc_init);
+module_exit(intel_scu_ipc_exit);
index 996223a7c009b01f080d0130e7c5e701872fa511..afd762b58ad9a21e9a28072bae31156b8efd5725 100644 (file)
@@ -59,6 +59,7 @@
 #include <linux/backlight.h>
 #include <linux/platform_device.h>
 #include <linux/rfkill.h>
+#include <linux/i8042.h>
 
 #define MSI_DRIVER_VERSION "0.5"
 
@@ -118,7 +119,8 @@ static int set_lcd_level(int level)
        buf[0] = 0x80;
        buf[1] = (u8) (level*31);
 
-       return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, buf, sizeof(buf), NULL, 0, 1);
+       return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, buf, sizeof(buf),
+                             NULL, 0, 1);
 }
 
 static int get_lcd_level(void)
@@ -126,7 +128,8 @@ static int get_lcd_level(void)
        u8 wdata = 0, rdata;
        int result;
 
-       result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1, 1);
+       result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1,
+                               &rdata, 1, 1);
        if (result < 0)
                return result;
 
@@ -138,7 +141,8 @@ static int get_auto_brightness(void)
        u8 wdata = 4, rdata;
        int result;
 
-       result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1, 1);
+       result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1,
+                               &rdata, 1, 1);
        if (result < 0)
                return result;
 
@@ -152,14 +156,16 @@ static int set_auto_brightness(int enable)
 
        wdata[0] = 4;
 
-       result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 1, &rdata, 1, 1);
+       result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 1,
+                               &rdata, 1, 1);
        if (result < 0)
                return result;
 
        wdata[0] = 0x84;
        wdata[1] = (rdata & 0xF7) | (enable ? 8 : 0);
 
-       return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 2, NULL, 0, 1);
+       return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 2,
+                             NULL, 0, 1);
 }
 
 static ssize_t set_device_state(const char *buf, size_t count, u8 mask)
@@ -254,7 +260,7 @@ static int bl_update_status(struct backlight_device *b)
        return set_lcd_level(b->props.brightness);
 }
 
-static struct backlight_ops msibl_ops = {
+static const struct backlight_ops msibl_ops = {
        .get_brightness = bl_get_brightness,
        .update_status  = bl_update_status,
 };
@@ -353,7 +359,8 @@ static ssize_t store_lcd_level(struct device *dev,
 
        int level, ret;
 
-       if (sscanf(buf, "%i", &level) != 1 || (level < 0 || level >= MSI_LCD_LEVEL_MAX))
+       if (sscanf(buf, "%i", &level) != 1 ||
+           (level < 0 || level >= MSI_LCD_LEVEL_MAX))
                return -EINVAL;
 
        ret = set_lcd_level(level);
@@ -393,7 +400,8 @@ static ssize_t store_auto_brightness(struct device *dev,
 }
 
 static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level);
-static DEVICE_ATTR(auto_brightness, 0644, show_auto_brightness, store_auto_brightness);
+static DEVICE_ATTR(auto_brightness, 0644, show_auto_brightness,
+                  store_auto_brightness);
 static DEVICE_ATTR(bluetooth, 0444, show_bluetooth, NULL);
 static DEVICE_ATTR(wlan, 0444, show_wlan, NULL);
 static DEVICE_ATTR(threeg, 0444, show_threeg, NULL);
@@ -424,8 +432,9 @@ static struct platform_device *msipf_device;
 
 static int dmi_check_cb(const struct dmi_system_id *id)
 {
-        printk("msi-laptop: Identified laptop model '%s'.\n", id->ident);
-        return 0;
+       printk(KERN_INFO "msi-laptop: Identified laptop model '%s'.\n",
+              id->ident);
+       return 0;
 }
 
 static struct dmi_system_id __initdata msi_dmi_table[] = {
@@ -435,7 +444,8 @@ static struct dmi_system_id __initdata msi_dmi_table[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "MS-1013"),
                        DMI_MATCH(DMI_PRODUCT_VERSION, "0131"),
-                       DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-STAR INT'L CO.,LTD")
+                       DMI_MATCH(DMI_CHASSIS_VENDOR,
+                                 "MICRO-STAR INT'L CO.,LTD")
                },
                .callback = dmi_check_cb
        },
@@ -465,7 +475,8 @@ static struct dmi_system_id __initdata msi_dmi_table[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "NOTEBOOK"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "SAM2000"),
                        DMI_MATCH(DMI_PRODUCT_VERSION, "0131"),
-                       DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-STAR INT'L CO.,LTD")
+                       DMI_MATCH(DMI_CHASSIS_VENDOR,
+                                 "MICRO-STAR INT'L CO.,LTD")
                },
                .callback = dmi_check_cb
        },
@@ -484,6 +495,35 @@ static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = {
                },
                .callback = dmi_check_cb
        },
+       {
+               .ident = "MSI N051",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR,
+                               "MICRO-STAR INTERNATIONAL CO., LTD"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MS-N051"),
+                       DMI_MATCH(DMI_CHASSIS_VENDOR,
+                       "MICRO-STAR INTERNATIONAL CO., LTD")
+               },
+               .callback = dmi_check_cb
+       },
+       {
+               .ident = "MSI N014",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR,
+                               "MICRO-STAR INTERNATIONAL CO., LTD"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MS-N014"),
+               },
+               .callback = dmi_check_cb
+       },
+       {
+               .ident = "MSI CR620",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR,
+                               "Micro-Star International"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "CR620"),
+               },
+               .callback = dmi_check_cb
+       },
        { }
 };
 
@@ -552,11 +592,71 @@ static void rfkill_cleanup(void)
        }
 }
 
+static void msi_update_rfkill(struct work_struct *ignored)
+{
+       get_wireless_state_ec_standard();
+
+       if (rfk_wlan)
+               rfkill_set_sw_state(rfk_wlan, !wlan_s);
+       if (rfk_bluetooth)
+               rfkill_set_sw_state(rfk_bluetooth, !bluetooth_s);
+       if (rfk_threeg)
+               rfkill_set_sw_state(rfk_threeg, !threeg_s);
+}
+static DECLARE_DELAYED_WORK(msi_rfkill_work, msi_update_rfkill);
+
+static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str,
+                               struct serio *port)
+{
+       static bool extended;
+
+       if (str & 0x20)
+               return false;
+
+       /* 0x54 wwan, 0x62 bluetooth, 0x76 wlan*/
+       if (unlikely(data == 0xe0)) {
+               extended = true;
+               return false;
+       } else if (unlikely(extended)) {
+               switch (data) {
+               case 0x54:
+               case 0x62:
+               case 0x76:
+                       schedule_delayed_work(&msi_rfkill_work,
+                               round_jiffies_relative(0.5 * HZ));
+                       break;
+               }
+               extended = false;
+       }
+
+       return false;
+}
+
+static void msi_init_rfkill(struct work_struct *ignored)
+{
+       if (rfk_wlan) {
+               rfkill_set_sw_state(rfk_wlan, !wlan_s);
+               rfkill_wlan_set(NULL, !wlan_s);
+       }
+       if (rfk_bluetooth) {
+               rfkill_set_sw_state(rfk_bluetooth, !bluetooth_s);
+               rfkill_bluetooth_set(NULL, !bluetooth_s);
+       }
+       if (rfk_threeg) {
+               rfkill_set_sw_state(rfk_threeg, !threeg_s);
+               rfkill_threeg_set(NULL, !threeg_s);
+       }
+}
+static DECLARE_DELAYED_WORK(msi_rfkill_init, msi_init_rfkill);
+
 static int rfkill_init(struct platform_device *sdev)
 {
        /* add rfkill */
        int retval;
 
+       /* keep the hardware wireless state */
+       get_wireless_state_ec_standard();
+
        rfk_bluetooth = rfkill_alloc("msi-bluetooth", &sdev->dev,
                                RFKILL_TYPE_BLUETOOTH,
                                &rfkill_bluetooth_ops, NULL);
@@ -590,6 +690,10 @@ static int rfkill_init(struct platform_device *sdev)
                        goto err_threeg;
        }
 
+       /* schedule to run rfkill state initial */
+       schedule_delayed_work(&msi_rfkill_init,
+                               round_jiffies_relative(1 * HZ));
+
        return 0;
 
 err_threeg:
@@ -653,9 +757,24 @@ static int load_scm_model_init(struct platform_device *sdev)
        /* initial rfkill */
        result = rfkill_init(sdev);
        if (result < 0)
-               return result;
+               goto fail_rfkill;
+
+       result = i8042_install_filter(msi_laptop_i8042_filter);
+       if (result) {
+               printk(KERN_ERR
+                       "msi-laptop: Unable to install key filter\n");
+               goto fail_filter;
+       }
 
        return 0;
+
+fail_filter:
+       rfkill_cleanup();
+
+fail_rfkill:
+
+       return result;
+
 }
 
 static int __init msi_init(void)
@@ -714,7 +833,8 @@ static int __init msi_init(void)
                goto fail_platform_device1;
        }
 
-       ret = sysfs_create_group(&msipf_device->dev.kobj, &msipf_attribute_group);
+       ret = sysfs_create_group(&msipf_device->dev.kobj,
+                                &msipf_attribute_group);
        if (ret)
                goto fail_platform_device2;
 
@@ -739,6 +859,11 @@ static int __init msi_init(void)
 
 fail_platform_device2:
 
+       if (load_scm_model) {
+               i8042_remove_filter(msi_laptop_i8042_filter);
+               cancel_delayed_work_sync(&msi_rfkill_work);
+               rfkill_cleanup();
+       }
        platform_device_del(msipf_device);
 
 fail_platform_device1:
@@ -758,6 +883,11 @@ fail_backlight:
 
 static void __exit msi_cleanup(void)
 {
+       if (load_scm_model) {
+               i8042_remove_filter(msi_laptop_i8042_filter);
+               cancel_delayed_work_sync(&msi_rfkill_work);
+               rfkill_cleanup();
+       }
 
        sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group);
        if (!old_ec_model && threeg_exists)
@@ -766,8 +896,6 @@ static void __exit msi_cleanup(void)
        platform_driver_unregister(&msipf_driver);
        backlight_device_unregister(msibl_device);
 
-       rfkill_cleanup();
-
        /* Enable automatic brightness control again */
        if (auto_brightness != 2)
                set_auto_brightness(1);
@@ -788,3 +916,6 @@ MODULE_ALIAS("dmi:*:svnMicro-StarInternational:pnMS-1058:pvr0581:rvnMSI:rnMS-105
 MODULE_ALIAS("dmi:*:svnMicro-StarInternational:pnMS-1412:*:rvnMSI:rnMS-1412:*:cvnMICRO-STARINT'LCO.,LTD:ct10:*");
 MODULE_ALIAS("dmi:*:svnNOTEBOOK:pnSAM2000:pvr0131*:cvnMICRO-STARINT'LCO.,LTD:ct10:*");
 MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N034:*");
+MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N051:*");
+MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N014:*");
+MODULE_ALIAS("dmi:*:svnMicro-StarInternational*:pnCR620:*");
index 63290b33c8796e203113309536ed8716a42ef1f7..4bdb13796e24eba6b494f1cd9ad315b1072652c1 100644 (file)
@@ -122,8 +122,14 @@ enum {
        TP_NVRAM_POS_LEVEL_VOLUME       = 0,
 };
 
+/* Misc NVRAM-related */
+enum {
+       TP_NVRAM_LEVEL_VOLUME_MAX = 14,
+};
+
 /* ACPI HIDs */
 #define TPACPI_ACPI_HKEY_HID           "IBM0068"
+#define TPACPI_ACPI_EC_HID             "PNP0C09"
 
 /* Input IDs */
 #define TPACPI_HKEY_INPUT_PRODUCT      0x5054 /* "TP" */
@@ -299,8 +305,8 @@ static struct {
        u32 hotkey_tablet:1;
        u32 light:1;
        u32 light_status:1;
-       u32 bright_16levels:1;
        u32 bright_acpimode:1;
+       u32 bright_unkfw:1;
        u32 wan:1;
        u32 uwb:1;
        u32 fan_ctrl_status_undef:1;
@@ -363,6 +369,9 @@ struct tpacpi_led_classdev {
        unsigned int led;
 };
 
+/* brightness level capabilities */
+static unsigned int bright_maxlvl;     /* 0 = unknown */
+
 #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
 static int dbg_wlswemul;
 static int tpacpi_wlsw_emulstate;
@@ -480,6 +489,15 @@ static unsigned long __init tpacpi_check_quirks(
        return 0;
 }
 
+static inline bool __pure __init tpacpi_is_lenovo(void)
+{
+       return thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO;
+}
+
+static inline bool __pure __init tpacpi_is_ibm(void)
+{
+       return thinkpad_id.vendor == PCI_VENDOR_ID_IBM;
+}
 
 /****************************************************************************
  ****************************************************************************
@@ -494,21 +512,13 @@ static unsigned long __init tpacpi_check_quirks(
  */
 
 static acpi_handle root_handle;
+static acpi_handle ec_handle;
 
 #define TPACPI_HANDLE(object, parent, paths...)                        \
        static acpi_handle  object##_handle;                    \
-       static acpi_handle *object##_parent = &parent##_handle; \
-       static char        *object##_path;                      \
-       static char        *object##_paths[] = { paths }
-
-TPACPI_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0",  /* 240, 240x */
-          "\\_SB.PCI.ISA.EC",  /* 570 */
-          "\\_SB.PCI0.ISA0.EC0",       /* 600e/x, 770e, 770x */
-          "\\_SB.PCI0.ISA.EC", /* A21e, A2xm/p, T20-22, X20-21 */
-          "\\_SB.PCI0.AD4S.EC0",       /* i1400, R30 */
-          "\\_SB.PCI0.ICH3.EC0",       /* R31 */
-          "\\_SB.PCI0.LPC.EC", /* all others */
-          );
+       static const acpi_handle *object##_parent __initdata =  \
+                                               &parent##_handle; \
+       static char *object##_paths[] __initdata = { paths }
 
 TPACPI_HANDLE(ecrd, ec, "ECRD");       /* 570 */
 TPACPI_HANDLE(ecwr, ec, "ECWR");       /* 570 */
@@ -528,6 +538,7 @@ TPACPI_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA",       /* 570 */
           "\\_SB.PCI0.AGP0.VID0",      /* 600e/x, 770x */
           "\\_SB.PCI0.VID0",   /* 770e */
           "\\_SB.PCI0.VID",    /* A21e, G4x, R50e, X30, X40 */
+          "\\_SB.PCI0.AGP.VGA",        /* X100e and a few others */
           "\\_SB.PCI0.AGP.VID",        /* all others */
           );                           /* R30, R31 */
 
@@ -594,9 +605,10 @@ static int acpi_evalf(acpi_handle handle,
 
        switch (res_type) {
        case 'd':               /* int */
-               if (res)
+               success = (status == AE_OK &&
+                          out_obj.type == ACPI_TYPE_INTEGER);
+               if (success && res)
                        *(int *)res = out_obj.integer.value;
-               success = status == AE_OK && out_obj.type == ACPI_TYPE_INTEGER;
                break;
        case 'v':               /* void */
                success = status == AE_OK;
@@ -609,8 +621,8 @@ static int acpi_evalf(acpi_handle handle,
        }
 
        if (!success && !quiet)
-               printk(TPACPI_ERR "acpi_evalf(%s, %s, ...) failed: %d\n",
-                      method, fmt0, status);
+               printk(TPACPI_ERR "acpi_evalf(%s, %s, ...) failed: %s\n",
+                      method, fmt0, acpi_format_exception(status));
 
        return success;
 }
@@ -661,11 +673,11 @@ static int issue_thinkpad_cmos_command(int cmos_cmd)
 
 #define TPACPI_ACPIHANDLE_INIT(object) \
        drv_acpi_handle_init(#object, &object##_handle, *object##_parent, \
-               object##_paths, ARRAY_SIZE(object##_paths), &object##_path)
+               object##_paths, ARRAY_SIZE(object##_paths))
 
-static void drv_acpi_handle_init(char *name,
-                          acpi_handle *handle, acpi_handle parent,
-                          char **paths, int num_paths, char **path)
+static void __init drv_acpi_handle_init(const char *name,
+                          acpi_handle *handle, const acpi_handle parent,
+                          char **paths, const int num_paths)
 {
        int i;
        acpi_status status;
@@ -676,10 +688,9 @@ static void drv_acpi_handle_init(char *name,
        for (i = 0; i < num_paths; i++) {
                status = acpi_get_handle(parent, paths[i], handle);
                if (ACPI_SUCCESS(status)) {
-                       *path = paths[i];
                        dbg_printk(TPACPI_DBG_INIT,
                                   "Found ACPI handle %s for %s\n",
-                                  *path, name);
+                                  paths[i], name);
                        return;
                }
        }
@@ -689,6 +700,43 @@ static void drv_acpi_handle_init(char *name,
        *handle = NULL;
 }
 
+static acpi_status __init tpacpi_acpi_handle_locate_callback(acpi_handle handle,
+                       u32 level, void *context, void **return_value)
+{
+       *(acpi_handle *)return_value = handle;
+
+       return AE_CTRL_TERMINATE;
+}
+
+static void __init tpacpi_acpi_handle_locate(const char *name,
+               const char *hid,
+               acpi_handle *handle)
+{
+       acpi_status status;
+       acpi_handle device_found;
+
+       BUG_ON(!name || !hid || !handle);
+       vdbg_printk(TPACPI_DBG_INIT,
+                       "trying to locate ACPI handle for %s, using HID %s\n",
+                       name, hid);
+
+       memset(&device_found, 0, sizeof(device_found));
+       status = acpi_get_devices(hid, tpacpi_acpi_handle_locate_callback,
+                                 (void *)name, &device_found);
+
+       *handle = NULL;
+
+       if (ACPI_SUCCESS(status)) {
+               *handle = device_found;
+               dbg_printk(TPACPI_DBG_INIT,
+                          "Found ACPI handle for %s\n", name);
+       } else {
+               vdbg_printk(TPACPI_DBG_INIT,
+                           "Could not locate an ACPI handle for %s: %s\n",
+                           name, acpi_format_exception(status));
+       }
+}
+
 static void dispatch_acpi_notify(acpi_handle handle, u32 event, void *data)
 {
        struct ibm_struct *ibm = data;
@@ -736,8 +784,8 @@ static int __init setup_acpi_notify(struct ibm_struct *ibm)
                               "handling %s events\n", ibm->name);
                } else {
                        printk(TPACPI_ERR
-                              "acpi_install_notify_handler(%s) failed: %d\n",
-                              ibm->name, status);
+                              "acpi_install_notify_handler(%s) failed: %s\n",
+                              ibm->name, acpi_format_exception(status));
                }
                return -ENODEV;
        }
@@ -1035,80 +1083,6 @@ static void tpacpi_disable_brightness_delay(void)
                        "ACPI backlight control delay disabled\n");
 }
 
-static int __init tpacpi_query_bcl_levels(acpi_handle handle)
-{
-       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-       union acpi_object *obj;
-       int rc;
-
-       if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) {
-               obj = (union acpi_object *)buffer.pointer;
-               if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
-                       printk(TPACPI_ERR "Unknown _BCL data, "
-                              "please report this to %s\n", TPACPI_MAIL);
-                       rc = 0;
-               } else {
-                       rc = obj->package.count;
-               }
-       } else {
-               return 0;
-       }
-
-       kfree(buffer.pointer);
-       return rc;
-}
-
-static acpi_status __init tpacpi_acpi_walk_find_bcl(acpi_handle handle,
-                                       u32 lvl, void *context, void **rv)
-{
-       char name[ACPI_PATH_SEGMENT_LENGTH];
-       struct acpi_buffer buffer = { sizeof(name), &name };
-
-       if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
-           !strncmp("_BCL", name, sizeof(name) - 1)) {
-               BUG_ON(!rv || !*rv);
-               **(int **)rv = tpacpi_query_bcl_levels(handle);
-               return AE_CTRL_TERMINATE;
-       } else {
-               return AE_OK;
-       }
-}
-
-/*
- * Returns 0 (no ACPI _BCL or _BCL invalid), or size of brightness map
- */
-static int __init tpacpi_check_std_acpi_brightness_support(void)
-{
-       int status;
-       int bcl_levels = 0;
-       void *bcl_ptr = &bcl_levels;
-
-       if (!vid_handle) {
-               TPACPI_ACPIHANDLE_INIT(vid);
-       }
-       if (!vid_handle)
-               return 0;
-
-       /*
-        * Search for a _BCL method, and execute it.  This is safe on all
-        * ThinkPads, and as a side-effect, _BCL will place a Lenovo Vista
-        * BIOS in ACPI backlight control mode.  We do NOT have to care
-        * about calling the _BCL method in an enabled video device, any
-        * will do for our purposes.
-        */
-
-       status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3,
-                                    tpacpi_acpi_walk_find_bcl, NULL, NULL,
-                                    &bcl_ptr);
-
-       if (ACPI_SUCCESS(status) && bcl_levels > 2) {
-               tp_features.bright_acpimode = 1;
-               return (bcl_levels - 2);
-       }
-
-       return 0;
-}
-
 static void printk_deprecated_attribute(const char * const what,
                                        const char * const details)
 {
@@ -1872,34 +1846,9 @@ static bool __init tpacpi_is_fw_known(void)
  ****************************************************************************/
 
 /*************************************************************************
- * thinkpad-acpi init subdriver
+ * thinkpad-acpi metadata subdriver
  */
 
-static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm)
-{
-       printk(TPACPI_INFO "%s v%s\n", TPACPI_DESC, TPACPI_VERSION);
-       printk(TPACPI_INFO "%s\n", TPACPI_URL);
-
-       printk(TPACPI_INFO "ThinkPad BIOS %s, EC %s\n",
-               (thinkpad_id.bios_version_str) ?
-                       thinkpad_id.bios_version_str : "unknown",
-               (thinkpad_id.ec_version_str) ?
-                       thinkpad_id.ec_version_str : "unknown");
-
-       if (thinkpad_id.vendor && thinkpad_id.model_str)
-               printk(TPACPI_INFO "%s %s, model %s\n",
-                       (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ?
-                               "IBM" : ((thinkpad_id.vendor ==
-                                               PCI_VENDOR_ID_LENOVO) ?
-                                       "Lenovo" : "Unknown vendor"),
-                       thinkpad_id.model_str,
-                       (thinkpad_id.nummodel_str) ?
-                               thinkpad_id.nummodel_str : "unknown");
-
-       tpacpi_check_outdated_fw();
-       return 0;
-}
-
 static int thinkpad_acpi_driver_read(struct seq_file *m)
 {
        seq_printf(m, "driver:\t\t%s\n", TPACPI_DESC);
@@ -2405,6 +2354,36 @@ static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn,
                        tpacpi_hotkey_send_key(__scancode); \
        } while (0)
 
+       void issue_volchange(const unsigned int oldvol,
+                            const unsigned int newvol)
+       {
+               unsigned int i = oldvol;
+
+               while (i > newvol) {
+                       TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN);
+                       i--;
+               }
+               while (i < newvol) {
+                       TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP);
+                       i++;
+               }
+       }
+
+       void issue_brightnesschange(const unsigned int oldbrt,
+                                   const unsigned int newbrt)
+       {
+               unsigned int i = oldbrt;
+
+               while (i > newbrt) {
+                       TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNEND);
+                       i--;
+               }
+               while (i < newbrt) {
+                       TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME);
+                       i++;
+               }
+       }
+
        TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_THINKPAD, thinkpad_toggle);
        TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNSPACE, zoom_toggle);
        TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF7, display_toggle);
@@ -2414,41 +2393,61 @@ static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn,
 
        TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF8, displayexp_toggle);
 
-       /* handle volume */
-       if (oldn->volume_toggle != newn->volume_toggle) {
-               if (oldn->mute != newn->mute) {
+       /*
+        * Handle volume
+        *
+        * This code is supposed to duplicate the IBM firmware behaviour:
+        * - Pressing MUTE issues mute hotkey message, even when already mute
+        * - Pressing Volume up/down issues volume up/down hotkey messages,
+        *   even when already at maximum or minumum volume
+        * - The act of unmuting issues volume up/down notification,
+        *   depending which key was used to unmute
+        *
+        * We are constrained to what the NVRAM can tell us, which is not much
+        * and certainly not enough if more than one volume hotkey was pressed
+        * since the last poll cycle.
+        *
+        * Just to make our life interesting, some newer Lenovo ThinkPads have
+        * bugs in the BIOS and may fail to update volume_toggle properly.
+        */
+       if (newn->mute) {
+               /* muted */
+               if (!oldn->mute ||
+                   oldn->volume_toggle != newn->volume_toggle ||
+                   oldn->volume_level != newn->volume_level) {
+                       /* recently muted, or repeated mute keypress, or
+                        * multiple presses ending in mute */
+                       issue_volchange(oldn->volume_level, newn->volume_level);
                        TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_MUTE);
                }
-               if (oldn->volume_level > newn->volume_level) {
-                       TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN);
-               } else if (oldn->volume_level < newn->volume_level) {
+       } else {
+               /* unmute */
+               if (oldn->mute) {
+                       /* recently unmuted, issue 'unmute' keypress */
                        TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP);
-               } else if (oldn->mute == newn->mute) {
-                       /* repeated key presses that didn't change state */
-                       if (newn->mute) {
-                               TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_MUTE);
-                       } else if (newn->volume_level != 0) {
-                               TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP);
-                       } else {
+               }
+               if (oldn->volume_level != newn->volume_level) {
+                       issue_volchange(oldn->volume_level, newn->volume_level);
+               } else if (oldn->volume_toggle != newn->volume_toggle) {
+                       /* repeated vol up/down keypress at end of scale ? */
+                       if (newn->volume_level == 0)
                                TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN);
-                       }
+                       else if (newn->volume_level >= TP_NVRAM_LEVEL_VOLUME_MAX)
+                               TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP);
                }
        }
 
        /* handle brightness */
-       if (oldn->brightness_toggle != newn->brightness_toggle) {
-               if (oldn->brightness_level < newn->brightness_level) {
-                       TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME);
-               } else if (oldn->brightness_level > newn->brightness_level) {
+       if (oldn->brightness_level != newn->brightness_level) {
+               issue_brightnesschange(oldn->brightness_level,
+                                      newn->brightness_level);
+       } else if (oldn->brightness_toggle != newn->brightness_toggle) {
+               /* repeated key presses that didn't change state */
+               if (newn->brightness_level == 0)
                        TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNEND);
-               } else {
-                       /* repeated key presses that didn't change state */
-                       if (newn->brightness_level != 0) {
-                               TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME);
-                       } else {
-                               TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNEND);
-                       }
-               }
+               else if (newn->brightness_level >= bright_maxlvl
+                               && !tp_features.bright_unkfw)
+                       TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME);
        }
 
 #undef TPACPI_COMPARE_KEY
@@ -3353,7 +3352,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
                goto err_exit;
        }
 
-       if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) {
+       if (tpacpi_is_lenovo()) {
                dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
                           "using Lenovo default hot key map\n");
                memcpy(hotkey_keycode_map, &lenovo_keycode_map,
@@ -3391,11 +3390,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
        }
 
        /* Do not issue duplicate brightness change events to
-        * userspace */
-       if (!tp_features.bright_acpimode)
-               /* update bright_acpimode... */
-               tpacpi_check_std_acpi_brightness_support();
-
+        * userspace. tpacpi_detect_brightness_capabilities() must have
+        * been called before this point  */
        if (tp_features.bright_acpimode && acpi_video_backlight_support()) {
                printk(TPACPI_INFO
                       "This ThinkPad has standard ACPI backlight "
@@ -4422,7 +4418,8 @@ static int __init video_init(struct ibm_init_struct *iibm)
        vdbg_printk(TPACPI_DBG_INIT, "initializing video subdriver\n");
 
        TPACPI_ACPIHANDLE_INIT(vid);
-       TPACPI_ACPIHANDLE_INIT(vid2);
+       if (tpacpi_is_ibm())
+               TPACPI_ACPIHANDLE_INIT(vid2);
 
        if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga)
                /* G41, assume IVGA doesn't change */
@@ -4431,10 +4428,12 @@ static int __init video_init(struct ibm_init_struct *iibm)
        if (!vid_handle)
                /* video switching not supported on R30, R31 */
                video_supported = TPACPI_VIDEO_NONE;
-       else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd"))
+       else if (tpacpi_is_ibm() &&
+                acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd"))
                /* 570 */
                video_supported = TPACPI_VIDEO_570;
-       else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd"))
+       else if (tpacpi_is_ibm() &&
+                acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd"))
                /* 600e/x, 770e, 770x */
                video_supported = TPACPI_VIDEO_770;
        else
@@ -4811,8 +4810,10 @@ static int __init light_init(struct ibm_init_struct *iibm)
 
        vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n");
 
-       TPACPI_ACPIHANDLE_INIT(ledb);
-       TPACPI_ACPIHANDLE_INIT(lght);
+       if (tpacpi_is_ibm()) {
+               TPACPI_ACPIHANDLE_INIT(ledb);
+               TPACPI_ACPIHANDLE_INIT(lght);
+       }
        TPACPI_ACPIHANDLE_INIT(cmos);
        INIT_WORK(&tpacpi_led_thinklight.work, light_set_status_worker);
 
@@ -5007,11 +5008,7 @@ enum {   /* For TPACPI_LED_OLD */
 
 static enum led_access_mode led_supported;
 
-TPACPI_HANDLE(led, ec, "SLED", /* 570 */
-          "SYSL",              /* 600e/x, 770e, 770x, A21e, A2xm/p, */
-                               /* T20-22, X20-21 */
-          "LED",               /* all others */
-          );                   /* R30, R31 */
+static acpi_handle led_handle;
 
 #define TPACPI_LED_NUMLEDS 16
 static struct tpacpi_led_classdev *tpacpi_leds;
@@ -5271,6 +5268,32 @@ static const struct tpacpi_quirk led_useful_qtable[] __initconst = {
 #undef TPACPI_LEDQ_IBM
 #undef TPACPI_LEDQ_LNV
 
+static enum led_access_mode __init led_init_detect_mode(void)
+{
+       acpi_status status;
+
+       if (tpacpi_is_ibm()) {
+               /* 570 */
+               status = acpi_get_handle(ec_handle, "SLED", &led_handle);
+               if (ACPI_SUCCESS(status))
+                       return TPACPI_LED_570;
+
+               /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
+               status = acpi_get_handle(ec_handle, "SYSL", &led_handle);
+               if (ACPI_SUCCESS(status))
+                       return TPACPI_LED_OLD;
+       }
+
+       /* most others */
+       status = acpi_get_handle(ec_handle, "LED", &led_handle);
+       if (ACPI_SUCCESS(status))
+               return TPACPI_LED_NEW;
+
+       /* R30, R31, and unknown firmwares */
+       led_handle = NULL;
+       return TPACPI_LED_NONE;
+}
+
 static int __init led_init(struct ibm_init_struct *iibm)
 {
        unsigned int i;
@@ -5279,20 +5302,7 @@ static int __init led_init(struct ibm_init_struct *iibm)
 
        vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n");
 
-       TPACPI_ACPIHANDLE_INIT(led);
-
-       if (!led_handle)
-               /* led not supported on R30, R31 */
-               led_supported = TPACPI_LED_NONE;
-       else if (strlencmp(led_path, "SLED") == 0)
-               /* 570 */
-               led_supported = TPACPI_LED_570;
-       else if (strlencmp(led_path, "SYSL") == 0)
-               /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
-               led_supported = TPACPI_LED_OLD;
-       else
-               /* all others */
-               led_supported = TPACPI_LED_NEW;
+       led_supported = led_init_detect_mode();
 
        vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n",
                str_supported(led_supported), led_supported);
@@ -5741,11 +5751,12 @@ static int __init thermal_init(struct ibm_init_struct *iibm)
                            TPACPI_THERMAL_TPEC_16 : TPACPI_THERMAL_TPEC_8;
                }
        } else if (acpi_tmp7) {
-               if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) {
+               if (tpacpi_is_ibm() &&
+                   acpi_evalf(ec_handle, NULL, "UPDT", "qv")) {
                        /* 600e/x, 770e, 770x */
                        thermal_read_mode = TPACPI_THERMAL_ACPI_UPDT;
                } else {
-                       /* Standard ACPI TMPx access, max 8 sensors */
+                       /* IBM/LENOVO DSDT EC.TMPx access, max 8 sensors */
                        thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07;
                }
        } else {
@@ -5954,7 +5965,7 @@ static unsigned int tpacpi_brightness_nvram_get(void)
        lnvram = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
                  & TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
                  >> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
-       lnvram &= (tp_features.bright_16levels) ? 0x0f : 0x07;
+       lnvram &= bright_maxlvl;
 
        return lnvram;
 }
@@ -6063,8 +6074,7 @@ static int brightness_set(unsigned int value)
 {
        int res;
 
-       if (value > ((tp_features.bright_16levels)? 15 : 7) ||
-           value < 0)
+       if (value > bright_maxlvl || value < 0)
                return -EINVAL;
 
        vdbg_printk(TPACPI_DBG_BRGHT,
@@ -6139,6 +6149,80 @@ static struct backlight_ops ibm_backlight_data = {
 
 /* --------------------------------------------------------------------- */
 
+static int __init tpacpi_query_bcl_levels(acpi_handle handle)
+{
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *obj;
+       int rc;
+
+       if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) {
+               obj = (union acpi_object *)buffer.pointer;
+               if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
+                       printk(TPACPI_ERR "Unknown _BCL data, "
+                              "please report this to %s\n", TPACPI_MAIL);
+                       rc = 0;
+               } else {
+                       rc = obj->package.count;
+               }
+       } else {
+               return 0;
+       }
+
+       kfree(buffer.pointer);
+       return rc;
+}
+
+static acpi_status __init tpacpi_acpi_walk_find_bcl(acpi_handle handle,
+                                       u32 lvl, void *context, void **rv)
+{
+       char name[ACPI_PATH_SEGMENT_LENGTH];
+       struct acpi_buffer buffer = { sizeof(name), &name };
+
+       if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
+           !strncmp("_BCL", name, sizeof(name) - 1)) {
+               BUG_ON(!rv || !*rv);
+               **(int **)rv = tpacpi_query_bcl_levels(handle);
+               return AE_CTRL_TERMINATE;
+       } else {
+               return AE_OK;
+       }
+}
+
+/*
+ * Returns 0 (no ACPI _BCL or _BCL invalid), or size of brightness map
+ */
+static unsigned int __init tpacpi_check_std_acpi_brightness_support(void)
+{
+       int status;
+       int bcl_levels = 0;
+       void *bcl_ptr = &bcl_levels;
+
+       if (!vid_handle)
+               TPACPI_ACPIHANDLE_INIT(vid);
+
+       if (!vid_handle)
+               return 0;
+
+       /*
+        * Search for a _BCL method, and execute it.  This is safe on all
+        * ThinkPads, and as a side-effect, _BCL will place a Lenovo Vista
+        * BIOS in ACPI backlight control mode.  We do NOT have to care
+        * about calling the _BCL method in an enabled video device, any
+        * will do for our purposes.
+        */
+
+       status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3,
+                                    tpacpi_acpi_walk_find_bcl, NULL, NULL,
+                                    &bcl_ptr);
+
+       if (ACPI_SUCCESS(status) && bcl_levels > 2) {
+               tp_features.bright_acpimode = 1;
+               return bcl_levels - 2;
+       }
+
+       return 0;
+}
+
 /*
  * These are only useful for models that have only one possibility
  * of GPU.  If the BIOS model handles both ATI and Intel, don't use
@@ -6169,6 +6253,47 @@ static const struct tpacpi_quirk brightness_quirk_table[] __initconst = {
        TPACPI_Q_IBM('7', '5', TPACPI_BRGHT_Q_NOEC),    /* X41 Tablet */
 };
 
+/*
+ * Returns < 0 for error, otherwise sets tp_features.bright_*
+ * and bright_maxlvl.
+ */
+static void __init tpacpi_detect_brightness_capabilities(void)
+{
+       unsigned int b;
+
+       vdbg_printk(TPACPI_DBG_INIT,
+                   "detecting firmware brightness interface capabilities\n");
+
+       /* we could run a quirks check here (same table used by
+        * brightness_init) if needed */
+
+       /*
+        * We always attempt to detect acpi support, so as to switch
+        * Lenovo Vista BIOS to ACPI brightness mode even if we are not
+        * going to publish a backlight interface
+        */
+       b = tpacpi_check_std_acpi_brightness_support();
+       switch (b) {
+       case 16:
+               bright_maxlvl = 15;
+               printk(TPACPI_INFO
+                      "detected a 16-level brightness capable ThinkPad\n");
+               break;
+       case 8:
+       case 0:
+               bright_maxlvl = 7;
+               printk(TPACPI_INFO
+                      "detected a 8-level brightness capable ThinkPad\n");
+               break;
+       default:
+               printk(TPACPI_ERR
+                      "Unsupported brightness interface, "
+                      "please contact %s\n", TPACPI_MAIL);
+               tp_features.bright_unkfw = 1;
+               bright_maxlvl = b - 1;
+       }
+}
+
 static int __init brightness_init(struct ibm_init_struct *iibm)
 {
        struct backlight_properties props;
@@ -6182,14 +6307,13 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
        quirks = tpacpi_check_quirks(brightness_quirk_table,
                                ARRAY_SIZE(brightness_quirk_table));
 
-       /*
-        * We always attempt to detect acpi support, so as to switch
-        * Lenovo Vista BIOS to ACPI brightness mode even if we are not
-        * going to publish a backlight interface
-        */
-       b = tpacpi_check_std_acpi_brightness_support();
-       if (b > 0) {
+       /* tpacpi_detect_brightness_capabilities() must have run already */
+
+       /* if it is unknown, we don't handle it: it wouldn't be safe */
+       if (tp_features.bright_unkfw)
+               return 1;
 
+       if (tp_features.bright_acpimode) {
                if (acpi_video_backlight_support()) {
                        if (brightness_enable > 1) {
                                printk(TPACPI_NOTICE
@@ -6218,15 +6342,6 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
                return 1;
        }
 
-       if (b > 16) {
-               printk(TPACPI_ERR
-                      "Unsupported brightness interface, "
-                      "please contact %s\n", TPACPI_MAIL);
-               return 1;
-       }
-       if (b == 16)
-               tp_features.bright_16levels = 1;
-
        /*
         * Check for module parameter bogosity, note that we
         * init brightness_mode to TPACPI_BRGHT_MODE_MAX in order to be
@@ -6249,7 +6364,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
        }
 
        /* Safety */
-       if (thinkpad_id.vendor != PCI_VENDOR_ID_IBM &&
+       if (!tpacpi_is_ibm() &&
            (brightness_mode == TPACPI_BRGHT_MODE_ECNVRAM ||
             brightness_mode == TPACPI_BRGHT_MODE_EC))
                return -EINVAL;
@@ -6257,12 +6372,9 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
        if (tpacpi_brightness_get_raw(&b) < 0)
                return 1;
 
-       if (tp_features.bright_16levels)
-               printk(TPACPI_INFO
-                      "detected a 16-level brightness capable ThinkPad\n");
-
        memset(&props, 0, sizeof(struct backlight_properties));
-       props.max_brightness = (tp_features.bright_16levels) ? 15 : 7;
+       props.max_brightness = bright_maxlvl;
+       props.brightness = b & TP_EC_BACKLIGHT_LVLMSK;
        ibm_backlight_device = backlight_device_register(TPACPI_BACKLIGHT_DEV_NAME,
                                                         NULL, NULL,
                                                         &ibm_backlight_data,
@@ -6285,7 +6397,10 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
                        "or not on your ThinkPad\n", TPACPI_MAIL);
        }
 
-       ibm_backlight_device->props.brightness = b & TP_EC_BACKLIGHT_LVLMSK;
+       /* Added by mistake in early 2007.  Probably useless, but it could
+        * be working around some unknown firmware problem where the value
+        * read at startup doesn't match the real hardware state... so leave
+        * it in place just in case */
        backlight_update_status(ibm_backlight_device);
 
        vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT,
@@ -6328,9 +6443,8 @@ static int brightness_read(struct seq_file *m)
        } else {
                seq_printf(m, "level:\t\t%d\n", level);
                seq_printf(m, "commands:\tup, down\n");
-               seq_printf(m, "commands:\tlevel <level>"
-                              " (<level> is 0-%d)\n",
-                              (tp_features.bright_16levels) ? 15 : 7);
+               seq_printf(m, "commands:\tlevel <level> (<level> is 0-%d)\n",
+                              bright_maxlvl);
        }
 
        return 0;
@@ -6341,7 +6455,6 @@ static int brightness_write(char *buf)
        int level;
        int rc;
        char *cmd;
-       int max_level = (tp_features.bright_16levels) ? 15 : 7;
 
        level = brightness_get(NULL);
        if (level < 0)
@@ -6349,13 +6462,13 @@ static int brightness_write(char *buf)
 
        while ((cmd = next_cmd(&buf))) {
                if (strlencmp(cmd, "up") == 0) {
-                       if (level < max_level)
+                       if (level < bright_maxlvl)
                                level++;
                } else if (strlencmp(cmd, "down") == 0) {
                        if (level > 0)
                                level--;
                } else if (sscanf(cmd, "level %d", &level) == 1 &&
-                          level >= 0 && level <= max_level) {
+                          level >= 0 && level <= bright_maxlvl) {
                        /* new level set */
                } else
                        return -EINVAL;
@@ -6669,6 +6782,8 @@ static int volume_alsa_vol_get(struct snd_kcontrol *kcontrol,
 static int volume_alsa_vol_put(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
+       tpacpi_disclose_usertask("ALSA", "set volume to %ld\n",
+                                ucontrol->value.integer.value[0]);
        return volume_alsa_set_volume(ucontrol->value.integer.value[0]);
 }
 
@@ -6692,6 +6807,9 @@ static int volume_alsa_mute_get(struct snd_kcontrol *kcontrol,
 static int volume_alsa_mute_put(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
+       tpacpi_disclose_usertask("ALSA", "%smute\n",
+                                ucontrol->value.integer.value[0] ?
+                                       "un" : "");
        return volume_alsa_set_mute(!ucontrol->value.integer.value[0]);
 }
 
@@ -7968,9 +8086,11 @@ static int __init fan_init(struct ibm_init_struct *iibm)
        tp_features.second_fan = 0;
        fan_control_desired_level = 7;
 
-       TPACPI_ACPIHANDLE_INIT(fans);
-       TPACPI_ACPIHANDLE_INIT(gfan);
-       TPACPI_ACPIHANDLE_INIT(sfan);
+       if (tpacpi_is_ibm()) {
+               TPACPI_ACPIHANDLE_INIT(fans);
+               TPACPI_ACPIHANDLE_INIT(gfan);
+               TPACPI_ACPIHANDLE_INIT(sfan);
+       }
 
        quirks = tpacpi_check_quirks(fan_quirk_table,
                                     ARRAY_SIZE(fan_quirk_table));
@@ -8662,6 +8782,10 @@ static int __init probe_for_thinkpad(void)
        if (acpi_disabled)
                return -ENODEV;
 
+       /* It would be dangerous to run the driver in this case */
+       if (!tpacpi_is_ibm() && !tpacpi_is_lenovo())
+               return -ENODEV;
+
        /*
         * Non-ancient models have better DMI tagging, but very old models
         * don't.  tpacpi_is_fw_known() is a cheat to help in that case.
@@ -8670,8 +8794,8 @@ static int __init probe_for_thinkpad(void)
                      (thinkpad_id.ec_model != 0) ||
                      tpacpi_is_fw_known();
 
-       /* ec is required because many other handles are relative to it */
-       TPACPI_ACPIHANDLE_INIT(ec);
+       /* The EC handler is required */
+       tpacpi_acpi_handle_locate("ec", TPACPI_ACPI_EC_HID, &ec_handle);
        if (!ec_handle) {
                if (is_thinkpad)
                        printk(TPACPI_ERR
@@ -8685,12 +8809,34 @@ static int __init probe_for_thinkpad(void)
        return 0;
 }
 
+static void __init thinkpad_acpi_init_banner(void)
+{
+       printk(TPACPI_INFO "%s v%s\n", TPACPI_DESC, TPACPI_VERSION);
+       printk(TPACPI_INFO "%s\n", TPACPI_URL);
+
+       printk(TPACPI_INFO "ThinkPad BIOS %s, EC %s\n",
+               (thinkpad_id.bios_version_str) ?
+                       thinkpad_id.bios_version_str : "unknown",
+               (thinkpad_id.ec_version_str) ?
+                       thinkpad_id.ec_version_str : "unknown");
+
+       BUG_ON(!thinkpad_id.vendor);
+
+       if (thinkpad_id.model_str)
+               printk(TPACPI_INFO "%s %s, model %s\n",
+                       (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ?
+                               "IBM" : ((thinkpad_id.vendor ==
+                                               PCI_VENDOR_ID_LENOVO) ?
+                                       "Lenovo" : "Unknown vendor"),
+                       thinkpad_id.model_str,
+                       (thinkpad_id.nummodel_str) ?
+                               thinkpad_id.nummodel_str : "unknown");
+}
 
 /* Module init, exit, parameters */
 
 static struct ibm_init_struct ibms_init[] __initdata = {
        {
-               .init = thinkpad_acpi_driver_init,
                .data = &thinkpad_acpi_driver_data,
        },
        {
@@ -8960,6 +9106,9 @@ static int __init thinkpad_acpi_module_init(void)
 
        /* Driver initialization */
 
+       thinkpad_acpi_init_banner();
+       tpacpi_check_outdated_fw();
+
        TPACPI_ACPIHANDLE_INIT(ecrd);
        TPACPI_ACPIHANDLE_INIT(ecwr);
 
@@ -9059,13 +9208,16 @@ static int __init thinkpad_acpi_module_init(void)
                tpacpi_inputdev->name = "ThinkPad Extra Buttons";
                tpacpi_inputdev->phys = TPACPI_DRVR_NAME "/input0";
                tpacpi_inputdev->id.bustype = BUS_HOST;
-               tpacpi_inputdev->id.vendor = (thinkpad_id.vendor) ?
-                                               thinkpad_id.vendor :
-                                               PCI_VENDOR_ID_IBM;
+               tpacpi_inputdev->id.vendor = thinkpad_id.vendor;
                tpacpi_inputdev->id.product = TPACPI_HKEY_INPUT_PRODUCT;
                tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION;
                tpacpi_inputdev->dev.parent = &tpacpi_pdev->dev;
        }
+
+       /* Init subdriver dependencies */
+       tpacpi_detect_brightness_capabilities();
+
+       /* Init subdrivers */
        for (i = 0; i < ARRAY_SIZE(ibms_init); i++) {
                ret = ibm_init(&ibms_init[i]);
                if (ret >= 0 && *ibms_init[i].param)
index 39ec5b6c2e3a804518bdad78257bb766812e3274..e4eaa14ed987973e980bab9a93e5d96dea499116 100644 (file)
@@ -81,6 +81,16 @@ static struct wmi_block wmi_blocks;
 #define ACPI_WMI_STRING      0x4       /* GUID takes & returns a string */
 #define ACPI_WMI_EVENT       0x8       /* GUID is an event */
 
+static int debug_event;
+module_param(debug_event, bool, 0444);
+MODULE_PARM_DESC(debug_event,
+                "Log WMI Events [0/1]");
+
+static int debug_dump_wdg;
+module_param(debug_dump_wdg, bool, 0444);
+MODULE_PARM_DESC(debug_dump_wdg,
+                "Dump available WMI interfaces [0/1]");
+
 static int acpi_wmi_remove(struct acpi_device *device, int type);
 static int acpi_wmi_add(struct acpi_device *device);
 static void acpi_wmi_notify(struct acpi_device *device, u32 event);
@@ -477,6 +487,64 @@ const struct acpi_buffer *in)
 }
 EXPORT_SYMBOL_GPL(wmi_set_block);
 
+static void wmi_dump_wdg(struct guid_block *g)
+{
+       char guid_string[37];
+
+       wmi_gtoa(g->guid, guid_string);
+       printk(KERN_INFO PREFIX "%s:\n", guid_string);
+       printk(KERN_INFO PREFIX "\tobject_id: %c%c\n",
+              g->object_id[0], g->object_id[1]);
+       printk(KERN_INFO PREFIX "\tnotify_id: %02X\n", g->notify_id);
+       printk(KERN_INFO PREFIX "\treserved: %02X\n", g->reserved);
+       printk(KERN_INFO PREFIX "\tinstance_count: %d\n", g->instance_count);
+       printk(KERN_INFO PREFIX "\tflags: %#x", g->flags);
+       if (g->flags) {
+               printk(" ");
+               if (g->flags & ACPI_WMI_EXPENSIVE)
+                       printk("ACPI_WMI_EXPENSIVE ");
+               if (g->flags & ACPI_WMI_METHOD)
+                       printk("ACPI_WMI_METHOD ");
+               if (g->flags & ACPI_WMI_STRING)
+                       printk("ACPI_WMI_STRING ");
+               if (g->flags & ACPI_WMI_EVENT)
+                       printk("ACPI_WMI_EVENT ");
+       }
+       printk("\n");
+
+}
+
+static void wmi_notify_debug(u32 value, void *context)
+{
+       struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *obj;
+
+       wmi_get_event_data(value, &response);
+
+       obj = (union acpi_object *)response.pointer;
+
+       if (!obj)
+               return;
+
+       printk(KERN_INFO PREFIX "DEBUG Event ");
+       switch(obj->type) {
+       case ACPI_TYPE_BUFFER:
+               printk("BUFFER_TYPE - length %d\n", obj->buffer.length);
+               break;
+       case ACPI_TYPE_STRING:
+               printk("STRING_TYPE - %s\n", obj->string.pointer);
+               break;
+       case ACPI_TYPE_INTEGER:
+               printk("INTEGER_TYPE - %llu\n", obj->integer.value);
+               break;
+       case ACPI_TYPE_PACKAGE:
+               printk("PACKAGE_TYPE - %d elements\n", obj->package.count);
+               break;
+       default:
+               printk("object type 0x%X\n", obj->type);
+       }
+}
+
 /**
  * wmi_install_notify_handler - Register handler for WMI events
  * @handler: Function to handle notifications
@@ -496,7 +564,7 @@ wmi_notify_handler handler, void *data)
        if (!find_guid(guid, &block))
                return AE_NOT_EXIST;
 
-       if (block->handler)
+       if (block->handler && block->handler != wmi_notify_debug)
                return AE_ALREADY_ACQUIRED;
 
        block->handler = handler;
@@ -516,7 +584,7 @@ EXPORT_SYMBOL_GPL(wmi_install_notify_handler);
 acpi_status wmi_remove_notify_handler(const char *guid)
 {
        struct wmi_block *block;
-       acpi_status status;
+       acpi_status status = AE_OK;
 
        if (!guid)
                return AE_BAD_PARAMETER;
@@ -524,14 +592,16 @@ acpi_status wmi_remove_notify_handler(const char *guid)
        if (!find_guid(guid, &block))
                return AE_NOT_EXIST;
 
-       if (!block->handler)
+       if (!block->handler || block->handler == wmi_notify_debug)
                return AE_NULL_ENTRY;
 
-       status = wmi_method_enable(block, 0);
-
-       block->handler = NULL;
-       block->handler_data = NULL;
-
+       if (debug_event) {
+               block->handler = wmi_notify_debug;
+       } else {
+               status = wmi_method_enable(block, 0);
+               block->handler = NULL;
+               block->handler_data = NULL;
+       }
        return status;
 }
 EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);
@@ -756,12 +826,10 @@ static __init acpi_status parse_wdg(acpi_handle handle)
 
        total = obj->buffer.length / sizeof(struct guid_block);
 
-       gblock = kzalloc(obj->buffer.length, GFP_KERNEL);
+       gblock = kmemdup(obj->buffer.pointer, obj->buffer.length, GFP_KERNEL);
        if (!gblock)
                return AE_NO_MEMORY;
 
-       memcpy(gblock, obj->buffer.pointer, obj->buffer.length);
-
        for (i = 0; i < total; i++) {
                /*
                  Some WMI devices, like those for nVidia hooks, have a
@@ -776,12 +844,19 @@ static __init acpi_status parse_wdg(acpi_handle handle)
                                guid_string);
                        continue;
                }
+               if (debug_dump_wdg)
+                       wmi_dump_wdg(&gblock[i]);
+
                wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
                if (!wblock)
                        return AE_NO_MEMORY;
 
                wblock->gblock = gblock[i];
                wblock->handle = handle;
+               if (debug_event) {
+                       wblock->handler = wmi_notify_debug;
+                       status = wmi_method_enable(wblock, 1);
+               }
                list_add_tail(&wblock->list, &wmi_blocks.list);
        }
 
@@ -840,6 +915,7 @@ static void acpi_wmi_notify(struct acpi_device *device, u32 event)
        struct guid_block *block;
        struct wmi_block *wblock;
        struct list_head *p;
+       char guid_string[37];
 
        list_for_each(p, &wmi_blocks.list) {
                wblock = list_entry(p, struct wmi_block, list);
@@ -849,6 +925,11 @@ static void acpi_wmi_notify(struct acpi_device *device, u32 event)
                        (block->notify_id == event)) {
                        if (wblock->handler)
                                wblock->handler(event, wblock->handler_data);
+                       if (debug_event) {
+                               wmi_gtoa(wblock->gblock.guid, guid_string);
+                               printk(KERN_INFO PREFIX "DEBUG Event GUID:"
+                                      " %s\n", guid_string);
+                       }
 
                        acpi_bus_generate_netlink_event(
                                device->pnp.device_class, dev_name(&device->dev),
index faaa9b4d0d0711ea2fc2420f37cbe62959891ba9..8e9ba177d8173b7df7794c19f0a691c9fca8c60a 100644 (file)
@@ -57,6 +57,11 @@ config WM8350_POWER
           Say Y here to enable support for the power management unit
          provided by the Wolfson Microelectronics WM8350 PMIC.
 
+config TEST_POWER
+       tristate "Test power driver"
+       help
+         This driver is used for testing. It's safe to say M here.
+
 config BATTERY_DS2760
        tristate "DS2760 battery driver (HP iPAQ & others)"
        select W1
@@ -65,10 +70,10 @@ config BATTERY_DS2760
          Say Y here to enable support for batteries with ds2760 chip.
 
 config BATTERY_DS2782
-       tristate "DS2782 standalone gas-gauge"
+       tristate "DS2782/DS2786 standalone gas-gauge"
        depends on I2C
        help
-         Say Y here to enable support for the DS2782 standalone battery
+         Say Y here to enable support for the DS2782/DS2786 standalone battery
          gas-gauge.
 
 config BATTERY_PMU
@@ -125,6 +130,12 @@ config BATTERY_MAX17040
          in handheld and portable equipment. The MAX17040 is configured
          to operate with a single lithium cell
 
+config BATTERY_Z2
+       tristate "Z2 battery driver"
+       depends on I2C && MACH_ZIPIT2
+       help
+         Say Y to include support for the battery on the Zipit Z2.
+
 config CHARGER_PCF50633
        tristate "NXP PCF50633 MBC"
        depends on MFD_PCF50633
index a2ba7c85c97a55623f05e61b9473fcb9c714c689..00050809a6c7498e5a8eaa7dbe6bbc5defeec17b 100644 (file)
@@ -20,6 +20,7 @@ obj-$(CONFIG_MAX8925_POWER)   += max8925_power.o
 obj-$(CONFIG_WM831X_BACKUP)    += wm831x_backup.o
 obj-$(CONFIG_WM831X_POWER)     += wm831x_power.o
 obj-$(CONFIG_WM8350_POWER)     += wm8350_power.o
+obj-$(CONFIG_TEST_POWER)       += test_power.o
 
 obj-$(CONFIG_BATTERY_DS2760)   += ds2760_battery.o
 obj-$(CONFIG_BATTERY_DS2782)   += ds2782_battery.o
@@ -31,4 +32,5 @@ obj-$(CONFIG_BATTERY_WM97XX)  += wm97xx_battery.o
 obj-$(CONFIG_BATTERY_BQ27x00)  += bq27x00_battery.o
 obj-$(CONFIG_BATTERY_DA9030)   += da9030_battery.o
 obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
+obj-$(CONFIG_BATTERY_Z2)       += z2_battery.o
 obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
index 3bf8d1f622e31319144a8077420d683231ed1195..4d3b27228a2e0ea6bd844f9ae9fbb4161059a3eb 100644 (file)
@@ -304,6 +304,28 @@ static void ds2760_battery_write_rated_capacity(struct ds2760_device_info *di,
        w1_ds2760_recall_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK1);
 }
 
+static void ds2760_battery_write_active_full(struct ds2760_device_info *di,
+                                            int active_full)
+{
+       unsigned char tmp[2] = {
+               active_full >> 8,
+               active_full & 0xff
+       };
+
+       if (tmp[0] == di->raw[DS2760_ACTIVE_FULL] &&
+           tmp[1] == di->raw[DS2760_ACTIVE_FULL + 1])
+               return;
+
+       w1_ds2760_write(di->w1_dev, tmp, DS2760_ACTIVE_FULL, sizeof(tmp));
+       w1_ds2760_store_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK0);
+       w1_ds2760_recall_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK0);
+
+       /* Write to the di->raw[] buffer directly - the DS2760_ACTIVE_FULL
+        * values won't be read back by ds2760_battery_read_status() */
+       di->raw[DS2760_ACTIVE_FULL] = tmp[0];
+       di->raw[DS2760_ACTIVE_FULL + 1] = tmp[1];
+}
+
 static void ds2760_battery_work(struct work_struct *work)
 {
        struct ds2760_device_info *di = container_of(work,
@@ -426,6 +448,45 @@ static int ds2760_battery_get_property(struct power_supply *psy,
        return 0;
 }
 
+static int ds2760_battery_set_property(struct power_supply *psy,
+                                      enum power_supply_property psp,
+                                      const union power_supply_propval *val)
+{
+       struct ds2760_device_info *di = to_ds2760_device_info(psy);
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_CHARGE_FULL:
+               /* the interface counts in uAh, convert the value */
+               ds2760_battery_write_active_full(di, val->intval / 1000L);
+               break;
+
+       case POWER_SUPPLY_PROP_CHARGE_NOW:
+               /* ds2760_battery_set_current_accum() does the conversion */
+               ds2760_battery_set_current_accum(di, val->intval);
+               break;
+
+       default:
+               return -EPERM;
+       }
+
+       return 0;
+}
+
+static int ds2760_battery_property_is_writeable(struct power_supply *psy,
+                                               enum power_supply_property psp)
+{
+       switch (psp) {
+       case POWER_SUPPLY_PROP_CHARGE_FULL:
+       case POWER_SUPPLY_PROP_CHARGE_NOW:
+               return 1;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
 static enum power_supply_property ds2760_battery_props[] = {
        POWER_SUPPLY_PROP_STATUS,
        POWER_SUPPLY_PROP_VOLTAGE_NOW,
@@ -460,6 +521,9 @@ static int ds2760_battery_probe(struct platform_device *pdev)
        di->bat.properties      = ds2760_battery_props;
        di->bat.num_properties  = ARRAY_SIZE(ds2760_battery_props);
        di->bat.get_property    = ds2760_battery_get_property;
+       di->bat.set_property    = ds2760_battery_set_property;
+       di->bat.property_is_writeable =
+                                 ds2760_battery_property_is_writeable;
        di->bat.set_charged     = ds2760_battery_set_charged;
        di->bat.external_power_changed =
                                  ds2760_battery_external_power_changed;
index 99c89976a902b1166cded15540f12aa53de0721e..d762a0cbc6af40b2c4aa58bde75e18e514fcd658 100644 (file)
@@ -5,6 +5,8 @@
  *
  * Author: Ryan Mallon <ryan@bluewatersys.com>
  *
+ * DS2786 added by Yulia Vilensky <vilensky@compulab.co.il>
+ *
  * 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/idr.h>
 #include <linux/power_supply.h>
 #include <linux/slab.h>
+#include <linux/ds2782_battery.h>
 
 #define DS2782_REG_RARC                0x06    /* Remaining active relative capacity */
 
-#define DS2782_REG_VOLT_MSB    0x0c
-#define DS2782_REG_TEMP_MSB    0x0a
-#define DS2782_REG_CURRENT_MSB 0x0e
+#define DS278x_REG_VOLT_MSB    0x0c
+#define DS278x_REG_TEMP_MSB    0x0a
+#define DS278x_REG_CURRENT_MSB 0x0e
 
 /* EEPROM Block */
 #define DS2782_REG_RSNSP       0x69    /* Sense resistor value */
 /* Current unit measurement in uA for a 1 milli-ohm sense resistor */
 #define DS2782_CURRENT_UNITS   1563
 
-#define to_ds2782_info(x) container_of(x, struct ds2782_info, battery)
+#define DS2786_REG_RARC                0x02    /* Remaining active relative capacity */
+
+#define DS2786_CURRENT_UNITS   25
+
+struct ds278x_info;
+
+struct ds278x_battery_ops {
+       int     (*get_current)(struct ds278x_info *info, int *current_uA);
+       int     (*get_voltage)(struct ds278x_info *info, int *voltage_uA);
+       int     (*get_capacity)(struct ds278x_info *info, int *capacity_uA);
+
+};
+
+#define to_ds278x_info(x) container_of(x, struct ds278x_info, battery)
 
-struct ds2782_info {
+struct ds278x_info {
        struct i2c_client       *client;
        struct power_supply     battery;
+       struct ds278x_battery_ops  *ops;
        int                     id;
+       int                     rsns;
 };
 
 static DEFINE_IDR(battery_id);
 static DEFINE_MUTEX(battery_lock);
 
-static inline int ds2782_read_reg(struct ds2782_info *info, int reg, u8 *val)
+static inline int ds278x_read_reg(struct ds278x_info *info, int reg, u8 *val)
 {
        int ret;
 
@@ -58,7 +76,7 @@ static inline int ds2782_read_reg(struct ds2782_info *info, int reg, u8 *val)
        return 0;
 }
 
-static inline int ds2782_read_reg16(struct ds2782_info *info, int reg_msb,
+static inline int ds278x_read_reg16(struct ds278x_info *info, int reg_msb,
                                    s16 *val)
 {
        int ret;
@@ -73,7 +91,7 @@ static inline int ds2782_read_reg16(struct ds2782_info *info, int reg_msb,
        return 0;
 }
 
-static int ds2782_get_temp(struct ds2782_info *info, int *temp)
+static int ds278x_get_temp(struct ds278x_info *info, int *temp)
 {
        s16 raw;
        int err;
@@ -84,14 +102,14 @@ static int ds2782_get_temp(struct ds2782_info *info, int *temp)
         * celsius. The temperature value is stored as a 10 bit number, plus
         * sign in the upper bits of a 16 bit register.
         */
-       err = ds2782_read_reg16(info, DS2782_REG_TEMP_MSB, &raw);
+       err = ds278x_read_reg16(info, DS278x_REG_TEMP_MSB, &raw);
        if (err)
                return err;
        *temp = ((raw / 32) * 125) / 100;
        return 0;
 }
 
-static int ds2782_get_current(struct ds2782_info *info, int *current_uA)
+static int ds2782_get_current(struct ds278x_info *info, int *current_uA)
 {
        int sense_res;
        int err;
@@ -102,7 +120,7 @@ static int ds2782_get_current(struct ds2782_info *info, int *current_uA)
         * The units of measurement for current are dependent on the value of
         * the sense resistor.
         */
-       err = ds2782_read_reg(info, DS2782_REG_RSNSP, &sense_res_raw);
+       err = ds278x_read_reg(info, DS2782_REG_RSNSP, &sense_res_raw);
        if (err)
                return err;
        if (sense_res_raw == 0) {
@@ -113,14 +131,14 @@ static int ds2782_get_current(struct ds2782_info *info, int *current_uA)
 
        dev_dbg(&info->client->dev, "sense resistor = %d milli-ohms\n",
                sense_res);
-       err = ds2782_read_reg16(info, DS2782_REG_CURRENT_MSB, &raw);
+       err = ds278x_read_reg16(info, DS278x_REG_CURRENT_MSB, &raw);
        if (err)
                return err;
        *current_uA = raw * (DS2782_CURRENT_UNITS / sense_res);
        return 0;
 }
 
-static int ds2782_get_voltage(struct ds2782_info *info, int *voltage_uA)
+static int ds2782_get_voltage(struct ds278x_info *info, int *voltage_uA)
 {
        s16 raw;
        int err;
@@ -129,36 +147,77 @@ static int ds2782_get_voltage(struct ds2782_info *info, int *voltage_uA)
         * Voltage is measured in units of 4.88mV. The voltage is stored as
         * a 10-bit number plus sign, in the upper bits of a 16-bit register
         */
-       err = ds2782_read_reg16(info, DS2782_REG_VOLT_MSB, &raw);
+       err = ds278x_read_reg16(info, DS278x_REG_VOLT_MSB, &raw);
        if (err)
                return err;
        *voltage_uA = (raw / 32) * 4800;
        return 0;
 }
 
-static int ds2782_get_capacity(struct ds2782_info *info, int *capacity)
+static int ds2782_get_capacity(struct ds278x_info *info, int *capacity)
 {
        int err;
        u8 raw;
 
-       err = ds2782_read_reg(info, DS2782_REG_RARC, &raw);
+       err = ds278x_read_reg(info, DS2782_REG_RARC, &raw);
        if (err)
                return err;
        *capacity = raw;
        return raw;
 }
 
-static int ds2782_get_status(struct ds2782_info *info, int *status)
+static int ds2786_get_current(struct ds278x_info *info, int *current_uA)
+{
+       int err;
+       s16 raw;
+
+       err = ds278x_read_reg16(info, DS278x_REG_CURRENT_MSB, &raw);
+       if (err)
+               return err;
+       *current_uA = (raw / 16) * (DS2786_CURRENT_UNITS / info->rsns);
+       return 0;
+}
+
+static int ds2786_get_voltage(struct ds278x_info *info, int *voltage_uA)
+{
+       s16 raw;
+       int err;
+
+       /*
+        * Voltage is measured in units of 1.22mV. The voltage is stored as
+        * a 10-bit number plus sign, in the upper bits of a 16-bit register
+        */
+       err = ds278x_read_reg16(info, DS278x_REG_VOLT_MSB, &raw);
+       if (err)
+               return err;
+       *voltage_uA = (raw / 8) * 1220;
+       return 0;
+}
+
+static int ds2786_get_capacity(struct ds278x_info *info, int *capacity)
+{
+       int err;
+       u8 raw;
+
+       err = ds278x_read_reg(info, DS2786_REG_RARC, &raw);
+       if (err)
+               return err;
+       /* Relative capacity is displayed with resolution 0.5 % */
+       *capacity = raw/2 ;
+       return 0;
+}
+
+static int ds278x_get_status(struct ds278x_info *info, int *status)
 {
        int err;
        int current_uA;
        int capacity;
 
-       err = ds2782_get_current(info, &current_uA);
+       err = info->ops->get_current(info, &current_uA);
        if (err)
                return err;
 
-       err = ds2782_get_capacity(info, &capacity);
+       err = info->ops->get_capacity(info, &capacity);
        if (err)
                return err;
 
@@ -174,32 +233,32 @@ static int ds2782_get_status(struct ds2782_info *info, int *status)
        return 0;
 }
 
-static int ds2782_battery_get_property(struct power_supply *psy,
+static int ds278x_battery_get_property(struct power_supply *psy,
                                       enum power_supply_property prop,
                                       union power_supply_propval *val)
 {
-       struct ds2782_info *info = to_ds2782_info(psy);
+       struct ds278x_info *info = to_ds278x_info(psy);
        int ret;
 
        switch (prop) {
        case POWER_SUPPLY_PROP_STATUS:
-               ret = ds2782_get_status(info, &val->intval);
+               ret = ds278x_get_status(info, &val->intval);
                break;
 
        case POWER_SUPPLY_PROP_CAPACITY:
-               ret = ds2782_get_capacity(info, &val->intval);
+               ret = info->ops->get_capacity(info, &val->intval);
                break;
 
        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
-               ret = ds2782_get_voltage(info, &val->intval);
+               ret = info->ops->get_voltage(info, &val->intval);
                break;
 
        case POWER_SUPPLY_PROP_CURRENT_NOW:
-               ret = ds2782_get_current(info, &val->intval);
+               ret = info->ops->get_current(info, &val->intval);
                break;
 
        case POWER_SUPPLY_PROP_TEMP:
-               ret = ds2782_get_temp(info, &val->intval);
+               ret = ds278x_get_temp(info, &val->intval);
                break;
 
        default:
@@ -209,7 +268,7 @@ static int ds2782_battery_get_property(struct power_supply *psy,
        return ret;
 }
 
-static enum power_supply_property ds2782_battery_props[] = {
+static enum power_supply_property ds278x_battery_props[] = {
        POWER_SUPPLY_PROP_STATUS,
        POWER_SUPPLY_PROP_CAPACITY,
        POWER_SUPPLY_PROP_VOLTAGE_NOW,
@@ -217,18 +276,18 @@ static enum power_supply_property ds2782_battery_props[] = {
        POWER_SUPPLY_PROP_TEMP,
 };
 
-static void ds2782_power_supply_init(struct power_supply *battery)
+static void ds278x_power_supply_init(struct power_supply *battery)
 {
        battery->type                   = POWER_SUPPLY_TYPE_BATTERY;
-       battery->properties             = ds2782_battery_props;
-       battery->num_properties         = ARRAY_SIZE(ds2782_battery_props);
-       battery->get_property           = ds2782_battery_get_property;
+       battery->properties             = ds278x_battery_props;
+       battery->num_properties         = ARRAY_SIZE(ds278x_battery_props);
+       battery->get_property           = ds278x_battery_get_property;
        battery->external_power_changed = NULL;
 }
 
-static int ds2782_battery_remove(struct i2c_client *client)
+static int ds278x_battery_remove(struct i2c_client *client)
 {
-       struct ds2782_info *info = i2c_get_clientdata(client);
+       struct ds278x_info *info = i2c_get_clientdata(client);
 
        power_supply_unregister(&info->battery);
        kfree(info->battery.name);
@@ -237,19 +296,45 @@ static int ds2782_battery_remove(struct i2c_client *client)
        idr_remove(&battery_id, info->id);
        mutex_unlock(&battery_lock);
 
-       i2c_set_clientdata(client, info);
-
        kfree(info);
        return 0;
 }
 
-static int ds2782_battery_probe(struct i2c_client *client,
+enum ds278x_num_id {
+       DS2782 = 0,
+       DS2786,
+};
+
+static struct ds278x_battery_ops ds278x_ops[] = {
+       [DS2782] = {
+               .get_current  = ds2782_get_current,
+               .get_voltage  = ds2782_get_voltage,
+               .get_capacity = ds2782_get_capacity,
+       },
+       [DS2786] = {
+               .get_current  = ds2786_get_current,
+               .get_voltage  = ds2786_get_voltage,
+               .get_capacity = ds2786_get_capacity,
+       }
+};
+
+static int ds278x_battery_probe(struct i2c_client *client,
                                const struct i2c_device_id *id)
 {
-       struct ds2782_info *info;
+       struct ds278x_platform_data *pdata = client->dev.platform_data;
+       struct ds278x_info *info;
        int ret;
        int num;
 
+       /*
+        * ds2786 should have the sense resistor value set
+        * in the platform data
+        */
+       if (id->driver_data == DS2786 && !pdata) {
+               dev_err(&client->dev, "missing platform data for ds2786\n");
+               return -EINVAL;
+       }
+
        /* Get an ID for this battery */
        ret = idr_pre_get(&battery_id, GFP_KERNEL);
        if (ret == 0) {
@@ -269,15 +354,20 @@ static int ds2782_battery_probe(struct i2c_client *client,
                goto fail_info;
        }
 
-       info->battery.name = kasprintf(GFP_KERNEL, "ds2782-%d", num);
+       info->battery.name = kasprintf(GFP_KERNEL, "%s-%d", client->name, num);
        if (!info->battery.name) {
                ret = -ENOMEM;
                goto fail_name;
        }
 
+       if (id->driver_data == DS2786)
+               info->rsns = pdata->rsns;
+
        i2c_set_clientdata(client, info);
        info->client = client;
-       ds2782_power_supply_init(&info->battery);
+       info->id = num;
+       info->ops  = &ds278x_ops[id->driver_data];
+       ds278x_power_supply_init(&info->battery);
 
        ret = power_supply_register(&client->dev, &info->battery);
        if (ret) {
@@ -290,7 +380,6 @@ static int ds2782_battery_probe(struct i2c_client *client,
 fail_register:
        kfree(info->battery.name);
 fail_name:
-       i2c_set_clientdata(client, info);
        kfree(info);
 fail_info:
        mutex_lock(&battery_lock);
@@ -300,31 +389,32 @@ fail_id:
        return ret;
 }
 
-static const struct i2c_device_id ds2782_id[] = {
-       {"ds2782", 0},
+static const struct i2c_device_id ds278x_id[] = {
+       {"ds2782", DS2782},
+       {"ds2786", DS2786},
        {},
 };
 
-static struct i2c_driver ds2782_battery_driver = {
+static struct i2c_driver ds278x_battery_driver = {
        .driver         = {
                .name   = "ds2782-battery",
        },
-       .probe          = ds2782_battery_probe,
-       .remove         = ds2782_battery_remove,
-       .id_table       = ds2782_id,
+       .probe          = ds278x_battery_probe,
+       .remove         = ds278x_battery_remove,
+       .id_table       = ds278x_id,
 };
 
-static int __init ds2782_init(void)
+static int __init ds278x_init(void)
 {
-       return i2c_add_driver(&ds2782_battery_driver);
+       return i2c_add_driver(&ds278x_battery_driver);
 }
-module_init(ds2782_init);
+module_init(ds278x_init);
 
-static void __exit ds2782_exit(void)
+static void __exit ds278x_exit(void)
 {
-       i2c_del_driver(&ds2782_battery_driver);
+       i2c_del_driver(&ds278x_battery_driver);
 }
-module_exit(ds2782_exit);
+module_exit(ds278x_exit);
 
 MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com>");
 MODULE_DESCRIPTION("Maxim/Dallas DS2782 Stand-Alone Fuel Gauage IC driver");
index a232de6a57037599f23dd8e99b2a2857f5c443a9..69f8aa3a6a4bda06b34ed6e7d147b09d723eaedc 100644 (file)
@@ -404,6 +404,13 @@ static int usb_wakeup_enabled;
 
 static int pda_power_suspend(struct platform_device *pdev, pm_message_t state)
 {
+       if (pdata->suspend) {
+               int ret = pdata->suspend(state);
+
+               if (ret)
+                       return ret;
+       }
+
        if (device_may_wakeup(&pdev->dev)) {
                if (ac_irq)
                        ac_wakeup_enabled = !enable_irq_wake(ac_irq->start);
@@ -423,6 +430,9 @@ static int pda_power_resume(struct platform_device *pdev)
                        disable_irq_wake(ac_irq->start);
        }
 
+       if (pdata->resume)
+               return pdata->resume();
+
        return 0;
 }
 #else
index f38ba482be75a52ed50e9715a021f2f4c1fda08d..018de2b26998e9b326c0f0a434c4e2b39182422a 100644 (file)
 
 #ifdef CONFIG_SYSFS
 
-extern int power_supply_create_attrs(struct power_supply *psy);
-extern void power_supply_remove_attrs(struct power_supply *psy);
+extern void power_supply_init_attrs(struct device_type *dev_type);
 extern int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env);
 
 #else
 
-static inline int power_supply_create_attrs(struct power_supply *psy)
-{ return 0; }
-static inline void power_supply_remove_attrs(struct power_supply *psy) {}
+static inline void power_supply_init_attrs(struct device_type *dev_type) {}
 #define power_supply_uevent NULL
 
 #endif /* CONFIG_SYSFS */
index cce75b40b4351b3c8de85261855f4b970f2a94ac..91606bb55318110307e3997bcb61722cd247ee73 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/init.h>
+#include <linux/slab.h>
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/power_supply.h>
@@ -22,6 +23,8 @@
 struct class *power_supply_class;
 EXPORT_SYMBOL_GPL(power_supply_class);
 
+static struct device_type power_supply_dev_type;
+
 static int __power_supply_changed_work(struct device *dev, void *data)
 {
        struct power_supply *psy = (struct power_supply *)data;
@@ -144,22 +147,39 @@ struct power_supply *power_supply_get_by_name(char *name)
 }
 EXPORT_SYMBOL_GPL(power_supply_get_by_name);
 
+static void power_supply_dev_release(struct device *dev)
+{
+       pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
+       kfree(dev);
+}
+
 int power_supply_register(struct device *parent, struct power_supply *psy)
 {
-       int rc = 0;
+       struct device *dev;
+       int rc;
 
-       psy->dev = device_create(power_supply_class, parent, 0, psy,
-                                "%s", psy->name);
-       if (IS_ERR(psy->dev)) {
-               rc = PTR_ERR(psy->dev);
-               goto dev_create_failed;
-       }
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
 
-       INIT_WORK(&psy->changed_work, power_supply_changed_work);
+       device_initialize(dev);
 
-       rc = power_supply_create_attrs(psy);
+       dev->class = power_supply_class;
+       dev->type = &power_supply_dev_type;
+       dev->parent = parent;
+       dev->release = power_supply_dev_release;
+       dev_set_drvdata(dev, psy);
+       psy->dev = dev;
+
+       rc = kobject_set_name(&dev->kobj, "%s", psy->name);
+       if (rc)
+               goto kobject_set_name_failed;
+
+       rc = device_add(dev);
        if (rc)
-               goto create_attrs_failed;
+               goto device_add_failed;
+
+       INIT_WORK(&psy->changed_work, power_supply_changed_work);
 
        rc = power_supply_create_triggers(psy);
        if (rc)
@@ -170,10 +190,10 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
        goto success;
 
 create_triggers_failed:
-       power_supply_remove_attrs(psy);
-create_attrs_failed:
        device_unregister(psy->dev);
-dev_create_failed:
+kobject_set_name_failed:
+device_add_failed:
+       kfree(dev);
 success:
        return rc;
 }
@@ -183,7 +203,6 @@ void power_supply_unregister(struct power_supply *psy)
 {
        flush_scheduled_work();
        power_supply_remove_triggers(psy);
-       power_supply_remove_attrs(psy);
        device_unregister(psy->dev);
 }
 EXPORT_SYMBOL_GPL(power_supply_unregister);
@@ -196,6 +215,7 @@ static int __init power_supply_class_init(void)
                return PTR_ERR(power_supply_class);
 
        power_supply_class->dev_uevent = power_supply_uevent;
+       power_supply_init_attrs(&power_supply_dev_type);
 
        return 0;
 }
index 5b6e352ac7c1e935fc7cfce0f5683028a541f94f..9d30eeb8c8104187320794eca0e11e8d191c8ad0 100644 (file)
@@ -31,9 +31,9 @@
 
 #define POWER_SUPPLY_ATTR(_name)                                       \
 {                                                                      \
-       .attr = { .name = #_name, .mode = 0444 },       \
+       .attr = { .name = #_name },                                     \
        .show = power_supply_show_property,                             \
-       .store = NULL,                                                  \
+       .store = power_supply_store_property,                           \
 }
 
 static struct device_attribute power_supply_attrs[];
@@ -41,6 +41,9 @@ static struct device_attribute power_supply_attrs[];
 static ssize_t power_supply_show_property(struct device *dev,
                                          struct device_attribute *attr,
                                          char *buf) {
+       static char *type_text[] = {
+               "Battery", "UPS", "Mains", "USB"
+       };
        static char *status_text[] = {
                "Unknown", "Charging", "Discharging", "Not charging", "Full"
        };
@@ -58,12 +61,15 @@ static ssize_t power_supply_show_property(struct device *dev,
        static char *capacity_level_text[] = {
                "Unknown", "Critical", "Low", "Normal", "High", "Full"
        };
-       ssize_t ret;
+       ssize_t ret = 0;
        struct power_supply *psy = dev_get_drvdata(dev);
        const ptrdiff_t off = attr - power_supply_attrs;
        union power_supply_propval value;
 
-       ret = psy->get_property(psy, off, &value);
+       if (off == POWER_SUPPLY_PROP_TYPE)
+               value.intval = psy->type;
+       else
+               ret = psy->get_property(psy, off, &value);
 
        if (ret < 0) {
                if (ret == -ENODATA)
@@ -85,12 +91,37 @@ static ssize_t power_supply_show_property(struct device *dev,
                return sprintf(buf, "%s\n", technology_text[value.intval]);
        else if (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL)
                return sprintf(buf, "%s\n", capacity_level_text[value.intval]);
+       else if (off == POWER_SUPPLY_PROP_TYPE)
+               return sprintf(buf, "%s\n", type_text[value.intval]);
        else if (off >= POWER_SUPPLY_PROP_MODEL_NAME)
                return sprintf(buf, "%s\n", value.strval);
 
        return sprintf(buf, "%d\n", value.intval);
 }
 
+static ssize_t power_supply_store_property(struct device *dev,
+                                          struct device_attribute *attr,
+                                          const char *buf, size_t count) {
+       ssize_t ret;
+       struct power_supply *psy = dev_get_drvdata(dev);
+       const ptrdiff_t off = attr - power_supply_attrs;
+       union power_supply_propval value;
+       long long_val;
+
+       /* TODO: support other types than int */
+       ret = strict_strtol(buf, 10, &long_val);
+       if (ret < 0)
+               return ret;
+
+       value.intval = long_val;
+
+       ret = psy->set_property(psy, off, &value);
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
 /* Must be in the same order as POWER_SUPPLY_PROP_* */
 static struct device_attribute power_supply_attrs[] = {
        /* Properties of type `int' */
@@ -132,67 +163,61 @@ static struct device_attribute power_supply_attrs[] = {
        POWER_SUPPLY_ATTR(time_to_empty_avg),
        POWER_SUPPLY_ATTR(time_to_full_now),
        POWER_SUPPLY_ATTR(time_to_full_avg),
+       POWER_SUPPLY_ATTR(type),
        /* Properties of type `const char *' */
        POWER_SUPPLY_ATTR(model_name),
        POWER_SUPPLY_ATTR(manufacturer),
        POWER_SUPPLY_ATTR(serial_number),
 };
 
-static ssize_t power_supply_show_static_attrs(struct device *dev,
-                                             struct device_attribute *attr,
-                                             char *buf) {
-       static char *type_text[] = { "Battery", "UPS", "Mains", "USB" };
+static struct attribute *
+__power_supply_attrs[ARRAY_SIZE(power_supply_attrs) + 1];
+
+static mode_t power_supply_attr_is_visible(struct kobject *kobj,
+                                          struct attribute *attr,
+                                          int attrno)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
        struct power_supply *psy = dev_get_drvdata(dev);
+       mode_t mode = S_IRUSR | S_IRGRP | S_IROTH;
+       int i;
 
-       return sprintf(buf, "%s\n", type_text[psy->type]);
-}
+       if (attrno == POWER_SUPPLY_PROP_TYPE)
+               return mode;
 
-static struct device_attribute power_supply_static_attrs[] = {
-       __ATTR(type, 0444, power_supply_show_static_attrs, NULL),
-};
+       for (i = 0; i < psy->num_properties; i++) {
+               int property = psy->properties[i];
 
-int power_supply_create_attrs(struct power_supply *psy)
-{
-       int rc = 0;
-       int i, j;
-
-       for (i = 0; i < ARRAY_SIZE(power_supply_static_attrs); i++) {
-               rc = device_create_file(psy->dev,
-                           &power_supply_static_attrs[i]);
-               if (rc)
-                       goto statics_failed;
-       }
+               if (property == attrno) {
+                       if (psy->property_is_writeable &&
+                           psy->property_is_writeable(psy, property) > 0)
+                               mode |= S_IWUSR;
 
-       for (j = 0; j < psy->num_properties; j++) {
-               rc = device_create_file(psy->dev,
-                           &power_supply_attrs[psy->properties[j]]);
-               if (rc)
-                       goto dynamics_failed;
+                       return mode;
+               }
        }
 
-       goto succeed;
-
-dynamics_failed:
-       while (j--)
-               device_remove_file(psy->dev,
-                          &power_supply_attrs[psy->properties[j]]);
-statics_failed:
-       while (i--)
-               device_remove_file(psy->dev, &power_supply_static_attrs[i]);
-succeed:
-       return rc;
+       return 0;
 }
 
-void power_supply_remove_attrs(struct power_supply *psy)
+static struct attribute_group power_supply_attr_group = {
+       .attrs = __power_supply_attrs,
+       .is_visible = power_supply_attr_is_visible,
+};
+
+static const struct attribute_group *power_supply_attr_groups[] = {
+       &power_supply_attr_group,
+       NULL,
+};
+
+void power_supply_init_attrs(struct device_type *dev_type)
 {
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(power_supply_static_attrs); i++)
-               device_remove_file(psy->dev, &power_supply_static_attrs[i]);
+       dev_type->groups = power_supply_attr_groups;
 
-       for (i = 0; i < psy->num_properties; i++)
-               device_remove_file(psy->dev,
-                           &power_supply_attrs[psy->properties[i]]);
+       for (i = 0; i < ARRAY_SIZE(power_supply_attrs); i++)
+               __power_supply_attrs[i] = &power_supply_attrs[i].attr;
 }
 
 static char *kstruprdup(const char *str, gfp_t gfp)
@@ -236,36 +261,6 @@ int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env)
        if (!prop_buf)
                return -ENOMEM;
 
-       for (j = 0; j < ARRAY_SIZE(power_supply_static_attrs); j++) {
-               struct device_attribute *attr;
-               char *line;
-
-               attr = &power_supply_static_attrs[j];
-
-               ret = power_supply_show_static_attrs(dev, attr, prop_buf);
-               if (ret < 0)
-                       goto out;
-
-               line = strchr(prop_buf, '\n');
-               if (line)
-                       *line = 0;
-
-               attrname = kstruprdup(attr->attr.name, GFP_KERNEL);
-               if (!attrname) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
-
-               dev_dbg(dev, "Static prop %s=%s\n", attrname, prop_buf);
-
-               ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf);
-               kfree(attrname);
-               if (ret)
-                       goto out;
-       }
-
-       dev_dbg(dev, "%zd dynamic props\n", psy->num_properties);
-
        for (j = 0; j < psy->num_properties; j++) {
                struct device_attribute *attr;
                char *line;
diff --git a/drivers/power/test_power.c b/drivers/power/test_power.c
new file mode 100644 (file)
index 0000000..0cd9f67
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * Power supply driver for testing.
+ *
+ * Copyright 2010  Anton Vorontsov <cbouatmailru@gmail.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/kernel.h>
+#include <linux/module.h>
+#include <linux/power_supply.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/vermagic.h>
+
+static int test_power_ac_online = 1;
+static int test_power_battery_status = POWER_SUPPLY_STATUS_CHARGING;
+
+static int test_power_get_ac_property(struct power_supply *psy,
+                                     enum power_supply_property psp,
+                                     union power_supply_propval *val)
+{
+       switch (psp) {
+       case POWER_SUPPLY_PROP_ONLINE:
+               val->intval = test_power_ac_online;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int test_power_get_battery_property(struct power_supply *psy,
+                                          enum power_supply_property psp,
+                                          union power_supply_propval *val)
+{
+       switch (psp) {
+       case POWER_SUPPLY_PROP_MODEL_NAME:
+               val->strval = "Test battery";
+               break;
+       case POWER_SUPPLY_PROP_MANUFACTURER:
+               val->strval = "Linux";
+               break;
+       case POWER_SUPPLY_PROP_SERIAL_NUMBER:
+               val->strval = UTS_RELEASE;
+               break;
+       case POWER_SUPPLY_PROP_STATUS:
+               val->intval = test_power_battery_status;
+               break;
+       case POWER_SUPPLY_PROP_CHARGE_TYPE:
+               val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
+               break;
+       case POWER_SUPPLY_PROP_HEALTH:
+               val->intval = POWER_SUPPLY_HEALTH_GOOD;
+               break;
+       case POWER_SUPPLY_PROP_TECHNOLOGY:
+               val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+               break;
+       case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
+               val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
+               break;
+       case POWER_SUPPLY_PROP_CAPACITY:
+               val->intval = 50;
+               break;
+       case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
+       case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:
+               val->intval = 3600;
+               break;
+       default:
+               pr_info("%s: some properties deliberately report errors.\n",
+                       __func__);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static enum power_supply_property test_power_ac_props[] = {
+       POWER_SUPPLY_PROP_ONLINE,
+};
+
+static enum power_supply_property test_power_battery_props[] = {
+       POWER_SUPPLY_PROP_STATUS,
+       POWER_SUPPLY_PROP_CHARGE_TYPE,
+       POWER_SUPPLY_PROP_HEALTH,
+       POWER_SUPPLY_PROP_TECHNOLOGY,
+       POWER_SUPPLY_PROP_CHARGE_FULL,
+       POWER_SUPPLY_PROP_CHARGE_EMPTY,
+       POWER_SUPPLY_PROP_CAPACITY,
+       POWER_SUPPLY_PROP_CAPACITY_LEVEL,
+       POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
+       POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
+       POWER_SUPPLY_PROP_MODEL_NAME,
+       POWER_SUPPLY_PROP_MANUFACTURER,
+       POWER_SUPPLY_PROP_SERIAL_NUMBER,
+};
+
+static char *test_power_ac_supplied_to[] = {
+       "test_battery",
+};
+
+static struct power_supply test_power_supplies[] = {
+       {
+               .name = "test_ac",
+               .type = POWER_SUPPLY_TYPE_MAINS,
+               .supplied_to = test_power_ac_supplied_to,
+               .num_supplicants = ARRAY_SIZE(test_power_ac_supplied_to),
+               .properties = test_power_ac_props,
+               .num_properties = ARRAY_SIZE(test_power_ac_props),
+               .get_property = test_power_get_ac_property,
+       }, {
+               .name = "test_battery",
+               .type = POWER_SUPPLY_TYPE_BATTERY,
+               .properties = test_power_battery_props,
+               .num_properties = ARRAY_SIZE(test_power_battery_props),
+               .get_property = test_power_get_battery_property,
+       },
+};
+
+static int __init test_power_init(void)
+{
+       int i;
+       int ret;
+
+       for (i = 0; i < ARRAY_SIZE(test_power_supplies); i++) {
+               ret = power_supply_register(NULL, &test_power_supplies[i]);
+               if (ret) {
+                       pr_err("%s: failed to register %s\n", __func__,
+                               test_power_supplies[i].name);
+                       goto failed;
+               }
+       }
+
+       return 0;
+failed:
+       while (--i >= 0)
+               power_supply_unregister(&test_power_supplies[i]);
+       return ret;
+}
+module_init(test_power_init);
+
+static void __exit test_power_exit(void)
+{
+       int i;
+
+       /* Let's see how we handle changes... */
+       test_power_ac_online = 0;
+       test_power_battery_status = POWER_SUPPLY_STATUS_DISCHARGING;
+       for (i = 0; i < ARRAY_SIZE(test_power_supplies); i++)
+               power_supply_changed(&test_power_supplies[i]);
+       pr_info("%s: 'changed' event sent, sleeping for 10 seconds...\n",
+               __func__);
+       ssleep(10);
+
+       for (i = 0; i < ARRAY_SIZE(test_power_supplies); i++)
+               power_supply_unregister(&test_power_supplies[i]);
+}
+module_exit(test_power_exit);
+
+MODULE_DESCRIPTION("Power supply driver for testing");
+MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>");
+MODULE_LICENSE("GPL");
index 2eab35aab3119cb29c02599b70fa6f826f971ac5..ee04936b2db56da2b49258bb067e8a813126d7f9 100644 (file)
@@ -61,7 +61,7 @@ static unsigned long tosa_read_bat(struct tosa_bat *bat)
        mutex_lock(&bat_lock);
        gpio_set_value(bat->gpio_bat, 1);
        msleep(5);
-       value = wm97xx_read_aux_adc(bat->psy.dev->parent->driver_data,
+       value = wm97xx_read_aux_adc(dev_get_drvdata(bat->psy.dev->parent),
                        bat->adc_bat);
        gpio_set_value(bat->gpio_bat, 0);
        mutex_unlock(&bat_lock);
@@ -81,7 +81,7 @@ static unsigned long tosa_read_temp(struct tosa_bat *bat)
        mutex_lock(&bat_lock);
        gpio_set_value(bat->gpio_temp, 1);
        msleep(5);
-       value = wm97xx_read_aux_adc(bat->psy.dev->parent->driver_data,
+       value = wm97xx_read_aux_adc(dev_get_drvdata(bat->psy.dev->parent),
                        bat->adc_temp);
        gpio_set_value(bat->gpio_temp, 0);
        mutex_unlock(&bat_lock);
index 875c4d0f776b90570058eef2e41328488f3f0b51..fbcc36dae470472fd685228ea261a349e664d145 100644 (file)
@@ -537,9 +537,9 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev)
                goto err_battery;
 
        irq = platform_get_irq_byname(pdev, "SYSLO");
-       ret = wm831x_request_irq(wm831x, irq, wm831x_syslo_irq,
-                                IRQF_TRIGGER_RISING, "SYSLO",
-                                power);
+       ret = request_threaded_irq(irq, NULL, wm831x_syslo_irq,
+                                  IRQF_TRIGGER_RISING, "System power low",
+                                  power);
        if (ret != 0) {
                dev_err(&pdev->dev, "Failed to request SYSLO IRQ %d: %d\n",
                        irq, ret);
@@ -547,9 +547,9 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev)
        }
 
        irq = platform_get_irq_byname(pdev, "PWR SRC");
-       ret = wm831x_request_irq(wm831x, irq, wm831x_pwr_src_irq,
-                                IRQF_TRIGGER_RISING, "Power source",
-                                power);
+       ret = request_threaded_irq(irq, NULL, wm831x_pwr_src_irq,
+                                  IRQF_TRIGGER_RISING, "Power source",
+                                  power);
        if (ret != 0) {
                dev_err(&pdev->dev, "Failed to request PWR SRC IRQ %d: %d\n",
                        irq, ret);
@@ -558,10 +558,10 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev)
 
        for (i = 0; i < ARRAY_SIZE(wm831x_bat_irqs); i++) {
                irq = platform_get_irq_byname(pdev, wm831x_bat_irqs[i]);
-               ret = wm831x_request_irq(wm831x, irq, wm831x_bat_irq,
-                                        IRQF_TRIGGER_RISING,
-                                        wm831x_bat_irqs[i],
-                                        power);
+               ret = request_threaded_irq(irq, NULL, wm831x_bat_irq,
+                                          IRQF_TRIGGER_RISING,
+                                          wm831x_bat_irqs[i],
+                                          power);
                if (ret != 0) {
                        dev_err(&pdev->dev,
                                "Failed to request %s IRQ %d: %d\n",
@@ -575,13 +575,13 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev)
 err_bat_irq:
        for (; i >= 0; i--) {
                irq = platform_get_irq_byname(pdev, wm831x_bat_irqs[i]);
-               wm831x_free_irq(wm831x, irq, power);
+               free_irq(irq, power);
        }
        irq = platform_get_irq_byname(pdev, "PWR SRC");
-       wm831x_free_irq(wm831x, irq, power);
+       free_irq(irq, power);
 err_syslo:
        irq = platform_get_irq_byname(pdev, "SYSLO");
-       wm831x_free_irq(wm831x, irq, power);
+       free_irq(irq, power);
 err_usb:
        power_supply_unregister(usb);
 err_battery:
@@ -596,19 +596,18 @@ err_kmalloc:
 static __devexit int wm831x_power_remove(struct platform_device *pdev)
 {
        struct wm831x_power *wm831x_power = platform_get_drvdata(pdev);
-       struct wm831x *wm831x = wm831x_power->wm831x;
        int irq, i;
 
        for (i = 0; i < ARRAY_SIZE(wm831x_bat_irqs); i++) {
                irq = platform_get_irq_byname(pdev, wm831x_bat_irqs[i]);
-               wm831x_free_irq(wm831x, irq, wm831x_power);
+               free_irq(irq, wm831x_power);
        }
 
        irq = platform_get_irq_byname(pdev, "PWR SRC");
-       wm831x_free_irq(wm831x, irq, wm831x_power);
+       free_irq(irq, wm831x_power);
 
        irq = platform_get_irq_byname(pdev, "SYSLO");
-       wm831x_free_irq(wm831x, irq, wm831x_power);
+       free_irq(irq, wm831x_power);
 
        power_supply_unregister(&wm831x_power->battery);
        power_supply_unregister(&wm831x_power->wall);
index 94c70650aafc90275fd24d74b798d6d66f91263c..4e8afce0c81805cbca50d2bd0ffdfd249fbeeab2 100644 (file)
@@ -308,6 +308,9 @@ static void __exit wm97xx_bat_exit(void)
        platform_driver_unregister(&wm97xx_bat_driver);
 }
 
+/* The interface is deprecated, as well as linux/wm97xx_batt.h */
+void wm97xx_bat_set_pdata(struct wm97xx_batt_info *data);
+
 void wm97xx_bat_set_pdata(struct wm97xx_batt_info *data)
 {
        gpdata = data;
diff --git a/drivers/power/z2_battery.c b/drivers/power/z2_battery.c
new file mode 100644 (file)
index 0000000..9cca465
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * Battery measurement code for Zipit Z2
+ *
+ * Copyright (C) 2009 Peter Edwards <sweetlilmre@gmail.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/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/i2c.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+#include <linux/z2_battery.h>
+
+#define        Z2_DEFAULT_NAME "Z2"
+
+struct z2_charger {
+       struct z2_battery_info  *info;
+       int                     bat_status;
+       struct i2c_client       *client;
+       struct power_supply     batt_ps;
+       struct mutex            work_lock;
+       struct work_struct      bat_work;
+};
+
+static unsigned long z2_read_bat(struct z2_charger *charger)
+{
+       int data;
+       data = i2c_smbus_read_byte_data(charger->client,
+                                       charger->info->batt_I2C_reg);
+       if (data < 0)
+               return 0;
+
+       return data * charger->info->batt_mult / charger->info->batt_div;
+}
+
+static int z2_batt_get_property(struct power_supply *batt_ps,
+                           enum power_supply_property psp,
+                           union power_supply_propval *val)
+{
+       struct z2_charger *charger = container_of(batt_ps, struct z2_charger,
+                                               batt_ps);
+       struct z2_battery_info *info = charger->info;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_STATUS:
+               val->intval = charger->bat_status;
+               break;
+       case POWER_SUPPLY_PROP_TECHNOLOGY:
+               val->intval = info->batt_tech;
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+               if (info->batt_I2C_reg >= 0)
+                       val->intval = z2_read_bat(charger);
+               else
+                       return -EINVAL;
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+               if (info->max_voltage >= 0)
+                       val->intval = info->max_voltage;
+               else
+                       return -EINVAL;
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_MIN:
+               if (info->min_voltage >= 0)
+                       val->intval = info->min_voltage;
+               else
+                       return -EINVAL;
+               break;
+       case POWER_SUPPLY_PROP_PRESENT:
+               val->intval = 1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void z2_batt_ext_power_changed(struct power_supply *batt_ps)
+{
+       struct z2_charger *charger = container_of(batt_ps, struct z2_charger,
+                                               batt_ps);
+       schedule_work(&charger->bat_work);
+}
+
+static void z2_batt_update(struct z2_charger *charger)
+{
+       int old_status = charger->bat_status;
+       struct z2_battery_info *info;
+
+       info = charger->info;
+
+       mutex_lock(&charger->work_lock);
+
+       charger->bat_status = (info->charge_gpio >= 0) ?
+               (gpio_get_value(info->charge_gpio) ?
+               POWER_SUPPLY_STATUS_CHARGING :
+               POWER_SUPPLY_STATUS_DISCHARGING) :
+               POWER_SUPPLY_STATUS_UNKNOWN;
+
+       if (old_status != charger->bat_status) {
+               pr_debug("%s: %i -> %i\n", charger->batt_ps.name, old_status,
+                       charger->bat_status);
+               power_supply_changed(&charger->batt_ps);
+       }
+
+       mutex_unlock(&charger->work_lock);
+}
+
+static void z2_batt_work(struct work_struct *work)
+{
+       struct z2_charger *charger;
+       charger = container_of(work, struct z2_charger, bat_work);
+       z2_batt_update(charger);
+}
+
+static irqreturn_t z2_charge_switch_irq(int irq, void *devid)
+{
+       struct z2_charger *charger = devid;
+       schedule_work(&charger->bat_work);
+       return IRQ_HANDLED;
+}
+
+static int z2_batt_ps_init(struct z2_charger *charger, int props)
+{
+       int i = 0;
+       enum power_supply_property *prop;
+       struct z2_battery_info *info = charger->info;
+
+       if (info->batt_tech >= 0)
+               props++;        /* POWER_SUPPLY_PROP_TECHNOLOGY */
+       if (info->batt_I2C_reg >= 0)
+               props++;        /* POWER_SUPPLY_PROP_VOLTAGE_NOW */
+       if (info->max_voltage >= 0)
+               props++;        /* POWER_SUPPLY_PROP_VOLTAGE_MAX */
+       if (info->min_voltage >= 0)
+               props++;        /* POWER_SUPPLY_PROP_VOLTAGE_MIN */
+
+       prop = kzalloc(props * sizeof(*prop), GFP_KERNEL);
+       if (!prop)
+               return -ENOMEM;
+
+       prop[i++] = POWER_SUPPLY_PROP_PRESENT;
+       if (info->charge_gpio >= 0)
+               prop[i++] = POWER_SUPPLY_PROP_STATUS;
+       if (info->batt_tech >= 0)
+               prop[i++] = POWER_SUPPLY_PROP_TECHNOLOGY;
+       if (info->batt_I2C_reg >= 0)
+               prop[i++] = POWER_SUPPLY_PROP_VOLTAGE_NOW;
+       if (info->max_voltage >= 0)
+               prop[i++] = POWER_SUPPLY_PROP_VOLTAGE_MAX;
+       if (info->min_voltage >= 0)
+               prop[i++] = POWER_SUPPLY_PROP_VOLTAGE_MIN;
+
+       if (!info->batt_name) {
+               dev_info(&charger->client->dev,
+                               "Please consider setting proper battery "
+                               "name in platform definition file, falling "
+                               "back to name \" Z2_DEFAULT_NAME \"\n");
+               charger->batt_ps.name = Z2_DEFAULT_NAME;
+       } else
+               charger->batt_ps.name = info->batt_name;
+
+       charger->batt_ps.properties             = prop;
+       charger->batt_ps.num_properties         = props;
+       charger->batt_ps.type                   = POWER_SUPPLY_TYPE_BATTERY;
+       charger->batt_ps.get_property           = z2_batt_get_property;
+       charger->batt_ps.external_power_changed = z2_batt_ext_power_changed;
+       charger->batt_ps.use_for_apm            = 1;
+
+       return 0;
+}
+
+static int __devinit z2_batt_probe(struct i2c_client *client,
+                               const struct i2c_device_id *id)
+{
+       int ret = 0;
+       int props = 1;  /* POWER_SUPPLY_PROP_PRESENT */
+       struct z2_charger *charger;
+       struct z2_battery_info *info = client->dev.platform_data;
+
+       if (info == NULL) {
+               dev_err(&client->dev,
+                       "Please set platform device platform_data"
+                       " to a valid z2_battery_info pointer!\n");
+               return -EINVAL;
+       }
+
+       charger = kzalloc(sizeof(*charger), GFP_KERNEL);
+       if (charger == NULL)
+               return -ENOMEM;
+
+       charger->bat_status = POWER_SUPPLY_STATUS_UNKNOWN;
+       charger->info = info;
+       charger->client = client;
+       i2c_set_clientdata(client, charger);
+
+       mutex_init(&charger->work_lock);
+
+       if (info->charge_gpio >= 0 && gpio_is_valid(info->charge_gpio)) {
+               ret = gpio_request(info->charge_gpio, "BATT CHRG");
+               if (ret)
+                       goto err;
+
+               ret = gpio_direction_input(info->charge_gpio);
+               if (ret)
+                       goto err2;
+
+               set_irq_type(gpio_to_irq(info->charge_gpio),
+                               IRQ_TYPE_EDGE_BOTH);
+               ret = request_irq(gpio_to_irq(info->charge_gpio),
+                               z2_charge_switch_irq, IRQF_DISABLED,
+                               "AC Detect", charger);
+               if (ret)
+                       goto err3;
+       }
+
+       ret = z2_batt_ps_init(charger, props);
+       if (ret)
+               goto err3;
+
+       INIT_WORK(&charger->bat_work, z2_batt_work);
+
+       ret = power_supply_register(&client->dev, &charger->batt_ps);
+       if (ret)
+               goto err4;
+
+       schedule_work(&charger->bat_work);
+
+       return 0;
+
+err4:
+       kfree(charger->batt_ps.properties);
+err3:
+       if (info->charge_gpio >= 0 && gpio_is_valid(info->charge_gpio))
+               free_irq(gpio_to_irq(info->charge_gpio), charger);
+err2:
+       if (info->charge_gpio >= 0 && gpio_is_valid(info->charge_gpio))
+               gpio_free(info->charge_gpio);
+err:
+       kfree(charger);
+       return ret;
+}
+
+static int __devexit z2_batt_remove(struct i2c_client *client)
+{
+       struct z2_charger *charger = i2c_get_clientdata(client);
+       struct z2_battery_info *info = charger->info;
+
+       flush_scheduled_work();
+       power_supply_unregister(&charger->batt_ps);
+
+       kfree(charger->batt_ps.properties);
+       if (info->charge_gpio >= 0 && gpio_is_valid(info->charge_gpio)) {
+               free_irq(gpio_to_irq(info->charge_gpio), charger);
+               gpio_free(info->charge_gpio);
+       }
+
+       kfree(charger);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int z2_batt_suspend(struct i2c_client *client, pm_message_t state)
+{
+       flush_scheduled_work();
+       return 0;
+}
+
+static int z2_batt_resume(struct i2c_client *client)
+{
+       struct z2_charger *charger = i2c_get_clientdata(client);
+
+       schedule_work(&charger->bat_work);
+       return 0;
+}
+#else
+#define z2_batt_suspend NULL
+#define z2_batt_resume NULL
+#endif
+
+static const struct i2c_device_id z2_batt_id[] = {
+       { "aer915", 0 },
+       { }
+};
+
+static struct i2c_driver z2_batt_driver = {
+       .driver = {
+               .name   = "z2-battery",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = z2_batt_probe,
+       .remove         = z2_batt_remove,
+       .suspend        = z2_batt_suspend,
+       .resume         = z2_batt_resume,
+       .id_table       = z2_batt_id,
+};
+
+static int __init z2_batt_init(void)
+{
+       return i2c_add_driver(&z2_batt_driver);
+}
+
+static void __exit z2_batt_exit(void)
+{
+       i2c_del_driver(&z2_batt_driver);
+}
+
+module_init(z2_batt_init);
+module_exit(z2_batt_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Peter Edwards <sweetlilmre@gmail.com>");
+MODULE_DESCRIPTION("Zipit Z2 battery driver");
index c32822ad84a40b6e0611557121b9aa1793104c16..070211a5955c7dc140799b55a2f57bbbe5ce0191 100644 (file)
@@ -8,3 +8,27 @@ config RAPIDIO_DISC_TIMEOUT
        ---help---
          Amount of time a discovery node waits for a host to complete
          enumeration before giving up.
+
+config RAPIDIO_ENABLE_RX_TX_PORTS
+       bool "Enable RapidIO Input/Output Ports"
+       depends on RAPIDIO
+       ---help---
+         The RapidIO specification describes a Output port transmit
+         enable and a Input port receive enable. The recommended state
+         for Input ports and Output ports should be disabled. When
+         this switch is set the RapidIO subsystem will enable all
+         ports for Input/Output direction to allow other traffic
+         than Maintenance transfers.
+
+source "drivers/rapidio/switches/Kconfig"
+
+config RAPIDIO_DEBUG
+       bool "RapidIO subsystem debug messages"
+       depends on RAPIDIO
+       help
+         Say Y here if you want the RapidIO subsystem to produce a bunch of
+         debug messages to the system log. Select this if you are having a
+         problem with the RapidIO subsystem and want to see more of what is
+         going on.
+
+         If you are unsure about this, say N here.
index 7c0e1818de5139e43207a1e479bb4328eec4ec97..b6139fe187bfe7389f1b30970dc03c16660ca161 100644 (file)
@@ -4,3 +4,7 @@
 obj-y += rio.o rio-access.o rio-driver.o rio-scan.o rio-sysfs.o
 
 obj-$(CONFIG_RAPIDIO)          += switches/
+
+ifeq ($(CONFIG_RAPIDIO_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
index 45415096c2940d5bb834341cdcf5c76f3ffc38e6..8070e074c739f89b0902cfcc1ed9c20e5374c76c 100644 (file)
@@ -4,6 +4,14 @@
  * Copyright 2005 MontaVista Software, Inc.
  * Matt Porter <mporter@kernel.crashing.org>
  *
+ * Copyright 2009 Integrated Device Technology, Inc.
+ * Alex Bounine <alexandre.bounine@idt.com>
+ * - Added Port-Write/Error Management initialization and handling
+ *
+ * Copyright 2009 Sysgo AG
+ * Thomas Moll <thomas.moll@sysgo.com>
+ * - Added Input- Output- enable functionality, to allow full communication
+ *
  * 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
 LIST_HEAD(rio_devices);
 static LIST_HEAD(rio_switches);
 
-#define RIO_ENUM_CMPL_MAGIC    0xdeadbeef
-
 static void rio_enum_timeout(unsigned long);
 
+static void rio_init_em(struct rio_dev *rdev);
+
 DEFINE_SPINLOCK(rio_global_list_lock);
 
 static int next_destid = 0;
 static int next_switchid = 0;
 static int next_net = 0;
+static int next_comptag;
 
 static struct timer_list rio_enum_timer =
 TIMER_INITIALIZER(rio_enum_timeout, 0, 0);
@@ -52,12 +61,6 @@ static int rio_mport_phys_table[] = {
        -1,
 };
 
-static int rio_sport_phys_table[] = {
-       RIO_EFB_PAR_EP_FREE_ID,
-       RIO_EFB_SER_EP_FREE_ID,
-       -1,
-};
-
 /**
  * rio_get_device_id - Get the base/extended device id for a device
  * @port: RIO master port
@@ -118,12 +121,26 @@ static int rio_clear_locks(struct rio_mport *port)
        u32 result;
        int ret = 0;
 
-       /* Write component tag CSR magic complete value */
-       rio_local_write_config_32(port, RIO_COMPONENT_TAG_CSR,
-                                 RIO_ENUM_CMPL_MAGIC);
-       list_for_each_entry(rdev, &rio_devices, global_list)
-           rio_write_config_32(rdev, RIO_COMPONENT_TAG_CSR,
-                               RIO_ENUM_CMPL_MAGIC);
+       /* Assign component tag to all devices */
+       next_comptag = 1;
+       rio_local_write_config_32(port, RIO_COMPONENT_TAG_CSR, next_comptag++);
+
+       list_for_each_entry(rdev, &rio_devices, global_list) {
+               /* Mark device as discovered */
+               rio_read_config_32(rdev,
+                                  rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR,
+                                  &result);
+               rio_write_config_32(rdev,
+                                   rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR,
+                                   result | RIO_PORT_GEN_DISCOVERED);
+
+               rio_write_config_32(rdev, RIO_COMPONENT_TAG_CSR, next_comptag);
+               rdev->comp_tag = next_comptag++;
+               if (next_comptag >= 0x10000) {
+                       pr_err("RIO: Component Tag Counter Overflow\n");
+                       break;
+               }
+       }
 
        /* Release host device id locks */
        rio_local_write_config_32(port, RIO_HOST_DID_LOCK_CSR,
@@ -229,27 +246,37 @@ static int rio_is_switch(struct rio_dev *rdev)
 }
 
 /**
- * rio_route_set_ops- Sets routing operations for a particular vendor switch
+ * rio_switch_init - Sets switch operations for a particular vendor switch
  * @rdev: RIO device
+ * @do_enum: Enumeration/Discovery mode flag
  *
- * Searches the RIO route ops table for known switch types. If the vid
- * and did match a switch table entry, then set the add_entry() and
- * get_entry() ops to the table entry values.
+ * Searches the RIO switch ops table for known switch types. If the vid
+ * and did match a switch table entry, then call switch initialization
+ * routine to setup switch-specific routines.
  */
-static void rio_route_set_ops(struct rio_dev *rdev)
+static void rio_switch_init(struct rio_dev *rdev, int do_enum)
 {
-       struct rio_route_ops *cur = __start_rio_route_ops;
-       struct rio_route_ops *end = __end_rio_route_ops;
+       struct rio_switch_ops *cur = __start_rio_switch_ops;
+       struct rio_switch_ops *end = __end_rio_switch_ops;
 
        while (cur < end) {
                if ((cur->vid == rdev->vid) && (cur->did == rdev->did)) {
-                       pr_debug("RIO: adding routing ops for %s\n", rio_name(rdev));
-                       rdev->rswitch->add_entry = cur->add_hook;
-                       rdev->rswitch->get_entry = cur->get_hook;
+                       pr_debug("RIO: calling init routine for %s\n",
+                                rio_name(rdev));
+                       cur->init_hook(rdev, do_enum);
+                       break;
                }
                cur++;
        }
 
+       if ((cur >= end) && (rdev->pef & RIO_PEF_STD_RT)) {
+               pr_debug("RIO: adding STD routing ops for %s\n",
+                       rio_name(rdev));
+               rdev->rswitch->add_entry = rio_std_route_add_entry;
+               rdev->rswitch->get_entry = rio_std_route_get_entry;
+               rdev->rswitch->clr_table = rio_std_route_clr_table;
+       }
+
        if (!rdev->rswitch->add_entry || !rdev->rswitch->get_entry)
                printk(KERN_ERR "RIO: missing routing ops for %s\n",
                       rio_name(rdev));
@@ -280,6 +307,65 @@ static int __devinit rio_add_device(struct rio_dev *rdev)
        return 0;
 }
 
+/**
+ * rio_enable_rx_tx_port - enable input reciever and output transmitter of
+ * given port
+ * @port: Master port associated with the RIO network
+ * @local: local=1 select local port otherwise a far device is reached
+ * @destid: Destination ID of the device to check host bit
+ * @hopcount: Number of hops to reach the target
+ * @port_num: Port (-number on switch) to enable on a far end device
+ *
+ * Returns 0 or 1 from on General Control Command and Status Register
+ * (EXT_PTR+0x3C)
+ */
+inline int rio_enable_rx_tx_port(struct rio_mport *port,
+                                int local, u16 destid,
+                                u8 hopcount, u8 port_num) {
+#ifdef CONFIG_RAPIDIO_ENABLE_RX_TX_PORTS
+       u32 regval;
+       u32 ext_ftr_ptr;
+
+       /*
+       * enable rx input tx output port
+       */
+       pr_debug("rio_enable_rx_tx_port(local = %d, destid = %d, hopcount = "
+                "%d, port_num = %d)\n", local, destid, hopcount, port_num);
+
+       ext_ftr_ptr = rio_mport_get_physefb(port, local, destid, hopcount);
+
+       if (local) {
+               rio_local_read_config_32(port, ext_ftr_ptr +
+                               RIO_PORT_N_CTL_CSR(0),
+                               &regval);
+       } else {
+               if (rio_mport_read_config_32(port, destid, hopcount,
+               ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num), &regval) < 0)
+                       return -EIO;
+       }
+
+       if (regval & RIO_PORT_N_CTL_P_TYP_SER) {
+               /* serial */
+               regval = regval | RIO_PORT_N_CTL_EN_RX_SER
+                               | RIO_PORT_N_CTL_EN_TX_SER;
+       } else {
+               /* parallel */
+               regval = regval | RIO_PORT_N_CTL_EN_RX_PAR
+                               | RIO_PORT_N_CTL_EN_TX_PAR;
+       }
+
+       if (local) {
+               rio_local_write_config_32(port, ext_ftr_ptr +
+                                         RIO_PORT_N_CTL_CSR(0), regval);
+       } else {
+               if (rio_mport_write_config_32(port, destid, hopcount,
+                   ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num), regval) < 0)
+                       return -EIO;
+       }
+#endif
+       return 0;
+}
+
 /**
  * rio_setup_device- Allocates and sets up a RIO device
  * @net: RIO network
@@ -325,8 +411,14 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
        rdev->asm_rev = result >> 16;
        rio_mport_read_config_32(port, destid, hopcount, RIO_PEF_CAR,
                                 &rdev->pef);
-       if (rdev->pef & RIO_PEF_EXT_FEATURES)
+       if (rdev->pef & RIO_PEF_EXT_FEATURES) {
                rdev->efptr = result & 0xffff;
+               rdev->phys_efptr = rio_mport_get_physefb(port, 0, destid,
+                                                        hopcount);
+
+               rdev->em_efptr = rio_mport_get_feature(port, 0, destid,
+                                               hopcount, RIO_EFB_ERR_MGMNT);
+       }
 
        rio_mport_read_config_32(port, destid, hopcount, RIO_SRC_OPS_CAR,
                                 &rdev->src_ops);
@@ -349,12 +441,13 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
        if (rio_is_switch(rdev)) {
                rio_mport_read_config_32(port, destid, hopcount,
                                         RIO_SWP_INFO_CAR, &rdev->swpinfo);
-               rswitch = kmalloc(sizeof(struct rio_switch), GFP_KERNEL);
+               rswitch = kzalloc(sizeof(struct rio_switch), GFP_KERNEL);
                if (!rswitch)
                        goto cleanup;
                rswitch->switchid = next_switchid;
                rswitch->hopcount = hopcount;
                rswitch->destid = destid;
+               rswitch->port_ok = 0;
                rswitch->route_table = kzalloc(sizeof(u8)*
                                        RIO_MAX_ROUTE_ENTRIES(port->sys_size),
                                        GFP_KERNEL);
@@ -367,13 +460,22 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
                rdev->rswitch = rswitch;
                dev_set_name(&rdev->dev, "%02x:s:%04x", rdev->net->id,
                             rdev->rswitch->switchid);
-               rio_route_set_ops(rdev);
+               rio_switch_init(rdev, do_enum);
+
+               if (do_enum && rdev->rswitch->clr_table)
+                       rdev->rswitch->clr_table(port, destid, hopcount,
+                                                RIO_GLOBAL_TABLE);
 
                list_add_tail(&rswitch->node, &rio_switches);
 
-       } else
+       } else {
+               if (do_enum)
+                       /*Enable Input Output Port (transmitter reviever)*/
+                       rio_enable_rx_tx_port(port, 0, destid, hopcount, 0);
+
                dev_set_name(&rdev->dev, "%02x:e:%04x", rdev->net->id,
                             rdev->destid);
+       }
 
        rdev->dev.bus = &rio_bus_type;
 
@@ -414,23 +516,29 @@ cleanup:
  *
  * Reads the port error status CSR for a particular switch port to
  * determine if the port has an active link.  Returns
- * %PORT_N_ERR_STS_PORT_OK if the port is active or %0 if it is
+ * %RIO_PORT_N_ERR_STS_PORT_OK if the port is active or %0 if it is
  * inactive.
  */
 static int
 rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport)
 {
-       u32 result;
+       u32 result = 0;
        u32 ext_ftr_ptr;
 
-       int *entry = rio_sport_phys_table;
-
-       do {
-               if ((ext_ftr_ptr =
-                    rio_mport_get_feature(port, 0, destid, hopcount, *entry)))
+       ext_ftr_ptr = rio_mport_get_efb(port, 0, destid, hopcount, 0);
 
+       while (ext_ftr_ptr) {
+               rio_mport_read_config_32(port, destid, hopcount,
+                                        ext_ftr_ptr, &result);
+               result = RIO_GET_BLOCK_ID(result);
+               if ((result == RIO_EFB_SER_EP_FREE_ID) ||
+                   (result == RIO_EFB_SER_EP_FREE_ID_V13P) ||
+                   (result == RIO_EFB_SER_EP_FREC_ID))
                        break;
-       } while (*++entry >= 0);
+
+               ext_ftr_ptr = rio_mport_get_efb(port, 0, destid, hopcount,
+                                               ext_ftr_ptr);
+       }
 
        if (ext_ftr_ptr)
                rio_mport_read_config_32(port, destid, hopcount,
@@ -438,7 +546,81 @@ rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport)
                                         RIO_PORT_N_ERR_STS_CSR(sport),
                                         &result);
 
-       return (result & PORT_N_ERR_STS_PORT_OK);
+       return result & RIO_PORT_N_ERR_STS_PORT_OK;
+}
+
+/**
+ * rio_lock_device - Acquires host device lock for specified device
+ * @port: Master port to send transaction
+ * @destid: Destination ID for device/switch
+ * @hopcount: Hopcount to reach switch
+ * @wait_ms: Max wait time in msec (0 = no timeout)
+ *
+ * Attepts to acquire host device lock for specified device
+ * Returns 0 if device lock acquired or EINVAL if timeout expires.
+ */
+static int
+rio_lock_device(struct rio_mport *port, u16 destid, u8 hopcount, int wait_ms)
+{
+       u32 result;
+       int tcnt = 0;
+
+       /* Attempt to acquire device lock */
+       rio_mport_write_config_32(port, destid, hopcount,
+                                 RIO_HOST_DID_LOCK_CSR, port->host_deviceid);
+       rio_mport_read_config_32(port, destid, hopcount,
+                                RIO_HOST_DID_LOCK_CSR, &result);
+
+       while (result != port->host_deviceid) {
+               if (wait_ms != 0 && tcnt == wait_ms) {
+                       pr_debug("RIO: timeout when locking device %x:%x\n",
+                               destid, hopcount);
+                       return -EINVAL;
+               }
+
+               /* Delay a bit */
+               mdelay(1);
+               tcnt++;
+               /* Try to acquire device lock again */
+               rio_mport_write_config_32(port, destid,
+                       hopcount,
+                       RIO_HOST_DID_LOCK_CSR,
+                       port->host_deviceid);
+               rio_mport_read_config_32(port, destid,
+                       hopcount,
+                       RIO_HOST_DID_LOCK_CSR, &result);
+       }
+
+       return 0;
+}
+
+/**
+ * rio_unlock_device - Releases host device lock for specified device
+ * @port: Master port to send transaction
+ * @destid: Destination ID for device/switch
+ * @hopcount: Hopcount to reach switch
+ *
+ * Returns 0 if device lock released or EINVAL if fails.
+ */
+static int
+rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount)
+{
+       u32 result;
+
+       /* Release device lock */
+       rio_mport_write_config_32(port, destid,
+                                 hopcount,
+                                 RIO_HOST_DID_LOCK_CSR,
+                                 port->host_deviceid);
+       rio_mport_read_config_32(port, destid, hopcount,
+               RIO_HOST_DID_LOCK_CSR, &result);
+       if ((result & 0xffff) != 0xffff) {
+               pr_debug("RIO: badness when releasing device lock %x:%x\n",
+                        destid, hopcount);
+               return -EINVAL;
+       }
+
+       return 0;
 }
 
 /**
@@ -448,6 +630,7 @@ rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport)
  * @table: Routing table ID
  * @route_destid: Destination ID to be routed
  * @route_port: Port number to be routed
+ * @lock: lock switch device flag
  *
  * Calls the switch specific add_entry() method to add a route entry
  * on a switch. The route table can be specified using the @table
@@ -456,12 +639,26 @@ rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport)
  * %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL
  * on failure.
  */
-static int rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswitch,
-                              u16 table, u16 route_destid, u8 route_port)
+static int
+rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswitch,
+                   u16 table, u16 route_destid, u8 route_port, int lock)
 {
-       return rswitch->add_entry(mport, rswitch->destid,
+       int rc;
+
+       if (lock) {
+               rc = rio_lock_device(mport, rswitch->destid,
+                                    rswitch->hopcount, 1000);
+               if (rc)
+                       return rc;
+       }
+
+       rc = rswitch->add_entry(mport, rswitch->destid,
                                        rswitch->hopcount, table,
                                        route_destid, route_port);
+       if (lock)
+               rio_unlock_device(mport, rswitch->destid, rswitch->hopcount);
+
+       return rc;
 }
 
 /**
@@ -471,6 +668,7 @@ static int rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswit
  * @table: Routing table ID
  * @route_destid: Destination ID to be routed
  * @route_port: Pointer to read port number into
+ * @lock: lock switch device flag
  *
  * Calls the switch specific get_entry() method to read a route entry
  * in a switch. The route table can be specified using the @table
@@ -481,11 +679,24 @@ static int rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswit
  */
 static int
 rio_route_get_entry(struct rio_mport *mport, struct rio_switch *rswitch, u16 table,
-                   u16 route_destid, u8 * route_port)
+                   u16 route_destid, u8 *route_port, int lock)
 {
-       return rswitch->get_entry(mport, rswitch->destid,
+       int rc;
+
+       if (lock) {
+               rc = rio_lock_device(mport, rswitch->destid,
+                                    rswitch->hopcount, 1000);
+               if (rc)
+                       return rc;
+       }
+
+       rc = rswitch->get_entry(mport, rswitch->destid,
                                        rswitch->hopcount, table,
                                        route_destid, route_port);
+       if (lock)
+               rio_unlock_device(mport, rswitch->destid, rswitch->hopcount);
+
+       return rc;
 }
 
 /**
@@ -625,14 +836,14 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
                sw_inport = rio_get_swpinfo_inport(port,
                                RIO_ANY_DESTID(port->sys_size), hopcount);
                rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE,
-                                   port->host_deviceid, sw_inport);
+                                   port->host_deviceid, sw_inport, 0);
                rdev->rswitch->route_table[port->host_deviceid] = sw_inport;
 
                for (destid = 0; destid < next_destid; destid++) {
                        if (destid == port->host_deviceid)
                                continue;
                        rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE,
-                                           destid, sw_inport);
+                                           destid, sw_inport, 0);
                        rdev->rswitch->route_table[destid] = sw_inport;
                }
 
@@ -644,8 +855,15 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
                    rio_name(rdev), rdev->vid, rdev->did, num_ports);
                sw_destid = next_destid;
                for (port_num = 0; port_num < num_ports; port_num++) {
-                       if (sw_inport == port_num)
+                       /*Enable Input Output Port (transmitter reviever)*/
+                       rio_enable_rx_tx_port(port, 0,
+                                             RIO_ANY_DESTID(port->sys_size),
+                                             hopcount, port_num);
+
+                       if (sw_inport == port_num) {
+                               rdev->rswitch->port_ok |= (1 << port_num);
                                continue;
+                       }
 
                        cur_destid = next_destid;
 
@@ -655,10 +873,11 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
                                pr_debug(
                                    "RIO: scanning device on port %d\n",
                                    port_num);
+                               rdev->rswitch->port_ok |= (1 << port_num);
                                rio_route_add_entry(port, rdev->rswitch,
                                                RIO_GLOBAL_TABLE,
                                                RIO_ANY_DESTID(port->sys_size),
-                                               port_num);
+                                               port_num, 0);
 
                                if (rio_enum_peer(net, port, hopcount + 1) < 0)
                                        return -1;
@@ -672,15 +891,35 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
                                                rio_route_add_entry(port, rdev->rswitch,
                                                                    RIO_GLOBAL_TABLE,
                                                                    destid,
-                                                                   port_num);
+                                                                   port_num,
+                                                                   0);
                                                rdev->rswitch->
                                                    route_table[destid] =
                                                    port_num;
                                        }
                                }
+                       } else {
+                               /* If switch supports Error Management,
+                                * set PORT_LOCKOUT bit for unused port
+                                */
+                               if (rdev->em_efptr)
+                                       rio_set_port_lockout(rdev, port_num, 1);
+
+                               rdev->rswitch->port_ok &= ~(1 << port_num);
                        }
                }
 
+               /* Direct Port-write messages to the enumeratiing host */
+               if ((rdev->src_ops & RIO_SRC_OPS_PORT_WRITE) &&
+                   (rdev->em_efptr)) {
+                       rio_write_config_32(rdev,
+                                       rdev->em_efptr + RIO_EM_PW_TGT_DEVID,
+                                       (port->host_deviceid << 16) |
+                                       (port->sys_size << 15));
+               }
+
+               rio_init_em(rdev);
+
                /* Check for empty switch */
                if (next_destid == sw_destid) {
                        next_destid++;
@@ -700,21 +939,16 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
  * rio_enum_complete- Tests if enumeration of a network is complete
  * @port: Master port to send transaction
  *
- * Tests the Component Tag CSR for presence of the magic enumeration
- * complete flag. Return %1 if enumeration is complete or %0 if
+ * Tests the Component Tag CSR for non-zero value (enumeration
+ * complete flag). Return %1 if enumeration is complete or %0 if
  * enumeration is incomplete.
  */
 static int rio_enum_complete(struct rio_mport *port)
 {
        u32 tag_csr;
-       int ret = 0;
 
        rio_local_read_config_32(port, RIO_COMPONENT_TAG_CSR, &tag_csr);
-
-       if (tag_csr == RIO_ENUM_CMPL_MAGIC)
-               ret = 1;
-
-       return ret;
+       return (tag_csr & 0xffff) ? 1 : 0;
 }
 
 /**
@@ -763,17 +997,21 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid,
                                pr_debug(
                                    "RIO: scanning device on port %d\n",
                                    port_num);
+
+                               rio_lock_device(port, destid, hopcount, 1000);
+
                                for (ndestid = 0;
                                     ndestid < RIO_ANY_DESTID(port->sys_size);
                                     ndestid++) {
                                        rio_route_get_entry(port, rdev->rswitch,
                                                            RIO_GLOBAL_TABLE,
                                                            ndestid,
-                                                           &route_port);
+                                                           &route_port, 0);
                                        if (route_port == port_num)
                                                break;
                                }
 
+                               rio_unlock_device(port, destid, hopcount);
                                if (rio_disc_peer
                                    (net, port, ndestid, hopcount + 1) < 0)
                                        return -1;
@@ -792,7 +1030,7 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid,
  *
  * Reads the port error status CSR for the master port to
  * determine if the port has an active link.  Returns
- * %PORT_N_ERR_STS_PORT_OK if the  master port is active
+ * %RIO_PORT_N_ERR_STS_PORT_OK if the  master port is active
  * or %0 if it is inactive.
  */
 static int rio_mport_is_active(struct rio_mport *port)
@@ -813,7 +1051,7 @@ static int rio_mport_is_active(struct rio_mport *port)
                                         RIO_PORT_N_ERR_STS_CSR(port->index),
                                         &result);
 
-       return (result & PORT_N_ERR_STS_PORT_OK);
+       return result & RIO_PORT_N_ERR_STS_PORT_OK;
 }
 
 /**
@@ -866,12 +1104,17 @@ static void rio_update_route_tables(struct rio_mport *port)
                                continue;
 
                        if (RIO_INVALID_ROUTE == rswitch->route_table[destid]) {
+                               /* Skip if destid ends in empty switch*/
+                               if (rswitch->destid == destid)
+                                       continue;
 
                                sport = rio_get_swpinfo_inport(port,
                                                rswitch->destid, rswitch->hopcount);
 
                                if (rswitch->add_entry) {
-                                       rio_route_add_entry(port, rswitch, RIO_GLOBAL_TABLE, destid, sport);
+                                       rio_route_add_entry(port, rswitch,
+                                               RIO_GLOBAL_TABLE, destid,
+                                               sport, 0);
                                        rswitch->route_table[destid] = sport;
                                }
                        }
@@ -879,6 +1122,32 @@ static void rio_update_route_tables(struct rio_mport *port)
        }
 }
 
+/**
+ * rio_init_em - Initializes RIO Error Management (for switches)
+ * @rdev: RIO device
+ *
+ * For each enumerated switch, call device-specific error management
+ * initialization routine (if supplied by the switch driver).
+ */
+static void rio_init_em(struct rio_dev *rdev)
+{
+       if (rio_is_switch(rdev) && (rdev->em_efptr) &&
+           (rdev->rswitch->em_init)) {
+               rdev->rswitch->em_init(rdev);
+       }
+}
+
+/**
+ * rio_pw_enable - Enables/disables port-write handling by a master port
+ * @port: Master port associated with port-write handling
+ * @enable:  1=enable,  0=disable
+ */
+static void rio_pw_enable(struct rio_mport *port, int enable)
+{
+       if (port->ops->pwenable)
+               port->ops->pwenable(port, enable);
+}
+
 /**
  * rio_enum_mport- Start enumeration through a master port
  * @mport: Master port to send transactions
@@ -911,6 +1180,10 @@ int __devinit rio_enum_mport(struct rio_mport *mport)
                        rc = -ENOMEM;
                        goto out;
                }
+
+               /* Enable Input Output Port (transmitter reviever) */
+               rio_enable_rx_tx_port(mport, 1, 0, 0, 0);
+
                if (rio_enum_peer(net, mport, 0) < 0) {
                        /* A higher priority host won enumeration, bail. */
                        printk(KERN_INFO
@@ -922,6 +1195,7 @@ int __devinit rio_enum_mport(struct rio_mport *mport)
                }
                rio_update_route_tables(mport);
                rio_clear_locks(mport);
+               rio_pw_enable(mport, 1);
        } else {
                printk(KERN_INFO "RIO: master port %d link inactive\n",
                       mport->id);
@@ -945,15 +1219,22 @@ static void rio_build_route_tables(void)
        u8 sport;
 
        list_for_each_entry(rdev, &rio_devices, global_list)
-           if (rio_is_switch(rdev))
-               for (i = 0;
-                    i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size);
-                    i++) {
-                       if (rio_route_get_entry
-                           (rdev->net->hport, rdev->rswitch, RIO_GLOBAL_TABLE,
-                            i, &sport) < 0)
-                               continue;
-                       rdev->rswitch->route_table[i] = sport;
+               if (rio_is_switch(rdev)) {
+                       rio_lock_device(rdev->net->hport, rdev->rswitch->destid,
+                                       rdev->rswitch->hopcount, 1000);
+                       for (i = 0;
+                            i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size);
+                            i++) {
+                               if (rio_route_get_entry
+                                   (rdev->net->hport, rdev->rswitch,
+                                    RIO_GLOBAL_TABLE, i, &sport, 0) < 0)
+                                       continue;
+                               rdev->rswitch->route_table[i] = sport;
+                       }
+
+                       rio_unlock_device(rdev->net->hport,
+                                         rdev->rswitch->destid,
+                                         rdev->rswitch->hopcount);
                }
 }
 
@@ -1012,6 +1293,13 @@ int __devinit rio_disc_mport(struct rio_mport *mport)
                del_timer_sync(&rio_enum_timer);
 
                pr_debug("done\n");
+
+               /* Read DestID assigned by enumerator */
+               rio_local_read_config_32(mport, RIO_DID_CSR,
+                                        &mport->host_deviceid);
+               mport->host_deviceid = RIO_GET_DID(mport->sys_size,
+                                                  mport->host_deviceid);
+
                if (rio_disc_peer(net, mport, RIO_ANY_DESTID(mport->sys_size),
                                        0) < 0) {
                        printk(KERN_INFO
index 6395c780008ba83534849cb47cd41267f4b63933..08fa453af9746a55302108bc3c0b2988cf66bded 100644 (file)
@@ -5,6 +5,10 @@
  * Copyright 2005 MontaVista Software, Inc.
  * Matt Porter <mporter@kernel.crashing.org>
  *
+ * Copyright 2009 Integrated Device Technology, Inc.
+ * Alex Bounine <alexandre.bounine@idt.com>
+ * - Added Port-Write/Error Management initialization and handling
+ *
  * 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
@@ -332,6 +336,331 @@ int rio_release_outb_dbell(struct rio_dev *rdev, struct resource *res)
        return rc;
 }
 
+/**
+ * rio_request_inb_pwrite - request inbound port-write message service
+ * @rdev: RIO device to which register inbound port-write callback routine
+ * @pwcback: Callback routine to execute when port-write is received
+ *
+ * Binds a port-write callback function to the RapidIO device.
+ * Returns 0 if the request has been satisfied.
+ */
+int rio_request_inb_pwrite(struct rio_dev *rdev,
+       int (*pwcback)(struct rio_dev *rdev, union rio_pw_msg *msg, int step))
+{
+       int rc = 0;
+
+       spin_lock(&rio_global_list_lock);
+       if (rdev->pwcback != NULL)
+               rc = -ENOMEM;
+       else
+               rdev->pwcback = pwcback;
+
+       spin_unlock(&rio_global_list_lock);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(rio_request_inb_pwrite);
+
+/**
+ * rio_release_inb_pwrite - release inbound port-write message service
+ * @rdev: RIO device which registered for inbound port-write callback
+ *
+ * Removes callback from the rio_dev structure. Returns 0 if the request
+ * has been satisfied.
+ */
+int rio_release_inb_pwrite(struct rio_dev *rdev)
+{
+       int rc = -ENOMEM;
+
+       spin_lock(&rio_global_list_lock);
+       if (rdev->pwcback) {
+               rdev->pwcback = NULL;
+               rc = 0;
+       }
+
+       spin_unlock(&rio_global_list_lock);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(rio_release_inb_pwrite);
+
+/**
+ * rio_mport_get_physefb - Helper function that returns register offset
+ *                      for Physical Layer Extended Features Block.
+ * @port: Master port to issue transaction
+ * @local: Indicate a local master port or remote device access
+ * @destid: Destination ID of the device
+ * @hopcount: Number of switch hops to the device
+ */
+u32
+rio_mport_get_physefb(struct rio_mport *port, int local,
+                     u16 destid, u8 hopcount)
+{
+       u32 ext_ftr_ptr;
+       u32 ftr_header;
+
+       ext_ftr_ptr = rio_mport_get_efb(port, local, destid, hopcount, 0);
+
+       while (ext_ftr_ptr)  {
+               if (local)
+                       rio_local_read_config_32(port, ext_ftr_ptr,
+                                                &ftr_header);
+               else
+                       rio_mport_read_config_32(port, destid, hopcount,
+                                                ext_ftr_ptr, &ftr_header);
+
+               ftr_header = RIO_GET_BLOCK_ID(ftr_header);
+               switch (ftr_header) {
+
+               case RIO_EFB_SER_EP_ID_V13P:
+               case RIO_EFB_SER_EP_REC_ID_V13P:
+               case RIO_EFB_SER_EP_FREE_ID_V13P:
+               case RIO_EFB_SER_EP_ID:
+               case RIO_EFB_SER_EP_REC_ID:
+               case RIO_EFB_SER_EP_FREE_ID:
+               case RIO_EFB_SER_EP_FREC_ID:
+
+                       return ext_ftr_ptr;
+
+               default:
+                       break;
+               }
+
+               ext_ftr_ptr = rio_mport_get_efb(port, local, destid,
+                                               hopcount, ext_ftr_ptr);
+       }
+
+       return ext_ftr_ptr;
+}
+
+/**
+ * rio_get_comptag - Begin or continue searching for a RIO device by component tag
+ * @comp_tag: RIO component tag to match
+ * @from: Previous RIO device found in search, or %NULL for new search
+ *
+ * Iterates through the list of known RIO devices. If a RIO device is
+ * found with a matching @comp_tag, a pointer to its device
+ * structure is returned. Otherwise, %NULL is returned. A new search
+ * is initiated by passing %NULL to the @from argument. Otherwise, if
+ * @from is not %NULL, searches continue from next device on the global
+ * list.
+ */
+static struct rio_dev *rio_get_comptag(u32 comp_tag, struct rio_dev *from)
+{
+       struct list_head *n;
+       struct rio_dev *rdev;
+
+       spin_lock(&rio_global_list_lock);
+       n = from ? from->global_list.next : rio_devices.next;
+
+       while (n && (n != &rio_devices)) {
+               rdev = rio_dev_g(n);
+               if (rdev->comp_tag == comp_tag)
+                       goto exit;
+               n = n->next;
+       }
+       rdev = NULL;
+exit:
+       spin_unlock(&rio_global_list_lock);
+       return rdev;
+}
+
+/**
+ * rio_set_port_lockout - Sets/clears LOCKOUT bit (RIO EM 1.3) for a switch port.
+ * @rdev: Pointer to RIO device control structure
+ * @pnum: Switch port number to set LOCKOUT bit
+ * @lock: Operation : set (=1) or clear (=0)
+ */
+int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock)
+{
+       u8 hopcount = 0xff;
+       u16 destid = rdev->destid;
+       u32 regval;
+
+       if (rdev->rswitch) {
+               destid = rdev->rswitch->destid;
+               hopcount = rdev->rswitch->hopcount;
+       }
+
+       rio_mport_read_config_32(rdev->net->hport, destid, hopcount,
+                                rdev->phys_efptr + RIO_PORT_N_CTL_CSR(pnum),
+                                &regval);
+       if (lock)
+               regval |= RIO_PORT_N_CTL_LOCKOUT;
+       else
+               regval &= ~RIO_PORT_N_CTL_LOCKOUT;
+
+       rio_mport_write_config_32(rdev->net->hport, destid, hopcount,
+                                 rdev->phys_efptr + RIO_PORT_N_CTL_CSR(pnum),
+                                 regval);
+       return 0;
+}
+
+/**
+ * rio_inb_pwrite_handler - process inbound port-write message
+ * @pw_msg: pointer to inbound port-write message
+ *
+ * Processes an inbound port-write message. Returns 0 if the request
+ * has been satisfied.
+ */
+int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg)
+{
+       struct rio_dev *rdev;
+       struct rio_mport *mport;
+       u8 hopcount;
+       u16 destid;
+       u32 err_status;
+       int rc, portnum;
+
+       rdev = rio_get_comptag(pw_msg->em.comptag, NULL);
+       if (rdev == NULL) {
+               /* Someting bad here (probably enumeration error) */
+               pr_err("RIO: %s No matching device for CTag 0x%08x\n",
+                       __func__, pw_msg->em.comptag);
+               return -EIO;
+       }
+
+       pr_debug("RIO: Port-Write message from %s\n", rio_name(rdev));
+
+#ifdef DEBUG_PW
+       {
+       u32 i;
+       for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32);) {
+                       pr_debug("0x%02x: %08x %08x %08x %08x",
+                                i*4, pw_msg->raw[i], pw_msg->raw[i + 1],
+                                pw_msg->raw[i + 2], pw_msg->raw[i + 3]);
+                       i += 4;
+       }
+       pr_debug("\n");
+       }
+#endif
+
+       /* Call an external service function (if such is registered
+        * for this device). This may be the service for endpoints that send
+        * device-specific port-write messages. End-point messages expected
+        * to be handled completely by EP specific device driver.
+        * For switches rc==0 signals that no standard processing required.
+        */
+       if (rdev->pwcback != NULL) {
+               rc = rdev->pwcback(rdev, pw_msg, 0);
+               if (rc == 0)
+                       return 0;
+       }
+
+       /* For End-point devices processing stops here */
+       if (!(rdev->pef & RIO_PEF_SWITCH))
+               return 0;
+
+       if (rdev->phys_efptr == 0) {
+               pr_err("RIO_PW: Bad switch initialization for %s\n",
+                       rio_name(rdev));
+               return 0;
+       }
+
+       mport = rdev->net->hport;
+       destid = rdev->rswitch->destid;
+       hopcount = rdev->rswitch->hopcount;
+
+       /*
+        * Process the port-write notification from switch
+        */
+
+       portnum = pw_msg->em.is_port & 0xFF;
+
+       if (rdev->rswitch->em_handle)
+               rdev->rswitch->em_handle(rdev, portnum);
+
+       rio_mport_read_config_32(mport, destid, hopcount,
+                       rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum),
+                       &err_status);
+       pr_debug("RIO_PW: SP%d_ERR_STS_CSR=0x%08x\n", portnum, err_status);
+
+       if (pw_msg->em.errdetect) {
+               pr_debug("RIO_PW: RIO_EM_P%d_ERR_DETECT=0x%08x\n",
+                        portnum, pw_msg->em.errdetect);
+               /* Clear EM Port N Error Detect CSR */
+               rio_mport_write_config_32(mport, destid, hopcount,
+                       rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), 0);
+       }
+
+       if (pw_msg->em.ltlerrdet) {
+               pr_debug("RIO_PW: RIO_EM_LTL_ERR_DETECT=0x%08x\n",
+                        pw_msg->em.ltlerrdet);
+               /* Clear EM L/T Layer Error Detect CSR */
+               rio_mport_write_config_32(mport, destid, hopcount,
+                       rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, 0);
+       }
+
+       /* Clear Port Errors */
+       rio_mport_write_config_32(mport, destid, hopcount,
+                       rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum),
+                       err_status & RIO_PORT_N_ERR_STS_CLR_MASK);
+
+       if (rdev->rswitch->port_ok & (1 << portnum)) {
+               if (err_status & RIO_PORT_N_ERR_STS_PORT_UNINIT) {
+                       rdev->rswitch->port_ok &= ~(1 << portnum);
+                       rio_set_port_lockout(rdev, portnum, 1);
+
+                       rio_mport_write_config_32(mport, destid, hopcount,
+                               rdev->phys_efptr +
+                                       RIO_PORT_N_ACK_STS_CSR(portnum),
+                               RIO_PORT_N_ACK_CLEAR);
+
+                       /* Schedule Extraction Service */
+                       pr_debug("RIO_PW: Device Extraction on [%s]-P%d\n",
+                              rio_name(rdev), portnum);
+               }
+       } else {
+               if (err_status & RIO_PORT_N_ERR_STS_PORT_OK) {
+                       rdev->rswitch->port_ok |= (1 << portnum);
+                       rio_set_port_lockout(rdev, portnum, 0);
+
+                       /* Schedule Insertion Service */
+                       pr_debug("RIO_PW: Device Insertion on [%s]-P%d\n",
+                              rio_name(rdev), portnum);
+               }
+       }
+
+       /* Clear Port-Write Pending bit */
+       rio_mport_write_config_32(mport, destid, hopcount,
+                       rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum),
+                       RIO_PORT_N_ERR_STS_PW_PEND);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rio_inb_pwrite_handler);
+
+/**
+ * rio_mport_get_efb - get pointer to next extended features block
+ * @port: Master port to issue transaction
+ * @local: Indicate a local master port or remote device access
+ * @destid: Destination ID of the device
+ * @hopcount: Number of switch hops to the device
+ * @from: Offset of  current Extended Feature block header (if 0 starts
+ * from        ExtFeaturePtr)
+ */
+u32
+rio_mport_get_efb(struct rio_mport *port, int local, u16 destid,
+                     u8 hopcount, u32 from)
+{
+       u32 reg_val;
+
+       if (from == 0) {
+               if (local)
+                       rio_local_read_config_32(port, RIO_ASM_INFO_CAR,
+                                                &reg_val);
+               else
+                       rio_mport_read_config_32(port, destid, hopcount,
+                                                RIO_ASM_INFO_CAR, &reg_val);
+               return reg_val & RIO_EXT_FTR_PTR_MASK;
+       } else {
+               if (local)
+                       rio_local_read_config_32(port, from, &reg_val);
+               else
+                       rio_mport_read_config_32(port, destid, hopcount,
+                                                from, &reg_val);
+               return RIO_GET_BLOCK_ID(reg_val);
+       }
+}
+
 /**
  * rio_mport_get_feature - query for devices' extended features
  * @port: Master port to issue transaction
@@ -451,6 +780,110 @@ struct rio_dev *rio_get_device(u16 vid, u16 did, struct rio_dev *from)
        return rio_get_asm(vid, did, RIO_ANY_ID, RIO_ANY_ID, from);
 }
 
+/**
+ * rio_std_route_add_entry - Add switch route table entry using standard
+ *   registers defined in RIO specification rev.1.3
+ * @mport: Master port to issue transaction
+ * @destid: Destination ID of the device
+ * @hopcount: Number of switch hops to the device
+ * @table: routing table ID (global or port-specific)
+ * @route_destid: destID entry in the RT
+ * @route_port: destination port for specified destID
+ */
+int rio_std_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u16 table, u16 route_destid, u8 route_port)
+{
+       if (table == RIO_GLOBAL_TABLE) {
+               rio_mport_write_config_32(mport, destid, hopcount,
+                               RIO_STD_RTE_CONF_DESTID_SEL_CSR,
+                               (u32)route_destid);
+               rio_mport_write_config_32(mport, destid, hopcount,
+                               RIO_STD_RTE_CONF_PORT_SEL_CSR,
+                               (u32)route_port);
+       }
+
+       udelay(10);
+       return 0;
+}
+
+/**
+ * rio_std_route_get_entry - Read switch route table entry (port number)
+ *   assosiated with specified destID using standard registers defined in RIO
+ *   specification rev.1.3
+ * @mport: Master port to issue transaction
+ * @destid: Destination ID of the device
+ * @hopcount: Number of switch hops to the device
+ * @table: routing table ID (global or port-specific)
+ * @route_destid: destID entry in the RT
+ * @route_port: returned destination port for specified destID
+ */
+int rio_std_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u16 table, u16 route_destid, u8 *route_port)
+{
+       u32 result;
+
+       if (table == RIO_GLOBAL_TABLE) {
+               rio_mport_write_config_32(mport, destid, hopcount,
+                               RIO_STD_RTE_CONF_DESTID_SEL_CSR, route_destid);
+               rio_mport_read_config_32(mport, destid, hopcount,
+                               RIO_STD_RTE_CONF_PORT_SEL_CSR, &result);
+
+               *route_port = (u8)result;
+       }
+
+       return 0;
+}
+
+/**
+ * rio_std_route_clr_table - Clear swotch route table using standard registers
+ *   defined in RIO specification rev.1.3.
+ * @mport: Master port to issue transaction
+ * @destid: Destination ID of the device
+ * @hopcount: Number of switch hops to the device
+ * @table: routing table ID (global or port-specific)
+ */
+int rio_std_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u16 table)
+{
+       u32 max_destid = 0xff;
+       u32 i, pef, id_inc = 1, ext_cfg = 0;
+       u32 port_sel = RIO_INVALID_ROUTE;
+
+       if (table == RIO_GLOBAL_TABLE) {
+               rio_mport_read_config_32(mport, destid, hopcount,
+                                        RIO_PEF_CAR, &pef);
+
+               if (mport->sys_size) {
+                       rio_mport_read_config_32(mport, destid, hopcount,
+                                                RIO_SWITCH_RT_LIMIT,
+                                                &max_destid);
+                       max_destid &= RIO_RT_MAX_DESTID;
+               }
+
+               if (pef & RIO_PEF_EXT_RT) {
+                       ext_cfg = 0x80000000;
+                       id_inc = 4;
+                       port_sel = (RIO_INVALID_ROUTE << 24) |
+                                  (RIO_INVALID_ROUTE << 16) |
+                                  (RIO_INVALID_ROUTE << 8) |
+                                  RIO_INVALID_ROUTE;
+               }
+
+               for (i = 0; i <= max_destid;) {
+                       rio_mport_write_config_32(mport, destid, hopcount,
+                                       RIO_STD_RTE_CONF_DESTID_SEL_CSR,
+                                       ext_cfg | i);
+                       rio_mport_write_config_32(mport, destid, hopcount,
+                                       RIO_STD_RTE_CONF_PORT_SEL_CSR,
+                                       port_sel);
+                       i += id_inc;
+               }
+       }
+
+       udelay(10);
+       return 0;
+}
+
 static void rio_fixup_device(struct rio_dev *dev)
 {
 }
index 7786d02581f2adf78dd086fec096e78beba41e43..f27b7a9c47d2c685269f847141e2fc64c3782e64 100644 (file)
 
 extern u32 rio_mport_get_feature(struct rio_mport *mport, int local, u16 destid,
                                 u8 hopcount, int ftr);
+extern u32 rio_mport_get_physefb(struct rio_mport *port, int local,
+                                u16 destid, u8 hopcount);
+extern u32 rio_mport_get_efb(struct rio_mport *port, int local, u16 destid,
+                            u8 hopcount, u32 from);
 extern int rio_create_sysfs_dev_files(struct rio_dev *rdev);
 extern int rio_enum_mport(struct rio_mport *mport);
 extern int rio_disc_mport(struct rio_mport *mport);
+extern int rio_std_route_add_entry(struct rio_mport *mport, u16 destid,
+                                  u8 hopcount, u16 table, u16 route_destid,
+                                  u8 route_port);
+extern int rio_std_route_get_entry(struct rio_mport *mport, u16 destid,
+                                  u8 hopcount, u16 table, u16 route_destid,
+                                  u8 *route_port);
+extern int rio_std_route_clr_table(struct rio_mport *mport, u16 destid,
+                                  u8 hopcount, u16 table);
+extern int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock);
 
 /* Structures internal to the RIO core code */
 extern struct device_attribute rio_dev_attrs[];
 extern spinlock_t rio_global_list_lock;
 
-extern struct rio_route_ops __start_rio_route_ops[];
-extern struct rio_route_ops __end_rio_route_ops[];
+extern struct rio_switch_ops __start_rio_switch_ops[];
+extern struct rio_switch_ops __end_rio_switch_ops[];
 
 /* Helpers internal to the RIO core code */
-#define DECLARE_RIO_ROUTE_SECTION(section, vid, did, add_hook, get_hook)  \
-       static struct rio_route_ops __rio_route_ops __used   \
-       __section(section)= { vid, did, add_hook, get_hook };
+#define DECLARE_RIO_SWITCH_SECTION(section, name, vid, did, init_hook) \
+       static const struct rio_switch_ops __rio_switch_##name __used \
+       __section(section) = { vid, did, init_hook };
 
 /**
- * DECLARE_RIO_ROUTE_OPS - Registers switch routing operations
+ * DECLARE_RIO_SWITCH_INIT - Registers switch initialization routine
  * @vid: RIO vendor ID
  * @did: RIO device ID
- * @add_hook: Callback that adds a route entry
- * @get_hook: Callback that gets a route entry
+ * @init_hook: Callback that performs switch-specific initialization
  *
- * Manipulating switch route tables in RIO is switch specific. This
- * registers a switch by vendor and device ID with two callbacks for
- * modifying and retrieving route entries in a switch. A &struct
- * rio_route_ops is initialized with the ops and placed into a
- * RIO-specific kernel section.
+ * Manipulating switch route tables and error management in RIO
+ * is switch specific. This registers a switch by vendor and device ID with
+ * initialization callback for setting up switch operations and (if required)
+ * hardware initialization. A &struct rio_switch_ops is initialized with
+ * pointer to the init routine and placed into a RIO-specific kernel section.
  */
-#define DECLARE_RIO_ROUTE_OPS(vid, did, add_hook, get_hook)            \
-       DECLARE_RIO_ROUTE_SECTION(.rio_route_ops,                       \
-                       vid, did, add_hook, get_hook)
+#define DECLARE_RIO_SWITCH_INIT(vid, did, init_hook)           \
+       DECLARE_RIO_SWITCH_SECTION(.rio_switch_ops, vid##did, \
+                       vid, did, init_hook)
 
 #define RIO_GET_DID(size, x)   (size ? (x & 0xffff) : ((x & 0x00ff0000) >> 16))
 #define RIO_SET_DID(size, x)   (size ? (x & 0xffff) : ((x & 0x000000ff) << 16))
diff --git a/drivers/rapidio/switches/Kconfig b/drivers/rapidio/switches/Kconfig
new file mode 100644 (file)
index 0000000..2b4e9b2
--- /dev/null
@@ -0,0 +1,28 @@
+#
+# RapidIO switches configuration
+#
+config RAPIDIO_TSI57X
+       bool "IDT Tsi57x SRIO switches support"
+       depends on RAPIDIO
+       ---help---
+         Includes support for IDT Tsi57x family of serial RapidIO switches.
+
+config RAPIDIO_CPS_XX
+       bool "IDT CPS-xx SRIO switches support"
+       depends on RAPIDIO
+       ---help---
+         Includes support for IDT CPS-16/12/10/8 serial RapidIO switches.
+
+config RAPIDIO_TSI568
+       bool "Tsi568 SRIO switch support"
+       depends on RAPIDIO
+       default n
+       ---help---
+         Includes support for IDT Tsi568 serial RapidIO switch.
+
+config RAPIDIO_TSI500
+       bool "Tsi500 Parallel RapidIO switch support"
+       depends on RAPIDIO
+       default n
+       ---help---
+         Includes support for IDT Tsi500 parallel RapidIO switch.
index b924f830176116169608c602f8509e85fce96ff3..fe4adc3e8d5f317ccfb08020c266138fc50d699f 100644 (file)
@@ -2,4 +2,11 @@
 # Makefile for RIO switches
 #
 
-obj-$(CONFIG_RAPIDIO)  += tsi500.o
+obj-$(CONFIG_RAPIDIO_TSI57X)   += tsi57x.o
+obj-$(CONFIG_RAPIDIO_CPS_XX)   += idtcps.o
+obj-$(CONFIG_RAPIDIO_TSI568)   += tsi568.o
+obj-$(CONFIG_RAPIDIO_TSI500)   += tsi500.o
+
+ifeq ($(CONFIG_RAPIDIO_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff --git a/drivers/rapidio/switches/idtcps.c b/drivers/rapidio/switches/idtcps.c
new file mode 100644 (file)
index 0000000..2c790c1
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * IDT CPS RapidIO switches support
+ *
+ * Copyright 2009-2010 Integrated Device Technology, Inc.
+ * Alexandre Bounine <alexandre.bounine@idt.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/rio.h>
+#include <linux/rio_drv.h>
+#include <linux/rio_ids.h>
+#include "../rio.h"
+
+#define CPS_DEFAULT_ROUTE      0xde
+#define CPS_NO_ROUTE           0xdf
+
+#define IDTCPS_RIO_DOMAIN 0xf20020
+
+static int
+idtcps_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u16 table, u16 route_destid, u8 route_port)
+{
+       u32 result;
+
+       if (table == RIO_GLOBAL_TABLE) {
+               rio_mport_write_config_32(mport, destid, hopcount,
+                               RIO_STD_RTE_CONF_DESTID_SEL_CSR, route_destid);
+
+               rio_mport_read_config_32(mport, destid, hopcount,
+                               RIO_STD_RTE_CONF_PORT_SEL_CSR, &result);
+
+               result = (0xffffff00 & result) | (u32)route_port;
+               rio_mport_write_config_32(mport, destid, hopcount,
+                               RIO_STD_RTE_CONF_PORT_SEL_CSR, result);
+       }
+
+       return 0;
+}
+
+static int
+idtcps_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u16 table, u16 route_destid, u8 *route_port)
+{
+       u32 result;
+
+       if (table == RIO_GLOBAL_TABLE) {
+               rio_mport_write_config_32(mport, destid, hopcount,
+                               RIO_STD_RTE_CONF_DESTID_SEL_CSR, route_destid);
+
+               rio_mport_read_config_32(mport, destid, hopcount,
+                               RIO_STD_RTE_CONF_PORT_SEL_CSR, &result);
+
+               if (CPS_DEFAULT_ROUTE == (u8)result ||
+                   CPS_NO_ROUTE == (u8)result)
+                       *route_port = RIO_INVALID_ROUTE;
+               else
+                       *route_port = (u8)result;
+       }
+
+       return 0;
+}
+
+static int
+idtcps_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u16 table)
+{
+       u32 i;
+
+       if (table == RIO_GLOBAL_TABLE) {
+               for (i = 0x80000000; i <= 0x800000ff;) {
+                       rio_mport_write_config_32(mport, destid, hopcount,
+                               RIO_STD_RTE_CONF_DESTID_SEL_CSR, i);
+                       rio_mport_write_config_32(mport, destid, hopcount,
+                               RIO_STD_RTE_CONF_PORT_SEL_CSR,
+                               (CPS_DEFAULT_ROUTE << 24) |
+                               (CPS_DEFAULT_ROUTE << 16) |
+                               (CPS_DEFAULT_ROUTE << 8) | CPS_DEFAULT_ROUTE);
+                       i += 4;
+               }
+       }
+
+       return 0;
+}
+
+static int
+idtcps_set_domain(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u8 sw_domain)
+{
+       /*
+        * Switch domain configuration operates only at global level
+        */
+       rio_mport_write_config_32(mport, destid, hopcount,
+                                 IDTCPS_RIO_DOMAIN, (u32)sw_domain);
+       return 0;
+}
+
+static int
+idtcps_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u8 *sw_domain)
+{
+       u32 regval;
+
+       /*
+        * Switch domain configuration operates only at global level
+        */
+       rio_mport_read_config_32(mport, destid, hopcount,
+                               IDTCPS_RIO_DOMAIN, &regval);
+
+       *sw_domain = (u8)(regval & 0xff);
+
+       return 0;
+}
+
+static int idtcps_switch_init(struct rio_dev *rdev, int do_enum)
+{
+       pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
+       rdev->rswitch->add_entry = idtcps_route_add_entry;
+       rdev->rswitch->get_entry = idtcps_route_get_entry;
+       rdev->rswitch->clr_table = idtcps_route_clr_table;
+       rdev->rswitch->set_domain = idtcps_set_domain;
+       rdev->rswitch->get_domain = idtcps_get_domain;
+       rdev->rswitch->em_init = NULL;
+       rdev->rswitch->em_handle = NULL;
+
+       return 0;
+}
+
+DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS6Q, idtcps_switch_init);
+DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS8, idtcps_switch_init);
+DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS10Q, idtcps_switch_init);
+DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS12, idtcps_switch_init);
+DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS16, idtcps_switch_init);
+DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDT70K200, idtcps_switch_init);
index c77c23bd9840d8e76c4a6b11d218f1ac17fbd08a..914eddd5aa42a86a06965881fd5ab27174013e0b 100644 (file)
@@ -1,6 +1,10 @@
 /*
  * RapidIO Tsi500 switch support
  *
+ * Copyright 2009-2010 Integrated Device Technology, Inc.
+ * Alexandre Bounine <alexandre.bounine@idt.com>
+ *  - Modified switch operations initialization.
+ *
  * Copyright 2005 MontaVista Software, Inc.
  * Matt Porter <mporter@kernel.crashing.org>
  *
@@ -57,4 +61,18 @@ tsi500_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount, u16 tab
        return ret;
 }
 
-DECLARE_RIO_ROUTE_OPS(RIO_VID_TUNDRA, RIO_DID_TSI500, tsi500_route_add_entry, tsi500_route_get_entry);
+static int tsi500_switch_init(struct rio_dev *rdev, int do_enum)
+{
+       pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
+       rdev->rswitch->add_entry = tsi500_route_add_entry;
+       rdev->rswitch->get_entry = tsi500_route_get_entry;
+       rdev->rswitch->clr_table = NULL;
+       rdev->rswitch->set_domain = NULL;
+       rdev->rswitch->get_domain = NULL;
+       rdev->rswitch->em_init = NULL;
+       rdev->rswitch->em_handle = NULL;
+
+       return 0;
+}
+
+DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI500, tsi500_switch_init);
diff --git a/drivers/rapidio/switches/tsi568.c b/drivers/rapidio/switches/tsi568.c
new file mode 100644 (file)
index 0000000..f7fd789
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * RapidIO Tsi568 switch support
+ *
+ * Copyright 2009-2010 Integrated Device Technology, Inc.
+ * Alexandre Bounine <alexandre.bounine@idt.com>
+ *  - Added EM support
+ *  - Modified switch operations initialization.
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * 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/rio.h>
+#include <linux/rio_drv.h>
+#include <linux/rio_ids.h>
+#include <linux/delay.h>
+#include "../rio.h"
+
+/* Global (broadcast) route registers */
+#define SPBC_ROUTE_CFG_DESTID  0x10070
+#define SPBC_ROUTE_CFG_PORT    0x10074
+
+/* Per port route registers */
+#define SPP_ROUTE_CFG_DESTID(n)        (0x11070 + 0x100*n)
+#define SPP_ROUTE_CFG_PORT(n)  (0x11074 + 0x100*n)
+
+#define TSI568_SP_MODE_BC      0x10004
+#define  TSI568_SP_MODE_PW_DIS 0x08000000
+
+static int
+tsi568_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u16 table, u16 route_destid, u8 route_port)
+{
+       if (table == RIO_GLOBAL_TABLE) {
+               rio_mport_write_config_32(mport, destid, hopcount,
+                                       SPBC_ROUTE_CFG_DESTID, route_destid);
+               rio_mport_write_config_32(mport, destid, hopcount,
+                                       SPBC_ROUTE_CFG_PORT, route_port);
+       } else {
+               rio_mport_write_config_32(mport, destid, hopcount,
+                                       SPP_ROUTE_CFG_DESTID(table),
+                                       route_destid);
+               rio_mport_write_config_32(mport, destid, hopcount,
+                                       SPP_ROUTE_CFG_PORT(table), route_port);
+       }
+
+       udelay(10);
+
+       return 0;
+}
+
+static int
+tsi568_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u16 table, u16 route_destid, u8 *route_port)
+{
+       int ret = 0;
+       u32 result;
+
+       if (table == RIO_GLOBAL_TABLE) {
+               rio_mport_write_config_32(mport, destid, hopcount,
+                                       SPBC_ROUTE_CFG_DESTID, route_destid);
+               rio_mport_read_config_32(mport, destid, hopcount,
+                                       SPBC_ROUTE_CFG_PORT, &result);
+       } else {
+               rio_mport_write_config_32(mport, destid, hopcount,
+                                       SPP_ROUTE_CFG_DESTID(table),
+                                       route_destid);
+               rio_mport_read_config_32(mport, destid, hopcount,
+                                       SPP_ROUTE_CFG_PORT(table), &result);
+       }
+
+       *route_port = result;
+       if (*route_port > 15)
+               ret = -1;
+
+       return ret;
+}
+
+static int
+tsi568_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u16 table)
+{
+       u32 route_idx;
+       u32 lut_size;
+
+       lut_size = (mport->sys_size) ? 0x1ff : 0xff;
+
+       if (table == RIO_GLOBAL_TABLE) {
+               rio_mport_write_config_32(mport, destid, hopcount,
+                                       SPBC_ROUTE_CFG_DESTID, 0x80000000);
+               for (route_idx = 0; route_idx <= lut_size; route_idx++)
+                       rio_mport_write_config_32(mport, destid, hopcount,
+                                               SPBC_ROUTE_CFG_PORT,
+                                               RIO_INVALID_ROUTE);
+       } else {
+               rio_mport_write_config_32(mport, destid, hopcount,
+                                       SPP_ROUTE_CFG_DESTID(table),
+                                       0x80000000);
+               for (route_idx = 0; route_idx <= lut_size; route_idx++)
+                       rio_mport_write_config_32(mport, destid, hopcount,
+                                               SPP_ROUTE_CFG_PORT(table),
+                                               RIO_INVALID_ROUTE);
+       }
+
+       return 0;
+}
+
+static int
+tsi568_em_init(struct rio_dev *rdev)
+{
+       struct rio_mport *mport = rdev->net->hport;
+       u16 destid = rdev->rswitch->destid;
+       u8 hopcount = rdev->rswitch->hopcount;
+       u32 regval;
+
+       pr_debug("TSI568 %s [%d:%d]\n", __func__, destid, hopcount);
+
+       /* Make sure that Port-Writes are disabled (for all ports) */
+       rio_mport_read_config_32(mport, destid, hopcount,
+                       TSI568_SP_MODE_BC, &regval);
+       rio_mport_write_config_32(mport, destid, hopcount,
+                       TSI568_SP_MODE_BC, regval | TSI568_SP_MODE_PW_DIS);
+
+       return 0;
+}
+
+static int tsi568_switch_init(struct rio_dev *rdev, int do_enum)
+{
+       pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
+       rdev->rswitch->add_entry = tsi568_route_add_entry;
+       rdev->rswitch->get_entry = tsi568_route_get_entry;
+       rdev->rswitch->clr_table = tsi568_route_clr_table;
+       rdev->rswitch->set_domain = NULL;
+       rdev->rswitch->get_domain = NULL;
+       rdev->rswitch->em_init = tsi568_em_init;
+       rdev->rswitch->em_handle = NULL;
+
+       return 0;
+}
+
+DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI568, tsi568_switch_init);
diff --git a/drivers/rapidio/switches/tsi57x.c b/drivers/rapidio/switches/tsi57x.c
new file mode 100644 (file)
index 0000000..d34df72
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+ * RapidIO Tsi57x switch family support
+ *
+ * Copyright 2009-2010 Integrated Device Technology, Inc.
+ * Alexandre Bounine <alexandre.bounine@idt.com>
+ *  - Added EM support
+ *  - Modified switch operations initialization.
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * 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/rio.h>
+#include <linux/rio_drv.h>
+#include <linux/rio_ids.h>
+#include <linux/delay.h>
+#include "../rio.h"
+
+/* Global (broadcast) route registers */
+#define SPBC_ROUTE_CFG_DESTID  0x10070
+#define SPBC_ROUTE_CFG_PORT    0x10074
+
+/* Per port route registers */
+#define SPP_ROUTE_CFG_DESTID(n)        (0x11070 + 0x100*n)
+#define SPP_ROUTE_CFG_PORT(n)  (0x11074 + 0x100*n)
+
+#define TSI578_SP_MODE(n)      (0x11004 + n*0x100)
+#define TSI578_SP_MODE_GLBL    0x10004
+#define  TSI578_SP_MODE_PW_DIS 0x08000000
+#define  TSI578_SP_MODE_LUT_512        0x01000000
+
+#define TSI578_SP_CTL_INDEP(n) (0x13004 + n*0x100)
+#define TSI578_SP_LUT_PEINF(n) (0x13010 + n*0x100)
+#define TSI578_SP_CS_TX(n)     (0x13014 + n*0x100)
+#define TSI578_SP_INT_STATUS(n) (0x13018 + n*0x100)
+
+#define TSI578_GLBL_ROUTE_BASE 0x10078
+
+static int
+tsi57x_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u16 table, u16 route_destid, u8 route_port)
+{
+       if (table == RIO_GLOBAL_TABLE) {
+               rio_mport_write_config_32(mport, destid, hopcount,
+                                         SPBC_ROUTE_CFG_DESTID, route_destid);
+               rio_mport_write_config_32(mport, destid, hopcount,
+                                         SPBC_ROUTE_CFG_PORT, route_port);
+       } else {
+               rio_mport_write_config_32(mport, destid, hopcount,
+                               SPP_ROUTE_CFG_DESTID(table), route_destid);
+               rio_mport_write_config_32(mport, destid, hopcount,
+                               SPP_ROUTE_CFG_PORT(table), route_port);
+       }
+
+       udelay(10);
+
+       return 0;
+}
+
+static int
+tsi57x_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u16 table, u16 route_destid, u8 *route_port)
+{
+       int ret = 0;
+       u32 result;
+
+       if (table == RIO_GLOBAL_TABLE) {
+               /* Use local RT of the ingress port to avoid possible
+                  race condition */
+               rio_mport_read_config_32(mport, destid, hopcount,
+                       RIO_SWP_INFO_CAR, &result);
+               table = (result & RIO_SWP_INFO_PORT_NUM_MASK);
+       }
+
+       rio_mport_write_config_32(mport, destid, hopcount,
+                               SPP_ROUTE_CFG_DESTID(table), route_destid);
+       rio_mport_read_config_32(mport, destid, hopcount,
+                               SPP_ROUTE_CFG_PORT(table), &result);
+
+       *route_port = (u8)result;
+       if (*route_port > 15)
+               ret = -1;
+
+       return ret;
+}
+
+static int
+tsi57x_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u16 table)
+{
+       u32 route_idx;
+       u32 lut_size;
+
+       lut_size = (mport->sys_size) ? 0x1ff : 0xff;
+
+       if (table == RIO_GLOBAL_TABLE) {
+               rio_mport_write_config_32(mport, destid, hopcount,
+                                         SPBC_ROUTE_CFG_DESTID, 0x80000000);
+               for (route_idx = 0; route_idx <= lut_size; route_idx++)
+                       rio_mport_write_config_32(mport, destid, hopcount,
+                                                 SPBC_ROUTE_CFG_PORT,
+                                                 RIO_INVALID_ROUTE);
+       } else {
+               rio_mport_write_config_32(mport, destid, hopcount,
+                               SPP_ROUTE_CFG_DESTID(table), 0x80000000);
+               for (route_idx = 0; route_idx <= lut_size; route_idx++)
+                       rio_mport_write_config_32(mport, destid, hopcount,
+                               SPP_ROUTE_CFG_PORT(table) , RIO_INVALID_ROUTE);
+       }
+
+       return 0;
+}
+
+static int
+tsi57x_set_domain(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u8 sw_domain)
+{
+       u32 regval;
+
+       /*
+        * Switch domain configuration operates only at global level
+        */
+
+       /* Turn off flat (LUT_512) mode */
+       rio_mport_read_config_32(mport, destid, hopcount,
+                                TSI578_SP_MODE_GLBL, &regval);
+       rio_mport_write_config_32(mport, destid, hopcount, TSI578_SP_MODE_GLBL,
+                                 regval & ~TSI578_SP_MODE_LUT_512);
+       /* Set switch domain base */
+       rio_mport_write_config_32(mport, destid, hopcount,
+                                 TSI578_GLBL_ROUTE_BASE,
+                                 (u32)(sw_domain << 24));
+       return 0;
+}
+
+static int
+tsi57x_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u8 *sw_domain)
+{
+       u32 regval;
+
+       /*
+        * Switch domain configuration operates only at global level
+        */
+       rio_mport_read_config_32(mport, destid, hopcount,
+                               TSI578_GLBL_ROUTE_BASE, &regval);
+
+       *sw_domain = (u8)(regval >> 24);
+
+       return 0;
+}
+
+static int
+tsi57x_em_init(struct rio_dev *rdev)
+{
+       struct rio_mport *mport = rdev->net->hport;
+       u16 destid = rdev->rswitch->destid;
+       u8 hopcount = rdev->rswitch->hopcount;
+       u32 regval;
+       int portnum;
+
+       pr_debug("TSI578 %s [%d:%d]\n", __func__, destid, hopcount);
+
+       for (portnum = 0; portnum < 16; portnum++) {
+               /* Make sure that Port-Writes are enabled (for all ports) */
+               rio_mport_read_config_32(mport, destid, hopcount,
+                               TSI578_SP_MODE(portnum), &regval);
+               rio_mport_write_config_32(mport, destid, hopcount,
+                               TSI578_SP_MODE(portnum),
+                               regval & ~TSI578_SP_MODE_PW_DIS);
+
+               /* Clear all pending interrupts */
+               rio_mport_read_config_32(mport, destid, hopcount,
+                               rdev->phys_efptr +
+                                       RIO_PORT_N_ERR_STS_CSR(portnum),
+                               &regval);
+               rio_mport_write_config_32(mport, destid, hopcount,
+                               rdev->phys_efptr +
+                                       RIO_PORT_N_ERR_STS_CSR(portnum),
+                               regval & 0x07120214);
+
+               rio_mport_read_config_32(mport, destid, hopcount,
+                               TSI578_SP_INT_STATUS(portnum), &regval);
+               rio_mport_write_config_32(mport, destid, hopcount,
+                               TSI578_SP_INT_STATUS(portnum),
+                               regval & 0x000700bd);
+
+               /* Enable all interrupts to allow ports to send a port-write */
+               rio_mport_read_config_32(mport, destid, hopcount,
+                               TSI578_SP_CTL_INDEP(portnum), &regval);
+               rio_mport_write_config_32(mport, destid, hopcount,
+                               TSI578_SP_CTL_INDEP(portnum),
+                               regval | 0x000b0000);
+
+               /* Skip next (odd) port if the current port is in x4 mode */
+               rio_mport_read_config_32(mport, destid, hopcount,
+                               rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum),
+                               &regval);
+               if ((regval & RIO_PORT_N_CTL_PWIDTH) == RIO_PORT_N_CTL_PWIDTH_4)
+                       portnum++;
+       }
+
+       return 0;
+}
+
+static int
+tsi57x_em_handler(struct rio_dev *rdev, u8 portnum)
+{
+       struct rio_mport *mport = rdev->net->hport;
+       u16 destid = rdev->rswitch->destid;
+       u8 hopcount = rdev->rswitch->hopcount;
+       u32 intstat, err_status;
+       int sendcount, checkcount;
+       u8 route_port;
+       u32 regval;
+
+       rio_mport_read_config_32(mport, destid, hopcount,
+                       rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum),
+                       &err_status);
+
+       if ((err_status & RIO_PORT_N_ERR_STS_PORT_OK) &&
+           (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES |
+                         RIO_PORT_N_ERR_STS_PW_INP_ES))) {
+               /* Remove any queued packets by locking/unlocking port */
+               rio_mport_read_config_32(mport, destid, hopcount,
+                       rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum),
+                       &regval);
+               if (!(regval & RIO_PORT_N_CTL_LOCKOUT)) {
+                       rio_mport_write_config_32(mport, destid, hopcount,
+                               rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum),
+                               regval | RIO_PORT_N_CTL_LOCKOUT);
+                       udelay(50);
+                       rio_mport_write_config_32(mport, destid, hopcount,
+                               rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum),
+                               regval);
+               }
+
+               /* Read from link maintenance response register to clear
+                * valid bit
+                */
+               rio_mport_read_config_32(mport, destid, hopcount,
+                       rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(portnum),
+                       &regval);
+
+               /* Send a Packet-Not-Accepted/Link-Request-Input-Status control
+                * symbol to recover from IES/OES
+                */
+               sendcount = 3;
+               while (sendcount) {
+                       rio_mport_write_config_32(mport, destid, hopcount,
+                                         TSI578_SP_CS_TX(portnum), 0x40fc8000);
+                       checkcount = 3;
+                       while (checkcount--) {
+                               udelay(50);
+                               rio_mport_read_config_32(
+                                       mport, destid, hopcount,
+                                       rdev->phys_efptr +
+                                               RIO_PORT_N_MNT_RSP_CSR(portnum),
+                                       &regval);
+                               if (regval & RIO_PORT_N_MNT_RSP_RVAL)
+                                       goto exit_es;
+                       }
+
+                       sendcount--;
+               }
+       }
+
+exit_es:
+       /* Clear implementation specific error status bits */
+       rio_mport_read_config_32(mport, destid, hopcount,
+                                TSI578_SP_INT_STATUS(portnum), &intstat);
+       pr_debug("TSI578[%x:%x] SP%d_INT_STATUS=0x%08x\n",
+                destid, hopcount, portnum, intstat);
+
+       if (intstat & 0x10000) {
+               rio_mport_read_config_32(mport, destid, hopcount,
+                               TSI578_SP_LUT_PEINF(portnum), &regval);
+               regval = (mport->sys_size) ? (regval >> 16) : (regval >> 24);
+               route_port = rdev->rswitch->route_table[regval];
+               pr_debug("RIO: TSI578[%s] P%d LUT Parity Error (destID=%d)\n",
+                       rio_name(rdev), portnum, regval);
+               tsi57x_route_add_entry(mport, destid, hopcount,
+                               RIO_GLOBAL_TABLE, regval, route_port);
+       }
+
+       rio_mport_write_config_32(mport, destid, hopcount,
+                                 TSI578_SP_INT_STATUS(portnum),
+                                 intstat & 0x000700bd);
+
+       return 0;
+}
+
+static int tsi57x_switch_init(struct rio_dev *rdev, int do_enum)
+{
+       pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
+       rdev->rswitch->add_entry = tsi57x_route_add_entry;
+       rdev->rswitch->get_entry = tsi57x_route_get_entry;
+       rdev->rswitch->clr_table = tsi57x_route_clr_table;
+       rdev->rswitch->set_domain = tsi57x_set_domain;
+       rdev->rswitch->get_domain = tsi57x_get_domain;
+       rdev->rswitch->em_init = tsi57x_em_init;
+       rdev->rswitch->em_handle = tsi57x_em_handler;
+
+       return 0;
+}
+
+DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI572, tsi57x_switch_init);
+DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI574, tsi57x_switch_init);
+DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI577, tsi57x_switch_init);
+DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI578, tsi57x_switch_init);
index 5fb83e2ced25981f5b2b06410ff6dcd1afd36bd3..7d149a8d8d9b6cb7fe92f73b71536a723cbf6249 100644 (file)
@@ -23,9 +23,9 @@ struct pm8607_regulator_info {
        struct regulator_dev    *regulator;
        struct i2c_client       *i2c;
 
-       int     min_uV;
-       int     max_uV;
-       int     step_uV;
+       unsigned int    *vol_table;
+       unsigned int    *vol_suspend;
+
        int     vol_reg;
        int     vol_shift;
        int     vol_nbits;
@@ -36,83 +36,189 @@ struct pm8607_regulator_info {
        int     slope_double;
 };
 
-static inline int check_range(struct pm8607_regulator_info *info,
-                               int min_uV, int max_uV)
-{
-       if (max_uV < info->min_uV || min_uV > info->max_uV || min_uV > max_uV)
-               return -EINVAL;
+static const unsigned int BUCK1_table[] = {
+        725000,  750000,  775000,  800000,  825000,  850000,  875000,  900000,
+        925000,  950000,  975000, 1000000, 1025000, 1050000, 1075000, 1100000,
+       1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000,
+       1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000,
+             0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
+        200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
+        400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
+        600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
+};
 
-       return 0;
-}
+static const unsigned int BUCK1_suspend_table[] = {
+             0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
+        200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
+        400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
+        600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
+        800000,  825000,  850000,  875000,  900000,  925000,  950000,  975000,
+       1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
+       1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000,
+       1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000,
+};
+
+static const unsigned int BUCK2_table[] = {
+             0,   50000,  100000,  150000,  200000,  250000,  300000,  350000,
+        400000,  450000,  500000,  550000,  600000,  650000,  700000,  750000,
+        800000,  850000,  900000,  950000, 1000000, 1050000, 1100000, 1150000,
+       1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1550000,
+       1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 1950000,
+       2000000, 2050000, 2100000, 2150000, 2200000, 2250000, 2300000, 2350000,
+       2400000, 2450000, 2500000, 2550000, 2600000, 2650000, 2700000, 2750000,
+       2800000, 2850000, 2900000, 2950000, 3000000, 3000000, 3000000, 3000000,
+};
+
+static const unsigned int BUCK2_suspend_table[] = {
+             0,   50000,  100000,  150000,  200000,  250000,  300000,  350000,
+        400000,  450000,  500000,  550000,  600000,  650000,  700000,  750000,
+        800000,  850000,  900000,  950000, 1000000, 1050000, 1100000, 1150000,
+       1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1550000,
+       1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 1950000,
+       2000000, 2050000, 2100000, 2150000, 2200000, 2250000, 2300000, 2350000,
+       2400000, 2450000, 2500000, 2550000, 2600000, 2650000, 2700000, 2750000,
+       2800000, 2850000, 2900000, 2950000, 3000000, 3000000, 3000000, 3000000,
+};
+
+static const unsigned int BUCK3_table[] = {
+              0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
+        200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
+        400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
+        600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
+        800000,  825000,  850000,  875000,  900000,  925000,  950000,  975000,
+       1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
+       1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000,
+       1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000,
+};
+
+static const unsigned int BUCK3_suspend_table[] = {
+              0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
+        200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
+        400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
+        600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
+        800000,  825000,  850000,  875000,  900000,  925000,  950000,  975000,
+       1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
+       1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000,
+       1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000,
+};
+
+static const unsigned int LDO1_table[] = {
+       1800000, 1200000, 2800000, 0,
+};
+
+static const unsigned int LDO1_suspend_table[] = {
+       1800000, 1200000, 0, 0,
+};
+
+static const unsigned int LDO2_table[] = {
+       1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
+};
+
+static const unsigned int LDO2_suspend_table[] = {
+       1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
+};
+
+static const unsigned int LDO3_table[] = {
+       1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
+};
+
+static const unsigned int LDO3_suspend_table[] = {
+       1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
+};
+
+static const unsigned int LDO4_table[] = {
+       1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2900000, 3300000,
+};
+
+static const unsigned int LDO4_suspend_table[] = {
+       1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2900000, 2900000,
+};
+
+static const unsigned int LDO5_table[] = {
+       2900000, 3000000, 3100000, 3300000,
+};
+
+static const unsigned int LDO5_suspend_table[] = {
+       2900000, 0, 0, 0,
+};
+
+static const unsigned int LDO6_table[] = {
+       1800000, 1850000, 2600000, 2650000, 2700000, 2750000, 2800000, 3300000,
+};
+
+static const unsigned int LDO6_suspend_table[] = {
+       1800000, 1850000, 2600000, 2650000, 2700000, 2750000, 2800000, 2900000,
+};
+
+static const unsigned int LDO7_table[] = {
+       1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
+};
+
+static const unsigned int LDO7_suspend_table[] = {
+       1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
+};
+
+static const unsigned int LDO8_table[] = {
+       1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
+};
+
+static const unsigned int LDO8_suspend_table[] = {
+       1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
+};
+
+static const unsigned int LDO9_table[] = {
+       1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
+};
+
+static const unsigned int LDO9_suspend_table[] = {
+       1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
+};
+
+static const unsigned int LDO10_table[] = {
+       1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
+       1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
+};
+
+static const unsigned int LDO10_suspend_table[] = {
+       1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
+       1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
+};
+
+static const unsigned int LDO12_table[] = {
+       1800000, 1900000, 2700000, 2800000, 2900000, 3000000, 3100000, 3300000,
+       1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
+};
+
+static const unsigned int LDO12_suspend_table[] = {
+       1800000, 1900000, 2700000, 2800000, 2900000, 2900000, 2900000, 2900000,
+       1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
+};
+
+static const unsigned int LDO13_table[] = {
+       1300000, 1800000, 2000000, 2500000, 2800000, 3000000, 0, 0,
+};
+
+static const unsigned int LDO13_suspend_table[] = {
+       0,
+};
+
+static const unsigned int LDO14_table[] = {
+       1800000, 1850000, 2700000, 2750000, 2800000, 2850000, 2900000, 3300000,
+};
+
+static const unsigned int LDO14_suspend_table[] = {
+       1800000, 1850000, 2700000, 2750000, 2800000, 2850000, 2900000, 2900000,
+};
 
 static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index)
 {
        struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
        int ret = -EINVAL;
 
-       switch (info->desc.id) {
-       case PM8607_ID_BUCK1:
-               ret = (index < 0x1d) ? (index * 25000 + 800000) :
-                       ((index < 0x20) ? 1500000 :
-                       ((index < 0x40) ? ((index - 0x20) * 25000) :
-                       -EINVAL));
-               break;
-       case PM8607_ID_BUCK3:
-               ret = (index < 0x3d) ? (index * 25000) :
-                       ((index < 0x40) ? 1500000 : -EINVAL);
-               if (ret < 0)
-                       break;
+       if (info->vol_table && (index < (2 << info->vol_nbits))) {
+               ret = info->vol_table[index];
                if (info->slope_double)
                        ret <<= 1;
-               break;
-       case PM8607_ID_LDO1:
-               ret = (index == 0) ? 1800000 :
-                       ((index == 1) ? 1200000 :
-                       ((index == 2) ? 2800000 : -EINVAL));
-               break;
-       case PM8607_ID_LDO5:
-               ret = (index == 0) ? 2900000 :
-                       ((index == 1) ? 3000000 :
-                       ((index == 2) ? 3100000 : 3300000));
-               break;
-       case PM8607_ID_LDO7:
-       case PM8607_ID_LDO8:
-               ret = (index < 3) ? (index * 50000 + 1800000) :
-                       ((index < 8) ? (index * 50000 + 2550000) :
-                        -EINVAL);
-               break;
-       case PM8607_ID_LDO12:
-               ret = (index < 2) ? (index * 100000 + 1800000) :
-                       ((index < 7) ? (index * 100000 + 2500000) :
-                       ((index == 7) ? 3300000 : 1200000));
-               break;
-       case PM8607_ID_LDO2:
-       case PM8607_ID_LDO3:
-       case PM8607_ID_LDO9:
-               ret = (index < 3) ? (index * 50000 + 1800000) :
-                       ((index < 7) ? (index * 50000 + 2550000) :
-                       3300000);
-               break;
-       case PM8607_ID_LDO4:
-               ret = (index < 3) ? (index * 50000 + 1800000) :
-                       ((index < 6) ? (index * 50000 + 2550000) :
-                       ((index == 6) ? 2900000 : 3300000));
-               break;
-       case PM8607_ID_LDO6:
-               ret = (index < 2) ? (index * 50000 + 1800000) :
-                       ((index < 7) ? (index * 50000 + 2500000) :
-                       3300000);
-               break;
-       case PM8607_ID_LDO10:
-               ret = (index < 3) ? (index * 50000 + 1800000) :
-                       ((index < 7) ? (index * 50000 + 2550000) :
-                       ((index == 7) ? 3300000 : 1200000));
-               break;
-       case PM8607_ID_LDO14:
-               ret = (index < 2) ? (index * 50000 + 1800000) :
-                       ((index < 7) ? (index * 50000 + 2600000) :
-                       3300000);
-               break;
        }
        return ret;
 }
@@ -120,174 +226,26 @@ static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index)
 static int choose_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
 {
        struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
-       int val = -ENOENT;
-       int ret;
+       int i, ret = -ENOENT;
 
-       switch (info->desc.id) {
-       case PM8607_ID_BUCK1:
-               if (min_uV >= 800000)           /* 800mV ~ 1500mV / 25mV */
-                       val = (min_uV - 775001) / 25000;
-               else {                          /* 25mV ~ 775mV / 25mV */
-                       val = (min_uV + 249999) / 25000;
-                       val += 32;
-               }
-               break;
-       case PM8607_ID_BUCK3:
-               if (info->slope_double)
-                       min_uV = min_uV >> 1;
-               val = (min_uV + 249999) / 25000; /* 0mV ~ 1500mV / 25mV */
-
-               break;
-       case PM8607_ID_LDO1:
-               if (min_uV > 1800000)
-                       val = 2;
-               else if (min_uV > 1200000)
-                       val = 0;
-               else
-                       val = 1;
-               break;
-       case PM8607_ID_LDO5:
-               if (min_uV > 3100000)
-                       val = 3;
-               else                            /* 2900mV ~ 3100mV / 100mV */
-                       val = (min_uV - 2800001) / 100000;
-               break;
-       case PM8607_ID_LDO7:
-       case PM8607_ID_LDO8:
-               if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */
-                       if (min_uV <= 1800000)
-                               val = 0;        /* 1800mv */
-                       else if (min_uV <= 1900000)
-                               val = (min_uV - 1750001) / 50000;
-                       else
-                               val = 3;        /* 2700mV */
-               } else {                 /* 2700mV ~ 2900mV / 50mV */
-                       if (min_uV <= 2900000) {
-                               val = (min_uV - 2650001) / 50000;
-                               val += 3;
-                       } else
-                               val = -EINVAL;
-               }
-               break;
-       case PM8607_ID_LDO10:
-               if (min_uV > 2850000)
-                       val = 7;
-               else if (min_uV <= 1200000)
-                       val = 8;
-               else if (min_uV < 2700000)      /* 1800mV ~ 1900mV / 50mV */
-                       val = (min_uV - 1750001) / 50000;
-               else {                          /* 2700mV ~ 2850mV / 50mV */
-                       val = (min_uV - 2650001) / 50000;
-                       val += 3;
-               }
-               break;
-       case PM8607_ID_LDO12:
-               if (min_uV < 2700000) {         /* 1800mV ~ 1900mV / 100mV */
-                       if (min_uV <= 1200000)
-                               val = 8;        /* 1200mV */
-                       else if (min_uV <= 1800000)
-                               val = 0;        /* 1800mV */
-                       else if (min_uV <= 1900000)
-                               val = (min_uV - 1700001) / 100000;
-                       else
-                               val = 2;        /* 2700mV */
-               } else {                        /* 2700mV ~ 3100mV / 100mV */
-                       if (min_uV <= 3100000) {
-                               val = (min_uV - 2600001) / 100000;
-                               val += 2;
-                       } else if (min_uV <= 3300000)
-                               val = 7;
-                       else
-                               val = -EINVAL;
-               }
-               break;
-       case PM8607_ID_LDO2:
-       case PM8607_ID_LDO3:
-       case PM8607_ID_LDO9:
-               if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */
-                       if (min_uV <= 1800000)
-                               val = 0;
-                       else if (min_uV <= 1900000)
-                               val = (min_uV - 1750001) / 50000;
-                       else
-                               val = 3;        /* 2700mV */
-               } else {                 /* 2700mV ~ 2850mV / 50mV */
-                       if (min_uV <= 2850000) {
-                               val = (min_uV - 2650001) / 50000;
-                               val += 3;
-                       } else if (min_uV <= 3300000)
-                               val = 7;
-                       else
-                               val = -EINVAL;
-               }
-               break;
-       case PM8607_ID_LDO4:
-               if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */
-                       if (min_uV <= 1800000)
-                               val = 0;
-                       else if (min_uV <= 1900000)
-                               val = (min_uV - 1750001) / 50000;
-                       else
-                               val = 3;        /* 2700mV */
-               } else {                 /* 2700mV ~ 2800mV / 50mV */
-                       if (min_uV <= 2850000) {
-                               val = (min_uV - 2650001) / 50000;
-                               val += 3;
-                       } else if (min_uV <= 2900000)
-                               val = 6;
-                       else if (min_uV <= 3300000)
-                               val = 7;
-                       else
-                               val = -EINVAL;
-               }
-               break;
-       case PM8607_ID_LDO6:
-               if (min_uV < 2600000) { /* 1800mV ~ 1850mV / 50mV */
-                       if (min_uV <= 1800000)
-                               val = 0;
-                       else if (min_uV <= 1850000)
-                               val = (min_uV - 1750001) / 50000;
-                       else
-                               val = 2;        /* 2600mV */
-               } else {                /* 2600mV ~ 2800mV / 50mV */
-                       if (min_uV <= 2800000) {
-                               val = (min_uV - 2550001) / 50000;
-                               val += 2;
-                       } else if (min_uV <= 3300000)
-                               val = 7;
-                       else
-                               val = -EINVAL;
-               }
-               break;
-       case PM8607_ID_LDO14:
-               if (min_uV < 2700000) { /* 1800mV ~ 1850mV / 50mV */
-                       if (min_uV <= 1800000)
-                               val = 0;
-                       else if (min_uV <= 1850000)
-                               val = (min_uV - 1750001) / 50000;
-                       else
-                               val = 2;        /* 2700mV */
-               } else {                 /* 2700mV ~ 2900mV / 50mV */
-                       if (min_uV <= 2900000) {
-                               val = (min_uV - 2650001) / 50000;
-                               val += 2;
-                       } else if (min_uV <= 3300000)
-                               val = 7;
-                       else
-                               val = -EINVAL;
-               }
-               break;
+       if (info->slope_double) {
+               min_uV = min_uV >> 1;
+               max_uV = max_uV >> 1;
        }
-       if (val >= 0) {
-               ret = pm8607_list_voltage(rdev, val);
-               if (ret > max_uV) {
-                       pr_err("exceed voltage range (%d %d) uV",
-                               min_uV, max_uV);
-                       return -EINVAL;
+       if (info->vol_table) {
+               for (i = 0; i < (2 << info->vol_nbits); i++) {
+                       if (!info->vol_table[i])
+                               break;
+                       if ((min_uV <= info->vol_table[i])
+                               && (max_uV >= info->vol_table[i])) {
+                               ret = i;
+                               break;
+                       }
                }
-       } else
-               pr_err("invalid voltage range (%d %d) uV", min_uV, max_uV);
-       return val;
+       }
+       if (ret < 0)
+               pr_err("invalid voltage range (%d %d) uV\n", min_uV, max_uV);
+       return ret;
 }
 
 static int pm8607_set_voltage(struct regulator_dev *rdev,
@@ -297,7 +255,7 @@ static int pm8607_set_voltage(struct regulator_dev *rdev,
        uint8_t val, mask;
        int ret;
 
-       if (check_range(info, min_uV, max_uV)) {
+       if (min_uV > max_uV) {
                pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
                return -EINVAL;
        }
@@ -375,18 +333,15 @@ static struct regulator_ops pm8607_regulator_ops = {
        .is_enabled     = pm8607_is_enabled,
 };
 
-#define PM8607_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \
+#define PM8607_DVC(vreg, nbits, ureg, ubit, ereg, ebit)                        \
 {                                                                      \
        .desc   = {                                                     \
-               .name   = "BUCK" #_id,                                  \
+               .name   = #vreg,                                        \
                .ops    = &pm8607_regulator_ops,                        \
                .type   = REGULATOR_VOLTAGE,                            \
-               .id     = PM8607_ID_BUCK##_id,                          \
+               .id     = PM8607_ID_##vreg,                             \
                .owner  = THIS_MODULE,                                  \
        },                                                              \
-       .min_uV         = (min) * 1000,                                 \
-       .max_uV         = (max) * 1000,                                 \
-       .step_uV        = (step) * 1000,                                \
        .vol_reg        = PM8607_##vreg,                                \
        .vol_shift      = (0),                                          \
        .vol_nbits      = (nbits),                                      \
@@ -395,9 +350,11 @@ static struct regulator_ops pm8607_regulator_ops = {
        .enable_reg     = PM8607_##ereg,                                \
        .enable_bit     = (ebit),                                       \
        .slope_double   = (0),                                          \
+       .vol_table      = (unsigned int *)&vreg##_table,                \
+       .vol_suspend    = (unsigned int *)&vreg##_suspend_table,        \
 }
 
-#define PM8607_LDO(_id, min, max, step, vreg, shift, nbits, ereg, ebit)        \
+#define PM8607_LDO(_id, vreg, shift, nbits, ereg, ebit)                        \
 {                                                                      \
        .desc   = {                                                     \
                .name   = "LDO" #_id,                                   \
@@ -406,33 +363,34 @@ static struct regulator_ops pm8607_regulator_ops = {
                .id     = PM8607_ID_LDO##_id,                           \
                .owner  = THIS_MODULE,                                  \
        },                                                              \
-       .min_uV         = (min) * 1000,                                 \
-       .max_uV         = (max) * 1000,                                 \
-       .step_uV        = (step) * 1000,                                \
        .vol_reg        = PM8607_##vreg,                                \
        .vol_shift      = (shift),                                      \
        .vol_nbits      = (nbits),                                      \
        .enable_reg     = PM8607_##ereg,                                \
        .enable_bit     = (ebit),                                       \
        .slope_double   = (0),                                          \
+       .vol_table      = (unsigned int *)&LDO##_id##_table,            \
+       .vol_suspend    = (unsigned int *)&LDO##_id##_suspend_table,    \
 }
 
 static struct pm8607_regulator_info pm8607_regulator_info[] = {
-       PM8607_DVC(1, 0, 1500, 25, BUCK1, 6, GO, 0, SUPPLIES_EN11, 0),
-       PM8607_DVC(3, 0, 1500, 25, BUCK3, 6, GO, 2, SUPPLIES_EN11, 2),
-
-       PM8607_LDO(1 , 1200, 2800, 0, LDO1 , 0, 2, SUPPLIES_EN11, 3),
-       PM8607_LDO(2 , 1800, 3300, 0, LDO2 , 0, 3, SUPPLIES_EN11, 4),
-       PM8607_LDO(3 , 1800, 3300, 0, LDO3 , 0, 3, SUPPLIES_EN11, 5),
-       PM8607_LDO(4 , 1800, 3300, 0, LDO4 , 0, 3, SUPPLIES_EN11, 6),
-       PM8607_LDO(5 , 2900, 3300, 0, LDO5 , 0, 2, SUPPLIES_EN11, 7),
-       PM8607_LDO(6 , 1800, 3300, 0, LDO6 , 0, 3, SUPPLIES_EN12, 0),
-       PM8607_LDO(7 , 1800, 2900, 0, LDO7 , 0, 3, SUPPLIES_EN12, 1),
-       PM8607_LDO(8 , 1800, 2900, 0, LDO8 , 0, 3, SUPPLIES_EN12, 2),
-       PM8607_LDO(9 , 1800, 3300, 0, LDO9 , 0, 3, SUPPLIES_EN12, 3),
-       PM8607_LDO(10, 1200, 3300, 0, LDO10, 0, 4, SUPPLIES_EN11, 4),
-       PM8607_LDO(12, 1200, 3300, 0, LDO12, 0, 4, SUPPLIES_EN11, 5),
-       PM8607_LDO(14, 1800, 3300, 0, LDO14, 0, 3, SUPPLIES_EN11, 6),
+       PM8607_DVC(BUCK1, 6, GO, 0, SUPPLIES_EN11, 0),
+       PM8607_DVC(BUCK2, 6, GO, 1, SUPPLIES_EN11, 1),
+       PM8607_DVC(BUCK3, 6, GO, 2, SUPPLIES_EN11, 2),
+
+       PM8607_LDO( 1,         LDO1, 0, 2, SUPPLIES_EN11, 3),
+       PM8607_LDO( 2,         LDO2, 0, 3, SUPPLIES_EN11, 4),
+       PM8607_LDO( 3,         LDO3, 0, 3, SUPPLIES_EN11, 5),
+       PM8607_LDO( 4,         LDO4, 0, 3, SUPPLIES_EN11, 6),
+       PM8607_LDO( 5,         LDO5, 0, 2, SUPPLIES_EN11, 7),
+       PM8607_LDO( 6,         LDO6, 0, 3, SUPPLIES_EN12, 0),
+       PM8607_LDO( 7,         LDO7, 0, 3, SUPPLIES_EN12, 1),
+       PM8607_LDO( 8,         LDO8, 0, 3, SUPPLIES_EN12, 2),
+       PM8607_LDO( 9,         LDO9, 0, 3, SUPPLIES_EN12, 3),
+       PM8607_LDO(10,        LDO10, 0, 3, SUPPLIES_EN12, 4),
+       PM8607_LDO(12,        LDO12, 0, 4, SUPPLIES_EN12, 5),
+       PM8607_LDO(13, VIBRATOR_SET, 1, 3,  VIBRATOR_SET, 0),
+       PM8607_LDO(14,        LDO14, 0, 4, SUPPLIES_EN12, 6),
 };
 
 static inline struct pm8607_regulator_info *find_regulator_info(int id)
@@ -484,60 +442,29 @@ static int __devexit pm8607_regulator_remove(struct platform_device *pdev)
 {
        struct pm8607_regulator_info *info = platform_get_drvdata(pdev);
 
+       platform_set_drvdata(pdev, NULL);
        regulator_unregister(info->regulator);
        return 0;
 }
 
-#define PM8607_REGULATOR_DRIVER(_name)                         \
-{                                                              \
-       .driver         = {                                     \
-               .name   = "88pm8607-" #_name,                   \
-               .owner  = THIS_MODULE,                          \
-       },                                                      \
-       .probe          = pm8607_regulator_probe,               \
-       .remove         = __devexit_p(pm8607_regulator_remove), \
-}
-
-static struct platform_driver pm8607_regulator_driver[] = {
-       PM8607_REGULATOR_DRIVER(buck1),
-       PM8607_REGULATOR_DRIVER(buck2),
-       PM8607_REGULATOR_DRIVER(buck3),
-       PM8607_REGULATOR_DRIVER(ldo1),
-       PM8607_REGULATOR_DRIVER(ldo2),
-       PM8607_REGULATOR_DRIVER(ldo3),
-       PM8607_REGULATOR_DRIVER(ldo4),
-       PM8607_REGULATOR_DRIVER(ldo5),
-       PM8607_REGULATOR_DRIVER(ldo6),
-       PM8607_REGULATOR_DRIVER(ldo7),
-       PM8607_REGULATOR_DRIVER(ldo8),
-       PM8607_REGULATOR_DRIVER(ldo9),
-       PM8607_REGULATOR_DRIVER(ldo10),
-       PM8607_REGULATOR_DRIVER(ldo12),
-       PM8607_REGULATOR_DRIVER(ldo14),
+static struct platform_driver pm8607_regulator_driver = {
+       .driver         = {
+               .name   = "88pm860x-regulator",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = pm8607_regulator_probe,
+       .remove         = __devexit_p(pm8607_regulator_remove),
 };
 
 static int __init pm8607_regulator_init(void)
 {
-       int i, count, ret;
-
-       count = ARRAY_SIZE(pm8607_regulator_driver);
-       for (i = 0; i < count; i++) {
-               ret = platform_driver_register(&pm8607_regulator_driver[i]);
-               if (ret != 0)
-                       pr_err("Failed to register regulator driver: %d\n",
-                               ret);
-       }
-       return 0;
+       return platform_driver_register(&pm8607_regulator_driver);
 }
 subsys_initcall(pm8607_regulator_init);
 
 static void __exit pm8607_regulator_exit(void)
 {
-       int i, count;
-
-       count = ARRAY_SIZE(pm8607_regulator_driver);
-       for (i = 0; i < count; i++)
-               platform_driver_unregister(&pm8607_regulator_driver[i]);
+       platform_driver_unregister(&pm8607_regulator_driver);
 }
 module_exit(pm8607_regulator_exit);
 
index 7de950959ed23e8892f5a1d55db4856dd87e518d..1afd008ca957a9fce09011fd05f85a3998dfda64 100644 (file)
@@ -492,18 +492,21 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = {
                .id   = AB3100_LDO_A,
                .ops  = &regulator_ops_fixed,
                .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
        },
        {
                .name = "LDO_C",
                .id   = AB3100_LDO_C,
                .ops  = &regulator_ops_fixed,
                .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
        },
        {
                .name = "LDO_D",
                .id   = AB3100_LDO_D,
                .ops  = &regulator_ops_fixed,
                .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
        },
        {
                .name = "LDO_E",
@@ -511,6 +514,7 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = {
                .ops  = &regulator_ops_variable_sleepable,
                .n_voltages = ARRAY_SIZE(ldo_e_buck_typ_voltages),
                .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
        },
        {
                .name = "LDO_F",
@@ -518,6 +522,7 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = {
                .ops  = &regulator_ops_variable,
                .n_voltages = ARRAY_SIZE(ldo_f_typ_voltages),
                .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
        },
        {
                .name = "LDO_G",
@@ -525,6 +530,7 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = {
                .ops  = &regulator_ops_variable,
                .n_voltages = ARRAY_SIZE(ldo_g_typ_voltages),
                .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
        },
        {
                .name = "LDO_H",
@@ -532,6 +538,7 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = {
                .ops  = &regulator_ops_variable,
                .n_voltages = ARRAY_SIZE(ldo_h_typ_voltages),
                .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
        },
        {
                .name = "LDO_K",
@@ -539,12 +546,14 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = {
                .ops  = &regulator_ops_variable,
                .n_voltages = ARRAY_SIZE(ldo_k_typ_voltages),
                .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
        },
        {
                .name = "LDO_EXT",
                .id   = AB3100_LDO_EXT,
                .ops  = &regulator_ops_external,
                .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
        },
        {
                .name = "BUCK",
@@ -552,6 +561,7 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = {
                .ops  = &regulator_ops_variable_sleepable,
                .n_voltages = ARRAY_SIZE(ldo_e_buck_typ_voltages),
                .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
        },
 };
 
index d08cd9b66c6dde8777af20b39b0dff428193bf2d..068d488a4f714a310528a5e1dcc1b9016cc59caa 100644 (file)
@@ -78,6 +78,7 @@ static struct regulator_desc bq24022_desc = {
        .name  = "bq24022",
        .ops   = &bq24022_ops,
        .type  = REGULATOR_CURRENT,
+       .owner = THIS_MODULE,
 };
 
 static int __init bq24022_probe(struct platform_device *pdev)
index 51cf2bb37438d92f9711bb385fde0f642e663c48..2248087b9be2456bc2430ddcbda3f4f0e6085d4f 100644 (file)
@@ -944,8 +944,13 @@ static int set_consumer_device_supply(struct regulator_dev *rdev,
                has_dev = 0;
 
        list_for_each_entry(node, &regulator_map_list, list) {
-               if (consumer_dev_name != node->dev_name)
+               if (node->dev_name && consumer_dev_name) {
+                       if (strcmp(node->dev_name, consumer_dev_name) != 0)
+                               continue;
+               } else if (node->dev_name || consumer_dev_name) {
                        continue;
+               }
+
                if (strcmp(node->supply, supply) != 0)
                        continue;
 
@@ -976,29 +981,6 @@ static int set_consumer_device_supply(struct regulator_dev *rdev,
        return 0;
 }
 
-static void unset_consumer_device_supply(struct regulator_dev *rdev,
-       const char *consumer_dev_name, struct device *consumer_dev)
-{
-       struct regulator_map *node, *n;
-
-       if (consumer_dev && !consumer_dev_name)
-               consumer_dev_name = dev_name(consumer_dev);
-
-       list_for_each_entry_safe(node, n, &regulator_map_list, list) {
-               if (rdev != node->regulator)
-                       continue;
-
-               if (consumer_dev_name && node->dev_name &&
-                   strcmp(consumer_dev_name, node->dev_name))
-                       continue;
-
-               list_del(&node->list);
-               kfree(node->dev_name);
-               kfree(node);
-               return;
-       }
-}
-
 static void unset_regulator_supplies(struct regulator_dev *rdev)
 {
        struct regulator_map *node, *n;
@@ -1008,7 +990,6 @@ static void unset_regulator_supplies(struct regulator_dev *rdev)
                        list_del(&node->list);
                        kfree(node->dev_name);
                        kfree(node);
-                       return;
                }
        }
 }
@@ -1764,6 +1745,7 @@ int regulator_set_mode(struct regulator *regulator, unsigned int mode)
 {
        struct regulator_dev *rdev = regulator->rdev;
        int ret;
+       int regulator_curr_mode;
 
        mutex_lock(&rdev->mutex);
 
@@ -1773,6 +1755,15 @@ int regulator_set_mode(struct regulator *regulator, unsigned int mode)
                goto out;
        }
 
+       /* return if the same mode is requested */
+       if (rdev->desc->ops->get_mode) {
+               regulator_curr_mode = rdev->desc->ops->get_mode(rdev);
+               if (regulator_curr_mode == mode) {
+                       ret = 0;
+                       goto out;
+               }
+       }
+
        /* constraints check */
        ret = regulator_check_mode(rdev, mode);
        if (ret < 0)
@@ -2328,7 +2319,37 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
                goto scrub;
 
        /* set supply regulator if it exists */
+       if (init_data->supply_regulator && init_data->supply_regulator_dev) {
+               dev_err(dev,
+                       "Supply regulator specified by both name and dev\n");
+               goto scrub;
+       }
+
+       if (init_data->supply_regulator) {
+               struct regulator_dev *r;
+               int found = 0;
+
+               list_for_each_entry(r, &regulator_list, list) {
+                       if (strcmp(rdev_get_name(r),
+                                  init_data->supply_regulator) == 0) {
+                               found = 1;
+                               break;
+                       }
+               }
+
+               if (!found) {
+                       dev_err(dev, "Failed to find supply %s\n",
+                               init_data->supply_regulator);
+                       goto scrub;
+               }
+
+               ret = set_supply(rdev, r);
+               if (ret < 0)
+                       goto scrub;
+       }
+
        if (init_data->supply_regulator_dev) {
+               dev_warn(dev, "Uses supply_regulator_dev instead of regulator_supply\n");
                ret = set_supply(rdev,
                        dev_get_drvdata(init_data->supply_regulator_dev));
                if (ret < 0)
@@ -2341,13 +2362,8 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
                        init_data->consumer_supplies[i].dev,
                        init_data->consumer_supplies[i].dev_name,
                        init_data->consumer_supplies[i].supply);
-               if (ret < 0) {
-                       for (--i; i >= 0; i--)
-                               unset_consumer_device_supply(rdev,
-                                   init_data->consumer_supplies[i].dev_name,
-                                   init_data->consumer_supplies[i].dev);
-                       goto scrub;
-               }
+               if (ret < 0)
+                       goto unset_supplies;
        }
 
        list_add(&rdev->list, &regulator_list);
@@ -2355,6 +2371,9 @@ out:
        mutex_unlock(&regulator_list_mutex);
        return rdev;
 
+unset_supplies:
+       unset_regulator_supplies(rdev);
+
 scrub:
        device_unregister(&rdev->dev);
        /* device core frees rdev */
index ad036dd8da136852bd1490eff9c36807a1bfef0a..4597d508a229efe5bb12a985955ebb71931e3ee4 100644 (file)
@@ -440,8 +440,8 @@ static int mc13783_fixed_regulator_set_voltage(struct regulator_dev *rdev,
        dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n",
                __func__, id, min_uV, max_uV);
 
-       if (min_uV > mc13783_regulators[id].voltages[0] &&
-           max_uV < mc13783_regulators[id].voltages[0])
+       if (min_uV >= mc13783_regulators[id].voltages[0] &&
+           max_uV <= mc13783_regulators[id].voltages[0])
                return 0;
        else
                return -EINVAL;
@@ -649,6 +649,6 @@ static void __exit mc13783_regulator_exit(void)
 module_exit(mc13783_regulator_exit);
 
 MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de");
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
 MODULE_DESCRIPTION("Regulator Driver for Freescale MC13783 PMIC");
 MODULE_ALIAS("platform:mc13783-regulator");
index 9729d760fb4ddc742771cf5bf4d2c71097d0c456..7e5892efc4375d06b5bb2a15426f3abe95a29fba 100644 (file)
@@ -49,6 +49,7 @@ struct twlreg_info {
 
        /* chip constraints on regulator behavior */
        u16                     min_mV;
+       u16                     max_mV;
 
        /* used by regulator core */
        struct regulator_desc   desc;
@@ -318,31 +319,8 @@ static const u16 VIO_VSEL_table[] = {
 static const u16 VINTANA2_VSEL_table[] = {
        2500, 2750,
 };
-static const u16 VAUX1_6030_VSEL_table[] = {
-       1000, 1300, 1800, 2500,
-       2800, 2900, 3000, 3000,
-};
-static const u16 VAUX2_6030_VSEL_table[] = {
-       1200, 1800, 2500, 2750,
-       2800, 2800, 2800, 2800,
-};
-static const u16 VAUX3_6030_VSEL_table[] = {
-       1000, 1200, 1300, 1800,
-       2500, 2800, 3000, 3000,
-};
-static const u16 VMMC_VSEL_table[] = {
-       1200, 1800, 2800, 2900,
-       3000, 3000, 3000, 3000,
-};
-static const u16 VPP_VSEL_table[] = {
-       1800, 1900, 2000, 2100,
-       2200, 2300, 2400, 2500,
-};
-static const u16 VUSIM_VSEL_table[] = {
-       1200, 1800, 2500, 2900,
-};
 
-static int twlldo_list_voltage(struct regulator_dev *rdev, unsigned index)
+static int twl4030ldo_list_voltage(struct regulator_dev *rdev, unsigned index)
 {
        struct twlreg_info      *info = rdev_get_drvdata(rdev);
        int                     mV = info->table[index];
@@ -351,7 +329,7 @@ static int twlldo_list_voltage(struct regulator_dev *rdev, unsigned index)
 }
 
 static int
-twlldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
+twl4030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
 {
        struct twlreg_info      *info = rdev_get_drvdata(rdev);
        int                     vsel;
@@ -375,7 +353,7 @@ twlldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
        return -EDOM;
 }
 
-static int twlldo_get_voltage(struct regulator_dev *rdev)
+static int twl4030ldo_get_voltage(struct regulator_dev *rdev)
 {
        struct twlreg_info      *info = rdev_get_drvdata(rdev);
        int             vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER,
@@ -388,11 +366,67 @@ static int twlldo_get_voltage(struct regulator_dev *rdev)
        return LDO_MV(info->table[vsel]) * 1000;
 }
 
-static struct regulator_ops twlldo_ops = {
-       .list_voltage   = twlldo_list_voltage,
+static struct regulator_ops twl4030ldo_ops = {
+       .list_voltage   = twl4030ldo_list_voltage,
 
-       .set_voltage    = twlldo_set_voltage,
-       .get_voltage    = twlldo_get_voltage,
+       .set_voltage    = twl4030ldo_set_voltage,
+       .get_voltage    = twl4030ldo_get_voltage,
+
+       .enable         = twlreg_enable,
+       .disable        = twlreg_disable,
+       .is_enabled     = twlreg_is_enabled,
+
+       .set_mode       = twlreg_set_mode,
+
+       .get_status     = twlreg_get_status,
+};
+
+static int twl6030ldo_list_voltage(struct regulator_dev *rdev, unsigned index)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+
+       return ((info->min_mV + (index * 100)) * 1000);
+}
+
+static int
+twl6030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+       int                     vsel;
+
+       if ((min_uV/1000 < info->min_mV) || (max_uV/1000 > info->max_mV))
+               return -EDOM;
+
+       /*
+        * Use the below formula to calculate vsel
+        * mV = 1000mv + 100mv * (vsel - 1)
+        */
+       vsel = (min_uV/1000 - 1000)/100 + 1;
+       return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE, vsel);
+
+}
+
+static int twl6030ldo_get_voltage(struct regulator_dev *rdev)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+       int             vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER,
+                                                               VREG_VOLTAGE);
+
+       if (vsel < 0)
+               return vsel;
+
+       /*
+        * Use the below formula to calculate vsel
+        * mV = 1000mv + 100mv * (vsel - 1)
+        */
+       return (1000 + (100 * (vsel - 1))) * 1000;
+}
+
+static struct regulator_ops twl6030ldo_ops = {
+       .list_voltage   = twl6030ldo_list_voltage,
+
+       .set_voltage    = twl6030ldo_set_voltage,
+       .get_voltage    = twl6030ldo_get_voltage,
 
        .enable         = twlreg_enable,
        .disable        = twlreg_disable,
@@ -438,24 +472,16 @@ static struct regulator_ops twlfixed_ops = {
 
 /*----------------------------------------------------------------------*/
 
-#define TWL4030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf) \
-               TWL_ADJUSTABLE_LDO(label, offset, num, turnon_delay, \
-                       remap_conf, TWL4030)
 #define TWL4030_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
                        remap_conf) \
                TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
                        remap_conf, TWL4030)
-#define TWL6030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, \
-                       remap_conf) \
-               TWL_ADJUSTABLE_LDO(label, offset, num, turnon_delay, \
-                       remap_conf, TWL6030)
 #define TWL6030_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
                        remap_conf) \
                TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
                        remap_conf, TWL6030)
 
-#define TWL_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf, \
-               family) { \
+#define TWL4030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf) { \
        .base = offset, \
        .id = num, \
        .table_len = ARRAY_SIZE(label##_VSEL_table), \
@@ -464,14 +490,32 @@ static struct regulator_ops twlfixed_ops = {
        .remap = remap_conf, \
        .desc = { \
                .name = #label, \
-               .id = family##_REG_##label, \
+               .id = TWL4030_REG_##label, \
                .n_voltages = ARRAY_SIZE(label##_VSEL_table), \
-               .ops = &twlldo_ops, \
+               .ops = &twl4030ldo_ops, \
                .type = REGULATOR_VOLTAGE, \
                .owner = THIS_MODULE, \
                }, \
        }
 
+#define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts, num, \
+               remap_conf) { \
+       .base = offset, \
+       .id = num, \
+       .min_mV = min_mVolts, \
+       .max_mV = max_mVolts, \
+       .remap = remap_conf, \
+       .desc = { \
+               .name = #label, \
+               .id = TWL6030_REG_##label, \
+               .n_voltages = (max_mVolts - min_mVolts)/100, \
+               .ops = &twl6030ldo_ops, \
+               .type = REGULATOR_VOLTAGE, \
+               .owner = THIS_MODULE, \
+               }, \
+       }
+
+
 #define TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, remap_conf, \
                family) { \
        .base = offset, \
@@ -519,12 +563,12 @@ static struct twlreg_info twl_regs[] = {
        /* 6030 REG with base as PMC Slave Misc : 0x0030 */
        /* Turnon-delay and remap configuration values for 6030 are not
           verified since the specification is not public */
-       TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1, 0, 0x21),
-       TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 2, 0, 0x21),
-       TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 3, 0, 0x21),
-       TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 4, 0, 0x21),
-       TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 5, 0, 0x21),
-       TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 7, 0, 0x21),
+       TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1000, 3300, 1, 0x21),
+       TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 1000, 3300, 2, 0x21),
+       TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 1000, 3300, 3, 0x21),
+       TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 1000, 3300, 4, 0x21),
+       TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 1000, 3300, 5, 0x21),
+       TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 1000, 3300, 7, 0x21),
        TWL6030_FIXED_LDO(VANA, 0x50, 2100, 15, 0, 0x21),
        TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 16, 0, 0x21),
        TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 17, 0, 0x21),
index 50ac047cd136e16e7fb1b6baf34e9b7dd6bc66bc..10ba12c8c5e004a044c59ec7a77a91f58cf8f61e 100644 (file)
@@ -611,6 +611,13 @@ config RTC_DRV_AB3100
          Select this to enable the ST-Ericsson AB3100 Mixed Signal IC RTC
          support. This chip contains a battery- and capacitor-backed RTC.
 
+config RTC_DRV_AB8500
+       tristate "ST-Ericsson AB8500 RTC"
+       depends on AB8500_CORE
+       help
+         Select this to enable the ST-Ericsson AB8500 power management IC RTC
+         support. This chip contains a battery- and capacitor-backed RTC.
+
 config RTC_DRV_NUC900
        tristate "NUC910/NUC920 RTC driver"
        depends on RTC_CLASS && ARCH_W90X900
@@ -640,7 +647,7 @@ config RTC_DRV_OMAP
 
 config RTC_DRV_S3C
        tristate "Samsung S3C series SoC RTC"
-       depends on ARCH_S3C2410
+       depends on ARCH_S3C2410 || ARCH_S3C64XX
        help
          RTC (Realtime Clock) driver for the clock inbuilt into the
          Samsung S3C24XX series of SoCs. This can provide periodic
index 245311a1348fdae26755b76d153c7e4f2dcb8507..5adbba7cf89cfdde453caf77e4571ab1786b9b16 100644 (file)
@@ -18,6 +18,7 @@ rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
 # Keep the list ordered.
 
 obj-$(CONFIG_RTC_DRV_AB3100)   += rtc-ab3100.o
+obj-$(CONFIG_RTC_DRV_AB8500)   += rtc-ab8500.o
 obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o
 obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
 obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o
diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c
new file mode 100644 (file)
index 0000000..2fda031
--- /dev/null
@@ -0,0 +1,363 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ * Author: Virupax Sadashivpetimath <virupax.sadashivpetimath@stericsson.com>
+ *
+ * RTC clock driver for the RTC part of the AB8500 Power management chip.
+ * Based on RTC clock driver for the AB3100 Analog Baseband Chip by
+ * Linus Walleij <linus.walleij@stericsson.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/mfd/ab8500.h>
+#include <linux/delay.h>
+
+#define AB8500_RTC_SOFF_STAT_REG       0x0F00
+#define AB8500_RTC_CC_CONF_REG         0x0F01
+#define AB8500_RTC_READ_REQ_REG                0x0F02
+#define AB8500_RTC_WATCH_TSECMID_REG   0x0F03
+#define AB8500_RTC_WATCH_TSECHI_REG    0x0F04
+#define AB8500_RTC_WATCH_TMIN_LOW_REG  0x0F05
+#define AB8500_RTC_WATCH_TMIN_MID_REG  0x0F06
+#define AB8500_RTC_WATCH_TMIN_HI_REG   0x0F07
+#define AB8500_RTC_ALRM_MIN_LOW_REG    0x0F08
+#define AB8500_RTC_ALRM_MIN_MID_REG    0x0F09
+#define AB8500_RTC_ALRM_MIN_HI_REG     0x0F0A
+#define AB8500_RTC_STAT_REG            0x0F0B
+#define AB8500_RTC_BKUP_CHG_REG                0x0F0C
+#define AB8500_RTC_FORCE_BKUP_REG      0x0F0D
+#define AB8500_RTC_CALIB_REG           0x0F0E
+#define AB8500_RTC_SWITCH_STAT_REG     0x0F0F
+#define AB8500_REV_REG                 0x1080
+
+/* RtcReadRequest bits */
+#define RTC_READ_REQUEST               0x01
+#define RTC_WRITE_REQUEST              0x02
+
+/* RtcCtrl bits */
+#define RTC_ALARM_ENA                  0x04
+#define RTC_STATUS_DATA                        0x01
+
+#define COUNTS_PER_SEC                 (0xF000 / 60)
+#define AB8500_RTC_EPOCH               2000
+
+static const unsigned long ab8500_rtc_time_regs[] = {
+       AB8500_RTC_WATCH_TMIN_HI_REG, AB8500_RTC_WATCH_TMIN_MID_REG,
+       AB8500_RTC_WATCH_TMIN_LOW_REG, AB8500_RTC_WATCH_TSECHI_REG,
+       AB8500_RTC_WATCH_TSECMID_REG
+};
+
+static const unsigned long ab8500_rtc_alarm_regs[] = {
+       AB8500_RTC_ALRM_MIN_HI_REG, AB8500_RTC_ALRM_MIN_MID_REG,
+       AB8500_RTC_ALRM_MIN_LOW_REG
+};
+
+/* Calculate the seconds from 1970 to 01-01-2000 00:00:00 */
+static unsigned long get_elapsed_seconds(int year)
+{
+       unsigned long secs;
+       struct rtc_time tm = {
+               .tm_year = year - 1900,
+               .tm_mday = 1,
+       };
+
+       /*
+        * This function calculates secs from 1970 and not from
+        * 1900, even if we supply the offset from year 1900.
+        */
+       rtc_tm_to_time(&tm, &secs);
+       return secs;
+}
+
+static int ab8500_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
+       unsigned long timeout = jiffies + HZ;
+       int retval, i;
+       unsigned long mins, secs;
+       unsigned char buf[ARRAY_SIZE(ab8500_rtc_time_regs)];
+
+       /* Request a data read */
+       retval = ab8500_write(ab8500, AB8500_RTC_READ_REQ_REG,
+                             RTC_READ_REQUEST);
+       if (retval < 0)
+               return retval;
+
+       /* Early AB8500 chips will not clear the rtc read request bit */
+       if (ab8500->revision == 0) {
+               msleep(1);
+       } else {
+               /* Wait for some cycles after enabling the rtc read in ab8500 */
+               while (time_before(jiffies, timeout)) {
+                       retval = ab8500_read(ab8500, AB8500_RTC_READ_REQ_REG);
+                       if (retval < 0)
+                               return retval;
+
+                       if (!(retval & RTC_READ_REQUEST))
+                               break;
+
+                       msleep(1);
+               }
+       }
+
+       /* Read the Watchtime registers */
+       for (i = 0; i < ARRAY_SIZE(ab8500_rtc_time_regs); i++) {
+               retval = ab8500_read(ab8500, ab8500_rtc_time_regs[i]);
+               if (retval < 0)
+                       return retval;
+               buf[i] = retval;
+       }
+
+       mins = (buf[0] << 16) | (buf[1] << 8) | buf[2];
+
+       secs =  (buf[3] << 8) | buf[4];
+       secs =  secs / COUNTS_PER_SEC;
+       secs =  secs + (mins * 60);
+
+       /* Add back the initially subtracted number of seconds */
+       secs += get_elapsed_seconds(AB8500_RTC_EPOCH);
+
+       rtc_time_to_tm(secs, tm);
+       return rtc_valid_tm(tm);
+}
+
+static int ab8500_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
+       int retval, i;
+       unsigned char buf[ARRAY_SIZE(ab8500_rtc_time_regs)];
+       unsigned long no_secs, no_mins, secs = 0;
+
+       if (tm->tm_year < (AB8500_RTC_EPOCH - 1900)) {
+               dev_dbg(dev, "year should be equal to or greater than %d\n",
+                               AB8500_RTC_EPOCH);
+               return -EINVAL;
+       }
+
+       /* Get the number of seconds since 1970 */
+       rtc_tm_to_time(tm, &secs);
+
+       /*
+        * Convert it to the number of seconds since 01-01-2000 00:00:00, since
+        * we only have a small counter in the RTC.
+        */
+       secs -= get_elapsed_seconds(AB8500_RTC_EPOCH);
+
+       no_mins = secs / 60;
+
+       no_secs = secs % 60;
+       /* Make the seconds count as per the RTC resolution */
+       no_secs = no_secs * COUNTS_PER_SEC;
+
+       buf[4] = no_secs & 0xFF;
+       buf[3] = (no_secs >> 8) & 0xFF;
+
+       buf[2] = no_mins & 0xFF;
+       buf[1] = (no_mins >> 8) & 0xFF;
+       buf[0] = (no_mins >> 16) & 0xFF;
+
+       for (i = 0; i < ARRAY_SIZE(ab8500_rtc_time_regs); i++) {
+               retval = ab8500_write(ab8500, ab8500_rtc_time_regs[i], buf[i]);
+               if (retval < 0)
+                       return retval;
+       }
+
+       /* Request a data write */
+       return ab8500_write(ab8500, AB8500_RTC_READ_REQ_REG, RTC_WRITE_REQUEST);
+}
+
+static int ab8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+       struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
+       int retval, i;
+       int rtc_ctrl;
+       unsigned char buf[ARRAY_SIZE(ab8500_rtc_alarm_regs)];
+       unsigned long secs, mins;
+
+       /* Check if the alarm is enabled or not */
+       rtc_ctrl = ab8500_read(ab8500, AB8500_RTC_STAT_REG);
+       if (rtc_ctrl < 0)
+               return rtc_ctrl;
+
+       if (rtc_ctrl & RTC_ALARM_ENA)
+               alarm->enabled = 1;
+       else
+               alarm->enabled = 0;
+
+       alarm->pending = 0;
+
+       for (i = 0; i < ARRAY_SIZE(ab8500_rtc_alarm_regs); i++) {
+               retval = ab8500_read(ab8500, ab8500_rtc_alarm_regs[i]);
+               if (retval < 0)
+                       return retval;
+               buf[i] = retval;
+       }
+
+       mins = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);
+       secs = mins * 60;
+
+       /* Add back the initially subtracted number of seconds */
+       secs += get_elapsed_seconds(AB8500_RTC_EPOCH);
+
+       rtc_time_to_tm(secs, &alarm->time);
+
+       return rtc_valid_tm(&alarm->time);
+}
+
+static int ab8500_rtc_irq_enable(struct device *dev, unsigned int enabled)
+{
+       struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
+
+       return ab8500_set_bits(ab8500, AB8500_RTC_STAT_REG, RTC_ALARM_ENA,
+                              enabled ? RTC_ALARM_ENA : 0);
+}
+
+static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+       struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
+       int retval, i;
+       unsigned char buf[ARRAY_SIZE(ab8500_rtc_alarm_regs)];
+       unsigned long mins, secs = 0;
+
+       if (alarm->time.tm_year < (AB8500_RTC_EPOCH - 1900)) {
+               dev_dbg(dev, "year should be equal to or greater than %d\n",
+                               AB8500_RTC_EPOCH);
+               return -EINVAL;
+       }
+
+       /* Get the number of seconds since 1970 */
+       rtc_tm_to_time(&alarm->time, &secs);
+
+       /*
+        * Convert it to the number of seconds since 01-01-2000 00:00:00, since
+        * we only have a small counter in the RTC.
+        */
+       secs -= get_elapsed_seconds(AB8500_RTC_EPOCH);
+
+       mins = secs / 60;
+
+       buf[2] = mins & 0xFF;
+       buf[1] = (mins >> 8) & 0xFF;
+       buf[0] = (mins >> 16) & 0xFF;
+
+       /* Set the alarm time */
+       for (i = 0; i < ARRAY_SIZE(ab8500_rtc_alarm_regs); i++) {
+               retval = ab8500_write(ab8500, ab8500_rtc_alarm_regs[i], buf[i]);
+               if (retval < 0)
+                       return retval;
+       }
+
+       return ab8500_rtc_irq_enable(dev, alarm->enabled);
+}
+
+static irqreturn_t rtc_alarm_handler(int irq, void *data)
+{
+       struct rtc_device *rtc = data;
+       unsigned long events = RTC_IRQF | RTC_AF;
+
+       dev_dbg(&rtc->dev, "%s\n", __func__);
+       rtc_update_irq(rtc, 1, events);
+
+       return IRQ_HANDLED;
+}
+
+static const struct rtc_class_ops ab8500_rtc_ops = {
+       .read_time              = ab8500_rtc_read_time,
+       .set_time               = ab8500_rtc_set_time,
+       .read_alarm             = ab8500_rtc_read_alarm,
+       .set_alarm              = ab8500_rtc_set_alarm,
+       .alarm_irq_enable       = ab8500_rtc_irq_enable,
+};
+
+static int __devinit ab8500_rtc_probe(struct platform_device *pdev)
+{
+       struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
+       int err;
+       struct rtc_device *rtc;
+       int rtc_ctrl;
+       int irq;
+
+       irq = platform_get_irq_byname(pdev, "ALARM");
+       if (irq < 0)
+               return irq;
+
+       /* For RTC supply test */
+       err = ab8500_set_bits(ab8500, AB8500_RTC_STAT_REG, RTC_STATUS_DATA,
+                       RTC_STATUS_DATA);
+       if (err < 0)
+               return err;
+
+       /* Wait for reset by the PorRtc */
+       msleep(1);
+
+       rtc_ctrl = ab8500_read(ab8500, AB8500_RTC_STAT_REG);
+       if (rtc_ctrl < 0)
+               return rtc_ctrl;
+
+       /* Check if the RTC Supply fails */
+       if (!(rtc_ctrl & RTC_STATUS_DATA)) {
+               dev_err(&pdev->dev, "RTC supply failure\n");
+               return -ENODEV;
+       }
+
+       rtc = rtc_device_register("ab8500-rtc", &pdev->dev, &ab8500_rtc_ops,
+                       THIS_MODULE);
+       if (IS_ERR(rtc)) {
+               dev_err(&pdev->dev, "Registration failed\n");
+               err = PTR_ERR(rtc);
+               return err;
+       }
+
+       err = request_threaded_irq(irq, NULL, rtc_alarm_handler, 0,
+                                  "ab8500-rtc", rtc);
+       if (err < 0) {
+               rtc_device_unregister(rtc);
+               return err;
+       }
+
+       platform_set_drvdata(pdev, rtc);
+
+       return 0;
+}
+
+static int __devexit ab8500_rtc_remove(struct platform_device *pdev)
+{
+       struct rtc_device *rtc = platform_get_drvdata(pdev);
+       int irq = platform_get_irq_byname(pdev, "ALARM");
+
+       free_irq(irq, rtc);
+       rtc_device_unregister(rtc);
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver ab8500_rtc_driver = {
+       .driver = {
+               .name = "ab8500-rtc",
+               .owner = THIS_MODULE,
+       },
+       .probe  = ab8500_rtc_probe,
+       .remove = __devexit_p(ab8500_rtc_remove),
+};
+
+static int __init ab8500_rtc_init(void)
+{
+       return platform_driver_register(&ab8500_rtc_driver);
+}
+
+static void __exit ab8500_rtc_exit(void)
+{
+       platform_driver_unregister(&ab8500_rtc_driver);
+}
+
+module_init(ab8500_rtc_init);
+module_exit(ab8500_rtc_exit);
+MODULE_AUTHOR("Virupax Sadashivpetimath <virupax.sadashivpetimath@stericsson.com>");
+MODULE_DESCRIPTION("AB8500 RTC Driver");
+MODULE_LICENSE("GPL v2");
index 96e8e70fbf1e1be9136a448cedd23ad1ec2f834d..11b8ea29d2b76ecf0e60e482195629d4d04d17f6 100644 (file)
@@ -719,6 +719,9 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
                }
        }
 
+       cmos_rtc.dev = dev;
+       dev_set_drvdata(dev, &cmos_rtc);
+
        cmos_rtc.rtc = rtc_device_register(driver_name, dev,
                                &cmos_rtc_ops, THIS_MODULE);
        if (IS_ERR(cmos_rtc.rtc)) {
@@ -726,8 +729,6 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
                goto cleanup0;
        }
 
-       cmos_rtc.dev = dev;
-       dev_set_drvdata(dev, &cmos_rtc);
        rename_region(ports, dev_name(&cmos_rtc.rtc->dev));
 
        spin_lock_irq(&rtc_lock);
index 532acf9b05d895f2a7c8762ce0ec9c98cfe620ff..359d1e04626cb938784290a5700058a3115d7b34 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/rtc.h>
 #include <linux/io.h>
 #include <linux/bcd.h>
-#include <asm/rtc.h>
 
 #define DRV_NAME       "rtc-ds1302"
 #define DRV_VERSION    "0.1.1"
 #define        RTC_ADDR_MIN    0x01            /* Address of minute register */
 #define        RTC_ADDR_SEC    0x00            /* Address of second register */
 
+#ifdef CONFIG_SH_SECUREEDGE5410
+#include <asm/rtc.h>
+#include <mach/snapgear.h>
+
 #define        RTC_RESET       0x1000
 #define        RTC_IODATA      0x0800
 #define        RTC_SCLK        0x0400
 
-#ifdef CONFIG_SH_SECUREEDGE5410
-#include <mach/snapgear.h>
 #define set_dp(x)      SECUREEDGE_WRITE_IOPORT(x, 0x1c00)
 #define get_dp()       SECUREEDGE_READ_IOPORT()
+#define ds1302_set_tx()
+#define ds1302_set_rx()
+
+static inline int ds1302_hw_init(void)
+{
+       return 0;
+}
+
+static inline void ds1302_reset(void)
+{
+       set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
+}
+
+static inline void ds1302_clock(void)
+{
+       set_dp(get_dp() | RTC_SCLK);    /* clock high */
+       set_dp(get_dp() & ~RTC_SCLK);   /* clock low */
+}
+
+static inline void ds1302_start(void)
+{
+       set_dp(get_dp() | RTC_RESET);
+}
+
+static inline void ds1302_stop(void)
+{
+       set_dp(get_dp() & ~RTC_RESET);
+}
+
+static inline void ds1302_txbit(int bit)
+{
+       set_dp((get_dp() & ~RTC_IODATA) | (bit ? RTC_IODATA : 0));
+}
+
+static inline int ds1302_rxbit(void)
+{
+       return !!(get_dp() & RTC_IODATA);
+}
+
 #else
 #error "Add support for your platform"
 #endif
@@ -50,11 +90,11 @@ static void ds1302_sendbits(unsigned int val)
 {
        int i;
 
+       ds1302_set_tx();
+
        for (i = 8; (i); i--, val >>= 1) {
-               set_dp((get_dp() & ~RTC_IODATA) | ((val & 0x1) ?
-                       RTC_IODATA : 0));
-               set_dp(get_dp() | RTC_SCLK);    /* clock high */
-               set_dp(get_dp() & ~RTC_SCLK);   /* clock low */
+               ds1302_txbit(val & 0x1);
+               ds1302_clock();
        }
 }
 
@@ -63,10 +103,11 @@ static unsigned int ds1302_recvbits(void)
        unsigned int val;
        int i;
 
+       ds1302_set_rx();
+
        for (i = 0, val = 0; (i < 8); i++) {
-               val |= (((get_dp() & RTC_IODATA) ? 1 : 0) << i);
-               set_dp(get_dp() | RTC_SCLK);    /* clock high */
-               set_dp(get_dp() & ~RTC_SCLK);   /* clock low */
+               val |= (ds1302_rxbit() << i);
+               ds1302_clock();
        }
 
        return val;
@@ -76,23 +117,24 @@ static unsigned int ds1302_readbyte(unsigned int addr)
 {
        unsigned int val;
 
-       set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
+       ds1302_reset();
 
-       set_dp(get_dp() | RTC_RESET);
+       ds1302_start();
        ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_READ);
        val = ds1302_recvbits();
-       set_dp(get_dp() & ~RTC_RESET);
+       ds1302_stop();
 
        return val;
 }
 
 static void ds1302_writebyte(unsigned int addr, unsigned int val)
 {
-       set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
-       set_dp(get_dp() | RTC_RESET);
+       ds1302_reset();
+
+       ds1302_start();
        ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_WRITE);
        ds1302_sendbits(val);
-       set_dp(get_dp() & ~RTC_RESET);
+       ds1302_stop();
 }
 
 static int ds1302_rtc_read_time(struct device *dev, struct rtc_time *tm)
@@ -167,13 +209,20 @@ static int __init ds1302_rtc_probe(struct platform_device *pdev)
 {
        struct rtc_device *rtc;
 
+       if (ds1302_hw_init()) {
+               dev_err(&pdev->dev, "Failed to init communication channel");
+               return -EINVAL;
+       }
+
        /* Reset */
-       set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
+       ds1302_reset();
 
        /* Write a magic value to the DS1302 RAM, and see if it sticks. */
        ds1302_writebyte(RTC_ADDR_RAM0, 0x42);
-       if (ds1302_readbyte(RTC_ADDR_RAM0) != 0x42)
+       if (ds1302_readbyte(RTC_ADDR_RAM0) != 0x42) {
+               dev_err(&pdev->dev, "Failed to probe");
                return -ENODEV;
+       }
 
        rtc = rtc_device_register("ds1302", &pdev->dev,
                                           &ds1302_rtc_ops, THIS_MODULE);
index 054e05294af8566e30d3834fc23c793b615239f9..468200c38ecbf4116e0abf1873aec8f0e65e85fd 100644 (file)
@@ -462,39 +462,16 @@ isl1208_sysfs_store_usr(struct device *dev,
 static DEVICE_ATTR(usr, S_IRUGO | S_IWUSR, isl1208_sysfs_show_usr,
                   isl1208_sysfs_store_usr);
 
-static int
-isl1208_sysfs_register(struct device *dev)
-{
-       int err;
-
-       err = device_create_file(dev, &dev_attr_atrim);
-       if (err)
-               return err;
-
-       err = device_create_file(dev, &dev_attr_dtrim);
-       if (err) {
-               device_remove_file(dev, &dev_attr_atrim);
-               return err;
-       }
-
-       err = device_create_file(dev, &dev_attr_usr);
-       if (err) {
-               device_remove_file(dev, &dev_attr_atrim);
-               device_remove_file(dev, &dev_attr_dtrim);
-       }
-
-       return 0;
-}
-
-static int
-isl1208_sysfs_unregister(struct device *dev)
-{
-       device_remove_file(dev, &dev_attr_dtrim);
-       device_remove_file(dev, &dev_attr_atrim);
-       device_remove_file(dev, &dev_attr_usr);
+static struct attribute *isl1208_rtc_attrs[] = {
+       &dev_attr_atrim.attr,
+       &dev_attr_dtrim.attr,
+       &dev_attr_usr.attr,
+       NULL
+};
 
-       return 0;
-}
+static const struct attribute_group isl1208_rtc_sysfs_files = {
+       .attrs  = isl1208_rtc_attrs,
+};
 
 static int
 isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
@@ -529,7 +506,7 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
                dev_warn(&client->dev, "rtc power failure detected, "
                         "please set clock.\n");
 
-       rc = isl1208_sysfs_register(&client->dev);
+       rc = sysfs_create_group(&client->dev.kobj, &isl1208_rtc_sysfs_files);
        if (rc)
                goto exit_unregister;
 
@@ -546,7 +523,7 @@ isl1208_remove(struct i2c_client *client)
 {
        struct rtc_device *rtc = i2c_get_clientdata(client);
 
-       isl1208_sysfs_unregister(&client->dev);
+       sysfs_remove_group(&client->dev.kobj, &isl1208_rtc_sysfs_files);
        rtc_device_unregister(rtc);
 
        return 0;
index 60fe266f0f494c7bd5db9b93763f4f4b7e7b2745..6dc4e6241418ac601a40abf5dfb0744401d44d5d 100644 (file)
@@ -595,10 +595,6 @@ static void wdt_disable(void)
 static ssize_t wdt_write(struct file *file, const char __user *buf,
                         size_t count, loff_t *ppos)
 {
-       /*  Can't seek (pwrite) on this device
-       if (ppos != &file->f_pos)
-       return -ESPIPE;
-       */
        if (count) {
                wdt_ping();
                return 1;
@@ -623,7 +619,7 @@ static ssize_t wdt_read(struct file *file, char __user *buf,
  *     according to their available features. We only actually usefully support
  *     querying capabilities and current status.
  */
-static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+static int wdt_ioctl(struct file *file, unsigned int cmd,
                     unsigned long arg)
 {
        int new_margin, rv;
@@ -676,6 +672,18 @@ static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
        return -ENOTTY;
 }
 
+static long wdt_unlocked_ioctl(struct file *file, unsigned int cmd,
+                              unsigned long arg)
+{
+       int ret;
+
+       lock_kernel();
+       ret = wdt_ioctl(file, cmd, arg);
+       unlock_kernel();
+
+       return ret;
+}
+
 /**
  *     wdt_open:
  *     @inode: inode of device
@@ -695,7 +703,7 @@ static int wdt_open(struct inode *inode, struct file *file)
                 */
                wdt_is_open = 1;
                unlock_kernel();
-               return 0;
+               return nonseekable_open(inode, file);
        }
        return -ENODEV;
 }
@@ -736,7 +744,7 @@ static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
 static const struct file_operations wdt_fops = {
        .owner  = THIS_MODULE,
        .read   = wdt_read,
-       .ioctl  = wdt_ioctl,
+       .unlocked_ioctl = wdt_unlocked_ioctl,
        .write  = wdt_write,
        .open   = wdt_open,
        .release = wdt_release,
index d71fe61db1d655427e3d10b40113482ee2063a4e..25ec921db07c8a4f5b1ef9f3f2016329007c8f7e 100644 (file)
@@ -379,7 +379,6 @@ static struct rtc_class_ops mxc_rtc_ops = {
 
 static int __init mxc_rtc_probe(struct platform_device *pdev)
 {
-       struct clk *clk;
        struct resource *res;
        struct rtc_device *rtc;
        struct rtc_plat_data *pdata = NULL;
@@ -402,14 +401,15 @@ static int __init mxc_rtc_probe(struct platform_device *pdev)
        pdata->ioaddr = devm_ioremap(&pdev->dev, res->start,
                                     resource_size(res));
 
-       clk = clk_get(&pdev->dev, "ckil");
-       if (IS_ERR(clk)) {
-               ret = PTR_ERR(clk);
+       pdata->clk = clk_get(&pdev->dev, "rtc");
+       if (IS_ERR(pdata->clk)) {
+               dev_err(&pdev->dev, "unable to get clock!\n");
+               ret = PTR_ERR(pdata->clk);
                goto exit_free_pdata;
        }
 
-       rate = clk_get_rate(clk);
-       clk_put(clk);
+       clk_enable(pdata->clk);
+       rate = clk_get_rate(pdata->clk);
 
        if (rate == 32768)
                reg = RTC_INPUT_CLK_32768HZ;
@@ -420,7 +420,7 @@ static int __init mxc_rtc_probe(struct platform_device *pdev)
        else {
                dev_err(&pdev->dev, "rtc clock is not valid (%lu)\n", rate);
                ret = -EINVAL;
-               goto exit_free_pdata;
+               goto exit_put_clk;
        }
 
        reg |= RTC_ENABLE_BIT;
@@ -428,18 +428,9 @@ static int __init mxc_rtc_probe(struct platform_device *pdev)
        if (((readw(pdata->ioaddr + RTC_RTCCTL)) & RTC_ENABLE_BIT) == 0) {
                dev_err(&pdev->dev, "hardware module can't be enabled!\n");
                ret = -EIO;
-               goto exit_free_pdata;
-       }
-
-       pdata->clk = clk_get(&pdev->dev, "rtc");
-       if (IS_ERR(pdata->clk)) {
-               dev_err(&pdev->dev, "unable to get clock!\n");
-               ret = PTR_ERR(pdata->clk);
-               goto exit_free_pdata;
+               goto exit_put_clk;
        }
 
-       clk_enable(pdata->clk);
-
        rtc = rtc_device_register(pdev->name, &pdev->dev, &mxc_rtc_ops,
                                  THIS_MODULE);
        if (IS_ERR(rtc)) {
index 4969b6059c896e3fafe9ee9d8bf591fdc87f03b0..e5972b2c17b7be04be983a4460ca5aec5c7063d2 100644 (file)
 #include <asm/irq.h>
 #include <plat/regs-rtc.h>
 
+enum s3c_cpu_type {
+       TYPE_S3C2410,
+       TYPE_S3C64XX,
+};
+
 /* I have yet to find an S3C implementation with more than one
  * of these rtc blocks in */
 
@@ -37,6 +42,7 @@ static struct resource *s3c_rtc_mem;
 static void __iomem *s3c_rtc_base;
 static int s3c_rtc_alarmno = NO_IRQ;
 static int s3c_rtc_tickno  = NO_IRQ;
+static enum s3c_cpu_type s3c_rtc_cpu_type;
 
 static DEFINE_SPINLOCK(s3c_rtc_pie_lock);
 
@@ -80,12 +86,25 @@ static int s3c_rtc_setpie(struct device *dev, int enabled)
        pr_debug("%s: pie=%d\n", __func__, enabled);
 
        spin_lock_irq(&s3c_rtc_pie_lock);
-       tmp = readb(s3c_rtc_base + S3C2410_TICNT) & ~S3C2410_TICNT_ENABLE;
 
-       if (enabled)
-               tmp |= S3C2410_TICNT_ENABLE;
+       if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
+               tmp = readb(s3c_rtc_base + S3C2410_RTCCON);
+               tmp &= ~S3C64XX_RTCCON_TICEN;
+
+               if (enabled)
+                       tmp |= S3C64XX_RTCCON_TICEN;
+
+               writeb(tmp, s3c_rtc_base + S3C2410_RTCCON);
+       } else {
+               tmp = readb(s3c_rtc_base + S3C2410_TICNT);
+               tmp &= ~S3C2410_TICNT_ENABLE;
+
+               if (enabled)
+                       tmp |= S3C2410_TICNT_ENABLE;
+
+               writeb(tmp, s3c_rtc_base + S3C2410_TICNT);
+       }
 
-       writeb(tmp, s3c_rtc_base + S3C2410_TICNT);
        spin_unlock_irq(&s3c_rtc_pie_lock);
 
        return 0;
@@ -93,15 +112,21 @@ static int s3c_rtc_setpie(struct device *dev, int enabled)
 
 static int s3c_rtc_setfreq(struct device *dev, int freq)
 {
-       unsigned int tmp;
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rtc_device *rtc_dev = platform_get_drvdata(pdev);
+       unsigned int tmp = 0;
 
        if (!is_power_of_2(freq))
                return -EINVAL;
 
        spin_lock_irq(&s3c_rtc_pie_lock);
 
-       tmp = readb(s3c_rtc_base + S3C2410_TICNT) & S3C2410_TICNT_ENABLE;
-       tmp |= (128 / freq)-1;
+       if (s3c_rtc_cpu_type == TYPE_S3C2410) {
+               tmp = readb(s3c_rtc_base + S3C2410_TICNT);
+               tmp &= S3C2410_TICNT_ENABLE;
+       }
+
+       tmp |= (rtc_dev->max_user_freq / freq)-1;
 
        writeb(tmp, s3c_rtc_base + S3C2410_TICNT);
        spin_unlock_irq(&s3c_rtc_pie_lock);
@@ -283,10 +308,17 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
 
 static int s3c_rtc_proc(struct device *dev, struct seq_file *seq)
 {
-       unsigned int ticnt = readb(s3c_rtc_base + S3C2410_TICNT);
+       unsigned int ticnt;
 
-       seq_printf(seq, "periodic_IRQ\t: %s\n",
-                    (ticnt & S3C2410_TICNT_ENABLE) ? "yes" : "no" );
+       if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
+               ticnt = readb(s3c_rtc_base + S3C2410_RTCCON);
+               ticnt &= S3C64XX_RTCCON_TICEN;
+       } else {
+               ticnt = readb(s3c_rtc_base + S3C2410_TICNT);
+               ticnt &= S3C2410_TICNT_ENABLE;
+       }
+
+       seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt  ? "yes" : "no");
        return 0;
 }
 
@@ -353,10 +385,16 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en)
 
        if (!en) {
                tmp = readb(base + S3C2410_RTCCON);
-               writeb(tmp & ~S3C2410_RTCCON_RTCEN, base + S3C2410_RTCCON);
-
-               tmp = readb(base + S3C2410_TICNT);
-               writeb(tmp & ~S3C2410_TICNT_ENABLE, base + S3C2410_TICNT);
+               if (s3c_rtc_cpu_type == TYPE_S3C64XX)
+                       tmp &= ~S3C64XX_RTCCON_TICEN;
+               tmp &= ~S3C2410_RTCCON_RTCEN;
+               writeb(tmp, base + S3C2410_RTCCON);
+
+               if (s3c_rtc_cpu_type == TYPE_S3C2410) {
+                       tmp = readb(base + S3C2410_TICNT);
+                       tmp &= ~S3C2410_TICNT_ENABLE;
+                       writeb(tmp, base + S3C2410_TICNT);
+               }
        } else {
                /* re-enable the device, and check it is ok */
 
@@ -472,7 +510,12 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
                goto err_nortc;
        }
 
-       rtc->max_user_freq = 128;
+       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);
        return 0;
@@ -492,20 +535,30 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
 
 /* RTC Power management control */
 
-static int ticnt_save;
+static int ticnt_save, ticnt_en_save;
 
 static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state)
 {
        /* save TICNT for anyone using periodic interrupts */
        ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);
+       if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
+               ticnt_en_save = readb(s3c_rtc_base + S3C2410_RTCCON);
+               ticnt_en_save &= S3C64XX_RTCCON_TICEN;
+       }
        s3c_rtc_enable(pdev, 0);
        return 0;
 }
 
 static int s3c_rtc_resume(struct platform_device *pdev)
 {
+       unsigned int tmp;
+
        s3c_rtc_enable(pdev, 1);
        writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
+       if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) {
+               tmp = readb(s3c_rtc_base + S3C2410_RTCCON);
+               writeb(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON);
+       }
        return 0;
 }
 #else
@@ -513,13 +566,27 @@ static int s3c_rtc_resume(struct platform_device *pdev)
 #define s3c_rtc_resume  NULL
 #endif
 
-static struct platform_driver s3c2410_rtc_driver = {
+static struct platform_device_id s3c_rtc_driver_ids[] = {
+       {
+               .name           = "s3c2410-rtc",
+               .driver_data    = TYPE_S3C2410,
+       }, {
+               .name           = "s3c64xx-rtc",
+               .driver_data    = TYPE_S3C64XX,
+       },
+       { }
+};
+
+MODULE_DEVICE_TABLE(platform, s3c_rtc_driver_ids);
+
+static struct platform_driver s3c_rtc_driver = {
        .probe          = s3c_rtc_probe,
        .remove         = __devexit_p(s3c_rtc_remove),
        .suspend        = s3c_rtc_suspend,
        .resume         = s3c_rtc_resume,
+       .id_table       = s3c_rtc_driver_ids,
        .driver         = {
-               .name   = "s3c2410-rtc",
+               .name   = "s3c-rtc",
                .owner  = THIS_MODULE,
        },
 };
@@ -529,12 +596,12 @@ static char __initdata banner[] = "S3C24XX RTC, (c) 2004,2006 Simtec Electronics
 static int __init s3c_rtc_init(void)
 {
        printk(banner);
-       return platform_driver_register(&s3c2410_rtc_driver);
+       return platform_driver_register(&s3c_rtc_driver);
 }
 
 static void __exit s3c_rtc_exit(void)
 {
-       platform_driver_unregister(&s3c2410_rtc_driver);
+       platform_driver_unregister(&s3c_rtc_driver);
 }
 
 module_init(s3c_rtc_init);
index b16cfe57a484b8590ab78e855963dc8840bd6d46..82931dc65c0bbc505460f4c3c1710accd3453723 100644 (file)
@@ -449,17 +449,17 @@ static int wm831x_rtc_probe(struct platform_device *pdev)
                goto err;
        }
 
-       ret = wm831x_request_irq(wm831x, per_irq, wm831x_per_irq,
-                                IRQF_TRIGGER_RISING, "wm831x_rtc_per",
-                                wm831x_rtc);
+       ret = request_threaded_irq(per_irq, NULL, wm831x_per_irq,
+                                  IRQF_TRIGGER_RISING, "RTC period",
+                                  wm831x_rtc);
        if (ret != 0) {
                dev_err(&pdev->dev, "Failed to request periodic IRQ %d: %d\n",
                        per_irq, ret);
        }
 
-       ret = wm831x_request_irq(wm831x, alm_irq, wm831x_alm_irq,
-                                IRQF_TRIGGER_RISING, "wm831x_rtc_alm",
-                                wm831x_rtc);
+       ret = request_threaded_irq(alm_irq, NULL, wm831x_alm_irq,
+                                  IRQF_TRIGGER_RISING, "RTC alarm",
+                                  wm831x_rtc);
        if (ret != 0) {
                dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n",
                        alm_irq, ret);
@@ -478,8 +478,8 @@ static int __devexit wm831x_rtc_remove(struct platform_device *pdev)
        int per_irq = platform_get_irq_byname(pdev, "PER");
        int alm_irq = platform_get_irq_byname(pdev, "ALM");
 
-       wm831x_free_irq(wm831x_rtc->wm831x, alm_irq, wm831x_rtc);
-       wm831x_free_irq(wm831x_rtc->wm831x, per_irq, wm831x_rtc);
+       free_irq(alm_irq, wm831x_rtc);
+       free_irq(per_irq, wm831x_rtc);
        rtc_device_unregister(wm831x_rtc->rtc);
        kfree(wm831x_rtc);
 
index 0e86247d791e1b68abd8fd95a966c83c7845dea8..33975e922d6524d47c5cbd1df034287ba21a9718 100644 (file)
@@ -1186,6 +1186,29 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
        dasd_schedule_device_bh(device);
 }
 
+enum uc_todo dasd_generic_uc_handler(struct ccw_device *cdev, struct irb *irb)
+{
+       struct dasd_device *device;
+
+       device = dasd_device_from_cdev_locked(cdev);
+
+       if (IS_ERR(device))
+               goto out;
+       if (test_bit(DASD_FLAG_OFFLINE, &device->flags) ||
+          device->state != device->target ||
+          !device->discipline->handle_unsolicited_interrupt){
+               dasd_put_device(device);
+               goto out;
+       }
+
+       dasd_device_clear_timer(device);
+       device->discipline->handle_unsolicited_interrupt(device, irb);
+       dasd_put_device(device);
+out:
+       return UC_TODO_RETRY;
+}
+EXPORT_SYMBOL_GPL(dasd_generic_uc_handler);
+
 /*
  * If we have an error on a dasd_block layer request then we cancel
  * and return all further requests from the same dasd_block as well.
index 5b1cd8d6e971eaf3601d84502f7043a60295681b..ab84da5592e8a0b00714ea1c25c81aea64eff604 100644 (file)
@@ -3436,6 +3436,7 @@ static struct ccw_driver dasd_eckd_driver = {
        .freeze      = dasd_generic_pm_freeze,
        .thaw        = dasd_generic_restore_device,
        .restore     = dasd_generic_restore_device,
+       .uc_handler  = dasd_generic_uc_handler,
 };
 
 /*
index 32fac186ba3f55f9bcc2cf377696b12bc252cbb2..49b431d135e066f8910777a90fec44ac37fe77ee 100644 (file)
@@ -617,6 +617,7 @@ int dasd_generic_notify(struct ccw_device *, int);
 void dasd_generic_handle_state_change(struct dasd_device *);
 int dasd_generic_pm_freeze(struct ccw_device *);
 int dasd_generic_restore_device(struct ccw_device *);
+enum uc_todo dasd_generic_uc_handler(struct ccw_device *, struct irb *);
 
 int dasd_generic_read_dev_chars(struct dasd_device *, int, void *, int);
 char *dasd_get_sense(struct irb *);
index 5f97ea2ee6b19f8b6ca80ac7e70239ab2f1dca7e..97b25d68e3e72c74c53994abf7cc140795774525 100644 (file)
@@ -123,8 +123,10 @@ ccwgroup_release (struct device *dev)
 
        for (i = 0; i < gdev->count; i++) {
                if (gdev->cdev[i]) {
+                       spin_lock_irq(gdev->cdev[i]->ccwlock);
                        if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev)
                                dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
+                       spin_unlock_irq(gdev->cdev[i]->ccwlock);
                        put_device(&gdev->cdev[i]->dev);
                }
        }
@@ -262,11 +264,14 @@ int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
                        goto error;
                }
                /* Don't allow a device to belong to more than one group. */
+               spin_lock_irq(gdev->cdev[i]->ccwlock);
                if (dev_get_drvdata(&gdev->cdev[i]->dev)) {
+                       spin_unlock_irq(gdev->cdev[i]->ccwlock);
                        rc = -EINVAL;
                        goto error;
                }
                dev_set_drvdata(&gdev->cdev[i]->dev, gdev);
+               spin_unlock_irq(gdev->cdev[i]->ccwlock);
        }
        /* Check for sufficient number of bus ids. */
        if (i < num_devices && !curr_buf) {
@@ -303,8 +308,10 @@ int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
 error:
        for (i = 0; i < num_devices; i++)
                if (gdev->cdev[i]) {
+                       spin_lock_irq(gdev->cdev[i]->ccwlock);
                        if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev)
                                dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
+                       spin_unlock_irq(gdev->cdev[i]->ccwlock);
                        put_device(&gdev->cdev[i]->dev);
                        gdev->cdev[i] = NULL;
                }
index 37df42af05ec604112871912cc58d57f47d19f19..7f206ed44fdf79b41d771a203a8700c3a6ba07b4 100644 (file)
@@ -159,6 +159,7 @@ static enum io_status ccwreq_status(struct ccw_device *cdev, struct irb *lcirb)
 {
        struct irb *irb = &cdev->private->irb;
        struct cmd_scsw *scsw = &irb->scsw.cmd;
+       enum uc_todo todo;
 
        /* Perform BASIC SENSE if needed. */
        if (ccw_device_accumulate_and_sense(cdev, lcirb))
@@ -178,6 +179,20 @@ static enum io_status ccwreq_status(struct ccw_device *cdev, struct irb *lcirb)
                /* Check for command reject. */
                if (irb->ecw[0] & SNS0_CMD_REJECT)
                        return IO_REJECTED;
+               /* Ask the driver what to do */
+               if (cdev->drv && cdev->drv->uc_handler) {
+                       todo = cdev->drv->uc_handler(cdev, lcirb);
+                       switch (todo) {
+                       case UC_TODO_RETRY:
+                               return IO_STATUS_ERROR;
+                       case UC_TODO_RETRY_ON_NEW_PATH:
+                               return IO_PATH_ERROR;
+                       case UC_TODO_STOP:
+                               return IO_REJECTED;
+                       default:
+                               return IO_STATUS_ERROR;
+                       }
+               }
                /* Assume that unexpected SENSE data implies an error. */
                return IO_STATUS_ERROR;
        }
index 759262792633e0ec5fd4ad0d3f43f80d47ad5225..fac06155773f11864041bc4cca74dd742e270579 100644 (file)
@@ -23,21 +23,6 @@ struct tpi_info {
  * Some S390 specific IO instructions as inline
  */
 
-static inline int stsch(struct subchannel_id schid, struct schib *addr)
-{
-       register struct subchannel_id reg1 asm ("1") = schid;
-       int ccode;
-
-       asm volatile(
-               "       stsch   0(%3)\n"
-               "       ipm     %0\n"
-               "       srl     %0,28"
-               : "=d" (ccode), "=m" (*addr)
-               : "d" (reg1), "a" (addr)
-               : "cc");
-       return ccode;
-}
-
 static inline int stsch_err(struct subchannel_id schid, struct schib *addr)
 {
        register struct subchannel_id reg1 asm ("1") = schid;
index b4951eb0358e4046ca64bc38a7c9d2f2cd41dd4a..103fdf6b0b89650cc207f3d24f8b5ceb116cc709 100644 (file)
@@ -565,9 +565,9 @@ int bbc_envctrl_init(struct bbc_i2c_bus *bp)
        int devidx = 0;
 
        while ((op = bbc_i2c_getdev(bp, devidx++)) != NULL) {
-               if (!strcmp(op->node->name, "temperature"))
+               if (!strcmp(op->dev.of_node->name, "temperature"))
                        attach_one_temp(bp, op, temp_index++);
-               if (!strcmp(op->node->name, "fan-control"))
+               if (!strcmp(op->dev.of_node->name, "fan-control"))
                        attach_one_fan(bp, op, fan_index++);
        }
        if (temp_index != 0 && fan_index != 0) {
index 7e30e5f6e032a30bbdae7d89355b49122b4f6b42..8bfdd63a1fcbc085c33fbbab85c61e8675347138 100644 (file)
@@ -97,7 +97,7 @@ struct bbc_i2c_client *bbc_i2c_attach(struct bbc_i2c_bus *bp, struct of_device *
        client->bp = bp;
        client->op = op;
 
-       reg = of_get_property(op->node, "reg", NULL);
+       reg = of_get_property(op->dev.of_node, "reg", NULL);
        if (!reg) {
                kfree(client);
                return NULL;
@@ -327,7 +327,7 @@ static struct bbc_i2c_bus * __init attach_one_i2c(struct of_device *op, int inde
        spin_lock_init(&bp->lock);
 
        entry = 0;
-       for (dp = op->node->child;
+       for (dp = op->dev.of_node->child;
             dp && entry < 8;
             dp = dp->sibling, entry++) {
                struct of_device *child_op;
@@ -414,8 +414,11 @@ static const struct of_device_id bbc_i2c_match[] = {
 MODULE_DEVICE_TABLE(of, bbc_i2c_match);
 
 static struct of_platform_driver bbc_i2c_driver = {
-       .name           = "bbc_i2c",
-       .match_table    = bbc_i2c_match,
+       .driver = {
+               .name = "bbc_i2c",
+               .owner = THIS_MODULE,
+               .of_match_table = bbc_i2c_match,
+       },
        .probe          = bbc_i2c_probe,
        .remove         = __devexit_p(bbc_i2c_remove),
 };
index 3e59189f4137292f3eab85a11fe9a1db268649be..7baf1b644039dd0e9282661051760eba8f20d010 100644 (file)
@@ -216,7 +216,7 @@ static int __devinit d7s_probe(struct of_device *op,
        writeb(regs,  p->regs);
 
        printk(KERN_INFO PFX "7-Segment Display%s at [%s:0x%llx] %s\n",
-              op->node->full_name,
+              op->dev.of_node->full_name,
               (regs & D7S_FLIP) ? " (FLIPPED)" : "",
               op->resource[0].start,
               sol_compat ? "in sol_compat mode" : "");
@@ -266,8 +266,11 @@ static const struct of_device_id d7s_match[] = {
 MODULE_DEVICE_TABLE(of, d7s_match);
 
 static struct of_platform_driver d7s_driver = {
-       .name           = DRIVER_NAME,
-       .match_table    = d7s_match,
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = d7s_match,
+       },
        .probe          = d7s_probe,
        .remove         = __devexit_p(d7s_remove),
 };
index c6e2eff19409c6cd3cdf6c4bcbe75bd77cccc3fc..c8166ecf527601423681e0311bfa9ad28de4acb4 100644 (file)
@@ -1043,7 +1043,7 @@ static int __devinit envctrl_probe(struct of_device *op,
                return -ENOMEM;
 
        index = 0;
-       dp = op->node->child;
+       dp = op->dev.of_node->child;
        while (dp) {
                if (!strcmp(dp->name, "gpio")) {
                        i2c_childlist[index].i2ctype = I2C_GPIO;
@@ -1131,8 +1131,11 @@ static const struct of_device_id envctrl_match[] = {
 MODULE_DEVICE_TABLE(of, envctrl_match);
 
 static struct of_platform_driver envctrl_driver = {
-       .name           = DRIVER_NAME,
-       .match_table    = envctrl_match,
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = envctrl_match,
+       },
        .probe          = envctrl_probe,
        .remove         = __devexit_p(envctrl_remove),
 };
index d3b62eb0fba7abf2f9547de5a410179e27fa81bf..368d66294d831ea8fdba4ef0e1e66c92b7f5fd87 100644 (file)
@@ -162,7 +162,7 @@ static struct miscdevice flash_dev = { FLASH_MINOR, "flash", &flash_fops };
 static int __devinit flash_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 device_node *parent;
 
        parent = dp->parent;
@@ -184,7 +184,7 @@ static int __devinit flash_probe(struct of_device *op,
        flash.busy = 0;
 
        printk(KERN_INFO "%s: OBP Flash, RD %lx[%lx] WR %lx[%lx]\n",
-              op->node->full_name,
+              op->dev.of_node->full_name,
               flash.read_base, flash.read_size,
               flash.write_base, flash.write_size);
 
@@ -207,8 +207,11 @@ static const struct of_device_id flash_match[] = {
 MODULE_DEVICE_TABLE(of, flash_match);
 
 static struct of_platform_driver flash_driver = {
-       .name           = "flash",
-       .match_table    = flash_match,
+       .driver = {
+               .name = "flash",
+               .owner = THIS_MODULE,
+               .of_match_table = flash_match,
+       },
        .probe          = flash_probe,
        .remove         = __devexit_p(flash_remove),
 };
index fc2f676e984da2aaf9937f4662cff2e83a73dcb7..d53e62ab09da46866e808affd0d1af11d16a3c18 100644 (file)
@@ -298,9 +298,9 @@ static int opromgetbootargs(void __user *argp, struct openpromio *op, int bufsiz
 /*
  *     SunOS and Solaris /dev/openprom ioctl calls.
  */
-static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
-                               unsigned int cmd, unsigned long arg,
-                               struct device_node *dp)
+static long openprom_sunos_ioctl(struct file * file,
+                                unsigned int cmd, unsigned long arg,
+                                struct device_node *dp)
 {
        DATA *data = file->private_data;
        struct openpromio *opp = NULL;
@@ -316,6 +316,8 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
        if (bufsize < 0)
                return bufsize;
 
+       lock_kernel();
+
        switch (cmd) {
        case OPROMGETOPT:
        case OPROMGETPROP:
@@ -365,6 +367,8 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
        }
 
        kfree(opp);
+       unlock_kernel();
+
        return error;
 }
 
@@ -547,13 +551,14 @@ static int opiocgetnext(unsigned int cmd, void __user *argp)
        return 0;
 }
 
-static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
+static int openprom_bsd_ioctl(struct file * file,
                              unsigned int cmd, unsigned long arg)
 {
        DATA *data = (DATA *) file->private_data;
        void __user *argp = (void __user *)arg;
        int err;
 
+       lock_kernel();
        switch (cmd) {
        case OPIOCGET:
                err = opiocget(argp, data);
@@ -570,10 +575,10 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
        case OPIOCGETOPTNODE:
                BUILD_BUG_ON(sizeof(phandle) != sizeof(int));
 
+               err = 0;
                if (copy_to_user(argp, &options_node->phandle, sizeof(phandle)))
-                       return -EFAULT;
-
-               return 0;
+                       err = -EFAULT;
+               break;
 
        case OPIOCGETNEXT:
        case OPIOCGETCHILD:
@@ -581,9 +586,10 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
                break;
 
        default:
-               return -EINVAL;
-
+               err = -EINVAL;
+               break;
        };
+       unlock_kernel();
 
        return err;
 }
@@ -592,8 +598,8 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
 /*
  *     Handoff control to the correct ioctl handler.
  */
-static int openprom_ioctl(struct inode * inode, struct file * file,
-                         unsigned int cmd, unsigned long arg)
+static long openprom_ioctl(struct file * file,
+                          unsigned int cmd, unsigned long arg)
 {
        DATA *data = (DATA *) file->private_data;
 
@@ -602,14 +608,14 @@ static int openprom_ioctl(struct inode * inode, struct file * file,
        case OPROMNXTOPT:
                if ((file->f_mode & FMODE_READ) == 0)
                        return -EPERM;
-               return openprom_sunos_ioctl(inode, file, cmd, arg,
+               return openprom_sunos_ioctl(file, cmd, arg,
                                            options_node);
 
        case OPROMSETOPT:
        case OPROMSETOPT2:
                if ((file->f_mode & FMODE_WRITE) == 0)
                        return -EPERM;
-               return openprom_sunos_ioctl(inode, file, cmd, arg,
+               return openprom_sunos_ioctl(file, cmd, arg,
                                            options_node);
 
        case OPROMNEXT:
@@ -618,7 +624,7 @@ static int openprom_ioctl(struct inode * inode, struct file * file,
        case OPROMNXTPROP:
                if ((file->f_mode & FMODE_READ) == 0)
                        return -EPERM;
-               return openprom_sunos_ioctl(inode, file, cmd, arg,
+               return openprom_sunos_ioctl(file, cmd, arg,
                                            data->current_node);
 
        case OPROMU2P:
@@ -630,7 +636,7 @@ static int openprom_ioctl(struct inode * inode, struct file * file,
        case OPROMPATH2NODE:
                if ((file->f_mode & FMODE_READ) == 0)
                        return -EPERM;
-               return openprom_sunos_ioctl(inode, file, cmd, arg, NULL);
+               return openprom_sunos_ioctl(file, cmd, arg, NULL);
 
        case OPIOCGET:
        case OPIOCNEXTPROP:
@@ -639,12 +645,12 @@ static int openprom_ioctl(struct inode * inode, struct file * file,
        case OPIOCGETCHILD:
                if ((file->f_mode & FMODE_READ) == 0)
                        return -EBADF;
-               return openprom_bsd_ioctl(inode,file,cmd,arg);
+               return openprom_bsd_ioctl(file,cmd,arg);
 
        case OPIOCSET:
                if ((file->f_mode & FMODE_WRITE) == 0)
                        return -EBADF;
-               return openprom_bsd_ioctl(inode,file,cmd,arg);
+               return openprom_bsd_ioctl(file,cmd,arg);
 
        default:
                return -EINVAL;
@@ -676,7 +682,7 @@ static long openprom_compat_ioctl(struct file *file, unsigned int cmd,
        case OPROMSETCUR:
        case OPROMPCI2NODE:
        case OPROMPATH2NODE:
-               rval = openprom_ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
+               rval = openprom_ioctl(file, cmd, arg);
                break;
        }
 
@@ -709,7 +715,7 @@ static int openprom_release(struct inode * inode, struct file * file)
 static const struct file_operations openprom_fops = {
        .owner =        THIS_MODULE,
        .llseek =       no_llseek,
-       .ioctl =        openprom_ioctl,
+       .unlocked_ioctl = openprom_ioctl,
        .compat_ioctl = openprom_compat_ioctl,
        .open =         openprom_open,
        .release =      openprom_release,
index 2c56fd56ec6395038ca6e0c83eb660849d15b4fa..5f253665a1da862b2c3d3159ab426485b4b6a16e 100644 (file)
@@ -382,7 +382,7 @@ static int __devinit uctrl_probe(struct of_device *op,
 
        sbus_writel(UCTRL_INTR_RXNE_REQ|UCTRL_INTR_RXNE_MSK, &p->regs->uctrl_intr);
        printk(KERN_INFO "%s: uctrl regs[0x%p] (irq %d)\n",
-              op->node->full_name, p->regs, p->irq);
+              op->dev.of_node->full_name, p->regs, p->irq);
        uctrl_get_event_status(p);
        uctrl_get_external_status(p);
 
@@ -425,8 +425,11 @@ static const struct of_device_id uctrl_match[] = {
 MODULE_DEVICE_TABLE(of, uctrl_match);
 
 static struct of_platform_driver uctrl_driver = {
-       .name           = "uctrl",
-       .match_table    = uctrl_match,
+       .driver = {
+               .name = "uctrl",
+               .owner = THIS_MODULE,
+               .of_match_table = uctrl_match,
+       },
        .probe          = uctrl_probe,
        .remove         = __devexit_p(uctrl_remove),
 };
index 1bb774becf251583bc13ffbfeb62281d3b55bb0a..e20b7bdd4c78e2409fc2783ad38e3fbb10e62e55 100644 (file)
@@ -125,7 +125,7 @@ static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_H
 static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id);
 static char *twa_aen_severity_lookup(unsigned char severity_code);
 static void twa_aen_sync_time(TW_Device_Extension *tw_dev, int request_id);
-static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static long twa_chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
 static int twa_chrdev_open(struct inode *inode, struct file *file);
 static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_sense, int print_host);
 static void twa_free_request_id(TW_Device_Extension *tw_dev,int request_id);
@@ -220,7 +220,7 @@ static struct device_attribute *twa_host_attrs[] = {
 /* File operations struct for character device */
 static const struct file_operations twa_fops = {
        .owner          = THIS_MODULE,
-       .ioctl          = twa_chrdev_ioctl,
+       .unlocked_ioctl = twa_chrdev_ioctl,
        .open           = twa_chrdev_open,
        .release        = NULL
 };
@@ -637,8 +637,9 @@ out:
 } /* End twa_check_srl() */
 
 /* This function handles ioctl for the character device */
-static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static long twa_chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
+       struct inode *inode = file->f_path.dentry->d_inode;
        long timeout;
        unsigned long *cpu_addr, data_buffer_length_adjusted = 0, flags = 0;
        dma_addr_t dma_handle;
@@ -657,6 +658,8 @@ static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int
        int retval = TW_IOCTL_ERROR_OS_EFAULT;
        void __user *argp = (void __user *)arg;
 
+       lock_kernel();
+
        /* Only let one of these through at a time */
        if (mutex_lock_interruptible(&tw_dev->ioctl_lock)) {
                retval = TW_IOCTL_ERROR_OS_EINTR;
@@ -876,6 +879,7 @@ out3:
 out2:
        mutex_unlock(&tw_dev->ioctl_lock);
 out:
+       unlock_kernel();
        return retval;
 } /* End twa_chrdev_ioctl() */
 
index d38000db9237ab81ca0581ae5250a21f98e40411..f481e734aad488f762bf16e3289f72ec42105508 100644 (file)
@@ -750,19 +750,22 @@ static void twl_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_comm
 
 /* This function handles ioctl for the character device
    This interface is used by smartmontools open source software */
-static int twl_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static long twl_chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        long timeout;
        unsigned long *cpu_addr, data_buffer_length_adjusted = 0, flags = 0;
        dma_addr_t dma_handle;
        int request_id = 0;
        TW_Ioctl_Driver_Command driver_command;
+       struct inode *inode = file->f_dentry->d_inode;
        TW_Ioctl_Buf_Apache *tw_ioctl;
        TW_Command_Full *full_command_packet;
        TW_Device_Extension *tw_dev = twl_device_extension_list[iminor(inode)];
        int retval = -EFAULT;
        void __user *argp = (void __user *)arg;
 
+       lock_kernel();
+
        /* Only let one of these through at a time */
        if (mutex_lock_interruptible(&tw_dev->ioctl_lock)) {
                retval = -EINTR;
@@ -858,6 +861,7 @@ out3:
 out2:
        mutex_unlock(&tw_dev->ioctl_lock);
 out:
+       unlock_kernel();
        return retval;
 } /* End twl_chrdev_ioctl() */
 
@@ -884,7 +888,7 @@ out:
 /* File operations struct for character device */
 static const struct file_operations twl_fops = {
        .owner          = THIS_MODULE,
-       .ioctl          = twl_chrdev_ioctl,
+       .unlocked_ioctl = twl_chrdev_ioctl,
        .open           = twl_chrdev_open,
        .release        = NULL
 };
index d119a614bf7d525e51d6c32d2192a0edcf510941..30d735ad35b5ee9a4909c686be1b6b7d0172a559 100644 (file)
@@ -881,7 +881,7 @@ static int tw_allocate_memory(TW_Device_Extension *tw_dev, int size, int which)
 } /* End tw_allocate_memory() */
 
 /* This function handles ioctl for the character device */
-static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static long tw_chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        int request_id;
        dma_addr_t dma_handle;
@@ -889,6 +889,7 @@ static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int
        unsigned long flags;
        unsigned int data_buffer_length = 0;
        unsigned long data_buffer_length_adjusted = 0;
+       struct inode *inode = file->f_dentry->d_inode;
        unsigned long *cpu_addr;
        long timeout;
        TW_New_Ioctl *tw_ioctl;
@@ -899,9 +900,12 @@ static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int
 
        dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl()\n");
 
+       lock_kernel();
        /* Only let one of these through at a time */
-       if (mutex_lock_interruptible(&tw_dev->ioctl_lock))
+       if (mutex_lock_interruptible(&tw_dev->ioctl_lock)) {
+               unlock_kernel();
                return -EINTR;
+       }
 
        /* First copy down the buffer length */
        if (copy_from_user(&data_buffer_length, argp, sizeof(unsigned int)))
@@ -1030,6 +1034,7 @@ out2:
        dma_free_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, cpu_addr, dma_handle);
 out:
        mutex_unlock(&tw_dev->ioctl_lock);
+       unlock_kernel();
        return retval;
 } /* End tw_chrdev_ioctl() */
 
@@ -1052,7 +1057,7 @@ static int tw_chrdev_open(struct inode *inode, struct file *file)
 /* File operations struct for character device */
 static const struct file_operations tw_fops = {
        .owner          = THIS_MODULE,
-       .ioctl          = tw_chrdev_ioctl,
+       .unlocked_ioctl = tw_chrdev_ioctl,
        .open           = tw_chrdev_open,
        .release        = NULL
 };
index 308541ff85cf9ff127a118696bc2b62d0d6d255e..1bb5d3f0e260f1a94a74b15deb47301212784d19 100644 (file)
@@ -1,34 +1,31 @@
 #include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/zorro.h>
 
-#include <asm/setup.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/amigaints.h>
 #include <asm/amigahw.h>
-#include <linux/zorro.h>
-#include <asm/irq.h>
-#include <linux/spinlock.h>
 
 #include "scsi.h"
-#include <scsi/scsi_host.h>
 #include "wd33c93.h"
 #include "a2091.h"
 
-#include <linux/stat.h>
-
 
-static int a2091_release(struct Scsi_Host *instance);
+struct a2091_hostdata {
+       struct WD33C93_hostdata wh;
+       struct a2091_scsiregs *regs;
+};
 
 static irqreturn_t a2091_intr(int irq, void *data)
 {
        struct Scsi_Host *instance = data;
-       a2091_scsiregs *regs = (a2091_scsiregs *)(instance->base);
-       unsigned int status = regs->ISTR;
+       struct a2091_hostdata *hdata = shost_priv(instance);
+       unsigned int status = hdata->regs->ISTR;
        unsigned long flags;
 
        if (!(status & (ISTR_INT_F | ISTR_INT_P)) || !(status & ISTR_INTS))
@@ -43,38 +40,39 @@ static irqreturn_t a2091_intr(int irq, void *data)
 static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
 {
        struct Scsi_Host *instance = cmd->device->host;
-       struct WD33C93_hostdata *hdata = shost_priv(instance);
-       a2091_scsiregs *regs = (a2091_scsiregs *)(instance->base);
+       struct a2091_hostdata *hdata = shost_priv(instance);
+       struct WD33C93_hostdata *wh = &hdata->wh;
+       struct a2091_scsiregs *regs = hdata->regs;
        unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
        unsigned long addr = virt_to_bus(cmd->SCp.ptr);
 
        /* don't allow DMA if the physical address is bad */
        if (addr & A2091_XFER_MASK) {
-               hdata->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff;
-               hdata->dma_bounce_buffer = kmalloc(hdata->dma_bounce_len,
-                                                  GFP_KERNEL);
+               wh->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff;
+               wh->dma_bounce_buffer = kmalloc(wh->dma_bounce_len,
+                                               GFP_KERNEL);
 
                /* can't allocate memory; use PIO */
-               if (!hdata->dma_bounce_buffer) {
-                       hdata->dma_bounce_len = 0;
+               if (!wh->dma_bounce_buffer) {
+                       wh->dma_bounce_len = 0;
                        return 1;
                }
 
                /* get the physical address of the bounce buffer */
-               addr = virt_to_bus(hdata->dma_bounce_buffer);
+               addr = virt_to_bus(wh->dma_bounce_buffer);
 
                /* the bounce buffer may not be in the first 16M of physmem */
                if (addr & A2091_XFER_MASK) {
                        /* we could use chipmem... maybe later */
-                       kfree(hdata->dma_bounce_buffer);
-                       hdata->dma_bounce_buffer = NULL;
-                       hdata->dma_bounce_len = 0;
+                       kfree(wh->dma_bounce_buffer);
+                       wh->dma_bounce_buffer = NULL;
+                       wh->dma_bounce_len = 0;
                        return 1;
                }
 
                if (!dir_in) {
                        /* copy to bounce buffer for a write */
-                       memcpy(hdata->dma_bounce_buffer, cmd->SCp.ptr,
+                       memcpy(wh->dma_bounce_buffer, cmd->SCp.ptr,
                               cmd->SCp.this_residual);
                }
        }
@@ -84,7 +82,7 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
                cntr |= CNTR_DDIR;
 
        /* remember direction */
-       hdata->dma_dir = dir_in;
+       wh->dma_dir = dir_in;
 
        regs->CNTR = cntr;
 
@@ -108,20 +106,21 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
 static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
                     int status)
 {
-       struct WD33C93_hostdata *hdata = shost_priv(instance);
-       a2091_scsiregs *regs = (a2091_scsiregs *)(instance->base);
+       struct a2091_hostdata *hdata = shost_priv(instance);
+       struct WD33C93_hostdata *wh = &hdata->wh;
+       struct a2091_scsiregs *regs = hdata->regs;
 
        /* disable SCSI interrupts */
        unsigned short cntr = CNTR_PDMD;
 
-       if (!hdata->dma_dir)
+       if (!wh->dma_dir)
                cntr |= CNTR_DDIR;
 
        /* disable SCSI interrupts */
        regs->CNTR = cntr;
 
        /* flush if we were reading */
-       if (hdata->dma_dir) {
+       if (wh->dma_dir) {
                regs->FLUSH = 1;
                while (!(regs->ISTR & ISTR_FE_FLG))
                        ;
@@ -137,95 +136,37 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
        regs->CNTR = CNTR_PDMD | CNTR_INTEN;
 
        /* copy from a bounce buffer, if necessary */
-       if (status && hdata->dma_bounce_buffer) {
-               if (hdata->dma_dir)
-                       memcpy(SCpnt->SCp.ptr, hdata->dma_bounce_buffer,
+       if (status && wh->dma_bounce_buffer) {
+               if (wh->dma_dir)
+                       memcpy(SCpnt->SCp.ptr, wh->dma_bounce_buffer,
                               SCpnt->SCp.this_residual);
-               kfree(hdata->dma_bounce_buffer);
-               hdata->dma_bounce_buffer = NULL;
-               hdata->dma_bounce_len = 0;
-       }
-}
-
-static int __init a2091_detect(struct scsi_host_template *tpnt)
-{
-       static unsigned char called = 0;
-       struct Scsi_Host *instance;
-       unsigned long address;
-       struct zorro_dev *z = NULL;
-       wd33c93_regs wdregs;
-       a2091_scsiregs *regs;
-       struct WD33C93_hostdata *hdata;
-       int num_a2091 = 0;
-
-       if (!MACH_IS_AMIGA || called)
-               return 0;
-       called = 1;
-
-       tpnt->proc_name = "A2091";
-       tpnt->proc_info = &wd33c93_proc_info;
-
-       while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
-               if (z->id != ZORRO_PROD_CBM_A590_A2091_1 &&
-                   z->id != ZORRO_PROD_CBM_A590_A2091_2)
-                       continue;
-               address = z->resource.start;
-               if (!request_mem_region(address, 256, "wd33c93"))
-                       continue;
-
-               instance = scsi_register(tpnt, sizeof(struct WD33C93_hostdata));
-               if (instance == NULL)
-                       goto release;
-               instance->base = ZTWO_VADDR(address);
-               instance->irq = IRQ_AMIGA_PORTS;
-               instance->unique_id = z->slotaddr;
-               regs = (a2091_scsiregs *)(instance->base);
-               regs->DAWR = DAWR_A2091;
-               wdregs.SASR = &regs->SASR;
-               wdregs.SCMD = &regs->SCMD;
-               hdata = shost_priv(instance);
-               hdata->no_sync = 0xff;
-               hdata->fast = 0;
-               hdata->dma_mode = CTRL_DMA;
-               wd33c93_init(instance, wdregs, dma_setup, dma_stop,
-                            WD33C93_FS_8_10);
-               if (request_irq(IRQ_AMIGA_PORTS, a2091_intr, IRQF_SHARED,
-                               "A2091 SCSI", instance))
-                       goto unregister;
-               regs->CNTR = CNTR_PDMD | CNTR_INTEN;
-               num_a2091++;
-               continue;
-
-unregister:
-               scsi_unregister(instance);
-release:
-               release_mem_region(address, 256);
+               kfree(wh->dma_bounce_buffer);
+               wh->dma_bounce_buffer = NULL;
+               wh->dma_bounce_len = 0;
        }
-
-       return num_a2091;
 }
 
 static int a2091_bus_reset(struct scsi_cmnd *cmd)
 {
+       struct Scsi_Host *instance = cmd->device->host;
+
        /* FIXME perform bus-specific reset */
 
        /* FIXME 2: kill this function, and let midlayer fall back
           to the same action, calling wd33c93_host_reset() */
 
-       spin_lock_irq(cmd->device->host->host_lock);
+       spin_lock_irq(instance->host_lock);
        wd33c93_host_reset(cmd);
-       spin_unlock_irq(cmd->device->host->host_lock);
+       spin_unlock_irq(instance->host_lock);
 
        return SUCCESS;
 }
 
-#define HOSTS_C
-
-static struct scsi_host_template driver_template = {
-       .proc_name              = "A2901",
+static struct scsi_host_template a2091_scsi_template = {
+       .module                 = THIS_MODULE,
        .name                   = "Commodore A2091/A590 SCSI",
-       .detect                 = a2091_detect,
-       .release                = a2091_release,
+       .proc_info              = wd33c93_proc_info,
+       .proc_name              = "A2901",
        .queuecommand           = wd33c93_queuecommand,
        .eh_abort_handler       = wd33c93_abort,
        .eh_bus_reset_handler   = a2091_bus_reset,
@@ -237,19 +178,103 @@ static struct scsi_host_template driver_template = {
        .use_clustering         = DISABLE_CLUSTERING
 };
 
+static int __devinit a2091_probe(struct zorro_dev *z,
+                                const struct zorro_device_id *ent)
+{
+       struct Scsi_Host *instance;
+       int error;
+       struct a2091_scsiregs *regs;
+       wd33c93_regs wdregs;
+       struct a2091_hostdata *hdata;
 
-#include "scsi_module.c"
+       if (!request_mem_region(z->resource.start, 256, "wd33c93"))
+               return -EBUSY;
 
-static int a2091_release(struct Scsi_Host *instance)
+       instance = scsi_host_alloc(&a2091_scsi_template,
+                                  sizeof(struct a2091_hostdata));
+       if (!instance) {
+               error = -ENOMEM;
+               goto fail_alloc;
+       }
+
+       instance->irq = IRQ_AMIGA_PORTS;
+       instance->unique_id = z->slotaddr;
+
+       regs = (struct a2091_scsiregs *)ZTWO_VADDR(z->resource.start);
+       regs->DAWR = DAWR_A2091;
+
+       wdregs.SASR = &regs->SASR;
+       wdregs.SCMD = &regs->SCMD;
+
+       hdata = shost_priv(instance);
+       hdata->wh.no_sync = 0xff;
+       hdata->wh.fast = 0;
+       hdata->wh.dma_mode = CTRL_DMA;
+       hdata->regs = regs;
+
+       wd33c93_init(instance, wdregs, dma_setup, dma_stop, WD33C93_FS_8_10);
+       error = request_irq(IRQ_AMIGA_PORTS, a2091_intr, IRQF_SHARED,
+                           "A2091 SCSI", instance);
+       if (error)
+               goto fail_irq;
+
+       regs->CNTR = CNTR_PDMD | CNTR_INTEN;
+
+       error = scsi_add_host(instance, NULL);
+       if (error)
+               goto fail_host;
+
+       zorro_set_drvdata(z, instance);
+
+       scsi_scan_host(instance);
+       return 0;
+
+fail_host:
+       free_irq(IRQ_AMIGA_PORTS, instance);
+fail_irq:
+       scsi_host_put(instance);
+fail_alloc:
+       release_mem_region(z->resource.start, 256);
+       return error;
+}
+
+static void __devexit a2091_remove(struct zorro_dev *z)
 {
-#ifdef MODULE
-       a2091_scsiregs *regs = (a2091_scsiregs *)(instance->base);
+       struct Scsi_Host *instance = zorro_get_drvdata(z);
+       struct a2091_hostdata *hdata = shost_priv(instance);
 
-       regs->CNTR = 0;
-       release_mem_region(ZTWO_PADDR(instance->base), 256);
+       hdata->regs->CNTR = 0;
+       scsi_remove_host(instance);
        free_irq(IRQ_AMIGA_PORTS, instance);
-#endif
-       return 1;
+       scsi_host_put(instance);
+       release_mem_region(z->resource.start, 256);
+}
+
+static struct zorro_device_id a2091_zorro_tbl[] __devinitdata = {
+       { ZORRO_PROD_CBM_A590_A2091_1 },
+       { ZORRO_PROD_CBM_A590_A2091_2 },
+       { 0 }
+};
+MODULE_DEVICE_TABLE(zorro, a2091_zorro_tbl);
+
+static struct zorro_driver a2091_driver = {
+       .name           = "a2091",
+       .id_table       = a2091_zorro_tbl,
+       .probe          = a2091_probe,
+       .remove         = __devexit_p(a2091_remove),
+};
+
+static int __init a2091_init(void)
+{
+       return zorro_register_driver(&a2091_driver);
+}
+module_init(a2091_init);
+
+static void __exit a2091_exit(void)
+{
+       zorro_unregister_driver(&a2091_driver);
 }
+module_exit(a2091_exit);
 
+MODULE_DESCRIPTION("Commodore A2091/A590 SCSI");
 MODULE_LICENSE("GPL");
index 1c3daa1fd754000b9a7d2d0a0ccb06c50d76b939..794b8e65c71133a565ada330ee8622732bcd402d 100644 (file)
@@ -25,7 +25,7 @@
  */
 #define A2091_XFER_MASK                (0xff000001)
 
-typedef struct {
+struct a2091_scsiregs {
                 unsigned char  pad1[64];
        volatile unsigned short ISTR;
        volatile unsigned short CNTR;
@@ -44,7 +44,7 @@ typedef struct {
        volatile unsigned short CINT;
                 unsigned char  pad7[2];
        volatile unsigned short FLUSH;
-} a2091_scsiregs;
+};
 
 #define DAWR_A2091             (3)
 
index bc6eb69f5fd09554ffe714e5339e3e9ec67b7a40..d9468027fb6150caed5a9854623b5673ddff58a4 100644 (file)
@@ -1,53 +1,52 @@
 #include <linux/types.h>
 #include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
+#include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
+#include <linux/platform_device.h>
 
-#include <asm/setup.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/amigaints.h>
 #include <asm/amigahw.h>
-#include <asm/irq.h>
 
 #include "scsi.h"
-#include <scsi/scsi_host.h>
 #include "wd33c93.h"
 #include "a3000.h"
 
-#include <linux/stat.h>
-
 
-#define DMA(ptr)       ((a3000_scsiregs *)((ptr)->base))
-
-static struct Scsi_Host *a3000_host = NULL;
-
-static int a3000_release(struct Scsi_Host *instance);
+struct a3000_hostdata {
+       struct WD33C93_hostdata wh;
+       struct a3000_scsiregs *regs;
+};
 
-static irqreturn_t a3000_intr(int irq, void *dummy)
+static irqreturn_t a3000_intr(int irq, void *data)
 {
+       struct Scsi_Host *instance = data;
+       struct a3000_hostdata *hdata = shost_priv(instance);
+       unsigned int status = hdata->regs->ISTR;
        unsigned long flags;
-       unsigned int status = DMA(a3000_host)->ISTR;
 
        if (!(status & ISTR_INT_P))
                return IRQ_NONE;
        if (status & ISTR_INTS) {
-               spin_lock_irqsave(a3000_host->host_lock, flags);
-               wd33c93_intr(a3000_host);
-               spin_unlock_irqrestore(a3000_host->host_lock, flags);
+               spin_lock_irqsave(instance->host_lock, flags);
+               wd33c93_intr(instance);
+               spin_unlock_irqrestore(instance->host_lock, flags);
                return IRQ_HANDLED;
        }
-       printk("Non-serviced A3000 SCSI-interrupt? ISTR = %02x\n", status);
+       pr_warning("Non-serviced A3000 SCSI-interrupt? ISTR = %02x\n", status);
        return IRQ_NONE;
 }
 
 static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
 {
-       struct WD33C93_hostdata *hdata = shost_priv(a3000_host);
+       struct Scsi_Host *instance = cmd->device->host;
+       struct a3000_hostdata *hdata = shost_priv(instance);
+       struct WD33C93_hostdata *wh = &hdata->wh;
+       struct a3000_scsiregs *regs = hdata->regs;
        unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
        unsigned long addr = virt_to_bus(cmd->SCp.ptr);
 
@@ -58,23 +57,23 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
         * buffer
         */
        if (addr & A3000_XFER_MASK) {
-               hdata->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff;
-               hdata->dma_bounce_buffer = kmalloc(hdata->dma_bounce_len,
-                                                  GFP_KERNEL);
+               wh->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff;
+               wh->dma_bounce_buffer = kmalloc(wh->dma_bounce_len,
+                                               GFP_KERNEL);
 
                /* can't allocate memory; use PIO */
-               if (!hdata->dma_bounce_buffer) {
-                       hdata->dma_bounce_len = 0;
+               if (!wh->dma_bounce_buffer) {
+                       wh->dma_bounce_len = 0;
                        return 1;
                }
 
                if (!dir_in) {
                        /* copy to bounce buffer for a write */
-                       memcpy(hdata->dma_bounce_buffer, cmd->SCp.ptr,
+                       memcpy(wh->dma_bounce_buffer, cmd->SCp.ptr,
                               cmd->SCp.this_residual);
                }
 
-               addr = virt_to_bus(hdata->dma_bounce_buffer);
+               addr = virt_to_bus(wh->dma_bounce_buffer);
        }
 
        /* setup dma direction */
@@ -82,12 +81,12 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
                cntr |= CNTR_DDIR;
 
        /* remember direction */
-       hdata->dma_dir = dir_in;
+       wh->dma_dir = dir_in;
 
-       DMA(a3000_host)->CNTR = cntr;
+       regs->CNTR = cntr;
 
        /* setup DMA *physical* address */
-       DMA(a3000_host)->ACR = addr;
+       regs->ACR = addr;
 
        if (dir_in) {
                /* invalidate any cache */
@@ -99,7 +98,7 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
 
        /* start DMA */
        mb();                   /* make sure setup is completed */
-       DMA(a3000_host)->ST_DMA = 1;
+       regs->ST_DMA = 1;
        mb();                   /* make sure DMA has started before next IO */
 
        /* return success */
@@ -109,22 +108,24 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
 static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
                     int status)
 {
-       struct WD33C93_hostdata *hdata = shost_priv(instance);
+       struct a3000_hostdata *hdata = shost_priv(instance);
+       struct WD33C93_hostdata *wh = &hdata->wh;
+       struct a3000_scsiregs *regs = hdata->regs;
 
        /* disable SCSI interrupts */
        unsigned short cntr = CNTR_PDMD;
 
-       if (!hdata->dma_dir)
+       if (!wh->dma_dir)
                cntr |= CNTR_DDIR;
 
-       DMA(instance)->CNTR = cntr;
+       regs->CNTR = cntr;
        mb();                   /* make sure CNTR is updated before next IO */
 
        /* flush if we were reading */
-       if (hdata->dma_dir) {
-               DMA(instance)->FLUSH = 1;
+       if (wh->dma_dir) {
+               regs->FLUSH = 1;
                mb();           /* don't allow prefetch */
-               while (!(DMA(instance)->ISTR & ISTR_FE_FLG))
+               while (!(regs->ISTR & ISTR_FE_FLG))
                        barrier();
                mb();           /* no IO until FLUSH is done */
        }
@@ -133,96 +134,54 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
        /* I think that this CINT is only necessary if you are
         * using the terminal count features.   HM 7 Mar 1994
         */
-       DMA(instance)->CINT = 1;
+       regs->CINT = 1;
 
        /* stop DMA */
-       DMA(instance)->SP_DMA = 1;
+       regs->SP_DMA = 1;
        mb();                   /* make sure DMA is stopped before next IO */
 
        /* restore the CONTROL bits (minus the direction flag) */
-       DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
+       regs->CNTR = CNTR_PDMD | CNTR_INTEN;
        mb();                   /* make sure CNTR is updated before next IO */
 
        /* copy from a bounce buffer, if necessary */
-       if (status && hdata->dma_bounce_buffer) {
+       if (status && wh->dma_bounce_buffer) {
                if (SCpnt) {
-                       if (hdata->dma_dir && SCpnt)
-                               memcpy(SCpnt->SCp.ptr,
-                                      hdata->dma_bounce_buffer,
+                       if (wh->dma_dir && SCpnt)
+                               memcpy(SCpnt->SCp.ptr, wh->dma_bounce_buffer,
                                       SCpnt->SCp.this_residual);
-                       kfree(hdata->dma_bounce_buffer);
-                       hdata->dma_bounce_buffer = NULL;
-                       hdata->dma_bounce_len = 0;
+                       kfree(wh->dma_bounce_buffer);
+                       wh->dma_bounce_buffer = NULL;
+                       wh->dma_bounce_len = 0;
                } else {
-                       kfree(hdata->dma_bounce_buffer);
-                       hdata->dma_bounce_buffer = NULL;
-                       hdata->dma_bounce_len = 0;
+                       kfree(wh->dma_bounce_buffer);
+                       wh->dma_bounce_buffer = NULL;
+                       wh->dma_bounce_len = 0;
                }
        }
 }
 
-static int __init a3000_detect(struct scsi_host_template *tpnt)
-{
-       wd33c93_regs regs;
-       struct WD33C93_hostdata *hdata;
-
-       if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(A3000_SCSI))
-               return 0;
-       if (!request_mem_region(0xDD0000, 256, "wd33c93"))
-               return 0;
-
-       tpnt->proc_name = "A3000";
-       tpnt->proc_info = &wd33c93_proc_info;
-
-       a3000_host = scsi_register(tpnt, sizeof(struct WD33C93_hostdata));
-       if (a3000_host == NULL)
-               goto fail_register;
-
-       a3000_host->base = ZTWO_VADDR(0xDD0000);
-       a3000_host->irq = IRQ_AMIGA_PORTS;
-       DMA(a3000_host)->DAWR = DAWR_A3000;
-       regs.SASR = &(DMA(a3000_host)->SASR);
-       regs.SCMD = &(DMA(a3000_host)->SCMD);
-       hdata = shost_priv(a3000_host);
-       hdata->no_sync = 0xff;
-       hdata->fast = 0;
-       hdata->dma_mode = CTRL_DMA;
-       wd33c93_init(a3000_host, regs, dma_setup, dma_stop, WD33C93_FS_12_15);
-       if (request_irq(IRQ_AMIGA_PORTS, a3000_intr, IRQF_SHARED, "A3000 SCSI",
-                       a3000_intr))
-               goto fail_irq;
-       DMA(a3000_host)->CNTR = CNTR_PDMD | CNTR_INTEN;
-
-       return 1;
-
-fail_irq:
-       scsi_unregister(a3000_host);
-fail_register:
-       release_mem_region(0xDD0000, 256);
-       return 0;
-}
-
 static int a3000_bus_reset(struct scsi_cmnd *cmd)
 {
+       struct Scsi_Host *instance = cmd->device->host;
+
        /* FIXME perform bus-specific reset */
 
        /* FIXME 2: kill this entire function, which should
           cause mid-layer to call wd33c93_host_reset anyway? */
 
-       spin_lock_irq(cmd->device->host->host_lock);
+       spin_lock_irq(instance->host_lock);
        wd33c93_host_reset(cmd);
-       spin_unlock_irq(cmd->device->host->host_lock);
+       spin_unlock_irq(instance->host_lock);
 
        return SUCCESS;
 }
 
-#define HOSTS_C
-
-static struct scsi_host_template driver_template = {
-       .proc_name              = "A3000",
+static struct scsi_host_template amiga_a3000_scsi_template = {
+       .module                 = THIS_MODULE,
        .name                   = "Amiga 3000 built-in SCSI",
-       .detect                 = a3000_detect,
-       .release                = a3000_release,
+       .proc_info              = wd33c93_proc_info,
+       .proc_name              = "A3000",
        .queuecommand           = wd33c93_queuecommand,
        .eh_abort_handler       = wd33c93_abort,
        .eh_bus_reset_handler   = a3000_bus_reset,
@@ -234,15 +193,104 @@ static struct scsi_host_template driver_template = {
        .use_clustering         = ENABLE_CLUSTERING
 };
 
+static int __init amiga_a3000_scsi_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       struct Scsi_Host *instance;
+       int error;
+       struct a3000_scsiregs *regs;
+       wd33c93_regs wdregs;
+       struct a3000_hostdata *hdata;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
+
+       if (!request_mem_region(res->start, resource_size(res), "wd33c93"))
+               return -EBUSY;
+
+       instance = scsi_host_alloc(&amiga_a3000_scsi_template,
+                                  sizeof(struct a3000_hostdata));
+       if (!instance) {
+               error = -ENOMEM;
+               goto fail_alloc;
+       }
+
+       instance->irq = IRQ_AMIGA_PORTS;
 
-#include "scsi_module.c"
+       regs = (struct a3000_scsiregs *)ZTWO_VADDR(res->start);
+       regs->DAWR = DAWR_A3000;
+
+       wdregs.SASR = &regs->SASR;
+       wdregs.SCMD = &regs->SCMD;
+
+       hdata = shost_priv(instance);
+       hdata->wh.no_sync = 0xff;
+       hdata->wh.fast = 0;
+       hdata->wh.dma_mode = CTRL_DMA;
+       hdata->regs = regs;
+
+       wd33c93_init(instance, wdregs, dma_setup, dma_stop, WD33C93_FS_12_15);
+       error = request_irq(IRQ_AMIGA_PORTS, a3000_intr, IRQF_SHARED,
+                           "A3000 SCSI", instance);
+       if (error)
+               goto fail_irq;
+
+       regs->CNTR = CNTR_PDMD | CNTR_INTEN;
+
+       error = scsi_add_host(instance, NULL);
+       if (error)
+               goto fail_host;
+
+       platform_set_drvdata(pdev, instance);
+
+       scsi_scan_host(instance);
+       return 0;
+
+fail_host:
+       free_irq(IRQ_AMIGA_PORTS, instance);
+fail_irq:
+       scsi_host_put(instance);
+fail_alloc:
+       release_mem_region(res->start, resource_size(res));
+       return error;
+}
+
+static int __exit amiga_a3000_scsi_remove(struct platform_device *pdev)
+{
+       struct Scsi_Host *instance = platform_get_drvdata(pdev);
+       struct a3000_hostdata *hdata = shost_priv(instance);
+       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       hdata->regs->CNTR = 0;
+       scsi_remove_host(instance);
+       free_irq(IRQ_AMIGA_PORTS, instance);
+       scsi_host_put(instance);
+       release_mem_region(res->start, resource_size(res));
+       return 0;
+}
+
+static struct platform_driver amiga_a3000_scsi_driver = {
+       .remove = __exit_p(amiga_a3000_scsi_remove),
+       .driver   = {
+               .name   = "amiga-a3000-scsi",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init amiga_a3000_scsi_init(void)
+{
+       return platform_driver_probe(&amiga_a3000_scsi_driver,
+                                    amiga_a3000_scsi_probe);
+}
+module_init(amiga_a3000_scsi_init);
 
-static int a3000_release(struct Scsi_Host *instance)
+static void __exit amiga_a3000_scsi_exit(void)
 {
-       DMA(instance)->CNTR = 0;
-       release_mem_region(0xDD0000, 256);
-       free_irq(IRQ_AMIGA_PORTS, a3000_intr);
-       return 1;
+       platform_driver_unregister(&amiga_a3000_scsi_driver);
 }
+module_exit(amiga_a3000_scsi_exit);
 
+MODULE_DESCRIPTION("Amiga 3000 built-in SCSI");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:amiga-a3000-scsi");
index 684813ee378c485cb5060b3ba9cfbcf483981bc6..49db4a335aaba4152ea553af335014fc234b74d2 100644 (file)
@@ -25,7 +25,7 @@
  */
 #define A3000_XFER_MASK                (0x00000003)
 
-typedef struct {
+struct a3000_scsiregs {
                 unsigned char  pad1[2];
        volatile unsigned short DAWR;
        volatile unsigned int   WTC;
@@ -46,7 +46,7 @@ typedef struct {
        volatile unsigned char  SASR;
                 unsigned char  pad9;
        volatile unsigned char  SCMD;
-} a3000_scsiregs;
+};
 
 #define DAWR_A3000             (3)
 
index 11ae6be8aeaf81ee466609eff419961d82c76d19..23c76f41883cf46a00bfa5bd00b8b17795be620d 100644 (file)
 
 #include "53c700.h"
 
-MODULE_AUTHOR("Alan Hourihane <alanh@fairlite.demon.co.uk> / Kars de Jong <jongk@linux-m68k.org>");
-MODULE_DESCRIPTION("Amiga A4000T NCR53C710 driver");
-MODULE_LICENSE("GPL");
-
 
 static struct scsi_host_template a4000t_scsi_driver_template = {
        .name           = "A4000T builtin SCSI",
@@ -32,30 +28,35 @@ static struct scsi_host_template a4000t_scsi_driver_template = {
        .module         = THIS_MODULE,
 };
 
-static struct platform_device *a4000t_scsi_device;
 
-#define A4000T_SCSI_ADDR 0xdd0040
+#define A4000T_SCSI_OFFSET     0x40
 
-static int __devinit a4000t_probe(struct platform_device *dev)
+static int __init amiga_a4000t_scsi_probe(struct platform_device *pdev)
 {
-       struct Scsi_Host *host;
+       struct resource *res;
+       phys_addr_t scsi_addr;
        struct NCR_700_Host_Parameters *hostdata;
+       struct Scsi_Host *host;
 
-       if (!(MACH_IS_AMIGA && AMIGAHW_PRESENT(A4000_SCSI)))
-               goto out;
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
 
-       if (!request_mem_region(A4000T_SCSI_ADDR, 0x1000,
+       if (!request_mem_region(res->start, resource_size(res),
                                "A4000T builtin SCSI"))
-               goto out;
+               return -EBUSY;
 
-       hostdata = kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
+       hostdata = kzalloc(sizeof(struct NCR_700_Host_Parameters),
+                          GFP_KERNEL);
        if (!hostdata) {
-               printk(KERN_ERR "a4000t-scsi: Failed to allocate host data\n");
+               dev_err(&pdev->dev, "Failed to allocate host data\n");
                goto out_release;
        }
 
+       scsi_addr = res->start + A4000T_SCSI_OFFSET;
+
        /* Fill in the required pieces of hostdata */
-       hostdata->base = (void __iomem *)ZTWO_VADDR(A4000T_SCSI_ADDR);
+       hostdata->base = (void __iomem *)ZTWO_VADDR(scsi_addr);
        hostdata->clock = 50;
        hostdata->chip710 = 1;
        hostdata->dmode_extra = DMODE_FC2;
@@ -63,26 +64,25 @@ static int __devinit a4000t_probe(struct platform_device *dev)
 
        /* and register the chip */
        host = NCR_700_detect(&a4000t_scsi_driver_template, hostdata,
-                             &dev->dev);
+                             &pdev->dev);
        if (!host) {
-               printk(KERN_ERR "a4000t-scsi: No host detected; "
-                               "board configuration problem?\n");
+               dev_err(&pdev->dev,
+                       "No host detected; board configuration problem?\n");
                goto out_free;
        }
 
        host->this_id = 7;
-       host->base = A4000T_SCSI_ADDR;
+       host->base = scsi_addr;
        host->irq = IRQ_AMIGA_PORTS;
 
        if (request_irq(host->irq, NCR_700_intr, IRQF_SHARED, "a4000t-scsi",
                        host)) {
-               printk(KERN_ERR "a4000t-scsi: request_irq failed\n");
+               dev_err(&pdev->dev, "request_irq failed\n");
                goto out_put_host;
        }
 
-       platform_set_drvdata(dev, host);
+       platform_set_drvdata(pdev, host);
        scsi_scan_host(host);
-
        return 0;
 
  out_put_host:
@@ -90,58 +90,49 @@ static int __devinit a4000t_probe(struct platform_device *dev)
  out_free:
        kfree(hostdata);
  out_release:
-       release_mem_region(A4000T_SCSI_ADDR, 0x1000);
- out:
+       release_mem_region(res->start, resource_size(res));
        return -ENODEV;
 }
 
-static __devexit int a4000t_device_remove(struct platform_device *dev)
+static int __exit amiga_a4000t_scsi_remove(struct platform_device *pdev)
 {
-       struct Scsi_Host *host = platform_get_drvdata(dev);
+       struct Scsi_Host *host = platform_get_drvdata(pdev);
        struct NCR_700_Host_Parameters *hostdata = shost_priv(host);
+       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
        scsi_remove_host(host);
-
        NCR_700_release(host);
        kfree(hostdata);
        free_irq(host->irq, host);
-       release_mem_region(A4000T_SCSI_ADDR, 0x1000);
-
+       release_mem_region(res->start, resource_size(res));
        return 0;
 }
 
-static struct platform_driver a4000t_scsi_driver = {
-       .driver = {
-               .name           = "a4000t-scsi",
-               .owner          = THIS_MODULE,
+static struct platform_driver amiga_a4000t_scsi_driver = {
+       .remove = __exit_p(amiga_a4000t_scsi_remove),
+       .driver   = {
+               .name   = "amiga-a4000t-scsi",
+               .owner  = THIS_MODULE,
        },
-       .probe          = a4000t_probe,
-       .remove         = __devexit_p(a4000t_device_remove),
 };
 
-static int __init a4000t_scsi_init(void)
+static int __init amiga_a4000t_scsi_init(void)
 {
-       int err;
-
-       err = platform_driver_register(&a4000t_scsi_driver);
-       if (err)
-               return err;
-
-       a4000t_scsi_device = platform_device_register_simple("a4000t-scsi",
-                       -1, NULL, 0);
-       if (IS_ERR(a4000t_scsi_device)) {
-               platform_driver_unregister(&a4000t_scsi_driver);
-               return PTR_ERR(a4000t_scsi_device);
-       }
-
-       return err;
+       return platform_driver_probe(&amiga_a4000t_scsi_driver,
+                                    amiga_a4000t_scsi_probe);
 }
 
-static void __exit a4000t_scsi_exit(void)
+module_init(amiga_a4000t_scsi_init);
+
+static void __exit amiga_a4000t_scsi_exit(void)
 {
-       platform_device_unregister(a4000t_scsi_device);
-       platform_driver_unregister(&a4000t_scsi_driver);
+       platform_driver_unregister(&amiga_a4000t_scsi_driver);
 }
 
-module_init(a4000t_scsi_init);
-module_exit(a4000t_scsi_exit);
+module_exit(amiga_a4000t_scsi_exit);
+
+MODULE_AUTHOR("Alan Hourihane <alanh@fairlite.demon.co.uk> / "
+             "Kars de Jong <jongk@linux-m68k.org>");
+MODULE_DESCRIPTION("Amiga A4000T NCR53C710 driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:amiga-a4000t-scsi");
index 9c0c91178538f61c9df636777e672f965e49d3e3..1a5bf5724750e95c269a2222ef9dc68539d5f0ee 100644 (file)
@@ -655,9 +655,9 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
                                /* Does this really need to be GFP_DMA? */
                                p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA);
                                if(!p) {
-                                       kfree (usg);
-                                       dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
+                                       dprintk((KERN_DEBUG "aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
                                          usg->sg[i].count,i,usg->count));
+                                       kfree(usg);
                                        rcode = -ENOMEM;
                                        goto cleanup;
                                }
index e9373a2d14fa3c5d37f1bf7660a73bc453a4d6a9..33898b61fdb53f3ae4f0b13037be14cca1a87326 100644 (file)
@@ -705,12 +705,17 @@ static int aac_cfg_open(struct inode *inode, struct file *file)
  *     Bugs: Needs to handle hot plugging
  */
 
-static int aac_cfg_ioctl(struct inode *inode, struct file *file,
+static long aac_cfg_ioctl(struct file *file,
                unsigned int cmd, unsigned long arg)
 {
+       int ret;
        if (!capable(CAP_SYS_RAWIO))
                return -EPERM;
-       return aac_do_ioctl(file->private_data, cmd, (void __user *)arg);
+       lock_kernel();
+       ret = aac_do_ioctl(file->private_data, cmd, (void __user *)arg);
+       unlock_kernel();
+
+       return ret;
 }
 
 #ifdef CONFIG_COMPAT
@@ -1029,7 +1034,7 @@ ssize_t aac_get_serial_number(struct device *device, char *buf)
 
 static const struct file_operations aac_cfg_fops = {
        .owner          = THIS_MODULE,
-       .ioctl          = aac_cfg_ioctl,
+       .unlocked_ioctl = aac_cfg_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = aac_compat_cfg_ioctl,
 #endif
index ab646e580d641dcb7f08a692921733b9a14e8129..ce5371b3cdd50767f0453c12829e83ad2627c63f 100644 (file)
@@ -48,7 +48,7 @@ struct device_attribute;
 /*The limit of outstanding scsi command that firmware can handle*/
 #define ARCMSR_MAX_OUTSTANDING_CMD                                             256
 #define ARCMSR_MAX_FREECCB_NUM                                                 320
-#define ARCMSR_DRIVER_VERSION               "Driver Version 1.20.00.15 2008/02/27"
+#define ARCMSR_DRIVER_VERSION               "Driver Version 1.20.00.15 2008/11/03"
 #define ARCMSR_SCSI_INITIATOR_ID                                               255
 #define ARCMSR_MAX_XFER_SECTORS                                                        512
 #define ARCMSR_MAX_XFER_SECTORS_B                                              4096
@@ -110,6 +110,8 @@ struct CMD_MESSAGE_FIELD
 #define FUNCTION_SAY_HELLO                     0x0807
 #define FUNCTION_SAY_GOODBYE                   0x0808
 #define FUNCTION_FLUSH_ADAPTER_CACHE           0x0809
+#define FUNCTION_GET_FIRMWARE_STATUS                   0x080A
+#define FUNCTION_HARDWARE_RESET                        0x080B
 /* ARECA IO CONTROL CODE*/
 #define ARCMSR_MESSAGE_READ_RQBUFFER       \
        ARECA_SATA_RAID | FUNCTION_READ_RQBUFFER
@@ -133,6 +135,7 @@ struct CMD_MESSAGE_FIELD
 #define ARCMSR_MESSAGE_RETURNCODE_OK              0x00000001
 #define ARCMSR_MESSAGE_RETURNCODE_ERROR           0x00000006
 #define ARCMSR_MESSAGE_RETURNCODE_3F              0x0000003F
+#define ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON  0x00000088
 /*
 *************************************************************
 **   structure for holding DMA address data
@@ -341,13 +344,13 @@ struct MessageUnit_B
        uint32_t        done_qbuffer[ARCMSR_MAX_HBB_POSTQUEUE];
        uint32_t        postq_index;
        uint32_t        doneq_index;
-       void            __iomem *drv2iop_doorbell_reg;
-       void            __iomem *drv2iop_doorbell_mask_reg;
-       void            __iomem *iop2drv_doorbell_reg;
-       void            __iomem *iop2drv_doorbell_mask_reg;
-       void            __iomem *msgcode_rwbuffer_reg;
-       void            __iomem *ioctl_wbuffer_reg;
-       void            __iomem *ioctl_rbuffer_reg;
+       uint32_t                __iomem *drv2iop_doorbell_reg;
+       uint32_t                __iomem *drv2iop_doorbell_mask_reg;
+       uint32_t                __iomem *iop2drv_doorbell_reg;
+       uint32_t                __iomem *iop2drv_doorbell_mask_reg;
+       uint32_t                __iomem *msgcode_rwbuffer_reg;
+       uint32_t                __iomem *ioctl_wbuffer_reg;
+       uint32_t                __iomem *ioctl_rbuffer_reg;
 };
 
 /*
@@ -375,6 +378,7 @@ struct AdapterControlBlock
        /* message unit ATU inbound base address0 */
 
        uint32_t                        acb_flags;
+       uint8_t                                 adapter_index;
        #define ACB_F_SCSISTOPADAPTER           0x0001
        #define ACB_F_MSG_STOP_BGRB             0x0002
        /* stop RAID background rebuild */
@@ -390,7 +394,7 @@ struct AdapterControlBlock
        #define ACB_F_BUS_RESET                 0x0080
        #define ACB_F_IOP_INITED                0x0100
        /* iop init */
-
+       #define ACB_F_FIRMWARE_TRAP                     0x0400
        struct CommandControlBlock *                    pccb_pool[ARCMSR_MAX_FREECCB_NUM];
        /* used for memory free */
        struct list_head                ccb_free_list;
@@ -423,12 +427,19 @@ struct AdapterControlBlock
 #define ARECA_RAID_GOOD               0xaa
        uint32_t                        num_resets;
        uint32_t                        num_aborts;
+       uint32_t                        signature;
        uint32_t                        firm_request_len;
        uint32_t                        firm_numbers_queue;
        uint32_t                        firm_sdram_size;
        uint32_t                        firm_hd_channels;
        char                            firm_model[12];
        char                            firm_version[20];
+       char                    device_map[20];                 /*21,84-99*/
+       struct work_struct              arcmsr_do_message_isr_bh;
+       struct timer_list               eternal_timer;
+       unsigned short          fw_state;
+       atomic_t                        rq_map_token;
+       int                     ante_token_value;
 };/* HW_DEVICE_EXTENSION */
 /*
 *******************************************************************************
index a4e04c50c436c9624031ad8272a877432b18fd12..07fdfe57e38e07eaf501ddc83a8aba77ed3ca39c 100644 (file)
@@ -192,6 +192,7 @@ static struct bin_attribute arcmsr_sysfs_message_read_attr = {
        .attr = {
                .name = "mu_read",
                .mode = S_IRUSR ,
+               .owner = THIS_MODULE,
        },
        .size = 1032,
        .read = arcmsr_sysfs_iop_message_read,
@@ -201,6 +202,7 @@ static struct bin_attribute arcmsr_sysfs_message_write_attr = {
        .attr = {
                .name = "mu_write",
                .mode = S_IWUSR,
+               .owner = THIS_MODULE,
        },
        .size = 1032,
        .write = arcmsr_sysfs_iop_message_write,
@@ -210,6 +212,7 @@ static struct bin_attribute arcmsr_sysfs_message_clear_attr = {
        .attr = {
                .name = "mu_clear",
                .mode = S_IWUSR,
+               .owner = THIS_MODULE,
        },
        .size = 1,
        .write = arcmsr_sysfs_iop_message_clear,
index ffbe2192da3c4bc42ac32e0bd8233db84eb1926f..ffa54792bb330126615a49a873b79bc718f01b78 100644 (file)
 #include <scsi/scsicam.h>
 #include "arcmsr.h"
 
+#ifdef CONFIG_SCSI_ARCMSR_RESET
+       static int sleeptime = 20;
+       static int retrycount = 12;
+       module_param(sleeptime, int, S_IRUGO|S_IWUSR);
+       MODULE_PARM_DESC(sleeptime, "The waiting period for FW ready while bus reset");
+       module_param(retrycount, int, S_IRUGO|S_IWUSR);
+       MODULE_PARM_DESC(retrycount, "The retry count for FW ready while bus reset");
+#endif
 MODULE_AUTHOR("Erich Chen <support@areca.com.tw>");
-MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/13xx/16xx) SATA/SAS RAID HOST Adapter");
+MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/13xx/16xx) SATA/SAS RAID Host Bus Adapter");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_VERSION(ARCMSR_DRIVER_VERSION);
 
@@ -96,6 +104,13 @@ static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb);
 static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb);
 static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb);
 static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb);
+static void arcmsr_request_device_map(unsigned long pacb);
+static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb);
+static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb);
+static void arcmsr_message_isr_bh_fn(struct work_struct *work);
+static void *arcmsr_get_firmware_spec(struct AdapterControlBlock *acb, int mode);
+static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb);
+
 static const char *arcmsr_info(struct Scsi_Host *);
 static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb);
 static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev,
@@ -112,7 +127,7 @@ static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev,
 
 static struct scsi_host_template arcmsr_scsi_host_template = {
        .module                 = THIS_MODULE,
-       .name                   = "ARCMSR ARECA SATA/SAS RAID HOST Adapter"
+       .name                   = "ARCMSR ARECA SATA/SAS RAID Host Bus Adapter"
                                                        ARCMSR_DRIVER_VERSION,
        .info                   = arcmsr_info,
        .queuecommand           = arcmsr_queue_command,
@@ -128,16 +143,6 @@ static struct scsi_host_template arcmsr_scsi_host_template = {
        .use_clustering         = ENABLE_CLUSTERING,
        .shost_attrs            = arcmsr_host_attrs,
 };
-#ifdef CONFIG_SCSI_ARCMSR_AER
-static pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev);
-static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev,
-                                               pci_channel_state_t state);
-
-static struct pci_error_handlers arcmsr_pci_error_handlers = {
-       .error_detected         = arcmsr_pci_error_detected,
-       .slot_reset             = arcmsr_pci_slot_reset,
-};
-#endif
 static struct pci_device_id arcmsr_device_id_table[] = {
        {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1110)},
        {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1120)},
@@ -166,9 +171,6 @@ static struct pci_driver arcmsr_pci_driver = {
        .probe                  = arcmsr_probe,
        .remove                 = arcmsr_remove,
        .shutdown               = arcmsr_shutdown,
-       #ifdef CONFIG_SCSI_ARCMSR_AER
-       .err_handler            = &arcmsr_pci_error_handlers,
-       #endif
 };
 
 static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id)
@@ -236,10 +238,9 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
                void *dma_coherent;
                dma_addr_t dma_coherent_handle, dma_addr;
                struct CommandControlBlock *ccb_tmp;
-               uint32_t intmask_org;
                int i, j;
 
-               acb->pmuA = pci_ioremap_bar(pdev, 0);
+               acb->pmuA = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
                if (!acb->pmuA) {
                        printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n",
                                                        acb->host->host_no);
@@ -281,12 +282,6 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
                for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
                        for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
                                acb->devstate[i][j] = ARECA_RAID_GONE;
-
-               /*
-               ** here we need to tell iop 331 our ccb_tmp.HighPart
-               ** if ccb_tmp.HighPart is not zero
-               */
-               intmask_org = arcmsr_disable_outbound_ints(acb);
                }
                break;
 
@@ -297,7 +292,6 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
                void __iomem *mem_base0, *mem_base1;
                void *dma_coherent;
                dma_addr_t dma_coherent_handle, dma_addr;
-               uint32_t intmask_org;
                struct CommandControlBlock *ccb_tmp;
                int i, j;
 
@@ -333,11 +327,13 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
                reg = (struct MessageUnit_B *)(dma_coherent +
                ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock));
                acb->pmuB = reg;
-               mem_base0 = pci_ioremap_bar(pdev, 0);
+               mem_base0 = ioremap(pci_resource_start(pdev, 0),
+                                       pci_resource_len(pdev, 0));
                if (!mem_base0)
                        goto out;
 
-               mem_base1 = pci_ioremap_bar(pdev, 2);
+               mem_base1 = ioremap(pci_resource_start(pdev, 2),
+                                       pci_resource_len(pdev, 2));
                if (!mem_base1) {
                        iounmap(mem_base0);
                        goto out;
@@ -357,12 +353,6 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
                for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
                        for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
                                acb->devstate[i][j] = ARECA_RAID_GOOD;
-
-               /*
-               ** here we need to tell iop 331 our ccb_tmp.HighPart
-               ** if ccb_tmp.HighPart is not zero
-               */
-               intmask_org = arcmsr_disable_outbound_ints(acb);
                }
                break;
        }
@@ -374,6 +364,88 @@ out:
                sizeof(struct MessageUnit_B)), acb->dma_coherent, acb->dma_coherent_handle);
        return -ENOMEM;
 }
+static void arcmsr_message_isr_bh_fn(struct work_struct *work)
+{
+       struct AdapterControlBlock *acb = container_of(work, struct AdapterControlBlock, arcmsr_do_message_isr_bh);
+
+       switch (acb->adapter_type) {
+               case ACB_ADAPTER_TYPE_A: {
+
+                       struct MessageUnit_A __iomem *reg  = acb->pmuA;
+                       char *acb_dev_map = (char *)acb->device_map;
+                       uint32_t __iomem *signature = (uint32_t __iomem *) (&reg->message_rwbuffer[0]);
+                       char __iomem *devicemap = (char __iomem *) (&reg->message_rwbuffer[21]);
+                       int target, lun;
+                       struct scsi_device *psdev;
+                       char diff;
+
+                       atomic_inc(&acb->rq_map_token);
+                       if (readl(signature) == ARCMSR_SIGNATURE_GET_CONFIG) {
+                               for (target = 0; target < ARCMSR_MAX_TARGETID - 1; target++) {
+                                       diff = (*acb_dev_map)^readb(devicemap);
+                                       if (diff != 0) {
+                                               char temp;
+                                               *acb_dev_map = readb(devicemap);
+                                               temp = *acb_dev_map;
+                                               for (lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) {
+                                                       if ((temp & 0x01) == 1 && (diff & 0x01) == 1) {
+                                                               scsi_add_device(acb->host, 0, target, lun);
+                                                       } else if ((temp & 0x01) == 0 && (diff & 0x01) == 1) {
+                                                               psdev = scsi_device_lookup(acb->host, 0, target, lun);
+                                                               if (psdev != NULL) {
+                                                                       scsi_remove_device(psdev);
+                                                                       scsi_device_put(psdev);
+                                                               }
+                                                       }
+                                                       temp >>= 1;
+                                                       diff >>= 1;
+                                               }
+                                       }
+                                       devicemap++;
+                                       acb_dev_map++;
+                               }
+                       }
+                       break;
+               }
+
+               case ACB_ADAPTER_TYPE_B: {
+                       struct MessageUnit_B *reg  = acb->pmuB;
+                       char *acb_dev_map = (char *)acb->device_map;
+                       uint32_t __iomem *signature = (uint32_t __iomem *)(&reg->msgcode_rwbuffer_reg[0]);
+                       char __iomem *devicemap = (char __iomem *)(&reg->msgcode_rwbuffer_reg[21]);
+                       int target, lun;
+                       struct scsi_device *psdev;
+                       char diff;
+
+                       atomic_inc(&acb->rq_map_token);
+                       if (readl(signature) == ARCMSR_SIGNATURE_GET_CONFIG) {
+                               for (target = 0; target < ARCMSR_MAX_TARGETID - 1; target++) {
+                                       diff = (*acb_dev_map)^readb(devicemap);
+                                       if (diff != 0) {
+                                               char temp;
+                                               *acb_dev_map = readb(devicemap);
+                                               temp = *acb_dev_map;
+                                               for (lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) {
+                                                       if ((temp & 0x01) == 1 && (diff & 0x01) == 1) {
+                                                               scsi_add_device(acb->host, 0, target, lun);
+                                                       } else if ((temp & 0x01) == 0 && (diff & 0x01) == 1) {
+                                                               psdev = scsi_device_lookup(acb->host, 0, target, lun);
+                                                               if (psdev != NULL) {
+                                                                       scsi_remove_device(psdev);
+                                                                       scsi_device_put(psdev);
+                                                               }
+                                                       }
+                                                       temp >>= 1;
+                                                       diff >>= 1;
+                                               }
+                                       }
+                                       devicemap++;
+                                       acb_dev_map++;
+                               }
+                       }
+               }
+       }
+}
 
 static int arcmsr_probe(struct pci_dev *pdev,
        const struct pci_device_id *id)
@@ -432,17 +504,17 @@ static int arcmsr_probe(struct pci_dev *pdev,
                           ACB_F_MESSAGE_WQBUFFER_READED);
        acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER;
        INIT_LIST_HEAD(&acb->ccb_free_list);
-
+       INIT_WORK(&acb->arcmsr_do_message_isr_bh, arcmsr_message_isr_bh_fn);
        error = arcmsr_alloc_ccb_pool(acb);
        if (error)
                goto out_release_regions;
 
+       arcmsr_iop_init(acb);
        error = request_irq(pdev->irq, arcmsr_do_interrupt,
                            IRQF_SHARED, "arcmsr", acb);
        if (error)
                goto out_free_ccb_pool;
 
-       arcmsr_iop_init(acb);
        pci_set_drvdata(pdev, host);
        if (strncmp(acb->firm_version, "V1.42", 5) >= 0)
                host->max_sectors= ARCMSR_MAX_XFER_SECTORS_B;
@@ -459,6 +531,14 @@ static int arcmsr_probe(struct pci_dev *pdev,
        #ifdef CONFIG_SCSI_ARCMSR_AER
        pci_enable_pcie_error_reporting(pdev);
        #endif
+       atomic_set(&acb->rq_map_token, 16);
+       acb->fw_state = true;
+       init_timer(&acb->eternal_timer);
+       acb->eternal_timer.expires = jiffies + msecs_to_jiffies(10*HZ);
+       acb->eternal_timer.data = (unsigned long) acb;
+       acb->eternal_timer.function = &arcmsr_request_device_map;
+       add_timer(&acb->eternal_timer);
+
        return 0;
  out_free_sysfs:
  out_free_irq:
@@ -518,40 +598,48 @@ static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb)
        return 0xff;
 }
 
-static void arcmsr_abort_hba_allcmd(struct AdapterControlBlock *acb)
+static uint8_t arcmsr_abort_hba_allcmd(struct AdapterControlBlock *acb)
 {
        struct MessageUnit_A __iomem *reg = acb->pmuA;
 
        writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, &reg->inbound_msgaddr0);
-       if (arcmsr_hba_wait_msgint_ready(acb))
+       if (arcmsr_hba_wait_msgint_ready(acb)) {
                printk(KERN_NOTICE
                        "arcmsr%d: wait 'abort all outstanding command' timeout \n"
                        , acb->host->host_no);
+               return 0xff;
+       }
+       return 0x00;
 }
 
-static void arcmsr_abort_hbb_allcmd(struct AdapterControlBlock *acb)
+static uint8_t arcmsr_abort_hbb_allcmd(struct AdapterControlBlock *acb)
 {
        struct MessageUnit_B *reg = acb->pmuB;
 
        writel(ARCMSR_MESSAGE_ABORT_CMD, reg->drv2iop_doorbell_reg);
-       if (arcmsr_hbb_wait_msgint_ready(acb))
+       if (arcmsr_hbb_wait_msgint_ready(acb)) {
                printk(KERN_NOTICE
                        "arcmsr%d: wait 'abort all outstanding command' timeout \n"
                        , acb->host->host_no);
+               return 0xff;
+       }
+       return 0x00;
 }
 
-static void arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
+static uint8_t arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
 {
+       uint8_t rtnval = 0;
        switch (acb->adapter_type) {
        case ACB_ADAPTER_TYPE_A: {
-               arcmsr_abort_hba_allcmd(acb);
+               rtnval = arcmsr_abort_hba_allcmd(acb);
                }
                break;
 
        case ACB_ADAPTER_TYPE_B: {
-               arcmsr_abort_hbb_allcmd(acb);
+               rtnval = arcmsr_abort_hbb_allcmd(acb);
                }
        }
+       return rtnval;
 }
 
 static void arcmsr_pci_unmap_dma(struct CommandControlBlock *ccb)
@@ -649,8 +737,7 @@ static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb)
 
        case ACB_ADAPTER_TYPE_A : {
                struct MessageUnit_A __iomem *reg = acb->pmuA;
-               orig_mask = readl(&reg->outbound_intmask)|\
-                               ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE;
+               orig_mask = readl(&reg->outbound_intmask);
                writel(orig_mask|ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE, \
                                                &reg->outbound_intmask);
                }
@@ -658,8 +745,7 @@ static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb)
 
        case ACB_ADAPTER_TYPE_B : {
                struct MessageUnit_B *reg = acb->pmuB;
-               orig_mask = readl(reg->iop2drv_doorbell_mask_reg) & \
-                                       (~ARCMSR_IOP2DRV_MESSAGE_CMD_DONE);
+               orig_mask = readl(reg->iop2drv_doorbell_mask_reg);
                writel(0, reg->iop2drv_doorbell_mask_reg);
                }
                break;
@@ -795,12 +881,13 @@ static void arcmsr_remove(struct pci_dev *pdev)
        struct AdapterControlBlock *acb =
                (struct AdapterControlBlock *) host->hostdata;
        int poll_count = 0;
-
        arcmsr_free_sysfs_attr(acb);
        scsi_remove_host(host);
+       flush_scheduled_work();
+       del_timer_sync(&acb->eternal_timer);
+       arcmsr_disable_outbound_ints(acb);
        arcmsr_stop_adapter_bgrb(acb);
        arcmsr_flush_adapter_cache(acb);
-       arcmsr_disable_outbound_ints(acb);
        acb->acb_flags |= ACB_F_SCSISTOPADAPTER;
        acb->acb_flags &= ~ACB_F_IOP_INITED;
 
@@ -841,7 +928,9 @@ static void arcmsr_shutdown(struct pci_dev *pdev)
        struct Scsi_Host *host = pci_get_drvdata(pdev);
        struct AdapterControlBlock *acb =
                (struct AdapterControlBlock *)host->hostdata;
-
+       del_timer_sync(&acb->eternal_timer);
+       arcmsr_disable_outbound_ints(acb);
+       flush_scheduled_work();
        arcmsr_stop_adapter_bgrb(acb);
        arcmsr_flush_adapter_cache(acb);
 }
@@ -861,7 +950,7 @@ static void arcmsr_module_exit(void)
 module_init(arcmsr_module_init);
 module_exit(arcmsr_module_exit);
 
-static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb, \
+static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb,
                                                u32 intmask_org)
 {
        u32 mask;
@@ -871,7 +960,8 @@ static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb, \
        case ACB_ADAPTER_TYPE_A : {
                struct MessageUnit_A __iomem *reg = acb->pmuA;
                mask = intmask_org & ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE |
-                            ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE);
+                            ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE|
+                            ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE);
                writel(mask, &reg->outbound_intmask);
                acb->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff;
                }
@@ -879,8 +969,10 @@ static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb, \
 
        case ACB_ADAPTER_TYPE_B : {
                struct MessageUnit_B *reg = acb->pmuB;
-               mask = intmask_org | (ARCMSR_IOP2DRV_DATA_WRITE_OK | \
-                       ARCMSR_IOP2DRV_DATA_READ_OK | ARCMSR_IOP2DRV_CDB_DONE);
+               mask = intmask_org | (ARCMSR_IOP2DRV_DATA_WRITE_OK |
+                       ARCMSR_IOP2DRV_DATA_READ_OK |
+                       ARCMSR_IOP2DRV_CDB_DONE |
+                       ARCMSR_IOP2DRV_MESSAGE_CMD_DONE);
                writel(mask, reg->iop2drv_doorbell_mask_reg);
                acb->outbound_int_enable = (intmask_org | mask) & 0x0000000f;
                }
@@ -1048,8 +1140,8 @@ static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb)
        }
        case ACB_ADAPTER_TYPE_B: {
                struct MessageUnit_B *reg = acb->pmuB;
-               iounmap(reg->drv2iop_doorbell_reg - ARCMSR_DRV2IOP_DOORBELL);
-               iounmap(reg->ioctl_wbuffer_reg - ARCMSR_IOCTL_WBUFFER);
+               iounmap((u8 *)reg->drv2iop_doorbell_reg - ARCMSR_DRV2IOP_DOORBELL);
+               iounmap((u8 *)reg->ioctl_wbuffer_reg - ARCMSR_IOCTL_WBUFFER);
                dma_free_coherent(&acb->pdev->dev,
                (ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock) + 0x20 +
                sizeof(struct MessageUnit_B)), acb->dma_coherent, acb->dma_coherent_handle);
@@ -1249,13 +1341,36 @@ static void arcmsr_hbb_postqueue_isr(struct AdapterControlBlock *acb)
                reg->doneq_index = index;
        }
 }
+/*
+**********************************************************************************
+** Handle a message interrupt
+**
+** The only message interrupt we expect is in response to a query for the current adapter config.
+** We want this in order to compare the drivemap so that we can detect newly-attached drives.
+**********************************************************************************
+*/
+static void arcmsr_hba_message_isr(struct AdapterControlBlock *acb)
+{
+       struct MessageUnit_A *reg  = acb->pmuA;
+
+       /*clear interrupt and message state*/
+       writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT, &reg->outbound_intstatus);
+       schedule_work(&acb->arcmsr_do_message_isr_bh);
+}
+static void arcmsr_hbb_message_isr(struct AdapterControlBlock *acb)
+{
+       struct MessageUnit_B *reg  = acb->pmuB;
 
+       /*clear interrupt and message state*/
+       writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell_reg);
+       schedule_work(&acb->arcmsr_do_message_isr_bh);
+}
 static int arcmsr_handle_hba_isr(struct AdapterControlBlock *acb)
 {
        uint32_t outbound_intstatus;
        struct MessageUnit_A __iomem *reg = acb->pmuA;
 
-       outbound_intstatus = readl(&reg->outbound_intstatus) & \
+       outbound_intstatus = readl(&reg->outbound_intstatus) &
                                                        acb->outbound_int_enable;
        if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT))      {
                return 1;
@@ -1267,6 +1382,10 @@ static int arcmsr_handle_hba_isr(struct AdapterControlBlock *acb)
        if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) {
                arcmsr_hba_postqueue_isr(acb);
        }
+       if (outbound_intstatus & ARCMSR_MU_OUTBOUND_MESSAGE0_INT)       {
+               /* messenger of "driver to iop commands" */
+               arcmsr_hba_message_isr(acb);
+       }
        return 0;
 }
 
@@ -1275,13 +1394,14 @@ static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb)
        uint32_t outbound_doorbell;
        struct MessageUnit_B *reg = acb->pmuB;
 
-       outbound_doorbell = readl(reg->iop2drv_doorbell_reg) & \
+       outbound_doorbell = readl(reg->iop2drv_doorbell_reg) &
                                                        acb->outbound_int_enable;
        if (!outbound_doorbell)
                return 1;
 
        writel(~outbound_doorbell, reg->iop2drv_doorbell_reg);
-       /*in case the last action of doorbell interrupt clearance is cached, this action can push HW to write down the clear bit*/
+       /*in case the last action of doorbell interrupt clearance is cached,
+       this action can push HW to write down the clear bit*/
        readl(reg->iop2drv_doorbell_reg);
        writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell_reg);
        if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK)   {
@@ -1293,6 +1413,10 @@ static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb)
        if (outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE) {
                arcmsr_hbb_postqueue_isr(acb);
        }
+       if (outbound_doorbell & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) {
+               /* messenger of "driver to iop commands" */
+               arcmsr_hbb_message_isr(acb);
+       }
 
        return 0;
 }
@@ -1360,7 +1484,7 @@ void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *acb)
        }
 }
 
-static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \
+static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
                                        struct scsi_cmnd *cmd)
 {
        struct CMD_MESSAGE_FIELD *pcmdmessagefld;
@@ -1398,6 +1522,13 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \
                        retvalue = ARCMSR_MESSAGE_FAIL;
                        goto message_out;
                }
+
+               if (!acb->fw_state) {
+                       pcmdmessagefld->cmdmessage.ReturnCode =
+                       ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
+                       goto message_out;
+               }
+
                ptmpQbuffer = ver_addr;
                while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex)
                        && (allxfer_len < 1031)) {
@@ -1444,6 +1575,12 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \
                        retvalue = ARCMSR_MESSAGE_FAIL;
                        goto message_out;
                }
+               if (!acb->fw_state) {
+                       pcmdmessagefld->cmdmessage.ReturnCode =
+                       ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
+                       goto message_out;
+               }
+
                ptmpuserbuffer = ver_addr;
                user_len = pcmdmessagefld->cmdmessage.Length;
                memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, user_len);
@@ -1496,6 +1633,11 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \
 
        case ARCMSR_MESSAGE_CLEAR_RQBUFFER: {
                uint8_t *pQbuffer = acb->rqbuffer;
+               if (!acb->fw_state) {
+                       pcmdmessagefld->cmdmessage.ReturnCode =
+                       ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
+                       goto message_out;
+               }
 
                if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
                        acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
@@ -1511,6 +1653,11 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \
 
        case ARCMSR_MESSAGE_CLEAR_WQBUFFER: {
                uint8_t *pQbuffer = acb->wqbuffer;
+               if (!acb->fw_state) {
+                       pcmdmessagefld->cmdmessage.ReturnCode =
+                       ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
+                       goto message_out;
+               }
 
                if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
                        acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
@@ -1529,6 +1676,11 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \
 
        case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: {
                uint8_t *pQbuffer;
+               if (!acb->fw_state) {
+                       pcmdmessagefld->cmdmessage.ReturnCode =
+                       ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
+                       goto message_out;
+               }
 
                if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
                        acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
@@ -1551,13 +1703,22 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \
                break;
 
        case ARCMSR_MESSAGE_RETURN_CODE_3F: {
+               if (!acb->fw_state) {
+                       pcmdmessagefld->cmdmessage.ReturnCode =
+                       ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
+                       goto message_out;
+               }
                pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_3F;
                }
                break;
 
        case ARCMSR_MESSAGE_SAY_HELLO: {
                int8_t *hello_string = "Hello! I am ARCMSR";
-
+               if (!acb->fw_state) {
+                       pcmdmessagefld->cmdmessage.ReturnCode =
+                       ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
+                       goto message_out;
+               }
                memcpy(pcmdmessagefld->messagedatabuffer, hello_string
                        , (int16_t)strlen(hello_string));
                pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
@@ -1565,10 +1726,20 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \
                break;
 
        case ARCMSR_MESSAGE_SAY_GOODBYE:
+               if (!acb->fw_state) {
+                       pcmdmessagefld->cmdmessage.ReturnCode =
+                       ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
+                       goto message_out;
+               }
                arcmsr_iop_parking(acb);
                break;
 
        case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE:
+               if (!acb->fw_state) {
+                       pcmdmessagefld->cmdmessage.ReturnCode =
+                       ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
+                       goto message_out;
+               }
                arcmsr_flush_adapter_cache(acb);
                break;
 
@@ -1651,16 +1822,57 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd,
        struct CommandControlBlock *ccb;
        int target = cmd->device->id;
        int lun = cmd->device->lun;
-
+       uint8_t scsicmd = cmd->cmnd[0];
        cmd->scsi_done = done;
        cmd->host_scribble = NULL;
        cmd->result = 0;
+
+       if ((scsicmd == SYNCHRONIZE_CACHE) || (scsicmd == SEND_DIAGNOSTIC)) {
+               if (acb->devstate[target][lun] == ARECA_RAID_GONE) {
+                       cmd->result = (DID_NO_CONNECT << 16);
+               }
+               cmd->scsi_done(cmd);
+               return 0;
+       }
+
        if (acb->acb_flags & ACB_F_BUS_RESET) {
-               printk(KERN_NOTICE "arcmsr%d: bus reset"
-                       " and return busy \n"
-                       , acb->host->host_no);
+               switch (acb->adapter_type) {
+                       case ACB_ADAPTER_TYPE_A: {
+                               struct MessageUnit_A __iomem *reg = acb->pmuA;
+                               uint32_t intmask_org, outbound_doorbell;
+
+                               if ((readl(&reg->outbound_msgaddr1) &
+                                       ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) {
+                                       printk(KERN_NOTICE "arcmsr%d: bus reset and return busy\n",
+                                               acb->host->host_no);
                return SCSI_MLQUEUE_HOST_BUSY;
        }
+
+                               acb->acb_flags &= ~ACB_F_FIRMWARE_TRAP;
+                               printk(KERN_NOTICE "arcmsr%d: hardware bus reset and reset ok\n",
+                                       acb->host->host_no);
+                               /* disable all outbound interrupt */
+                               intmask_org = arcmsr_disable_outbound_ints(acb);
+                               arcmsr_get_firmware_spec(acb, 1);
+                               /*start background rebuild*/
+                               arcmsr_start_adapter_bgrb(acb);
+                               /* clear Qbuffer if door bell ringed */
+                               outbound_doorbell = readl(&reg->outbound_doorbell);
+                               /*clear interrupt */
+                               writel(outbound_doorbell, &reg->outbound_doorbell);
+                               writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
+                                       &reg->inbound_doorbell);
+                               /* enable outbound Post Queue,outbound doorbell Interrupt */
+                               arcmsr_enable_outbound_ints(acb, intmask_org);
+                               acb->acb_flags |= ACB_F_IOP_INITED;
+                               acb->acb_flags &= ~ACB_F_BUS_RESET;
+                       }
+                       break;
+                       case ACB_ADAPTER_TYPE_B: {
+                       }
+               }
+       }
+
        if (target == 16) {
                /* virtual device for iop message transfer */
                arcmsr_handle_virtual_command(acb, cmd);
@@ -1699,21 +1911,25 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd,
        return 0;
 }
 
-static void arcmsr_get_hba_config(struct AdapterControlBlock *acb)
+static void *arcmsr_get_hba_config(struct AdapterControlBlock *acb, int mode)
 {
        struct MessageUnit_A __iomem *reg = acb->pmuA;
        char *acb_firm_model = acb->firm_model;
        char *acb_firm_version = acb->firm_version;
+       char *acb_device_map = acb->device_map;
        char __iomem *iop_firm_model = (char __iomem *)(&reg->message_rwbuffer[15]);
        char __iomem *iop_firm_version = (char __iomem *)(&reg->message_rwbuffer[17]);
+       char __iomem *iop_device_map = (char __iomem *) (&reg->message_rwbuffer[21]);
        int count;
 
        writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
        if (arcmsr_hba_wait_msgint_ready(acb)) {
                printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
                        miscellaneous data' timeout \n", acb->host->host_no);
+               return NULL;
        }
 
+       if (mode == 1) {
        count = 8;
        while (count) {
                *acb_firm_model = readb(iop_firm_model);
@@ -1730,34 +1946,48 @@ static void arcmsr_get_hba_config(struct AdapterControlBlock *acb)
                count--;
        }
 
+               count = 16;
+               while (count) {
+                       *acb_device_map = readb(iop_device_map);
+                       acb_device_map++;
+                       iop_device_map++;
+                       count--;
+               }
+
        printk(KERN_INFO        "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n"
                , acb->host->host_no
                , acb->firm_version);
-
+               acb->signature = readl(&reg->message_rwbuffer[0]);
        acb->firm_request_len = readl(&reg->message_rwbuffer[1]);
        acb->firm_numbers_queue = readl(&reg->message_rwbuffer[2]);
        acb->firm_sdram_size = readl(&reg->message_rwbuffer[3]);
        acb->firm_hd_channels = readl(&reg->message_rwbuffer[4]);
 }
-
-static void arcmsr_get_hbb_config(struct AdapterControlBlock *acb)
+       return reg->message_rwbuffer;
+}
+static void __iomem *arcmsr_get_hbb_config(struct AdapterControlBlock *acb, int mode)
 {
        struct MessageUnit_B *reg = acb->pmuB;
        uint32_t __iomem *lrwbuffer = reg->msgcode_rwbuffer_reg;
        char *acb_firm_model = acb->firm_model;
        char *acb_firm_version = acb->firm_version;
+       char *acb_device_map = acb->device_map;
        char __iomem *iop_firm_model = (char __iomem *)(&lrwbuffer[15]);
        /*firm_model,15,60-67*/
        char __iomem *iop_firm_version = (char __iomem *)(&lrwbuffer[17]);
        /*firm_version,17,68-83*/
+       char __iomem *iop_device_map = (char __iomem *) (&lrwbuffer[21]);
+       /*firm_version,21,84-99*/
        int count;
 
        writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell_reg);
        if (arcmsr_hbb_wait_msgint_ready(acb)) {
                printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
                        miscellaneous data' timeout \n", acb->host->host_no);
+               return NULL;
        }
 
+       if (mode == 1) {
        count = 8;
        while (count)
        {
@@ -1776,11 +2006,20 @@ static void arcmsr_get_hbb_config(struct AdapterControlBlock *acb)
                count--;
        }
 
+               count = 16;
+               while (count) {
+                       *acb_device_map = readb(iop_device_map);
+                       acb_device_map++;
+                       iop_device_map++;
+                       count--;
+               }
+
        printk(KERN_INFO "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n",
                        acb->host->host_no,
                        acb->firm_version);
 
-       lrwbuffer++;
+               acb->signature = readl(lrwbuffer++);
+               /*firm_signature,1,00-03*/
        acb->firm_request_len = readl(lrwbuffer++);
        /*firm_request_len,1,04-07*/
        acb->firm_numbers_queue = readl(lrwbuffer++);
@@ -1790,20 +2029,23 @@ static void arcmsr_get_hbb_config(struct AdapterControlBlock *acb)
        acb->firm_hd_channels = readl(lrwbuffer);
        /*firm_ide_channels,4,16-19*/
 }
-
-static void arcmsr_get_firmware_spec(struct AdapterControlBlock *acb)
+       return reg->msgcode_rwbuffer_reg;
+}
+static void *arcmsr_get_firmware_spec(struct AdapterControlBlock *acb, int mode)
 {
+       void *rtnval = 0;
        switch (acb->adapter_type) {
        case ACB_ADAPTER_TYPE_A: {
-               arcmsr_get_hba_config(acb);
+               rtnval = arcmsr_get_hba_config(acb, mode);
                }
                break;
 
        case ACB_ADAPTER_TYPE_B: {
-               arcmsr_get_hbb_config(acb);
+               rtnval = arcmsr_get_hbb_config(acb, mode);
                }
                break;
        }
+       return rtnval;
 }
 
 static void arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb,
@@ -2043,6 +2285,66 @@ static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb)
        }
 }
 
+static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb)
+{
+       struct MessageUnit_A __iomem *reg = acb->pmuA;
+
+       if (unlikely(atomic_read(&acb->rq_map_token) == 0)) {
+               acb->fw_state = false;
+       } else {
+       /*to prevent rq_map_token from changing by other interrupt, then
+       avoid the dead-lock*/
+               acb->fw_state = true;
+               atomic_dec(&acb->rq_map_token);
+               if (!(acb->fw_state) ||
+                       (acb->ante_token_value == atomic_read(&acb->rq_map_token))) {
+                       atomic_set(&acb->rq_map_token, 16);
+               }
+               acb->ante_token_value = atomic_read(&acb->rq_map_token);
+               writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
+       }
+       mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6000));
+       return;
+}
+
+static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb)
+{
+       struct MessageUnit_B __iomem *reg = acb->pmuB;
+
+       if (unlikely(atomic_read(&acb->rq_map_token) == 0)) {
+               acb->fw_state = false;
+       } else {
+       /*to prevent rq_map_token from changing by other interrupt, then
+       avoid the dead-lock*/
+               acb->fw_state = true;
+               atomic_dec(&acb->rq_map_token);
+               if (!(acb->fw_state) ||
+                       (acb->ante_token_value == atomic_read(&acb->rq_map_token))) {
+                       atomic_set(&acb->rq_map_token, 16);
+               }
+               acb->ante_token_value = atomic_read(&acb->rq_map_token);
+               writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell_reg);
+       }
+       mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6000));
+       return;
+}
+
+static void arcmsr_request_device_map(unsigned long pacb)
+{
+       struct AdapterControlBlock *acb = (struct AdapterControlBlock *)pacb;
+
+       switch (acb->adapter_type) {
+               case ACB_ADAPTER_TYPE_A: {
+                       arcmsr_request_hba_device_map(acb);
+               }
+               break;
+               case ACB_ADAPTER_TYPE_B: {
+                       arcmsr_request_hbb_device_map(acb);
+               }
+               break;
+       }
+}
+
 static void arcmsr_start_hba_bgrb(struct AdapterControlBlock *acb)
 {
        struct MessageUnit_A __iomem *reg = acb->pmuA;
@@ -2121,6 +2423,60 @@ static void arcmsr_enable_eoi_mode(struct AdapterControlBlock *acb)
        return;
 }
 
+static void arcmsr_hardware_reset(struct AdapterControlBlock *acb)
+{
+       uint8_t value[64];
+       int i;
+
+       /* backup pci config data */
+       for (i = 0; i < 64; i++) {
+               pci_read_config_byte(acb->pdev, i, &value[i]);
+       }
+       /* hardware reset signal */
+       pci_write_config_byte(acb->pdev, 0x84, 0x20);
+       msleep(1000);
+       /* write back pci config data */
+       for (i = 0; i < 64; i++) {
+               pci_write_config_byte(acb->pdev, i, value[i]);
+       }
+       msleep(1000);
+       return;
+}
+/*
+****************************************************************************
+****************************************************************************
+*/
+#ifdef CONFIG_SCSI_ARCMSR_RESET
+       int arcmsr_sleep_for_bus_reset(struct scsi_cmnd *cmd)
+       {
+                       struct Scsi_Host *shost = NULL;
+                       spinlock_t *host_lock = NULL;
+                       int i, isleep;
+
+                       shost = cmd->device->host;
+                       host_lock = shost->host_lock;
+
+                       printk(KERN_NOTICE "Host %d bus reset over, sleep %d seconds (busy %d, can queue %d) ...........\n",
+                                       shost->host_no, sleeptime, shost->host_busy, shost->can_queue);
+                       isleep = sleeptime / 10;
+                       spin_unlock_irq(host_lock);
+                       if (isleep > 0) {
+                               for (i = 0; i < isleep; i++) {
+                                       msleep(10000);
+                                       printk(KERN_NOTICE "^%d^\n", i);
+                               }
+                       }
+
+                       isleep = sleeptime % 10;
+                       if (isleep > 0) {
+                               msleep(isleep * 1000);
+                               printk(KERN_NOTICE "^v^\n");
+                       }
+                       spin_lock_irq(host_lock);
+                       printk(KERN_NOTICE "***** wake up *****\n");
+                       return 0;
+       }
+#endif
 static void arcmsr_iop_init(struct AdapterControlBlock *acb)
 {
        uint32_t intmask_org;
@@ -2129,7 +2485,7 @@ static void arcmsr_iop_init(struct AdapterControlBlock *acb)
        intmask_org = arcmsr_disable_outbound_ints(acb);
        arcmsr_wait_firmware_ready(acb);
        arcmsr_iop_confirm(acb);
-       arcmsr_get_firmware_spec(acb);
+       arcmsr_get_firmware_spec(acb, 1);
        /*start background rebuild*/
        arcmsr_start_adapter_bgrb(acb);
        /* empty doorbell Qbuffer if door bell ringed */
@@ -2140,51 +2496,110 @@ static void arcmsr_iop_init(struct AdapterControlBlock *acb)
        acb->acb_flags |= ACB_F_IOP_INITED;
 }
 
-static void arcmsr_iop_reset(struct AdapterControlBlock *acb)
+static uint8_t arcmsr_iop_reset(struct AdapterControlBlock *acb)
 {
        struct CommandControlBlock *ccb;
        uint32_t intmask_org;
+       uint8_t rtnval = 0x00;
        int i = 0;
 
        if (atomic_read(&acb->ccboutstandingcount) != 0) {
+               /* disable all outbound interrupt */
+               intmask_org = arcmsr_disable_outbound_ints(acb);
                /* talk to iop 331 outstanding command aborted */
-               arcmsr_abort_allcmd(acb);
-
+               rtnval = arcmsr_abort_allcmd(acb);
                /* wait for 3 sec for all command aborted*/
                ssleep(3);
-
-               /* disable all outbound interrupt */
-               intmask_org = arcmsr_disable_outbound_ints(acb);
                /* clear all outbound posted Q */
                arcmsr_done4abort_postqueue(acb);
                for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
                        ccb = acb->pccb_pool[i];
                        if (ccb->startdone == ARCMSR_CCB_START) {
-                               ccb->startdone = ARCMSR_CCB_ABORTED;
                                arcmsr_ccb_complete(ccb, 1);
                        }
                }
+               atomic_set(&acb->ccboutstandingcount, 0);
                /* enable all outbound interrupt */
                arcmsr_enable_outbound_ints(acb, intmask_org);
+               return rtnval;
        }
+       return rtnval;
 }
 
 static int arcmsr_bus_reset(struct scsi_cmnd *cmd)
 {
        struct AdapterControlBlock *acb =
                (struct AdapterControlBlock *)cmd->device->host->hostdata;
-       int i;
+       int retry = 0;
 
-       acb->num_resets++;
+       if (acb->acb_flags & ACB_F_BUS_RESET)
+               return SUCCESS;
+
+       printk(KERN_NOTICE "arcmsr%d: bus reset ..... \n", acb->adapter_index);
        acb->acb_flags |= ACB_F_BUS_RESET;
-       for (i = 0; i < 400; i++) {
-               if (!atomic_read(&acb->ccboutstandingcount))
+       acb->num_resets++;
+       while (atomic_read(&acb->ccboutstandingcount) != 0 && retry < 4) {
+               arcmsr_interrupt(acb);
+               retry++;
+       }
+
+       if (arcmsr_iop_reset(acb)) {
+               switch (acb->adapter_type) {
+               case ACB_ADAPTER_TYPE_A: {
+                       printk(KERN_NOTICE "arcmsr%d: do hardware bus reset, num_resets = %d num_aborts = %d \n",
+                               acb->adapter_index, acb->num_resets, acb->num_aborts);
+                       arcmsr_hardware_reset(acb);
+                       acb->acb_flags |= ACB_F_FIRMWARE_TRAP;
+                       acb->acb_flags &= ~ACB_F_IOP_INITED;
+                       #ifdef CONFIG_SCSI_ARCMSR_RESET
+                       struct MessageUnit_A __iomem *reg = acb->pmuA;
+                       uint32_t intmask_org, outbound_doorbell;
+                       int retry_count = 0;
+sleep_again:
+                       arcmsr_sleep_for_bus_reset(cmd);
+                       if ((readl(&reg->outbound_msgaddr1) &
+                       ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) {
+                       printk(KERN_NOTICE "arcmsr%d: hardware bus reset and return busy, retry=%d \n",
+                       acb->host->host_no, retry_count);
+                       if (retry_count > retrycount) {
+                               printk(KERN_NOTICE "arcmsr%d: hardware bus reset and return busy, retry aborted \n",
+                               acb->host->host_no);
+                       return SUCCESS;
+                       }
+                       retry_count++;
+                       goto sleep_again;
+                       }
+                       acb->acb_flags &= ~ACB_F_FIRMWARE_TRAP;
+                       acb->acb_flags |= ACB_F_IOP_INITED;
+                       acb->acb_flags &= ~ACB_F_BUS_RESET;
+                       printk(KERN_NOTICE "arcmsr%d: hardware bus reset and reset ok \n",
+                               acb->host->host_no);
+                       /* disable all outbound interrupt */
+                       intmask_org = arcmsr_disable_outbound_ints(acb);
+                       arcmsr_get_firmware_spec(acb, 1);
+                       /*start background rebuild*/
+                       arcmsr_start_adapter_bgrb(acb);
+                       /* clear Qbuffer if door bell ringed */
+                       outbound_doorbell = readl(&reg->outbound_doorbell);
+                       writel(outbound_doorbell, &reg->outbound_doorbell); /*clear interrupt */
+                       writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, &reg->inbound_doorbell);
+                       /* enable outbound Post Queue,outbound doorbell Interrupt */
+                       arcmsr_enable_outbound_ints(acb, intmask_org);
+                       atomic_set(&acb->rq_map_token, 16);
+                       init_timer(&acb->eternal_timer);
+                       acb->eternal_timer.expires = jiffies + msecs_to_jiffies(20*HZ);
+                       acb->eternal_timer.data = (unsigned long) acb;
+                       acb->eternal_timer.function = &arcmsr_request_device_map;
+                       add_timer(&acb->eternal_timer);
+                       #endif
+               }
                        break;
-               arcmsr_interrupt(acb);/* FIXME: need spinlock */
-               msleep(25);
+               case ACB_ADAPTER_TYPE_B: {
        }
-       arcmsr_iop_reset(acb);
+               }
+       } else {
        acb->acb_flags &= ~ACB_F_BUS_RESET;
+       }
        return SUCCESS;
 }
 
@@ -2277,98 +2692,3 @@ static const char *arcmsr_info(struct Scsi_Host *host)
                        ARCMSR_DRIVER_VERSION);
        return buf;
 }
-#ifdef CONFIG_SCSI_ARCMSR_AER
-static pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev)
-{
-       struct Scsi_Host *host = pci_get_drvdata(pdev);
-       struct AdapterControlBlock *acb =
-               (struct AdapterControlBlock *) host->hostdata;
-       uint32_t intmask_org;
-       int i, j;
-
-       if (pci_enable_device(pdev)) {
-               return PCI_ERS_RESULT_DISCONNECT;
-       }
-       pci_set_master(pdev);
-       intmask_org = arcmsr_disable_outbound_ints(acb);
-       acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
-                          ACB_F_MESSAGE_RQBUFFER_CLEARED |
-                          ACB_F_MESSAGE_WQBUFFER_READED);
-       acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER;
-       for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
-               for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
-                       acb->devstate[i][j] = ARECA_RAID_GONE;
-
-       arcmsr_wait_firmware_ready(acb);
-       arcmsr_iop_confirm(acb);
-       /* disable all outbound interrupt */
-       arcmsr_get_firmware_spec(acb);
-       /*start background rebuild*/
-       arcmsr_start_adapter_bgrb(acb);
-       /* empty doorbell Qbuffer if door bell ringed */
-       arcmsr_clear_doorbell_queue_buffer(acb);
-       arcmsr_enable_eoi_mode(acb);
-       /* enable outbound Post Queue,outbound doorbell Interrupt */
-       arcmsr_enable_outbound_ints(acb, intmask_org);
-       acb->acb_flags |= ACB_F_IOP_INITED;
-
-       pci_enable_pcie_error_reporting(pdev);
-       return PCI_ERS_RESULT_RECOVERED;
-}
-
-static void arcmsr_pci_ers_need_reset_forepart(struct pci_dev *pdev)
-{
-       struct Scsi_Host *host = pci_get_drvdata(pdev);
-       struct AdapterControlBlock *acb = (struct AdapterControlBlock *)host->hostdata;
-       struct CommandControlBlock *ccb;
-       uint32_t intmask_org;
-       int i = 0;
-
-       if (atomic_read(&acb->ccboutstandingcount) != 0) {
-               /* talk to iop 331 outstanding command aborted */
-               arcmsr_abort_allcmd(acb);
-               /* wait for 3 sec for all command aborted*/
-               ssleep(3);
-               /* disable all outbound interrupt */
-               intmask_org = arcmsr_disable_outbound_ints(acb);
-               /* clear all outbound posted Q */
-               arcmsr_done4abort_postqueue(acb);
-               for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
-                       ccb = acb->pccb_pool[i];
-                       if (ccb->startdone == ARCMSR_CCB_START) {
-                               ccb->startdone = ARCMSR_CCB_ABORTED;
-                               arcmsr_ccb_complete(ccb, 1);
-                       }
-               }
-               /* enable all outbound interrupt */
-               arcmsr_enable_outbound_ints(acb, intmask_org);
-       }
-       pci_disable_device(pdev);
-}
-
-static void arcmsr_pci_ers_disconnect_forepart(struct pci_dev *pdev)
-{
-                       struct Scsi_Host *host = pci_get_drvdata(pdev);
-                       struct AdapterControlBlock *acb = \
-                               (struct AdapterControlBlock *)host->hostdata;
-
-                       arcmsr_stop_adapter_bgrb(acb);
-                       arcmsr_flush_adapter_cache(acb);
-}
-
-static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev,
-                                               pci_channel_state_t state)
-{
-       switch (state) {
-       case pci_channel_io_frozen:
-                       arcmsr_pci_ers_need_reset_forepart(pdev);
-                       return PCI_ERS_RESULT_NEED_RESET;
-       case pci_channel_io_perm_failure:
-                       arcmsr_pci_ers_disconnect_forepart(pdev);
-                       return PCI_ERS_RESULT_DISCONNECT;
-                       break;
-       default:
-                       return PCI_ERS_RESULT_NEED_RESET;
-         }
-}
-#endif
index e641922f20bc5eb58a4ce0adb879b55e55cad13d..350cbeaae1608f6382dc492ad913a376ca48c7ae 100644 (file)
@@ -167,10 +167,9 @@ unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba,
                                &nonemb_cmd.dma);
        if (nonemb_cmd.va == NULL) {
                SE_DEBUG(DBG_LVL_1,
-                        "Failed to allocate memory for"
-                        "mgmt_invalidate_icds \n");
+                        "Failed to allocate memory for mgmt_invalidate_icds\n");
                spin_unlock(&ctrl->mbox_lock);
-               return -1;
+               return 0;
        }
        nonemb_cmd.size = sizeof(struct invalidate_commands_params_in);
        req = nonemb_cmd.va;
index 0c08e185a7666606729f10d9856d54be2ed503b9..3a7b3f88932f81a99ba7bd3d9b19322d918ae66b 100644 (file)
@@ -84,11 +84,32 @@ bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo)
        for (i = 0; hal_mods[i]; i++)
                hal_mods[i]->meminfo(cfg, &km_len, &dm_len);
 
+       dm_len += bfa_port_meminfo();
 
        meminfo->meminfo[BFA_MEM_TYPE_KVA - 1].mem_len = km_len;
        meminfo->meminfo[BFA_MEM_TYPE_DMA - 1].mem_len = dm_len;
 }
 
+static void
+bfa_com_port_attach(struct bfa_s *bfa, struct bfa_meminfo_s *mi)
+{
+       struct bfa_port_s       *port = &bfa->modules.port;
+       uint32_t                dm_len;
+       uint8_t                 *dm_kva;
+       uint64_t                dm_pa;
+
+       dm_len = bfa_port_meminfo();
+       dm_kva = bfa_meminfo_dma_virt(mi);
+       dm_pa  = bfa_meminfo_dma_phys(mi);
+
+       memset(port, 0, sizeof(struct bfa_port_s));
+       bfa_port_attach(port, &bfa->ioc, bfa, bfa->trcmod, bfa->logm);
+       bfa_port_mem_claim(port, dm_kva, dm_pa);
+
+       bfa_meminfo_dma_virt(mi) = dm_kva + dm_len;
+       bfa_meminfo_dma_phys(mi) = dm_pa + dm_len;
+}
+
 /**
  * Use this function to do attach the driver instance with the BFA
  * library. This function will not trigger any HW initialization
@@ -140,6 +161,7 @@ bfa_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
        for (i = 0; hal_mods[i]; i++)
                hal_mods[i]->attach(bfa, bfad, cfg, meminfo, pcidev);
 
+       bfa_com_port_attach(bfa, meminfo);
 }
 
 /**
index 0435d044c9da1fa12dfc03455e79629126c9593b..b0c576f84b2863a0e523f51f743ee402222e8396 100644 (file)
@@ -114,12 +114,13 @@ static int hba_count = 0;
 
 static struct class *adpt_sysfs_class;
 
+static long adpt_unlocked_ioctl(struct file *, unsigned int, unsigned long);
 #ifdef CONFIG_COMPAT
 static long compat_adpt_ioctl(struct file *, unsigned int, unsigned long);
 #endif
 
 static const struct file_operations adpt_fops = {
-       .ioctl          = adpt_ioctl,
+       .unlocked_ioctl = adpt_unlocked_ioctl,
        .open           = adpt_open,
        .release        = adpt_close,
 #ifdef CONFIG_COMPAT
@@ -2069,8 +2070,7 @@ static int adpt_system_info(void __user *buffer)
        return 0;
 }
 
-static int adpt_ioctl(struct inode *inode, struct file *file, uint cmd,
-             ulong arg)
+static int adpt_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
 {
        int minor;
        int error = 0;
@@ -2153,6 +2153,20 @@ static int adpt_ioctl(struct inode *inode, struct file *file, uint cmd,
        return error;
 }
 
+static long adpt_unlocked_ioctl(struct file *file, uint cmd, ulong arg)
+{
+       struct inode *inode;
+       long ret;
+       inode = file->f_dentry->d_inode;
+       lock_kernel();
+       ret = adpt_ioctl(inode, file, cmd, arg);
+       unlock_kernel();
+
+       return ret;
+}
+
 #ifdef CONFIG_COMPAT
 static long compat_adpt_ioctl(struct file *file,
                                unsigned int cmd, unsigned long arg)
index 9276121db1efc15ffe7dc9539f83813a088e9356..44a07593de56020b444ab64c84074b512d07aef9 100644 (file)
@@ -688,7 +688,7 @@ static int fcoe_shost_config(struct fc_lport *lport, struct device *dev)
        }
 
        if (!lport->vport)
-               fc_host_max_npiv_vports(lport->host) = USHORT_MAX;
+               fc_host_max_npiv_vports(lport->host) = USHRT_MAX;
 
        snprintf(fc_host_symbolic_name(lport->host), FC_SYMBOLIC_NAME_SIZE,
                 "%s v%s over %s", FCOE_NAME, FCOE_VERSION,
index a765fe7a55c39b57270a23486cd4a509cb7ca848..f672d6213eea8747e61d3f3ba09a99d49527586f 100644 (file)
@@ -180,8 +180,8 @@ static const char *gdth_ctr_name(gdth_ha_str *ha);
 
 static int gdth_open(struct inode *inode, struct file *filep);
 static int gdth_close(struct inode *inode, struct file *filep);
-static int gdth_ioctl(struct inode *inode, struct file *filep,
-                      unsigned int cmd, unsigned long arg);
+static long gdth_unlocked_ioctl(struct file *filep, unsigned int cmd,
+                               unsigned long arg);
 
 static void gdth_flush(gdth_ha_str *ha);
 static int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *));
@@ -369,7 +369,7 @@ MODULE_LICENSE("GPL");
 
 /* ioctl interface */
 static const struct file_operations gdth_fops = {
-    .ioctl   = gdth_ioctl,
+    .unlocked_ioctl   = gdth_unlocked_ioctl,
     .open    = gdth_open,
     .release = gdth_close,
 };
@@ -4462,8 +4462,7 @@ free_fail:
     return rc;
 }
   
-static int gdth_ioctl(struct inode *inode, struct file *filep,
-                      unsigned int cmd, unsigned long arg)
+static int gdth_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
 {
     gdth_ha_str *ha; 
     Scsi_Cmnd *scp;
@@ -4611,6 +4610,17 @@ static int gdth_ioctl(struct inode *inode, struct file *filep,
     return 0;
 }
 
+static long gdth_unlocked_ioctl(struct file *file, unsigned int cmd,
+                               unsigned long arg)
+{
+       int ret;
+
+       lock_kernel();
+       ret = gdth_ioctl(file, cmd, arg);
+       unlock_kernel();
+
+       return ret;
+}
 
 /* flush routine */
 static void gdth_flush(gdth_ha_str *ha)
index 18b7102bb80e87bf7315a125400350ec5d3e1eef..2ce26eb7a1ec5c24062a2764181dfc3a8666c578 100644 (file)
@@ -1,36 +1,35 @@
 #include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/zorro.h>
 
-#include <asm/setup.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/amigaints.h>
 #include <asm/amigahw.h>
-#include <linux/zorro.h>
-#include <asm/irq.h>
-#include <linux/spinlock.h>
 
 #include "scsi.h"
-#include <scsi/scsi_host.h>
 #include "wd33c93.h"
 #include "gvp11.h"
 
-#include <linux/stat.h>
 
+#define CHECK_WD33C93
 
-#define DMA(ptr)       ((gvp11_scsiregs *)((ptr)->base))
+struct gvp11_hostdata {
+       struct WD33C93_hostdata wh;
+       struct gvp11_scsiregs *regs;
+};
 
-static irqreturn_t gvp11_intr(int irq, void *_instance)
+static irqreturn_t gvp11_intr(int irq, void *data)
 {
+       struct Scsi_Host *instance = data;
+       struct gvp11_hostdata *hdata = shost_priv(instance);
+       unsigned int status = hdata->regs->CNTR;
        unsigned long flags;
-       unsigned int status;
-       struct Scsi_Host *instance = (struct Scsi_Host *)_instance;
 
-       status = DMA(instance)->CNTR;
        if (!(status & GVP11_DMAC_INT_PENDING))
                return IRQ_NONE;
 
@@ -50,64 +49,66 @@ void gvp11_setup(char *str, int *ints)
 static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
 {
        struct Scsi_Host *instance = cmd->device->host;
-       struct WD33C93_hostdata *hdata = shost_priv(instance);
+       struct gvp11_hostdata *hdata = shost_priv(instance);
+       struct WD33C93_hostdata *wh = &hdata->wh;
+       struct gvp11_scsiregs *regs = hdata->regs;
        unsigned short cntr = GVP11_DMAC_INT_ENABLE;
        unsigned long addr = virt_to_bus(cmd->SCp.ptr);
        int bank_mask;
        static int scsi_alloc_out_of_range = 0;
 
        /* use bounce buffer if the physical address is bad */
-       if (addr & hdata->dma_xfer_mask) {
-               hdata->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff;
+       if (addr & wh->dma_xfer_mask) {
+               wh->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff;
 
                if (!scsi_alloc_out_of_range) {
-                       hdata->dma_bounce_buffer =
-                               kmalloc(hdata->dma_bounce_len, GFP_KERNEL);
-                       hdata->dma_buffer_pool = BUF_SCSI_ALLOCED;
+                       wh->dma_bounce_buffer =
+                               kmalloc(wh->dma_bounce_len, GFP_KERNEL);
+                       wh->dma_buffer_pool = BUF_SCSI_ALLOCED;
                }
 
                if (scsi_alloc_out_of_range ||
-                   !hdata->dma_bounce_buffer) {
-                       hdata->dma_bounce_buffer =
-                               amiga_chip_alloc(hdata->dma_bounce_len,
+                   !wh->dma_bounce_buffer) {
+                       wh->dma_bounce_buffer =
+                               amiga_chip_alloc(wh->dma_bounce_len,
                                                 "GVP II SCSI Bounce Buffer");
 
-                       if (!hdata->dma_bounce_buffer) {
-                               hdata->dma_bounce_len = 0;
+                       if (!wh->dma_bounce_buffer) {
+                               wh->dma_bounce_len = 0;
                                return 1;
                        }
 
-                       hdata->dma_buffer_pool = BUF_CHIP_ALLOCED;
+                       wh->dma_buffer_pool = BUF_CHIP_ALLOCED;
                }
 
                /* check if the address of the bounce buffer is OK */
-               addr = virt_to_bus(hdata->dma_bounce_buffer);
+               addr = virt_to_bus(wh->dma_bounce_buffer);
 
-               if (addr & hdata->dma_xfer_mask) {
+               if (addr & wh->dma_xfer_mask) {
                        /* fall back to Chip RAM if address out of range */
-                       if (hdata->dma_buffer_pool == BUF_SCSI_ALLOCED) {
-                               kfree(hdata->dma_bounce_buffer);
+                       if (wh->dma_buffer_pool == BUF_SCSI_ALLOCED) {
+                               kfree(wh->dma_bounce_buffer);
                                scsi_alloc_out_of_range = 1;
                        } else {
-                               amiga_chip_free(hdata->dma_bounce_buffer);
+                               amiga_chip_free(wh->dma_bounce_buffer);
                        }
 
-                       hdata->dma_bounce_buffer =
-                               amiga_chip_alloc(hdata->dma_bounce_len,
+                       wh->dma_bounce_buffer =
+                               amiga_chip_alloc(wh->dma_bounce_len,
                                                 "GVP II SCSI Bounce Buffer");
 
-                       if (!hdata->dma_bounce_buffer) {
-                               hdata->dma_bounce_len = 0;
+                       if (!wh->dma_bounce_buffer) {
+                               wh->dma_bounce_len = 0;
                                return 1;
                        }
 
-                       addr = virt_to_bus(hdata->dma_bounce_buffer);
-                       hdata->dma_buffer_pool = BUF_CHIP_ALLOCED;
+                       addr = virt_to_bus(wh->dma_bounce_buffer);
+                       wh->dma_buffer_pool = BUF_CHIP_ALLOCED;
                }
 
                if (!dir_in) {
                        /* copy to bounce buffer for a write */
-                       memcpy(hdata->dma_bounce_buffer, cmd->SCp.ptr,
+                       memcpy(wh->dma_bounce_buffer, cmd->SCp.ptr,
                               cmd->SCp.this_residual);
                }
        }
@@ -116,11 +117,11 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
        if (!dir_in)
                cntr |= GVP11_DMAC_DIR_WRITE;
 
-       hdata->dma_dir = dir_in;
-       DMA(cmd->device->host)->CNTR = cntr;
+       wh->dma_dir = dir_in;
+       regs->CNTR = cntr;
 
        /* setup DMA *physical* address */
-       DMA(cmd->device->host)->ACR = addr;
+       regs->ACR = addr;
 
        if (dir_in) {
                /* invalidate any cache */
@@ -130,12 +131,12 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
                cache_push(addr, cmd->SCp.this_residual);
        }
 
-       bank_mask = (~hdata->dma_xfer_mask >> 18) & 0x01c0;
+       bank_mask = (~wh->dma_xfer_mask >> 18) & 0x01c0;
        if (bank_mask)
-               DMA(cmd->device->host)->BANK = bank_mask & (addr >> 18);
+               regs->BANK = bank_mask & (addr >> 18);
 
        /* start DMA */
-       DMA(cmd->device->host)->ST_DMA = 1;
+       regs->ST_DMA = 1;
 
        /* return success */
        return 0;
@@ -144,236 +145,53 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
 static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
                     int status)
 {
-       struct WD33C93_hostdata *hdata = shost_priv(instance);
+       struct gvp11_hostdata *hdata = shost_priv(instance);
+       struct WD33C93_hostdata *wh = &hdata->wh;
+       struct gvp11_scsiregs *regs = hdata->regs;
 
        /* stop DMA */
-       DMA(instance)->SP_DMA = 1;
+       regs->SP_DMA = 1;
        /* remove write bit from CONTROL bits */
-       DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE;
+       regs->CNTR = GVP11_DMAC_INT_ENABLE;
 
        /* copy from a bounce buffer, if necessary */
-       if (status && hdata->dma_bounce_buffer) {
-               if (hdata->dma_dir && SCpnt)
-                       memcpy(SCpnt->SCp.ptr, hdata->dma_bounce_buffer,
+       if (status && wh->dma_bounce_buffer) {
+               if (wh->dma_dir && SCpnt)
+                       memcpy(SCpnt->SCp.ptr, wh->dma_bounce_buffer,
                               SCpnt->SCp.this_residual);
 
-               if (hdata->dma_buffer_pool == BUF_SCSI_ALLOCED)
-                       kfree(hdata->dma_bounce_buffer);
-               else
-                       amiga_chip_free(hdata->dma_bounce_buffer);
-
-               hdata->dma_bounce_buffer = NULL;
-               hdata->dma_bounce_len = 0;
-       }
-}
-
-#define CHECK_WD33C93
-
-int __init gvp11_detect(struct scsi_host_template *tpnt)
-{
-       static unsigned char called = 0;
-       struct Scsi_Host *instance;
-       unsigned long address;
-       unsigned int epc;
-       struct zorro_dev *z = NULL;
-       unsigned int default_dma_xfer_mask;
-       struct WD33C93_hostdata *hdata;
-       wd33c93_regs regs;
-       int num_gvp11 = 0;
-#ifdef CHECK_WD33C93
-       volatile unsigned char *sasr_3393, *scmd_3393;
-       unsigned char save_sasr;
-       unsigned char q, qq;
-#endif
-
-       if (!MACH_IS_AMIGA || called)
-               return 0;
-       called = 1;
-
-       tpnt->proc_name = "GVP11";
-       tpnt->proc_info = &wd33c93_proc_info;
-
-       while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
-               /*
-                * This should (hopefully) be the correct way to identify
-                * all the different GVP SCSI controllers (except for the
-                * SERIES I though).
-                */
-
-               if (z->id == ZORRO_PROD_GVP_COMBO_030_R3_SCSI ||
-                   z->id == ZORRO_PROD_GVP_SERIES_II)
-                       default_dma_xfer_mask = ~0x00ffffff;
-               else if (z->id == ZORRO_PROD_GVP_GFORCE_030_SCSI ||
-                        z->id == ZORRO_PROD_GVP_A530_SCSI ||
-                        z->id == ZORRO_PROD_GVP_COMBO_030_R4_SCSI)
-                       default_dma_xfer_mask = ~0x01ffffff;
-               else if (z->id == ZORRO_PROD_GVP_A1291 ||
-                        z->id == ZORRO_PROD_GVP_GFORCE_040_SCSI_1)
-                       default_dma_xfer_mask = ~0x07ffffff;
+               if (wh->dma_buffer_pool == BUF_SCSI_ALLOCED)
+                       kfree(wh->dma_bounce_buffer);
                else
-                       continue;
-
-               /*
-                * Rumors state that some GVP ram boards use the same product
-                * code as the SCSI controllers. Therefore if the board-size
-                * is not 64KB we asume it is a ram board and bail out.
-                */
-               if (z->resource.end - z->resource.start != 0xffff)
-                       continue;
+                       amiga_chip_free(wh->dma_bounce_buffer);
 
-               address = z->resource.start;
-               if (!request_mem_region(address, 256, "wd33c93"))
-                       continue;
-
-#ifdef CHECK_WD33C93
-
-               /*
-                * These darn GVP boards are a problem - it can be tough to tell
-                * whether or not they include a SCSI controller. This is the
-                * ultimate Yet-Another-GVP-Detection-Hack in that it actually
-                * probes for a WD33c93 chip: If we find one, it's extremely
-                * likely that this card supports SCSI, regardless of Product_
-                * Code, Board_Size, etc.
-                */
-
-               /* Get pointers to the presumed register locations and save contents */
-
-               sasr_3393 = &(((gvp11_scsiregs *)(ZTWO_VADDR(address)))->SASR);
-               scmd_3393 = &(((gvp11_scsiregs *)(ZTWO_VADDR(address)))->SCMD);
-               save_sasr = *sasr_3393;
-
-               /* First test the AuxStatus Reg */
-
-               q = *sasr_3393; /* read it */
-               if (q & 0x08)   /* bit 3 should always be clear */
-                       goto release;
-               *sasr_3393 = WD_AUXILIARY_STATUS;       /* setup indirect address */
-               if (*sasr_3393 == WD_AUXILIARY_STATUS) {        /* shouldn't retain the write */
-                       *sasr_3393 = save_sasr; /* Oops - restore this byte */
-                       goto release;
-               }
-               if (*sasr_3393 != q) {  /* should still read the same */
-                       *sasr_3393 = save_sasr; /* Oops - restore this byte */
-                       goto release;
-               }
-               if (*scmd_3393 != q)    /* and so should the image at 0x1f */
-                       goto release;
-
-               /*
-                * Ok, we probably have a wd33c93, but let's check a few other places
-                * for good measure. Make sure that this works for both 'A and 'B
-                * chip versions.
-                */
-
-               *sasr_3393 = WD_SCSI_STATUS;
-               q = *scmd_3393;
-               *sasr_3393 = WD_SCSI_STATUS;
-               *scmd_3393 = ~q;
-               *sasr_3393 = WD_SCSI_STATUS;
-               qq = *scmd_3393;
-               *sasr_3393 = WD_SCSI_STATUS;
-               *scmd_3393 = q;
-               if (qq != q)    /* should be read only */
-                       goto release;
-               *sasr_3393 = 0x1e;      /* this register is unimplemented */
-               q = *scmd_3393;
-               *sasr_3393 = 0x1e;
-               *scmd_3393 = ~q;
-               *sasr_3393 = 0x1e;
-               qq = *scmd_3393;
-               *sasr_3393 = 0x1e;
-               *scmd_3393 = q;
-               if (qq != q || qq != 0xff)      /* should be read only, all 1's */
-                       goto release;
-               *sasr_3393 = WD_TIMEOUT_PERIOD;
-               q = *scmd_3393;
-               *sasr_3393 = WD_TIMEOUT_PERIOD;
-               *scmd_3393 = ~q;
-               *sasr_3393 = WD_TIMEOUT_PERIOD;
-               qq = *scmd_3393;
-               *sasr_3393 = WD_TIMEOUT_PERIOD;
-               *scmd_3393 = q;
-               if (qq != (~q & 0xff))  /* should be read/write */
-                       goto release;
-#endif
-
-               instance = scsi_register(tpnt, sizeof(struct WD33C93_hostdata));
-               if (instance == NULL)
-                       goto release;
-               instance->base = ZTWO_VADDR(address);
-               instance->irq = IRQ_AMIGA_PORTS;
-               instance->unique_id = z->slotaddr;
-
-               hdata = shost_priv(instance);
-               if (gvp11_xfer_mask)
-                       hdata->dma_xfer_mask = gvp11_xfer_mask;
-               else
-                       hdata->dma_xfer_mask = default_dma_xfer_mask;
-
-               DMA(instance)->secret2 = 1;
-               DMA(instance)->secret1 = 0;
-               DMA(instance)->secret3 = 15;
-               while (DMA(instance)->CNTR & GVP11_DMAC_BUSY)
-                       ;
-               DMA(instance)->CNTR = 0;
-
-               DMA(instance)->BANK = 0;
-
-               epc = *(unsigned short *)(ZTWO_VADDR(address) + 0x8000);
-
-               /*
-                * Check for 14MHz SCSI clock
-                */
-               regs.SASR = &(DMA(instance)->SASR);
-               regs.SCMD = &(DMA(instance)->SCMD);
-               hdata->no_sync = 0xff;
-               hdata->fast = 0;
-               hdata->dma_mode = CTRL_DMA;
-               wd33c93_init(instance, regs, dma_setup, dma_stop,
-                            (epc & GVP_SCSICLKMASK) ? WD33C93_FS_8_10
-                                                    : WD33C93_FS_12_15);
-
-               if (request_irq(IRQ_AMIGA_PORTS, gvp11_intr, IRQF_SHARED,
-                               "GVP11 SCSI", instance))
-                       goto unregister;
-               DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE;
-               num_gvp11++;
-               continue;
-
-unregister:
-               scsi_unregister(instance);
-release:
-               release_mem_region(address, 256);
+               wh->dma_bounce_buffer = NULL;
+               wh->dma_bounce_len = 0;
        }
-
-       return num_gvp11;
 }
 
 static int gvp11_bus_reset(struct scsi_cmnd *cmd)
 {
+       struct Scsi_Host *instance = cmd->device->host;
+
        /* FIXME perform bus-specific reset */
 
        /* FIXME 2: shouldn't we no-op this function (return
           FAILED), and fall back to host reset function,
           wd33c93_host_reset ? */
 
-       spin_lock_irq(cmd->device->host->host_lock);
+       spin_lock_irq(instance->host_lock);
        wd33c93_host_reset(cmd);
-       spin_unlock_irq(cmd->device->host->host_lock);
+       spin_unlock_irq(instance->host_lock);
 
        return SUCCESS;
 }
 
-
-#define HOSTS_C
-
-#include "gvp11.h"
-
-static struct scsi_host_template driver_template = {
-       .proc_name              = "GVP11",
+static struct scsi_host_template gvp11_scsi_template = {
+       .module                 = THIS_MODULE,
        .name                   = "GVP Series II SCSI",
-       .detect                 = gvp11_detect,
-       .release                = gvp11_release,
+       .proc_info              = wd33c93_proc_info,
+       .proc_name              = "GVP11",
        .queuecommand           = wd33c93_queuecommand,
        .eh_abort_handler       = wd33c93_abort,
        .eh_bus_reset_handler   = gvp11_bus_reset,
@@ -385,17 +203,230 @@ static struct scsi_host_template driver_template = {
        .use_clustering         = DISABLE_CLUSTERING
 };
 
+static int __devinit check_wd33c93(struct gvp11_scsiregs *regs)
+{
+#ifdef CHECK_WD33C93
+       volatile unsigned char *sasr_3393, *scmd_3393;
+       unsigned char save_sasr;
+       unsigned char q, qq;
 
-#include "scsi_module.c"
+       /*
+        * These darn GVP boards are a problem - it can be tough to tell
+        * whether or not they include a SCSI controller. This is the
+        * ultimate Yet-Another-GVP-Detection-Hack in that it actually
+        * probes for a WD33c93 chip: If we find one, it's extremely
+        * likely that this card supports SCSI, regardless of Product_
+        * Code, Board_Size, etc.
+        */
+
+       /* Get pointers to the presumed register locations and save contents */
+
+       sasr_3393 = &regs->SASR;
+       scmd_3393 = &regs->SCMD;
+       save_sasr = *sasr_3393;
+
+       /* First test the AuxStatus Reg */
+
+       q = *sasr_3393; /* read it */
+       if (q & 0x08)   /* bit 3 should always be clear */
+               return -ENODEV;
+       *sasr_3393 = WD_AUXILIARY_STATUS;       /* setup indirect address */
+       if (*sasr_3393 == WD_AUXILIARY_STATUS) {        /* shouldn't retain the write */
+               *sasr_3393 = save_sasr; /* Oops - restore this byte */
+               return -ENODEV;
+       }
+       if (*sasr_3393 != q) {  /* should still read the same */
+               *sasr_3393 = save_sasr; /* Oops - restore this byte */
+               return -ENODEV;
+       }
+       if (*scmd_3393 != q)    /* and so should the image at 0x1f */
+               return -ENODEV;
+
+       /*
+        * Ok, we probably have a wd33c93, but let's check a few other places
+        * for good measure. Make sure that this works for both 'A and 'B
+        * chip versions.
+        */
+
+       *sasr_3393 = WD_SCSI_STATUS;
+       q = *scmd_3393;
+       *sasr_3393 = WD_SCSI_STATUS;
+       *scmd_3393 = ~q;
+       *sasr_3393 = WD_SCSI_STATUS;
+       qq = *scmd_3393;
+       *sasr_3393 = WD_SCSI_STATUS;
+       *scmd_3393 = q;
+       if (qq != q)    /* should be read only */
+               return -ENODEV;
+       *sasr_3393 = 0x1e;      /* this register is unimplemented */
+       q = *scmd_3393;
+       *sasr_3393 = 0x1e;
+       *scmd_3393 = ~q;
+       *sasr_3393 = 0x1e;
+       qq = *scmd_3393;
+       *sasr_3393 = 0x1e;
+       *scmd_3393 = q;
+       if (qq != q || qq != 0xff)      /* should be read only, all 1's */
+               return -ENODEV;
+       *sasr_3393 = WD_TIMEOUT_PERIOD;
+       q = *scmd_3393;
+       *sasr_3393 = WD_TIMEOUT_PERIOD;
+       *scmd_3393 = ~q;
+       *sasr_3393 = WD_TIMEOUT_PERIOD;
+       qq = *scmd_3393;
+       *sasr_3393 = WD_TIMEOUT_PERIOD;
+       *scmd_3393 = q;
+       if (qq != (~q & 0xff))  /* should be read/write */
+               return -ENODEV;
+#endif /* CHECK_WD33C93 */
 
-int gvp11_release(struct Scsi_Host *instance)
+       return 0;
+}
+
+static int __devinit gvp11_probe(struct zorro_dev *z,
+                                const struct zorro_device_id *ent)
 {
-#ifdef MODULE
-       DMA(instance)->CNTR = 0;
-       release_mem_region(ZTWO_PADDR(instance->base), 256);
+       struct Scsi_Host *instance;
+       unsigned long address;
+       int error;
+       unsigned int epc;
+       unsigned int default_dma_xfer_mask;
+       struct gvp11_hostdata *hdata;
+       struct gvp11_scsiregs *regs;
+       wd33c93_regs wdregs;
+
+       default_dma_xfer_mask = ent->driver_data;
+
+       /*
+        * Rumors state that some GVP ram boards use the same product
+        * code as the SCSI controllers. Therefore if the board-size
+        * is not 64KB we asume it is a ram board and bail out.
+        */
+       if (zorro_resource_len(z) != 0x10000)
+               return -ENODEV;
+
+       address = z->resource.start;
+       if (!request_mem_region(address, 256, "wd33c93"))
+               return -EBUSY;
+
+       regs = (struct gvp11_scsiregs *)(ZTWO_VADDR(address));
+
+       error = check_wd33c93(regs);
+       if (error)
+               goto fail_check_or_alloc;
+
+       instance = scsi_host_alloc(&gvp11_scsi_template,
+                                  sizeof(struct gvp11_hostdata));
+       if (!instance) {
+               error = -ENOMEM;
+               goto fail_check_or_alloc;
+       }
+
+       instance->irq = IRQ_AMIGA_PORTS;
+       instance->unique_id = z->slotaddr;
+
+       regs->secret2 = 1;
+       regs->secret1 = 0;
+       regs->secret3 = 15;
+       while (regs->CNTR & GVP11_DMAC_BUSY)
+               ;
+       regs->CNTR = 0;
+       regs->BANK = 0;
+
+       wdregs.SASR = &regs->SASR;
+       wdregs.SCMD = &regs->SCMD;
+
+       hdata = shost_priv(instance);
+       if (gvp11_xfer_mask)
+               hdata->wh.dma_xfer_mask = gvp11_xfer_mask;
+       else
+               hdata->wh.dma_xfer_mask = default_dma_xfer_mask;
+
+       hdata->wh.no_sync = 0xff;
+       hdata->wh.fast = 0;
+       hdata->wh.dma_mode = CTRL_DMA;
+       hdata->regs = regs;
+
+       /*
+        * Check for 14MHz SCSI clock
+        */
+       epc = *(unsigned short *)(ZTWO_VADDR(address) + 0x8000);
+       wd33c93_init(instance, wdregs, dma_setup, dma_stop,
+                    (epc & GVP_SCSICLKMASK) ? WD33C93_FS_8_10
+                                            : WD33C93_FS_12_15);
+
+       error = request_irq(IRQ_AMIGA_PORTS, gvp11_intr, IRQF_SHARED,
+                           "GVP11 SCSI", instance);
+       if (error)
+               goto fail_irq;
+
+       regs->CNTR = GVP11_DMAC_INT_ENABLE;
+
+       error = scsi_add_host(instance, NULL);
+       if (error)
+               goto fail_host;
+
+       zorro_set_drvdata(z, instance);
+       scsi_scan_host(instance);
+       return 0;
+
+fail_host:
        free_irq(IRQ_AMIGA_PORTS, instance);
-#endif
-       return 1;
+fail_irq:
+       scsi_host_put(instance);
+fail_check_or_alloc:
+       release_mem_region(address, 256);
+       return error;
+}
+
+static void __devexit gvp11_remove(struct zorro_dev *z)
+{
+       struct Scsi_Host *instance = zorro_get_drvdata(z);
+       struct gvp11_hostdata *hdata = shost_priv(instance);
+
+       hdata->regs->CNTR = 0;
+       scsi_remove_host(instance);
+       free_irq(IRQ_AMIGA_PORTS, instance);
+       scsi_host_put(instance);
+       release_mem_region(z->resource.start, 256);
+}
+
+       /*
+        * This should (hopefully) be the correct way to identify
+        * all the different GVP SCSI controllers (except for the
+        * SERIES I though).
+        */
+
+static struct zorro_device_id gvp11_zorro_tbl[] __devinitdata = {
+       { ZORRO_PROD_GVP_COMBO_030_R3_SCSI,     ~0x00ffffff },
+       { ZORRO_PROD_GVP_SERIES_II,             ~0x00ffffff },
+       { ZORRO_PROD_GVP_GFORCE_030_SCSI,       ~0x01ffffff },
+       { ZORRO_PROD_GVP_A530_SCSI,             ~0x01ffffff },
+       { ZORRO_PROD_GVP_COMBO_030_R4_SCSI,     ~0x01ffffff },
+       { ZORRO_PROD_GVP_A1291,                 ~0x07ffffff },
+       { ZORRO_PROD_GVP_GFORCE_040_SCSI_1,     ~0x07ffffff },
+       { 0 }
+};
+MODULE_DEVICE_TABLE(zorro, gvp11_zorro_tbl);
+
+static struct zorro_driver gvp11_driver = {
+       .name           = "gvp11",
+       .id_table       = gvp11_zorro_tbl,
+       .probe          = gvp11_probe,
+       .remove         = __devexit_p(gvp11_remove),
+};
+
+static int __init gvp11_init(void)
+{
+       return zorro_register_driver(&gvp11_driver);
+}
+module_init(gvp11_init);
+
+static void __exit gvp11_exit(void)
+{
+       zorro_unregister_driver(&gvp11_driver);
 }
+module_exit(gvp11_exit);
 
+MODULE_DESCRIPTION("GVP Series II SCSI");
 MODULE_LICENSE("GPL");
index e2efdf9601ef98fb0b5490bb7378bab2b6906d2f..852913cde5dd9a5b5bdf43722d76613ef68c12d2 100644 (file)
@@ -11,9 +11,6 @@
 
 #include <linux/types.h>
 
-int gvp11_detect(struct scsi_host_template *);
-int gvp11_release(struct Scsi_Host *);
-
 #ifndef CMD_PER_LUN
 #define CMD_PER_LUN            2
 #endif
@@ -22,15 +19,13 @@ int gvp11_release(struct Scsi_Host *);
 #define CAN_QUEUE              16
 #endif
 
-#ifndef HOSTS_C
-
 /*
  * if the transfer address ANDed with this results in a non-zero
  * result, then we can't use DMA.
  */
 #define GVP11_XFER_MASK                (0xff000001)
 
-typedef struct {
+struct gvp11_scsiregs {
                 unsigned char  pad1[64];
        volatile unsigned short CNTR;
                 unsigned char  pad2[31];
@@ -46,7 +41,7 @@ typedef struct {
        volatile unsigned short SP_DMA;
        volatile unsigned short secret2; /* store 1 here */
        volatile unsigned short secret3; /* store 15 here */
-} gvp11_scsiregs;
+};
 
 /* bits in CNTR */
 #define GVP11_DMAC_BUSY                (1<<0)
@@ -54,6 +49,4 @@ typedef struct {
 #define GVP11_DMAC_INT_ENABLE  (1<<3)
 #define GVP11_DMAC_DIR_WRITE   (1<<4)
 
-#endif /* else def HOSTS_C */
-
 #endif /* GVP11_H */
index 3eb2b7b3d8b0ec7e1e0860495b14ac7167bade7f..fef49521cbc3f6888684789f4bd50a67f1b5a3bb 100644 (file)
@@ -1157,7 +1157,7 @@ static void ibmvfc_gather_partition_info(struct ibmvfc_host *vhost)
 static void ibmvfc_set_login_info(struct ibmvfc_host *vhost)
 {
        struct ibmvfc_npiv_login *login_info = &vhost->login_info;
-       struct device_node *of_node = vhost->dev->archdata.of_node;
+       struct device_node *of_node = vhost->dev->of_node;
        const char *location;
 
        memset(login_info, 0, sizeof(*login_info));
index 88bad0e81bdda3b5195396b9e2e6d0d7dc4f26e2..aad35cc41e49bfbfb7d27c3b28b8759dd60962d2 100644 (file)
@@ -932,7 +932,7 @@ static void send_mad_capabilities(struct ibmvscsi_host_data *hostdata)
        struct viosrp_capabilities *req;
        struct srp_event_struct *evt_struct;
        unsigned long flags;
-       struct device_node *of_node = hostdata->dev->archdata.of_node;
+       struct device_node *of_node = hostdata->dev->of_node;
        const char *location;
 
        evt_struct = get_event_struct(&hostdata->pool);
index 6a6661c35b2f9bb753f3de02e540a46678084c46..82ea4a8226b0242040716134ab3f3efc19bdf254 100644 (file)
@@ -567,7 +567,8 @@ static void ipr_trc_hook(struct ipr_cmnd *ipr_cmd,
 static void ipr_reinit_ipr_cmnd(struct ipr_cmnd *ipr_cmd)
 {
        struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
-       struct ipr_ioasa *ioasa = &ipr_cmd->ioasa;
+       struct ipr_ioasa *ioasa = &ipr_cmd->s.ioasa;
+       struct ipr_ioasa64 *ioasa64 = &ipr_cmd->s.ioasa64;
        dma_addr_t dma_addr = ipr_cmd->dma_addr;
 
        memset(&ioarcb->cmd_pkt, 0, sizeof(struct ipr_cmd_pkt));
@@ -576,19 +577,19 @@ static void ipr_reinit_ipr_cmnd(struct ipr_cmnd *ipr_cmd)
        ioarcb->ioadl_len = 0;
        ioarcb->read_ioadl_len = 0;
 
-       if (ipr_cmd->ioa_cfg->sis64)
+       if (ipr_cmd->ioa_cfg->sis64) {
                ioarcb->u.sis64_addr_data.data_ioadl_addr =
                        cpu_to_be64(dma_addr + offsetof(struct ipr_cmnd, i.ioadl64));
-       else {
+               ioasa64->u.gata.status = 0;
+       } else {
                ioarcb->write_ioadl_addr =
                        cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, i.ioadl));
                ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr;
+               ioasa->u.gata.status = 0;
        }
 
-       ioasa->ioasc = 0;
-       ioasa->residual_data_len = 0;
-       ioasa->u.gata.status = 0;
-
+       ioasa->hdr.ioasc = 0;
+       ioasa->hdr.residual_data_len = 0;
        ipr_cmd->scsi_cmd = NULL;
        ipr_cmd->qc = NULL;
        ipr_cmd->sense_buffer[0] = 0;
@@ -768,8 +769,8 @@ static void ipr_fail_all_ops(struct ipr_ioa_cfg *ioa_cfg)
        list_for_each_entry_safe(ipr_cmd, temp, &ioa_cfg->pending_q, queue) {
                list_del(&ipr_cmd->queue);
 
-               ipr_cmd->ioasa.ioasc = cpu_to_be32(IPR_IOASC_IOA_WAS_RESET);
-               ipr_cmd->ioasa.ilid = cpu_to_be32(IPR_DRIVER_ILID);
+               ipr_cmd->s.ioasa.hdr.ioasc = cpu_to_be32(IPR_IOASC_IOA_WAS_RESET);
+               ipr_cmd->s.ioasa.hdr.ilid = cpu_to_be32(IPR_DRIVER_ILID);
 
                if (ipr_cmd->scsi_cmd)
                        ipr_cmd->done = ipr_scsi_eh_done;
@@ -1040,7 +1041,7 @@ static void ipr_init_res_entry(struct ipr_resource_entry *res,
                proto = cfgtew->u.cfgte64->proto;
                res->res_flags = cfgtew->u.cfgte64->res_flags;
                res->qmodel = IPR_QUEUEING_MODEL64(res);
-               res->type = cfgtew->u.cfgte64->res_type & 0x0f;
+               res->type = cfgtew->u.cfgte64->res_type;
 
                memcpy(res->res_path, &cfgtew->u.cfgte64->res_path,
                        sizeof(res->res_path));
@@ -1319,7 +1320,7 @@ static void ipr_process_ccn(struct ipr_cmnd *ipr_cmd)
 {
        struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
        struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb;
-       u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+       u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc);
 
        list_del(&hostrcb->queue);
        list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
@@ -2354,7 +2355,7 @@ static void ipr_process_error(struct ipr_cmnd *ipr_cmd)
 {
        struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
        struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb;
-       u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+       u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc);
        u32 fd_ioasc;
 
        if (ioa_cfg->sis64)
@@ -4509,11 +4510,16 @@ static int ipr_device_reset(struct ipr_ioa_cfg *ioa_cfg,
        }
 
        ipr_send_blocking_cmd(ipr_cmd, ipr_timeout, IPR_DEVICE_RESET_TIMEOUT);
-       ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+       ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc);
        list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
-       if (ipr_is_gata(res) && res->sata_port && ioasc != IPR_IOASC_IOA_WAS_RESET)
-               memcpy(&res->sata_port->ioasa, &ipr_cmd->ioasa.u.gata,
-                      sizeof(struct ipr_ioasa_gata));
+       if (ipr_is_gata(res) && res->sata_port && ioasc != IPR_IOASC_IOA_WAS_RESET) {
+               if (ipr_cmd->ioa_cfg->sis64)
+                       memcpy(&res->sata_port->ioasa, &ipr_cmd->s.ioasa64.u.gata,
+                              sizeof(struct ipr_ioasa_gata));
+               else
+                       memcpy(&res->sata_port->ioasa, &ipr_cmd->s.ioasa.u.gata,
+                              sizeof(struct ipr_ioasa_gata));
+       }
 
        LEAVE;
        return (IPR_IOASC_SENSE_KEY(ioasc) ? -EIO : 0);
@@ -4768,7 +4774,7 @@ static int ipr_cancel_op(struct scsi_cmnd * scsi_cmd)
        scmd_printk(KERN_ERR, scsi_cmd, "Aborting command: %02X\n",
                    scsi_cmd->cmnd[0]);
        ipr_send_blocking_cmd(ipr_cmd, ipr_abort_timeout, IPR_CANCEL_ALL_TIMEOUT);
-       ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+       ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc);
 
        /*
         * If the abort task timed out and we sent a bus reset, we will get
@@ -4812,15 +4818,39 @@ static int ipr_eh_abort(struct scsi_cmnd * scsi_cmd)
 /**
  * ipr_handle_other_interrupt - Handle "other" interrupts
  * @ioa_cfg:   ioa config struct
- * @int_reg:   interrupt register
  *
  * Return value:
  *     IRQ_NONE / IRQ_HANDLED
  **/
-static irqreturn_t ipr_handle_other_interrupt(struct ipr_ioa_cfg *ioa_cfg,
-                                             volatile u32 int_reg)
+static irqreturn_t ipr_handle_other_interrupt(struct ipr_ioa_cfg *ioa_cfg)
 {
        irqreturn_t rc = IRQ_HANDLED;
+       volatile u32 int_reg, int_mask_reg;
+
+       int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg32);
+       int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32) & ~int_mask_reg;
+
+       /* If an interrupt on the adapter did not occur, ignore it.
+        * Or in the case of SIS 64, check for a stage change interrupt.
+        */
+       if ((int_reg & IPR_PCII_OPER_INTERRUPTS) == 0) {
+               if (ioa_cfg->sis64) {
+                       int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
+                       int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg;
+                       if (int_reg & IPR_PCII_IPL_STAGE_CHANGE) {
+
+                               /* clear stage change */
+                               writel(IPR_PCII_IPL_STAGE_CHANGE, ioa_cfg->regs.clr_interrupt_reg);
+                               int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg;
+                               list_del(&ioa_cfg->reset_cmd->queue);
+                               del_timer(&ioa_cfg->reset_cmd->timer);
+                               ipr_reset_ioa_job(ioa_cfg->reset_cmd);
+                               return IRQ_HANDLED;
+                       }
+               }
+
+               return IRQ_NONE;
+       }
 
        if (int_reg & IPR_PCII_IOA_TRANS_TO_OPER) {
                /* Mask the interrupt */
@@ -4881,7 +4911,7 @@ static irqreturn_t ipr_isr(int irq, void *devp)
 {
        struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)devp;
        unsigned long lock_flags = 0;
-       volatile u32 int_reg, int_mask_reg;
+       volatile u32 int_reg;
        u32 ioasc;
        u16 cmd_index;
        int num_hrrq = 0;
@@ -4896,33 +4926,6 @@ static irqreturn_t ipr_isr(int irq, void *devp)
                return IRQ_NONE;
        }
 
-       int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg32);
-       int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32) & ~int_mask_reg;
-
-       /* If an interrupt on the adapter did not occur, ignore it.
-        * Or in the case of SIS 64, check for a stage change interrupt.
-        */
-       if (unlikely((int_reg & IPR_PCII_OPER_INTERRUPTS) == 0)) {
-               if (ioa_cfg->sis64) {
-                       int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
-                       int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg;
-                       if (int_reg & IPR_PCII_IPL_STAGE_CHANGE) {
-
-                               /* clear stage change */
-                               writel(IPR_PCII_IPL_STAGE_CHANGE, ioa_cfg->regs.clr_interrupt_reg);
-                               int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg;
-                               list_del(&ioa_cfg->reset_cmd->queue);
-                               del_timer(&ioa_cfg->reset_cmd->timer);
-                               ipr_reset_ioa_job(ioa_cfg->reset_cmd);
-                               spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
-                               return IRQ_HANDLED;
-                       }
-               }
-
-               spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
-               return IRQ_NONE;
-       }
-
        while (1) {
                ipr_cmd = NULL;
 
@@ -4940,7 +4943,7 @@ static irqreturn_t ipr_isr(int irq, void *devp)
 
                        ipr_cmd = ioa_cfg->ipr_cmnd_list[cmd_index];
 
-                       ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+                       ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc);
 
                        ipr_trc_hook(ipr_cmd, IPR_TRACE_FINISH, ioasc);
 
@@ -4962,7 +4965,7 @@ static irqreturn_t ipr_isr(int irq, void *devp)
                        /* Clear the PCI interrupt */
                        do {
                                writel(IPR_PCII_HRRQ_UPDATED, ioa_cfg->regs.clr_interrupt_reg32);
-                               int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32) & ~int_mask_reg;
+                               int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32);
                        } while (int_reg & IPR_PCII_HRRQ_UPDATED &&
                                        num_hrrq++ < IPR_MAX_HRRQ_RETRIES);
 
@@ -4977,7 +4980,7 @@ static irqreturn_t ipr_isr(int irq, void *devp)
        }
 
        if (unlikely(rc == IRQ_NONE))
-               rc = ipr_handle_other_interrupt(ioa_cfg, int_reg);
+               rc = ipr_handle_other_interrupt(ioa_cfg);
 
        spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
        return rc;
@@ -5014,6 +5017,10 @@ static int ipr_build_ioadl64(struct ipr_ioa_cfg *ioa_cfg,
 
        ipr_cmd->dma_use_sg = nseg;
 
+       ioarcb->data_transfer_length = cpu_to_be32(length);
+       ioarcb->ioadl_len =
+               cpu_to_be32(sizeof(struct ipr_ioadl64_desc) * ipr_cmd->dma_use_sg);
+
        if (scsi_cmd->sc_data_direction == DMA_TO_DEVICE) {
                ioadl_flags = IPR_IOADL_FLAGS_WRITE;
                ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ;
@@ -5135,7 +5142,7 @@ static void ipr_erp_done(struct ipr_cmnd *ipr_cmd)
        struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
        struct ipr_resource_entry *res = scsi_cmd->device->hostdata;
        struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
-       u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+       u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc);
 
        if (IPR_IOASC_SENSE_KEY(ioasc) > 0) {
                scsi_cmd->result |= (DID_ERROR << 16);
@@ -5166,7 +5173,7 @@ static void ipr_erp_done(struct ipr_cmnd *ipr_cmd)
 static void ipr_reinit_ipr_cmnd_for_erp(struct ipr_cmnd *ipr_cmd)
 {
        struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
-       struct ipr_ioasa *ioasa = &ipr_cmd->ioasa;
+       struct ipr_ioasa *ioasa = &ipr_cmd->s.ioasa;
        dma_addr_t dma_addr = ipr_cmd->dma_addr;
 
        memset(&ioarcb->cmd_pkt, 0, sizeof(struct ipr_cmd_pkt));
@@ -5174,8 +5181,8 @@ static void ipr_reinit_ipr_cmnd_for_erp(struct ipr_cmnd *ipr_cmd)
        ioarcb->read_data_transfer_length = 0;
        ioarcb->ioadl_len = 0;
        ioarcb->read_ioadl_len = 0;
-       ioasa->ioasc = 0;
-       ioasa->residual_data_len = 0;
+       ioasa->hdr.ioasc = 0;
+       ioasa->hdr.residual_data_len = 0;
 
        if (ipr_cmd->ioa_cfg->sis64)
                ioarcb->u.sis64_addr_data.data_ioadl_addr =
@@ -5200,7 +5207,7 @@ static void ipr_reinit_ipr_cmnd_for_erp(struct ipr_cmnd *ipr_cmd)
 static void ipr_erp_request_sense(struct ipr_cmnd *ipr_cmd)
 {
        struct ipr_cmd_pkt *cmd_pkt = &ipr_cmd->ioarcb.cmd_pkt;
-       u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+       u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc);
 
        if (IPR_IOASC_SENSE_KEY(ioasc) > 0) {
                ipr_erp_done(ipr_cmd);
@@ -5277,12 +5284,12 @@ static void ipr_dump_ioasa(struct ipr_ioa_cfg *ioa_cfg,
        int i;
        u16 data_len;
        u32 ioasc, fd_ioasc;
-       struct ipr_ioasa *ioasa = &ipr_cmd->ioasa;
+       struct ipr_ioasa *ioasa = &ipr_cmd->s.ioasa;
        __be32 *ioasa_data = (__be32 *)ioasa;
        int error_index;
 
-       ioasc = be32_to_cpu(ioasa->ioasc) & IPR_IOASC_IOASC_MASK;
-       fd_ioasc = be32_to_cpu(ioasa->fd_ioasc) & IPR_IOASC_IOASC_MASK;
+       ioasc = be32_to_cpu(ioasa->hdr.ioasc) & IPR_IOASC_IOASC_MASK;
+       fd_ioasc = be32_to_cpu(ioasa->hdr.fd_ioasc) & IPR_IOASC_IOASC_MASK;
 
        if (0 == ioasc)
                return;
@@ -5297,7 +5304,7 @@ static void ipr_dump_ioasa(struct ipr_ioa_cfg *ioa_cfg,
 
        if (ioa_cfg->log_level < IPR_MAX_LOG_LEVEL) {
                /* Don't log an error if the IOA already logged one */
-               if (ioasa->ilid != 0)
+               if (ioasa->hdr.ilid != 0)
                        return;
 
                if (!ipr_is_gscsi(res))
@@ -5309,10 +5316,11 @@ static void ipr_dump_ioasa(struct ipr_ioa_cfg *ioa_cfg,
 
        ipr_res_err(ioa_cfg, res, "%s\n", ipr_error_table[error_index].error);
 
-       if (sizeof(struct ipr_ioasa) < be16_to_cpu(ioasa->ret_stat_len))
+       data_len = be16_to_cpu(ioasa->hdr.ret_stat_len);
+       if (ioa_cfg->sis64 && sizeof(struct ipr_ioasa64) < data_len)
+               data_len = sizeof(struct ipr_ioasa64);
+       else if (!ioa_cfg->sis64 && sizeof(struct ipr_ioasa) < data_len)
                data_len = sizeof(struct ipr_ioasa);
-       else
-               data_len = be16_to_cpu(ioasa->ret_stat_len);
 
        ipr_err("IOASA Dump:\n");
 
@@ -5338,8 +5346,8 @@ static void ipr_gen_sense(struct ipr_cmnd *ipr_cmd)
        u32 failing_lba;
        u8 *sense_buf = ipr_cmd->scsi_cmd->sense_buffer;
        struct ipr_resource_entry *res = ipr_cmd->scsi_cmd->device->hostdata;
-       struct ipr_ioasa *ioasa = &ipr_cmd->ioasa;
-       u32 ioasc = be32_to_cpu(ioasa->ioasc);
+       struct ipr_ioasa *ioasa = &ipr_cmd->s.ioasa;
+       u32 ioasc = be32_to_cpu(ioasa->hdr.ioasc);
 
        memset(sense_buf, 0, SCSI_SENSE_BUFFERSIZE);
 
@@ -5382,7 +5390,7 @@ static void ipr_gen_sense(struct ipr_cmnd *ipr_cmd)
 
                /* Illegal request */
                if ((IPR_IOASC_SENSE_KEY(ioasc) == 0x05) &&
-                   (be32_to_cpu(ioasa->ioasc_specific) & IPR_FIELD_POINTER_VALID)) {
+                   (be32_to_cpu(ioasa->hdr.ioasc_specific) & IPR_FIELD_POINTER_VALID)) {
                        sense_buf[7] = 10;      /* additional length */
 
                        /* IOARCB was in error */
@@ -5393,10 +5401,10 @@ static void ipr_gen_sense(struct ipr_cmnd *ipr_cmd)
 
                        sense_buf[16] =
                            ((IPR_FIELD_POINTER_MASK &
-                             be32_to_cpu(ioasa->ioasc_specific)) >> 8) & 0xff;
+                             be32_to_cpu(ioasa->hdr.ioasc_specific)) >> 8) & 0xff;
                        sense_buf[17] =
                            (IPR_FIELD_POINTER_MASK &
-                            be32_to_cpu(ioasa->ioasc_specific)) & 0xff;
+                            be32_to_cpu(ioasa->hdr.ioasc_specific)) & 0xff;
                } else {
                        if (ioasc == IPR_IOASC_MED_DO_NOT_REALLOC) {
                                if (ipr_is_vset_device(res))
@@ -5428,14 +5436,20 @@ static void ipr_gen_sense(struct ipr_cmnd *ipr_cmd)
  **/
 static int ipr_get_autosense(struct ipr_cmnd *ipr_cmd)
 {
-       struct ipr_ioasa *ioasa = &ipr_cmd->ioasa;
+       struct ipr_ioasa *ioasa = &ipr_cmd->s.ioasa;
+       struct ipr_ioasa64 *ioasa64 = &ipr_cmd->s.ioasa64;
 
-       if ((be32_to_cpu(ioasa->ioasc_specific) & IPR_AUTOSENSE_VALID) == 0)
+       if ((be32_to_cpu(ioasa->hdr.ioasc_specific) & IPR_AUTOSENSE_VALID) == 0)
                return 0;
 
-       memcpy(ipr_cmd->scsi_cmd->sense_buffer, ioasa->auto_sense.data,
-              min_t(u16, be16_to_cpu(ioasa->auto_sense.auto_sense_len),
-                  SCSI_SENSE_BUFFERSIZE));
+       if (ipr_cmd->ioa_cfg->sis64)
+               memcpy(ipr_cmd->scsi_cmd->sense_buffer, ioasa64->auto_sense.data,
+                      min_t(u16, be16_to_cpu(ioasa64->auto_sense.auto_sense_len),
+                          SCSI_SENSE_BUFFERSIZE));
+       else
+               memcpy(ipr_cmd->scsi_cmd->sense_buffer, ioasa->auto_sense.data,
+                      min_t(u16, be16_to_cpu(ioasa->auto_sense.auto_sense_len),
+                          SCSI_SENSE_BUFFERSIZE));
        return 1;
 }
 
@@ -5455,7 +5469,7 @@ static void ipr_erp_start(struct ipr_ioa_cfg *ioa_cfg,
 {
        struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
        struct ipr_resource_entry *res = scsi_cmd->device->hostdata;
-       u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+       u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc);
        u32 masked_ioasc = ioasc & IPR_IOASC_IOASC_MASK;
 
        if (!res) {
@@ -5547,9 +5561,9 @@ static void ipr_scsi_done(struct ipr_cmnd *ipr_cmd)
 {
        struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
        struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
-       u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+       u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc);
 
-       scsi_set_resid(scsi_cmd, be32_to_cpu(ipr_cmd->ioasa.residual_data_len));
+       scsi_set_resid(scsi_cmd, be32_to_cpu(ipr_cmd->s.ioasa.hdr.residual_data_len));
 
        if (likely(IPR_IOASC_SENSE_KEY(ioasc) == 0)) {
                scsi_dma_unmap(ipr_cmd->scsi_cmd);
@@ -5839,19 +5853,23 @@ static void ipr_sata_done(struct ipr_cmnd *ipr_cmd)
        struct ata_queued_cmd *qc = ipr_cmd->qc;
        struct ipr_sata_port *sata_port = qc->ap->private_data;
        struct ipr_resource_entry *res = sata_port->res;
-       u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+       u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc);
 
-       memcpy(&sata_port->ioasa, &ipr_cmd->ioasa.u.gata,
-              sizeof(struct ipr_ioasa_gata));
+       if (ipr_cmd->ioa_cfg->sis64)
+               memcpy(&sata_port->ioasa, &ipr_cmd->s.ioasa64.u.gata,
+                      sizeof(struct ipr_ioasa_gata));
+       else
+               memcpy(&sata_port->ioasa, &ipr_cmd->s.ioasa.u.gata,
+                      sizeof(struct ipr_ioasa_gata));
        ipr_dump_ioasa(ioa_cfg, ipr_cmd, res);
 
-       if (be32_to_cpu(ipr_cmd->ioasa.ioasc_specific) & IPR_ATA_DEVICE_WAS_RESET)
+       if (be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc_specific) & IPR_ATA_DEVICE_WAS_RESET)
                scsi_report_device_reset(ioa_cfg->host, res->bus, res->target);
 
        if (IPR_IOASC_SENSE_KEY(ioasc) > RECOVERED_ERROR)
-               qc->err_mask |= __ac_err_mask(ipr_cmd->ioasa.u.gata.status);
+               qc->err_mask |= __ac_err_mask(sata_port->ioasa.status);
        else
-               qc->err_mask |= ac_err_mask(ipr_cmd->ioasa.u.gata.status);
+               qc->err_mask |= ac_err_mask(sata_port->ioasa.status);
        list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
        ata_qc_complete(qc);
 }
@@ -6520,7 +6538,7 @@ static void ipr_build_mode_sense(struct ipr_cmnd *ipr_cmd,
 static int ipr_reset_cmd_failed(struct ipr_cmnd *ipr_cmd)
 {
        struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
-       u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+       u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc);
 
        dev_err(&ioa_cfg->pdev->dev,
                "0x%02X failed with IOASC: 0x%08X\n",
@@ -6544,7 +6562,7 @@ static int ipr_reset_cmd_failed(struct ipr_cmnd *ipr_cmd)
 static int ipr_reset_mode_sense_failed(struct ipr_cmnd *ipr_cmd)
 {
        struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
-       u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+       u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc);
 
        if (ioasc == IPR_IOASC_IR_INVALID_REQ_TYPE_OR_PKT) {
                ipr_cmd->job_step = ipr_set_supported_devs;
@@ -6634,7 +6652,7 @@ static int ipr_ioafp_mode_select_page24(struct ipr_cmnd *ipr_cmd)
  **/
 static int ipr_reset_mode_sense_page24_failed(struct ipr_cmnd *ipr_cmd)
 {
-       u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+       u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc);
 
        if (ioasc == IPR_IOASC_IR_INVALID_REQ_TYPE_OR_PKT) {
                ipr_cmd->job_step = ipr_ioafp_mode_sense_page28;
@@ -6706,7 +6724,7 @@ static int ipr_init_res_table(struct ipr_cmnd *ipr_cmd)
                list_move_tail(&res->queue, &old_res);
 
        if (ioa_cfg->sis64)
-               entries = ioa_cfg->u.cfg_table64->hdr64.num_entries;
+               entries = be16_to_cpu(ioa_cfg->u.cfg_table64->hdr64.num_entries);
        else
                entries = ioa_cfg->u.cfg_table->hdr.num_entries;
 
@@ -6792,6 +6810,7 @@ static int ipr_ioafp_query_ioa_cfg(struct ipr_cmnd *ipr_cmd)
        ioarcb->res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE);
 
        ioarcb->cmd_pkt.cdb[0] = IPR_QUERY_IOA_CONFIG;
+       ioarcb->cmd_pkt.cdb[6] = (ioa_cfg->cfg_table_size >> 16) & 0xff;
        ioarcb->cmd_pkt.cdb[7] = (ioa_cfg->cfg_table_size >> 8) & 0xff;
        ioarcb->cmd_pkt.cdb[8] = ioa_cfg->cfg_table_size & 0xff;
 
@@ -7122,7 +7141,9 @@ static int ipr_reset_next_stage(struct ipr_cmnd *ipr_cmd)
        ipr_dbg("IPL stage = 0x%lx, IPL stage time = %ld\n", stage, stage_time);
 
        /* sanity check the stage_time value */
-       if (stage_time < IPR_IPL_INIT_MIN_STAGE_TIME)
+       if (stage_time == 0)
+               stage_time = IPR_IPL_INIT_DEFAULT_STAGE_TIME;
+       else if (stage_time < IPR_IPL_INIT_MIN_STAGE_TIME)
                stage_time = IPR_IPL_INIT_MIN_STAGE_TIME;
        else if (stage_time > IPR_LONG_OPERATIONAL_TIMEOUT)
                stage_time = IPR_LONG_OPERATIONAL_TIMEOUT;
@@ -7165,13 +7186,14 @@ static int ipr_reset_enable_ioa(struct ipr_cmnd *ipr_cmd)
 {
        struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
        volatile u32 int_reg;
+       volatile u64 maskval;
 
        ENTER;
        ipr_cmd->job_step = ipr_ioafp_identify_hrrq;
        ipr_init_ioa_mem(ioa_cfg);
 
        ioa_cfg->allow_interrupts = 1;
-       int_reg = readl(ioa_cfg->regs.sense_interrupt_reg);
+       int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32);
 
        if (int_reg & IPR_PCII_IOA_TRANS_TO_OPER) {
                writel((IPR_PCII_ERROR_INTERRUPTS | IPR_PCII_HRRQ_UPDATED),
@@ -7183,9 +7205,12 @@ static int ipr_reset_enable_ioa(struct ipr_cmnd *ipr_cmd)
        /* Enable destructive diagnostics on IOA */
        writel(ioa_cfg->doorbell, ioa_cfg->regs.set_uproc_interrupt_reg32);
 
-       writel(IPR_PCII_OPER_INTERRUPTS, ioa_cfg->regs.clr_interrupt_mask_reg32);
-       if (ioa_cfg->sis64)
-               writel(IPR_PCII_IPL_STAGE_CHANGE, ioa_cfg->regs.clr_interrupt_mask_reg);
+       if (ioa_cfg->sis64) {
+               maskval = IPR_PCII_IPL_STAGE_CHANGE;
+               maskval = (maskval << 32) | IPR_PCII_OPER_INTERRUPTS;
+               writeq(maskval, ioa_cfg->regs.clr_interrupt_mask_reg);
+       } else
+               writel(IPR_PCII_OPER_INTERRUPTS, ioa_cfg->regs.clr_interrupt_mask_reg32);
 
        int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
 
@@ -7332,12 +7357,12 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd)
        rc = pci_restore_state(ioa_cfg->pdev);
 
        if (rc != PCIBIOS_SUCCESSFUL) {
-               ipr_cmd->ioasa.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR);
+               ipr_cmd->s.ioasa.hdr.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR);
                return IPR_RC_JOB_CONTINUE;
        }
 
        if (ipr_set_pcix_cmd_reg(ioa_cfg)) {
-               ipr_cmd->ioasa.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR);
+               ipr_cmd->s.ioasa.hdr.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR);
                return IPR_RC_JOB_CONTINUE;
        }
 
@@ -7364,7 +7389,7 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd)
                }
        }
 
-       ENTER;
+       LEAVE;
        return IPR_RC_JOB_CONTINUE;
 }
 
@@ -7406,7 +7431,7 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd)
 
        if (rc != PCIBIOS_SUCCESSFUL) {
                pci_unblock_user_cfg_access(ipr_cmd->ioa_cfg->pdev);
-               ipr_cmd->ioasa.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR);
+               ipr_cmd->s.ioasa.hdr.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR);
                rc = IPR_RC_JOB_CONTINUE;
        } else {
                ipr_cmd->job_step = ipr_reset_bist_done;
@@ -7665,7 +7690,7 @@ static void ipr_reset_ioa_job(struct ipr_cmnd *ipr_cmd)
        struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
 
        do {
-               ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+               ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc);
 
                if (ioa_cfg->reset_cmd != ipr_cmd) {
                        /*
@@ -8048,13 +8073,13 @@ static int __devinit ipr_alloc_cmd_blks(struct ipr_ioa_cfg *ioa_cfg)
                        ioarcb->u.sis64_addr_data.data_ioadl_addr =
                                cpu_to_be64(dma_addr + offsetof(struct ipr_cmnd, i.ioadl64));
                        ioarcb->u.sis64_addr_data.ioasa_host_pci_addr =
-                               cpu_to_be64(dma_addr + offsetof(struct ipr_cmnd, ioasa));
+                               cpu_to_be64(dma_addr + offsetof(struct ipr_cmnd, s.ioasa64));
                } else {
                        ioarcb->write_ioadl_addr =
                                cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, i.ioadl));
                        ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr;
                        ioarcb->ioasa_host_pci_addr =
-                               cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, ioasa));
+                               cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, s.ioasa));
                }
                ioarcb->ioasa_len = cpu_to_be16(sizeof(struct ipr_ioasa));
                ipr_cmd->cmd_index = i;
index 4c267b5e0b96c97c505149d1193891914c15f217..9ecd2259eb398dcc0f1e88746df8555dca09e80d 100644 (file)
 #define IPR_RUNTIME_RESET                              0x40000000
 
 #define IPR_IPL_INIT_MIN_STAGE_TIME                    5
+#define IPR_IPL_INIT_DEFAULT_STAGE_TIME                 15
 #define IPR_IPL_INIT_STAGE_UNKNOWN                     0x0
 #define IPR_IPL_INIT_STAGE_TRANSOP                     0xB0000000
 #define IPR_IPL_INIT_STAGE_MASK                                0xff000000
@@ -613,7 +614,7 @@ struct ipr_auto_sense {
        __be32 data[SCSI_SENSE_BUFFERSIZE/sizeof(__be32)];
 };
 
-struct ipr_ioasa {
+struct ipr_ioasa_hdr {
        __be32 ioasc;
 #define IPR_IOASC_SENSE_KEY(ioasc) ((ioasc) >> 24)
 #define IPR_IOASC_SENSE_CODE(ioasc) (((ioasc) & 0x00ff0000) >> 16)
@@ -645,6 +646,25 @@ struct ipr_ioasa {
 #define IPR_FIELD_POINTER_VALID                (0x80000000 >> 8)
 #define IPR_FIELD_POINTER_MASK         0x0000ffff
 
+}__attribute__((packed, aligned (4)));
+
+struct ipr_ioasa {
+       struct ipr_ioasa_hdr hdr;
+
+       union {
+               struct ipr_ioasa_vset vset;
+               struct ipr_ioasa_af_dasd dasd;
+               struct ipr_ioasa_gpdd gpdd;
+               struct ipr_ioasa_gata gata;
+       } u;
+
+       struct ipr_auto_sense auto_sense;
+}__attribute__((packed, aligned (4)));
+
+struct ipr_ioasa64 {
+       struct ipr_ioasa_hdr hdr;
+       u8 fd_res_path[8];
+
        union {
                struct ipr_ioasa_vset vset;
                struct ipr_ioasa_af_dasd dasd;
@@ -804,7 +824,7 @@ struct ipr_hostrcb_array_data_entry_enhanced {
 }__attribute__((packed, aligned (4)));
 
 struct ipr_hostrcb_type_ff_error {
-       __be32 ioa_data[502];
+       __be32 ioa_data[758];
 }__attribute__((packed, aligned (4)));
 
 struct ipr_hostrcb_type_01_error {
@@ -1181,7 +1201,7 @@ struct ipr_resource_entry {
        u8 flags;
        __be16 res_flags;
 
-       __be32 type;
+       u8 type;
 
        u8 qmodel;
        struct ipr_std_inq_data std_inq_data;
@@ -1464,7 +1484,10 @@ struct ipr_cmnd {
                struct ipr_ioadl64_desc ioadl64[IPR_NUM_IOADL_ENTRIES];
                struct ipr_ata64_ioadl ata_ioadl;
        } i;
-       struct ipr_ioasa ioasa;
+       union {
+               struct ipr_ioasa ioasa;
+               struct ipr_ioasa64 ioasa64;
+       } s;
        struct list_head queue;
        struct scsi_cmnd *scsi_cmd;
        struct ata_queued_cmd *qc;
index bf55d305741306b0d35ef9584d942229e11152b4..fec47de72535984f1e36b83048f763e7cd0a15a8 100644 (file)
@@ -601,10 +601,8 @@ static void iscsi_sw_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
        set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
        write_unlock_bh(&tcp_sw_conn->sock->sk->sk_callback_lock);
 
-       if (sk_sleep(sock->sk)) {
-               sock->sk->sk_err = EIO;
-               wake_up_interruptible(sk_sleep(sock->sk));
-       }
+       sock->sk->sk_err = EIO;
+       wake_up_interruptible(sk_sleep(sock->sk));
 
        iscsi_conn_stop(cls_conn, flag);
        iscsi_sw_tcp_release_conn(conn);
index 4bf7edca9e69a249fa29642650640250053dde56..0b6e3228610ae08371ec9189ae95511b20e186d4 100644 (file)
@@ -91,12 +91,15 @@ static struct proc_dir_entry *mega_proc_dir_entry;
 /* For controller re-ordering */
 static struct mega_hbas mega_hbas[MAX_CONTROLLERS];
 
+static long
+megadev_unlocked_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
+
 /*
  * The File Operations structure for the serial/ioctl interface of the driver
  */
 static const struct file_operations megadev_fops = {
        .owner          = THIS_MODULE,
-       .ioctl          = megadev_ioctl,
+       .unlocked_ioctl = megadev_unlocked_ioctl,
        .open           = megadev_open,
 };
 
@@ -3302,8 +3305,7 @@ megadev_open (struct inode *inode, struct file *filep)
  * controller.
  */
 static int
-megadev_ioctl(struct inode *inode, struct file *filep, unsigned int cmd,
-               unsigned long arg)
+megadev_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
 {
        adapter_t       *adapter;
        nitioctl_t      uioc;
@@ -3694,6 +3696,18 @@ freemem_and_return:
        return 0;
 }
 
+static long
+megadev_unlocked_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+       int ret;
+
+       lock_kernel();
+       ret = megadev_ioctl(filep, cmd, arg);
+       unlock_kernel();
+
+       return ret;
+}
+
 /**
  * mega_m_to_n()
  * @arg - user address
index d310f49d077e68351549213a2f444e41033b243e..2b4a048cadf1b31d41a0659e1be55acb96815cd9 100644 (file)
@@ -1013,8 +1013,7 @@ static void mega_8_to_40ld (mraid_inquiry *inquiry,
                mega_inquiry3 *enquiry3, mega_product_info *);
 
 static int megadev_open (struct inode *, struct file *);
-static int megadev_ioctl (struct inode *, struct file *, unsigned int,
-               unsigned long);
+static int megadev_ioctl (struct file *, unsigned int, unsigned long);
 static int mega_m_to_n(void __user *, nitioctl_t *);
 static int mega_n_to_m(void __user *, megacmd_t *);
 
index 36e0b7d05c1dbc13cc6252094f02b68fbabc02c4..41f82f76d8845ad92b7bfa765936ca513f325dee 100644 (file)
@@ -22,7 +22,7 @@
 
 // Entry points for char node driver
 static int mraid_mm_open(struct inode *, struct file *);
-static int mraid_mm_ioctl(struct inode *, struct file *, uint, unsigned long);
+static long mraid_mm_unlocked_ioctl(struct file *, uint, unsigned long);
 
 
 // routines to convert to and from the old the format
@@ -70,7 +70,7 @@ static wait_queue_head_t wait_q;
 
 static const struct file_operations lsi_fops = {
        .open   = mraid_mm_open,
-       .ioctl  = mraid_mm_ioctl,
+       .unlocked_ioctl = mraid_mm_unlocked_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl = mraid_mm_compat_ioctl,
 #endif
@@ -110,8 +110,7 @@ mraid_mm_open(struct inode *inode, struct file *filep)
  * @arg                : user ioctl packet
  */
 static int
-mraid_mm_ioctl(struct inode *inode, struct file *filep, unsigned int cmd,
-                                                       unsigned long arg)
+mraid_mm_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
 {
        uioc_t          *kioc;
        char            signature[EXT_IOCTL_SIGN_SZ]    = {0};
@@ -218,6 +217,19 @@ mraid_mm_ioctl(struct inode *inode, struct file *filep, unsigned int cmd,
        return rval;
 }
 
+static long
+mraid_mm_unlocked_ioctl(struct file *filep, unsigned int cmd,
+                       unsigned long arg)
+{
+       int err;
+
+       /* inconsistant: mraid_mm_compat_ioctl doesn't take the BKL */
+       lock_kernel();
+       err = mraid_mm_ioctl(filep, cmd, arg);
+       unlock_kernel();
+
+       return err;
+}
 
 /**
  * mraid_mm_get_adapter - Returns corresponding adapters for the mimd packet
@@ -1225,7 +1237,7 @@ mraid_mm_compat_ioctl(struct file *filep, unsigned int cmd,
 {
        int err;
 
-       err = mraid_mm_ioctl(NULL, filep, cmd, arg);
+       err = mraid_mm_ioctl(filep, cmd, arg);
 
        return err;
 }
index b830d61684ddb35fafb13401c106881b1070bb46..0ec1ed389c209b1e8273b0f4b6cdf97fc599a144 100644 (file)
@@ -3757,7 +3757,7 @@ _base_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
                if (ioc->config_cmds.status & MPT2_CMD_PENDING) {
                        ioc->config_cmds.status |= MPT2_CMD_RESET;
                        mpt2sas_base_free_smid(ioc, ioc->config_cmds.smid);
-                       ioc->config_cmds.smid = USHORT_MAX;
+                       ioc->config_cmds.smid = USHRT_MAX;
                        complete(&ioc->config_cmds.done);
                }
                break;
index e762dd3e2fcb8d04403470d0867cd24a84fd9a72..c65442982d7bbf1640c450f81d1fd25150bae6db 100644 (file)
@@ -258,7 +258,7 @@ mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
 #ifdef CONFIG_SCSI_MPT2SAS_LOGGING
        _config_display_some_debug(ioc, smid, "config_done", mpi_reply);
 #endif
-       ioc->config_cmds.smid = USHORT_MAX;
+       ioc->config_cmds.smid = USHRT_MAX;
        complete(&ioc->config_cmds.done);
        return 1;
 }
index 716d1785cda726fc3180cd854e0c4aebeb2879ab..c29d0dbb9660b97e34515317927208a475215f95 100644 (file)
 #include <linux/stat.h>
 
 
-static struct Scsi_Host *mvme147_host = NULL;
-
-static irqreturn_t mvme147_intr(int irq, void *dummy)
+static irqreturn_t mvme147_intr(int irq, void *data)
 {
+       struct Scsi_Host *instance = data;
+
        if (irq == MVME147_IRQ_SCSI_PORT)
-               wd33c93_intr(mvme147_host);
+               wd33c93_intr(instance);
        else
                m147_pcc->dma_intr = 0x89;      /* Ack and enable ints */
        return IRQ_HANDLED;
@@ -29,7 +29,8 @@ static irqreturn_t mvme147_intr(int irq, void *dummy)
 
 static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
 {
-       struct WD33C93_hostdata *hdata = shost_priv(mvme147_host);
+       struct Scsi_Host *instance = cmd->device->host;
+       struct WD33C93_hostdata *hdata = shost_priv(instance);
        unsigned char flags = 0x01;
        unsigned long addr = virt_to_bus(cmd->SCp.ptr);
 
@@ -66,6 +67,7 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
 int mvme147_detect(struct scsi_host_template *tpnt)
 {
        static unsigned char called = 0;
+       struct Scsi_Host *instance;
        wd33c93_regs regs;
        struct WD33C93_hostdata *hdata;
 
@@ -76,25 +78,25 @@ int mvme147_detect(struct scsi_host_template *tpnt)
        tpnt->proc_name = "MVME147";
        tpnt->proc_info = &wd33c93_proc_info;
 
-       mvme147_host = scsi_register(tpnt, sizeof(struct WD33C93_hostdata));
-       if (!mvme147_host)
+       instance = scsi_register(tpnt, sizeof(struct WD33C93_hostdata));
+       if (!instance)
                goto err_out;
 
-       mvme147_host->base = 0xfffe4000;
-       mvme147_host->irq = MVME147_IRQ_SCSI_PORT;
+       instance->base = 0xfffe4000;
+       instance->irq = MVME147_IRQ_SCSI_PORT;
        regs.SASR = (volatile unsigned char *)0xfffe4000;
        regs.SCMD = (volatile unsigned char *)0xfffe4001;
-       hdata = shost_priv(mvme147_host);
+       hdata = shost_priv(instance);
        hdata->no_sync = 0xff;
        hdata->fast = 0;
        hdata->dma_mode = CTRL_DMA;
-       wd33c93_init(mvme147_host, regs, dma_setup, dma_stop, WD33C93_FS_8_10);
+       wd33c93_init(instance, regs, dma_setup, dma_stop, WD33C93_FS_8_10);
 
        if (request_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr, 0,
-                       "MVME147 SCSI PORT", mvme147_intr))
+                       "MVME147 SCSI PORT", instance))
                goto err_unregister;
        if (request_irq(MVME147_IRQ_SCSI_DMA, mvme147_intr, 0,
-                       "MVME147 SCSI DMA", mvme147_intr))
+                       "MVME147 SCSI DMA", instance))
                goto err_free_irq;
 #if 0  /* Disabled; causes problems booting */
        m147_pcc->scsi_interrupt = 0x10;        /* Assert SCSI bus reset */
@@ -113,7 +115,7 @@ int mvme147_detect(struct scsi_host_template *tpnt)
 err_free_irq:
        free_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr);
 err_unregister:
-       scsi_unregister(mvme147_host);
+       scsi_unregister(instance);
 err_out:
        return 0;
 }
@@ -132,9 +134,6 @@ static int mvme147_bus_reset(struct scsi_cmnd *cmd)
        return SUCCESS;
 }
 
-#define HOSTS_C
-
-#include "mvme147.h"
 
 static struct scsi_host_template driver_template = {
        .proc_name              = "MVME147",
index b219118f8bd6abccc03d6cc9e3c9f4500c7c9de3..d64b7178fa088a3eb24453affaa6e5782037d195 100644 (file)
@@ -3587,7 +3587,7 @@ if (SRpnt) printk(KERN_ERR "%s:A: Not supposed to have SRpnt at line %d\n", name
                if (i == (-ENOSPC)) {
                        transfer = STp->buffer->writing;        /* FIXME -- check this logic */
                        if (transfer <= do_count) {
-                               filp->f_pos += do_count - transfer;
+                               *ppos += do_count - transfer;
                                count -= do_count - transfer;
                                if (STps->drv_block >= 0) {
                                        STps->drv_block += (do_count - transfer) / STp->block_size;
@@ -3625,7 +3625,7 @@ if (SRpnt) printk(KERN_ERR "%s:A: Not supposed to have SRpnt at line %d\n", name
                        goto out;
                }
 
-               filp->f_pos += do_count;
+               *ppos += do_count;
                b_point += do_count;
                count -= do_count;
                if (STps->drv_block >= 0) {
@@ -3647,7 +3647,7 @@ if (SRpnt) printk(KERN_ERR "%s:A: Not supposed to have SRpnt at line %d\n", name
                if (STps->drv_block >= 0) {
                        STps->drv_block += blks;
                }
-               filp->f_pos += count;
+               *ppos += count;
                count = 0;
        }
 
@@ -3823,7 +3823,7 @@ static ssize_t osst_read(struct file * filp, char __user * buf, size_t count, lo
                        }
                        STp->logical_blk_num += transfer / STp->block_size;
                        STps->drv_block      += transfer / STp->block_size;
-                       filp->f_pos          += transfer;
+                       *ppos          += transfer;
                        buf                  += transfer;
                        total                += transfer;
                }
@@ -4932,7 +4932,7 @@ static int os_scsi_tape_close(struct inode * inode, struct file * filp)
 
 
 /* The ioctl command */
-static int osst_ioctl(struct inode * inode,struct file * file,
+static long osst_ioctl(struct file * file,
         unsigned int cmd_in, unsigned long arg)
 {
        int                   i, cmd_nr, cmd_type, blk, retval = 0;
@@ -4943,8 +4943,11 @@ static int osst_ioctl(struct inode * inode,struct file * file,
        char                * name  = tape_name(STp);
        void        __user  * p     = (void __user *)arg;
 
-       if (mutex_lock_interruptible(&STp->lock))
+       lock_kernel();
+       if (mutex_lock_interruptible(&STp->lock)) {
+               unlock_kernel();
                return -ERESTARTSYS;
+       }
 
 #if DEBUG
        if (debugging && !STp->in_use) {
@@ -5256,12 +5259,15 @@ static int osst_ioctl(struct inode * inode,struct file * file,
 
        mutex_unlock(&STp->lock);
 
-       return scsi_ioctl(STp->device, cmd_in, p);
+       retval = scsi_ioctl(STp->device, cmd_in, p);
+       unlock_kernel();
+       return retval;
 
 out:
        if (SRpnt) osst_release_request(SRpnt);
 
        mutex_unlock(&STp->lock);
+       unlock_kernel();
 
        return retval;
 }
@@ -5613,13 +5619,14 @@ static const struct file_operations osst_fops = {
        .owner =        THIS_MODULE,
        .read =         osst_read,
        .write =        osst_write,
-       .ioctl =        osst_ioctl,
+       .unlocked_ioctl = osst_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl = osst_compat_ioctl,
 #endif
        .open =         os_scsi_tape_open,
        .flush =        os_scsi_tape_flush,
        .release =      os_scsi_tape_close,
+       .llseek =       noop_llseek,
 };
 
 static int osst_supports(struct scsi_device * SDp)
index aa406497eebcf912cd296dd1554fdc9120611aa2..ca5c15c779cfc5a4d26659818545414b12682052 100644 (file)
@@ -755,7 +755,7 @@ static void __devinit qpti_get_scsi_id(struct qlogicpti *qpti)
        struct of_device *op = qpti->op;
        struct device_node *dp;
 
-       dp = op->node;
+       dp = op->dev.of_node;
 
        qpti->scsi_id = of_getintprop_default(dp, "initiator-id", -1);
        if (qpti->scsi_id == -1)
@@ -776,8 +776,8 @@ static void qpti_get_bursts(struct qlogicpti *qpti)
        struct of_device *op = qpti->op;
        u8 bursts, bmask;
 
-       bursts = of_getintprop_default(op->node, "burst-sizes", 0xff);
-       bmask = of_getintprop_default(op->node->parent, "burst-sizes", 0xff);
+       bursts = of_getintprop_default(op->dev.of_node, "burst-sizes", 0xff);
+       bmask = of_getintprop_default(op->dev.of_node->parent, "burst-sizes", 0xff);
        if (bmask != 0xff)
                bursts &= bmask;
        if (bursts == 0xff ||
@@ -1293,7 +1293,7 @@ static struct scsi_host_template qpti_template = {
 static int __devinit qpti_sbus_probe(struct of_device *op, const struct of_device_id *match)
 {
        struct scsi_host_template *tpnt = match->data;
-       struct device_node *dp = op->node;
+       struct device_node *dp = op->dev.of_node;
        struct Scsi_Host *host;
        struct qlogicpti *qpti;
        static int nqptis;
@@ -1315,7 +1315,7 @@ static int __devinit qpti_sbus_probe(struct of_device *op, const struct of_devic
        qpti->qhost = host;
        qpti->op = op;
        qpti->qpti_id = nqptis;
-       strcpy(qpti->prom_name, op->node->name);
+       strcpy(qpti->prom_name, op->dev.of_node->name);
        qpti->is_pti = strcmp(qpti->prom_name, "QLGC,isp");
 
        if (qpti_map_regs(qpti) < 0)
@@ -1456,8 +1456,11 @@ static const struct of_device_id qpti_match[] = {
 MODULE_DEVICE_TABLE(of, qpti_match);
 
 static struct of_platform_driver qpti_sbus_driver = {
-       .name           = "qpti",
-       .match_table    = qpti_match,
+       .driver = {
+               .name = "qpti",
+               .owner = THIS_MODULE,
+               .of_match_table = qpti_match,
+       },
        .probe          = qpti_sbus_probe,
        .remove         = __devexit_p(qpti_sbus_remove),
 };
index c992ecf4e37206a6f28fe8a33787b5cf1b3267cb..1c027a97d8b9ea570d0a48d254908a71cfe84377 100644 (file)
@@ -492,19 +492,20 @@ void scsi_target_reap(struct scsi_target *starget)
        struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
        unsigned long flags;
        enum scsi_target_state state;
-       int empty;
+       int empty = 0;
 
        spin_lock_irqsave(shost->host_lock, flags);
        state = starget->state;
-       empty = --starget->reap_ref == 0 &&
-               list_empty(&starget->devices) ? 1 : 0;
+       if (--starget->reap_ref == 0 && list_empty(&starget->devices)) {
+               empty = 1;
+               starget->state = STARGET_DEL;
+       }
        spin_unlock_irqrestore(shost->host_lock, flags);
 
        if (!empty)
                return;
 
        BUG_ON(state == STARGET_DEL);
-       starget->state = STARGET_DEL;
        if (state == STARGET_CREATED)
                scsi_target_destroy(starget);
        else
@@ -1220,7 +1221,7 @@ static void scsi_sequential_lun_scan(struct scsi_target *starget,
 }
 
 /**
- * scsilun_to_int: convert a scsi_lun to an int
+ * scsilun_to_int - convert a scsi_lun to an int
  * @scsilun:   struct scsi_lun to be converted.
  *
  * Description:
@@ -1252,7 +1253,7 @@ int scsilun_to_int(struct scsi_lun *scsilun)
 EXPORT_SYMBOL(scsilun_to_int);
 
 /**
- * int_to_scsilun: reverts an int into a scsi_lun
+ * int_to_scsilun - reverts an int into a scsi_lun
  * @lun:        integer to be reverted
  * @scsilun:   struct scsi_lun to be set.
  *
@@ -1876,12 +1877,9 @@ void scsi_forget_host(struct Scsi_Host *shost)
        spin_unlock_irqrestore(shost->host_lock, flags);
 }
 
-/*
- * Function:    scsi_get_host_dev()
- *
- * Purpose:     Create a scsi_device that points to the host adapter itself.
- *
- * Arguments:   SHpnt   - Host that needs a scsi_device
+/**
+ * scsi_get_host_dev - Create a scsi_device that points to the host adapter itself
+ * @shost: Host that needs a scsi_device
  *
  * Lock status: None assumed.
  *
@@ -1894,7 +1892,7 @@ void scsi_forget_host(struct Scsi_Host *shost)
  *
  *     Note - this device is not accessible from any high-level
  *     drivers (including generics), which is probably not
- *     optimal.  We can add hooks later to attach 
+ *     optimal.  We can add hooks later to attach.
  */
 struct scsi_device *scsi_get_host_dev(struct Scsi_Host *shost)
 {
@@ -1920,18 +1918,13 @@ struct scsi_device *scsi_get_host_dev(struct Scsi_Host *shost)
 }
 EXPORT_SYMBOL(scsi_get_host_dev);
 
-/*
- * Function:    scsi_free_host_dev()
- *
- * Purpose:     Free a scsi_device that points to the host adapter itself.
- *
- * Arguments:   SHpnt   - Host that needs a scsi_device
+/**
+ * scsi_free_host_dev - Free a scsi_device that points to the host adapter itself
+ * @sdev: Host device to be freed
  *
  * Lock status: None assumed.
  *
  * Returns:     Nothing
- *
- * Notes:
  */
 void scsi_free_host_dev(struct scsi_device *sdev)
 {
index dee1c96288d4420e2461c68c4d18ac253d46c6f7..ef752b248c4d5ef7842589299d75a2297ec8178e 100644 (file)
@@ -758,8 +758,7 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp,
 }
 
 static int
-sg_ioctl(struct inode *inode, struct file *filp,
-        unsigned int cmd_in, unsigned long arg)
+sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
 {
        void __user *p = (void __user *)arg;
        int __user *ip = p;
@@ -1078,6 +1077,18 @@ sg_ioctl(struct inode *inode, struct file *filp,
        }
 }
 
+static long
+sg_unlocked_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
+{
+       int ret;
+
+       lock_kernel();
+       ret = sg_ioctl(filp, cmd_in, arg);
+       unlock_kernel();
+
+       return ret;
+}
+
 #ifdef CONFIG_COMPAT
 static long sg_compat_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
 {
@@ -1322,7 +1333,7 @@ static const struct file_operations sg_fops = {
        .read = sg_read,
        .write = sg_write,
        .poll = sg_poll,
-       .ioctl = sg_ioctl,
+       .unlocked_ioctl = sg_unlocked_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl = sg_compat_ioctl,
 #endif
index 3ea1a713ef250fcc35a64b10c71a65ac73ea6e42..24211d0efa6d5d82557dac4e6047c3b9efc25c3f 100644 (file)
@@ -3962,6 +3962,7 @@ static const struct file_operations st_fops =
        .open =         st_open,
        .flush =        st_flush,
        .release =      st_release,
+       .llseek =       noop_llseek,
 };
 
 static int st_probe(struct device *dev)
index fc23d273fb1a6c17d37a648e6fd05c1cbaccbf75..386dd9d602b6e32ce4d262375caa4738ff9b1b5e 100644 (file)
@@ -125,7 +125,7 @@ static void __devinit esp_get_scsi_id(struct esp *esp, struct of_device *espdma)
        struct of_device *op = esp->dev;
        struct device_node *dp;
 
-       dp = op->node;
+       dp = op->dev.of_node;
        esp->scsi_id = of_getintprop_default(dp, "initiator-id", 0xff);
        if (esp->scsi_id != 0xff)
                goto done;
@@ -134,7 +134,7 @@ static void __devinit esp_get_scsi_id(struct esp *esp, struct of_device *espdma)
        if (esp->scsi_id != 0xff)
                goto done;
 
-       esp->scsi_id = of_getintprop_default(espdma->node,
+       esp->scsi_id = of_getintprop_default(espdma->dev.of_node,
                                             "scsi-initiator-id", 7);
 
 done:
@@ -147,7 +147,7 @@ static void __devinit esp_get_differential(struct esp *esp)
        struct of_device *op = esp->dev;
        struct device_node *dp;
 
-       dp = op->node;
+       dp = op->dev.of_node;
        if (of_find_property(dp, "differential", NULL))
                esp->flags |= ESP_FLAG_DIFFERENTIAL;
        else
@@ -160,7 +160,7 @@ static void __devinit esp_get_clock_params(struct esp *esp)
        struct device_node *bus_dp, *dp;
        int fmhz;
 
-       dp = op->node;
+       dp = op->dev.of_node;
        bus_dp = dp->parent;
 
        fmhz = of_getintprop_default(dp, "clock-frequency", 0);
@@ -172,12 +172,12 @@ static void __devinit esp_get_clock_params(struct esp *esp)
 
 static void __devinit esp_get_bursts(struct esp *esp, struct of_device *dma_of)
 {
-       struct device_node *dma_dp = dma_of->node;
+       struct device_node *dma_dp = dma_of->dev.of_node;
        struct of_device *op = esp->dev;
        struct device_node *dp;
        u8 bursts, val;
 
-       dp = op->node;
+       dp = op->dev.of_node;
        bursts = of_getintprop_default(dp, "burst-sizes", 0xff);
        val = of_getintprop_default(dma_dp, "burst-sizes", 0xff);
        if (val != 0xff)
@@ -565,7 +565,7 @@ fail:
 static int __devinit esp_sbus_probe(struct of_device *op, const struct of_device_id *match)
 {
        struct device_node *dma_node = NULL;
-       struct device_node *dp = op->node;
+       struct device_node *dp = op->dev.of_node;
        struct of_device *dma_of = NULL;
        int hme = 0;
 
@@ -574,7 +574,7 @@ static int __devinit esp_sbus_probe(struct of_device *op, const struct of_device
             !strcmp(dp->parent->name, "dma")))
                dma_node = dp->parent;
        else if (!strcmp(dp->name, "SUNW,fas")) {
-               dma_node = op->node;
+               dma_node = op->dev.of_node;
                hme = 1;
        }
        if (dma_node)
@@ -633,8 +633,11 @@ static const struct of_device_id esp_match[] = {
 MODULE_DEVICE_TABLE(of, esp_match);
 
 static struct of_platform_driver esp_sbus_driver = {
-       .name           = "esp",
-       .match_table    = esp_match,
+       .driver = {
+               .name = "esp",
+               .owner = THIS_MODULE,
+               .of_match_table = esp_match,
+       },
        .probe          = esp_sbus_probe,
        .remove         = __devexit_p(esp_sbus_remove),
 };
index 78ed24bb6a35d4eb09f9a4f90939f5b4f7151d20..30463862603b18e819ddcd69ead819dee18f0d44 100644 (file)
@@ -1437,7 +1437,7 @@ int m68328_console_setup(struct console *cp, char *arg)
        for (i = 0; i < ARRAY_SIZE(baud_table); i++)
                if (baud_table[i] == n)
                        break;
-       if (i < BAUD_TABLE_SIZE) {
+       if (i < ARRAY_SIZE(baud_table)) {
                m68328_console_baud = n;
                m68328_console_cbaud = 0;
                if (i > 15) {
index fe91319b5f65b30a15c5b89baea504c27871b6e6..0099b8692b60c7b2f23781b32a530702e56457d7 100644 (file)
@@ -559,7 +559,7 @@ static int __devinit apbuart_probe(struct of_device *op,
 
        i = 0;
        for (i = 0; i < grlib_apbuart_port_nr; i++) {
-               if (op->node == grlib_apbuart_nodes[i])
+               if (op->dev.of_node == grlib_apbuart_nodes[i])
                        break;
        }
 
@@ -584,12 +584,12 @@ static struct of_device_id __initdata apbuart_match[] = {
 };
 
 static struct of_platform_driver grlib_apbuart_of_driver = {
-       .match_table = apbuart_match,
        .probe = apbuart_probe,
        .driver = {
-                  .owner = THIS_MODULE,
-                  .name = "grlib-apbuart",
-                  },
+               .owner = THIS_MODULE,
+               .name = "grlib-apbuart",
+               .of_match_table = apbuart_match,
+       },
 };
 
 
index 300cea768d746939762afee7f42a8ad2cf5d06a1..9eb62a256e9a675af529475d178c7925e6de5302 100644 (file)
@@ -1342,7 +1342,7 @@ static int __devinit cpm_uart_probe(struct of_device *ofdev,
        /* initialize the device pointer for the port */
        pinfo->port.dev = &ofdev->dev;
 
-       ret = cpm_uart_init_port(ofdev->node, pinfo);
+       ret = cpm_uart_init_port(ofdev->dev.of_node, pinfo);
        if (ret)
                return ret;
 
@@ -1372,8 +1372,11 @@ static struct of_device_id cpm_uart_match[] = {
 };
 
 static struct of_platform_driver cpm_uart_driver = {
-       .name = "cpm_uart",
-       .match_table = cpm_uart_match,
+       .driver = {
+               .name = "cpm_uart",
+               .owner = THIS_MODULE,
+               .of_match_table = cpm_uart_match,
+       },
        .probe = cpm_uart_probe,
        .remove = cpm_uart_remove,
  };
index 02469c31bf0b6939f37e96e03ac7e1af98a45a14..84a35f6990169f44c3a387e1cb19ae4e5b7f017c 100644 (file)
@@ -397,34 +397,10 @@ static unsigned long mpc512x_getuartclk(void *p)
        return mpc5xxx_get_bus_frequency(p);
 }
 
-#define DEFAULT_FIFO_SIZE 16
-
-static unsigned int __init get_fifo_size(struct device_node *np,
-                                        char *fifo_name)
-{
-       const unsigned int *fp;
-
-       fp = of_get_property(np, fifo_name, NULL);
-       if (fp)
-               return *fp;
-
-       pr_warning("no %s property in %s node, defaulting to %d\n",
-                  fifo_name, np->full_name, DEFAULT_FIFO_SIZE);
-
-       return DEFAULT_FIFO_SIZE;
-}
-
-#define FIFOC(_base) ((struct mpc512x_psc_fifo __iomem *) \
-                   ((u32)(_base) + sizeof(struct mpc52xx_psc)))
-
 /* Init PSC FIFO Controller */
 static int __init mpc512x_psc_fifoc_init(void)
 {
        struct device_node *np;
-       void __iomem *psc;
-       unsigned int tx_fifo_size;
-       unsigned int rx_fifo_size;
-       int fifobase = 0; /* current fifo address in 32 bit words */
 
        np = of_find_compatible_node(NULL, NULL,
                                     "fsl,mpc5121-psc-fifo");
@@ -447,51 +423,6 @@ static int __init mpc512x_psc_fifoc_init(void)
                return -ENODEV;
        }
 
-       for_each_compatible_node(np, NULL, "fsl,mpc5121-psc-uart") {
-               tx_fifo_size = get_fifo_size(np, "fsl,tx-fifo-size");
-               rx_fifo_size = get_fifo_size(np, "fsl,rx-fifo-size");
-
-               /* size in register is in 4 byte units */
-               tx_fifo_size /= 4;
-               rx_fifo_size /= 4;
-               if (!tx_fifo_size)
-                       tx_fifo_size = 1;
-               if (!rx_fifo_size)
-                       rx_fifo_size = 1;
-
-               psc = of_iomap(np, 0);
-               if (!psc) {
-                       pr_err("%s: Can't map %s device\n",
-                               __func__, np->full_name);
-                       continue;
-               }
-
-               /* FIFO space is 4KiB, check if requested size is available */
-               if ((fifobase + tx_fifo_size + rx_fifo_size) > 0x1000) {
-                       pr_err("%s: no fifo space available for %s\n",
-                               __func__, np->full_name);
-                       iounmap(psc);
-                       /*
-                        * chances are that another device requests less
-                        * fifo space, so we continue.
-                        */
-                       continue;
-               }
-               /* set tx and rx fifo size registers */
-               out_be32(&FIFOC(psc)->txsz, (fifobase << 16) | tx_fifo_size);
-               fifobase += tx_fifo_size;
-               out_be32(&FIFOC(psc)->rxsz, (fifobase << 16) | rx_fifo_size);
-               fifobase += rx_fifo_size;
-
-               /* reset and enable the slices */
-               out_be32(&FIFOC(psc)->txcmd, 0x80);
-               out_be32(&FIFOC(psc)->txcmd, 0x01);
-               out_be32(&FIFOC(psc)->rxcmd, 0x80);
-               out_be32(&FIFOC(psc)->rxcmd, 0x01);
-
-               iounmap(psc);
-       }
-
        return 0;
 }
 
@@ -1295,14 +1226,14 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
 
        /* Check validity & presence */
        for (idx = 0; idx < MPC52xx_PSC_MAXNUM; idx++)
-               if (mpc52xx_uart_nodes[idx] == op->node)
+               if (mpc52xx_uart_nodes[idx] == op->dev.of_node)
                        break;
        if (idx >= MPC52xx_PSC_MAXNUM)
                return -EINVAL;
        pr_debug("Found %s assigned to ttyPSC%x\n",
                 mpc52xx_uart_nodes[idx]->full_name, idx);
 
-       uartclk = psc_ops->getuartclk(op->node);
+       uartclk = psc_ops->getuartclk(op->dev.of_node);
        if (uartclk == 0) {
                dev_dbg(&op->dev, "Could not find uart clock frequency!\n");
                return -EINVAL;
@@ -1322,7 +1253,7 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
        port->dev       = &op->dev;
 
        /* Search for IRQ and mapbase */
-       ret = of_address_to_resource(op->node, 0, &res);
+       ret = of_address_to_resource(op->dev.of_node, 0, &res);
        if (ret)
                return ret;
 
@@ -1332,7 +1263,7 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
                return -EINVAL;
        }
 
-       psc_ops->get_irq(port, op->node);
+       psc_ops->get_irq(port, op->dev.of_node);
        if (port->irq == NO_IRQ) {
                dev_dbg(&op->dev, "Could not get irq\n");
                return -EINVAL;
@@ -1431,15 +1362,16 @@ mpc52xx_uart_of_enumerate(void)
 MODULE_DEVICE_TABLE(of, mpc52xx_uart_of_match);
 
 static struct of_platform_driver mpc52xx_uart_of_driver = {
-       .match_table    = mpc52xx_uart_of_match,
        .probe          = mpc52xx_uart_of_probe,
        .remove         = mpc52xx_uart_of_remove,
 #ifdef CONFIG_PM
        .suspend        = mpc52xx_uart_of_suspend,
        .resume         = mpc52xx_uart_of_resume,
 #endif
-       .driver         = {
-               .name   = "mpc52xx-psc-uart",
+       .driver = {
+               .name = "mpc52xx-psc-uart",
+               .owner = THIS_MODULE,
+               .of_match_table = mpc52xx_uart_of_match,
        },
 };
 
index e1ab8ec0a4a64f86326494ee14112da85dc2d69b..3c02fa96f2825e119526752e9d8e127082cabdac 100644 (file)
@@ -344,7 +344,7 @@ int nwpserial_register_port(struct uart_port *port)
 
        mutex_lock(&nwpserial_mutex);
 
-       dn = to_of_device(port->dev)->node;
+       dn = to_of_device(port->dev)->dev.of_node;
        if (dn == NULL)
                goto out;
 
index 4abfebdb0fccdb5ca4131c2c9bbe3c3cf0288eee..a48d9080f5525f1c97ac0fff59023f85f19d1b67 100644 (file)
@@ -31,7 +31,7 @@ static int __devinit of_platform_serial_setup(struct of_device *ofdev,
                                        int type, struct uart_port *port)
 {
        struct resource resource;
-       struct device_node *np = ofdev->node;
+       struct device_node *np = ofdev->dev.of_node;
        const unsigned int *clk, *spd;
        const u32 *prop;
        int ret, prop_size;
@@ -88,7 +88,7 @@ static int __devinit of_platform_serial_probe(struct of_device *ofdev,
        int port_type;
        int ret;
 
-       if (of_find_property(ofdev->node, "used-by-rtas", NULL))
+       if (of_find_property(ofdev->dev.of_node, "used-by-rtas", NULL))
                return -EBUSY;
 
        info = kmalloc(sizeof(*info), GFP_KERNEL);
@@ -175,11 +175,13 @@ static struct of_device_id __devinitdata of_platform_serial_table[] = {
 };
 
 static struct of_platform_driver of_platform_serial_driver = {
-       .owner = THIS_MODULE,
-       .name = "of_serial",
+       .driver = {
+               .name = "of_serial",
+               .owner = THIS_MODULE,
+               .of_match_table = of_platform_serial_table,
+       },
        .probe = of_platform_serial_probe,
        .remove = of_platform_serial_remove,
-       .match_table = of_platform_serial_table,
 };
 
 static int __init of_platform_serial_init(void)
index 700e10833bf98965280491ba49771b1ad7c3d618..cabbdc7ba5838bf62e1fa799a6ed2678eb650864 100644 (file)
@@ -1611,7 +1611,7 @@ static int pmz_attach(struct macio_dev *mdev, const struct of_device_id *match)
        /* Iterate the pmz_ports array to find a matching entry
         */
        for (i = 0; i < MAX_ZS_PORTS; i++)
-               if (pmz_ports[i].node == mdev->ofdev.node) {
+               if (pmz_ports[i].node == mdev->ofdev.dev.of_node) {
                        struct uart_pmac_port *uap = &pmz_ports[i];
 
                        uap->dev = mdev;
index 8dc03837617b7bc0fd271ce5f103e63a65d8c5fc..4a789e5361a4e7fafe0e5b21522eb3deaf157df4 100644 (file)
@@ -119,7 +119,7 @@ static int s5p_serial_probe(struct platform_device *pdev)
        return s3c24xx_serial_probe(pdev, s5p_uart_inf[pdev->id]);
 }
 
-static struct platform_driver s5p_serial_drv = {
+static struct platform_driver s5p_serial_driver = {
        .probe          = s5p_serial_probe,
        .remove         = __devexit_p(s3c24xx_serial_remove),
        .driver         = {
@@ -130,19 +130,19 @@ static struct platform_driver s5p_serial_drv = {
 
 static int __init s5pv210_serial_console_init(void)
 {
-       return s3c24xx_serial_initconsole(&s5p_serial_drv, s5p_uart_inf);
+       return s3c24xx_serial_initconsole(&s5p_serial_driver, s5p_uart_inf);
 }
 
 console_initcall(s5pv210_serial_console_init);
 
 static int __init s5p_serial_init(void)
 {
-       return s3c24xx_serial_init(&s5p_serial_drv, *s5p_uart_inf);
+       return s3c24xx_serial_init(&s5p_serial_driver, *s5p_uart_inf);
 }
 
 static void __exit s5p_serial_exit(void)
 {
-       platform_driver_unregister(&s5p_serial_drv);
+       platform_driver_unregister(&s5p_serial_driver);
 }
 
 module_init(s5p_serial_init);
index 4f73fb756745cc19a2ddce3f62302369579aa1df..5f90fcd7d107573312bbd44ab7be8839ab61b567 100644 (file)
@@ -1004,8 +1004,9 @@ static void sci_rx_dma_release(struct sci_port *s, bool enable_pio)
        s->chan_rx = NULL;
        s->cookie_rx[0] = s->cookie_rx[1] = -EINVAL;
        dma_release_channel(chan);
-       dma_free_coherent(port->dev, s->buf_len_rx * 2,
-                         sg_virt(&s->sg_rx[0]), sg_dma_address(&s->sg_rx[0]));
+       if (sg_dma_address(&s->sg_rx[0]))
+               dma_free_coherent(port->dev, s->buf_len_rx * 2,
+                                 sg_virt(&s->sg_rx[0]), sg_dma_address(&s->sg_rx[0]));
        if (enable_pio)
                sci_start_rx(port);
 }
index d14cca7fb88d2510f6c8fb2232160eff83c3efa4..890f91742962433e8b710d060ede982070e09391 100644 (file)
@@ -565,7 +565,7 @@ static int __devinit hv_probe(struct of_device *op, const struct of_device_id *m
        if (err)
                goto out_free_con_read_page;
 
-       sunserial_console_match(&sunhv_console, op->node,
+       sunserial_console_match(&sunhv_console, op->dev.of_node,
                                &sunhv_reg, port->line, false);
 
        err = uart_add_one_port(&sunhv_reg, port);
@@ -630,8 +630,11 @@ static const struct of_device_id hv_match[] = {
 MODULE_DEVICE_TABLE(of, hv_match);
 
 static struct of_platform_driver hv_driver = {
-       .name           = "hv",
-       .match_table    = hv_match,
+       .driver = {
+               .name = "hv",
+               .owner = THIS_MODULE,
+               .of_match_table = hv_match,
+       },
        .probe          = hv_probe,
        .remove         = __devexit_p(hv_remove),
 };
index d2e0321049e2e1e3952244f35300da0bc887aff2..5e81bc6b48b0738ad307b9be94149da299f6063f 100644 (file)
@@ -883,7 +883,7 @@ static int sunsab_console_setup(struct console *con, char *options)
        printk("Console: ttyS%d (SAB82532)\n",
               (sunsab_reg.minor - 64) + con->index);
 
-       sunserial_console_termios(con, to_of_device(up->port.dev)->node);
+       sunserial_console_termios(con, to_of_device(up->port.dev)->dev.of_node);
 
        switch (con->cflag & CBAUD) {
        case B150: baud = 150; break;
@@ -1026,11 +1026,11 @@ static int __devinit sab_probe(struct of_device *op, const struct of_device_id *
        if (err)
                goto out1;
 
-       sunserial_console_match(SUNSAB_CONSOLE(), op->node,
+       sunserial_console_match(SUNSAB_CONSOLE(), op->dev.of_node,
                                &sunsab_reg, up[0].port.line,
                                false);
 
-       sunserial_console_match(SUNSAB_CONSOLE(), op->node,
+       sunserial_console_match(SUNSAB_CONSOLE(), op->dev.of_node,
                                &sunsab_reg, up[1].port.line,
                                false);
 
@@ -1093,8 +1093,11 @@ static const struct of_device_id sab_match[] = {
 MODULE_DEVICE_TABLE(of, sab_match);
 
 static struct of_platform_driver sab_driver = {
-       .name           = "sab",
-       .match_table    = sab_match,
+       .driver = {
+               .name = "sab",
+               .owner = THIS_MODULE,
+               .of_match_table = sab_match,
+       },
        .probe          = sab_probe,
        .remove         = __devexit_p(sab_remove),
 };
index 01f7731e59b89feed0745b89d5ab4282699b2164..234459c2f0122fc24e78f5b173f3fe4a3f83555d 100644 (file)
@@ -1200,7 +1200,7 @@ static int __devinit sunsu_kbd_ms_init(struct uart_sunsu_port *up)
                return -ENODEV;
 
        printk("%s: %s port at %llx, irq %u\n",
-              to_of_device(up->port.dev)->node->full_name,
+              to_of_device(up->port.dev)->dev.of_node->full_name,
               (up->su_type == SU_PORT_KBD) ? "Keyboard" : "Mouse",
               (unsigned long long) up->port.mapbase,
               up->port.irq);
@@ -1352,7 +1352,7 @@ static int __init sunsu_console_setup(struct console *co, char *options)
        spin_lock_init(&port->lock);
 
        /* Get firmware console settings.  */
-       sunserial_console_termios(co, to_of_device(port->dev)->node);
+       sunserial_console_termios(co, to_of_device(port->dev)->dev.of_node);
 
        memset(&termios, 0, sizeof(struct ktermios));
        termios.c_cflag = co->cflag;
@@ -1409,7 +1409,7 @@ static enum su_type __devinit su_get_type(struct device_node *dp)
 static int __devinit su_probe(struct of_device *op, const struct of_device_id *match)
 {
        static int inst;
-       struct device_node *dp = op->node;
+       struct device_node *dp = op->dev.of_node;
        struct uart_sunsu_port *up;
        struct resource *rp;
        enum su_type type;
@@ -1539,8 +1539,11 @@ static const struct of_device_id su_match[] = {
 MODULE_DEVICE_TABLE(of, su_match);
 
 static struct of_platform_driver su_driver = {
-       .name           = "su",
-       .match_table    = su_match,
+       .driver = {
+               .name = "su",
+               .owner = THIS_MODULE,
+               .of_match_table = su_match,
+       },
        .probe          = su_probe,
        .remove         = __devexit_p(su_remove),
 };
index 978b3cee02d72f0f1430b952f71b4c25f4499473..f9a24f4ebb3479626073c23ffa906320dcf025a5 100644 (file)
@@ -1230,7 +1230,7 @@ static int __init sunzilog_console_setup(struct console *con, char *options)
               (sunzilog_reg.minor - 64) + con->index, con->index);
 
        /* Get firmware console settings.  */
-       sunserial_console_termios(con, to_of_device(up->port.dev)->node);
+       sunserial_console_termios(con, to_of_device(up->port.dev)->dev.of_node);
 
        /* Firmware console speed is limited to 150-->38400 baud so
         * this hackish cflag thing is OK.
@@ -1408,7 +1408,7 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m
        int keyboard_mouse = 0;
        int err;
 
-       if (of_find_property(op->node, "keyboard", NULL))
+       if (of_find_property(op->dev.of_node, "keyboard", NULL))
                keyboard_mouse = 1;
 
        /* uarts must come before keyboards/mice */
@@ -1465,7 +1465,7 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m
        sunzilog_init_hw(&up[1]);
 
        if (!keyboard_mouse) {
-               if (sunserial_console_match(SUNZILOG_CONSOLE(), op->node,
+               if (sunserial_console_match(SUNZILOG_CONSOLE(), op->dev.of_node,
                                            &sunzilog_reg, up[0].port.line,
                                            false))
                        up->flags |= SUNZILOG_FLAG_IS_CONS;
@@ -1475,7 +1475,7 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m
                                   rp, sizeof(struct zilog_layout));
                        return err;
                }
-               if (sunserial_console_match(SUNZILOG_CONSOLE(), op->node,
+               if (sunserial_console_match(SUNZILOG_CONSOLE(), op->dev.of_node,
                                            &sunzilog_reg, up[1].port.line,
                                            false))
                        up->flags |= SUNZILOG_FLAG_IS_CONS;
@@ -1541,8 +1541,11 @@ static const struct of_device_id zs_match[] = {
 MODULE_DEVICE_TABLE(of, zs_match);
 
 static struct of_platform_driver zs_driver = {
-       .name           = "zs",
-       .match_table    = zs_match,
+       .driver = {
+               .name = "zs",
+               .owner = THIS_MODULE,
+               .of_match_table = zs_match,
+       },
        .probe          = zs_probe,
        .remove         = __devexit_p(zs_remove),
 };
index e6639a95d2768563ffc87846db8e3232933a95e1..8acccd564378aaa405f2fb04cf1958b532499993 100644 (file)
@@ -591,15 +591,15 @@ ulite_of_probe(struct of_device *op, const struct of_device_id *match)
 
        dev_dbg(&op->dev, "%s(%p, %p)\n", __func__, op, match);
 
-       rc = of_address_to_resource(op->node, 0, &res);
+       rc = of_address_to_resource(op->dev.of_node, 0, &res);
        if (rc) {
                dev_err(&op->dev, "invalid address\n");
                return rc;
        }
 
-       irq = irq_of_parse_and_map(op->node, 0);
+       irq = irq_of_parse_and_map(op->dev.of_node, 0);
 
-       id = of_get_property(op->node, "port-number", NULL);
+       id = of_get_property(op->dev.of_node, "port-number", NULL);
 
        return ulite_assign(&op->dev, id ? *id : -1, res.start, irq);
 }
@@ -610,13 +610,12 @@ static int __devexit ulite_of_remove(struct of_device *op)
 }
 
 static struct of_platform_driver ulite_of_driver = {
-       .owner = THIS_MODULE,
-       .name = "uartlite",
-       .match_table = ulite_of_match,
        .probe = ulite_of_probe,
        .remove = __devexit_p(ulite_of_remove),
        .driver = {
                .name = "uartlite",
+               .owner = THIS_MODULE,
+               .of_match_table = ulite_of_match,
        },
 };
 
index 074904912f642caa23a89af5a8b7e838501e9fd5..907b06f5c447cabb94e4a723e8c58fad37a2ebd5 100644 (file)
@@ -1197,7 +1197,7 @@ static void uart_firmware_cont(const struct firmware *fw, void *context)
 static int ucc_uart_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;
        const unsigned int *iprop;      /* Integer OF properties */
        const char *sprop;      /* String OF properties */
        struct uart_qe_port *qe_port = NULL;
@@ -1486,9 +1486,11 @@ static struct of_device_id ucc_uart_match[] = {
 MODULE_DEVICE_TABLE(of, ucc_uart_match);
 
 static struct of_platform_driver ucc_uart_of_driver = {
-       .owner          = THIS_MODULE,
-       .name           = "ucc_uart",
-       .match_table    = ucc_uart_match,
+       .driver = {
+               .name = "ucc_uart",
+               .owner = THIS_MODULE,
+               .of_match_table    = ucc_uart_match,
+       },
        .probe          = ucc_uart_probe,
        .remove         = ucc_uart_remove,
 };
index 34aba30eb84bec5047f359586b9ea65b62e09c82..f5b4ca581541539f8336aaec73c286de1f0773fb 100644 (file)
@@ -173,3 +173,44 @@ int sfi_acpi_table_parse(char *signature, char *oem_id, char *oem_table_id,
        sfi_acpi_put_table(table);
        return ret;
 }
+
+static ssize_t sfi_acpi_table_show(struct file *filp, struct kobject *kobj,
+                              struct bin_attribute *bin_attr, char *buf,
+                              loff_t offset, size_t count)
+{
+       struct sfi_table_attr *tbl_attr =
+           container_of(bin_attr, struct sfi_table_attr, attr);
+       struct acpi_table_header *th = NULL;
+       struct sfi_table_key key;
+       ssize_t cnt;
+
+       key.sig = tbl_attr->name;
+       key.oem_id = NULL;
+       key.oem_table_id = NULL;
+
+       th = sfi_acpi_get_table(&key);
+       if (!th)
+               return 0;
+
+       cnt =  memory_read_from_buffer(buf, count, &offset,
+                                       th, th->length);
+       sfi_acpi_put_table(th);
+
+       return cnt;
+}
+
+
+void __init sfi_acpi_sysfs_init(void)
+{
+       u32 tbl_cnt, i;
+       struct sfi_table_attr *tbl_attr;
+
+       tbl_cnt = XSDT_GET_NUM_ENTRIES(xsdt_va, u64);
+       for (i = 0; i < tbl_cnt; i++) {
+               tbl_attr =
+                       sfi_sysfs_install_table(xsdt_va->table_offset_entry[i]);
+               tbl_attr->attr.read = sfi_acpi_table_show;
+       }
+
+       return;
+}
index b204a09291393406acd9450ba641d754fd0707ed..005195958647b03acded28a822bfd7374744d210 100644 (file)
@@ -67,6 +67,7 @@
 #include <linux/acpi.h>
 #include <linux/init.h>
 #include <linux/sfi.h>
+#include <linux/slab.h>
 
 #include "sfi_core.h"
 
@@ -382,6 +383,102 @@ static __init int sfi_find_syst(void)
        return -1;
 }
 
+static struct kobject *sfi_kobj;
+static struct kobject *tables_kobj;
+
+static ssize_t sfi_table_show(struct file *filp, struct kobject *kobj,
+                              struct bin_attribute *bin_attr, char *buf,
+                              loff_t offset, size_t count)
+{
+       struct sfi_table_attr *tbl_attr =
+           container_of(bin_attr, struct sfi_table_attr, attr);
+       struct sfi_table_header *th = NULL;
+       struct sfi_table_key key;
+       ssize_t cnt;
+
+       key.sig = tbl_attr->name;
+       key.oem_id = NULL;
+       key.oem_table_id = NULL;
+
+       if (strncmp(SFI_SIG_SYST, tbl_attr->name, SFI_SIGNATURE_SIZE)) {
+               th = sfi_get_table(&key);
+               if (!th)
+                       return 0;
+
+               cnt =  memory_read_from_buffer(buf, count, &offset,
+                                               th, th->len);
+               sfi_put_table(th);
+       } else
+               cnt =  memory_read_from_buffer(buf, count, &offset,
+                                       syst_va, syst_va->header.len);
+
+       return cnt;
+}
+
+struct sfi_table_attr __init *sfi_sysfs_install_table(u64 pa)
+{
+       struct sfi_table_attr *tbl_attr;
+       struct sfi_table_header *th;
+       int ret;
+
+       tbl_attr = kzalloc(sizeof(struct sfi_table_attr), GFP_KERNEL);
+       if (!tbl_attr)
+               return NULL;
+
+       th = sfi_map_table(pa);
+       if (!th || !th->sig[0]) {
+               kfree(tbl_attr);
+               return NULL;
+       }
+
+       sysfs_attr_init(&tbl_attr->attr.attr);
+       memcpy(tbl_attr->name, th->sig, SFI_SIGNATURE_SIZE);
+
+       tbl_attr->attr.size = 0;
+       tbl_attr->attr.read = sfi_table_show;
+       tbl_attr->attr.attr.name = tbl_attr->name;
+       tbl_attr->attr.attr.mode = 0400;
+
+       ret = sysfs_create_bin_file(tables_kobj,
+                                 &tbl_attr->attr);
+       if (ret)
+               kfree(tbl_attr);
+
+       sfi_unmap_table(th);
+       return tbl_attr;
+}
+
+static int __init sfi_sysfs_init(void)
+{
+       int tbl_cnt, i;
+
+       if (sfi_disabled)
+               return 0;
+
+       sfi_kobj = kobject_create_and_add("sfi", firmware_kobj);
+       if (!sfi_kobj)
+               return 0;
+
+       tables_kobj = kobject_create_and_add("tables", sfi_kobj);
+       if (!tables_kobj) {
+               kobject_put(sfi_kobj);
+               return 0;
+       }
+
+       sfi_sysfs_install_table(syst_pa);
+
+       tbl_cnt = SFI_GET_NUM_ENTRIES(syst_va, u64);
+
+       for (i = 0; i < tbl_cnt; i++)
+               sfi_sysfs_install_table(syst_va->pentry[i]);
+
+       sfi_acpi_sysfs_init();
+       kobject_uevent(sfi_kobj, KOBJ_ADD);
+       kobject_uevent(tables_kobj, KOBJ_ADD);
+       pr_info("SFI sysfs interfaces init success\n");
+       return 0;
+}
+
 void __init sfi_init(void)
 {
        if (!acpi_disabled)
@@ -390,7 +487,7 @@ void __init sfi_init(void)
        if (sfi_disabled)
                return;
 
-       pr_info("Simple Firmware Interface v0.7 http://simplefirmware.org\n");
+       pr_info("Simple Firmware Interface v0.81 http://simplefirmware.org\n");
 
        if (sfi_find_syst() || sfi_parse_syst() || sfi_platform_init())
                disable_sfi();
@@ -414,3 +511,9 @@ void __init sfi_init_late(void)
 
        sfi_acpi_init();
 }
+
+/*
+ * The reason we put it here becasue we need wait till the /sys/firmware
+ * is setup, then our interface can be registered in /sys/firmware/sfi
+ */
+core_initcall(sfi_sysfs_init);
index da82d39e104dd18350e8f27a28dbe5735d6ceca3..b7cf220d44ec575f31160926433eefc50653dd87 100644 (file)
@@ -61,6 +61,12 @@ struct sfi_table_key{
        char    *oem_table_id;
 };
 
+/* sysfs interface */
+struct sfi_table_attr {
+       struct bin_attribute attr;
+       char name[8];
+};
+
 #define SFI_ANY_KEY { .sig = NULL, .oem_id = NULL, .oem_table_id = NULL }
 
 extern int __init sfi_acpi_init(void);
@@ -68,3 +74,5 @@ extern  struct sfi_table_header *sfi_check_table(u64 paddr,
                                        struct sfi_table_key *key);
 struct sfi_table_header *sfi_get_table(struct sfi_table_key *key);
 extern void sfi_put_table(struct sfi_table_header *table);
+extern struct sfi_table_attr __init *sfi_sysfs_install_table(u64 pa);
+extern void __init sfi_acpi_sysfs_init(void);
index f950b63169492765d9d955c1bd87bfbb93b368ff..91c2f4f3af10ecfc33a6a101a19b0f1762c79aea 100644 (file)
@@ -117,6 +117,16 @@ config SPI_DAVINCI
        help
          SPI master controller for DaVinci and DA8xx SPI modules.
 
+config SPI_EP93XX
+       tristate "Cirrus Logic EP93xx SPI controller"
+       depends on ARCH_EP93XX
+       help
+         This enables using the Cirrus EP93xx SPI controller in master
+         mode.
+
+         To compile this driver as a module, choose M here. The module will be
+         called ep93xx_spi.
+
 config SPI_GPIO
        tristate "GPIO-based bitbanging SPI Master"
        depends on GENERIC_GPIO
@@ -165,6 +175,13 @@ config SPI_MPC52xx_PSC
          This enables using the Freescale MPC52xx Programmable Serial
          Controller in master SPI mode.
 
+config SPI_MPC512x_PSC
+       tristate "Freescale MPC512x PSC SPI controller"
+       depends on SPI_MASTER && PPC_MPC512x
+       help
+         This enables using the Freescale MPC5121 Programmable Serial
+         Controller in SPI master mode.
+
 config SPI_MPC8xxx
        tristate "Freescale MPC8xxx SPI controller"
        depends on FSL_SOC
index d7d0f89b797bbcf180475215cc64bc44d5c97400..e9cbd18217a0559248698075141b6dd3f9d1277f 100644 (file)
@@ -21,6 +21,7 @@ obj-$(CONFIG_SPI_DAVINCI)             += davinci_spi.o
 obj-$(CONFIG_SPI_DESIGNWARE)           += dw_spi.o
 obj-$(CONFIG_SPI_DW_PCI)               += dw_spi_pci.o
 obj-$(CONFIG_SPI_DW_MMIO)              += dw_spi_mmio.o
+obj-$(CONFIG_SPI_EP93XX)               += ep93xx_spi.o
 obj-$(CONFIG_SPI_GPIO)                 += spi_gpio.o
 obj-$(CONFIG_SPI_IMX)                  += spi_imx.o
 obj-$(CONFIG_SPI_LM70_LLP)             += spi_lm70llp.o
@@ -30,6 +31,7 @@ obj-$(CONFIG_SPI_OMAP24XX)            += omap2_mcspi.o
 obj-$(CONFIG_SPI_OMAP_100K)            += omap_spi_100k.o
 obj-$(CONFIG_SPI_ORION)                        += orion_spi.o
 obj-$(CONFIG_SPI_PL022)                        += amba-pl022.o
+obj-$(CONFIG_SPI_MPC512x_PSC)          += mpc512x_psc_spi.o
 obj-$(CONFIG_SPI_MPC52xx_PSC)          += mpc52xx_psc_spi.o
 obj-$(CONFIG_SPI_MPC52xx)              += mpc52xx_spi.o
 obj-$(CONFIG_SPI_MPC8xxx)              += spi_mpc8xxx.o
index e9aeee16d922aba598f731e3cbd61b48e6d5b63c..f0a1418ce66078bcb58b5485de978f3dbdb2a49b 100644 (file)
 /*
  * SSP Control Register 0  - SSP_CR0
  */
-#define SSP_CR0_MASK_DSS       (0x1FUL << 0)
-#define SSP_CR0_MASK_HALFDUP   (0x1UL << 5)
+#define SSP_CR0_MASK_DSS       (0x0FUL << 0)
+#define SSP_CR0_MASK_FRF       (0x3UL << 4)
 #define SSP_CR0_MASK_SPO       (0x1UL << 6)
 #define SSP_CR0_MASK_SPH       (0x1UL << 7)
 #define SSP_CR0_MASK_SCR       (0xFFUL << 8)
-#define SSP_CR0_MASK_CSS       (0x1FUL << 16)
-#define SSP_CR0_MASK_FRF       (0x3UL << 21)
+
+/*
+ * The ST version of this block moves som bits
+ * in SSP_CR0 and extends it to 32 bits
+ */
+#define SSP_CR0_MASK_DSS_ST    (0x1FUL << 0)
+#define SSP_CR0_MASK_HALFDUP_ST        (0x1UL << 5)
+#define SSP_CR0_MASK_CSS_ST    (0x1FUL << 16)
+#define SSP_CR0_MASK_FRF_ST    (0x3UL << 21)
+
 
 /*
  * SSP Control Register 0  - SSP_CR1
 #define SSP_CR1_MASK_SSE       (0x1UL << 1)
 #define SSP_CR1_MASK_MS                (0x1UL << 2)
 #define SSP_CR1_MASK_SOD       (0x1UL << 3)
-#define SSP_CR1_MASK_RENDN     (0x1UL << 4)
-#define SSP_CR1_MASK_TENDN     (0x1UL << 5)
-#define SSP_CR1_MASK_MWAIT     (0x1UL << 6)
-#define SSP_CR1_MASK_RXIFLSEL  (0x7UL << 7)
-#define SSP_CR1_MASK_TXIFLSEL  (0x7UL << 10)
 
 /*
- * SSP Data Register - SSP_DR
+ * The ST version of this block adds some bits
+ * in SSP_CR1
  */
-#define SSP_DR_MASK_DATA       0xFFFFFFFF
+#define SSP_CR1_MASK_RENDN_ST  (0x1UL << 4)
+#define SSP_CR1_MASK_TENDN_ST  (0x1UL << 5)
+#define SSP_CR1_MASK_MWAIT_ST  (0x1UL << 6)
+#define SSP_CR1_MASK_RXIFLSEL_ST (0x7UL << 7)
+#define SSP_CR1_MASK_TXIFLSEL_ST (0x7UL << 10)
+/* This one is only in the PL023 variant */
+#define SSP_CR1_MASK_FBCLKDEL_ST (0x7UL << 13)
 
 /*
  * SSP Status Register - SSP_SR
 #define SSP_SR_MASK_TFE                (0x1UL << 0) /* Transmit FIFO empty */
 #define SSP_SR_MASK_TNF                (0x1UL << 1) /* Transmit FIFO not full */
 #define SSP_SR_MASK_RNE                (0x1UL << 2) /* Receive FIFO not empty */
-#define SSP_SR_MASK_RFF        (0x1UL << 3) /* Receive FIFO full */
+#define SSP_SR_MASK_RFF                (0x1UL << 3) /* Receive FIFO full */
 #define SSP_SR_MASK_BSY                (0x1UL << 4) /* Busy Flag */
 
 /*
 /*
  * SSP Test Data Register - SSP_TDR
  */
-#define TDR_MASK_TESTDATA              (0xFFFFFFFF)
+#define TDR_MASK_TESTDATA              (0xFFFFFFFF)
 
 /*
  * Message State
  * hold a single state value, that's why all this
  * (void *) casting is done here.
  */
-#define STATE_START                     ((void *) 0)
-#define STATE_RUNNING                   ((void *) 1)
-#define STATE_DONE                      ((void *) 2)
-#define STATE_ERROR                     ((void *) -1)
+#define STATE_START                    ((void *) 0)
+#define STATE_RUNNING                  ((void *) 1)
+#define STATE_DONE                     ((void *) 2)
+#define STATE_ERROR                    ((void *) -1)
 
 /*
  * Queue State
  */
-#define QUEUE_RUNNING                   (0)
-#define QUEUE_STOPPED                   (1)
+#define QUEUE_RUNNING                  (0)
+#define QUEUE_STOPPED                  (1)
 /*
  * SSP State - Whether Enabled or Disabled
  */
-#define SSP_DISABLED                   (0)
-#define SSP_ENABLED                    (1)
+#define SSP_DISABLED                   (0)
+#define SSP_ENABLED                    (1)
 
 /*
  * SSP DMA State - Whether DMA Enabled or Disabled
  */
-#define SSP_DMA_DISABLED               (0)
-#define SSP_DMA_ENABLED                (1)
+#define SSP_DMA_DISABLED               (0)
+#define SSP_DMA_ENABLED                        (1)
 
 /*
  * SSP Clock Defaults
  */
-#define NMDK_SSP_DEFAULT_CLKRATE 0x2
-#define NMDK_SSP_DEFAULT_PRESCALE 0x40
+#define SSP_DEFAULT_CLKRATE 0x2
+#define SSP_DEFAULT_PRESCALE 0x40
 
 /*
  * SSP Clock Parameter ranges
@@ -307,16 +317,22 @@ enum ssp_writing {
  * @fifodepth: depth of FIFOs (both)
  * @max_bpw: maximum number of bits per word
  * @unidir: supports unidirection transfers
+ * @extended_cr: 32 bit wide control register 0 with extra
+ * features and extra features in CR1 as found in the ST variants
+ * @pl023: supports a subset of the ST extensions called "PL023"
  */
 struct vendor_data {
        int fifodepth;
        int max_bpw;
        bool unidir;
+       bool extended_cr;
+       bool pl023;
 };
 
 /**
  * struct pl022 - This is the private SSP driver data structure
  * @adev: AMBA device model hookup
+ * @vendor: Vendor data for the IP block
  * @phybase: The physical memory where the SSP device resides
  * @virtbase: The virtual memory where the SSP is mapped
  * @master: SPI framework hookup
@@ -369,7 +385,8 @@ struct pl022 {
 
 /**
  * struct chip_data - To maintain runtime state of SSP for each client chip
- * @cr0: Value of control register CR0 of SSP
+ * @cr0: Value of control register CR0 of SSP - on later ST variants this
+ *       register is 32 bits wide rather than just 16
  * @cr1: Value of control register CR1 of SSP
  * @dmacr: Value of DMA control Register of SSP
  * @cpsr: Value of Clock prescale register
@@ -384,7 +401,7 @@ struct pl022 {
  * This would be set according to the current message that would be served
  */
 struct chip_data {
-       u16 cr0;
+       u32 cr0;
        u16 cr1;
        u16 dmacr;
        u16 cpsr;
@@ -517,7 +534,10 @@ static void restore_state(struct pl022 *pl022)
 {
        struct chip_data *chip = pl022->cur_chip;
 
-       writew(chip->cr0, SSP_CR0(pl022->virtbase));
+       if (pl022->vendor->extended_cr)
+               writel(chip->cr0, SSP_CR0(pl022->virtbase));
+       else
+               writew(chip->cr0, SSP_CR0(pl022->virtbase));
        writew(chip->cr1, SSP_CR1(pl022->virtbase));
        writew(chip->dmacr, SSP_DMACR(pl022->virtbase));
        writew(chip->cpsr, SSP_CPSR(pl022->virtbase));
@@ -525,38 +545,70 @@ static void restore_state(struct pl022 *pl022)
        writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase));
 }
 
-/**
- * load_ssp_default_config - Load default configuration for SSP
- * @pl022: SSP driver private data structure
- */
-
 /*
  * Default SSP Register Values
  */
 #define DEFAULT_SSP_REG_CR0 ( \
        GEN_MASK_BITS(SSP_DATA_BITS_12, SSP_CR0_MASK_DSS, 0)    | \
-       GEN_MASK_BITS(SSP_MICROWIRE_CHANNEL_FULL_DUPLEX, SSP_CR0_MASK_HALFDUP, 5) | \
+       GEN_MASK_BITS(SSP_INTERFACE_MOTOROLA_SPI, SSP_CR0_MASK_FRF, 4) | \
        GEN_MASK_BITS(SSP_CLK_POL_IDLE_LOW, SSP_CR0_MASK_SPO, 6) | \
        GEN_MASK_BITS(SSP_CLK_SECOND_EDGE, SSP_CR0_MASK_SPH, 7) | \
-       GEN_MASK_BITS(NMDK_SSP_DEFAULT_CLKRATE, SSP_CR0_MASK_SCR, 8) | \
-       GEN_MASK_BITS(SSP_BITS_8, SSP_CR0_MASK_CSS, 16) | \
-       GEN_MASK_BITS(SSP_INTERFACE_MOTOROLA_SPI, SSP_CR0_MASK_FRF, 21) \
+       GEN_MASK_BITS(SSP_DEFAULT_CLKRATE, SSP_CR0_MASK_SCR, 8) \
+)
+
+/* ST versions have slightly different bit layout */
+#define DEFAULT_SSP_REG_CR0_ST ( \
+       GEN_MASK_BITS(SSP_DATA_BITS_12, SSP_CR0_MASK_DSS_ST, 0) | \
+       GEN_MASK_BITS(SSP_MICROWIRE_CHANNEL_FULL_DUPLEX, SSP_CR0_MASK_HALFDUP_ST, 5) | \
+       GEN_MASK_BITS(SSP_CLK_POL_IDLE_LOW, SSP_CR0_MASK_SPO, 6) | \
+       GEN_MASK_BITS(SSP_CLK_SECOND_EDGE, SSP_CR0_MASK_SPH, 7) | \
+       GEN_MASK_BITS(SSP_DEFAULT_CLKRATE, SSP_CR0_MASK_SCR, 8) | \
+       GEN_MASK_BITS(SSP_BITS_8, SSP_CR0_MASK_CSS_ST, 16)      | \
+       GEN_MASK_BITS(SSP_INTERFACE_MOTOROLA_SPI, SSP_CR0_MASK_FRF_ST, 21) \
+)
+
+/* The PL023 version is slightly different again */
+#define DEFAULT_SSP_REG_CR0_ST_PL023 ( \
+       GEN_MASK_BITS(SSP_DATA_BITS_12, SSP_CR0_MASK_DSS_ST, 0) | \
+       GEN_MASK_BITS(SSP_CLK_POL_IDLE_LOW, SSP_CR0_MASK_SPO, 6) | \
+       GEN_MASK_BITS(SSP_CLK_SECOND_EDGE, SSP_CR0_MASK_SPH, 7) | \
+       GEN_MASK_BITS(SSP_DEFAULT_CLKRATE, SSP_CR0_MASK_SCR, 8) \
 )
 
 #define DEFAULT_SSP_REG_CR1 ( \
        GEN_MASK_BITS(LOOPBACK_DISABLED, SSP_CR1_MASK_LBM, 0) | \
+       GEN_MASK_BITS(SSP_DISABLED, SSP_CR1_MASK_SSE, 1) | \
+       GEN_MASK_BITS(SSP_MASTER, SSP_CR1_MASK_MS, 2) | \
+       GEN_MASK_BITS(DO_NOT_DRIVE_TX, SSP_CR1_MASK_SOD, 3) \
+)
+
+/* ST versions extend this register to use all 16 bits */
+#define DEFAULT_SSP_REG_CR1_ST ( \
+       DEFAULT_SSP_REG_CR1 | \
+       GEN_MASK_BITS(SSP_RX_MSB, SSP_CR1_MASK_RENDN_ST, 4) | \
+       GEN_MASK_BITS(SSP_TX_MSB, SSP_CR1_MASK_TENDN_ST, 5) | \
+       GEN_MASK_BITS(SSP_MWIRE_WAIT_ZERO, SSP_CR1_MASK_MWAIT_ST, 6) |\
+       GEN_MASK_BITS(SSP_RX_1_OR_MORE_ELEM, SSP_CR1_MASK_RXIFLSEL_ST, 7) | \
+       GEN_MASK_BITS(SSP_TX_1_OR_MORE_EMPTY_LOC, SSP_CR1_MASK_TXIFLSEL_ST, 10) \
+)
+
+/*
+ * The PL023 variant has further differences: no loopback mode, no microwire
+ * support, and a new clock feedback delay setting.
+ */
+#define DEFAULT_SSP_REG_CR1_ST_PL023 ( \
        GEN_MASK_BITS(SSP_DISABLED, SSP_CR1_MASK_SSE, 1) | \
        GEN_MASK_BITS(SSP_MASTER, SSP_CR1_MASK_MS, 2) | \
        GEN_MASK_BITS(DO_NOT_DRIVE_TX, SSP_CR1_MASK_SOD, 3) | \
-       GEN_MASK_BITS(SSP_RX_MSB, SSP_CR1_MASK_RENDN, 4) | \
-       GEN_MASK_BITS(SSP_TX_MSB, SSP_CR1_MASK_TENDN, 5) | \
-       GEN_MASK_BITS(SSP_MWIRE_WAIT_ZERO, SSP_CR1_MASK_MWAIT, 6) |\
-       GEN_MASK_BITS(SSP_RX_1_OR_MORE_ELEM, SSP_CR1_MASK_RXIFLSEL, 7) | \
-       GEN_MASK_BITS(SSP_TX_1_OR_MORE_EMPTY_LOC, SSP_CR1_MASK_TXIFLSEL, 10) \
+       GEN_MASK_BITS(SSP_RX_MSB, SSP_CR1_MASK_RENDN_ST, 4) | \
+       GEN_MASK_BITS(SSP_TX_MSB, SSP_CR1_MASK_TENDN_ST, 5) | \
+       GEN_MASK_BITS(SSP_RX_1_OR_MORE_ELEM, SSP_CR1_MASK_RXIFLSEL_ST, 7) | \
+       GEN_MASK_BITS(SSP_TX_1_OR_MORE_EMPTY_LOC, SSP_CR1_MASK_TXIFLSEL_ST, 10) | \
+       GEN_MASK_BITS(SSP_FEEDBACK_CLK_DELAY_NONE, SSP_CR1_MASK_FBCLKDEL_ST, 13) \
 )
 
 #define DEFAULT_SSP_REG_CPSR ( \
-       GEN_MASK_BITS(NMDK_SSP_DEFAULT_PRESCALE, SSP_CPSR_MASK_CPSDVSR, 0) \
+       GEN_MASK_BITS(SSP_DEFAULT_PRESCALE, SSP_CPSR_MASK_CPSDVSR, 0) \
 )
 
 #define DEFAULT_SSP_REG_DMACR (\
@@ -564,11 +616,22 @@ static void restore_state(struct pl022 *pl022)
        GEN_MASK_BITS(SSP_DMA_DISABLED, SSP_DMACR_MASK_TXDMAE, 1) \
 )
 
-
+/**
+ * load_ssp_default_config - Load default configuration for SSP
+ * @pl022: SSP driver private data structure
+ */
 static void load_ssp_default_config(struct pl022 *pl022)
 {
-       writew(DEFAULT_SSP_REG_CR0, SSP_CR0(pl022->virtbase));
-       writew(DEFAULT_SSP_REG_CR1, SSP_CR1(pl022->virtbase));
+       if (pl022->vendor->pl023) {
+               writel(DEFAULT_SSP_REG_CR0_ST_PL023, SSP_CR0(pl022->virtbase));
+               writew(DEFAULT_SSP_REG_CR1_ST_PL023, SSP_CR1(pl022->virtbase));
+       } else if (pl022->vendor->extended_cr) {
+               writel(DEFAULT_SSP_REG_CR0_ST, SSP_CR0(pl022->virtbase));
+               writew(DEFAULT_SSP_REG_CR1_ST, SSP_CR1(pl022->virtbase));
+       } else {
+               writew(DEFAULT_SSP_REG_CR0, SSP_CR0(pl022->virtbase));
+               writew(DEFAULT_SSP_REG_CR1, SSP_CR1(pl022->virtbase));
+       }
        writew(DEFAULT_SSP_REG_DMACR, SSP_DMACR(pl022->virtbase));
        writew(DEFAULT_SSP_REG_CPSR, SSP_CPSR(pl022->virtbase));
        writew(DISABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase));
@@ -1008,7 +1071,7 @@ static void do_polling_transfer(void *data)
                writew((readw(SSP_CR1(pl022->virtbase)) | SSP_CR1_MASK_SSE),
                       SSP_CR1(pl022->virtbase));
 
-               dev_dbg(&pl022->adev->dev, "POLLING TRANSFER ONGOING ... \n");
+               dev_dbg(&pl022->adev->dev, "polling transfer ongoing ...\n");
                /* FIXME: insert a timeout so we don't hang here indefinately */
                while (pl022->tx < pl022->tx_end || pl022->rx < pl022->rx_end)
                        readwriter(pl022);
@@ -1148,7 +1211,6 @@ static int stop_queue(struct pl022 *pl022)
         * A wait_queue on the pl022->busy could be used, but then the common
         * execution path (pump_messages) would be required to call wake_up or
         * friends on every SPI message. Do this instead */
-       pl022->run = QUEUE_STOPPED;
        while (!list_empty(&pl022->queue) && pl022->busy && limit--) {
                spin_unlock_irqrestore(&pl022->queue_lock, flags);
                msleep(10);
@@ -1157,6 +1219,7 @@ static int stop_queue(struct pl022 *pl022)
 
        if (!list_empty(&pl022->queue) || pl022->busy)
                status = -EBUSY;
+       else pl022->run = QUEUE_STOPPED;
 
        spin_unlock_irqrestore(&pl022->queue_lock, flags);
 
@@ -1280,11 +1343,21 @@ static int verify_controller_parameters(struct pl022 *pl022,
                                "Wait State is configured incorrectly\n");
                        return -EINVAL;
                }
-               if ((chip_info->duplex != SSP_MICROWIRE_CHANNEL_FULL_DUPLEX)
-                   && (chip_info->duplex !=
-                       SSP_MICROWIRE_CHANNEL_HALF_DUPLEX)) {
-                       dev_err(chip_info->dev,
-                               "DUPLEX is configured incorrectly\n");
+               /* Half duplex is only available in the ST Micro version */
+               if (pl022->vendor->extended_cr) {
+                       if ((chip_info->duplex !=
+                            SSP_MICROWIRE_CHANNEL_FULL_DUPLEX)
+                           && (chip_info->duplex !=
+                               SSP_MICROWIRE_CHANNEL_HALF_DUPLEX))
+                               dev_err(chip_info->dev,
+                                       "Microwire duplex mode is configured incorrectly\n");
+                               return -EINVAL;
+               } else {
+                       if (chip_info->duplex != SSP_MICROWIRE_CHANNEL_FULL_DUPLEX)
+                               dev_err(chip_info->dev,
+                                       "Microwire half duplex mode requested,"
+                                       " but this is only available in the"
+                                       " ST version of PL022\n");
                        return -EINVAL;
                }
        }
@@ -1581,22 +1654,49 @@ static int pl022_setup(struct spi_device *spi)
 
        chip->cpsr = chip_info->clk_freq.cpsdvsr;
 
-       SSP_WRITE_BITS(chip->cr0, chip_info->data_size, SSP_CR0_MASK_DSS, 0);
-       SSP_WRITE_BITS(chip->cr0, chip_info->duplex, SSP_CR0_MASK_HALFDUP, 5);
+       /* Special setup for the ST micro extended control registers */
+       if (pl022->vendor->extended_cr) {
+               if (pl022->vendor->pl023) {
+                       /* These bits are only in the PL023 */
+                       SSP_WRITE_BITS(chip->cr1, chip_info->clkdelay,
+                                      SSP_CR1_MASK_FBCLKDEL_ST, 13);
+               } else {
+                       /* These bits are in the PL022 but not PL023 */
+                       SSP_WRITE_BITS(chip->cr0, chip_info->duplex,
+                                      SSP_CR0_MASK_HALFDUP_ST, 5);
+                       SSP_WRITE_BITS(chip->cr0, chip_info->ctrl_len,
+                                      SSP_CR0_MASK_CSS_ST, 16);
+                       SSP_WRITE_BITS(chip->cr0, chip_info->iface,
+                                      SSP_CR0_MASK_FRF_ST, 21);
+                       SSP_WRITE_BITS(chip->cr1, chip_info->wait_state,
+                                      SSP_CR1_MASK_MWAIT_ST, 6);
+               }
+               SSP_WRITE_BITS(chip->cr0, chip_info->data_size,
+                              SSP_CR0_MASK_DSS_ST, 0);
+               SSP_WRITE_BITS(chip->cr1, chip_info->endian_rx,
+                              SSP_CR1_MASK_RENDN_ST, 4);
+               SSP_WRITE_BITS(chip->cr1, chip_info->endian_tx,
+                              SSP_CR1_MASK_TENDN_ST, 5);
+               SSP_WRITE_BITS(chip->cr1, chip_info->rx_lev_trig,
+                              SSP_CR1_MASK_RXIFLSEL_ST, 7);
+               SSP_WRITE_BITS(chip->cr1, chip_info->tx_lev_trig,
+                              SSP_CR1_MASK_TXIFLSEL_ST, 10);
+       } else {
+               SSP_WRITE_BITS(chip->cr0, chip_info->data_size,
+                              SSP_CR0_MASK_DSS, 0);
+               SSP_WRITE_BITS(chip->cr0, chip_info->iface,
+                              SSP_CR0_MASK_FRF, 4);
+       }
+       /* Stuff that is common for all versions */
        SSP_WRITE_BITS(chip->cr0, chip_info->clk_pol, SSP_CR0_MASK_SPO, 6);
        SSP_WRITE_BITS(chip->cr0, chip_info->clk_phase, SSP_CR0_MASK_SPH, 7);
        SSP_WRITE_BITS(chip->cr0, chip_info->clk_freq.scr, SSP_CR0_MASK_SCR, 8);
-       SSP_WRITE_BITS(chip->cr0, chip_info->ctrl_len, SSP_CR0_MASK_CSS, 16);
-       SSP_WRITE_BITS(chip->cr0, chip_info->iface, SSP_CR0_MASK_FRF, 21);
-       SSP_WRITE_BITS(chip->cr1, chip_info->lbm, SSP_CR1_MASK_LBM, 0);
+       /* Loopback is available on all versions except PL023 */
+       if (!pl022->vendor->pl023)
+               SSP_WRITE_BITS(chip->cr1, chip_info->lbm, SSP_CR1_MASK_LBM, 0);
        SSP_WRITE_BITS(chip->cr1, SSP_DISABLED, SSP_CR1_MASK_SSE, 1);
        SSP_WRITE_BITS(chip->cr1, chip_info->hierarchy, SSP_CR1_MASK_MS, 2);
        SSP_WRITE_BITS(chip->cr1, chip_info->slave_tx_disable, SSP_CR1_MASK_SOD, 3);
-       SSP_WRITE_BITS(chip->cr1, chip_info->endian_rx, SSP_CR1_MASK_RENDN, 4);
-       SSP_WRITE_BITS(chip->cr1, chip_info->endian_tx, SSP_CR1_MASK_TENDN, 5);
-       SSP_WRITE_BITS(chip->cr1, chip_info->wait_state, SSP_CR1_MASK_MWAIT, 6);
-       SSP_WRITE_BITS(chip->cr1, chip_info->rx_lev_trig, SSP_CR1_MASK_RXIFLSEL, 7);
-       SSP_WRITE_BITS(chip->cr1, chip_info->tx_lev_trig, SSP_CR1_MASK_TXIFLSEL, 10);
 
        /* Save controller_state */
        spi_set_ctldata(spi, chip);
@@ -1809,6 +1909,8 @@ static struct vendor_data vendor_arm = {
        .fifodepth = 8,
        .max_bpw = 16,
        .unidir = false,
+       .extended_cr = false,
+       .pl023 = false,
 };
 
 
@@ -1816,6 +1918,16 @@ static struct vendor_data vendor_st = {
        .fifodepth = 32,
        .max_bpw = 32,
        .unidir = false,
+       .extended_cr = true,
+       .pl023 = false,
+};
+
+static struct vendor_data vendor_st_pl023 = {
+       .fifodepth = 32,
+       .max_bpw = 32,
+       .unidir = false,
+       .extended_cr = true,
+       .pl023 = true,
 };
 
 static struct amba_id pl022_ids[] = {
@@ -1837,6 +1949,18 @@ static struct amba_id pl022_ids[] = {
                .mask   = 0xffffffff,
                .data   = &vendor_st,
        },
+       {
+               /*
+                * ST-Ericsson derivative "PL023" (this is not
+                * an official ARM number), this is a PL022 SSP block
+                * stripped to SPI mode only, it has 32bit wide
+                * and 32 locations deep TX/RX FIFO but no extended
+                * CR0/CR1 register
+                */
+               .id     = 0x00080023,
+               .mask   = 0xffffffff,
+               .data   = &vendor_st_pl023,
+       },
        { 0, 0 },
 };
 
index 95afb6b77395f3c60b4c8a18bafe2b4146369229..b85090caf7cf57df0a596f131944a13d64588d70 100644 (file)
@@ -301,7 +301,7 @@ static int davinci_spi_setup_transfer(struct spi_device *spi,
        struct davinci_spi *davinci_spi;
        struct davinci_spi_platform_data *pdata;
        u8 bits_per_word = 0;
-       u32 hz = 0, prescale;
+       u32 hz = 0, prescale = 0, clkspeed;
 
        davinci_spi = spi_master_get_devdata(spi->master);
        pdata = davinci_spi->pdata;
@@ -338,10 +338,16 @@ static int davinci_spi_setup_transfer(struct spi_device *spi,
        set_fmt_bits(davinci_spi->base, bits_per_word & 0x1f,
                        spi->chip_select);
 
-       prescale = ((clk_get_rate(davinci_spi->clk) / hz) - 1) & 0xff;
+       clkspeed = clk_get_rate(davinci_spi->clk);
+       if (hz > clkspeed / 2)
+               prescale = 1 << 8;
+       if (hz < clkspeed / 256)
+               prescale = 255 << 8;
+       if (!prescale)
+               prescale = ((clkspeed / hz - 1) << 8) & 0x0000ff00;
 
        clear_fmt_bits(davinci_spi->base, 0x0000ff00, spi->chip_select);
-       set_fmt_bits(davinci_spi->base, prescale << 8, spi->chip_select);
+       set_fmt_bits(davinci_spi->base, prescale, spi->chip_select);
 
        return 0;
 }
diff --git a/drivers/spi/ep93xx_spi.c b/drivers/spi/ep93xx_spi.c
new file mode 100644 (file)
index 0000000..0ba35df
--- /dev/null
@@ -0,0 +1,938 @@
+/*
+ * Driver for Cirrus Logic EP93xx SPI controller.
+ *
+ * Copyright (c) 2010 Mika Westerberg
+ *
+ * Explicit FIFO handling code was inspired by amba-pl022 driver.
+ *
+ * Chip select support using other than built-in GPIOs by H. Hartley Sweeten.
+ *
+ * For more information about the SPI controller see documentation on Cirrus
+ * Logic web site:
+ *     http://www.cirrus.com/en/pubs/manual/EP93xx_Users_Guide_UM1.pdf
+ *
+ * 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/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/sched.h>
+#include <linux/spi/spi.h>
+
+#include <mach/ep93xx_spi.h>
+
+#define SSPCR0                 0x0000
+#define SSPCR0_MODE_SHIFT      6
+#define SSPCR0_SCR_SHIFT       8
+
+#define SSPCR1                 0x0004
+#define SSPCR1_RIE             BIT(0)
+#define SSPCR1_TIE             BIT(1)
+#define SSPCR1_RORIE           BIT(2)
+#define SSPCR1_LBM             BIT(3)
+#define SSPCR1_SSE             BIT(4)
+#define SSPCR1_MS              BIT(5)
+#define SSPCR1_SOD             BIT(6)
+
+#define SSPDR                  0x0008
+
+#define SSPSR                  0x000c
+#define SSPSR_TFE              BIT(0)
+#define SSPSR_TNF              BIT(1)
+#define SSPSR_RNE              BIT(2)
+#define SSPSR_RFF              BIT(3)
+#define SSPSR_BSY              BIT(4)
+#define SSPCPSR                        0x0010
+
+#define SSPIIR                 0x0014
+#define SSPIIR_RIS             BIT(0)
+#define SSPIIR_TIS             BIT(1)
+#define SSPIIR_RORIS           BIT(2)
+#define SSPICR                 SSPIIR
+
+/* timeout in milliseconds */
+#define SPI_TIMEOUT            5
+/* maximum depth of RX/TX FIFO */
+#define SPI_FIFO_SIZE          8
+
+/**
+ * struct ep93xx_spi - EP93xx SPI controller structure
+ * @lock: spinlock that protects concurrent accesses to fields @running,
+ *        @current_msg and @msg_queue
+ * @pdev: pointer to platform device
+ * @clk: clock for the controller
+ * @regs_base: pointer to ioremap()'d registers
+ * @irq: IRQ number used by the driver
+ * @min_rate: minimum clock rate (in Hz) supported by the controller
+ * @max_rate: maximum clock rate (in Hz) supported by the controller
+ * @running: is the queue running
+ * @wq: workqueue used by the driver
+ * @msg_work: work that is queued for the driver
+ * @wait: wait here until given transfer is completed
+ * @msg_queue: queue for the messages
+ * @current_msg: message that is currently processed (or %NULL if none)
+ * @tx: current byte in transfer to transmit
+ * @rx: current byte in transfer to receive
+ * @fifo_level: how full is FIFO (%0..%SPI_FIFO_SIZE - %1). Receiving one
+ *              frame decreases this level and sending one frame increases it.
+ *
+ * This structure holds EP93xx SPI controller specific information. When
+ * @running is %true, driver accepts transfer requests from protocol drivers.
+ * @current_msg is used to hold pointer to the message that is currently
+ * processed. If @current_msg is %NULL, it means that no processing is going
+ * on.
+ *
+ * Most of the fields are only written once and they can be accessed without
+ * taking the @lock. Fields that are accessed concurrently are: @current_msg,
+ * @running, and @msg_queue.
+ */
+struct ep93xx_spi {
+       spinlock_t                      lock;
+       const struct platform_device    *pdev;
+       struct clk                      *clk;
+       void __iomem                    *regs_base;
+       int                             irq;
+       unsigned long                   min_rate;
+       unsigned long                   max_rate;
+       bool                            running;
+       struct workqueue_struct         *wq;
+       struct work_struct              msg_work;
+       struct completion               wait;
+       struct list_head                msg_queue;
+       struct spi_message              *current_msg;
+       size_t                          tx;
+       size_t                          rx;
+       size_t                          fifo_level;
+};
+
+/**
+ * struct ep93xx_spi_chip - SPI device hardware settings
+ * @spi: back pointer to the SPI device
+ * @rate: max rate in hz this chip supports
+ * @div_cpsr: cpsr (pre-scaler) divider
+ * @div_scr: scr divider
+ * @dss: bits per word (4 - 16 bits)
+ * @ops: private chip operations
+ *
+ * This structure is used to store hardware register specific settings for each
+ * SPI device. Settings are written to hardware by function
+ * ep93xx_spi_chip_setup().
+ */
+struct ep93xx_spi_chip {
+       const struct spi_device         *spi;
+       unsigned long                   rate;
+       u8                              div_cpsr;
+       u8                              div_scr;
+       u8                              dss;
+       struct ep93xx_spi_chip_ops      *ops;
+};
+
+/* converts bits per word to CR0.DSS value */
+#define bits_per_word_to_dss(bpw)      ((bpw) - 1)
+
+static inline void
+ep93xx_spi_write_u8(const struct ep93xx_spi *espi, u16 reg, u8 value)
+{
+       __raw_writeb(value, espi->regs_base + reg);
+}
+
+static inline u8
+ep93xx_spi_read_u8(const struct ep93xx_spi *spi, u16 reg)
+{
+       return __raw_readb(spi->regs_base + reg);
+}
+
+static inline void
+ep93xx_spi_write_u16(const struct ep93xx_spi *espi, u16 reg, u16 value)
+{
+       __raw_writew(value, espi->regs_base + reg);
+}
+
+static inline u16
+ep93xx_spi_read_u16(const struct ep93xx_spi *spi, u16 reg)
+{
+       return __raw_readw(spi->regs_base + reg);
+}
+
+static int ep93xx_spi_enable(const struct ep93xx_spi *espi)
+{
+       u8 regval;
+       int err;
+
+       err = clk_enable(espi->clk);
+       if (err)
+               return err;
+
+       regval = ep93xx_spi_read_u8(espi, SSPCR1);
+       regval |= SSPCR1_SSE;
+       ep93xx_spi_write_u8(espi, SSPCR1, regval);
+
+       return 0;
+}
+
+static void ep93xx_spi_disable(const struct ep93xx_spi *espi)
+{
+       u8 regval;
+
+       regval = ep93xx_spi_read_u8(espi, SSPCR1);
+       regval &= ~SSPCR1_SSE;
+       ep93xx_spi_write_u8(espi, SSPCR1, regval);
+
+       clk_disable(espi->clk);
+}
+
+static void ep93xx_spi_enable_interrupts(const struct ep93xx_spi *espi)
+{
+       u8 regval;
+
+       regval = ep93xx_spi_read_u8(espi, SSPCR1);
+       regval |= (SSPCR1_RORIE | SSPCR1_TIE | SSPCR1_RIE);
+       ep93xx_spi_write_u8(espi, SSPCR1, regval);
+}
+
+static void ep93xx_spi_disable_interrupts(const struct ep93xx_spi *espi)
+{
+       u8 regval;
+
+       regval = ep93xx_spi_read_u8(espi, SSPCR1);
+       regval &= ~(SSPCR1_RORIE | SSPCR1_TIE | SSPCR1_RIE);
+       ep93xx_spi_write_u8(espi, SSPCR1, regval);
+}
+
+/**
+ * ep93xx_spi_calc_divisors() - calculates SPI clock divisors
+ * @espi: ep93xx SPI controller struct
+ * @chip: divisors are calculated for this chip
+ * @rate: desired SPI output clock rate
+ *
+ * Function calculates cpsr (clock pre-scaler) and scr divisors based on
+ * given @rate and places them to @chip->div_cpsr and @chip->div_scr. If,
+ * for some reason, divisors cannot be calculated nothing is stored and
+ * %-EINVAL is returned.
+ */
+static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi,
+                                   struct ep93xx_spi_chip *chip,
+                                   unsigned long rate)
+{
+       unsigned long spi_clk_rate = clk_get_rate(espi->clk);
+       int cpsr, scr;
+
+       /*
+        * Make sure that max value is between values supported by the
+        * controller. Note that minimum value is already checked in
+        * ep93xx_spi_transfer().
+        */
+       rate = clamp(rate, espi->min_rate, espi->max_rate);
+
+       /*
+        * Calculate divisors so that we can get speed according the
+        * following formula:
+        *      rate = spi_clock_rate / (cpsr * (1 + scr))
+        *
+        * cpsr must be even number and starts from 2, scr can be any number
+        * between 0 and 255.
+        */
+       for (cpsr = 2; cpsr <= 254; cpsr += 2) {
+               for (scr = 0; scr <= 255; scr++) {
+                       if ((spi_clk_rate / (cpsr * (scr + 1))) <= rate) {
+                               chip->div_scr = (u8)scr;
+                               chip->div_cpsr = (u8)cpsr;
+                               return 0;
+                       }
+               }
+       }
+
+       return -EINVAL;
+}
+
+static void ep93xx_spi_cs_control(struct spi_device *spi, bool control)
+{
+       struct ep93xx_spi_chip *chip = spi_get_ctldata(spi);
+       int value = (spi->mode & SPI_CS_HIGH) ? control : !control;
+
+       if (chip->ops && chip->ops->cs_control)
+               chip->ops->cs_control(spi, value);
+}
+
+/**
+ * ep93xx_spi_setup() - setup an SPI device
+ * @spi: SPI device to setup
+ *
+ * This function sets up SPI device mode, speed etc. Can be called multiple
+ * times for a single device. Returns %0 in case of success, negative error in
+ * case of failure. When this function returns success, the device is
+ * deselected.
+ */
+static int ep93xx_spi_setup(struct spi_device *spi)
+{
+       struct ep93xx_spi *espi = spi_master_get_devdata(spi->master);
+       struct ep93xx_spi_chip *chip;
+
+       if (spi->bits_per_word < 4 || spi->bits_per_word > 16) {
+               dev_err(&espi->pdev->dev, "invalid bits per word %d\n",
+                       spi->bits_per_word);
+               return -EINVAL;
+       }
+
+       chip = spi_get_ctldata(spi);
+       if (!chip) {
+               dev_dbg(&espi->pdev->dev, "initial setup for %s\n",
+                       spi->modalias);
+
+               chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+               if (!chip)
+                       return -ENOMEM;
+
+               chip->spi = spi;
+               chip->ops = spi->controller_data;
+
+               if (chip->ops && chip->ops->setup) {
+                       int ret = chip->ops->setup(spi);
+                       if (ret) {
+                               kfree(chip);
+                               return ret;
+                       }
+               }
+
+               spi_set_ctldata(spi, chip);
+       }
+
+       if (spi->max_speed_hz != chip->rate) {
+               int err;
+
+               err = ep93xx_spi_calc_divisors(espi, chip, spi->max_speed_hz);
+               if (err != 0) {
+                       spi_set_ctldata(spi, NULL);
+                       kfree(chip);
+                       return err;
+               }
+               chip->rate = spi->max_speed_hz;
+       }
+
+       chip->dss = bits_per_word_to_dss(spi->bits_per_word);
+
+       ep93xx_spi_cs_control(spi, false);
+       return 0;
+}
+
+/**
+ * ep93xx_spi_transfer() - queue message to be transferred
+ * @spi: target SPI device
+ * @msg: message to be transferred
+ *
+ * This function is called by SPI device drivers when they are going to transfer
+ * a new message. It simply puts the message in the queue and schedules
+ * workqueue to perform the actual transfer later on.
+ *
+ * Returns %0 on success and negative error in case of failure.
+ */
+static int ep93xx_spi_transfer(struct spi_device *spi, struct spi_message *msg)
+{
+       struct ep93xx_spi *espi = spi_master_get_devdata(spi->master);
+       struct spi_transfer *t;
+       unsigned long flags;
+
+       if (!msg || !msg->complete)
+               return -EINVAL;
+
+       /* first validate each transfer */
+       list_for_each_entry(t, &msg->transfers, transfer_list) {
+               if (t->bits_per_word) {
+                       if (t->bits_per_word < 4 || t->bits_per_word > 16)
+                               return -EINVAL;
+               }
+               if (t->speed_hz && t->speed_hz < espi->min_rate)
+                               return -EINVAL;
+       }
+
+       /*
+        * Now that we own the message, let's initialize it so that it is
+        * suitable for us. We use @msg->status to signal whether there was
+        * error in transfer and @msg->state is used to hold pointer to the
+        * current transfer (or %NULL if no active current transfer).
+        */
+       msg->state = NULL;
+       msg->status = 0;
+       msg->actual_length = 0;
+
+       spin_lock_irqsave(&espi->lock, flags);
+       if (!espi->running) {
+               spin_unlock_irqrestore(&espi->lock, flags);
+               return -ESHUTDOWN;
+       }
+       list_add_tail(&msg->queue, &espi->msg_queue);
+       queue_work(espi->wq, &espi->msg_work);
+       spin_unlock_irqrestore(&espi->lock, flags);
+
+       return 0;
+}
+
+/**
+ * ep93xx_spi_cleanup() - cleans up master controller specific state
+ * @spi: SPI device to cleanup
+ *
+ * This function releases master controller specific state for given @spi
+ * device.
+ */
+static void ep93xx_spi_cleanup(struct spi_device *spi)
+{
+       struct ep93xx_spi_chip *chip;
+
+       chip = spi_get_ctldata(spi);
+       if (chip) {
+               if (chip->ops && chip->ops->cleanup)
+                       chip->ops->cleanup(spi);
+               spi_set_ctldata(spi, NULL);
+               kfree(chip);
+       }
+}
+
+/**
+ * ep93xx_spi_chip_setup() - configures hardware according to given @chip
+ * @espi: ep93xx SPI controller struct
+ * @chip: chip specific settings
+ *
+ * This function sets up the actual hardware registers with settings given in
+ * @chip. Note that no validation is done so make sure that callers validate
+ * settings before calling this.
+ */
+static void ep93xx_spi_chip_setup(const struct ep93xx_spi *espi,
+                                 const struct ep93xx_spi_chip *chip)
+{
+       u16 cr0;
+
+       cr0 = chip->div_scr << SSPCR0_SCR_SHIFT;
+       cr0 |= (chip->spi->mode & (SPI_CPHA|SPI_CPOL)) << SSPCR0_MODE_SHIFT;
+       cr0 |= chip->dss;
+
+       dev_dbg(&espi->pdev->dev, "setup: mode %d, cpsr %d, scr %d, dss %d\n",
+               chip->spi->mode, chip->div_cpsr, chip->div_scr, chip->dss);
+       dev_dbg(&espi->pdev->dev, "setup: cr0 %#x", cr0);
+
+       ep93xx_spi_write_u8(espi, SSPCPSR, chip->div_cpsr);
+       ep93xx_spi_write_u16(espi, SSPCR0, cr0);
+}
+
+static inline int bits_per_word(const struct ep93xx_spi *espi)
+{
+       struct spi_message *msg = espi->current_msg;
+       struct spi_transfer *t = msg->state;
+
+       return t->bits_per_word ? t->bits_per_word : msg->spi->bits_per_word;
+}
+
+static void ep93xx_do_write(struct ep93xx_spi *espi, struct spi_transfer *t)
+{
+       if (bits_per_word(espi) > 8) {
+               u16 tx_val = 0;
+
+               if (t->tx_buf)
+                       tx_val = ((u16 *)t->tx_buf)[espi->tx];
+               ep93xx_spi_write_u16(espi, SSPDR, tx_val);
+               espi->tx += sizeof(tx_val);
+       } else {
+               u8 tx_val = 0;
+
+               if (t->tx_buf)
+                       tx_val = ((u8 *)t->tx_buf)[espi->tx];
+               ep93xx_spi_write_u8(espi, SSPDR, tx_val);
+               espi->tx += sizeof(tx_val);
+       }
+}
+
+static void ep93xx_do_read(struct ep93xx_spi *espi, struct spi_transfer *t)
+{
+       if (bits_per_word(espi) > 8) {
+               u16 rx_val;
+
+               rx_val = ep93xx_spi_read_u16(espi, SSPDR);
+               if (t->rx_buf)
+                       ((u16 *)t->rx_buf)[espi->rx] = rx_val;
+               espi->rx += sizeof(rx_val);
+       } else {
+               u8 rx_val;
+
+               rx_val = ep93xx_spi_read_u8(espi, SSPDR);
+               if (t->rx_buf)
+                       ((u8 *)t->rx_buf)[espi->rx] = rx_val;
+               espi->rx += sizeof(rx_val);
+       }
+}
+
+/**
+ * ep93xx_spi_read_write() - perform next RX/TX transfer
+ * @espi: ep93xx SPI controller struct
+ *
+ * This function transfers next bytes (or half-words) to/from RX/TX FIFOs. If
+ * called several times, the whole transfer will be completed. Returns
+ * %-EINPROGRESS when current transfer was not yet completed otherwise %0.
+ *
+ * When this function is finished, RX FIFO should be empty and TX FIFO should be
+ * full.
+ */
+static int ep93xx_spi_read_write(struct ep93xx_spi *espi)
+{
+       struct spi_message *msg = espi->current_msg;
+       struct spi_transfer *t = msg->state;
+
+       /* read as long as RX FIFO has frames in it */
+       while ((ep93xx_spi_read_u8(espi, SSPSR) & SSPSR_RNE)) {
+               ep93xx_do_read(espi, t);
+               espi->fifo_level--;
+       }
+
+       /* write as long as TX FIFO has room */
+       while (espi->fifo_level < SPI_FIFO_SIZE && espi->tx < t->len) {
+               ep93xx_do_write(espi, t);
+               espi->fifo_level++;
+       }
+
+       if (espi->rx == t->len) {
+               msg->actual_length += t->len;
+               return 0;
+       }
+
+       return -EINPROGRESS;
+}
+
+/**
+ * ep93xx_spi_process_transfer() - processes one SPI transfer
+ * @espi: ep93xx SPI controller struct
+ * @msg: current message
+ * @t: transfer to process
+ *
+ * This function processes one SPI transfer given in @t. Function waits until
+ * transfer is complete (may sleep) and updates @msg->status based on whether
+ * transfer was succesfully processed or not.
+ */
+static void ep93xx_spi_process_transfer(struct ep93xx_spi *espi,
+                                       struct spi_message *msg,
+                                       struct spi_transfer *t)
+{
+       struct ep93xx_spi_chip *chip = spi_get_ctldata(msg->spi);
+
+       msg->state = t;
+
+       /*
+        * Handle any transfer specific settings if needed. We use
+        * temporary chip settings here and restore original later when
+        * the transfer is finished.
+        */
+       if (t->speed_hz || t->bits_per_word) {
+               struct ep93xx_spi_chip tmp_chip = *chip;
+
+               if (t->speed_hz) {
+                       int err;
+
+                       err = ep93xx_spi_calc_divisors(espi, &tmp_chip,
+                                                      t->speed_hz);
+                       if (err) {
+                               dev_err(&espi->pdev->dev,
+                                       "failed to adjust speed\n");
+                               msg->status = err;
+                               return;
+                       }
+               }
+
+               if (t->bits_per_word)
+                       tmp_chip.dss = bits_per_word_to_dss(t->bits_per_word);
+
+               /*
+                * Set up temporary new hw settings for this transfer.
+                */
+               ep93xx_spi_chip_setup(espi, &tmp_chip);
+       }
+
+       espi->rx = 0;
+       espi->tx = 0;
+
+       /*
+        * Now everything is set up for the current transfer. We prime the TX
+        * FIFO, enable interrupts, and wait for the transfer to complete.
+        */
+       if (ep93xx_spi_read_write(espi)) {
+               ep93xx_spi_enable_interrupts(espi);
+               wait_for_completion(&espi->wait);
+       }
+
+       /*
+        * In case of error during transmit, we bail out from processing
+        * the message.
+        */
+       if (msg->status)
+               return;
+
+       /*
+        * After this transfer is finished, perform any possible
+        * post-transfer actions requested by the protocol driver.
+        */
+       if (t->delay_usecs) {
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(usecs_to_jiffies(t->delay_usecs));
+       }
+       if (t->cs_change) {
+               if (!list_is_last(&t->transfer_list, &msg->transfers)) {
+                       /*
+                        * In case protocol driver is asking us to drop the
+                        * chipselect briefly, we let the scheduler to handle
+                        * any "delay" here.
+                        */
+                       ep93xx_spi_cs_control(msg->spi, false);
+                       cond_resched();
+                       ep93xx_spi_cs_control(msg->spi, true);
+               }
+       }
+
+       if (t->speed_hz || t->bits_per_word)
+               ep93xx_spi_chip_setup(espi, chip);
+}
+
+/*
+ * ep93xx_spi_process_message() - process one SPI message
+ * @espi: ep93xx SPI controller struct
+ * @msg: message to process
+ *
+ * This function processes a single SPI message. We go through all transfers in
+ * the message and pass them to ep93xx_spi_process_transfer(). Chipselect is
+ * asserted during the whole message (unless per transfer cs_change is set).
+ *
+ * @msg->status contains %0 in case of success or negative error code in case of
+ * failure.
+ */
+static void ep93xx_spi_process_message(struct ep93xx_spi *espi,
+                                      struct spi_message *msg)
+{
+       unsigned long timeout;
+       struct spi_transfer *t;
+       int err;
+
+       /*
+        * Enable the SPI controller and its clock.
+        */
+       err = ep93xx_spi_enable(espi);
+       if (err) {
+               dev_err(&espi->pdev->dev, "failed to enable SPI controller\n");
+               msg->status = err;
+               return;
+       }
+
+       /*
+        * Just to be sure: flush any data from RX FIFO.
+        */
+       timeout = jiffies + msecs_to_jiffies(SPI_TIMEOUT);
+       while (ep93xx_spi_read_u16(espi, SSPSR) & SSPSR_RNE) {
+               if (time_after(jiffies, timeout)) {
+                       dev_warn(&espi->pdev->dev,
+                                "timeout while flushing RX FIFO\n");
+                       msg->status = -ETIMEDOUT;
+                       return;
+               }
+               ep93xx_spi_read_u16(espi, SSPDR);
+       }
+
+       /*
+        * We explicitly handle FIFO level. This way we don't have to check TX
+        * FIFO status using %SSPSR_TNF bit which may cause RX FIFO overruns.
+        */
+       espi->fifo_level = 0;
+
+       /*
+        * Update SPI controller registers according to spi device and assert
+        * the chipselect.
+        */
+       ep93xx_spi_chip_setup(espi, spi_get_ctldata(msg->spi));
+       ep93xx_spi_cs_control(msg->spi, true);
+
+       list_for_each_entry(t, &msg->transfers, transfer_list) {
+               ep93xx_spi_process_transfer(espi, msg, t);
+               if (msg->status)
+                       break;
+       }
+
+       /*
+        * Now the whole message is transferred (or failed for some reason). We
+        * deselect the device and disable the SPI controller.
+        */
+       ep93xx_spi_cs_control(msg->spi, false);
+       ep93xx_spi_disable(espi);
+}
+
+#define work_to_espi(work) (container_of((work), struct ep93xx_spi, msg_work))
+
+/**
+ * ep93xx_spi_work() - EP93xx SPI workqueue worker function
+ * @work: work struct
+ *
+ * Workqueue worker function. This function is called when there are new
+ * SPI messages to be processed. Message is taken out from the queue and then
+ * passed to ep93xx_spi_process_message().
+ *
+ * After message is transferred, protocol driver is notified by calling
+ * @msg->complete(). In case of error, @msg->status is set to negative error
+ * number, otherwise it contains zero (and @msg->actual_length is updated).
+ */
+static void ep93xx_spi_work(struct work_struct *work)
+{
+       struct ep93xx_spi *espi = work_to_espi(work);
+       struct spi_message *msg;
+
+       spin_lock_irq(&espi->lock);
+       if (!espi->running || espi->current_msg ||
+               list_empty(&espi->msg_queue)) {
+               spin_unlock_irq(&espi->lock);
+               return;
+       }
+       msg = list_first_entry(&espi->msg_queue, struct spi_message, queue);
+       list_del_init(&msg->queue);
+       espi->current_msg = msg;
+       spin_unlock_irq(&espi->lock);
+
+       ep93xx_spi_process_message(espi, msg);
+
+       /*
+        * Update the current message and re-schedule ourselves if there are
+        * more messages in the queue.
+        */
+       spin_lock_irq(&espi->lock);
+       espi->current_msg = NULL;
+       if (espi->running && !list_empty(&espi->msg_queue))
+               queue_work(espi->wq, &espi->msg_work);
+       spin_unlock_irq(&espi->lock);
+
+       /* notify the protocol driver that we are done with this message */
+       msg->complete(msg->context);
+}
+
+static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
+{
+       struct ep93xx_spi *espi = dev_id;
+       u8 irq_status = ep93xx_spi_read_u8(espi, SSPIIR);
+
+       /*
+        * If we got ROR (receive overrun) interrupt we know that something is
+        * wrong. Just abort the message.
+        */
+       if (unlikely(irq_status & SSPIIR_RORIS)) {
+               /* clear the overrun interrupt */
+               ep93xx_spi_write_u8(espi, SSPICR, 0);
+               dev_warn(&espi->pdev->dev,
+                        "receive overrun, aborting the message\n");
+               espi->current_msg->status = -EIO;
+       } else {
+               /*
+                * Interrupt is either RX (RIS) or TX (TIS). For both cases we
+                * simply execute next data transfer.
+                */
+               if (ep93xx_spi_read_write(espi)) {
+                       /*
+                        * In normal case, there still is some processing left
+                        * for current transfer. Let's wait for the next
+                        * interrupt then.
+                        */
+                       return IRQ_HANDLED;
+               }
+       }
+
+       /*
+        * Current transfer is finished, either with error or with success. In
+        * any case we disable interrupts and notify the worker to handle
+        * any post-processing of the message.
+        */
+       ep93xx_spi_disable_interrupts(espi);
+       complete(&espi->wait);
+       return IRQ_HANDLED;
+}
+
+static int __init ep93xx_spi_probe(struct platform_device *pdev)
+{
+       struct spi_master *master;
+       struct ep93xx_spi_info *info;
+       struct ep93xx_spi *espi;
+       struct resource *res;
+       int error;
+
+       info = pdev->dev.platform_data;
+
+       master = spi_alloc_master(&pdev->dev, sizeof(*espi));
+       if (!master) {
+               dev_err(&pdev->dev, "failed to allocate spi master\n");
+               return -ENOMEM;
+       }
+
+       master->setup = ep93xx_spi_setup;
+       master->transfer = ep93xx_spi_transfer;
+       master->cleanup = ep93xx_spi_cleanup;
+       master->bus_num = pdev->id;
+       master->num_chipselect = info->num_chipselect;
+       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+
+       platform_set_drvdata(pdev, master);
+
+       espi = spi_master_get_devdata(master);
+
+       espi->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(espi->clk)) {
+               dev_err(&pdev->dev, "unable to get spi clock\n");
+               error = PTR_ERR(espi->clk);
+               goto fail_release_master;
+       }
+
+       spin_lock_init(&espi->lock);
+       init_completion(&espi->wait);
+
+       /*
+        * Calculate maximum and minimum supported clock rates
+        * for the controller.
+        */
+       espi->max_rate = clk_get_rate(espi->clk) / 2;
+       espi->min_rate = clk_get_rate(espi->clk) / (254 * 256);
+       espi->pdev = pdev;
+
+       espi->irq = platform_get_irq(pdev, 0);
+       if (espi->irq < 0) {
+               error = -EBUSY;
+               dev_err(&pdev->dev, "failed to get irq resources\n");
+               goto fail_put_clock;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "unable to get iomem resource\n");
+               error = -ENODEV;
+               goto fail_put_clock;
+       }
+
+       res = request_mem_region(res->start, resource_size(res), pdev->name);
+       if (!res) {
+               dev_err(&pdev->dev, "unable to request iomem resources\n");
+               error = -EBUSY;
+               goto fail_put_clock;
+       }
+
+       espi->regs_base = ioremap(res->start, resource_size(res));
+       if (!espi->regs_base) {
+               dev_err(&pdev->dev, "failed to map resources\n");
+               error = -ENODEV;
+               goto fail_free_mem;
+       }
+
+       error = request_irq(espi->irq, ep93xx_spi_interrupt, 0,
+                           "ep93xx-spi", espi);
+       if (error) {
+               dev_err(&pdev->dev, "failed to request irq\n");
+               goto fail_unmap_regs;
+       }
+
+       espi->wq = create_singlethread_workqueue("ep93xx_spid");
+       if (!espi->wq) {
+               dev_err(&pdev->dev, "unable to create workqueue\n");
+               goto fail_free_irq;
+       }
+       INIT_WORK(&espi->msg_work, ep93xx_spi_work);
+       INIT_LIST_HEAD(&espi->msg_queue);
+       espi->running = true;
+
+       /* make sure that the hardware is disabled */
+       ep93xx_spi_write_u8(espi, SSPCR1, 0);
+
+       error = spi_register_master(master);
+       if (error) {
+               dev_err(&pdev->dev, "failed to register SPI master\n");
+               goto fail_free_queue;
+       }
+
+       dev_info(&pdev->dev, "EP93xx SPI Controller at 0x%08lx irq %d\n",
+                (unsigned long)res->start, espi->irq);
+
+       return 0;
+
+fail_free_queue:
+       destroy_workqueue(espi->wq);
+fail_free_irq:
+       free_irq(espi->irq, espi);
+fail_unmap_regs:
+       iounmap(espi->regs_base);
+fail_free_mem:
+       release_mem_region(res->start, resource_size(res));
+fail_put_clock:
+       clk_put(espi->clk);
+fail_release_master:
+       spi_master_put(master);
+       platform_set_drvdata(pdev, NULL);
+
+       return error;
+}
+
+static int __exit ep93xx_spi_remove(struct platform_device *pdev)
+{
+       struct spi_master *master = platform_get_drvdata(pdev);
+       struct ep93xx_spi *espi = spi_master_get_devdata(master);
+       struct resource *res;
+
+       spin_lock_irq(&espi->lock);
+       espi->running = false;
+       spin_unlock_irq(&espi->lock);
+
+       destroy_workqueue(espi->wq);
+
+       /*
+        * Complete remaining messages with %-ESHUTDOWN status.
+        */
+       spin_lock_irq(&espi->lock);
+       while (!list_empty(&espi->msg_queue)) {
+               struct spi_message *msg;
+
+               msg = list_first_entry(&espi->msg_queue,
+                                      struct spi_message, queue);
+               list_del_init(&msg->queue);
+               msg->status = -ESHUTDOWN;
+               spin_unlock_irq(&espi->lock);
+               msg->complete(msg->context);
+               spin_lock_irq(&espi->lock);
+       }
+       spin_unlock_irq(&espi->lock);
+
+       free_irq(espi->irq, espi);
+       iounmap(espi->regs_base);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(res->start, resource_size(res));
+       clk_put(espi->clk);
+       platform_set_drvdata(pdev, NULL);
+
+       spi_unregister_master(master);
+       return 0;
+}
+
+static struct platform_driver ep93xx_spi_driver = {
+       .driver         = {
+               .name   = "ep93xx-spi",
+               .owner  = THIS_MODULE,
+       },
+       .remove         = __exit_p(ep93xx_spi_remove),
+};
+
+static int __init ep93xx_spi_init(void)
+{
+       return platform_driver_probe(&ep93xx_spi_driver, ep93xx_spi_probe);
+}
+module_init(ep93xx_spi_init);
+
+static void __exit ep93xx_spi_exit(void)
+{
+       platform_driver_unregister(&ep93xx_spi_driver);
+}
+module_exit(ep93xx_spi_exit);
+
+MODULE_DESCRIPTION("EP93xx SPI Controller driver");
+MODULE_AUTHOR("Mika Westerberg <mika.westerberg@iki.fi>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ep93xx-spi");
diff --git a/drivers/spi/mpc512x_psc_spi.c b/drivers/spi/mpc512x_psc_spi.c
new file mode 100644 (file)
index 0000000..28a126d
--- /dev/null
@@ -0,0 +1,576 @@
+/*
+ * MPC512x PSC in SPI mode driver.
+ *
+ * Copyright (C) 2007,2008 Freescale Semiconductor Inc.
+ * Original port from 52xx driver:
+ *     Hongjun Chen <hong-jun.chen@freescale.com>
+ *
+ * Fork of mpc52xx_psc_spi.c:
+ *     Copyright (C) 2006 TOPTICA Photonics AG., Dragos Carp
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/of_platform.h>
+#include <linux/workqueue.h>
+#include <linux/completion.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/spi/spi.h>
+#include <linux/fsl_devices.h>
+#include <asm/mpc52xx_psc.h>
+
+struct mpc512x_psc_spi {
+       void (*cs_control)(struct spi_device *spi, bool on);
+       u32 sysclk;
+
+       /* driver internal data */
+       struct mpc52xx_psc __iomem *psc;
+       struct mpc512x_psc_fifo __iomem *fifo;
+       unsigned int irq;
+       u8 bits_per_word;
+       u8 busy;
+       u32 mclk;
+       u8 eofbyte;
+
+       struct workqueue_struct *workqueue;
+       struct work_struct work;
+
+       struct list_head queue;
+       spinlock_t lock;        /* Message queue lock */
+
+       struct completion done;
+};
+
+/* controller state */
+struct mpc512x_psc_spi_cs {
+       int bits_per_word;
+       int speed_hz;
+};
+
+/* set clock freq, clock ramp, bits per work
+ * if t is NULL then reset the values to the default values
+ */
+static int mpc512x_psc_spi_transfer_setup(struct spi_device *spi,
+                                         struct spi_transfer *t)
+{
+       struct mpc512x_psc_spi_cs *cs = spi->controller_state;
+
+       cs->speed_hz = (t && t->speed_hz)
+           ? t->speed_hz : spi->max_speed_hz;
+       cs->bits_per_word = (t && t->bits_per_word)
+           ? t->bits_per_word : spi->bits_per_word;
+       cs->bits_per_word = ((cs->bits_per_word + 7) / 8) * 8;
+       return 0;
+}
+
+static void mpc512x_psc_spi_activate_cs(struct spi_device *spi)
+{
+       struct mpc512x_psc_spi_cs *cs = spi->controller_state;
+       struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
+       struct mpc52xx_psc __iomem *psc = mps->psc;
+       u32 sicr;
+       u32 ccr;
+       u16 bclkdiv;
+
+       sicr = in_be32(&psc->sicr);
+
+       /* Set clock phase and polarity */
+       if (spi->mode & SPI_CPHA)
+               sicr |= 0x00001000;
+       else
+               sicr &= ~0x00001000;
+
+       if (spi->mode & SPI_CPOL)
+               sicr |= 0x00002000;
+       else
+               sicr &= ~0x00002000;
+
+       if (spi->mode & SPI_LSB_FIRST)
+               sicr |= 0x10000000;
+       else
+               sicr &= ~0x10000000;
+       out_be32(&psc->sicr, sicr);
+
+       ccr = in_be32(&psc->ccr);
+       ccr &= 0xFF000000;
+       if (cs->speed_hz)
+               bclkdiv = (mps->mclk / cs->speed_hz) - 1;
+       else
+               bclkdiv = (mps->mclk / 1000000) - 1;    /* default 1MHz */
+
+       ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8));
+       out_be32(&psc->ccr, ccr);
+       mps->bits_per_word = cs->bits_per_word;
+
+       if (mps->cs_control)
+               mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 1 : 0);
+}
+
+static void mpc512x_psc_spi_deactivate_cs(struct spi_device *spi)
+{
+       struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
+
+       if (mps->cs_control)
+               mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 0 : 1);
+
+}
+
+/* extract and scale size field in txsz or rxsz */
+#define MPC512x_PSC_FIFO_SZ(sz) ((sz & 0x7ff) << 2);
+
+#define EOFBYTE 1
+
+static int mpc512x_psc_spi_transfer_rxtx(struct spi_device *spi,
+                                        struct spi_transfer *t)
+{
+       struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
+       struct mpc52xx_psc __iomem *psc = mps->psc;
+       struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
+       size_t len = t->len;
+       u8 *tx_buf = (u8 *)t->tx_buf;
+       u8 *rx_buf = (u8 *)t->rx_buf;
+
+       if (!tx_buf && !rx_buf && t->len)
+               return -EINVAL;
+
+       /* Zero MR2 */
+       in_8(&psc->mode);
+       out_8(&psc->mode, 0x0);
+
+       while (len) {
+               int count;
+               int i;
+               u8 data;
+               size_t fifosz;
+               int rxcount;
+
+               /*
+                * The number of bytes that can be sent at a time
+                * depends on the fifo size.
+                */
+               fifosz = MPC512x_PSC_FIFO_SZ(in_be32(&fifo->txsz));
+               count = min(fifosz, len);
+
+               for (i = count; i > 0; i--) {
+                       data = tx_buf ? *tx_buf++ : 0;
+                       if (len == EOFBYTE)
+                               setbits32(&fifo->txcmd, MPC512x_PSC_FIFO_EOF);
+                       out_8(&fifo->txdata_8, data);
+                       len--;
+               }
+
+               INIT_COMPLETION(mps->done);
+
+               /* interrupt on tx fifo empty */
+               out_be32(&fifo->txisr, MPC512x_PSC_FIFO_EMPTY);
+               out_be32(&fifo->tximr, MPC512x_PSC_FIFO_EMPTY);
+
+               /* enable transmiter/receiver */
+               out_8(&psc->command,
+                     MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
+
+               wait_for_completion(&mps->done);
+
+               mdelay(1);
+
+               /* rx fifo should have count bytes in it */
+               rxcount = in_be32(&fifo->rxcnt);
+               if (rxcount != count)
+                       mdelay(1);
+
+               rxcount = in_be32(&fifo->rxcnt);
+               if (rxcount != count) {
+                       dev_warn(&spi->dev, "expected %d bytes in rx fifo "
+                                "but got %d\n", count, rxcount);
+               }
+
+               rxcount = min(rxcount, count);
+               for (i = rxcount; i > 0; i--) {
+                       data = in_8(&fifo->rxdata_8);
+                       if (rx_buf)
+                               *rx_buf++ = data;
+               }
+               while (in_be32(&fifo->rxcnt)) {
+                       in_8(&fifo->rxdata_8);
+               }
+
+               out_8(&psc->command,
+                     MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
+       }
+       /* disable transmiter/receiver and fifo interrupt */
+       out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
+       out_be32(&fifo->tximr, 0);
+       return 0;
+}
+
+static void mpc512x_psc_spi_work(struct work_struct *work)
+{
+       struct mpc512x_psc_spi *mps = container_of(work,
+                                                  struct mpc512x_psc_spi,
+                                                  work);
+
+       spin_lock_irq(&mps->lock);
+       mps->busy = 1;
+       while (!list_empty(&mps->queue)) {
+               struct spi_message *m;
+               struct spi_device *spi;
+               struct spi_transfer *t = NULL;
+               unsigned cs_change;
+               int status;
+
+               m = container_of(mps->queue.next, struct spi_message, queue);
+               list_del_init(&m->queue);
+               spin_unlock_irq(&mps->lock);
+
+               spi = m->spi;
+               cs_change = 1;
+               status = 0;
+               list_for_each_entry(t, &m->transfers, transfer_list) {
+                       if (t->bits_per_word || t->speed_hz) {
+                               status = mpc512x_psc_spi_transfer_setup(spi, t);
+                               if (status < 0)
+                                       break;
+                       }
+
+                       if (cs_change)
+                               mpc512x_psc_spi_activate_cs(spi);
+                       cs_change = t->cs_change;
+
+                       status = mpc512x_psc_spi_transfer_rxtx(spi, t);
+                       if (status)
+                               break;
+                       m->actual_length += t->len;
+
+                       if (t->delay_usecs)
+                               udelay(t->delay_usecs);
+
+                       if (cs_change)
+                               mpc512x_psc_spi_deactivate_cs(spi);
+               }
+
+               m->status = status;
+               m->complete(m->context);
+
+               if (status || !cs_change)
+                       mpc512x_psc_spi_deactivate_cs(spi);
+
+               mpc512x_psc_spi_transfer_setup(spi, NULL);
+
+               spin_lock_irq(&mps->lock);
+       }
+       mps->busy = 0;
+       spin_unlock_irq(&mps->lock);
+}
+
+static int mpc512x_psc_spi_setup(struct spi_device *spi)
+{
+       struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
+       struct mpc512x_psc_spi_cs *cs = spi->controller_state;
+       unsigned long flags;
+
+       if (spi->bits_per_word % 8)
+               return -EINVAL;
+
+       if (!cs) {
+               cs = kzalloc(sizeof *cs, GFP_KERNEL);
+               if (!cs)
+                       return -ENOMEM;
+               spi->controller_state = cs;
+       }
+
+       cs->bits_per_word = spi->bits_per_word;
+       cs->speed_hz = spi->max_speed_hz;
+
+       spin_lock_irqsave(&mps->lock, flags);
+       if (!mps->busy)
+               mpc512x_psc_spi_deactivate_cs(spi);
+       spin_unlock_irqrestore(&mps->lock, flags);
+
+       return 0;
+}
+
+static int mpc512x_psc_spi_transfer(struct spi_device *spi,
+                                   struct spi_message *m)
+{
+       struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
+       unsigned long flags;
+
+       m->actual_length = 0;
+       m->status = -EINPROGRESS;
+
+       spin_lock_irqsave(&mps->lock, flags);
+       list_add_tail(&m->queue, &mps->queue);
+       queue_work(mps->workqueue, &mps->work);
+       spin_unlock_irqrestore(&mps->lock, flags);
+
+       return 0;
+}
+
+static void mpc512x_psc_spi_cleanup(struct spi_device *spi)
+{
+       kfree(spi->controller_state);
+}
+
+static int mpc512x_psc_spi_port_config(struct spi_master *master,
+                                      struct mpc512x_psc_spi *mps)
+{
+       struct mpc52xx_psc __iomem *psc = mps->psc;
+       struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
+       struct clk *spiclk;
+       int ret = 0;
+       char name[32];
+       u32 sicr;
+       u32 ccr;
+       u16 bclkdiv;
+
+       sprintf(name, "psc%d_mclk", master->bus_num);
+       spiclk = clk_get(&master->dev, name);
+       clk_enable(spiclk);
+       mps->mclk = clk_get_rate(spiclk);
+       clk_put(spiclk);
+
+       /* Reset the PSC into a known state */
+       out_8(&psc->command, MPC52xx_PSC_RST_RX);
+       out_8(&psc->command, MPC52xx_PSC_RST_TX);
+       out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
+
+       /* Disable psc interrupts all useful interrupts are in fifo */
+       out_be16(&psc->isr_imr.imr, 0);
+
+       /* Disable fifo interrupts, will be enabled later */
+       out_be32(&fifo->tximr, 0);
+       out_be32(&fifo->rximr, 0);
+
+       /* Setup fifo slice address and size */
+       /*out_be32(&fifo->txsz, 0x0fe00004);*/
+       /*out_be32(&fifo->rxsz, 0x0ff00004);*/
+
+       sicr =  0x01000000 |    /* SIM = 0001 -- 8 bit */
+               0x00800000 |    /* GenClk = 1 -- internal clk */
+               0x00008000 |    /* SPI = 1 */
+               0x00004000 |    /* MSTR = 1   -- SPI master */
+               0x00000800;     /* UseEOF = 1 -- SS low until EOF */
+
+       out_be32(&psc->sicr, sicr);
+
+       ccr = in_be32(&psc->ccr);
+       ccr &= 0xFF000000;
+       bclkdiv = (mps->mclk / 1000000) - 1;    /* default 1MHz */
+       ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8));
+       out_be32(&psc->ccr, ccr);
+
+       /* Set 2ms DTL delay */
+       out_8(&psc->ctur, 0x00);
+       out_8(&psc->ctlr, 0x82);
+
+       /* we don't use the alarms */
+       out_be32(&fifo->rxalarm, 0xfff);
+       out_be32(&fifo->txalarm, 0);
+
+       /* Enable FIFO slices for Rx/Tx */
+       out_be32(&fifo->rxcmd,
+                MPC512x_PSC_FIFO_ENABLE_SLICE | MPC512x_PSC_FIFO_ENABLE_DMA);
+       out_be32(&fifo->txcmd,
+                MPC512x_PSC_FIFO_ENABLE_SLICE | MPC512x_PSC_FIFO_ENABLE_DMA);
+
+       mps->bits_per_word = 8;
+
+       return ret;
+}
+
+static irqreturn_t mpc512x_psc_spi_isr(int irq, void *dev_id)
+{
+       struct mpc512x_psc_spi *mps = (struct mpc512x_psc_spi *)dev_id;
+       struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
+
+       /* clear interrupt and wake up the work queue */
+       if (in_be32(&fifo->txisr) &
+           in_be32(&fifo->tximr) & MPC512x_PSC_FIFO_EMPTY) {
+               out_be32(&fifo->txisr, MPC512x_PSC_FIFO_EMPTY);
+               out_be32(&fifo->tximr, 0);
+               complete(&mps->done);
+               return IRQ_HANDLED;
+       }
+       return IRQ_NONE;
+}
+
+/* bus_num is used only for the case dev->platform_data == NULL */
+static int __init mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
+                                          u32 size, unsigned int irq,
+                                          s16 bus_num)
+{
+       struct fsl_spi_platform_data *pdata = dev->platform_data;
+       struct mpc512x_psc_spi *mps;
+       struct spi_master *master;
+       int ret;
+       void *tempp;
+
+       master = spi_alloc_master(dev, sizeof *mps);
+       if (master == NULL)
+               return -ENOMEM;
+
+       dev_set_drvdata(dev, master);
+       mps = spi_master_get_devdata(master);
+       mps->irq = irq;
+
+       if (pdata == NULL) {
+               dev_err(dev, "probe called without platform data, no "
+                       "cs_control function will be called\n");
+               mps->cs_control = NULL;
+               mps->sysclk = 0;
+               master->bus_num = bus_num;
+               master->num_chipselect = 255;
+       } else {
+               mps->cs_control = pdata->cs_control;
+               mps->sysclk = pdata->sysclk;
+               master->bus_num = pdata->bus_num;
+               master->num_chipselect = pdata->max_chipselect;
+       }
+
+       master->setup = mpc512x_psc_spi_setup;
+       master->transfer = mpc512x_psc_spi_transfer;
+       master->cleanup = mpc512x_psc_spi_cleanup;
+
+       tempp = ioremap(regaddr, size);
+       if (!tempp) {
+               dev_err(dev, "could not ioremap I/O port range\n");
+               ret = -EFAULT;
+               goto free_master;
+       }
+       mps->psc = tempp;
+       mps->fifo =
+               (struct mpc512x_psc_fifo *)(tempp + sizeof(struct mpc52xx_psc));
+
+       ret = request_irq(mps->irq, mpc512x_psc_spi_isr, IRQF_SHARED,
+                         "mpc512x-psc-spi", mps);
+       if (ret)
+               goto free_master;
+
+       ret = mpc512x_psc_spi_port_config(master, mps);
+       if (ret < 0)
+               goto free_irq;
+
+       spin_lock_init(&mps->lock);
+       init_completion(&mps->done);
+       INIT_WORK(&mps->work, mpc512x_psc_spi_work);
+       INIT_LIST_HEAD(&mps->queue);
+
+       mps->workqueue =
+               create_singlethread_workqueue(dev_name(master->dev.parent));
+       if (mps->workqueue == NULL) {
+               ret = -EBUSY;
+               goto free_irq;
+       }
+
+       ret = spi_register_master(master);
+       if (ret < 0)
+               goto unreg_master;
+
+       return ret;
+
+unreg_master:
+       destroy_workqueue(mps->workqueue);
+free_irq:
+       free_irq(mps->irq, mps);
+free_master:
+       if (mps->psc)
+               iounmap(mps->psc);
+       spi_master_put(master);
+
+       return ret;
+}
+
+static int __exit mpc512x_psc_spi_do_remove(struct device *dev)
+{
+       struct spi_master *master = dev_get_drvdata(dev);
+       struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
+
+       flush_workqueue(mps->workqueue);
+       destroy_workqueue(mps->workqueue);
+       spi_unregister_master(master);
+       free_irq(mps->irq, mps);
+       if (mps->psc)
+               iounmap(mps->psc);
+
+       return 0;
+}
+
+static int __init mpc512x_psc_spi_of_probe(struct of_device *op,
+                                          const struct of_device_id *match)
+{
+       const u32 *regaddr_p;
+       u64 regaddr64, size64;
+       s16 id = -1;
+
+       regaddr_p = of_get_address(op->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);
+
+       /* 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);
+               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);
+                       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);
+}
+
+static int __exit mpc512x_psc_spi_of_remove(struct of_device *op)
+{
+       return mpc512x_psc_spi_do_remove(&op->dev);
+}
+
+static struct of_device_id mpc512x_psc_spi_of_match[] = {
+       { .compatible = "fsl,mpc5121-psc-spi", },
+       {},
+};
+
+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,
+       },
+};
+
+static int __init mpc512x_psc_spi_init(void)
+{
+       return of_register_platform_driver(&mpc512x_psc_spi_of_driver);
+}
+module_init(mpc512x_psc_spi_init);
+
+static void __exit mpc512x_psc_spi_exit(void)
+{
+       of_unregister_platform_driver(&mpc512x_psc_spi_of_driver);
+}
+module_exit(mpc512x_psc_spi_exit);
+
+MODULE_AUTHOR("John Rigby");
+MODULE_DESCRIPTION("MPC512x PSC SPI Driver");
+MODULE_LICENSE("GPL");
index 77d4cc88edea137251be529ded2a53dc11a8aa61..7104cb739da7eceab4af5a2bcf644c0aaa239d26 100644 (file)
@@ -472,18 +472,18 @@ static int __init mpc52xx_psc_spi_of_probe(struct of_device *op,
        s16 id = -1;
        int rc;
 
-       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 (1..6, 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 > 5) {
                        dev_err(&op->dev, "Invalid cell-index property\n");
                        return -EINVAL;
@@ -492,9 +492,10 @@ static int __init mpc52xx_psc_spi_of_probe(struct of_device *op,
        }
 
        rc = mpc52xx_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);
        if (rc == 0)
-               of_register_spi_devices(dev_get_drvdata(&op->dev), op->node);
+               of_register_spi_devices(dev_get_drvdata(&op->dev),
+                                       op->dev.of_node);
 
        return rc;
 }
@@ -513,14 +514,12 @@ static const struct of_device_id mpc52xx_psc_spi_of_match[] = {
 MODULE_DEVICE_TABLE(of, mpc52xx_psc_spi_of_match);
 
 static struct of_platform_driver mpc52xx_psc_spi_of_driver = {
-       .owner = THIS_MODULE,
-       .name = "mpc52xx-psc-spi",
-       .match_table = mpc52xx_psc_spi_of_match,
        .probe = mpc52xx_psc_spi_of_probe,
        .remove = __exit_p(mpc52xx_psc_spi_of_remove),
        .driver = {
                .name = "mpc52xx-psc-spi",
                .owner = THIS_MODULE,
+               .of_match_table = mpc52xx_psc_spi_of_match,
        },
 };
 
index cd68f1ce5cc3ffa78dcd7d6ad49bc49396dee834..b1a76bff775f8f2c11e0c1d35efc41039fa95acf 100644 (file)
@@ -403,7 +403,7 @@ static int __devinit mpc52xx_spi_probe(struct of_device *op,
 
        /* MMIO registers */
        dev_dbg(&op->dev, "probing mpc5200 SPI device\n");
-       regs = of_iomap(op->node, 0);
+       regs = of_iomap(op->dev.of_node, 0);
        if (!regs)
                return -ENODEV;
 
@@ -445,11 +445,11 @@ static int __devinit mpc52xx_spi_probe(struct of_device *op,
        ms = spi_master_get_devdata(master);
        ms->master = master;
        ms->regs = regs;
-       ms->irq0 = irq_of_parse_and_map(op->node, 0);
-       ms->irq1 = irq_of_parse_and_map(op->node, 1);
+       ms->irq0 = irq_of_parse_and_map(op->dev.of_node, 0);
+       ms->irq1 = irq_of_parse_and_map(op->dev.of_node, 1);
        ms->state = mpc52xx_spi_fsmstate_idle;
-       ms->ipb_freq = mpc5xxx_get_bus_frequency(op->node);
-       ms->gpio_cs_count = of_gpio_count(op->node);
+       ms->ipb_freq = mpc5xxx_get_bus_frequency(op->dev.of_node);
+       ms->gpio_cs_count = of_gpio_count(op->dev.of_node);
        if (ms->gpio_cs_count > 0) {
                master->num_chipselect = ms->gpio_cs_count;
                ms->gpio_cs = kmalloc(ms->gpio_cs_count * sizeof(unsigned int),
@@ -460,7 +460,7 @@ static int __devinit mpc52xx_spi_probe(struct of_device *op,
                }
 
                for (i = 0; i < ms->gpio_cs_count; i++) {
-                       gpio_cs = of_get_gpio(op->node, i);
+                       gpio_cs = of_get_gpio(op->dev.of_node, i);
                        if (gpio_cs < 0) {
                                dev_err(&op->dev,
                                        "could not parse the gpio field "
@@ -512,7 +512,7 @@ static int __devinit mpc52xx_spi_probe(struct of_device *op,
        if (rc)
                goto err_register;
 
-       of_register_spi_devices(master, op->node);
+       of_register_spi_devices(master, op->dev.of_node);
        dev_info(&ms->master->dev, "registered MPC5200 SPI bus\n");
 
        return rc;
@@ -558,9 +558,11 @@ static const struct of_device_id mpc52xx_spi_match[] __devinitconst = {
 MODULE_DEVICE_TABLE(of, mpc52xx_spi_match);
 
 static struct of_platform_driver mpc52xx_spi_of_driver = {
-       .owner = THIS_MODULE,
-       .name = "mpc52xx-spi",
-       .match_table = mpc52xx_spi_match,
+       .driver = {
+               .name = "mpc52xx-spi",
+               .owner = THIS_MODULE,
+               .of_match_table = mpc52xx_spi_match,
+       },
        .probe = mpc52xx_spi_probe,
        .remove = __exit_p(mpc52xx_spi_remove),
 };
index e0de0d0eedeaf26909075194abce7267b61dcddd..b3a94ca0a75a01abc643f96fb3209b6a359d1dc6 100644 (file)
@@ -38,7 +38,7 @@
 
 #include <plat/dma.h>
 #include <plat/clock.h>
-
+#include <plat/mcspi.h>
 
 #define OMAP2_MCSPI_MAX_FREQ           48000000
 
@@ -113,7 +113,7 @@ struct omap2_mcspi_dma {
 /* use PIO for small transfers, avoiding DMA setup/teardown overhead and
  * cache operations; better heuristics consider wordsize and bitrate.
  */
-#define DMA_MIN_BYTES                  8
+#define DMA_MIN_BYTES                  160
 
 
 struct omap2_mcspi {
@@ -229,6 +229,8 @@ static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable)
 
        l = enable ? OMAP2_MCSPI_CHCTRL_EN : 0;
        mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, l);
+       /* Flash post-writes */
+       mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCTRL0);
 }
 
 static void omap2_mcspi_force_cs(struct spi_device *spi, int cs_active)
@@ -303,11 +305,14 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
        unsigned int            count, c;
        unsigned long           base, tx_reg, rx_reg;
        int                     word_len, data_type, element_count;
+       int                     elements;
+       u32                     l;
        u8                      * rx;
        const u8                * tx;
 
        mcspi = spi_master_get_devdata(spi->master);
        mcspi_dma = &mcspi->dma_channels[spi->chip_select];
+       l = mcspi_cached_chconf0(spi);
 
        count = xfer->len;
        c = count;
@@ -346,8 +351,12 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
        }
 
        if (rx != NULL) {
+               elements = element_count - 1;
+               if (l & OMAP2_MCSPI_CHCONF_TURBO)
+                       elements--;
+
                omap_set_dma_transfer_params(mcspi_dma->dma_rx_channel,
-                               data_type, element_count - 1, 1,
+                               data_type, elements, 1,
                                OMAP_DMA_SYNC_ELEMENT,
                                mcspi_dma->dma_rx_sync_dev, 1);
 
@@ -379,17 +388,42 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
                wait_for_completion(&mcspi_dma->dma_rx_completion);
                dma_unmap_single(NULL, xfer->rx_dma, count, DMA_FROM_DEVICE);
                omap2_mcspi_set_enable(spi, 0);
+
+               if (l & OMAP2_MCSPI_CHCONF_TURBO) {
+
+                       if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
+                                  & OMAP2_MCSPI_CHSTAT_RXS)) {
+                               u32 w;
+
+                               w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
+                               if (word_len <= 8)
+                                       ((u8 *)xfer->rx_buf)[elements++] = w;
+                               else if (word_len <= 16)
+                                       ((u16 *)xfer->rx_buf)[elements++] = w;
+                               else /* word_len <= 32 */
+                                       ((u32 *)xfer->rx_buf)[elements++] = w;
+                       } else {
+                               dev_err(&spi->dev,
+                                       "DMA RX penultimate word empty");
+                               count -= (word_len <= 8)  ? 2 :
+                                       (word_len <= 16) ? 4 :
+                                       /* word_len <= 32 */ 8;
+                               omap2_mcspi_set_enable(spi, 1);
+                               return count;
+                       }
+               }
+
                if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
                                & OMAP2_MCSPI_CHSTAT_RXS)) {
                        u32 w;
 
                        w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
                        if (word_len <= 8)
-                               ((u8 *)xfer->rx_buf)[element_count - 1] = w;
+                               ((u8 *)xfer->rx_buf)[elements] = w;
                        else if (word_len <= 16)
-                               ((u16 *)xfer->rx_buf)[element_count - 1] = w;
+                               ((u16 *)xfer->rx_buf)[elements] = w;
                        else /* word_len <= 32 */
-                               ((u32 *)xfer->rx_buf)[element_count - 1] = w;
+                               ((u32 *)xfer->rx_buf)[elements] = w;
                } else {
                        dev_err(&spi->dev, "DMA RX last word empty");
                        count -= (word_len <= 8)  ? 1 :
@@ -433,7 +467,6 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
        word_len = cs->word_len;
 
        l = mcspi_cached_chconf0(spi);
-       l &= ~OMAP2_MCSPI_CHCONF_TRM_MASK;
 
        /* We store the pre-calculated register addresses on stack to speed
         * up the transfer loop. */
@@ -468,11 +501,26 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                                        dev_err(&spi->dev, "RXS timed out\n");
                                        goto out;
                                }
-                               /* prevent last RX_ONLY read from triggering
-                                * more word i/o: switch to rx+tx
-                                */
-                               if (c == 0 && tx == NULL)
-                                       mcspi_write_chconf0(spi, l);
+
+                               if (c == 1 && tx == NULL &&
+                                   (l & OMAP2_MCSPI_CHCONF_TURBO)) {
+                                       omap2_mcspi_set_enable(spi, 0);
+                                       *rx++ = __raw_readl(rx_reg);
+#ifdef VERBOSE
+                                       dev_dbg(&spi->dev, "read-%d %02x\n",
+                                                   word_len, *(rx - 1));
+#endif
+                                       if (mcspi_wait_for_reg_bit(chstat_reg,
+                                               OMAP2_MCSPI_CHSTAT_RXS) < 0) {
+                                               dev_err(&spi->dev,
+                                                       "RXS timed out\n");
+                                               goto out;
+                                       }
+                                       c = 0;
+                               } else if (c == 0 && tx == NULL) {
+                                       omap2_mcspi_set_enable(spi, 0);
+                               }
+
                                *rx++ = __raw_readl(rx_reg);
 #ifdef VERBOSE
                                dev_dbg(&spi->dev, "read-%d %02x\n",
@@ -506,11 +554,26 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                                        dev_err(&spi->dev, "RXS timed out\n");
                                        goto out;
                                }
-                               /* prevent last RX_ONLY read from triggering
-                                * more word i/o: switch to rx+tx
-                                */
-                               if (c == 0 && tx == NULL)
-                                       mcspi_write_chconf0(spi, l);
+
+                               if (c == 2 && tx == NULL &&
+                                   (l & OMAP2_MCSPI_CHCONF_TURBO)) {
+                                       omap2_mcspi_set_enable(spi, 0);
+                                       *rx++ = __raw_readl(rx_reg);
+#ifdef VERBOSE
+                                       dev_dbg(&spi->dev, "read-%d %04x\n",
+                                                   word_len, *(rx - 1));
+#endif
+                                       if (mcspi_wait_for_reg_bit(chstat_reg,
+                                               OMAP2_MCSPI_CHSTAT_RXS) < 0) {
+                                               dev_err(&spi->dev,
+                                                       "RXS timed out\n");
+                                               goto out;
+                                       }
+                                       c = 0;
+                               } else if (c == 0 && tx == NULL) {
+                                       omap2_mcspi_set_enable(spi, 0);
+                               }
+
                                *rx++ = __raw_readl(rx_reg);
 #ifdef VERBOSE
                                dev_dbg(&spi->dev, "read-%d %04x\n",
@@ -544,11 +607,26 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                                        dev_err(&spi->dev, "RXS timed out\n");
                                        goto out;
                                }
-                               /* prevent last RX_ONLY read from triggering
-                                * more word i/o: switch to rx+tx
-                                */
-                               if (c == 0 && tx == NULL)
-                                       mcspi_write_chconf0(spi, l);
+
+                               if (c == 4 && tx == NULL &&
+                                   (l & OMAP2_MCSPI_CHCONF_TURBO)) {
+                                       omap2_mcspi_set_enable(spi, 0);
+                                       *rx++ = __raw_readl(rx_reg);
+#ifdef VERBOSE
+                                       dev_dbg(&spi->dev, "read-%d %08x\n",
+                                                   word_len, *(rx - 1));
+#endif
+                                       if (mcspi_wait_for_reg_bit(chstat_reg,
+                                               OMAP2_MCSPI_CHSTAT_RXS) < 0) {
+                                               dev_err(&spi->dev,
+                                                       "RXS timed out\n");
+                                               goto out;
+                                       }
+                                       c = 0;
+                               } else if (c == 0 && tx == NULL) {
+                                       omap2_mcspi_set_enable(spi, 0);
+                               }
+
                                *rx++ = __raw_readl(rx_reg);
 #ifdef VERBOSE
                                dev_dbg(&spi->dev, "read-%d %08x\n",
@@ -568,6 +646,7 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                        dev_err(&spi->dev, "EOT timed out\n");
        }
 out:
+       omap2_mcspi_set_enable(spi, 1);
        return count - c;
 }
 
@@ -755,7 +834,6 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)
        struct omap2_mcspi_cs   *cs;
 
        mcspi = spi_master_get_devdata(spi->master);
-       mcspi_dma = &mcspi->dma_channels[spi->chip_select];
 
        if (spi->controller_state) {
                /* Unlink controller state from context save list */
@@ -765,13 +843,17 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)
                kfree(spi->controller_state);
        }
 
-       if (mcspi_dma->dma_rx_channel != -1) {
-               omap_free_dma(mcspi_dma->dma_rx_channel);
-               mcspi_dma->dma_rx_channel = -1;
-       }
-       if (mcspi_dma->dma_tx_channel != -1) {
-               omap_free_dma(mcspi_dma->dma_tx_channel);
-               mcspi_dma->dma_tx_channel = -1;
+       if (spi->chip_select < spi->master->num_chipselect) {
+               mcspi_dma = &mcspi->dma_channels[spi->chip_select];
+
+               if (mcspi_dma->dma_rx_channel != -1) {
+                       omap_free_dma(mcspi_dma->dma_rx_channel);
+                       mcspi_dma->dma_rx_channel = -1;
+               }
+               if (mcspi_dma->dma_tx_channel != -1) {
+                       omap_free_dma(mcspi_dma->dma_tx_channel);
+                       mcspi_dma->dma_tx_channel = -1;
+               }
        }
 }
 
@@ -797,6 +879,7 @@ static void omap2_mcspi_work(struct work_struct *work)
                struct spi_transfer             *t = NULL;
                int                             cs_active = 0;
                struct omap2_mcspi_cs           *cs;
+               struct omap2_mcspi_device_config *cd;
                int                             par_override = 0;
                int                             status = 0;
                u32                             chconf;
@@ -809,6 +892,7 @@ static void omap2_mcspi_work(struct work_struct *work)
 
                spi = m->spi;
                cs = spi->controller_state;
+               cd = spi->controller_data;
 
                omap2_mcspi_set_enable(spi, 1);
                list_for_each_entry(t, &m->transfers, transfer_list) {
@@ -832,10 +916,19 @@ static void omap2_mcspi_work(struct work_struct *work)
 
                        chconf = mcspi_cached_chconf0(spi);
                        chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK;
+                       chconf &= ~OMAP2_MCSPI_CHCONF_TURBO;
+
                        if (t->tx_buf == NULL)
                                chconf |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY;
                        else if (t->rx_buf == NULL)
                                chconf |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY;
+
+                       if (cd && cd->turbo_mode && t->tx_buf == NULL) {
+                               /* Turbo mode is for more than one word */
+                               if (t->len > ((cs->word_len + 7) >> 3))
+                                       chconf |= OMAP2_MCSPI_CHCONF_TURBO;
+                       }
+
                        mcspi_write_chconf0(spi, chconf);
 
                        if (t->len) {
diff --git a/drivers/spi/spi_bitbang_txrx.h b/drivers/spi/spi_bitbang_txrx.h
new file mode 100644 (file)
index 0000000..fc033bb
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Mix this utility code with some glue code to get one of several types of
+ * simple SPI master driver.  Two do polled word-at-a-time I/O:
+ *
+ *   - GPIO/parport bitbangers.  Provide chipselect() and txrx_word[](),
+ *     expanding the per-word routines from the inline templates below.
+ *
+ *   - Drivers for controllers resembling bare shift registers.  Provide
+ *     chipselect() and txrx_word[](), with custom setup()/cleanup() methods
+ *     that use your controller's clock and chipselect registers.
+ *
+ * Some hardware works well with requests at spi_transfer scope:
+ *
+ *   - Drivers leveraging smarter hardware, with fifos or DMA; or for half
+ *     duplex (MicroWire) controllers.  Provide chipselect() and txrx_bufs(),
+ *     and custom setup()/cleanup() methods.
+ */
+
+/*
+ * The code that knows what GPIO pins do what should have declared four
+ * functions, ideally as inlines, before including this header:
+ *
+ *  void setsck(struct spi_device *, int is_on);
+ *  void setmosi(struct spi_device *, int is_on);
+ *  int getmiso(struct spi_device *);
+ *  void spidelay(unsigned);
+ *
+ * setsck()'s is_on parameter is a zero/nonzero boolean.
+ *
+ * setmosi()'s is_on parameter is a zero/nonzero boolean.
+ *
+ * getmiso() is required to return 0 or 1 only. Any other value is invalid
+ * and will result in improper operation.
+ *
+ * A non-inlined routine would call bitbang_txrx_*() routines.  The
+ * main loop could easily compile down to a handful of instructions,
+ * especially if the delay is a NOP (to run at peak speed).
+ *
+ * Since this is software, the timings may not be exactly what your board's
+ * chips need ... there may be several reasons you'd need to tweak timings
+ * in these routines, not just make to make it faster or slower to match a
+ * particular CPU clock rate.
+ */
+
+static inline u32
+bitbang_txrx_be_cpha0(struct spi_device *spi,
+               unsigned nsecs, unsigned cpol,
+               u32 word, u8 bits)
+{
+       /* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */
+
+       /* clock starts at inactive polarity */
+       for (word <<= (32 - bits); likely(bits); bits--) {
+
+               /* setup MSB (to slave) on trailing edge */
+               setmosi(spi, word & (1 << 31));
+               spidelay(nsecs);        /* T(setup) */
+
+               setsck(spi, !cpol);
+               spidelay(nsecs);
+
+               /* sample MSB (from slave) on leading edge */
+               word <<= 1;
+               word |= getmiso(spi);
+               setsck(spi, cpol);
+       }
+       return word;
+}
+
+static inline u32
+bitbang_txrx_be_cpha1(struct spi_device *spi,
+               unsigned nsecs, unsigned cpol,
+               u32 word, u8 bits)
+{
+       /* if (cpol == 0) this is SPI_MODE_1; else this is SPI_MODE_3 */
+
+       /* clock starts at inactive polarity */
+       for (word <<= (32 - bits); likely(bits); bits--) {
+
+               /* setup MSB (to slave) on leading edge */
+               setsck(spi, !cpol);
+               setmosi(spi, word & (1 << 31));
+               spidelay(nsecs); /* T(setup) */
+
+               setsck(spi, cpol);
+               spidelay(nsecs);
+
+               /* sample MSB (from slave) on trailing edge */
+               word <<= 1;
+               word |= getmiso(spi);
+       }
+       return word;
+}
index c2184866fa9cffc76c5f5af96f34c8956d9e8967..8b52812811110d5a1ff4835813a4f613c5713f0c 100644 (file)
@@ -149,8 +149,7 @@ static void butterfly_chipselect(struct spi_device *spi, int value)
 #define        spidelay(X)     do{}while(0)
 //#define      spidelay        ndelay
 
-#define        EXPAND_BITBANG_TXRX
-#include <linux/spi/spi_bitbang.h>
+#include "spi_bitbang_txrx.h"
 
 static u32
 butterfly_txrx_word_mode0(struct spi_device *spi,
index 26bd03e61855fba412726f23b638066a90abcaa9..7edbd5807e0eb05e1e72242d0e304c034c4ae11b 100644 (file)
@@ -127,8 +127,7 @@ static inline int getmiso(const struct spi_device *spi)
  */
 #define spidelay(nsecs)        do {} while (0)
 
-#define        EXPAND_BITBANG_TXRX
-#include <linux/spi/spi_bitbang.h>
+#include "spi_bitbang_txrx.h"
 
 /*
  * These functions can leverage inline expansion of GPIO calls to shrink
index 568c781ad91c05de9efe0ba653a56729beb30ac6..86fb7b5993db124a763fb6a3ad52a863f96fb450 100644 (file)
@@ -174,8 +174,7 @@ static inline int getmiso(struct spi_device *s)
 }
 /*--------------------------------------------------------------------*/
 
-#define EXPAND_BITBANG_TXRX 1
-#include <linux/spi/spi_bitbang.h>
+#include "spi_bitbang_txrx.h"
 
 static void lm70_chipselect(struct spi_device *spi, int value)
 {
index e324627d97a2db99156cc5e848620a493e26b2cd..ffa111a7e9d443f23cda4287eeeb17d53d323a46 100644 (file)
@@ -241,7 +241,6 @@ static void mpc8xxx_spi_change_mode(struct spi_device *spi)
 
        /* Turn off SPI unit prior changing mode */
        mpc8xxx_spi_write_reg(mode, cs->hw_mode & ~SPMODE_ENABLE);
-       mpc8xxx_spi_write_reg(mode, cs->hw_mode);
 
        /* When in CPM mode, we need to reinit tx and rx. */
        if (mspi->flags & SPI_CPM_MODE) {
@@ -258,7 +257,7 @@ static void mpc8xxx_spi_change_mode(struct spi_device *spi)
                        }
                }
        }
-
+       mpc8xxx_spi_write_reg(mode, cs->hw_mode);
        local_irq_restore(flags);
 }
 
@@ -287,36 +286,12 @@ static void mpc8xxx_spi_chipselect(struct spi_device *spi, int value)
        }
 }
 
-static
-int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
+static int
+mspi_apply_cpu_mode_quirks(struct spi_mpc8xxx_cs *cs,
+                          struct spi_device *spi,
+                          struct mpc8xxx_spi *mpc8xxx_spi,
+                          int bits_per_word)
 {
-       struct mpc8xxx_spi *mpc8xxx_spi;
-       u8 bits_per_word, pm;
-       u32 hz;
-       struct spi_mpc8xxx_cs   *cs = spi->controller_state;
-
-       mpc8xxx_spi = spi_master_get_devdata(spi->master);
-
-       if (t) {
-               bits_per_word = t->bits_per_word;
-               hz = t->speed_hz;
-       } else {
-               bits_per_word = 0;
-               hz = 0;
-       }
-
-       /* spi_transfer level calls that work per-word */
-       if (!bits_per_word)
-               bits_per_word = spi->bits_per_word;
-
-       /* Make sure its a bit width we support [4..16, 32] */
-       if ((bits_per_word < 4)
-           || ((bits_per_word > 16) && (bits_per_word != 32)))
-               return -EINVAL;
-
-       if (!hz)
-               hz = spi->max_speed_hz;
-
        cs->rx_shift = 0;
        cs->tx_shift = 0;
        if (bits_per_word <= 8) {
@@ -340,19 +315,82 @@ int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
                return -EINVAL;
 
        if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE &&
-                       spi->mode & SPI_LSB_FIRST) {
+           spi->mode & SPI_LSB_FIRST) {
                cs->tx_shift = 0;
                if (bits_per_word <= 8)
                        cs->rx_shift = 8;
                else
                        cs->rx_shift = 0;
        }
-
        mpc8xxx_spi->rx_shift = cs->rx_shift;
        mpc8xxx_spi->tx_shift = cs->tx_shift;
        mpc8xxx_spi->get_rx = cs->get_rx;
        mpc8xxx_spi->get_tx = cs->get_tx;
 
+       return bits_per_word;
+}
+
+static int
+mspi_apply_qe_mode_quirks(struct spi_mpc8xxx_cs *cs,
+                         struct spi_device *spi,
+                         int bits_per_word)
+{
+       /* QE uses Little Endian for words > 8
+        * so transform all words > 8 into 8 bits
+        * Unfortnatly that doesn't work for LSB so
+        * reject these for now */
+       /* Note: 32 bits word, LSB works iff
+        * tfcr/rfcr is set to CPMFCR_GBL */
+       if (spi->mode & SPI_LSB_FIRST &&
+           bits_per_word > 8)
+               return -EINVAL;
+       if (bits_per_word > 8)
+               return 8; /* pretend its 8 bits */
+       return bits_per_word;
+}
+
+static
+int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
+{
+       struct mpc8xxx_spi *mpc8xxx_spi;
+       int bits_per_word;
+       u8 pm;
+       u32 hz;
+       struct spi_mpc8xxx_cs   *cs = spi->controller_state;
+
+       mpc8xxx_spi = spi_master_get_devdata(spi->master);
+
+       if (t) {
+               bits_per_word = t->bits_per_word;
+               hz = t->speed_hz;
+       } else {
+               bits_per_word = 0;
+               hz = 0;
+       }
+
+       /* spi_transfer level calls that work per-word */
+       if (!bits_per_word)
+               bits_per_word = spi->bits_per_word;
+
+       /* Make sure its a bit width we support [4..16, 32] */
+       if ((bits_per_word < 4)
+           || ((bits_per_word > 16) && (bits_per_word != 32)))
+               return -EINVAL;
+
+       if (!hz)
+               hz = spi->max_speed_hz;
+
+       if (!(mpc8xxx_spi->flags & SPI_CPM_MODE))
+               bits_per_word = mspi_apply_cpu_mode_quirks(cs, spi,
+                                                          mpc8xxx_spi,
+                                                          bits_per_word);
+       else if (mpc8xxx_spi->flags & SPI_QE)
+               bits_per_word = mspi_apply_qe_mode_quirks(cs, spi,
+                                                         bits_per_word);
+
+       if (bits_per_word < 0)
+               return bits_per_word;
+
        if (bits_per_word == 32)
                bits_per_word = 0;
        else
@@ -438,7 +476,7 @@ static int mpc8xxx_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
                        dev_err(dev, "unable to map tx dma\n");
                        return -ENOMEM;
                }
-       } else {
+       } else if (t->tx_buf) {
                mspi->tx_dma = t->tx_dma;
        }
 
@@ -449,7 +487,7 @@ static int mpc8xxx_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
                        dev_err(dev, "unable to map rx dma\n");
                        goto err_rx_dma;
                }
-       } else {
+       } else if (t->rx_buf) {
                mspi->rx_dma = t->rx_dma;
        }
 
@@ -477,7 +515,7 @@ static void mpc8xxx_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi)
 
        if (mspi->map_tx_dma)
                dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE);
-       if (mspi->map_tx_dma)
+       if (mspi->map_rx_dma)
                dma_unmap_single(dev, mspi->rx_dma, t->len, DMA_FROM_DEVICE);
        mspi->xfer_in_progress = NULL;
 }
@@ -797,7 +835,7 @@ static void mpc8xxx_spi_free_dummy_rx(void)
 static unsigned long mpc8xxx_spi_cpm_get_pram(struct mpc8xxx_spi *mspi)
 {
        struct device *dev = mspi->dev;
-       struct device_node *np = dev_archdata_get_node(&dev->archdata);
+       struct device_node *np = dev->of_node;
        const u32 *iprop;
        int size;
        unsigned long spi_base_ofs;
@@ -851,7 +889,7 @@ static unsigned long mpc8xxx_spi_cpm_get_pram(struct mpc8xxx_spi *mspi)
 static int mpc8xxx_spi_cpm_init(struct mpc8xxx_spi *mspi)
 {
        struct device *dev = mspi->dev;
-       struct device_node *np = dev_archdata_get_node(&dev->archdata);
+       struct device_node *np = dev->of_node;
        const u32 *iprop;
        int size;
        unsigned long pram_ofs;
@@ -1123,7 +1161,7 @@ static void mpc8xxx_spi_cs_control(struct spi_device *spi, bool on)
 
 static int of_mpc8xxx_spi_get_chipselects(struct device *dev)
 {
-       struct device_node *np = dev_archdata_get_node(&dev->archdata);
+       struct device_node *np = dev->of_node;
        struct fsl_spi_platform_data *pdata = dev->platform_data;
        struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
        unsigned int ngpios;
@@ -1224,7 +1262,7 @@ static int __devinit of_mpc8xxx_spi_probe(struct of_device *ofdev,
                                          const struct of_device_id *ofid)
 {
        struct device *dev = &ofdev->dev;
-       struct device_node *np = ofdev->node;
+       struct device_node *np = ofdev->dev.of_node;
        struct mpc8xxx_spi_probe_info *pinfo;
        struct fsl_spi_platform_data *pdata;
        struct spi_master *master;
@@ -1312,8 +1350,11 @@ static const struct of_device_id of_mpc8xxx_spi_match[] = {
 MODULE_DEVICE_TABLE(of, of_mpc8xxx_spi_match);
 
 static struct of_platform_driver of_mpc8xxx_spi_driver = {
-       .name           = "mpc8xxx_spi",
-       .match_table    = of_mpc8xxx_spi_match,
+       .driver = {
+               .name = "mpc8xxx_spi",
+               .owner = THIS_MODULE,
+               .of_match_table = of_mpc8xxx_spi_match,
+       },
        .probe          = of_mpc8xxx_spi_probe,
        .remove         = __devexit_p(of_mpc8xxx_spi_remove),
 };
index 7cb5ff37f6e2662254eb66a321b1be2acb2c604b..19c0b3b34fce0160d7cb4d0b0c16f14d8143671d 100644 (file)
@@ -587,12 +587,12 @@ static const struct of_device_id spi_ppc4xx_of_match[] = {
 MODULE_DEVICE_TABLE(of, spi_ppc4xx_of_match);
 
 static struct of_platform_driver spi_ppc4xx_of_driver = {
-       .match_table = spi_ppc4xx_of_match,
        .probe = spi_ppc4xx_of_probe,
        .remove = __exit_p(spi_ppc4xx_of_remove),
        .driver = {
                .name = DRIVER_NAME,
                .owner = THIS_MODULE,
+               .of_match_table = spi_ppc4xx_of_match,
        },
 };
 
index bbf9371cd2846c56e3650b4e7f88b8b05a820616..8979a75dbd7b5cc2d0c77459fcab43966f36c03e 100644 (file)
@@ -58,8 +58,7 @@ static inline u32 getmiso(struct spi_device *dev)
 
 #define spidelay(x) ndelay(x)
 
-#define        EXPAND_BITBANG_TXRX
-#include <linux/spi/spi_bitbang.h>
+#include "spi_bitbang_txrx.h"
 
 
 static u32 s3c2410_spigpio_txrx_mode0(struct spi_device *spi,
index a65c12ffa73352a79a160dcc5ae665fecb862dc1..a511be7961a0a843f0d46c0b37dfb0c3dfd06175 100644 (file)
@@ -78,8 +78,7 @@ static inline u32 getmiso(struct spi_device *dev)
 
 #define spidelay(x) ndelay(x)
 
-#define EXPAND_BITBANG_TXRX
-#include <linux/spi/spi_bitbang.h>
+#include "spi_bitbang_txrx.h"
 
 static u32 sh_sci_spi_txrx_mode0(struct spi_device *spi,
                                      unsigned nsecs, u32 word, u8 bits)
index 748d33a76d290286c6435ff3d11965c2e023525d..4654805b08d887f8b44460ef174941040effc0b6 100644 (file)
@@ -48,13 +48,13 @@ static int __devinit xilinx_spi_of_probe(struct of_device *ofdev,
        const u32 *prop;
        int len;
 
-       rc = of_address_to_resource(ofdev->node, 0, &r_mem);
+       rc = of_address_to_resource(ofdev->dev.of_node, 0, &r_mem);
        if (rc) {
                dev_warn(&ofdev->dev, "invalid address\n");
                return rc;
        }
 
-       rc = of_irq_to_resource(ofdev->node, 0, &r_irq);
+       rc = of_irq_to_resource(ofdev->dev.of_node, 0, &r_irq);
        if (rc == NO_IRQ) {
                dev_warn(&ofdev->dev, "no IRQ found\n");
                return -ENODEV;
@@ -67,7 +67,7 @@ static int __devinit xilinx_spi_of_probe(struct of_device *ofdev,
                return -ENOMEM;
 
        /* number of slave select bits is required */
-       prop = of_get_property(ofdev->node, "xlnx,num-ss-bits", &len);
+       prop = of_get_property(ofdev->dev.of_node, "xlnx,num-ss-bits", &len);
        if (!prop || len < sizeof(*prop)) {
                dev_warn(&ofdev->dev, "no 'xlnx,num-ss-bits' property\n");
                return -EINVAL;
@@ -81,7 +81,7 @@ static int __devinit xilinx_spi_of_probe(struct of_device *ofdev,
        dev_set_drvdata(&ofdev->dev, master);
 
        /* Add any subnodes on the SPI bus */
-       of_register_spi_devices(master, ofdev->node);
+       of_register_spi_devices(master, ofdev->dev.of_node);
 
        return 0;
 }
@@ -109,12 +109,12 @@ static const struct of_device_id xilinx_spi_of_match[] = {
 MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
 
 static struct of_platform_driver xilinx_spi_of_driver = {
-       .match_table = xilinx_spi_of_match,
        .probe = xilinx_spi_of_probe,
        .remove = __exit_p(xilinx_spi_of_remove),
        .driver = {
                .name = "xilinx-xps-spi",
                .owner = THIS_MODULE,
+               .of_match_table = xilinx_spi_of_match,
        },
 };
 
index 49f0d31c118a4103e8b56ff3c1d5d8f74a1e9a21..cf7c34a994590ef4d004ed5f3c79b28a8e383068 100644 (file)
@@ -242,13 +242,13 @@ static void saa7134_go7007_irq_ts_done(struct saa7134_dev *dev,
                printk(KERN_DEBUG "saa7134-go7007: irq: lost %ld\n",
                                (status >> 16) & 0x0f);
        if (status & 0x100000) {
-               dma_sync_single(&dev->pci->dev,
-                               saa->bottom_dma, PAGE_SIZE, DMA_FROM_DEVICE);
+               dma_sync_single_for_cpu(&dev->pci->dev,
+                                       saa->bottom_dma, PAGE_SIZE, DMA_FROM_DEVICE);
                go7007_parse_video_stream(go, saa->bottom, PAGE_SIZE);
                saa_writel(SAA7134_RS_BA2(5), cpu_to_le32(saa->bottom_dma));
        } else {
-               dma_sync_single(&dev->pci->dev,
-                               saa->top_dma, PAGE_SIZE, DMA_FROM_DEVICE);
+               dma_sync_single_for_cpu(&dev->pci->dev,
+                                       saa->top_dma, PAGE_SIZE, DMA_FROM_DEVICE);
                go7007_parse_video_stream(go, saa->top, PAGE_SIZE);
                saa_writel(SAA7134_RS_BA1(5), cpu_to_le32(saa->top_dma));
        }
index 9286e863b0e74d70a5aa32b94e5e0cfb9357393a..643b413d9f0f395fca978a56641cbe582beee773 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/slab.h>
 #include <linux/statfs.h>
 #include <linux/writeback.h>
-#include <linux/quotaops.h>
 
 #include "netfs.h"
 
@@ -880,7 +879,7 @@ static struct inode *pohmelfs_alloc_inode(struct super_block *sb)
 /*
  * We want fsync() to work on POHMELFS.
  */
-static int pohmelfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+static int pohmelfs_fsync(struct file *file, int datasync)
 {
        struct inode *inode = file->f_mapping->host;
        struct writeback_control wbc = {
@@ -969,13 +968,6 @@ int pohmelfs_setattr_raw(struct inode *inode, struct iattr *attr)
                goto err_out_exit;
        }
 
-       if ((attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
-           (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
-               err = dquot_transfer(inode, attr);
-               if (err)
-                       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);
index 21a95ffdfb865aa461e2eb5bb63b9b09f925b331..a09038542f26c5de83a71cd93cbbf6d3fa44ed6d 100644 (file)
@@ -2810,17 +2810,6 @@ void UserCfgInit(struct rt_rtmp_adapter *pAd)
 }
 
 /* IRQL = PASSIVE_LEVEL */
-u8 BtoH(char ch)
-{
-       if (ch >= '0' && ch <= '9')
-               return (ch - '0');      /* Handle numerals */
-       if (ch >= 'A' && ch <= 'F')
-               return (ch - 'A' + 0xA);        /* Handle capitol hex digits */
-       if (ch >= 'a' && ch <= 'f')
-               return (ch - 'a' + 0xA);        /* Handle small hex digits */
-       return (255);
-}
-
 /* */
 /*  FUNCTION: AtoH(char *, u8 *, int) */
 /* */
@@ -2847,8 +2836,8 @@ void AtoH(char *src, u8 *dest, int destlen)
        destTemp = (u8 *)dest;
 
        while (destlen--) {
-               *destTemp = BtoH(*srcptr++) << 4;       /* Put 1st ascii byte in upper nibble. */
-               *destTemp += BtoH(*srcptr++);   /* Add 2nd ascii byte to above. */
+               *destTemp = hex_to_bin(*srcptr++) << 4; /* Put 1st ascii byte in upper nibble. */
+               *destTemp += hex_to_bin(*srcptr++);     /* Add 2nd ascii byte to above. */
                destTemp++;
        }
 }
index ab525ee1504257632640ef5126012b0cac28c1b2..82b6e783b33fd4916f65cbe0a978850019a3ec5d 100644 (file)
@@ -2356,8 +2356,6 @@ void RTMPMoveMemory(void *pDest, void *pSrc, unsigned long Length);
 
 void AtoH(char *src, u8 *dest, int destlen);
 
-u8 BtoH(char ch);
-
 void RTMPPatchMacBbpBug(struct rt_rtmp_adapter *pAd);
 
 void RTMPInitTimer(struct rt_rtmp_adapter *pAd,
index e89304c725686896b78164543016f8189992295b..b53deee25d74d525faa4692e3539af0cd3ceb369 100644 (file)
@@ -5879,20 +5879,13 @@ out:
 static int ixj_build_filter_cadence(IXJ *j, IXJ_FILTER_CADENCE __user * cp)
 {
        IXJ_FILTER_CADENCE *lcp;
-       lcp = kmalloc(sizeof(IXJ_FILTER_CADENCE), GFP_KERNEL);
-       if (lcp == NULL) {
+       lcp = memdup_user(cp, sizeof(IXJ_FILTER_CADENCE));
+       if (IS_ERR(lcp)) {
                if(ixjdebug & 0x0001) {
-                       printk(KERN_INFO "Could not allocate memory for cadence\n");
+                       printk(KERN_INFO "Could not allocate memory for cadence or could not copy cadence to kernel\n");
                }
-               return -ENOMEM;
+               return PTR_ERR(lcp);
         }
-       if (copy_from_user(lcp, cp, sizeof(IXJ_FILTER_CADENCE))) {
-               if(ixjdebug & 0x0001) {
-                       printk(KERN_INFO "Could not copy cadence to kernel\n");
-               }
-               kfree(lcp);
-               return -EFAULT;
-       }
        if (lcp->filter > 5) {
                if(ixjdebug & 0x0001) {
                        printk(KERN_INFO "Cadence out of range\n");
index 1e9ba4bdffeff65e501751569eb41c5d8944966c..1335456b4f9396284aea64258199cd9575e49924 100644 (file)
@@ -127,8 +127,6 @@ MODULE_PARM_DESC(ModemOption, "default: 0x10,0x00,0x00,0x00,0x20");
 #define ENDPOINT_ISOC_DATA     0x07
 #define ENDPOINT_FIRMWARE      0x05
 
-#define hex2int(c) ( (c >= '0') && (c <= '9') ? (c - '0') : ((c & 0xf) + 9) )
-
 struct speedtch_params {
        unsigned int altsetting;
        unsigned int BMaxDSL;
@@ -669,7 +667,8 @@ static int speedtch_atm_start(struct usbatm_data *usbatm, struct atm_dev *atm_de
        memset(atm_dev->esi, 0, sizeof(atm_dev->esi));
        if (usb_string(usb_dev, usb_dev->descriptor.iSerialNumber, mac_str, sizeof(mac_str)) == 12) {
                for (i = 0; i < 6; i++)
-                       atm_dev->esi[i] = (hex2int(mac_str[i * 2]) * 16) + (hex2int(mac_str[i * 2 + 1]));
+                       atm_dev->esi[i] = (hex_to_bin(mac_str[i * 2]) << 4) +
+                               hex_to_bin(mac_str[i * 2 + 1]);
        }
 
        /* Start modem synchronisation */
index 3537d51073b2e9216e9dd02891894f46e9f0fc63..2928523268b53ac61470959ac6d6cd41519633d1 100644 (file)
@@ -2768,8 +2768,11 @@ static const struct of_device_id qe_udc_match[] __devinitconst = {
 MODULE_DEVICE_TABLE(of, qe_udc_match);
 
 static struct of_platform_driver udc_driver = {
-       .name           = (char *)driver_name,
-       .match_table    = qe_udc_match,
+       .driver = {
+               .name = (char *)driver_name,
+               .owner = THIS_MODULE,
+               .of_match_table = qe_udc_match,
+       },
        .probe          = qe_udc_probe,
        .remove         = __devexit_p(qe_udc_remove),
 #ifdef CONFIG_PM
index 6b8bf8c781c4938c123f475baec357b45dbf0c75..43abf55d8c60fcbc7029d4a0d4545188b9ab4308 100644 (file)
@@ -794,7 +794,7 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
 }
 
 static int
-printer_fsync(struct file *fd, struct dentry *dentry, int datasync)
+printer_fsync(struct file *fd, int datasync)
 {
        struct printer_dev      *dev = fd->private_data;
        unsigned long           flags;
index 868d8ee86756671192a2fd1e93c866ae06121229..04c462ff0ea6af1d6c8e6bf49926c3b1da15d396 100644 (file)
@@ -654,7 +654,7 @@ static int fsg_lun_fsync_sub(struct fsg_lun *curlun)
 
        if (curlun->ro || !filp)
                return 0;
-       return vfs_fsync(filp, filp->f_path.dentry, 1);
+       return vfs_fsync(filp, 1);
 }
 
 static void store_cdrom_address(u8 *dest, int msf, u32 addr)
index ead59f42e69b10e75be28c14a2186573d0723fdd..544ccfd7056ed5ff13d7a3daea6178d22e9efbd6 100644 (file)
@@ -199,8 +199,8 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
        writel(pdata->portsc, hcd->regs + PORTSC_OFFSET);
        mdelay(10);
 
-       /* setup USBCONTROL. */
-       ret = mxc_set_usbcontrol(pdev->id, pdata->flags);
+       /* setup specific usb hw */
+       ret = mxc_initialize_usb_hw(pdev->id, pdata->flags);
        if (ret < 0)
                goto err_init;
 
index 8df33b8a634c4c944bf1c385cbba056f393d09db..5aec92866ab3e1398ac4450ec62f9d9dfe9c195c 100644 (file)
@@ -108,7 +108,7 @@ ppc44x_enable_bmt(struct device_node *dn)
 static int __devinit
 ehci_hcd_ppc_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 = NULL;
        struct resource res;
@@ -274,13 +274,12 @@ MODULE_DEVICE_TABLE(of, ehci_hcd_ppc_of_match);
 
 
 static struct of_platform_driver ehci_hcd_ppc_of_driver = {
-       .name           = "ppc-of-ehci",
-       .match_table    = ehci_hcd_ppc_of_match,
        .probe          = ehci_hcd_ppc_of_probe,
        .remove         = ehci_hcd_ppc_of_remove,
        .shutdown       = ehci_hcd_ppc_of_shutdown,
-       .driver         = {
-               .name   = "ppc-of-ehci",
-               .owner  = THIS_MODULE,
+       .driver = {
+               .name = "ppc-of-ehci",
+               .owner = THIS_MODULE,
+               .of_match_table = ehci_hcd_ppc_of_match,
        },
 };
index f603bb2c0a8eedba86bbbad4370e154e1b9c7b0c..013972bbde57d21bd16c737c1a1e455a1f90876a 100644 (file)
@@ -288,13 +288,12 @@ static const struct of_device_id ehci_hcd_xilinx_of_match[] = {
 MODULE_DEVICE_TABLE(of, ehci_hcd_xilinx_of_match);
 
 static struct of_platform_driver ehci_hcd_xilinx_of_driver = {
-       .name           = "xilinx-of-ehci",
-       .match_table    = ehci_hcd_xilinx_of_match,
        .probe          = ehci_hcd_xilinx_of_probe,
        .remove         = ehci_hcd_xilinx_of_remove,
        .shutdown       = ehci_hcd_xilinx_of_shutdown,
-       .driver         = {
-               .name   = "xilinx-of-ehci",
-               .owner  = THIS_MODULE,
+       .driver = {
+               .name = "xilinx-of-ehci",
+               .owner = THIS_MODULE,
+               .of_match_table = ehci_hcd_xilinx_of_match,
        },
 };
index 90453379a43469237c88ecde2ec2b3a0ba5ed94e..c7c8392a88b9ed02c9dc1ebbd61a190c2cac1ccb 100644 (file)
@@ -565,7 +565,7 @@ static int __devinit of_fhci_probe(struct of_device *ofdev,
                                   const struct of_device_id *ofid)
 {
        struct device *dev = &ofdev->dev;
-       struct device_node *node = ofdev->node;
+       struct device_node *node = dev->of_node;
        struct usb_hcd *hcd;
        struct fhci_hcd *fhci;
        struct resource usb_regs;
@@ -670,7 +670,7 @@ static int __devinit of_fhci_probe(struct of_device *ofdev,
        }
 
        for (j = 0; j < NUM_PINS; j++) {
-               fhci->pins[j] = qe_pin_request(ofdev->node, j);
+               fhci->pins[j] = qe_pin_request(node, j);
                if (IS_ERR(fhci->pins[j])) {
                        ret = PTR_ERR(fhci->pins[j]);
                        dev_err(dev, "can't get pin %d: %d\n", j, ret);
@@ -813,8 +813,11 @@ static const struct of_device_id of_fhci_match[] = {
 MODULE_DEVICE_TABLE(of, of_fhci_match);
 
 static struct of_platform_driver of_fhci_driver = {
-       .name           = "fsl,usb-fhci",
-       .match_table    = of_fhci_match,
+       .driver = {
+               .name = "fsl,usb-fhci",
+               .owner = THIS_MODULE,
+               .of_match_table = of_fhci_match,
+       },
        .probe          = of_fhci_probe,
        .remove         = __devexit_p(of_fhci_remove),
 };
index 8f0259eaa2c73094bbfcfbcbd6905882d40bd0fa..ec85d0c3cc3e79de60700bd480f41bfdc1448f6e 100644 (file)
@@ -31,7 +31,7 @@ static int of_isp1760_probe(struct of_device *dev,
                const struct of_device_id *match)
 {
        struct usb_hcd *hcd;
-       struct device_node *dp = dev->node;
+       struct device_node *dp = dev->dev.of_node;
        struct resource *res;
        struct resource memory;
        struct of_irq oirq;
@@ -120,8 +120,11 @@ static const struct of_device_id of_isp1760_match[] = {
 MODULE_DEVICE_TABLE(of, of_isp1760_match);
 
 static struct of_platform_driver isp1760_of_driver = {
-       .name           = "nxp-isp1760",
-       .match_table    = of_isp1760_match,
+       .driver = {
+               .name = "nxp-isp1760",
+               .owner = THIS_MODULE,
+               .of_match_table = of_isp1760_match,
+       },
        .probe          = of_isp1760_probe,
        .remove         = of_isp1760_remove,
 };
index 103263c230cfd669ff4059909f03a7cae4e3c331..df165917412a85d821084dcd37c991522254e4b2 100644 (file)
@@ -83,7 +83,7 @@ static const struct hc_driver ohci_ppc_of_hc_driver = {
 static int __devinit
 ohci_hcd_ppc_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 ohci_hcd *ohci;
        struct resource res;
@@ -244,18 +244,13 @@ MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match);
 
 
 static struct of_platform_driver ohci_hcd_ppc_of_driver = {
-       .name           = "ppc-of-ohci",
-       .match_table    = ohci_hcd_ppc_of_match,
        .probe          = ohci_hcd_ppc_of_probe,
        .remove         = ohci_hcd_ppc_of_remove,
        .shutdown       = ohci_hcd_ppc_of_shutdown,
-#ifdef CONFIG_PM
-       /*.suspend      = ohci_hcd_ppc_soc_drv_suspend,*/
-       /*.resume       = ohci_hcd_ppc_soc_drv_resume,*/
-#endif
-       .driver         = {
-               .name   = "ppc-of-ohci",
-               .owner  = THIS_MODULE,
+       .driver = {
+               .name = "ppc-of-ohci",
+               .owner = THIS_MODULE,
+               .of_match_table = ohci_hcd_ppc_of_match,
        },
 };
 
index e7fa3644ba6a74ade9300d4cc5384e08bbfb30e2..61c76b13f0f18eed38902054d36943d7ce472dfc 100644 (file)
@@ -954,8 +954,7 @@ static int mon_bin_queued(struct mon_reader_bin *rp)
 
 /*
  */
-static int mon_bin_ioctl(struct inode *inode, struct file *file,
-    unsigned int cmd, unsigned long arg)
+static int mon_bin_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        struct mon_reader_bin *rp = file->private_data;
        // struct mon_bus* mbus = rp->r.m_bus;
@@ -1095,6 +1094,19 @@ static int mon_bin_ioctl(struct inode *inode, struct file *file,
        return ret;
 }
 
+static long mon_bin_unlocked_ioctl(struct file *file, unsigned int cmd,
+                                  unsigned long arg)
+{
+       int ret;
+
+       lock_kernel();
+       ret = mon_bin_ioctl(file, cmd, arg);
+       unlock_kernel();
+
+       return ret;
+}
+
+
 #ifdef CONFIG_COMPAT
 static long mon_bin_compat_ioctl(struct file *file,
     unsigned int cmd, unsigned long arg)
@@ -1148,14 +1160,13 @@ static long mon_bin_compat_ioctl(struct file *file,
                return 0;
 
        case MON_IOCG_STATS:
-               return mon_bin_ioctl(NULL, file, cmd,
-                                           (unsigned long) compat_ptr(arg));
+               return mon_bin_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
 
        case MON_IOCQ_URB_LEN:
        case MON_IOCQ_RING_SIZE:
        case MON_IOCT_RING_SIZE:
        case MON_IOCH_MFLUSH:
-               return mon_bin_ioctl(NULL, file, cmd, arg);
+               return mon_bin_ioctl(file, cmd, arg);
 
        default:
                ;
@@ -1239,7 +1250,7 @@ static const struct file_operations mon_fops_binary = {
        .read =         mon_bin_read,
        /* .write =     mon_text_write, */
        .poll =         mon_bin_poll,
-       .ioctl =        mon_bin_ioctl,
+       .unlocked_ioctl = mon_bin_unlocked_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl = mon_bin_compat_ioctl,
 #endif
index 1becdc3837e6ce5f897d5b6a2e4b0f4dcdd12c3b..8ec94f15a73820ce5a1b26b8ed5d86fa04b6bba4 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/slab.h>
 #include <linux/usb.h>
 #include <linux/fs.h>
+#include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 
 #include "usb_mon.h"
@@ -63,6 +64,6 @@ const struct file_operations mon_fops_stat = {
        .read =         mon_stat_read,
        /* .write =     mon_stat_write, */
        /* .poll =              mon_stat_poll, */
-       /* .ioctl =     mon_stat_ioctl, */
+       /* .unlocked_ioctl =    mon_stat_ioctl, */
        .release =      mon_stat_release,
 };
index aa88911c95045d10e1089ae477b1f43eab7de614..0f41c9195e9bb9942adc2e6e15a43af4a34393e2 100644 (file)
@@ -593,17 +593,17 @@ static long vhost_net_ioctl(struct file *f, unsigned int ioctl,
        int r;
        switch (ioctl) {
        case VHOST_NET_SET_BACKEND:
-               r = copy_from_user(&backend, argp, sizeof backend);
-               if (r < 0)
-                       return r;
+               if (copy_from_user(&backend, argp, sizeof backend))
+                       return -EFAULT;
                return vhost_net_set_backend(n, backend.index, backend.fd);
        case VHOST_GET_FEATURES:
                features = VHOST_FEATURES;
-               return copy_to_user(featurep, &features, sizeof features);
+               if (copy_to_user(featurep, &features, sizeof features))
+                       return -EFAULT;
+               return 0;
        case VHOST_SET_FEATURES:
-               r = copy_from_user(&features, featurep, sizeof features);
-               if (r < 0)
-                       return r;
+               if (copy_from_user(&features, featurep, sizeof features))
+                       return -EFAULT;
                if (features & ~VHOST_FEATURES)
                        return -EOPNOTSUPP;
                return vhost_net_set_features(n, features);
index 750effe0f98b61f7134b69d7b14a85a54723cc45..3b83382e06ebb9fb98fcbfaa95151965fbbb64b3 100644 (file)
@@ -320,10 +320,8 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
 {
        struct vhost_memory mem, *newmem, *oldmem;
        unsigned long size = offsetof(struct vhost_memory, regions);
-       long r;
-       r = copy_from_user(&mem, m, size);
-       if (r)
-               return r;
+       if (copy_from_user(&mem, m, size))
+               return -EFAULT;
        if (mem.padding)
                return -EOPNOTSUPP;
        if (mem.nregions > VHOST_MEMORY_MAX_NREGIONS)
@@ -333,15 +331,16 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
                return -ENOMEM;
 
        memcpy(newmem, &mem, size);
-       r = copy_from_user(newmem->regions, m->regions,
-                          mem.nregions * sizeof *m->regions);
-       if (r) {
+       if (copy_from_user(newmem->regions, m->regions,
+                          mem.nregions * sizeof *m->regions)) {
                kfree(newmem);
-               return r;
+               return -EFAULT;
        }
 
-       if (!memory_access_ok(d, newmem, vhost_has_feature(d, VHOST_F_LOG_ALL)))
+       if (!memory_access_ok(d, newmem, vhost_has_feature(d, VHOST_F_LOG_ALL))) {
+               kfree(newmem);
                return -EFAULT;
+       }
        oldmem = d->memory;
        rcu_assign_pointer(d->memory, newmem);
        synchronize_rcu();
@@ -374,7 +373,7 @@ static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp)
        r = get_user(idx, idxp);
        if (r < 0)
                return r;
-       if (idx > d->nvqs)
+       if (idx >= d->nvqs)
                return -ENOBUFS;
 
        vq = d->vqs + idx;
@@ -389,9 +388,10 @@ static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp)
                        r = -EBUSY;
                        break;
                }
-               r = copy_from_user(&s, argp, sizeof s);
-               if (r < 0)
+               if (copy_from_user(&s, argp, sizeof s)) {
+                       r = -EFAULT;
                        break;
+               }
                if (!s.num || s.num > 0xffff || (s.num & (s.num - 1))) {
                        r = -EINVAL;
                        break;
@@ -405,9 +405,10 @@ static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp)
                        r = -EBUSY;
                        break;
                }
-               r = copy_from_user(&s, argp, sizeof s);
-               if (r < 0)
+               if (copy_from_user(&s, argp, sizeof s)) {
+                       r = -EFAULT;
                        break;
+               }
                if (s.num > 0xffff) {
                        r = -EINVAL;
                        break;
@@ -419,12 +420,14 @@ static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp)
        case VHOST_GET_VRING_BASE:
                s.index = idx;
                s.num = vq->last_avail_idx;
-               r = copy_to_user(argp, &s, sizeof s);
+               if (copy_to_user(argp, &s, sizeof s))
+                       r = -EFAULT;
                break;
        case VHOST_SET_VRING_ADDR:
-               r = copy_from_user(&a, argp, sizeof a);
-               if (r < 0)
+               if (copy_from_user(&a, argp, sizeof a)) {
+                       r = -EFAULT;
                        break;
+               }
                if (a.flags & ~(0x1 << VHOST_VRING_F_LOG)) {
                        r = -EOPNOTSUPP;
                        break;
@@ -477,9 +480,10 @@ static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp)
                vq->used = (void __user *)(unsigned long)a.used_user_addr;
                break;
        case VHOST_SET_VRING_KICK:
-               r = copy_from_user(&f, argp, sizeof f);
-               if (r < 0)
+               if (copy_from_user(&f, argp, sizeof f)) {
+                       r = -EFAULT;
                        break;
+               }
                eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd);
                if (IS_ERR(eventfp)) {
                        r = PTR_ERR(eventfp);
@@ -492,9 +496,10 @@ static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp)
                        filep = eventfp;
                break;
        case VHOST_SET_VRING_CALL:
-               r = copy_from_user(&f, argp, sizeof f);
-               if (r < 0)
+               if (copy_from_user(&f, argp, sizeof f)) {
+                       r = -EFAULT;
                        break;
+               }
                eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd);
                if (IS_ERR(eventfp)) {
                        r = PTR_ERR(eventfp);
@@ -510,9 +515,10 @@ static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp)
                        filep = eventfp;
                break;
        case VHOST_SET_VRING_ERR:
-               r = copy_from_user(&f, argp, sizeof f);
-               if (r < 0)
+               if (copy_from_user(&f, argp, sizeof f)) {
+                       r = -EFAULT;
                        break;
+               }
                eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd);
                if (IS_ERR(eventfp)) {
                        r = PTR_ERR(eventfp);
@@ -575,9 +581,10 @@ long vhost_dev_ioctl(struct vhost_dev *d, unsigned int ioctl, unsigned long arg)
                r = vhost_set_memory(d, argp);
                break;
        case VHOST_SET_LOG_BASE:
-               r = copy_from_user(&p, argp, sizeof p);
-               if (r < 0)
+               if (copy_from_user(&p, argp, sizeof p)) {
+                       r = -EFAULT;
                        break;
+               }
                if ((u64)(unsigned long)p != p) {
                        r = -EFAULT;
                        break;
@@ -806,7 +813,7 @@ static unsigned get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq,
        count = indirect->len / sizeof desc;
        /* Buffers are chained via a 16 bit next field, so
         * we can have at most 2^16 of these. */
-       if (count > USHORT_MAX + 1) {
+       if (count > USHRT_MAX + 1) {
                vq_err(vq, "Indirect buffer length too big: %d\n",
                       indirect->len);
                return -E2BIG;
index 8d406fb689c132330dcaa4972a60cd271f3b348d..f3d7440f00723878b201712e13fdd96a68f6c549 100644 (file)
@@ -80,7 +80,7 @@ struct arcfb_par {
        spinlock_t lock;
 };
 
-static struct fb_fix_screeninfo arcfb_fix __initdata = {
+static struct fb_fix_screeninfo arcfb_fix __devinitdata = {
        .id =           "arcfb",
        .type =         FB_TYPE_PACKED_PIXELS,
        .visual =       FB_VISUAL_MONO01,
@@ -90,7 +90,7 @@ static struct fb_fix_screeninfo arcfb_fix __initdata = {
        .accel =        FB_ACCEL_NONE,
 };
 
-static struct fb_var_screeninfo arcfb_var __initdata = {
+static struct fb_var_screeninfo arcfb_var __devinitdata = {
        .xres           = 128,
        .yres           = 64,
        .xres_virtual   = 128,
@@ -588,7 +588,7 @@ err:
        return retval;
 }
 
-static int arcfb_remove(struct platform_device *dev)
+static int __devexit arcfb_remove(struct platform_device *dev)
 {
        struct fb_info *info = platform_get_drvdata(dev);
 
@@ -602,7 +602,7 @@ static int arcfb_remove(struct platform_device *dev)
 
 static struct platform_driver arcfb_driver = {
        .probe  = arcfb_probe,
-       .remove = arcfb_remove,
+       .remove = __devexit_p(arcfb_remove),
        .driver = {
                .name   = "arcfb",
        },
index 29d72851f85bd1d01aa50448b1cc9f1e34f5924f..f8d69ad36830310e1d9c49332d3835dcdb102c3a 100644 (file)
@@ -1820,10 +1820,6 @@ struct atyclk {
 #define ATYIO_FEATW            0x41545903      /* ATY\03 */
 #endif
 
-#ifndef FBIO_WAITFORVSYNC
-#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
-#endif
-
 static int atyfb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
 {
        struct atyfb_par *par = (struct atyfb_par *) info->par;
index 68d2518fadaa67fc56af119fde89fd7dd49648a3..38ffc3fbcbe411a99f1d7214c664accf790af535 100644 (file)
@@ -222,6 +222,7 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
        data->port = __check_device(pdata, name);
        if (data->port < 0) {
                dev_err(&pdev->dev, "wrong platform data is assigned");
+               kfree(data);
                return -EINVAL;
        }
 
@@ -266,6 +267,7 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
        backlight_update_status(bl);
        return 0;
 out:
+       backlight_device_unregister(bl);
        kfree(data);
        return ret;
 }
index c025c84601b01d805d98bf5336806b6ae8273062..e54a337227ea964c5c6fea4c9bd32fdb5ced97a0 100644 (file)
@@ -8,12 +8,13 @@ menuconfig BACKLIGHT_LCD_SUPPORT
          Enable this to be able to choose the drivers for controlling the
          backlight and the LCD panel on some platforms, for example on PDAs.
 
+if BACKLIGHT_LCD_SUPPORT
+
 #
 # LCD
 #
 config LCD_CLASS_DEVICE
         tristate "Lowlevel LCD controls"
-       depends on BACKLIGHT_LCD_SUPPORT
        default m
        help
          This framework adds support for low-level control of LCD.
@@ -24,31 +25,32 @@ config LCD_CLASS_DEVICE
          To have support for your specific LCD panel you will have to
          select the proper drivers which depend on this option.
 
+if LCD_CLASS_DEVICE
+
 config LCD_CORGI
        tristate "LCD Panel support for SHARP corgi/spitz model"
-       depends on LCD_CLASS_DEVICE && SPI_MASTER && PXA_SHARPSL
+       depends on SPI_MASTER && PXA_SHARPSL
        help
          Say y here to support the LCD panels usually found on SHARP
          corgi (C7x0) and spitz (Cxx00) models.
 
 config LCD_L4F00242T03
        tristate "Epson L4F00242T03 LCD"
-       depends on LCD_CLASS_DEVICE && SPI_MASTER && GENERIC_GPIO
+       depends on SPI_MASTER && GENERIC_GPIO
        help
          SPI driver for Epson L4F00242T03. This provides basic support
          for init and powering the LCD up/down through a sysfs interface.
 
 config LCD_LMS283GF05
        tristate "Samsung LMS283GF05 LCD"
-       depends on LCD_CLASS_DEVICE && SPI_MASTER && GENERIC_GPIO
+       depends on SPI_MASTER && GENERIC_GPIO
        help
          SPI driver for Samsung LMS283GF05. This provides basic support
          for powering the LCD up/down through a sysfs interface.
 
 config LCD_LTV350QV
        tristate "Samsung LTV350QV LCD Panel"
-       depends on LCD_CLASS_DEVICE && SPI_MASTER
-       default n
+       depends on SPI_MASTER
        help
          If you have a Samsung LTV350QV LCD panel, say y to include a
          power control driver for it.  The panel starts up in power
@@ -59,60 +61,61 @@ config LCD_LTV350QV
 
 config LCD_ILI9320
        tristate
-       depends on LCD_CLASS_DEVICE && BACKLIGHT_LCD_SUPPORT
-       default n
        help
          If you have a panel based on the ILI9320 controller chip
          then say y to include a power driver for it.
 
 config LCD_TDO24M
        tristate "Toppoly TDO24M  and TDO35S LCD Panels support"
-       depends on LCD_CLASS_DEVICE && SPI_MASTER
-       default n
+       depends on SPI_MASTER
        help
          If you have a Toppoly TDO24M/TDO35S series LCD panel, say y here to
          include the support for it.
 
 config LCD_VGG2432A4
        tristate "VGG2432A4 LCM device support"
-       depends on BACKLIGHT_LCD_SUPPORT && LCD_CLASS_DEVICE && SPI_MASTER
+       depends on SPI_MASTER
        select LCD_ILI9320
-       default n
        help
          If you have a VGG2432A4 panel based on the ILI9320 controller chip
          then say y to include a power driver for it.
 
 config LCD_PLATFORM
        tristate "Platform LCD controls"
-       depends on LCD_CLASS_DEVICE
        help
          This driver provides a platform-device registered LCD power
          control interface.
 
 config LCD_TOSA
        tristate "Sharp SL-6000 LCD Driver"
-       depends on LCD_CLASS_DEVICE && SPI
-       depends on MACH_TOSA
-       default n
+       depends on SPI && MACH_TOSA
        help
          If you have an Sharp SL-6000 Zaurus say Y to enable a driver
          for its LCD.
 
 config LCD_HP700
        tristate "HP Jornada 700 series LCD Driver"
-       depends on LCD_CLASS_DEVICE
        depends on SA1100_JORNADA720_SSP && !PREEMPT
        default y
        help
          If you have an HP Jornada 700 series handheld (710/720/728)
          say Y to enable LCD control driver.
 
+config LCD_S6E63M0
+       tristate "S6E63M0 AMOLED LCD Driver"
+       depends on SPI && BACKLIGHT_CLASS_DEVICE
+       default n
+       help
+         If you have an S6E63M0 LCD Panel, say Y to enable its
+         LCD control driver.
+
+endif # LCD_CLASS_DEVICE
+
 #
 # Backlight
 #
 config BACKLIGHT_CLASS_DEVICE
         tristate "Lowlevel Backlight controls"
-       depends on BACKLIGHT_LCD_SUPPORT
        default m
        help
          This framework adds support for low-level control of the LCD
@@ -121,9 +124,11 @@ config BACKLIGHT_CLASS_DEVICE
          To have support for your specific LCD panel you will have to
          select the proper drivers which depend on this option.
 
+if BACKLIGHT_CLASS_DEVICE
+
 config BACKLIGHT_ATMEL_LCDC
        bool "Atmel LCDC Contrast-as-Backlight control"
-       depends on BACKLIGHT_CLASS_DEVICE && FB_ATMEL
+       depends on FB_ATMEL
        default y if MACH_SAM9261EK || MACH_SAM9G10EK || MACH_SAM9263EK
        help
          This provides a backlight control internal to the Atmel LCDC
@@ -136,8 +141,7 @@ config BACKLIGHT_ATMEL_LCDC
 
 config BACKLIGHT_ATMEL_PWM
        tristate "Atmel PWM backlight control"
-       depends on BACKLIGHT_CLASS_DEVICE && ATMEL_PWM
-       default n
+       depends on ATMEL_PWM
        help
          Say Y here if you want to use the PWM peripheral in Atmel AT91 and
          AVR32 devices. This driver will need additional platform data to know
@@ -146,9 +150,18 @@ config BACKLIGHT_ATMEL_PWM
          To compile this driver as a module, choose M here: the module will be
          called atmel-pwm-bl.
 
+config BACKLIGHT_EP93XX
+       tristate "Cirrus EP93xx Backlight Driver"
+       depends on FB_EP93XX
+       help
+         If you have a LCD backlight connected to the BRIGHT output of
+         the EP93xx, say Y here to enable this driver.
+
+         To compile this driver as a module, choose M here: the module will
+         be called ep93xx_bl.
+
 config BACKLIGHT_GENERIC
        tristate "Generic (aka Sharp Corgi) Backlight Driver"
-       depends on BACKLIGHT_CLASS_DEVICE
        default y
        help
          Say y to enable the generic platform backlight driver previously
@@ -157,7 +170,7 @@ config BACKLIGHT_GENERIC
 
 config BACKLIGHT_LOCOMO
        tristate "Sharp LOCOMO LCD/Backlight Driver"
-       depends on BACKLIGHT_CLASS_DEVICE && SHARP_LOCOMO
+       depends on SHARP_LOCOMO
        default y
        help
          If you have a Sharp Zaurus SL-5500 (Collie) or SL-5600 (Poodle) say y to
@@ -165,7 +178,7 @@ config BACKLIGHT_LOCOMO
 
 config BACKLIGHT_OMAP1
        tristate "OMAP1 PWL-based LCD Backlight"
-       depends on BACKLIGHT_CLASS_DEVICE && ARCH_OMAP1
+       depends on ARCH_OMAP1
        default y
        help
          This driver controls the LCD backlight level and power for
@@ -174,7 +187,7 @@ config BACKLIGHT_OMAP1
 
 config BACKLIGHT_HP680
        tristate "HP Jornada 680 Backlight Driver"
-       depends on BACKLIGHT_CLASS_DEVICE && SH_HP6XX
+       depends on SH_HP6XX
        default y
        help
          If you have a HP Jornada 680, say y to enable the
@@ -182,7 +195,6 @@ config BACKLIGHT_HP680
 
 config BACKLIGHT_HP700
        tristate "HP Jornada 700 series Backlight Driver"
-       depends on BACKLIGHT_CLASS_DEVICE
        depends on SA1100_JORNADA720_SSP && !PREEMPT
        default y
        help
@@ -191,76 +203,70 @@ config BACKLIGHT_HP700
 
 config BACKLIGHT_PROGEAR
        tristate "Frontpath ProGear Backlight Driver"
-       depends on BACKLIGHT_CLASS_DEVICE && PCI && X86
-       default n
+       depends on PCI && X86
        help
          If you have a Frontpath ProGear say Y to enable the
          backlight driver.
 
 config BACKLIGHT_CARILLO_RANCH
        tristate "Intel Carillo Ranch Backlight Driver"
-       depends on BACKLIGHT_CLASS_DEVICE && LCD_CLASS_DEVICE && PCI && X86 && FB_LE80578
-       default n
+       depends on LCD_CLASS_DEVICE && PCI && X86 && FB_LE80578
        help
          If you have a Intel LE80578 (Carillo Ranch) say Y to enable the
          backlight driver.
 
 config BACKLIGHT_PWM
        tristate "Generic PWM based Backlight Driver"
-       depends on BACKLIGHT_CLASS_DEVICE && HAVE_PWM
+       depends on HAVE_PWM
        help
          If you have a LCD backlight adjustable by PWM, say Y to enable
          this driver.
 
 config BACKLIGHT_DA903X
        tristate "Backlight Driver for DA9030/DA9034 using WLED"
-       depends on BACKLIGHT_CLASS_DEVICE && PMIC_DA903X
+       depends on PMIC_DA903X
        help
          If you have a LCD backlight connected to the WLED output of DA9030
          or DA9034 WLED output, say Y here to enable this driver.
 
 config BACKLIGHT_MAX8925
        tristate "Backlight driver for MAX8925"
-       depends on BACKLIGHT_CLASS_DEVICE && MFD_MAX8925
+       depends on MFD_MAX8925
        help
          If you have a LCD backlight connected to the WLED output of MAX8925
          WLED output, say Y here to enable this driver.
 
 config BACKLIGHT_MBP_NVIDIA
        tristate "MacBook Pro Nvidia Backlight Driver"
-       depends on BACKLIGHT_CLASS_DEVICE && X86
-       default n
+       depends on X86
        help
          If you have an Apple Macbook Pro with Nvidia graphics hardware say Y
         to enable a driver for its backlight
 
 config BACKLIGHT_TOSA
        tristate "Sharp SL-6000 Backlight Driver"
-       depends on BACKLIGHT_CLASS_DEVICE && I2C
-       depends on MACH_TOSA && LCD_TOSA
-       default n
+       depends on I2C && MACH_TOSA && LCD_TOSA
        help
          If you have an Sharp SL-6000 Zaurus say Y to enable a driver
          for its backlight
 
 config BACKLIGHT_SAHARA
        tristate "Tabletkiosk Sahara Touch-iT Backlight Driver"
-       depends on BACKLIGHT_CLASS_DEVICE && X86
-       default n
+       depends on X86
        help
          If you have a Tabletkiosk Sahara Touch-iT, say y to enable the
          backlight driver.
 
 config BACKLIGHT_WM831X
        tristate "WM831x PMIC Backlight Driver"
-       depends on BACKLIGHT_CLASS_DEVICE && MFD_WM831X
+       depends on MFD_WM831X
        help
          If you have a backlight driven by the ISINK and DCDC of a
          WM831x PMIC say y to enable the backlight driver for it.
 
 config BACKLIGHT_ADX
        tristate "Avionic Design Xanthos Backlight Driver"
-       depends on BACKLIGHT_CLASS_DEVICE && ARCH_PXA_ADX
+       depends on ARCH_PXA_ADX
        default y
        help
          Say Y to enable the backlight driver on Avionic Design Xanthos-based
@@ -268,7 +274,7 @@ config BACKLIGHT_ADX
 
 config BACKLIGHT_ADP5520
        tristate "Backlight Driver for ADP5520/ADP5501 using WLED"
-       depends on BACKLIGHT_CLASS_DEVICE && PMIC_ADP5520
+       depends on PMIC_ADP5520
        help
          If you have a LCD backlight connected to the BST/BL_SNK output of
          ADP5520 or ADP5501, say Y here to enable this driver.
@@ -276,9 +282,31 @@ config BACKLIGHT_ADP5520
          To compile this driver as a module, choose M here: the module will
          be called adp5520_bl.
 
+config BACKLIGHT_ADP8860
+       tristate "Backlight Driver for ADP8860/ADP8861/ADP8863 using WLED"
+       depends on BACKLIGHT_CLASS_DEVICE && I2C
+       select NEW_LEDS
+       select LEDS_CLASS
+       help
+         If you have a LCD backlight connected to the ADP8860, ADP8861 or
+         ADP8863 say Y here to enable this driver.
+
+         To compile this driver as a module, choose M here: the module will
+         be called adp8860_bl.
+
 config BACKLIGHT_88PM860X
        tristate "Backlight Driver for 88PM8606 using WLED"
-       depends on BACKLIGHT_CLASS_DEVICE && MFD_88PM860X
+       depends on MFD_88PM860X
        help
          Say Y to enable the backlight driver for Marvell 88PM8606.
 
+config BACKLIGHT_PCF50633
+       tristate "Backlight driver for NXP PCF50633 MFD"
+       depends on BACKLIGHT_CLASS_DEVICE && MFD_PCF50633
+       help
+         If you have a backlight driven by a NXP PCF50633 MFD, say Y here to
+         enable its driver.
+
+endif # BACKLIGHT_CLASS_DEVICE
+
+endif # BACKLIGHT_LCD_SUPPORT
index 09d1f14d6257ac1ceedb9a8988c8017d24f6e265..44c0f81ad85d96c731e1bfe3f1a2068c37f3484c 100644 (file)
@@ -11,9 +11,11 @@ obj-$(CONFIG_LCD_PLATFORM)      += platform_lcd.o
 obj-$(CONFIG_LCD_VGG2432A4)       += vgg2432a4.o
 obj-$(CONFIG_LCD_TDO24M)          += tdo24m.o
 obj-$(CONFIG_LCD_TOSA)            += tosa_lcd.o
+obj-$(CONFIG_LCD_S6E63M0)      += s6e63m0.o
 
 obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
 obj-$(CONFIG_BACKLIGHT_ATMEL_PWM)    += atmel-pwm-bl.o
+obj-$(CONFIG_BACKLIGHT_EP93XX) += ep93xx_bl.o
 obj-$(CONFIG_BACKLIGHT_GENERIC)        += generic_bl.o
 obj-$(CONFIG_BACKLIGHT_HP700)  += jornada720_bl.o
 obj-$(CONFIG_BACKLIGHT_HP680)  += hp680_bl.o
@@ -30,5 +32,7 @@ obj-$(CONFIG_BACKLIGHT_SAHARA)        += kb3886_bl.o
 obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o
 obj-$(CONFIG_BACKLIGHT_ADX)    += adx_bl.o
 obj-$(CONFIG_BACKLIGHT_ADP5520)        += adp5520_bl.o
+obj-$(CONFIG_BACKLIGHT_ADP8860)        += adp8860_bl.o
 obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o
+obj-$(CONFIG_BACKLIGHT_PCF50633)       += pcf50633-backlight.o
 
diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c
new file mode 100644 (file)
index 0000000..921ca37
--- /dev/null
@@ -0,0 +1,838 @@
+/*
+ * Backlight driver for Analog Devices ADP8860 Backlight Devices
+ *
+ * Copyright 2009-2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
+#include <linux/leds.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+
+#include <linux/i2c/adp8860.h>
+#define ADP8860_EXT_FEATURES
+#define ADP8860_USE_LEDS
+
+#define ADP8860_MFDVID 0x00 /* Manufacturer and device ID */
+#define ADP8860_MDCR 0x01 /* Device mode and status */
+#define ADP8860_MDCR2 0x02 /* Device mode and Status Register 2 */
+#define ADP8860_INTR_EN 0x03 /* Interrupts enable */
+#define ADP8860_CFGR 0x04 /* Configuration register */
+#define ADP8860_BLSEN 0x05 /* Sink enable backlight or independent */
+#define ADP8860_BLOFF 0x06 /* Backlight off timeout */
+#define ADP8860_BLDIM 0x07 /* Backlight dim timeout */
+#define ADP8860_BLFR 0x08 /* Backlight fade in and out rates */
+#define ADP8860_BLMX1 0x09 /* Backlight (Brightness Level 1-daylight) maximum current */
+#define ADP8860_BLDM1 0x0A /* Backlight (Brightness Level 1-daylight) dim current */
+#define ADP8860_BLMX2 0x0B /* Backlight (Brightness Level 2-office) maximum current */
+#define ADP8860_BLDM2 0x0C /* Backlight (Brightness Level 2-office) dim current */
+#define ADP8860_BLMX3 0x0D /* Backlight (Brightness Level 3-dark) maximum current */
+#define ADP8860_BLDM3 0x0E /* Backlight (Brightness Level 3-dark) dim current */
+#define ADP8860_ISCFR 0x0F /* Independent sink current fade control register */
+#define ADP8860_ISCC 0x10 /* Independent sink current control register */
+#define ADP8860_ISCT1 0x11 /* Independent Sink Current Timer Register LED[7:5] */
+#define ADP8860_ISCT2 0x12 /* Independent Sink Current Timer Register LED[4:1] */
+#define ADP8860_ISCF 0x13 /* Independent sink current fade register */
+#define ADP8860_ISC7 0x14 /* Independent Sink Current LED7 */
+#define ADP8860_ISC6 0x15 /* Independent Sink Current LED6 */
+#define ADP8860_ISC5 0x16 /* Independent Sink Current LED5 */
+#define ADP8860_ISC4 0x17 /* Independent Sink Current LED4 */
+#define ADP8860_ISC3 0x18 /* Independent Sink Current LED3 */
+#define ADP8860_ISC2 0x19 /* Independent Sink Current LED2 */
+#define ADP8860_ISC1 0x1A /* Independent Sink Current LED1 */
+#define ADP8860_CCFG 0x1B /* Comparator configuration */
+#define ADP8860_CCFG2 0x1C /* Second comparator configuration */
+#define ADP8860_L2_TRP 0x1D /* L2 comparator reference */
+#define ADP8860_L2_HYS 0x1E /* L2 hysteresis */
+#define ADP8860_L3_TRP 0x1F /* L3 comparator reference */
+#define ADP8860_L3_HYS 0x20 /* L3 hysteresis */
+#define ADP8860_PH1LEVL 0x21 /* First phototransistor ambient light level-low byte register */
+#define ADP8860_PH1LEVH 0x22 /* First phototransistor ambient light level-high byte register */
+#define ADP8860_PH2LEVL 0x23 /* Second phototransistor ambient light level-low byte register */
+#define ADP8860_PH2LEVH 0x24 /* Second phototransistor ambient light level-high byte register */
+
+#define ADP8860_MANUFID                0x0  /* Analog Devices ADP8860 Manufacturer ID */
+#define ADP8861_MANUFID                0x4  /* Analog Devices ADP8861 Manufacturer ID */
+#define ADP8863_MANUFID                0x2  /* Analog Devices ADP8863 Manufacturer ID */
+
+#define ADP8860_DEVID(x)       ((x) & 0xF)
+#define ADP8860_MANID(x)       ((x) >> 4)
+
+/* MDCR Device mode and status */
+#define INT_CFG                        (1 << 6)
+#define NSTBY                  (1 << 5)
+#define DIM_EN                 (1 << 4)
+#define GDWN_DIS               (1 << 3)
+#define SIS_EN                 (1 << 2)
+#define CMP_AUTOEN             (1 << 1)
+#define BLEN                   (1 << 0)
+
+/* ADP8860_CCFG Main ALS comparator level enable */
+#define L3_EN                  (1 << 1)
+#define L2_EN                  (1 << 0)
+
+#define CFGR_BLV_SHIFT         3
+#define CFGR_BLV_MASK          0x3
+#define ADP8860_FLAG_LED_MASK  0xFF
+
+#define FADE_VAL(in, out)      ((0xF & (in)) | ((0xF & (out)) << 4))
+#define BL_CFGR_VAL(law, blv)  ((((blv) & CFGR_BLV_MASK) << CFGR_BLV_SHIFT) | ((0x3 & (law)) << 1))
+#define ALS_CCFG_VAL(filt)     ((0x7 & filt) << 5)
+
+enum {
+       adp8860,
+       adp8861,
+       adp8863
+};
+
+struct adp8860_led {
+       struct led_classdev     cdev;
+       struct work_struct      work;
+       struct i2c_client       *client;
+       enum led_brightness     new_brightness;
+       int                     id;
+       int                     flags;
+};
+
+struct adp8860_bl {
+       struct i2c_client *client;
+       struct backlight_device *bl;
+       struct adp8860_led *led;
+       struct adp8860_backlight_platform_data *pdata;
+       struct mutex lock;
+       unsigned long cached_daylight_max;
+       int id;
+       int revid;
+       int current_brightness;
+       unsigned en_ambl_sens:1;
+       unsigned gdwn_dis:1;
+};
+
+static int adp8860_read(struct i2c_client *client, int reg, uint8_t *val)
+{
+       int ret;
+
+       ret = i2c_smbus_read_byte_data(client, reg);
+       if (ret < 0) {
+               dev_err(&client->dev, "failed reading at 0x%02x\n", reg);
+               return ret;
+       }
+
+       *val = (uint8_t)ret;
+       return 0;
+}
+
+static int adp8860_write(struct i2c_client *client, u8 reg, u8 val)
+{
+       return i2c_smbus_write_byte_data(client, reg, val);
+}
+
+static int adp8860_set_bits(struct i2c_client *client, int reg, uint8_t bit_mask)
+{
+       struct adp8860_bl *data = i2c_get_clientdata(client);
+       uint8_t reg_val;
+       int ret;
+
+       mutex_lock(&data->lock);
+
+       ret = adp8860_read(client, reg, &reg_val);
+
+       if (!ret && ((reg_val & bit_mask) == 0)) {
+               reg_val |= bit_mask;
+               ret = adp8860_write(client, reg, reg_val);
+       }
+
+       mutex_unlock(&data->lock);
+       return ret;
+}
+
+static int adp8860_clr_bits(struct i2c_client *client, int reg, uint8_t bit_mask)
+{
+       struct adp8860_bl *data = i2c_get_clientdata(client);
+       uint8_t reg_val;
+       int ret;
+
+       mutex_lock(&data->lock);
+
+       ret = adp8860_read(client, reg, &reg_val);
+
+       if (!ret && (reg_val & bit_mask)) {
+               reg_val &= ~bit_mask;
+               ret = adp8860_write(client, reg, reg_val);
+       }
+
+       mutex_unlock(&data->lock);
+       return ret;
+}
+
+/*
+ * Independent sink / LED
+ */
+#if defined(ADP8860_USE_LEDS)
+static void adp8860_led_work(struct work_struct *work)
+{
+       struct adp8860_led *led = container_of(work, struct adp8860_led, work);
+       adp8860_write(led->client, ADP8860_ISC1 - led->id + 1,
+                        led->new_brightness >> 1);
+}
+
+static void adp8860_led_set(struct led_classdev *led_cdev,
+                          enum led_brightness value)
+{
+       struct adp8860_led *led;
+
+       led = container_of(led_cdev, struct adp8860_led, cdev);
+       led->new_brightness = value;
+       schedule_work(&led->work);
+}
+
+static int adp8860_led_setup(struct adp8860_led *led)
+{
+       struct i2c_client *client = led->client;
+       int ret = 0;
+
+       ret = adp8860_write(client, ADP8860_ISC1 - led->id + 1, 0);
+       ret |= adp8860_set_bits(client, ADP8860_ISCC, 1 << (led->id - 1));
+
+       if (led->id > 4)
+               ret |= adp8860_set_bits(client, ADP8860_ISCT1,
+                               (led->flags & 0x3) << ((led->id - 5) * 2));
+       else
+               ret |= adp8860_set_bits(client, ADP8860_ISCT2,
+                               (led->flags & 0x3) << ((led->id - 1) * 2));
+
+       return ret;
+}
+
+static int __devinit adp8860_led_probe(struct i2c_client *client)
+{
+       struct adp8860_backlight_platform_data *pdata =
+               client->dev.platform_data;
+       struct adp8860_bl *data = i2c_get_clientdata(client);
+       struct adp8860_led *led, *led_dat;
+       struct led_info *cur_led;
+       int ret, i;
+
+       led = kzalloc(sizeof(*led) * pdata->num_leds, GFP_KERNEL);
+       if (led == NULL) {
+               dev_err(&client->dev, "failed to alloc memory\n");
+               return -ENOMEM;
+       }
+
+       ret = adp8860_write(client, ADP8860_ISCFR, pdata->led_fade_law);
+       ret = adp8860_write(client, ADP8860_ISCT1,
+                       (pdata->led_on_time & 0x3) << 6);
+       ret |= adp8860_write(client, ADP8860_ISCF,
+                       FADE_VAL(pdata->led_fade_in, pdata->led_fade_out));
+
+       if (ret) {
+               dev_err(&client->dev, "failed to write\n");
+               goto err_free;
+       }
+
+       for (i = 0; i < pdata->num_leds; ++i) {
+               cur_led = &pdata->leds[i];
+               led_dat = &led[i];
+
+               led_dat->id = cur_led->flags & ADP8860_FLAG_LED_MASK;
+
+               if (led_dat->id > 7 || led_dat->id < 1) {
+                       dev_err(&client->dev, "Invalid LED ID %d\n",
+                               led_dat->id);
+                       goto err;
+               }
+
+               if (pdata->bl_led_assign & (1 << (led_dat->id - 1))) {
+                       dev_err(&client->dev, "LED %d used by Backlight\n",
+                               led_dat->id);
+                       goto err;
+               }
+
+               led_dat->cdev.name = cur_led->name;
+               led_dat->cdev.default_trigger = cur_led->default_trigger;
+               led_dat->cdev.brightness_set = adp8860_led_set;
+               led_dat->cdev.brightness = LED_OFF;
+               led_dat->flags = cur_led->flags >> FLAG_OFFT_SHIFT;
+               led_dat->client = client;
+               led_dat->new_brightness = LED_OFF;
+               INIT_WORK(&led_dat->work, adp8860_led_work);
+
+               ret = led_classdev_register(&client->dev, &led_dat->cdev);
+               if (ret) {
+                       dev_err(&client->dev, "failed to register LED %d\n",
+                               led_dat->id);
+                       goto err;
+               }
+
+               ret = adp8860_led_setup(led_dat);
+               if (ret) {
+                       dev_err(&client->dev, "failed to write\n");
+                       i++;
+                       goto err;
+               }
+       }
+
+       data->led = led;
+
+       return 0;
+
+ err:
+       for (i = i - 1; i >= 0; --i) {
+               led_classdev_unregister(&led[i].cdev);
+               cancel_work_sync(&led[i].work);
+       }
+
+ err_free:
+       kfree(led);
+
+       return ret;
+}
+
+static int __devexit adp8860_led_remove(struct i2c_client *client)
+{
+       struct adp8860_backlight_platform_data *pdata =
+               client->dev.platform_data;
+       struct adp8860_bl *data = i2c_get_clientdata(client);
+       int i;
+
+       for (i = 0; i < pdata->num_leds; i++) {
+               led_classdev_unregister(&data->led[i].cdev);
+               cancel_work_sync(&data->led[i].work);
+       }
+
+       kfree(data->led);
+       return 0;
+}
+#else
+static int __devinit adp8860_led_probe(struct i2c_client *client)
+{
+       return 0;
+}
+
+static int __devexit adp8860_led_remove(struct i2c_client *client)
+{
+       return 0;
+}
+#endif
+
+static int adp8860_bl_set(struct backlight_device *bl, int brightness)
+{
+       struct adp8860_bl *data = bl_get_data(bl);
+       struct i2c_client *client = data->client;
+       int ret = 0;
+
+       if (data->en_ambl_sens) {
+               if ((brightness > 0) && (brightness < ADP8860_MAX_BRIGHTNESS)) {
+                       /* Disable Ambient Light auto adjust */
+                       ret |= adp8860_clr_bits(client, ADP8860_MDCR,
+                                       CMP_AUTOEN);
+                       ret |= adp8860_write(client, ADP8860_BLMX1, brightness);
+               } else {
+                       /*
+                        * MAX_BRIGHTNESS -> Enable Ambient Light auto adjust
+                        * restore daylight l1 sysfs brightness
+                        */
+                       ret |= adp8860_write(client, ADP8860_BLMX1,
+                                        data->cached_daylight_max);
+                       ret |= adp8860_set_bits(client, ADP8860_MDCR,
+                                        CMP_AUTOEN);
+               }
+       } else
+               ret |= adp8860_write(client, ADP8860_BLMX1, brightness);
+
+       if (data->current_brightness && brightness == 0)
+               ret |= adp8860_set_bits(client,
+                               ADP8860_MDCR, DIM_EN);
+       else if (data->current_brightness == 0 && brightness)
+               ret |= adp8860_clr_bits(client,
+                               ADP8860_MDCR, DIM_EN);
+
+       if (!ret)
+               data->current_brightness = brightness;
+
+       return ret;
+}
+
+static int adp8860_bl_update_status(struct backlight_device *bl)
+{
+       int brightness = bl->props.brightness;
+       if (bl->props.power != FB_BLANK_UNBLANK)
+               brightness = 0;
+
+       if (bl->props.fb_blank != FB_BLANK_UNBLANK)
+               brightness = 0;
+
+       return adp8860_bl_set(bl, brightness);
+}
+
+static int adp8860_bl_get_brightness(struct backlight_device *bl)
+{
+       struct adp8860_bl *data = bl_get_data(bl);
+
+       return data->current_brightness;
+}
+
+static const struct backlight_ops adp8860_bl_ops = {
+       .update_status  = adp8860_bl_update_status,
+       .get_brightness = adp8860_bl_get_brightness,
+};
+
+static int adp8860_bl_setup(struct backlight_device *bl)
+{
+       struct adp8860_bl *data = bl_get_data(bl);
+       struct i2c_client *client = data->client;
+       struct adp8860_backlight_platform_data *pdata = data->pdata;
+       int ret = 0;
+
+       ret |= adp8860_write(client, ADP8860_BLSEN, ~pdata->bl_led_assign);
+       ret |= adp8860_write(client, ADP8860_BLMX1, pdata->l1_daylight_max);
+       ret |= adp8860_write(client, ADP8860_BLDM1, pdata->l1_daylight_dim);
+
+       if (data->en_ambl_sens) {
+               data->cached_daylight_max = pdata->l1_daylight_max;
+               ret |= adp8860_write(client, ADP8860_BLMX2,
+                                               pdata->l2_office_max);
+               ret |= adp8860_write(client, ADP8860_BLDM2,
+                                               pdata->l2_office_dim);
+               ret |= adp8860_write(client, ADP8860_BLMX3,
+                                               pdata->l3_dark_max);
+               ret |= adp8860_write(client, ADP8860_BLDM3,
+                                               pdata->l3_dark_dim);
+
+               ret |= adp8860_write(client, ADP8860_L2_TRP, pdata->l2_trip);
+               ret |= adp8860_write(client, ADP8860_L2_HYS, pdata->l2_hyst);
+               ret |= adp8860_write(client, ADP8860_L3_TRP, pdata->l3_trip);
+               ret |= adp8860_write(client, ADP8860_L3_HYS, pdata->l3_hyst);
+               ret |= adp8860_write(client, ADP8860_CCFG, L2_EN | L3_EN |
+                                               ALS_CCFG_VAL(pdata->abml_filt));
+       }
+
+       ret |= adp8860_write(client, ADP8860_CFGR,
+                       BL_CFGR_VAL(pdata->bl_fade_law, 0));
+
+       ret |= adp8860_write(client, ADP8860_BLFR, FADE_VAL(pdata->bl_fade_in,
+                       pdata->bl_fade_out));
+
+       ret |= adp8860_set_bits(client, ADP8860_MDCR, BLEN | DIM_EN | NSTBY |
+                       (data->gdwn_dis ? GDWN_DIS : 0));
+
+       return ret;
+}
+
+static ssize_t adp8860_show(struct device *dev, char *buf, int reg)
+{
+       struct adp8860_bl *data = dev_get_drvdata(dev);
+       int error;
+       uint8_t reg_val;
+
+       mutex_lock(&data->lock);
+       error = adp8860_read(data->client, reg, &reg_val);
+       mutex_unlock(&data->lock);
+
+       if (error < 0)
+               return error;
+
+       return sprintf(buf, "%u\n", reg_val);
+}
+
+static ssize_t adp8860_store(struct device *dev, const char *buf,
+                        size_t count, int reg)
+{
+       struct adp8860_bl *data = dev_get_drvdata(dev);
+       unsigned long val;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &val);
+       if (ret)
+               return ret;
+
+       mutex_lock(&data->lock);
+       adp8860_write(data->client, reg, val);
+       mutex_unlock(&data->lock);
+
+       return count;
+}
+
+static ssize_t adp8860_bl_l3_dark_max_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       return adp8860_show(dev, buf, ADP8860_BLMX3);
+}
+
+static ssize_t adp8860_bl_l3_dark_max_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       return adp8860_store(dev, buf, count, ADP8860_BLMX3);
+}
+
+static DEVICE_ATTR(l3_dark_max, 0664, adp8860_bl_l3_dark_max_show,
+                       adp8860_bl_l3_dark_max_store);
+
+static ssize_t adp8860_bl_l2_office_max_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       return adp8860_show(dev, buf, ADP8860_BLMX2);
+}
+
+static ssize_t adp8860_bl_l2_office_max_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       return adp8860_store(dev, buf, count, ADP8860_BLMX2);
+}
+static DEVICE_ATTR(l2_office_max, 0664, adp8860_bl_l2_office_max_show,
+                       adp8860_bl_l2_office_max_store);
+
+static ssize_t adp8860_bl_l1_daylight_max_show(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       return adp8860_show(dev, buf, ADP8860_BLMX1);
+}
+
+static ssize_t adp8860_bl_l1_daylight_max_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct adp8860_bl *data = dev_get_drvdata(dev);
+
+       strict_strtoul(buf, 10, &data->cached_daylight_max);
+       return adp8860_store(dev, buf, count, ADP8860_BLMX1);
+}
+static DEVICE_ATTR(l1_daylight_max, 0664, adp8860_bl_l1_daylight_max_show,
+                       adp8860_bl_l1_daylight_max_store);
+
+static ssize_t adp8860_bl_l3_dark_dim_show(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       return adp8860_show(dev, buf, ADP8860_BLDM3);
+}
+
+static ssize_t adp8860_bl_l3_dark_dim_store(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       return adp8860_store(dev, buf, count, ADP8860_BLDM3);
+}
+static DEVICE_ATTR(l3_dark_dim, 0664, adp8860_bl_l3_dark_dim_show,
+                       adp8860_bl_l3_dark_dim_store);
+
+static ssize_t adp8860_bl_l2_office_dim_show(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       return adp8860_show(dev, buf, ADP8860_BLDM2);
+}
+
+static ssize_t adp8860_bl_l2_office_dim_store(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       return adp8860_store(dev, buf, count, ADP8860_BLDM2);
+}
+static DEVICE_ATTR(l2_office_dim, 0664, adp8860_bl_l2_office_dim_show,
+                       adp8860_bl_l2_office_dim_store);
+
+static ssize_t adp8860_bl_l1_daylight_dim_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       return adp8860_show(dev, buf, ADP8860_BLDM1);
+}
+
+static ssize_t adp8860_bl_l1_daylight_dim_store(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       return adp8860_store(dev, buf, count, ADP8860_BLDM1);
+}
+static DEVICE_ATTR(l1_daylight_dim, 0664, adp8860_bl_l1_daylight_dim_show,
+                       adp8860_bl_l1_daylight_dim_store);
+
+#ifdef ADP8860_EXT_FEATURES
+static ssize_t adp8860_bl_ambient_light_level_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       struct adp8860_bl *data = dev_get_drvdata(dev);
+       int error;
+       uint8_t reg_val;
+       uint16_t ret_val;
+
+       mutex_lock(&data->lock);
+       error = adp8860_read(data->client, ADP8860_PH1LEVL, &reg_val);
+       ret_val = reg_val;
+       error |= adp8860_read(data->client, ADP8860_PH1LEVH, &reg_val);
+       mutex_unlock(&data->lock);
+
+       if (error < 0)
+               return error;
+
+       /* Return 13-bit conversion value for the first light sensor */
+       ret_val += (reg_val & 0x1F) << 8;
+
+       return sprintf(buf, "%u\n", ret_val);
+}
+static DEVICE_ATTR(ambient_light_level, 0444,
+               adp8860_bl_ambient_light_level_show, NULL);
+
+static ssize_t adp8860_bl_ambient_light_zone_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       struct adp8860_bl *data = dev_get_drvdata(dev);
+       int error;
+       uint8_t reg_val;
+
+       mutex_lock(&data->lock);
+       error = adp8860_read(data->client, ADP8860_CFGR, &reg_val);
+       mutex_unlock(&data->lock);
+
+       if (error < 0)
+               return error;
+
+       return sprintf(buf, "%u\n",
+               ((reg_val >> CFGR_BLV_SHIFT) & CFGR_BLV_MASK) + 1);
+}
+
+static ssize_t adp8860_bl_ambient_light_zone_store(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       struct adp8860_bl *data = dev_get_drvdata(dev);
+       unsigned long val;
+       uint8_t reg_val;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &val);
+       if (ret)
+               return ret;
+
+       if (val == 0) {
+               /* Enable automatic ambient light sensing */
+               adp8860_set_bits(data->client, ADP8860_MDCR, CMP_AUTOEN);
+       } else if ((val > 0) && (val < 6)) {
+               /* Disable automatic ambient light sensing */
+               adp8860_clr_bits(data->client, ADP8860_MDCR, CMP_AUTOEN);
+
+               /* Set user supplied ambient light zone */
+               mutex_lock(&data->lock);
+               adp8860_read(data->client, ADP8860_CFGR, &reg_val);
+               reg_val &= ~(CFGR_BLV_MASK << CFGR_BLV_SHIFT);
+               reg_val |= val << CFGR_BLV_SHIFT;
+               adp8860_write(data->client, ADP8860_CFGR, reg_val);
+               mutex_unlock(&data->lock);
+       }
+
+       return count;
+}
+static DEVICE_ATTR(ambient_light_zone, 0664,
+               adp8860_bl_ambient_light_zone_show,
+               adp8860_bl_ambient_light_zone_store);
+#endif
+
+static struct attribute *adp8860_bl_attributes[] = {
+       &dev_attr_l3_dark_max.attr,
+       &dev_attr_l3_dark_dim.attr,
+       &dev_attr_l2_office_max.attr,
+       &dev_attr_l2_office_dim.attr,
+       &dev_attr_l1_daylight_max.attr,
+       &dev_attr_l1_daylight_dim.attr,
+#ifdef ADP8860_EXT_FEATURES
+       &dev_attr_ambient_light_level.attr,
+       &dev_attr_ambient_light_zone.attr,
+#endif
+       NULL
+};
+
+static const struct attribute_group adp8860_bl_attr_group = {
+       .attrs = adp8860_bl_attributes,
+};
+
+static int __devinit adp8860_probe(struct i2c_client *client,
+                                       const struct i2c_device_id *id)
+{
+       struct backlight_device *bl;
+       struct adp8860_bl *data;
+       struct adp8860_backlight_platform_data *pdata =
+               client->dev.platform_data;
+       struct backlight_properties props;
+       uint8_t reg_val;
+       int ret;
+
+       if (!i2c_check_functionality(client->adapter,
+                                       I2C_FUNC_SMBUS_BYTE_DATA)) {
+               dev_err(&client->dev, "SMBUS Byte Data not Supported\n");
+               return -EIO;
+       }
+
+       if (!pdata) {
+               dev_err(&client->dev, "no platform data?\n");
+               return -EINVAL;
+       }
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (data == NULL)
+               return -ENOMEM;
+
+       ret = adp8860_read(client, ADP8860_MFDVID, &reg_val);
+       if (ret < 0)
+               goto out2;
+
+       switch (ADP8860_MANID(reg_val)) {
+       case ADP8863_MANUFID:
+               data->gdwn_dis = !!pdata->gdwn_dis;
+       case ADP8860_MANUFID:
+               data->en_ambl_sens = !!pdata->en_ambl_sens;
+               break;
+       case ADP8861_MANUFID:
+               data->gdwn_dis = !!pdata->gdwn_dis;
+               break;
+       default:
+               dev_err(&client->dev, "failed to probe\n");
+               ret = -ENODEV;
+               goto out2;
+       }
+
+       /* It's confirmed that the DEVID field is actually a REVID */
+
+       data->revid = ADP8860_DEVID(reg_val);
+       data->client = client;
+       data->pdata = pdata;
+       data->id = id->driver_data;
+       data->current_brightness = 0;
+       i2c_set_clientdata(client, data);
+
+       memset(&props, 0, sizeof(props));
+       props.max_brightness = ADP8860_MAX_BRIGHTNESS;
+
+       mutex_init(&data->lock);
+
+       bl = backlight_device_register(dev_driver_string(&client->dev),
+                       &client->dev, data, &adp8860_bl_ops, &props);
+       if (IS_ERR(bl)) {
+               dev_err(&client->dev, "failed to register backlight\n");
+               ret = PTR_ERR(bl);
+               goto out2;
+       }
+
+       bl->props.max_brightness =
+               bl->props.brightness = ADP8860_MAX_BRIGHTNESS;
+
+       data->bl = bl;
+
+       if (data->en_ambl_sens)
+               ret = sysfs_create_group(&bl->dev.kobj,
+                       &adp8860_bl_attr_group);
+
+       if (ret) {
+               dev_err(&client->dev, "failed to register sysfs\n");
+               goto out1;
+       }
+
+       ret = adp8860_bl_setup(bl);
+       if (ret) {
+               ret = -EIO;
+               goto out;
+       }
+
+       backlight_update_status(bl);
+
+       dev_info(&client->dev, "%s Rev.%d Backlight\n",
+               client->name, data->revid);
+
+       if (pdata->num_leds)
+               adp8860_led_probe(client);
+
+       return 0;
+
+out:
+       if (data->en_ambl_sens)
+               sysfs_remove_group(&data->bl->dev.kobj,
+                       &adp8860_bl_attr_group);
+out1:
+       backlight_device_unregister(bl);
+out2:
+       i2c_set_clientdata(client, NULL);
+       kfree(data);
+
+       return ret;
+}
+
+static int __devexit adp8860_remove(struct i2c_client *client)
+{
+       struct adp8860_bl *data = i2c_get_clientdata(client);
+
+       adp8860_clr_bits(client, ADP8860_MDCR, NSTBY);
+
+       if (data->led)
+               adp8860_led_remove(client);
+
+       if (data->en_ambl_sens)
+               sysfs_remove_group(&data->bl->dev.kobj,
+                       &adp8860_bl_attr_group);
+
+       backlight_device_unregister(data->bl);
+       i2c_set_clientdata(client, NULL);
+       kfree(data);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int adp8860_i2c_suspend(struct i2c_client *client, pm_message_t message)
+{
+       adp8860_clr_bits(client, ADP8860_MDCR, NSTBY);
+
+       return 0;
+}
+
+static int adp8860_i2c_resume(struct i2c_client *client)
+{
+       adp8860_set_bits(client, ADP8860_MDCR, NSTBY);
+
+       return 0;
+}
+#else
+#define adp8860_i2c_suspend NULL
+#define adp8860_i2c_resume NULL
+#endif
+
+static const struct i2c_device_id adp8860_id[] = {
+       { "adp8860", adp8860 },
+       { "adp8861", adp8861 },
+       { "adp8863", adp8863 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, adp8860_id);
+
+static struct i2c_driver adp8860_driver = {
+       .driver = {
+               .name = KBUILD_MODNAME,
+       },
+       .probe    = adp8860_probe,
+       .remove   = __devexit_p(adp8860_remove),
+       .suspend = adp8860_i2c_suspend,
+       .resume  = adp8860_i2c_resume,
+       .id_table = adp8860_id,
+};
+
+static int __init adp8860_init(void)
+{
+       return i2c_add_driver(&adp8860_driver);
+}
+module_init(adp8860_init);
+
+static void __exit adp8860_exit(void)
+{
+       i2c_del_driver(&adp8860_driver);
+}
+module_exit(adp8860_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("ADP8860 Backlight driver");
+MODULE_ALIAS("i2c:adp8860-backlight");
index 7f4a7c30a98b1f3a09fd020c4c5906f386a1015c..fe9af129c5dd1cb969ea0e0cf418a7b66d5db3b2 100644 (file)
@@ -107,8 +107,8 @@ static int __devinit adx_backlight_probe(struct platform_device *pdev)
        props.max_brightness = 0xff;
        bldev = backlight_device_register(dev_name(&pdev->dev), &pdev->dev,
                                          bl, &adx_backlight_ops, &props);
-       if (!bldev) {
-               ret = -ENOMEM;
+       if (IS_ERR(bldev)) {
+               ret = PTR_ERR(bldev);
                goto out;
        }
 
diff --git a/drivers/video/backlight/ep93xx_bl.c b/drivers/video/backlight/ep93xx_bl.c
new file mode 100644 (file)
index 0000000..b0cc491
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Driver for the Cirrus EP93xx lcd backlight
+ *
+ * Copyright (c) 2010 H Hartley Sweeten <hsweeten@visionengravers.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 driver controls the pulse width modulated brightness control output,
+ * BRIGHT, on the Cirrus EP9307, EP9312, and EP9315 processors.
+ */
+
+
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
+
+#include <mach/hardware.h>
+
+#define EP93XX_RASTER_REG(x)           (EP93XX_RASTER_BASE + (x))
+#define EP93XX_RASTER_BRIGHTNESS       EP93XX_RASTER_REG(0x20)
+
+#define EP93XX_MAX_COUNT               255
+#define EP93XX_MAX_BRIGHT              255
+#define EP93XX_DEF_BRIGHT              128
+
+struct ep93xxbl {
+       void __iomem *mmio;
+       int brightness;
+};
+
+static int ep93xxbl_set(struct backlight_device *bl, int brightness)
+{
+       struct ep93xxbl *ep93xxbl = bl_get_data(bl);
+
+       __raw_writel((brightness << 8) | EP93XX_MAX_COUNT, ep93xxbl->mmio);
+
+       ep93xxbl->brightness = brightness;
+
+       return 0;
+}
+
+static int ep93xxbl_update_status(struct backlight_device *bl)
+{
+       int brightness = bl->props.brightness;
+
+       if (bl->props.power != FB_BLANK_UNBLANK ||
+           bl->props.fb_blank != FB_BLANK_UNBLANK)
+               brightness = 0;
+
+       return ep93xxbl_set(bl, brightness);
+}
+
+static int ep93xxbl_get_brightness(struct backlight_device *bl)
+{
+       struct ep93xxbl *ep93xxbl = bl_get_data(bl);
+
+       return ep93xxbl->brightness;
+}
+
+static const struct backlight_ops ep93xxbl_ops = {
+       .update_status  = ep93xxbl_update_status,
+       .get_brightness = ep93xxbl_get_brightness,
+};
+
+static int __init ep93xxbl_probe(struct platform_device *dev)
+{
+       struct ep93xxbl *ep93xxbl;
+       struct backlight_device *bl;
+       struct backlight_properties props;
+
+       ep93xxbl = devm_kzalloc(&dev->dev, sizeof(*ep93xxbl), GFP_KERNEL);
+       if (!ep93xxbl)
+               return -ENOMEM;
+
+       /*
+        * This register is located in the range already ioremap'ed by
+        * the framebuffer driver.  A MFD driver seems a bit of overkill
+        * to handle this so use the static I/O mapping; this address
+        * is already virtual.
+        *
+        * NOTE: No locking is required; the framebuffer does not touch
+        * this register.
+        */
+       ep93xxbl->mmio = EP93XX_RASTER_BRIGHTNESS;
+
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = EP93XX_MAX_BRIGHT;
+       bl = backlight_device_register(dev->name, &dev->dev, ep93xxbl,
+                                      &ep93xxbl_ops, &props);
+       if (IS_ERR(bl))
+               return PTR_ERR(bl);
+
+       bl->props.brightness = EP93XX_DEF_BRIGHT;
+
+       platform_set_drvdata(dev, bl);
+
+       ep93xxbl_update_status(bl);
+
+       return 0;
+}
+
+static int ep93xxbl_remove(struct platform_device *dev)
+{
+       struct backlight_device *bl = platform_get_drvdata(dev);
+
+       backlight_device_unregister(bl);
+       platform_set_drvdata(dev, NULL);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int ep93xxbl_suspend(struct platform_device *dev, pm_message_t state)
+{
+       struct backlight_device *bl = platform_get_drvdata(dev);
+
+       return ep93xxbl_set(bl, 0);
+}
+
+static int ep93xxbl_resume(struct platform_device *dev)
+{
+       struct backlight_device *bl = platform_get_drvdata(dev);
+
+       backlight_update_status(bl);
+       return 0;
+}
+#else
+#define ep93xxbl_suspend       NULL
+#define ep93xxbl_resume                NULL
+#endif
+
+static struct platform_driver ep93xxbl_driver = {
+       .driver         = {
+               .name   = "ep93xx-bl",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = ep93xxbl_probe,
+       .remove         = __devexit_p(ep93xxbl_remove),
+       .suspend        = ep93xxbl_suspend,
+       .resume         = ep93xxbl_resume,
+};
+
+static int __init ep93xxbl_init(void)
+{
+       return platform_driver_register(&ep93xxbl_driver);
+}
+module_init(ep93xxbl_init);
+
+static void __exit ep93xxbl_exit(void)
+{
+       platform_driver_unregister(&ep93xxbl_driver);
+}
+module_exit(ep93xxbl_exit);
+
+MODULE_DESCRIPTION("EP93xx Backlight Driver");
+MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ep93xx-bl");
index bcdb12c93efddeed8f35c3d55d0bf6a63d170f89..9093ef0fa8696f2da8b086984042001aa94d8eec 100644 (file)
@@ -125,8 +125,7 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi)
 
        if (priv == NULL) {
                dev_err(&spi->dev, "No memory for this device.\n");
-               ret = -ENOMEM;
-               goto err;
+               return -ENOMEM;
        }
 
        dev_set_drvdata(&spi->dev, priv);
@@ -139,7 +138,7 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi)
        if (ret) {
                dev_err(&spi->dev,
                        "Unable to get the lcd l4f00242t03 reset gpio.\n");
-               return ret;
+               goto err;
        }
 
        ret = gpio_direction_output(pdata->reset_gpio, 1);
@@ -151,7 +150,7 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi)
        if (ret) {
                dev_err(&spi->dev,
                        "Unable to get the lcd l4f00242t03 data en gpio.\n");
-               return ret;
+               goto err2;
        }
 
        ret = gpio_direction_output(pdata->data_enable_gpio, 0);
@@ -222,9 +221,9 @@ static int __devexit l4f00242t03_remove(struct spi_device *spi)
        gpio_free(pdata->reset_gpio);
 
        if (priv->io_reg)
-               regulator_put(priv->core_reg);
-       if (priv->core_reg)
                regulator_put(priv->io_reg);
+       if (priv->core_reg)
+               regulator_put(priv->core_reg);
 
        kfree(priv);
 
index b5accc957ad37e50d5644f68749bb37d44667acf..b2b2c7ba1f63f1d1865d2b490f685fa27c2bb6b3 100644 (file)
@@ -162,6 +162,7 @@ static int __devinit max8925_backlight_probe(struct platform_device *pdev)
        backlight_update_status(bl);
        return 0;
 out:
+       backlight_device_unregister(bl);
        kfree(data);
        return ret;
 }
index 1b5d3fe6bbbccd3093cfb2772d4ee9deae42bcea..9fb533f6373e6ab958646ccfdcba047c43b99d9d 100644 (file)
@@ -141,7 +141,7 @@ static const struct dmi_system_id __initdata mbp_device_table[] = {
                .callback       = mbp_dmi_match,
                .ident          = "MacBook 1,1",
                .matches        = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."),
                        DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"),
                },
                .driver_data    = (void *)&intel_chipset_data,
@@ -182,6 +182,42 @@ static const struct dmi_system_id __initdata mbp_device_table[] = {
                },
                .driver_data    = (void *)&intel_chipset_data,
        },
+       {
+               .callback       = mbp_dmi_match,
+               .ident          = "MacBookPro 1,1",
+               .matches        = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro1,1"),
+               },
+               .driver_data    = (void *)&intel_chipset_data,
+       },
+       {
+               .callback       = mbp_dmi_match,
+               .ident          = "MacBookPro 1,2",
+               .matches        = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro1,2"),
+               },
+               .driver_data    = (void *)&intel_chipset_data,
+       },
+       {
+               .callback       = mbp_dmi_match,
+               .ident          = "MacBookPro 2,1",
+               .matches        = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,1"),
+               },
+               .driver_data    = (void *)&intel_chipset_data,
+       },
+       {
+               .callback       = mbp_dmi_match,
+               .ident          = "MacBookPro 2,2",
+               .matches        = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,2"),
+               },
+               .driver_data    = (void *)&intel_chipset_data,
+       },
        {
                .callback       = mbp_dmi_match,
                .ident          = "MacBookPro 3,1",
@@ -236,6 +272,15 @@ static const struct dmi_system_id __initdata mbp_device_table[] = {
                },
                .driver_data    = (void *)&nvidia_chipset_data,
        },
+       {
+               .callback       = mbp_dmi_match,
+               .ident          = "MacBook 6,1",
+               .matches        = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBook6,1"),
+               },
+               .driver_data    = (void *)&nvidia_chipset_data,
+       },
        {
                .callback       = mbp_dmi_match,
                .ident          = "MacBookAir 2,1",
diff --git a/drivers/video/backlight/pcf50633-backlight.c b/drivers/video/backlight/pcf50633-backlight.c
new file mode 100644 (file)
index 0000000..3c424f7
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ *  Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
+ *      PCF50633 backlight device driver
+ *
+ *  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.
+ *
+ *  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.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+#include <linux/backlight.h>
+#include <linux/fb.h>
+
+#include <linux/mfd/pcf50633/core.h>
+#include <linux/mfd/pcf50633/backlight.h>
+
+struct pcf50633_bl {
+       struct pcf50633 *pcf;
+       struct backlight_device *bl;
+
+       unsigned int brightness;
+       unsigned int brightness_limit;
+};
+
+/*
+ * pcf50633_bl_set_brightness_limit
+ *
+ * Update the brightness limit for the pc50633 backlight. The actual brightness
+ * will not go above the limit. This is useful to limit power drain for example
+ * on low battery.
+ *
+ * @dev: Pointer to a pcf50633 device
+ * @limit: The brightness limit. Valid values are 0-63
+ */
+int pcf50633_bl_set_brightness_limit(struct pcf50633 *pcf, unsigned int limit)
+{
+       struct pcf50633_bl *pcf_bl = platform_get_drvdata(pcf->bl_pdev);
+
+       if (!pcf_bl)
+               return -ENODEV;
+
+       pcf_bl->brightness_limit = limit & 0x3f;
+       backlight_update_status(pcf_bl->bl);
+
+    return 0;
+}
+
+static int pcf50633_bl_update_status(struct backlight_device *bl)
+{
+       struct pcf50633_bl *pcf_bl = bl_get_data(bl);
+       unsigned int new_brightness;
+
+
+       if (bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK) ||
+               bl->props.power != FB_BLANK_UNBLANK)
+               new_brightness = 0;
+       else if (bl->props.brightness < pcf_bl->brightness_limit)
+               new_brightness = bl->props.brightness;
+       else
+               new_brightness = pcf_bl->brightness_limit;
+
+
+       if (pcf_bl->brightness == new_brightness)
+               return 0;
+
+       if (new_brightness) {
+               pcf50633_reg_write(pcf_bl->pcf, PCF50633_REG_LEDOUT,
+                                       new_brightness);
+               if (!pcf_bl->brightness)
+                       pcf50633_reg_write(pcf_bl->pcf, PCF50633_REG_LEDENA, 1);
+       } else {
+               pcf50633_reg_write(pcf_bl->pcf, PCF50633_REG_LEDENA, 0);
+       }
+
+       pcf_bl->brightness = new_brightness;
+
+       return 0;
+}
+
+static int pcf50633_bl_get_brightness(struct backlight_device *bl)
+{
+       struct pcf50633_bl *pcf_bl = bl_get_data(bl);
+       return pcf_bl->brightness;
+}
+
+static const struct backlight_ops pcf50633_bl_ops = {
+       .get_brightness = pcf50633_bl_get_brightness,
+       .update_status  = pcf50633_bl_update_status,
+       .options        = BL_CORE_SUSPENDRESUME,
+};
+
+static int __devinit pcf50633_bl_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct pcf50633_bl *pcf_bl;
+       struct device *parent = pdev->dev.parent;
+       struct pcf50633_platform_data *pcf50633_data = parent->platform_data;
+       struct pcf50633_bl_platform_data *pdata = pcf50633_data->backlight_data;
+       struct backlight_properties bl_props;
+
+       pcf_bl = kzalloc(sizeof(*pcf_bl), GFP_KERNEL);
+       if (!pcf_bl)
+               return -ENOMEM;
+
+       bl_props.max_brightness = 0x3f;
+       bl_props.power = FB_BLANK_UNBLANK;
+
+       if (pdata) {
+               bl_props.brightness = pdata->default_brightness;
+               pcf_bl->brightness_limit = pdata->default_brightness_limit;
+       } else {
+               bl_props.brightness = 0x3f;
+               pcf_bl->brightness_limit = 0x3f;
+       }
+
+       pcf_bl->pcf = dev_to_pcf50633(pdev->dev.parent);
+
+       pcf_bl->bl = backlight_device_register(pdev->name, &pdev->dev, pcf_bl,
+                                               &pcf50633_bl_ops, &bl_props);
+
+       if (IS_ERR(pcf_bl->bl)) {
+               ret = PTR_ERR(pcf_bl->bl);
+               goto err_free;
+       }
+
+       platform_set_drvdata(pdev, pcf_bl);
+
+       pcf50633_reg_write(pcf_bl->pcf, PCF50633_REG_LEDDIM, pdata->ramp_time);
+
+       /* Should be different from bl_props.brightness, so we do not exit
+        * update_status early the first time it's called */
+       pcf_bl->brightness = pcf_bl->bl->props.brightness + 1;
+
+       backlight_update_status(pcf_bl->bl);
+
+       return 0;
+
+err_free:
+       kfree(pcf_bl);
+
+       return ret;
+}
+
+static int __devexit pcf50633_bl_remove(struct platform_device *pdev)
+{
+       struct pcf50633_bl *pcf_bl = platform_get_drvdata(pdev);
+
+       backlight_device_unregister(pcf_bl->bl);
+
+       platform_set_drvdata(pdev, NULL);
+
+       kfree(pcf_bl);
+
+       return 0;
+}
+
+static struct platform_driver pcf50633_bl_driver = {
+       .probe =        pcf50633_bl_probe,
+       .remove =       __devexit_p(pcf50633_bl_remove),
+       .driver = {
+               .name = "pcf50633-backlight",
+       },
+};
+
+static int __init pcf50633_bl_init(void)
+{
+       return platform_driver_register(&pcf50633_bl_driver);
+}
+module_init(pcf50633_bl_init);
+
+static void __exit pcf50633_bl_exit(void)
+{
+       platform_driver_unregister(&pcf50633_bl_driver);
+}
+module_exit(pcf50633_bl_exit);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("PCF50633 backlight driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pcf50633-backlight");
diff --git a/drivers/video/backlight/s6e63m0.c b/drivers/video/backlight/s6e63m0.c
new file mode 100644 (file)
index 0000000..a3128c9
--- /dev/null
@@ -0,0 +1,920 @@
+/*
+ * S6E63M0 AMOLED LCD panel driver.
+ *
+ * Author: InKi Dae  <inki.dae@samsung.com>
+ *
+ * Derived from drivers/video/omap/lcd-apollon.c
+ *
+ * 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/wait.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/lcd.h>
+#include <linux/backlight.h>
+
+#include "s6e63m0_gamma.h"
+
+#define SLEEPMSEC              0x1000
+#define ENDDEF                 0x2000
+#define        DEFMASK                 0xFF00
+#define COMMAND_ONLY           0xFE
+#define DATA_ONLY              0xFF
+
+#define MIN_BRIGHTNESS         0
+#define MAX_BRIGHTNESS         10
+
+#define POWER_IS_ON(pwr)       ((pwr) <= FB_BLANK_NORMAL)
+
+struct s6e63m0 {
+       struct device                   *dev;
+       struct spi_device               *spi;
+       unsigned int                    power;
+       unsigned int                    current_brightness;
+       unsigned int                    gamma_mode;
+       unsigned int                    gamma_table_count;
+       struct lcd_device               *ld;
+       struct backlight_device         *bd;
+       struct lcd_platform_data        *lcd_pd;
+};
+
+static const unsigned short SEQ_PANEL_CONDITION_SET[] = {
+       0xF8, 0x01,
+       DATA_ONLY, 0x27,
+       DATA_ONLY, 0x27,
+       DATA_ONLY, 0x07,
+       DATA_ONLY, 0x07,
+       DATA_ONLY, 0x54,
+       DATA_ONLY, 0x9f,
+       DATA_ONLY, 0x63,
+       DATA_ONLY, 0x86,
+       DATA_ONLY, 0x1a,
+       DATA_ONLY, 0x33,
+       DATA_ONLY, 0x0d,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+
+       ENDDEF, 0x0000
+};
+
+static const unsigned short SEQ_DISPLAY_CONDITION_SET[] = {
+       0xf2, 0x02,
+       DATA_ONLY, 0x03,
+       DATA_ONLY, 0x1c,
+       DATA_ONLY, 0x10,
+       DATA_ONLY, 0x10,
+
+       0xf7, 0x03,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+
+       ENDDEF, 0x0000
+};
+
+static const unsigned short SEQ_GAMMA_SETTING[] = {
+       0xfa, 0x00,
+       DATA_ONLY, 0x18,
+       DATA_ONLY, 0x08,
+       DATA_ONLY, 0x24,
+       DATA_ONLY, 0x64,
+       DATA_ONLY, 0x56,
+       DATA_ONLY, 0x33,
+       DATA_ONLY, 0xb6,
+       DATA_ONLY, 0xba,
+       DATA_ONLY, 0xa8,
+       DATA_ONLY, 0xac,
+       DATA_ONLY, 0xb1,
+       DATA_ONLY, 0x9d,
+       DATA_ONLY, 0xc1,
+       DATA_ONLY, 0xc1,
+       DATA_ONLY, 0xb7,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x9c,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x9f,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0xd6,
+
+       0xfa, 0x01,
+
+       ENDDEF, 0x0000
+};
+
+static const unsigned short SEQ_ETC_CONDITION_SET[] = {
+       0xf6, 0x00,
+       DATA_ONLY, 0x8c,
+       DATA_ONLY, 0x07,
+
+       0xb3, 0xc,
+
+       0xb5, 0x2c,
+       DATA_ONLY, 0x12,
+       DATA_ONLY, 0x0c,
+       DATA_ONLY, 0x0a,
+       DATA_ONLY, 0x10,
+       DATA_ONLY, 0x0e,
+       DATA_ONLY, 0x17,
+       DATA_ONLY, 0x13,
+       DATA_ONLY, 0x1f,
+       DATA_ONLY, 0x1a,
+       DATA_ONLY, 0x2a,
+       DATA_ONLY, 0x24,
+       DATA_ONLY, 0x1f,
+       DATA_ONLY, 0x1b,
+       DATA_ONLY, 0x1a,
+       DATA_ONLY, 0x17,
+
+       DATA_ONLY, 0x2b,
+       DATA_ONLY, 0x26,
+       DATA_ONLY, 0x22,
+       DATA_ONLY, 0x20,
+       DATA_ONLY, 0x3a,
+       DATA_ONLY, 0x34,
+       DATA_ONLY, 0x30,
+       DATA_ONLY, 0x2c,
+       DATA_ONLY, 0x29,
+       DATA_ONLY, 0x26,
+       DATA_ONLY, 0x25,
+       DATA_ONLY, 0x23,
+       DATA_ONLY, 0x21,
+       DATA_ONLY, 0x20,
+       DATA_ONLY, 0x1e,
+       DATA_ONLY, 0x1e,
+
+       0xb6, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x11,
+       DATA_ONLY, 0x22,
+       DATA_ONLY, 0x33,
+       DATA_ONLY, 0x44,
+       DATA_ONLY, 0x44,
+       DATA_ONLY, 0x44,
+
+       DATA_ONLY, 0x55,
+       DATA_ONLY, 0x55,
+       DATA_ONLY, 0x66,
+       DATA_ONLY, 0x66,
+       DATA_ONLY, 0x66,
+       DATA_ONLY, 0x66,
+       DATA_ONLY, 0x66,
+       DATA_ONLY, 0x66,
+
+       0xb7, 0x2c,
+       DATA_ONLY, 0x12,
+       DATA_ONLY, 0x0c,
+       DATA_ONLY, 0x0a,
+       DATA_ONLY, 0x10,
+       DATA_ONLY, 0x0e,
+       DATA_ONLY, 0x17,
+       DATA_ONLY, 0x13,
+       DATA_ONLY, 0x1f,
+       DATA_ONLY, 0x1a,
+       DATA_ONLY, 0x2a,
+       DATA_ONLY, 0x24,
+       DATA_ONLY, 0x1f,
+       DATA_ONLY, 0x1b,
+       DATA_ONLY, 0x1a,
+       DATA_ONLY, 0x17,
+
+       DATA_ONLY, 0x2b,
+       DATA_ONLY, 0x26,
+       DATA_ONLY, 0x22,
+       DATA_ONLY, 0x20,
+       DATA_ONLY, 0x3a,
+       DATA_ONLY, 0x34,
+       DATA_ONLY, 0x30,
+       DATA_ONLY, 0x2c,
+       DATA_ONLY, 0x29,
+       DATA_ONLY, 0x26,
+       DATA_ONLY, 0x25,
+       DATA_ONLY, 0x23,
+       DATA_ONLY, 0x21,
+       DATA_ONLY, 0x20,
+       DATA_ONLY, 0x1e,
+       DATA_ONLY, 0x1e,
+
+       0xb8, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x11,
+       DATA_ONLY, 0x22,
+       DATA_ONLY, 0x33,
+       DATA_ONLY, 0x44,
+       DATA_ONLY, 0x44,
+       DATA_ONLY, 0x44,
+
+       DATA_ONLY, 0x55,
+       DATA_ONLY, 0x55,
+       DATA_ONLY, 0x66,
+       DATA_ONLY, 0x66,
+       DATA_ONLY, 0x66,
+       DATA_ONLY, 0x66,
+       DATA_ONLY, 0x66,
+       DATA_ONLY, 0x66,
+
+       0xb9, 0x2c,
+       DATA_ONLY, 0x12,
+       DATA_ONLY, 0x0c,
+       DATA_ONLY, 0x0a,
+       DATA_ONLY, 0x10,
+       DATA_ONLY, 0x0e,
+       DATA_ONLY, 0x17,
+       DATA_ONLY, 0x13,
+       DATA_ONLY, 0x1f,
+       DATA_ONLY, 0x1a,
+       DATA_ONLY, 0x2a,
+       DATA_ONLY, 0x24,
+       DATA_ONLY, 0x1f,
+       DATA_ONLY, 0x1b,
+       DATA_ONLY, 0x1a,
+       DATA_ONLY, 0x17,
+
+       DATA_ONLY, 0x2b,
+       DATA_ONLY, 0x26,
+       DATA_ONLY, 0x22,
+       DATA_ONLY, 0x20,
+       DATA_ONLY, 0x3a,
+       DATA_ONLY, 0x34,
+       DATA_ONLY, 0x30,
+       DATA_ONLY, 0x2c,
+       DATA_ONLY, 0x29,
+       DATA_ONLY, 0x26,
+       DATA_ONLY, 0x25,
+       DATA_ONLY, 0x23,
+       DATA_ONLY, 0x21,
+       DATA_ONLY, 0x20,
+       DATA_ONLY, 0x1e,
+       DATA_ONLY, 0x1e,
+
+       0xba, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x11,
+       DATA_ONLY, 0x22,
+       DATA_ONLY, 0x33,
+       DATA_ONLY, 0x44,
+       DATA_ONLY, 0x44,
+       DATA_ONLY, 0x44,
+
+       DATA_ONLY, 0x55,
+       DATA_ONLY, 0x55,
+       DATA_ONLY, 0x66,
+       DATA_ONLY, 0x66,
+       DATA_ONLY, 0x66,
+       DATA_ONLY, 0x66,
+       DATA_ONLY, 0x66,
+       DATA_ONLY, 0x66,
+
+       0xc1, 0x4d,
+       DATA_ONLY, 0x96,
+       DATA_ONLY, 0x1d,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x01,
+       DATA_ONLY, 0xdf,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x03,
+       DATA_ONLY, 0x1f,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x03,
+       DATA_ONLY, 0x06,
+       DATA_ONLY, 0x09,
+       DATA_ONLY, 0x0d,
+       DATA_ONLY, 0x0f,
+       DATA_ONLY, 0x12,
+       DATA_ONLY, 0x15,
+       DATA_ONLY, 0x18,
+
+       0xb2, 0x10,
+       DATA_ONLY, 0x10,
+       DATA_ONLY, 0x0b,
+       DATA_ONLY, 0x05,
+
+       ENDDEF, 0x0000
+};
+
+static const unsigned short SEQ_ACL_ON[] = {
+       /* ACL on */
+       0xc0, 0x01,
+
+       ENDDEF, 0x0000
+};
+
+static const unsigned short SEQ_ACL_OFF[] = {
+       /* ACL off */
+       0xc0, 0x00,
+
+       ENDDEF, 0x0000
+};
+
+static const unsigned short SEQ_ELVSS_ON[] = {
+       /* ELVSS on */
+       0xb1, 0x0b,
+
+       ENDDEF, 0x0000
+};
+
+static const unsigned short SEQ_ELVSS_OFF[] = {
+       /* ELVSS off */
+       0xb1, 0x0a,
+
+       ENDDEF, 0x0000
+};
+
+static const unsigned short SEQ_STAND_BY_OFF[] = {
+       0x11, COMMAND_ONLY,
+
+       ENDDEF, 0x0000
+};
+
+static const unsigned short SEQ_STAND_BY_ON[] = {
+       0x10, COMMAND_ONLY,
+
+       ENDDEF, 0x0000
+};
+
+static const unsigned short SEQ_DISPLAY_ON[] = {
+       0x29, COMMAND_ONLY,
+
+       ENDDEF, 0x0000
+};
+
+
+static int s6e63m0_spi_write_byte(struct s6e63m0 *lcd, int addr, int data)
+{
+       u16 buf[1];
+       struct spi_message msg;
+
+       struct spi_transfer xfer = {
+               .len            = 2,
+               .tx_buf         = buf,
+       };
+
+       buf[0] = (addr << 8) | data;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+
+       return spi_sync(lcd->spi, &msg);
+}
+
+static int s6e63m0_spi_write(struct s6e63m0 *lcd, unsigned char address,
+       unsigned char command)
+{
+       int ret = 0;
+
+       if (address != DATA_ONLY)
+               ret = s6e63m0_spi_write_byte(lcd, 0x0, address);
+       if (command != COMMAND_ONLY)
+               ret = s6e63m0_spi_write_byte(lcd, 0x1, command);
+
+       return ret;
+}
+
+static int s6e63m0_panel_send_sequence(struct s6e63m0 *lcd,
+       const unsigned short *wbuf)
+{
+       int ret = 0, i = 0;
+
+       while ((wbuf[i] & DEFMASK) != ENDDEF) {
+               if ((wbuf[i] & DEFMASK) != SLEEPMSEC) {
+                       ret = s6e63m0_spi_write(lcd, wbuf[i], wbuf[i+1]);
+                       if (ret)
+                               break;
+               } else
+                       udelay(wbuf[i+1]*1000);
+               i += 2;
+       }
+
+       return ret;
+}
+
+static int _s6e63m0_gamma_ctl(struct s6e63m0 *lcd, const unsigned int *gamma)
+{
+       unsigned int i = 0;
+       int ret = 0;
+
+       /* disable gamma table updating. */
+       ret = s6e63m0_spi_write(lcd, 0xfa, 0x00);
+       if (ret) {
+               dev_err(lcd->dev, "failed to disable gamma table updating.\n");
+               goto gamma_err;
+       }
+
+       for (i = 0 ; i < GAMMA_TABLE_COUNT; i++) {
+               ret = s6e63m0_spi_write(lcd, DATA_ONLY, gamma[i]);
+               if (ret) {
+                       dev_err(lcd->dev, "failed to set gamma table.\n");
+                       goto gamma_err;
+               }
+       }
+
+       /* update gamma table. */
+       ret = s6e63m0_spi_write(lcd, 0xfa, 0x01);
+       if (ret)
+               dev_err(lcd->dev, "failed to update gamma table.\n");
+
+gamma_err:
+       return ret;
+}
+
+static int s6e63m0_gamma_ctl(struct s6e63m0 *lcd, int gamma)
+{
+       int ret = 0;
+
+       ret = _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_22_table[gamma]);
+
+       return ret;
+}
+
+
+static int s6e63m0_ldi_init(struct s6e63m0 *lcd)
+{
+       int ret, i;
+       const unsigned short *init_seq[] = {
+               SEQ_PANEL_CONDITION_SET,
+               SEQ_DISPLAY_CONDITION_SET,
+               SEQ_GAMMA_SETTING,
+               SEQ_ETC_CONDITION_SET,
+               SEQ_ACL_ON,
+               SEQ_ELVSS_ON,
+       };
+
+       for (i = 0; i < ARRAY_SIZE(init_seq); i++) {
+               ret = s6e63m0_panel_send_sequence(lcd, init_seq[i]);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+
+static int s6e63m0_ldi_enable(struct s6e63m0 *lcd)
+{
+       int ret = 0, i;
+       const unsigned short *enable_seq[] = {
+               SEQ_STAND_BY_OFF,
+               SEQ_DISPLAY_ON,
+       };
+
+       for (i = 0; i < ARRAY_SIZE(enable_seq); i++) {
+               ret = s6e63m0_panel_send_sequence(lcd, enable_seq[i]);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+
+static int s6e63m0_ldi_disable(struct s6e63m0 *lcd)
+{
+       int ret;
+
+       ret = s6e63m0_panel_send_sequence(lcd, SEQ_STAND_BY_ON);
+
+       return ret;
+}
+
+static int s6e63m0_power_on(struct s6e63m0 *lcd)
+{
+       int ret = 0;
+       struct lcd_platform_data *pd = NULL;
+       struct backlight_device *bd = NULL;
+
+       pd = lcd->lcd_pd;
+       if (!pd) {
+               dev_err(lcd->dev, "platform data is NULL.\n");
+               return -EFAULT;
+       }
+
+       bd = lcd->bd;
+       if (!bd) {
+               dev_err(lcd->dev, "backlight device is NULL.\n");
+               return -EFAULT;
+       }
+
+       if (!pd->power_on) {
+               dev_err(lcd->dev, "power_on is NULL.\n");
+               return -EFAULT;
+       } else {
+               pd->power_on(lcd->ld, 1);
+               mdelay(pd->power_on_delay);
+       }
+
+       if (!pd->reset) {
+               dev_err(lcd->dev, "reset is NULL.\n");
+               return -EFAULT;
+       } else {
+               pd->reset(lcd->ld);
+               mdelay(pd->reset_delay);
+       }
+
+       ret = s6e63m0_ldi_init(lcd);
+       if (ret) {
+               dev_err(lcd->dev, "failed to initialize ldi.\n");
+               return ret;
+       }
+
+       ret = s6e63m0_ldi_enable(lcd);
+       if (ret) {
+               dev_err(lcd->dev, "failed to enable ldi.\n");
+               return ret;
+       }
+
+       /* set brightness to current value after power on or resume. */
+       ret = s6e63m0_gamma_ctl(lcd, bd->props.brightness);
+       if (ret) {
+               dev_err(lcd->dev, "lcd gamma setting failed.\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int s6e63m0_power_off(struct s6e63m0 *lcd)
+{
+       int ret = 0;
+       struct lcd_platform_data *pd = NULL;
+
+       pd = lcd->lcd_pd;
+       if (!pd) {
+               dev_err(lcd->dev, "platform data is NULL.\n");
+               return -EFAULT;
+       }
+
+       ret = s6e63m0_ldi_disable(lcd);
+       if (ret) {
+               dev_err(lcd->dev, "lcd setting failed.\n");
+               return -EIO;
+       }
+
+       mdelay(pd->power_off_delay);
+
+       if (!pd->power_on) {
+               dev_err(lcd->dev, "power_on is NULL.\n");
+               return -EFAULT;
+       } else
+               pd->power_on(lcd->ld, 0);
+
+       return 0;
+}
+
+static int s6e63m0_power(struct s6e63m0 *lcd, int power)
+{
+       int ret = 0;
+
+       if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power))
+               ret = s6e63m0_power_on(lcd);
+       else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power))
+               ret = s6e63m0_power_off(lcd);
+
+       if (!ret)
+               lcd->power = power;
+
+       return ret;
+}
+
+static int s6e63m0_set_power(struct lcd_device *ld, int power)
+{
+       struct s6e63m0 *lcd = lcd_get_data(ld);
+
+       if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN &&
+               power != FB_BLANK_NORMAL) {
+               dev_err(lcd->dev, "power value should be 0, 1 or 4.\n");
+               return -EINVAL;
+       }
+
+       return s6e63m0_power(lcd, power);
+}
+
+static int s6e63m0_get_power(struct lcd_device *ld)
+{
+       struct s6e63m0 *lcd = lcd_get_data(ld);
+
+       return lcd->power;
+}
+
+static int s6e63m0_get_brightness(struct backlight_device *bd)
+{
+       return bd->props.brightness;
+}
+
+static int s6e63m0_set_brightness(struct backlight_device *bd)
+{
+       int ret = 0, brightness = bd->props.brightness;
+       struct s6e63m0 *lcd = bl_get_data(bd);
+
+       if (brightness < MIN_BRIGHTNESS ||
+               brightness > bd->props.max_brightness) {
+               dev_err(&bd->dev, "lcd brightness should be %d to %d.\n",
+                       MIN_BRIGHTNESS, MAX_BRIGHTNESS);
+               return -EINVAL;
+       }
+
+       ret = s6e63m0_gamma_ctl(lcd, bd->props.brightness);
+       if (ret) {
+               dev_err(&bd->dev, "lcd brightness setting failed.\n");
+               return -EIO;
+       }
+
+       return ret;
+}
+
+static struct lcd_ops s6e63m0_lcd_ops = {
+       .set_power = s6e63m0_set_power,
+       .get_power = s6e63m0_get_power,
+};
+
+static const struct backlight_ops s6e63m0_backlight_ops  = {
+       .get_brightness = s6e63m0_get_brightness,
+       .update_status = s6e63m0_set_brightness,
+};
+
+static ssize_t s6e63m0_sysfs_show_gamma_mode(struct device *dev,
+                                     struct device_attribute *attr, char *buf)
+{
+       struct s6e63m0 *lcd = dev_get_drvdata(dev);
+       char temp[10];
+
+       switch (lcd->gamma_mode) {
+       case 0:
+               sprintf(temp, "2.2 mode\n");
+               strcat(buf, temp);
+               break;
+       case 1:
+               sprintf(temp, "1.9 mode\n");
+               strcat(buf, temp);
+               break;
+       case 2:
+               sprintf(temp, "1.7 mode\n");
+               strcat(buf, temp);
+               break;
+       default:
+               dev_info(dev, "gamma mode could be 0:2.2, 1:1.9 or 2:1.7)n");
+               break;
+       }
+
+       return strlen(buf);
+}
+
+static ssize_t s6e63m0_sysfs_store_gamma_mode(struct device *dev,
+                                      struct device_attribute *attr,
+                                      const char *buf, size_t len)
+{
+       struct s6e63m0 *lcd = dev_get_drvdata(dev);
+       struct backlight_device *bd = NULL;
+       int brightness, rc;
+
+       rc = strict_strtoul(buf, 0, (unsigned long *)&lcd->gamma_mode);
+       if (rc < 0)
+               return rc;
+
+       bd = lcd->bd;
+
+       brightness = bd->props.brightness;
+
+       switch (lcd->gamma_mode) {
+       case 0:
+               _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_22_table[brightness]);
+               break;
+       case 1:
+               _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_19_table[brightness]);
+               break;
+       case 2:
+               _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_17_table[brightness]);
+               break;
+       default:
+               dev_info(dev, "gamma mode could be 0:2.2, 1:1.9 or 2:1.7\n");
+               _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_22_table[brightness]);
+               break;
+       }
+       return len;
+}
+
+static DEVICE_ATTR(gamma_mode, 0644,
+               s6e63m0_sysfs_show_gamma_mode, s6e63m0_sysfs_store_gamma_mode);
+
+static ssize_t s6e63m0_sysfs_show_gamma_table(struct device *dev,
+                                     struct device_attribute *attr, char *buf)
+{
+       struct s6e63m0 *lcd = dev_get_drvdata(dev);
+       char temp[3];
+
+       sprintf(temp, "%d\n", lcd->gamma_table_count);
+       strcpy(buf, temp);
+
+       return strlen(buf);
+}
+static DEVICE_ATTR(gamma_table, 0644,
+               s6e63m0_sysfs_show_gamma_table, NULL);
+
+static int __init s6e63m0_probe(struct spi_device *spi)
+{
+       int ret = 0;
+       struct s6e63m0 *lcd = NULL;
+       struct lcd_device *ld = NULL;
+       struct backlight_device *bd = NULL;
+
+       lcd = kzalloc(sizeof(struct s6e63m0), GFP_KERNEL);
+       if (!lcd)
+               return -ENOMEM;
+
+       /* s6e63m0 lcd panel uses 3-wire 9bits SPI Mode. */
+       spi->bits_per_word = 9;
+
+       ret = spi_setup(spi);
+       if (ret < 0) {
+               dev_err(&spi->dev, "spi setup failed.\n");
+               goto out_free_lcd;
+       }
+
+       lcd->spi = spi;
+       lcd->dev = &spi->dev;
+
+       lcd->lcd_pd = (struct lcd_platform_data *)spi->dev.platform_data;
+       if (!lcd->lcd_pd) {
+               dev_err(&spi->dev, "platform data is NULL.\n");
+               goto out_free_lcd;
+       }
+
+       ld = lcd_device_register("s6e63m0", &spi->dev, lcd, &s6e63m0_lcd_ops);
+       if (IS_ERR(ld)) {
+               ret = PTR_ERR(ld);
+               goto out_free_lcd;
+       }
+
+       lcd->ld = ld;
+
+       bd = backlight_device_register("s6e63m0bl-bl", &spi->dev, lcd,
+               &s6e63m0_backlight_ops, NULL);
+       if (IS_ERR(bd)) {
+               ret =  PTR_ERR(bd);
+               goto out_lcd_unregister;
+       }
+
+       bd->props.max_brightness = MAX_BRIGHTNESS;
+       bd->props.brightness = MAX_BRIGHTNESS;
+       lcd->bd = bd;
+
+       /*
+        * it gets gamma table count available so it gets user
+        * know that.
+        */
+       lcd->gamma_table_count =
+           sizeof(gamma_table) / (MAX_GAMMA_LEVEL * sizeof(int));
+
+       ret = device_create_file(&(spi->dev), &dev_attr_gamma_mode);
+       if (ret < 0)
+               dev_err(&(spi->dev), "failed to add sysfs entries\n");
+
+       ret = device_create_file(&(spi->dev), &dev_attr_gamma_table);
+       if (ret < 0)
+               dev_err(&(spi->dev), "failed to add sysfs entries\n");
+
+       /*
+        * if lcd panel was on from bootloader like u-boot then
+        * do not lcd on.
+        */
+       if (!lcd->lcd_pd->lcd_enabled) {
+               /*
+                * if lcd panel was off from bootloader then
+                * current lcd status is powerdown and then
+                * it enables lcd panel.
+                */
+               lcd->power = FB_BLANK_POWERDOWN;
+
+               s6e63m0_power(lcd, FB_BLANK_UNBLANK);
+       } else
+               lcd->power = FB_BLANK_UNBLANK;
+
+       dev_set_drvdata(&spi->dev, lcd);
+
+       dev_info(&spi->dev, "s6e63m0 panel driver has been probed.\n");
+
+       return 0;
+
+out_lcd_unregister:
+       lcd_device_unregister(ld);
+out_free_lcd:
+       kfree(lcd);
+       return ret;
+}
+
+static int __devexit s6e63m0_remove(struct spi_device *spi)
+{
+       struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev);
+
+       s6e63m0_power(lcd, FB_BLANK_POWERDOWN);
+       lcd_device_unregister(lcd->ld);
+       kfree(lcd);
+
+       return 0;
+}
+
+#if defined(CONFIG_PM)
+unsigned int before_power;
+
+static int s6e63m0_suspend(struct spi_device *spi, pm_message_t mesg)
+{
+       int ret = 0;
+       struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev);
+
+       dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power);
+
+       before_power = lcd->power;
+
+       /*
+        * when lcd panel is suspend, lcd panel becomes off
+        * regardless of status.
+        */
+       ret = s6e63m0_power(lcd, FB_BLANK_POWERDOWN);
+
+       return ret;
+}
+
+static int s6e63m0_resume(struct spi_device *spi)
+{
+       int ret = 0;
+       struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev);
+
+       /*
+        * after suspended, if lcd panel status is FB_BLANK_UNBLANK
+        * (at that time, before_power is FB_BLANK_UNBLANK) then
+        * it changes that status to FB_BLANK_POWERDOWN to get lcd on.
+        */
+       if (before_power == FB_BLANK_UNBLANK)
+               lcd->power = FB_BLANK_POWERDOWN;
+
+       dev_dbg(&spi->dev, "before_power = %d\n", before_power);
+
+       ret = s6e63m0_power(lcd, before_power);
+
+       return ret;
+}
+#else
+#define s6e63m0_suspend                NULL
+#define s6e63m0_resume         NULL
+#endif
+
+/* Power down all displays on reboot, poweroff or halt. */
+static void s6e63m0_shutdown(struct spi_device *spi)
+{
+       struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev);
+
+       s6e63m0_power(lcd, FB_BLANK_POWERDOWN);
+}
+
+static struct spi_driver s6e63m0_driver = {
+       .driver = {
+               .name   = "s6e63m0",
+               .bus    = &spi_bus_type,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = s6e63m0_probe,
+       .remove         = __devexit_p(s6e63m0_remove),
+       .shutdown       = s6e63m0_shutdown,
+       .suspend        = s6e63m0_suspend,
+       .resume         = s6e63m0_resume,
+};
+
+static int __init s6e63m0_init(void)
+{
+       return spi_register_driver(&s6e63m0_driver);
+}
+
+static void __exit s6e63m0_exit(void)
+{
+       spi_unregister_driver(&s6e63m0_driver);
+}
+
+module_init(s6e63m0_init);
+module_exit(s6e63m0_exit);
+
+MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>");
+MODULE_DESCRIPTION("S6E63M0 LCD Driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/video/backlight/s6e63m0_gamma.h b/drivers/video/backlight/s6e63m0_gamma.h
new file mode 100644 (file)
index 0000000..2c44bdb
--- /dev/null
@@ -0,0 +1,266 @@
+/* linux/drivers/video/samsung/s6e63m0_brightness.h
+ *
+ * Gamma level definitions.
+ *
+ * Copyright (c) 2009 Samsung Electronics
+ * InKi Dae <inki.dae@samsung.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 _S6E63M0_BRIGHTNESS_H
+#define _S6E63M0_BRIGHTNESS_H
+
+#define MAX_GAMMA_LEVEL                11
+#define GAMMA_TABLE_COUNT      21
+
+/* gamma value: 2.2 */
+static const unsigned int s6e63m0_22_300[] = {
+       0x18, 0x08, 0x24, 0x5f, 0x50, 0x2d, 0xB6,
+       0xB9, 0xA7, 0xAd, 0xB1, 0x9f, 0xbe, 0xC0,
+       0xB5, 0x00, 0xa0, 0x00, 0xa4, 0x00, 0xdb
+};
+
+static const unsigned int s6e63m0_22_280[] = {
+       0x18, 0x08, 0x24, 0x64, 0x56, 0x33, 0xB6,
+       0xBA, 0xA8, 0xAC, 0xB1, 0x9D, 0xC1, 0xC1,
+       0xB7, 0x00, 0x9C, 0x00, 0x9F, 0x00, 0xD6
+};
+
+static const unsigned int s6e63m0_22_260[] = {
+       0x18, 0x08, 0x24, 0x66, 0x58, 0x34, 0xB6,
+       0xBA, 0xA7, 0xAF, 0xB3, 0xA0, 0xC1, 0xC2,
+       0xB7, 0x00, 0x97, 0x00, 0x9A, 0x00, 0xD1
+
+};
+
+static const unsigned int s6e63m0_22_240[] = {
+       0x18, 0x08, 0x24, 0x62, 0x54, 0x30, 0xB9,
+       0xBB, 0xA9, 0xB0, 0xB3, 0xA1, 0xC1, 0xC3,
+       0xB7, 0x00, 0x91, 0x00, 0x95, 0x00, 0xDA
+
+};
+static const unsigned int s6e63m0_22_220[] = {
+       0x18, 0x08, 0x24, 0x63, 0x53, 0x31, 0xB8,
+       0xBC, 0xA9, 0xB0, 0xB5, 0xA2, 0xC4, 0xC4,
+       0xB8, 0x00, 0x8B, 0x00, 0x8E, 0x00, 0xC2
+};
+
+static const unsigned int s6e63m0_22_200[] = {
+       0x18, 0x08, 0x24, 0x66, 0x55, 0x34, 0xBA,
+       0xBD, 0xAB, 0xB1, 0xB5, 0xA3, 0xC5, 0xC6,
+       0xB9, 0x00, 0x85, 0x00, 0x88, 0x00, 0xBA
+};
+
+static const unsigned int s6e63m0_22_170[] = {
+       0x18, 0x08, 0x24, 0x69, 0x54, 0x37, 0xBB,
+       0xBE, 0xAC, 0xB4, 0xB7, 0xA6, 0xC7, 0xC8,
+       0xBC, 0x00, 0x7B, 0x00, 0x7E, 0x00, 0xAB
+};
+
+static const unsigned int s6e63m0_22_140[] = {
+       0x18, 0x08, 0x24, 0x6C, 0x54, 0x3A, 0xBC,
+       0xBF, 0xAC, 0xB7, 0xBB, 0xA9, 0xC9, 0xC9,
+       0xBE, 0x00, 0x71, 0x00, 0x73, 0x00, 0x9E
+};
+
+static const unsigned int s6e63m0_22_110[] = {
+       0x18, 0x08, 0x24, 0x70, 0x51, 0x3E, 0xBF,
+       0xC1, 0xAF, 0xB9, 0xBC, 0xAB, 0xCC, 0xCC,
+       0xC2, 0x00, 0x65, 0x00, 0x67, 0x00, 0x8D
+};
+
+static const unsigned int s6e63m0_22_90[] = {
+       0x18, 0x08, 0x24, 0x73, 0x4A, 0x3D, 0xC0,
+       0xC2, 0xB1, 0xBB, 0xBE, 0xAC, 0xCE, 0xCF,
+       0xC5, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x82
+};
+
+static const unsigned int s6e63m0_22_30[] = {
+       0x18, 0x08, 0x24, 0x78, 0xEC, 0x3D, 0xC8,
+       0xC2, 0xB6, 0xC4, 0xC7, 0xB6, 0xD5, 0xD7,
+       0xCC, 0x00, 0x39, 0x00, 0x36, 0x00, 0x51
+};
+
+/* gamma value: 1.9 */
+static const unsigned int s6e63m0_19_300[] = {
+       0x18, 0x08, 0x24, 0x61, 0x5F, 0x39, 0xBA,
+       0xBD, 0xAD, 0xB1, 0xB6, 0xA5, 0xC4, 0xC5,
+       0xBC, 0x00, 0xA0, 0x00, 0xA4, 0x00, 0xDB
+};
+
+static const unsigned int s6e63m0_19_280[] = {
+       0x18, 0x08, 0x24, 0x61, 0x60, 0x39, 0xBB,
+       0xBE, 0xAD, 0xB2, 0xB6, 0xA6, 0xC5, 0xC7,
+       0xBD, 0x00, 0x9B, 0x00, 0x9E, 0x00, 0xD5
+};
+
+static const unsigned int s6e63m0_19_260[] = {
+       0x18, 0x08, 0x24, 0x63, 0x61, 0x3B, 0xBA,
+       0xBE, 0xAC, 0xB3, 0xB8, 0xA7, 0xC6, 0xC8,
+       0xBD, 0x00, 0x96, 0x00, 0x98, 0x00, 0xCF
+};
+
+static const unsigned int s6e63m0_19_240[] = {
+       0x18, 0x08, 0x24, 0x67, 0x64, 0x3F, 0xBB,
+       0xBE, 0xAD, 0xB3, 0xB9, 0xA7, 0xC8, 0xC9,
+       0xBE, 0x00, 0x90, 0x00, 0x92, 0x00, 0xC8
+};
+
+static const unsigned int s6e63m0_19_220[] = {
+       0x18, 0x08, 0x24, 0x68, 0x64, 0x40, 0xBC,
+       0xBF, 0xAF, 0xB4, 0xBA, 0xA9, 0xC8, 0xCA,
+       0xBE, 0x00, 0x8B, 0x00, 0x8C, 0x00, 0xC0
+};
+
+static const unsigned int s6e63m0_19_200[] = {
+       0x18, 0x08, 0x24, 0x68, 0x64, 0x3F, 0xBE,
+       0xC0, 0xB0, 0xB6, 0xBB, 0xAB, 0xC8, 0xCB,
+       0xBF, 0x00, 0x85, 0x00, 0x86, 0x00, 0xB8
+};
+
+static const unsigned int s6e63m0_19_170[] = {
+       0x18, 0x08, 0x24, 0x69, 0x64, 0x40, 0xBF,
+       0xC1, 0xB0, 0xB9, 0xBE, 0xAD, 0xCB, 0xCD,
+       0xC2, 0x00, 0x7A, 0x00, 0x7B, 0x00, 0xAA
+};
+
+static const unsigned int s6e63m0_19_140[] = {
+       0x18, 0x08, 0x24, 0x6E, 0x65, 0x45, 0xC0,
+       0xC3, 0xB2, 0xBA, 0xBE, 0xAE, 0xCD, 0xD0,
+       0xC4, 0x00, 0x70, 0x00, 0x70, 0x00, 0x9C
+};
+
+static const unsigned int s6e63m0_19_110[] = {
+       0x18, 0x08, 0x24, 0x6F, 0x65, 0x46, 0xC2,
+       0xC4, 0xB3, 0xBF, 0xC2, 0xB2, 0xCF, 0xD1,
+       0xC6, 0x00, 0x64, 0x00, 0x64, 0x00, 0x8D
+};
+
+static const unsigned int s6e63m0_19_90[] = {
+       0x18, 0x08, 0x24, 0x74, 0x60, 0x4A, 0xC3,
+       0xC6, 0xB5, 0xBF, 0xC3, 0xB2, 0xD2, 0xD3,
+       0xC8, 0x00, 0x5B, 0x00, 0x5B, 0x00, 0x81
+};
+
+static const unsigned int s6e63m0_19_30[] = {
+       0x18, 0x08, 0x24, 0x84, 0x45, 0x4F, 0xCA,
+       0xCB, 0xBC, 0xC9, 0xCB, 0xBC, 0xDA, 0xDA,
+       0xD0, 0x00, 0x35, 0x00, 0x34, 0x00, 0x4E
+};
+
+/* gamma value: 1.7 */
+static const unsigned int s6e63m0_17_300[] = {
+       0x18, 0x08, 0x24, 0x70, 0x70, 0x4F, 0xBF,
+       0xC2, 0xB2, 0xB8, 0xBC, 0xAC, 0xCB, 0xCD,
+       0xC3, 0x00, 0xA0, 0x00, 0xA4, 0x00, 0xDB
+};
+
+static const unsigned int s6e63m0_17_280[] = {
+       0x18, 0x08, 0x24, 0x71, 0x71, 0x50, 0xBF,
+       0xC2, 0xB2, 0xBA, 0xBE, 0xAE, 0xCB, 0xCD,
+       0xC3, 0x00, 0x9C, 0x00, 0x9F, 0x00, 0xD6
+};
+
+static const unsigned int s6e63m0_17_260[] = {
+       0x18, 0x08, 0x24, 0x72, 0x72, 0x50, 0xC0,
+       0xC3, 0xB4, 0xB9, 0xBE, 0xAE, 0xCC, 0xCF,
+       0xC4, 0x00, 0x97, 0x00, 0x9A, 0x00, 0xD1
+};
+
+static const unsigned int s6e63m0_17_240[] = {
+       0x18, 0x08, 0x24, 0x71, 0x72, 0x4F, 0xC2,
+       0xC4, 0xB5, 0xBB, 0xBF, 0xB0, 0xCC, 0xCF,
+       0xC3, 0x00, 0x91, 0x00, 0x95, 0x00, 0xCA
+};
+
+static const unsigned int s6e63m0_17_220[] = {
+       0x18, 0x08, 0x24, 0x71, 0x73, 0x4F, 0xC2,
+       0xC5, 0xB5, 0xBD, 0xC0, 0xB2, 0xCD, 0xD1,
+       0xC5, 0x00, 0x8B, 0x00, 0x8E, 0x00, 0xC2
+};
+
+static const unsigned int s6e63m0_17_200[] = {
+       0x18, 0x08, 0x24, 0x72, 0x75, 0x51, 0xC2,
+       0xC6, 0xB5, 0xBF, 0xC1, 0xB3, 0xCE, 0xD1,
+       0xC6, 0x00, 0x85, 0x00, 0x88, 0x00, 0xBA
+};
+
+static const unsigned int s6e63m0_17_170[] = {
+       0x18, 0x08, 0x24, 0x75, 0x77, 0x54, 0xC3,
+       0xC7, 0xB7, 0xC0, 0xC3, 0xB4, 0xD1, 0xD3,
+       0xC9, 0x00, 0x7B, 0x00, 0x7E, 0x00, 0xAB
+};
+
+static const unsigned int s6e63m0_17_140[] = {
+       0x18, 0x08, 0x24, 0x7B, 0x77, 0x58, 0xC3,
+       0xC8, 0xB8, 0xC2, 0xC6, 0xB6, 0xD3, 0xD4,
+       0xCA, 0x00, 0x71, 0x00, 0x73, 0x00, 0x9E
+};
+
+static const unsigned int s6e63m0_17_110[] = {
+       0x18, 0x08, 0x24, 0x81, 0x7B, 0x5D, 0xC6,
+       0xCA, 0xBB, 0xC3, 0xC7, 0xB8, 0xD6, 0xD8,
+       0xCD, 0x00, 0x65, 0x00, 0x67, 0x00, 0x8D
+};
+
+static const unsigned int s6e63m0_17_90[] = {
+       0x18, 0x08, 0x24, 0x82, 0x7A, 0x5B, 0xC8,
+       0xCB, 0xBD, 0xC5, 0xCA, 0xBA, 0xD6, 0xD8,
+       0xCE, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x82
+};
+
+static const unsigned int s6e63m0_17_30[] = {
+       0x18, 0x08, 0x24, 0x8F, 0x73, 0x63, 0xD1,
+       0xD0, 0xC5, 0xCC, 0xD1, 0xC2, 0xDE, 0xE0,
+       0xD6, 0x00, 0x39, 0x00, 0x36, 0x00, 0x51
+};
+
+struct s6e63m0_gamma {
+       unsigned int *gamma_22_table[MAX_GAMMA_LEVEL];
+       unsigned int *gamma_19_table[MAX_GAMMA_LEVEL];
+       unsigned int *gamma_17_table[MAX_GAMMA_LEVEL];
+};
+
+static struct s6e63m0_gamma gamma_table = {
+       .gamma_22_table[0] = (unsigned int *)&s6e63m0_22_30,
+       .gamma_22_table[1] = (unsigned int *)&s6e63m0_22_90,
+       .gamma_22_table[2] = (unsigned int *)&s6e63m0_22_110,
+       .gamma_22_table[3] = (unsigned int *)&s6e63m0_22_140,
+       .gamma_22_table[4] = (unsigned int *)&s6e63m0_22_170,
+       .gamma_22_table[5] = (unsigned int *)&s6e63m0_22_200,
+       .gamma_22_table[6] = (unsigned int *)&s6e63m0_22_220,
+       .gamma_22_table[7] = (unsigned int *)&s6e63m0_22_240,
+       .gamma_22_table[8] = (unsigned int *)&s6e63m0_22_260,
+       .gamma_22_table[9] = (unsigned int *)&s6e63m0_22_280,
+       .gamma_22_table[10] = (unsigned int *)&s6e63m0_22_300,
+
+       .gamma_19_table[0] = (unsigned int *)&s6e63m0_19_30,
+       .gamma_19_table[1] = (unsigned int *)&s6e63m0_19_90,
+       .gamma_19_table[2] = (unsigned int *)&s6e63m0_19_110,
+       .gamma_19_table[3] = (unsigned int *)&s6e63m0_19_140,
+       .gamma_19_table[4] = (unsigned int *)&s6e63m0_19_170,
+       .gamma_19_table[5] = (unsigned int *)&s6e63m0_19_200,
+       .gamma_19_table[6] = (unsigned int *)&s6e63m0_19_220,
+       .gamma_19_table[7] = (unsigned int *)&s6e63m0_19_240,
+       .gamma_19_table[8] = (unsigned int *)&s6e63m0_19_260,
+       .gamma_19_table[9] = (unsigned int *)&s6e63m0_19_280,
+       .gamma_19_table[10] = (unsigned int *)&s6e63m0_19_300,
+
+       .gamma_17_table[0] = (unsigned int *)&s6e63m0_17_30,
+       .gamma_17_table[1] = (unsigned int *)&s6e63m0_17_90,
+       .gamma_17_table[2] = (unsigned int *)&s6e63m0_17_110,
+       .gamma_17_table[3] = (unsigned int *)&s6e63m0_17_140,
+       .gamma_17_table[4] = (unsigned int *)&s6e63m0_17_170,
+       .gamma_17_table[5] = (unsigned int *)&s6e63m0_17_200,
+       .gamma_17_table[6] = (unsigned int *)&s6e63m0_17_220,
+       .gamma_17_table[7] = (unsigned int *)&s6e63m0_17_240,
+       .gamma_17_table[8] = (unsigned int *)&s6e63m0_17_260,
+       .gamma_17_table[9] = (unsigned int *)&s6e63m0_17_280,
+       .gamma_17_table[10] = (unsigned int *)&s6e63m0_17_300,
+};
+
+#endif
+
index 23b2a8c0dbfcbdee211e253a5df9fd7b19aad80a..b020ba7f1cf22f6fabad4dfc0d682243402ba245 100644 (file)
@@ -501,7 +501,9 @@ static irqreturn_t bfin_bf54x_irq_error(int irq, void *dev_id)
 
 static int __devinit bfin_bf54x_probe(struct platform_device *pdev)
 {
+#ifndef NO_BL_SUPPORT
        struct backlight_properties props;
+#endif
        struct bfin_bf54xfb_info *info;
        struct fb_info *fbinfo;
        int ret;
@@ -654,7 +656,8 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev)
                printk(KERN_ERR DRIVER_NAME
                        ": unable to register backlight.\n");
                ret = -EINVAL;
-               goto out9;
+               unregister_framebuffer(fbinfo);
+               goto out8;
        }
 
        lcd_dev = lcd_device_register(DRIVER_NAME, &pdev->dev, NULL, &bfin_lcd_ops);
@@ -663,8 +666,6 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev)
 
        return 0;
 
-out9:
-       unregister_framebuffer(fbinfo);
 out8:
        free_irq(info->irq, info);
 out7:
index 2baac7cc14255ea3b7401f442951f42580a0d7a3..c8e1f04941bd5333e467fa358f06691067ad0e3a 100644 (file)
 #define LCD_X_RES              320     /* Horizontal Resolution */
 #define LCD_Y_RES              240     /* Vertical Resolution */
 #define        DMA_BUS_SIZE            16
+#define U_LINE                 4       /* Blanking Lines */
 
-#define USE_RGB565_16_BIT_PPI
-
-#ifdef USE_RGB565_16_BIT_PPI
-#define LCD_BPP                16      /* Bit Per Pixel */
-#define CLOCKS_PER_PIX 1
-#define CPLD_PIPELINE_DELAY_COR 0      /* NO CPLB */
-#endif
 
 /* Interface 16/18-bit TFT over an 8-bit wide PPI using a small Programmable Logic Device (CPLD)
  * http://blackfin.uclinux.org/gf/project/stamp/frs/?action=FrsReleaseBrowse&frs_package_id=165
  */
 
-#ifdef USE_RGB565_8_BIT_PPI
-#define LCD_BPP                16      /* Bit Per Pixel */
-#define CLOCKS_PER_PIX 2
-#define CPLD_PIPELINE_DELAY_COR 3      /* RGB565 */
-#endif
-
-#ifdef USE_RGB888_8_BIT_PPI
-#define LCD_BPP                24      /* Bit Per Pixel */
-#define CLOCKS_PER_PIX 3
-#define CPLD_PIPELINE_DELAY_COR 5      /* RGB888 */
-#endif
-
-       /*
-        * HS and VS timing parameters (all in number of PPI clk ticks)
-        */
-
-#define U_LINE         4                               /* Blanking Lines */
-
-#define H_ACTPIX       (LCD_X_RES * CLOCKS_PER_PIX)    /* active horizontal pixel */
-#define H_PERIOD       (336 * CLOCKS_PER_PIX)          /* HS period */
-#define H_PULSE                (2 * CLOCKS_PER_PIX)                            /* HS pulse width */
-#define H_START                (7 * CLOCKS_PER_PIX + CPLD_PIPELINE_DELAY_COR)  /* first valid pixel */
-
-#define        V_LINES         (LCD_Y_RES + U_LINE)            /* total vertical lines */
-#define V_PULSE                (2 * CLOCKS_PER_PIX)            /* VS pulse width (1-5 H_PERIODs) */
-#define V_PERIOD       (H_PERIOD * V_LINES)            /* VS period */
-
-#define ACTIVE_VIDEO_MEM_OFFSET                ((U_LINE / 2) * LCD_X_RES * (LCD_BPP / 8))
 
 #define BFIN_LCD_NBR_PALETTE_ENTRIES   256
 
 #define PPI_PORT_CFG_01                        0x10
 #define PPI_POLS_1                     0x8000
 
-#if (CLOCKS_PER_PIX > 1)
-#define PPI_PMODE (DLEN_8 | PACK_EN)
-#else
-#define PPI_PMODE (DLEN_16)
-#endif
-
 #define LQ035_INDEX                    0x74
 #define LQ035_DATA                     0x76
 
@@ -139,6 +99,15 @@ struct bfin_lq035q1fb_info {
        int irq;
        spinlock_t lock;        /* lock */
        u32 pseudo_pal[16];
+
+       u32 lcd_bpp;
+       u32 h_actpix;
+       u32 h_period;
+       u32 h_pulse;
+       u32 h_start;
+       u32 v_lines;
+       u32 v_pulse;
+       u32 v_period;
 };
 
 static int nocursor;
@@ -234,16 +203,69 @@ static int lq035q1_backlight(struct bfin_lq035q1fb_info *info, unsigned arg)
        return 0;
 }
 
+static int bfin_lq035q1_calc_timing(struct bfin_lq035q1fb_info *fbi)
+{
+       unsigned long clocks_per_pix, cpld_pipeline_delay_cor;
+
+       /*
+        * Interface 16/18-bit TFT over an 8-bit wide PPI using a small
+        * Programmable Logic Device (CPLD)
+        * http://blackfin.uclinux.org/gf/project/stamp/frs/?action=FrsReleaseBrowse&frs_package_id=165
+        */
+
+       switch (fbi->disp_info->ppi_mode) {
+       case USE_RGB565_16_BIT_PPI:
+               fbi->lcd_bpp = 16;
+               clocks_per_pix = 1;
+               cpld_pipeline_delay_cor = 0;
+               break;
+       case USE_RGB565_8_BIT_PPI:
+               fbi->lcd_bpp = 16;
+               clocks_per_pix = 2;
+               cpld_pipeline_delay_cor = 3;
+               break;
+       case USE_RGB888_8_BIT_PPI:
+               fbi->lcd_bpp = 24;
+               clocks_per_pix = 3;
+               cpld_pipeline_delay_cor = 5;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /*
+        * HS and VS timing parameters (all in number of PPI clk ticks)
+        */
+
+       fbi->h_actpix = (LCD_X_RES * clocks_per_pix);   /* active horizontal pixel */
+       fbi->h_period = (336 * clocks_per_pix);         /* HS period */
+       fbi->h_pulse = (2 * clocks_per_pix);                            /* HS pulse width */
+       fbi->h_start = (7 * clocks_per_pix + cpld_pipeline_delay_cor);  /* first valid pixel */
+
+       fbi->v_lines = (LCD_Y_RES + U_LINE);            /* total vertical lines */
+       fbi->v_pulse = (2 * clocks_per_pix);            /* VS pulse width (1-5 H_PERIODs) */
+       fbi->v_period = (fbi->h_period * fbi->v_lines); /* VS period */
+
+       return 0;
+}
+
 static void bfin_lq035q1_config_ppi(struct bfin_lq035q1fb_info *fbi)
 {
-       bfin_write_PPI_DELAY(H_START);
-       bfin_write_PPI_COUNT(H_ACTPIX - 1);
-       bfin_write_PPI_FRAME(V_LINES);
+       unsigned ppi_pmode;
+
+       if (fbi->disp_info->ppi_mode == USE_RGB565_16_BIT_PPI)
+               ppi_pmode = DLEN_16;
+       else
+               ppi_pmode = (DLEN_8 | PACK_EN);
+
+       bfin_write_PPI_DELAY(fbi->h_start);
+       bfin_write_PPI_COUNT(fbi->h_actpix - 1);
+       bfin_write_PPI_FRAME(fbi->v_lines);
 
        bfin_write_PPI_CONTROL(PPI_TX_MODE |       /* output mode , PORT_DIR */
                                PPI_XFER_TYPE_11 | /* sync mode XFR_TYPE */
                                PPI_PORT_CFG_01 |  /* two frame sync PORT_CFG */
-                               PPI_PMODE |        /* 8/16 bit data length / PACK_EN? */
+                               ppi_pmode |        /* 8/16 bit data length / PACK_EN? */
                                PPI_POLS_1);       /* faling edge syncs POLS */
 }
 
@@ -272,19 +294,19 @@ static void bfin_lq035q1_stop_timers(void)
 
 }
 
-static void bfin_lq035q1_init_timers(void)
+static void bfin_lq035q1_init_timers(struct bfin_lq035q1fb_info *fbi)
 {
 
        bfin_lq035q1_stop_timers();
 
-       set_gptimer_period(TIMER_HSYNC_id, H_PERIOD);
-       set_gptimer_pwidth(TIMER_HSYNC_id, H_PULSE);
+       set_gptimer_period(TIMER_HSYNC_id, fbi->h_period);
+       set_gptimer_pwidth(TIMER_HSYNC_id, fbi->h_pulse);
        set_gptimer_config(TIMER_HSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT |
                                      TIMER_TIN_SEL | TIMER_CLK_SEL|
                                      TIMER_EMU_RUN);
 
-       set_gptimer_period(TIMER_VSYNC_id, V_PERIOD);
-       set_gptimer_pwidth(TIMER_VSYNC_id, V_PULSE);
+       set_gptimer_period(TIMER_VSYNC_id, fbi->v_period);
+       set_gptimer_pwidth(TIMER_VSYNC_id, fbi->v_pulse);
        set_gptimer_config(TIMER_VSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT |
                                      TIMER_TIN_SEL | TIMER_CLK_SEL |
                                      TIMER_EMU_RUN);
@@ -294,21 +316,21 @@ static void bfin_lq035q1_init_timers(void)
 static void bfin_lq035q1_config_dma(struct bfin_lq035q1fb_info *fbi)
 {
 
+
        set_dma_config(CH_PPI,
                       set_bfin_dma_config(DIR_READ, DMA_FLOW_AUTO,
                                           INTR_DISABLE, DIMENSION_2D,
                                           DATA_SIZE_16,
                                           DMA_NOSYNC_KEEP_DMA_BUF));
-       set_dma_x_count(CH_PPI, (LCD_X_RES * LCD_BPP) / DMA_BUS_SIZE);
+       set_dma_x_count(CH_PPI, (LCD_X_RES * fbi->lcd_bpp) / DMA_BUS_SIZE);
        set_dma_x_modify(CH_PPI, DMA_BUS_SIZE / 8);
-       set_dma_y_count(CH_PPI, V_LINES);
+       set_dma_y_count(CH_PPI, fbi->v_lines);
 
        set_dma_y_modify(CH_PPI, DMA_BUS_SIZE / 8);
        set_dma_start_addr(CH_PPI, (unsigned long)fbi->fb_buffer);
 
 }
 
-#if (CLOCKS_PER_PIX == 1)
 static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
                            P_PPI0_D0, P_PPI0_D1, P_PPI0_D2,
                            P_PPI0_D3, P_PPI0_D4, P_PPI0_D5,
@@ -316,22 +338,27 @@ static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
                            P_PPI0_D9, P_PPI0_D10, P_PPI0_D11,
                            P_PPI0_D12, P_PPI0_D13, P_PPI0_D14,
                            P_PPI0_D15, 0};
-#else
-static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
+
+static const u16 ppi0_req_8[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
                            P_PPI0_D0, P_PPI0_D1, P_PPI0_D2,
                            P_PPI0_D3, P_PPI0_D4, P_PPI0_D5,
                            P_PPI0_D6, P_PPI0_D7, 0};
-#endif
 
-static inline void bfin_lq035q1_free_ports(void)
+static inline void bfin_lq035q1_free_ports(unsigned ppi16)
 {
-       peripheral_free_list(ppi0_req_16);
+       if (ppi16)
+               peripheral_free_list(ppi0_req_16);
+       else
+               peripheral_free_list(ppi0_req_8);
+
        if (ANOMALY_05000400)
                gpio_free(P_IDENT(P_PPI0_FS3));
 }
 
-static int __devinit bfin_lq035q1_request_ports(struct platform_device *pdev)
+static int __devinit bfin_lq035q1_request_ports(struct platform_device *pdev,
+                                               unsigned ppi16)
 {
+       int ret;
        /* ANOMALY_05000400 - PPI Does Not Start Properly In Specific Mode:
         * Drive PPI_FS3 Low
         */
@@ -342,7 +369,12 @@ static int __devinit bfin_lq035q1_request_ports(struct platform_device *pdev)
                gpio_direction_output(P_IDENT(P_PPI0_FS3), 0);
        }
 
-       if (peripheral_request_list(ppi0_req_16, DRIVER_NAME)) {
+       if (ppi16)
+               ret = peripheral_request_list(ppi0_req_16, DRIVER_NAME);
+       else
+               ret = peripheral_request_list(ppi0_req_8, DRIVER_NAME);
+
+       if (ret) {
                dev_err(&pdev->dev, "requesting peripherals failed\n");
                return -EFAULT;
        }
@@ -364,7 +396,7 @@ static int bfin_lq035q1_fb_open(struct fb_info *info, int user)
 
                bfin_lq035q1_config_dma(fbi);
                bfin_lq035q1_config_ppi(fbi);
-               bfin_lq035q1_init_timers();
+               bfin_lq035q1_init_timers(fbi);
 
                /* start dma */
                enable_dma(CH_PPI);
@@ -402,12 +434,9 @@ static int bfin_lq035q1_fb_release(struct fb_info *info, int user)
 static int bfin_lq035q1_fb_check_var(struct fb_var_screeninfo *var,
                                     struct fb_info *info)
 {
-       switch (var->bits_per_pixel) {
-#if (LCD_BPP == 24)
-       case 24:/* TRUECOLOUR, 16m */
-#else
-       case 16:/* DIRECTCOLOUR, 64k */
-#endif
+       struct bfin_lq035q1fb_info *fbi = info->par;
+
+       if (var->bits_per_pixel == fbi->lcd_bpp) {
                var->red.offset = info->var.red.offset;
                var->green.offset = info->var.green.offset;
                var->blue.offset = info->var.blue.offset;
@@ -420,8 +449,7 @@ static int bfin_lq035q1_fb_check_var(struct fb_var_screeninfo *var,
                var->red.msb_right = 0;
                var->green.msb_right = 0;
                var->blue.msb_right = 0;
-               break;
-       default:
+       } else {
                pr_debug("%s: depth not supported: %u BPP\n", __func__,
                         var->bits_per_pixel);
                return -EINVAL;
@@ -528,6 +556,7 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
 {
        struct bfin_lq035q1fb_info *info;
        struct fb_info *fbinfo;
+       u32 active_video_mem_offset;
        int ret;
 
        ret = request_dma(CH_PPI, DRIVER_NAME"_CH_PPI");
@@ -550,6 +579,12 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, fbinfo);
 
+       ret = bfin_lq035q1_calc_timing(info);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed PPI Mode\n");
+               goto out3;
+       }
+
        strcpy(fbinfo->fix.id, DRIVER_NAME);
 
        fbinfo->fix.type = FB_TYPE_PACKED_PIXELS;
@@ -571,46 +606,48 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
        fbinfo->var.xres_virtual = LCD_X_RES;
        fbinfo->var.yres = LCD_Y_RES;
        fbinfo->var.yres_virtual = LCD_Y_RES;
-       fbinfo->var.bits_per_pixel = LCD_BPP;
+       fbinfo->var.bits_per_pixel = info->lcd_bpp;
 
        if (info->disp_info->mode & LQ035_BGR) {
-#if (LCD_BPP == 24)
-               fbinfo->var.red.offset = 0;
-               fbinfo->var.green.offset = 8;
-               fbinfo->var.blue.offset = 16;
-#else
-               fbinfo->var.red.offset = 0;
-               fbinfo->var.green.offset = 5;
-               fbinfo->var.blue.offset = 11;
-#endif
+               if (info->lcd_bpp == 24) {
+                       fbinfo->var.red.offset = 0;
+                       fbinfo->var.green.offset = 8;
+                       fbinfo->var.blue.offset = 16;
+               } else {
+                       fbinfo->var.red.offset = 0;
+                       fbinfo->var.green.offset = 5;
+                       fbinfo->var.blue.offset = 11;
+               }
        } else {
-#if (LCD_BPP == 24)
-               fbinfo->var.red.offset = 16;
-               fbinfo->var.green.offset = 8;
-               fbinfo->var.blue.offset = 0;
-#else
-               fbinfo->var.red.offset = 11;
-               fbinfo->var.green.offset = 5;
-               fbinfo->var.blue.offset = 0;
-#endif
+               if (info->lcd_bpp == 24) {
+                       fbinfo->var.red.offset = 16;
+                       fbinfo->var.green.offset = 8;
+                       fbinfo->var.blue.offset = 0;
+               } else {
+                       fbinfo->var.red.offset = 11;
+                       fbinfo->var.green.offset = 5;
+                       fbinfo->var.blue.offset = 0;
+               }
        }
 
        fbinfo->var.transp.offset = 0;
 
-#if (LCD_BPP == 24)
-       fbinfo->var.red.length = 8;
-       fbinfo->var.green.length = 8;
-       fbinfo->var.blue.length = 8;
-#else
-       fbinfo->var.red.length = 5;
-       fbinfo->var.green.length = 6;
-       fbinfo->var.blue.length = 5;
-#endif
+       if (info->lcd_bpp == 24) {
+               fbinfo->var.red.length = 8;
+               fbinfo->var.green.length = 8;
+               fbinfo->var.blue.length = 8;
+       } else {
+               fbinfo->var.red.length = 5;
+               fbinfo->var.green.length = 6;
+               fbinfo->var.blue.length = 5;
+       }
 
        fbinfo->var.transp.length = 0;
 
-       fbinfo->fix.smem_len = LCD_X_RES * LCD_Y_RES * LCD_BPP / 8
-                               + ACTIVE_VIDEO_MEM_OFFSET;
+       active_video_mem_offset = ((U_LINE / 2) * LCD_X_RES * (info->lcd_bpp / 8));
+
+       fbinfo->fix.smem_len = LCD_X_RES * LCD_Y_RES * info->lcd_bpp / 8
+                               + active_video_mem_offset;
 
        fbinfo->fix.line_length = fbinfo->var.xres_virtual *
            fbinfo->var.bits_per_pixel / 8;
@@ -629,8 +666,8 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
                goto out3;
        }
 
-       fbinfo->screen_base = (void *)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET;
-       fbinfo->fix.smem_start = (int)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET;
+       fbinfo->screen_base = (void *)info->fb_buffer + active_video_mem_offset;
+       fbinfo->fix.smem_start = (int)info->fb_buffer + active_video_mem_offset;
 
        fbinfo->fbops = &bfin_lq035q1_fb_ops;
 
@@ -643,7 +680,8 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
                goto out4;
        }
 
-       ret = bfin_lq035q1_request_ports(pdev);
+       ret = bfin_lq035q1_request_ports(pdev,
+                       info->disp_info->ppi_mode == USE_RGB565_16_BIT_PPI);
        if (ret) {
                dev_err(&pdev->dev, "couldn't request gpio port\n");
                goto out6;
@@ -693,7 +731,7 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
        }
 
        dev_info(&pdev->dev, "%dx%d %d-bit RGB FrameBuffer initialized\n",
-               LCD_X_RES, LCD_Y_RES, LCD_BPP);
+               LCD_X_RES, LCD_Y_RES, info->lcd_bpp);
 
        return 0;
 
@@ -705,7 +743,8 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
  out8:
        free_irq(info->irq, info);
  out7:
-       bfin_lq035q1_free_ports();
+       bfin_lq035q1_free_ports(info->disp_info->ppi_mode ==
+                               USE_RGB565_16_BIT_PPI);
  out6:
        fb_dealloc_cmap(&fbinfo->cmap);
  out4:
@@ -742,7 +781,8 @@ static int __devexit bfin_lq035q1_remove(struct platform_device *pdev)
 
        fb_dealloc_cmap(&fbinfo->cmap);
 
-       bfin_lq035q1_free_ports();
+       bfin_lq035q1_free_ports(info->disp_info->ppi_mode ==
+                               USE_RGB565_16_BIT_PPI);
 
        platform_set_drvdata(pdev, NULL);
        framebuffer_release(fbinfo);
@@ -781,7 +821,7 @@ static int bfin_lq035q1_resume(struct device *dev)
 
                bfin_lq035q1_config_dma(info);
                bfin_lq035q1_config_ppi(info);
-               bfin_lq035q1_init_timers();
+               bfin_lq035q1_init_timers(info);
 
                /* start dma */
                enable_dma(CH_PPI);
index c2ec3dcd4e918023886376b3103b21928c8b1e27..7a50272eaab94972e459efd8776785c789e4b478 100644 (file)
@@ -420,7 +420,9 @@ static irqreturn_t bfin_t350mcqb_irq_error(int irq, void *dev_id)
 
 static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev)
 {
+#ifndef NO_BL_SUPPORT
        struct backlight_properties props;
+#endif
        struct bfin_t350mcqbfb_info *info;
        struct fb_info *fbinfo;
        int ret;
@@ -550,7 +552,8 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev)
                printk(KERN_ERR DRIVER_NAME
                        ": unable to register backlight.\n");
                ret = -EINVAL;
-               goto out9;
+               unregister_framebuffer(fbinfo);
+               goto out8;
        }
 
        lcd_dev = lcd_device_register(DRIVER_NAME, NULL, &bfin_lcd_ops);
@@ -559,8 +562,6 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev)
 
        return 0;
 
-out9:
-       unregister_framebuffer(fbinfo);
 out8:
        free_irq(info->irq, info);
 out7:
index 43320925c4cea48b980a905fa0d5766cadcad335..2c371c07f0daaff562b844184bfb742284b9cc53 100644 (file)
@@ -376,8 +376,11 @@ static const struct of_device_id bw2_match[] = {
 MODULE_DEVICE_TABLE(of, bw2_match);
 
 static struct of_platform_driver bw2_driver = {
-       .name           = "bw2",
-       .match_table    = bw2_match,
+       .driver = {
+               .name = "bw2",
+               .owner = THIS_MODULE,
+               .of_match_table = bw2_match,
+       },
        .probe          = bw2_probe,
        .remove         = __devexit_p(bw2_remove),
 };
index 77a040af20a7860626b9bae5696b88fce42a0c20..d12e05b6e63f96ce0cd36ba1ddb810167953d280 100644 (file)
@@ -596,8 +596,11 @@ static const struct of_device_id cg14_match[] = {
 MODULE_DEVICE_TABLE(of, cg14_match);
 
 static struct of_platform_driver cg14_driver = {
-       .name           = "cg14",
-       .match_table    = cg14_match,
+       .driver = {
+               .name = "cg14",
+               .owner = THIS_MODULE,
+               .of_match_table = cg14_match,
+       },
        .probe          = cg14_probe,
        .remove         = __devexit_p(cg14_remove),
 };
index 30eedf79322c4dcff534da06fe7938a5753d112c..b98f93f7f6638f0a02a39250aaeaca54b595bbb3 100644 (file)
@@ -463,8 +463,11 @@ static const struct of_device_id cg3_match[] = {
 MODULE_DEVICE_TABLE(of, cg3_match);
 
 static struct of_platform_driver cg3_driver = {
-       .name           = "cg3",
-       .match_table    = cg3_match,
+       .driver = {
+               .name = "cg3",
+               .owner = THIS_MODULE,
+               .of_match_table = cg3_match,
+       },
        .probe          = cg3_probe,
        .remove         = __devexit_p(cg3_remove),
 };
index 6d0fcb43696ec10bed2b44a020ee46e787b238e4..480d761a27a839b1e265eefe8204a17fb1f56504 100644 (file)
@@ -740,7 +740,7 @@ static void cg6_unmap_regs(struct of_device *op, struct fb_info *info,
 static int __devinit cg6_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 cg6_par *par;
        int linebytes, err;
@@ -856,8 +856,11 @@ static const struct of_device_id cg6_match[] = {
 MODULE_DEVICE_TABLE(of, cg6_match);
 
 static struct of_platform_driver cg6_driver = {
-       .name           = "cg6",
-       .match_table    = cg6_match,
+       .driver = {
+               .name = "cg6",
+               .owner = THIS_MODULE,
+               .of_match_table = cg6_match,
+       },
        .probe          = cg6_probe,
        .remove         = __devexit_p(cg6_remove),
 };
index 8d244ba0f6019689293bb7929a60ed065de6fdca..cad7d45c8bac2b94a1e3f06b57a241d26ed4570c 100644 (file)
@@ -36,7 +36,9 @@
 #define DRIVER_NAME "da8xx_lcdc"
 
 /* LCD Status Register */
+#define LCD_END_OF_FRAME1              BIT(9)
 #define LCD_END_OF_FRAME0              BIT(8)
+#define LCD_PL_LOAD_DONE               BIT(6)
 #define LCD_FIFO_UNDERFLOW             BIT(5)
 #define LCD_SYNC_LOST                  BIT(2)
 
 #define LCD_PALETTE_LOAD_MODE(x)       ((x) << 20)
 #define PALETTE_AND_DATA               0x00
 #define PALETTE_ONLY                   0x01
+#define DATA_ONLY                      0x02
 
 #define LCD_MONO_8BIT_MODE             BIT(9)
 #define LCD_RASTER_ORDER               BIT(8)
 #define LCD_TFT_MODE                   BIT(7)
 #define LCD_UNDERFLOW_INT_ENA          BIT(6)
+#define LCD_PL_ENABLE                  BIT(4)
 #define LCD_MONOCHROME_MODE            BIT(1)
 #define LCD_RASTER_ENABLE              BIT(0)
 #define LCD_TFT_ALT_ENABLE             BIT(23)
 #define  LCD_DMA_CTRL_REG                      0x40
 #define  LCD_DMA_FRM_BUF_BASE_ADDR_0_REG       0x44
 #define  LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG    0x48
+#define  LCD_DMA_FRM_BUF_BASE_ADDR_1_REG       0x4C
+#define  LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG    0x50
+
+#define LCD_NUM_BUFFERS        2
 
 #define WSI_TIMEOUT    50
 #define PALETTE_SIZE   256
@@ -111,13 +119,20 @@ static inline void lcdc_write(unsigned int val, unsigned int addr)
 struct da8xx_fb_par {
        resource_size_t p_palette_base;
        unsigned char *v_palette_base;
+       dma_addr_t              vram_phys;
+       unsigned long           vram_size;
+       void                    *vram_virt;
+       unsigned int            dma_start;
+       unsigned int            dma_end;
        struct clk *lcdc_clk;
        int irq;
        unsigned short pseudo_palette[16];
-       unsigned int databuf_sz;
        unsigned int palette_sz;
        unsigned int pxl_clk;
        int blank;
+       wait_queue_head_t       vsync_wait;
+       int                     vsync_flag;
+       int                     vsync_timeout;
 #ifdef CONFIG_CPU_FREQ
        struct notifier_block   freq_transition;
 #endif
@@ -148,9 +163,9 @@ static struct fb_fix_screeninfo da8xx_fb_fix __devinitdata = {
        .type = FB_TYPE_PACKED_PIXELS,
        .type_aux = 0,
        .visual = FB_VISUAL_PSEUDOCOLOR,
-       .xpanstep = 1,
+       .xpanstep = 0,
        .ypanstep = 1,
-       .ywrapstep = 1,
+       .ywrapstep = 0,
        .accel = FB_ACCEL_NONE
 };
 
@@ -221,22 +236,48 @@ static inline void lcd_disable_raster(void)
 
 static void lcd_blit(int load_mode, struct da8xx_fb_par *par)
 {
-       u32 tmp = par->p_palette_base + par->databuf_sz - 4;
-       u32 reg;
+       u32 start;
+       u32 end;
+       u32 reg_ras;
+       u32 reg_dma;
+
+       /* init reg to clear PLM (loading mode) fields */
+       reg_ras = lcdc_read(LCD_RASTER_CTRL_REG);
+       reg_ras &= ~(3 << 20);
+
+       reg_dma  = lcdc_read(LCD_DMA_CTRL_REG);
+
+       if (load_mode == LOAD_DATA) {
+               start    = par->dma_start;
+               end      = par->dma_end;
+
+               reg_ras |= LCD_PALETTE_LOAD_MODE(DATA_ONLY);
+               reg_dma |= LCD_END_OF_FRAME_INT_ENA;
+               reg_dma |= LCD_DUAL_FRAME_BUFFER_ENABLE;
+
+               lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
+               lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
+               lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
+               lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG);
+       } else if (load_mode == LOAD_PALETTE) {
+               start    = par->p_palette_base;
+               end      = start + par->palette_sz - 1;
+
+               reg_ras |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY);
+               reg_ras |= LCD_PL_ENABLE;
+
+               lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
+               lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
+       }
 
-       /* Update the databuf in the hw. */
-       lcdc_write(par->p_palette_base, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
-       lcdc_write(tmp, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
+       lcdc_write(reg_dma, LCD_DMA_CTRL_REG);
+       lcdc_write(reg_ras, LCD_RASTER_CTRL_REG);
 
-       /* Start the DMA. */
-       reg = lcdc_read(LCD_RASTER_CTRL_REG);
-       reg &= ~(3 << 20);
-       if (load_mode == LOAD_DATA)
-               reg |= LCD_PALETTE_LOAD_MODE(PALETTE_AND_DATA);
-       else if (load_mode == LOAD_PALETTE)
-               reg |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY);
-
-       lcdc_write(reg, LCD_RASTER_CTRL_REG);
+       /*
+        * The Raster enable bit must be set after all other control fields are
+        * set.
+        */
+       lcd_enable_raster();
 }
 
 /* Configure the Burst Size of DMA */
@@ -368,12 +409,8 @@ static int lcd_cfg_display(const struct lcd_ctrl_config *cfg)
 static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height,
                u32 bpp, u32 raster_order)
 {
-       u32 bpl, reg;
+       u32 reg;
 
-       /* Disable Dual Frame Buffer. */
-       reg = lcdc_read(LCD_DMA_CTRL_REG);
-       lcdc_write(reg & ~LCD_DUAL_FRAME_BUFFER_ENABLE,
-                                               LCD_DMA_CTRL_REG);
        /* Set the Panel Width */
        /* Pixels per line = (PPL + 1)*16 */
        /*0x3F in bits 4..9 gives max horisontal resolution = 1024 pixels*/
@@ -410,9 +447,6 @@ static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height,
                return -EINVAL;
        }
 
-       bpl = width * bpp / 8;
-       par->databuf_sz = height * bpl + par->palette_sz;
-
        return 0;
 }
 
@@ -421,8 +455,9 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green,
                              struct fb_info *info)
 {
        struct da8xx_fb_par *par = info->par;
-       unsigned short *palette = (unsigned short *)par->v_palette_base;
+       unsigned short *palette = (unsigned short *) par->v_palette_base;
        u_short pal;
+       int update_hw = 0;
 
        if (regno > 255)
                return 1;
@@ -439,8 +474,10 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green,
                pal |= (green & 0x00f0);
                pal |= (blue & 0x000f);
 
-               palette[regno] = pal;
-
+               if (palette[regno] != pal) {
+                       update_hw = 1;
+                       palette[regno] = pal;
+               }
        } else if ((info->var.bits_per_pixel == 16) && regno < 16) {
                red >>= (16 - info->var.red.length);
                red <<= info->var.red.offset;
@@ -453,9 +490,16 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green,
 
                par->pseudo_palette[regno] = red | green | blue;
 
-               palette[0] = 0x4000;
+               if (palette[0] != 0x4000) {
+                       update_hw = 1;
+                       palette[0] = 0x4000;
+               }
        }
 
+       /* Update the palette in the h/w as needed. */
+       if (update_hw)
+               lcd_blit(LOAD_PALETTE, par);
+
        return 0;
 }
 
@@ -541,15 +585,54 @@ static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg,
 
 static irqreturn_t lcdc_irq_handler(int irq, void *arg)
 {
+       struct da8xx_fb_par *par = arg;
        u32 stat = lcdc_read(LCD_STAT_REG);
+       u32 reg_ras;
 
        if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) {
                lcd_disable_raster();
                lcdc_write(stat, LCD_STAT_REG);
                lcd_enable_raster();
-       } else
+       } else if (stat & LCD_PL_LOAD_DONE) {
+               /*
+                * Must disable raster before changing state of any control bit.
+                * And also must be disabled before clearing the PL loading
+                * interrupt via the following write to the status register. If
+                * this is done after then one gets multiple PL done interrupts.
+                */
+               lcd_disable_raster();
+
                lcdc_write(stat, LCD_STAT_REG);
 
+               /* Disable PL completion inerrupt */
+               reg_ras  = lcdc_read(LCD_RASTER_CTRL_REG);
+               reg_ras &= ~LCD_PL_ENABLE;
+               lcdc_write(reg_ras, LCD_RASTER_CTRL_REG);
+
+               /* Setup and start data loading mode */
+               lcd_blit(LOAD_DATA, par);
+       } else {
+               lcdc_write(stat, LCD_STAT_REG);
+
+               if (stat & LCD_END_OF_FRAME0) {
+                       lcdc_write(par->dma_start,
+                                  LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
+                       lcdc_write(par->dma_end,
+                                  LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
+                       par->vsync_flag = 1;
+                       wake_up_interruptible(&par->vsync_wait);
+               }
+
+               if (stat & LCD_END_OF_FRAME1) {
+                       lcdc_write(par->dma_start,
+                                  LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
+                       lcdc_write(par->dma_end,
+                                  LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG);
+                       par->vsync_flag = 1;
+                       wake_up_interruptible(&par->vsync_wait);
+               }
+       }
+
        return IRQ_HANDLED;
 }
 
@@ -654,9 +737,10 @@ static int __devexit fb_remove(struct platform_device *dev)
 
                unregister_framebuffer(info);
                fb_dealloc_cmap(&info->cmap);
-               dma_free_coherent(NULL, par->databuf_sz + PAGE_SIZE,
-                                       info->screen_base - PAGE_SIZE,
-                                       info->fix.smem_start);
+               dma_free_coherent(NULL, PALETTE_SIZE, par->v_palette_base,
+                                 par->p_palette_base);
+               dma_free_coherent(NULL, par->vram_size, par->vram_virt,
+                                 par->vram_phys);
                free_irq(par->irq, par);
                clk_disable(par->lcdc_clk);
                clk_put(par->lcdc_clk);
@@ -668,6 +752,39 @@ static int __devexit fb_remove(struct platform_device *dev)
        return 0;
 }
 
+/*
+ * Function to wait for vertical sync which for this LCD peripheral
+ * translates into waiting for the current raster frame to complete.
+ */
+static int fb_wait_for_vsync(struct fb_info *info)
+{
+       struct da8xx_fb_par *par = info->par;
+       int ret;
+
+       /*
+        * Set flag to 0 and wait for isr to set to 1. It would seem there is a
+        * race condition here where the ISR could have occured just before or
+        * just after this set. But since we are just coarsely waiting for
+        * a frame to complete then that's OK. i.e. if the frame completed
+        * just before this code executed then we have to wait another full
+        * frame time but there is no way to avoid such a situation. On the
+        * other hand if the frame completed just after then we don't need
+        * to wait long at all. Either way we are guaranteed to return to the
+        * user immediately after a frame completion which is all that is
+        * required.
+        */
+       par->vsync_flag = 0;
+       ret = wait_event_interruptible_timeout(par->vsync_wait,
+                                              par->vsync_flag != 0,
+                                              par->vsync_timeout);
+       if (ret < 0)
+               return ret;
+       if (ret == 0)
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
 static int fb_ioctl(struct fb_info *info, unsigned int cmd,
                          unsigned long arg)
 {
@@ -697,6 +814,8 @@ static int fb_ioctl(struct fb_info *info, unsigned int cmd,
                                        sync_arg.pulse_width,
                                        sync_arg.front_porch);
                break;
+       case FBIO_WAITFORVSYNC:
+               return fb_wait_for_vsync(info);
        default:
                return -EINVAL;
        }
@@ -732,10 +851,47 @@ static int cfb_blank(int blank, struct fb_info *info)
        return ret;
 }
 
+/*
+ * Set new x,y offsets in the virtual display for the visible area and switch
+ * to the new mode.
+ */
+static int da8xx_pan_display(struct fb_var_screeninfo *var,
+                            struct fb_info *fbi)
+{
+       int ret = 0;
+       struct fb_var_screeninfo new_var;
+       struct da8xx_fb_par         *par = fbi->par;
+       struct fb_fix_screeninfo    *fix = &fbi->fix;
+       unsigned int end;
+       unsigned int start;
+
+       if (var->xoffset != fbi->var.xoffset ||
+                       var->yoffset != fbi->var.yoffset) {
+               memcpy(&new_var, &fbi->var, sizeof(new_var));
+               new_var.xoffset = var->xoffset;
+               new_var.yoffset = var->yoffset;
+               if (fb_check_var(&new_var, fbi))
+                       ret = -EINVAL;
+               else {
+                       memcpy(&fbi->var, &new_var, sizeof(new_var));
+
+                       start   = fix->smem_start +
+                               new_var.yoffset * fix->line_length +
+                               new_var.xoffset * var->bits_per_pixel / 8;
+                       end     = start + var->yres * fix->line_length - 1;
+                       par->dma_start  = start;
+                       par->dma_end    = end;
+               }
+       }
+
+       return ret;
+}
+
 static struct fb_ops da8xx_fb_ops = {
        .owner = THIS_MODULE,
        .fb_check_var = fb_check_var,
        .fb_setcolreg = fb_setcolreg,
+       .fb_pan_display = da8xx_pan_display,
        .fb_ioctl = fb_ioctl,
        .fb_fillrect = cfb_fillrect,
        .fb_copyarea = cfb_copyarea,
@@ -829,40 +985,53 @@ static int __init fb_probe(struct platform_device *device)
        }
 
        /* allocate frame buffer */
-       da8xx_fb_info->screen_base = dma_alloc_coherent(NULL,
-                                       par->databuf_sz + PAGE_SIZE,
-                                       (resource_size_t *)
-                                       &da8xx_fb_info->fix.smem_start,
-                                       GFP_KERNEL | GFP_DMA);
-
-       if (!da8xx_fb_info->screen_base) {
+       par->vram_size = lcdc_info->width * lcdc_info->height * lcd_cfg->bpp;
+       par->vram_size = PAGE_ALIGN(par->vram_size/8);
+       par->vram_size = par->vram_size * LCD_NUM_BUFFERS;
+
+       par->vram_virt = dma_alloc_coherent(NULL,
+                                           par->vram_size,
+                                           (resource_size_t *) &par->vram_phys,
+                                           GFP_KERNEL | GFP_DMA);
+       if (!par->vram_virt) {
                dev_err(&device->dev,
                        "GLCD: kmalloc for frame buffer failed\n");
                ret = -EINVAL;
                goto err_release_fb;
        }
 
-       /* move palette base pointer by (PAGE_SIZE - palette_sz) bytes */
-       par->v_palette_base = da8xx_fb_info->screen_base +
-                               (PAGE_SIZE - par->palette_sz);
-       par->p_palette_base = da8xx_fb_info->fix.smem_start +
-                               (PAGE_SIZE - par->palette_sz);
-
-       /* the rest of the frame buffer is pixel data */
-       da8xx_fb_info->screen_base = par->v_palette_base + par->palette_sz;
-       da8xx_fb_fix.smem_start = par->p_palette_base + par->palette_sz;
-       da8xx_fb_fix.smem_len = par->databuf_sz - par->palette_sz;
-       da8xx_fb_fix.line_length = (lcdc_info->width * lcd_cfg->bpp) / 8;
+       da8xx_fb_info->screen_base = (char __iomem *) par->vram_virt;
+       da8xx_fb_fix.smem_start    = par->vram_phys;
+       da8xx_fb_fix.smem_len      = par->vram_size;
+       da8xx_fb_fix.line_length   = (lcdc_info->width * lcd_cfg->bpp) / 8;
+
+       par->dma_start = par->vram_phys;
+       par->dma_end   = par->dma_start + lcdc_info->height *
+               da8xx_fb_fix.line_length - 1;
+
+       /* allocate palette buffer */
+       par->v_palette_base = dma_alloc_coherent(NULL,
+                                              PALETTE_SIZE,
+                                              (resource_size_t *)
+                                              &par->p_palette_base,
+                                              GFP_KERNEL | GFP_DMA);
+       if (!par->v_palette_base) {
+               dev_err(&device->dev,
+                       "GLCD: kmalloc for palette buffer failed\n");
+               ret = -EINVAL;
+               goto err_release_fb_mem;
+       }
+       memset(par->v_palette_base, 0, PALETTE_SIZE);
 
        par->irq = platform_get_irq(device, 0);
        if (par->irq < 0) {
                ret = -ENOENT;
-               goto err_release_fb_mem;
+               goto err_release_pl_mem;
        }
 
        ret = request_irq(par->irq, lcdc_irq_handler, 0, DRIVER_NAME, par);
        if (ret)
-               goto err_release_fb_mem;
+               goto err_release_pl_mem;
 
        /* Initialize par */
        da8xx_fb_info->var.bits_per_pixel = lcd_cfg->bpp;
@@ -870,8 +1039,8 @@ static int __init fb_probe(struct platform_device *device)
        da8xx_fb_var.xres = lcdc_info->width;
        da8xx_fb_var.xres_virtual = lcdc_info->width;
 
-       da8xx_fb_var.yres = lcdc_info->height;
-       da8xx_fb_var.yres_virtual = lcdc_info->height;
+       da8xx_fb_var.yres         = lcdc_info->height;
+       da8xx_fb_var.yres_virtual = lcdc_info->height * LCD_NUM_BUFFERS;
 
        da8xx_fb_var.grayscale =
            lcd_cfg->p_disp_panel->panel_shade == MONOCHROME ? 1 : 0;
@@ -892,18 +1061,18 @@ static int __init fb_probe(struct platform_device *device)
        ret = fb_alloc_cmap(&da8xx_fb_info->cmap, PALETTE_SIZE, 0);
        if (ret)
                goto err_free_irq;
-
-       /* First palette_sz byte of the frame buffer is the palette */
        da8xx_fb_info->cmap.len = par->palette_sz;
 
-       /* Flush the buffer to the screen. */
-       lcd_blit(LOAD_DATA, par);
-
        /* initialize var_screeninfo */
        da8xx_fb_var.activate = FB_ACTIVATE_FORCE;
        fb_set_var(da8xx_fb_info, &da8xx_fb_var);
 
        dev_set_drvdata(&device->dev, da8xx_fb_info);
+
+       /* initialize the vsync wait queue */
+       init_waitqueue_head(&par->vsync_wait);
+       par->vsync_timeout = HZ / 5;
+
        /* Register the Frame Buffer  */
        if (register_framebuffer(da8xx_fb_info) < 0) {
                dev_err(&device->dev,
@@ -919,10 +1088,6 @@ static int __init fb_probe(struct platform_device *device)
                goto err_cpu_freq;
        }
 #endif
-
-       /* enable raster engine */
-       lcd_enable_raster();
-
        return 0;
 
 #ifdef CONFIG_CPU_FREQ
@@ -936,10 +1101,12 @@ err_dealloc_cmap:
 err_free_irq:
        free_irq(par->irq, par);
 
+err_release_pl_mem:
+       dma_free_coherent(NULL, PALETTE_SIZE, par->v_palette_base,
+                         par->p_palette_base);
+
 err_release_fb_mem:
-       dma_free_coherent(NULL, par->databuf_sz + PAGE_SIZE,
-                               da8xx_fb_info->screen_base - PAGE_SIZE,
-                               da8xx_fb_info->fix.smem_start);
+       dma_free_coherent(NULL, par->vram_size, par->vram_virt, par->vram_phys);
 
 err_release_fb:
        framebuffer_release(da8xx_fb_info);
index 6113c47e095aaa0e94805c42622c47a344ff4dce..073c9b408cf7ce1ceff2b5eb52c6f49510273291 100644 (file)
@@ -66,7 +66,7 @@ static int fb_deferred_io_fault(struct vm_area_struct *vma,
        return 0;
 }
 
-int fb_deferred_io_fsync(struct file *file, struct dentry *dentry, int datasync)
+int fb_deferred_io_fsync(struct file *file, int datasync)
 {
        struct fb_info *info = file->private_data;
 
@@ -155,25 +155,41 @@ 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(cur, &fbdefio->pagelist, lru) {
-               lock_page(cur);
-               page_mkclean(cur);
-               unlock_page(cur);
+       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);
        }
 
        /* driver's callback with pagelist */
        fbdefio->deferred_io(info, &fbdefio->pagelist);
 
-       /* clear the list */
-       list_for_each_safe(node, next, &fbdefio->pagelist) {
+       /* clear the list... */
+       list_for_each_safe(node, tmp_node, &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);
 }
 
@@ -202,6 +218,7 @@ 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;
 
@@ -209,6 +226,13 @@ 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);
index e08b7b5cb326efc056912a4a453632470d53982e..731fce64df9d09ef04f9516f7877b891f4d1fbb8 100644 (file)
@@ -1491,7 +1491,10 @@ static bool fb_do_apertures_overlap(struct apertures_struct *gena,
                for (j = 0; j < gena->count; ++j) {
                        struct aperture *g = &gena->ranges[j];
                        printk(KERN_DEBUG "checking generic (%llx %llx) vs hw (%llx %llx)\n",
-                               g->base, g->size, h->base, h->size);
+                               (unsigned long long)g->base,
+                               (unsigned long long)g->size,
+                               (unsigned long long)h->base,
+                               (unsigned long long)h->size);
                        if (apertures_overlap(g, h))
                                return true;
                }
index a42fabab69dfe5d43b96cd63902625b219845f46..95c0227f47fcfd7fd30ea784b4202af1dace340a 100644 (file)
@@ -896,7 +896,7 @@ static void ffb_init_fix(struct fb_info *info)
 static int __devinit ffb_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 ffb_fbc __iomem *fbc;
        struct ffb_dac __iomem *dac;
        struct fb_info *info;
@@ -1053,8 +1053,11 @@ static const struct of_device_id ffb_match[] = {
 MODULE_DEVICE_TABLE(of, ffb_match);
 
 static struct of_platform_driver ffb_driver = {
-       .name           = "ffb",
-       .match_table    = ffb_match,
+       .driver = {
+               .name = "ffb",
+               .owner = THIS_MODULE,
+               .of_match_table = ffb_match,
+       },
        .probe          = ffb_probe,
        .remove         = __devexit_p(ffb_remove),
 };
index 994358a4f30298d9684148db609a8c15723de82c..27455ce298b724bbecb03c1598d5b296309ce655 100644 (file)
@@ -1421,7 +1421,7 @@ static ssize_t show_monitor(struct device *device,
 static int __devinit fsl_diu_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 mfb_info *mfbi;
        phys_addr_t dummy_ad_addr;
        int ret, i, error = 0;
@@ -1647,9 +1647,11 @@ static struct of_device_id fsl_diu_match[] = {
 MODULE_DEVICE_TABLE(of, fsl_diu_match);
 
 static struct of_platform_driver fsl_diu_driver = {
-       .owner          = THIS_MODULE,
-       .name           = "fsl_diu",
-       .match_table    = fsl_diu_match,
+       .driver = {
+               .name = "fsl_diu",
+               .owner = THIS_MODULE,
+               .of_match_table = fsl_diu_match,
+       },
        .probe          = fsl_diu_probe,
        .remove         = fsl_diu_remove,
        .suspend        = fsl_diu_suspend,
index 8bbf251f83d9800ffef5dbe6efccc02105f5b065..af8f0f2cc7828519796dca8a1559cf40923f780d 100644 (file)
@@ -106,7 +106,7 @@ static DEFINE_SPINLOCK(hga_reg_lock);
 
 /* Framebuffer driver structures */
 
-static struct fb_var_screeninfo __initdata hga_default_var = {
+static struct fb_var_screeninfo hga_default_var __devinitdata = {
        .xres           = 720,
        .yres           = 348,
        .xres_virtual   = 720,
@@ -120,7 +120,7 @@ static struct fb_var_screeninfo __initdata hga_default_var = {
        .width          = -1,
 };
 
-static struct fb_fix_screeninfo __initdata hga_fix = {
+static struct fb_fix_screeninfo hga_fix __devinitdata = {
        .id             = "HGA",
        .type           = FB_TYPE_PACKED_PIXELS,        /* (not sure) */
        .visual         = FB_VISUAL_MONO10,
@@ -276,7 +276,7 @@ static void hga_blank(int blank_mode)
        spin_unlock_irqrestore(&hga_reg_lock, flags);
 }
 
-static int __init hga_card_detect(void)
+static int __devinit hga_card_detect(void)
 {
        int count = 0;
        void __iomem *p, *q;
@@ -596,7 +596,7 @@ static int __devinit hgafb_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int hgafb_remove(struct platform_device *pdev)
+static int __devexit hgafb_remove(struct platform_device *pdev)
 {
        struct fb_info *info = platform_get_drvdata(pdev);
 
@@ -621,7 +621,7 @@ static int hgafb_remove(struct platform_device *pdev)
 
 static struct platform_driver hgafb_driver = {
        .probe = hgafb_probe,
-       .remove = hgafb_remove,
+       .remove = __devexit_p(hgafb_remove),
        .driver = {
                .name = "hgafb",
        },
index 393f3f3d3dfe4149957c524d1cd56de8011c42e0..cfb8d6451014e06ca1f6b3775e65569ade4fdc8d 100644 (file)
 
 #define        WIDTH 640
 
-static struct fb_var_screeninfo hitfb_var __initdata = {
+static struct fb_var_screeninfo hitfb_var __devinitdata = {
        .activate       = FB_ACTIVATE_NOW,
        .height         = -1,
        .width          = -1,
        .vmode          = FB_VMODE_NONINTERLACED,
 };
 
-static struct fb_fix_screeninfo hitfb_fix __initdata = {
+static struct fb_fix_screeninfo hitfb_fix __devinitdata = {
        .id             = "Hitachi HD64461",
        .type           = FB_TYPE_PACKED_PIXELS,
        .accel          = FB_ACCEL_NONE,
@@ -417,7 +417,7 @@ err_fb:
        return ret;
 }
 
-static int __exit hitfb_remove(struct platform_device *dev)
+static int __devexit hitfb_remove(struct platform_device *dev)
 {
        struct fb_info *info = platform_get_drvdata(dev);
 
@@ -462,7 +462,7 @@ static const struct dev_pm_ops hitfb_dev_pm_ops = {
 
 static struct platform_driver hitfb_driver = {
        .probe          = hitfb_probe,
-       .remove         = __exit_p(hitfb_remove),
+       .remove         = __devexit_p(hitfb_remove),
        .driver         = {
                .name   = "hitfb",
                .owner  = THIS_MODULE,
index 40984551c9275827146d101f6caf69f904bd14dc..6b51175629c741edb36ef98a890020eafe0091c4 100644 (file)
@@ -371,10 +371,6 @@ struct intelfb_info {
                        ((dinfo)->chipset == INTEL_965G) ||     \
                        ((dinfo)->chipset == INTEL_965GM))
 
-#ifndef FBIO_WAITFORVSYNC
-#define FBIO_WAITFORVSYNC      _IOW('F', 0x20, __u32)
-#endif
-
 /*** function prototypes ***/
 
 extern int intelfb_var_to_depth(const struct fb_var_screeninfo *var);
index 1db55f128490213ebfc35a6ad6ed87176af670fb..3d7895316eaf37e79bb56f2413d748fcbdfca131 100644 (file)
@@ -663,8 +663,11 @@ static const struct of_device_id leo_match[] = {
 MODULE_DEVICE_TABLE(of, leo_match);
 
 static struct of_platform_driver leo_driver = {
-       .name           = "leo",
-       .match_table    = leo_match,
+       .driver = {
+               .name = "leo",
+               .owner = THIS_MODULE,
+               .of_match_table = leo_match,
+       },
        .probe          = leo_probe,
        .remove         = __devexit_p(leo_remove),
 };
index 8280a58a0e557c4368f5de03ce129d24f38aa649..0540de4f5cb48f062bedb6d9874964ab1423d62b 100644 (file)
@@ -718,9 +718,11 @@ static struct of_device_id __devinitdata of_platform_mb862xx_tbl[] = {
 };
 
 static struct of_platform_driver of_platform_mb862xxfb_driver = {
-       .owner          = THIS_MODULE,
-       .name           = DRV_NAME,
-       .match_table    = of_platform_mb862xx_tbl,
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = of_platform_mb862xx_tbl,
+       },
        .probe          = of_platform_mb862xx_probe,
        .remove         = __devexit_p(of_platform_mb862xx_remove),
 };
index 6bf0d460a738532a39e767ed4719aa3db3833359..d4cde79ea15e61362a34736179520053d68383bc 100644 (file)
@@ -667,7 +667,7 @@ release_irq:
 release_regs:
        iounmap(fbi->io);
 release_mem_region:
-       release_mem_region((unsigned long)fbi->mem, size);
+       release_mem_region(res->start, size);
 free_fb:
        framebuffer_release(fbinfo);
        return ret;
index 81440f2b90919c2e9904343c24528fe989472270..c85dd408a9b87369fffdce371fad0754f1100810 100644 (file)
@@ -353,8 +353,11 @@ static const struct of_device_id p9100_match[] = {
 MODULE_DEVICE_TABLE(of, p9100_match);
 
 static struct of_platform_driver p9100_driver = {
-       .name           = "p9100",
-       .match_table    = p9100_match,
+       .driver = {
+               .name = "p9100",
+               .owner = THIS_MODULE,
+               .of_match_table = p9100_match,
+       },
        .probe          = p9100_probe,
        .remove         = __devexit_p(p9100_remove),
 };
index 8a204e7a5b5b655a95897ba533c12b032434f16b..72a1f4c047326c1d69634110fa68ec3061c20b48 100644 (file)
@@ -536,7 +536,7 @@ static int __init platinumfb_setup(char *options)
 static int __devinit platinumfb_probe(struct of_device* odev,
                                      const struct of_device_id *match)
 {
-       struct device_node      *dp = odev->node;
+       struct device_node      *dp = odev->dev.of_node;
        struct fb_info          *info;
        struct fb_info_platinum *pinfo;
        volatile __u8           *fbuffer;
@@ -679,8 +679,11 @@ static struct of_device_id platinumfb_match[] =
 
 static struct of_platform_driver platinum_driver = 
 {
-       .name           = "platinumfb",
-       .match_table    = platinumfb_match,
+       .driver = {
+               .name = "platinumfb",
+               .owner = THIS_MODULE,
+               .of_match_table = platinumfb_match,
+       },
        .probe          = platinumfb_probe,
        .remove         = platinumfb_remove,
 };
index 2b094dec4a567523b0fe47499b1924fc2312e6e9..46b430978bcc9fc4fab55597711aef5072d94504 100644 (file)
@@ -631,7 +631,7 @@ static struct fb_ops s3c2410fb_ops = {
  *     cache.  Once this area is remapped, all virtual memory
  *     access to the video memory should occur at the new region.
  */
-static int __init s3c2410fb_map_video_memory(struct fb_info *info)
+static int __devinit s3c2410fb_map_video_memory(struct fb_info *info)
 {
        struct s3c2410fb_info *fbi = info->par;
        dma_addr_t map_dma;
@@ -814,7 +814,7 @@ static inline void s3c2410fb_cpufreq_deregister(struct s3c2410fb_info *info)
 
 static char driver_name[] = "s3c2410fb";
 
-static int __init s3c24xxfb_probe(struct platform_device *pdev,
+static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
                                  enum s3c_drv_type drv_type)
 {
        struct s3c2410fb_info *info;
@@ -1018,7 +1018,7 @@ static int __devinit s3c2412fb_probe(struct platform_device *pdev)
 /*
  *  Cleanup
  */
-static int s3c2410fb_remove(struct platform_device *pdev)
+static int __devexit s3c2410fb_remove(struct platform_device *pdev)
 {
        struct fb_info *fbinfo = platform_get_drvdata(pdev);
        struct s3c2410fb_info *info = fbinfo->par;
@@ -1096,7 +1096,7 @@ static int s3c2410fb_resume(struct platform_device *dev)
 
 static struct platform_driver s3c2410fb_driver = {
        .probe          = s3c2410fb_probe,
-       .remove         = s3c2410fb_remove,
+       .remove         = __devexit_p(s3c2410fb_remove),
        .suspend        = s3c2410fb_suspend,
        .resume         = s3c2410fb_resume,
        .driver         = {
@@ -1107,7 +1107,7 @@ static struct platform_driver s3c2410fb_driver = {
 
 static struct platform_driver s3c2412fb_driver = {
        .probe          = s3c2412fb_probe,
-       .remove         = s3c2410fb_remove,
+       .remove         = __devexit_p(s3c2410fb_remove),
        .suspend        = s3c2410fb_suspend,
        .resume         = s3c2410fb_resume,
        .driver         = {
index d4471b4c037476e82a8ade24acac32164fc6727e..dce8c97b4333b4871f356b6d5cac1c17f351a600 100644 (file)
@@ -71,7 +71,8 @@ static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64",
                        "S3 Trio64UV+", "S3 Trio64V2/DX", "S3 Trio64V2/GX",
                        "S3 Plato/PX", "S3 Aurora64VP", "S3 Virge",
                        "S3 Virge/VX", "S3 Virge/DX", "S3 Virge/GX",
-                       "S3 Virge/GX2", "S3 Virge/GX2P", "S3 Virge/GX2P"};
+                       "S3 Virge/GX2", "S3 Virge/GX2P", "S3 Virge/GX2P",
+                       "S3 Trio3D/1X", "S3 Trio3D/2X", "S3 Trio3D/2X"};
 
 #define CHIP_UNKNOWN           0x00
 #define CHIP_732_TRIO32                0x01
@@ -89,10 +90,14 @@ static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64",
 #define CHIP_356_VIRGE_GX2     0x0D
 #define CHIP_357_VIRGE_GX2P    0x0E
 #define CHIP_359_VIRGE_GX2P    0x0F
+#define CHIP_360_TRIO3D_1X     0x10
+#define CHIP_362_TRIO3D_2X     0x11
+#define CHIP_368_TRIO3D_2X     0x12
 
 #define CHIP_XXX_TRIO          0x80
 #define CHIP_XXX_TRIO64V2_DXGX 0x81
 #define CHIP_XXX_VIRGE_DXGX    0x82
+#define CHIP_36X_TRIO3D_1X_2X  0x83
 
 #define CHIP_UNDECIDED_FLAG    0x80
 #define CHIP_MASK              0xFF
@@ -324,6 +329,7 @@ static void s3fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 
 static void s3_set_pixclock(struct fb_info *info, u32 pixclock)
 {
+       struct s3fb_info *par = info->par;
        u16 m, n, r;
        u8 regval;
        int rv;
@@ -339,7 +345,13 @@ static void s3_set_pixclock(struct fb_info *info, u32 pixclock)
        vga_w(NULL, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD);
 
        /* Set S3 clock registers */
-       vga_wseq(NULL, 0x12, ((n - 2) | (r << 5)));
+       if (par->chip == CHIP_360_TRIO3D_1X ||
+           par->chip == CHIP_362_TRIO3D_2X ||
+           par->chip == CHIP_368_TRIO3D_2X) {
+               vga_wseq(NULL, 0x12, (n - 2) | ((r & 3) << 6)); /* n and two bits of r */
+               vga_wseq(NULL, 0x29, r >> 2); /* remaining highest bit of r */
+       } else
+               vga_wseq(NULL, 0x12, (n - 2) | (r << 5));
        vga_wseq(NULL, 0x13, m - 2);
 
        udelay(1000);
@@ -456,7 +468,7 @@ static int s3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 static int s3fb_set_par(struct fb_info *info)
 {
        struct s3fb_info *par = info->par;
-       u32 value, mode, hmul, offset_value, screen_size, multiplex;
+       u32 value, mode, hmul, offset_value, screen_size, multiplex, dbytes;
        u32 bpp = info->var.bits_per_pixel;
 
        if (bpp != 0) {
@@ -518,7 +530,7 @@ static int s3fb_set_par(struct fb_info *info)
        svga_wcrt_mask(0x33, 0x00, 0x08); /* no DDR ?   */
        svga_wcrt_mask(0x43, 0x00, 0x01); /* no DDR ?   */
 
-       svga_wcrt_mask(0x5D, 0x00, 0x28); // Clear strange HSlen bits
+       svga_wcrt_mask(0x5D, 0x00, 0x28); /* Clear strange HSlen bits */
 
 /*     svga_wcrt_mask(0x58, 0x03, 0x03); */
 
@@ -530,10 +542,14 @@ static int s3fb_set_par(struct fb_info *info)
        pr_debug("fb%d: offset register       : %d\n", info->node, offset_value);
        svga_wcrt_multi(s3_offset_regs, offset_value);
 
-       vga_wcrt(NULL, 0x54, 0x18); /* M parameter */
-       vga_wcrt(NULL, 0x60, 0xff); /* N parameter */
-       vga_wcrt(NULL, 0x61, 0xff); /* L parameter */
-       vga_wcrt(NULL, 0x62, 0xff); /* L parameter */
+       if (par->chip != CHIP_360_TRIO3D_1X &&
+           par->chip != CHIP_362_TRIO3D_2X &&
+           par->chip != CHIP_368_TRIO3D_2X) {
+               vga_wcrt(NULL, 0x54, 0x18); /* M parameter */
+               vga_wcrt(NULL, 0x60, 0xff); /* N parameter */
+               vga_wcrt(NULL, 0x61, 0xff); /* L parameter */
+               vga_wcrt(NULL, 0x62, 0xff); /* L parameter */
+       }
 
        vga_wcrt(NULL, 0x3A, 0x35);
        svga_wattr(0x33, 0x00);
@@ -570,6 +586,16 @@ static int s3fb_set_par(struct fb_info *info)
                vga_wcrt(NULL, 0x66, 0x90);
        }
 
+       if (par->chip == CHIP_360_TRIO3D_1X ||
+           par->chip == CHIP_362_TRIO3D_2X ||
+           par->chip == CHIP_368_TRIO3D_2X) {
+               dbytes = info->var.xres * ((bpp+7)/8);
+               vga_wcrt(NULL, 0x91, (dbytes + 7) / 8);
+               vga_wcrt(NULL, 0x90, (((dbytes + 7) / 8) >> 8) | 0x80);
+
+               vga_wcrt(NULL, 0x66, 0x81);
+       }
+
        svga_wcrt_mask(0x31, 0x00, 0x40);
        multiplex = 0;
        hmul = 1;
@@ -615,11 +641,13 @@ static int s3fb_set_par(struct fb_info *info)
                break;
        case 3:
                pr_debug("fb%d: 8 bit pseudocolor\n", info->node);
-               if (info->var.pixclock > 20000) {
-                       svga_wcrt_mask(0x50, 0x00, 0x30);
+               svga_wcrt_mask(0x50, 0x00, 0x30);
+               if (info->var.pixclock > 20000 ||
+                   par->chip == CHIP_360_TRIO3D_1X ||
+                   par->chip == CHIP_362_TRIO3D_2X ||
+                   par->chip == CHIP_368_TRIO3D_2X)
                        svga_wcrt_mask(0x67, 0x00, 0xF0);
-               } else {
-                       svga_wcrt_mask(0x50, 0x00, 0x30);
+               else {
                        svga_wcrt_mask(0x67, 0x10, 0xF0);
                        multiplex = 1;
                }
@@ -634,7 +662,10 @@ static int s3fb_set_par(struct fb_info *info)
                } else {
                        svga_wcrt_mask(0x50, 0x10, 0x30);
                        svga_wcrt_mask(0x67, 0x30, 0xF0);
-                       hmul = 2;
+                       if (par->chip != CHIP_360_TRIO3D_1X &&
+                           par->chip != CHIP_362_TRIO3D_2X &&
+                           par->chip != CHIP_368_TRIO3D_2X)
+                               hmul = 2;
                }
                break;
        case 5:
@@ -647,7 +678,10 @@ static int s3fb_set_par(struct fb_info *info)
                } else {
                        svga_wcrt_mask(0x50, 0x10, 0x30);
                        svga_wcrt_mask(0x67, 0x50, 0xF0);
-                       hmul = 2;
+                       if (par->chip != CHIP_360_TRIO3D_1X &&
+                           par->chip != CHIP_362_TRIO3D_2X &&
+                           par->chip != CHIP_368_TRIO3D_2X)
+                               hmul = 2;
                }
                break;
        case 6:
@@ -866,6 +900,17 @@ static int __devinit s3_identification(int chip)
                        return CHIP_385_VIRGE_GX;
        }
 
+       if (chip == CHIP_36X_TRIO3D_1X_2X) {
+               switch (vga_rcrt(NULL, 0x2f)) {
+               case 0x00:
+                       return CHIP_360_TRIO3D_1X;
+               case 0x01:
+                       return CHIP_362_TRIO3D_2X;
+               case 0x02:
+                       return CHIP_368_TRIO3D_2X;
+               }
+       }
+
        return CHIP_UNKNOWN;
 }
 
@@ -930,17 +975,32 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i
        vga_wcrt(NULL, 0x38, 0x48);
        vga_wcrt(NULL, 0x39, 0xA5);
 
-       /* Find how many physical memory there is on card */
-       /* 0x36 register is accessible even if other registers are locked */
-       regval = vga_rcrt(NULL, 0x36);
-       info->screen_size = s3_memsizes[regval >> 5] << 10;
-       info->fix.smem_len = info->screen_size;
-
+       /* Identify chip type */
        par->chip = id->driver_data & CHIP_MASK;
        par->rev = vga_rcrt(NULL, 0x2f);
        if (par->chip & CHIP_UNDECIDED_FLAG)
                par->chip = s3_identification(par->chip);
 
+       /* Find how many physical memory there is on card */
+       /* 0x36 register is accessible even if other registers are locked */
+       regval = vga_rcrt(NULL, 0x36);
+       if (par->chip == CHIP_360_TRIO3D_1X ||
+           par->chip == CHIP_362_TRIO3D_2X ||
+           par->chip == CHIP_368_TRIO3D_2X) {
+               switch ((regval & 0xE0) >> 5) {
+               case 0: /* 8MB -- only 4MB usable for display */
+               case 1: /* 4MB with 32-bit bus */
+               case 2: /* 4MB */
+                       info->screen_size = 4 << 20;
+                       break;
+               case 6: /* 2MB */
+                       info->screen_size = 2 << 20;
+                       break;
+               }
+       } else
+               info->screen_size = s3_memsizes[regval >> 5] << 10;
+       info->fix.smem_len = info->screen_size;
+
        /* Find MCLK frequency */
        regval = vga_rseq(NULL, 0x10);
        par->mclk_freq = ((vga_rseq(NULL, 0x11) + 2) * 14318) / ((regval & 0x1F)  + 2);
@@ -1131,6 +1191,7 @@ static struct pci_device_id s3_devices[] __devinitdata = {
        {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A10), .driver_data = CHIP_356_VIRGE_GX2},
        {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A11), .driver_data = CHIP_357_VIRGE_GX2P},
        {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A12), .driver_data = CHIP_359_VIRGE_GX2P},
+       {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A13), .driver_data = CHIP_36X_TRIO3D_1X_2X},
 
        {0, 0, 0, 0, 0, 0, 0}
 };
index 7a3a5e28eca13411f74022a8326d0f581a5194d2..53455f2955107a1dd2072c90503d8047ff3dc49e 100644 (file)
@@ -47,7 +47,7 @@ static int ywrap = 0;
 
 static int flatpanel_id = -1;
 
-static struct fb_fix_screeninfo sgivwfb_fix __initdata = {
+static struct fb_fix_screeninfo sgivwfb_fix __devinitdata = {
        .id             = "SGI Vis WS FB",
        .type           = FB_TYPE_PACKED_PIXELS,
         .visual                = FB_VISUAL_PSEUDOCOLOR,
@@ -57,7 +57,7 @@ static struct fb_fix_screeninfo sgivwfb_fix __initdata = {
        .line_length    = 640,
 };
 
-static struct fb_var_screeninfo sgivwfb_var __initdata = {
+static struct fb_var_screeninfo sgivwfb_var __devinitdata = {
        /* 640x480, 8 bpp */
        .xres           = 640,
        .yres           = 480,
@@ -79,7 +79,7 @@ static struct fb_var_screeninfo sgivwfb_var __initdata = {
        .vmode          = FB_VMODE_NONINTERLACED
 };
 
-static struct fb_var_screeninfo sgivwfb_var1600sw __initdata = {
+static struct fb_var_screeninfo sgivwfb_var1600sw __devinitdata = {
        /* 1600x1024, 8 bpp */
        .xres           = 1600,
        .yres           = 1024,
@@ -825,7 +825,7 @@ fail_ioremap_regs:
        return -ENXIO;
 }
 
-static int sgivwfb_remove(struct platform_device *dev)
+static int __devexit sgivwfb_remove(struct platform_device *dev)
 {
        struct fb_info *info = platform_get_drvdata(dev);
 
@@ -845,7 +845,7 @@ static int sgivwfb_remove(struct platform_device *dev)
 
 static struct platform_driver sgivwfb_driver = {
        .probe  = sgivwfb_probe,
-       .remove = sgivwfb_remove,
+       .remove = __devexit_p(sgivwfb_remove),
        .driver = {
                .name   = "sgivwfb",
        },
index a531a0f7cdf2d7ba27e0f44b8028efa0307d7ab2..559bf1727a2b8f252a193d6fac276aed56124428 100644 (file)
@@ -1845,7 +1845,7 @@ sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
 
        memset(fix, 0, sizeof(struct fb_fix_screeninfo));
 
-       strcpy(fix->id, ivideo->myid);
+       strlcpy(fix->id, ivideo->myid, sizeof(fix->id));
 
        mutex_lock(&info->mm_lock);
        fix->smem_start  = ivideo->video_base + ivideo->video_offset;
index 23e69e834a18de9b3e97056f5b6aebc85bea008f..489b44e8db8153dac7a06bda8abae694c878d7e0 100644 (file)
@@ -114,7 +114,7 @@ static int __devinit gfb_set_fbinfo(struct gfb_info *gp)
 static int __devinit gfb_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 gfb_info *gp;
        int err;
@@ -199,10 +199,13 @@ static const struct of_device_id gfb_match[] = {
 MODULE_DEVICE_TABLE(of, ffb_match);
 
 static struct of_platform_driver gfb_driver = {
-       .name           = "gfb",
-       .match_table    = gfb_match,
        .probe          = gfb_probe,
        .remove         = __devexit_p(gfb_remove),
+       .driver = {
+               .name           = "gfb",
+               .owner          = THIS_MODULE,
+               .of_match_table = gfb_match,
+       },
 };
 
 static int __init gfb_init(void)
index c0c2b18fcdcff6229bdd7afaffa2cbd36c30a891..ef7a7bd8b503492fec8aa1f56ab678adfe2f06f0 100644 (file)
@@ -512,8 +512,11 @@ static const struct of_device_id tcx_match[] = {
 MODULE_DEVICE_TABLE(of, tcx_match);
 
 static struct of_platform_driver tcx_driver = {
-       .name           = "tcx",
-       .match_table    = tcx_match,
+       .driver = {
+               .name = "tcx",
+               .owner = THIS_MODULE,
+               .of_match_table = tcx_match,
+       },
        .probe          = tcx_probe,
        .remove         = __devexit_p(tcx_remove),
 };
index 9b5532b4de35fe9f622b37a7d1fbe14815ba5049..bc67251f1a2f1d0e3662d4bec1f46f91bd2884d8 100644 (file)
@@ -78,7 +78,7 @@ static void rvfree(void *mem, unsigned long size)
        vfree(mem);
 }
 
-static struct fb_var_screeninfo vfb_default __initdata = {
+static struct fb_var_screeninfo vfb_default __devinitdata = {
        .xres =         640,
        .yres =         480,
        .xres_virtual = 640,
@@ -100,7 +100,7 @@ static struct fb_var_screeninfo vfb_default __initdata = {
        .vmode =        FB_VMODE_NONINTERLACED,
 };
 
-static struct fb_fix_screeninfo vfb_fix __initdata = {
+static struct fb_fix_screeninfo vfb_fix __devinitdata = {
        .id =           "Virtual FB",
        .type =         FB_TYPE_PACKED_PIXELS,
        .visual =       FB_VISUAL_PSEUDOCOLOR,
index 149c47ac7e9330dee5d3fbc6c560423a9cdeb851..28ccab44a39181c5f4f5caa7f7d58d2e2bf689e0 100644 (file)
@@ -65,7 +65,7 @@ struct vga16fb_par {
 
 /* --------------------------------------------------------------------- */
 
-static struct fb_var_screeninfo vga16fb_defined __initdata = {
+static struct fb_var_screeninfo vga16fb_defined __devinitdata = {
        .xres           = 640,
        .yres           = 480,
        .xres_virtual   = 640,
@@ -85,7 +85,7 @@ static struct fb_var_screeninfo vga16fb_defined __initdata = {
 };
 
 /* name should not depend on EGA/VGA */
-static struct fb_fix_screeninfo vga16fb_fix __initdata = {
+static struct fb_fix_screeninfo vga16fb_fix __devinitdata = {
        .id             = "VGA16 VGA",
        .smem_start     = VGA_FB_PHYS,
        .smem_len       = VGA_FB_PHYS_LEN,
@@ -1287,7 +1287,7 @@ static struct fb_ops vga16fb_ops = {
 };
 
 #ifndef MODULE
-static int vga16fb_setup(char *options)
+static int __init vga16fb_setup(char *options)
 {
        char *this_opt;
        
@@ -1393,7 +1393,7 @@ static int __devinit vga16fb_probe(struct platform_device *dev)
        return ret;
 }
 
-static int vga16fb_remove(struct platform_device *dev)
+static int __devexit vga16fb_remove(struct platform_device *dev)
 {
        struct fb_info *info = platform_get_drvdata(dev);
 
@@ -1405,7 +1405,7 @@ static int vga16fb_remove(struct platform_device *dev)
 
 static struct platform_driver vga16fb_driver = {
        .probe = vga16fb_probe,
-       .remove = vga16fb_remove,
+       .remove = __devexit_p(vga16fb_remove),
        .driver = {
                .name = "vga16fb",
        },
index 2bc40e682f9509acd5ede1696058aebbdcfeea92..1082541358f01aaa4799f4c287b700c7cd8eafee 100644 (file)
@@ -578,14 +578,9 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
                break;
 
        case VIAFB_SET_GAMMA_LUT:
-               viafb_gamma_table = kmalloc(256 * sizeof(u32), GFP_KERNEL);
-               if (!viafb_gamma_table)
-                       return -ENOMEM;
-               if (copy_from_user(viafb_gamma_table, argp,
-                               256 * sizeof(u32))) {
-                       kfree(viafb_gamma_table);
-                       return -EFAULT;
-               }
+               viafb_gamma_table = memdup_user(argp, 256 * sizeof(u32));
+               if (IS_ERR(viafb_gamma_table))
+                       return PTR_ERR(viafb_gamma_table);
                viafb_set_gamma_table(viafb_bpp, viafb_gamma_table);
                kfree(viafb_gamma_table);
                break;
index 31b0e17ed090f4316dc39fed9c99e73ba2455893..e66b8b19ce5dc1c3695a2d5a721dd3de3d951a3c 100644 (file)
@@ -53,7 +53,7 @@ static void w100_update_enable(void);
 static void w100_update_disable(void);
 static void calc_hsync(struct w100fb_par *par);
 static void w100_init_graphic_engine(struct w100fb_par *par);
-struct w100_pll_info *w100_get_xtal_table(unsigned int freq);
+struct w100_pll_info *w100_get_xtal_table(unsigned int freq) __devinit;
 
 /* Pseudo palette size */
 #define MAX_PALETTES      16
@@ -782,7 +782,7 @@ out:
 }
 
 
-static int w100fb_remove(struct platform_device *pdev)
+static int __devexit w100fb_remove(struct platform_device *pdev)
 {
        struct fb_info *info = platform_get_drvdata(pdev);
        struct w100fb_par *par=info->par;
@@ -1020,7 +1020,7 @@ static struct pll_entries {
        { 0 },
 };
 
-struct w100_pll_info *w100_get_xtal_table(unsigned int freq)
+struct w100_pll_info __devinit *w100_get_xtal_table(unsigned int freq)
 {
        struct pll_entries *pll_entry = w100_pll_tables;
 
@@ -1611,7 +1611,7 @@ static void w100_vsync(void)
 
 static struct platform_driver w100fb_driver = {
        .probe          = w100fb_probe,
-       .remove         = w100fb_remove,
+       .remove         = __devexit_p(w100fb_remove),
        .suspend        = w100fb_suspend,
        .resume         = w100fb_resume,
        .driver         = {
@@ -1619,7 +1619,7 @@ static struct platform_driver w100fb_driver = {
        },
 };
 
-int __devinit w100fb_init(void)
+int __init w100fb_init(void)
 {
        return platform_driver_register(&w100fb_driver);
 }
index 3fcb83f03881e58f94c27004e05ebdd82eca8e93..574dc54e12d43e97038eacae80292dc75d53419b 100644 (file)
@@ -423,7 +423,7 @@ xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match)
         * To check whether the core is connected directly to DCR or PLB
         * interface and initialize the tft_access accordingly.
         */
-       p = (u32 *)of_get_property(op->node, "xlnx,dcr-splb-slave-if", NULL);
+       p = (u32 *)of_get_property(op->dev.of_node, "xlnx,dcr-splb-slave-if", NULL);
        tft_access = p ? *p : 0;
 
        /*
@@ -432,41 +432,41 @@ xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match)
         */
        if (tft_access) {
                drvdata->flags |= PLB_ACCESS_FLAG;
-               rc = of_address_to_resource(op->node, 0, &res);
+               rc = of_address_to_resource(op->dev.of_node, 0, &res);
                if (rc) {
                        dev_err(&op->dev, "invalid address\n");
                        goto err;
                }
        } else {
                res.start = 0;
-               start = dcr_resource_start(op->node, 0);
-               drvdata->dcr_len = dcr_resource_len(op->node, 0);
-               drvdata->dcr_host = dcr_map(op->node, start, drvdata->dcr_len);
+               start = dcr_resource_start(op->dev.of_node, 0);
+               drvdata->dcr_len = dcr_resource_len(op->dev.of_node, 0);
+               drvdata->dcr_host = dcr_map(op->dev.of_node, start, drvdata->dcr_len);
                if (!DCR_MAP_OK(drvdata->dcr_host)) {
                        dev_err(&op->dev, "invalid DCR address\n");
                        goto err;
                }
        }
 
-       prop = of_get_property(op->node, "phys-size", &size);
+       prop = of_get_property(op->dev.of_node, "phys-size", &size);
        if ((prop) && (size >= sizeof(u32)*2)) {
                pdata.screen_width_mm = prop[0];
                pdata.screen_height_mm = prop[1];
        }
 
-       prop = of_get_property(op->node, "resolution", &size);
+       prop = of_get_property(op->dev.of_node, "resolution", &size);
        if ((prop) && (size >= sizeof(u32)*2)) {
                pdata.xres = prop[0];
                pdata.yres = prop[1];
        }
 
-       prop = of_get_property(op->node, "virtual-resolution", &size);
+       prop = of_get_property(op->dev.of_node, "virtual-resolution", &size);
        if ((prop) && (size >= sizeof(u32)*2)) {
                pdata.xvirt = prop[0];
                pdata.yvirt = prop[1];
        }
 
-       if (of_find_property(op->node, "rotate-display", NULL))
+       if (of_find_property(op->dev.of_node, "rotate-display", NULL))
                pdata.rotate_screen = 1;
 
        dev_set_drvdata(&op->dev, drvdata);
@@ -492,13 +492,12 @@ static struct of_device_id xilinxfb_of_match[] __devinitdata = {
 MODULE_DEVICE_TABLE(of, xilinxfb_of_match);
 
 static struct of_platform_driver xilinxfb_of_driver = {
-       .owner = THIS_MODULE,
-       .name = DRIVER_NAME,
-       .match_table = xilinxfb_of_match,
        .probe = xilinxfb_of_probe,
        .remove = __devexit_p(xilinxfb_of_remove),
        .driver = {
                .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = xilinxfb_of_match,
        },
 };
 
index bfec7c29486df963c16c2f3a1f292242eedc09eb..0f1da45ba47dd8a917c38a797beca69a00f0a67c 100644 (file)
@@ -75,7 +75,7 @@ static void balloon_ack(struct virtqueue *vq)
        struct virtio_balloon *vb;
        unsigned int len;
 
-       vb = vq->vq_ops->get_buf(vq, &len);
+       vb = virtqueue_get_buf(vq, &len);
        if (vb)
                complete(&vb->acked);
 }
@@ -89,9 +89,9 @@ static void tell_host(struct virtio_balloon *vb, struct virtqueue *vq)
        init_completion(&vb->acked);
 
        /* We should always be able to add one buffer to an empty queue. */
-       if (vq->vq_ops->add_buf(vq, &sg, 1, 0, vb) < 0)
+       if (virtqueue_add_buf(vq, &sg, 1, 0, vb) < 0)
                BUG();
-       vq->vq_ops->kick(vq);
+       virtqueue_kick(vq);
 
        /* When host has read buffer, this completes via balloon_ack */
        wait_for_completion(&vb->acked);
@@ -204,7 +204,7 @@ static void stats_request(struct virtqueue *vq)
        struct virtio_balloon *vb;
        unsigned int len;
 
-       vb = vq->vq_ops->get_buf(vq, &len);
+       vb = virtqueue_get_buf(vq, &len);
        if (!vb)
                return;
        vb->need_stats_update = 1;
@@ -221,9 +221,9 @@ static void stats_handle_request(struct virtio_balloon *vb)
 
        vq = vb->stats_vq;
        sg_init_one(&sg, vb->stats, sizeof(vb->stats));
-       if (vq->vq_ops->add_buf(vq, &sg, 1, 0, vb) < 0)
+       if (virtqueue_add_buf(vq, &sg, 1, 0, vb) < 0)
                BUG();
-       vq->vq_ops->kick(vq);
+       virtqueue_kick(vq);
 }
 
 static void virtballoon_changed(struct virtio_device *vdev)
@@ -314,10 +314,9 @@ static int virtballoon_probe(struct virtio_device *vdev)
                 * use it to signal us later.
                 */
                sg_init_one(&sg, vb->stats, sizeof vb->stats);
-               if (vb->stats_vq->vq_ops->add_buf(vb->stats_vq,
-                                                 &sg, 1, 0, vb) < 0)
+               if (virtqueue_add_buf(vb->stats_vq, &sg, 1, 0, vb) < 0)
                        BUG();
-               vb->stats_vq->vq_ops->kick(vb->stats_vq);
+               virtqueue_kick(vb->stats_vq);
        }
 
        vb->thread = kthread_run(balloon, vb, "vballoon");
index 0f90634bcb85d170e64ce6e2addee12f5fb37f82..1ca88908723badfcb3aa9d07463b8f2988c28981 100644 (file)
@@ -110,13 +110,14 @@ struct vring_virtqueue
 static int vring_add_indirect(struct vring_virtqueue *vq,
                              struct scatterlist sg[],
                              unsigned int out,
-                             unsigned int in)
+                             unsigned int in,
+                             gfp_t gfp)
 {
        struct vring_desc *desc;
        unsigned head;
        int i;
 
-       desc = kmalloc((out + in) * sizeof(struct vring_desc), GFP_ATOMIC);
+       desc = kmalloc((out + in) * sizeof(struct vring_desc), gfp);
        if (!desc)
                return vq->vring.num;
 
@@ -155,11 +156,12 @@ static int vring_add_indirect(struct vring_virtqueue *vq,
        return head;
 }
 
-static int vring_add_buf(struct virtqueue *_vq,
-                        struct scatterlist sg[],
-                        unsigned int out,
-                        unsigned int in,
-                        void *data)
+int virtqueue_add_buf_gfp(struct virtqueue *_vq,
+                         struct scatterlist sg[],
+                         unsigned int out,
+                         unsigned int in,
+                         void *data,
+                         gfp_t gfp)
 {
        struct vring_virtqueue *vq = to_vvq(_vq);
        unsigned int i, avail, head, uninitialized_var(prev);
@@ -171,7 +173,7 @@ static int vring_add_buf(struct virtqueue *_vq,
        /* If the host supports indirect descriptor tables, and we have multiple
         * buffers, then go indirect. FIXME: tune this threshold */
        if (vq->indirect && (out + in) > 1 && vq->num_free) {
-               head = vring_add_indirect(vq, sg, out, in);
+               head = vring_add_indirect(vq, sg, out, in, gfp);
                if (head != vq->vring.num)
                        goto add_head;
        }
@@ -232,8 +234,9 @@ add_head:
                return vq->num_free ? vq->vring.num : 0;
        return vq->num_free;
 }
+EXPORT_SYMBOL_GPL(virtqueue_add_buf_gfp);
 
-static void vring_kick(struct virtqueue *_vq)
+void virtqueue_kick(struct virtqueue *_vq)
 {
        struct vring_virtqueue *vq = to_vvq(_vq);
        START_USE(vq);
@@ -253,6 +256,7 @@ static void vring_kick(struct virtqueue *_vq)
 
        END_USE(vq);
 }
+EXPORT_SYMBOL_GPL(virtqueue_kick);
 
 static void detach_buf(struct vring_virtqueue *vq, unsigned int head)
 {
@@ -284,7 +288,7 @@ static inline bool more_used(const struct vring_virtqueue *vq)
        return vq->last_used_idx != vq->vring.used->idx;
 }
 
-static void *vring_get_buf(struct virtqueue *_vq, unsigned int *len)
+void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len)
 {
        struct vring_virtqueue *vq = to_vvq(_vq);
        void *ret;
@@ -325,15 +329,17 @@ static void *vring_get_buf(struct virtqueue *_vq, unsigned int *len)
        END_USE(vq);
        return ret;
 }
+EXPORT_SYMBOL_GPL(virtqueue_get_buf);
 
-static void vring_disable_cb(struct virtqueue *_vq)
+void virtqueue_disable_cb(struct virtqueue *_vq)
 {
        struct vring_virtqueue *vq = to_vvq(_vq);
 
        vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
 }
+EXPORT_SYMBOL_GPL(virtqueue_disable_cb);
 
-static bool vring_enable_cb(struct virtqueue *_vq)
+bool virtqueue_enable_cb(struct virtqueue *_vq)
 {
        struct vring_virtqueue *vq = to_vvq(_vq);
 
@@ -351,8 +357,9 @@ static bool vring_enable_cb(struct virtqueue *_vq)
        END_USE(vq);
        return true;
 }
+EXPORT_SYMBOL_GPL(virtqueue_enable_cb);
 
-static void *vring_detach_unused_buf(struct virtqueue *_vq)
+void *virtqueue_detach_unused_buf(struct virtqueue *_vq)
 {
        struct vring_virtqueue *vq = to_vvq(_vq);
        unsigned int i;
@@ -375,6 +382,7 @@ static void *vring_detach_unused_buf(struct virtqueue *_vq)
        END_USE(vq);
        return NULL;
 }
+EXPORT_SYMBOL_GPL(virtqueue_detach_unused_buf);
 
 irqreturn_t vring_interrupt(int irq, void *_vq)
 {
@@ -396,15 +404,6 @@ irqreturn_t vring_interrupt(int irq, void *_vq)
 }
 EXPORT_SYMBOL_GPL(vring_interrupt);
 
-static struct virtqueue_ops vring_vq_ops = {
-       .add_buf = vring_add_buf,
-       .get_buf = vring_get_buf,
-       .kick = vring_kick,
-       .disable_cb = vring_disable_cb,
-       .enable_cb = vring_enable_cb,
-       .detach_unused_buf = vring_detach_unused_buf,
-};
-
 struct virtqueue *vring_new_virtqueue(unsigned int num,
                                      unsigned int vring_align,
                                      struct virtio_device *vdev,
@@ -429,7 +428,6 @@ struct virtqueue *vring_new_virtqueue(unsigned int num,
        vring_init(&vq->vring, num, pages, vring_align);
        vq->vq.callback = callback;
        vq->vq.vdev = vdev;
-       vq->vq.vq_ops = &vring_vq_ops;
        vq->vq.name = name;
        vq->notify = notify;
        vq->broken = false;
index b87ba23442d26e2118a5437cadc57272358dd042..afcfacc9bbe2f0b8718c4ef3a5b8cc6a7c7e62b3 100644 (file)
@@ -145,13 +145,19 @@ config KS8695_WATCHDOG
          Watchdog timer embedded into KS8695 processor. This will reboot your
          system when the timeout is reached.
 
+config HAVE_S3C2410_WATCHDOG
+       bool
+       help
+         This will include watchdog timer support for Samsung SoCs. If
+         you want to include watchdog support for any machine, kindly
+         select this in the respective mach-XXXX/Kconfig file.
+
 config S3C2410_WATCHDOG
        tristate "S3C2410 Watchdog"
-       depends on ARCH_S3C2410
+       depends on ARCH_S3C2410 || HAVE_S3C2410_WATCHDOG
        help
-         Watchdog timer block in the Samsung S3C2410 chips. This will
-         reboot the system when the timer expires with the watchdog
-         enabled.
+         Watchdog timer block in the Samsung SoCs. This will reboot
+         the system when the timer expires with the watchdog enabled.
 
          The driver is limited by the speed of the system's PCLK
          signal, so with reasonably fast systems (PCLK around 50-66MHz)
@@ -306,6 +312,18 @@ config MAX63XX_WATCHDOG
        help
          Support for memory mapped max63{69,70,71,72,73,74} watchdog timer.
 
+config IMX2_WDT
+       tristate "IMX2+ Watchdog"
+       depends on ARCH_MX2 || ARCH_MX25 || ARCH_MX3 || ARCH_MX5
+       help
+         This is the driver for the hardware watchdog
+         on the Freescale IMX2 and later processors.
+         If you have one of these processors and wish to have
+         watchdog support enabled, say Y, otherwise say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called imx2_wdt.
+
 # AVR32 Architecture
 
 config AT32AP700X_WDT
index 5e3cb95bb0e9cc58c653eb632cd2a990eb1ea486..72f3e2073f8e4e468f9bb720a313cbf3509bb9ce 100644 (file)
@@ -47,6 +47,7 @@ obj-$(CONFIG_STMP3XXX_WATCHDOG) += stmp3xxx_wdt.o
 obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o
 obj-$(CONFIG_ADX_WATCHDOG) += adx_wdt.o
 obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o
+obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o
 
 # AVR32 Architecture
 obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
index 9c7ccd1e9088fbd5f108fe7c96980d7cda07d8e3..9042a95fc98c04e2bf3a0f10c3d9bcf460a849fc 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/interrupt.h>
 #include <linux/uaccess.h>
 #include <asm/blackfin.h>
+#include <asm/bfin_watchdog.h>
 
 #define stamp(fmt, args...) \
        pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args)
 # define bfin_write_WDOG_STAT(x) bfin_write_WDOGA_STAT(x)
 #endif
 
-/* Bit in SWRST that indicates boot caused by watchdog */
-#define SWRST_RESET_WDOG 0x4000
-
-/* Bit in WDOG_CTL that indicates watchdog has expired (WDR0) */
-#define WDOG_EXPIRED 0x8000
-
-/* Masks for WDEV field in WDOG_CTL register */
-#define ICTL_RESET   0x0
-#define ICTL_NMI     0x2
-#define ICTL_GPI     0x4
-#define ICTL_NONE    0x6
-#define ICTL_MASK    0x6
-
-/* Masks for WDEN field in WDOG_CTL register */
-#define WDEN_MASK    0x0FF0
-#define WDEN_ENABLE  0x0000
-#define WDEN_DISABLE 0x0AD0
-
 /* some defaults */
 #define WATCHDOG_TIMEOUT 20
 
index 801ead1914999c435b36fba4624329758936aadf..3d49671cdf5aebf1f78e52d0a92a185dd9026a31 100644 (file)
@@ -137,12 +137,12 @@ static long booke_wdt_ioctl(struct file *file,
                if (copy_to_user((void *)arg, &ident, sizeof(ident)))
                        return -EFAULT;
        case WDIOC_GETSTATUS:
-               return put_user(ident.options, p);
+               return put_user(0, p);
        case WDIOC_GETBOOTSTATUS:
                /* XXX: something is clearing TSR */
                tmp = mfspr(SPRN_TSR) & TSR_WRS(3);
-               /* returns 1 if last reset was caused by the WDT */
-               return (tmp ? 1 : 0);
+               /* returns CARDRESET if last reset was caused by the WDT */
+               return (tmp ? WDIOF_CARDRESET : 0);
        case WDIOC_SETOPTIONS:
                if (get_user(tmp, p))
                        return -EINVAL;
index ba2efce4b40ef795ee7f7fd6e3ca469d3f0f5a43..d62b9ce8f773cb0d402bb43794b121bddae02209 100644 (file)
@@ -577,7 +577,7 @@ static int __devinit cpwd_probe(struct of_device *op,
         * interrupt_mask register cannot be written, so no timer
         * interrupts can be masked within the PLD.
         */
-       str_prop = of_get_property(op->node, "model", NULL);
+       str_prop = of_get_property(op->dev.of_node, "model", NULL);
        p->broken = (str_prop && !strcmp(str_prop, WD_BADMODEL));
 
        if (!p->enabled)
@@ -677,8 +677,11 @@ static const struct of_device_id cpwd_match[] = {
 MODULE_DEVICE_TABLE(of, cpwd_match);
 
 static struct of_platform_driver cpwd_driver = {
-       .name           = DRIVER_NAME,
-       .match_table    = cpwd_match,
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = cpwd_match,
+       },
        .probe          = cpwd_probe,
        .remove         = __devexit_p(cpwd_remove),
 };
index d1c4e55b1db0edd7abaf8bf6109998999254b1bc..3f3dc093ad68030d4d22442df70cfd532ace9039 100644 (file)
@@ -68,7 +68,6 @@ static spinlock_t eurwdt_lock;
 
 /*
  * You must set these - there is no sane way to probe for this board.
- * You can use eurwdt=x,y to set these now.
  */
 
 static int io = 0x3f0;
index abdbad034a6c8aec9f7ecf3fa0641db4bf66690f..ca0f4c6cf5ab98217f1b444a94611b0098781041 100644 (file)
@@ -303,9 +303,11 @@ static const struct of_device_id gef_wdt_ids[] = {
 };
 
 static struct of_platform_driver gef_wdt_driver = {
-       .owner          = THIS_MODULE,
-       .name           = "gef_wdt",
-       .match_table    = gef_wdt_ids,
+       .driver = {
+               .name = "gef_wdt",
+               .owner = THIS_MODULE,
+               .of_match_table = gef_wdt_ids,
+       },
        .probe          = gef_wdt_probe,
 };
 
index 5133bca5ccbea69ea8ea0a9af367db4c085fcb06..481d1ad434640a3c58c1d1a58791f985d75567f5 100644 (file)
@@ -101,13 +101,6 @@ static void supermicro_old_pre_stop(unsigned long acpibase)
        outl(val32, SMI_EN);    /* Needed to deactivate watchdog */
 }
 
-static void supermicro_old_pre_keepalive(unsigned long acpibase)
-{
-       /* Reload TCO Timer (done in iTCO_wdt_keepalive) + */
-       /* Clear "Expire Flag" (Bit 3 of TC01_STS register) */
-       outb(0x08, TCO1_STS);
-}
-
 /*
  *     Vendor Support: 2
  *     Board: Super Micro Computer Inc. P4SBx, P4DPx
@@ -337,9 +330,7 @@ EXPORT_SYMBOL(iTCO_vendor_pre_stop);
 
 void iTCO_vendor_pre_keepalive(unsigned long acpibase, unsigned int heartbeat)
 {
-       if (vendorsupport == SUPERMICRO_OLD_BOARD)
-               supermicro_old_pre_keepalive(acpibase);
-       else if (vendorsupport == SUPERMICRO_NEW_BOARD)
+       if (vendorsupport == SUPERMICRO_NEW_BOARD)
                supermicro_new_pre_set_heartbeat(heartbeat);
 }
 EXPORT_SYMBOL(iTCO_vendor_pre_keepalive);
index 8da8860353748a6fcae9c72cc9e0fd2b1b4deb3c..69de8713b8e49ccb474e798748e4f0aca59ac9ee 100644 (file)
@@ -40,7 +40,7 @@
 
 /* Module and version information */
 #define DRV_NAME       "iTCO_wdt"
-#define DRV_VERSION    "1.05"
+#define DRV_VERSION    "1.06"
 #define PFX            DRV_NAME ": "
 
 /* Includes */
@@ -391,8 +391,8 @@ static struct platform_device *iTCO_wdt_platform_device;
 #define WATCHDOG_HEARTBEAT 30  /* 30 sec default heartbeat */
 static int heartbeat = WATCHDOG_HEARTBEAT;  /* in seconds */
 module_param(heartbeat, int, 0);
-MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. "
-       "(2<heartbeat<39 (TCO v1) or 613 (TCO v2), default="
+MODULE_PARM_DESC(heartbeat, "Watchdog timeout in seconds. "
+       "5..76 (TCO v1) or 3..614 (TCO v2), default="
                                __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
 
 static int nowayout = WATCHDOG_NOWAYOUT;
@@ -523,8 +523,13 @@ static int iTCO_wdt_keepalive(void)
        /* Reload the timer by writing to the TCO Timer Counter register */
        if (iTCO_wdt_private.iTCO_version == 2)
                outw(0x01, TCO_RLD);
-       else if (iTCO_wdt_private.iTCO_version == 1)
+       else if (iTCO_wdt_private.iTCO_version == 1) {
+               /* Reset the timeout status bit so that the timer
+                * needs to count down twice again before rebooting */
+               outw(0x0008, TCO1_STS); /* write 1 to clear bit */
+
                outb(0x01, TCO_RLD);
+       }
 
        spin_unlock(&iTCO_wdt_private.io_lock);
        return 0;
@@ -537,6 +542,11 @@ static int iTCO_wdt_set_heartbeat(int t)
        unsigned int tmrval;
 
        tmrval = seconds_to_ticks(t);
+
+       /* For TCO v1 the timer counts down twice before rebooting */
+       if (iTCO_wdt_private.iTCO_version == 1)
+               tmrval /= 2;
+
        /* from the specs: */
        /* "Values of 0h-3h are ignored and should not be attempted" */
        if (tmrval < 0x04)
@@ -593,6 +603,8 @@ static int iTCO_wdt_get_timeleft(int *time_left)
                spin_lock(&iTCO_wdt_private.io_lock);
                val8 = inb(TCO_RLD);
                val8 &= 0x3f;
+               if (!(inw(TCO1_STS) & 0x0008))
+                       val8 += (inb(TCOv1_TMR) & 0x3f);
                spin_unlock(&iTCO_wdt_private.io_lock);
 
                *time_left = (val8 * 6) / 10;
@@ -832,9 +844,9 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
                        TCOBASE);
 
        /* Clear out the (probably old) status */
-       outb(8, TCO1_STS);      /* Clear the Time Out Status bit */
-       outb(2, TCO2_STS);      /* Clear SECOND_TO_STS bit */
-       outb(4, TCO2_STS);      /* Clear BOOT_STS bit */
+       outw(0x0008, TCO1_STS); /* Clear the Time Out Status bit */
+       outw(0x0002, TCO2_STS); /* Clear SECOND_TO_STS bit */
+       outw(0x0004, TCO2_STS); /* Clear BOOT_STS bit */
 
        /* Make sure the watchdog is not running */
        iTCO_wdt_stop();
@@ -844,8 +856,7 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
        if (iTCO_wdt_set_heartbeat(heartbeat)) {
                iTCO_wdt_set_heartbeat(WATCHDOG_HEARTBEAT);
                printk(KERN_INFO PFX
-                       "heartbeat value must be 2 < heartbeat < 39 (TCO v1) "
-                               "or 613 (TCO v2), using %d\n", heartbeat);
+                       "timeout value out of range, using %d\n", heartbeat);
        }
 
        ret = misc_register(&iTCO_wdt_miscdev);
diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c
new file mode 100644 (file)
index 0000000..ea25885
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ * Watchdog driver for IMX2 and later processors
+ *
+ *  Copyright (C) 2010 Wolfram Sang, Pengutronix e.K. <w.sang@pengutronix.de>
+ *
+ * some parts adapted by similar drivers from Darius Augulis and Vladimir
+ * Zapolskiy, additional improvements by Wim Van Sebroeck.
+ *
+ * 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.
+ *
+ * NOTE: MX1 has a slightly different Watchdog than MX2 and later:
+ *
+ *                     MX1:            MX2+:
+ *                     ----            -----
+ * Registers:          32-bit          16-bit
+ * Stopable timer:     Yes             No
+ * Need to enable clk: No              Yes
+ * Halt on suspend:    Manual          Can be automatic
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/watchdog.h>
+#include <linux/clk.h>
+#include <linux/fs.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+#include <mach/hardware.h>
+
+#define DRIVER_NAME "imx2-wdt"
+
+#define IMX2_WDT_WCR           0x00            /* Control Register */
+#define IMX2_WDT_WCR_WT                (0xFF << 8)     /* -> Watchdog Timeout Field */
+#define IMX2_WDT_WCR_WRE       (1 << 3)        /* -> WDOG Reset Enable */
+#define IMX2_WDT_WCR_WDE       (1 << 2)        /* -> Watchdog Enable */
+
+#define IMX2_WDT_WSR           0x02            /* Service Register */
+#define IMX2_WDT_SEQ1          0x5555          /* -> service sequence 1 */
+#define IMX2_WDT_SEQ2          0xAAAA          /* -> service sequence 2 */
+
+#define IMX2_WDT_MAX_TIME      128
+#define IMX2_WDT_DEFAULT_TIME  60              /* in seconds */
+
+#define WDOG_SEC_TO_COUNT(s)   ((s * 2 - 1) << 8)
+
+#define IMX2_WDT_STATUS_OPEN   0
+#define IMX2_WDT_STATUS_STARTED        1
+#define IMX2_WDT_EXPECT_CLOSE  2
+
+static struct {
+       struct clk *clk;
+       void __iomem *base;
+       unsigned timeout;
+       unsigned long status;
+       struct timer_list timer;        /* Pings the watchdog when closed */
+} imx2_wdt;
+
+static struct miscdevice imx2_wdt_miscdev;
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+                               __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+
+static unsigned timeout = IMX2_WDT_DEFAULT_TIME;
+module_param(timeout, uint, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default="
+                               __MODULE_STRING(IMX2_WDT_DEFAULT_TIME) ")");
+
+static const struct watchdog_info imx2_wdt_info = {
+       .identity = "imx2+ watchdog",
+       .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
+};
+
+static inline void imx2_wdt_setup(void)
+{
+       u16 val = __raw_readw(imx2_wdt.base + IMX2_WDT_WCR);
+
+       /* Strip the old watchdog Time-Out value */
+       val &= ~IMX2_WDT_WCR_WT;
+       /* Generate reset if WDOG times out */
+       val &= ~IMX2_WDT_WCR_WRE;
+       /* Keep Watchdog Disabled */
+       val &= ~IMX2_WDT_WCR_WDE;
+       /* Set the watchdog's Time-Out value */
+       val |= WDOG_SEC_TO_COUNT(imx2_wdt.timeout);
+
+       __raw_writew(val, imx2_wdt.base + IMX2_WDT_WCR);
+
+       /* enable the watchdog */
+       val |= IMX2_WDT_WCR_WDE;
+       __raw_writew(val, imx2_wdt.base + IMX2_WDT_WCR);
+}
+
+static inline void imx2_wdt_ping(void)
+{
+       __raw_writew(IMX2_WDT_SEQ1, imx2_wdt.base + IMX2_WDT_WSR);
+       __raw_writew(IMX2_WDT_SEQ2, imx2_wdt.base + IMX2_WDT_WSR);
+}
+
+static void imx2_wdt_timer_ping(unsigned long arg)
+{
+       /* ping it every imx2_wdt.timeout / 2 seconds to prevent reboot */
+       imx2_wdt_ping();
+       mod_timer(&imx2_wdt.timer, jiffies + imx2_wdt.timeout * HZ / 2);
+}
+
+static void imx2_wdt_start(void)
+{
+       if (!test_and_set_bit(IMX2_WDT_STATUS_STARTED, &imx2_wdt.status)) {
+               /* at our first start we enable clock and do initialisations */
+               clk_enable(imx2_wdt.clk);
+
+               imx2_wdt_setup();
+       } else  /* delete the timer that pings the watchdog after close */
+               del_timer_sync(&imx2_wdt.timer);
+
+       /* Watchdog is enabled - time to reload the timeout value */
+       imx2_wdt_ping();
+}
+
+static void imx2_wdt_stop(void)
+{
+       /* we don't need a clk_disable, it cannot be disabled once started.
+        * We use a timer to ping the watchdog while /dev/watchdog is closed */
+       imx2_wdt_timer_ping(0);
+}
+
+static void imx2_wdt_set_timeout(int new_timeout)
+{
+       u16 val = __raw_readw(imx2_wdt.base + IMX2_WDT_WCR);
+
+       /* set the new timeout value in the WSR */
+       val &= ~IMX2_WDT_WCR_WT;
+       val |= WDOG_SEC_TO_COUNT(new_timeout);
+       __raw_writew(val, imx2_wdt.base + IMX2_WDT_WCR);
+}
+
+static int imx2_wdt_open(struct inode *inode, struct file *file)
+{
+       if (test_and_set_bit(IMX2_WDT_STATUS_OPEN, &imx2_wdt.status))
+               return -EBUSY;
+
+       imx2_wdt_start();
+       return nonseekable_open(inode, file);
+}
+
+static int imx2_wdt_close(struct inode *inode, struct file *file)
+{
+       if (test_bit(IMX2_WDT_EXPECT_CLOSE, &imx2_wdt.status) && !nowayout)
+               imx2_wdt_stop();
+       else {
+               dev_crit(imx2_wdt_miscdev.parent,
+                       "Unexpected close: Expect reboot!\n");
+               imx2_wdt_ping();
+       }
+
+       clear_bit(IMX2_WDT_EXPECT_CLOSE, &imx2_wdt.status);
+       clear_bit(IMX2_WDT_STATUS_OPEN, &imx2_wdt.status);
+       return 0;
+}
+
+static long imx2_wdt_ioctl(struct file *file, unsigned int cmd,
+                                                       unsigned long arg)
+{
+       void __user *argp = (void __user *)arg;
+       int __user *p = argp;
+       int new_value;
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               return copy_to_user(argp, &imx2_wdt_info,
+                       sizeof(struct watchdog_info)) ? -EFAULT : 0;
+
+       case WDIOC_GETSTATUS:
+       case WDIOC_GETBOOTSTATUS:
+               return put_user(0, p);
+
+       case WDIOC_KEEPALIVE:
+               imx2_wdt_ping();
+               return 0;
+
+       case WDIOC_SETTIMEOUT:
+               if (get_user(new_value, p))
+                       return -EFAULT;
+               if ((new_value < 1) || (new_value > IMX2_WDT_MAX_TIME))
+                       return -EINVAL;
+               imx2_wdt_set_timeout(new_value);
+               imx2_wdt.timeout = new_value;
+               imx2_wdt_ping();
+
+               /* Fallthrough to return current value */
+       case WDIOC_GETTIMEOUT:
+               return put_user(imx2_wdt.timeout, p);
+
+       default:
+               return -ENOTTY;
+       }
+}
+
+static ssize_t imx2_wdt_write(struct file *file, const char __user *data,
+                                               size_t len, loff_t *ppos)
+{
+       size_t i;
+       char c;
+
+       if (len == 0)   /* Can we see this even ? */
+               return 0;
+
+       clear_bit(IMX2_WDT_EXPECT_CLOSE, &imx2_wdt.status);
+       /* scan to see whether or not we got the magic character */
+       for (i = 0; i != len; i++) {
+               if (get_user(c, data + i))
+                       return -EFAULT;
+               if (c == 'V')
+                       set_bit(IMX2_WDT_EXPECT_CLOSE, &imx2_wdt.status);
+       }
+
+       imx2_wdt_ping();
+       return len;
+}
+
+static const struct file_operations imx2_wdt_fops = {
+       .owner = THIS_MODULE,
+       .llseek = no_llseek,
+       .unlocked_ioctl = imx2_wdt_ioctl,
+       .open = imx2_wdt_open,
+       .release = imx2_wdt_close,
+       .write = imx2_wdt_write,
+};
+
+static struct miscdevice imx2_wdt_miscdev = {
+       .minor = WATCHDOG_MINOR,
+       .name = "watchdog",
+       .fops = &imx2_wdt_fops,
+};
+
+static int __init imx2_wdt_probe(struct platform_device *pdev)
+{
+       int ret;
+       int res_size;
+       struct resource *res;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "can't get device resources\n");
+               return -ENODEV;
+       }
+
+       res_size = resource_size(res);
+       if (!devm_request_mem_region(&pdev->dev, res->start, res_size,
+               res->name)) {
+               dev_err(&pdev->dev, "can't allocate %d bytes at %d address\n",
+                       res_size, res->start);
+               return -ENOMEM;
+       }
+
+       imx2_wdt.base = devm_ioremap_nocache(&pdev->dev, res->start, res_size);
+       if (!imx2_wdt.base) {
+               dev_err(&pdev->dev, "ioremap failed\n");
+               return -ENOMEM;
+       }
+
+       imx2_wdt.clk = clk_get_sys("imx-wdt.0", NULL);
+       if (IS_ERR(imx2_wdt.clk)) {
+               dev_err(&pdev->dev, "can't get Watchdog clock\n");
+               return PTR_ERR(imx2_wdt.clk);
+       }
+
+       imx2_wdt.timeout = clamp_t(unsigned, timeout, 1, IMX2_WDT_MAX_TIME);
+       if (imx2_wdt.timeout != timeout)
+               dev_warn(&pdev->dev, "Initial timeout out of range! "
+                       "Clamped from %u to %u\n", timeout, imx2_wdt.timeout);
+
+       setup_timer(&imx2_wdt.timer, imx2_wdt_timer_ping, 0);
+
+       imx2_wdt_miscdev.parent = &pdev->dev;
+       ret = misc_register(&imx2_wdt_miscdev);
+       if (ret)
+               goto fail;
+
+       dev_info(&pdev->dev,
+               "IMX2+ Watchdog Timer enabled. timeout=%ds (nowayout=%d)\n",
+                                               imx2_wdt.timeout, nowayout);
+       return 0;
+
+fail:
+       imx2_wdt_miscdev.parent = NULL;
+       clk_put(imx2_wdt.clk);
+       return ret;
+}
+
+static int __exit imx2_wdt_remove(struct platform_device *pdev)
+{
+       misc_deregister(&imx2_wdt_miscdev);
+
+       if (test_bit(IMX2_WDT_STATUS_STARTED, &imx2_wdt.status)) {
+               del_timer_sync(&imx2_wdt.timer);
+
+               dev_crit(imx2_wdt_miscdev.parent,
+                       "Device removed: Expect reboot!\n");
+       } else
+               clk_put(imx2_wdt.clk);
+
+       imx2_wdt_miscdev.parent = NULL;
+       return 0;
+}
+
+static void imx2_wdt_shutdown(struct platform_device *pdev)
+{
+       if (test_bit(IMX2_WDT_STATUS_STARTED, &imx2_wdt.status)) {
+               /* we are running, we need to delete the timer but will give
+                * max timeout before reboot will take place */
+               del_timer_sync(&imx2_wdt.timer);
+               imx2_wdt_set_timeout(IMX2_WDT_MAX_TIME);
+               imx2_wdt_ping();
+
+               dev_crit(imx2_wdt_miscdev.parent,
+                       "Device shutdown: Expect reboot!\n");
+       }
+}
+
+static struct platform_driver imx2_wdt_driver = {
+       .probe          = imx2_wdt_probe,
+       .remove         = __exit_p(imx2_wdt_remove),
+       .shutdown       = imx2_wdt_shutdown,
+       .driver         = {
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init imx2_wdt_init(void)
+{
+       return platform_driver_probe(&imx2_wdt_driver, imx2_wdt_probe);
+}
+module_init(imx2_wdt_init);
+
+static void __exit imx2_wdt_exit(void)
+{
+       platform_driver_unregister(&imx2_wdt_driver);
+}
+module_exit(imx2_wdt_exit);
+
+MODULE_AUTHOR("Wolfram Sang");
+MODULE_DESCRIPTION("Watchdog driver for IMX2 and later");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_ALIAS("platform:" DRIVER_NAME);
index 4e3941c5e29330e1685f63105e962ab1745fc33e..6622335773bbc53fd2f0c3aa90b986d6b2dca0ea 100644 (file)
@@ -53,7 +53,7 @@ static int mpc8xxx_wdt_init_late(void);
 static u16 timeout = 0xffff;
 module_param(timeout, ushort, 0);
 MODULE_PARM_DESC(timeout,
-       "Watchdog timeout in ticks. (0<timeout<65536, default=65535");
+       "Watchdog timeout in ticks. (0<timeout<65536, default=65535)");
 
 static int reset = 1;
 module_param(reset, bool, 0);
@@ -273,12 +273,12 @@ static const struct of_device_id mpc8xxx_wdt_match[] = {
 MODULE_DEVICE_TABLE(of, mpc8xxx_wdt_match);
 
 static struct of_platform_driver mpc8xxx_wdt_driver = {
-       .match_table    = mpc8xxx_wdt_match,
        .probe          = mpc8xxx_wdt_probe,
        .remove         = __devexit_p(mpc8xxx_wdt_remove),
-       .driver         = {
-               .name   = "mpc8xxx_wdt",
-               .owner  = THIS_MODULE,
+       .driver = {
+               .name = "mpc8xxx_wdt",
+               .owner = THIS_MODULE,
+               .of_match_table = mpc8xxx_wdt_match,
        },
 };
 
index d3aa2f1fe61db4152cd51d0202dbc1b7f19dacad..3a56bc3609247f4fbb6e8fe5fffd5bacb2e209d1 100644 (file)
@@ -53,7 +53,9 @@
 #define WDTO                0x11       /* Watchdog timeout register */
 #define WDCFG               0x12       /* Watchdog config register */
 
-static int io = 0x2E;                  /* Address used on Portwell Boards */
+#define IO_DEFAULT     0x2E            /* Address used on Portwell Boards */
+
+static int io = IO_DEFAULT;
 
 static int timeout = DEFAULT_TIMEOUT;  /* timeout value */
 static unsigned long timer_enabled;    /* is the timer enabled? */
@@ -583,12 +585,13 @@ MODULE_LICENSE("GPL");
 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
 
 module_param(io, int, 0);
-MODULE_PARM_DESC(io, MODNAME " I/O port (default: " __MODULE_STRING(io) ").");
+MODULE_PARM_DESC(io, MODNAME " I/O port (default: "
+                                       __MODULE_STRING(IO_DEFAULT) ").");
 
 module_param(timeout, int, 0);
 MODULE_PARM_DESC(timeout,
                "Watchdog timeout in minutes (default="
-                               __MODULE_STRING(timeout) ").");
+                               __MODULE_STRING(DEFAULT_TIMEOUT) ").");
 
 module_param(nowayout, int, 0);
 MODULE_PARM_DESC(nowayout,
index 09102f09e681607189cd385c63f25bf65b3df286..a7b5ad2a98bd4208466d82f70a1681bdca70e298 100644 (file)
@@ -33,6 +33,8 @@
 #define PFX "pnx833x: "
 #define WATCHDOG_TIMEOUT 30            /* 30 sec Maximum timeout */
 #define WATCHDOG_COUNT_FREQUENCY 68000000U /* Watchdog counts at 68MHZ. */
+#define        PNX_WATCHDOG_TIMEOUT    (WATCHDOG_TIMEOUT * WATCHDOG_COUNT_FREQUENCY)
+#define PNX_TIMEOUT_VALUE      2040000000U
 
 /** CONFIG block */
 #define PNX833X_CONFIG                      (0x07000U)
 static int pnx833x_wdt_alive;
 
 /* Set default timeout in MHZ.*/
-static int pnx833x_wdt_timeout = (WATCHDOG_TIMEOUT * WATCHDOG_COUNT_FREQUENCY);
+static int pnx833x_wdt_timeout = PNX_WATCHDOG_TIMEOUT;
 module_param(pnx833x_wdt_timeout, int, 0);
 MODULE_PARM_DESC(timeout, "Watchdog timeout in Mhz. (68Mhz clock), default="
-                       __MODULE_STRING(pnx833x_wdt_timeout) "(30 seconds).");
+                       __MODULE_STRING(PNX_TIMEOUT_VALUE) "(30 seconds).");
 
 static int nowayout = WATCHDOG_NOWAYOUT;
 module_param(nowayout, int, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
                                        __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
-static int start_enabled = 1;
+#define START_DEFAULT  1
+static int start_enabled = START_DEFAULT;
 module_param(start_enabled, int, 0);
 MODULE_PARM_DESC(start_enabled, "Watchdog is started on module insertion "
-                               "(default=" __MODULE_STRING(start_enabled) ")");
+                               "(default=" __MODULE_STRING(START_DEFAULT) ")");
 
 static void pnx833x_wdt_start(void)
 {
index ea7f803f624862f973a024737d9e49ef039202a0..5dceeddc88596c833add1e6abc2ec5db65048279 100644 (file)
@@ -239,8 +239,11 @@ static const struct of_device_id riowd_match[] = {
 MODULE_DEVICE_TABLE(of, riowd_match);
 
 static struct of_platform_driver riowd_driver = {
-       .name           = DRIVER_NAME,
-       .match_table    = riowd_match,
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = riowd_match,
+       },
        .probe          = riowd_probe,
        .remove         = __devexit_p(riowd_remove),
 };
index e4cebef55177f62e3067e0b2a7195f76ee03d725..300932580ded93e26e38f3dfaa1c0583d0b89976 100644 (file)
@@ -63,7 +63,7 @@ module_param(nowayout,    int, 0);
 module_param(soft_noboot, int, 0);
 module_param(debug,      int, 0);
 
-MODULE_PARM_DESC(tmr_margin, "Watchdog tmr_margin in seconds. default="
+MODULE_PARM_DESC(tmr_margin, "Watchdog tmr_margin in seconds. (default="
                __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME) ")");
 MODULE_PARM_DESC(tmr_atboot,
                "Watchdog is started at boot time if set to 1, default="
@@ -71,8 +71,8 @@ MODULE_PARM_DESC(tmr_atboot,
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
                        __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, "
-                       "0 to reboot (default depends on ONLY_TESTING)");
-MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug, (default 0)");
+                       "0 to reboot (default 0)");
+MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug (default 0)");
 
 static unsigned long open_lock;
 static struct device    *wdt_dev;      /* platform device attached to */
@@ -426,8 +426,7 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev)
        wdt_mem = request_mem_region(res->start, size, pdev->name);
        if (wdt_mem == NULL) {
                dev_err(dev, "failed to get memory region\n");
-               ret = -ENOENT;
-               goto err_req;
+               return -EBUSY;
        }
 
        wdt_base = ioremap(res->start, size);
index a03f84e5ee1ffb9c0d7092b79a8fb333d7da4ac9..6fc74065abee9bef283fc0da35e870f707d38a33 100644 (file)
@@ -496,7 +496,7 @@ MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
 module_param(clock_division_ratio, int, 0);
 MODULE_PARM_DESC(clock_division_ratio,
        "Clock division ratio. Valid ranges are from 0x5 (1.31ms) "
-       "to 0x7 (5.25ms). (default=" __MODULE_STRING(clock_division_ratio) ")");
+       "to 0x7 (5.25ms). (default=" __MODULE_STRING(WTCSR_CKS_4096) ")");
 
 module_param(heartbeat, int, 0);
 MODULE_PARM_DESC(heartbeat,
index dcabe77ad14128384b26722fa1e57a7e0d5fe22a..b5045ca7e61ccd03c3fa631026f27fe4ddc72e4f 100644 (file)
@@ -190,6 +190,8 @@ static int __devinit twl4030_wdt_probe(struct platform_device *pdev)
 
        twl4030_wdt_dev = pdev;
 
+       twl4030_wdt_disable(wdt);
+
        ret = misc_register(&wdt->miscdev);
        if (ret) {
                dev_err(wdt->miscdev.parent,
index bfda2e99dd8908ffeb0d23e24c3b12dc92f682c8..552a4381e78f83037b7a0eb100fbab304bf42de0 100644 (file)
@@ -91,7 +91,7 @@ MODULE_PARM_DESC(tachometer,
 static int type = 500;
 module_param(type, int, 0);
 MODULE_PARM_DESC(type,
-               "WDT501-P Card type (500 or 501 , default=500)");
+               "WDT501-P Card type (500 or 501, default=500)");
 
 /*
  *     Programming support
index 90ef70eb47d74fe38f2812bd171239fe5d643de9..5c2521fc836c3fa7c7829d3ad63fe5de5ebcdbe0 100644 (file)
@@ -63,7 +63,7 @@ static        char expect_close;
 static DEFINE_SPINLOCK(spinlock);
 
 module_param(timeout, int, 0);
-MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (60..15300), default="
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (60..15300, default="
                                __MODULE_STRING(DEFAULT_TIMEOUT) ")");
 module_param(testmode, int, 0);
 MODULE_PARM_DESC(testmode, "Watchdog testmode (1 = no reboot), default=0");
index 8943b8ccee1a2ba3c35ac8eabfc14bd716fb136c..07e857b0de13958e974181ff76f9da11e1af7c7e 100644 (file)
@@ -185,6 +185,7 @@ static void shutdown_handler(struct xenbus_watch *watch,
        kfree(str);
 }
 
+#ifdef CONFIG_MAGIC_SYSRQ
 static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
                          unsigned int len)
 {
@@ -214,15 +215,16 @@ static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
                handle_sysrq(sysrq_key, NULL);
 }
 
-static struct xenbus_watch shutdown_watch = {
-       .node = "control/shutdown",
-       .callback = shutdown_handler
-};
-
 static struct xenbus_watch sysrq_watch = {
        .node = "control/sysrq",
        .callback = sysrq_handler
 };
+#endif
+
+static struct xenbus_watch shutdown_watch = {
+       .node = "control/shutdown",
+       .callback = shutdown_handler
+};
 
 static int setup_shutdown_watcher(void)
 {
@@ -234,11 +236,13 @@ static int setup_shutdown_watcher(void)
                return err;
        }
 
+#ifdef CONFIG_MAGIC_SYSRQ
        err = register_xenbus_watch(&sysrq_watch);
        if (err) {
                printk(KERN_ERR "Failed to set sysrq watcher\n");
                return err;
        }
+#endif
 
        return 0;
 }
index ed835836e0dc35f9eab51e2a86d611d8c5d6808f..32ef4009d030063328d9811a9bcaf7daaf5e762d 100644 (file)
@@ -40,7 +40,9 @@
 extern struct file_system_type v9fs_fs_type;
 extern const struct address_space_operations v9fs_addr_operations;
 extern const struct file_operations v9fs_file_operations;
+extern const struct file_operations v9fs_file_operations_dotl;
 extern const struct file_operations v9fs_dir_operations;
+extern const struct file_operations v9fs_dir_operations_dotl;
 extern const struct dentry_operations v9fs_dentry_operations;
 extern const struct dentry_operations v9fs_cached_dentry_operations;
 
index 0adfd64dfcee88117a93aa9d2a0547cb6852d6e4..d61e3b28ce37a09caca5b5c40214b0e1ec109b22 100644 (file)
@@ -203,3 +203,11 @@ const struct file_operations v9fs_dir_operations = {
        .open = v9fs_file_open,
        .release = v9fs_dir_release,
 };
+
+const struct file_operations v9fs_dir_operations_dotl = {
+       .read = generic_read_dir,
+       .llseek = generic_file_llseek,
+       .readdir = v9fs_dir_readdir,
+       .open = v9fs_file_open,
+       .release = v9fs_dir_release,
+};
index df52d488d2a697ad917e53ee96428c7c2714ae98..2bedc6c94fc2c805f407e4fb5ad7970e36f27a83 100644 (file)
@@ -257,15 +257,13 @@ v9fs_file_write(struct file *filp, const char __user * data,
        return total;
 }
 
-static int v9fs_file_fsync(struct file *filp, struct dentry *dentry,
-                                       int datasync)
+static int v9fs_file_fsync(struct file *filp, int datasync)
 {
        struct p9_fid *fid;
        struct p9_wstat wstat;
        int retval;
 
-       P9_DPRINTK(P9_DEBUG_VFS, "filp %p dentry %p datasync %x\n", filp,
-                                               dentry, datasync);
+       P9_DPRINTK(P9_DEBUG_VFS, "filp %p datasync %x\n", filp, datasync);
 
        fid = filp->private_data;
        v9fs_blank_wstat(&wstat);
@@ -296,3 +294,14 @@ const struct file_operations v9fs_file_operations = {
        .mmap = generic_file_readonly_mmap,
        .fsync = v9fs_file_fsync,
 };
+
+const struct file_operations v9fs_file_operations_dotl = {
+       .llseek = generic_file_llseek,
+       .read = v9fs_file_read,
+       .write = v9fs_file_write,
+       .open = v9fs_file_open,
+       .release = v9fs_dir_release,
+       .lock = v9fs_file_lock,
+       .mmap = generic_file_readonly_mmap,
+       .fsync = v9fs_file_fsync,
+};
index f2434fc9d2c44f620e2e579a19318321e12d6e71..4331b3b5ee1c978a8a7b4b719ed6da14ede32cff 100644 (file)
 #include "cache.h"
 
 static const struct inode_operations v9fs_dir_inode_operations;
-static const struct inode_operations v9fs_dir_inode_operations_ext;
+static const struct inode_operations v9fs_dir_inode_operations_dotu;
+static const struct inode_operations v9fs_dir_inode_operations_dotl;
 static const struct inode_operations v9fs_file_inode_operations;
+static const struct inode_operations v9fs_file_inode_operations_dotl;
 static const struct inode_operations v9fs_symlink_inode_operations;
+static const struct inode_operations v9fs_symlink_inode_operations_dotl;
 
 /**
  * unixmode2p9mode - convert unix mode bits to plan 9
@@ -253,9 +256,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
                return ERR_PTR(-ENOMEM);
        }
 
-       inode->i_mode = mode;
-       inode->i_uid = current_fsuid();
-       inode->i_gid = current_fsgid();
+       inode_init_owner(inode, NULL, mode);
        inode->i_blocks = 0;
        inode->i_rdev = 0;
        inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
@@ -275,25 +276,44 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
                init_special_inode(inode, inode->i_mode, inode->i_rdev);
                break;
        case S_IFREG:
-               inode->i_op = &v9fs_file_inode_operations;
-               inode->i_fop = &v9fs_file_operations;
+               if (v9fs_proto_dotl(v9ses)) {
+                       inode->i_op = &v9fs_file_inode_operations_dotl;
+                       inode->i_fop = &v9fs_file_operations_dotl;
+               } else {
+                       inode->i_op = &v9fs_file_inode_operations;
+                       inode->i_fop = &v9fs_file_operations;
+               }
+
                break;
+
        case S_IFLNK:
-               if (!v9fs_proto_dotu(v9ses)) {
-                       P9_DPRINTK(P9_DEBUG_ERROR,
-                                  "extended modes used w/o 9P2000.u\n");
+               if (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses)) {
+                       P9_DPRINTK(P9_DEBUG_ERROR, "extended modes used with "
+                                               "legacy protocol.\n");
                        err = -EINVAL;
                        goto error;
                }
-               inode->i_op = &v9fs_symlink_inode_operations;
+
+               if (v9fs_proto_dotl(v9ses))
+                       inode->i_op = &v9fs_symlink_inode_operations_dotl;
+               else
+                       inode->i_op = &v9fs_symlink_inode_operations;
+
                break;
        case S_IFDIR:
                inc_nlink(inode);
-               if (v9fs_proto_dotu(v9ses))
-                       inode->i_op = &v9fs_dir_inode_operations_ext;
+               if (v9fs_proto_dotl(v9ses))
+                       inode->i_op = &v9fs_dir_inode_operations_dotl;
+               else if (v9fs_proto_dotu(v9ses))
+                       inode->i_op = &v9fs_dir_inode_operations_dotu;
                else
                        inode->i_op = &v9fs_dir_inode_operations;
-               inode->i_fop = &v9fs_dir_operations;
+
+               if (v9fs_proto_dotl(v9ses))
+                       inode->i_fop = &v9fs_dir_operations_dotl;
+               else
+                       inode->i_fop = &v9fs_dir_operations;
+
                break;
        default:
                P9_DPRINTK(P9_DEBUG_ERROR, "BAD mode 0x%x S_IFMT 0x%x\n",
@@ -434,14 +454,12 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
 {
        int retval;
        struct inode *file_inode;
-       struct v9fs_session_info *v9ses;
        struct p9_fid *v9fid;
 
        P9_DPRINTK(P9_DEBUG_VFS, "inode: %p dentry: %p rmdir: %d\n", dir, file,
                rmdir);
 
        file_inode = file->d_inode;
-       v9ses = v9fs_inode2v9ses(file_inode);
        v9fid = v9fs_fid_clone(file);
        if (IS_ERR(v9fid))
                return PTR_ERR(v9fid);
@@ -484,12 +502,11 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
        ofid = NULL;
        fid = NULL;
        name = (char *) dentry->d_name.name;
-       dfid = v9fs_fid_clone(dentry->d_parent);
+       dfid = v9fs_fid_lookup(dentry->d_parent);
        if (IS_ERR(dfid)) {
                err = PTR_ERR(dfid);
-               P9_DPRINTK(P9_DEBUG_VFS, "fid clone failed %d\n", err);
-               dfid = NULL;
-               goto error;
+               P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
+               return ERR_PTR(err);
        }
 
        /* clone a fid to use for creation */
@@ -497,8 +514,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
        if (IS_ERR(ofid)) {
                err = PTR_ERR(ofid);
                P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
-               ofid = NULL;
-               goto error;
+               return ERR_PTR(err);
        }
 
        err = p9_client_fcreate(ofid, name, perm, mode, extension);
@@ -508,14 +524,13 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
        }
 
        /* now walk from the parent so we can get unopened fid */
-       fid = p9_client_walk(dfid, 1, &name, 0);
+       fid = p9_client_walk(dfid, 1, &name, 1);
        if (IS_ERR(fid)) {
                err = PTR_ERR(fid);
                P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
                fid = NULL;
                goto error;
-       } else
-               dfid = NULL;
+       }
 
        /* instantiate inode and assign the unopened fid to the dentry */
        inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
@@ -538,9 +553,6 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
        return ofid;
 
 error:
-       if (dfid)
-               p9_client_clunk(dfid);
-
        if (ofid)
                p9_client_clunk(ofid);
 
@@ -675,8 +687,8 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
        if (IS_ERR(fid)) {
                result = PTR_ERR(fid);
                if (result == -ENOENT) {
-                       d_add(dentry, NULL);
-                       return NULL;
+                       inode = NULL;
+                       goto inst_out;
                }
 
                return ERR_PTR(result);
@@ -693,7 +705,8 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
        if (result < 0)
                goto error;
 
-       if ((fid->qid.version) && (v9ses->cache))
+inst_out:
+       if (v9ses->cache)
                dentry->d_op = &v9fs_cached_dentry_operations;
        else
                dentry->d_op = &v9fs_dentry_operations;
@@ -772,6 +785,13 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                goto clunk_olddir;
        }
 
+       if (v9fs_proto_dotl(v9ses)) {
+               retval = p9_client_rename(oldfid, newdirfid,
+                                       (char *) new_dentry->d_name.name);
+               if (retval != -ENOSYS)
+                       goto clunk_newdir;
+       }
+
        /* 9P can only handle file rename in the same directory */
        if (memcmp(&olddirfid->qid, &newdirfid->qid, sizeof(newdirfid->qid))) {
                P9_DPRINTK(P9_DEBUG_ERROR,
@@ -1197,6 +1217,8 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
                sprintf(name, "c %u %u", MAJOR(rdev), MINOR(rdev));
        else if (S_ISFIFO(mode))
                *name = 0;
+       else if (S_ISSOCK(mode))
+               *name = 0;
        else {
                __putname(name);
                return -EINVAL;
@@ -1208,7 +1230,21 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
        return retval;
 }
 
-static const struct inode_operations v9fs_dir_inode_operations_ext = {
+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,
+       .unlink = v9fs_vfs_unlink,
+       .mkdir = v9fs_vfs_mkdir,
+       .rmdir = v9fs_vfs_rmdir,
+       .mknod = v9fs_vfs_mknod,
+       .rename = v9fs_vfs_rename,
+       .getattr = v9fs_vfs_getattr,
+       .setattr = v9fs_vfs_setattr,
+};
+
+static const struct inode_operations v9fs_dir_inode_operations_dotl = {
        .create = v9fs_vfs_create,
        .lookup = v9fs_vfs_lookup,
        .symlink = v9fs_vfs_symlink,
@@ -1239,6 +1275,11 @@ static const struct inode_operations v9fs_file_inode_operations = {
        .setattr = v9fs_vfs_setattr,
 };
 
+static const struct inode_operations v9fs_file_inode_operations_dotl = {
+       .getattr = v9fs_vfs_getattr,
+       .setattr = v9fs_vfs_setattr,
+};
+
 static const struct inode_operations v9fs_symlink_inode_operations = {
        .readlink = generic_readlink,
        .follow_link = v9fs_vfs_follow_link,
@@ -1246,3 +1287,11 @@ static const struct inode_operations v9fs_symlink_inode_operations = {
        .getattr = v9fs_vfs_getattr,
        .setattr = v9fs_vfs_setattr,
 };
+
+static const struct inode_operations v9fs_symlink_inode_operations_dotl = {
+       .readlink = generic_readlink,
+       .follow_link = v9fs_vfs_follow_link,
+       .put_link = v9fs_vfs_put_link,
+       .getattr = v9fs_vfs_getattr,
+       .setattr = v9fs_vfs_setattr,
+};
index 806da5d3b3a0803ee572eab76af384c772dba18d..be74d020436e2d7badad70f6e89e430d12f9d6e8 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/idr.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/statfs.h>
 #include <net/9p/9p.h>
 #include <net/9p/client.h>
 
@@ -45,7 +46,7 @@
 #include "v9fs_vfs.h"
 #include "fid.h"
 
-static const struct super_operations v9fs_super_ops;
+static const struct super_operations v9fs_super_ops, v9fs_super_ops_dotl;
 
 /**
  * v9fs_set_super - set the superblock
@@ -76,7 +77,10 @@ v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses,
        sb->s_blocksize_bits = fls(v9ses->maxdata - 1);
        sb->s_blocksize = 1 << sb->s_blocksize_bits;
        sb->s_magic = V9FS_MAGIC;
-       sb->s_op = &v9fs_super_ops;
+       if (v9fs_proto_dotl(v9ses))
+               sb->s_op = &v9fs_super_ops_dotl;
+       else
+               sb->s_op = &v9fs_super_ops;
        sb->s_bdi = &v9ses->bdi;
 
        sb->s_flags = flags | MS_ACTIVE | MS_SYNCHRONOUS | MS_DIRSYNC |
@@ -211,6 +215,42 @@ v9fs_umount_begin(struct super_block *sb)
        v9fs_session_begin_cancel(v9ses);
 }
 
+static int v9fs_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+       struct v9fs_session_info *v9ses;
+       struct p9_fid *fid;
+       struct p9_rstatfs rs;
+       int res;
+
+       fid = v9fs_fid_lookup(dentry);
+       if (IS_ERR(fid)) {
+               res = PTR_ERR(fid);
+               goto done;
+       }
+
+       v9ses = v9fs_inode2v9ses(dentry->d_inode);
+       if (v9fs_proto_dotl(v9ses)) {
+               res = p9_client_statfs(fid, &rs);
+               if (res == 0) {
+                       buf->f_type = rs.type;
+                       buf->f_bsize = rs.bsize;
+                       buf->f_blocks = rs.blocks;
+                       buf->f_bfree = rs.bfree;
+                       buf->f_bavail = rs.bavail;
+                       buf->f_files = rs.files;
+                       buf->f_ffree = rs.ffree;
+                       buf->f_fsid.val[0] = rs.fsid & 0xFFFFFFFFUL;
+                       buf->f_fsid.val[1] = (rs.fsid >> 32) & 0xFFFFFFFFUL;
+                       buf->f_namelen = rs.namelen;
+               }
+               if (res != -ENOSYS)
+                       goto done;
+       }
+       res = simple_statfs(dentry, buf);
+done:
+       return res;
+}
+
 static const struct super_operations v9fs_super_ops = {
 #ifdef CONFIG_9P_FSCACHE
        .alloc_inode = v9fs_alloc_inode,
@@ -222,6 +262,17 @@ static const struct super_operations v9fs_super_ops = {
        .umount_begin = v9fs_umount_begin,
 };
 
+static const struct super_operations v9fs_super_ops_dotl = {
+#ifdef CONFIG_9P_FSCACHE
+       .alloc_inode = v9fs_alloc_inode,
+       .destroy_inode = v9fs_destroy_inode,
+#endif
+       .statfs = v9fs_statfs,
+       .clear_inode = v9fs_clear_inode,
+       .show_options = generic_show_options,
+       .umount_begin = v9fs_umount_begin,
+};
+
 struct file_system_type v9fs_fs_type = {
        .name = "9p",
        .get_sb = v9fs_get_sb,
index 97f340f14ba2d7a181e0788a404ed3698a382ed9..e6ec1d309b1d2ba43dd3e036a9f8dcfba9a757a1 100644 (file)
@@ -11,7 +11,7 @@ obj-y :=      open.o read_write.o file_table.o super.o \
                attr.o bad_inode.o file.o filesystems.o namespace.o \
                seq_file.o xattr.o libfs.o fs-writeback.o \
                pnode.o drop_caches.o splice.o sync.o utimes.o \
-               stack.o fs_struct.o
+               stack.o fs_struct.o statfs.o
 
 ifeq ($(CONFIG_BLOCK),y)
 obj-y +=       buffer.o bio.o block_dev.o direct-io.o mpage.o ioprio.o
index 23aa52f548a068d8c23f00a8cbc10293975924ee..f4287e4de744093d8f71d10a1e443057befe6e22 100644 (file)
@@ -197,7 +197,7 @@ const struct file_operations adfs_dir_operations = {
        .read           = generic_read_dir,
        .llseek         = generic_file_llseek,
        .readdir        = adfs_readdir,
-       .fsync          = simple_fsync,
+       .fsync          = generic_file_fsync,
 };
 
 static int
index 005ea34d1758d12e07bb64d0f4a82f5974e566ff..a36da5382b40dc9c09ab6aa59762d9c1a7808b72 100644 (file)
@@ -26,7 +26,7 @@ const struct file_operations adfs_file_operations = {
        .read           = do_sync_read,
        .aio_read       = generic_file_aio_read,
        .mmap           = generic_file_mmap,
-       .fsync          = simple_fsync,
+       .fsync          = generic_file_fsync,
        .write          = do_sync_write,
        .aio_write      = generic_file_aio_write,
        .splice_read    = generic_file_splice_read,
index 0f5e309781355cf8244f67033585451c553c2b68..6f850b06ab625e7e106a6c149f7449c223407665 100644 (file)
@@ -322,8 +322,9 @@ adfs_notify_change(struct dentry *dentry, struct iattr *attr)
        if (error)
                goto out;
 
+       /* XXX: this is missing some actual on-disk truncation.. */
        if (ia_valid & ATTR_SIZE)
-               error = vmtruncate(inode, attr->ia_size);
+               error = simple_setsize(inode, attr->ia_size);
 
        if (error)
                goto out;
index 861dae68ac12f0b5ea5861e87997ecb78dc97202..f05b6155ccc8fa045983ab5ef89b7a4b1c926fd1 100644 (file)
@@ -183,7 +183,7 @@ extern int                   affs_add_entry(struct inode *dir, struct inode *inode, struct dent
 
 void           affs_free_prealloc(struct inode *inode);
 extern void    affs_truncate(struct inode *);
-int            affs_file_fsync(struct file *, struct dentry *, int);
+int            affs_file_fsync(struct file *, int);
 
 /* dir.c */
 
index 184e55c1c9ba4ec374752c5cf034ad80ac18c351..322710c3eedf25c35ca4ca5888e4c2ab96bed728 100644 (file)
@@ -916,9 +916,9 @@ affs_truncate(struct inode *inode)
        affs_free_prealloc(inode);
 }
 
-int affs_file_fsync(struct file *filp, struct dentry *dentry, int datasync)
+int affs_file_fsync(struct file *filp, int datasync)
 {
-       struct inode * inode = dentry->d_inode;
+       struct inode *inode = filp->f_mapping->host;
        int ret, err;
 
        ret = write_inode_now(inode, 0);
index d70bbbac6b7be31709f407f081672d0d6893fda5..914d1c0bc07a0e3928cb71a0d65bff35d96e0310 100644 (file)
@@ -224,7 +224,7 @@ affs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
                affs_brelse(bh);
                inode = affs_iget(sb, ino);
                if (IS_ERR(inode))
-                       return ERR_PTR(PTR_ERR(inode));
+                       return ERR_CAST(inode);
        }
        dentry->d_op = AFFS_SB(sb)->s_flags & SF_INTL ? &affs_intl_dentry_operations : &affs_dentry_operations;
        d_add(dentry, inode);
index adc1cb771b57ef6be60bee4b90c5da577d0faaa4..b42d5cc1d6d21aace96eaae96fe3aa521822c7c9 100644 (file)
@@ -189,13 +189,9 @@ static struct page *afs_dir_get_page(struct inode *dir, unsigned long index,
                                     struct key *key)
 {
        struct page *page;
-       struct file file = {
-               .private_data = key,
-       };
-
        _enter("{%lu},%lu", dir->i_ino, index);
 
-       page = read_mapping_page(dir->i_mapping, index, &file);
+       page = read_cache_page(dir->i_mapping, index, afs_page_filler, key);
        if (!IS_ERR(page)) {
                kmap(page);
                if (!PageChecked(page))
index 0df9bc2b724d86c1b310d0a987c15132dbf980e8..14d89fa58feec61d52cb8afe572883647c62a997 100644 (file)
@@ -121,34 +121,19 @@ static void afs_file_readpage_read_complete(struct page *page,
 #endif
 
 /*
- * AFS read page from file, directory or symlink
+ * read page from file, directory or symlink, given a key to use
  */
-static int afs_readpage(struct file *file, struct page *page)
+int afs_page_filler(void *data, struct page *page)
 {
-       struct afs_vnode *vnode;
-       struct inode *inode;
-       struct key *key;
+       struct inode *inode = page->mapping->host;
+       struct afs_vnode *vnode = AFS_FS_I(inode);
+       struct key *key = data;
        size_t len;
        off_t offset;
        int ret;
 
-       inode = page->mapping->host;
-
-       if (file) {
-               key = file->private_data;
-               ASSERT(key != NULL);
-       } else {
-               key = afs_request_key(AFS_FS_S(inode->i_sb)->volume->cell);
-               if (IS_ERR(key)) {
-                       ret = PTR_ERR(key);
-                       goto error_nokey;
-               }
-       }
-
        _enter("{%x},{%lu},{%lu}", key_serial(key), inode->i_ino, page->index);
 
-       vnode = AFS_FS_I(inode);
-
        BUG_ON(!PageLocked(page));
 
        ret = -ESTALE;
@@ -214,31 +199,56 @@ static int afs_readpage(struct file *file, struct page *page)
                unlock_page(page);
        }
 
-       if (!file)
-               key_put(key);
        _leave(" = 0");
        return 0;
 
 error:
        SetPageError(page);
        unlock_page(page);
-       if (!file)
-               key_put(key);
-error_nokey:
        _leave(" = %d", ret);
        return ret;
 }
 
+/*
+ * read page from file, directory or symlink, given a file to nominate the key
+ * to be used
+ */
+static int afs_readpage(struct file *file, struct page *page)
+{
+       struct key *key;
+       int ret;
+
+       if (file) {
+               key = file->private_data;
+               ASSERT(key != NULL);
+               ret = afs_page_filler(key, page);
+       } else {
+               struct inode *inode = page->mapping->host;
+               key = afs_request_key(AFS_FS_S(inode->i_sb)->volume->cell);
+               if (IS_ERR(key)) {
+                       ret = PTR_ERR(key);
+               } else {
+                       ret = afs_page_filler(key, page);
+                       key_put(key);
+               }
+       }
+       return ret;
+}
+
 /*
  * read a set of pages
  */
 static int afs_readpages(struct file *file, struct address_space *mapping,
                         struct list_head *pages, unsigned nr_pages)
 {
+       struct key *key = file->private_data;
        struct afs_vnode *vnode;
        int ret = 0;
 
-       _enter(",{%lu},,%d", mapping->host->i_ino, nr_pages);
+       _enter("{%d},{%lu},,%d",
+              key_serial(key), mapping->host->i_ino, nr_pages);
+
+       ASSERT(key != NULL);
 
        vnode = AFS_FS_I(mapping->host);
        if (vnode->flags & AFS_VNODE_DELETED) {
@@ -279,7 +289,7 @@ static int afs_readpages(struct file *file, struct address_space *mapping,
        }
 
        /* load the missing pages from the network */
-       ret = read_cache_pages(mapping, pages, (void *) afs_readpage, file);
+       ret = read_cache_pages(mapping, pages, afs_page_filler, key);
 
        _leave(" = %d [netting]", ret);
        return ret;
index a10f2582844fefd9712e36343e27ec1a513620cc..5f679b77ce24cf581cfab842236ae4e5ed391475 100644 (file)
@@ -494,6 +494,7 @@ extern const struct file_operations afs_file_operations;
 
 extern int afs_open(struct inode *, struct file *);
 extern int afs_release(struct inode *, struct file *);
+extern int afs_page_filler(void *, struct page *);
 
 /*
  * flock.c
@@ -739,7 +740,7 @@ extern void afs_pages_written_back(struct afs_vnode *, struct afs_call *);
 extern ssize_t afs_file_write(struct kiocb *, const struct iovec *,
                              unsigned long, loff_t);
 extern int afs_writeback_all(struct afs_vnode *);
-extern int afs_fsync(struct file *, struct dentry *, int);
+extern int afs_fsync(struct file *, int);
 
 
 /*****************************************************************************/
index b3feddc4f7d649d240487fac866a21878f4258cd..a9e23039ea34604649156b66cd10dc664ece394a 100644 (file)
@@ -49,9 +49,6 @@ static unsigned long afs_mntpt_expiry_timeout = 10 * 60;
  */
 int afs_mntpt_check_symlink(struct afs_vnode *vnode, struct key *key)
 {
-       struct file file = {
-               .private_data = key,
-       };
        struct page *page;
        size_t size;
        char *buf;
@@ -61,7 +58,8 @@ int afs_mntpt_check_symlink(struct afs_vnode *vnode, struct key *key)
               vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique);
 
        /* read the contents of the symlink into the pagecache */
-       page = read_mapping_page(AFS_VNODE_TO_I(vnode)->i_mapping, 0, &file);
+       page = read_cache_page(AFS_VNODE_TO_I(vnode)->i_mapping, 0,
+                              afs_page_filler, key);
        if (IS_ERR(page)) {
                ret = PTR_ERR(page);
                goto out;
index 3bed54a294d4300e234e9c65b49338aced33c7f2..3dab9e9948d0f39a55a4ddaf22f4524bcb0ffb4a 100644 (file)
@@ -701,8 +701,9 @@ int afs_writeback_all(struct afs_vnode *vnode)
  * - the return status from this call provides a reliable indication of
  *   whether any write errors occurred for this process.
  */
-int afs_fsync(struct file *file, struct dentry *dentry, int datasync)
+int afs_fsync(struct file *file, int datasync)
 {
+       struct dentry *dentry = file->f_path.dentry;
        struct afs_writeback *wb, *xwb;
        struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode);
        int ret;
index 1cf12b3dd83a0654d7c0629786d8ab7fd4388a23..1ccf25cef1f027a61449ed2cf12b56fb077686ea 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -36,6 +36,7 @@
 #include <linux/blkdev.h>
 #include <linux/mempool.h>
 #include <linux/hash.h>
+#include <linux/compat.h>
 
 #include <asm/kmap_types.h>
 #include <asm/uaccess.h>
@@ -526,7 +527,7 @@ static void aio_fput_routine(struct work_struct *data)
 
                /* Complete the fput(s) */
                if (req->ki_filp != NULL)
-                       __fput(req->ki_filp);
+                       fput(req->ki_filp);
 
                /* Link the iocb into the context's free list */
                spin_lock_irq(&ctx->ctx_lock);
@@ -559,11 +560,11 @@ static int __aio_put_req(struct kioctx *ctx, struct kiocb *req)
 
        /*
         * Try to optimize the aio and eventfd file* puts, by avoiding to
-        * schedule work in case it is not __fput() time. In normal cases,
+        * schedule work in case it is not final fput() time. In normal cases,
         * we would not be holding the last reference to the file*, so
         * this function will be executed w/out any aio kthread wakeup.
         */
-       if (unlikely(atomic_long_dec_and_test(&req->ki_filp->f_count))) {
+       if (unlikely(!fput_atomic(req->ki_filp))) {
                get_ioctx(ctx);
                spin_lock(&fput_lock);
                list_add(&req->ki_list, &fput_head);
@@ -1384,13 +1385,22 @@ static ssize_t aio_fsync(struct kiocb *iocb)
        return ret;
 }
 
-static ssize_t aio_setup_vectored_rw(int type, struct kiocb *kiocb)
+static ssize_t aio_setup_vectored_rw(int type, struct kiocb *kiocb, bool compat)
 {
        ssize_t ret;
 
-       ret = rw_copy_check_uvector(type, (struct iovec __user *)kiocb->ki_buf,
-                                   kiocb->ki_nbytes, 1,
-                                   &kiocb->ki_inline_vec, &kiocb->ki_iovec);
+#ifdef CONFIG_COMPAT
+       if (compat)
+               ret = compat_rw_copy_check_uvector(type,
+                               (struct compat_iovec __user *)kiocb->ki_buf,
+                               kiocb->ki_nbytes, 1, &kiocb->ki_inline_vec,
+                               &kiocb->ki_iovec);
+       else
+#endif
+               ret = rw_copy_check_uvector(type,
+                               (struct iovec __user *)kiocb->ki_buf,
+                               kiocb->ki_nbytes, 1, &kiocb->ki_inline_vec,
+                               &kiocb->ki_iovec);
        if (ret < 0)
                goto out;
 
@@ -1420,7 +1430,7 @@ static ssize_t aio_setup_single_vector(struct kiocb *kiocb)
  *     Performs the initial checks and aio retry method
  *     setup for the kiocb at the time of io submission.
  */
-static ssize_t aio_setup_iocb(struct kiocb *kiocb)
+static ssize_t aio_setup_iocb(struct kiocb *kiocb, bool compat)
 {
        struct file *file = kiocb->ki_filp;
        ssize_t ret = 0;
@@ -1469,7 +1479,7 @@ static ssize_t aio_setup_iocb(struct kiocb *kiocb)
                ret = security_file_permission(file, MAY_READ);
                if (unlikely(ret))
                        break;
-               ret = aio_setup_vectored_rw(READ, kiocb);
+               ret = aio_setup_vectored_rw(READ, kiocb, compat);
                if (ret)
                        break;
                ret = -EINVAL;
@@ -1483,7 +1493,7 @@ static ssize_t aio_setup_iocb(struct kiocb *kiocb)
                ret = security_file_permission(file, MAY_WRITE);
                if (unlikely(ret))
                        break;
-               ret = aio_setup_vectored_rw(WRITE, kiocb);
+               ret = aio_setup_vectored_rw(WRITE, kiocb, compat);
                if (ret)
                        break;
                ret = -EINVAL;
@@ -1548,7 +1558,8 @@ static void aio_batch_free(struct hlist_head *batch_hash)
 }
 
 static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
-                        struct iocb *iocb, struct hlist_head *batch_hash)
+                        struct iocb *iocb, struct hlist_head *batch_hash,
+                        bool compat)
 {
        struct kiocb *req;
        struct file *file;
@@ -1609,7 +1620,7 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
        req->ki_left = req->ki_nbytes = iocb->aio_nbytes;
        req->ki_opcode = iocb->aio_lio_opcode;
 
-       ret = aio_setup_iocb(req);
+       ret = aio_setup_iocb(req, compat);
 
        if (ret)
                goto out_put_req;
@@ -1637,20 +1648,8 @@ out_put_req:
        return ret;
 }
 
-/* sys_io_submit:
- *     Queue the nr iocbs pointed to by iocbpp for processing.  Returns
- *     the number of iocbs queued.  May return -EINVAL if the aio_context
- *     specified by ctx_id is invalid, if nr is < 0, if the iocb at
- *     *iocbpp[0] is not properly initialized, if the operation specified
- *     is invalid for the file descriptor in the iocb.  May fail with
- *     -EFAULT if any of the data structures point to invalid data.  May
- *     fail with -EBADF if the file descriptor specified in the first
- *     iocb is invalid.  May fail with -EAGAIN if insufficient resources
- *     are available to queue any iocbs.  Will return 0 if nr is 0.  Will
- *     fail with -ENOSYS if not implemented.
- */
-SYSCALL_DEFINE3(io_submit, aio_context_t, ctx_id, long, nr,
-               struct iocb __user * __user *, iocbpp)
+long do_io_submit(aio_context_t ctx_id, long nr,
+                 struct iocb __user *__user *iocbpp, bool compat)
 {
        struct kioctx *ctx;
        long ret = 0;
@@ -1687,7 +1686,7 @@ SYSCALL_DEFINE3(io_submit, aio_context_t, ctx_id, long, nr,
                        break;
                }
 
-               ret = io_submit_one(ctx, user_iocb, &tmp, batch_hash);
+               ret = io_submit_one(ctx, user_iocb, &tmp, batch_hash, compat);
                if (ret)
                        break;
        }
@@ -1697,6 +1696,24 @@ SYSCALL_DEFINE3(io_submit, aio_context_t, ctx_id, long, nr,
        return i ? i : ret;
 }
 
+/* sys_io_submit:
+ *     Queue the nr iocbs pointed to by iocbpp for processing.  Returns
+ *     the number of iocbs queued.  May return -EINVAL if the aio_context
+ *     specified by ctx_id is invalid, if nr is < 0, if the iocb at
+ *     *iocbpp[0] is not properly initialized, if the operation specified
+ *     is invalid for the file descriptor in the iocb.  May fail with
+ *     -EFAULT if any of the data structures point to invalid data.  May
+ *     fail with -EBADF if the file descriptor specified in the first
+ *     iocb is invalid.  May fail with -EAGAIN if insufficient resources
+ *     are available to queue any iocbs.  Will return 0 if nr is 0.  Will
+ *     fail with -ENOSYS if not implemented.
+ */
+SYSCALL_DEFINE3(io_submit, aio_context_t, ctx_id, long, nr,
+               struct iocb __user * __user *, iocbpp)
+{
+       return do_io_submit(ctx_id, nr, iocbpp, 0);
+}
+
 /* lookup_kiocb
  *     Finds a given iocb for cancellation.
  */
index 0815e93bb487e0651619d942b6bd78d7fe6a2e89..b4fa3b0aa59691ac4ca33d30e9afc308d5df98bd 100644 (file)
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -67,14 +67,14 @@ EXPORT_SYMBOL(inode_change_ok);
  * @offset:    the new size to assign to the inode
  * @Returns:   0 on success, -ve errno on failure
  *
+ * inode_newsize_ok must be called with i_mutex held.
+ *
  * inode_newsize_ok will check filesystem limits and ulimits to check that the
  * new inode size is within limits. inode_newsize_ok will also send SIGXFSZ
  * when necessary. Caller must not proceed with inode size change if failure is
  * returned. @inode must be a file (not directory), with appropriate
  * permissions to allow truncate (inode_newsize_ok does NOT check these
  * conditions).
- *
- * inode_newsize_ok must be called with i_mutex held.
  */
 int inode_newsize_ok(const struct inode *inode, loff_t offset)
 {
@@ -104,17 +104,25 @@ out_big:
 }
 EXPORT_SYMBOL(inode_newsize_ok);
 
-int inode_setattr(struct inode * inode, struct iattr * attr)
+/**
+ * generic_setattr - 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.
+ *
+ * generic_setattr 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.
+ *
+ * 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)
 {
        unsigned int ia_valid = attr->ia_valid;
 
-       if (ia_valid & ATTR_SIZE &&
-           attr->ia_size != i_size_read(inode)) {
-               int error = vmtruncate(inode, attr->ia_size);
-               if (error)
-                       return error;
-       }
-
        if (ia_valid & ATTR_UID)
                inode->i_uid = attr->ia_uid;
        if (ia_valid & ATTR_GID)
@@ -135,6 +143,28 @@ int inode_setattr(struct inode * inode, struct iattr * attr)
                        mode &= ~S_ISGID;
                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;
index 8713c7cfbc799efe1fa604df04dcbebe3966f225..9a0520b50663b52f9508eb962bd3fbd92f55baa4 100644 (file)
@@ -28,6 +28,7 @@ static int autofs_root_mkdir(struct inode *,struct dentry *,int);
 static int autofs_root_ioctl(struct inode *, struct file *,unsigned int,unsigned long);
 
 const struct file_operations autofs_root_operations = {
+       .llseek         = generic_file_llseek,
        .read           = generic_read_dir,
        .readdir        = autofs_root_readdir,
        .ioctl          = autofs_root_ioctl,
index d29b7f6df86285d173de7340c7a338d2d75d09fc..ba4a38b9c22ff63d9897ad59c30c1479a0c54fed 100644 (file)
@@ -95,7 +95,7 @@ static int check_dev_ioctl_version(int cmd, struct autofs_dev_ioctl *param)
  */
 static struct autofs_dev_ioctl *copy_dev_ioctl(struct autofs_dev_ioctl __user *in)
 {
-       struct autofs_dev_ioctl tmp, *ads;
+       struct autofs_dev_ioctl tmp;
 
        if (copy_from_user(&tmp, in, sizeof(tmp)))
                return ERR_PTR(-EFAULT);
@@ -103,16 +103,7 @@ static struct autofs_dev_ioctl *copy_dev_ioctl(struct autofs_dev_ioctl __user *i
        if (tmp.size < sizeof(tmp))
                return ERR_PTR(-EINVAL);
 
-       ads = kmalloc(tmp.size, GFP_KERNEL);
-       if (!ads)
-               return ERR_PTR(-ENOMEM);
-
-       if (copy_from_user(ads, in, tmp.size)) {
-               kfree(ads);
-               return ERR_PTR(-EFAULT);
-       }
-
-       return ads;
+       return memdup_user(in, tmp.size);
 }
 
 static inline void free_dev_ioctl(struct autofs_dev_ioctl *param)
@@ -736,11 +727,14 @@ static const struct file_operations _dev_ioctl_fops = {
 };
 
 static struct miscdevice _autofs_dev_ioctl_misc = {
-       .minor          = MISC_DYNAMIC_MINOR,
+       .minor          = AUTOFS_MINOR,
        .name           = AUTOFS_DEVICE_NAME,
        .fops           = &_dev_ioctl_fops
 };
 
+MODULE_ALIAS_MISCDEV(AUTOFS_MINOR);
+MODULE_ALIAS("devname:autofs");
+
 /* Register/deregister misc character device */
 int autofs_dev_ioctl_init(void)
 {
index e8e5e63ac9503b6f42d20681a26fc6565e43641b..db4117ed78031232b2741a5052a2e383e899e457 100644 (file)
 #include <linux/slab.h>
 #include <linux/param.h>
 #include <linux/time.h>
+#include <linux/smp_lock.h>
 #include "autofs_i.h"
 
 static int autofs4_dir_symlink(struct inode *,struct dentry *,const char *);
 static int autofs4_dir_unlink(struct inode *,struct dentry *);
 static int autofs4_dir_rmdir(struct inode *,struct dentry *);
 static int autofs4_dir_mkdir(struct inode *,struct dentry *,int);
-static int autofs4_root_ioctl(struct inode *, struct file *,unsigned int,unsigned long);
+static long autofs4_root_ioctl(struct file *,unsigned int,unsigned long);
 static int autofs4_dir_open(struct inode *inode, struct file *file);
 static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *);
 static void *autofs4_follow_link(struct dentry *, struct nameidata *);
@@ -38,7 +39,7 @@ const struct file_operations autofs4_root_operations = {
        .read           = generic_read_dir,
        .readdir        = dcache_readdir,
        .llseek         = dcache_dir_lseek,
-       .ioctl          = autofs4_root_ioctl,
+       .unlocked_ioctl = autofs4_root_ioctl,
 };
 
 const struct file_operations autofs4_dir_operations = {
@@ -902,8 +903,8 @@ int is_autofs4_dentry(struct dentry *dentry)
  * ioctl()'s on the root directory is the chief method for the daemon to
  * generate kernel reactions
  */
-static int autofs4_root_ioctl(struct inode *inode, struct file *filp,
-                            unsigned int cmd, unsigned long arg)
+static int autofs4_root_ioctl_unlocked(struct inode *inode, struct file *filp,
+                                      unsigned int cmd, unsigned long arg)
 {
        struct autofs_sb_info *sbi = autofs4_sbi(inode->i_sb);
        void __user *p = (void __user *)arg;
@@ -947,3 +948,16 @@ static int autofs4_root_ioctl(struct inode *inode, struct file *filp,
                return -ENOSYS;
        }
 }
+
+static long autofs4_root_ioctl(struct file *filp,
+                              unsigned int cmd, unsigned long arg)
+{
+       long ret;
+       struct inode *inode = filp->f_dentry->d_inode;
+
+       lock_kernel();
+       ret = autofs4_root_ioctl_unlocked(inode, filp, cmd, arg);
+       unlock_kernel();
+
+       return ret;
+}
index a05287a23f62e1d28d66b28dc101b74db3690971..52e59bf4aa5f512f365d509768984fa95b7d62f0 100644 (file)
@@ -93,8 +93,7 @@ static int bad_file_release(struct inode *inode, struct file *filp)
        return -EIO;
 }
 
-static int bad_file_fsync(struct file *file, struct dentry *dentry,
-                       int datasync)
+static int bad_file_fsync(struct file *file, int datasync)
 {
        return -EIO;
 }
index 1e41aadb1068672a1969d6496dce9dd5e930b656..d967e052b779d80490e08e097f5849ddc88ae48d 100644 (file)
@@ -78,7 +78,7 @@ static int bfs_readdir(struct file *f, void *dirent, filldir_t filldir)
 const struct file_operations bfs_dir_operations = {
        .read           = generic_read_dir,
        .readdir        = bfs_readdir,
-       .fsync          = simple_fsync,
+       .fsync          = generic_file_fsync,
        .llseek         = generic_file_llseek,
 };
 
@@ -105,14 +105,12 @@ static int bfs_create(struct inode *dir, struct dentry *dentry, int mode,
        }
        set_bit(ino, info->si_imap);
        info->si_freei--;
-       inode->i_uid = current_fsuid();
-       inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current_fsgid();
+       inode_init_owner(inode, dir, mode);
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
        inode->i_blocks = 0;
        inode->i_op = &bfs_file_inops;
        inode->i_fop = &bfs_file_operations;
        inode->i_mapping->a_ops = &bfs_aops;
-       inode->i_mode = mode;
        inode->i_ino = ino;
        BFS_I(inode)->i_dsk_ino = ino;
        BFS_I(inode)->i_sblock = 0;
index 55dcb7884f4d3824ef641b6ec5daf454e53cd1f3..7346c96308a581546b7f5773fd94d41f9a3c7345 100644 (file)
@@ -172,8 +172,9 @@ 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(rw, iocb, inode, I_BDEV(inode),
-                               iov, offset, nr_segs, blkdev_get_blocks, NULL);
+       return blockdev_direct_IO_no_locking_newtrunc(rw, iocb, inode,
+                               I_BDEV(inode), iov, offset, nr_segs,
+                               blkdev_get_blocks, NULL);
 }
 
 int __sync_blockdev(struct block_device *bdev, int wait)
@@ -245,37 +246,14 @@ struct super_block *freeze_bdev(struct block_device *bdev)
        sb = get_active_super(bdev);
        if (!sb)
                goto out;
-       if (sb->s_flags & MS_RDONLY) {
-               sb->s_frozen = SB_FREEZE_TRANS;
-               up_write(&sb->s_umount);
+       error = freeze_super(sb);
+       if (error) {
+               deactivate_super(sb);
+               bdev->bd_fsfreeze_count--;
                mutex_unlock(&bdev->bd_fsfreeze_mutex);
-               return sb;
-       }
-
-       sb->s_frozen = SB_FREEZE_WRITE;
-       smp_wmb();
-
-       sync_filesystem(sb);
-
-       sb->s_frozen = SB_FREEZE_TRANS;
-       smp_wmb();
-
-       sync_blockdev(sb->s_bdev);
-
-       if (sb->s_op->freeze_fs) {
-               error = sb->s_op->freeze_fs(sb);
-               if (error) {
-                       printk(KERN_ERR
-                               "VFS:Filesystem freeze failed\n");
-                       sb->s_frozen = SB_UNFROZEN;
-                       deactivate_locked_super(sb);
-                       bdev->bd_fsfreeze_count--;
-                       mutex_unlock(&bdev->bd_fsfreeze_mutex);
-                       return ERR_PTR(error);
-               }
+               return ERR_PTR(error);
        }
-       up_write(&sb->s_umount);
-
+       deactivate_super(sb);
  out:
        sync_blockdev(bdev);
        mutex_unlock(&bdev->bd_fsfreeze_mutex);
@@ -296,40 +274,22 @@ int thaw_bdev(struct block_device *bdev, struct super_block *sb)
 
        mutex_lock(&bdev->bd_fsfreeze_mutex);
        if (!bdev->bd_fsfreeze_count)
-               goto out_unlock;
+               goto out;
 
        error = 0;
        if (--bdev->bd_fsfreeze_count > 0)
-               goto out_unlock;
+               goto out;
 
        if (!sb)
-               goto out_unlock;
-
-       BUG_ON(sb->s_bdev != bdev);
-       down_write(&sb->s_umount);
-       if (sb->s_flags & MS_RDONLY)
-               goto out_unfrozen;
-
-       if (sb->s_op->unfreeze_fs) {
-               error = sb->s_op->unfreeze_fs(sb);
-               if (error) {
-                       printk(KERN_ERR
-                               "VFS:Filesystem thaw failed\n");
-                       sb->s_frozen = SB_FREEZE_TRANS;
-                       bdev->bd_fsfreeze_count++;
-                       mutex_unlock(&bdev->bd_fsfreeze_mutex);
-                       return error;
-               }
-       }
-
-out_unfrozen:
-       sb->s_frozen = SB_UNFROZEN;
-       smp_wmb();
-       wake_up(&sb->s_wait_unfrozen);
+               goto out;
 
-       if (sb)
-               deactivate_locked_super(sb);
-out_unlock:
+       error = thaw_super(sb);
+       if (error) {
+               bdev->bd_fsfreeze_count++;
+               mutex_unlock(&bdev->bd_fsfreeze_mutex);
+               return error;
+       }
+out:
        mutex_unlock(&bdev->bd_fsfreeze_mutex);
        return 0;
 }
@@ -350,8 +310,8 @@ static int blkdev_write_begin(struct file *file, struct address_space *mapping,
                        struct page **pagep, void **fsdata)
 {
        *pagep = NULL;
-       return block_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
-                               blkdev_get_block);
+       return block_write_begin_newtrunc(file, mapping, pos, len, flags,
+                               pagep, fsdata, blkdev_get_block);
 }
 
 static int blkdev_write_end(struct file *file, struct address_space *mapping,
@@ -399,12 +359,7 @@ static loff_t block_llseek(struct file *file, loff_t offset, int origin)
        return retval;
 }
        
-/*
- *     Filp is never NULL; the only case when ->fsync() is called with
- *     NULL first argument is nfsd_sync_dir() and that's not a directory.
- */
-int blkdev_fsync(struct file *filp, struct dentry *dentry, int datasync)
+int blkdev_fsync(struct file *filp, int datasync)
 {
        struct inode *bd_inode = filp->f_mapping->host;
        struct block_device *bdev = I_BDEV(bd_inode);
index 6ef7b26724ec6cd964400c1074db9ed5f95289f1..8d432cd9d580d39ed2e94bf3be99c17667a8b0dd 100644 (file)
@@ -282,14 +282,14 @@ int btrfs_acl_chmod(struct inode *inode)
        return ret;
 }
 
-struct xattr_handler btrfs_xattr_acl_default_handler = {
+const struct xattr_handler btrfs_xattr_acl_default_handler = {
        .prefix = POSIX_ACL_XATTR_DEFAULT,
        .flags  = ACL_TYPE_DEFAULT,
        .get    = btrfs_xattr_acl_get,
        .set    = btrfs_xattr_acl_set,
 };
 
-struct xattr_handler btrfs_xattr_acl_access_handler = {
+const struct xattr_handler btrfs_xattr_acl_access_handler = {
        .prefix = POSIX_ACL_XATTR_ACCESS,
        .flags  = ACL_TYPE_ACCESS,
        .get    = btrfs_xattr_acl_get,
index 462859a30141faa7c6ee645ad750cf0ae48c9692..7ec14097fef1f3bbb9b7611a96111c55d0ba9e19 100644 (file)
@@ -377,6 +377,7 @@ again:
                                if (!list_empty(&worker->pending) ||
                                    !list_empty(&worker->prio_pending)) {
                                        spin_unlock_irq(&worker->lock);
+                                       set_current_state(TASK_RUNNING);
                                        goto again;
                                }
 
index 7a4dee19983235660c05679cc615709fa8b2141a..6ad63f17eca0acad289d0dbf972607933bf9fd50 100644 (file)
@@ -137,8 +137,8 @@ struct btrfs_inode {
         * of extent items we've reserved metadata for.
         */
        spinlock_t accounting_lock;
+       atomic_t outstanding_extents;
        int reserved_extents;
-       int outstanding_extents;
 
        /*
         * ordered_data_close is set by truncate when a file that used
@@ -151,6 +151,7 @@ struct btrfs_inode {
         * of these.
         */
        unsigned ordered_data_close:1;
+       unsigned orphan_meta_reserved:1;
        unsigned dummy_inode:1;
 
        /*
index 6795a713b2052bbd7560590dccbba8b33ca6c717..0d1d966b0fe45d20e6ff75f44a6dea64f66eb54e 100644 (file)
@@ -280,7 +280,8 @@ int btrfs_block_can_be_shared(struct btrfs_root *root,
 static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
                                       struct btrfs_root *root,
                                       struct extent_buffer *buf,
-                                      struct extent_buffer *cow)
+                                      struct extent_buffer *cow,
+                                      int *last_ref)
 {
        u64 refs;
        u64 owner;
@@ -366,6 +367,7 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
                        BUG_ON(ret);
                }
                clean_tree_block(trans, root, buf);
+               *last_ref = 1;
        }
        return 0;
 }
@@ -392,6 +394,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
        struct btrfs_disk_key disk_key;
        struct extent_buffer *cow;
        int level;
+       int last_ref = 0;
        int unlock_orig = 0;
        u64 parent_start;
 
@@ -442,7 +445,10 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
                            (unsigned long)btrfs_header_fsid(cow),
                            BTRFS_FSID_SIZE);
 
-       update_ref_for_cow(trans, root, buf, cow);
+       update_ref_for_cow(trans, root, buf, cow, &last_ref);
+
+       if (root->ref_cows)
+               btrfs_reloc_cow_block(trans, root, buf, cow);
 
        if (buf == root->node) {
                WARN_ON(parent && parent != buf);
@@ -457,8 +463,8 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
                extent_buffer_get(cow);
                spin_unlock(&root->node_lock);
 
-               btrfs_free_tree_block(trans, root, buf->start, buf->len,
-                               parent_start, root->root_key.objectid, level);
+               btrfs_free_tree_block(trans, root, buf, parent_start,
+                                     last_ref);
                free_extent_buffer(buf);
                add_root_to_dirty_list(root);
        } else {
@@ -473,8 +479,8 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
                btrfs_set_node_ptr_generation(parent, parent_slot,
                                              trans->transid);
                btrfs_mark_buffer_dirty(parent);
-               btrfs_free_tree_block(trans, root, buf->start, buf->len,
-                               parent_start, root->root_key.objectid, level);
+               btrfs_free_tree_block(trans, root, buf, parent_start,
+                                     last_ref);
        }
        if (unlock_orig)
                btrfs_tree_unlock(buf);
@@ -949,6 +955,22 @@ int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key,
        return bin_search(eb, key, level, slot);
 }
 
+static void root_add_used(struct btrfs_root *root, u32 size)
+{
+       spin_lock(&root->accounting_lock);
+       btrfs_set_root_used(&root->root_item,
+                           btrfs_root_used(&root->root_item) + size);
+       spin_unlock(&root->accounting_lock);
+}
+
+static void root_sub_used(struct btrfs_root *root, u32 size)
+{
+       spin_lock(&root->accounting_lock);
+       btrfs_set_root_used(&root->root_item,
+                           btrfs_root_used(&root->root_item) - size);
+       spin_unlock(&root->accounting_lock);
+}
+
 /* given a node and slot number, this reads the blocks it points to.  The
  * extent buffer is returned with a reference taken (but unlocked).
  * NULL is returned on error.
@@ -1019,7 +1041,11 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
                btrfs_tree_lock(child);
                btrfs_set_lock_blocking(child);
                ret = btrfs_cow_block(trans, root, child, mid, 0, &child);
-               BUG_ON(ret);
+               if (ret) {
+                       btrfs_tree_unlock(child);
+                       free_extent_buffer(child);
+                       goto enospc;
+               }
 
                spin_lock(&root->node_lock);
                root->node = child;
@@ -1034,11 +1060,12 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
                btrfs_tree_unlock(mid);
                /* once for the path */
                free_extent_buffer(mid);
-               ret = btrfs_free_tree_block(trans, root, mid->start, mid->len,
-                                           0, root->root_key.objectid, level);
+
+               root_sub_used(root, mid->len);
+               btrfs_free_tree_block(trans, root, mid, 0, 1);
                /* once for the root ptr */
                free_extent_buffer(mid);
-               return ret;
+               return 0;
        }
        if (btrfs_header_nritems(mid) >
            BTRFS_NODEPTRS_PER_BLOCK(root) / 4)
@@ -1088,23 +1115,16 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
                if (wret < 0 && wret != -ENOSPC)
                        ret = wret;
                if (btrfs_header_nritems(right) == 0) {
-                       u64 bytenr = right->start;
-                       u32 blocksize = right->len;
-
                        clean_tree_block(trans, root, right);
                        btrfs_tree_unlock(right);
-                       free_extent_buffer(right);
-                       right = NULL;
                        wret = del_ptr(trans, root, path, level + 1, pslot +
                                       1);
                        if (wret)
                                ret = wret;
-                       wret = btrfs_free_tree_block(trans, root,
-                                                    bytenr, blocksize, 0,
-                                                    root->root_key.objectid,
-                                                    level);
-                       if (wret)
-                               ret = wret;
+                       root_sub_used(root, right->len);
+                       btrfs_free_tree_block(trans, root, right, 0, 1);
+                       free_extent_buffer(right);
+                       right = NULL;
                } else {
                        struct btrfs_disk_key right_key;
                        btrfs_node_key(right, &right_key, 0);
@@ -1136,21 +1156,15 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
                BUG_ON(wret == 1);
        }
        if (btrfs_header_nritems(mid) == 0) {
-               /* we've managed to empty the middle node, drop it */
-               u64 bytenr = mid->start;
-               u32 blocksize = mid->len;
-
                clean_tree_block(trans, root, mid);
                btrfs_tree_unlock(mid);
-               free_extent_buffer(mid);
-               mid = NULL;
                wret = del_ptr(trans, root, path, level + 1, pslot);
                if (wret)
                        ret = wret;
-               wret = btrfs_free_tree_block(trans, root, bytenr, blocksize,
-                                        0, root->root_key.objectid, level);
-               if (wret)
-                       ret = wret;
+               root_sub_used(root, mid->len);
+               btrfs_free_tree_block(trans, root, mid, 0, 1);
+               free_extent_buffer(mid);
+               mid = NULL;
        } else {
                /* update the parent key to reflect our changes */
                struct btrfs_disk_key mid_key;
@@ -1590,7 +1604,7 @@ read_block_for_search(struct btrfs_trans_handle *trans,
        btrfs_release_path(NULL, p);
 
        ret = -EAGAIN;
-       tmp = read_tree_block(root, blocknr, blocksize, gen);
+       tmp = read_tree_block(root, blocknr, blocksize, 0);
        if (tmp) {
                /*
                 * If the read above didn't mark this buffer up to date,
@@ -1740,7 +1754,6 @@ again:
                                              p->nodes[level + 1],
                                              p->slots[level + 1], &b);
                        if (err) {
-                               free_extent_buffer(b);
                                ret = err;
                                goto done;
                        }
@@ -2076,6 +2089,8 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans,
        if (IS_ERR(c))
                return PTR_ERR(c);
 
+       root_add_used(root, root->nodesize);
+
        memset_extent_buffer(c, 0, 0, sizeof(struct btrfs_header));
        btrfs_set_header_nritems(c, 1);
        btrfs_set_header_level(c, level);
@@ -2134,6 +2149,7 @@ static int insert_ptr(struct btrfs_trans_handle *trans, struct btrfs_root
        int nritems;
 
        BUG_ON(!path->nodes[level]);
+       btrfs_assert_tree_locked(path->nodes[level]);
        lower = path->nodes[level];
        nritems = btrfs_header_nritems(lower);
        BUG_ON(slot > nritems);
@@ -2202,6 +2218,8 @@ static noinline int split_node(struct btrfs_trans_handle *trans,
        if (IS_ERR(split))
                return PTR_ERR(split);
 
+       root_add_used(root, root->nodesize);
+
        memset_extent_buffer(split, 0, 0, sizeof(struct btrfs_header));
        btrfs_set_header_level(split, btrfs_header_level(c));
        btrfs_set_header_bytenr(split, split->start);
@@ -2415,6 +2433,9 @@ static noinline int __push_leaf_right(struct btrfs_trans_handle *trans,
 
        if (left_nritems)
                btrfs_mark_buffer_dirty(left);
+       else
+               clean_tree_block(trans, root, left);
+
        btrfs_mark_buffer_dirty(right);
 
        btrfs_item_key(right, &disk_key, 0);
@@ -2660,6 +2681,8 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,
        btrfs_mark_buffer_dirty(left);
        if (right_nritems)
                btrfs_mark_buffer_dirty(right);
+       else
+               clean_tree_block(trans, root, right);
 
        btrfs_item_key(right, &disk_key, 0);
        wret = fixup_low_keys(trans, root, path, &disk_key, 1);
@@ -2669,8 +2692,6 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,
        /* then fixup the leaf pointer in the path */
        if (path->slots[0] < push_items) {
                path->slots[0] += old_left_nritems;
-               if (btrfs_header_nritems(path->nodes[0]) == 0)
-                       clean_tree_block(trans, root, path->nodes[0]);
                btrfs_tree_unlock(path->nodes[0]);
                free_extent_buffer(path->nodes[0]);
                path->nodes[0] = left;
@@ -2932,10 +2953,10 @@ again:
        right = btrfs_alloc_free_block(trans, root, root->leafsize, 0,
                                        root->root_key.objectid,
                                        &disk_key, 0, l->start, 0);
-       if (IS_ERR(right)) {
-               BUG_ON(1);
+       if (IS_ERR(right))
                return PTR_ERR(right);
-       }
+
+       root_add_used(root, root->leafsize);
 
        memset_extent_buffer(right, 0, 0, sizeof(struct btrfs_header));
        btrfs_set_header_bytenr(right, right->start);
@@ -3054,7 +3075,8 @@ static noinline int setup_leaf_for_split(struct btrfs_trans_handle *trans,
 
        btrfs_set_path_blocking(path);
        ret = split_leaf(trans, root, &key, path, ins_len, 1);
-       BUG_ON(ret);
+       if (ret)
+               goto err;
 
        path->keep_locks = 0;
        btrfs_unlock_up_safe(path, 1);
@@ -3796,9 +3818,10 @@ static noinline int btrfs_del_leaf(struct btrfs_trans_handle *trans,
         */
        btrfs_unlock_up_safe(path, 0);
 
-       ret = btrfs_free_tree_block(trans, root, leaf->start, leaf->len,
-                                   0, root->root_key.objectid, 0);
-       return ret;
+       root_sub_used(root, leaf->len);
+
+       btrfs_free_tree_block(trans, root, leaf, 0, 1);
+       return 0;
 }
 /*
  * delete the item at the leaf level in path.  If that empties
@@ -3865,6 +3888,8 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                if (leaf == root->node) {
                        btrfs_set_header_level(leaf, 0);
                } else {
+                       btrfs_set_path_blocking(path);
+                       clean_tree_block(trans, root, leaf);
                        ret = btrfs_del_leaf(trans, root, path, leaf);
                        BUG_ON(ret);
                }
index 746a7248678ebe3d7396c7bd5746b4ce3b654f80..29c20092847e8afb16575df07ca2c50298d5bc13 100644 (file)
@@ -34,6 +34,7 @@
 
 struct btrfs_trans_handle;
 struct btrfs_transaction;
+struct btrfs_pending_snapshot;
 extern struct kmem_cache *btrfs_trans_handle_cachep;
 extern struct kmem_cache *btrfs_transaction_cachep;
 extern struct kmem_cache *btrfs_bit_radix_cachep;
@@ -663,6 +664,7 @@ struct btrfs_csum_item {
 #define BTRFS_BLOCK_GROUP_RAID1    (1 << 4)
 #define BTRFS_BLOCK_GROUP_DUP     (1 << 5)
 #define BTRFS_BLOCK_GROUP_RAID10   (1 << 6)
+#define BTRFS_NR_RAID_TYPES       5
 
 struct btrfs_block_group_item {
        __le64 used;
@@ -674,42 +676,46 @@ struct btrfs_space_info {
        u64 flags;
 
        u64 total_bytes;        /* total bytes in the space */
-       u64 bytes_used;         /* total bytes used on disk */
+       u64 bytes_used;         /* total bytes used,
+                                  this does't take mirrors into account */
        u64 bytes_pinned;       /* total bytes pinned, will be freed when the
                                   transaction finishes */
        u64 bytes_reserved;     /* total bytes the allocator has reserved for
                                   current allocations */
        u64 bytes_readonly;     /* total bytes that are read only */
-       u64 bytes_super;        /* total bytes reserved for the super blocks */
-       u64 bytes_root;         /* the number of bytes needed to commit a
-                                  transaction */
+
        u64 bytes_may_use;      /* number of bytes that may be used for
                                   delalloc/allocations */
-       u64 bytes_delalloc;     /* number of bytes currently reserved for
-                                  delayed allocation */
+       u64 disk_used;          /* total bytes used on disk */
 
        int full;               /* indicates that we cannot allocate any more
                                   chunks for this space */
        int force_alloc;        /* set if we need to force a chunk alloc for
                                   this space */
-       int force_delalloc;     /* make people start doing filemap_flush until
-                                  we're under a threshold */
 
        struct list_head list;
 
-       /* for controlling how we free up space for allocations */
-       wait_queue_head_t allocate_wait;
-       wait_queue_head_t flush_wait;
-       int allocating_chunk;
-       int flushing;
-
        /* for block groups in our same type */
-       struct list_head block_groups;
+       struct list_head block_groups[BTRFS_NR_RAID_TYPES];
        spinlock_t lock;
        struct rw_semaphore groups_sem;
        atomic_t caching_threads;
 };
 
+struct btrfs_block_rsv {
+       u64 size;
+       u64 reserved;
+       u64 freed[2];
+       struct btrfs_space_info *space_info;
+       struct list_head list;
+       spinlock_t lock;
+       atomic_t usage;
+       unsigned int priority:8;
+       unsigned int durable:1;
+       unsigned int refill_used:1;
+       unsigned int full:1;
+};
+
 /*
  * free clusters are used to claim free space in relatively large chunks,
  * allowing us to do less seeky writes.  They are used for all metadata
@@ -760,6 +766,7 @@ struct btrfs_block_group_cache {
        spinlock_t lock;
        u64 pinned;
        u64 reserved;
+       u64 reserved_pinned;
        u64 bytes_super;
        u64 flags;
        u64 sectorsize;
@@ -825,6 +832,22 @@ struct btrfs_fs_info {
        /* logical->physical extent mapping */
        struct btrfs_mapping_tree mapping_tree;
 
+       /* block reservation for extent, checksum and root tree */
+       struct btrfs_block_rsv global_block_rsv;
+       /* block reservation for delay allocation */
+       struct btrfs_block_rsv delalloc_block_rsv;
+       /* block reservation for metadata operations */
+       struct btrfs_block_rsv trans_block_rsv;
+       /* block reservation for chunk tree */
+       struct btrfs_block_rsv chunk_block_rsv;
+
+       struct btrfs_block_rsv empty_block_rsv;
+
+       /* list of block reservations that cross multiple transactions */
+       struct list_head durable_block_rsv_list;
+
+       struct mutex durable_block_rsv_mutex;
+
        u64 generation;
        u64 last_trans_committed;
 
@@ -927,7 +950,6 @@ struct btrfs_fs_info {
        struct btrfs_workers endio_meta_write_workers;
        struct btrfs_workers endio_write_workers;
        struct btrfs_workers submit_workers;
-       struct btrfs_workers enospc_workers;
        /*
         * fixup workers take dirty pages that didn't properly go through
         * the cow mechanism and make them safe to write.  It happens
@@ -943,6 +965,7 @@ struct btrfs_fs_info {
        int do_barriers;
        int closing;
        int log_root_recovering;
+       int enospc_unlink;
 
        u64 total_pinned;
 
@@ -1012,6 +1035,9 @@ struct btrfs_root {
        struct completion kobj_unregister;
        struct mutex objectid_mutex;
 
+       spinlock_t accounting_lock;
+       struct btrfs_block_rsv *block_rsv;
+
        struct mutex log_mutex;
        wait_queue_head_t log_writer_wait;
        wait_queue_head_t log_commit_wait[2];
@@ -1043,7 +1069,6 @@ struct btrfs_root {
        int ref_cows;
        int track_dirty;
        int in_radix;
-       int clean_orphans;
 
        u64 defrag_trans_start;
        struct btrfs_key defrag_progress;
@@ -1057,8 +1082,11 @@ struct btrfs_root {
 
        struct list_head root_list;
 
-       spinlock_t list_lock;
+       spinlock_t orphan_lock;
        struct list_head orphan_list;
+       struct btrfs_block_rsv *orphan_block_rsv;
+       int orphan_item_inserted;
+       int orphan_cleanup_state;
 
        spinlock_t inode_lock;
        /* red-black tree that keeps track of in-memory inodes */
@@ -1965,6 +1993,9 @@ void btrfs_put_block_group(struct btrfs_block_group_cache *cache);
 int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
                           struct btrfs_root *root, unsigned long count);
 int btrfs_lookup_extent(struct btrfs_root *root, u64 start, u64 len);
+int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans,
+                            struct btrfs_root *root, u64 bytenr,
+                            u64 num_bytes, u64 *refs, u64 *flags);
 int btrfs_pin_extent(struct btrfs_root *root,
                     u64 bytenr, u64 num, int reserved);
 int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans,
@@ -1984,10 +2015,10 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
                                        u64 parent, u64 root_objectid,
                                        struct btrfs_disk_key *key, int level,
                                        u64 hint, u64 empty_size);
-int btrfs_free_tree_block(struct btrfs_trans_handle *trans,
-                         struct btrfs_root *root,
-                         u64 bytenr, u32 blocksize,
-                         u64 parent, u64 root_objectid, int level);
+void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
+                          struct btrfs_root *root,
+                          struct extent_buffer *buf,
+                          u64 parent, int last_ref);
 struct extent_buffer *btrfs_init_new_buffer(struct btrfs_trans_handle *trans,
                                            struct btrfs_root *root,
                                            u64 bytenr, u32 blocksize,
@@ -2041,27 +2072,49 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
                           u64 size);
 int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root, u64 group_start);
-int btrfs_prepare_block_group_relocation(struct btrfs_root *root,
-                               struct btrfs_block_group_cache *group);
-
 u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags);
 void btrfs_set_inode_space_info(struct btrfs_root *root, struct inode *ionde);
 void btrfs_clear_space_info_full(struct btrfs_fs_info *info);
-
-int btrfs_reserve_metadata_space(struct btrfs_root *root, int num_items);
-int btrfs_unreserve_metadata_space(struct btrfs_root *root, int num_items);
-int btrfs_unreserve_metadata_for_delalloc(struct btrfs_root *root,
-                                         struct inode *inode, int num_items);
-int btrfs_reserve_metadata_for_delalloc(struct btrfs_root *root,
-                                       struct inode *inode, int num_items);
-int btrfs_check_data_free_space(struct btrfs_root *root, struct inode *inode,
-                               u64 bytes);
-void btrfs_free_reserved_data_space(struct btrfs_root *root,
-                                   struct inode *inode, u64 bytes);
-void btrfs_delalloc_reserve_space(struct btrfs_root *root, struct inode *inode,
-                                u64 bytes);
-void btrfs_delalloc_free_space(struct btrfs_root *root, struct inode *inode,
-                             u64 bytes);
+int btrfs_check_data_free_space(struct inode *inode, u64 bytes);
+void btrfs_free_reserved_data_space(struct inode *inode, u64 bytes);
+int btrfs_trans_reserve_metadata(struct btrfs_trans_handle *trans,
+                               struct btrfs_root *root,
+                               int num_items, int *retries);
+void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans,
+                               struct btrfs_root *root);
+int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans,
+                                 struct inode *inode);
+void btrfs_orphan_release_metadata(struct inode *inode);
+int btrfs_snap_reserve_metadata(struct btrfs_trans_handle *trans,
+                               struct btrfs_pending_snapshot *pending);
+int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes);
+void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes);
+int btrfs_delalloc_reserve_space(struct inode *inode, u64 num_bytes);
+void btrfs_delalloc_release_space(struct inode *inode, u64 num_bytes);
+void btrfs_init_block_rsv(struct btrfs_block_rsv *rsv);
+struct btrfs_block_rsv *btrfs_alloc_block_rsv(struct btrfs_root *root);
+void btrfs_free_block_rsv(struct btrfs_root *root,
+                         struct btrfs_block_rsv *rsv);
+void btrfs_add_durable_block_rsv(struct btrfs_fs_info *fs_info,
+                                struct btrfs_block_rsv *rsv);
+int btrfs_block_rsv_add(struct btrfs_trans_handle *trans,
+                       struct btrfs_root *root,
+                       struct btrfs_block_rsv *block_rsv,
+                       u64 num_bytes, int *retries);
+int btrfs_block_rsv_check(struct btrfs_trans_handle *trans,
+                         struct btrfs_root *root,
+                         struct btrfs_block_rsv *block_rsv,
+                         u64 min_reserved, int min_factor);
+int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src_rsv,
+                           struct btrfs_block_rsv *dst_rsv,
+                           u64 num_bytes);
+void btrfs_block_rsv_release(struct btrfs_root *root,
+                            struct btrfs_block_rsv *block_rsv,
+                            u64 num_bytes);
+int btrfs_set_block_group_ro(struct btrfs_root *root,
+                            struct btrfs_block_group_cache *cache);
+int btrfs_set_block_group_rw(struct btrfs_root *root,
+                            struct btrfs_block_group_cache *cache);
 /* ctree.c */
 int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key,
                     int level, int *slot);
@@ -2152,7 +2205,8 @@ static inline int btrfs_insert_empty_item(struct btrfs_trans_handle *trans,
 int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path);
 int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path);
 int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf);
-int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref);
+int btrfs_drop_snapshot(struct btrfs_root *root,
+                       struct btrfs_block_rsv *block_rsv, int update_ref);
 int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
                        struct btrfs_root *root,
                        struct extent_buffer *node,
@@ -2245,6 +2299,12 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
                           struct btrfs_root *root,
                           const char *name, int name_len,
                           u64 inode_objectid, u64 ref_objectid, u64 *index);
+struct btrfs_inode_ref *
+btrfs_lookup_inode_ref(struct btrfs_trans_handle *trans,
+                       struct btrfs_root *root,
+                       struct btrfs_path *path,
+                       const char *name, int name_len,
+                       u64 inode_objectid, u64 ref_objectid, int mod);
 int btrfs_insert_empty_inode(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root,
                             struct btrfs_path *path, u64 objectid);
@@ -2257,6 +2317,8 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
                    struct btrfs_root *root, u64 bytenr, u64 len);
 int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode,
                          struct bio *bio, u32 *dst);
+int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode,
+                             struct bio *bio, u64 logical_offset, u32 *dst);
 int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root,
                             u64 objectid, u64 pos,
@@ -2311,6 +2373,7 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
                               u32 min_type);
 
 int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput);
+int btrfs_start_one_delalloc_inode(struct btrfs_root *root, int delay_iput);
 int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end,
                              struct extent_state **cached_state);
 int btrfs_writepages(struct address_space *mapping,
@@ -2349,10 +2412,20 @@ int btrfs_update_inode(struct btrfs_trans_handle *trans,
 int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode);
 int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode);
 void btrfs_orphan_cleanup(struct btrfs_root *root);
+void btrfs_orphan_pre_snapshot(struct btrfs_trans_handle *trans,
+                               struct btrfs_pending_snapshot *pending,
+                               u64 *bytes_to_reserve);
+void btrfs_orphan_post_snapshot(struct btrfs_trans_handle *trans,
+                               struct btrfs_pending_snapshot *pending);
+void btrfs_orphan_commit_root(struct btrfs_trans_handle *trans,
+                             struct btrfs_root *root);
 int btrfs_cont_expand(struct inode *inode, loff_t size);
 int btrfs_invalidate_inodes(struct btrfs_root *root);
 void btrfs_add_delayed_iput(struct inode *inode);
 void btrfs_run_delayed_iputs(struct btrfs_root *root);
+int btrfs_prealloc_file_range(struct inode *inode, int mode,
+                             u64 start, u64 num_bytes, u64 min_size,
+                             loff_t actual_len, u64 *alloc_hint);
 extern const struct dentry_operations btrfs_dentry_operations;
 
 /* ioctl.c */
@@ -2361,7 +2434,7 @@ void btrfs_update_iflags(struct inode *inode);
 void btrfs_inherit_iflags(struct inode *inode, struct inode *dir);
 
 /* file.c */
-int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync);
+int btrfs_sync_file(struct file *file, int datasync);
 int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
                            int skip_pinned);
 int btrfs_check_file(struct btrfs_root *root, struct inode *inode);
@@ -2409,4 +2482,12 @@ int btrfs_update_reloc_root(struct btrfs_trans_handle *trans,
                            struct btrfs_root *root);
 int btrfs_recover_relocation(struct btrfs_root *root);
 int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len);
+void btrfs_reloc_cow_block(struct btrfs_trans_handle *trans,
+                          struct btrfs_root *root, struct extent_buffer *buf,
+                          struct extent_buffer *cow);
+void btrfs_reloc_pre_snapshot(struct btrfs_trans_handle *trans,
+                             struct btrfs_pending_snapshot *pending,
+                             u64 *bytes_to_reserve);
+void btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans,
+                             struct btrfs_pending_snapshot *pending);
 #endif
index 902ce507c4e34a01e4e5afbcba26aa31c9d18d63..e807b143b8578a5ed58d3f90dfeec06fa5af7f20 100644 (file)
@@ -318,107 +318,6 @@ out:
        return ret;
 }
 
-/*
- * helper function to lookup reference count and flags of extent.
- *
- * the head node for delayed ref is used to store the sum of all the
- * reference count modifications queued up in the rbtree. the head
- * node may also store the extent flags to set. This way you can check
- * to see what the reference count and extent flags would be if all of
- * the delayed refs are not processed.
- */
-int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans,
-                            struct btrfs_root *root, u64 bytenr,
-                            u64 num_bytes, u64 *refs, u64 *flags)
-{
-       struct btrfs_delayed_ref_node *ref;
-       struct btrfs_delayed_ref_head *head;
-       struct btrfs_delayed_ref_root *delayed_refs;
-       struct btrfs_path *path;
-       struct btrfs_extent_item *ei;
-       struct extent_buffer *leaf;
-       struct btrfs_key key;
-       u32 item_size;
-       u64 num_refs;
-       u64 extent_flags;
-       int ret;
-
-       path = btrfs_alloc_path();
-       if (!path)
-               return -ENOMEM;
-
-       key.objectid = bytenr;
-       key.type = BTRFS_EXTENT_ITEM_KEY;
-       key.offset = num_bytes;
-       delayed_refs = &trans->transaction->delayed_refs;
-again:
-       ret = btrfs_search_slot(trans, root->fs_info->extent_root,
-                               &key, path, 0, 0);
-       if (ret < 0)
-               goto out;
-
-       if (ret == 0) {
-               leaf = path->nodes[0];
-               item_size = btrfs_item_size_nr(leaf, path->slots[0]);
-               if (item_size >= sizeof(*ei)) {
-                       ei = btrfs_item_ptr(leaf, path->slots[0],
-                                           struct btrfs_extent_item);
-                       num_refs = btrfs_extent_refs(leaf, ei);
-                       extent_flags = btrfs_extent_flags(leaf, ei);
-               } else {
-#ifdef BTRFS_COMPAT_EXTENT_TREE_V0
-                       struct btrfs_extent_item_v0 *ei0;
-                       BUG_ON(item_size != sizeof(*ei0));
-                       ei0 = btrfs_item_ptr(leaf, path->slots[0],
-                                            struct btrfs_extent_item_v0);
-                       num_refs = btrfs_extent_refs_v0(leaf, ei0);
-                       /* FIXME: this isn't correct for data */
-                       extent_flags = BTRFS_BLOCK_FLAG_FULL_BACKREF;
-#else
-                       BUG();
-#endif
-               }
-               BUG_ON(num_refs == 0);
-       } else {
-               num_refs = 0;
-               extent_flags = 0;
-               ret = 0;
-       }
-
-       spin_lock(&delayed_refs->lock);
-       ref = find_ref_head(&delayed_refs->root, bytenr, NULL);
-       if (ref) {
-               head = btrfs_delayed_node_to_head(ref);
-               if (!mutex_trylock(&head->mutex)) {
-                       atomic_inc(&ref->refs);
-                       spin_unlock(&delayed_refs->lock);
-
-                       btrfs_release_path(root->fs_info->extent_root, path);
-
-                       mutex_lock(&head->mutex);
-                       mutex_unlock(&head->mutex);
-                       btrfs_put_delayed_ref(ref);
-                       goto again;
-               }
-               if (head->extent_op && head->extent_op->update_flags)
-                       extent_flags |= head->extent_op->flags_to_set;
-               else
-                       BUG_ON(num_refs == 0);
-
-               num_refs += ref->ref_mod;
-               mutex_unlock(&head->mutex);
-       }
-       WARN_ON(num_refs == 0);
-       if (refs)
-               *refs = num_refs;
-       if (flags)
-               *flags = extent_flags;
-out:
-       spin_unlock(&delayed_refs->lock);
-       btrfs_free_path(path);
-       return ret;
-}
-
 /*
  * helper function to update an extent delayed ref in the
  * rbtree.  existing and update must both have the same
index f6fc67ddad363f4235698f074b977174cc6c3b80..50e3cf92fbdac1610261e02c314a580b71c2f9ab 100644 (file)
@@ -167,9 +167,6 @@ int btrfs_add_delayed_extent_op(struct btrfs_trans_handle *trans,
 struct btrfs_delayed_ref_head *
 btrfs_find_delayed_ref_head(struct btrfs_trans_handle *trans, u64 bytenr);
 int btrfs_delayed_ref_pending(struct btrfs_trans_handle *trans, u64 bytenr);
-int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans,
-                            struct btrfs_root *root, u64 bytenr,
-                            u64 num_bytes, u64 *refs, u64 *flags);
 int btrfs_update_delayed_ref(struct btrfs_trans_handle *trans,
                          u64 bytenr, u64 num_bytes, u64 orig_parent,
                          u64 parent, u64 orig_ref_root, u64 ref_root,
index feca04197d028e9d25a73dd177299319e1af351d..f3b287c22caf2e6855cf89bf780cf0b4b675c902 100644 (file)
@@ -74,6 +74,11 @@ struct async_submit_bio {
        int rw;
        int mirror_num;
        unsigned long bio_flags;
+       /*
+        * bio_offset is optional, can be used if the pages in the bio
+        * can't tell us where in the file the bio should go
+        */
+       u64 bio_offset;
        struct btrfs_work work;
 };
 
@@ -534,7 +539,8 @@ static void run_one_async_start(struct btrfs_work *work)
        async = container_of(work, struct  async_submit_bio, work);
        fs_info = BTRFS_I(async->inode)->root->fs_info;
        async->submit_bio_start(async->inode, async->rw, async->bio,
-                              async->mirror_num, async->bio_flags);
+                              async->mirror_num, async->bio_flags,
+                              async->bio_offset);
 }
 
 static void run_one_async_done(struct btrfs_work *work)
@@ -556,7 +562,8 @@ static void run_one_async_done(struct btrfs_work *work)
                wake_up(&fs_info->async_submit_wait);
 
        async->submit_bio_done(async->inode, async->rw, async->bio,
-                              async->mirror_num, async->bio_flags);
+                              async->mirror_num, async->bio_flags,
+                              async->bio_offset);
 }
 
 static void run_one_async_free(struct btrfs_work *work)
@@ -570,6 +577,7 @@ static void run_one_async_free(struct btrfs_work *work)
 int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode,
                        int rw, struct bio *bio, int mirror_num,
                        unsigned long bio_flags,
+                       u64 bio_offset,
                        extent_submit_bio_hook_t *submit_bio_start,
                        extent_submit_bio_hook_t *submit_bio_done)
 {
@@ -592,6 +600,7 @@ int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode,
 
        async->work.flags = 0;
        async->bio_flags = bio_flags;
+       async->bio_offset = bio_offset;
 
        atomic_inc(&fs_info->nr_async_submits);
 
@@ -627,7 +636,8 @@ static int btree_csum_one_bio(struct bio *bio)
 
 static int __btree_submit_bio_start(struct inode *inode, int rw,
                                    struct bio *bio, int mirror_num,
-                                   unsigned long bio_flags)
+                                   unsigned long bio_flags,
+                                   u64 bio_offset)
 {
        /*
         * when we're called for a write, we're already in the async
@@ -638,7 +648,8 @@ static int __btree_submit_bio_start(struct inode *inode, int rw,
 }
 
 static int __btree_submit_bio_done(struct inode *inode, int rw, struct bio *bio,
-                                int mirror_num, unsigned long bio_flags)
+                                int mirror_num, unsigned long bio_flags,
+                                u64 bio_offset)
 {
        /*
         * when we're called for a write, we're already in the async
@@ -648,7 +659,8 @@ static int __btree_submit_bio_done(struct inode *inode, int rw, struct bio *bio,
 }
 
 static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
-                                int mirror_num, unsigned long bio_flags)
+                                int mirror_num, unsigned long bio_flags,
+                                u64 bio_offset)
 {
        int ret;
 
@@ -671,6 +683,7 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
         */
        return btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info,
                                   inode, rw, bio, mirror_num, 0,
+                                  bio_offset,
                                   __btree_submit_bio_start,
                                   __btree_submit_bio_done);
 }
@@ -894,7 +907,8 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
        root->ref_cows = 0;
        root->track_dirty = 0;
        root->in_radix = 0;
-       root->clean_orphans = 0;
+       root->orphan_item_inserted = 0;
+       root->orphan_cleanup_state = 0;
 
        root->fs_info = fs_info;
        root->objectid = objectid;
@@ -903,13 +917,16 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
        root->name = NULL;
        root->in_sysfs = 0;
        root->inode_tree = RB_ROOT;
+       root->block_rsv = NULL;
+       root->orphan_block_rsv = NULL;
 
        INIT_LIST_HEAD(&root->dirty_list);
        INIT_LIST_HEAD(&root->orphan_list);
        INIT_LIST_HEAD(&root->root_list);
        spin_lock_init(&root->node_lock);
-       spin_lock_init(&root->list_lock);
+       spin_lock_init(&root->orphan_lock);
        spin_lock_init(&root->inode_lock);
+       spin_lock_init(&root->accounting_lock);
        mutex_init(&root->objectid_mutex);
        mutex_init(&root->log_mutex);
        init_waitqueue_head(&root->log_writer_wait);
@@ -968,42 +985,6 @@ static int find_and_setup_root(struct btrfs_root *tree_root,
        return 0;
 }
 
-int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans,
-                            struct btrfs_fs_info *fs_info)
-{
-       struct extent_buffer *eb;
-       struct btrfs_root *log_root_tree = fs_info->log_root_tree;
-       u64 start = 0;
-       u64 end = 0;
-       int ret;
-
-       if (!log_root_tree)
-               return 0;
-
-       while (1) {
-               ret = find_first_extent_bit(&log_root_tree->dirty_log_pages,
-                               0, &start, &end, EXTENT_DIRTY | EXTENT_NEW);
-               if (ret)
-                       break;
-
-               clear_extent_bits(&log_root_tree->dirty_log_pages, start, end,
-                                 EXTENT_DIRTY | EXTENT_NEW, GFP_NOFS);
-       }
-       eb = fs_info->log_root_tree->node;
-
-       WARN_ON(btrfs_header_level(eb) != 0);
-       WARN_ON(btrfs_header_nritems(eb) != 0);
-
-       ret = btrfs_free_reserved_extent(fs_info->tree_root,
-                               eb->start, eb->len);
-       BUG_ON(ret);
-
-       free_extent_buffer(eb);
-       kfree(fs_info->log_root_tree);
-       fs_info->log_root_tree = NULL;
-       return 0;
-}
-
 static struct btrfs_root *alloc_log_tree(struct btrfs_trans_handle *trans,
                                         struct btrfs_fs_info *fs_info)
 {
@@ -1191,19 +1172,23 @@ again:
        if (root)
                return root;
 
-       ret = btrfs_find_orphan_item(fs_info->tree_root, location->objectid);
-       if (ret == 0)
-               ret = -ENOENT;
-       if (ret < 0)
-               return ERR_PTR(ret);
-
        root = btrfs_read_fs_root_no_radix(fs_info->tree_root, location);
        if (IS_ERR(root))
                return root;
 
-       WARN_ON(btrfs_root_refs(&root->root_item) == 0);
        set_anon_super(&root->anon_super, NULL);
 
+       if (btrfs_root_refs(&root->root_item) == 0) {
+               ret = -ENOENT;
+               goto fail;
+       }
+
+       ret = btrfs_find_orphan_item(fs_info->tree_root, location->objectid);
+       if (ret < 0)
+               goto fail;
+       if (ret == 0)
+               root->orphan_item_inserted = 1;
+
        ret = radix_tree_preload(GFP_NOFS & ~__GFP_HIGHMEM);
        if (ret)
                goto fail;
@@ -1212,10 +1197,9 @@ again:
        ret = radix_tree_insert(&fs_info->fs_roots_radix,
                                (unsigned long)root->root_key.objectid,
                                root);
-       if (ret == 0) {
+       if (ret == 0)
                root->in_radix = 1;
-               root->clean_orphans = 1;
-       }
+
        spin_unlock(&fs_info->fs_roots_radix_lock);
        radix_tree_preload_end();
        if (ret) {
@@ -1461,10 +1445,6 @@ static int cleaner_kthread(void *arg)
        struct btrfs_root *root = arg;
 
        do {
-               smp_mb();
-               if (root->fs_info->closing)
-                       break;
-
                vfs_check_frozen(root->fs_info->sb, SB_FREEZE_WRITE);
 
                if (!(root->fs_info->sb->s_flags & MS_RDONLY) &&
@@ -1477,11 +1457,9 @@ static int cleaner_kthread(void *arg)
                if (freezing(current)) {
                        refrigerator();
                } else {
-                       smp_mb();
-                       if (root->fs_info->closing)
-                               break;
                        set_current_state(TASK_INTERRUPTIBLE);
-                       schedule();
+                       if (!kthread_should_stop())
+                               schedule();
                        __set_current_state(TASK_RUNNING);
                }
        } while (!kthread_should_stop());
@@ -1493,36 +1471,40 @@ static int transaction_kthread(void *arg)
        struct btrfs_root *root = arg;
        struct btrfs_trans_handle *trans;
        struct btrfs_transaction *cur;
+       u64 transid;
        unsigned long now;
        unsigned long delay;
        int ret;
 
        do {
-               smp_mb();
-               if (root->fs_info->closing)
-                       break;
-
                delay = HZ * 30;
                vfs_check_frozen(root->fs_info->sb, SB_FREEZE_WRITE);
                mutex_lock(&root->fs_info->transaction_kthread_mutex);
 
-               mutex_lock(&root->fs_info->trans_mutex);
+               spin_lock(&root->fs_info->new_trans_lock);
                cur = root->fs_info->running_transaction;
                if (!cur) {
-                       mutex_unlock(&root->fs_info->trans_mutex);
+                       spin_unlock(&root->fs_info->new_trans_lock);
                        goto sleep;
                }
 
                now = get_seconds();
-               if (now < cur->start_time || now - cur->start_time < 30) {
-                       mutex_unlock(&root->fs_info->trans_mutex);
+               if (!cur->blocked &&
+                   (now < cur->start_time || now - cur->start_time < 30)) {
+                       spin_unlock(&root->fs_info->new_trans_lock);
                        delay = HZ * 5;
                        goto sleep;
                }
-               mutex_unlock(&root->fs_info->trans_mutex);
-               trans = btrfs_start_transaction(root, 1);
-               ret = btrfs_commit_transaction(trans, root);
+               transid = cur->transid;
+               spin_unlock(&root->fs_info->new_trans_lock);
 
+               trans = btrfs_join_transaction(root, 1);
+               if (transid == trans->transid) {
+                       ret = btrfs_commit_transaction(trans, root);
+                       BUG_ON(ret);
+               } else {
+                       btrfs_end_transaction(trans, root);
+               }
 sleep:
                wake_up_process(root->fs_info->cleaner_kthread);
                mutex_unlock(&root->fs_info->transaction_kthread_mutex);
@@ -1530,10 +1512,10 @@ sleep:
                if (freezing(current)) {
                        refrigerator();
                } else {
-                       if (root->fs_info->closing)
-                               break;
                        set_current_state(TASK_INTERRUPTIBLE);
-                       schedule_timeout(delay);
+                       if (!kthread_should_stop() &&
+                           !btrfs_transaction_blocked(root->fs_info))
+                               schedule_timeout(delay);
                        __set_current_state(TASK_RUNNING);
                }
        } while (!kthread_should_stop());
@@ -1620,6 +1602,13 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots);
        INIT_LIST_HEAD(&fs_info->space_info);
        btrfs_mapping_init(&fs_info->mapping_tree);
+       btrfs_init_block_rsv(&fs_info->global_block_rsv);
+       btrfs_init_block_rsv(&fs_info->delalloc_block_rsv);
+       btrfs_init_block_rsv(&fs_info->trans_block_rsv);
+       btrfs_init_block_rsv(&fs_info->chunk_block_rsv);
+       btrfs_init_block_rsv(&fs_info->empty_block_rsv);
+       INIT_LIST_HEAD(&fs_info->durable_block_rsv_list);
+       mutex_init(&fs_info->durable_block_rsv_mutex);
        atomic_set(&fs_info->nr_async_submits, 0);
        atomic_set(&fs_info->async_delalloc_pages, 0);
        atomic_set(&fs_info->async_submit_draining, 0);
@@ -1759,9 +1748,6 @@ struct btrfs_root *open_ctree(struct super_block *sb,
                           min_t(u64, fs_devices->num_devices,
                           fs_info->thread_pool_size),
                           &fs_info->generic_worker);
-       btrfs_init_workers(&fs_info->enospc_workers, "enospc",
-                          fs_info->thread_pool_size,
-                          &fs_info->generic_worker);
 
        /* a higher idle thresh on the submit workers makes it much more
         * likely that bios will be send down in a sane order to the
@@ -1809,7 +1795,6 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        btrfs_start_workers(&fs_info->endio_meta_workers, 1);
        btrfs_start_workers(&fs_info->endio_meta_write_workers, 1);
        btrfs_start_workers(&fs_info->endio_write_workers, 1);
-       btrfs_start_workers(&fs_info->enospc_workers, 1);
 
        fs_info->bdi.ra_pages *= btrfs_super_num_devices(disk_super);
        fs_info->bdi.ra_pages = max(fs_info->bdi.ra_pages,
@@ -1912,17 +1897,18 @@ struct btrfs_root *open_ctree(struct super_block *sb,
 
        csum_root->track_dirty = 1;
 
+       fs_info->generation = generation;
+       fs_info->last_trans_committed = generation;
+       fs_info->data_alloc_profile = (u64)-1;
+       fs_info->metadata_alloc_profile = (u64)-1;
+       fs_info->system_alloc_profile = fs_info->metadata_alloc_profile;
+
        ret = btrfs_read_block_groups(extent_root);
        if (ret) {
                printk(KERN_ERR "Failed to read block groups: %d\n", ret);
                goto fail_block_groups;
        }
 
-       fs_info->generation = generation;
-       fs_info->last_trans_committed = generation;
-       fs_info->data_alloc_profile = (u64)-1;
-       fs_info->metadata_alloc_profile = (u64)-1;
-       fs_info->system_alloc_profile = fs_info->metadata_alloc_profile;
        fs_info->cleaner_kthread = kthread_run(cleaner_kthread, tree_root,
                                               "btrfs-cleaner");
        if (IS_ERR(fs_info->cleaner_kthread))
@@ -1977,6 +1963,9 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        BUG_ON(ret);
 
        if (!(sb->s_flags & MS_RDONLY)) {
+               ret = btrfs_cleanup_fs_roots(fs_info);
+               BUG_ON(ret);
+
                ret = btrfs_recover_relocation(tree_root);
                if (ret < 0) {
                        printk(KERN_WARNING
@@ -2040,7 +2029,6 @@ fail_sb_buffer:
        btrfs_stop_workers(&fs_info->endio_meta_write_workers);
        btrfs_stop_workers(&fs_info->endio_write_workers);
        btrfs_stop_workers(&fs_info->submit_workers);
-       btrfs_stop_workers(&fs_info->enospc_workers);
 fail_iput:
        invalidate_inode_pages2(fs_info->btree_inode->i_mapping);
        iput(fs_info->btree_inode);
@@ -2405,11 +2393,11 @@ int btrfs_commit_super(struct btrfs_root *root)
        down_write(&root->fs_info->cleanup_work_sem);
        up_write(&root->fs_info->cleanup_work_sem);
 
-       trans = btrfs_start_transaction(root, 1);
+       trans = btrfs_join_transaction(root, 1);
        ret = btrfs_commit_transaction(trans, root);
        BUG_ON(ret);
        /* run commit again to drop the original snapshot */
-       trans = btrfs_start_transaction(root, 1);
+       trans = btrfs_join_transaction(root, 1);
        btrfs_commit_transaction(trans, root);
        ret = btrfs_write_and_wait_transaction(NULL, root);
        BUG_ON(ret);
@@ -2426,15 +2414,15 @@ int close_ctree(struct btrfs_root *root)
        fs_info->closing = 1;
        smp_mb();
 
-       kthread_stop(root->fs_info->transaction_kthread);
-       kthread_stop(root->fs_info->cleaner_kthread);
-
        if (!(fs_info->sb->s_flags & MS_RDONLY)) {
                ret =  btrfs_commit_super(root);
                if (ret)
                        printk(KERN_ERR "btrfs: commit super ret %d\n", ret);
        }
 
+       kthread_stop(root->fs_info->transaction_kthread);
+       kthread_stop(root->fs_info->cleaner_kthread);
+
        fs_info->closing = 2;
        smp_mb();
 
@@ -2473,7 +2461,6 @@ int close_ctree(struct btrfs_root *root)
        btrfs_stop_workers(&fs_info->endio_meta_write_workers);
        btrfs_stop_workers(&fs_info->endio_write_workers);
        btrfs_stop_workers(&fs_info->submit_workers);
-       btrfs_stop_workers(&fs_info->enospc_workers);
 
        btrfs_close_devices(fs_info->fs_devices);
        btrfs_mapping_tree_free(&fs_info->mapping_tree);
index c958ecbc19168ef0e7ef8e7bdd123f5f527b55f7..88e825a0bf216a0030d03da33bd340682016ee35 100644 (file)
@@ -87,7 +87,7 @@ int btrfs_bio_wq_end_io(struct btrfs_fs_info *info, struct bio *bio,
                        int metadata);
 int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode,
                        int rw, struct bio *bio, int mirror_num,
-                       unsigned long bio_flags,
+                       unsigned long bio_flags, u64 bio_offset,
                        extent_submit_bio_hook_t *submit_bio_start,
                        extent_submit_bio_hook_t *submit_bio_done);
 
@@ -95,8 +95,6 @@ int btrfs_congested_async(struct btrfs_fs_info *info, int iodone);
 unsigned long btrfs_async_submit_limit(struct btrfs_fs_info *info);
 int btrfs_write_tree_block(struct extent_buffer *buf);
 int btrfs_wait_tree_block_writeback(struct extent_buffer *buf);
-int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans,
-                            struct btrfs_fs_info *fs_info);
 int btrfs_init_log_root_tree(struct btrfs_trans_handle *trans,
                             struct btrfs_fs_info *fs_info);
 int btrfs_add_log_tree(struct btrfs_trans_handle *trans,
index c6a4f459ad76d87cf5a7d5295ad518ad2010c38f..b9080d71991a35cea63d2620d1534234cde6e0a9 100644 (file)
 
 static int update_block_group(struct btrfs_trans_handle *trans,
                              struct btrfs_root *root,
-                             u64 bytenr, u64 num_bytes, int alloc,
-                             int mark_free);
-static int update_reserved_extents(struct btrfs_block_group_cache *cache,
-                                  u64 num_bytes, int reserve);
+                             u64 bytenr, u64 num_bytes, int alloc);
+static int update_reserved_bytes(struct btrfs_block_group_cache *cache,
+                                u64 num_bytes, int reserve, int sinfo);
 static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                                struct btrfs_root *root,
                                u64 bytenr, u64 num_bytes, u64 parent,
@@ -61,12 +60,6 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
 static int do_chunk_alloc(struct btrfs_trans_handle *trans,
                          struct btrfs_root *extent_root, u64 alloc_bytes,
                          u64 flags, int force);
-static int pin_down_bytes(struct btrfs_trans_handle *trans,
-                         struct btrfs_root *root,
-                         struct btrfs_path *path,
-                         u64 bytenr, u64 num_bytes,
-                         int is_data, int reserved,
-                         struct extent_buffer **must_clean);
 static int find_next_key(struct btrfs_path *path, int level,
                         struct btrfs_key *key);
 static void dump_space_info(struct btrfs_space_info *info, u64 bytes,
@@ -91,8 +84,12 @@ void btrfs_get_block_group(struct btrfs_block_group_cache *cache)
 
 void btrfs_put_block_group(struct btrfs_block_group_cache *cache)
 {
-       if (atomic_dec_and_test(&cache->count))
+       if (atomic_dec_and_test(&cache->count)) {
+               WARN_ON(cache->pinned > 0);
+               WARN_ON(cache->reserved > 0);
+               WARN_ON(cache->reserved_pinned > 0);
                kfree(cache);
+       }
 }
 
 /*
@@ -319,7 +316,7 @@ static int caching_kthread(void *data)
 
        exclude_super_stripes(extent_root, block_group);
        spin_lock(&block_group->space_info->lock);
-       block_group->space_info->bytes_super += block_group->bytes_super;
+       block_group->space_info->bytes_readonly += block_group->bytes_super;
        spin_unlock(&block_group->space_info->lock);
 
        last = max_t(u64, block_group->key.objectid, BTRFS_SUPER_INFO_OFFSET);
@@ -507,6 +504,9 @@ static struct btrfs_space_info *__find_space_info(struct btrfs_fs_info *info,
        struct list_head *head = &info->space_info;
        struct btrfs_space_info *found;
 
+       flags &= BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_SYSTEM |
+                BTRFS_BLOCK_GROUP_METADATA;
+
        rcu_read_lock();
        list_for_each_entry_rcu(found, head, list) {
                if (found->flags == flags) {
@@ -609,6 +609,113 @@ int btrfs_lookup_extent(struct btrfs_root *root, u64 start, u64 len)
        return ret;
 }
 
+/*
+ * helper function to lookup reference count and flags of extent.
+ *
+ * the head node for delayed ref is used to store the sum of all the
+ * reference count modifications queued up in the rbtree. the head
+ * node may also store the extent flags to set. This way you can check
+ * to see what the reference count and extent flags would be if all of
+ * the delayed refs are not processed.
+ */
+int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans,
+                            struct btrfs_root *root, u64 bytenr,
+                            u64 num_bytes, u64 *refs, u64 *flags)
+{
+       struct btrfs_delayed_ref_head *head;
+       struct btrfs_delayed_ref_root *delayed_refs;
+       struct btrfs_path *path;
+       struct btrfs_extent_item *ei;
+       struct extent_buffer *leaf;
+       struct btrfs_key key;
+       u32 item_size;
+       u64 num_refs;
+       u64 extent_flags;
+       int ret;
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
+       key.objectid = bytenr;
+       key.type = BTRFS_EXTENT_ITEM_KEY;
+       key.offset = num_bytes;
+       if (!trans) {
+               path->skip_locking = 1;
+               path->search_commit_root = 1;
+       }
+again:
+       ret = btrfs_search_slot(trans, root->fs_info->extent_root,
+                               &key, path, 0, 0);
+       if (ret < 0)
+               goto out_free;
+
+       if (ret == 0) {
+               leaf = path->nodes[0];
+               item_size = btrfs_item_size_nr(leaf, path->slots[0]);
+               if (item_size >= sizeof(*ei)) {
+                       ei = btrfs_item_ptr(leaf, path->slots[0],
+                                           struct btrfs_extent_item);
+                       num_refs = btrfs_extent_refs(leaf, ei);
+                       extent_flags = btrfs_extent_flags(leaf, ei);
+               } else {
+#ifdef BTRFS_COMPAT_EXTENT_TREE_V0
+                       struct btrfs_extent_item_v0 *ei0;
+                       BUG_ON(item_size != sizeof(*ei0));
+                       ei0 = btrfs_item_ptr(leaf, path->slots[0],
+                                            struct btrfs_extent_item_v0);
+                       num_refs = btrfs_extent_refs_v0(leaf, ei0);
+                       /* FIXME: this isn't correct for data */
+                       extent_flags = BTRFS_BLOCK_FLAG_FULL_BACKREF;
+#else
+                       BUG();
+#endif
+               }
+               BUG_ON(num_refs == 0);
+       } else {
+               num_refs = 0;
+               extent_flags = 0;
+               ret = 0;
+       }
+
+       if (!trans)
+               goto out;
+
+       delayed_refs = &trans->transaction->delayed_refs;
+       spin_lock(&delayed_refs->lock);
+       head = btrfs_find_delayed_ref_head(trans, bytenr);
+       if (head) {
+               if (!mutex_trylock(&head->mutex)) {
+                       atomic_inc(&head->node.refs);
+                       spin_unlock(&delayed_refs->lock);
+
+                       btrfs_release_path(root->fs_info->extent_root, path);
+
+                       mutex_lock(&head->mutex);
+                       mutex_unlock(&head->mutex);
+                       btrfs_put_delayed_ref(&head->node);
+                       goto again;
+               }
+               if (head->extent_op && head->extent_op->update_flags)
+                       extent_flags |= head->extent_op->flags_to_set;
+               else
+                       BUG_ON(num_refs == 0);
+
+               num_refs += head->node.ref_mod;
+               mutex_unlock(&head->mutex);
+       }
+       spin_unlock(&delayed_refs->lock);
+out:
+       WARN_ON(num_refs == 0);
+       if (refs)
+               *refs = num_refs;
+       if (flags)
+               *flags = extent_flags;
+out_free:
+       btrfs_free_path(path);
+       return ret;
+}
+
 /*
  * Back reference rules.  Back refs have three main goals:
  *
@@ -1871,7 +1978,6 @@ static int run_delayed_tree_ref(struct btrfs_trans_handle *trans,
        return ret;
 }
 
-
 /* helper function to actually process a single delayed ref entry */
 static int run_one_delayed_ref(struct btrfs_trans_handle *trans,
                               struct btrfs_root *root,
@@ -1891,32 +1997,14 @@ static int run_one_delayed_ref(struct btrfs_trans_handle *trans,
                BUG_ON(extent_op);
                head = btrfs_delayed_node_to_head(node);
                if (insert_reserved) {
-                       int mark_free = 0;
-                       struct extent_buffer *must_clean = NULL;
-
-                       ret = pin_down_bytes(trans, root, NULL,
-                                            node->bytenr, node->num_bytes,
-                                            head->is_data, 1, &must_clean);
-                       if (ret > 0)
-                               mark_free = 1;
-
-                       if (must_clean) {
-                               clean_tree_block(NULL, root, must_clean);
-                               btrfs_tree_unlock(must_clean);
-                               free_extent_buffer(must_clean);
-                       }
+                       btrfs_pin_extent(root, node->bytenr,
+                                        node->num_bytes, 1);
                        if (head->is_data) {
                                ret = btrfs_del_csums(trans, root,
                                                      node->bytenr,
                                                      node->num_bytes);
                                BUG_ON(ret);
                        }
-                       if (mark_free) {
-                               ret = btrfs_free_reserved_extent(root,
-                                                       node->bytenr,
-                                                       node->num_bytes);
-                               BUG_ON(ret);
-                       }
                }
                mutex_unlock(&head->mutex);
                return 0;
@@ -2347,6 +2435,8 @@ int btrfs_cross_ref_exist(struct btrfs_trans_handle *trans,
                ret = 0;
 out:
        btrfs_free_path(path);
+       if (root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID)
+               WARN_ON(ret > 0);
        return ret;
 }
 
@@ -2660,12 +2750,21 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags,
                             struct btrfs_space_info **space_info)
 {
        struct btrfs_space_info *found;
+       int i;
+       int factor;
+
+       if (flags & (BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1 |
+                    BTRFS_BLOCK_GROUP_RAID10))
+               factor = 2;
+       else
+               factor = 1;
 
        found = __find_space_info(info, flags);
        if (found) {
                spin_lock(&found->lock);
                found->total_bytes += total_bytes;
                found->bytes_used += bytes_used;
+               found->disk_used += bytes_used * factor;
                found->full = 0;
                spin_unlock(&found->lock);
                *space_info = found;
@@ -2675,18 +2774,20 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags,
        if (!found)
                return -ENOMEM;
 
-       INIT_LIST_HEAD(&found->block_groups);
+       for (i = 0; i < BTRFS_NR_RAID_TYPES; i++)
+               INIT_LIST_HEAD(&found->block_groups[i]);
        init_rwsem(&found->groups_sem);
-       init_waitqueue_head(&found->flush_wait);
-       init_waitqueue_head(&found->allocate_wait);
        spin_lock_init(&found->lock);
-       found->flags = flags;
+       found->flags = flags & (BTRFS_BLOCK_GROUP_DATA |
+                               BTRFS_BLOCK_GROUP_SYSTEM |
+                               BTRFS_BLOCK_GROUP_METADATA);
        found->total_bytes = total_bytes;
        found->bytes_used = bytes_used;
+       found->disk_used = bytes_used * factor;
        found->bytes_pinned = 0;
        found->bytes_reserved = 0;
        found->bytes_readonly = 0;
-       found->bytes_delalloc = 0;
+       found->bytes_may_use = 0;
        found->full = 0;
        found->force_alloc = 0;
        *space_info = found;
@@ -2711,19 +2812,6 @@ static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags)
        }
 }
 
-static void set_block_group_readonly(struct btrfs_block_group_cache *cache)
-{
-       spin_lock(&cache->space_info->lock);
-       spin_lock(&cache->lock);
-       if (!cache->ro) {
-               cache->space_info->bytes_readonly += cache->key.offset -
-                                       btrfs_block_group_used(&cache->item);
-               cache->ro = 1;
-       }
-       spin_unlock(&cache->lock);
-       spin_unlock(&cache->space_info->lock);
-}
-
 u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags)
 {
        u64 num_devices = root->fs_info->fs_devices->rw_devices;
@@ -2752,722 +2840,946 @@ u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags)
        return flags;
 }
 
-static u64 btrfs_get_alloc_profile(struct btrfs_root *root, u64 data)
-{
-       struct btrfs_fs_info *info = root->fs_info;
-       u64 alloc_profile;
-
-       if (data) {
-               alloc_profile = info->avail_data_alloc_bits &
-                       info->data_alloc_profile;
-               data = BTRFS_BLOCK_GROUP_DATA | alloc_profile;
-       } else if (root == root->fs_info->chunk_root) {
-               alloc_profile = info->avail_system_alloc_bits &
-                       info->system_alloc_profile;
-               data = BTRFS_BLOCK_GROUP_SYSTEM | alloc_profile;
-       } else {
-               alloc_profile = info->avail_metadata_alloc_bits &
-                       info->metadata_alloc_profile;
-               data = BTRFS_BLOCK_GROUP_METADATA | alloc_profile;
-       }
-
-       return btrfs_reduce_alloc_profile(root, data);
-}
-
-void btrfs_set_inode_space_info(struct btrfs_root *root, struct inode *inode)
+static u64 get_alloc_profile(struct btrfs_root *root, u64 flags)
 {
-       u64 alloc_target;
-
-       alloc_target = btrfs_get_alloc_profile(root, 1);
-       BTRFS_I(inode)->space_info = __find_space_info(root->fs_info,
-                                                      alloc_target);
+       if (flags & BTRFS_BLOCK_GROUP_DATA)
+               flags |= root->fs_info->avail_data_alloc_bits &
+                        root->fs_info->data_alloc_profile;
+       else if (flags & BTRFS_BLOCK_GROUP_SYSTEM)
+               flags |= root->fs_info->avail_system_alloc_bits &
+                        root->fs_info->system_alloc_profile;
+       else if (flags & BTRFS_BLOCK_GROUP_METADATA)
+               flags |= root->fs_info->avail_metadata_alloc_bits &
+                        root->fs_info->metadata_alloc_profile;
+       return btrfs_reduce_alloc_profile(root, flags);
 }
 
-static u64 calculate_bytes_needed(struct btrfs_root *root, int num_items)
+static u64 btrfs_get_alloc_profile(struct btrfs_root *root, int data)
 {
-       u64 num_bytes;
-       int level;
-
-       level = BTRFS_MAX_LEVEL - 2;
-       /*
-        * NOTE: these calculations are absolutely the worst possible case.
-        * This assumes that _every_ item we insert will require a new leaf, and
-        * that the tree has grown to its maximum level size.
-        */
+       u64 flags;
 
-       /*
-        * for every item we insert we could insert both an extent item and a
-        * extent ref item.  Then for ever item we insert, we will need to cow
-        * both the original leaf, plus the leaf to the left and right of it.
-        *
-        * Unless we are talking about the extent root, then we just want the
-        * number of items * 2, since we just need the extent item plus its ref.
-        */
-       if (root == root->fs_info->extent_root)
-               num_bytes = num_items * 2;
+       if (data)
+               flags = BTRFS_BLOCK_GROUP_DATA;
+       else if (root == root->fs_info->chunk_root)
+               flags = BTRFS_BLOCK_GROUP_SYSTEM;
        else
-               num_bytes = (num_items + (2 * num_items)) * 3;
+               flags = BTRFS_BLOCK_GROUP_METADATA;
 
-       /*
-        * num_bytes is total number of leaves we could need times the leaf
-        * size, and then for every leaf we could end up cow'ing 2 nodes per
-        * level, down to the leaf level.
-        */
-       num_bytes = (num_bytes * root->leafsize) +
-               (num_bytes * (level * 2)) * root->nodesize;
+       return get_alloc_profile(root, flags);
+}
 
-       return num_bytes;
+void btrfs_set_inode_space_info(struct btrfs_root *root, struct inode *inode)
+{
+       BTRFS_I(inode)->space_info = __find_space_info(root->fs_info,
+                                                      BTRFS_BLOCK_GROUP_DATA);
 }
 
 /*
- * Unreserve metadata space for delalloc.  If we have less reserved credits than
- * we have extents, this function does nothing.
+ * This will check the space that the inode allocates from to make sure we have
+ * enough space for bytes.
  */
-int btrfs_unreserve_metadata_for_delalloc(struct btrfs_root *root,
-                                         struct inode *inode, int num_items)
+int btrfs_check_data_free_space(struct inode *inode, u64 bytes)
 {
-       struct btrfs_fs_info *info = root->fs_info;
-       struct btrfs_space_info *meta_sinfo;
-       u64 num_bytes;
-       u64 alloc_target;
-       bool bug = false;
+       struct btrfs_space_info *data_sinfo;
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       u64 used;
+       int ret = 0, committed = 0;
 
-       /* get the space info for where the metadata will live */
-       alloc_target = btrfs_get_alloc_profile(root, 0);
-       meta_sinfo = __find_space_info(info, alloc_target);
+       /* make sure bytes are sectorsize aligned */
+       bytes = (bytes + root->sectorsize - 1) & ~((u64)root->sectorsize - 1);
 
-       num_bytes = calculate_bytes_needed(root->fs_info->extent_root,
-                                          num_items);
+       data_sinfo = BTRFS_I(inode)->space_info;
+       if (!data_sinfo)
+               goto alloc;
 
-       spin_lock(&meta_sinfo->lock);
-       spin_lock(&BTRFS_I(inode)->accounting_lock);
-       if (BTRFS_I(inode)->reserved_extents <=
-           BTRFS_I(inode)->outstanding_extents) {
-               spin_unlock(&BTRFS_I(inode)->accounting_lock);
-               spin_unlock(&meta_sinfo->lock);
-               return 0;
-       }
-       spin_unlock(&BTRFS_I(inode)->accounting_lock);
+again:
+       /* make sure we have enough space to handle the data first */
+       spin_lock(&data_sinfo->lock);
+       used = data_sinfo->bytes_used + data_sinfo->bytes_reserved +
+               data_sinfo->bytes_pinned + data_sinfo->bytes_readonly +
+               data_sinfo->bytes_may_use;
+
+       if (used + bytes > data_sinfo->total_bytes) {
+               struct btrfs_trans_handle *trans;
 
-       BTRFS_I(inode)->reserved_extents -= num_items;
-       BUG_ON(BTRFS_I(inode)->reserved_extents < 0);
+               /*
+                * if we don't have enough free bytes in this space then we need
+                * to alloc a new chunk.
+                */
+               if (!data_sinfo->full) {
+                       u64 alloc_target;
 
-       if (meta_sinfo->bytes_delalloc < num_bytes) {
-               bug = true;
-               meta_sinfo->bytes_delalloc = 0;
-       } else {
-               meta_sinfo->bytes_delalloc -= num_bytes;
-       }
-       spin_unlock(&meta_sinfo->lock);
+                       data_sinfo->force_alloc = 1;
+                       spin_unlock(&data_sinfo->lock);
+alloc:
+                       alloc_target = btrfs_get_alloc_profile(root, 1);
+                       trans = btrfs_join_transaction(root, 1);
+                       if (IS_ERR(trans))
+                               return PTR_ERR(trans);
 
-       BUG_ON(bug);
+                       ret = do_chunk_alloc(trans, root->fs_info->extent_root,
+                                            bytes + 2 * 1024 * 1024,
+                                            alloc_target, 0);
+                       btrfs_end_transaction(trans, root);
+                       if (ret < 0)
+                               return ret;
 
-       return 0;
-}
+                       if (!data_sinfo) {
+                               btrfs_set_inode_space_info(root, inode);
+                               data_sinfo = BTRFS_I(inode)->space_info;
+                       }
+                       goto again;
+               }
+               spin_unlock(&data_sinfo->lock);
 
-static void check_force_delalloc(struct btrfs_space_info *meta_sinfo)
-{
-       u64 thresh;
+               /* commit the current transaction and try again */
+               if (!committed && !root->fs_info->open_ioctl_trans) {
+                       committed = 1;
+                       trans = btrfs_join_transaction(root, 1);
+                       if (IS_ERR(trans))
+                               return PTR_ERR(trans);
+                       ret = btrfs_commit_transaction(trans, root);
+                       if (ret)
+                               return ret;
+                       goto again;
+               }
 
-       thresh = meta_sinfo->bytes_used + meta_sinfo->bytes_reserved +
-               meta_sinfo->bytes_pinned + meta_sinfo->bytes_readonly +
-               meta_sinfo->bytes_super + meta_sinfo->bytes_root +
-               meta_sinfo->bytes_may_use;
+#if 0 /* I hope we never need this code again, just in case */
+               printk(KERN_ERR "no space left, need %llu, %llu bytes_used, "
+                      "%llu bytes_reserved, " "%llu bytes_pinned, "
+                      "%llu bytes_readonly, %llu may use %llu total\n",
+                      (unsigned long long)bytes,
+                      (unsigned long long)data_sinfo->bytes_used,
+                      (unsigned long long)data_sinfo->bytes_reserved,
+                      (unsigned long long)data_sinfo->bytes_pinned,
+                      (unsigned long long)data_sinfo->bytes_readonly,
+                      (unsigned long long)data_sinfo->bytes_may_use,
+                      (unsigned long long)data_sinfo->total_bytes);
+#endif
+               return -ENOSPC;
+       }
+       data_sinfo->bytes_may_use += bytes;
+       BTRFS_I(inode)->reserved_bytes += bytes;
+       spin_unlock(&data_sinfo->lock);
 
-       thresh = meta_sinfo->total_bytes - thresh;
-       thresh *= 80;
-       do_div(thresh, 100);
-       if (thresh <= meta_sinfo->bytes_delalloc)
-               meta_sinfo->force_delalloc = 1;
-       else
-               meta_sinfo->force_delalloc = 0;
+       return 0;
 }
 
-struct async_flush {
-       struct btrfs_root *root;
-       struct btrfs_space_info *info;
-       struct btrfs_work work;
-};
-
-static noinline void flush_delalloc_async(struct btrfs_work *work)
+/*
+ * called when we are clearing an delalloc extent from the
+ * inode's io_tree or there was an error for whatever reason
+ * after calling btrfs_check_data_free_space
+ */
+void btrfs_free_reserved_data_space(struct inode *inode, u64 bytes)
 {
-       struct async_flush *async;
-       struct btrfs_root *root;
-       struct btrfs_space_info *info;
-
-       async = container_of(work, struct async_flush, work);
-       root = async->root;
-       info = async->info;
-
-       btrfs_start_delalloc_inodes(root, 0);
-       wake_up(&info->flush_wait);
-       btrfs_wait_ordered_extents(root, 0, 0);
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       struct btrfs_space_info *data_sinfo;
 
-       spin_lock(&info->lock);
-       info->flushing = 0;
-       spin_unlock(&info->lock);
-       wake_up(&info->flush_wait);
+       /* make sure bytes are sectorsize aligned */
+       bytes = (bytes + root->sectorsize - 1) & ~((u64)root->sectorsize - 1);
 
-       kfree(async);
+       data_sinfo = BTRFS_I(inode)->space_info;
+       spin_lock(&data_sinfo->lock);
+       data_sinfo->bytes_may_use -= bytes;
+       BTRFS_I(inode)->reserved_bytes -= bytes;
+       spin_unlock(&data_sinfo->lock);
 }
 
-static void wait_on_flush(struct btrfs_space_info *info)
+static void force_metadata_allocation(struct btrfs_fs_info *info)
 {
-       DEFINE_WAIT(wait);
-       u64 used;
-
-       while (1) {
-               prepare_to_wait(&info->flush_wait, &wait,
-                               TASK_UNINTERRUPTIBLE);
-               spin_lock(&info->lock);
-               if (!info->flushing) {
-                       spin_unlock(&info->lock);
-                       break;
-               }
+       struct list_head *head = &info->space_info;
+       struct btrfs_space_info *found;
 
-               used = info->bytes_used + info->bytes_reserved +
-                       info->bytes_pinned + info->bytes_readonly +
-                       info->bytes_super + info->bytes_root +
-                       info->bytes_may_use + info->bytes_delalloc;
-               if (used < info->total_bytes) {
-                       spin_unlock(&info->lock);
-                       break;
-               }
-               spin_unlock(&info->lock);
-               schedule();
+       rcu_read_lock();
+       list_for_each_entry_rcu(found, head, list) {
+               if (found->flags & BTRFS_BLOCK_GROUP_METADATA)
+                       found->force_alloc = 1;
        }
-       finish_wait(&info->flush_wait, &wait);
+       rcu_read_unlock();
 }
 
-static void flush_delalloc(struct btrfs_root *root,
-                                struct btrfs_space_info *info)
+static int should_alloc_chunk(struct btrfs_space_info *sinfo,
+                             u64 alloc_bytes)
 {
-       struct async_flush *async;
-       bool wait = false;
-
-       spin_lock(&info->lock);
-
-       if (!info->flushing)
-               info->flushing = 1;
-       else
-               wait = true;
-
-       spin_unlock(&info->lock);
-
-       if (wait) {
-               wait_on_flush(info);
-               return;
-       }
-
-       async = kzalloc(sizeof(*async), GFP_NOFS);
-       if (!async)
-               goto flush;
-
-       async->root = root;
-       async->info = info;
-       async->work.func = flush_delalloc_async;
+       u64 num_bytes = sinfo->total_bytes - sinfo->bytes_readonly;
 
-       btrfs_queue_worker(&root->fs_info->enospc_workers,
-                          &async->work);
-       wait_on_flush(info);
-       return;
+       if (sinfo->bytes_used + sinfo->bytes_reserved +
+           alloc_bytes + 256 * 1024 * 1024 < num_bytes)
+               return 0;
 
-flush:
-       btrfs_start_delalloc_inodes(root, 0);
-       btrfs_wait_ordered_extents(root, 0, 0);
+       if (sinfo->bytes_used + sinfo->bytes_reserved +
+           alloc_bytes < div_factor(num_bytes, 8))
+               return 0;
 
-       spin_lock(&info->lock);
-       info->flushing = 0;
-       spin_unlock(&info->lock);
-       wake_up(&info->flush_wait);
+       return 1;
 }
 
-static int maybe_allocate_chunk(struct btrfs_root *root,
-                                struct btrfs_space_info *info)
+static int do_chunk_alloc(struct btrfs_trans_handle *trans,
+                         struct btrfs_root *extent_root, u64 alloc_bytes,
+                         u64 flags, int force)
 {
-       struct btrfs_super_block *disk_super = &root->fs_info->super_copy;
-       struct btrfs_trans_handle *trans;
-       bool wait = false;
+       struct btrfs_space_info *space_info;
+       struct btrfs_fs_info *fs_info = extent_root->fs_info;
        int ret = 0;
-       u64 min_metadata;
-       u64 free_space;
 
-       free_space = btrfs_super_total_bytes(disk_super);
-       /*
-        * we allow the metadata to grow to a max of either 10gb or 5% of the
-        * space in the volume.
-        */
-       min_metadata = min((u64)10 * 1024 * 1024 * 1024,
-                            div64_u64(free_space * 5, 100));
-       if (info->total_bytes >= min_metadata) {
-               spin_unlock(&info->lock);
-               return 0;
-       }
+       mutex_lock(&fs_info->chunk_mutex);
 
-       if (info->full) {
-               spin_unlock(&info->lock);
-               return 0;
+       flags = btrfs_reduce_alloc_profile(extent_root, flags);
+
+       space_info = __find_space_info(extent_root->fs_info, flags);
+       if (!space_info) {
+               ret = update_space_info(extent_root->fs_info, flags,
+                                       0, 0, &space_info);
+               BUG_ON(ret);
        }
+       BUG_ON(!space_info);
 
-       if (!info->allocating_chunk) {
-               info->force_alloc = 1;
-               info->allocating_chunk = 1;
-       } else {
-               wait = true;
+       spin_lock(&space_info->lock);
+       if (space_info->force_alloc)
+               force = 1;
+       if (space_info->full) {
+               spin_unlock(&space_info->lock);
+               goto out;
        }
 
-       spin_unlock(&info->lock);
-
-       if (wait) {
-               wait_event(info->allocate_wait,
-                          !info->allocating_chunk);
-               return 1;
+       if (!force && !should_alloc_chunk(space_info, alloc_bytes)) {
+               spin_unlock(&space_info->lock);
+               goto out;
        }
+       spin_unlock(&space_info->lock);
 
-       trans = btrfs_start_transaction(root, 1);
-       if (!trans) {
-               ret = -ENOMEM;
-               goto out;
+       /*
+        * if we're doing a data chunk, go ahead and make sure that
+        * we keep a reasonable number of metadata chunks allocated in the
+        * FS as well.
+        */
+       if (flags & BTRFS_BLOCK_GROUP_DATA && fs_info->metadata_ratio) {
+               fs_info->data_chunk_allocations++;
+               if (!(fs_info->data_chunk_allocations %
+                     fs_info->metadata_ratio))
+                       force_metadata_allocation(fs_info);
        }
 
-       ret = do_chunk_alloc(trans, root->fs_info->extent_root,
-                            4096 + 2 * 1024 * 1024,
-                            info->flags, 0);
-       btrfs_end_transaction(trans, root);
+       ret = btrfs_alloc_chunk(trans, extent_root, flags);
+       spin_lock(&space_info->lock);
        if (ret)
-               goto out;
+               space_info->full = 1;
+       else
+               ret = 1;
+       space_info->force_alloc = 0;
+       spin_unlock(&space_info->lock);
 out:
-       spin_lock(&info->lock);
-       info->allocating_chunk = 0;
-       spin_unlock(&info->lock);
-       wake_up(&info->allocate_wait);
+       mutex_unlock(&extent_root->fs_info->chunk_mutex);
+       return ret;
+}
 
-       if (ret)
+static int maybe_allocate_chunk(struct btrfs_trans_handle *trans,
+                               struct btrfs_root *root,
+                               struct btrfs_space_info *sinfo, u64 num_bytes)
+{
+       int ret;
+       int end_trans = 0;
+
+       if (sinfo->full)
                return 0;
-       return 1;
+
+       spin_lock(&sinfo->lock);
+       ret = should_alloc_chunk(sinfo, num_bytes + 2 * 1024 * 1024);
+       spin_unlock(&sinfo->lock);
+       if (!ret)
+               return 0;
+
+       if (!trans) {
+               trans = btrfs_join_transaction(root, 1);
+               BUG_ON(IS_ERR(trans));
+               end_trans = 1;
+       }
+
+       ret = do_chunk_alloc(trans, root->fs_info->extent_root,
+                            num_bytes + 2 * 1024 * 1024,
+                            get_alloc_profile(root, sinfo->flags), 0);
+
+       if (end_trans)
+               btrfs_end_transaction(trans, root);
+
+       return ret == 1 ? 1 : 0;
 }
 
 /*
- * Reserve metadata space for delalloc.
+ * shrink metadata reservation for delalloc
  */
-int btrfs_reserve_metadata_for_delalloc(struct btrfs_root *root,
-                                       struct inode *inode, int num_items)
+static int shrink_delalloc(struct btrfs_trans_handle *trans,
+                          struct btrfs_root *root, u64 to_reclaim)
+{
+       struct btrfs_block_rsv *block_rsv;
+       u64 reserved;
+       u64 max_reclaim;
+       u64 reclaimed = 0;
+       int pause = 1;
+       int ret;
+
+       block_rsv = &root->fs_info->delalloc_block_rsv;
+       spin_lock(&block_rsv->lock);
+       reserved = block_rsv->reserved;
+       spin_unlock(&block_rsv->lock);
+
+       if (reserved == 0)
+               return 0;
+
+       max_reclaim = min(reserved, to_reclaim);
+
+       while (1) {
+               ret = btrfs_start_one_delalloc_inode(root, trans ? 1 : 0);
+               if (!ret) {
+                       __set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(pause);
+                       pause <<= 1;
+                       if (pause > HZ / 10)
+                               pause = HZ / 10;
+               } else {
+                       pause = 1;
+               }
+
+               spin_lock(&block_rsv->lock);
+               if (reserved > block_rsv->reserved)
+                       reclaimed = reserved - block_rsv->reserved;
+               reserved = block_rsv->reserved;
+               spin_unlock(&block_rsv->lock);
+
+               if (reserved == 0 || reclaimed >= max_reclaim)
+                       break;
+
+               if (trans && trans->transaction->blocked)
+                       return -EAGAIN;
+       }
+       return reclaimed >= to_reclaim;
+}
+
+static int should_retry_reserve(struct btrfs_trans_handle *trans,
+                               struct btrfs_root *root,
+                               struct btrfs_block_rsv *block_rsv,
+                               u64 num_bytes, int *retries)
 {
-       struct btrfs_fs_info *info = root->fs_info;
-       struct btrfs_space_info *meta_sinfo;
-       u64 num_bytes;
-       u64 used;
-       u64 alloc_target;
-       int flushed = 0;
-       int force_delalloc;
+       struct btrfs_space_info *space_info = block_rsv->space_info;
+       int ret;
 
-       /* get the space info for where the metadata will live */
-       alloc_target = btrfs_get_alloc_profile(root, 0);
-       meta_sinfo = __find_space_info(info, alloc_target);
+       if ((*retries) > 2)
+               return -ENOSPC;
 
-       num_bytes = calculate_bytes_needed(root->fs_info->extent_root,
-                                          num_items);
-again:
-       spin_lock(&meta_sinfo->lock);
+       ret = maybe_allocate_chunk(trans, root, space_info, num_bytes);
+       if (ret)
+               return 1;
 
-       force_delalloc = meta_sinfo->force_delalloc;
+       if (trans && trans->transaction->in_commit)
+               return -ENOSPC;
 
-       if (unlikely(!meta_sinfo->bytes_root))
-               meta_sinfo->bytes_root = calculate_bytes_needed(root, 6);
+       ret = shrink_delalloc(trans, root, num_bytes);
+       if (ret)
+               return ret;
 
-       if (!flushed)
-               meta_sinfo->bytes_delalloc += num_bytes;
+       spin_lock(&space_info->lock);
+       if (space_info->bytes_pinned < num_bytes)
+               ret = 1;
+       spin_unlock(&space_info->lock);
+       if (ret)
+               return -ENOSPC;
 
-       used = meta_sinfo->bytes_used + meta_sinfo->bytes_reserved +
-               meta_sinfo->bytes_pinned + meta_sinfo->bytes_readonly +
-               meta_sinfo->bytes_super + meta_sinfo->bytes_root +
-               meta_sinfo->bytes_may_use + meta_sinfo->bytes_delalloc;
+       (*retries)++;
 
-       if (used > meta_sinfo->total_bytes) {
-               flushed++;
+       if (trans)
+               return -EAGAIN;
 
-               if (flushed == 1) {
-                       if (maybe_allocate_chunk(root, meta_sinfo))
-                               goto again;
-                       flushed++;
+       trans = btrfs_join_transaction(root, 1);
+       BUG_ON(IS_ERR(trans));
+       ret = btrfs_commit_transaction(trans, root);
+       BUG_ON(ret);
+
+       return 1;
+}
+
+static int reserve_metadata_bytes(struct btrfs_block_rsv *block_rsv,
+                                 u64 num_bytes)
+{
+       struct btrfs_space_info *space_info = block_rsv->space_info;
+       u64 unused;
+       int ret = -ENOSPC;
+
+       spin_lock(&space_info->lock);
+       unused = space_info->bytes_used + space_info->bytes_reserved +
+                space_info->bytes_pinned + space_info->bytes_readonly;
+
+       if (unused < space_info->total_bytes)
+               unused = space_info->total_bytes - unused;
+       else
+               unused = 0;
+
+       if (unused >= num_bytes) {
+               if (block_rsv->priority >= 10) {
+                       space_info->bytes_reserved += num_bytes;
+                       ret = 0;
                } else {
-                       spin_unlock(&meta_sinfo->lock);
+                       if ((unused + block_rsv->reserved) *
+                           block_rsv->priority >=
+                           (num_bytes + block_rsv->reserved) * 10) {
+                               space_info->bytes_reserved += num_bytes;
+                               ret = 0;
+                       }
                }
+       }
+       spin_unlock(&space_info->lock);
 
-               if (flushed == 2) {
-                       filemap_flush(inode->i_mapping);
-                       goto again;
-               } else if (flushed == 3) {
-                       flush_delalloc(root, meta_sinfo);
-                       goto again;
+       return ret;
+}
+
+static struct btrfs_block_rsv *get_block_rsv(struct btrfs_trans_handle *trans,
+                                            struct btrfs_root *root)
+{
+       struct btrfs_block_rsv *block_rsv;
+       if (root->ref_cows)
+               block_rsv = trans->block_rsv;
+       else
+               block_rsv = root->block_rsv;
+
+       if (!block_rsv)
+               block_rsv = &root->fs_info->empty_block_rsv;
+
+       return block_rsv;
+}
+
+static int block_rsv_use_bytes(struct btrfs_block_rsv *block_rsv,
+                              u64 num_bytes)
+{
+       int ret = -ENOSPC;
+       spin_lock(&block_rsv->lock);
+       if (block_rsv->reserved >= num_bytes) {
+               block_rsv->reserved -= num_bytes;
+               if (block_rsv->reserved < block_rsv->size)
+                       block_rsv->full = 0;
+               ret = 0;
+       }
+       spin_unlock(&block_rsv->lock);
+       return ret;
+}
+
+static void block_rsv_add_bytes(struct btrfs_block_rsv *block_rsv,
+                               u64 num_bytes, int update_size)
+{
+       spin_lock(&block_rsv->lock);
+       block_rsv->reserved += num_bytes;
+       if (update_size)
+               block_rsv->size += num_bytes;
+       else if (block_rsv->reserved >= block_rsv->size)
+               block_rsv->full = 1;
+       spin_unlock(&block_rsv->lock);
+}
+
+void block_rsv_release_bytes(struct btrfs_block_rsv *block_rsv,
+                            struct btrfs_block_rsv *dest, u64 num_bytes)
+{
+       struct btrfs_space_info *space_info = block_rsv->space_info;
+
+       spin_lock(&block_rsv->lock);
+       if (num_bytes == (u64)-1)
+               num_bytes = block_rsv->size;
+       block_rsv->size -= num_bytes;
+       if (block_rsv->reserved >= block_rsv->size) {
+               num_bytes = block_rsv->reserved - block_rsv->size;
+               block_rsv->reserved = block_rsv->size;
+               block_rsv->full = 1;
+       } else {
+               num_bytes = 0;
+       }
+       spin_unlock(&block_rsv->lock);
+
+       if (num_bytes > 0) {
+               if (dest) {
+                       block_rsv_add_bytes(dest, num_bytes, 0);
+               } else {
+                       spin_lock(&space_info->lock);
+                       space_info->bytes_reserved -= num_bytes;
+                       spin_unlock(&space_info->lock);
                }
-               spin_lock(&meta_sinfo->lock);
-               meta_sinfo->bytes_delalloc -= num_bytes;
-               spin_unlock(&meta_sinfo->lock);
-               printk(KERN_ERR "enospc, has %d, reserved %d\n",
-                      BTRFS_I(inode)->outstanding_extents,
-                      BTRFS_I(inode)->reserved_extents);
-               dump_space_info(meta_sinfo, 0, 0);
-               return -ENOSPC;
        }
+}
 
-       BTRFS_I(inode)->reserved_extents += num_items;
-       check_force_delalloc(meta_sinfo);
-       spin_unlock(&meta_sinfo->lock);
+static int block_rsv_migrate_bytes(struct btrfs_block_rsv *src,
+                                  struct btrfs_block_rsv *dst, u64 num_bytes)
+{
+       int ret;
 
-       if (!flushed && force_delalloc)
-               filemap_flush(inode->i_mapping);
+       ret = block_rsv_use_bytes(src, num_bytes);
+       if (ret)
+               return ret;
 
+       block_rsv_add_bytes(dst, num_bytes, 1);
        return 0;
 }
 
-/*
- * unreserve num_items number of items worth of metadata space.  This needs to
- * be paired with btrfs_reserve_metadata_space.
- *
- * NOTE: if you have the option, run this _AFTER_ you do a
- * btrfs_end_transaction, since btrfs_end_transaction will run delayed ref
- * oprations which will result in more used metadata, so we want to make sure we
- * can do that without issue.
- */
-int btrfs_unreserve_metadata_space(struct btrfs_root *root, int num_items)
+void btrfs_init_block_rsv(struct btrfs_block_rsv *rsv)
 {
-       struct btrfs_fs_info *info = root->fs_info;
-       struct btrfs_space_info *meta_sinfo;
-       u64 num_bytes;
+       memset(rsv, 0, sizeof(*rsv));
+       spin_lock_init(&rsv->lock);
+       atomic_set(&rsv->usage, 1);
+       rsv->priority = 6;
+       INIT_LIST_HEAD(&rsv->list);
+}
+
+struct btrfs_block_rsv *btrfs_alloc_block_rsv(struct btrfs_root *root)
+{
+       struct btrfs_block_rsv *block_rsv;
+       struct btrfs_fs_info *fs_info = root->fs_info;
        u64 alloc_target;
-       bool bug = false;
 
-       /* get the space info for where the metadata will live */
-       alloc_target = btrfs_get_alloc_profile(root, 0);
-       meta_sinfo = __find_space_info(info, alloc_target);
+       block_rsv = kmalloc(sizeof(*block_rsv), GFP_NOFS);
+       if (!block_rsv)
+               return NULL;
 
-       num_bytes = calculate_bytes_needed(root, num_items);
+       btrfs_init_block_rsv(block_rsv);
 
-       spin_lock(&meta_sinfo->lock);
-       if (meta_sinfo->bytes_may_use < num_bytes) {
-               bug = true;
-               meta_sinfo->bytes_may_use = 0;
-       } else {
-               meta_sinfo->bytes_may_use -= num_bytes;
-       }
-       spin_unlock(&meta_sinfo->lock);
+       alloc_target = btrfs_get_alloc_profile(root, 0);
+       block_rsv->space_info = __find_space_info(fs_info,
+                                                 BTRFS_BLOCK_GROUP_METADATA);
 
-       BUG_ON(bug);
+       return block_rsv;
+}
 
-       return 0;
+void btrfs_free_block_rsv(struct btrfs_root *root,
+                         struct btrfs_block_rsv *rsv)
+{
+       if (rsv && atomic_dec_and_test(&rsv->usage)) {
+               btrfs_block_rsv_release(root, rsv, (u64)-1);
+               if (!rsv->durable)
+                       kfree(rsv);
+       }
 }
 
 /*
- * Reserve some metadata space for use.  We'll calculate the worste case number
- * of bytes that would be needed to modify num_items number of items.  If we
- * have space, fantastic, if not, you get -ENOSPC.  Please call
- * btrfs_unreserve_metadata_space when you are done for the _SAME_ number of
- * items you reserved, since whatever metadata you needed should have already
- * been allocated.
- *
- * This will commit the transaction to make more space if we don't have enough
- * metadata space.  THe only time we don't do this is if we're reserving space
- * inside of a transaction, then we will just return -ENOSPC and it is the
- * callers responsibility to handle it properly.
+ * make the block_rsv struct be able to capture freed space.
+ * the captured space will re-add to the the block_rsv struct
+ * after transaction commit
  */
-int btrfs_reserve_metadata_space(struct btrfs_root *root, int num_items)
+void btrfs_add_durable_block_rsv(struct btrfs_fs_info *fs_info,
+                                struct btrfs_block_rsv *block_rsv)
 {
-       struct btrfs_fs_info *info = root->fs_info;
-       struct btrfs_space_info *meta_sinfo;
-       u64 num_bytes;
-       u64 used;
-       u64 alloc_target;
-       int retries = 0;
+       block_rsv->durable = 1;
+       mutex_lock(&fs_info->durable_block_rsv_mutex);
+       list_add_tail(&block_rsv->list, &fs_info->durable_block_rsv_list);
+       mutex_unlock(&fs_info->durable_block_rsv_mutex);
+}
 
-       /* get the space info for where the metadata will live */
-       alloc_target = btrfs_get_alloc_profile(root, 0);
-       meta_sinfo = __find_space_info(info, alloc_target);
+int btrfs_block_rsv_add(struct btrfs_trans_handle *trans,
+                       struct btrfs_root *root,
+                       struct btrfs_block_rsv *block_rsv,
+                       u64 num_bytes, int *retries)
+{
+       int ret;
 
-       num_bytes = calculate_bytes_needed(root, num_items);
+       if (num_bytes == 0)
+               return 0;
 again:
-       spin_lock(&meta_sinfo->lock);
+       ret = reserve_metadata_bytes(block_rsv, num_bytes);
+       if (!ret) {
+               block_rsv_add_bytes(block_rsv, num_bytes, 1);
+               return 0;
+       }
 
-       if (unlikely(!meta_sinfo->bytes_root))
-               meta_sinfo->bytes_root = calculate_bytes_needed(root, 6);
+       ret = should_retry_reserve(trans, root, block_rsv, num_bytes, retries);
+       if (ret > 0)
+               goto again;
+
+       return ret;
+}
 
-       if (!retries)
-               meta_sinfo->bytes_may_use += num_bytes;
+int btrfs_block_rsv_check(struct btrfs_trans_handle *trans,
+                         struct btrfs_root *root,
+                         struct btrfs_block_rsv *block_rsv,
+                         u64 min_reserved, int min_factor)
+{
+       u64 num_bytes = 0;
+       int commit_trans = 0;
+       int ret = -ENOSPC;
 
-       used = meta_sinfo->bytes_used + meta_sinfo->bytes_reserved +
-               meta_sinfo->bytes_pinned + meta_sinfo->bytes_readonly +
-               meta_sinfo->bytes_super + meta_sinfo->bytes_root +
-               meta_sinfo->bytes_may_use + meta_sinfo->bytes_delalloc;
+       if (!block_rsv)
+               return 0;
 
-       if (used > meta_sinfo->total_bytes) {
-               retries++;
-               if (retries == 1) {
-                       if (maybe_allocate_chunk(root, meta_sinfo))
-                               goto again;
-                       retries++;
-               } else {
-                       spin_unlock(&meta_sinfo->lock);
-               }
+       spin_lock(&block_rsv->lock);
+       if (min_factor > 0)
+               num_bytes = div_factor(block_rsv->size, min_factor);
+       if (min_reserved > num_bytes)
+               num_bytes = min_reserved;
 
-               if (retries == 2) {
-                       flush_delalloc(root, meta_sinfo);
-                       goto again;
+       if (block_rsv->reserved >= num_bytes) {
+               ret = 0;
+       } else {
+               num_bytes -= block_rsv->reserved;
+               if (block_rsv->durable &&
+                   block_rsv->freed[0] + block_rsv->freed[1] >= num_bytes)
+                       commit_trans = 1;
+       }
+       spin_unlock(&block_rsv->lock);
+       if (!ret)
+               return 0;
+
+       if (block_rsv->refill_used) {
+               ret = reserve_metadata_bytes(block_rsv, num_bytes);
+               if (!ret) {
+                       block_rsv_add_bytes(block_rsv, num_bytes, 0);
+                       return 0;
                }
-               spin_lock(&meta_sinfo->lock);
-               meta_sinfo->bytes_may_use -= num_bytes;
-               spin_unlock(&meta_sinfo->lock);
+       }
 
-               dump_space_info(meta_sinfo, 0, 0);
-               return -ENOSPC;
+       if (commit_trans) {
+               if (trans)
+                       return -EAGAIN;
+
+               trans = btrfs_join_transaction(root, 1);
+               BUG_ON(IS_ERR(trans));
+               ret = btrfs_commit_transaction(trans, root);
+               return 0;
        }
 
-       check_force_delalloc(meta_sinfo);
-       spin_unlock(&meta_sinfo->lock);
+       WARN_ON(1);
+       printk(KERN_INFO"block_rsv size %llu reserved %llu freed %llu %llu\n",
+               block_rsv->size, block_rsv->reserved,
+               block_rsv->freed[0], block_rsv->freed[1]);
 
-       return 0;
+       return -ENOSPC;
+}
+
+int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src_rsv,
+                           struct btrfs_block_rsv *dst_rsv,
+                           u64 num_bytes)
+{
+       return block_rsv_migrate_bytes(src_rsv, dst_rsv, num_bytes);
+}
+
+void btrfs_block_rsv_release(struct btrfs_root *root,
+                            struct btrfs_block_rsv *block_rsv,
+                            u64 num_bytes)
+{
+       struct btrfs_block_rsv *global_rsv = &root->fs_info->global_block_rsv;
+       if (global_rsv->full || global_rsv == block_rsv ||
+           block_rsv->space_info != global_rsv->space_info)
+               global_rsv = NULL;
+       block_rsv_release_bytes(block_rsv, global_rsv, num_bytes);
 }
 
 /*
- * This will check the space that the inode allocates from to make sure we have
- * enough space for bytes.
+ * helper to calculate size of global block reservation.
+ * the desired value is sum of space used by extent tree,
+ * checksum tree and root tree
  */
-int btrfs_check_data_free_space(struct btrfs_root *root, struct inode *inode,
-                               u64 bytes)
+static u64 calc_global_metadata_size(struct btrfs_fs_info *fs_info)
 {
-       struct btrfs_space_info *data_sinfo;
-       u64 used;
-       int ret = 0, committed = 0, flushed = 0;
+       struct btrfs_space_info *sinfo;
+       u64 num_bytes;
+       u64 meta_used;
+       u64 data_used;
+       int csum_size = btrfs_super_csum_size(&fs_info->super_copy);
+#if 0
+       /*
+        * per tree used space accounting can be inaccuracy, so we
+        * can't rely on it.
+        */
+       spin_lock(&fs_info->extent_root->accounting_lock);
+       num_bytes = btrfs_root_used(&fs_info->extent_root->root_item);
+       spin_unlock(&fs_info->extent_root->accounting_lock);
 
-       /* make sure bytes are sectorsize aligned */
-       bytes = (bytes + root->sectorsize - 1) & ~((u64)root->sectorsize - 1);
+       spin_lock(&fs_info->csum_root->accounting_lock);
+       num_bytes += btrfs_root_used(&fs_info->csum_root->root_item);
+       spin_unlock(&fs_info->csum_root->accounting_lock);
 
-       data_sinfo = BTRFS_I(inode)->space_info;
-       if (!data_sinfo)
-               goto alloc;
+       spin_lock(&fs_info->tree_root->accounting_lock);
+       num_bytes += btrfs_root_used(&fs_info->tree_root->root_item);
+       spin_unlock(&fs_info->tree_root->accounting_lock);
+#endif
+       sinfo = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_DATA);
+       spin_lock(&sinfo->lock);
+       data_used = sinfo->bytes_used;
+       spin_unlock(&sinfo->lock);
 
-again:
-       /* make sure we have enough space to handle the data first */
-       spin_lock(&data_sinfo->lock);
-       used = data_sinfo->bytes_used + data_sinfo->bytes_delalloc +
-               data_sinfo->bytes_reserved + data_sinfo->bytes_pinned +
-               data_sinfo->bytes_readonly + data_sinfo->bytes_may_use +
-               data_sinfo->bytes_super;
+       sinfo = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA);
+       spin_lock(&sinfo->lock);
+       meta_used = sinfo->bytes_used;
+       spin_unlock(&sinfo->lock);
 
-       if (used + bytes > data_sinfo->total_bytes) {
-               struct btrfs_trans_handle *trans;
+       num_bytes = (data_used >> fs_info->sb->s_blocksize_bits) *
+                   csum_size * 2;
+       num_bytes += div64_u64(data_used + meta_used, 50);
 
-               if (!flushed) {
-                       spin_unlock(&data_sinfo->lock);
-                       flush_delalloc(root, data_sinfo);
-                       flushed = 1;
-                       goto again;
-               }
+       if (num_bytes * 3 > meta_used)
+               num_bytes = div64_u64(meta_used, 3);
 
-               /*
-                * if we don't have enough free bytes in this space then we need
-                * to alloc a new chunk.
-                */
-               if (!data_sinfo->full) {
-                       u64 alloc_target;
+       return ALIGN(num_bytes, fs_info->extent_root->leafsize << 10);
+}
 
-                       data_sinfo->force_alloc = 1;
-                       spin_unlock(&data_sinfo->lock);
-alloc:
-                       alloc_target = btrfs_get_alloc_profile(root, 1);
-                       trans = btrfs_start_transaction(root, 1);
-                       if (!trans)
-                               return -ENOMEM;
+static void update_global_block_rsv(struct btrfs_fs_info *fs_info)
+{
+       struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv;
+       struct btrfs_space_info *sinfo = block_rsv->space_info;
+       u64 num_bytes;
 
-                       ret = do_chunk_alloc(trans, root->fs_info->extent_root,
-                                            bytes + 2 * 1024 * 1024,
-                                            alloc_target, 0);
-                       btrfs_end_transaction(trans, root);
-                       if (ret)
-                               return ret;
+       num_bytes = calc_global_metadata_size(fs_info);
 
-                       if (!data_sinfo) {
-                               btrfs_set_inode_space_info(root, inode);
-                               data_sinfo = BTRFS_I(inode)->space_info;
-                       }
-                       goto again;
-               }
-               spin_unlock(&data_sinfo->lock);
+       spin_lock(&block_rsv->lock);
+       spin_lock(&sinfo->lock);
 
-               /* commit the current transaction and try again */
-               if (!committed && !root->fs_info->open_ioctl_trans) {
-                       committed = 1;
-                       trans = btrfs_join_transaction(root, 1);
-                       if (!trans)
-                               return -ENOMEM;
-                       ret = btrfs_commit_transaction(trans, root);
-                       if (ret)
-                               return ret;
-                       goto again;
-               }
+       block_rsv->size = num_bytes;
 
-               printk(KERN_ERR "no space left, need %llu, %llu delalloc bytes"
-                      ", %llu bytes_used, %llu bytes_reserved, "
-                      "%llu bytes_pinned, %llu bytes_readonly, %llu may use "
-                      "%llu total\n", (unsigned long long)bytes,
-                      (unsigned long long)data_sinfo->bytes_delalloc,
-                      (unsigned long long)data_sinfo->bytes_used,
-                      (unsigned long long)data_sinfo->bytes_reserved,
-                      (unsigned long long)data_sinfo->bytes_pinned,
-                      (unsigned long long)data_sinfo->bytes_readonly,
-                      (unsigned long long)data_sinfo->bytes_may_use,
-                      (unsigned long long)data_sinfo->total_bytes);
-               return -ENOSPC;
+       num_bytes = sinfo->bytes_used + sinfo->bytes_pinned +
+                   sinfo->bytes_reserved + sinfo->bytes_readonly;
+
+       if (sinfo->total_bytes > num_bytes) {
+               num_bytes = sinfo->total_bytes - num_bytes;
+               block_rsv->reserved += num_bytes;
+               sinfo->bytes_reserved += num_bytes;
        }
-       data_sinfo->bytes_may_use += bytes;
-       BTRFS_I(inode)->reserved_bytes += bytes;
-       spin_unlock(&data_sinfo->lock);
 
-       return 0;
+       if (block_rsv->reserved >= block_rsv->size) {
+               num_bytes = block_rsv->reserved - block_rsv->size;
+               sinfo->bytes_reserved -= num_bytes;
+               block_rsv->reserved = block_rsv->size;
+               block_rsv->full = 1;
+       }
+#if 0
+       printk(KERN_INFO"global block rsv size %llu reserved %llu\n",
+               block_rsv->size, block_rsv->reserved);
+#endif
+       spin_unlock(&sinfo->lock);
+       spin_unlock(&block_rsv->lock);
 }
 
-/*
- * if there was an error for whatever reason after calling
- * btrfs_check_data_free_space, call this so we can cleanup the counters.
- */
-void btrfs_free_reserved_data_space(struct btrfs_root *root,
-                                   struct inode *inode, u64 bytes)
+static void init_global_block_rsv(struct btrfs_fs_info *fs_info)
 {
-       struct btrfs_space_info *data_sinfo;
+       struct btrfs_space_info *space_info;
 
-       /* make sure bytes are sectorsize aligned */
-       bytes = (bytes + root->sectorsize - 1) & ~((u64)root->sectorsize - 1);
+       space_info = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_SYSTEM);
+       fs_info->chunk_block_rsv.space_info = space_info;
+       fs_info->chunk_block_rsv.priority = 10;
 
-       data_sinfo = BTRFS_I(inode)->space_info;
-       spin_lock(&data_sinfo->lock);
-       data_sinfo->bytes_may_use -= bytes;
-       BTRFS_I(inode)->reserved_bytes -= bytes;
-       spin_unlock(&data_sinfo->lock);
+       space_info = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA);
+       fs_info->global_block_rsv.space_info = space_info;
+       fs_info->global_block_rsv.priority = 10;
+       fs_info->global_block_rsv.refill_used = 1;
+       fs_info->delalloc_block_rsv.space_info = space_info;
+       fs_info->trans_block_rsv.space_info = space_info;
+       fs_info->empty_block_rsv.space_info = space_info;
+       fs_info->empty_block_rsv.priority = 10;
+
+       fs_info->extent_root->block_rsv = &fs_info->global_block_rsv;
+       fs_info->csum_root->block_rsv = &fs_info->global_block_rsv;
+       fs_info->dev_root->block_rsv = &fs_info->global_block_rsv;
+       fs_info->tree_root->block_rsv = &fs_info->global_block_rsv;
+       fs_info->chunk_root->block_rsv = &fs_info->chunk_block_rsv;
+
+       btrfs_add_durable_block_rsv(fs_info, &fs_info->global_block_rsv);
+
+       btrfs_add_durable_block_rsv(fs_info, &fs_info->delalloc_block_rsv);
+
+       update_global_block_rsv(fs_info);
 }
 
-/* called when we are adding a delalloc extent to the inode's io_tree */
-void btrfs_delalloc_reserve_space(struct btrfs_root *root, struct inode *inode,
-                                 u64 bytes)
+static void release_global_block_rsv(struct btrfs_fs_info *fs_info)
 {
-       struct btrfs_space_info *data_sinfo;
+       block_rsv_release_bytes(&fs_info->global_block_rsv, NULL, (u64)-1);
+       WARN_ON(fs_info->delalloc_block_rsv.size > 0);
+       WARN_ON(fs_info->delalloc_block_rsv.reserved > 0);
+       WARN_ON(fs_info->trans_block_rsv.size > 0);
+       WARN_ON(fs_info->trans_block_rsv.reserved > 0);
+       WARN_ON(fs_info->chunk_block_rsv.size > 0);
+       WARN_ON(fs_info->chunk_block_rsv.reserved > 0);
+}
 
-       /* get the space info for where this inode will be storing its data */
-       data_sinfo = BTRFS_I(inode)->space_info;
+static u64 calc_trans_metadata_size(struct btrfs_root *root, int num_items)
+{
+       return (root->leafsize + root->nodesize * (BTRFS_MAX_LEVEL - 1)) *
+               3 * num_items;
+}
 
-       /* make sure we have enough space to handle the data first */
-       spin_lock(&data_sinfo->lock);
-       data_sinfo->bytes_delalloc += bytes;
+int btrfs_trans_reserve_metadata(struct btrfs_trans_handle *trans,
+                                struct btrfs_root *root,
+                                int num_items, int *retries)
+{
+       u64 num_bytes;
+       int ret;
 
-       /*
-        * we are adding a delalloc extent without calling
-        * btrfs_check_data_free_space first.  This happens on a weird
-        * writepage condition, but shouldn't hurt our accounting
-        */
-       if (unlikely(bytes > BTRFS_I(inode)->reserved_bytes)) {
-               data_sinfo->bytes_may_use -= BTRFS_I(inode)->reserved_bytes;
-               BTRFS_I(inode)->reserved_bytes = 0;
-       } else {
-               data_sinfo->bytes_may_use -= bytes;
-               BTRFS_I(inode)->reserved_bytes -= bytes;
-       }
+       if (num_items == 0 || root->fs_info->chunk_root == root)
+               return 0;
 
-       spin_unlock(&data_sinfo->lock);
+       num_bytes = calc_trans_metadata_size(root, num_items);
+       ret = btrfs_block_rsv_add(trans, root, &root->fs_info->trans_block_rsv,
+                                 num_bytes, retries);
+       if (!ret) {
+               trans->bytes_reserved += num_bytes;
+               trans->block_rsv = &root->fs_info->trans_block_rsv;
+       }
+       return ret;
 }
 
-/* called when we are clearing an delalloc extent from the inode's io_tree */
-void btrfs_delalloc_free_space(struct btrfs_root *root, struct inode *inode,
-                             u64 bytes)
+void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans,
+                                 struct btrfs_root *root)
 {
-       struct btrfs_space_info *info;
+       if (!trans->bytes_reserved)
+               return;
 
-       info = BTRFS_I(inode)->space_info;
+       BUG_ON(trans->block_rsv != &root->fs_info->trans_block_rsv);
+       btrfs_block_rsv_release(root, trans->block_rsv,
+                               trans->bytes_reserved);
+       trans->bytes_reserved = 0;
+}
 
-       spin_lock(&info->lock);
-       info->bytes_delalloc -= bytes;
-       spin_unlock(&info->lock);
+int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans,
+                                 struct inode *inode)
+{
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       struct btrfs_block_rsv *src_rsv = get_block_rsv(trans, root);
+       struct btrfs_block_rsv *dst_rsv = root->orphan_block_rsv;
+
+       /*
+        * one for deleting orphan item, one for updating inode and
+        * two for calling btrfs_truncate_inode_items.
+        *
+        * btrfs_truncate_inode_items is a delete operation, it frees
+        * more space than it uses in most cases. So two units of
+        * metadata space should be enough for calling it many times.
+        * If all of the metadata space is used, we can commit
+        * transaction and use space it freed.
+        */
+       u64 num_bytes = calc_trans_metadata_size(root, 4);
+       return block_rsv_migrate_bytes(src_rsv, dst_rsv, num_bytes);
 }
 
-static void force_metadata_allocation(struct btrfs_fs_info *info)
+void btrfs_orphan_release_metadata(struct inode *inode)
 {
-       struct list_head *head = &info->space_info;
-       struct btrfs_space_info *found;
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       u64 num_bytes = calc_trans_metadata_size(root, 4);
+       btrfs_block_rsv_release(root, root->orphan_block_rsv, num_bytes);
+}
 
-       rcu_read_lock();
-       list_for_each_entry_rcu(found, head, list) {
-               if (found->flags & BTRFS_BLOCK_GROUP_METADATA)
-                       found->force_alloc = 1;
-       }
-       rcu_read_unlock();
+int btrfs_snap_reserve_metadata(struct btrfs_trans_handle *trans,
+                               struct btrfs_pending_snapshot *pending)
+{
+       struct btrfs_root *root = pending->root;
+       struct btrfs_block_rsv *src_rsv = get_block_rsv(trans, root);
+       struct btrfs_block_rsv *dst_rsv = &pending->block_rsv;
+       /*
+        * two for root back/forward refs, two for directory entries
+        * and one for root of the snapshot.
+        */
+       u64 num_bytes = calc_trans_metadata_size(root, 5);
+       dst_rsv->space_info = src_rsv->space_info;
+       return block_rsv_migrate_bytes(src_rsv, dst_rsv, num_bytes);
 }
 
-static int do_chunk_alloc(struct btrfs_trans_handle *trans,
-                         struct btrfs_root *extent_root, u64 alloc_bytes,
-                         u64 flags, int force)
+static u64 calc_csum_metadata_size(struct inode *inode, u64 num_bytes)
 {
-       struct btrfs_space_info *space_info;
-       struct btrfs_fs_info *fs_info = extent_root->fs_info;
-       u64 thresh;
-       int ret = 0;
+       return num_bytes >>= 3;
+}
 
-       mutex_lock(&fs_info->chunk_mutex);
+int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
+{
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       struct btrfs_block_rsv *block_rsv = &root->fs_info->delalloc_block_rsv;
+       u64 to_reserve;
+       int nr_extents;
+       int retries = 0;
+       int ret;
 
-       flags = btrfs_reduce_alloc_profile(extent_root, flags);
+       if (btrfs_transaction_in_commit(root->fs_info))
+               schedule_timeout(1);
 
-       space_info = __find_space_info(extent_root->fs_info, flags);
-       if (!space_info) {
-               ret = update_space_info(extent_root->fs_info, flags,
-                                       0, 0, &space_info);
-               BUG_ON(ret);
+       num_bytes = ALIGN(num_bytes, root->sectorsize);
+again:
+       spin_lock(&BTRFS_I(inode)->accounting_lock);
+       nr_extents = atomic_read(&BTRFS_I(inode)->outstanding_extents) + 1;
+       if (nr_extents > BTRFS_I(inode)->reserved_extents) {
+               nr_extents -= BTRFS_I(inode)->reserved_extents;
+               to_reserve = calc_trans_metadata_size(root, nr_extents);
+       } else {
+               nr_extents = 0;
+               to_reserve = 0;
        }
-       BUG_ON(!space_info);
 
-       spin_lock(&space_info->lock);
-       if (space_info->force_alloc)
-               force = 1;
-       if (space_info->full) {
-               spin_unlock(&space_info->lock);
-               goto out;
+       to_reserve += calc_csum_metadata_size(inode, num_bytes);
+       ret = reserve_metadata_bytes(block_rsv, to_reserve);
+       if (ret) {
+               spin_unlock(&BTRFS_I(inode)->accounting_lock);
+               ret = should_retry_reserve(NULL, root, block_rsv, to_reserve,
+                                          &retries);
+               if (ret > 0)
+                       goto again;
+               return ret;
        }
 
-       thresh = space_info->total_bytes - space_info->bytes_readonly;
-       thresh = div_factor(thresh, 8);
-       if (!force &&
-          (space_info->bytes_used + space_info->bytes_pinned +
-           space_info->bytes_reserved + alloc_bytes) < thresh) {
-               spin_unlock(&space_info->lock);
-               goto out;
-       }
-       spin_unlock(&space_info->lock);
+       BTRFS_I(inode)->reserved_extents += nr_extents;
+       atomic_inc(&BTRFS_I(inode)->outstanding_extents);
+       spin_unlock(&BTRFS_I(inode)->accounting_lock);
 
-       /*
-        * if we're doing a data chunk, go ahead and make sure that
-        * we keep a reasonable number of metadata chunks allocated in the
-        * FS as well.
-        */
-       if (flags & BTRFS_BLOCK_GROUP_DATA && fs_info->metadata_ratio) {
-               fs_info->data_chunk_allocations++;
-               if (!(fs_info->data_chunk_allocations %
-                     fs_info->metadata_ratio))
-                       force_metadata_allocation(fs_info);
+       block_rsv_add_bytes(block_rsv, to_reserve, 1);
+
+       if (block_rsv->size > 512 * 1024 * 1024)
+               shrink_delalloc(NULL, root, to_reserve);
+
+       return 0;
+}
+
+void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes)
+{
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       u64 to_free;
+       int nr_extents;
+
+       num_bytes = ALIGN(num_bytes, root->sectorsize);
+       atomic_dec(&BTRFS_I(inode)->outstanding_extents);
+
+       spin_lock(&BTRFS_I(inode)->accounting_lock);
+       nr_extents = atomic_read(&BTRFS_I(inode)->outstanding_extents);
+       if (nr_extents < BTRFS_I(inode)->reserved_extents) {
+               nr_extents = BTRFS_I(inode)->reserved_extents - nr_extents;
+               BTRFS_I(inode)->reserved_extents -= nr_extents;
+       } else {
+               nr_extents = 0;
        }
+       spin_unlock(&BTRFS_I(inode)->accounting_lock);
 
-       ret = btrfs_alloc_chunk(trans, extent_root, flags);
-       spin_lock(&space_info->lock);
+       to_free = calc_csum_metadata_size(inode, num_bytes);
+       if (nr_extents > 0)
+               to_free += calc_trans_metadata_size(root, nr_extents);
+
+       btrfs_block_rsv_release(root, &root->fs_info->delalloc_block_rsv,
+                               to_free);
+}
+
+int btrfs_delalloc_reserve_space(struct inode *inode, u64 num_bytes)
+{
+       int ret;
+
+       ret = btrfs_check_data_free_space(inode, num_bytes);
        if (ret)
-               space_info->full = 1;
-       space_info->force_alloc = 0;
-       spin_unlock(&space_info->lock);
-out:
-       mutex_unlock(&extent_root->fs_info->chunk_mutex);
-       return ret;
+               return ret;
+
+       ret = btrfs_delalloc_reserve_metadata(inode, num_bytes);
+       if (ret) {
+               btrfs_free_reserved_data_space(inode, num_bytes);
+               return ret;
+       }
+
+       return 0;
+}
+
+void btrfs_delalloc_release_space(struct inode *inode, u64 num_bytes)
+{
+       btrfs_delalloc_release_metadata(inode, num_bytes);
+       btrfs_free_reserved_data_space(inode, num_bytes);
 }
 
 static int update_block_group(struct btrfs_trans_handle *trans,
                              struct btrfs_root *root,
-                             u64 bytenr, u64 num_bytes, int alloc,
-                             int mark_free)
+                             u64 bytenr, u64 num_bytes, int alloc)
 {
        struct btrfs_block_group_cache *cache;
        struct btrfs_fs_info *info = root->fs_info;
+       int factor;
        u64 total = num_bytes;
        u64 old_val;
        u64 byte_in_group;
@@ -3486,6 +3798,12 @@ static int update_block_group(struct btrfs_trans_handle *trans,
                cache = btrfs_lookup_block_group(info, bytenr);
                if (!cache)
                        return -1;
+               if (cache->flags & (BTRFS_BLOCK_GROUP_DUP |
+                                   BTRFS_BLOCK_GROUP_RAID1 |
+                                   BTRFS_BLOCK_GROUP_RAID10))
+                       factor = 2;
+               else
+                       factor = 1;
                byte_in_group = bytenr - cache->key.objectid;
                WARN_ON(byte_in_group > cache->key.offset);
 
@@ -3498,31 +3816,24 @@ static int update_block_group(struct btrfs_trans_handle *trans,
                        old_val += num_bytes;
                        btrfs_set_block_group_used(&cache->item, old_val);
                        cache->reserved -= num_bytes;
-                       cache->space_info->bytes_used += num_bytes;
                        cache->space_info->bytes_reserved -= num_bytes;
-                       if (cache->ro)
-                               cache->space_info->bytes_readonly -= num_bytes;
+                       cache->space_info->bytes_used += num_bytes;
+                       cache->space_info->disk_used += num_bytes * factor;
                        spin_unlock(&cache->lock);
                        spin_unlock(&cache->space_info->lock);
                } else {
                        old_val -= num_bytes;
-                       cache->space_info->bytes_used -= num_bytes;
-                       if (cache->ro)
-                               cache->space_info->bytes_readonly += num_bytes;
                        btrfs_set_block_group_used(&cache->item, old_val);
+                       cache->pinned += num_bytes;
+                       cache->space_info->bytes_pinned += num_bytes;
+                       cache->space_info->bytes_used -= num_bytes;
+                       cache->space_info->disk_used -= num_bytes * factor;
                        spin_unlock(&cache->lock);
                        spin_unlock(&cache->space_info->lock);
-                       if (mark_free) {
-                               int ret;
 
-                               ret = btrfs_discard_extent(root, bytenr,
-                                                          num_bytes);
-                               WARN_ON(ret);
-
-                               ret = btrfs_add_free_space(cache, bytenr,
-                                                          num_bytes);
-                               WARN_ON(ret);
-                       }
+                       set_extent_dirty(info->pinned_extents,
+                                        bytenr, bytenr + num_bytes - 1,
+                                        GFP_NOFS | __GFP_NOFAIL);
                }
                btrfs_put_block_group(cache);
                total -= num_bytes;
@@ -3546,18 +3857,10 @@ static u64 first_logical_byte(struct btrfs_root *root, u64 search_start)
        return bytenr;
 }
 
-/*
- * this function must be called within transaction
- */
-int btrfs_pin_extent(struct btrfs_root *root,
-                    u64 bytenr, u64 num_bytes, int reserved)
+static int pin_down_extent(struct btrfs_root *root,
+                          struct btrfs_block_group_cache *cache,
+                          u64 bytenr, u64 num_bytes, int reserved)
 {
-       struct btrfs_fs_info *fs_info = root->fs_info;
-       struct btrfs_block_group_cache *cache;
-
-       cache = btrfs_lookup_block_group(fs_info, bytenr);
-       BUG_ON(!cache);
-
        spin_lock(&cache->space_info->lock);
        spin_lock(&cache->lock);
        cache->pinned += num_bytes;
@@ -3569,28 +3872,68 @@ int btrfs_pin_extent(struct btrfs_root *root,
        spin_unlock(&cache->lock);
        spin_unlock(&cache->space_info->lock);
 
-       btrfs_put_block_group(cache);
+       set_extent_dirty(root->fs_info->pinned_extents, bytenr,
+                        bytenr + num_bytes - 1, GFP_NOFS | __GFP_NOFAIL);
+       return 0;
+}
+
+/*
+ * this function must be called within transaction
+ */
+int btrfs_pin_extent(struct btrfs_root *root,
+                    u64 bytenr, u64 num_bytes, int reserved)
+{
+       struct btrfs_block_group_cache *cache;
 
-       set_extent_dirty(fs_info->pinned_extents,
-                        bytenr, bytenr + num_bytes - 1, GFP_NOFS);
+       cache = btrfs_lookup_block_group(root->fs_info, bytenr);
+       BUG_ON(!cache);
+
+       pin_down_extent(root, cache, bytenr, num_bytes, reserved);
+
+       btrfs_put_block_group(cache);
        return 0;
 }
 
-static int update_reserved_extents(struct btrfs_block_group_cache *cache,
-                                  u64 num_bytes, int reserve)
+/*
+ * update size of reserved extents. this function may return -EAGAIN
+ * if 'reserve' is true or 'sinfo' is false.
+ */
+static int update_reserved_bytes(struct btrfs_block_group_cache *cache,
+                                u64 num_bytes, int reserve, int sinfo)
 {
-       spin_lock(&cache->space_info->lock);
-       spin_lock(&cache->lock);
-       if (reserve) {
-               cache->reserved += num_bytes;
-               cache->space_info->bytes_reserved += num_bytes;
+       int ret = 0;
+       if (sinfo) {
+               struct btrfs_space_info *space_info = cache->space_info;
+               spin_lock(&space_info->lock);
+               spin_lock(&cache->lock);
+               if (reserve) {
+                       if (cache->ro) {
+                               ret = -EAGAIN;
+                       } else {
+                               cache->reserved += num_bytes;
+                               space_info->bytes_reserved += num_bytes;
+                       }
+               } else {
+                       if (cache->ro)
+                               space_info->bytes_readonly += num_bytes;
+                       cache->reserved -= num_bytes;
+                       space_info->bytes_reserved -= num_bytes;
+               }
+               spin_unlock(&cache->lock);
+               spin_unlock(&space_info->lock);
        } else {
-               cache->reserved -= num_bytes;
-               cache->space_info->bytes_reserved -= num_bytes;
+               spin_lock(&cache->lock);
+               if (cache->ro) {
+                       ret = -EAGAIN;
+               } else {
+                       if (reserve)
+                               cache->reserved += num_bytes;
+                       else
+                               cache->reserved -= num_bytes;
+               }
+               spin_unlock(&cache->lock);
        }
-       spin_unlock(&cache->lock);
-       spin_unlock(&cache->space_info->lock);
-       return 0;
+       return ret;
 }
 
 int btrfs_prepare_extent_commit(struct btrfs_trans_handle *trans,
@@ -3621,6 +3964,8 @@ int btrfs_prepare_extent_commit(struct btrfs_trans_handle *trans,
                fs_info->pinned_extents = &fs_info->freed_extents[0];
 
        up_write(&fs_info->extent_commit_sem);
+
+       update_global_block_rsv(fs_info);
        return 0;
 }
 
@@ -3647,14 +3992,21 @@ static int unpin_extent_range(struct btrfs_root *root, u64 start, u64 end)
                        btrfs_add_free_space(cache, start, len);
                }
 
+               start += len;
+
                spin_lock(&cache->space_info->lock);
                spin_lock(&cache->lock);
                cache->pinned -= len;
                cache->space_info->bytes_pinned -= len;
+               if (cache->ro) {
+                       cache->space_info->bytes_readonly += len;
+               } else if (cache->reserved_pinned > 0) {
+                       len = min(len, cache->reserved_pinned);
+                       cache->reserved_pinned -= len;
+                       cache->space_info->bytes_reserved += len;
+               }
                spin_unlock(&cache->lock);
                spin_unlock(&cache->space_info->lock);
-
-               start += len;
        }
 
        if (cache)
@@ -3667,8 +4019,11 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
 {
        struct btrfs_fs_info *fs_info = root->fs_info;
        struct extent_io_tree *unpin;
+       struct btrfs_block_rsv *block_rsv;
+       struct btrfs_block_rsv *next_rsv;
        u64 start;
        u64 end;
+       int idx;
        int ret;
 
        if (fs_info->pinned_extents == &fs_info->freed_extents[0])
@@ -3689,59 +4044,30 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
                cond_resched();
        }
 
-       return ret;
-}
-
-static int pin_down_bytes(struct btrfs_trans_handle *trans,
-                         struct btrfs_root *root,
-                         struct btrfs_path *path,
-                         u64 bytenr, u64 num_bytes,
-                         int is_data, int reserved,
-                         struct extent_buffer **must_clean)
-{
-       int err = 0;
-       struct extent_buffer *buf;
-
-       if (is_data)
-               goto pinit;
-
-       /*
-        * discard is sloooow, and so triggering discards on
-        * individual btree blocks isn't a good plan.  Just
-        * pin everything in discard mode.
-        */
-       if (btrfs_test_opt(root, DISCARD))
-               goto pinit;
+       mutex_lock(&fs_info->durable_block_rsv_mutex);
+       list_for_each_entry_safe(block_rsv, next_rsv,
+                                &fs_info->durable_block_rsv_list, list) {
 
-       buf = btrfs_find_tree_block(root, bytenr, num_bytes);
-       if (!buf)
-               goto pinit;
+               idx = trans->transid & 0x1;
+               if (block_rsv->freed[idx] > 0) {
+                       block_rsv_add_bytes(block_rsv,
+                                           block_rsv->freed[idx], 0);
+                       block_rsv->freed[idx] = 0;
+               }
+               if (atomic_read(&block_rsv->usage) == 0) {
+                       btrfs_block_rsv_release(root, block_rsv, (u64)-1);
 
-       /* we can reuse a block if it hasn't been written
-        * and it is from this transaction.  We can't
-        * reuse anything from the tree log root because
-        * it has tiny sub-transactions.
-        */
-       if (btrfs_buffer_uptodate(buf, 0) &&
-           btrfs_try_tree_lock(buf)) {
-               u64 header_owner = btrfs_header_owner(buf);
-               u64 header_transid = btrfs_header_generation(buf);
-               if (header_owner != BTRFS_TREE_LOG_OBJECTID &&
-                   header_transid == trans->transid &&
-                   !btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN)) {
-                       *must_clean = buf;
-                       return 1;
+                       if (block_rsv->freed[0] == 0 &&
+                           block_rsv->freed[1] == 0) {
+                               list_del_init(&block_rsv->list);
+                               kfree(block_rsv);
+                       }
+               } else {
+                       btrfs_block_rsv_release(root, block_rsv, 0);
                }
-               btrfs_tree_unlock(buf);
        }
-       free_extent_buffer(buf);
-pinit:
-       if (path)
-               btrfs_set_path_blocking(path);
-       /* unlocks the pinned mutex */
-       btrfs_pin_extent(root, bytenr, num_bytes, reserved);
+       mutex_unlock(&fs_info->durable_block_rsv_mutex);
 
-       BUG_ON(err < 0);
        return 0;
 }
 
@@ -3902,9 +4228,6 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                        BUG_ON(ret);
                }
        } else {
-               int mark_free = 0;
-               struct extent_buffer *must_clean = NULL;
-
                if (found_extent) {
                        BUG_ON(is_data && refs_to_drop !=
                               extent_data_ref_count(root, path, iref));
@@ -3917,31 +4240,11 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                        }
                }
 
-               ret = pin_down_bytes(trans, root, path, bytenr,
-                                    num_bytes, is_data, 0, &must_clean);
-               if (ret > 0)
-                       mark_free = 1;
-               BUG_ON(ret < 0);
-               /*
-                * it is going to be very rare for someone to be waiting
-                * on the block we're freeing.  del_items might need to
-                * schedule, so rather than get fancy, just force it
-                * to blocking here
-                */
-               if (must_clean)
-                       btrfs_set_lock_blocking(must_clean);
-
                ret = btrfs_del_items(trans, extent_root, path, path->slots[0],
                                      num_to_del);
                BUG_ON(ret);
                btrfs_release_path(extent_root, path);
 
-               if (must_clean) {
-                       clean_tree_block(NULL, root, must_clean);
-                       btrfs_tree_unlock(must_clean);
-                       free_extent_buffer(must_clean);
-               }
-
                if (is_data) {
                        ret = btrfs_del_csums(trans, root, bytenr, num_bytes);
                        BUG_ON(ret);
@@ -3951,8 +4254,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                             (bytenr + num_bytes - 1) >> PAGE_CACHE_SHIFT);
                }
 
-               ret = update_block_group(trans, root, bytenr, num_bytes, 0,
-                                        mark_free);
+               ret = update_block_group(trans, root, bytenr, num_bytes, 0);
                BUG_ON(ret);
        }
        btrfs_free_path(path);
@@ -3960,7 +4262,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
 }
 
 /*
- * when we free an extent, it is possible (and likely) that we free the last
+ * when we free an block, it is possible (and likely) that we free the last
  * delayed ref for that extent as well.  This searches the delayed ref tree for
  * a given extent, and if there are no other delayed refs to be processed, it
  * removes it from the tree.
@@ -3972,7 +4274,7 @@ static noinline int check_ref_cleanup(struct btrfs_trans_handle *trans,
        struct btrfs_delayed_ref_root *delayed_refs;
        struct btrfs_delayed_ref_node *ref;
        struct rb_node *node;
-       int ret;
+       int ret = 0;
 
        delayed_refs = &trans->transaction->delayed_refs;
        spin_lock(&delayed_refs->lock);
@@ -4024,17 +4326,99 @@ static noinline int check_ref_cleanup(struct btrfs_trans_handle *trans,
        list_del_init(&head->cluster);
        spin_unlock(&delayed_refs->lock);
 
-       ret = run_one_delayed_ref(trans, root->fs_info->tree_root,
-                                 &head->node, head->extent_op,
-                                 head->must_insert_reserved);
-       BUG_ON(ret);
+       BUG_ON(head->extent_op);
+       if (head->must_insert_reserved)
+               ret = 1;
+
+       mutex_unlock(&head->mutex);
        btrfs_put_delayed_ref(&head->node);
-       return 0;
+       return ret;
 out:
        spin_unlock(&delayed_refs->lock);
        return 0;
 }
 
+void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
+                          struct btrfs_root *root,
+                          struct extent_buffer *buf,
+                          u64 parent, int last_ref)
+{
+       struct btrfs_block_rsv *block_rsv;
+       struct btrfs_block_group_cache *cache = NULL;
+       int ret;
+
+       if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) {
+               ret = btrfs_add_delayed_tree_ref(trans, buf->start, buf->len,
+                                               parent, root->root_key.objectid,
+                                               btrfs_header_level(buf),
+                                               BTRFS_DROP_DELAYED_REF, NULL);
+               BUG_ON(ret);
+       }
+
+       if (!last_ref)
+               return;
+
+       block_rsv = get_block_rsv(trans, root);
+       cache = btrfs_lookup_block_group(root->fs_info, buf->start);
+       BUG_ON(block_rsv->space_info != cache->space_info);
+
+       if (btrfs_header_generation(buf) == trans->transid) {
+               if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) {
+                       ret = check_ref_cleanup(trans, root, buf->start);
+                       if (!ret)
+                               goto pin;
+               }
+
+               if (btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN)) {
+                       pin_down_extent(root, cache, buf->start, buf->len, 1);
+                       goto pin;
+               }
+
+               WARN_ON(test_bit(EXTENT_BUFFER_DIRTY, &buf->bflags));
+
+               btrfs_add_free_space(cache, buf->start, buf->len);
+               ret = update_reserved_bytes(cache, buf->len, 0, 0);
+               if (ret == -EAGAIN) {
+                       /* block group became read-only */
+                       update_reserved_bytes(cache, buf->len, 0, 1);
+                       goto out;
+               }
+
+               ret = 1;
+               spin_lock(&block_rsv->lock);
+               if (block_rsv->reserved < block_rsv->size) {
+                       block_rsv->reserved += buf->len;
+                       ret = 0;
+               }
+               spin_unlock(&block_rsv->lock);
+
+               if (ret) {
+                       spin_lock(&cache->space_info->lock);
+                       cache->space_info->bytes_reserved -= buf->len;
+                       spin_unlock(&cache->space_info->lock);
+               }
+               goto out;
+       }
+pin:
+       if (block_rsv->durable && !cache->ro) {
+               ret = 0;
+               spin_lock(&cache->lock);
+               if (!cache->ro) {
+                       cache->reserved_pinned += buf->len;
+                       ret = 1;
+               }
+               spin_unlock(&cache->lock);
+
+               if (ret) {
+                       spin_lock(&block_rsv->lock);
+                       block_rsv->freed[trans->transid & 0x1] += buf->len;
+                       spin_unlock(&block_rsv->lock);
+               }
+       }
+out:
+       btrfs_put_block_group(cache);
+}
+
 int btrfs_free_extent(struct btrfs_trans_handle *trans,
                      struct btrfs_root *root,
                      u64 bytenr, u64 num_bytes, u64 parent,
@@ -4056,8 +4440,6 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans,
                                        parent, root_objectid, (int)owner,
                                        BTRFS_DROP_DELAYED_REF, NULL);
                BUG_ON(ret);
-               ret = check_ref_cleanup(trans, root, bytenr);
-               BUG_ON(ret);
        } else {
                ret = btrfs_add_delayed_data_ref(trans, bytenr, num_bytes,
                                        parent, root_objectid, owner,
@@ -4067,21 +4449,6 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans,
        return ret;
 }
 
-int btrfs_free_tree_block(struct btrfs_trans_handle *trans,
-                         struct btrfs_root *root,
-                         u64 bytenr, u32 blocksize,
-                         u64 parent, u64 root_objectid, int level)
-{
-       u64 used;
-       spin_lock(&root->node_lock);
-       used = btrfs_root_used(&root->root_item) - blocksize;
-       btrfs_set_root_used(&root->root_item, used);
-       spin_unlock(&root->node_lock);
-
-       return btrfs_free_extent(trans, root, bytenr, blocksize,
-                                parent, root_objectid, level, 0);
-}
-
 static u64 stripe_align(struct btrfs_root *root, u64 val)
 {
        u64 mask = ((u64)root->stripesize - 1);
@@ -4134,6 +4501,22 @@ wait_block_group_cache_done(struct btrfs_block_group_cache *cache)
        return 0;
 }
 
+static int get_block_group_index(struct btrfs_block_group_cache *cache)
+{
+       int index;
+       if (cache->flags & BTRFS_BLOCK_GROUP_RAID10)
+               index = 0;
+       else if (cache->flags & BTRFS_BLOCK_GROUP_RAID1)
+               index = 1;
+       else if (cache->flags & BTRFS_BLOCK_GROUP_DUP)
+               index = 2;
+       else if (cache->flags & BTRFS_BLOCK_GROUP_RAID0)
+               index = 3;
+       else
+               index = 4;
+       return index;
+}
+
 enum btrfs_loop_type {
        LOOP_FIND_IDEAL = 0,
        LOOP_CACHING_NOWAIT = 1,
@@ -4155,7 +4538,6 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans,
                                     u64 num_bytes, u64 empty_size,
                                     u64 search_start, u64 search_end,
                                     u64 hint_byte, struct btrfs_key *ins,
-                                    u64 exclude_start, u64 exclude_nr,
                                     int data)
 {
        int ret = 0;
@@ -4168,6 +4550,7 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans,
        struct btrfs_space_info *space_info;
        int last_ptr_loop = 0;
        int loop = 0;
+       int index = 0;
        bool found_uncached_bg = false;
        bool failed_cluster_refill = false;
        bool failed_alloc = false;
@@ -4237,6 +4620,7 @@ ideal_cache:
                                btrfs_put_block_group(block_group);
                                up_read(&space_info->groups_sem);
                        } else {
+                               index = get_block_group_index(block_group);
                                goto have_block_group;
                        }
                } else if (block_group) {
@@ -4245,7 +4629,8 @@ ideal_cache:
        }
 search:
        down_read(&space_info->groups_sem);
-       list_for_each_entry(block_group, &space_info->block_groups, list) {
+       list_for_each_entry(block_group, &space_info->block_groups[index],
+                           list) {
                u64 offset;
                int cached;
 
@@ -4436,23 +4821,22 @@ checks:
                        goto loop;
                }
 
-               if (exclude_nr > 0 &&
-                   (search_start + num_bytes > exclude_start &&
-                    search_start < exclude_start + exclude_nr)) {
-                       search_start = exclude_start + exclude_nr;
+               ins->objectid = search_start;
+               ins->offset = num_bytes;
+
+               if (offset < search_start)
+                       btrfs_add_free_space(block_group, offset,
+                                            search_start - offset);
+               BUG_ON(offset > search_start);
 
+               ret = update_reserved_bytes(block_group, num_bytes, 1,
+                                           (data & BTRFS_BLOCK_GROUP_DATA));
+               if (ret == -EAGAIN) {
                        btrfs_add_free_space(block_group, offset, num_bytes);
-                       /*
-                        * if search_start is still in this block group
-                        * then we just re-search this block group
-                        */
-                       if (search_start >= block_group->key.objectid &&
-                           search_start < (block_group->key.objectid +
-                                           block_group->key.offset))
-                               goto have_block_group;
                        goto loop;
                }
 
+               /* we are all good, lets return */
                ins->objectid = search_start;
                ins->offset = num_bytes;
 
@@ -4460,18 +4844,18 @@ checks:
                        btrfs_add_free_space(block_group, offset,
                                             search_start - offset);
                BUG_ON(offset > search_start);
-
-               update_reserved_extents(block_group, num_bytes, 1);
-
-               /* we are all good, lets return */
                break;
 loop:
                failed_cluster_refill = false;
                failed_alloc = false;
+               BUG_ON(index != get_block_group_index(block_group));
                btrfs_put_block_group(block_group);
        }
        up_read(&space_info->groups_sem);
 
+       if (!ins->objectid && ++index < BTRFS_NR_RAID_TYPES)
+               goto search;
+
        /* LOOP_FIND_IDEAL, only search caching/cached bg's, and don't wait for
         *                      for them to make caching progress.  Also
         *                      determine the best possible bg to cache
@@ -4485,6 +4869,7 @@ loop:
        if (!ins->objectid && loop < LOOP_NO_EMPTY_SIZE &&
            (found_uncached_bg || empty_size || empty_cluster ||
             allowed_chunk_alloc)) {
+               index = 0;
                if (loop == LOOP_FIND_IDEAL && found_uncached_bg) {
                        found_uncached_bg = false;
                        loop++;
@@ -4567,31 +4952,30 @@ static void dump_space_info(struct btrfs_space_info *info, u64 bytes,
                            int dump_block_groups)
 {
        struct btrfs_block_group_cache *cache;
+       int index = 0;
 
        spin_lock(&info->lock);
        printk(KERN_INFO "space_info has %llu free, is %sfull\n",
               (unsigned long long)(info->total_bytes - info->bytes_used -
                                    info->bytes_pinned - info->bytes_reserved -
-                                   info->bytes_super),
+                                   info->bytes_readonly),
               (info->full) ? "" : "not ");
-       printk(KERN_INFO "space_info total=%llu, pinned=%llu, delalloc=%llu,"
-              " may_use=%llu, used=%llu, root=%llu, super=%llu, reserved=%llu"
-              "\n",
+       printk(KERN_INFO "space_info total=%llu, used=%llu, pinned=%llu, "
+              "reserved=%llu, may_use=%llu, readonly=%llu\n",
               (unsigned long long)info->total_bytes,
+              (unsigned long long)info->bytes_used,
               (unsigned long long)info->bytes_pinned,
-              (unsigned long long)info->bytes_delalloc,
+              (unsigned long long)info->bytes_reserved,
               (unsigned long long)info->bytes_may_use,
-              (unsigned long long)info->bytes_used,
-              (unsigned long long)info->bytes_root,
-              (unsigned long long)info->bytes_super,
-              (unsigned long long)info->bytes_reserved);
+              (unsigned long long)info->bytes_readonly);
        spin_unlock(&info->lock);
 
        if (!dump_block_groups)
                return;
 
        down_read(&info->groups_sem);
-       list_for_each_entry(cache, &info->block_groups, list) {
+again:
+       list_for_each_entry(cache, &info->block_groups[index], list) {
                spin_lock(&cache->lock);
                printk(KERN_INFO "block group %llu has %llu bytes, %llu used "
                       "%llu pinned %llu reserved\n",
@@ -4603,6 +4987,8 @@ static void dump_space_info(struct btrfs_space_info *info, u64 bytes,
                btrfs_dump_free_space(cache, bytes);
                spin_unlock(&cache->lock);
        }
+       if (++index < BTRFS_NR_RAID_TYPES)
+               goto again;
        up_read(&info->groups_sem);
 }
 
@@ -4628,9 +5014,8 @@ again:
 
        WARN_ON(num_bytes < root->sectorsize);
        ret = find_free_extent(trans, root, num_bytes, empty_size,
-                              search_start, search_end, hint_byte, ins,
-                              trans->alloc_exclude_start,
-                              trans->alloc_exclude_nr, data);
+                              search_start, search_end, hint_byte,
+                              ins, data);
 
        if (ret == -ENOSPC && num_bytes > min_alloc_size) {
                num_bytes = num_bytes >> 1;
@@ -4668,7 +5053,7 @@ int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len)
        ret = btrfs_discard_extent(root, start, len);
 
        btrfs_add_free_space(cache, start, len);
-       update_reserved_extents(cache, len, 0);
+       update_reserved_bytes(cache, len, 0, 1);
        btrfs_put_block_group(cache);
 
        return ret;
@@ -4731,8 +5116,7 @@ static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
        btrfs_mark_buffer_dirty(path->nodes[0]);
        btrfs_free_path(path);
 
-       ret = update_block_group(trans, root, ins->objectid, ins->offset,
-                                1, 0);
+       ret = update_block_group(trans, root, ins->objectid, ins->offset, 1);
        if (ret) {
                printk(KERN_ERR "btrfs update block group failed for %llu "
                       "%llu\n", (unsigned long long)ins->objectid,
@@ -4792,8 +5176,7 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
        btrfs_mark_buffer_dirty(leaf);
        btrfs_free_path(path);
 
-       ret = update_block_group(trans, root, ins->objectid, ins->offset,
-                                1, 0);
+       ret = update_block_group(trans, root, ins->objectid, ins->offset, 1);
        if (ret) {
                printk(KERN_ERR "btrfs update block group failed for %llu "
                       "%llu\n", (unsigned long long)ins->objectid,
@@ -4869,73 +5252,14 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans,
                put_caching_control(caching_ctl);
        }
 
-       update_reserved_extents(block_group, ins->offset, 1);
+       ret = update_reserved_bytes(block_group, ins->offset, 1, 1);
+       BUG_ON(ret);
        btrfs_put_block_group(block_group);
        ret = alloc_reserved_file_extent(trans, root, 0, root_objectid,
                                         0, owner, offset, ins, 1);
        return ret;
 }
 
-/*
- * finds a free extent and does all the dirty work required for allocation
- * returns the key for the extent through ins, and a tree buffer for
- * the first block of the extent through buf.
- *
- * returns 0 if everything worked, non-zero otherwise.
- */
-static int alloc_tree_block(struct btrfs_trans_handle *trans,
-                           struct btrfs_root *root,
-                           u64 num_bytes, u64 parent, u64 root_objectid,
-                           struct btrfs_disk_key *key, int level,
-                           u64 empty_size, u64 hint_byte, u64 search_end,
-                           struct btrfs_key *ins)
-{
-       int ret;
-       u64 flags = 0;
-
-       ret = btrfs_reserve_extent(trans, root, num_bytes, num_bytes,
-                                  empty_size, hint_byte, search_end,
-                                  ins, 0);
-       if (ret)
-               return ret;
-
-       if (root_objectid == BTRFS_TREE_RELOC_OBJECTID) {
-               if (parent == 0)
-                       parent = ins->objectid;
-               flags |= BTRFS_BLOCK_FLAG_FULL_BACKREF;
-       } else
-               BUG_ON(parent > 0);
-
-       if (root_objectid != BTRFS_TREE_LOG_OBJECTID) {
-               struct btrfs_delayed_extent_op *extent_op;
-               extent_op = kmalloc(sizeof(*extent_op), GFP_NOFS);
-               BUG_ON(!extent_op);
-               if (key)
-                       memcpy(&extent_op->key, key, sizeof(extent_op->key));
-               else
-                       memset(&extent_op->key, 0, sizeof(extent_op->key));
-               extent_op->flags_to_set = flags;
-               extent_op->update_key = 1;
-               extent_op->update_flags = 1;
-               extent_op->is_data = 0;
-
-               ret = btrfs_add_delayed_tree_ref(trans, ins->objectid,
-                                       ins->offset, parent, root_objectid,
-                                       level, BTRFS_ADD_DELAYED_EXTENT,
-                                       extent_op);
-               BUG_ON(ret);
-       }
-
-       if (root_objectid == root->root_key.objectid) {
-               u64 used;
-               spin_lock(&root->node_lock);
-               used = btrfs_root_used(&root->root_item) + num_bytes;
-               btrfs_set_root_used(&root->root_item, used);
-               spin_unlock(&root->node_lock);
-       }
-       return ret;
-}
-
 struct extent_buffer *btrfs_init_new_buffer(struct btrfs_trans_handle *trans,
                                            struct btrfs_root *root,
                                            u64 bytenr, u32 blocksize,
@@ -4974,8 +5298,45 @@ struct extent_buffer *btrfs_init_new_buffer(struct btrfs_trans_handle *trans,
        return buf;
 }
 
+static struct btrfs_block_rsv *
+use_block_rsv(struct btrfs_trans_handle *trans,
+             struct btrfs_root *root, u32 blocksize)
+{
+       struct btrfs_block_rsv *block_rsv;
+       int ret;
+
+       block_rsv = get_block_rsv(trans, root);
+
+       if (block_rsv->size == 0) {
+               ret = reserve_metadata_bytes(block_rsv, blocksize);
+               if (ret)
+                       return ERR_PTR(ret);
+               return block_rsv;
+       }
+
+       ret = block_rsv_use_bytes(block_rsv, blocksize);
+       if (!ret)
+               return block_rsv;
+
+       WARN_ON(1);
+       printk(KERN_INFO"block_rsv size %llu reserved %llu freed %llu %llu\n",
+               block_rsv->size, block_rsv->reserved,
+               block_rsv->freed[0], block_rsv->freed[1]);
+
+       return ERR_PTR(-ENOSPC);
+}
+
+static void unuse_block_rsv(struct btrfs_block_rsv *block_rsv, u32 blocksize)
+{
+       block_rsv_add_bytes(block_rsv, blocksize, 0);
+       block_rsv_release_bytes(block_rsv, NULL, 0);
+}
+
 /*
- * helper function to allocate a block for a given tree
+ * finds a free extent and does all the dirty work required for allocation
+ * returns the key for the extent through ins, and a tree buffer for
+ * the first block of the extent through buf.
+ *
  * returns the tree buffer or NULL.
  */
 struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
@@ -4985,18 +5346,53 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
                                        u64 hint, u64 empty_size)
 {
        struct btrfs_key ins;
-       int ret;
+       struct btrfs_block_rsv *block_rsv;
        struct extent_buffer *buf;
+       u64 flags = 0;
+       int ret;
+
 
-       ret = alloc_tree_block(trans, root, blocksize, parent, root_objectid,
-                              key, level, empty_size, hint, (u64)-1, &ins);
+       block_rsv = use_block_rsv(trans, root, blocksize);
+       if (IS_ERR(block_rsv))
+               return ERR_CAST(block_rsv);
+
+       ret = btrfs_reserve_extent(trans, root, blocksize, blocksize,
+                                  empty_size, hint, (u64)-1, &ins, 0);
        if (ret) {
-               BUG_ON(ret > 0);
+               unuse_block_rsv(block_rsv, blocksize);
                return ERR_PTR(ret);
        }
 
        buf = btrfs_init_new_buffer(trans, root, ins.objectid,
                                    blocksize, level);
+       BUG_ON(IS_ERR(buf));
+
+       if (root_objectid == BTRFS_TREE_RELOC_OBJECTID) {
+               if (parent == 0)
+                       parent = ins.objectid;
+               flags |= BTRFS_BLOCK_FLAG_FULL_BACKREF;
+       } else
+               BUG_ON(parent > 0);
+
+       if (root_objectid != BTRFS_TREE_LOG_OBJECTID) {
+               struct btrfs_delayed_extent_op *extent_op;
+               extent_op = kmalloc(sizeof(*extent_op), GFP_NOFS);
+               BUG_ON(!extent_op);
+               if (key)
+                       memcpy(&extent_op->key, key, sizeof(extent_op->key));
+               else
+                       memset(&extent_op->key, 0, sizeof(extent_op->key));
+               extent_op->flags_to_set = flags;
+               extent_op->update_key = 1;
+               extent_op->update_flags = 1;
+               extent_op->is_data = 0;
+
+               ret = btrfs_add_delayed_tree_ref(trans, ins.objectid,
+                                       ins.offset, parent, root_objectid,
+                                       level, BTRFS_ADD_DELAYED_EXTENT,
+                                       extent_op);
+               BUG_ON(ret);
+       }
        return buf;
 }
 
@@ -5321,7 +5717,7 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans,
                                 struct btrfs_path *path,
                                 struct walk_control *wc)
 {
-       int ret = 0;
+       int ret;
        int level = wc->level;
        struct extent_buffer *eb = path->nodes[level];
        u64 parent = 0;
@@ -5399,13 +5795,11 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans,
                               btrfs_header_owner(path->nodes[level + 1]));
        }
 
-       ret = btrfs_free_extent(trans, root, eb->start, eb->len, parent,
-                               root->root_key.objectid, level, 0);
-       BUG_ON(ret);
+       btrfs_free_tree_block(trans, root, eb, parent, wc->refs[level] == 1);
 out:
        wc->refs[level] = 0;
        wc->flags[level] = 0;
-       return ret;
+       return 0;
 }
 
 static noinline int walk_down_tree(struct btrfs_trans_handle *trans,
@@ -5483,7 +5877,8 @@ static noinline int walk_up_tree(struct btrfs_trans_handle *trans,
  * also make sure backrefs for the shared block and all lower level
  * blocks are properly updated.
  */
-int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref)
+int btrfs_drop_snapshot(struct btrfs_root *root,
+                       struct btrfs_block_rsv *block_rsv, int update_ref)
 {
        struct btrfs_path *path;
        struct btrfs_trans_handle *trans;
@@ -5501,7 +5896,9 @@ int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref)
        wc = kzalloc(sizeof(*wc), GFP_NOFS);
        BUG_ON(!wc);
 
-       trans = btrfs_start_transaction(tree_root, 1);
+       trans = btrfs_start_transaction(tree_root, 0);
+       if (block_rsv)
+               trans->block_rsv = block_rsv;
 
        if (btrfs_disk_key_objectid(&root_item->drop_progress) == 0) {
                level = btrfs_header_level(root->node);
@@ -5589,22 +5986,16 @@ int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref)
                }
 
                BUG_ON(wc->level == 0);
-               if (trans->transaction->in_commit ||
-                   trans->transaction->delayed_refs.flushing) {
+               if (btrfs_should_end_transaction(trans, tree_root)) {
                        ret = btrfs_update_root(trans, tree_root,
                                                &root->root_key,
                                                root_item);
                        BUG_ON(ret);
 
-                       btrfs_end_transaction(trans, tree_root);
-                       trans = btrfs_start_transaction(tree_root, 1);
-               } else {
-                       unsigned long update;
-                       update = trans->delayed_ref_updates;
-                       trans->delayed_ref_updates = 0;
-                       if (update)
-                               btrfs_run_delayed_refs(trans, tree_root,
-                                                      update);
+                       btrfs_end_transaction_throttle(trans, tree_root);
+                       trans = btrfs_start_transaction(tree_root, 0);
+                       if (block_rsv)
+                               trans->block_rsv = block_rsv;
                }
        }
        btrfs_release_path(root, path);
@@ -5632,7 +6023,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref)
                kfree(root);
        }
 out:
-       btrfs_end_transaction(trans, tree_root);
+       btrfs_end_transaction_throttle(trans, tree_root);
        kfree(wc);
        btrfs_free_path(path);
        return err;
@@ -7228,48 +7619,80 @@ static u64 update_block_group_flags(struct btrfs_root *root, u64 flags)
        return flags;
 }
 
-static int __alloc_chunk_for_shrink(struct btrfs_root *root,
-                    struct btrfs_block_group_cache *shrink_block_group,
-                    int force)
+static int set_block_group_ro(struct btrfs_block_group_cache *cache)
 {
-       struct btrfs_trans_handle *trans;
-       u64 new_alloc_flags;
-       u64 calc;
+       struct btrfs_space_info *sinfo = cache->space_info;
+       u64 num_bytes;
+       int ret = -ENOSPC;
 
-       spin_lock(&shrink_block_group->lock);
-       if (btrfs_block_group_used(&shrink_block_group->item) +
-           shrink_block_group->reserved > 0) {
-               spin_unlock(&shrink_block_group->lock);
+       if (cache->ro)
+               return 0;
 
-               trans = btrfs_start_transaction(root, 1);
-               spin_lock(&shrink_block_group->lock);
+       spin_lock(&sinfo->lock);
+       spin_lock(&cache->lock);
+       num_bytes = cache->key.offset - cache->reserved - cache->pinned -
+                   cache->bytes_super - btrfs_block_group_used(&cache->item);
+
+       if (sinfo->bytes_used + sinfo->bytes_reserved + sinfo->bytes_pinned +
+           sinfo->bytes_may_use + sinfo->bytes_readonly +
+           cache->reserved_pinned + num_bytes < sinfo->total_bytes) {
+               sinfo->bytes_readonly += num_bytes;
+               sinfo->bytes_reserved += cache->reserved_pinned;
+               cache->reserved_pinned = 0;
+               cache->ro = 1;
+               ret = 0;
+       }
+       spin_unlock(&cache->lock);
+       spin_unlock(&sinfo->lock);
+       return ret;
+}
 
-               new_alloc_flags = update_block_group_flags(root,
-                                                  shrink_block_group->flags);
-               if (new_alloc_flags != shrink_block_group->flags) {
-                       calc =
-                            btrfs_block_group_used(&shrink_block_group->item);
-               } else {
-                       calc = shrink_block_group->key.offset;
-               }
-               spin_unlock(&shrink_block_group->lock);
+int btrfs_set_block_group_ro(struct btrfs_root *root,
+                            struct btrfs_block_group_cache *cache)
 
-               do_chunk_alloc(trans, root->fs_info->extent_root,
-                              calc + 2 * 1024 * 1024, new_alloc_flags, force);
+{
+       struct btrfs_trans_handle *trans;
+       u64 alloc_flags;
+       int ret;
 
-               btrfs_end_transaction(trans, root);
-       } else
-               spin_unlock(&shrink_block_group->lock);
-       return 0;
-}
+       BUG_ON(cache->ro);
 
+       trans = btrfs_join_transaction(root, 1);
+       BUG_ON(IS_ERR(trans));
 
-int btrfs_prepare_block_group_relocation(struct btrfs_root *root,
-                                        struct btrfs_block_group_cache *group)
+       alloc_flags = update_block_group_flags(root, cache->flags);
+       if (alloc_flags != cache->flags)
+               do_chunk_alloc(trans, root, 2 * 1024 * 1024, alloc_flags, 1);
+
+       ret = set_block_group_ro(cache);
+       if (!ret)
+               goto out;
+       alloc_flags = get_alloc_profile(root, cache->space_info->flags);
+       ret = do_chunk_alloc(trans, root, 2 * 1024 * 1024, alloc_flags, 1);
+       if (ret < 0)
+               goto out;
+       ret = set_block_group_ro(cache);
+out:
+       btrfs_end_transaction(trans, root);
+       return ret;
+}
 
+int btrfs_set_block_group_rw(struct btrfs_root *root,
+                             struct btrfs_block_group_cache *cache)
 {
-       __alloc_chunk_for_shrink(root, group, 1);
-       set_block_group_readonly(group);
+       struct btrfs_space_info *sinfo = cache->space_info;
+       u64 num_bytes;
+
+       BUG_ON(!cache->ro);
+
+       spin_lock(&sinfo->lock);
+       spin_lock(&cache->lock);
+       num_bytes = cache->key.offset - cache->reserved - cache->pinned -
+                   cache->bytes_super - btrfs_block_group_used(&cache->item);
+       sinfo->bytes_readonly -= num_bytes;
+       cache->ro = 0;
+       spin_unlock(&cache->lock);
+       spin_unlock(&sinfo->lock);
        return 0;
 }
 
@@ -7436,17 +7859,33 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
         */
        synchronize_rcu();
 
+       release_global_block_rsv(info);
+
        while(!list_empty(&info->space_info)) {
                space_info = list_entry(info->space_info.next,
                                        struct btrfs_space_info,
                                        list);
-
+               if (space_info->bytes_pinned > 0 ||
+                   space_info->bytes_reserved > 0) {
+                       WARN_ON(1);
+                       dump_space_info(space_info, 0, 0);
+               }
                list_del(&space_info->list);
                kfree(space_info);
        }
        return 0;
 }
 
+static void __link_block_group(struct btrfs_space_info *space_info,
+                              struct btrfs_block_group_cache *cache)
+{
+       int index = get_block_group_index(cache);
+
+       down_write(&space_info->groups_sem);
+       list_add_tail(&cache->list, &space_info->block_groups[index]);
+       up_write(&space_info->groups_sem);
+}
+
 int btrfs_read_block_groups(struct btrfs_root *root)
 {
        struct btrfs_path *path;
@@ -7468,10 +7907,8 @@ int btrfs_read_block_groups(struct btrfs_root *root)
 
        while (1) {
                ret = find_first_block_group(root, path, &key);
-               if (ret > 0) {
-                       ret = 0;
-                       goto error;
-               }
+               if (ret > 0)
+                       break;
                if (ret != 0)
                        goto error;
 
@@ -7480,7 +7917,7 @@ int btrfs_read_block_groups(struct btrfs_root *root)
                cache = kzalloc(sizeof(*cache), GFP_NOFS);
                if (!cache) {
                        ret = -ENOMEM;
-                       break;
+                       goto error;
                }
 
                atomic_set(&cache->count, 1);
@@ -7537,20 +7974,36 @@ int btrfs_read_block_groups(struct btrfs_root *root)
                BUG_ON(ret);
                cache->space_info = space_info;
                spin_lock(&cache->space_info->lock);
-               cache->space_info->bytes_super += cache->bytes_super;
+               cache->space_info->bytes_readonly += cache->bytes_super;
                spin_unlock(&cache->space_info->lock);
 
-               down_write(&space_info->groups_sem);
-               list_add_tail(&cache->list, &space_info->block_groups);
-               up_write(&space_info->groups_sem);
+               __link_block_group(space_info, cache);
 
                ret = btrfs_add_block_group_cache(root->fs_info, cache);
                BUG_ON(ret);
 
                set_avail_alloc_bits(root->fs_info, cache->flags);
                if (btrfs_chunk_readonly(root, cache->key.objectid))
-                       set_block_group_readonly(cache);
+                       set_block_group_ro(cache);
+       }
+
+       list_for_each_entry_rcu(space_info, &root->fs_info->space_info, list) {
+               if (!(get_alloc_profile(root, space_info->flags) &
+                     (BTRFS_BLOCK_GROUP_RAID10 |
+                      BTRFS_BLOCK_GROUP_RAID1 |
+                      BTRFS_BLOCK_GROUP_DUP)))
+                       continue;
+               /*
+                * avoid allocating from un-mirrored block group if there are
+                * mirrored block groups.
+                */
+               list_for_each_entry(cache, &space_info->block_groups[3], list)
+                       set_block_group_ro(cache);
+               list_for_each_entry(cache, &space_info->block_groups[4], list)
+                       set_block_group_ro(cache);
        }
+
+       init_global_block_rsv(info);
        ret = 0;
 error:
        btrfs_free_path(path);
@@ -7611,12 +8064,10 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
        BUG_ON(ret);
 
        spin_lock(&cache->space_info->lock);
-       cache->space_info->bytes_super += cache->bytes_super;
+       cache->space_info->bytes_readonly += cache->bytes_super;
        spin_unlock(&cache->space_info->lock);
 
-       down_write(&cache->space_info->groups_sem);
-       list_add_tail(&cache->list, &cache->space_info->block_groups);
-       up_write(&cache->space_info->groups_sem);
+       __link_block_group(cache->space_info, cache);
 
        ret = btrfs_add_block_group_cache(root->fs_info, cache);
        BUG_ON(ret);
index d2d03684fab261fb9663f1d18ef19d9f23d98b78..a4080c21ec55377b4e5e60fc5bc8fa59e032a1ee 100644 (file)
@@ -135,7 +135,7 @@ static struct extent_state *alloc_extent_state(gfp_t mask)
        return state;
 }
 
-static void free_extent_state(struct extent_state *state)
+void free_extent_state(struct extent_state *state)
 {
        if (!state)
                return;
@@ -335,21 +335,18 @@ static int merge_state(struct extent_io_tree *tree,
 }
 
 static int set_state_cb(struct extent_io_tree *tree,
-                        struct extent_state *state,
-                        unsigned long bits)
+                        struct extent_state *state, int *bits)
 {
        if (tree->ops && tree->ops->set_bit_hook) {
                return tree->ops->set_bit_hook(tree->mapping->host,
-                                              state->start, state->end,
-                                              state->state, bits);
+                                              state, bits);
        }
 
        return 0;
 }
 
 static void clear_state_cb(struct extent_io_tree *tree,
-                          struct extent_state *state,
-                          unsigned long bits)
+                          struct extent_state *state, int *bits)
 {
        if (tree->ops && tree->ops->clear_bit_hook)
                tree->ops->clear_bit_hook(tree->mapping->host, state, bits);
@@ -367,9 +364,10 @@ static void clear_state_cb(struct extent_io_tree *tree,
  */
 static int insert_state(struct extent_io_tree *tree,
                        struct extent_state *state, u64 start, u64 end,
-                       int bits)
+                       int *bits)
 {
        struct rb_node *node;
+       int bits_to_set = *bits & ~EXTENT_CTLBITS;
        int ret;
 
        if (end < start) {
@@ -384,9 +382,9 @@ static int insert_state(struct extent_io_tree *tree,
        if (ret)
                return ret;
 
-       if (bits & EXTENT_DIRTY)
+       if (bits_to_set & EXTENT_DIRTY)
                tree->dirty_bytes += end - start + 1;
-       state->state |= bits;
+       state->state |= bits_to_set;
        node = tree_insert(&tree->state, end, &state->rb_node);
        if (node) {
                struct extent_state *found;
@@ -456,13 +454,13 @@ static int split_state(struct extent_io_tree *tree, struct extent_state *orig,
  * struct is freed and removed from the tree
  */
 static int clear_state_bit(struct extent_io_tree *tree,
-                           struct extent_state *state, int bits, int wake,
-                           int delete)
+                           struct extent_state *state,
+                           int *bits, int wake)
 {
-       int bits_to_clear = bits & ~EXTENT_DO_ACCOUNTING;
+       int bits_to_clear = *bits & ~EXTENT_CTLBITS;
        int ret = state->state & bits_to_clear;
 
-       if ((bits & EXTENT_DIRTY) && (state->state & EXTENT_DIRTY)) {
+       if ((bits_to_clear & EXTENT_DIRTY) && (state->state & EXTENT_DIRTY)) {
                u64 range = state->end - state->start + 1;
                WARN_ON(range > tree->dirty_bytes);
                tree->dirty_bytes -= range;
@@ -471,9 +469,8 @@ static int clear_state_bit(struct extent_io_tree *tree,
        state->state &= ~bits_to_clear;
        if (wake)
                wake_up(&state->wq);
-       if (delete || state->state == 0) {
+       if (state->state == 0) {
                if (state->tree) {
-                       clear_state_cb(tree, state, state->state);
                        rb_erase(&state->rb_node, &tree->state);
                        state->tree = NULL;
                        free_extent_state(state);
@@ -514,6 +511,10 @@ int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
        int set = 0;
        int clear = 0;
 
+       if (delete)
+               bits |= ~EXTENT_CTLBITS;
+       bits |= EXTENT_FIRST_DELALLOC;
+
        if (bits & (EXTENT_IOBITS | EXTENT_BOUNDARY))
                clear = 1;
 again:
@@ -580,8 +581,7 @@ hit_next:
                if (err)
                        goto out;
                if (state->end <= end) {
-                       set |= clear_state_bit(tree, state, bits, wake,
-                                              delete);
+                       set |= clear_state_bit(tree, state, &bits, wake);
                        if (last_end == (u64)-1)
                                goto out;
                        start = last_end + 1;
@@ -602,7 +602,7 @@ hit_next:
                if (wake)
                        wake_up(&state->wq);
 
-               set |= clear_state_bit(tree, prealloc, bits, wake, delete);
+               set |= clear_state_bit(tree, prealloc, &bits, wake);
 
                prealloc = NULL;
                goto out;
@@ -613,7 +613,7 @@ hit_next:
        else
                next_node = NULL;
 
-       set |= clear_state_bit(tree, state, bits, wake, delete);
+       set |= clear_state_bit(tree, state, &bits, wake);
        if (last_end == (u64)-1)
                goto out;
        start = last_end + 1;
@@ -706,19 +706,19 @@ out:
 
 static int set_state_bits(struct extent_io_tree *tree,
                           struct extent_state *state,
-                          int bits)
+                          int *bits)
 {
        int ret;
+       int bits_to_set = *bits & ~EXTENT_CTLBITS;
 
        ret = set_state_cb(tree, state, bits);
        if (ret)
                return ret;
-
-       if ((bits & EXTENT_DIRTY) && !(state->state & EXTENT_DIRTY)) {
+       if ((bits_to_set & EXTENT_DIRTY) && !(state->state & EXTENT_DIRTY)) {
                u64 range = state->end - state->start + 1;
                tree->dirty_bytes += range;
        }
-       state->state |= bits;
+       state->state |= bits_to_set;
 
        return 0;
 }
@@ -745,10 +745,9 @@ static void cache_state(struct extent_state *state,
  * [start, end] is inclusive This takes the tree lock.
  */
 
-static int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
-                         int bits, int exclusive_bits, u64 *failed_start,
-                         struct extent_state **cached_state,
-                         gfp_t mask)
+int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
+                  int bits, int exclusive_bits, u64 *failed_start,
+                  struct extent_state **cached_state, gfp_t mask)
 {
        struct extent_state *state;
        struct extent_state *prealloc = NULL;
@@ -757,6 +756,7 @@ static int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
        u64 last_start;
        u64 last_end;
 
+       bits |= EXTENT_FIRST_DELALLOC;
 again:
        if (!prealloc && (mask & __GFP_WAIT)) {
                prealloc = alloc_extent_state(mask);
@@ -778,7 +778,7 @@ again:
         */
        node = tree_search(tree, start);
        if (!node) {
-               err = insert_state(tree, prealloc, start, end, bits);
+               err = insert_state(tree, prealloc, start, end, &bits);
                prealloc = NULL;
                BUG_ON(err == -EEXIST);
                goto out;
@@ -802,7 +802,7 @@ hit_next:
                        goto out;
                }
 
-               err = set_state_bits(tree, state, bits);
+               err = set_state_bits(tree, state, &bits);
                if (err)
                        goto out;
 
@@ -852,7 +852,7 @@ hit_next:
                if (err)
                        goto out;
                if (state->end <= end) {
-                       err = set_state_bits(tree, state, bits);
+                       err = set_state_bits(tree, state, &bits);
                        if (err)
                                goto out;
                        cache_state(state, cached_state);
@@ -877,7 +877,7 @@ hit_next:
                else
                        this_end = last_start - 1;
                err = insert_state(tree, prealloc, start, this_end,
-                                  bits);
+                                  &bits);
                BUG_ON(err == -EEXIST);
                if (err) {
                        prealloc = NULL;
@@ -903,7 +903,7 @@ hit_next:
                err = split_state(tree, state, prealloc, end + 1);
                BUG_ON(err == -EEXIST);
 
-               err = set_state_bits(tree, prealloc, bits);
+               err = set_state_bits(tree, prealloc, &bits);
                if (err) {
                        prealloc = NULL;
                        goto out;
@@ -966,8 +966,7 @@ int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end,
 {
        return clear_extent_bit(tree, start, end,
                                EXTENT_DIRTY | EXTENT_DELALLOC |
-                               EXTENT_DO_ACCOUNTING, 0, 0,
-                               NULL, mask);
+                               EXTENT_DO_ACCOUNTING, 0, 0, NULL, mask);
 }
 
 int set_extent_new(struct extent_io_tree *tree, u64 start, u64 end,
@@ -1435,9 +1434,6 @@ int extent_clear_unlock_delalloc(struct inode *inode,
        if (op & EXTENT_CLEAR_DELALLOC)
                clear_bits |= EXTENT_DELALLOC;
 
-       if (op & EXTENT_CLEAR_ACCOUNTING)
-               clear_bits |= EXTENT_DO_ACCOUNTING;
-
        clear_extent_bit(tree, start, end, clear_bits, 1, 0, NULL, GFP_NOFS);
        if (!(op & (EXTENT_CLEAR_UNLOCK_PAGE | EXTENT_CLEAR_DIRTY |
                    EXTENT_SET_WRITEBACK | EXTENT_END_WRITEBACK |
@@ -1916,7 +1912,7 @@ static int submit_one_bio(int rw, struct bio *bio, int mirror_num,
 
        if (tree->ops && tree->ops->submit_bio_hook)
                tree->ops->submit_bio_hook(page->mapping->host, rw, bio,
-                                          mirror_num, bio_flags);
+                                          mirror_num, bio_flags, start);
        else
                submit_bio(rw, bio);
        if (bio_flagged(bio, BIO_EOPNOTSUPP))
@@ -2020,6 +2016,7 @@ static int __extent_read_full_page(struct extent_io_tree *tree,
        sector_t sector;
        struct extent_map *em;
        struct block_device *bdev;
+       struct btrfs_ordered_extent *ordered;
        int ret;
        int nr = 0;
        size_t page_offset = 0;
@@ -2031,7 +2028,15 @@ static int __extent_read_full_page(struct extent_io_tree *tree,
        set_page_extent_mapped(page);
 
        end = page_end;
-       lock_extent(tree, start, end, GFP_NOFS);
+       while (1) {
+               lock_extent(tree, start, end, GFP_NOFS);
+               ordered = btrfs_lookup_ordered_extent(inode, start);
+               if (!ordered)
+                       break;
+               unlock_extent(tree, start, end, GFP_NOFS);
+               btrfs_start_ordered_extent(inode, ordered, 1);
+               btrfs_put_ordered_extent(ordered);
+       }
 
        if (page->index == last_byte >> PAGE_CACHE_SHIFT) {
                char *userpage;
index bbab4813646f92a2df9c462daabde89b452826ab..5691c7b590dae86844ccbeccecdb5d8a2b3e2554 100644 (file)
@@ -16,7 +16,9 @@
 #define EXTENT_BOUNDARY (1 << 9)
 #define EXTENT_NODATASUM (1 << 10)
 #define EXTENT_DO_ACCOUNTING (1 << 11)
+#define EXTENT_FIRST_DELALLOC (1 << 12)
 #define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK)
+#define EXTENT_CTLBITS (EXTENT_DO_ACCOUNTING | EXTENT_FIRST_DELALLOC)
 
 /* flags for bio submission */
 #define EXTENT_BIO_COMPRESSED 1
@@ -47,7 +49,7 @@ struct extent_state;
 
 typedef        int (extent_submit_bio_hook_t)(struct inode *inode, int rw,
                                       struct bio *bio, int mirror_num,
-                                      unsigned long bio_flags);
+                                      unsigned long bio_flags, u64 bio_offset);
 struct extent_io_ops {
        int (*fill_delalloc)(struct inode *inode, struct page *locked_page,
                             u64 start, u64 end, int *page_started,
@@ -69,10 +71,10 @@ struct extent_io_ops {
                                    struct extent_state *state);
        int (*writepage_end_io_hook)(struct page *page, u64 start, u64 end,
                                      struct extent_state *state, int uptodate);
-       int (*set_bit_hook)(struct inode *inode, u64 start, u64 end,
-                           unsigned long old, unsigned long bits);
+       int (*set_bit_hook)(struct inode *inode, struct extent_state *state,
+                           int *bits);
        int (*clear_bit_hook)(struct inode *inode, struct extent_state *state,
-                             unsigned long bits);
+                             int *bits);
        int (*merge_extent_hook)(struct inode *inode,
                                 struct extent_state *new,
                                 struct extent_state *other);
@@ -176,6 +178,7 @@ u64 count_range_bits(struct extent_io_tree *tree,
                     u64 *start, u64 search_end,
                     u64 max_bytes, unsigned long bits);
 
+void free_extent_state(struct extent_state *state);
 int test_range_bit(struct extent_io_tree *tree, u64 start, u64 end,
                   int bits, int filled, struct extent_state *cached_state);
 int clear_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
@@ -185,6 +188,9 @@ int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
                     gfp_t mask);
 int set_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
                    int bits, gfp_t mask);
+int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
+                  int bits, int exclusive_bits, u64 *failed_start,
+                  struct extent_state **cached_state, gfp_t mask);
 int set_extent_uptodate(struct extent_io_tree *tree, u64 start, u64 end,
                        gfp_t mask);
 int set_extent_new(struct extent_io_tree *tree, u64 start, u64 end,
index 54a255065aa3235a7672d64f5fcf506615ae8ef3..a562a250ae773f9c6607ac2034b8ed84bf28e784 100644 (file)
@@ -149,13 +149,14 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
 }
 
 
-int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode,
-                         struct bio *bio, u32 *dst)
+static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
+                                  struct inode *inode, struct bio *bio,
+                                  u64 logical_offset, u32 *dst, int dio)
 {
        u32 sum;
        struct bio_vec *bvec = bio->bi_io_vec;
        int bio_index = 0;
-       u64 offset;
+       u64 offset = 0;
        u64 item_start_offset = 0;
        u64 item_last_offset = 0;
        u64 disk_bytenr;
@@ -174,8 +175,11 @@ int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode,
        WARN_ON(bio->bi_vcnt <= 0);
 
        disk_bytenr = (u64)bio->bi_sector << 9;
+       if (dio)
+               offset = logical_offset;
        while (bio_index < bio->bi_vcnt) {
-               offset = page_offset(bvec->bv_page) + bvec->bv_offset;
+               if (!dio)
+                       offset = page_offset(bvec->bv_page) + bvec->bv_offset;
                ret = btrfs_find_ordered_sum(inode, offset, disk_bytenr, &sum);
                if (ret == 0)
                        goto found;
@@ -238,6 +242,7 @@ found:
                else
                        set_state_private(io_tree, offset, sum);
                disk_bytenr += bvec->bv_len;
+               offset += bvec->bv_len;
                bio_index++;
                bvec++;
        }
@@ -245,6 +250,18 @@ found:
        return 0;
 }
 
+int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode,
+                         struct bio *bio, u32 *dst)
+{
+       return __btrfs_lookup_bio_sums(root, inode, bio, 0, dst, 0);
+}
+
+int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode,
+                             struct bio *bio, u64 offset, u32 *dst)
+{
+       return __btrfs_lookup_bio_sums(root, inode, bio, offset, dst, 1);
+}
+
 int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
                             struct list_head *list)
 {
@@ -657,6 +674,9 @@ again:
                goto found;
        }
        ret = PTR_ERR(item);
+       if (ret != -EFBIG && ret != -ENOENT)
+               goto fail_unlock;
+
        if (ret == -EFBIG) {
                u32 item_size;
                /* we found one, but it isn't big enough yet */
index 29ff749ff4caaa35386f35173b169502e9ac3ded..787b50a16a146eea9bb4ec4202fcdab1f3f4bec0 100644 (file)
 static noinline int btrfs_copy_from_user(loff_t pos, int num_pages,
                                         int write_bytes,
                                         struct page **prepared_pages,
-                                        const char __user *buf)
+                                        struct iov_iter *i)
 {
-       long page_fault = 0;
-       int i;
+       size_t copied;
+       int pg = 0;
        int offset = pos & (PAGE_CACHE_SIZE - 1);
 
-       for (i = 0; i < num_pages && write_bytes > 0; i++, offset = 0) {
+       while (write_bytes > 0) {
                size_t count = min_t(size_t,
                                     PAGE_CACHE_SIZE - offset, write_bytes);
-               struct page *page = prepared_pages[i];
-               fault_in_pages_readable(buf, count);
+               struct page *page = prepared_pages[pg];
+again:
+               if (unlikely(iov_iter_fault_in_readable(i, count)))
+                       return -EFAULT;
 
                /* Copy data from userspace to the current page */
-               kmap(page);
-               page_fault = __copy_from_user(page_address(page) + offset,
-                                             buf, count);
+               copied = iov_iter_copy_from_user(page, i, offset, count);
+
                /* Flush processor's dcache for this page */
                flush_dcache_page(page);
-               kunmap(page);
-               buf += count;
-               write_bytes -= count;
+               iov_iter_advance(i, copied);
+               write_bytes -= copied;
 
-               if (page_fault)
-                       break;
+               if (unlikely(copied == 0)) {
+                       count = min_t(size_t, PAGE_CACHE_SIZE - offset,
+                                     iov_iter_single_seg_count(i));
+                       goto again;
+               }
+
+               if (unlikely(copied < PAGE_CACHE_SIZE - offset)) {
+                       offset += copied;
+               } else {
+                       pg++;
+                       offset = 0;
+               }
        }
-       return page_fault ? -EFAULT : 0;
+       return 0;
 }
 
 /*
@@ -126,8 +136,7 @@ static noinline int dirty_and_release_pages(struct btrfs_trans_handle *trans,
        end_of_last_block = start_pos + num_bytes - 1;
        err = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block,
                                        NULL);
-       if (err)
-               return err;
+       BUG_ON(err);
 
        for (i = 0; i < num_pages; i++) {
                struct page *p = pages[i];
@@ -142,7 +151,7 @@ static noinline int dirty_and_release_pages(struct btrfs_trans_handle *trans,
                 * at this time.
                 */
        }
-       return err;
+       return 0;
 }
 
 /*
@@ -823,45 +832,46 @@ again:
        return 0;
 }
 
-static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
-                               size_t count, loff_t *ppos)
+static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
+                                   const struct iovec *iov,
+                                   unsigned long nr_segs, loff_t pos)
 {
-       loff_t pos;
+       struct file *file = iocb->ki_filp;
+       struct inode *inode = fdentry(file)->d_inode;
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       struct page *pinned[2];
+       struct page **pages = NULL;
+       struct iov_iter i;
+       loff_t *ppos = &iocb->ki_pos;
        loff_t start_pos;
        ssize_t num_written = 0;
        ssize_t err = 0;
+       size_t count;
+       size_t ocount;
        int ret = 0;
-       struct inode *inode = fdentry(file)->d_inode;
-       struct btrfs_root *root = BTRFS_I(inode)->root;
-       struct page **pages = NULL;
        int nrptrs;
-       struct page *pinned[2];
        unsigned long first_index;
        unsigned long last_index;
        int will_write;
+       int buffered = 0;
 
        will_write = ((file->f_flags & O_DSYNC) || IS_SYNC(inode) ||
                      (file->f_flags & O_DIRECT));
 
-       nrptrs = min((count + PAGE_CACHE_SIZE - 1) / PAGE_CACHE_SIZE,
-                    PAGE_CACHE_SIZE / (sizeof(struct page *)));
        pinned[0] = NULL;
        pinned[1] = NULL;
 
-       pos = *ppos;
        start_pos = pos;
 
        vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE);
 
-       /* do the reserve before the mutex lock in case we have to do some
-        * flushing.  We wouldn't deadlock, but this is more polite.
-        */
-       err = btrfs_reserve_metadata_for_delalloc(root, inode, 1);
-       if (err)
-               goto out_nolock;
-
        mutex_lock(&inode->i_mutex);
 
+       err = generic_segment_checks(iov, &nr_segs, &ocount, VERIFY_READ);
+       if (err)
+               goto out;
+       count = ocount;
+
        current->backing_dev_info = inode->i_mapping->backing_dev_info;
        err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode));
        if (err)
@@ -875,15 +885,53 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
                goto out;
 
        file_update_time(file);
+       BTRFS_I(inode)->sequence++;
+
+       if (unlikely(file->f_flags & O_DIRECT)) {
+               num_written = generic_file_direct_write(iocb, iov, &nr_segs,
+                                                       pos, ppos, count,
+                                                       ocount);
+               /*
+                * the generic O_DIRECT will update in-memory i_size after the
+                * DIOs are done.  But our endio handlers that update the on
+                * disk i_size never update past the in memory i_size.  So we
+                * need one more update here to catch any additions to the
+                * file
+                */
+               if (inode->i_size != BTRFS_I(inode)->disk_i_size) {
+                       btrfs_ordered_update_i_size(inode, inode->i_size, NULL);
+                       mark_inode_dirty(inode);
+               }
 
+               if (num_written < 0) {
+                       ret = num_written;
+                       num_written = 0;
+                       goto out;
+               } else if (num_written == count) {
+                       /* pick up pos changes done by the generic code */
+                       pos = *ppos;
+                       goto out;
+               }
+               /*
+                * We are going to do buffered for the rest of the range, so we
+                * need to make sure to invalidate the buffered pages when we're
+                * done.
+                */
+               buffered = 1;
+               pos += num_written;
+       }
+
+       iov_iter_init(&i, iov, nr_segs, count, num_written);
+       nrptrs = min((iov_iter_count(&i) + PAGE_CACHE_SIZE - 1) /
+                    PAGE_CACHE_SIZE, PAGE_CACHE_SIZE /
+                    (sizeof(struct page *)));
        pages = kmalloc(nrptrs * sizeof(struct page *), GFP_KERNEL);
 
        /* generic_write_checks can change our pos */
        start_pos = pos;
 
-       BTRFS_I(inode)->sequence++;
        first_index = pos >> PAGE_CACHE_SHIFT;
-       last_index = (pos + count) >> PAGE_CACHE_SHIFT;
+       last_index = (pos + iov_iter_count(&i)) >> PAGE_CACHE_SHIFT;
 
        /*
         * there are lots of better ways to do this, but this code
@@ -900,7 +948,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
                        unlock_page(pinned[0]);
                }
        }
-       if ((pos + count) & (PAGE_CACHE_SIZE - 1)) {
+       if ((pos + iov_iter_count(&i)) & (PAGE_CACHE_SIZE - 1)) {
                pinned[1] = grab_cache_page(inode->i_mapping, last_index);
                if (!PageUptodate(pinned[1])) {
                        ret = btrfs_readpage(NULL, pinned[1]);
@@ -911,10 +959,10 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
                }
        }
 
-       while (count > 0) {
+       while (iov_iter_count(&i) > 0) {
                size_t offset = pos & (PAGE_CACHE_SIZE - 1);
-               size_t write_bytes = min(count, nrptrs *
-                                       (size_t)PAGE_CACHE_SIZE -
+               size_t write_bytes = min(iov_iter_count(&i),
+                                        nrptrs * (size_t)PAGE_CACHE_SIZE -
                                         offset);
                size_t num_pages = (write_bytes + PAGE_CACHE_SIZE - 1) >>
                                        PAGE_CACHE_SHIFT;
@@ -922,7 +970,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
                WARN_ON(num_pages > nrptrs);
                memset(pages, 0, sizeof(struct page *) * nrptrs);
 
-               ret = btrfs_check_data_free_space(root, inode, write_bytes);
+               ret = btrfs_delalloc_reserve_space(inode, write_bytes);
                if (ret)
                        goto out;
 
@@ -930,26 +978,20 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
                                    pos, first_index, last_index,
                                    write_bytes);
                if (ret) {
-                       btrfs_free_reserved_data_space(root, inode,
-                                                      write_bytes);
+                       btrfs_delalloc_release_space(inode, write_bytes);
                        goto out;
                }
 
                ret = btrfs_copy_from_user(pos, num_pages,
-                                          write_bytes, pages, buf);
-               if (ret) {
-                       btrfs_free_reserved_data_space(root, inode,
-                                                      write_bytes);
-                       btrfs_drop_pages(pages, num_pages);
-                       goto out;
+                                          write_bytes, pages, &i);
+               if (ret == 0) {
+                       dirty_and_release_pages(NULL, root, file, pages,
+                                               num_pages, pos, write_bytes);
                }
 
-               ret = dirty_and_release_pages(NULL, root, file, pages,
-                                             num_pages, pos, write_bytes);
                btrfs_drop_pages(pages, num_pages);
                if (ret) {
-                       btrfs_free_reserved_data_space(root, inode,
-                                                      write_bytes);
+                       btrfs_delalloc_release_space(inode, write_bytes);
                        goto out;
                }
 
@@ -965,8 +1007,6 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
                        btrfs_throttle(root);
                }
 
-               buf += write_bytes;
-               count -= write_bytes;
                pos += write_bytes;
                num_written += write_bytes;
 
@@ -976,9 +1016,7 @@ out:
        mutex_unlock(&inode->i_mutex);
        if (ret)
                err = ret;
-       btrfs_unreserve_metadata_for_delalloc(root, inode, 1);
 
-out_nolock:
        kfree(pages);
        if (pinned[0])
                page_cache_release(pinned[0]);
@@ -1008,7 +1046,7 @@ out_nolock:
                        num_written = err;
 
                if ((file->f_flags & O_DSYNC) || IS_SYNC(inode)) {
-                       trans = btrfs_start_transaction(root, 1);
+                       trans = btrfs_start_transaction(root, 0);
                        ret = btrfs_log_dentry_safe(trans, root,
                                                    file->f_dentry);
                        if (ret == 0) {
@@ -1023,7 +1061,7 @@ out_nolock:
                                btrfs_end_transaction(trans, root);
                        }
                }
-               if (file->f_flags & O_DIRECT) {
+               if (file->f_flags & O_DIRECT && buffered) {
                        invalidate_mapping_pages(inode->i_mapping,
                              start_pos >> PAGE_CACHE_SHIFT,
                             (start_pos + num_written - 1) >> PAGE_CACHE_SHIFT);
@@ -1063,8 +1101,9 @@ int btrfs_release_file(struct inode *inode, struct file *filp)
  * important optimization for directories because holding the mutex prevents
  * new operations on the dir while we write to disk.
  */
-int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
+int btrfs_sync_file(struct file *file, int datasync)
 {
+       struct dentry *dentry = file->f_path.dentry;
        struct inode *inode = dentry->d_inode;
        struct btrfs_root *root = BTRFS_I(inode)->root;
        int ret = 0;
@@ -1104,9 +1143,9 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
        if (file && file->private_data)
                btrfs_ioctl_trans_end(file);
 
-       trans = btrfs_start_transaction(root, 1);
-       if (!trans) {
-               ret = -ENOMEM;
+       trans = btrfs_start_transaction(root, 0);
+       if (IS_ERR(trans)) {
+               ret = PTR_ERR(trans);
                goto out;
        }
 
@@ -1161,7 +1200,7 @@ const struct file_operations btrfs_file_operations = {
        .read           = do_sync_read,
        .aio_read       = generic_file_aio_read,
        .splice_read    = generic_file_splice_read,
-       .write          = btrfs_file_write,
+       .aio_write      = btrfs_file_aio_write,
        .mmap           = btrfs_file_mmap,
        .open           = generic_file_open,
        .release        = btrfs_release_file,
index 72ce3c173d6a3d111826e40ce8421b8f7f57f9b1..64f1150bb48d1fb1cd5b7c7d29742b3f9afff7cd 100644 (file)
@@ -49,6 +49,33 @@ static int find_name_in_backref(struct btrfs_path *path, const char *name,
        return 0;
 }
 
+struct btrfs_inode_ref *
+btrfs_lookup_inode_ref(struct btrfs_trans_handle *trans,
+                       struct btrfs_root *root,
+                       struct btrfs_path *path,
+                       const char *name, int name_len,
+                       u64 inode_objectid, u64 ref_objectid, int mod)
+{
+       struct btrfs_key key;
+       struct btrfs_inode_ref *ref;
+       int ins_len = mod < 0 ? -1 : 0;
+       int cow = mod != 0;
+       int ret;
+
+       key.objectid = inode_objectid;
+       key.type = BTRFS_INODE_REF_KEY;
+       key.offset = ref_objectid;
+
+       ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
+       if (ret < 0)
+               return ERR_PTR(ret);
+       if (ret > 0)
+               return NULL;
+       if (!find_name_in_backref(path, name, name_len, &ref))
+               return NULL;
+       return ref;
+}
+
 int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
                           struct btrfs_root *root,
                           const char *name, int name_len,
index 2bfdc641d4e3ba046f3afd89400f362ec959e46b..fa6ccc1bfe2a9a73e2de97ed04cac8708efa99f9 100644 (file)
@@ -252,6 +252,7 @@ static noinline int cow_file_range_inline(struct btrfs_trans_handle *trans,
                                   inline_len, compressed_size,
                                   compressed_pages);
        BUG_ON(ret);
+       btrfs_delalloc_release_metadata(inode, end + 1 - start);
        btrfs_drop_extent_cache(inode, start, aligned_end - 1, 0);
        return 0;
 }
@@ -414,6 +415,7 @@ again:
                trans = btrfs_join_transaction(root, 1);
                BUG_ON(!trans);
                btrfs_set_trans_block_group(trans, inode);
+               trans->block_rsv = &root->fs_info->delalloc_block_rsv;
 
                /* lets try to make an inline extent */
                if (ret || total_in < (actual_end - start)) {
@@ -439,7 +441,6 @@ again:
                             start, end, NULL,
                             EXTENT_CLEAR_UNLOCK_PAGE | EXTENT_CLEAR_DIRTY |
                             EXTENT_CLEAR_DELALLOC |
-                            EXTENT_CLEAR_ACCOUNTING |
                             EXTENT_SET_WRITEBACK | EXTENT_END_WRITEBACK);
 
                        btrfs_end_transaction(trans, root);
@@ -697,6 +698,38 @@ retry:
        return 0;
 }
 
+static u64 get_extent_allocation_hint(struct inode *inode, u64 start,
+                                     u64 num_bytes)
+{
+       struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
+       struct extent_map *em;
+       u64 alloc_hint = 0;
+
+       read_lock(&em_tree->lock);
+       em = search_extent_mapping(em_tree, start, num_bytes);
+       if (em) {
+               /*
+                * if block start isn't an actual block number then find the
+                * first block in this inode and use that as a hint.  If that
+                * block is also bogus then just don't worry about it.
+                */
+               if (em->block_start >= EXTENT_MAP_LAST_BYTE) {
+                       free_extent_map(em);
+                       em = search_extent_mapping(em_tree, 0, 0);
+                       if (em && em->block_start < EXTENT_MAP_LAST_BYTE)
+                               alloc_hint = em->block_start;
+                       if (em)
+                               free_extent_map(em);
+               } else {
+                       alloc_hint = em->block_start;
+                       free_extent_map(em);
+               }
+       }
+       read_unlock(&em_tree->lock);
+
+       return alloc_hint;
+}
+
 /*
  * when extent_io.c finds a delayed allocation range in the file,
  * the call backs end up in this code.  The basic idea is to
@@ -734,6 +767,7 @@ static noinline int cow_file_range(struct inode *inode,
        trans = btrfs_join_transaction(root, 1);
        BUG_ON(!trans);
        btrfs_set_trans_block_group(trans, inode);
+       trans->block_rsv = &root->fs_info->delalloc_block_rsv;
 
        actual_end = min_t(u64, isize, end + 1);
 
@@ -753,7 +787,6 @@ static noinline int cow_file_range(struct inode *inode,
                                     EXTENT_CLEAR_UNLOCK_PAGE |
                                     EXTENT_CLEAR_UNLOCK |
                                     EXTENT_CLEAR_DELALLOC |
-                                    EXTENT_CLEAR_ACCOUNTING |
                                     EXTENT_CLEAR_DIRTY |
                                     EXTENT_SET_WRITEBACK |
                                     EXTENT_END_WRITEBACK);
@@ -769,29 +802,7 @@ static noinline int cow_file_range(struct inode *inode,
        BUG_ON(disk_num_bytes >
               btrfs_super_total_bytes(&root->fs_info->super_copy));
 
-
-       read_lock(&BTRFS_I(inode)->extent_tree.lock);
-       em = search_extent_mapping(&BTRFS_I(inode)->extent_tree,
-                                  start, num_bytes);
-       if (em) {
-               /*
-                * if block start isn't an actual block number then find the
-                * first block in this inode and use that as a hint.  If that
-                * block is also bogus then just don't worry about it.
-                */
-               if (em->block_start >= EXTENT_MAP_LAST_BYTE) {
-                       free_extent_map(em);
-                       em = search_extent_mapping(em_tree, 0, 0);
-                       if (em && em->block_start < EXTENT_MAP_LAST_BYTE)
-                               alloc_hint = em->block_start;
-                       if (em)
-                               free_extent_map(em);
-               } else {
-                       alloc_hint = em->block_start;
-                       free_extent_map(em);
-               }
-       }
-       read_unlock(&BTRFS_I(inode)->extent_tree.lock);
+       alloc_hint = get_extent_allocation_hint(inode, start, num_bytes);
        btrfs_drop_extent_cache(inode, start, start + num_bytes - 1, 0);
 
        while (disk_num_bytes > 0) {
@@ -1174,6 +1185,13 @@ out_check:
                                               num_bytes, num_bytes, type);
                BUG_ON(ret);
 
+               if (root->root_key.objectid ==
+                   BTRFS_DATA_RELOC_TREE_OBJECTID) {
+                       ret = btrfs_reloc_clone_csums(inode, cur_offset,
+                                                     num_bytes);
+                       BUG_ON(ret);
+               }
+
                extent_clear_unlock_delalloc(inode, &BTRFS_I(inode)->io_tree,
                                cur_offset, cur_offset + num_bytes - 1,
                                locked_page, EXTENT_CLEAR_UNLOCK_PAGE |
@@ -1226,15 +1244,13 @@ static int run_delalloc_range(struct inode *inode, struct page *locked_page,
 }
 
 static int btrfs_split_extent_hook(struct inode *inode,
-                                   struct extent_state *orig, u64 split)
+                                  struct extent_state *orig, u64 split)
 {
+       /* not delalloc, ignore it */
        if (!(orig->state & EXTENT_DELALLOC))
                return 0;
 
-       spin_lock(&BTRFS_I(inode)->accounting_lock);
-       BTRFS_I(inode)->outstanding_extents++;
-       spin_unlock(&BTRFS_I(inode)->accounting_lock);
-
+       atomic_inc(&BTRFS_I(inode)->outstanding_extents);
        return 0;
 }
 
@@ -1252,10 +1268,7 @@ static int btrfs_merge_extent_hook(struct inode *inode,
        if (!(other->state & EXTENT_DELALLOC))
                return 0;
 
-       spin_lock(&BTRFS_I(inode)->accounting_lock);
-       BTRFS_I(inode)->outstanding_extents--;
-       spin_unlock(&BTRFS_I(inode)->accounting_lock);
-
+       atomic_dec(&BTRFS_I(inode)->outstanding_extents);
        return 0;
 }
 
@@ -1264,8 +1277,8 @@ static int btrfs_merge_extent_hook(struct inode *inode,
  * bytes in this file, and to maintain the list of inodes that
  * have pending delalloc work to be done.
  */
-static int btrfs_set_bit_hook(struct inode *inode, u64 start, u64 end,
-                      unsigned long old, unsigned long bits)
+static int btrfs_set_bit_hook(struct inode *inode,
+                             struct extent_state *state, int *bits)
 {
 
        /*
@@ -1273,17 +1286,18 @@ static int btrfs_set_bit_hook(struct inode *inode, u64 start, u64 end,
         * but in this case, we are only testeing for the DELALLOC
         * bit, which is only set or cleared with irqs on
         */
-       if (!(old & EXTENT_DELALLOC) && (bits & EXTENT_DELALLOC)) {
+       if (!(state->state & EXTENT_DELALLOC) && (*bits & EXTENT_DELALLOC)) {
                struct btrfs_root *root = BTRFS_I(inode)->root;
+               u64 len = state->end + 1 - state->start;
 
-               spin_lock(&BTRFS_I(inode)->accounting_lock);
-               BTRFS_I(inode)->outstanding_extents++;
-               spin_unlock(&BTRFS_I(inode)->accounting_lock);
-               btrfs_delalloc_reserve_space(root, inode, end - start + 1);
+               if (*bits & EXTENT_FIRST_DELALLOC)
+                       *bits &= ~EXTENT_FIRST_DELALLOC;
+               else
+                       atomic_inc(&BTRFS_I(inode)->outstanding_extents);
 
                spin_lock(&root->fs_info->delalloc_lock);
-               BTRFS_I(inode)->delalloc_bytes += end - start + 1;
-               root->fs_info->delalloc_bytes += end - start + 1;
+               BTRFS_I(inode)->delalloc_bytes += len;
+               root->fs_info->delalloc_bytes += len;
                if (list_empty(&BTRFS_I(inode)->delalloc_inodes)) {
                        list_add_tail(&BTRFS_I(inode)->delalloc_inodes,
                                      &root->fs_info->delalloc_inodes);
@@ -1297,45 +1311,32 @@ static int btrfs_set_bit_hook(struct inode *inode, u64 start, u64 end,
  * extent_io.c clear_bit_hook, see set_bit_hook for why
  */
 static int btrfs_clear_bit_hook(struct inode *inode,
-                               struct extent_state *state, unsigned long bits)
+                               struct extent_state *state, int *bits)
 {
        /*
         * set_bit and clear bit hooks normally require _irqsave/restore
         * but in this case, we are only testeing for the DELALLOC
         * bit, which is only set or cleared with irqs on
         */
-       if ((state->state & EXTENT_DELALLOC) && (bits & EXTENT_DELALLOC)) {
+       if ((state->state & EXTENT_DELALLOC) && (*bits & EXTENT_DELALLOC)) {
                struct btrfs_root *root = BTRFS_I(inode)->root;
+               u64 len = state->end + 1 - state->start;
 
-               if (bits & EXTENT_DO_ACCOUNTING) {
-                       spin_lock(&BTRFS_I(inode)->accounting_lock);
-                       WARN_ON(!BTRFS_I(inode)->outstanding_extents);
-                       BTRFS_I(inode)->outstanding_extents--;
-                       spin_unlock(&BTRFS_I(inode)->accounting_lock);
-                       btrfs_unreserve_metadata_for_delalloc(root, inode, 1);
-               }
+               if (*bits & EXTENT_FIRST_DELALLOC)
+                       *bits &= ~EXTENT_FIRST_DELALLOC;
+               else if (!(*bits & EXTENT_DO_ACCOUNTING))
+                       atomic_dec(&BTRFS_I(inode)->outstanding_extents);
+
+               if (*bits & EXTENT_DO_ACCOUNTING)
+                       btrfs_delalloc_release_metadata(inode, len);
+
+               if (root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID)
+                       btrfs_free_reserved_data_space(inode, len);
 
                spin_lock(&root->fs_info->delalloc_lock);
-               if (state->end - state->start + 1 >
-                   root->fs_info->delalloc_bytes) {
-                       printk(KERN_INFO "btrfs warning: delalloc account "
-                              "%llu %llu\n",
-                              (unsigned long long)
-                              state->end - state->start + 1,
-                              (unsigned long long)
-                              root->fs_info->delalloc_bytes);
-                       btrfs_delalloc_free_space(root, inode, (u64)-1);
-                       root->fs_info->delalloc_bytes = 0;
-                       BTRFS_I(inode)->delalloc_bytes = 0;
-               } else {
-                       btrfs_delalloc_free_space(root, inode,
-                                                 state->end -
-                                                 state->start + 1);
-                       root->fs_info->delalloc_bytes -= state->end -
-                               state->start + 1;
-                       BTRFS_I(inode)->delalloc_bytes -= state->end -
-                               state->start + 1;
-               }
+               root->fs_info->delalloc_bytes -= len;
+               BTRFS_I(inode)->delalloc_bytes -= len;
+
                if (BTRFS_I(inode)->delalloc_bytes == 0 &&
                    !list_empty(&BTRFS_I(inode)->delalloc_inodes)) {
                        list_del_init(&BTRFS_I(inode)->delalloc_inodes);
@@ -1384,7 +1385,8 @@ int btrfs_merge_bio_hook(struct page *page, unsigned long offset,
  */
 static int __btrfs_submit_bio_start(struct inode *inode, int rw,
                                    struct bio *bio, int mirror_num,
-                                   unsigned long bio_flags)
+                                   unsigned long bio_flags,
+                                   u64 bio_offset)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
        int ret = 0;
@@ -1403,7 +1405,8 @@ static int __btrfs_submit_bio_start(struct inode *inode, int rw,
  * are inserted into the btree
  */
 static int __btrfs_submit_bio_done(struct inode *inode, int rw, struct bio *bio,
-                         int mirror_num, unsigned long bio_flags)
+                         int mirror_num, unsigned long bio_flags,
+                         u64 bio_offset)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
        return btrfs_map_bio(root, rw, bio, mirror_num, 1);
@@ -1414,7 +1417,8 @@ static int __btrfs_submit_bio_done(struct inode *inode, int rw, struct bio *bio,
  * on write, or reading the csums from the tree before a read
  */
 static int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
-                         int mirror_num, unsigned long bio_flags)
+                         int mirror_num, unsigned long bio_flags,
+                         u64 bio_offset)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
        int ret = 0;
@@ -1439,7 +1443,8 @@ static int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
                /* we're doing a write, do the async checksumming */
                return btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info,
                                   inode, rw, bio, mirror_num,
-                                  bio_flags, __btrfs_submit_bio_start,
+                                  bio_flags, bio_offset,
+                                  __btrfs_submit_bio_start,
                                   __btrfs_submit_bio_done);
        }
 
@@ -1520,6 +1525,7 @@ again:
                goto again;
        }
 
+       BUG();
        btrfs_set_extent_delalloc(inode, page_start, page_end, &cached_state);
        ClearPageChecked(page);
 out:
@@ -1650,7 +1656,7 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
 static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
-       struct btrfs_trans_handle *trans;
+       struct btrfs_trans_handle *trans = NULL;
        struct btrfs_ordered_extent *ordered_extent = NULL;
        struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
        struct extent_state *cached_state = NULL;
@@ -1668,9 +1674,10 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
                ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent);
                if (!ret) {
                        trans = btrfs_join_transaction(root, 1);
+                       btrfs_set_trans_block_group(trans, inode);
+                       trans->block_rsv = &root->fs_info->delalloc_block_rsv;
                        ret = btrfs_update_inode(trans, root, inode);
                        BUG_ON(ret);
-                       btrfs_end_transaction(trans, root);
                }
                goto out;
        }
@@ -1680,6 +1687,8 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
                         0, &cached_state, GFP_NOFS);
 
        trans = btrfs_join_transaction(root, 1);
+       btrfs_set_trans_block_group(trans, inode);
+       trans->block_rsv = &root->fs_info->delalloc_block_rsv;
 
        if (test_bit(BTRFS_ORDERED_COMPRESSED, &ordered_extent->flags))
                compressed = 1;
@@ -1711,12 +1720,13 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
        add_pending_csums(trans, inode, ordered_extent->file_offset,
                          &ordered_extent->list);
 
-       /* this also removes the ordered extent from the tree */
        btrfs_ordered_update_i_size(inode, 0, ordered_extent);
        ret = btrfs_update_inode(trans, root, inode);
        BUG_ON(ret);
-       btrfs_end_transaction(trans, root);
 out:
+       btrfs_delalloc_release_metadata(inode, ordered_extent->len);
+       if (trans)
+               btrfs_end_transaction(trans, root);
        /* once for us */
        btrfs_put_ordered_extent(ordered_extent);
        /* once for the tree */
@@ -1838,7 +1848,7 @@ static int btrfs_io_failed_hook(struct bio *failed_bio,
 
        BTRFS_I(inode)->io_tree.ops->submit_bio_hook(inode, rw, bio,
                                                      failrec->last_mirror,
-                                                     failrec->bio_flags);
+                                                     failrec->bio_flags, 0);
        return 0;
 }
 
@@ -1992,33 +2002,197 @@ void btrfs_run_delayed_iputs(struct btrfs_root *root)
        up_read(&root->fs_info->cleanup_work_sem);
 }
 
+/*
+ * calculate extra metadata reservation when snapshotting a subvolume
+ * contains orphan files.
+ */
+void btrfs_orphan_pre_snapshot(struct btrfs_trans_handle *trans,
+                               struct btrfs_pending_snapshot *pending,
+                               u64 *bytes_to_reserve)
+{
+       struct btrfs_root *root;
+       struct btrfs_block_rsv *block_rsv;
+       u64 num_bytes;
+       int index;
+
+       root = pending->root;
+       if (!root->orphan_block_rsv || list_empty(&root->orphan_list))
+               return;
+
+       block_rsv = root->orphan_block_rsv;
+
+       /* orphan block reservation for the snapshot */
+       num_bytes = block_rsv->size;
+
+       /*
+        * after the snapshot is created, COWing tree blocks may use more
+        * space than it frees. So we should make sure there is enough
+        * reserved space.
+        */
+       index = trans->transid & 0x1;
+       if (block_rsv->reserved + block_rsv->freed[index] < block_rsv->size) {
+               num_bytes += block_rsv->size -
+                            (block_rsv->reserved + block_rsv->freed[index]);
+       }
+
+       *bytes_to_reserve += num_bytes;
+}
+
+void btrfs_orphan_post_snapshot(struct btrfs_trans_handle *trans,
+                               struct btrfs_pending_snapshot *pending)
+{
+       struct btrfs_root *root = pending->root;
+       struct btrfs_root *snap = pending->snap;
+       struct btrfs_block_rsv *block_rsv;
+       u64 num_bytes;
+       int index;
+       int ret;
+
+       if (!root->orphan_block_rsv || list_empty(&root->orphan_list))
+               return;
+
+       /* refill source subvolume's orphan block reservation */
+       block_rsv = root->orphan_block_rsv;
+       index = trans->transid & 0x1;
+       if (block_rsv->reserved + block_rsv->freed[index] < block_rsv->size) {
+               num_bytes = block_rsv->size -
+                           (block_rsv->reserved + block_rsv->freed[index]);
+               ret = btrfs_block_rsv_migrate(&pending->block_rsv,
+                                             root->orphan_block_rsv,
+                                             num_bytes);
+               BUG_ON(ret);
+       }
+
+       /* setup orphan block reservation for the snapshot */
+       block_rsv = btrfs_alloc_block_rsv(snap);
+       BUG_ON(!block_rsv);
+
+       btrfs_add_durable_block_rsv(root->fs_info, block_rsv);
+       snap->orphan_block_rsv = block_rsv;
+
+       num_bytes = root->orphan_block_rsv->size;
+       ret = btrfs_block_rsv_migrate(&pending->block_rsv,
+                                     block_rsv, num_bytes);
+       BUG_ON(ret);
+
+#if 0
+       /* insert orphan item for the snapshot */
+       WARN_ON(!root->orphan_item_inserted);
+       ret = btrfs_insert_orphan_item(trans, root->fs_info->tree_root,
+                                      snap->root_key.objectid);
+       BUG_ON(ret);
+       snap->orphan_item_inserted = 1;
+#endif
+}
+
+enum btrfs_orphan_cleanup_state {
+       ORPHAN_CLEANUP_STARTED  = 1,
+       ORPHAN_CLEANUP_DONE     = 2,
+};
+
+/*
+ * This is called in transaction commmit time. If there are no orphan
+ * files in the subvolume, it removes orphan item and frees block_rsv
+ * structure.
+ */
+void btrfs_orphan_commit_root(struct btrfs_trans_handle *trans,
+                             struct btrfs_root *root)
+{
+       int ret;
+
+       if (!list_empty(&root->orphan_list) ||
+           root->orphan_cleanup_state != ORPHAN_CLEANUP_DONE)
+               return;
+
+       if (root->orphan_item_inserted &&
+           btrfs_root_refs(&root->root_item) > 0) {
+               ret = btrfs_del_orphan_item(trans, root->fs_info->tree_root,
+                                           root->root_key.objectid);
+               BUG_ON(ret);
+               root->orphan_item_inserted = 0;
+       }
+
+       if (root->orphan_block_rsv) {
+               WARN_ON(root->orphan_block_rsv->size > 0);
+               btrfs_free_block_rsv(root, root->orphan_block_rsv);
+               root->orphan_block_rsv = NULL;
+       }
+}
+
 /*
  * This creates an orphan entry for the given inode in case something goes
  * wrong in the middle of an unlink/truncate.
+ *
+ * NOTE: caller of this function should reserve 5 units of metadata for
+ *      this function.
  */
 int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
-       int ret = 0;
+       struct btrfs_block_rsv *block_rsv = NULL;
+       int reserve = 0;
+       int insert = 0;
+       int ret;
+
+       if (!root->orphan_block_rsv) {
+               block_rsv = btrfs_alloc_block_rsv(root);
+               BUG_ON(!block_rsv);
+       }
 
-       spin_lock(&root->list_lock);
+       spin_lock(&root->orphan_lock);
+       if (!root->orphan_block_rsv) {
+               root->orphan_block_rsv = block_rsv;
+       } else if (block_rsv) {
+               btrfs_free_block_rsv(root, block_rsv);
+               block_rsv = NULL;
+       }
 
-       /* already on the orphan list, we're good */
-       if (!list_empty(&BTRFS_I(inode)->i_orphan)) {
-               spin_unlock(&root->list_lock);
-               return 0;
+       if (list_empty(&BTRFS_I(inode)->i_orphan)) {
+               list_add(&BTRFS_I(inode)->i_orphan, &root->orphan_list);
+#if 0
+               /*
+                * For proper ENOSPC handling, we should do orphan
+                * cleanup when mounting. But this introduces backward
+                * compatibility issue.
+                */
+               if (!xchg(&root->orphan_item_inserted, 1))
+                       insert = 2;
+               else
+                       insert = 1;
+#endif
+               insert = 1;
+       } else {
+               WARN_ON(!BTRFS_I(inode)->orphan_meta_reserved);
        }
 
-       list_add(&BTRFS_I(inode)->i_orphan, &root->orphan_list);
+       if (!BTRFS_I(inode)->orphan_meta_reserved) {
+               BTRFS_I(inode)->orphan_meta_reserved = 1;
+               reserve = 1;
+       }
+       spin_unlock(&root->orphan_lock);
 
-       spin_unlock(&root->list_lock);
+       if (block_rsv)
+               btrfs_add_durable_block_rsv(root->fs_info, block_rsv);
 
-       /*
-        * insert an orphan item to track this unlinked/truncated file
-        */
-       ret = btrfs_insert_orphan_item(trans, root, inode->i_ino);
+       /* grab metadata reservation from transaction handle */
+       if (reserve) {
+               ret = btrfs_orphan_reserve_metadata(trans, inode);
+               BUG_ON(ret);
+       }
 
-       return ret;
+       /* insert an orphan item to track this unlinked/truncated file */
+       if (insert >= 1) {
+               ret = btrfs_insert_orphan_item(trans, root, inode->i_ino);
+               BUG_ON(ret);
+       }
+
+       /* insert an orphan item to track subvolume contains orphan files */
+       if (insert >= 2) {
+               ret = btrfs_insert_orphan_item(trans, root->fs_info->tree_root,
+                                              root->root_key.objectid);
+               BUG_ON(ret);
+       }
+       return 0;
 }
 
 /*
@@ -2028,26 +2202,31 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode)
 int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
+       int delete_item = 0;
+       int release_rsv = 0;
        int ret = 0;
 
-       spin_lock(&root->list_lock);
-
-       if (list_empty(&BTRFS_I(inode)->i_orphan)) {
-               spin_unlock(&root->list_lock);
-               return 0;
+       spin_lock(&root->orphan_lock);
+       if (!list_empty(&BTRFS_I(inode)->i_orphan)) {
+               list_del_init(&BTRFS_I(inode)->i_orphan);
+               delete_item = 1;
        }
 
-       list_del_init(&BTRFS_I(inode)->i_orphan);
-       if (!trans) {
-               spin_unlock(&root->list_lock);
-               return 0;
+       if (BTRFS_I(inode)->orphan_meta_reserved) {
+               BTRFS_I(inode)->orphan_meta_reserved = 0;
+               release_rsv = 1;
        }
+       spin_unlock(&root->orphan_lock);
 
-       spin_unlock(&root->list_lock);
+       if (trans && delete_item) {
+               ret = btrfs_del_orphan_item(trans, root, inode->i_ino);
+               BUG_ON(ret);
+       }
 
-       ret = btrfs_del_orphan_item(trans, root, inode->i_ino);
+       if (release_rsv)
+               btrfs_orphan_release_metadata(inode);
 
-       return ret;
+       return 0;
 }
 
 /*
@@ -2064,7 +2243,7 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
        struct inode *inode;
        int ret = 0, nr_unlink = 0, nr_truncate = 0;
 
-       if (!xchg(&root->clean_orphans, 0))
+       if (cmpxchg(&root->orphan_cleanup_state, 0, ORPHAN_CLEANUP_STARTED))
                return;
 
        path = btrfs_alloc_path();
@@ -2117,16 +2296,15 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
                found_key.type = BTRFS_INODE_ITEM_KEY;
                found_key.offset = 0;
                inode = btrfs_iget(root->fs_info->sb, &found_key, root, NULL);
-               if (IS_ERR(inode))
-                       break;
+               BUG_ON(IS_ERR(inode));
 
                /*
                 * add this inode to the orphan list so btrfs_orphan_del does
                 * the proper thing when we hit it
                 */
-               spin_lock(&root->list_lock);
+               spin_lock(&root->orphan_lock);
                list_add(&BTRFS_I(inode)->i_orphan, &root->orphan_list);
-               spin_unlock(&root->list_lock);
+               spin_unlock(&root->orphan_lock);
 
                /*
                 * if this is a bad inode, means we actually succeeded in
@@ -2135,7 +2313,7 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
                 * do a destroy_inode
                 */
                if (is_bad_inode(inode)) {
-                       trans = btrfs_start_transaction(root, 1);
+                       trans = btrfs_start_transaction(root, 0);
                        btrfs_orphan_del(trans, inode);
                        btrfs_end_transaction(trans, root);
                        iput(inode);
@@ -2153,13 +2331,23 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
                /* this will do delete_inode and everything for us */
                iput(inode);
        }
+       btrfs_free_path(path);
+
+       root->orphan_cleanup_state = ORPHAN_CLEANUP_DONE;
+
+       if (root->orphan_block_rsv)
+               btrfs_block_rsv_release(root, root->orphan_block_rsv,
+                                       (u64)-1);
+
+       if (root->orphan_block_rsv || root->orphan_item_inserted) {
+               trans = btrfs_join_transaction(root, 1);
+               btrfs_end_transaction(trans, root);
+       }
 
        if (nr_unlink)
                printk(KERN_INFO "btrfs: unlinked %d orphans\n", nr_unlink);
        if (nr_truncate)
                printk(KERN_INFO "btrfs: truncated %d orphans\n", nr_truncate);
-
-       btrfs_free_path(path);
 }
 
 /*
@@ -2478,103 +2666,276 @@ out:
        return ret;
 }
 
-static int btrfs_unlink(struct inode *dir, struct dentry *dentry)
+/* helper to check if there is any shared block in the path */
+static int check_path_shared(struct btrfs_root *root,
+                            struct btrfs_path *path)
 {
-       struct btrfs_root *root;
-       struct btrfs_trans_handle *trans;
-       struct inode *inode = dentry->d_inode;
+       struct extent_buffer *eb;
+       int level;
        int ret;
-       unsigned long nr = 0;
-
-       root = BTRFS_I(dir)->root;
-
-       /*
-        * 5 items for unlink inode
-        * 1 for orphan
-        */
-       ret = btrfs_reserve_metadata_space(root, 6);
-       if (ret)
-               return ret;
+       u64 refs;
 
-       trans = btrfs_start_transaction(root, 1);
-       if (IS_ERR(trans)) {
-               btrfs_unreserve_metadata_space(root, 6);
-               return PTR_ERR(trans);
+       for (level = 0; level < BTRFS_MAX_LEVEL; level++) {
+               if (!path->nodes[level])
+                       break;
+               eb = path->nodes[level];
+               if (!btrfs_block_can_be_shared(root, eb))
+                       continue;
+               ret = btrfs_lookup_extent_info(NULL, root, eb->start, eb->len,
+                                              &refs, NULL);
+               if (refs > 1)
+                       return 1;
        }
-
-       btrfs_set_trans_block_group(trans, dir);
-
-       btrfs_record_unlink_dir(trans, dir, dentry->d_inode, 0);
-
-       ret = btrfs_unlink_inode(trans, root, dir, dentry->d_inode,
-                                dentry->d_name.name, dentry->d_name.len);
-
-       if (inode->i_nlink == 0)
-               ret = btrfs_orphan_add(trans, inode);
-
-       nr = trans->blocks_used;
-
-       btrfs_end_transaction_throttle(trans, root);
-       btrfs_unreserve_metadata_space(root, 6);
-       btrfs_btree_balance_dirty(root, nr);
-       return ret;
+       return 0;
 }
 
-int btrfs_unlink_subvol(struct btrfs_trans_handle *trans,
-                       struct btrfs_root *root,
-                       struct inode *dir, u64 objectid,
-                       const char *name, int name_len)
+/*
+ * helper to start transaction for unlink and rmdir.
+ *
+ * unlink and rmdir are special in btrfs, they do not always free space.
+ * so in enospc case, we should make sure they will free space before
+ * allowing them to use the global metadata reservation.
+ */
+static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir,
+                                                      struct dentry *dentry)
 {
+       struct btrfs_trans_handle *trans;
+       struct btrfs_root *root = BTRFS_I(dir)->root;
        struct btrfs_path *path;
-       struct extent_buffer *leaf;
+       struct btrfs_inode_ref *ref;
        struct btrfs_dir_item *di;
-       struct btrfs_key key;
+       struct inode *inode = dentry->d_inode;
        u64 index;
+       int check_link = 1;
+       int err = -ENOSPC;
        int ret;
 
-       path = btrfs_alloc_path();
-       if (!path)
-               return -ENOMEM;
+       trans = btrfs_start_transaction(root, 10);
+       if (!IS_ERR(trans) || PTR_ERR(trans) != -ENOSPC)
+               return trans;
 
-       di = btrfs_lookup_dir_item(trans, root, path, dir->i_ino,
-                                  name, name_len, -1);
-       BUG_ON(!di || IS_ERR(di));
+       if (inode->i_ino == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)
+               return ERR_PTR(-ENOSPC);
 
-       leaf = path->nodes[0];
-       btrfs_dir_item_key_to_cpu(leaf, di, &key);
-       WARN_ON(key.type != BTRFS_ROOT_ITEM_KEY || key.objectid != objectid);
-       ret = btrfs_delete_one_dir_name(trans, root, path, di);
-       BUG_ON(ret);
-       btrfs_release_path(root, path);
+       /* check if there is someone else holds reference */
+       if (S_ISDIR(inode->i_mode) && atomic_read(&inode->i_count) > 1)
+               return ERR_PTR(-ENOSPC);
 
-       ret = btrfs_del_root_ref(trans, root->fs_info->tree_root,
-                                objectid, root->root_key.objectid,
-                                dir->i_ino, &index, name, name_len);
-       if (ret < 0) {
-               BUG_ON(ret != -ENOENT);
-               di = btrfs_search_dir_index_item(root, path, dir->i_ino,
-                                                name, name_len);
-               BUG_ON(!di || IS_ERR(di));
+       if (atomic_read(&inode->i_count) > 2)
+               return ERR_PTR(-ENOSPC);
 
-               leaf = path->nodes[0];
-               btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
-               btrfs_release_path(root, path);
-               index = key.offset;
+       if (xchg(&root->fs_info->enospc_unlink, 1))
+               return ERR_PTR(-ENOSPC);
+
+       path = btrfs_alloc_path();
+       if (!path) {
+               root->fs_info->enospc_unlink = 0;
+               return ERR_PTR(-ENOMEM);
        }
 
-       di = btrfs_lookup_dir_index_item(trans, root, path, dir->i_ino,
-                                        index, name, name_len, -1);
-       BUG_ON(!di || IS_ERR(di));
+       trans = btrfs_start_transaction(root, 0);
+       if (IS_ERR(trans)) {
+               btrfs_free_path(path);
+               root->fs_info->enospc_unlink = 0;
+               return trans;
+       }
 
-       leaf = path->nodes[0];
-       btrfs_dir_item_key_to_cpu(leaf, di, &key);
-       WARN_ON(key.type != BTRFS_ROOT_ITEM_KEY || key.objectid != objectid);
-       ret = btrfs_delete_one_dir_name(trans, root, path, di);
-       BUG_ON(ret);
-       btrfs_release_path(root, path);
+       path->skip_locking = 1;
+       path->search_commit_root = 1;
 
-       btrfs_i_size_write(dir, dir->i_size - name_len * 2);
-       dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+       ret = btrfs_lookup_inode(trans, root, path,
+                               &BTRFS_I(dir)->location, 0);
+       if (ret < 0) {
+               err = ret;
+               goto out;
+       }
+       if (ret == 0) {
+               if (check_path_shared(root, path))
+                       goto out;
+       } else {
+               check_link = 0;
+       }
+       btrfs_release_path(root, path);
+
+       ret = btrfs_lookup_inode(trans, root, path,
+                               &BTRFS_I(inode)->location, 0);
+       if (ret < 0) {
+               err = ret;
+               goto out;
+       }
+       if (ret == 0) {
+               if (check_path_shared(root, path))
+                       goto out;
+       } else {
+               check_link = 0;
+       }
+       btrfs_release_path(root, path);
+
+       if (ret == 0 && S_ISREG(inode->i_mode)) {
+               ret = btrfs_lookup_file_extent(trans, root, path,
+                                              inode->i_ino, (u64)-1, 0);
+               if (ret < 0) {
+                       err = ret;
+                       goto out;
+               }
+               BUG_ON(ret == 0);
+               if (check_path_shared(root, path))
+                       goto out;
+               btrfs_release_path(root, path);
+       }
+
+       if (!check_link) {
+               err = 0;
+               goto out;
+       }
+
+       di = btrfs_lookup_dir_item(trans, root, path, dir->i_ino,
+                               dentry->d_name.name, dentry->d_name.len, 0);
+       if (IS_ERR(di)) {
+               err = PTR_ERR(di);
+               goto out;
+       }
+       if (di) {
+               if (check_path_shared(root, path))
+                       goto out;
+       } else {
+               err = 0;
+               goto out;
+       }
+       btrfs_release_path(root, path);
+
+       ref = btrfs_lookup_inode_ref(trans, root, path,
+                               dentry->d_name.name, dentry->d_name.len,
+                               inode->i_ino, dir->i_ino, 0);
+       if (IS_ERR(ref)) {
+               err = PTR_ERR(ref);
+               goto out;
+       }
+       BUG_ON(!ref);
+       if (check_path_shared(root, path))
+               goto out;
+       index = btrfs_inode_ref_index(path->nodes[0], ref);
+       btrfs_release_path(root, path);
+
+       di = btrfs_lookup_dir_index_item(trans, root, path, dir->i_ino, index,
+                               dentry->d_name.name, dentry->d_name.len, 0);
+       if (IS_ERR(di)) {
+               err = PTR_ERR(di);
+               goto out;
+       }
+       BUG_ON(ret == -ENOENT);
+       if (check_path_shared(root, path))
+               goto out;
+
+       err = 0;
+out:
+       btrfs_free_path(path);
+       if (err) {
+               btrfs_end_transaction(trans, root);
+               root->fs_info->enospc_unlink = 0;
+               return ERR_PTR(err);
+       }
+
+       trans->block_rsv = &root->fs_info->global_block_rsv;
+       return trans;
+}
+
+static void __unlink_end_trans(struct btrfs_trans_handle *trans,
+                              struct btrfs_root *root)
+{
+       if (trans->block_rsv == &root->fs_info->global_block_rsv) {
+               BUG_ON(!root->fs_info->enospc_unlink);
+               root->fs_info->enospc_unlink = 0;
+       }
+       btrfs_end_transaction_throttle(trans, root);
+}
+
+static int btrfs_unlink(struct inode *dir, struct dentry *dentry)
+{
+       struct btrfs_root *root = BTRFS_I(dir)->root;
+       struct btrfs_trans_handle *trans;
+       struct inode *inode = dentry->d_inode;
+       int ret;
+       unsigned long nr = 0;
+
+       trans = __unlink_start_trans(dir, dentry);
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
+
+       btrfs_set_trans_block_group(trans, dir);
+
+       btrfs_record_unlink_dir(trans, dir, dentry->d_inode, 0);
+
+       ret = btrfs_unlink_inode(trans, root, dir, dentry->d_inode,
+                                dentry->d_name.name, dentry->d_name.len);
+       BUG_ON(ret);
+
+       if (inode->i_nlink == 0) {
+               ret = btrfs_orphan_add(trans, inode);
+               BUG_ON(ret);
+       }
+
+       nr = trans->blocks_used;
+       __unlink_end_trans(trans, root);
+       btrfs_btree_balance_dirty(root, nr);
+       return ret;
+}
+
+int btrfs_unlink_subvol(struct btrfs_trans_handle *trans,
+                       struct btrfs_root *root,
+                       struct inode *dir, u64 objectid,
+                       const char *name, int name_len)
+{
+       struct btrfs_path *path;
+       struct extent_buffer *leaf;
+       struct btrfs_dir_item *di;
+       struct btrfs_key key;
+       u64 index;
+       int ret;
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
+       di = btrfs_lookup_dir_item(trans, root, path, dir->i_ino,
+                                  name, name_len, -1);
+       BUG_ON(!di || IS_ERR(di));
+
+       leaf = path->nodes[0];
+       btrfs_dir_item_key_to_cpu(leaf, di, &key);
+       WARN_ON(key.type != BTRFS_ROOT_ITEM_KEY || key.objectid != objectid);
+       ret = btrfs_delete_one_dir_name(trans, root, path, di);
+       BUG_ON(ret);
+       btrfs_release_path(root, path);
+
+       ret = btrfs_del_root_ref(trans, root->fs_info->tree_root,
+                                objectid, root->root_key.objectid,
+                                dir->i_ino, &index, name, name_len);
+       if (ret < 0) {
+               BUG_ON(ret != -ENOENT);
+               di = btrfs_search_dir_index_item(root, path, dir->i_ino,
+                                                name, name_len);
+               BUG_ON(!di || IS_ERR(di));
+
+               leaf = path->nodes[0];
+               btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
+               btrfs_release_path(root, path);
+               index = key.offset;
+       }
+
+       di = btrfs_lookup_dir_index_item(trans, root, path, dir->i_ino,
+                                        index, name, name_len, -1);
+       BUG_ON(!di || IS_ERR(di));
+
+       leaf = path->nodes[0];
+       btrfs_dir_item_key_to_cpu(leaf, di, &key);
+       WARN_ON(key.type != BTRFS_ROOT_ITEM_KEY || key.objectid != objectid);
+       ret = btrfs_delete_one_dir_name(trans, root, path, di);
+       BUG_ON(ret);
+       btrfs_release_path(root, path);
+
+       btrfs_i_size_write(dir, dir->i_size - name_len * 2);
+       dir->i_mtime = dir->i_ctime = CURRENT_TIME;
        ret = btrfs_update_inode(trans, root, dir);
        BUG_ON(ret);
        dir->i_sb->s_dirt = 1;
@@ -2587,7 +2948,6 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
 {
        struct inode *inode = dentry->d_inode;
        int err = 0;
-       int ret;
        struct btrfs_root *root = BTRFS_I(dir)->root;
        struct btrfs_trans_handle *trans;
        unsigned long nr = 0;
@@ -2596,15 +2956,9 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
            inode->i_ino == BTRFS_FIRST_FREE_OBJECTID)
                return -ENOTEMPTY;
 
-       ret = btrfs_reserve_metadata_space(root, 5);
-       if (ret)
-               return ret;
-
-       trans = btrfs_start_transaction(root, 1);
-       if (IS_ERR(trans)) {
-               btrfs_unreserve_metadata_space(root, 5);
+       trans = __unlink_start_trans(dir, dentry);
+       if (IS_ERR(trans))
                return PTR_ERR(trans);
-       }
 
        btrfs_set_trans_block_group(trans, dir);
 
@@ -2627,12 +2981,9 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
                btrfs_i_size_write(inode, 0);
 out:
        nr = trans->blocks_used;
-       ret = btrfs_end_transaction_throttle(trans, root);
-       btrfs_unreserve_metadata_space(root, 5);
+       __unlink_end_trans(trans, root);
        btrfs_btree_balance_dirty(root, nr);
 
-       if (ret && !err)
-               err = ret;
        return err;
 }
 
@@ -3029,6 +3380,7 @@ out:
        if (pending_del_nr) {
                ret = btrfs_del_items(trans, root, path, pending_del_slot,
                                      pending_del_nr);
+               BUG_ON(ret);
        }
        btrfs_free_path(path);
        return err;
@@ -3056,11 +3408,7 @@ static int btrfs_truncate_page(struct address_space *mapping, loff_t from)
 
        if ((offset & (blocksize - 1)) == 0)
                goto out;
-       ret = btrfs_check_data_free_space(root, inode, PAGE_CACHE_SIZE);
-       if (ret)
-               goto out;
-
-       ret = btrfs_reserve_metadata_for_delalloc(root, inode, 1);
+       ret = btrfs_delalloc_reserve_space(inode, PAGE_CACHE_SIZE);
        if (ret)
                goto out;
 
@@ -3068,8 +3416,7 @@ static int btrfs_truncate_page(struct address_space *mapping, loff_t from)
 again:
        page = grab_cache_page(mapping, index);
        if (!page) {
-               btrfs_free_reserved_data_space(root, inode, PAGE_CACHE_SIZE);
-               btrfs_unreserve_metadata_for_delalloc(root, inode, 1);
+               btrfs_delalloc_release_space(inode, PAGE_CACHE_SIZE);
                goto out;
        }
 
@@ -3132,8 +3479,7 @@ again:
 
 out_unlock:
        if (ret)
-               btrfs_free_reserved_data_space(root, inode, PAGE_CACHE_SIZE);
-       btrfs_unreserve_metadata_for_delalloc(root, inode, 1);
+               btrfs_delalloc_release_space(inode, PAGE_CACHE_SIZE);
        unlock_page(page);
        page_cache_release(page);
 out:
@@ -3145,7 +3491,7 @@ int btrfs_cont_expand(struct inode *inode, loff_t size)
        struct btrfs_trans_handle *trans;
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
-       struct extent_map *em;
+       struct extent_map *em = NULL;
        struct extent_state *cached_state = NULL;
        u64 mask = root->sectorsize - 1;
        u64 hole_start = (inode->i_size + mask) & ~mask;
@@ -3183,11 +3529,11 @@ int btrfs_cont_expand(struct inode *inode, loff_t size)
                        u64 hint_byte = 0;
                        hole_size = last_byte - cur_offset;
 
-                       err = btrfs_reserve_metadata_space(root, 2);
-                       if (err)
+                       trans = btrfs_start_transaction(root, 2);
+                       if (IS_ERR(trans)) {
+                               err = PTR_ERR(trans);
                                break;
-
-                       trans = btrfs_start_transaction(root, 1);
+                       }
                        btrfs_set_trans_block_group(trans, inode);
 
                        err = btrfs_drop_extents(trans, inode, cur_offset,
@@ -3205,14 +3551,15 @@ int btrfs_cont_expand(struct inode *inode, loff_t size)
                                        last_byte - 1, 0);
 
                        btrfs_end_transaction(trans, root);
-                       btrfs_unreserve_metadata_space(root, 2);
                }
                free_extent_map(em);
+               em = NULL;
                cur_offset = last_byte;
                if (cur_offset >= block_end)
                        break;
        }
 
+       free_extent_map(em);
        unlock_extent_cached(io_tree, hole_start, block_end - 1, &cached_state,
                             GFP_NOFS);
        return err;
@@ -3239,11 +3586,10 @@ static int btrfs_setattr_size(struct inode *inode, struct iattr *attr)
                }
        }
 
-       ret = btrfs_reserve_metadata_space(root, 1);
-       if (ret)
-               return ret;
+       trans = btrfs_start_transaction(root, 5);
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
 
-       trans = btrfs_start_transaction(root, 1);
        btrfs_set_trans_block_group(trans, inode);
 
        ret = btrfs_orphan_add(trans, inode);
@@ -3251,7 +3597,6 @@ static int btrfs_setattr_size(struct inode *inode, struct iattr *attr)
 
        nr = trans->blocks_used;
        btrfs_end_transaction(trans, root);
-       btrfs_unreserve_metadata_space(root, 1);
        btrfs_btree_balance_dirty(root, nr);
 
        if (attr->ia_size > inode->i_size) {
@@ -3264,8 +3609,11 @@ static int btrfs_setattr_size(struct inode *inode, struct iattr *attr)
                i_size_write(inode, attr->ia_size);
                btrfs_ordered_update_i_size(inode, inode->i_size, NULL);
 
-               trans = btrfs_start_transaction(root, 1);
+               trans = btrfs_start_transaction(root, 0);
+               BUG_ON(IS_ERR(trans));
                btrfs_set_trans_block_group(trans, inode);
+               trans->block_rsv = root->orphan_block_rsv;
+               BUG_ON(!trans->block_rsv);
 
                ret = btrfs_update_inode(trans, root, inode);
                BUG_ON(ret);
@@ -3345,10 +3693,21 @@ void btrfs_delete_inode(struct inode *inode)
        btrfs_i_size_write(inode, 0);
 
        while (1) {
-               trans = btrfs_start_transaction(root, 1);
+               trans = btrfs_start_transaction(root, 0);
+               BUG_ON(IS_ERR(trans));
                btrfs_set_trans_block_group(trans, inode);
-               ret = btrfs_truncate_inode_items(trans, root, inode, 0, 0);
+               trans->block_rsv = root->orphan_block_rsv;
+
+               ret = btrfs_block_rsv_check(trans, root,
+                                           root->orphan_block_rsv, 0, 5);
+               if (ret) {
+                       BUG_ON(ret != -EAGAIN);
+                       ret = btrfs_commit_transaction(trans, root);
+                       BUG_ON(ret);
+                       continue;
+               }
 
+               ret = btrfs_truncate_inode_items(trans, root, inode, 0, 0);
                if (ret != -EAGAIN)
                        break;
 
@@ -3356,6 +3715,7 @@ void btrfs_delete_inode(struct inode *inode)
                btrfs_end_transaction(trans, root);
                trans = NULL;
                btrfs_btree_balance_dirty(root, nr);
+
        }
 
        if (ret == 0) {
@@ -3596,40 +3956,10 @@ again:
        return 0;
 }
 
-static noinline void init_btrfs_i(struct inode *inode)
-{
-       struct btrfs_inode *bi = BTRFS_I(inode);
-
-       bi->generation = 0;
-       bi->sequence = 0;
-       bi->last_trans = 0;
-       bi->last_sub_trans = 0;
-       bi->logged_trans = 0;
-       bi->delalloc_bytes = 0;
-       bi->reserved_bytes = 0;
-       bi->disk_i_size = 0;
-       bi->flags = 0;
-       bi->index_cnt = (u64)-1;
-       bi->last_unlink_trans = 0;
-       bi->ordered_data_close = 0;
-       bi->force_compress = 0;
-       extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
-       extent_io_tree_init(&BTRFS_I(inode)->io_tree,
-                            inode->i_mapping, GFP_NOFS);
-       extent_io_tree_init(&BTRFS_I(inode)->io_failure_tree,
-                            inode->i_mapping, GFP_NOFS);
-       INIT_LIST_HEAD(&BTRFS_I(inode)->delalloc_inodes);
-       INIT_LIST_HEAD(&BTRFS_I(inode)->ordered_operations);
-       RB_CLEAR_NODE(&BTRFS_I(inode)->rb_node);
-       btrfs_ordered_inode_tree_init(&BTRFS_I(inode)->ordered_tree);
-       mutex_init(&BTRFS_I(inode)->log_mutex);
-}
-
 static int btrfs_init_locked_inode(struct inode *inode, void *p)
 {
        struct btrfs_iget_args *args = p;
        inode->i_ino = args->ino;
-       init_btrfs_i(inode);
        BTRFS_I(inode)->root = args->root;
        btrfs_set_inode_space_info(args->root, inode);
        return 0;
@@ -3692,8 +4022,6 @@ static struct inode *new_simple_dir(struct super_block *s,
        if (!inode)
                return ERR_PTR(-ENOMEM);
 
-       init_btrfs_i(inode);
-
        BTRFS_I(inode)->root = root;
        memcpy(&BTRFS_I(inode)->location, key, sizeof(*key));
        BTRFS_I(inode)->dummy_inode = 1;
@@ -3950,7 +4278,7 @@ int btrfs_write_inode(struct inode *inode, struct writeback_control *wbc)
        struct btrfs_trans_handle *trans;
        int ret = 0;
 
-       if (root->fs_info->btree_inode == inode)
+       if (BTRFS_I(inode)->dummy_inode)
                return 0;
 
        if (wbc->sync_mode == WB_SYNC_ALL) {
@@ -3971,10 +4299,38 @@ void btrfs_dirty_inode(struct inode *inode)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_trans_handle *trans;
+       int ret;
+
+       if (BTRFS_I(inode)->dummy_inode)
+               return;
 
        trans = btrfs_join_transaction(root, 1);
        btrfs_set_trans_block_group(trans, inode);
-       btrfs_update_inode(trans, root, inode);
+
+       ret = btrfs_update_inode(trans, root, inode);
+       if (ret && ret == -ENOSPC) {
+               /* whoops, lets try again with the full transaction */
+               btrfs_end_transaction(trans, root);
+               trans = btrfs_start_transaction(root, 1);
+               if (IS_ERR(trans)) {
+                       if (printk_ratelimit()) {
+                               printk(KERN_ERR "btrfs: fail to "
+                                      "dirty  inode %lu error %ld\n",
+                                      inode->i_ino, PTR_ERR(trans));
+                       }
+                       return;
+               }
+               btrfs_set_trans_block_group(trans, inode);
+
+               ret = btrfs_update_inode(trans, root, inode);
+               if (ret) {
+                       if (printk_ratelimit()) {
+                               printk(KERN_ERR "btrfs: fail to "
+                                      "dirty  inode %lu error %d\n",
+                                      inode->i_ino, ret);
+                       }
+               }
+       }
        btrfs_end_transaction(trans, root);
 }
 
@@ -4092,7 +4448,6 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
         * btrfs_get_inode_index_count has an explanation for the magic
         * number
         */
-       init_btrfs_i(inode);
        BTRFS_I(inode)->index_cnt = 2;
        BTRFS_I(inode)->root = root;
        BTRFS_I(inode)->generation = trans->transid;
@@ -4121,16 +4476,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
        if (ret != 0)
                goto fail;
 
-       inode->i_uid = current_fsuid();
-
-       if (dir && (dir->i_mode & S_ISGID)) {
-               inode->i_gid = dir->i_gid;
-               if (S_ISDIR(mode))
-                       mode |= S_ISGID;
-       } else
-               inode->i_gid = current_fsgid();
-
-       inode->i_mode = mode;
+       inode_init_owner(inode, dir, mode);
        inode->i_ino = objectid;
        inode_set_bytes(inode, 0);
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
@@ -4256,26 +4602,21 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry,
        if (!new_valid_dev(rdev))
                return -EINVAL;
 
+       err = btrfs_find_free_objectid(NULL, root, dir->i_ino, &objectid);
+       if (err)
+               return err;
+
        /*
         * 2 for inode item and ref
         * 2 for dir items
         * 1 for xattr if selinux is on
         */
-       err = btrfs_reserve_metadata_space(root, 5);
-       if (err)
-               return err;
+       trans = btrfs_start_transaction(root, 5);
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
 
-       trans = btrfs_start_transaction(root, 1);
-       if (!trans)
-               goto fail;
        btrfs_set_trans_block_group(trans, dir);
 
-       err = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid);
-       if (err) {
-               err = -ENOSPC;
-               goto out_unlock;
-       }
-
        inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
                                dentry->d_name.len,
                                dentry->d_parent->d_inode->i_ino, objectid,
@@ -4304,13 +4645,11 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry,
 out_unlock:
        nr = trans->blocks_used;
        btrfs_end_transaction_throttle(trans, root);
-fail:
-       btrfs_unreserve_metadata_space(root, 5);
+       btrfs_btree_balance_dirty(root, nr);
        if (drop_inode) {
                inode_dec_link_count(inode);
                iput(inode);
        }
-       btrfs_btree_balance_dirty(root, nr);
        return err;
 }
 
@@ -4320,32 +4659,26 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
        struct btrfs_trans_handle *trans;
        struct btrfs_root *root = BTRFS_I(dir)->root;
        struct inode *inode = NULL;
-       int err;
        int drop_inode = 0;
+       int err;
        unsigned long nr = 0;
        u64 objectid;
        u64 index = 0;
 
+       err = btrfs_find_free_objectid(NULL, root, dir->i_ino, &objectid);
+       if (err)
+               return err;
        /*
         * 2 for inode item and ref
         * 2 for dir items
         * 1 for xattr if selinux is on
         */
-       err = btrfs_reserve_metadata_space(root, 5);
-       if (err)
-               return err;
+       trans = btrfs_start_transaction(root, 5);
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
 
-       trans = btrfs_start_transaction(root, 1);
-       if (!trans)
-               goto fail;
        btrfs_set_trans_block_group(trans, dir);
 
-       err = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid);
-       if (err) {
-               err = -ENOSPC;
-               goto out_unlock;
-       }
-
        inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
                                dentry->d_name.len,
                                dentry->d_parent->d_inode->i_ino,
@@ -4377,8 +4710,6 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
 out_unlock:
        nr = trans->blocks_used;
        btrfs_end_transaction_throttle(trans, root);
-fail:
-       btrfs_unreserve_metadata_space(root, 5);
        if (drop_inode) {
                inode_dec_link_count(inode);
                iput(inode);
@@ -4405,21 +4736,21 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
        if (root->objectid != BTRFS_I(inode)->root->objectid)
                return -EPERM;
 
-       /*
-        * 1 item for inode ref
-        * 2 items for dir items
-        */
-       err = btrfs_reserve_metadata_space(root, 3);
-       if (err)
-               return err;
-
        btrfs_inc_nlink(inode);
 
        err = btrfs_set_inode_index(dir, &index);
        if (err)
                goto fail;
 
-       trans = btrfs_start_transaction(root, 1);
+       /*
+        * 1 item for inode ref
+        * 2 items for dir items
+        */
+       trans = btrfs_start_transaction(root, 3);
+       if (IS_ERR(trans)) {
+               err = PTR_ERR(trans);
+               goto fail;
+       }
 
        btrfs_set_trans_block_group(trans, dir);
        atomic_inc(&inode->i_count);
@@ -4438,7 +4769,6 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
        nr = trans->blocks_used;
        btrfs_end_transaction_throttle(trans, root);
 fail:
-       btrfs_unreserve_metadata_space(root, 3);
        if (drop_inode) {
                inode_dec_link_count(inode);
                iput(inode);
@@ -4458,28 +4788,20 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        u64 index = 0;
        unsigned long nr = 1;
 
+       err = btrfs_find_free_objectid(NULL, root, dir->i_ino, &objectid);
+       if (err)
+               return err;
+
        /*
         * 2 items for inode and ref
         * 2 items for dir items
         * 1 for xattr if selinux is on
         */
-       err = btrfs_reserve_metadata_space(root, 5);
-       if (err)
-               return err;
-
-       trans = btrfs_start_transaction(root, 1);
-       if (!trans) {
-               err = -ENOMEM;
-               goto out_unlock;
-       }
+       trans = btrfs_start_transaction(root, 5);
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
        btrfs_set_trans_block_group(trans, dir);
 
-       err = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid);
-       if (err) {
-               err = -ENOSPC;
-               goto out_fail;
-       }
-
        inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
                                dentry->d_name.len,
                                dentry->d_parent->d_inode->i_ino, objectid,
@@ -4519,9 +4841,6 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 out_fail:
        nr = trans->blocks_used;
        btrfs_end_transaction_throttle(trans, root);
-
-out_unlock:
-       btrfs_unreserve_metadata_space(root, 5);
        if (drop_on_err)
                iput(inode);
        btrfs_btree_balance_dirty(root, nr);
@@ -4779,6 +5098,7 @@ again:
                        }
                        flush_dcache_page(page);
                } else if (create && PageUptodate(page)) {
+                       WARN_ON(1);
                        if (!trans) {
                                kunmap(page);
                                free_extent_map(em);
@@ -4875,11 +5195,651 @@ out:
        return em;
 }
 
+static struct extent_map *btrfs_new_extent_direct(struct inode *inode,
+                                                 u64 start, u64 len)
+{
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       struct btrfs_trans_handle *trans;
+       struct extent_map *em;
+       struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
+       struct btrfs_key ins;
+       u64 alloc_hint;
+       int ret;
+
+       btrfs_drop_extent_cache(inode, start, start + len - 1, 0);
+
+       trans = btrfs_join_transaction(root, 0);
+       if (!trans)
+               return ERR_PTR(-ENOMEM);
+
+       trans->block_rsv = &root->fs_info->delalloc_block_rsv;
+
+       alloc_hint = get_extent_allocation_hint(inode, start, len);
+       ret = btrfs_reserve_extent(trans, root, len, root->sectorsize, 0,
+                                  alloc_hint, (u64)-1, &ins, 1);
+       if (ret) {
+               em = ERR_PTR(ret);
+               goto out;
+       }
+
+       em = alloc_extent_map(GFP_NOFS);
+       if (!em) {
+               em = ERR_PTR(-ENOMEM);
+               goto out;
+       }
+
+       em->start = start;
+       em->orig_start = em->start;
+       em->len = ins.offset;
+
+       em->block_start = ins.objectid;
+       em->block_len = ins.offset;
+       em->bdev = root->fs_info->fs_devices->latest_bdev;
+       set_bit(EXTENT_FLAG_PINNED, &em->flags);
+
+       while (1) {
+               write_lock(&em_tree->lock);
+               ret = add_extent_mapping(em_tree, em);
+               write_unlock(&em_tree->lock);
+               if (ret != -EEXIST)
+                       break;
+               btrfs_drop_extent_cache(inode, start, start + em->len - 1, 0);
+       }
+
+       ret = btrfs_add_ordered_extent_dio(inode, start, ins.objectid,
+                                          ins.offset, ins.offset, 0);
+       if (ret) {
+               btrfs_free_reserved_extent(root, ins.objectid, ins.offset);
+               em = ERR_PTR(ret);
+       }
+out:
+       btrfs_end_transaction(trans, root);
+       return em;
+}
+
+/*
+ * returns 1 when the nocow is safe, < 1 on error, 0 if the
+ * block must be cow'd
+ */
+static noinline int can_nocow_odirect(struct btrfs_trans_handle *trans,
+                                     struct inode *inode, u64 offset, u64 len)
+{
+       struct btrfs_path *path;
+       int ret;
+       struct extent_buffer *leaf;
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       struct btrfs_file_extent_item *fi;
+       struct btrfs_key key;
+       u64 disk_bytenr;
+       u64 backref_offset;
+       u64 extent_end;
+       u64 num_bytes;
+       int slot;
+       int found_type;
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
+       ret = btrfs_lookup_file_extent(trans, root, path, inode->i_ino,
+                                      offset, 0);
+       if (ret < 0)
+               goto out;
+
+       slot = path->slots[0];
+       if (ret == 1) {
+               if (slot == 0) {
+                       /* can't find the item, must cow */
+                       ret = 0;
+                       goto out;
+               }
+               slot--;
+       }
+       ret = 0;
+       leaf = path->nodes[0];
+       btrfs_item_key_to_cpu(leaf, &key, slot);
+       if (key.objectid != inode->i_ino ||
+           key.type != BTRFS_EXTENT_DATA_KEY) {
+               /* not our file or wrong item type, must cow */
+               goto out;
+       }
+
+       if (key.offset > offset) {
+               /* Wrong offset, must cow */
+               goto out;
+       }
+
+       fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);
+       found_type = btrfs_file_extent_type(leaf, fi);
+       if (found_type != BTRFS_FILE_EXTENT_REG &&
+           found_type != BTRFS_FILE_EXTENT_PREALLOC) {
+               /* not a regular extent, must cow */
+               goto out;
+       }
+       disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi);
+       backref_offset = btrfs_file_extent_offset(leaf, fi);
+
+       extent_end = key.offset + btrfs_file_extent_num_bytes(leaf, fi);
+       if (extent_end < offset + len) {
+               /* extent doesn't include our full range, must cow */
+               goto out;
+       }
+
+       if (btrfs_extent_readonly(root, disk_bytenr))
+               goto out;
+
+       /*
+        * look for other files referencing this extent, if we
+        * find any we must cow
+        */
+       if (btrfs_cross_ref_exist(trans, root, inode->i_ino,
+                                 key.offset - backref_offset, disk_bytenr))
+               goto out;
+
+       /*
+        * adjust disk_bytenr and num_bytes to cover just the bytes
+        * in this extent we are about to write.  If there
+        * are any csums in that range we have to cow in order
+        * to keep the csums correct
+        */
+       disk_bytenr += backref_offset;
+       disk_bytenr += offset - key.offset;
+       num_bytes = min(offset + len, extent_end) - offset;
+       if (csum_exist_in_range(root, disk_bytenr, num_bytes))
+                               goto out;
+       /*
+        * all of the above have passed, it is safe to overwrite this extent
+        * without cow
+        */
+       ret = 1;
+out:
+       btrfs_free_path(path);
+       return ret;
+}
+
+static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
+                                  struct buffer_head *bh_result, int create)
+{
+       struct extent_map *em;
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       u64 start = iblock << inode->i_blkbits;
+       u64 len = bh_result->b_size;
+       struct btrfs_trans_handle *trans;
+
+       em = btrfs_get_extent(inode, NULL, 0, start, len, 0);
+       if (IS_ERR(em))
+               return PTR_ERR(em);
+
+       /*
+        * Ok for INLINE and COMPRESSED extents we need to fallback on buffered
+        * io.  INLINE is special, and we could probably kludge it in here, but
+        * it's still buffered so for safety lets just fall back to the generic
+        * buffered path.
+        *
+        * For COMPRESSED we _have_ to read the entire extent in so we can
+        * decompress it, so there will be buffering required no matter what we
+        * do, so go ahead and fallback to buffered.
+        *
+        * We return -ENOTBLK because thats what makes DIO go ahead and go back
+        * to buffered IO.  Don't blame me, this is the price we pay for using
+        * the generic code.
+        */
+       if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags) ||
+           em->block_start == EXTENT_MAP_INLINE) {
+               free_extent_map(em);
+               return -ENOTBLK;
+       }
+
+       /* Just a good old fashioned hole, return */
+       if (!create && (em->block_start == EXTENT_MAP_HOLE ||
+                       test_bit(EXTENT_FLAG_PREALLOC, &em->flags))) {
+               free_extent_map(em);
+               /* DIO will do one hole at a time, so just unlock a sector */
+               unlock_extent(&BTRFS_I(inode)->io_tree, start,
+                             start + root->sectorsize - 1, GFP_NOFS);
+               return 0;
+       }
+
+       /*
+        * We don't allocate a new extent in the following cases
+        *
+        * 1) The inode is marked as NODATACOW.  In this case we'll just use the
+        * existing extent.
+        * 2) The extent is marked as PREALLOC.  We're good to go here and can
+        * just use the extent.
+        *
+        */
+       if (!create) {
+               len = em->len - (start - em->start);
+               goto map;
+       }
+
+       if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags) ||
+           ((BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW) &&
+            em->block_start != EXTENT_MAP_HOLE)) {
+               int type;
+               int ret;
+               u64 block_start;
+
+               if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags))
+                       type = BTRFS_ORDERED_PREALLOC;
+               else
+                       type = BTRFS_ORDERED_NOCOW;
+               len = min(len, em->len - (start - em->start));
+               block_start = em->block_start + (start - em->start);
+
+               /*
+                * we're not going to log anything, but we do need
+                * to make sure the current transaction stays open
+                * while we look for nocow cross refs
+                */
+               trans = btrfs_join_transaction(root, 0);
+               if (!trans)
+                       goto must_cow;
+
+               if (can_nocow_odirect(trans, inode, start, len) == 1) {
+                       ret = btrfs_add_ordered_extent_dio(inode, start,
+                                          block_start, len, len, type);
+                       btrfs_end_transaction(trans, root);
+                       if (ret) {
+                               free_extent_map(em);
+                               return ret;
+                       }
+                       goto unlock;
+               }
+               btrfs_end_transaction(trans, root);
+       }
+must_cow:
+       /*
+        * this will cow the extent, reset the len in case we changed
+        * it above
+        */
+       len = bh_result->b_size;
+       free_extent_map(em);
+       em = btrfs_new_extent_direct(inode, start, len);
+       if (IS_ERR(em))
+               return PTR_ERR(em);
+       len = min(len, em->len - (start - em->start));
+unlock:
+       clear_extent_bit(&BTRFS_I(inode)->io_tree, start, start + len - 1,
+                         EXTENT_LOCKED | EXTENT_DELALLOC | EXTENT_DIRTY, 1,
+                         0, NULL, GFP_NOFS);
+map:
+       bh_result->b_blocknr = (em->block_start + (start - em->start)) >>
+               inode->i_blkbits;
+       bh_result->b_size = len;
+       bh_result->b_bdev = em->bdev;
+       set_buffer_mapped(bh_result);
+       if (create && !test_bit(EXTENT_FLAG_PREALLOC, &em->flags))
+               set_buffer_new(bh_result);
+
+       free_extent_map(em);
+
+       return 0;
+}
+
+struct btrfs_dio_private {
+       struct inode *inode;
+       u64 logical_offset;
+       u64 disk_bytenr;
+       u64 bytes;
+       u32 *csums;
+       void *private;
+};
+
+static void btrfs_endio_direct_read(struct bio *bio, int err)
+{
+       struct bio_vec *bvec_end = bio->bi_io_vec + bio->bi_vcnt - 1;
+       struct bio_vec *bvec = bio->bi_io_vec;
+       struct btrfs_dio_private *dip = bio->bi_private;
+       struct inode *inode = dip->inode;
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       u64 start;
+       u32 *private = dip->csums;
+
+       start = dip->logical_offset;
+       do {
+               if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) {
+                       struct page *page = bvec->bv_page;
+                       char *kaddr;
+                       u32 csum = ~(u32)0;
+                       unsigned long flags;
+
+                       local_irq_save(flags);
+                       kaddr = kmap_atomic(page, KM_IRQ0);
+                       csum = btrfs_csum_data(root, kaddr + bvec->bv_offset,
+                                              csum, bvec->bv_len);
+                       btrfs_csum_final(csum, (char *)&csum);
+                       kunmap_atomic(kaddr, KM_IRQ0);
+                       local_irq_restore(flags);
+
+                       flush_dcache_page(bvec->bv_page);
+                       if (csum != *private) {
+                               printk(KERN_ERR "btrfs csum failed ino %lu off"
+                                     " %llu csum %u private %u\n",
+                                     inode->i_ino, (unsigned long long)start,
+                                     csum, *private);
+                               err = -EIO;
+                       }
+               }
+
+               start += bvec->bv_len;
+               private++;
+               bvec++;
+       } while (bvec <= bvec_end);
+
+       unlock_extent(&BTRFS_I(inode)->io_tree, dip->logical_offset,
+                     dip->logical_offset + dip->bytes - 1, GFP_NOFS);
+       bio->bi_private = dip->private;
+
+       kfree(dip->csums);
+       kfree(dip);
+       dio_end_io(bio, err);
+}
+
+static void btrfs_endio_direct_write(struct bio *bio, int err)
+{
+       struct btrfs_dio_private *dip = bio->bi_private;
+       struct inode *inode = dip->inode;
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       struct btrfs_trans_handle *trans;
+       struct btrfs_ordered_extent *ordered = NULL;
+       struct extent_state *cached_state = NULL;
+       int ret;
+
+       if (err)
+               goto out_done;
+
+       ret = btrfs_dec_test_ordered_pending(inode, &ordered,
+                                            dip->logical_offset, dip->bytes);
+       if (!ret)
+               goto out_done;
+
+       BUG_ON(!ordered);
+
+       trans = btrfs_join_transaction(root, 1);
+       if (!trans) {
+               err = -ENOMEM;
+               goto out;
+       }
+       trans->block_rsv = &root->fs_info->delalloc_block_rsv;
+
+       if (test_bit(BTRFS_ORDERED_NOCOW, &ordered->flags)) {
+               ret = btrfs_ordered_update_i_size(inode, 0, ordered);
+               if (!ret)
+                       ret = btrfs_update_inode(trans, root, inode);
+               err = ret;
+               goto out;
+       }
+
+       lock_extent_bits(&BTRFS_I(inode)->io_tree, ordered->file_offset,
+                        ordered->file_offset + ordered->len - 1, 0,
+                        &cached_state, GFP_NOFS);
+
+       if (test_bit(BTRFS_ORDERED_PREALLOC, &ordered->flags)) {
+               ret = btrfs_mark_extent_written(trans, inode,
+                                               ordered->file_offset,
+                                               ordered->file_offset +
+                                               ordered->len);
+               if (ret) {
+                       err = ret;
+                       goto out_unlock;
+               }
+       } else {
+               ret = insert_reserved_file_extent(trans, inode,
+                                                 ordered->file_offset,
+                                                 ordered->start,
+                                                 ordered->disk_len,
+                                                 ordered->len,
+                                                 ordered->len,
+                                                 0, 0, 0,
+                                                 BTRFS_FILE_EXTENT_REG);
+               unpin_extent_cache(&BTRFS_I(inode)->extent_tree,
+                                  ordered->file_offset, ordered->len);
+               if (ret) {
+                       err = ret;
+                       WARN_ON(1);
+                       goto out_unlock;
+               }
+       }
+
+       add_pending_csums(trans, inode, ordered->file_offset, &ordered->list);
+       btrfs_ordered_update_i_size(inode, 0, ordered);
+       btrfs_update_inode(trans, root, inode);
+out_unlock:
+       unlock_extent_cached(&BTRFS_I(inode)->io_tree, ordered->file_offset,
+                            ordered->file_offset + ordered->len - 1,
+                            &cached_state, GFP_NOFS);
+out:
+       btrfs_delalloc_release_metadata(inode, ordered->len);
+       btrfs_end_transaction(trans, root);
+       btrfs_put_ordered_extent(ordered);
+       btrfs_put_ordered_extent(ordered);
+out_done:
+       bio->bi_private = dip->private;
+
+       kfree(dip->csums);
+       kfree(dip);
+       dio_end_io(bio, err);
+}
+
+static int __btrfs_submit_bio_start_direct_io(struct inode *inode, int rw,
+                                   struct bio *bio, int mirror_num,
+                                   unsigned long bio_flags, u64 offset)
+{
+       int ret;
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       ret = btrfs_csum_one_bio(root, inode, bio, offset, 1);
+       BUG_ON(ret);
+       return 0;
+}
+
+static void btrfs_submit_direct(int rw, struct bio *bio, struct inode *inode,
+                               loff_t file_offset)
+{
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       struct btrfs_dio_private *dip;
+       struct bio_vec *bvec = bio->bi_io_vec;
+       u64 start;
+       int skip_sum;
+       int write = rw & (1 << BIO_RW);
+       int ret = 0;
+
+       skip_sum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM;
+
+       dip = kmalloc(sizeof(*dip), GFP_NOFS);
+       if (!dip) {
+               ret = -ENOMEM;
+               goto free_ordered;
+       }
+       dip->csums = NULL;
+
+       if (!skip_sum) {
+               dip->csums = kmalloc(sizeof(u32) * bio->bi_vcnt, GFP_NOFS);
+               if (!dip->csums) {
+                       ret = -ENOMEM;
+                       goto free_ordered;
+               }
+       }
+
+       dip->private = bio->bi_private;
+       dip->inode = inode;
+       dip->logical_offset = file_offset;
+
+       start = dip->logical_offset;
+       dip->bytes = 0;
+       do {
+               dip->bytes += bvec->bv_len;
+               bvec++;
+       } while (bvec <= (bio->bi_io_vec + bio->bi_vcnt - 1));
+
+       dip->disk_bytenr = (u64)bio->bi_sector << 9;
+       bio->bi_private = dip;
+
+       if (write)
+               bio->bi_end_io = btrfs_endio_direct_write;
+       else
+               bio->bi_end_io = btrfs_endio_direct_read;
+
+       ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0);
+       if (ret)
+               goto out_err;
+
+       if (write && !skip_sum) {
+               ret = btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info,
+                                  inode, rw, bio, 0, 0,
+                                  dip->logical_offset,
+                                  __btrfs_submit_bio_start_direct_io,
+                                  __btrfs_submit_bio_done);
+               if (ret)
+                       goto out_err;
+               return;
+       } else if (!skip_sum)
+               btrfs_lookup_bio_sums_dio(root, inode, bio,
+                                         dip->logical_offset, dip->csums);
+
+       ret = btrfs_map_bio(root, rw, bio, 0, 1);
+       if (ret)
+               goto out_err;
+       return;
+out_err:
+       kfree(dip->csums);
+       kfree(dip);
+free_ordered:
+       /*
+        * If this is a write, we need to clean up the reserved space and kill
+        * the ordered extent.
+        */
+       if (write) {
+               struct btrfs_ordered_extent *ordered;
+               ordered = btrfs_lookup_ordered_extent(inode,
+                                                     dip->logical_offset);
+               if (!test_bit(BTRFS_ORDERED_PREALLOC, &ordered->flags) &&
+                   !test_bit(BTRFS_ORDERED_NOCOW, &ordered->flags))
+                       btrfs_free_reserved_extent(root, ordered->start,
+                                                  ordered->disk_len);
+               btrfs_put_ordered_extent(ordered);
+               btrfs_put_ordered_extent(ordered);
+       }
+       bio_endio(bio, ret);
+}
+
+static ssize_t check_direct_IO(struct btrfs_root *root, int rw, struct kiocb *iocb,
+                       const struct iovec *iov, loff_t offset,
+                       unsigned long nr_segs)
+{
+       int seg;
+       size_t size;
+       unsigned long addr;
+       unsigned blocksize_mask = root->sectorsize - 1;
+       ssize_t retval = -EINVAL;
+       loff_t end = offset;
+
+       if (offset & blocksize_mask)
+               goto out;
+
+       /* Check the memory alignment.  Blocks cannot straddle pages */
+       for (seg = 0; seg < nr_segs; seg++) {
+               addr = (unsigned long)iov[seg].iov_base;
+               size = iov[seg].iov_len;
+               end += size;
+               if ((addr & blocksize_mask) || (size & blocksize_mask)) 
+                       goto out;
+       }
+       retval = 0;
+out:
+       return retval;
+}
 static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
                        const struct iovec *iov, loff_t offset,
                        unsigned long nr_segs)
 {
-       return -EINVAL;
+       struct file *file = iocb->ki_filp;
+       struct inode *inode = file->f_mapping->host;
+       struct btrfs_ordered_extent *ordered;
+       struct extent_state *cached_state = NULL;
+       u64 lockstart, lockend;
+       ssize_t ret;
+       int writing = rw & WRITE;
+       int write_bits = 0;
+       size_t count = iov_length(iov, nr_segs);
+
+       if (check_direct_IO(BTRFS_I(inode)->root, rw, iocb, iov,
+                           offset, nr_segs)) {
+               return 0;
+       }
+
+       lockstart = offset;
+       lockend = offset + count - 1;
+
+       if (writing) {
+               ret = btrfs_delalloc_reserve_space(inode, count);
+               if (ret)
+                       goto out;
+       }
+
+       while (1) {
+               lock_extent_bits(&BTRFS_I(inode)->io_tree, lockstart, lockend,
+                                0, &cached_state, GFP_NOFS);
+               /*
+                * We're concerned with the entire range that we're going to be
+                * doing DIO to, so we need to make sure theres no ordered
+                * extents in this range.
+                */
+               ordered = btrfs_lookup_ordered_range(inode, lockstart,
+                                                    lockend - lockstart + 1);
+               if (!ordered)
+                       break;
+               unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend,
+                                    &cached_state, GFP_NOFS);
+               btrfs_start_ordered_extent(inode, ordered, 1);
+               btrfs_put_ordered_extent(ordered);
+               cond_resched();
+       }
+
+       /*
+        * we don't use btrfs_set_extent_delalloc because we don't want
+        * the dirty or uptodate bits
+        */
+       if (writing) {
+               write_bits = EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING;
+               ret = set_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, lockend,
+                                    EXTENT_DELALLOC, 0, NULL, &cached_state,
+                                    GFP_NOFS);
+               if (ret) {
+                       clear_extent_bit(&BTRFS_I(inode)->io_tree, lockstart,
+                                        lockend, EXTENT_LOCKED | write_bits,
+                                        1, 0, &cached_state, GFP_NOFS);
+                       goto out;
+               }
+       }
+
+       free_extent_state(cached_state);
+       cached_state = NULL;
+
+       ret = __blockdev_direct_IO(rw, iocb, inode,
+                  BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev,
+                  iov, offset, nr_segs, btrfs_get_blocks_direct, NULL,
+                  btrfs_submit_direct, 0);
+
+       if (ret < 0 && ret != -EIOCBQUEUED) {
+               clear_extent_bit(&BTRFS_I(inode)->io_tree, offset,
+                             offset + iov_length(iov, nr_segs) - 1,
+                             EXTENT_LOCKED | write_bits, 1, 0,
+                             &cached_state, GFP_NOFS);
+       } else if (ret >= 0 && ret < iov_length(iov, nr_segs)) {
+               /*
+                * We're falling back to buffered, unlock the section we didn't
+                * do IO on.
+                */
+               clear_extent_bit(&BTRFS_I(inode)->io_tree, offset + ret,
+                             offset + iov_length(iov, nr_segs) - 1,
+                             EXTENT_LOCKED | write_bits, 1, 0,
+                             &cached_state, GFP_NOFS);
+       }
+out:
+       free_extent_state(cached_state);
+       return ret;
 }
 
 static int btrfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
@@ -5043,7 +6003,7 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
        u64 page_start;
        u64 page_end;
 
-       ret = btrfs_check_data_free_space(root, inode, PAGE_CACHE_SIZE);
+       ret  = btrfs_delalloc_reserve_space(inode, PAGE_CACHE_SIZE);
        if (ret) {
                if (ret == -ENOMEM)
                        ret = VM_FAULT_OOM;
@@ -5052,13 +6012,6 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
                goto out;
        }
 
-       ret = btrfs_reserve_metadata_for_delalloc(root, inode, 1);
-       if (ret) {
-               btrfs_free_reserved_data_space(root, inode, PAGE_CACHE_SIZE);
-               ret = VM_FAULT_SIGBUS;
-               goto out;
-       }
-
        ret = VM_FAULT_NOPAGE; /* make the VM retry the fault */
 again:
        lock_page(page);
@@ -5068,7 +6021,6 @@ again:
 
        if ((page->mapping != inode->i_mapping) ||
            (page_start >= size)) {
-               btrfs_free_reserved_data_space(root, inode, PAGE_CACHE_SIZE);
                /* page got truncated out from underneath us */
                goto out_unlock;
        }
@@ -5109,7 +6061,6 @@ again:
                unlock_extent_cached(io_tree, page_start, page_end,
                                     &cached_state, GFP_NOFS);
                ret = VM_FAULT_SIGBUS;
-               btrfs_free_reserved_data_space(root, inode, PAGE_CACHE_SIZE);
                goto out_unlock;
        }
        ret = 0;
@@ -5136,10 +6087,10 @@ again:
        unlock_extent_cached(io_tree, page_start, page_end, &cached_state, GFP_NOFS);
 
 out_unlock:
-       btrfs_unreserve_metadata_for_delalloc(root, inode, 1);
        if (!ret)
                return VM_FAULT_LOCKED;
        unlock_page(page);
+       btrfs_delalloc_release_space(inode, PAGE_CACHE_SIZE);
 out:
        return ret;
 }
@@ -5164,8 +6115,10 @@ static void btrfs_truncate(struct inode *inode)
        btrfs_wait_ordered_range(inode, inode->i_size & (~mask), (u64)-1);
        btrfs_ordered_update_i_size(inode, inode->i_size, NULL);
 
-       trans = btrfs_start_transaction(root, 1);
+       trans = btrfs_start_transaction(root, 0);
+       BUG_ON(IS_ERR(trans));
        btrfs_set_trans_block_group(trans, inode);
+       trans->block_rsv = root->orphan_block_rsv;
 
        /*
         * setattr is responsible for setting the ordered_data_close flag,
@@ -5188,6 +6141,23 @@ static void btrfs_truncate(struct inode *inode)
                btrfs_add_ordered_operation(trans, root, inode);
 
        while (1) {
+               if (!trans) {
+                       trans = btrfs_start_transaction(root, 0);
+                       BUG_ON(IS_ERR(trans));
+                       btrfs_set_trans_block_group(trans, inode);
+                       trans->block_rsv = root->orphan_block_rsv;
+               }
+
+               ret = btrfs_block_rsv_check(trans, root,
+                                           root->orphan_block_rsv, 0, 5);
+               if (ret) {
+                       BUG_ON(ret != -EAGAIN);
+                       ret = btrfs_commit_transaction(trans, root);
+                       BUG_ON(ret);
+                       trans = NULL;
+                       continue;
+               }
+
                ret = btrfs_truncate_inode_items(trans, root, inode,
                                                 inode->i_size,
                                                 BTRFS_EXTENT_DATA_KEY);
@@ -5199,10 +6169,8 @@ static void btrfs_truncate(struct inode *inode)
 
                nr = trans->blocks_used;
                btrfs_end_transaction(trans, root);
+               trans = NULL;
                btrfs_btree_balance_dirty(root, nr);
-
-               trans = btrfs_start_transaction(root, 1);
-               btrfs_set_trans_block_group(trans, inode);
        }
 
        if (ret == 0 && inode->i_nlink > 0) {
@@ -5263,21 +6231,47 @@ unsigned long btrfs_force_ra(struct address_space *mapping,
 struct inode *btrfs_alloc_inode(struct super_block *sb)
 {
        struct btrfs_inode *ei;
+       struct inode *inode;
 
        ei = kmem_cache_alloc(btrfs_inode_cachep, GFP_NOFS);
        if (!ei)
                return NULL;
+
+       ei->root = NULL;
+       ei->space_info = NULL;
+       ei->generation = 0;
+       ei->sequence = 0;
        ei->last_trans = 0;
        ei->last_sub_trans = 0;
        ei->logged_trans = 0;
-       ei->outstanding_extents = 0;
-       ei->reserved_extents = 0;
-       ei->root = NULL;
+       ei->delalloc_bytes = 0;
+       ei->reserved_bytes = 0;
+       ei->disk_i_size = 0;
+       ei->flags = 0;
+       ei->index_cnt = (u64)-1;
+       ei->last_unlink_trans = 0;
+
        spin_lock_init(&ei->accounting_lock);
+       atomic_set(&ei->outstanding_extents, 0);
+       ei->reserved_extents = 0;
+
+       ei->ordered_data_close = 0;
+       ei->orphan_meta_reserved = 0;
+       ei->dummy_inode = 0;
+       ei->force_compress = 0;
+
+       inode = &ei->vfs_inode;
+       extent_map_tree_init(&ei->extent_tree, GFP_NOFS);
+       extent_io_tree_init(&ei->io_tree, &inode->i_data, GFP_NOFS);
+       extent_io_tree_init(&ei->io_failure_tree, &inode->i_data, GFP_NOFS);
+       mutex_init(&ei->log_mutex);
        btrfs_ordered_inode_tree_init(&ei->ordered_tree);
        INIT_LIST_HEAD(&ei->i_orphan);
+       INIT_LIST_HEAD(&ei->delalloc_inodes);
        INIT_LIST_HEAD(&ei->ordered_operations);
-       return &ei->vfs_inode;
+       RB_CLEAR_NODE(&ei->rb_node);
+
+       return inode;
 }
 
 void btrfs_destroy_inode(struct inode *inode)
@@ -5287,6 +6281,8 @@ void btrfs_destroy_inode(struct inode *inode)
 
        WARN_ON(!list_empty(&inode->i_dentry));
        WARN_ON(inode->i_data.nrpages);
+       WARN_ON(atomic_read(&BTRFS_I(inode)->outstanding_extents));
+       WARN_ON(BTRFS_I(inode)->reserved_extents);
 
        /*
         * This can happen where we create an inode, but somebody else also
@@ -5307,13 +6303,13 @@ void btrfs_destroy_inode(struct inode *inode)
                spin_unlock(&root->fs_info->ordered_extent_lock);
        }
 
-       spin_lock(&root->list_lock);
+       spin_lock(&root->orphan_lock);
        if (!list_empty(&BTRFS_I(inode)->i_orphan)) {
                printk(KERN_INFO "BTRFS: inode %lu still on the orphan list\n",
                       inode->i_ino);
                list_del_init(&BTRFS_I(inode)->i_orphan);
        }
-       spin_unlock(&root->list_lock);
+       spin_unlock(&root->orphan_lock);
 
        while (1) {
                ordered = btrfs_lookup_first_ordered_extent(inode, (u64)-1);
@@ -5434,19 +6430,6 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (S_ISDIR(old_inode->i_mode) && new_inode &&
            new_inode->i_size > BTRFS_EMPTY_DIR_SIZE)
                return -ENOTEMPTY;
-
-       /*
-        * We want to reserve the absolute worst case amount of items.  So if
-        * both inodes are subvols and we need to unlink them then that would
-        * require 4 item modifications, but if they are both normal inodes it
-        * would require 5 item modifications, so we'll assume their normal
-        * inodes.  So 5 * 2 is 10, plus 1 for the new link, so 11 total items
-        * should cover the worst case number of items we'll modify.
-        */
-       ret = btrfs_reserve_metadata_space(root, 11);
-       if (ret)
-               return ret;
-
        /*
         * we're using rename to replace one file with another.
         * and the replacement file is large.  Start IO on it now so
@@ -5459,8 +6442,18 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        /* close the racy window with snapshot create/destroy ioctl */
        if (old_inode->i_ino == BTRFS_FIRST_FREE_OBJECTID)
                down_read(&root->fs_info->subvol_sem);
+       /*
+        * We want to reserve the absolute worst case amount of items.  So if
+        * both inodes are subvols and we need to unlink them then that would
+        * require 4 item modifications, but if they are both normal inodes it
+        * would require 5 item modifications, so we'll assume their normal
+        * inodes.  So 5 * 2 is 10, plus 1 for the new link, so 11 total items
+        * should cover the worst case number of items we'll modify.
+        */
+       trans = btrfs_start_transaction(root, 20);
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
 
-       trans = btrfs_start_transaction(root, 1);
        btrfs_set_trans_block_group(trans, new_dir);
 
        if (dest != root)
@@ -5559,7 +6552,6 @@ out_fail:
        if (old_inode->i_ino == BTRFS_FIRST_FREE_OBJECTID)
                up_read(&root->fs_info->subvol_sem);
 
-       btrfs_unreserve_metadata_space(root, 11);
        return ret;
 }
 
@@ -5611,6 +6603,38 @@ int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput)
        return 0;
 }
 
+int btrfs_start_one_delalloc_inode(struct btrfs_root *root, int delay_iput)
+{
+       struct btrfs_inode *binode;
+       struct inode *inode = NULL;
+
+       spin_lock(&root->fs_info->delalloc_lock);
+       while (!list_empty(&root->fs_info->delalloc_inodes)) {
+               binode = list_entry(root->fs_info->delalloc_inodes.next,
+                                   struct btrfs_inode, delalloc_inodes);
+               inode = igrab(&binode->vfs_inode);
+               if (inode) {
+                       list_move_tail(&binode->delalloc_inodes,
+                                      &root->fs_info->delalloc_inodes);
+                       break;
+               }
+
+               list_del_init(&binode->delalloc_inodes);
+               cond_resched_lock(&root->fs_info->delalloc_lock);
+       }
+       spin_unlock(&root->fs_info->delalloc_lock);
+
+       if (inode) {
+               write_inode_now(inode, 0);
+               if (delay_iput)
+                       btrfs_add_delayed_iput(inode);
+               else
+                       iput(inode);
+               return 1;
+       }
+       return 0;
+}
+
 static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
                         const char *symname)
 {
@@ -5634,26 +6658,20 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
        if (name_len > BTRFS_MAX_INLINE_DATA_SIZE(root))
                return -ENAMETOOLONG;
 
+       err = btrfs_find_free_objectid(NULL, root, dir->i_ino, &objectid);
+       if (err)
+               return err;
        /*
         * 2 items for inode item and ref
         * 2 items for dir items
         * 1 item for xattr if selinux is on
         */
-       err = btrfs_reserve_metadata_space(root, 5);
-       if (err)
-               return err;
+       trans = btrfs_start_transaction(root, 5);
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
 
-       trans = btrfs_start_transaction(root, 1);
-       if (!trans)
-               goto out_fail;
        btrfs_set_trans_block_group(trans, dir);
 
-       err = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid);
-       if (err) {
-               err = -ENOSPC;
-               goto out_unlock;
-       }
-
        inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
                                dentry->d_name.len,
                                dentry->d_parent->d_inode->i_ino, objectid,
@@ -5725,8 +6743,6 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
 out_unlock:
        nr = trans->blocks_used;
        btrfs_end_transaction_throttle(trans, root);
-out_fail:
-       btrfs_unreserve_metadata_space(root, 5);
        if (drop_inode) {
                inode_dec_link_count(inode);
                iput(inode);
@@ -5735,33 +6751,28 @@ out_fail:
        return err;
 }
 
-static int prealloc_file_range(struct inode *inode, u64 start, u64 end,
-                       u64 alloc_hint, int mode, loff_t actual_len)
+int btrfs_prealloc_file_range(struct inode *inode, int mode,
+                             u64 start, u64 num_bytes, u64 min_size,
+                             loff_t actual_len, u64 *alloc_hint)
 {
        struct btrfs_trans_handle *trans;
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_key ins;
        u64 cur_offset = start;
-       u64 num_bytes = end - start;
        int ret = 0;
-       u64 i_size;
 
        while (num_bytes > 0) {
-               trans = btrfs_start_transaction(root, 1);
-
-               ret = btrfs_reserve_extent(trans, root, num_bytes,
-                                          root->sectorsize, 0, alloc_hint,
-                                          (u64)-1, &ins, 1);
-               if (ret) {
-                       WARN_ON(1);
-                       goto stop_trans;
+               trans = btrfs_start_transaction(root, 3);
+               if (IS_ERR(trans)) {
+                       ret = PTR_ERR(trans);
+                       break;
                }
 
-               ret = btrfs_reserve_metadata_space(root, 3);
+               ret = btrfs_reserve_extent(trans, root, num_bytes, min_size,
+                                          0, *alloc_hint, (u64)-1, &ins, 1);
                if (ret) {
-                       btrfs_free_reserved_extent(root, ins.objectid,
-                                                  ins.offset);
-                       goto stop_trans;
+                       btrfs_end_transaction(trans, root);
+                       break;
                }
 
                ret = insert_reserved_file_extent(trans, inode,
@@ -5775,34 +6786,27 @@ static int prealloc_file_range(struct inode *inode, u64 start, u64 end,
 
                num_bytes -= ins.offset;
                cur_offset += ins.offset;
-               alloc_hint = ins.objectid + ins.offset;
+               *alloc_hint = ins.objectid + ins.offset;
 
                inode->i_ctime = CURRENT_TIME;
                BTRFS_I(inode)->flags |= BTRFS_INODE_PREALLOC;
                if (!(mode & FALLOC_FL_KEEP_SIZE) &&
-                       (actual_len > inode->i_size) &&
-                       (cur_offset > inode->i_size)) {
-
+                   (actual_len > inode->i_size) &&
+                   (cur_offset > inode->i_size)) {
                        if (cur_offset > actual_len)
-                               i_size  = actual_len;
+                               i_size_write(inode, actual_len);
                        else
-                               i_size = cur_offset;
-                       i_size_write(inode, i_size);
-                       btrfs_ordered_update_i_size(inode, i_size, NULL);
+                               i_size_write(inode, cur_offset);
+                       i_size_write(inode, cur_offset);
+                       btrfs_ordered_update_i_size(inode, cur_offset, NULL);
                }
 
                ret = btrfs_update_inode(trans, root, inode);
                BUG_ON(ret);
 
                btrfs_end_transaction(trans, root);
-               btrfs_unreserve_metadata_space(root, 3);
        }
        return ret;
-
-stop_trans:
-       btrfs_end_transaction(trans, root);
-       return ret;
-
 }
 
 static long btrfs_fallocate(struct inode *inode, int mode,
@@ -5835,8 +6839,7 @@ static long btrfs_fallocate(struct inode *inode, int mode,
                        goto out;
        }
 
-       ret = btrfs_check_data_free_space(BTRFS_I(inode)->root, inode,
-                                         alloc_end - alloc_start);
+       ret = btrfs_check_data_free_space(inode, alloc_end - alloc_start);
        if (ret)
                goto out;
 
@@ -5881,16 +6884,16 @@ static long btrfs_fallocate(struct inode *inode, int mode,
                if (em->block_start == EXTENT_MAP_HOLE ||
                    (cur_offset >= inode->i_size &&
                     !test_bit(EXTENT_FLAG_PREALLOC, &em->flags))) {
-                       ret = prealloc_file_range(inode,
-                                                 cur_offset, last_byte,
-                                               alloc_hint, mode, offset+len);
+                       ret = btrfs_prealloc_file_range(inode, 0, cur_offset,
+                                                       last_byte - cur_offset,
+                                                       1 << inode->i_blkbits,
+                                                       offset + len,
+                                                       &alloc_hint);
                        if (ret < 0) {
                                free_extent_map(em);
                                break;
                        }
                }
-               if (em->block_start <= EXTENT_MAP_LAST_BYTE)
-                       alloc_hint = em->block_start;
                free_extent_map(em);
 
                cur_offset = last_byte;
@@ -5902,8 +6905,7 @@ static long btrfs_fallocate(struct inode *inode, int mode,
        unlock_extent_cached(&BTRFS_I(inode)->io_tree, alloc_start, locked_end,
                             &cached_state, GFP_NOFS);
 
-       btrfs_free_reserved_data_space(BTRFS_I(inode)->root, inode,
-                                      alloc_end - alloc_start);
+       btrfs_free_reserved_data_space(inode, alloc_end - alloc_start);
 out:
        mutex_unlock(&inode->i_mutex);
        return ret;
index 97a97839a867f1c0773f8a684a1289ae185d0eb6..4cdb98cf26de174e644e7d74e2a97e2fe037f08b 100644 (file)
@@ -239,23 +239,19 @@ static noinline int create_subvol(struct btrfs_root *root,
        u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID;
        u64 index = 0;
 
+       ret = btrfs_find_free_objectid(NULL, root->fs_info->tree_root,
+                                      0, &objectid);
+       if (ret)
+               return ret;
        /*
         * 1 - inode item
         * 2 - refs
         * 1 - root item
         * 2 - dir items
         */
-       ret = btrfs_reserve_metadata_space(root, 6);
-       if (ret)
-               return ret;
-
-       trans = btrfs_start_transaction(root, 1);
-       BUG_ON(!trans);
-
-       ret = btrfs_find_free_objectid(trans, root->fs_info->tree_root,
-                                      0, &objectid);
-       if (ret)
-               goto fail;
+       trans = btrfs_start_transaction(root, 6);
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
 
        leaf = btrfs_alloc_free_block(trans, root, root->leafsize,
                                      0, objectid, NULL, 0, 0, 0);
@@ -345,13 +341,10 @@ fail:
        err = btrfs_commit_transaction(trans, root);
        if (err && !ret)
                ret = err;
-
-       btrfs_unreserve_metadata_space(root, 6);
        return ret;
 }
 
-static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
-                          char *name, int namelen)
+static int create_snapshot(struct btrfs_root *root, struct dentry *dentry)
 {
        struct inode *inode;
        struct btrfs_pending_snapshot *pending_snapshot;
@@ -361,40 +354,33 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
        if (!root->ref_cows)
                return -EINVAL;
 
-       /*
-        * 1 - inode item
-        * 2 - refs
-        * 1 - root item
-        * 2 - dir items
-        */
-       ret = btrfs_reserve_metadata_space(root, 6);
-       if (ret)
-               goto fail;
-
        pending_snapshot = kzalloc(sizeof(*pending_snapshot), GFP_NOFS);
-       if (!pending_snapshot) {
-               ret = -ENOMEM;
-               btrfs_unreserve_metadata_space(root, 6);
-               goto fail;
-       }
-       pending_snapshot->name = kmalloc(namelen + 1, GFP_NOFS);
-       if (!pending_snapshot->name) {
-               ret = -ENOMEM;
-               kfree(pending_snapshot);
-               btrfs_unreserve_metadata_space(root, 6);
-               goto fail;
-       }
-       memcpy(pending_snapshot->name, name, namelen);
-       pending_snapshot->name[namelen] = '\0';
+       if (!pending_snapshot)
+               return -ENOMEM;
+
+       btrfs_init_block_rsv(&pending_snapshot->block_rsv);
        pending_snapshot->dentry = dentry;
-       trans = btrfs_start_transaction(root, 1);
-       BUG_ON(!trans);
        pending_snapshot->root = root;
+
+       trans = btrfs_start_transaction(root->fs_info->extent_root, 5);
+       if (IS_ERR(trans)) {
+               ret = PTR_ERR(trans);
+               goto fail;
+       }
+
+       ret = btrfs_snap_reserve_metadata(trans, pending_snapshot);
+       BUG_ON(ret);
+
        list_add(&pending_snapshot->list,
                 &trans->transaction->pending_snapshots);
-       ret = btrfs_commit_transaction(trans, root);
+       ret = btrfs_commit_transaction(trans, root->fs_info->extent_root);
        BUG_ON(ret);
-       btrfs_unreserve_metadata_space(root, 6);
+
+       ret = pending_snapshot->error;
+       if (ret)
+               goto fail;
+
+       btrfs_orphan_cleanup(pending_snapshot->snap);
 
        inode = btrfs_lookup_dentry(dentry->d_parent->d_inode, dentry);
        if (IS_ERR(inode)) {
@@ -405,6 +391,7 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
        d_instantiate(dentry, inode);
        ret = 0;
 fail:
+       kfree(pending_snapshot);
        return ret;
 }
 
@@ -456,8 +443,7 @@ static noinline int btrfs_mksubvol(struct path *parent,
                goto out_up_read;
 
        if (snap_src) {
-               error = create_snapshot(snap_src, dentry,
-                                       name, namelen);
+               error = create_snapshot(snap_src, dentry);
        } else {
                error = create_subvol(BTRFS_I(dir)->root, dentry,
                                      name, namelen);
@@ -601,19 +587,9 @@ static int btrfs_defrag_file(struct file *file,
                if (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS)
                        BTRFS_I(inode)->force_compress = 1;
 
-               ret = btrfs_check_data_free_space(root, inode, PAGE_CACHE_SIZE);
-               if (ret) {
-                       ret = -ENOSPC;
-                       break;
-               }
-
-               ret = btrfs_reserve_metadata_for_delalloc(root, inode, 1);
-               if (ret) {
-                       btrfs_free_reserved_data_space(root, inode,
-                                                      PAGE_CACHE_SIZE);
-                       ret = -ENOSPC;
-                       break;
-               }
+               ret  = btrfs_delalloc_reserve_space(inode, PAGE_CACHE_SIZE);
+               if (ret)
+                       goto err_unlock;
 again:
                if (inode->i_size == 0 ||
                    i > ((inode->i_size - 1) >> PAGE_CACHE_SHIFT)) {
@@ -622,8 +598,10 @@ again:
                }
 
                page = grab_cache_page(inode->i_mapping, i);
-               if (!page)
+               if (!page) {
+                       ret = -ENOMEM;
                        goto err_reservations;
+               }
 
                if (!PageUptodate(page)) {
                        btrfs_readpage(NULL, page);
@@ -631,6 +609,7 @@ again:
                        if (!PageUptodate(page)) {
                                unlock_page(page);
                                page_cache_release(page);
+                               ret = -EIO;
                                goto err_reservations;
                        }
                }
@@ -644,8 +623,7 @@ again:
                wait_on_page_writeback(page);
 
                if (PageDirty(page)) {
-                       btrfs_free_reserved_data_space(root, inode,
-                                                      PAGE_CACHE_SIZE);
+                       btrfs_delalloc_release_space(inode, PAGE_CACHE_SIZE);
                        goto loop_unlock;
                }
 
@@ -683,7 +661,6 @@ loop_unlock:
                page_cache_release(page);
                mutex_unlock(&inode->i_mutex);
 
-               btrfs_unreserve_metadata_for_delalloc(root, inode, 1);
                balance_dirty_pages_ratelimited_nr(inode->i_mapping, 1);
                i++;
        }
@@ -713,9 +690,9 @@ loop_unlock:
        return 0;
 
 err_reservations:
+       btrfs_delalloc_release_space(inode, PAGE_CACHE_SIZE);
+err_unlock:
        mutex_unlock(&inode->i_mutex);
-       btrfs_free_reserved_data_space(root, inode, PAGE_CACHE_SIZE);
-       btrfs_unreserve_metadata_for_delalloc(root, inode, 1);
        return ret;
 }
 
@@ -811,7 +788,7 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root,
                device->name, (unsigned long long)new_size);
 
        if (new_size > old_size) {
-               trans = btrfs_start_transaction(root, 1);
+               trans = btrfs_start_transaction(root, 0);
                ret = btrfs_grow_device(trans, device, new_size);
                btrfs_commit_transaction(trans, root);
        } else {
@@ -1300,7 +1277,13 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
        if (err)
                goto out_up_write;
 
-       trans = btrfs_start_transaction(root, 1);
+       trans = btrfs_start_transaction(root, 0);
+       if (IS_ERR(trans)) {
+               err = PTR_ERR(trans);
+               goto out;
+       }
+       trans->block_rsv = &root->fs_info->global_block_rsv;
+
        ret = btrfs_unlink_subvol(trans, root, dir,
                                dest->root_key.objectid,
                                dentry->d_name.name,
@@ -1314,10 +1297,12 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
        dest->root_item.drop_level = 0;
        btrfs_set_root_refs(&dest->root_item, 0);
 
-       ret = btrfs_insert_orphan_item(trans,
-                               root->fs_info->tree_root,
-                               dest->root_key.objectid);
-       BUG_ON(ret);
+       if (!xchg(&dest->orphan_item_inserted, 1)) {
+               ret = btrfs_insert_orphan_item(trans,
+                                       root->fs_info->tree_root,
+                                       dest->root_key.objectid);
+               BUG_ON(ret);
+       }
 
        ret = btrfs_commit_transaction(trans, root);
        BUG_ON(ret);
@@ -1358,8 +1343,10 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp)
                        ret = -EPERM;
                        goto out;
                }
-               btrfs_defrag_root(root, 0);
-               btrfs_defrag_root(root->fs_info->extent_root, 0);
+               ret = btrfs_defrag_root(root, 0);
+               if (ret)
+                       goto out;
+               ret = btrfs_defrag_root(root->fs_info->extent_root, 0);
                break;
        case S_IFREG:
                if (!(file->f_mode & FMODE_WRITE)) {
@@ -1389,9 +1376,11 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp)
                        /* the rest are all set to zero by kzalloc */
                        range->len = (u64)-1;
                }
-               btrfs_defrag_file(file, range);
+               ret = btrfs_defrag_file(file, range);
                kfree(range);
                break;
+       default:
+               ret = -EINVAL;
        }
 out:
        mnt_drop_write(file->f_path.mnt);
@@ -1550,12 +1539,6 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
                btrfs_wait_ordered_range(src, off, off+len);
        }
 
-       trans = btrfs_start_transaction(root, 1);
-       BUG_ON(!trans);
-
-       /* punch hole in destination first */
-       btrfs_drop_extents(trans, inode, off, off + len, &hint_byte, 1);
-
        /* clone data */
        key.objectid = src->i_ino;
        key.type = BTRFS_EXTENT_DATA_KEY;
@@ -1566,7 +1549,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
                 * note the key will change type as we walk through the
                 * tree.
                 */
-               ret = btrfs_search_slot(trans, root, &key, path, 0, 0);
+               ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
                if (ret < 0)
                        goto out;
 
@@ -1629,12 +1612,31 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
                        new_key.objectid = inode->i_ino;
                        new_key.offset = key.offset + destoff - off;
 
+                       trans = btrfs_start_transaction(root, 1);
+                       if (IS_ERR(trans)) {
+                               ret = PTR_ERR(trans);
+                               goto out;
+                       }
+
                        if (type == BTRFS_FILE_EXTENT_REG ||
                            type == BTRFS_FILE_EXTENT_PREALLOC) {
+                               if (off > key.offset) {
+                                       datao += off - key.offset;
+                                       datal -= off - key.offset;
+                               }
+
+                               if (key.offset + datal > off + len)
+                                       datal = off + len - key.offset;
+
+                               ret = btrfs_drop_extents(trans, inode,
+                                                        new_key.offset,
+                                                        new_key.offset + datal,
+                                                        &hint_byte, 1);
+                               BUG_ON(ret);
+
                                ret = btrfs_insert_empty_item(trans, root, path,
                                                              &new_key, size);
-                               if (ret)
-                                       goto out;
+                               BUG_ON(ret);
 
                                leaf = path->nodes[0];
                                slot = path->slots[0];
@@ -1645,14 +1647,6 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
                                extent = btrfs_item_ptr(leaf, slot,
                                                struct btrfs_file_extent_item);
 
-                               if (off > key.offset) {
-                                       datao += off - key.offset;
-                                       datal -= off - key.offset;
-                               }
-
-                               if (key.offset + datal > off + len)
-                                       datal = off + len - key.offset;
-
                                /* disko == 0 means it's a hole */
                                if (!disko)
                                        datao = 0;
@@ -1683,14 +1677,21 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
 
                                if (comp && (skip || trim)) {
                                        ret = -EINVAL;
+                                       btrfs_end_transaction(trans, root);
                                        goto out;
                                }
                                size -= skip + trim;
                                datal -= skip + trim;
+
+                               ret = btrfs_drop_extents(trans, inode,
+                                                        new_key.offset,
+                                                        new_key.offset + datal,
+                                                        &hint_byte, 1);
+                               BUG_ON(ret);
+
                                ret = btrfs_insert_empty_item(trans, root, path,
                                                              &new_key, size);
-                               if (ret)
-                                       goto out;
+                               BUG_ON(ret);
 
                                if (skip) {
                                        u32 start =
@@ -1708,8 +1709,17 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
                        }
 
                        btrfs_mark_buffer_dirty(leaf);
-               }
+                       btrfs_release_path(root, path);
 
+                       inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+                       if (new_key.offset + datal > inode->i_size)
+                               btrfs_i_size_write(inode,
+                                                  new_key.offset + datal);
+                       BTRFS_I(inode)->flags = BTRFS_I(src)->flags;
+                       ret = btrfs_update_inode(trans, root, inode);
+                       BUG_ON(ret);
+                       btrfs_end_transaction(trans, root);
+               }
 next:
                btrfs_release_path(root, path);
                key.offset++;
@@ -1717,17 +1727,7 @@ next:
        ret = 0;
 out:
        btrfs_release_path(root, path);
-       if (ret == 0) {
-               inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-               if (destoff + olen > inode->i_size)
-                       btrfs_i_size_write(inode, destoff + olen);
-               BTRFS_I(inode)->flags = BTRFS_I(src)->flags;
-               ret = btrfs_update_inode(trans, root, inode);
-       }
-       btrfs_end_transaction(trans, root);
        unlock_extent(&BTRFS_I(src)->io_tree, off, off+len, GFP_NOFS);
-       if (ret)
-               vmtruncate(inode, 0);
 out_unlock:
        mutex_unlock(&src->i_mutex);
        mutex_unlock(&inode->i_mutex);
index a127c0ebb2dcaec1d6ac6733855ac88cb6aff4a3..e56c72bc5adddcdb4338b573a2f7cbc05e2b4a37 100644 (file)
@@ -124,6 +124,15 @@ static int offset_in_entry(struct btrfs_ordered_extent *entry, u64 file_offset)
        return 1;
 }
 
+static int range_overlaps(struct btrfs_ordered_extent *entry, u64 file_offset,
+                         u64 len)
+{
+       if (file_offset + len <= entry->file_offset ||
+           entry->file_offset + entry->len <= file_offset)
+               return 0;
+       return 1;
+}
+
 /*
  * look find the first ordered struct that has this offset, otherwise
  * the first one less than this offset
@@ -161,8 +170,9 @@ static inline struct rb_node *tree_search(struct btrfs_ordered_inode_tree *tree,
  * The tree is given a single reference on the ordered extent that was
  * inserted.
  */
-int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
-                            u64 start, u64 len, u64 disk_len, int type)
+static int __btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
+                                     u64 start, u64 len, u64 disk_len,
+                                     int type, int dio)
 {
        struct btrfs_ordered_inode_tree *tree;
        struct rb_node *node;
@@ -182,6 +192,9 @@ int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
        if (type != BTRFS_ORDERED_IO_DONE && type != BTRFS_ORDERED_COMPLETE)
                set_bit(type, &entry->flags);
 
+       if (dio)
+               set_bit(BTRFS_ORDERED_DIRECT, &entry->flags);
+
        /* one ref for the tree */
        atomic_set(&entry->refs, 1);
        init_waitqueue_head(&entry->wait);
@@ -203,6 +216,20 @@ int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
        return 0;
 }
 
+int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
+                            u64 start, u64 len, u64 disk_len, int type)
+{
+       return __btrfs_add_ordered_extent(inode, file_offset, start, len,
+                                         disk_len, type, 0);
+}
+
+int btrfs_add_ordered_extent_dio(struct inode *inode, u64 file_offset,
+                                u64 start, u64 len, u64 disk_len, int type)
+{
+       return __btrfs_add_ordered_extent(inode, file_offset, start, len,
+                                         disk_len, type, 1);
+}
+
 /*
  * Add a struct btrfs_ordered_sum into the list of checksums to be inserted
  * when an ordered extent is finished.  If the list covers more than one
@@ -311,13 +338,6 @@ static int __btrfs_remove_ordered_extent(struct inode *inode,
        tree->last = NULL;
        set_bit(BTRFS_ORDERED_COMPLETE, &entry->flags);
 
-       spin_lock(&BTRFS_I(inode)->accounting_lock);
-       WARN_ON(!BTRFS_I(inode)->outstanding_extents);
-       BTRFS_I(inode)->outstanding_extents--;
-       spin_unlock(&BTRFS_I(inode)->accounting_lock);
-       btrfs_unreserve_metadata_for_delalloc(BTRFS_I(inode)->root,
-                                             inode, 1);
-
        spin_lock(&root->fs_info->ordered_extent_lock);
        list_del_init(&entry->root_extent_list);
 
@@ -491,7 +511,8 @@ void btrfs_start_ordered_extent(struct inode *inode,
         * start IO on any dirty ones so the wait doesn't stall waiting
         * for pdflush to find them
         */
-       filemap_fdatawrite_range(inode->i_mapping, start, end);
+       if (!test_bit(BTRFS_ORDERED_DIRECT, &entry->flags))
+               filemap_fdatawrite_range(inode->i_mapping, start, end);
        if (wait) {
                wait_event(entry->wait, test_bit(BTRFS_ORDERED_COMPLETE,
                                                 &entry->flags));
@@ -588,6 +609,47 @@ out:
        return entry;
 }
 
+/* Since the DIO code tries to lock a wide area we need to look for any ordered
+ * extents that exist in the range, rather than just the start of the range.
+ */
+struct btrfs_ordered_extent *btrfs_lookup_ordered_range(struct inode *inode,
+                                                       u64 file_offset,
+                                                       u64 len)
+{
+       struct btrfs_ordered_inode_tree *tree;
+       struct rb_node *node;
+       struct btrfs_ordered_extent *entry = NULL;
+
+       tree = &BTRFS_I(inode)->ordered_tree;
+       spin_lock(&tree->lock);
+       node = tree_search(tree, file_offset);
+       if (!node) {
+               node = tree_search(tree, file_offset + len);
+               if (!node)
+                       goto out;
+       }
+
+       while (1) {
+               entry = rb_entry(node, struct btrfs_ordered_extent, rb_node);
+               if (range_overlaps(entry, file_offset, len))
+                       break;
+
+               if (entry->file_offset >= file_offset + len) {
+                       entry = NULL;
+                       break;
+               }
+               entry = NULL;
+               node = rb_next(node);
+               if (!node)
+                       break;
+       }
+out:
+       if (entry)
+               atomic_inc(&entry->refs);
+       spin_unlock(&tree->lock);
+       return entry;
+}
+
 /*
  * lookup and return any extent before 'file_offset'.  NULL is returned
  * if none is found
index c82f76a9f04082ac254319b14625840170707f66..8ac365492a3f4f01ba13aac1bb6f1041a97f3608 100644 (file)
@@ -72,6 +72,8 @@ struct btrfs_ordered_sum {
 
 #define BTRFS_ORDERED_PREALLOC 4 /* set when writing to prealloced extent */
 
+#define BTRFS_ORDERED_DIRECT 5 /* set when we're doing DIO with this extent */
+
 struct btrfs_ordered_extent {
        /* logical offset in the file */
        u64 file_offset;
@@ -140,7 +142,9 @@ int btrfs_dec_test_ordered_pending(struct inode *inode,
                                   struct btrfs_ordered_extent **cached,
                                   u64 file_offset, u64 io_size);
 int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
-                            u64 start, u64 len, u64 disk_len, int tyep);
+                            u64 start, u64 len, u64 disk_len, int type);
+int btrfs_add_ordered_extent_dio(struct inode *inode, u64 file_offset,
+                                u64 start, u64 len, u64 disk_len, int type);
 int btrfs_add_ordered_sum(struct inode *inode,
                          struct btrfs_ordered_extent *entry,
                          struct btrfs_ordered_sum *sum);
@@ -151,6 +155,9 @@ void btrfs_start_ordered_extent(struct inode *inode,
 int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len);
 struct btrfs_ordered_extent *
 btrfs_lookup_first_ordered_extent(struct inode * inode, u64 file_offset);
+struct btrfs_ordered_extent *btrfs_lookup_ordered_range(struct inode *inode,
+                                                       u64 file_offset,
+                                                       u64 len);
 int btrfs_ordered_update_i_size(struct inode *inode, u64 offset,
                                struct btrfs_ordered_extent *ordered);
 int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr, u32 *sum);
index e558dd941ded32d39493a9a605156d77983abed2..05d41e569236330cc8ed8e5e0f8b17566080791c 100644 (file)
@@ -44,8 +44,12 @@ struct tree_entry {
 struct backref_node {
        struct rb_node rb_node;
        u64 bytenr;
-       /* objectid tree block owner */
+
+       u64 new_bytenr;
+       /* objectid of tree block owner, can be not uptodate */
        u64 owner;
+       /* link to pending, changed or detached list */
+       struct list_head list;
        /* list of upper level blocks reference this block */
        struct list_head upper;
        /* list of child blocks in the cache */
@@ -56,9 +60,9 @@ struct backref_node {
        struct extent_buffer *eb;
        /* level of tree block */
        unsigned int level:8;
-       /* 1 if the block is root of old snapshot */
-       unsigned int old_root:1;
-       /* 1 if no child blocks in the cache */
+       /* is the block in non-reference counted tree */
+       unsigned int cowonly:1;
+       /* 1 if no child node in the cache */
        unsigned int lowest:1;
        /* is the extent buffer locked */
        unsigned int locked:1;
@@ -66,6 +70,16 @@ struct backref_node {
        unsigned int processed:1;
        /* have backrefs of this block been checked */
        unsigned int checked:1;
+       /*
+        * 1 if corresponding block has been cowed but some upper
+        * level block pointers may not point to the new location
+        */
+       unsigned int pending:1;
+       /*
+        * 1 if the backref node isn't connected to any other
+        * backref node.
+        */
+       unsigned int detached:1;
 };
 
 /*
@@ -74,7 +88,6 @@ struct backref_node {
 struct backref_edge {
        struct list_head list[2];
        struct backref_node *node[2];
-       u64 blockptr;
 };
 
 #define LOWER  0
@@ -83,9 +96,25 @@ struct backref_edge {
 struct backref_cache {
        /* red black tree of all backref nodes in the cache */
        struct rb_root rb_root;
-       /* list of backref nodes with no child block in the cache */
+       /* for passing backref nodes to btrfs_reloc_cow_block */
+       struct backref_node *path[BTRFS_MAX_LEVEL];
+       /*
+        * list of blocks that have been cowed but some block
+        * pointers in upper level blocks may not reflect the
+        * new location
+        */
        struct list_head pending[BTRFS_MAX_LEVEL];
-       spinlock_t lock;
+       /* list of backref nodes with no child node */
+       struct list_head leaves;
+       /* list of blocks that have been cowed in current transaction */
+       struct list_head changed;
+       /* list of detached backref node. */
+       struct list_head detached;
+
+       u64 last_trans;
+
+       int nr_nodes;
+       int nr_edges;
 };
 
 /*
@@ -113,15 +142,6 @@ struct tree_block {
        unsigned int key_ready:1;
 };
 
-/* inode vector */
-#define INODEVEC_SIZE 16
-
-struct inodevec {
-       struct list_head list;
-       struct inode *inode[INODEVEC_SIZE];
-       int nr;
-};
-
 #define MAX_EXTENTS 128
 
 struct file_extent_cluster {
@@ -138,36 +158,43 @@ struct reloc_control {
        struct btrfs_root *extent_root;
        /* inode for moving data */
        struct inode *data_inode;
-       struct btrfs_workers workers;
+
+       struct btrfs_block_rsv *block_rsv;
+
+       struct backref_cache backref_cache;
+
+       struct file_extent_cluster cluster;
        /* tree blocks have been processed */
        struct extent_io_tree processed_blocks;
        /* map start of tree root to corresponding reloc tree */
        struct mapping_tree reloc_root_tree;
        /* list of reloc trees */
        struct list_head reloc_roots;
+       /* size of metadata reservation for merging reloc trees */
+       u64 merging_rsv_size;
+       /* size of relocated tree nodes */
+       u64 nodes_relocated;
+
        u64 search_start;
        u64 extents_found;
-       u64 extents_skipped;
-       int stage;
-       int create_reloc_root;
+
+       int block_rsv_retries;
+
+       unsigned int stage:8;
+       unsigned int create_reloc_tree:1;
+       unsigned int merge_reloc_tree:1;
        unsigned int found_file_extent:1;
-       unsigned int found_old_snapshot:1;
+       unsigned int commit_transaction:1;
 };
 
 /* stages of data relocation */
 #define MOVE_DATA_EXTENTS      0
 #define UPDATE_DATA_PTRS       1
 
-/*
- * merge reloc tree to corresponding fs tree in worker threads
- */
-struct async_merge {
-       struct btrfs_work work;
-       struct reloc_control *rc;
-       struct btrfs_root *root;
-       struct completion *done;
-       atomic_t *num_pending;
-};
+static void remove_backref_node(struct backref_cache *cache,
+                               struct backref_node *node);
+static void __mark_block_processed(struct reloc_control *rc,
+                                  struct backref_node *node);
 
 static void mapping_tree_init(struct mapping_tree *tree)
 {
@@ -181,15 +208,80 @@ static void backref_cache_init(struct backref_cache *cache)
        cache->rb_root = RB_ROOT;
        for (i = 0; i < BTRFS_MAX_LEVEL; i++)
                INIT_LIST_HEAD(&cache->pending[i]);
-       spin_lock_init(&cache->lock);
+       INIT_LIST_HEAD(&cache->changed);
+       INIT_LIST_HEAD(&cache->detached);
+       INIT_LIST_HEAD(&cache->leaves);
+}
+
+static void backref_cache_cleanup(struct backref_cache *cache)
+{
+       struct backref_node *node;
+       int i;
+
+       while (!list_empty(&cache->detached)) {
+               node = list_entry(cache->detached.next,
+                                 struct backref_node, list);
+               remove_backref_node(cache, node);
+       }
+
+       while (!list_empty(&cache->leaves)) {
+               node = list_entry(cache->leaves.next,
+                                 struct backref_node, lower);
+               remove_backref_node(cache, node);
+       }
+
+       cache->last_trans = 0;
+
+       for (i = 0; i < BTRFS_MAX_LEVEL; i++)
+               BUG_ON(!list_empty(&cache->pending[i]));
+       BUG_ON(!list_empty(&cache->changed));
+       BUG_ON(!list_empty(&cache->detached));
+       BUG_ON(!RB_EMPTY_ROOT(&cache->rb_root));
+       BUG_ON(cache->nr_nodes);
+       BUG_ON(cache->nr_edges);
+}
+
+static struct backref_node *alloc_backref_node(struct backref_cache *cache)
+{
+       struct backref_node *node;
+
+       node = kzalloc(sizeof(*node), GFP_NOFS);
+       if (node) {
+               INIT_LIST_HEAD(&node->list);
+               INIT_LIST_HEAD(&node->upper);
+               INIT_LIST_HEAD(&node->lower);
+               RB_CLEAR_NODE(&node->rb_node);
+               cache->nr_nodes++;
+       }
+       return node;
+}
+
+static void free_backref_node(struct backref_cache *cache,
+                             struct backref_node *node)
+{
+       if (node) {
+               cache->nr_nodes--;
+               kfree(node);
+       }
+}
+
+static struct backref_edge *alloc_backref_edge(struct backref_cache *cache)
+{
+       struct backref_edge *edge;
+
+       edge = kzalloc(sizeof(*edge), GFP_NOFS);
+       if (edge)
+               cache->nr_edges++;
+       return edge;
 }
 
-static void backref_node_init(struct backref_node *node)
+static void free_backref_edge(struct backref_cache *cache,
+                             struct backref_edge *edge)
 {
-       memset(node, 0, sizeof(*node));
-       INIT_LIST_HEAD(&node->upper);
-       INIT_LIST_HEAD(&node->lower);
-       RB_CLEAR_NODE(&node->rb_node);
+       if (edge) {
+               cache->nr_edges--;
+               kfree(edge);
+       }
 }
 
 static struct rb_node *tree_insert(struct rb_root *root, u64 bytenr,
@@ -250,6 +342,7 @@ static struct backref_node *walk_up_backref(struct backref_node *node,
                edges[idx++] = edge;
                node = edge->node[UPPER];
        }
+       BUG_ON(node->detached);
        *index = idx;
        return node;
 }
@@ -281,13 +374,18 @@ static struct backref_node *walk_down_backref(struct backref_edge *edges[],
        return NULL;
 }
 
+static void unlock_node_buffer(struct backref_node *node)
+{
+       if (node->locked) {
+               btrfs_tree_unlock(node->eb);
+               node->locked = 0;
+       }
+}
+
 static void drop_node_buffer(struct backref_node *node)
 {
        if (node->eb) {
-               if (node->locked) {
-                       btrfs_tree_unlock(node->eb);
-                       node->locked = 0;
-               }
+               unlock_node_buffer(node);
                free_extent_buffer(node->eb);
                node->eb = NULL;
        }
@@ -296,14 +394,14 @@ static void drop_node_buffer(struct backref_node *node)
 static void drop_backref_node(struct backref_cache *tree,
                              struct backref_node *node)
 {
-       BUG_ON(!node->lowest);
        BUG_ON(!list_empty(&node->upper));
 
        drop_node_buffer(node);
+       list_del(&node->list);
        list_del(&node->lower);
-
-       rb_erase(&node->rb_node, &tree->rb_root);
-       kfree(node);
+       if (!RB_EMPTY_NODE(&node->rb_node))
+               rb_erase(&node->rb_node, &tree->rb_root);
+       free_backref_node(tree, node);
 }
 
 /*
@@ -318,27 +416,121 @@ static void remove_backref_node(struct backref_cache *cache,
        if (!node)
                return;
 
-       BUG_ON(!node->lowest);
+       BUG_ON(!node->lowest && !node->detached);
        while (!list_empty(&node->upper)) {
                edge = list_entry(node->upper.next, struct backref_edge,
                                  list[LOWER]);
                upper = edge->node[UPPER];
                list_del(&edge->list[LOWER]);
                list_del(&edge->list[UPPER]);
-               kfree(edge);
+               free_backref_edge(cache, edge);
+
+               if (RB_EMPTY_NODE(&upper->rb_node)) {
+                       BUG_ON(!list_empty(&node->upper));
+                       drop_backref_node(cache, node);
+                       node = upper;
+                       node->lowest = 1;
+                       continue;
+               }
                /*
-                * add the node to pending list if no other
+                * add the node to leaf node list if no other
                 * child block cached.
                 */
                if (list_empty(&upper->lower)) {
-                       list_add_tail(&upper->lower,
-                                     &cache->pending[upper->level]);
+                       list_add_tail(&upper->lower, &cache->leaves);
                        upper->lowest = 1;
                }
        }
+
        drop_backref_node(cache, node);
 }
 
+static void update_backref_node(struct backref_cache *cache,
+                               struct backref_node *node, u64 bytenr)
+{
+       struct rb_node *rb_node;
+       rb_erase(&node->rb_node, &cache->rb_root);
+       node->bytenr = bytenr;
+       rb_node = tree_insert(&cache->rb_root, node->bytenr, &node->rb_node);
+       BUG_ON(rb_node);
+}
+
+/*
+ * update backref cache after a transaction commit
+ */
+static int update_backref_cache(struct btrfs_trans_handle *trans,
+                               struct backref_cache *cache)
+{
+       struct backref_node *node;
+       int level = 0;
+
+       if (cache->last_trans == 0) {
+               cache->last_trans = trans->transid;
+               return 0;
+       }
+
+       if (cache->last_trans == trans->transid)
+               return 0;
+
+       /*
+        * detached nodes are used to avoid unnecessary backref
+        * lookup. transaction commit changes the extent tree.
+        * so the detached nodes are no longer useful.
+        */
+       while (!list_empty(&cache->detached)) {
+               node = list_entry(cache->detached.next,
+                                 struct backref_node, list);
+               remove_backref_node(cache, node);
+       }
+
+       while (!list_empty(&cache->changed)) {
+               node = list_entry(cache->changed.next,
+                                 struct backref_node, list);
+               list_del_init(&node->list);
+               BUG_ON(node->pending);
+               update_backref_node(cache, node, node->new_bytenr);
+       }
+
+       /*
+        * some nodes can be left in the pending list if there were
+        * errors during processing the pending nodes.
+        */
+       for (level = 0; level < BTRFS_MAX_LEVEL; level++) {
+               list_for_each_entry(node, &cache->pending[level], list) {
+                       BUG_ON(!node->pending);
+                       if (node->bytenr == node->new_bytenr)
+                               continue;
+                       update_backref_node(cache, node, node->new_bytenr);
+               }
+       }
+
+       cache->last_trans = 0;
+       return 1;
+}
+
+static int should_ignore_root(struct btrfs_root *root)
+{
+       struct btrfs_root *reloc_root;
+
+       if (!root->ref_cows)
+               return 0;
+
+       reloc_root = root->reloc_root;
+       if (!reloc_root)
+               return 0;
+
+       if (btrfs_root_last_snapshot(&reloc_root->root_item) ==
+           root->fs_info->running_transaction->transid - 1)
+               return 0;
+       /*
+        * if there is reloc tree and it was created in previous
+        * transaction backref lookup can find the reloc tree,
+        * so backref node for the fs tree root is useless for
+        * relocation.
+        */
+       return 1;
+}
+
 /*
  * find reloc tree by address of tree root
  */
@@ -453,11 +645,12 @@ int find_inline_backref(struct extent_buffer *leaf, int slot,
  * for all upper level blocks that directly/indirectly reference the
  * block are also cached.
  */
-static struct backref_node *build_backref_tree(struct reloc_control *rc,
-                                              struct backref_cache *cache,
-                                              struct btrfs_key *node_key,
-                                              int level, u64 bytenr)
+static noinline_for_stack
+struct backref_node *build_backref_tree(struct reloc_control *rc,
+                                       struct btrfs_key *node_key,
+                                       int level, u64 bytenr)
 {
+       struct backref_cache *cache = &rc->backref_cache;
        struct btrfs_path *path1;
        struct btrfs_path *path2;
        struct extent_buffer *eb;
@@ -473,6 +666,8 @@ static struct backref_node *build_backref_tree(struct reloc_control *rc,
        unsigned long end;
        unsigned long ptr;
        LIST_HEAD(list);
+       LIST_HEAD(useless);
+       int cowonly;
        int ret;
        int err = 0;
 
@@ -483,15 +678,13 @@ static struct backref_node *build_backref_tree(struct reloc_control *rc,
                goto out;
        }
 
-       node = kmalloc(sizeof(*node), GFP_NOFS);
+       node = alloc_backref_node(cache);
        if (!node) {
                err = -ENOMEM;
                goto out;
        }
 
-       backref_node_init(node);
        node->bytenr = bytenr;
-       node->owner = 0;
        node->level = level;
        node->lowest = 1;
        cur = node;
@@ -587,17 +780,20 @@ again:
 #ifdef BTRFS_COMPAT_EXTENT_TREE_V0
                if (key.type == BTRFS_SHARED_BLOCK_REF_KEY ||
                    key.type == BTRFS_EXTENT_REF_V0_KEY) {
-                       if (key.objectid == key.offset &&
-                           key.type == BTRFS_EXTENT_REF_V0_KEY) {
+                       if (key.type == BTRFS_EXTENT_REF_V0_KEY) {
                                struct btrfs_extent_ref_v0 *ref0;
                                ref0 = btrfs_item_ptr(eb, path1->slots[0],
                                                struct btrfs_extent_ref_v0);
                                root = find_tree_root(rc, eb, ref0);
-                               if (root)
-                                       cur->root = root;
-                               else
-                                       cur->old_root = 1;
-                               break;
+                               if (!root->ref_cows)
+                                       cur->cowonly = 1;
+                               if (key.objectid == key.offset) {
+                                       if (root && !should_ignore_root(root))
+                                               cur->root = root;
+                                       else
+                                               list_add(&cur->list, &useless);
+                                       break;
+                               }
                        }
 #else
                BUG_ON(key.type == BTRFS_EXTENT_REF_V0_KEY);
@@ -614,22 +810,20 @@ again:
                                break;
                        }
 
-                       edge = kzalloc(sizeof(*edge), GFP_NOFS);
+                       edge = alloc_backref_edge(cache);
                        if (!edge) {
                                err = -ENOMEM;
                                goto out;
                        }
                        rb_node = tree_search(&cache->rb_root, key.offset);
                        if (!rb_node) {
-                               upper = kmalloc(sizeof(*upper), GFP_NOFS);
+                               upper = alloc_backref_node(cache);
                                if (!upper) {
-                                       kfree(edge);
+                                       free_backref_edge(cache, edge);
                                        err = -ENOMEM;
                                        goto out;
                                }
-                               backref_node_init(upper);
                                upper->bytenr = key.offset;
-                               upper->owner = 0;
                                upper->level = cur->level + 1;
                                /*
                                 *  backrefs for the upper level block isn't
@@ -639,11 +833,12 @@ again:
                        } else {
                                upper = rb_entry(rb_node, struct backref_node,
                                                 rb_node);
+                               BUG_ON(!upper->checked);
                                INIT_LIST_HEAD(&edge->list[UPPER]);
                        }
-                       list_add(&edge->list[LOWER], &cur->upper);
-                       edge->node[UPPER] = upper;
+                       list_add_tail(&edge->list[LOWER], &cur->upper);
                        edge->node[LOWER] = cur;
+                       edge->node[UPPER] = upper;
 
                        goto next;
                } else if (key.type != BTRFS_TREE_BLOCK_REF_KEY) {
@@ -657,11 +852,17 @@ again:
                        goto out;
                }
 
+               if (!root->ref_cows)
+                       cur->cowonly = 1;
+
                if (btrfs_root_level(&root->root_item) == cur->level) {
                        /* tree root */
                        BUG_ON(btrfs_root_bytenr(&root->root_item) !=
                               cur->bytenr);
-                       cur->root = root;
+                       if (should_ignore_root(root))
+                               list_add(&cur->list, &useless);
+                       else
+                               cur->root = root;
                        break;
                }
 
@@ -692,11 +893,14 @@ again:
                        if (!path2->nodes[level]) {
                                BUG_ON(btrfs_root_bytenr(&root->root_item) !=
                                       lower->bytenr);
-                               lower->root = root;
+                               if (should_ignore_root(root))
+                                       list_add(&lower->list, &useless);
+                               else
+                                       lower->root = root;
                                break;
                        }
 
-                       edge = kzalloc(sizeof(*edge), GFP_NOFS);
+                       edge = alloc_backref_edge(cache);
                        if (!edge) {
                                err = -ENOMEM;
                                goto out;
@@ -705,16 +909,17 @@ again:
                        eb = path2->nodes[level];
                        rb_node = tree_search(&cache->rb_root, eb->start);
                        if (!rb_node) {
-                               upper = kmalloc(sizeof(*upper), GFP_NOFS);
+                               upper = alloc_backref_node(cache);
                                if (!upper) {
-                                       kfree(edge);
+                                       free_backref_edge(cache, edge);
                                        err = -ENOMEM;
                                        goto out;
                                }
-                               backref_node_init(upper);
                                upper->bytenr = eb->start;
                                upper->owner = btrfs_header_owner(eb);
                                upper->level = lower->level + 1;
+                               if (!root->ref_cows)
+                                       upper->cowonly = 1;
 
                                /*
                                 * if we know the block isn't shared
@@ -744,10 +949,12 @@ again:
                                                 rb_node);
                                BUG_ON(!upper->checked);
                                INIT_LIST_HEAD(&edge->list[UPPER]);
+                               if (!upper->owner)
+                                       upper->owner = btrfs_header_owner(eb);
                        }
                        list_add_tail(&edge->list[LOWER], &lower->upper);
-                       edge->node[UPPER] = upper;
                        edge->node[LOWER] = lower;
+                       edge->node[UPPER] = upper;
 
                        if (rb_node)
                                break;
@@ -785,8 +992,13 @@ next:
         * into the cache.
         */
        BUG_ON(!node->checked);
-       rb_node = tree_insert(&cache->rb_root, node->bytenr, &node->rb_node);
-       BUG_ON(rb_node);
+       cowonly = node->cowonly;
+       if (!cowonly) {
+               rb_node = tree_insert(&cache->rb_root, node->bytenr,
+                                     &node->rb_node);
+               BUG_ON(rb_node);
+               list_add_tail(&node->lower, &cache->leaves);
+       }
 
        list_for_each_entry(edge, &node->upper, list[LOWER])
                list_add_tail(&edge->list[UPPER], &list);
@@ -795,6 +1007,14 @@ next:
                edge = list_entry(list.next, struct backref_edge, list[UPPER]);
                list_del_init(&edge->list[UPPER]);
                upper = edge->node[UPPER];
+               if (upper->detached) {
+                       list_del(&edge->list[LOWER]);
+                       lower = edge->node[LOWER];
+                       free_backref_edge(cache, edge);
+                       if (list_empty(&lower->upper))
+                               list_add(&lower->list, &useless);
+                       continue;
+               }
 
                if (!RB_EMPTY_NODE(&upper->rb_node)) {
                        if (upper->lowest) {
@@ -807,25 +1027,69 @@ next:
                }
 
                BUG_ON(!upper->checked);
-               rb_node = tree_insert(&cache->rb_root, upper->bytenr,
-                                     &upper->rb_node);
-               BUG_ON(rb_node);
+               BUG_ON(cowonly != upper->cowonly);
+               if (!cowonly) {
+                       rb_node = tree_insert(&cache->rb_root, upper->bytenr,
+                                             &upper->rb_node);
+                       BUG_ON(rb_node);
+               }
 
                list_add_tail(&edge->list[UPPER], &upper->lower);
 
                list_for_each_entry(edge, &upper->upper, list[LOWER])
                        list_add_tail(&edge->list[UPPER], &list);
        }
+       /*
+        * process useless backref nodes. backref nodes for tree leaves
+        * are deleted from the cache. backref nodes for upper level
+        * tree blocks are left in the cache to avoid unnecessary backref
+        * lookup.
+        */
+       while (!list_empty(&useless)) {
+               upper = list_entry(useless.next, struct backref_node, list);
+               list_del_init(&upper->list);
+               BUG_ON(!list_empty(&upper->upper));
+               if (upper == node)
+                       node = NULL;
+               if (upper->lowest) {
+                       list_del_init(&upper->lower);
+                       upper->lowest = 0;
+               }
+               while (!list_empty(&upper->lower)) {
+                       edge = list_entry(upper->lower.next,
+                                         struct backref_edge, list[UPPER]);
+                       list_del(&edge->list[UPPER]);
+                       list_del(&edge->list[LOWER]);
+                       lower = edge->node[LOWER];
+                       free_backref_edge(cache, edge);
+
+                       if (list_empty(&lower->upper))
+                               list_add(&lower->list, &useless);
+               }
+               __mark_block_processed(rc, upper);
+               if (upper->level > 0) {
+                       list_add(&upper->list, &cache->detached);
+                       upper->detached = 1;
+               } else {
+                       rb_erase(&upper->rb_node, &cache->rb_root);
+                       free_backref_node(cache, upper);
+               }
+       }
 out:
        btrfs_free_path(path1);
        btrfs_free_path(path2);
        if (err) {
-               INIT_LIST_HEAD(&list);
+               while (!list_empty(&useless)) {
+                       lower = list_entry(useless.next,
+                                          struct backref_node, upper);
+                       list_del_init(&lower->upper);
+               }
                upper = node;
+               INIT_LIST_HEAD(&list);
                while (upper) {
                        if (RB_EMPTY_NODE(&upper->rb_node)) {
                                list_splice_tail(&upper->upper, &list);
-                               kfree(upper);
+                               free_backref_node(cache, upper);
                        }
 
                        if (list_empty(&list))
@@ -833,14 +1097,103 @@ out:
 
                        edge = list_entry(list.next, struct backref_edge,
                                          list[LOWER]);
+                       list_del(&edge->list[LOWER]);
                        upper = edge->node[UPPER];
-                       kfree(edge);
+                       free_backref_edge(cache, edge);
                }
                return ERR_PTR(err);
        }
+       BUG_ON(node && node->detached);
        return node;
 }
 
+/*
+ * helper to add backref node for the newly created snapshot.
+ * the backref node is created by cloning backref node that
+ * corresponds to root of source tree
+ */
+static int clone_backref_node(struct btrfs_trans_handle *trans,
+                             struct reloc_control *rc,
+                             struct btrfs_root *src,
+                             struct btrfs_root *dest)
+{
+       struct btrfs_root *reloc_root = src->reloc_root;
+       struct backref_cache *cache = &rc->backref_cache;
+       struct backref_node *node = NULL;
+       struct backref_node *new_node;
+       struct backref_edge *edge;
+       struct backref_edge *new_edge;
+       struct rb_node *rb_node;
+
+       if (cache->last_trans > 0)
+               update_backref_cache(trans, cache);
+
+       rb_node = tree_search(&cache->rb_root, src->commit_root->start);
+       if (rb_node) {
+               node = rb_entry(rb_node, struct backref_node, rb_node);
+               if (node->detached)
+                       node = NULL;
+               else
+                       BUG_ON(node->new_bytenr != reloc_root->node->start);
+       }
+
+       if (!node) {
+               rb_node = tree_search(&cache->rb_root,
+                                     reloc_root->commit_root->start);
+               if (rb_node) {
+                       node = rb_entry(rb_node, struct backref_node,
+                                       rb_node);
+                       BUG_ON(node->detached);
+               }
+       }
+
+       if (!node)
+               return 0;
+
+       new_node = alloc_backref_node(cache);
+       if (!new_node)
+               return -ENOMEM;
+
+       new_node->bytenr = dest->node->start;
+       new_node->level = node->level;
+       new_node->lowest = node->lowest;
+       new_node->root = dest;
+
+       if (!node->lowest) {
+               list_for_each_entry(edge, &node->lower, list[UPPER]) {
+                       new_edge = alloc_backref_edge(cache);
+                       if (!new_edge)
+                               goto fail;
+
+                       new_edge->node[UPPER] = new_node;
+                       new_edge->node[LOWER] = edge->node[LOWER];
+                       list_add_tail(&new_edge->list[UPPER],
+                                     &new_node->lower);
+               }
+       }
+
+       rb_node = tree_insert(&cache->rb_root, new_node->bytenr,
+                             &new_node->rb_node);
+       BUG_ON(rb_node);
+
+       if (!new_node->lowest) {
+               list_for_each_entry(new_edge, &new_node->lower, list[UPPER]) {
+                       list_add_tail(&new_edge->list[LOWER],
+                                     &new_edge->node[LOWER]->upper);
+               }
+       }
+       return 0;
+fail:
+       while (!list_empty(&new_node->lower)) {
+               new_edge = list_entry(new_node->lower.next,
+                                     struct backref_edge, list[UPPER]);
+               list_del(&new_edge->list[UPPER]);
+               free_backref_edge(cache, new_edge);
+       }
+       free_backref_node(cache, new_node);
+       return -ENOMEM;
+}
+
 /*
  * helper to add 'address of tree root -> reloc tree' mapping
  */
@@ -901,12 +1254,8 @@ static int __update_reloc_root(struct btrfs_root *root, int del)
        return 0;
 }
 
-/*
- * create reloc tree for a given fs tree. reloc tree is just a
- * snapshot of the fs tree with special root objectid.
- */
-int btrfs_init_reloc_root(struct btrfs_trans_handle *trans,
-                         struct btrfs_root *root)
+static struct btrfs_root *create_reloc_root(struct btrfs_trans_handle *trans,
+                                       struct btrfs_root *root, u64 objectid)
 {
        struct btrfs_root *reloc_root;
        struct extent_buffer *eb;
@@ -914,36 +1263,45 @@ int btrfs_init_reloc_root(struct btrfs_trans_handle *trans,
        struct btrfs_key root_key;
        int ret;
 
-       if (root->reloc_root) {
-               reloc_root = root->reloc_root;
-               reloc_root->last_trans = trans->transid;
-               return 0;
-       }
-
-       if (!root->fs_info->reloc_ctl ||
-           !root->fs_info->reloc_ctl->create_reloc_root ||
-           root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID)
-               return 0;
-
        root_item = kmalloc(sizeof(*root_item), GFP_NOFS);
        BUG_ON(!root_item);
 
        root_key.objectid = BTRFS_TREE_RELOC_OBJECTID;
        root_key.type = BTRFS_ROOT_ITEM_KEY;
-       root_key.offset = root->root_key.objectid;
+       root_key.offset = objectid;
 
-       ret = btrfs_copy_root(trans, root, root->commit_root, &eb,
-                             BTRFS_TREE_RELOC_OBJECTID);
-       BUG_ON(ret);
+       if (root->root_key.objectid == objectid) {
+               /* called by btrfs_init_reloc_root */
+               ret = btrfs_copy_root(trans, root, root->commit_root, &eb,
+                                     BTRFS_TREE_RELOC_OBJECTID);
+               BUG_ON(ret);
+
+               btrfs_set_root_last_snapshot(&root->root_item,
+                                            trans->transid - 1);
+       } else {
+               /*
+                * called by btrfs_reloc_post_snapshot_hook.
+                * the source tree is a reloc tree, all tree blocks
+                * modified after it was created have RELOC flag
+                * set in their headers. so it's OK to not update
+                * the 'last_snapshot'.
+                */
+               ret = btrfs_copy_root(trans, root, root->node, &eb,
+                                     BTRFS_TREE_RELOC_OBJECTID);
+               BUG_ON(ret);
+       }
 
-       btrfs_set_root_last_snapshot(&root->root_item, trans->transid - 1);
        memcpy(root_item, &root->root_item, sizeof(*root_item));
-       btrfs_set_root_refs(root_item, 1);
        btrfs_set_root_bytenr(root_item, eb->start);
        btrfs_set_root_level(root_item, btrfs_header_level(eb));
        btrfs_set_root_generation(root_item, trans->transid);
-       memset(&root_item->drop_progress, 0, sizeof(struct btrfs_disk_key));
-       root_item->drop_level = 0;
+
+       if (root->root_key.objectid == objectid) {
+               btrfs_set_root_refs(root_item, 0);
+               memset(&root_item->drop_progress, 0,
+                      sizeof(struct btrfs_disk_key));
+               root_item->drop_level = 0;
+       }
 
        btrfs_tree_unlock(eb);
        free_extent_buffer(eb);
@@ -957,6 +1315,37 @@ int btrfs_init_reloc_root(struct btrfs_trans_handle *trans,
                                                 &root_key);
        BUG_ON(IS_ERR(reloc_root));
        reloc_root->last_trans = trans->transid;
+       return reloc_root;
+}
+
+/*
+ * create reloc tree for a given fs tree. reloc tree is just a
+ * snapshot of the fs tree with special root objectid.
+ */
+int btrfs_init_reloc_root(struct btrfs_trans_handle *trans,
+                         struct btrfs_root *root)
+{
+       struct btrfs_root *reloc_root;
+       struct reloc_control *rc = root->fs_info->reloc_ctl;
+       int clear_rsv = 0;
+
+       if (root->reloc_root) {
+               reloc_root = root->reloc_root;
+               reloc_root->last_trans = trans->transid;
+               return 0;
+       }
+
+       if (!rc || !rc->create_reloc_tree ||
+           root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID)
+               return 0;
+
+       if (!trans->block_rsv) {
+               trans->block_rsv = rc->block_rsv;
+               clear_rsv = 1;
+       }
+       reloc_root = create_reloc_root(trans, root, root->root_key.objectid);
+       if (clear_rsv)
+               trans->block_rsv = NULL;
 
        __add_reloc_root(reloc_root);
        root->reloc_root = reloc_root;
@@ -980,7 +1369,8 @@ int btrfs_update_reloc_root(struct btrfs_trans_handle *trans,
        reloc_root = root->reloc_root;
        root_item = &reloc_root->root_item;
 
-       if (btrfs_root_refs(root_item) == 0) {
+       if (root->fs_info->reloc_ctl->merge_reloc_tree &&
+           btrfs_root_refs(root_item) == 0) {
                root->reloc_root = NULL;
                del = 1;
        }
@@ -1102,8 +1492,7 @@ static int get_new_location(struct inode *reloc_inode, u64 *new_bytenr,
                goto out;
        }
 
-       if (new_bytenr)
-               *new_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi);
+       *new_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi);
        ret = 0;
 out:
        btrfs_free_path(path);
@@ -1114,19 +1503,18 @@ out:
  * update file extent items in the tree leaf to point to
  * the new locations.
  */
-static int replace_file_extents(struct btrfs_trans_handle *trans,
-                               struct reloc_control *rc,
-                               struct btrfs_root *root,
-                               struct extent_buffer *leaf,
-                               struct list_head *inode_list)
+static noinline_for_stack
+int replace_file_extents(struct btrfs_trans_handle *trans,
+                        struct reloc_control *rc,
+                        struct btrfs_root *root,
+                        struct extent_buffer *leaf)
 {
        struct btrfs_key key;
        struct btrfs_file_extent_item *fi;
        struct inode *inode = NULL;
-       struct inodevec *ivec = NULL;
        u64 parent;
        u64 bytenr;
-       u64 new_bytenr;
+       u64 new_bytenr = 0;
        u64 num_bytes;
        u64 end;
        u32 nritems;
@@ -1166,21 +1554,12 @@ static int replace_file_extents(struct btrfs_trans_handle *trans,
                 * to complete and drop the extent cache
                 */
                if (root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID) {
-                       if (!ivec || ivec->nr == INODEVEC_SIZE) {
-                               ivec = kmalloc(sizeof(*ivec), GFP_NOFS);
-                               BUG_ON(!ivec);
-                               ivec->nr = 0;
-                               list_add_tail(&ivec->list, inode_list);
-                       }
                        if (first) {
                                inode = find_next_inode(root, key.objectid);
-                               if (inode)
-                                       ivec->inode[ivec->nr++] = inode;
                                first = 0;
                        } else if (inode && inode->i_ino < key.objectid) {
+                               btrfs_add_delayed_iput(inode);
                                inode = find_next_inode(root, key.objectid);
-                               if (inode)
-                                       ivec->inode[ivec->nr++] = inode;
                        }
                        if (inode && inode->i_ino == key.objectid) {
                                end = key.offset +
@@ -1204,8 +1583,10 @@ static int replace_file_extents(struct btrfs_trans_handle *trans,
 
                ret = get_new_location(rc->data_inode, &new_bytenr,
                                       bytenr, num_bytes);
-               if (ret > 0)
+               if (ret > 0) {
+                       WARN_ON(1);
                        continue;
+               }
                BUG_ON(ret < 0);
 
                btrfs_set_file_extent_disk_bytenr(leaf, fi, new_bytenr);
@@ -1225,6 +1606,8 @@ static int replace_file_extents(struct btrfs_trans_handle *trans,
        }
        if (dirty)
                btrfs_mark_buffer_dirty(leaf);
+       if (inode)
+               btrfs_add_delayed_iput(inode);
        return 0;
 }
 
@@ -1248,11 +1631,11 @@ int memcmp_node_keys(struct extent_buffer *eb, int slot,
  * if no block got replaced, 0 is returned. if there are other
  * errors, a negative error number is returned.
  */
-static int replace_path(struct btrfs_trans_handle *trans,
-                       struct btrfs_root *dest, struct btrfs_root *src,
-                       struct btrfs_path *path, struct btrfs_key *next_key,
-                       struct extent_buffer **leaf,
-                       int lowest_level, int max_level)
+static noinline_for_stack
+int replace_path(struct btrfs_trans_handle *trans,
+                struct btrfs_root *dest, struct btrfs_root *src,
+                struct btrfs_path *path, struct btrfs_key *next_key,
+                int lowest_level, int max_level)
 {
        struct extent_buffer *eb;
        struct extent_buffer *parent;
@@ -1263,16 +1646,16 @@ static int replace_path(struct btrfs_trans_handle *trans,
        u64 new_ptr_gen;
        u64 last_snapshot;
        u32 blocksize;
+       int cow = 0;
        int level;
        int ret;
        int slot;
 
        BUG_ON(src->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID);
        BUG_ON(dest->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID);
-       BUG_ON(lowest_level > 1 && leaf);
 
        last_snapshot = btrfs_root_last_snapshot(&src->root_item);
-
+again:
        slot = path->slots[lowest_level];
        btrfs_node_key_to_cpu(path->nodes[lowest_level], &key, slot);
 
@@ -1286,8 +1669,10 @@ static int replace_path(struct btrfs_trans_handle *trans,
                return 0;
        }
 
-       ret = btrfs_cow_block(trans, dest, eb, NULL, 0, &eb);
-       BUG_ON(ret);
+       if (cow) {
+               ret = btrfs_cow_block(trans, dest, eb, NULL, 0, &eb);
+               BUG_ON(ret);
+       }
        btrfs_set_lock_blocking(eb);
 
        if (next_key) {
@@ -1331,7 +1716,7 @@ static int replace_path(struct btrfs_trans_handle *trans,
 
                if (new_bytenr == 0 || old_ptr_gen > last_snapshot ||
                    memcmp_node_keys(parent, slot, path, level)) {
-                       if (level <= lowest_level && !leaf) {
+                       if (level <= lowest_level) {
                                ret = 0;
                                break;
                        }
@@ -1339,16 +1724,12 @@ static int replace_path(struct btrfs_trans_handle *trans,
                        eb = read_tree_block(dest, old_bytenr, blocksize,
                                             old_ptr_gen);
                        btrfs_tree_lock(eb);
-                       ret = btrfs_cow_block(trans, dest, eb, parent,
-                                             slot, &eb);
-                       BUG_ON(ret);
-                       btrfs_set_lock_blocking(eb);
-
-                       if (level <= lowest_level) {
-                               *leaf = eb;
-                               ret = 0;
-                               break;
+                       if (cow) {
+                               ret = btrfs_cow_block(trans, dest, eb, parent,
+                                                     slot, &eb);
+                               BUG_ON(ret);
                        }
+                       btrfs_set_lock_blocking(eb);
 
                        btrfs_tree_unlock(parent);
                        free_extent_buffer(parent);
@@ -1357,6 +1738,13 @@ static int replace_path(struct btrfs_trans_handle *trans,
                        continue;
                }
 
+               if (!cow) {
+                       btrfs_tree_unlock(parent);
+                       free_extent_buffer(parent);
+                       cow = 1;
+                       goto again;
+               }
+
                btrfs_node_key_to_cpu(path->nodes[level], &key,
                                      path->slots[level]);
                btrfs_release_path(src, path);
@@ -1562,20 +1950,6 @@ static int invalidate_extent_cache(struct btrfs_root *root,
        return 0;
 }
 
-static void put_inodes(struct list_head *list)
-{
-       struct inodevec *ivec;
-       while (!list_empty(list)) {
-               ivec = list_entry(list->next, struct inodevec, list);
-               list_del(&ivec->list);
-               while (ivec->nr > 0) {
-                       ivec->nr--;
-                       iput(ivec->inode[ivec->nr]);
-               }
-               kfree(ivec);
-       }
-}
-
 static int find_next_key(struct btrfs_path *path, int level,
                         struct btrfs_key *key)
 
@@ -1608,13 +1982,14 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,
        struct btrfs_root *reloc_root;
        struct btrfs_root_item *root_item;
        struct btrfs_path *path;
-       struct extent_buffer *leaf = NULL;
+       struct extent_buffer *leaf;
        unsigned long nr;
        int level;
        int max_level;
        int replaced = 0;
        int ret;
        int err = 0;
+       u32 min_reserved;
 
        path = btrfs_alloc_path();
        if (!path)
@@ -1648,34 +2023,23 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,
                btrfs_unlock_up_safe(path, 0);
        }
 
-       if (level == 0 && rc->stage == UPDATE_DATA_PTRS) {
-               trans = btrfs_start_transaction(root, 1);
+       min_reserved = root->nodesize * (BTRFS_MAX_LEVEL - 1) * 2;
+       memset(&next_key, 0, sizeof(next_key));
 
-               leaf = path->nodes[0];
-               btrfs_item_key_to_cpu(leaf, &key, 0);
-               btrfs_release_path(reloc_root, path);
+       while (1) {
+               trans = btrfs_start_transaction(root, 0);
+               trans->block_rsv = rc->block_rsv;
 
-               ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
-               if (ret < 0) {
-                       err = ret;
-                       goto out;
+               ret = btrfs_block_rsv_check(trans, root, rc->block_rsv,
+                                           min_reserved, 0);
+               if (ret) {
+                       BUG_ON(ret != -EAGAIN);
+                       ret = btrfs_commit_transaction(trans, root);
+                       BUG_ON(ret);
+                       continue;
                }
 
-               leaf = path->nodes[0];
-               btrfs_unlock_up_safe(path, 1);
-               ret = replace_file_extents(trans, rc, root, leaf,
-                                          &inode_list);
-               if (ret < 0)
-                       err = ret;
-               goto out;
-       }
-
-       memset(&next_key, 0, sizeof(next_key));
-
-       while (1) {
-               leaf = NULL;
                replaced = 0;
-               trans = btrfs_start_transaction(root, 1);
                max_level = level;
 
                ret = walk_down_reloc_tree(reloc_root, path, &level);
@@ -1689,14 +2053,9 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,
                if (!find_next_key(path, level, &key) &&
                    btrfs_comp_cpu_keys(&next_key, &key) >= 0) {
                        ret = 0;
-               } else if (level == 1 && rc->stage == UPDATE_DATA_PTRS) {
-                       ret = replace_path(trans, root, reloc_root,
-                                          path, &next_key, &leaf,
-                                          level, max_level);
                } else {
-                       ret = replace_path(trans, root, reloc_root,
-                                          path, &next_key, NULL,
-                                          level, max_level);
+                       ret = replace_path(trans, root, reloc_root, path,
+                                          &next_key, level, max_level);
                }
                if (ret < 0) {
                        err = ret;
@@ -1708,16 +2067,6 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,
                        btrfs_node_key_to_cpu(path->nodes[level], &key,
                                              path->slots[level]);
                        replaced = 1;
-               } else if (leaf) {
-                       /*
-                        * no block got replaced, try replacing file extents
-                        */
-                       btrfs_item_key_to_cpu(leaf, &key, 0);
-                       ret = replace_file_extents(trans, rc, root, leaf,
-                                                  &inode_list);
-                       btrfs_tree_unlock(leaf);
-                       free_extent_buffer(leaf);
-                       BUG_ON(ret < 0);
                }
 
                ret = walk_up_reloc_tree(reloc_root, path, &level);
@@ -1734,15 +2083,10 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,
                root_item->drop_level = level;
 
                nr = trans->blocks_used;
-               btrfs_end_transaction(trans, root);
+               btrfs_end_transaction_throttle(trans, root);
 
                btrfs_btree_balance_dirty(root, nr);
 
-               /*
-                * put inodes outside transaction, otherwise we may deadlock.
-                */
-               put_inodes(&inode_list);
-
                if (replaced && rc->stage == UPDATE_DATA_PTRS)
                        invalidate_extent_cache(root, &key, &next_key);
        }
@@ -1765,87 +2109,125 @@ out:
                       sizeof(root_item->drop_progress));
                root_item->drop_level = 0;
                btrfs_set_root_refs(root_item, 0);
+               btrfs_update_reloc_root(trans, root);
        }
 
        nr = trans->blocks_used;
-       btrfs_end_transaction(trans, root);
+       btrfs_end_transaction_throttle(trans, root);
 
        btrfs_btree_balance_dirty(root, nr);
 
-       put_inodes(&inode_list);
-
        if (replaced && rc->stage == UPDATE_DATA_PTRS)
                invalidate_extent_cache(root, &key, &next_key);
 
        return err;
 }
 
-/*
- * callback for the work threads.
- * this function merges reloc tree with corresponding fs tree,
- * and then drops the reloc tree.
- */
-static void merge_func(struct btrfs_work *work)
+static noinline_for_stack
+int prepare_to_merge(struct reloc_control *rc, int err)
 {
-       struct btrfs_trans_handle *trans;
-       struct btrfs_root *root;
+       struct btrfs_root *root = rc->extent_root;
        struct btrfs_root *reloc_root;
-       struct async_merge *async;
+       struct btrfs_trans_handle *trans;
+       LIST_HEAD(reloc_roots);
+       u64 num_bytes = 0;
+       int ret;
+       int retries = 0;
+
+       mutex_lock(&root->fs_info->trans_mutex);
+       rc->merging_rsv_size += root->nodesize * (BTRFS_MAX_LEVEL - 1) * 2;
+       rc->merging_rsv_size += rc->nodes_relocated * 2;
+       mutex_unlock(&root->fs_info->trans_mutex);
+again:
+       if (!err) {
+               num_bytes = rc->merging_rsv_size;
+               ret = btrfs_block_rsv_add(NULL, root, rc->block_rsv,
+                                         num_bytes, &retries);
+               if (ret)
+                       err = ret;
+       }
 
-       async = container_of(work, struct async_merge, work);
-       reloc_root = async->root;
+       trans = btrfs_join_transaction(rc->extent_root, 1);
+
+       if (!err) {
+               if (num_bytes != rc->merging_rsv_size) {
+                       btrfs_end_transaction(trans, rc->extent_root);
+                       btrfs_block_rsv_release(rc->extent_root,
+                                               rc->block_rsv, num_bytes);
+                       retries = 0;
+                       goto again;
+               }
+       }
+
+       rc->merge_reloc_tree = 1;
+
+       while (!list_empty(&rc->reloc_roots)) {
+               reloc_root = list_entry(rc->reloc_roots.next,
+                                       struct btrfs_root, root_list);
+               list_del_init(&reloc_root->root_list);
 
-       if (btrfs_root_refs(&reloc_root->root_item) > 0) {
                root = read_fs_root(reloc_root->fs_info,
                                    reloc_root->root_key.offset);
                BUG_ON(IS_ERR(root));
                BUG_ON(root->reloc_root != reloc_root);
 
-               merge_reloc_root(async->rc, root);
-
-               trans = btrfs_start_transaction(root, 1);
+               /*
+                * set reference count to 1, so btrfs_recover_relocation
+                * knows it should resumes merging
+                */
+               if (!err)
+                       btrfs_set_root_refs(&reloc_root->root_item, 1);
                btrfs_update_reloc_root(trans, root);
-               btrfs_end_transaction(trans, root);
-       }
 
-       btrfs_drop_snapshot(reloc_root, 0);
+               list_add(&reloc_root->root_list, &reloc_roots);
+       }
 
-       if (atomic_dec_and_test(async->num_pending))
-               complete(async->done);
+       list_splice(&reloc_roots, &rc->reloc_roots);
 
-       kfree(async);
+       if (!err)
+               btrfs_commit_transaction(trans, rc->extent_root);
+       else
+               btrfs_end_transaction(trans, rc->extent_root);
+       return err;
 }
 
-static int merge_reloc_roots(struct reloc_control *rc)
+static noinline_for_stack
+int merge_reloc_roots(struct reloc_control *rc)
 {
-       struct async_merge *async;
        struct btrfs_root *root;
-       struct completion done;
-       atomic_t num_pending;
+       struct btrfs_root *reloc_root;
+       LIST_HEAD(reloc_roots);
+       int found = 0;
+       int ret;
+again:
+       root = rc->extent_root;
+       mutex_lock(&root->fs_info->trans_mutex);
+       list_splice_init(&rc->reloc_roots, &reloc_roots);
+       mutex_unlock(&root->fs_info->trans_mutex);
 
-       init_completion(&done);
-       atomic_set(&num_pending, 1);
+       while (!list_empty(&reloc_roots)) {
+               found = 1;
+               reloc_root = list_entry(reloc_roots.next,
+                                       struct btrfs_root, root_list);
 
-       while (!list_empty(&rc->reloc_roots)) {
-               root = list_entry(rc->reloc_roots.next,
-                                 struct btrfs_root, root_list);
-               list_del_init(&root->root_list);
+               if (btrfs_root_refs(&reloc_root->root_item) > 0) {
+                       root = read_fs_root(reloc_root->fs_info,
+                                           reloc_root->root_key.offset);
+                       BUG_ON(IS_ERR(root));
+                       BUG_ON(root->reloc_root != reloc_root);
 
-               async = kmalloc(sizeof(*async), GFP_NOFS);
-               BUG_ON(!async);
-               async->work.func = merge_func;
-               async->work.flags = 0;
-               async->rc = rc;
-               async->root = root;
-               async->done = &done;
-               async->num_pending = &num_pending;
-               atomic_inc(&num_pending);
-               btrfs_queue_worker(&rc->workers, &async->work);
+                       ret = merge_reloc_root(rc, root);
+                       BUG_ON(ret);
+               } else {
+                       list_del_init(&reloc_root->root_list);
+               }
+               btrfs_drop_snapshot(reloc_root, rc->block_rsv, 0);
        }
 
-       if (!atomic_dec_and_test(&num_pending))
-               wait_for_completion(&done);
-
+       if (found) {
+               found = 0;
+               goto again;
+       }
        BUG_ON(!RB_EMPTY_ROOT(&rc->reloc_root_tree.rb_root));
        return 0;
 }
@@ -1876,119 +2258,169 @@ static int record_reloc_root_in_trans(struct btrfs_trans_handle *trans,
        return btrfs_record_root_in_trans(trans, root);
 }
 
-/*
- * select one tree from trees that references the block.
- * for blocks in refernce counted trees, we preper reloc tree.
- * if no reloc tree found and reloc_only is true, NULL is returned.
- */
-static struct btrfs_root *__select_one_root(struct btrfs_trans_handle *trans,
-                                           struct backref_node *node,
-                                           struct backref_edge *edges[],
-                                           int *nr, int reloc_only)
+static noinline_for_stack
+struct btrfs_root *select_reloc_root(struct btrfs_trans_handle *trans,
+                                    struct reloc_control *rc,
+                                    struct backref_node *node,
+                                    struct backref_edge *edges[], int *nr)
 {
        struct backref_node *next;
        struct btrfs_root *root;
-       int index;
-       int loop = 0;
-again:
-       index = 0;
+       int index = 0;
+
        next = node;
        while (1) {
                cond_resched();
                next = walk_up_backref(next, edges, &index);
                root = next->root;
-               if (!root) {
-                       BUG_ON(!node->old_root);
-                       goto skip;
-               }
-
-               /* no other choice for non-refernce counted tree */
-               if (!root->ref_cows) {
-                       BUG_ON(reloc_only);
-                       break;
-               }
+               BUG_ON(!root);
+               BUG_ON(!root->ref_cows);
 
                if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) {
                        record_reloc_root_in_trans(trans, root);
                        break;
                }
 
-               if (loop) {
-                       btrfs_record_root_in_trans(trans, root);
+               btrfs_record_root_in_trans(trans, root);
+               root = root->reloc_root;
+
+               if (next->new_bytenr != root->node->start) {
+                       BUG_ON(next->new_bytenr);
+                       BUG_ON(!list_empty(&next->list));
+                       next->new_bytenr = root->node->start;
+                       next->root = root;
+                       list_add_tail(&next->list,
+                                     &rc->backref_cache.changed);
+                       __mark_block_processed(rc, next);
                        break;
                }
 
-               if (reloc_only || next != node) {
-                       if (!root->reloc_root)
-                               btrfs_record_root_in_trans(trans, root);
-                       root = root->reloc_root;
-                       /*
-                        * if the reloc tree was created in current
-                        * transation, there is no node in backref tree
-                        * corresponds to the root of the reloc tree.
-                        */
-                       if (btrfs_root_last_snapshot(&root->root_item) ==
-                           trans->transid - 1)
-                               break;
-               }
-skip:
+               WARN_ON(1);
                root = NULL;
                next = walk_down_backref(edges, &index);
                if (!next || next->level <= node->level)
                        break;
        }
+       if (!root)
+               return NULL;
 
-       if (!root && !loop && !reloc_only) {
-               loop = 1;
-               goto again;
+       *nr = index;
+       next = node;
+       /* setup backref node path for btrfs_reloc_cow_block */
+       while (1) {
+               rc->backref_cache.path[next->level] = next;
+               if (--index < 0)
+                       break;
+               next = edges[index]->node[UPPER];
        }
-
-       if (root)
-               *nr = index;
-       else
-               *nr = 0;
-
        return root;
 }
 
+/*
+ * select a tree root for relocation. return NULL if the block
+ * is reference counted. we should use do_relocation() in this
+ * case. return a tree root pointer if the block isn't reference
+ * counted. return -ENOENT if the block is root of reloc tree.
+ */
 static noinline_for_stack
 struct btrfs_root *select_one_root(struct btrfs_trans_handle *trans,
                                   struct backref_node *node)
 {
+       struct backref_node *next;
+       struct btrfs_root *root;
+       struct btrfs_root *fs_root = NULL;
        struct backref_edge *edges[BTRFS_MAX_LEVEL - 1];
-       int nr;
-       return __select_one_root(trans, node, edges, &nr, 0);
+       int index = 0;
+
+       next = node;
+       while (1) {
+               cond_resched();
+               next = walk_up_backref(next, edges, &index);
+               root = next->root;
+               BUG_ON(!root);
+
+               /* no other choice for non-refernce counted tree */
+               if (!root->ref_cows)
+                       return root;
+
+               if (root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID)
+                       fs_root = root;
+
+               if (next != node)
+                       return NULL;
+
+               next = walk_down_backref(edges, &index);
+               if (!next || next->level <= node->level)
+                       break;
+       }
+
+       if (!fs_root)
+               return ERR_PTR(-ENOENT);
+       return fs_root;
 }
 
 static noinline_for_stack
-struct btrfs_root *select_reloc_root(struct btrfs_trans_handle *trans,
-                                    struct backref_node *node,
-                                    struct backref_edge *edges[], int *nr)
+u64 calcu_metadata_size(struct reloc_control *rc,
+                       struct backref_node *node, int reserve)
 {
-       return __select_one_root(trans, node, edges, nr, 1);
+       struct backref_node *next = node;
+       struct backref_edge *edge;
+       struct backref_edge *edges[BTRFS_MAX_LEVEL - 1];
+       u64 num_bytes = 0;
+       int index = 0;
+
+       BUG_ON(reserve && node->processed);
+
+       while (next) {
+               cond_resched();
+               while (1) {
+                       if (next->processed && (reserve || next != node))
+                               break;
+
+                       num_bytes += btrfs_level_size(rc->extent_root,
+                                                     next->level);
+
+                       if (list_empty(&next->upper))
+                               break;
+
+                       edge = list_entry(next->upper.next,
+                                         struct backref_edge, list[LOWER]);
+                       edges[index++] = edge;
+                       next = edge->node[UPPER];
+               }
+               next = walk_down_backref(edges, &index);
+       }
+       return num_bytes;
 }
 
-static void grab_path_buffers(struct btrfs_path *path,
-                             struct backref_node *node,
-                             struct backref_edge *edges[], int nr)
+static int reserve_metadata_space(struct btrfs_trans_handle *trans,
+                                 struct reloc_control *rc,
+                                 struct backref_node *node)
 {
-       int i = 0;
-       while (1) {
-               drop_node_buffer(node);
-               node->eb = path->nodes[node->level];
-               BUG_ON(!node->eb);
-               if (path->locks[node->level])
-                       node->locked = 1;
-               path->nodes[node->level] = NULL;
-               path->locks[node->level] = 0;
-
-               if (i >= nr)
-                       break;
+       struct btrfs_root *root = rc->extent_root;
+       u64 num_bytes;
+       int ret;
 
-               edges[i]->blockptr = node->eb->start;
-               node = edges[i]->node[UPPER];
-               i++;
+       num_bytes = calcu_metadata_size(rc, node, 1) * 2;
+
+       trans->block_rsv = rc->block_rsv;
+       ret = btrfs_block_rsv_add(trans, root, rc->block_rsv, num_bytes,
+                                 &rc->block_rsv_retries);
+       if (ret) {
+               if (ret == -EAGAIN)
+                       rc->commit_transaction = 1;
+               return ret;
        }
+
+       rc->block_rsv_retries = 0;
+       return 0;
+}
+
+static void release_metadata_space(struct reloc_control *rc,
+                                  struct backref_node *node)
+{
+       u64 num_bytes = calcu_metadata_size(rc, node, 0) * 2;
+       btrfs_block_rsv_release(rc->extent_root, rc->block_rsv, num_bytes);
 }
 
 /*
@@ -1999,6 +2431,7 @@ static void grab_path_buffers(struct btrfs_path *path,
  * in that case this function just updates pointers.
  */
 static int do_relocation(struct btrfs_trans_handle *trans,
+                        struct reloc_control *rc,
                         struct backref_node *node,
                         struct btrfs_key *key,
                         struct btrfs_path *path, int lowest)
@@ -2019,18 +2452,25 @@ static int do_relocation(struct btrfs_trans_handle *trans,
        BUG_ON(lowest && node->eb);
 
        path->lowest_level = node->level + 1;
+       rc->backref_cache.path[node->level] = node;
        list_for_each_entry(edge, &node->upper, list[LOWER]) {
                cond_resched();
-               if (node->eb && node->eb->start == edge->blockptr)
-                       continue;
 
                upper = edge->node[UPPER];
-               root = select_reloc_root(trans, upper, edges, &nr);
-               if (!root)
-                       continue;
-
-               if (upper->eb && !upper->locked)
+               root = select_reloc_root(trans, rc, upper, edges, &nr);
+               BUG_ON(!root);
+
+               if (upper->eb && !upper->locked) {
+                       if (!lowest) {
+                               ret = btrfs_bin_search(upper->eb, key,
+                                                      upper->level, &slot);
+                               BUG_ON(ret);
+                               bytenr = btrfs_node_blockptr(upper->eb, slot);
+                               if (node->eb->start == bytenr)
+                                       goto next;
+                       }
                        drop_node_buffer(upper);
+               }
 
                if (!upper->eb) {
                        ret = btrfs_search_slot(trans, root, key, path, 0, 1);
@@ -2040,11 +2480,17 @@ static int do_relocation(struct btrfs_trans_handle *trans,
                        }
                        BUG_ON(ret > 0);
 
-                       slot = path->slots[upper->level];
+                       if (!upper->eb) {
+                               upper->eb = path->nodes[upper->level];
+                               path->nodes[upper->level] = NULL;
+                       } else {
+                               BUG_ON(upper->eb != path->nodes[upper->level]);
+                       }
 
-                       btrfs_unlock_up_safe(path, upper->level + 1);
-                       grab_path_buffers(path, upper, edges, nr);
+                       upper->locked = 1;
+                       path->locks[upper->level] = 0;
 
+                       slot = path->slots[upper->level];
                        btrfs_release_path(NULL, path);
                } else {
                        ret = btrfs_bin_search(upper->eb, key, upper->level,
@@ -2053,14 +2499,11 @@ static int do_relocation(struct btrfs_trans_handle *trans,
                }
 
                bytenr = btrfs_node_blockptr(upper->eb, slot);
-               if (!lowest) {
-                       if (node->eb->start == bytenr) {
-                               btrfs_tree_unlock(upper->eb);
-                               upper->locked = 0;
-                               continue;
-                       }
+               if (lowest) {
+                       BUG_ON(bytenr != node->bytenr);
                } else {
-                       BUG_ON(node->bytenr != bytenr);
+                       if (node->eb->start == bytenr)
+                               goto next;
                }
 
                blocksize = btrfs_level_size(root, node->level);
@@ -2072,13 +2515,13 @@ static int do_relocation(struct btrfs_trans_handle *trans,
                if (!node->eb) {
                        ret = btrfs_cow_block(trans, root, eb, upper->eb,
                                              slot, &eb);
+                       btrfs_tree_unlock(eb);
+                       free_extent_buffer(eb);
                        if (ret < 0) {
                                err = ret;
-                               break;
+                               goto next;
                        }
-                       btrfs_set_lock_blocking(eb);
-                       node->eb = eb;
-                       node->locked = 1;
+                       BUG_ON(node->eb != eb);
                } else {
                        btrfs_set_node_blockptr(upper->eb, slot,
                                                node->eb->start);
@@ -2096,67 +2539,80 @@ static int do_relocation(struct btrfs_trans_handle *trans,
                        ret = btrfs_drop_subtree(trans, root, eb, upper->eb);
                        BUG_ON(ret);
                }
-               if (!lowest) {
-                       btrfs_tree_unlock(upper->eb);
-                       upper->locked = 0;
-               }
+next:
+               if (!upper->pending)
+                       drop_node_buffer(upper);
+               else
+                       unlock_node_buffer(upper);
+               if (err)
+                       break;
+       }
+
+       if (!err && node->pending) {
+               drop_node_buffer(node);
+               list_move_tail(&node->list, &rc->backref_cache.changed);
+               node->pending = 0;
        }
+
        path->lowest_level = 0;
+       BUG_ON(err == -ENOSPC);
        return err;
 }
 
 static int link_to_upper(struct btrfs_trans_handle *trans,
+                        struct reloc_control *rc,
                         struct backref_node *node,
                         struct btrfs_path *path)
 {
        struct btrfs_key key;
-       if (!node->eb || list_empty(&node->upper))
-               return 0;
 
        btrfs_node_key_to_cpu(node->eb, &key, 0);
-       return do_relocation(trans, node, &key, path, 0);
+       return do_relocation(trans, rc, node, &key, path, 0);
 }
 
 static int finish_pending_nodes(struct btrfs_trans_handle *trans,
-                               struct backref_cache *cache,
-                               struct btrfs_path *path)
+                               struct reloc_control *rc,
+                               struct btrfs_path *path, int err)
 {
+       LIST_HEAD(list);
+       struct backref_cache *cache = &rc->backref_cache;
        struct backref_node *node;
        int level;
        int ret;
-       int err = 0;
 
        for (level = 0; level < BTRFS_MAX_LEVEL; level++) {
                while (!list_empty(&cache->pending[level])) {
                        node = list_entry(cache->pending[level].next,
-                                         struct backref_node, lower);
-                       BUG_ON(node->level != level);
+                                         struct backref_node, list);
+                       list_move_tail(&node->list, &list);
+                       BUG_ON(!node->pending);
 
-                       ret = link_to_upper(trans, node, path);
-                       if (ret < 0)
-                               err = ret;
-                       /*
-                        * this remove the node from the pending list and
-                        * may add some other nodes to the level + 1
-                        * pending list
-                        */
-                       remove_backref_node(cache, node);
+                       if (!err) {
+                               ret = link_to_upper(trans, rc, node, path);
+                               if (ret < 0)
+                                       err = ret;
+                       }
                }
+               list_splice_init(&list, &cache->pending[level]);
        }
-       BUG_ON(!RB_EMPTY_ROOT(&cache->rb_root));
        return err;
 }
 
 static void mark_block_processed(struct reloc_control *rc,
-                                struct backref_node *node)
+                                u64 bytenr, u32 blocksize)
+{
+       set_extent_bits(&rc->processed_blocks, bytenr, bytenr + blocksize - 1,
+                       EXTENT_DIRTY, GFP_NOFS);
+}
+
+static void __mark_block_processed(struct reloc_control *rc,
+                                  struct backref_node *node)
 {
        u32 blocksize;
        if (node->level == 0 ||
            in_block_group(node->bytenr, rc->block_group)) {
                blocksize = btrfs_level_size(rc->extent_root, node->level);
-               set_extent_bits(&rc->processed_blocks, node->bytenr,
-                               node->bytenr + blocksize - 1, EXTENT_DIRTY,
-                               GFP_NOFS);
+               mark_block_processed(rc, node->bytenr, blocksize);
        }
        node->processed = 1;
 }
@@ -2179,7 +2635,7 @@ static void update_processed_blocks(struct reloc_control *rc,
                        if (next->processed)
                                break;
 
-                       mark_block_processed(rc, next);
+                       __mark_block_processed(rc, next);
 
                        if (list_empty(&next->upper))
                                break;
@@ -2202,138 +2658,6 @@ static int tree_block_processed(u64 bytenr, u32 blocksize,
        return 0;
 }
 
-/*
- * check if there are any file extent pointers in the leaf point to
- * data require processing
- */
-static int check_file_extents(struct reloc_control *rc,
-                             u64 bytenr, u32 blocksize, u64 ptr_gen)
-{
-       struct btrfs_key found_key;
-       struct btrfs_file_extent_item *fi;
-       struct extent_buffer *leaf;
-       u32 nritems;
-       int i;
-       int ret = 0;
-
-       leaf = read_tree_block(rc->extent_root, bytenr, blocksize, ptr_gen);
-
-       nritems = btrfs_header_nritems(leaf);
-       for (i = 0; i < nritems; i++) {
-               cond_resched();
-               btrfs_item_key_to_cpu(leaf, &found_key, i);
-               if (found_key.type != BTRFS_EXTENT_DATA_KEY)
-                       continue;
-               fi = btrfs_item_ptr(leaf, i, struct btrfs_file_extent_item);
-               if (btrfs_file_extent_type(leaf, fi) ==
-                   BTRFS_FILE_EXTENT_INLINE)
-                       continue;
-               bytenr = btrfs_file_extent_disk_bytenr(leaf, fi);
-               if (bytenr == 0)
-                       continue;
-               if (in_block_group(bytenr, rc->block_group)) {
-                       ret = 1;
-                       break;
-               }
-       }
-       free_extent_buffer(leaf);
-       return ret;
-}
-
-/*
- * scan child blocks of a given block to find blocks require processing
- */
-static int add_child_blocks(struct btrfs_trans_handle *trans,
-                           struct reloc_control *rc,
-                           struct backref_node *node,
-                           struct rb_root *blocks)
-{
-       struct tree_block *block;
-       struct rb_node *rb_node;
-       u64 bytenr;
-       u64 ptr_gen;
-       u32 blocksize;
-       u32 nritems;
-       int i;
-       int err = 0;
-
-       nritems = btrfs_header_nritems(node->eb);
-       blocksize = btrfs_level_size(rc->extent_root, node->level - 1);
-       for (i = 0; i < nritems; i++) {
-               cond_resched();
-               bytenr = btrfs_node_blockptr(node->eb, i);
-               ptr_gen = btrfs_node_ptr_generation(node->eb, i);
-               if (ptr_gen == trans->transid)
-                       continue;
-               if (!in_block_group(bytenr, rc->block_group) &&
-                   (node->level > 1 || rc->stage == MOVE_DATA_EXTENTS))
-                       continue;
-               if (tree_block_processed(bytenr, blocksize, rc))
-                       continue;
-
-               readahead_tree_block(rc->extent_root,
-                                    bytenr, blocksize, ptr_gen);
-       }
-
-       for (i = 0; i < nritems; i++) {
-               cond_resched();
-               bytenr = btrfs_node_blockptr(node->eb, i);
-               ptr_gen = btrfs_node_ptr_generation(node->eb, i);
-               if (ptr_gen == trans->transid)
-                       continue;
-               if (!in_block_group(bytenr, rc->block_group) &&
-                   (node->level > 1 || rc->stage == MOVE_DATA_EXTENTS))
-                       continue;
-               if (tree_block_processed(bytenr, blocksize, rc))
-                       continue;
-               if (!in_block_group(bytenr, rc->block_group) &&
-                   !check_file_extents(rc, bytenr, blocksize, ptr_gen))
-                       continue;
-
-               block = kmalloc(sizeof(*block), GFP_NOFS);
-               if (!block) {
-                       err = -ENOMEM;
-                       break;
-               }
-               block->bytenr = bytenr;
-               btrfs_node_key_to_cpu(node->eb, &block->key, i);
-               block->level = node->level - 1;
-               block->key_ready = 1;
-               rb_node = tree_insert(blocks, block->bytenr, &block->rb_node);
-               BUG_ON(rb_node);
-       }
-       if (err)
-               free_block_list(blocks);
-       return err;
-}
-
-/*
- * find adjacent blocks require processing
- */
-static noinline_for_stack
-int add_adjacent_blocks(struct btrfs_trans_handle *trans,
-                       struct reloc_control *rc,
-                       struct backref_cache *cache,
-                       struct rb_root *blocks, int level,
-                       struct backref_node **upper)
-{
-       struct backref_node *node;
-       int ret = 0;
-
-       WARN_ON(!list_empty(&cache->pending[level]));
-
-       if (list_empty(&cache->pending[level + 1]))
-               return 1;
-
-       node = list_entry(cache->pending[level + 1].next,
-                         struct backref_node, lower);
-       if (node->eb)
-               ret = add_child_blocks(trans, rc, node, blocks);
-
-       *upper = node;
-       return ret;
-}
-
 static int get_tree_block_key(struct reloc_control *rc,
                              struct tree_block *block)
 {
@@ -2371,40 +2695,53 @@ static int relocate_tree_block(struct btrfs_trans_handle *trans,
                                struct btrfs_path *path)
 {
        struct btrfs_root *root;
-       int ret;
+       int release = 0;
+       int ret = 0;
 
+       if (!node)
+               return 0;
+
+       BUG_ON(node->processed);
        root = select_one_root(trans, node);
-       if (unlikely(!root)) {
-               rc->found_old_snapshot = 1;
+       if (root == ERR_PTR(-ENOENT)) {
                update_processed_blocks(rc, node);
-               return 0;
+               goto out;
        }
 
-       if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) {
-               ret = do_relocation(trans, node, key, path, 1);
-               if (ret < 0)
-                       goto out;
-               if (node->level == 0 && rc->stage == UPDATE_DATA_PTRS) {
-                       ret = replace_file_extents(trans, rc, root,
-                                                  node->eb, NULL);
-                       if (ret < 0)
-                               goto out;
-               }
-               drop_node_buffer(node);
-       } else if (!root->ref_cows) {
-               path->lowest_level = node->level;
-               ret = btrfs_search_slot(trans, root, key, path, 0, 1);
-               btrfs_release_path(root, path);
-               if (ret < 0)
+       if (!root || root->ref_cows) {
+               ret = reserve_metadata_space(trans, rc, node);
+               if (ret)
                        goto out;
-       } else if (root != node->root) {
-               WARN_ON(node->level > 0 || rc->stage != UPDATE_DATA_PTRS);
+               release = 1;
        }
 
-       update_processed_blocks(rc, node);
-       ret = 0;
+       if (root) {
+               if (root->ref_cows) {
+                       BUG_ON(node->new_bytenr);
+                       BUG_ON(!list_empty(&node->list));
+                       btrfs_record_root_in_trans(trans, root);
+                       root = root->reloc_root;
+                       node->new_bytenr = root->node->start;
+                       node->root = root;
+                       list_add_tail(&node->list, &rc->backref_cache.changed);
+               } else {
+                       path->lowest_level = node->level;
+                       ret = btrfs_search_slot(trans, root, key, path, 0, 1);
+                       btrfs_release_path(root, path);
+                       if (ret > 0)
+                               ret = 0;
+               }
+               if (!ret)
+                       update_processed_blocks(rc, node);
+       } else {
+               ret = do_relocation(trans, rc, node, key, path, 1);
+       }
 out:
-       drop_node_buffer(node);
+       if (ret || node->level == 0 || node->cowonly) {
+               if (release)
+                       release_metadata_space(rc, node);
+               remove_backref_node(&rc->backref_cache, node);
+       }
        return ret;
 }
 
@@ -2415,12 +2752,10 @@ static noinline_for_stack
 int relocate_tree_blocks(struct btrfs_trans_handle *trans,
                         struct reloc_control *rc, struct rb_root *blocks)
 {
-       struct backref_cache *cache;
        struct backref_node *node;
        struct btrfs_path *path;
        struct tree_block *block;
        struct rb_node *rb_node;
-       int level = -1;
        int ret;
        int err = 0;
 
@@ -2428,21 +2763,9 @@ int relocate_tree_blocks(struct btrfs_trans_handle *trans,
        if (!path)
                return -ENOMEM;
 
-       cache = kmalloc(sizeof(*cache), GFP_NOFS);
-       if (!cache) {
-               btrfs_free_path(path);
-               return -ENOMEM;
-       }
-
-       backref_cache_init(cache);
-
        rb_node = rb_first(blocks);
        while (rb_node) {
                block = rb_entry(rb_node, struct tree_block, rb_node);
-               if (level == -1)
-                       level = block->level;
-               else
-                       BUG_ON(level != block->level);
                if (!block->key_ready)
                        reada_tree_block(rc, block);
                rb_node = rb_next(rb_node);
@@ -2452,99 +2775,82 @@ int relocate_tree_blocks(struct btrfs_trans_handle *trans,
        while (rb_node) {
                block = rb_entry(rb_node, struct tree_block, rb_node);
                if (!block->key_ready)
-                       get_tree_block_key(rc, block);
-               rb_node = rb_next(rb_node);
-       }
-
-       rb_node = rb_first(blocks);
-       while (rb_node) {
-               block = rb_entry(rb_node, struct tree_block, rb_node);
-
-               node = build_backref_tree(rc, cache, &block->key,
-                                         block->level, block->bytenr);
-               if (IS_ERR(node)) {
-                       err = PTR_ERR(node);
-                       goto out;
-               }
-
-               ret = relocate_tree_block(trans, rc, node, &block->key,
-                                         path);
-               if (ret < 0) {
-                       err = ret;
-                       goto out;
-               }
-               remove_backref_node(cache, node);
-               rb_node = rb_next(rb_node);
-       }
-
-       if (level > 0)
-               goto out;
-
-       free_block_list(blocks);
-
-       /*
-        * now backrefs of some upper level tree blocks have been cached,
-        * try relocating blocks referenced by these upper level blocks.
-        */
-       while (1) {
-               struct backref_node *upper = NULL;
-               if (trans->transaction->in_commit ||
-                   trans->transaction->delayed_refs.flushing)
-                       break;
-
-               ret = add_adjacent_blocks(trans, rc, cache, blocks, level,
-                                         &upper);
-               if (ret < 0)
-                       err = ret;
-               if (ret != 0)
-                       break;
+                       get_tree_block_key(rc, block);
+               rb_node = rb_next(rb_node);
+       }
 
-               rb_node = rb_first(blocks);
-               while (rb_node) {
-                       block = rb_entry(rb_node, struct tree_block, rb_node);
-                       if (trans->transaction->in_commit ||
-                           trans->transaction->delayed_refs.flushing)
-                               goto out;
-                       BUG_ON(!block->key_ready);
-                       node = build_backref_tree(rc, cache, &block->key,
-                                                 level, block->bytenr);
-                       if (IS_ERR(node)) {
-                               err = PTR_ERR(node);
-                               goto out;
-                       }
+       rb_node = rb_first(blocks);
+       while (rb_node) {
+               block = rb_entry(rb_node, struct tree_block, rb_node);
 
-                       ret = relocate_tree_block(trans, rc, node,
-                                                 &block->key, path);
-                       if (ret < 0) {
-                               err = ret;
-                               goto out;
-                       }
-                       remove_backref_node(cache, node);
-                       rb_node = rb_next(rb_node);
+               node = build_backref_tree(rc, &block->key,
+                                         block->level, block->bytenr);
+               if (IS_ERR(node)) {
+                       err = PTR_ERR(node);
+                       goto out;
                }
-               free_block_list(blocks);
 
-               if (upper) {
-                       ret = link_to_upper(trans, upper, path);
-                       if (ret < 0) {
+               ret = relocate_tree_block(trans, rc, node, &block->key,
+                                         path);
+               if (ret < 0) {
+                       if (ret != -EAGAIN || rb_node == rb_first(blocks))
                                err = ret;
-                               break;
-                       }
-                       remove_backref_node(cache, upper);
+                       goto out;
                }
+               rb_node = rb_next(rb_node);
        }
 out:
        free_block_list(blocks);
+       err = finish_pending_nodes(trans, rc, path, err);
 
-       ret = finish_pending_nodes(trans, cache, path);
-       if (ret < 0)
-               err = ret;
-
-       kfree(cache);
        btrfs_free_path(path);
        return err;
 }
 
+static noinline_for_stack
+int prealloc_file_extent_cluster(struct inode *inode,
+                                struct file_extent_cluster *cluster)
+{
+       u64 alloc_hint = 0;
+       u64 start;
+       u64 end;
+       u64 offset = BTRFS_I(inode)->index_cnt;
+       u64 num_bytes;
+       int nr = 0;
+       int ret = 0;
+
+       BUG_ON(cluster->start != cluster->boundary[0]);
+       mutex_lock(&inode->i_mutex);
+
+       ret = btrfs_check_data_free_space(inode, cluster->end +
+                                         1 - cluster->start);
+       if (ret)
+               goto out;
+
+       while (nr < cluster->nr) {
+               start = cluster->boundary[nr] - offset;
+               if (nr + 1 < cluster->nr)
+                       end = cluster->boundary[nr + 1] - 1 - offset;
+               else
+                       end = cluster->end - offset;
+
+               lock_extent(&BTRFS_I(inode)->io_tree, start, end, GFP_NOFS);
+               num_bytes = end + 1 - start;
+               ret = btrfs_prealloc_file_range(inode, 0, start,
+                                               num_bytes, num_bytes,
+                                               end + 1, &alloc_hint);
+               unlock_extent(&BTRFS_I(inode)->io_tree, start, end, GFP_NOFS);
+               if (ret)
+                       break;
+               nr++;
+       }
+       btrfs_free_reserved_data_space(inode, cluster->end +
+                                      1 - cluster->start);
+out:
+       mutex_unlock(&inode->i_mutex);
+       return ret;
+}
+
 static noinline_for_stack
 int setup_extent_mapping(struct inode *inode, u64 start, u64 end,
                         u64 block_start)
@@ -2588,7 +2894,6 @@ static int relocate_file_extent_cluster(struct inode *inode,
        u64 offset = BTRFS_I(inode)->index_cnt;
        unsigned long index;
        unsigned long last_index;
-       unsigned int dirty_page = 0;
        struct page *page;
        struct file_ra_state *ra;
        int nr = 0;
@@ -2601,21 +2906,24 @@ static int relocate_file_extent_cluster(struct inode *inode,
        if (!ra)
                return -ENOMEM;
 
-       index = (cluster->start - offset) >> PAGE_CACHE_SHIFT;
-       last_index = (cluster->end - offset) >> PAGE_CACHE_SHIFT;
+       ret = prealloc_file_extent_cluster(inode, cluster);
+       if (ret)
+               goto out;
 
-       mutex_lock(&inode->i_mutex);
+       file_ra_state_init(ra, inode->i_mapping);
 
-       i_size_write(inode, cluster->end + 1 - offset);
        ret = setup_extent_mapping(inode, cluster->start - offset,
                                   cluster->end - offset, cluster->start);
        if (ret)
-               goto out_unlock;
-
-       file_ra_state_init(ra, inode->i_mapping);
+               goto out;
 
-       WARN_ON(cluster->start != cluster->boundary[0]);
+       index = (cluster->start - offset) >> PAGE_CACHE_SHIFT;
+       last_index = (cluster->end - offset) >> PAGE_CACHE_SHIFT;
        while (index <= last_index) {
+               ret = btrfs_delalloc_reserve_metadata(inode, PAGE_CACHE_SIZE);
+               if (ret)
+                       goto out;
+
                page = find_lock_page(inode->i_mapping, index);
                if (!page) {
                        page_cache_sync_readahead(inode->i_mapping,
@@ -2623,8 +2931,10 @@ static int relocate_file_extent_cluster(struct inode *inode,
                                                  last_index + 1 - index);
                        page = grab_cache_page(inode->i_mapping, index);
                        if (!page) {
+                               btrfs_delalloc_release_metadata(inode,
+                                                       PAGE_CACHE_SIZE);
                                ret = -ENOMEM;
-                               goto out_unlock;
+                               goto out;
                        }
                }
 
@@ -2640,8 +2950,10 @@ static int relocate_file_extent_cluster(struct inode *inode,
                        if (!PageUptodate(page)) {
                                unlock_page(page);
                                page_cache_release(page);
+                               btrfs_delalloc_release_metadata(inode,
+                                                       PAGE_CACHE_SIZE);
                                ret = -EIO;
-                               goto out_unlock;
+                               goto out;
                        }
                }
 
@@ -2660,10 +2972,9 @@ static int relocate_file_extent_cluster(struct inode *inode,
                                        EXTENT_BOUNDARY, GFP_NOFS);
                        nr++;
                }
-               btrfs_set_extent_delalloc(inode, page_start, page_end, NULL);
 
+               btrfs_set_extent_delalloc(inode, page_start, page_end, NULL);
                set_page_dirty(page);
-               dirty_page++;
 
                unlock_extent(&BTRFS_I(inode)->io_tree,
                              page_start, page_end, GFP_NOFS);
@@ -2671,20 +2982,11 @@ static int relocate_file_extent_cluster(struct inode *inode,
                page_cache_release(page);
 
                index++;
-               if (nr < cluster->nr &&
-                   page_end + 1 + offset == cluster->boundary[nr]) {
-                       balance_dirty_pages_ratelimited_nr(inode->i_mapping,
-                                                          dirty_page);
-                       dirty_page = 0;
-               }
-       }
-       if (dirty_page) {
-               balance_dirty_pages_ratelimited_nr(inode->i_mapping,
-                                                  dirty_page);
+               balance_dirty_pages_ratelimited(inode->i_mapping);
+               btrfs_throttle(BTRFS_I(inode)->root);
        }
        WARN_ON(nr != cluster->nr);
-out_unlock:
-       mutex_unlock(&inode->i_mutex);
+out:
        kfree(ra);
        return ret;
 }
@@ -2870,9 +3172,6 @@ out:
 static int block_use_full_backref(struct reloc_control *rc,
                                  struct extent_buffer *eb)
 {
-       struct btrfs_path *path;
-       struct btrfs_extent_item *ei;
-       struct btrfs_key key;
        u64 flags;
        int ret;
 
@@ -2880,28 +3179,14 @@ static int block_use_full_backref(struct reloc_control *rc,
            btrfs_header_backref_rev(eb) < BTRFS_MIXED_BACKREF_REV)
                return 1;
 
-       path = btrfs_alloc_path();
-       BUG_ON(!path);
-
-       key.objectid = eb->start;
-       key.type = BTRFS_EXTENT_ITEM_KEY;
-       key.offset = eb->len;
-
-       path->search_commit_root = 1;
-       path->skip_locking = 1;
-       ret = btrfs_search_slot(NULL, rc->extent_root,
-                               &key, path, 0, 0);
+       ret = btrfs_lookup_extent_info(NULL, rc->extent_root,
+                                      eb->start, eb->len, NULL, &flags);
        BUG_ON(ret);
 
-       ei = btrfs_item_ptr(path->nodes[0], path->slots[0],
-                           struct btrfs_extent_item);
-       flags = btrfs_extent_flags(path->nodes[0], ei);
-       BUG_ON(!(flags & BTRFS_EXTENT_FLAG_TREE_BLOCK));
        if (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)
                ret = 1;
        else
                ret = 0;
-       btrfs_free_path(path);
        return ret;
 }
 
@@ -3074,22 +3359,10 @@ int add_data_references(struct reloc_control *rc,
        struct btrfs_extent_inline_ref *iref;
        unsigned long ptr;
        unsigned long end;
-       u32 blocksize;
+       u32 blocksize = btrfs_level_size(rc->extent_root, 0);
        int ret;
        int err = 0;
 
-       ret = get_new_location(rc->data_inode, NULL, extent_key->objectid,
-                              extent_key->offset);
-       BUG_ON(ret < 0);
-       if (ret > 0) {
-               /* the relocated data is fragmented */
-               rc->extents_skipped++;
-               btrfs_release_path(rc->extent_root, path);
-               return 0;
-       }
-
-       blocksize = btrfs_level_size(rc->extent_root, 0);
-
        eb = path->nodes[0];
        ptr = btrfs_item_ptr_offset(eb, path->slots[0]);
        end = ptr + btrfs_item_size_nr(eb, path->slots[0]);
@@ -3170,7 +3443,8 @@ int add_data_references(struct reloc_control *rc,
  */
 static noinline_for_stack
 int find_next_extent(struct btrfs_trans_handle *trans,
-                    struct reloc_control *rc, struct btrfs_path *path)
+                    struct reloc_control *rc, struct btrfs_path *path,
+                    struct btrfs_key *extent_key)
 {
        struct btrfs_key key;
        struct extent_buffer *leaf;
@@ -3225,6 +3499,7 @@ next:
                        rc->search_start = end + 1;
                } else {
                        rc->search_start = key.objectid + key.offset;
+                       memcpy(extent_key, &key, sizeof(key));
                        return 0;
                }
        }
@@ -3262,12 +3537,49 @@ static int check_extent_flags(u64 flags)
        return 0;
 }
 
+static noinline_for_stack
+int prepare_to_relocate(struct reloc_control *rc)
+{
+       struct btrfs_trans_handle *trans;
+       int ret;
+
+       rc->block_rsv = btrfs_alloc_block_rsv(rc->extent_root);
+       if (!rc->block_rsv)
+               return -ENOMEM;
+
+       /*
+        * reserve some space for creating reloc trees.
+        * btrfs_init_reloc_root will use them when there
+        * is no reservation in transaction handle.
+        */
+       ret = btrfs_block_rsv_add(NULL, rc->extent_root, rc->block_rsv,
+                                 rc->extent_root->nodesize * 256,
+                                 &rc->block_rsv_retries);
+       if (ret)
+               return ret;
+
+       rc->block_rsv->refill_used = 1;
+       btrfs_add_durable_block_rsv(rc->extent_root->fs_info, rc->block_rsv);
+
+       memset(&rc->cluster, 0, sizeof(rc->cluster));
+       rc->search_start = rc->block_group->key.objectid;
+       rc->extents_found = 0;
+       rc->nodes_relocated = 0;
+       rc->merging_rsv_size = 0;
+       rc->block_rsv_retries = 0;
+
+       rc->create_reloc_tree = 1;
+       set_reloc_control(rc);
+
+       trans = btrfs_join_transaction(rc->extent_root, 1);
+       btrfs_commit_transaction(trans, rc->extent_root);
+       return 0;
+}
 
 static noinline_for_stack int relocate_block_group(struct reloc_control *rc)
 {
        struct rb_root blocks = RB_ROOT;
        struct btrfs_key key;
-       struct file_extent_cluster *cluster;
        struct btrfs_trans_handle *trans = NULL;
        struct btrfs_path *path;
        struct btrfs_extent_item *ei;
@@ -3277,33 +3589,25 @@ static noinline_for_stack int relocate_block_group(struct reloc_control *rc)
        int ret;
        int err = 0;
 
-       cluster = kzalloc(sizeof(*cluster), GFP_NOFS);
-       if (!cluster)
-               return -ENOMEM;
-
        path = btrfs_alloc_path();
-       if (!path) {
-               kfree(cluster);
+       if (!path)
                return -ENOMEM;
-       }
-
-       rc->extents_found = 0;
-       rc->extents_skipped = 0;
 
-       rc->search_start = rc->block_group->key.objectid;
-       clear_extent_bits(&rc->processed_blocks, 0, (u64)-1, EXTENT_DIRTY,
-                         GFP_NOFS);
-
-       rc->create_reloc_root = 1;
-       set_reloc_control(rc);
-
-       trans = btrfs_start_transaction(rc->extent_root, 1);
-       btrfs_commit_transaction(trans, rc->extent_root);
+       ret = prepare_to_relocate(rc);
+       if (ret) {
+               err = ret;
+               goto out_free;
+       }
 
        while (1) {
-               trans = btrfs_start_transaction(rc->extent_root, 1);
+               trans = btrfs_start_transaction(rc->extent_root, 0);
+
+               if (update_backref_cache(trans, &rc->backref_cache)) {
+                       btrfs_end_transaction(trans, rc->extent_root);
+                       continue;
+               }
 
-               ret = find_next_extent(trans, rc, path);
+               ret = find_next_extent(trans, rc, path, &key);
                if (ret < 0)
                        err = ret;
                if (ret != 0)
@@ -3313,9 +3617,7 @@ static noinline_for_stack int relocate_block_group(struct reloc_control *rc)
 
                ei = btrfs_item_ptr(path->nodes[0], path->slots[0],
                                    struct btrfs_extent_item);
-               btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
-               item_size = btrfs_item_size_nr(path->nodes[0],
-                                              path->slots[0]);
+               item_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]);
                if (item_size >= sizeof(*ei)) {
                        flags = btrfs_extent_flags(path->nodes[0], ei);
                        ret = check_extent_flags(flags);
@@ -3356,73 +3658,100 @@ static noinline_for_stack int relocate_block_group(struct reloc_control *rc)
                if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
                        ret = add_tree_block(rc, &key, path, &blocks);
                } else if (rc->stage == UPDATE_DATA_PTRS &&
-                        (flags & BTRFS_EXTENT_FLAG_DATA)) {
+                          (flags & BTRFS_EXTENT_FLAG_DATA)) {
                        ret = add_data_references(rc, &key, path, &blocks);
                } else {
                        btrfs_release_path(rc->extent_root, path);
                        ret = 0;
                }
                if (ret < 0) {
-                       err = 0;
+                       err = ret;
                        break;
                }
 
                if (!RB_EMPTY_ROOT(&blocks)) {
                        ret = relocate_tree_blocks(trans, rc, &blocks);
                        if (ret < 0) {
+                               if (ret != -EAGAIN) {
+                                       err = ret;
+                                       break;
+                               }
+                               rc->extents_found--;
+                               rc->search_start = key.objectid;
+                       }
+               }
+
+               ret = btrfs_block_rsv_check(trans, rc->extent_root,
+                                           rc->block_rsv, 0, 5);
+               if (ret < 0) {
+                       if (ret != -EAGAIN) {
                                err = ret;
+                               WARN_ON(1);
                                break;
                        }
+                       rc->commit_transaction = 1;
                }
 
-               nr = trans->blocks_used;
-               btrfs_end_transaction(trans, rc->extent_root);
+               if (rc->commit_transaction) {
+                       rc->commit_transaction = 0;
+                       ret = btrfs_commit_transaction(trans, rc->extent_root);
+                       BUG_ON(ret);
+               } else {
+                       nr = trans->blocks_used;
+                       btrfs_end_transaction_throttle(trans, rc->extent_root);
+                       btrfs_btree_balance_dirty(rc->extent_root, nr);
+               }
                trans = NULL;
-               btrfs_btree_balance_dirty(rc->extent_root, nr);
 
                if (rc->stage == MOVE_DATA_EXTENTS &&
                    (flags & BTRFS_EXTENT_FLAG_DATA)) {
                        rc->found_file_extent = 1;
                        ret = relocate_data_extent(rc->data_inode,
-                                                  &key, cluster);
+                                                  &key, &rc->cluster);
                        if (ret < 0) {
                                err = ret;
                                break;
                        }
                }
        }
-       btrfs_free_path(path);
+
+       btrfs_release_path(rc->extent_root, path);
+       clear_extent_bits(&rc->processed_blocks, 0, (u64)-1, EXTENT_DIRTY,
+                         GFP_NOFS);
 
        if (trans) {
                nr = trans->blocks_used;
-               btrfs_end_transaction(trans, rc->extent_root);
+               btrfs_end_transaction_throttle(trans, rc->extent_root);
                btrfs_btree_balance_dirty(rc->extent_root, nr);
        }
 
        if (!err) {
-               ret = relocate_file_extent_cluster(rc->data_inode, cluster);
+               ret = relocate_file_extent_cluster(rc->data_inode,
+                                                  &rc->cluster);
                if (ret < 0)
                        err = ret;
        }
 
-       kfree(cluster);
+       rc->create_reloc_tree = 0;
+       set_reloc_control(rc);
 
-       rc->create_reloc_root = 0;
-       smp_mb();
+       backref_cache_cleanup(&rc->backref_cache);
+       btrfs_block_rsv_release(rc->extent_root, rc->block_rsv, (u64)-1);
 
-       if (rc->extents_found > 0) {
-               trans = btrfs_start_transaction(rc->extent_root, 1);
-               btrfs_commit_transaction(trans, rc->extent_root);
-       }
+       err = prepare_to_merge(rc, err);
 
        merge_reloc_roots(rc);
 
+       rc->merge_reloc_tree = 0;
        unset_reloc_control(rc);
+       btrfs_block_rsv_release(rc->extent_root, rc->block_rsv, (u64)-1);
 
        /* get rid of pinned extents */
-       trans = btrfs_start_transaction(rc->extent_root, 1);
+       trans = btrfs_join_transaction(rc->extent_root, 1);
        btrfs_commit_transaction(trans, rc->extent_root);
-
+out_free:
+       btrfs_free_block_rsv(rc->extent_root, rc->block_rsv);
+       btrfs_free_path(path);
        return err;
 }
 
@@ -3448,7 +3777,8 @@ static int __insert_orphan_inode(struct btrfs_trans_handle *trans,
        btrfs_set_inode_generation(leaf, item, 1);
        btrfs_set_inode_size(leaf, item, 0);
        btrfs_set_inode_mode(leaf, item, S_IFREG | 0600);
-       btrfs_set_inode_flags(leaf, item, BTRFS_INODE_NOCOMPRESS);
+       btrfs_set_inode_flags(leaf, item, BTRFS_INODE_NOCOMPRESS |
+                                         BTRFS_INODE_PREALLOC);
        btrfs_mark_buffer_dirty(leaf);
        btrfs_release_path(root, path);
 out:
@@ -3460,8 +3790,9 @@ out:
  * helper to create inode for data relocation.
  * the inode is in data relocation tree and its link count is 0
  */
-static struct inode *create_reloc_inode(struct btrfs_fs_info *fs_info,
-                                       struct btrfs_block_group_cache *group)
+static noinline_for_stack
+struct inode *create_reloc_inode(struct btrfs_fs_info *fs_info,
+                                struct btrfs_block_group_cache *group)
 {
        struct inode *inode = NULL;
        struct btrfs_trans_handle *trans;
@@ -3475,8 +3806,9 @@ static struct inode *create_reloc_inode(struct btrfs_fs_info *fs_info,
        if (IS_ERR(root))
                return ERR_CAST(root);
 
-       trans = btrfs_start_transaction(root, 1);
-       BUG_ON(!trans);
+       trans = btrfs_start_transaction(root, 6);
+       if (IS_ERR(trans))
+               return ERR_CAST(trans);
 
        err = btrfs_find_free_objectid(trans, root, objectid, &objectid);
        if (err)
@@ -3496,7 +3828,6 @@ static struct inode *create_reloc_inode(struct btrfs_fs_info *fs_info,
 out:
        nr = trans->blocks_used;
        btrfs_end_transaction(trans, root);
-
        btrfs_btree_balance_dirty(root, nr);
        if (err) {
                if (inode)
@@ -3506,6 +3837,21 @@ out:
        return inode;
 }
 
+static struct reloc_control *alloc_reloc_control(void)
+{
+       struct reloc_control *rc;
+
+       rc = kzalloc(sizeof(*rc), GFP_NOFS);
+       if (!rc)
+               return NULL;
+
+       INIT_LIST_HEAD(&rc->reloc_roots);
+       backref_cache_init(&rc->backref_cache);
+       mapping_tree_init(&rc->reloc_root_tree);
+       extent_io_tree_init(&rc->processed_blocks, NULL, GFP_NOFS);
+       return rc;
+}
+
 /*
  * function to relocate all extents in a block group.
  */
@@ -3514,24 +3860,26 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start)
        struct btrfs_fs_info *fs_info = extent_root->fs_info;
        struct reloc_control *rc;
        int ret;
+       int rw = 0;
        int err = 0;
 
-       rc = kzalloc(sizeof(*rc), GFP_NOFS);
+       rc = alloc_reloc_control();
        if (!rc)
                return -ENOMEM;
 
-       mapping_tree_init(&rc->reloc_root_tree);
-       extent_io_tree_init(&rc->processed_blocks, NULL, GFP_NOFS);
-       INIT_LIST_HEAD(&rc->reloc_roots);
+       rc->extent_root = extent_root;
 
        rc->block_group = btrfs_lookup_block_group(fs_info, group_start);
        BUG_ON(!rc->block_group);
 
-       btrfs_init_workers(&rc->workers, "relocate",
-                          fs_info->thread_pool_size, NULL);
-
-       rc->extent_root = extent_root;
-       btrfs_prepare_block_group_relocation(extent_root, rc->block_group);
+       if (!rc->block_group->ro) {
+               ret = btrfs_set_block_group_ro(extent_root, rc->block_group);
+               if (ret) {
+                       err = ret;
+                       goto out;
+               }
+               rw = 1;
+       }
 
        rc->data_inode = create_reloc_inode(fs_info, rc->block_group);
        if (IS_ERR(rc->data_inode)) {
@@ -3548,9 +3896,6 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start)
        btrfs_wait_ordered_extents(fs_info->tree_root, 0, 0);
 
        while (1) {
-               rc->extents_found = 0;
-               rc->extents_skipped = 0;
-
                mutex_lock(&fs_info->cleaner_mutex);
 
                btrfs_clean_old_snapshots(fs_info->tree_root);
@@ -3559,7 +3904,7 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start)
                mutex_unlock(&fs_info->cleaner_mutex);
                if (ret < 0) {
                        err = ret;
-                       break;
+                       goto out;
                }
 
                if (rc->extents_found == 0)
@@ -3573,18 +3918,6 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start)
                        invalidate_mapping_pages(rc->data_inode->i_mapping,
                                                 0, -1);
                        rc->stage = UPDATE_DATA_PTRS;
-               } else if (rc->stage == UPDATE_DATA_PTRS &&
-                          rc->extents_skipped >= rc->extents_found) {
-                       iput(rc->data_inode);
-                       rc->data_inode = create_reloc_inode(fs_info,
-                                                           rc->block_group);
-                       if (IS_ERR(rc->data_inode)) {
-                               err = PTR_ERR(rc->data_inode);
-                               rc->data_inode = NULL;
-                               break;
-                       }
-                       rc->stage = MOVE_DATA_EXTENTS;
-                       rc->found_file_extent = 0;
                }
        }
 
@@ -3597,8 +3930,9 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start)
        WARN_ON(rc->block_group->reserved > 0);
        WARN_ON(btrfs_block_group_used(&rc->block_group->item) > 0);
 out:
+       if (err && rw)
+               btrfs_set_block_group_rw(extent_root, rc->block_group);
        iput(rc->data_inode);
-       btrfs_stop_workers(&rc->workers);
        btrfs_put_block_group(rc->block_group);
        kfree(rc);
        return err;
@@ -3609,7 +3943,7 @@ static noinline_for_stack int mark_garbage_root(struct btrfs_root *root)
        struct btrfs_trans_handle *trans;
        int ret;
 
-       trans = btrfs_start_transaction(root->fs_info->tree_root, 1);
+       trans = btrfs_start_transaction(root->fs_info->tree_root, 0);
 
        memset(&root->root_item.drop_progress, 0,
                sizeof(root->root_item.drop_progress));
@@ -3702,20 +4036,20 @@ int btrfs_recover_relocation(struct btrfs_root *root)
        if (list_empty(&reloc_roots))
                goto out;
 
-       rc = kzalloc(sizeof(*rc), GFP_NOFS);
+       rc = alloc_reloc_control();
        if (!rc) {
                err = -ENOMEM;
                goto out;
        }
 
-       mapping_tree_init(&rc->reloc_root_tree);
-       INIT_LIST_HEAD(&rc->reloc_roots);
-       btrfs_init_workers(&rc->workers, "relocate",
-                          root->fs_info->thread_pool_size, NULL);
        rc->extent_root = root->fs_info->extent_root;
 
        set_reloc_control(rc);
 
+       trans = btrfs_join_transaction(rc->extent_root, 1);
+
+       rc->merge_reloc_tree = 1;
+
        while (!list_empty(&reloc_roots)) {
                reloc_root = list_entry(reloc_roots.next,
                                        struct btrfs_root, root_list);
@@ -3735,20 +4069,16 @@ int btrfs_recover_relocation(struct btrfs_root *root)
                fs_root->reloc_root = reloc_root;
        }
 
-       trans = btrfs_start_transaction(rc->extent_root, 1);
        btrfs_commit_transaction(trans, rc->extent_root);
 
        merge_reloc_roots(rc);
 
        unset_reloc_control(rc);
 
-       trans = btrfs_start_transaction(rc->extent_root, 1);
+       trans = btrfs_join_transaction(rc->extent_root, 1);
        btrfs_commit_transaction(trans, rc->extent_root);
 out:
-       if (rc) {
-               btrfs_stop_workers(&rc->workers);
-               kfree(rc);
-       }
+       kfree(rc);
        while (!list_empty(&reloc_roots)) {
                reloc_root = list_entry(reloc_roots.next,
                                        struct btrfs_root, root_list);
@@ -3814,3 +4144,130 @@ int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len)
        btrfs_put_ordered_extent(ordered);
        return 0;
 }
+
+void btrfs_reloc_cow_block(struct btrfs_trans_handle *trans,
+                          struct btrfs_root *root, struct extent_buffer *buf,
+                          struct extent_buffer *cow)
+{
+       struct reloc_control *rc;
+       struct backref_node *node;
+       int first_cow = 0;
+       int level;
+       int ret;
+
+       rc = root->fs_info->reloc_ctl;
+       if (!rc)
+               return;
+
+       BUG_ON(rc->stage == UPDATE_DATA_PTRS &&
+              root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID);
+
+       level = btrfs_header_level(buf);
+       if (btrfs_header_generation(buf) <=
+           btrfs_root_last_snapshot(&root->root_item))
+               first_cow = 1;
+
+       if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID &&
+           rc->create_reloc_tree) {
+               WARN_ON(!first_cow && level == 0);
+
+               node = rc->backref_cache.path[level];
+               BUG_ON(node->bytenr != buf->start &&
+                      node->new_bytenr != buf->start);
+
+               drop_node_buffer(node);
+               extent_buffer_get(cow);
+               node->eb = cow;
+               node->new_bytenr = cow->start;
+
+               if (!node->pending) {
+                       list_move_tail(&node->list,
+                                      &rc->backref_cache.pending[level]);
+                       node->pending = 1;
+               }
+
+               if (first_cow)
+                       __mark_block_processed(rc, node);
+
+               if (first_cow && level > 0)
+                       rc->nodes_relocated += buf->len;
+       }
+
+       if (level == 0 && first_cow && rc->stage == UPDATE_DATA_PTRS) {
+               ret = replace_file_extents(trans, rc, root, cow);
+               BUG_ON(ret);
+       }
+}
+
+/*
+ * called before creating snapshot. it calculates metadata reservation
+ * requried for relocating tree blocks in the snapshot
+ */
+void btrfs_reloc_pre_snapshot(struct btrfs_trans_handle *trans,
+                             struct btrfs_pending_snapshot *pending,
+                             u64 *bytes_to_reserve)
+{
+       struct btrfs_root *root;
+       struct reloc_control *rc;
+
+       root = pending->root;
+       if (!root->reloc_root)
+               return;
+
+       rc = root->fs_info->reloc_ctl;
+       if (!rc->merge_reloc_tree)
+               return;
+
+       root = root->reloc_root;
+       BUG_ON(btrfs_root_refs(&root->root_item) == 0);
+       /*
+        * relocation is in the stage of merging trees. the space
+        * used by merging a reloc tree is twice the size of
+        * relocated tree nodes in the worst case. half for cowing
+        * the reloc tree, half for cowing the fs tree. the space
+        * used by cowing the reloc tree will be freed after the
+        * tree is dropped. if we create snapshot, cowing the fs
+        * tree may use more space than it frees. so we need
+        * reserve extra space.
+        */
+       *bytes_to_reserve += rc->nodes_relocated;
+}
+
+/*
+ * called after snapshot is created. migrate block reservation
+ * and create reloc root for the newly created snapshot
+ */
+void btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans,
+                              struct btrfs_pending_snapshot *pending)
+{
+       struct btrfs_root *root = pending->root;
+       struct btrfs_root *reloc_root;
+       struct btrfs_root *new_root;
+       struct reloc_control *rc;
+       int ret;
+
+       if (!root->reloc_root)
+               return;
+
+       rc = root->fs_info->reloc_ctl;
+       rc->merging_rsv_size += rc->nodes_relocated;
+
+       if (rc->merge_reloc_tree) {
+               ret = btrfs_block_rsv_migrate(&pending->block_rsv,
+                                             rc->block_rsv,
+                                             rc->nodes_relocated);
+               BUG_ON(ret);
+       }
+
+       new_root = pending->snap;
+       reloc_root = create_reloc_root(trans, root->reloc_root,
+                                      new_root->root_key.objectid);
+
+       __add_reloc_root(reloc_root);
+       new_root->reloc_root = reloc_root;
+
+       if (rc->create_reloc_tree) {
+               ret = clone_backref_node(trans, rc, root, reloc_root);
+               BUG_ON(ret);
+       }
+}
index 67fa2d29d663dcc2f665b3217bba98302784a60e..b91ccd972644b48048329806044ebc3c62d1b550 100644 (file)
@@ -259,6 +259,8 @@ int btrfs_find_orphan_roots(struct btrfs_root *tree_root)
        struct extent_buffer *leaf;
        struct btrfs_path *path;
        struct btrfs_key key;
+       struct btrfs_key root_key;
+       struct btrfs_root *root;
        int err = 0;
        int ret;
 
@@ -270,6 +272,9 @@ int btrfs_find_orphan_roots(struct btrfs_root *tree_root)
        key.type = BTRFS_ORPHAN_ITEM_KEY;
        key.offset = 0;
 
+       root_key.type = BTRFS_ROOT_ITEM_KEY;
+       root_key.offset = (u64)-1;
+
        while (1) {
                ret = btrfs_search_slot(NULL, tree_root, &key, path, 0, 0);
                if (ret < 0) {
@@ -294,13 +299,25 @@ int btrfs_find_orphan_roots(struct btrfs_root *tree_root)
                    key.type != BTRFS_ORPHAN_ITEM_KEY)
                        break;
 
-               ret = btrfs_find_dead_roots(tree_root, key.offset);
-               if (ret) {
+               root_key.objectid = key.offset;
+               key.offset++;
+
+               root = btrfs_read_fs_root_no_name(tree_root->fs_info,
+                                                 &root_key);
+               if (!IS_ERR(root))
+                       continue;
+
+               ret = PTR_ERR(root);
+               if (ret != -ENOENT) {
                        err = ret;
                        break;
                }
 
-               key.offset++;
+               ret = btrfs_find_dead_roots(tree_root, root_key.objectid);
+               if (ret) {
+                       err = ret;
+                       break;
+               }
        }
 
        btrfs_free_path(path);
index 1866dff0538ef626a17d2dcbf29d9df4df46b3aa..d34b2dfc9628cde65f6181b5ed4043cf8603541c 100644 (file)
@@ -498,7 +498,7 @@ int btrfs_sync_fs(struct super_block *sb, int wait)
        btrfs_start_delalloc_inodes(root, 0);
        btrfs_wait_ordered_extents(root, 0, 0);
 
-       trans = btrfs_start_transaction(root, 1);
+       trans = btrfs_start_transaction(root, 0);
        ret = btrfs_commit_transaction(trans, root);
        return ret;
 }
@@ -694,11 +694,11 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
                if (btrfs_super_log_root(&root->fs_info->super_copy) != 0)
                        return -EINVAL;
 
-               /* recover relocation */
-               ret = btrfs_recover_relocation(root);
+               ret = btrfs_cleanup_fs_roots(root->fs_info);
                WARN_ON(ret);
 
-               ret = btrfs_cleanup_fs_roots(root->fs_info);
+               /* recover relocation */
+               ret = btrfs_recover_relocation(root);
                WARN_ON(ret);
 
                sb->s_flags &= ~MS_RDONLY;
@@ -714,34 +714,18 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        struct list_head *head = &root->fs_info->space_info;
        struct btrfs_space_info *found;
        u64 total_used = 0;
-       u64 data_used = 0;
        int bits = dentry->d_sb->s_blocksize_bits;
        __be32 *fsid = (__be32 *)root->fs_info->fsid;
 
        rcu_read_lock();
-       list_for_each_entry_rcu(found, head, list) {
-               if (found->flags & (BTRFS_BLOCK_GROUP_DUP|
-                                   BTRFS_BLOCK_GROUP_RAID10|
-                                   BTRFS_BLOCK_GROUP_RAID1)) {
-                       total_used += found->bytes_used;
-                       if (found->flags & BTRFS_BLOCK_GROUP_DATA)
-                               data_used += found->bytes_used;
-                       else
-                               data_used += found->total_bytes;
-               }
-
-               total_used += found->bytes_used;
-               if (found->flags & BTRFS_BLOCK_GROUP_DATA)
-                       data_used += found->bytes_used;
-               else
-                       data_used += found->total_bytes;
-       }
+       list_for_each_entry_rcu(found, head, list)
+               total_used += found->disk_used;
        rcu_read_unlock();
 
        buf->f_namelen = BTRFS_NAME_LEN;
        buf->f_blocks = btrfs_super_total_bytes(disk_super) >> bits;
        buf->f_bfree = buf->f_blocks - (total_used >> bits);
-       buf->f_bavail = buf->f_blocks - (data_used >> bits);
+       buf->f_bavail = buf->f_bfree;
        buf->f_bsize = dentry->d_sb->s_blocksize;
        buf->f_type = BTRFS_SUPER_MAGIC;
 
@@ -832,11 +816,14 @@ static const struct file_operations btrfs_ctl_fops = {
 };
 
 static struct miscdevice btrfs_misc = {
-       .minor          = MISC_DYNAMIC_MINOR,
+       .minor          = BTRFS_MINOR,
        .name           = "btrfs-control",
        .fops           = &btrfs_ctl_fops
 };
 
+MODULE_ALIAS_MISCDEV(BTRFS_MINOR);
+MODULE_ALIAS("devname:btrfs-control");
+
 static int btrfs_interface_init(void)
 {
        return misc_register(&btrfs_misc);
index 2cb116099b90207d0f1910176de8a029bd23c93f..66e4c66cc63bf114900c6da4462c32e6bd0e65e0 100644 (file)
@@ -165,54 +165,89 @@ enum btrfs_trans_type {
        TRANS_USERSPACE,
 };
 
+static int may_wait_transaction(struct btrfs_root *root, int type)
+{
+       if (!root->fs_info->log_root_recovering &&
+           ((type == TRANS_START && !root->fs_info->open_ioctl_trans) ||
+            type == TRANS_USERSPACE))
+               return 1;
+       return 0;
+}
+
 static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
-                                            int num_blocks, int type)
+                                                   u64 num_items, int type)
 {
-       struct btrfs_trans_handle *h =
-               kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS);
+       struct btrfs_trans_handle *h;
+       struct btrfs_transaction *cur_trans;
+       int retries = 0;
        int ret;
+again:
+       h = kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS);
+       if (!h)
+               return ERR_PTR(-ENOMEM);
 
        mutex_lock(&root->fs_info->trans_mutex);
-       if (!root->fs_info->log_root_recovering &&
-           ((type == TRANS_START && !root->fs_info->open_ioctl_trans) ||
-            type == TRANS_USERSPACE))
+       if (may_wait_transaction(root, type))
                wait_current_trans(root);
+
        ret = join_transaction(root);
        BUG_ON(ret);
 
-       h->transid = root->fs_info->running_transaction->transid;
-       h->transaction = root->fs_info->running_transaction;
-       h->blocks_reserved = num_blocks;
+       cur_trans = root->fs_info->running_transaction;
+       cur_trans->use_count++;
+       mutex_unlock(&root->fs_info->trans_mutex);
+
+       h->transid = cur_trans->transid;
+       h->transaction = cur_trans;
        h->blocks_used = 0;
        h->block_group = 0;
-       h->alloc_exclude_nr = 0;
-       h->alloc_exclude_start = 0;
+       h->bytes_reserved = 0;
        h->delayed_ref_updates = 0;
+       h->block_rsv = NULL;
 
-       if (!current->journal_info && type != TRANS_USERSPACE)
-               current->journal_info = h;
+       smp_mb();
+       if (cur_trans->blocked && may_wait_transaction(root, type)) {
+               btrfs_commit_transaction(h, root);
+               goto again;
+       }
+
+       if (num_items > 0) {
+               ret = btrfs_trans_reserve_metadata(h, root, num_items,
+                                                  &retries);
+               if (ret == -EAGAIN) {
+                       btrfs_commit_transaction(h, root);
+                       goto again;
+               }
+               if (ret < 0) {
+                       btrfs_end_transaction(h, root);
+                       return ERR_PTR(ret);
+               }
+       }
 
-       root->fs_info->running_transaction->use_count++;
+       mutex_lock(&root->fs_info->trans_mutex);
        record_root_in_trans(h, root);
        mutex_unlock(&root->fs_info->trans_mutex);
+
+       if (!current->journal_info && type != TRANS_USERSPACE)
+               current->journal_info = h;
        return h;
 }
 
 struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root,
-                                                  int num_blocks)
+                                                  int num_items)
 {
-       return start_transaction(root, num_blocks, TRANS_START);
+       return start_transaction(root, num_items, TRANS_START);
 }
 struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root,
                                                   int num_blocks)
 {
-       return start_transaction(root, num_blocks, TRANS_JOIN);
+       return start_transaction(root, 0, TRANS_JOIN);
 }
 
 struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *r,
                                                         int num_blocks)
 {
-       return start_transaction(r, num_blocks, TRANS_USERSPACE);
+       return start_transaction(r, 0, TRANS_USERSPACE);
 }
 
 /* wait for a transaction commit to be fully complete */
@@ -286,10 +321,36 @@ void btrfs_throttle(struct btrfs_root *root)
        mutex_unlock(&root->fs_info->trans_mutex);
 }
 
+static int should_end_transaction(struct btrfs_trans_handle *trans,
+                                 struct btrfs_root *root)
+{
+       int ret;
+       ret = btrfs_block_rsv_check(trans, root,
+                                   &root->fs_info->global_block_rsv, 0, 5);
+       return ret ? 1 : 0;
+}
+
+int btrfs_should_end_transaction(struct btrfs_trans_handle *trans,
+                                struct btrfs_root *root)
+{
+       struct btrfs_transaction *cur_trans = trans->transaction;
+       int updates;
+
+       if (cur_trans->blocked || cur_trans->delayed_refs.flushing)
+               return 1;
+
+       updates = trans->delayed_ref_updates;
+       trans->delayed_ref_updates = 0;
+       if (updates)
+               btrfs_run_delayed_refs(trans, root, updates);
+
+       return should_end_transaction(trans, root);
+}
+
 static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
                          struct btrfs_root *root, int throttle)
 {
-       struct btrfs_transaction *cur_trans;
+       struct btrfs_transaction *cur_trans = trans->transaction;
        struct btrfs_fs_info *info = root->fs_info;
        int count = 0;
 
@@ -313,9 +374,21 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
                count++;
        }
 
+       btrfs_trans_release_metadata(trans, root);
+
+       if (!root->fs_info->open_ioctl_trans &&
+           should_end_transaction(trans, root))
+               trans->transaction->blocked = 1;
+
+       if (cur_trans->blocked && !cur_trans->in_commit) {
+               if (throttle)
+                       return btrfs_commit_transaction(trans, root);
+               else
+                       wake_up_process(info->transaction_kthread);
+       }
+
        mutex_lock(&info->trans_mutex);
-       cur_trans = info->running_transaction;
-       WARN_ON(cur_trans != trans->transaction);
+       WARN_ON(cur_trans != info->running_transaction);
        WARN_ON(cur_trans->num_writers < 1);
        cur_trans->num_writers--;
 
@@ -603,6 +676,7 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans,
 
                        btrfs_free_log(trans, root);
                        btrfs_update_reloc_root(trans, root);
+                       btrfs_orphan_commit_root(trans, root);
 
                        if (root->commit_root != root->node) {
                                switch_commit_root(root);
@@ -627,30 +701,30 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans,
 int btrfs_defrag_root(struct btrfs_root *root, int cacheonly)
 {
        struct btrfs_fs_info *info = root->fs_info;
-       int ret;
        struct btrfs_trans_handle *trans;
+       int ret;
        unsigned long nr;
 
-       smp_mb();
-       if (root->defrag_running)
+       if (xchg(&root->defrag_running, 1))
                return 0;
-       trans = btrfs_start_transaction(root, 1);
+
        while (1) {
-               root->defrag_running = 1;
+               trans = btrfs_start_transaction(root, 0);
+               if (IS_ERR(trans))
+                       return PTR_ERR(trans);
+
                ret = btrfs_defrag_leaves(trans, root, cacheonly);
+
                nr = trans->blocks_used;
                btrfs_end_transaction(trans, root);
                btrfs_btree_balance_dirty(info->tree_root, nr);
                cond_resched();
 
-               trans = btrfs_start_transaction(root, 1);
                if (root->fs_info->closing || ret != -EAGAIN)
                        break;
        }
        root->defrag_running = 0;
-       smp_mb();
-       btrfs_end_transaction(trans, root);
-       return 0;
+       return ret;
 }
 
 #if 0
@@ -758,47 +832,63 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
        struct btrfs_root *root = pending->root;
        struct btrfs_root *parent_root;
        struct inode *parent_inode;
+       struct dentry *dentry;
        struct extent_buffer *tmp;
        struct extent_buffer *old;
        int ret;
-       u64 objectid;
-       int namelen;
+       int retries = 0;
+       u64 to_reserve = 0;
        u64 index = 0;
-
-       parent_inode = pending->dentry->d_parent->d_inode;
-       parent_root = BTRFS_I(parent_inode)->root;
+       u64 objectid;
 
        new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS);
        if (!new_root_item) {
-               ret = -ENOMEM;
+               pending->error = -ENOMEM;
                goto fail;
        }
+
        ret = btrfs_find_free_objectid(trans, tree_root, 0, &objectid);
-       if (ret)
+       if (ret) {
+               pending->error = ret;
                goto fail;
+       }
+
+       btrfs_reloc_pre_snapshot(trans, pending, &to_reserve);
+       btrfs_orphan_pre_snapshot(trans, pending, &to_reserve);
+
+       if (to_reserve > 0) {
+               ret = btrfs_block_rsv_add(trans, root, &pending->block_rsv,
+                                         to_reserve, &retries);
+               if (ret) {
+                       pending->error = ret;
+                       goto fail;
+               }
+       }
 
        key.objectid = objectid;
-       /* record when the snapshot was created in key.offset */
-       key.offset = trans->transid;
-       btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
+       key.offset = (u64)-1;
+       key.type = BTRFS_ROOT_ITEM_KEY;
 
-       memcpy(&pending->root_key, &key, sizeof(key));
-       pending->root_key.offset = (u64)-1;
+       trans->block_rsv = &pending->block_rsv;
 
+       dentry = pending->dentry;
+       parent_inode = dentry->d_parent->d_inode;
+       parent_root = BTRFS_I(parent_inode)->root;
        record_root_in_trans(trans, parent_root);
+
        /*
         * insert the directory item
         */
-       namelen = strlen(pending->name);
        ret = btrfs_set_inode_index(parent_inode, &index);
        BUG_ON(ret);
        ret = btrfs_insert_dir_item(trans, parent_root,
-                           pending->name, namelen,
-                           parent_inode->i_ino,
-                           &pending->root_key, BTRFS_FT_DIR, index);
+                               dentry->d_name.name, dentry->d_name.len,
+                               parent_inode->i_ino, &key,
+                               BTRFS_FT_DIR, index);
        BUG_ON(ret);
 
-       btrfs_i_size_write(parent_inode, parent_inode->i_size + namelen * 2);
+       btrfs_i_size_write(parent_inode, parent_inode->i_size +
+                                        dentry->d_name.len * 2);
        ret = btrfs_update_inode(trans, parent_root, parent_inode);
        BUG_ON(ret);
 
@@ -815,22 +905,32 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
        free_extent_buffer(old);
 
        btrfs_set_root_node(new_root_item, tmp);
-       ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key,
-                               new_root_item);
-       BUG_ON(ret);
+       /* record when the snapshot was created in key.offset */
+       key.offset = trans->transid;
+       ret = btrfs_insert_root(trans, tree_root, &key, new_root_item);
        btrfs_tree_unlock(tmp);
        free_extent_buffer(tmp);
+       BUG_ON(ret);
 
-       ret = btrfs_add_root_ref(trans, parent_root->fs_info->tree_root,
-                                pending->root_key.objectid,
+       /*
+        * insert root back/forward references
+        */
+       ret = btrfs_add_root_ref(trans, tree_root, objectid,
                                 parent_root->root_key.objectid,
-                                parent_inode->i_ino, index, pending->name,
-                                namelen);
+                                parent_inode->i_ino, index,
+                                dentry->d_name.name, dentry->d_name.len);
        BUG_ON(ret);
 
+       key.offset = (u64)-1;
+       pending->snap = btrfs_read_fs_root_no_name(root->fs_info, &key);
+       BUG_ON(IS_ERR(pending->snap));
+
+       btrfs_reloc_post_snapshot(trans, pending);
+       btrfs_orphan_post_snapshot(trans, pending);
 fail:
        kfree(new_root_item);
-       return ret;
+       btrfs_block_rsv_release(root, &pending->block_rsv, (u64)-1);
+       return 0;
 }
 
 /*
@@ -878,6 +978,16 @@ int btrfs_transaction_in_commit(struct btrfs_fs_info *info)
        return ret;
 }
 
+int btrfs_transaction_blocked(struct btrfs_fs_info *info)
+{
+       int ret = 0;
+       spin_lock(&info->new_trans_lock);
+       if (info->running_transaction)
+               ret = info->running_transaction->blocked;
+       spin_unlock(&info->new_trans_lock);
+       return ret;
+}
+
 int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root)
 {
@@ -899,6 +1009,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
        ret = btrfs_run_delayed_refs(trans, root, 0);
        BUG_ON(ret);
 
+       btrfs_trans_release_metadata(trans, root);
+
        cur_trans = trans->transaction;
        /*
         * set the flushing flag so procs in this transaction have to
@@ -951,9 +1063,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
                        snap_pending = 1;
 
                WARN_ON(cur_trans != trans->transaction);
-               prepare_to_wait(&cur_trans->writer_wait, &wait,
-                               TASK_UNINTERRUPTIBLE);
-
                if (cur_trans->num_writers > 1)
                        timeout = MAX_SCHEDULE_TIMEOUT;
                else if (should_grow)
@@ -976,6 +1085,9 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
                 */
                btrfs_run_ordered_operations(root, 1);
 
+               prepare_to_wait(&cur_trans->writer_wait, &wait,
+                               TASK_UNINTERRUPTIBLE);
+
                smp_mb();
                if (cur_trans->num_writers > 1 || should_grow)
                        schedule_timeout(timeout);
@@ -1103,9 +1215,9 @@ int btrfs_clean_old_snapshots(struct btrfs_root *root)
 
                if (btrfs_header_backref_rev(root->node) <
                    BTRFS_MIXED_BACKREF_REV)
-                       btrfs_drop_snapshot(root, 0);
+                       btrfs_drop_snapshot(root, NULL, 0);
                else
-                       btrfs_drop_snapshot(root, 1);
+                       btrfs_drop_snapshot(root, NULL, 1);
        }
        return 0;
 }
index 93c7ccb33118f38d420c00c3b790fe0040b7f0ca..e104986d0bfd682e036ec67d236d65d062422164 100644 (file)
@@ -45,20 +45,23 @@ struct btrfs_transaction {
 
 struct btrfs_trans_handle {
        u64 transid;
+       u64 block_group;
+       u64 bytes_reserved;
        unsigned long blocks_reserved;
        unsigned long blocks_used;
-       struct btrfs_transaction *transaction;
-       u64 block_group;
-       u64 alloc_exclude_start;
-       u64 alloc_exclude_nr;
        unsigned long delayed_ref_updates;
+       struct btrfs_transaction *transaction;
+       struct btrfs_block_rsv *block_rsv;
 };
 
 struct btrfs_pending_snapshot {
        struct dentry *dentry;
        struct btrfs_root *root;
-       char *name;
-       struct btrfs_key root_key;
+       struct btrfs_root *snap;
+       /* block reservation for the operation */
+       struct btrfs_block_rsv block_rsv;
+       /* extra metadata reseration for relocation */
+       int error;
        struct list_head list;
 };
 
@@ -85,11 +88,11 @@ static inline void btrfs_set_inode_last_trans(struct btrfs_trans_handle *trans,
 int btrfs_end_transaction(struct btrfs_trans_handle *trans,
                          struct btrfs_root *root);
 struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root,
-                                                  int num_blocks);
+                                                  int num_items);
 struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root,
-                                                  int num_blocks);
+                                                 int num_blocks);
 struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *r,
-                                                  int num_blocks);
+                                                        int num_blocks);
 int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans,
                                     struct btrfs_root *root);
 int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans,
@@ -103,6 +106,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root);
 int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans,
                                   struct btrfs_root *root);
+int btrfs_should_end_transaction(struct btrfs_trans_handle *trans,
+                                struct btrfs_root *root);
 void btrfs_throttle(struct btrfs_root *root);
 int btrfs_record_root_in_trans(struct btrfs_trans_handle *trans,
                                struct btrfs_root *root);
@@ -112,5 +117,6 @@ int btrfs_write_marked_extents(struct btrfs_root *root,
                                struct extent_io_tree *dirty_pages, int mark);
 int btrfs_wait_marked_extents(struct btrfs_root *root,
                                struct extent_io_tree *dirty_pages, int mark);
+int btrfs_transaction_blocked(struct btrfs_fs_info *info);
 int btrfs_transaction_in_commit(struct btrfs_fs_info *info);
 #endif
index b10eacdb16200e686b3519a46747b706b927761f..f7ac8e013ed73459139ae07b00189ffa952bba08 100644 (file)
@@ -117,13 +117,14 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
                                 path->nodes[1], 0,
                                 cache_only, &last_ret,
                                 &root->defrag_progress);
-       WARN_ON(ret && ret != -EAGAIN);
+       if (ret) {
+               WARN_ON(ret == -EAGAIN);
+               goto out;
+       }
        if (next_key_ret == 0) {
                memcpy(&root->defrag_progress, &key, sizeof(key));
                ret = -EAGAIN;
        }
-
-       btrfs_release_path(root, path);
 out:
        if (path)
                btrfs_free_path(path);
index af57dd2b43d429777ff2530dfbc978ed33f76e2a..fb102a9aee9cc1ee3213d04bc1bae6fec6644f2d 100644 (file)
@@ -135,6 +135,7 @@ static int start_log_trans(struct btrfs_trans_handle *trans,
                           struct btrfs_root *root)
 {
        int ret;
+       int err = 0;
 
        mutex_lock(&root->log_mutex);
        if (root->log_root) {
@@ -155,17 +156,19 @@ static int start_log_trans(struct btrfs_trans_handle *trans,
        mutex_lock(&root->fs_info->tree_log_mutex);
        if (!root->fs_info->log_root_tree) {
                ret = btrfs_init_log_root_tree(trans, root->fs_info);
-               BUG_ON(ret);
+               if (ret)
+                       err = ret;
        }
-       if (!root->log_root) {
+       if (err == 0 && !root->log_root) {
                ret = btrfs_add_log_tree(trans, root);
-               BUG_ON(ret);
+               if (ret)
+                       err = ret;
        }
        mutex_unlock(&root->fs_info->tree_log_mutex);
        root->log_batch++;
        atomic_inc(&root->log_writers);
        mutex_unlock(&root->log_mutex);
-       return 0;
+       return err;
 }
 
 /*
@@ -376,7 +379,7 @@ insert:
                        BUG_ON(ret);
                }
        } else if (ret) {
-               BUG();
+               return ret;
        }
        dst_ptr = btrfs_item_ptr_offset(path->nodes[0],
                                        path->slots[0]);
@@ -1699,9 +1702,9 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
 
                next = btrfs_find_create_tree_block(root, bytenr, blocksize);
 
-               wc->process_func(root, next, wc, ptr_gen);
-
                if (*level == 1) {
+                       wc->process_func(root, next, wc, ptr_gen);
+
                        path->slots[*level]++;
                        if (wc->free) {
                                btrfs_read_buffer(next, ptr_gen);
@@ -1734,35 +1737,7 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
        WARN_ON(*level < 0);
        WARN_ON(*level >= BTRFS_MAX_LEVEL);
 
-       if (path->nodes[*level] == root->node)
-               parent = path->nodes[*level];
-       else
-               parent = path->nodes[*level + 1];
-
-       bytenr = path->nodes[*level]->start;
-
-       blocksize = btrfs_level_size(root, *level);
-       root_owner = btrfs_header_owner(parent);
-       root_gen = btrfs_header_generation(parent);
-
-       wc->process_func(root, path->nodes[*level], wc,
-                        btrfs_header_generation(path->nodes[*level]));
-
-       if (wc->free) {
-               next = path->nodes[*level];
-               btrfs_tree_lock(next);
-               clean_tree_block(trans, root, next);
-               btrfs_set_lock_blocking(next);
-               btrfs_wait_tree_block_writeback(next);
-               btrfs_tree_unlock(next);
-
-               WARN_ON(root_owner != BTRFS_TREE_LOG_OBJECTID);
-               ret = btrfs_free_reserved_extent(root, bytenr, blocksize);
-               BUG_ON(ret);
-       }
-       free_extent_buffer(path->nodes[*level]);
-       path->nodes[*level] = NULL;
-       *level += 1;
+       path->slots[*level] = btrfs_header_nritems(path->nodes[*level]);
 
        cond_resched();
        return 0;
@@ -1781,7 +1756,7 @@ static noinline int walk_up_log_tree(struct btrfs_trans_handle *trans,
 
        for (i = *level; i < BTRFS_MAX_LEVEL - 1 && path->nodes[i]; i++) {
                slot = path->slots[i];
-               if (slot < btrfs_header_nritems(path->nodes[i]) - 1) {
+               if (slot + 1 < btrfs_header_nritems(path->nodes[i])) {
                        struct extent_buffer *node;
                        node = path->nodes[i];
                        path->slots[i]++;
@@ -2047,7 +2022,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
        mutex_unlock(&log_root_tree->log_mutex);
 
        ret = update_log_root(trans, log);
-       BUG_ON(ret);
 
        mutex_lock(&log_root_tree->log_mutex);
        if (atomic_dec_and_test(&log_root_tree->log_writers)) {
@@ -2056,6 +2030,15 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
                        wake_up(&log_root_tree->log_writer_wait);
        }
 
+       if (ret) {
+               BUG_ON(ret != -ENOSPC);
+               root->fs_info->last_trans_log_full_commit = trans->transid;
+               btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
+               mutex_unlock(&log_root_tree->log_mutex);
+               ret = -EAGAIN;
+               goto out;
+       }
+
        index2 = log_root_tree->log_transid % 2;
        if (atomic_read(&log_root_tree->log_commit[index2])) {
                btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
@@ -2129,15 +2112,10 @@ out:
        return 0;
 }
 
-/*
- * free all the extents used by the tree log.  This should be called
- * at commit time of the full transaction
- */
-int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root)
+static void free_log_tree(struct btrfs_trans_handle *trans,
+                         struct btrfs_root *log)
 {
        int ret;
-       struct btrfs_root *log;
-       struct key;
        u64 start;
        u64 end;
        struct walk_control wc = {
@@ -2145,10 +2123,6 @@ int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root)
                .process_func = process_one_buffer
        };
 
-       if (!root->log_root || root->fs_info->log_root_recovering)
-               return 0;
-
-       log = root->log_root;
        ret = walk_log_tree(trans, log, &wc);
        BUG_ON(ret);
 
@@ -2162,14 +2136,30 @@ int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root)
                                  EXTENT_DIRTY | EXTENT_NEW, GFP_NOFS);
        }
 
-       if (log->log_transid > 0) {
-               ret = btrfs_del_root(trans, root->fs_info->log_root_tree,
-                                    &log->root_key);
-               BUG_ON(ret);
-       }
-       root->log_root = NULL;
        free_extent_buffer(log->node);
        kfree(log);
+}
+
+/*
+ * free all the extents used by the tree log.  This should be called
+ * at commit time of the full transaction
+ */
+int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root)
+{
+       if (root->log_root) {
+               free_log_tree(trans, root->log_root);
+               root->log_root = NULL;
+       }
+       return 0;
+}
+
+int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans,
+                            struct btrfs_fs_info *fs_info)
+{
+       if (fs_info->log_root_tree) {
+               free_log_tree(trans, fs_info->log_root_tree);
+               fs_info->log_root_tree = NULL;
+       }
        return 0;
 }
 
@@ -2203,6 +2193,7 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
        struct btrfs_dir_item *di;
        struct btrfs_path *path;
        int ret;
+       int err = 0;
        int bytes_del = 0;
 
        if (BTRFS_I(dir)->logged_trans < trans->transid)
@@ -2218,7 +2209,11 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
        path = btrfs_alloc_path();
        di = btrfs_lookup_dir_item(trans, log, path, dir->i_ino,
                                   name, name_len, -1);
-       if (di && !IS_ERR(di)) {
+       if (IS_ERR(di)) {
+               err = PTR_ERR(di);
+               goto fail;
+       }
+       if (di) {
                ret = btrfs_delete_one_dir_name(trans, log, path, di);
                bytes_del += name_len;
                BUG_ON(ret);
@@ -2226,7 +2221,11 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
        btrfs_release_path(log, path);
        di = btrfs_lookup_dir_index_item(trans, log, path, dir->i_ino,
                                         index, name, name_len, -1);
-       if (di && !IS_ERR(di)) {
+       if (IS_ERR(di)) {
+               err = PTR_ERR(di);
+               goto fail;
+       }
+       if (di) {
                ret = btrfs_delete_one_dir_name(trans, log, path, di);
                bytes_del += name_len;
                BUG_ON(ret);
@@ -2244,6 +2243,10 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
                btrfs_release_path(log, path);
 
                ret = btrfs_search_slot(trans, log, &key, path, 0, 1);
+               if (ret < 0) {
+                       err = ret;
+                       goto fail;
+               }
                if (ret == 0) {
                        struct btrfs_inode_item *item;
                        u64 i_size;
@@ -2261,9 +2264,13 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
                        ret = 0;
                btrfs_release_path(log, path);
        }
-
+fail:
        btrfs_free_path(path);
        mutex_unlock(&BTRFS_I(dir)->log_mutex);
+       if (ret == -ENOSPC) {
+               root->fs_info->last_trans_log_full_commit = trans->transid;
+               ret = 0;
+       }
        btrfs_end_log_trans(root);
 
        return 0;
@@ -2291,6 +2298,10 @@ int btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans,
        ret = btrfs_del_inode_ref(trans, log, name, name_len, inode->i_ino,
                                  dirid, &index);
        mutex_unlock(&BTRFS_I(inode)->log_mutex);
+       if (ret == -ENOSPC) {
+               root->fs_info->last_trans_log_full_commit = trans->transid;
+               ret = 0;
+       }
        btrfs_end_log_trans(root);
 
        return ret;
@@ -2318,7 +2329,8 @@ static noinline int insert_dir_log_key(struct btrfs_trans_handle *trans,
        else
                key.type = BTRFS_DIR_LOG_INDEX_KEY;
        ret = btrfs_insert_empty_item(trans, log, path, &key, sizeof(*item));
-       BUG_ON(ret);
+       if (ret)
+               return ret;
 
        item = btrfs_item_ptr(path->nodes[0], path->slots[0],
                              struct btrfs_dir_log_item);
@@ -2343,6 +2355,7 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
        struct btrfs_key max_key;
        struct btrfs_root *log = root->log_root;
        struct extent_buffer *src;
+       int err = 0;
        int ret;
        int i;
        int nritems;
@@ -2405,6 +2418,10 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
                        ret = overwrite_item(trans, log, dst_path,
                                             path->nodes[0], path->slots[0],
                                             &tmp);
+                       if (ret) {
+                               err = ret;
+                               goto done;
+                       }
                }
        }
        btrfs_release_path(root, path);
@@ -2432,7 +2449,10 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
                                goto done;
                        ret = overwrite_item(trans, log, dst_path, src, i,
                                             &min_key);
-                       BUG_ON(ret);
+                       if (ret) {
+                               err = ret;
+                               goto done;
+                       }
                }
                path->slots[0] = nritems;
 
@@ -2454,22 +2474,30 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
                        ret = overwrite_item(trans, log, dst_path,
                                             path->nodes[0], path->slots[0],
                                             &tmp);
-
-                       BUG_ON(ret);
-                       last_offset = tmp.offset;
+                       if (ret)
+                               err = ret;
+                       else
+                               last_offset = tmp.offset;
                        goto done;
                }
        }
 done:
-       *last_offset_ret = last_offset;
        btrfs_release_path(root, path);
        btrfs_release_path(log, dst_path);
 
-       /* insert the log range keys to indicate where the log is valid */
-       ret = insert_dir_log_key(trans, log, path, key_type, inode->i_ino,
-                                first_offset, last_offset);
-       BUG_ON(ret);
-       return 0;
+       if (err == 0) {
+               *last_offset_ret = last_offset;
+               /*
+                * insert the log range keys to indicate where the log
+                * is valid
+                */
+               ret = insert_dir_log_key(trans, log, path, key_type,
+                                        inode->i_ino, first_offset,
+                                        last_offset);
+               if (ret)
+                       err = ret;
+       }
+       return err;
 }
 
 /*
@@ -2501,7 +2529,8 @@ again:
                ret = log_dir_items(trans, root, inode, path,
                                    dst_path, key_type, min_key,
                                    &max_key);
-               BUG_ON(ret);
+               if (ret)
+                       return ret;
                if (max_key == (u64)-1)
                        break;
                min_key = max_key + 1;
@@ -2535,8 +2564,8 @@ static int drop_objectid_items(struct btrfs_trans_handle *trans,
 
        while (1) {
                ret = btrfs_search_slot(trans, log, &key, path, -1, 1);
-
-               if (ret != 1)
+               BUG_ON(ret == 0);
+               if (ret < 0)
                        break;
 
                if (path->slots[0] == 0)
@@ -2554,7 +2583,7 @@ static int drop_objectid_items(struct btrfs_trans_handle *trans,
                btrfs_release_path(log, path);
        }
        btrfs_release_path(log, path);
-       return 0;
+       return ret;
 }
 
 static noinline int copy_items(struct btrfs_trans_handle *trans,
@@ -2587,7 +2616,10 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
        }
        ret = btrfs_insert_empty_items(trans, log, dst_path,
                                       ins_keys, ins_sizes, nr);
-       BUG_ON(ret);
+       if (ret) {
+               kfree(ins_data);
+               return ret;
+       }
 
        for (i = 0; i < nr; i++, dst_path->slots[0]++) {
                dst_offset = btrfs_item_ptr_offset(dst_path->nodes[0],
@@ -2660,16 +2692,17 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
         * we have to do this after the loop above to avoid changing the
         * log tree while trying to change the log tree.
         */
+       ret = 0;
        while (!list_empty(&ordered_sums)) {
                struct btrfs_ordered_sum *sums = list_entry(ordered_sums.next,
                                                   struct btrfs_ordered_sum,
                                                   list);
-               ret = btrfs_csum_file_blocks(trans, log, sums);
-               BUG_ON(ret);
+               if (!ret)
+                       ret = btrfs_csum_file_blocks(trans, log, sums);
                list_del(&sums->list);
                kfree(sums);
        }
-       return 0;
+       return ret;
 }
 
 /* log a single inode in the tree log.
@@ -2697,6 +2730,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
        struct btrfs_root *log = root->log_root;
        struct extent_buffer *src = NULL;
        u32 size;
+       int err = 0;
        int ret;
        int nritems;
        int ins_start_slot = 0;
@@ -2739,7 +2773,10 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
        } else {
                ret = btrfs_truncate_inode_items(trans, log, inode, 0, 0);
        }
-       BUG_ON(ret);
+       if (ret) {
+               err = ret;
+               goto out_unlock;
+       }
        path->keep_locks = 1;
 
        while (1) {
@@ -2768,7 +2805,10 @@ again:
 
                ret = copy_items(trans, log, dst_path, src, ins_start_slot,
                                 ins_nr, inode_only);
-               BUG_ON(ret);
+               if (ret) {
+                       err = ret;
+                       goto out_unlock;
+               }
                ins_nr = 1;
                ins_start_slot = path->slots[0];
 next_slot:
@@ -2784,7 +2824,10 @@ next_slot:
                        ret = copy_items(trans, log, dst_path, src,
                                         ins_start_slot,
                                         ins_nr, inode_only);
-                       BUG_ON(ret);
+                       if (ret) {
+                               err = ret;
+                               goto out_unlock;
+                       }
                        ins_nr = 0;
                }
                btrfs_release_path(root, path);
@@ -2802,7 +2845,10 @@ next_slot:
                ret = copy_items(trans, log, dst_path, src,
                                 ins_start_slot,
                                 ins_nr, inode_only);
-               BUG_ON(ret);
+               if (ret) {
+                       err = ret;
+                       goto out_unlock;
+               }
                ins_nr = 0;
        }
        WARN_ON(ins_nr);
@@ -2810,14 +2856,18 @@ next_slot:
                btrfs_release_path(root, path);
                btrfs_release_path(log, dst_path);
                ret = log_directory_changes(trans, root, inode, path, dst_path);
-               BUG_ON(ret);
+               if (ret) {
+                       err = ret;
+                       goto out_unlock;
+               }
        }
        BTRFS_I(inode)->logged_trans = trans->transid;
+out_unlock:
        mutex_unlock(&BTRFS_I(inode)->log_mutex);
 
        btrfs_free_path(path);
        btrfs_free_path(dst_path);
-       return 0;
+       return err;
 }
 
 /*
@@ -2942,10 +2992,13 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
                goto end_no_trans;
        }
 
-       start_log_trans(trans, root);
+       ret = start_log_trans(trans, root);
+       if (ret)
+               goto end_trans;
 
        ret = btrfs_log_inode(trans, root, inode, inode_only);
-       BUG_ON(ret);
+       if (ret)
+               goto end_trans;
 
        /*
         * for regular files, if its inode is already on disk, we don't
@@ -2955,8 +3008,10 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
         */
        if (S_ISREG(inode->i_mode) &&
            BTRFS_I(inode)->generation <= last_committed &&
-           BTRFS_I(inode)->last_unlink_trans <= last_committed)
-                       goto no_parent;
+           BTRFS_I(inode)->last_unlink_trans <= last_committed) {
+               ret = 0;
+               goto end_trans;
+       }
 
        inode_only = LOG_INODE_EXISTS;
        while (1) {
@@ -2970,15 +3025,21 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
                if (BTRFS_I(inode)->generation >
                    root->fs_info->last_trans_committed) {
                        ret = btrfs_log_inode(trans, root, inode, inode_only);
-                       BUG_ON(ret);
+                       if (ret)
+                               goto end_trans;
                }
                if (IS_ROOT(parent))
                        break;
 
                parent = parent->d_parent;
        }
-no_parent:
        ret = 0;
+end_trans:
+       if (ret < 0) {
+               BUG_ON(ret != -ENOSPC);
+               root->fs_info->last_trans_log_full_commit = trans->transid;
+               ret = 1;
+       }
        btrfs_end_log_trans(root);
 end_no_trans:
        return ret;
@@ -3020,7 +3081,7 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree)
        path = btrfs_alloc_path();
        BUG_ON(!path);
 
-       trans = btrfs_start_transaction(fs_info->tree_root, 1);
+       trans = btrfs_start_transaction(fs_info->tree_root, 0);
 
        wc.trans = trans;
        wc.pin = 1;
index 0776eacb50830f14c405bd44d8d8817dc9554295..3dfae84c8cc8bc1fada072bb45a3676dcedb323d 100644 (file)
@@ -25,6 +25,8 @@
 int btrfs_sync_log(struct btrfs_trans_handle *trans,
                   struct btrfs_root *root);
 int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root);
+int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans,
+                            struct btrfs_fs_info *fs_info);
 int btrfs_recover_log_trees(struct btrfs_root *tree_root);
 int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans,
                          struct btrfs_root *root, struct dentry *dentry);
index 8db7b14bbae8be31c726b8e8596d0ff0640fa35f..d6e3af8be95b9a1509b6b61f29ae8841ce52af31 100644 (file)
@@ -1097,7 +1097,7 @@ static int btrfs_rm_dev_item(struct btrfs_root *root,
        if (!path)
                return -ENOMEM;
 
-       trans = btrfs_start_transaction(root, 1);
+       trans = btrfs_start_transaction(root, 0);
        key.objectid = BTRFS_DEV_ITEMS_OBJECTID;
        key.type = BTRFS_DEV_ITEM_KEY;
        key.offset = device->devid;
@@ -1486,7 +1486,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
                goto error;
        }
 
-       trans = btrfs_start_transaction(root, 1);
+       trans = btrfs_start_transaction(root, 0);
        lock_chunks(root);
 
        device->barriers = 1;
@@ -1751,9 +1751,10 @@ static int btrfs_relocate_chunk(struct btrfs_root *root,
 
        /* step one, relocate all the extents inside this chunk */
        ret = btrfs_relocate_block_group(extent_root, chunk_offset);
-       BUG_ON(ret);
+       if (ret)
+               return ret;
 
-       trans = btrfs_start_transaction(root, 1);
+       trans = btrfs_start_transaction(root, 0);
        BUG_ON(!trans);
 
        lock_chunks(root);
@@ -1925,7 +1926,7 @@ int btrfs_balance(struct btrfs_root *dev_root)
                        break;
                BUG_ON(ret);
 
-               trans = btrfs_start_transaction(dev_root, 1);
+               trans = btrfs_start_transaction(dev_root, 0);
                BUG_ON(!trans);
 
                ret = btrfs_grow_device(trans, device, old_size);
@@ -2094,11 +2095,7 @@ again:
        }
 
        /* Shrinking succeeded, else we would be at "done". */
-       trans = btrfs_start_transaction(root, 1);
-       if (!trans) {
-               ret = -ENOMEM;
-               goto done;
-       }
+       trans = btrfs_start_transaction(root, 0);
        lock_chunks(root);
 
        device->disk_total_bytes = new_size;
index 193b58f7d3f3b36d027a85756c917aa7191f99b2..88ecbb215878ae3573a5bbedfc4afadc6ef0a73d 100644 (file)
@@ -154,15 +154,10 @@ int __btrfs_setxattr(struct btrfs_trans_handle *trans,
        if (trans)
                return do_setxattr(trans, inode, name, value, size, flags);
 
-       ret = btrfs_reserve_metadata_space(root, 2);
-       if (ret)
-               return ret;
+       trans = btrfs_start_transaction(root, 2);
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
 
-       trans = btrfs_start_transaction(root, 1);
-       if (!trans) {
-               ret = -ENOMEM;
-               goto out;
-       }
        btrfs_set_trans_block_group(trans, inode);
 
        ret = do_setxattr(trans, inode, name, value, size, flags);
@@ -174,7 +169,6 @@ int __btrfs_setxattr(struct btrfs_trans_handle *trans,
        BUG_ON(ret);
 out:
        btrfs_end_transaction_throttle(trans, root);
-       btrfs_unreserve_metadata_space(root, 2);
        return ret;
 }
 
@@ -282,7 +276,7 @@ err:
  * List of handlers for synthetic system.* attributes.  All real ondisk
  * attributes are handled directly.
  */
-struct xattr_handler *btrfs_xattr_handlers[] = {
+const struct xattr_handler *btrfs_xattr_handlers[] = {
 #ifdef CONFIG_BTRFS_FS_POSIX_ACL
        &btrfs_xattr_acl_access_handler,
        &btrfs_xattr_acl_default_handler,
index 721efa0346e037c2f6f32c91d7f284fbc580c87f..7a43fd640bbb54b97c63fe37ab2dbea9e28c00e0 100644 (file)
@@ -21,9 +21,9 @@
 
 #include <linux/xattr.h>
 
-extern struct xattr_handler btrfs_xattr_acl_access_handler;
-extern struct xattr_handler btrfs_xattr_acl_default_handler;
-extern struct xattr_handler *btrfs_xattr_handlers[];
+extern const struct xattr_handler btrfs_xattr_acl_access_handler;
+extern const struct xattr_handler btrfs_xattr_acl_default_handler;
+extern const struct xattr_handler *btrfs_xattr_handlers[];
 
 extern ssize_t __btrfs_getxattr(struct inode *inode, const char *name,
                void *buffer, size_t size);
index 08e422d5699674c246bf614d62fe826b6b0aaf43..d54812b198e9d968007e407448a898cbc83fddb9 100644 (file)
@@ -561,26 +561,17 @@ repeat:
        return err;
 }
 
-static void do_thaw_all(struct work_struct *work)
+static void do_thaw_one(struct super_block *sb, void *unused)
 {
-       struct super_block *sb;
        char b[BDEVNAME_SIZE];
+       while (sb->s_bdev && !thaw_bdev(sb->s_bdev, sb))
+               printk(KERN_WARNING "Emergency Thaw on %s\n",
+                      bdevname(sb->s_bdev, b));
+}
 
-       spin_lock(&sb_lock);
-restart:
-       list_for_each_entry(sb, &super_blocks, s_list) {
-               sb->s_count++;
-               spin_unlock(&sb_lock);
-               down_read(&sb->s_umount);
-               while (sb->s_bdev && !thaw_bdev(sb->s_bdev, sb))
-                       printk(KERN_WARNING "Emergency Thaw on %s\n",
-                              bdevname(sb->s_bdev, b));
-               up_read(&sb->s_umount);
-               spin_lock(&sb_lock);
-               if (__put_super_and_need_restart(sb))
-                       goto restart;
-       }
-       spin_unlock(&sb_lock);
+static void do_thaw_all(struct work_struct *work)
+{
+       iterate_supers(do_thaw_one, NULL);
        kfree(work);
        printk(KERN_WARNING "Emergency Thaw complete\n");
 }
@@ -1958,14 +1949,11 @@ static int __block_commit_write(struct inode *inode, struct page *page,
 }
 
 /*
- * 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.
+ * 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(struct file *file, struct address_space *mapping,
+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)
@@ -2001,20 +1989,50 @@ int block_write_begin(struct file *file, struct address_space *mapping,
                        unlock_page(page);
                        page_cache_release(page);
                        *pagep = NULL;
-
-                       /*
-                        * 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 (pos + len > inode->i_size)
-                               vmtruncate(inode, inode->i_size);
                }
        }
 
 out:
        return status;
 }
+EXPORT_SYMBOL(block_write_begin_newtrunc);
+
+/*
+ * 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.
+ */
+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 ret;
+
+       ret = block_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.
+        *
+        * 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);
+       }
+
+       return ret;
+}
 EXPORT_SYMBOL(block_write_begin);
 
 int block_write_end(struct file *file, struct address_space *mapping,
@@ -2333,7 +2351,7 @@ out:
  * For moronic filesystems that do not allow holes in file.
  * We may have to extend the file.
  */
-int cont_write_begin(struct file *file, struct address_space *mapping,
+int cont_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, loff_t *bytes)
@@ -2354,11 +2372,30 @@ int cont_write_begin(struct file *file, struct address_space *mapping,
        }
 
        *pagep = NULL;
-       err = block_write_begin(file, mapping, pos, len,
+       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;
+}
 EXPORT_SYMBOL(cont_write_begin);
 
 int block_prepare_write(struct page *page, unsigned from, unsigned to,
@@ -2390,7 +2427,7 @@ EXPORT_SYMBOL(block_commit_write);
  *
  * We are not allowed to take the i_mutex here so we have to play games to
  * protect against truncate races as the page could now be beyond EOF.  Because
- * vmtruncate() writes the inode size before removing pages, once we have the
+ * truncate writes the inode size before removing pages, once we have the
  * page lock we can determine safely if the page is beyond EOF. If it is not
  * beyond EOF, then the page is guaranteed safe against truncation until we
  * unlock the page.
@@ -2473,10 +2510,11 @@ static void attach_nobh_buffers(struct page *page, struct buffer_head *head)
 }
 
 /*
- * On entry, the page is fully not uptodate.
- * On exit the page is fully uptodate in the areas outside (from,to)
+ * 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 nobh_write_begin(struct file *file, struct address_space *mapping,
+int nobh_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)
@@ -2509,8 +2547,8 @@ int nobh_write_begin(struct file *file, struct address_space *mapping,
                unlock_page(page);
                page_cache_release(page);
                *pagep = NULL;
-               return block_write_begin(file, mapping, pos, len, flags, pagep,
-                                       fsdata, get_block);
+               return block_write_begin_newtrunc(file, mapping, pos, len,
+                                       flags, pagep, fsdata, get_block);
        }
 
        if (PageMappedToDisk(page))
@@ -2614,8 +2652,34 @@ out_release:
        page_cache_release(page);
        *pagep = NULL;
 
-       if (pos + len > inode->i_size)
-               vmtruncate(inode, inode->i_size);
+       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;
 }
index a9005d862ed4b7e415f03ddf25fc241420cb2d48..d9c60b84949a6c6a0f807ab59a234f2760fca90d 100644 (file)
@@ -274,7 +274,6 @@ static int ceph_readpages(struct file *file, struct address_space *mapping,
        struct ceph_osd_client *osdc = &ceph_inode_to_client(inode)->osdc;
        int rc = 0;
        struct page **pages;
-       struct pagevec pvec;
        loff_t offset;
        u64 len;
 
@@ -297,8 +296,6 @@ static int ceph_readpages(struct file *file, struct address_space *mapping,
        if (rc < 0)
                goto out;
 
-       /* set uptodate and add to lru in pagevec-sized chunks */
-       pagevec_init(&pvec, 0);
        for (; !list_empty(page_list) && len > 0;
             rc -= PAGE_CACHE_SIZE, len -= PAGE_CACHE_SIZE) {
                struct page *page =
@@ -312,7 +309,7 @@ static int ceph_readpages(struct file *file, struct address_space *mapping,
                        zero_user_segment(page, s, PAGE_CACHE_SIZE);
                }
 
-               if (add_to_page_cache(page, mapping, page->index, GFP_NOFS)) {
+               if (add_to_page_cache_lru(page, mapping, page->index, GFP_NOFS)) {
                        page_cache_release(page);
                        dout("readpages %p add_to_page_cache failed %p\n",
                             inode, page);
@@ -323,10 +320,8 @@ static int ceph_readpages(struct file *file, struct address_space *mapping,
                flush_dcache_page(page);
                SetPageUptodate(page);
                unlock_page(page);
-               if (pagevec_add(&pvec, page) == 0)
-                       pagevec_lru_add_file(&pvec);   /* add to lru */
+               page_cache_release(page);
        }
-       pagevec_lru_add_file(&pvec);
        rc = 0;
 
 out:
@@ -568,7 +563,7 @@ static void writepages_finish(struct ceph_osd_request *req,
        ceph_release_pages(req->r_pages, req->r_num_pages);
        if (req->r_pages_from_pool)
                mempool_free(req->r_pages,
-                            ceph_client(inode->i_sb)->wb_pagevec_pool);
+                            ceph_sb_to_client(inode->i_sb)->wb_pagevec_pool);
        else
                kfree(req->r_pages);
        ceph_osdc_put_request(req);
index 818afe72e6c75dd0c6ce36b55107a07f780be510..89490beaf5374a08bd933686fd6482c608d6d3a2 100644 (file)
@@ -1,7 +1,6 @@
 #include "ceph_debug.h"
 
 #include <linux/module.h>
-#include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/slab.h>
 
@@ -150,7 +149,8 @@ int ceph_build_auth_request(struct ceph_auth_client *ac,
 
        ret = ac->ops->build_request(ac, p + sizeof(u32), end);
        if (ret < 0) {
-               pr_err("error %d building request\n", ret);
+               pr_err("error %d building auth method %s request\n", ret,
+                      ac->ops->name);
                return ret;
        }
        dout(" built request %d bytes\n", ret);
@@ -229,7 +229,7 @@ int ceph_handle_auth_reply(struct ceph_auth_client *ac,
        if (ret == -EAGAIN) {
                return ceph_build_auth_request(ac, reply_buf, reply_len);
        } else if (ret) {
-               pr_err("authentication error %d\n", ret);
+               pr_err("auth method '%s' error %d\n", ac->ops->name, ret);
                return ret;
        }
        return 0;
@@ -246,7 +246,7 @@ int ceph_build_auth(struct ceph_auth_client *ac,
        if (!ac->protocol)
                return ceph_auth_build_hello(ac, msg_buf, msg_len);
        BUG_ON(!ac->ops);
-       if (!ac->ops->is_authenticated(ac))
+       if (ac->ops->should_authenticate(ac))
                return ceph_build_auth_request(ac, msg_buf, msg_len);
        return 0;
 }
index ca4f57cfb26776fc1fba826fb629bec2a060f45b..d38a2fb4a13762fc6e37578f840b166ee85efd16 100644 (file)
@@ -15,12 +15,20 @@ struct ceph_auth_client;
 struct ceph_authorizer;
 
 struct ceph_auth_client_ops {
+       const char *name;
+
        /*
         * true if we are authenticated and can connect to
         * services.
         */
        int (*is_authenticated)(struct ceph_auth_client *ac);
 
+       /*
+        * true if we should (re)authenticate, e.g., when our tickets
+        * are getting old and crusty.
+        */
+       int (*should_authenticate)(struct ceph_auth_client *ac);
+
        /*
         * build requests and process replies during monitor
         * handshake.  if handle_reply returns -EAGAIN, we build
index 8cd9e3af07f7f8df750b2a3ec5ad27a0fbe8ec96..ad1dc21286c7f3ca9c84d75d7a2630bc0069dae4 100644 (file)
@@ -31,6 +31,13 @@ static int is_authenticated(struct ceph_auth_client *ac)
        return !xi->starting;
 }
 
+static int should_authenticate(struct ceph_auth_client *ac)
+{
+       struct ceph_auth_none_info *xi = ac->private;
+
+       return xi->starting;
+}
+
 /*
  * the generic auth code decode the global_id, and we carry no actual
  * authenticate state, so nothing happens here.
@@ -94,9 +101,11 @@ static void ceph_auth_none_destroy_authorizer(struct ceph_auth_client *ac,
 }
 
 static const struct ceph_auth_client_ops ceph_auth_none_ops = {
+       .name = "none",
        .reset = reset,
        .destroy = destroy,
        .is_authenticated = is_authenticated,
+       .should_authenticate = should_authenticate,
        .handle_reply = handle_reply,
        .create_authorizer = ceph_auth_none_create_authorizer,
        .destroy_authorizer = ceph_auth_none_destroy_authorizer,
index fee5a08da8818d5abd7d3996e7bfb9e1e0e6e0bb..83d4d2785ffeba31db02a8fc374c146f62bcb201 100644 (file)
@@ -27,6 +27,17 @@ static int ceph_x_is_authenticated(struct ceph_auth_client *ac)
        return (ac->want_keys & xi->have_keys) == ac->want_keys;
 }
 
+static int ceph_x_should_authenticate(struct ceph_auth_client *ac)
+{
+       struct ceph_x_info *xi = ac->private;
+       int need;
+
+       ceph_x_validate_tickets(ac, &need);
+       dout("ceph_x_should_authenticate want=%d need=%d have=%d\n",
+            ac->want_keys, need, xi->have_keys);
+       return need != 0;
+}
+
 static int ceph_x_encrypt_buflen(int ilen)
 {
        return sizeof(struct ceph_x_encrypt_header) + ilen + 16 +
@@ -127,7 +138,7 @@ static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac,
        int ret;
        char *dbuf;
        char *ticket_buf;
-       u8 struct_v;
+       u8 reply_struct_v;
 
        dbuf = kmalloc(TEMP_TICKET_BUF_LEN, GFP_NOFS);
        if (!dbuf)
@@ -139,14 +150,14 @@ static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac,
                goto out_dbuf;
 
        ceph_decode_need(&p, end, 1 + sizeof(u32), bad);
-       struct_v = ceph_decode_8(&p);
-       if (struct_v != 1)
+       reply_struct_v = ceph_decode_8(&p);
+       if (reply_struct_v != 1)
                goto bad;
        num = ceph_decode_32(&p);
        dout("%d tickets\n", num);
        while (num--) {
                int type;
-               u8 struct_v;
+               u8 tkt_struct_v, blob_struct_v;
                struct ceph_x_ticket_handler *th;
                void *dp, *dend;
                int dlen;
@@ -165,8 +176,8 @@ static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac,
                type = ceph_decode_32(&p);
                dout(" ticket type %d %s\n", type, ceph_entity_type_name(type));
 
-               struct_v = ceph_decode_8(&p);
-               if (struct_v != 1)
+               tkt_struct_v = ceph_decode_8(&p);
+               if (tkt_struct_v != 1)
                        goto bad;
 
                th = get_ticket_handler(ac, type);
@@ -186,8 +197,8 @@ static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac,
                dend = dbuf + dlen;
                dp = dbuf;
 
-               struct_v = ceph_decode_8(&dp);
-               if (struct_v != 1)
+               tkt_struct_v = ceph_decode_8(&dp);
+               if (tkt_struct_v != 1)
                        goto bad;
 
                memcpy(&old_key, &th->session_key, sizeof(old_key));
@@ -224,7 +235,7 @@ static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac,
                tpend = tp + dlen;
                dout(" ticket blob is %d bytes\n", dlen);
                ceph_decode_need(&tp, tpend, 1 + sizeof(u64), bad);
-               struct_v = ceph_decode_8(&tp);
+               blob_struct_v = ceph_decode_8(&tp);
                new_secret_id = ceph_decode_64(&tp);
                ret = ceph_decode_buffer(&new_ticket_blob, &tp, tpend);
                if (ret)
@@ -618,7 +629,9 @@ static void ceph_x_invalidate_authorizer(struct ceph_auth_client *ac,
 
 
 static const struct ceph_auth_client_ops ceph_x_ops = {
+       .name = "x",
        .is_authenticated = ceph_x_is_authenticated,
+       .should_authenticate = ceph_x_should_authenticate,
        .build_request = ceph_x_build_request,
        .handle_reply = ceph_x_handle_reply,
        .create_authorizer = ceph_x_create_authorizer,
index d9400534b2790158e072a547d652876f35079f9c..ae3e3a3064451f7b49fedaa3931120ff1af6d169 100644 (file)
@@ -867,7 +867,8 @@ void __ceph_remove_cap(struct ceph_cap *cap)
 {
        struct ceph_mds_session *session = cap->session;
        struct ceph_inode_info *ci = cap->ci;
-       struct ceph_mds_client *mdsc = &ceph_client(ci->vfs_inode.i_sb)->mdsc;
+       struct ceph_mds_client *mdsc =
+               &ceph_sb_to_client(ci->vfs_inode.i_sb)->mdsc;
        int removed = 0;
 
        dout("__ceph_remove_cap %p from %p\n", cap, &ci->vfs_inode);
@@ -937,9 +938,9 @@ static int send_cap_msg(struct ceph_mds_session *session,
             seq, issue_seq, mseq, follows, size, max_size,
             xattr_version, xattrs_buf ? (int)xattrs_buf->vec.iov_len : 0);
 
-       msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPS, sizeof(*fc), 0, 0, NULL);
-       if (IS_ERR(msg))
-               return PTR_ERR(msg);
+       msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPS, sizeof(*fc), GFP_NOFS);
+       if (!msg)
+               return -ENOMEM;
 
        msg->hdr.tid = cpu_to_le64(flush_tid);
 
@@ -1298,7 +1299,8 @@ static void ceph_flush_snaps(struct ceph_inode_info *ci)
  */
 void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask)
 {
-       struct ceph_mds_client *mdsc = &ceph_client(ci->vfs_inode.i_sb)->mdsc;
+       struct ceph_mds_client *mdsc =
+               &ceph_sb_to_client(ci->vfs_inode.i_sb)->mdsc;
        struct inode *inode = &ci->vfs_inode;
        int was = ci->i_dirty_caps;
        int dirty = 0;
@@ -1336,7 +1338,7 @@ void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask)
 static int __mark_caps_flushing(struct inode *inode,
                                 struct ceph_mds_session *session)
 {
-       struct ceph_mds_client *mdsc = &ceph_client(inode->i_sb)->mdsc;
+       struct ceph_mds_client *mdsc = &ceph_sb_to_client(inode->i_sb)->mdsc;
        struct ceph_inode_info *ci = ceph_inode(inode);
        int flushing;
 
@@ -1663,7 +1665,7 @@ ack:
 static int try_flush_caps(struct inode *inode, struct ceph_mds_session *session,
                          unsigned *flush_tid)
 {
-       struct ceph_mds_client *mdsc = &ceph_client(inode->i_sb)->mdsc;
+       struct ceph_mds_client *mdsc = &ceph_sb_to_client(inode->i_sb)->mdsc;
        struct ceph_inode_info *ci = ceph_inode(inode);
        int unlock_session = session ? 0 : 1;
        int flushing = 0;
@@ -1716,10 +1718,9 @@ out_unlocked:
 static int caps_are_flushed(struct inode *inode, unsigned tid)
 {
        struct ceph_inode_info *ci = ceph_inode(inode);
-       int dirty, i, ret = 1;
+       int i, ret = 1;
 
        spin_lock(&inode->i_lock);
-       dirty = __ceph_caps_dirty(ci);
        for (i = 0; i < CEPH_CAP_BITS; i++)
                if ((ci->i_flushing_caps & (1 << i)) &&
                    ci->i_cap_flush_tid[i] <= tid) {
@@ -1775,9 +1776,9 @@ out:
        spin_unlock(&ci->i_unsafe_lock);
 }
 
-int ceph_fsync(struct file *file, struct dentry *dentry, int datasync)
+int ceph_fsync(struct file *file, int datasync)
 {
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = file->f_mapping->host;
        struct ceph_inode_info *ci = ceph_inode(inode);
        unsigned flush_tid;
        int ret;
@@ -1829,7 +1830,8 @@ int ceph_write_inode(struct inode *inode, struct writeback_control *wbc)
                        err = wait_event_interruptible(ci->i_cap_wq,
                                       caps_are_flushed(inode, flush_tid));
        } else {
-               struct ceph_mds_client *mdsc = &ceph_client(inode->i_sb)->mdsc;
+               struct ceph_mds_client *mdsc =
+                       &ceph_sb_to_client(inode->i_sb)->mdsc;
 
                spin_lock(&inode->i_lock);
                if (__ceph_caps_dirty(ci))
@@ -2411,7 +2413,7 @@ static void handle_cap_flush_ack(struct inode *inode, u64 flush_tid,
        __releases(inode->i_lock)
 {
        struct ceph_inode_info *ci = ceph_inode(inode);
-       struct ceph_mds_client *mdsc = &ceph_client(inode->i_sb)->mdsc;
+       struct ceph_mds_client *mdsc = &ceph_sb_to_client(inode->i_sb)->mdsc;
        unsigned seq = le32_to_cpu(m->seq);
        int dirty = le32_to_cpu(m->dirty);
        int cleaned = 0;
index 0c2241ef3653242657fc56a8c9cd7c49ea89af7b..2fa992eaf7daae57217ab5e7f8b2f228299fc101 100644 (file)
@@ -19,7 +19,7 @@
  * Ceph release version
  */
 #define CEPH_VERSION_MAJOR 0
-#define CEPH_VERSION_MINOR 19
+#define CEPH_VERSION_MINOR 20
 #define CEPH_VERSION_PATCH 0
 
 #define _CEPH_STRINGIFY(x) #x
@@ -36,7 +36,7 @@
  * client-facing protocol.
  */
 #define CEPH_OSD_PROTOCOL     8 /* cluster internal */
-#define CEPH_MDS_PROTOCOL     9 /* cluster internal */
+#define CEPH_MDS_PROTOCOL    12 /* cluster internal */
 #define CEPH_MON_PROTOCOL     5 /* cluster internal */
 #define CEPH_OSDC_PROTOCOL   24 /* server/client */
 #define CEPH_MDSC_PROTOCOL   32 /* server/client */
 /*
  * feature bits
  */
-#define CEPH_FEATURE_SUPPORTED  0
-#define CEPH_FEATURE_REQUIRED   0
+#define CEPH_FEATURE_UID        1
+#define CEPH_FEATURE_NOSRCADDR  2
+#define CEPH_FEATURE_FLOCK      4
+
+#define CEPH_FEATURE_SUPPORTED_MON  CEPH_FEATURE_UID|CEPH_FEATURE_NOSRCADDR
+#define CEPH_FEATURE_REQUIRED_MON   CEPH_FEATURE_UID
+#define CEPH_FEATURE_SUPPORTED_MDS  CEPH_FEATURE_UID|CEPH_FEATURE_NOSRCADDR|CEPH_FEATURE_FLOCK
+#define CEPH_FEATURE_REQUIRED_MDS   CEPH_FEATURE_UID
+#define CEPH_FEATURE_SUPPORTED_OSD  CEPH_FEATURE_UID|CEPH_FEATURE_NOSRCADDR
+#define CEPH_FEATURE_REQUIRED_OSD   CEPH_FEATURE_UID
+#define CEPH_FEATURE_SUPPORTED_CLIENT CEPH_FEATURE_NOSRCADDR
+#define CEPH_FEATURE_REQUIRED_CLIENT CEPH_FEATURE_NOSRCADDR
 
 
 /*
@@ -91,6 +101,8 @@ int ceph_file_layout_is_valid(const struct ceph_file_layout *layout);
 #define CEPH_AUTH_NONE         0x1
 #define CEPH_AUTH_CEPHX                0x2
 
+#define CEPH_AUTH_UID_DEFAULT ((__u64) -1)
+
 
 /*********************************************
  * message layer
@@ -128,11 +140,27 @@ int ceph_file_layout_is_valid(const struct ceph_file_layout *layout);
 #define CEPH_MSG_CLIENT_SNAP            0x312
 #define CEPH_MSG_CLIENT_CAPRELEASE      0x313
 
+/* pool ops */
+#define CEPH_MSG_POOLOP_REPLY           48
+#define CEPH_MSG_POOLOP                 49
+
+
 /* osd */
 #define CEPH_MSG_OSD_MAP          41
 #define CEPH_MSG_OSD_OP           42
 #define CEPH_MSG_OSD_OPREPLY      43
 
+/* pool operations */
+enum {
+  POOL_OP_CREATE                       = 0x01,
+  POOL_OP_DELETE                       = 0x02,
+  POOL_OP_AUID_CHANGE                  = 0x03,
+  POOL_OP_CREATE_SNAP                  = 0x11,
+  POOL_OP_DELETE_SNAP                  = 0x12,
+  POOL_OP_CREATE_UNMANAGED_SNAP                = 0x21,
+  POOL_OP_DELETE_UNMANAGED_SNAP                = 0x22,
+};
+
 struct ceph_mon_request_header {
        __le64 have_version;
        __le16 session_mon;
@@ -155,6 +183,31 @@ struct ceph_mon_statfs_reply {
        struct ceph_statfs st;
 } __attribute__ ((packed));
 
+const char *ceph_pool_op_name(int op);
+
+struct ceph_mon_poolop {
+       struct ceph_mon_request_header monhdr;
+       struct ceph_fsid fsid;
+       __le32 pool;
+       __le32 op;
+       __le64 auid;
+       __le64 snapid;
+       __le32 name_len;
+} __attribute__ ((packed));
+
+struct ceph_mon_poolop_reply {
+       struct ceph_mon_request_header monhdr;
+       struct ceph_fsid fsid;
+       __le32 reply_code;
+       __le32 epoch;
+       char has_data;
+       char data[0];
+} __attribute__ ((packed));
+
+struct ceph_mon_unmanaged_snap {
+       __le64 snapid;
+} __attribute__ ((packed));
+
 struct ceph_osd_getmap {
        struct ceph_mon_request_header monhdr;
        struct ceph_fsid fsid;
@@ -212,16 +265,17 @@ extern const char *ceph_mds_state_name(int s);
  *  - they also define the lock ordering by the MDS
  *  - a few of these are internal to the mds
  */
-#define CEPH_LOCK_DN          1
-#define CEPH_LOCK_ISNAP       2
-#define CEPH_LOCK_IVERSION    4     /* mds internal */
-#define CEPH_LOCK_IFILE       8     /* mds internal */
-#define CEPH_LOCK_IAUTH       32
-#define CEPH_LOCK_ILINK       64
-#define CEPH_LOCK_IDFT        128   /* dir frag tree */
-#define CEPH_LOCK_INEST       256   /* mds internal */
-#define CEPH_LOCK_IXATTR      512
-#define CEPH_LOCK_INO         2048  /* immutable inode bits; not a lock */
+#define CEPH_LOCK_DVERSION    1
+#define CEPH_LOCK_DN          2
+#define CEPH_LOCK_ISNAP       16
+#define CEPH_LOCK_IVERSION    32    /* mds internal */
+#define CEPH_LOCK_IFILE       64
+#define CEPH_LOCK_IAUTH       128
+#define CEPH_LOCK_ILINK       256
+#define CEPH_LOCK_IDFT        512   /* dir frag tree */
+#define CEPH_LOCK_INEST       1024  /* mds internal */
+#define CEPH_LOCK_IXATTR      2048
+#define CEPH_LOCK_INO         8192  /* immutable inode bits; not a lock */
 
 /* client_session ops */
 enum {
@@ -308,6 +362,7 @@ union ceph_mds_request_args {
        struct {
                __le32 frag;                 /* which dir fragment */
                __le32 max_entries;          /* how many dentries to grab */
+               __le32 max_bytes;
        } __attribute__ ((packed)) readdir;
        struct {
                __le32 mode;
index 8e4be6a80c62a0466c3758a25e5367493f54bd77..7503aee828cef9156e3a875f91e9b87e132911b9 100644 (file)
@@ -10,7 +10,6 @@ const char *ceph_entity_type_name(int type)
        case CEPH_ENTITY_TYPE_OSD: return "osd";
        case CEPH_ENTITY_TYPE_MON: return "mon";
        case CEPH_ENTITY_TYPE_CLIENT: return "client";
-       case CEPH_ENTITY_TYPE_ADMIN: return "admin";
        case CEPH_ENTITY_TYPE_AUTH: return "auth";
        default: return "unknown";
        }
@@ -45,6 +44,7 @@ const char *ceph_osd_op_name(int op)
        case CEPH_OSD_OP_SETXATTRS: return "setxattrs";
        case CEPH_OSD_OP_RESETXATTRS: return "resetxattrs";
        case CEPH_OSD_OP_RMXATTR: return "rmxattr";
+       case CEPH_OSD_OP_CMPXATTR: return "cmpxattr";
 
        case CEPH_OSD_OP_PULL: return "pull";
        case CEPH_OSD_OP_PUSH: return "push";
@@ -174,3 +174,17 @@ const char *ceph_snap_op_name(int o)
        }
        return "???";
 }
+
+const char *ceph_pool_op_name(int op)
+{
+       switch (op) {
+       case POOL_OP_CREATE: return "create";
+       case POOL_OP_DELETE: return "delete";
+       case POOL_OP_AUID_CHANGE: return "auid change";
+       case POOL_OP_CREATE_SNAP: return "create snap";
+       case POOL_OP_DELETE_SNAP: return "delete snap";
+       case POOL_OP_CREATE_UNMANAGED_SNAP: return "create unmanaged snap";
+       case POOL_OP_DELETE_UNMANAGED_SNAP: return "delete unmanaged snap";
+       }
+       return "???";
+}
index f7048da92acc58a9479657ad933e4a99b5199fa3..3be33fb066cc5f1ada8be5ebb50115c5dc9c9a7e 100644 (file)
@@ -113,7 +113,7 @@ static int osdmap_show(struct seq_file *s, void *p)
 static int monc_show(struct seq_file *s, void *p)
 {
        struct ceph_client *client = s->private;
-       struct ceph_mon_statfs_request *req;
+       struct ceph_mon_generic_request *req;
        struct ceph_mon_client *monc = &client->monc;
        struct rb_node *rp;
 
@@ -126,9 +126,14 @@ static int monc_show(struct seq_file *s, void *p)
        if (monc->want_next_osdmap)
                seq_printf(s, "want next osdmap\n");
 
-       for (rp = rb_first(&monc->statfs_request_tree); rp; rp = rb_next(rp)) {
-               req = rb_entry(rp, struct ceph_mon_statfs_request, node);
-               seq_printf(s, "%lld statfs\n", req->tid);
+       for (rp = rb_first(&monc->generic_request_tree); rp; rp = rb_next(rp)) {
+               __u16 op;
+               req = rb_entry(rp, struct ceph_mon_generic_request, node);
+               op = le16_to_cpu(req->request->hdr.type);
+               if (op == CEPH_MSG_STATFS)
+                       seq_printf(s, "%lld statfs\n", req->tid);
+               else
+                       seq_printf(s, "%lld unknown\n", req->tid);
        }
 
        mutex_unlock(&monc->mutex);
index 650d2db5ed26a48923266fd2bc836d92e4edf1f1..f85719310db2f7aa48d15dee2b3b278e5e8375e0 100644 (file)
@@ -51,8 +51,11 @@ int ceph_init_dentry(struct dentry *dentry)
                return -ENOMEM;          /* oh well */
 
        spin_lock(&dentry->d_lock);
-       if (dentry->d_fsdata) /* lost a race */
+       if (dentry->d_fsdata) {
+               /* lost a race */
+               kmem_cache_free(ceph_dentry_cachep, di);
                goto out_unlock;
+       }
        di->dentry = dentry;
        di->lease_session = NULL;
        dentry->d_fsdata = di;
@@ -125,7 +128,8 @@ more:
        dentry = list_entry(p, struct dentry, d_u.d_child);
        di = ceph_dentry(dentry);
        while (1) {
-               dout(" p %p/%p d_subdirs %p/%p\n", p->prev, p->next,
+               dout(" p %p/%p %s d_subdirs %p/%p\n", p->prev, p->next,
+                    d_unhashed(dentry) ? "!hashed" : "hashed",
                     parent->d_subdirs.prev, parent->d_subdirs.next);
                if (p == &parent->d_subdirs) {
                        fi->at_end = 1;
@@ -229,6 +233,7 @@ static int ceph_readdir(struct file *filp, void *dirent, filldir_t filldir)
        u32 ftype;
        struct ceph_mds_reply_info_parsed *rinfo;
        const int max_entries = client->mount_args->max_readdir;
+       const int max_bytes = client->mount_args->max_readdir_bytes;
 
        dout("readdir %p filp %p frag %u off %u\n", inode, filp, frag, off);
        if (fi->at_end)
@@ -312,6 +317,7 @@ more:
                req->r_readdir_offset = fi->next_offset;
                req->r_args.readdir.frag = cpu_to_le32(frag);
                req->r_args.readdir.max_entries = cpu_to_le32(max_entries);
+               req->r_args.readdir.max_bytes = cpu_to_le32(max_bytes);
                req->r_num_caps = max_entries + 1;
                err = ceph_mdsc_do_request(mdsc, NULL, req);
                if (err < 0) {
@@ -335,7 +341,7 @@ more:
                if (req->r_reply_info.dir_end) {
                        kfree(fi->last_name);
                        fi->last_name = NULL;
-                       fi->next_offset = 0;
+                       fi->next_offset = 2;
                } else {
                        rinfo = &req->r_reply_info;
                        err = note_last_dentry(fi,
@@ -478,7 +484,7 @@ static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int origin)
 struct dentry *ceph_finish_lookup(struct ceph_mds_request *req,
                                  struct dentry *dentry, int err)
 {
-       struct ceph_client *client = ceph_client(dentry->d_sb);
+       struct ceph_client *client = ceph_sb_to_client(dentry->d_sb);
        struct inode *parent = dentry->d_parent->d_inode;
 
        /* .snap dir? */
@@ -568,7 +574,6 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
                    !is_root_ceph_dentry(dir, dentry) &&
                    (ci->i_ceph_flags & CEPH_I_COMPLETE) &&
                    (__ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1))) {
-                       di->offset = ci->i_max_offset++;
                        spin_unlock(&dir->i_lock);
                        dout(" dir %p complete, -ENOENT\n", dir);
                        d_add(dentry, NULL);
@@ -582,7 +587,7 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
                CEPH_MDS_OP_LOOKUPSNAP : CEPH_MDS_OP_LOOKUP;
        req = ceph_mdsc_create_request(mdsc, op, USE_ANY_MDS);
        if (IS_ERR(req))
-               return ERR_PTR(PTR_ERR(req));
+               return ERR_CAST(req);
        req->r_dentry = dget(dentry);
        req->r_num_caps = 2;
        /* we only need inode linkage */
@@ -888,13 +893,22 @@ static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry,
 
                /* ensure target dentry is invalidated, despite
                   rehashing bug in vfs_rename_dir */
-               new_dentry->d_time = jiffies;
-               ceph_dentry(new_dentry)->lease_shared_gen = 0;
+               ceph_invalidate_dentry_lease(new_dentry);
        }
        ceph_mdsc_put_request(req);
        return err;
 }
 
+/*
+ * Ensure a dentry lease will no longer revalidate.
+ */
+void ceph_invalidate_dentry_lease(struct dentry *dentry)
+{
+       spin_lock(&dentry->d_lock);
+       dentry->d_time = jiffies;
+       ceph_dentry(dentry)->lease_shared_gen = 0;
+       spin_unlock(&dentry->d_lock);
+}
 
 /*
  * Check if dentry lease is valid.  If not, delete the lease.  Try to
@@ -972,8 +986,9 @@ static int ceph_d_revalidate(struct dentry *dentry, struct nameidata *nd)
 {
        struct inode *dir = dentry->d_parent->d_inode;
 
-       dout("d_revalidate %p '%.*s' inode %p\n", dentry,
-            dentry->d_name.len, dentry->d_name.name, dentry->d_inode);
+       dout("d_revalidate %p '%.*s' inode %p offset %lld\n", dentry,
+            dentry->d_name.len, dentry->d_name.name, dentry->d_inode,
+            ceph_dentry(dentry)->offset);
 
        /* always trust cached snapped dentries, snapdir dentry */
        if (ceph_snap(dir) != CEPH_NOSNAP) {
@@ -1050,7 +1065,7 @@ static ssize_t ceph_read_dir(struct file *file, char __user *buf, size_t size,
        struct ceph_inode_info *ci = ceph_inode(inode);
        int left;
 
-       if (!ceph_test_opt(ceph_client(inode->i_sb), DIRSTAT))
+       if (!ceph_test_opt(ceph_sb_to_client(inode->i_sb), DIRSTAT))
                return -EISDIR;
 
        if (!cf->dir_info) {
@@ -1092,10 +1107,9 @@ static ssize_t ceph_read_dir(struct file *file, char __user *buf, size_t size,
  * an fsync() on a dir will wait for any uncommitted directory
  * operations to commit.
  */
-static int ceph_dir_fsync(struct file *file, struct dentry *dentry,
-                         int datasync)
+static int ceph_dir_fsync(struct file *file, int datasync)
 {
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = file->f_path.dentry->d_inode;
        struct ceph_inode_info *ci = ceph_inode(inode);
        struct list_head *head = &ci->i_unsafe_dirops;
        struct ceph_mds_request *req;
@@ -1152,7 +1166,7 @@ void ceph_dentry_lru_add(struct dentry *dn)
        dout("dentry_lru_add %p %p '%.*s'\n", di, dn,
             dn->d_name.len, dn->d_name.name);
        if (di) {
-               mdsc = &ceph_client(dn->d_sb)->mdsc;
+               mdsc = &ceph_sb_to_client(dn->d_sb)->mdsc;
                spin_lock(&mdsc->dentry_lru_lock);
                list_add_tail(&di->lru, &mdsc->dentry_lru);
                mdsc->num_dentry++;
@@ -1165,10 +1179,10 @@ void ceph_dentry_lru_touch(struct dentry *dn)
        struct ceph_dentry_info *di = ceph_dentry(dn);
        struct ceph_mds_client *mdsc;
 
-       dout("dentry_lru_touch %p %p '%.*s'\n", di, dn,
-            dn->d_name.len, dn->d_name.name);
+       dout("dentry_lru_touch %p %p '%.*s' (offset %lld)\n", di, dn,
+            dn->d_name.len, dn->d_name.name, di->offset);
        if (di) {
-               mdsc = &ceph_client(dn->d_sb)->mdsc;
+               mdsc = &ceph_sb_to_client(dn->d_sb)->mdsc;
                spin_lock(&mdsc->dentry_lru_lock);
                list_move_tail(&di->lru, &mdsc->dentry_lru);
                spin_unlock(&mdsc->dentry_lru_lock);
@@ -1183,7 +1197,7 @@ void ceph_dentry_lru_del(struct dentry *dn)
        dout("dentry_lru_del %p %p '%.*s'\n", di, dn,
             dn->d_name.len, dn->d_name.name);
        if (di) {
-               mdsc = &ceph_client(dn->d_sb)->mdsc;
+               mdsc = &ceph_sb_to_client(dn->d_sb)->mdsc;
                spin_lock(&mdsc->dentry_lru_lock);
                list_del_init(&di->lru);
                mdsc->num_dentry--;
index 9d67572fb3285490eefbf8d8b12b3aafaddcb224..4480cb1c63e7c69b107628481388cf1e35f49b8d 100644 (file)
@@ -93,11 +93,11 @@ static struct dentry *__fh_to_dentry(struct super_block *sb,
                return ERR_PTR(-ESTALE);
 
        dentry = d_obtain_alias(inode);
-       if (!dentry) {
+       if (IS_ERR(dentry)) {
                pr_err("fh_to_dentry %llx -- inode %p but ENOMEM\n",
                       fh->ino, inode);
                iput(inode);
-               return ERR_PTR(-ENOMEM);
+               return dentry;
        }
        err = ceph_init_dentry(dentry);
 
@@ -115,7 +115,7 @@ static struct dentry *__fh_to_dentry(struct super_block *sb,
 static struct dentry *__cfh_to_dentry(struct super_block *sb,
                                      struct ceph_nfs_confh *cfh)
 {
-       struct ceph_mds_client *mdsc = &ceph_client(sb)->mdsc;
+       struct ceph_mds_client *mdsc = &ceph_sb_to_client(sb)->mdsc;
        struct inode *inode;
        struct dentry *dentry;
        struct ceph_vino vino;
@@ -133,7 +133,7 @@ static struct dentry *__cfh_to_dentry(struct super_block *sb,
                req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPHASH,
                                               USE_ANY_MDS);
                if (IS_ERR(req))
-                       return ERR_PTR(PTR_ERR(req));
+                       return ERR_CAST(req);
 
                req->r_ino1 = vino;
                req->r_ino2.ino = cfh->parent_ino;
@@ -149,11 +149,11 @@ static struct dentry *__cfh_to_dentry(struct super_block *sb,
        }
 
        dentry = d_obtain_alias(inode);
-       if (!dentry) {
+       if (IS_ERR(dentry)) {
                pr_err("cfh_to_dentry %llx -- inode %p but ENOMEM\n",
                       cfh->ino, inode);
                iput(inode);
-               return ERR_PTR(-ENOMEM);
+               return dentry;
        }
        err = ceph_init_dentry(dentry);
        if (err < 0) {
@@ -202,11 +202,11 @@ static struct dentry *ceph_fh_to_parent(struct super_block *sb,
                return ERR_PTR(-ESTALE);
 
        dentry = d_obtain_alias(inode);
-       if (!dentry) {
+       if (IS_ERR(dentry)) {
                pr_err("fh_to_parent %llx -- inode %p but ENOMEM\n",
                       cfh->ino, inode);
                iput(inode);
-               return ERR_PTR(-ENOMEM);
+               return dentry;
        }
        err = ceph_init_dentry(dentry);
        if (err < 0) {
index ed6f19721d6e56d661ac7f11fe2aac04ba18e1a5..6251a1574b9473b7e267c987cd6f9613e49eb57f 100644 (file)
@@ -230,7 +230,7 @@ struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry,
        /* do the open */
        req = prepare_open_request(dir->i_sb, flags, mode);
        if (IS_ERR(req))
-               return ERR_PTR(PTR_ERR(req));
+               return ERR_CAST(req);
        req->r_dentry = dget(dentry);
        req->r_num_caps = 2;
        if (flags & O_CREAT) {
@@ -317,16 +317,16 @@ void ceph_release_page_vector(struct page **pages, int num_pages)
 /*
  * allocate a vector new pages
  */
-static struct page **alloc_page_vector(int num_pages)
+struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags)
 {
        struct page **pages;
        int i;
 
-       pages = kmalloc(sizeof(*pages) * num_pages, GFP_NOFS);
+       pages = kmalloc(sizeof(*pages) * num_pages, flags);
        if (!pages)
                return ERR_PTR(-ENOMEM);
        for (i = 0; i < num_pages; i++) {
-               pages[i] = alloc_page(GFP_NOFS);
+               pages[i] = __page_cache_alloc(flags);
                if (pages[i] == NULL) {
                        ceph_release_page_vector(pages, i);
                        return ERR_PTR(-ENOMEM);
@@ -540,7 +540,7 @@ static ssize_t ceph_sync_read(struct file *file, char __user *data,
                 * in sequence.
                 */
        } else {
-               pages = alloc_page_vector(num_pages);
+               pages = ceph_alloc_page_vector(num_pages, GFP_NOFS);
        }
        if (IS_ERR(pages))
                return PTR_ERR(pages);
@@ -649,8 +649,8 @@ more:
                                    do_sync,
                                    ci->i_truncate_seq, ci->i_truncate_size,
                                    &mtime, false, 2);
-       if (IS_ERR(req))
-               return PTR_ERR(req);
+       if (!req)
+               return -ENOMEM;
 
        num_pages = calc_pages_for(pos, len);
 
@@ -668,7 +668,7 @@ more:
                truncate_inode_pages_range(inode->i_mapping, pos, 
                                           (pos+len) | (PAGE_CACHE_SIZE-1));
        } else {
-               pages = alloc_page_vector(num_pages);
+               pages = ceph_alloc_page_vector(num_pages, GFP_NOFS);
                if (IS_ERR(pages)) {
                        ret = PTR_ERR(pages);
                        goto out;
@@ -809,7 +809,7 @@ static ssize_t ceph_aio_write(struct kiocb *iocb, const struct iovec *iov,
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_dentry->d_inode;
        struct ceph_inode_info *ci = ceph_inode(inode);
-       struct ceph_osd_client *osdc = &ceph_client(inode->i_sb)->osdc;
+       struct ceph_osd_client *osdc = &ceph_sb_to_client(inode->i_sb)->osdc;
        loff_t endoff = pos + iov->iov_len;
        int got = 0;
        int ret, err;
@@ -844,8 +844,7 @@ retry_snap:
                if ((ret >= 0 || ret == -EIOCBQUEUED) &&
                    ((file->f_flags & O_SYNC) || IS_SYNC(file->f_mapping->host)
                     || ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_NEARFULL))) {
-                       err = vfs_fsync_range(file, file->f_path.dentry,
-                                             pos, pos + ret - 1, 1);
+                       err = vfs_fsync_range(file, pos, pos + ret - 1, 1);
                        if (err < 0)
                                ret = err;
                }
index 85b4d2ffdeba933da4ac816663a04c3c9ed91924..226f5a50d36294163e44de833c6949967c04348d 100644 (file)
@@ -69,7 +69,7 @@ struct inode *ceph_get_snapdir(struct inode *parent)
 
        BUG_ON(!S_ISDIR(parent->i_mode));
        if (IS_ERR(inode))
-               return ERR_PTR(PTR_ERR(inode));
+               return inode;
        inode->i_mode = parent->i_mode;
        inode->i_uid = parent->i_uid;
        inode->i_gid = parent->i_gid;
@@ -384,7 +384,7 @@ void ceph_destroy_inode(struct inode *inode)
         */
        if (ci->i_snap_realm) {
                struct ceph_mds_client *mdsc =
-                       &ceph_client(ci->vfs_inode.i_sb)->mdsc;
+                       &ceph_sb_to_client(ci->vfs_inode.i_sb)->mdsc;
                struct ceph_snap_realm *realm = ci->i_snap_realm;
 
                dout(" dropping residual ref to snap realm %p\n", realm);
@@ -619,11 +619,12 @@ static int fill_inode(struct inode *inode,
                        memcpy(ci->i_xattrs.blob->vec.iov_base,
                               iinfo->xattr_data, iinfo->xattr_len);
                ci->i_xattrs.version = le64_to_cpu(info->xattr_version);
+               xattr_blob = NULL;
        }
 
        inode->i_mapping->a_ops = &ceph_aops;
        inode->i_mapping->backing_dev_info =
-               &ceph_client(inode->i_sb)->backing_dev_info;
+               &ceph_sb_to_client(inode->i_sb)->backing_dev_info;
 
        switch (inode->i_mode & S_IFMT) {
        case S_IFIFO:
@@ -674,14 +675,15 @@ static int fill_inode(struct inode *inode,
                /* set dir completion flag? */
                if (ci->i_files == 0 && ci->i_subdirs == 0 &&
                    ceph_snap(inode) == CEPH_NOSNAP &&
-                   (le32_to_cpu(info->cap.caps) & CEPH_CAP_FILE_SHARED)) {
+                   (le32_to_cpu(info->cap.caps) & CEPH_CAP_FILE_SHARED) &&
+                   (ci->i_ceph_flags & CEPH_I_COMPLETE) == 0) {
                        dout(" marking %p complete (empty)\n", inode);
                        ci->i_ceph_flags |= CEPH_I_COMPLETE;
                        ci->i_max_offset = 2;
                }
 
                /* it may be better to set st_size in getattr instead? */
-               if (ceph_test_opt(ceph_client(inode->i_sb), RBYTES))
+               if (ceph_test_opt(ceph_sb_to_client(inode->i_sb), RBYTES))
                        inode->i_size = ci->i_rbytes;
                break;
        default:
@@ -801,6 +803,37 @@ out_unlock:
        return;
 }
 
+/*
+ * Set dentry's directory position based on the current dir's max, and
+ * order it in d_subdirs, so that dcache_readdir behaves.
+ */
+static void ceph_set_dentry_offset(struct dentry *dn)
+{
+       struct dentry *dir = dn->d_parent;
+       struct inode *inode = dn->d_parent->d_inode;
+       struct ceph_dentry_info *di;
+
+       BUG_ON(!inode);
+
+       di = ceph_dentry(dn);
+
+       spin_lock(&inode->i_lock);
+       if ((ceph_inode(inode)->i_ceph_flags & CEPH_I_COMPLETE) == 0) {
+               spin_unlock(&inode->i_lock);
+               return;
+       }
+       di->offset = ceph_inode(inode)->i_max_offset++;
+       spin_unlock(&inode->i_lock);
+
+       spin_lock(&dcache_lock);
+       spin_lock(&dn->d_lock);
+       list_move_tail(&dir->d_subdirs, &dn->d_u.d_child);
+       dout("set_dentry_offset %p %lld (%p %p)\n", dn, di->offset,
+            dn->d_u.d_child.prev, dn->d_u.d_child.next);
+       spin_unlock(&dn->d_lock);
+       spin_unlock(&dcache_lock);
+}
+
 /*
  * splice a dentry to an inode.
  * caller must hold directory i_mutex for this to be safe.
@@ -814,6 +847,8 @@ static struct dentry *splice_dentry(struct dentry *dn, struct inode *in,
 {
        struct dentry *realdn;
 
+       BUG_ON(dn->d_inode);
+
        /* dn must be unhashed */
        if (!d_unhashed(dn))
                d_drop(dn);
@@ -835,43 +870,16 @@ static struct dentry *splice_dentry(struct dentry *dn, struct inode *in,
                dn = realdn;
        } else {
                BUG_ON(!ceph_dentry(dn));
-
                dout("dn %p attached to %p ino %llx.%llx\n",
                     dn, dn->d_inode, ceph_vinop(dn->d_inode));
        }
        if ((!prehash || *prehash) && d_unhashed(dn))
                d_rehash(dn);
+       ceph_set_dentry_offset(dn);
 out:
        return dn;
 }
 
-/*
- * Set dentry's directory position based on the current dir's max, and
- * order it in d_subdirs, so that dcache_readdir behaves.
- */
-static void ceph_set_dentry_offset(struct dentry *dn)
-{
-       struct dentry *dir = dn->d_parent;
-       struct inode *inode = dn->d_parent->d_inode;
-       struct ceph_dentry_info *di;
-
-       BUG_ON(!inode);
-
-       di = ceph_dentry(dn);
-
-       spin_lock(&inode->i_lock);
-       di->offset = ceph_inode(inode)->i_max_offset++;
-       spin_unlock(&inode->i_lock);
-
-       spin_lock(&dcache_lock);
-       spin_lock(&dn->d_lock);
-       list_move_tail(&dir->d_subdirs, &dn->d_u.d_child);
-       dout("set_dentry_offset %p %lld (%p %p)\n", dn, di->offset,
-            dn->d_u.d_child.prev, dn->d_u.d_child.next);
-       spin_unlock(&dn->d_lock);
-       spin_unlock(&dcache_lock);
-}
-
 /*
  * Incorporate results into the local cache.  This is either just
  * one inode, or a directory, dentry, and possibly linked-to inode (e.g.,
@@ -933,14 +941,8 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
 
        if (!rinfo->head->is_target && !rinfo->head->is_dentry) {
                dout("fill_trace reply is empty!\n");
-               if (rinfo->head->result == 0 && req->r_locked_dir) {
-                       struct ceph_inode_info *ci =
-                               ceph_inode(req->r_locked_dir);
-                       dout(" clearing %p complete (empty trace)\n",
-                            req->r_locked_dir);
-                       ci->i_ceph_flags &= ~CEPH_I_COMPLETE;
-                       ci->i_release_count++;
-               }
+               if (rinfo->head->result == 0 && req->r_locked_dir)
+                       ceph_invalidate_dir_request(req);
                return 0;
        }
 
@@ -1011,13 +1013,18 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
                             req->r_old_dentry->d_name.len,
                             req->r_old_dentry->d_name.name,
                             dn, dn->d_name.len, dn->d_name.name);
+
                        /* ensure target dentry is invalidated, despite
                           rehashing bug in vfs_rename_dir */
-                       dn->d_time = jiffies;
-                       ceph_dentry(dn)->lease_shared_gen = 0;
+                       ceph_invalidate_dentry_lease(dn);
+
                        /* take overwritten dentry's readdir offset */
+                       dout("dn %p gets %p offset %lld (old offset %lld)\n",
+                            req->r_old_dentry, dn, ceph_dentry(dn)->offset,
+                            ceph_dentry(req->r_old_dentry)->offset);
                        ceph_dentry(req->r_old_dentry)->offset =
                                ceph_dentry(dn)->offset;
+
                        dn = req->r_old_dentry;  /* use old_dentry */
                        in = dn->d_inode;
                }
@@ -1059,7 +1066,6 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
                                goto done;
                        }
                        req->r_dentry = dn;  /* may have spliced */
-                       ceph_set_dentry_offset(dn);
                        igrab(in);
                } else if (ceph_ino(in) == vino.ino &&
                           ceph_snap(in) == vino.snap) {
@@ -1102,7 +1108,6 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
                        err = PTR_ERR(dn);
                        goto done;
                }
-               ceph_set_dentry_offset(dn);
                req->r_dentry = dn;  /* may have spliced */
                igrab(in);
                rinfo->head->is_dentry = 1;  /* fool notrace handlers */
@@ -1429,7 +1434,7 @@ void ceph_queue_vmtruncate(struct inode *inode)
 {
        struct ceph_inode_info *ci = ceph_inode(inode);
 
-       if (queue_work(ceph_client(inode->i_sb)->trunc_wq,
+       if (queue_work(ceph_sb_to_client(inode->i_sb)->trunc_wq,
                       &ci->i_vmtruncate_work)) {
                dout("ceph_queue_vmtruncate %p\n", inode);
                igrab(inode);
@@ -1518,7 +1523,7 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)
        struct inode *parent_inode = dentry->d_parent->d_inode;
        const unsigned int ia_valid = attr->ia_valid;
        struct ceph_mds_request *req;
-       struct ceph_mds_client *mdsc = &ceph_client(dentry->d_sb)->mdsc;
+       struct ceph_mds_client *mdsc = &ceph_sb_to_client(dentry->d_sb)->mdsc;
        int issued;
        int release = 0, dirtied = 0;
        int mask = 0;
index 8a5bcae6284631cc6f020c1f71e03b8eb6e0821e..d085f07756b42159c7c3b916b123bdeabbfc35b8 100644 (file)
@@ -98,7 +98,7 @@ static long ceph_ioctl_get_dataloc(struct file *file, void __user *arg)
        struct ceph_ioctl_dataloc dl;
        struct inode *inode = file->f_dentry->d_inode;
        struct ceph_inode_info *ci = ceph_inode(inode);
-       struct ceph_osd_client *osdc = &ceph_client(inode->i_sb)->osdc;
+       struct ceph_osd_client *osdc = &ceph_sb_to_client(inode->i_sb)->osdc;
        u64 len = 1, olen;
        u64 tmp;
        struct ceph_object_layout ol;
index 24561a557e01c0ae55c35700e2615b318c8cdb4c..b49f12822cbcb77b1dab660f4d1aa602df5effb9 100644 (file)
@@ -40,7 +40,7 @@
 static void __wake_requests(struct ceph_mds_client *mdsc,
                            struct list_head *head);
 
-const static struct ceph_connection_operations mds_con_ops;
+static const struct ceph_connection_operations mds_con_ops;
 
 
 /*
@@ -665,10 +665,10 @@ static struct ceph_msg *create_session_msg(u32 op, u64 seq)
        struct ceph_msg *msg;
        struct ceph_mds_session_head *h;
 
-       msg = ceph_msg_new(CEPH_MSG_CLIENT_SESSION, sizeof(*h), 0, 0, NULL);
-       if (IS_ERR(msg)) {
+       msg = ceph_msg_new(CEPH_MSG_CLIENT_SESSION, sizeof(*h), GFP_NOFS);
+       if (!msg) {
                pr_err("create_session_msg ENOMEM creating msg\n");
-               return ERR_PTR(PTR_ERR(msg));
+               return NULL;
        }
        h = msg->front.iov_base;
        h->op = cpu_to_le32(op);
@@ -687,7 +687,6 @@ static int __open_session(struct ceph_mds_client *mdsc,
        struct ceph_msg *msg;
        int mstate;
        int mds = session->s_mds;
-       int err = 0;
 
        /* wait for mds to go active? */
        mstate = ceph_mdsmap_get_state(mdsc->mdsmap, mds);
@@ -698,13 +697,9 @@ static int __open_session(struct ceph_mds_client *mdsc,
 
        /* send connect message */
        msg = create_session_msg(CEPH_SESSION_REQUEST_OPEN, session->s_seq);
-       if (IS_ERR(msg)) {
-               err = PTR_ERR(msg);
-               goto out;
-       }
+       if (!msg)
+               return -ENOMEM;
        ceph_con_send(&session->s_con, msg);
-
-out:
        return 0;
 }
 
@@ -804,12 +799,49 @@ out:
 }
 
 static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap,
-                                  void *arg)
+                                 void *arg)
 {
        struct ceph_inode_info *ci = ceph_inode(inode);
+       int drop = 0;
+
        dout("removing cap %p, ci is %p, inode is %p\n",
             cap, ci, &ci->vfs_inode);
-       ceph_remove_cap(cap);
+       spin_lock(&inode->i_lock);
+       __ceph_remove_cap(cap);
+       if (!__ceph_is_any_real_caps(ci)) {
+               struct ceph_mds_client *mdsc =
+                       &ceph_sb_to_client(inode->i_sb)->mdsc;
+
+               spin_lock(&mdsc->cap_dirty_lock);
+               if (!list_empty(&ci->i_dirty_item)) {
+                       pr_info(" dropping dirty %s state for %p %lld\n",
+                               ceph_cap_string(ci->i_dirty_caps),
+                               inode, ceph_ino(inode));
+                       ci->i_dirty_caps = 0;
+                       list_del_init(&ci->i_dirty_item);
+                       drop = 1;
+               }
+               if (!list_empty(&ci->i_flushing_item)) {
+                       pr_info(" dropping dirty+flushing %s state for %p %lld\n",
+                               ceph_cap_string(ci->i_flushing_caps),
+                               inode, ceph_ino(inode));
+                       ci->i_flushing_caps = 0;
+                       list_del_init(&ci->i_flushing_item);
+                       mdsc->num_cap_flushing--;
+                       drop = 1;
+               }
+               if (drop && ci->i_wrbuffer_ref) {
+                       pr_info(" dropping dirty data for %p %lld\n",
+                               inode, ceph_ino(inode));
+                       ci->i_wrbuffer_ref = 0;
+                       ci->i_wrbuffer_ref_head = 0;
+                       drop++;
+               }
+               spin_unlock(&mdsc->cap_dirty_lock);
+       }
+       spin_unlock(&inode->i_lock);
+       while (drop--)
+               iput(inode);
        return 0;
 }
 
@@ -821,6 +853,7 @@ static void remove_session_caps(struct ceph_mds_session *session)
        dout("remove_session_caps on %p\n", session);
        iterate_session_caps(session, remove_session_caps_cb, NULL);
        BUG_ON(session->s_nr_caps > 0);
+       BUG_ON(!list_empty(&session->s_cap_flushing));
        cleanup_cap_releases(session);
 }
 
@@ -883,8 +916,8 @@ static int send_renew_caps(struct ceph_mds_client *mdsc,
                ceph_mds_state_name(state));
        msg = create_session_msg(CEPH_SESSION_REQUEST_RENEWCAPS,
                                 ++session->s_renew_seq);
-       if (IS_ERR(msg))
-               return PTR_ERR(msg);
+       if (!msg)
+               return -ENOMEM;
        ceph_con_send(&session->s_con, msg);
        return 0;
 }
@@ -931,17 +964,15 @@ static int request_close_session(struct ceph_mds_client *mdsc,
                                 struct ceph_mds_session *session)
 {
        struct ceph_msg *msg;
-       int err = 0;
 
        dout("request_close_session mds%d state %s seq %lld\n",
             session->s_mds, session_state_name(session->s_state),
             session->s_seq);
        msg = create_session_msg(CEPH_SESSION_REQUEST_CLOSE, session->s_seq);
-       if (IS_ERR(msg))
-               err = PTR_ERR(msg);
-       else
-               ceph_con_send(&session->s_con, msg);
-       return err;
+       if (!msg)
+               return -ENOMEM;
+       ceph_con_send(&session->s_con, msg);
+       return 0;
 }
 
 /*
@@ -1059,7 +1090,7 @@ static int add_cap_releases(struct ceph_mds_client *mdsc,
        while (session->s_num_cap_releases < session->s_nr_caps + extra) {
                spin_unlock(&session->s_cap_lock);
                msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPRELEASE, PAGE_CACHE_SIZE,
-                                  0, 0, NULL);
+                                  GFP_NOFS);
                if (!msg)
                        goto out_unlocked;
                dout("add_cap_releases %p msg %p now %d\n", session, msg,
@@ -1151,10 +1182,8 @@ static void send_cap_releases(struct ceph_mds_client *mdsc,
        struct ceph_msg *msg;
 
        dout("send_cap_releases mds%d\n", session->s_mds);
-       while (1) {
-               spin_lock(&session->s_cap_lock);
-               if (list_empty(&session->s_cap_releases_done))
-                       break;
+       spin_lock(&session->s_cap_lock);
+       while (!list_empty(&session->s_cap_releases_done)) {
                msg = list_first_entry(&session->s_cap_releases_done,
                                 struct ceph_msg, list_head);
                list_del_init(&msg->list_head);
@@ -1162,10 +1191,49 @@ static void send_cap_releases(struct ceph_mds_client *mdsc,
                msg->hdr.front_len = cpu_to_le32(msg->front.iov_len);
                dout("send_cap_releases mds%d %p\n", session->s_mds, msg);
                ceph_con_send(&session->s_con, msg);
+               spin_lock(&session->s_cap_lock);
        }
        spin_unlock(&session->s_cap_lock);
 }
 
+static void discard_cap_releases(struct ceph_mds_client *mdsc,
+                                struct ceph_mds_session *session)
+{
+       struct ceph_msg *msg;
+       struct ceph_mds_cap_release *head;
+       unsigned num;
+
+       dout("discard_cap_releases mds%d\n", session->s_mds);
+       spin_lock(&session->s_cap_lock);
+
+       /* zero out the in-progress message */
+       msg = list_first_entry(&session->s_cap_releases,
+                              struct ceph_msg, list_head);
+       head = msg->front.iov_base;
+       num = le32_to_cpu(head->num);
+       dout("discard_cap_releases mds%d %p %u\n", session->s_mds, msg, num);
+       head->num = cpu_to_le32(0);
+       session->s_num_cap_releases += num;
+
+       /* requeue completed messages */
+       while (!list_empty(&session->s_cap_releases_done)) {
+               msg = list_first_entry(&session->s_cap_releases_done,
+                                struct ceph_msg, list_head);
+               list_del_init(&msg->list_head);
+
+               head = msg->front.iov_base;
+               num = le32_to_cpu(head->num);
+               dout("discard_cap_releases mds%d %p %u\n", session->s_mds, msg,
+                    num);
+               session->s_num_cap_releases += num;
+               head->num = cpu_to_le32(0);
+               msg->front.iov_len = sizeof(*head);
+               list_add(&msg->list_head, &session->s_cap_releases);
+       }
+
+       spin_unlock(&session->s_cap_lock);
+}
+
 /*
  * requests
  */
@@ -1181,6 +1249,7 @@ ceph_mdsc_create_request(struct ceph_mds_client *mdsc, int op, int mode)
        if (!req)
                return ERR_PTR(-ENOMEM);
 
+       mutex_init(&req->r_fill_mutex);
        req->r_started = jiffies;
        req->r_resend_mds = -1;
        INIT_LIST_HEAD(&req->r_unsafe_dir_item);
@@ -1251,7 +1320,7 @@ retry:
                        len += 1 + temp->d_name.len;
                temp = temp->d_parent;
                if (temp == NULL) {
-                       pr_err("build_path_dentry corrupt dentry %p\n", dentry);
+                       pr_err("build_path corrupt dentry %p\n", dentry);
                        return ERR_PTR(-EINVAL);
                }
        }
@@ -1267,7 +1336,7 @@ retry:
                struct inode *inode = temp->d_inode;
 
                if (inode && ceph_snap(inode) == CEPH_SNAPDIR) {
-                       dout("build_path_dentry path+%d: %p SNAPDIR\n",
+                       dout("build_path path+%d: %p SNAPDIR\n",
                             pos, temp);
                } else if (stop_on_nosnap && inode &&
                           ceph_snap(inode) == CEPH_NOSNAP) {
@@ -1278,20 +1347,18 @@ retry:
                                break;
                        strncpy(path + pos, temp->d_name.name,
                                temp->d_name.len);
-                       dout("build_path_dentry path+%d: %p '%.*s'\n",
-                            pos, temp, temp->d_name.len, path + pos);
                }
                if (pos)
                        path[--pos] = '/';
                temp = temp->d_parent;
                if (temp == NULL) {
-                       pr_err("build_path_dentry corrupt dentry\n");
+                       pr_err("build_path corrupt dentry\n");
                        kfree(path);
                        return ERR_PTR(-EINVAL);
                }
        }
        if (pos != 0) {
-               pr_err("build_path_dentry did not end path lookup where "
+               pr_err("build_path did not end path lookup where "
                       "expected, namelen is %d, pos is %d\n", len, pos);
                /* presumably this is only possible if racing with a
                   rename of one of the parent directories (we can not
@@ -1303,7 +1370,7 @@ retry:
 
        *base = ceph_ino(temp->d_inode);
        *plen = len;
-       dout("build_path_dentry on %p %d built %llx '%.*s'\n",
+       dout("build_path on %p %d built %llx '%.*s'\n",
             dentry, atomic_read(&dentry->d_count), *base, len, path);
        return path;
 }
@@ -1426,9 +1493,11 @@ static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc,
        if (req->r_old_dentry_drop)
                len += req->r_old_dentry->d_name.len;
 
-       msg = ceph_msg_new(CEPH_MSG_CLIENT_REQUEST, len, 0, 0, NULL);
-       if (IS_ERR(msg))
+       msg = ceph_msg_new(CEPH_MSG_CLIENT_REQUEST, len, GFP_NOFS);
+       if (!msg) {
+               msg = ERR_PTR(-ENOMEM);
                goto out_free2;
+       }
 
        msg->hdr.tid = cpu_to_le64(req->r_tid);
 
@@ -1517,9 +1586,9 @@ static int __prepare_send_request(struct ceph_mds_client *mdsc,
        }
        msg = create_request_message(mdsc, req, mds);
        if (IS_ERR(msg)) {
-               req->r_reply = ERR_PTR(PTR_ERR(msg));
+               req->r_err = PTR_ERR(msg);
                complete_request(mdsc, req);
-               return -PTR_ERR(msg);
+               return PTR_ERR(msg);
        }
        req->r_request = msg;
 
@@ -1552,7 +1621,7 @@ static int __do_request(struct ceph_mds_client *mdsc,
        int mds = -1;
        int err = -EAGAIN;
 
-       if (req->r_reply)
+       if (req->r_err || req->r_got_result)
                goto out;
 
        if (req->r_timeout &&
@@ -1609,7 +1678,7 @@ out:
        return err;
 
 finish:
-       req->r_reply = ERR_PTR(err);
+       req->r_err = err;
        complete_request(mdsc, req);
        goto out;
 }
@@ -1630,10 +1699,9 @@ static void __wake_requests(struct ceph_mds_client *mdsc,
 
 /*
  * Wake up threads with requests pending for @mds, so that they can
- * resubmit their requests to a possibly different mds.  If @all is set,
- * wake up if their requests has been forwarded to @mds, too.
+ * resubmit their requests to a possibly different mds.
  */
-static void kick_requests(struct ceph_mds_client *mdsc, int mds, int all)
+static void kick_requests(struct ceph_mds_client *mdsc, int mds)
 {
        struct ceph_mds_request *req;
        struct rb_node *p;
@@ -1689,63 +1757,77 @@ int ceph_mdsc_do_request(struct ceph_mds_client *mdsc,
        __register_request(mdsc, req, dir);
        __do_request(mdsc, req);
 
-       /* wait */
-       if (!req->r_reply) {
-               mutex_unlock(&mdsc->mutex);
-               if (req->r_timeout) {
-                       err = (long)wait_for_completion_interruptible_timeout(
-                               &req->r_completion, req->r_timeout);
-                       if (err == 0)
-                               req->r_reply = ERR_PTR(-EIO);
-                       else if (err < 0)
-                               req->r_reply = ERR_PTR(err);
-               } else {
-                        err = wait_for_completion_interruptible(
-                                &req->r_completion);
-                        if (err)
-                                req->r_reply = ERR_PTR(err);
-               }
-               mutex_lock(&mdsc->mutex);
+       if (req->r_err) {
+               err = req->r_err;
+               __unregister_request(mdsc, req);
+               dout("do_request early error %d\n", err);
+               goto out;
        }
 
-       if (IS_ERR(req->r_reply)) {
-               err = PTR_ERR(req->r_reply);
-               req->r_reply = NULL;
+       /* wait */
+       mutex_unlock(&mdsc->mutex);
+       dout("do_request waiting\n");
+       if (req->r_timeout) {
+               err = (long)wait_for_completion_killable_timeout(
+                       &req->r_completion, req->r_timeout);
+               if (err == 0)
+                       err = -EIO;
+       } else {
+               err = wait_for_completion_killable(&req->r_completion);
+       }
+       dout("do_request waited, got %d\n", err);
+       mutex_lock(&mdsc->mutex);
 
-               if (err == -ERESTARTSYS) {
-                       /* aborted */
-                       req->r_aborted = true;
+       /* only abort if we didn't race with a real reply */
+       if (req->r_got_result) {
+               err = le32_to_cpu(req->r_reply_info.head->result);
+       } else if (err < 0) {
+               dout("aborted request %lld with %d\n", req->r_tid, err);
 
-                       if (req->r_locked_dir &&
-                           (req->r_op & CEPH_MDS_OP_WRITE)) {
-                               struct ceph_inode_info *ci =
-                                       ceph_inode(req->r_locked_dir);
+               /*
+                * ensure we aren't running concurrently with
+                * ceph_fill_trace or ceph_readdir_prepopulate, which
+                * rely on locks (dir mutex) held by our caller.
+                */
+               mutex_lock(&req->r_fill_mutex);
+               req->r_err = err;
+               req->r_aborted = true;
+               mutex_unlock(&req->r_fill_mutex);
 
-                               dout("aborted, clearing I_COMPLETE on %p\n", 
-                                    req->r_locked_dir);
-                               spin_lock(&req->r_locked_dir->i_lock);
-                               ci->i_ceph_flags &= ~CEPH_I_COMPLETE;
-                               ci->i_release_count++;
-                               spin_unlock(&req->r_locked_dir->i_lock);
-                       }
-               } else {
-                       /* clean up this request */
-                       __unregister_request(mdsc, req);
-                       if (!list_empty(&req->r_unsafe_item))
-                               list_del_init(&req->r_unsafe_item);
-                       complete(&req->r_safe_completion);
-               }
-       } else if (req->r_err) {
-               err = req->r_err;
+               if (req->r_locked_dir &&
+                   (req->r_op & CEPH_MDS_OP_WRITE))
+                       ceph_invalidate_dir_request(req);
        } else {
-               err = le32_to_cpu(req->r_reply_info.head->result);
+               err = req->r_err;
        }
-       mutex_unlock(&mdsc->mutex);
 
+out:
+       mutex_unlock(&mdsc->mutex);
        dout("do_request %p done, result %d\n", req, err);
        return err;
 }
 
+/*
+ * Invalidate dir I_COMPLETE, dentry lease state on an aborted MDS
+ * namespace request.
+ */
+void ceph_invalidate_dir_request(struct ceph_mds_request *req)
+{
+       struct inode *inode = req->r_locked_dir;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+
+       dout("invalidate_dir_request %p (I_COMPLETE, lease(s))\n", inode);
+       spin_lock(&inode->i_lock);
+       ci->i_ceph_flags &= ~CEPH_I_COMPLETE;
+       ci->i_release_count++;
+       spin_unlock(&inode->i_lock);
+
+       if (req->r_dentry)
+               ceph_invalidate_dentry_lease(req->r_dentry);
+       if (req->r_old_dentry)
+               ceph_invalidate_dentry_lease(req->r_old_dentry);
+}
+
 /*
  * Handle mds reply.
  *
@@ -1797,6 +1879,12 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg)
                mutex_unlock(&mdsc->mutex);
                goto out;
        }
+       if (req->r_got_safe && !head->safe) {
+               pr_warning("got unsafe after safe on %llu from mds%d\n",
+                          tid, mds);
+               mutex_unlock(&mdsc->mutex);
+               goto out;
+       }
 
        result = le32_to_cpu(head->result);
 
@@ -1838,11 +1926,7 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg)
                        mutex_unlock(&mdsc->mutex);
                        goto out;
                }
-       }
-
-       BUG_ON(req->r_reply);
-
-       if (!head->safe) {
+       } else {
                req->r_got_unsafe = true;
                list_add_tail(&req->r_unsafe_item, &req->r_session->s_unsafe);
        }
@@ -1871,21 +1955,30 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg)
        }
 
        /* insert trace into our cache */
+       mutex_lock(&req->r_fill_mutex);
        err = ceph_fill_trace(mdsc->client->sb, req, req->r_session);
        if (err == 0) {
                if (result == 0 && rinfo->dir_nr)
                        ceph_readdir_prepopulate(req, req->r_session);
                ceph_unreserve_caps(&req->r_caps_reservation);
        }
+       mutex_unlock(&req->r_fill_mutex);
 
        up_read(&mdsc->snap_rwsem);
 out_err:
-       if (err) {
-               req->r_err = err;
+       mutex_lock(&mdsc->mutex);
+       if (!req->r_aborted) {
+               if (err) {
+                       req->r_err = err;
+               } else {
+                       req->r_reply = msg;
+                       ceph_msg_get(msg);
+                       req->r_got_result = true;
+               }
        } else {
-               req->r_reply = msg;
-               ceph_msg_get(msg);
+               dout("reply arrived after request %lld was aborted\n", tid);
        }
+       mutex_unlock(&mdsc->mutex);
 
        add_cap_releases(mdsc, req->r_session, -1);
        mutex_unlock(&session->s_mutex);
@@ -1921,16 +2014,21 @@ static void handle_forward(struct ceph_mds_client *mdsc,
        mutex_lock(&mdsc->mutex);
        req = __lookup_request(mdsc, tid);
        if (!req) {
-               dout("forward %llu to mds%d - req dne\n", tid, next_mds);
+               dout("forward tid %llu to mds%d - req dne\n", tid, next_mds);
                goto out;  /* dup reply? */
        }
 
-       if (fwd_seq <= req->r_num_fwd) {
-               dout("forward %llu to mds%d - old seq %d <= %d\n",
+       if (req->r_aborted) {
+               dout("forward tid %llu aborted, unregistering\n", tid);
+               __unregister_request(mdsc, req);
+       } else if (fwd_seq <= req->r_num_fwd) {
+               dout("forward tid %llu to mds%d - old seq %d <= %d\n",
                     tid, next_mds, req->r_num_fwd, fwd_seq);
        } else {
                /* resend. forward race not possible; mds would drop */
-               dout("forward %llu to mds%d (we resend)\n", tid, next_mds);
+               dout("forward tid %llu to mds%d (we resend)\n", tid, next_mds);
+               BUG_ON(req->r_err);
+               BUG_ON(req->r_got_result);
                req->r_num_fwd = fwd_seq;
                req->r_resend_mds = next_mds;
                put_request_session(req);
@@ -1984,6 +2082,8 @@ static void handle_session(struct ceph_mds_session *session,
 
        switch (op) {
        case CEPH_SESSION_OPEN:
+               if (session->s_state == CEPH_MDS_SESSION_RECONNECTING)
+                       pr_info("mds%d reconnect success\n", session->s_mds);
                session->s_state = CEPH_MDS_SESSION_OPEN;
                renewed_caps(mdsc, session, 0);
                wake = 1;
@@ -1997,10 +2097,12 @@ static void handle_session(struct ceph_mds_session *session,
                break;
 
        case CEPH_SESSION_CLOSE:
+               if (session->s_state == CEPH_MDS_SESSION_RECONNECTING)
+                       pr_info("mds%d reconnect denied\n", session->s_mds);
                remove_session_caps(session);
                wake = 1; /* for good measure */
                complete(&mdsc->session_close_waiters);
-               kick_requests(mdsc, mds, 0);      /* cur only */
+               kick_requests(mdsc, mds);
                break;
 
        case CEPH_SESSION_STALE:
@@ -2132,54 +2234,44 @@ out:
  *
  * called with mdsc->mutex held.
  */
-static void send_mds_reconnect(struct ceph_mds_client *mdsc, int mds)
+static void send_mds_reconnect(struct ceph_mds_client *mdsc,
+                              struct ceph_mds_session *session)
 {
-       struct ceph_mds_session *session = NULL;
        struct ceph_msg *reply;
        struct rb_node *p;
+       int mds = session->s_mds;
        int err = -ENOMEM;
        struct ceph_pagelist *pagelist;
 
-       pr_info("reconnect to recovering mds%d\n", mds);
+       pr_info("mds%d reconnect start\n", mds);
 
        pagelist = kmalloc(sizeof(*pagelist), GFP_NOFS);
        if (!pagelist)
                goto fail_nopagelist;
        ceph_pagelist_init(pagelist);
 
-       reply = ceph_msg_new(CEPH_MSG_CLIENT_RECONNECT, 0, 0, 0, NULL);
-       if (IS_ERR(reply)) {
-               err = PTR_ERR(reply);
+       reply = ceph_msg_new(CEPH_MSG_CLIENT_RECONNECT, 0, GFP_NOFS);
+       if (!reply)
                goto fail_nomsg;
-       }
-
-       /* find session */
-       session = __ceph_lookup_mds_session(mdsc, mds);
-       mutex_unlock(&mdsc->mutex);    /* drop lock for duration */
 
-       if (session) {
-               mutex_lock(&session->s_mutex);
+       mutex_lock(&session->s_mutex);
+       session->s_state = CEPH_MDS_SESSION_RECONNECTING;
+       session->s_seq = 0;
 
-               session->s_state = CEPH_MDS_SESSION_RECONNECTING;
-               session->s_seq = 0;
+       ceph_con_open(&session->s_con,
+                     ceph_mdsmap_get_addr(mdsc->mdsmap, mds));
 
-               ceph_con_open(&session->s_con,
-                             ceph_mdsmap_get_addr(mdsc->mdsmap, mds));
-
-               /* replay unsafe requests */
-               replay_unsafe_requests(mdsc, session);
-       } else {
-               dout("no session for mds%d, will send short reconnect\n",
-                    mds);
-       }
+       /* replay unsafe requests */
+       replay_unsafe_requests(mdsc, session);
 
        down_read(&mdsc->snap_rwsem);
 
-       if (!session)
-               goto send;
        dout("session %p state %s\n", session,
             session_state_name(session->s_state));
 
+       /* drop old cap expires; we're about to reestablish that state */
+       discard_cap_releases(mdsc, session);
+
        /* traverse this session's caps */
        err = ceph_pagelist_encode_32(pagelist, session->s_nr_caps);
        if (err)
@@ -2208,36 +2300,29 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc, int mds)
                        goto fail;
        }
 
-send:
        reply->pagelist = pagelist;
        reply->hdr.data_len = cpu_to_le32(pagelist->length);
        reply->nr_pages = calc_pages_for(0, pagelist->length);
        ceph_con_send(&session->s_con, reply);
 
-       session->s_state = CEPH_MDS_SESSION_OPEN;
        mutex_unlock(&session->s_mutex);
 
        mutex_lock(&mdsc->mutex);
        __wake_requests(mdsc, &session->s_waiting);
        mutex_unlock(&mdsc->mutex);
 
-       ceph_put_mds_session(session);
-
        up_read(&mdsc->snap_rwsem);
-       mutex_lock(&mdsc->mutex);
        return;
 
 fail:
        ceph_msg_put(reply);
        up_read(&mdsc->snap_rwsem);
        mutex_unlock(&session->s_mutex);
-       ceph_put_mds_session(session);
 fail_nomsg:
        ceph_pagelist_release(pagelist);
        kfree(pagelist);
 fail_nopagelist:
        pr_err("error %d preparing reconnect for mds%d\n", err, mds);
-       mutex_lock(&mdsc->mutex);
        return;
 }
 
@@ -2290,7 +2375,7 @@ static void check_new_map(struct ceph_mds_client *mdsc,
                        }
 
                        /* kick any requests waiting on the recovering mds */
-                       kick_requests(mdsc, i, 1);
+                       kick_requests(mdsc, i);
                } else if (oldstate == newstate) {
                        continue;  /* nothing new with this mds */
                }
@@ -2299,22 +2384,21 @@ static void check_new_map(struct ceph_mds_client *mdsc,
                 * send reconnect?
                 */
                if (s->s_state == CEPH_MDS_SESSION_RESTARTING &&
-                   newstate >= CEPH_MDS_STATE_RECONNECT)
-                       send_mds_reconnect(mdsc, i);
+                   newstate >= CEPH_MDS_STATE_RECONNECT) {
+                       mutex_unlock(&mdsc->mutex);
+                       send_mds_reconnect(mdsc, s);
+                       mutex_lock(&mdsc->mutex);
+               }
 
                /*
-                * kick requests on any mds that has gone active.
-                *
-                * kick requests on cur or forwarder: we may have sent
-                * the request to mds1, mds1 told us it forwarded it
-                * to mds2, but then we learn mds1 failed and can't be
-                * sure it successfully forwarded our request before
-                * it died.
+                * kick request on any mds that has gone active.
                 */
                if (oldstate < CEPH_MDS_STATE_ACTIVE &&
                    newstate >= CEPH_MDS_STATE_ACTIVE) {
-                       pr_info("mds%d reconnect completed\n", s->s_mds);
-                       kick_requests(mdsc, i, 1);
+                       if (oldstate != CEPH_MDS_STATE_CREATING &&
+                           oldstate != CEPH_MDS_STATE_STARTING)
+                               pr_info("mds%d recovery completed\n", s->s_mds);
+                       kick_requests(mdsc, i);
                        ceph_kick_flushing_caps(mdsc, s);
                        wake_up_session_caps(s, 1);
                }
@@ -2457,12 +2541,12 @@ void ceph_mdsc_lease_send_msg(struct ceph_mds_session *session,
        dnamelen = dentry->d_name.len;
        len += dnamelen;
 
-       msg = ceph_msg_new(CEPH_MSG_CLIENT_LEASE, len, 0, 0, NULL);
-       if (IS_ERR(msg))
+       msg = ceph_msg_new(CEPH_MSG_CLIENT_LEASE, len, GFP_NOFS);
+       if (!msg)
                return;
        lease = msg->front.iov_base;
        lease->action = action;
-       lease->mask = cpu_to_le16(CEPH_LOCK_DN);
+       lease->mask = cpu_to_le16(1);
        lease->ino = cpu_to_le64(ceph_vino(inode).ino);
        lease->first = lease->last = cpu_to_le64(ceph_vino(inode).snap);
        lease->seq = cpu_to_le32(seq);
@@ -2492,7 +2576,7 @@ void ceph_mdsc_lease_release(struct ceph_mds_client *mdsc, struct inode *inode,
 
        BUG_ON(inode == NULL);
        BUG_ON(dentry == NULL);
-       BUG_ON(mask != CEPH_LOCK_DN);
+       BUG_ON(mask == 0);
 
        /* is dentry lease valid? */
        spin_lock(&dentry->d_lock);
@@ -2603,7 +2687,9 @@ static void delayed_work(struct work_struct *work)
                else
                        ceph_con_keepalive(&s->s_con);
                add_cap_releases(mdsc, s, -1);
-               send_cap_releases(mdsc, s);
+               if (s->s_state == CEPH_MDS_SESSION_OPEN ||
+                   s->s_state == CEPH_MDS_SESSION_HUNG)
+                       send_cap_releases(mdsc, s);
                mutex_unlock(&s->s_mutex);
                ceph_put_mds_session(s);
 
@@ -2620,6 +2706,9 @@ int ceph_mdsc_init(struct ceph_mds_client *mdsc, struct ceph_client *client)
        mdsc->client = client;
        mutex_init(&mdsc->mutex);
        mdsc->mdsmap = kzalloc(sizeof(*mdsc->mdsmap), GFP_NOFS);
+       if (mdsc->mdsmap == NULL)
+               return -ENOMEM;
+
        init_completion(&mdsc->safe_umount_waiters);
        init_completion(&mdsc->session_close_waiters);
        INIT_LIST_HEAD(&mdsc->waiting_for_map);
@@ -2645,6 +2734,7 @@ int ceph_mdsc_init(struct ceph_mds_client *mdsc, struct ceph_client *client)
        init_waitqueue_head(&mdsc->cap_flushing_wq);
        spin_lock_init(&mdsc->dentry_lru_lock);
        INIT_LIST_HEAD(&mdsc->dentry_lru);
+
        return 0;
 }
 
@@ -2740,6 +2830,9 @@ void ceph_mdsc_sync(struct ceph_mds_client *mdsc)
 {
        u64 want_tid, want_flush;
 
+       if (mdsc->client->mount_state == CEPH_MOUNT_SHUTDOWN)
+               return;
+
        dout("sync\n");
        mutex_lock(&mdsc->mutex);
        want_tid = mdsc->last_tid;
@@ -2922,9 +3015,10 @@ static void con_put(struct ceph_connection *con)
 static void peer_reset(struct ceph_connection *con)
 {
        struct ceph_mds_session *s = con->private;
+       struct ceph_mds_client *mdsc = s->s_mdsc;
 
-       pr_err("mds%d gave us the boot.  IMPLEMENT RECONNECT.\n",
-              s->s_mds);
+       pr_warning("mds%d closed our session\n", s->s_mds);
+       send_mds_reconnect(mdsc, s);
 }
 
 static void dispatch(struct ceph_connection *con, struct ceph_msg *msg)
@@ -3031,7 +3125,7 @@ static int invalidate_authorizer(struct ceph_connection *con)
        return ceph_monc_validate_auth(&mdsc->client->monc);
 }
 
-const static struct ceph_connection_operations mds_con_ops = {
+static const struct ceph_connection_operations mds_con_ops = {
        .get = con_get,
        .put = con_put,
        .dispatch = dispatch,
index 961cc6f65878df8bd536683a12911581f8cca036..d9936c4f12122a6a670a198a8a50249d06c27543 100644 (file)
@@ -165,6 +165,8 @@ struct ceph_mds_request {
        struct inode *r_locked_dir; /* dir (if any) i_mutex locked by vfs */
        struct inode *r_target_inode;       /* resulting inode */
 
+       struct mutex r_fill_mutex;
+
        union ceph_mds_request_args r_args;
        int r_fmode;        /* file mode, if expecting cap */
 
@@ -213,7 +215,7 @@ struct ceph_mds_request {
        struct completion r_safe_completion;
        ceph_mds_request_callback_t r_callback;
        struct list_head  r_unsafe_item;  /* per-session unsafe list item */
-       bool              r_got_unsafe, r_got_safe;
+       bool              r_got_unsafe, r_got_safe, r_got_result;
 
        bool              r_did_prepopulate;
        u32               r_readdir_offset;
@@ -301,6 +303,8 @@ extern void ceph_mdsc_lease_release(struct ceph_mds_client *mdsc,
                                    struct inode *inode,
                                    struct dentry *dn, int mask);
 
+extern void ceph_invalidate_dir_request(struct ceph_mds_request *req);
+
 extern struct ceph_mds_request *
 ceph_mdsc_create_request(struct ceph_mds_client *mdsc, int op, int mode);
 extern void ceph_mdsc_submit_request(struct ceph_mds_client *mdsc,
index cd4fadb6491afe3a48ad5081b5f4ab2a41e4b0bf..64b8b1f7863d7af7cbca11bfee570209a10d3e3e 100644 (file)
@@ -39,18 +39,6 @@ static void queue_con(struct ceph_connection *con);
 static void con_work(struct work_struct *);
 static void ceph_fault(struct ceph_connection *con);
 
-const char *ceph_name_type_str(int t)
-{
-       switch (t) {
-       case CEPH_ENTITY_TYPE_MON: return "mon";
-       case CEPH_ENTITY_TYPE_MDS: return "mds";
-       case CEPH_ENTITY_TYPE_OSD: return "osd";
-       case CEPH_ENTITY_TYPE_CLIENT: return "client";
-       case CEPH_ENTITY_TYPE_ADMIN: return "admin";
-       default: return "???";
-       }
-}
-
 /*
  * nicely render a sockaddr as a string.
  */
@@ -132,6 +120,12 @@ void ceph_msgr_exit(void)
        destroy_workqueue(ceph_msgr_wq);
 }
 
+void ceph_msgr_flush()
+{
+       flush_workqueue(ceph_msgr_wq);
+}
+
+
 /*
  * socket callback functions
  */
@@ -340,6 +334,7 @@ static void reset_connection(struct ceph_connection *con)
                ceph_msg_put(con->out_msg);
                con->out_msg = NULL;
        }
+       con->out_keepalive_pending = false;
        con->in_seq = 0;
        con->in_seq_acked = 0;
 }
@@ -357,6 +352,7 @@ void ceph_con_close(struct ceph_connection *con)
        clear_bit(WRITE_PENDING, &con->state);
        mutex_lock(&con->mutex);
        reset_connection(con);
+       con->peer_global_seq = 0;
        cancel_delayed_work(&con->work);
        mutex_unlock(&con->mutex);
        queue_con(con);
@@ -661,7 +657,7 @@ static void prepare_write_connect(struct ceph_messenger *msgr,
        dout("prepare_write_connect %p cseq=%d gseq=%d proto=%d\n", con,
             con->connect_seq, global_seq, proto);
 
-       con->out_connect.features = CEPH_FEATURE_SUPPORTED;
+       con->out_connect.features = CEPH_FEATURE_SUPPORTED_CLIENT;
        con->out_connect.host_type = cpu_to_le32(CEPH_ENTITY_TYPE_CLIENT);
        con->out_connect.connect_seq = cpu_to_le32(con->connect_seq);
        con->out_connect.global_seq = cpu_to_le32(global_seq);
@@ -1124,8 +1120,8 @@ static void fail_protocol(struct ceph_connection *con)
 
 static int process_connect(struct ceph_connection *con)
 {
-       u64 sup_feat = CEPH_FEATURE_SUPPORTED;
-       u64 req_feat = CEPH_FEATURE_REQUIRED;
+       u64 sup_feat = CEPH_FEATURE_SUPPORTED_CLIENT;
+       u64 req_feat = CEPH_FEATURE_REQUIRED_CLIENT;
        u64 server_feat = le64_to_cpu(con->in_reply.features);
 
        dout("process_connect on %p tag %d\n", con, (int)con->in_tag);
@@ -1233,6 +1229,7 @@ static int process_connect(struct ceph_connection *con)
                clear_bit(CONNECTING, &con->state);
                con->peer_global_seq = le32_to_cpu(con->in_reply.global_seq);
                con->connect_seq++;
+               con->peer_features = server_feat;
                dout("process_connect got READY gseq %d cseq %d (%d)\n",
                     con->peer_global_seq,
                     le32_to_cpu(con->in_reply.connect_seq),
@@ -1402,19 +1399,17 @@ static int read_partial_message(struct ceph_connection *con)
                con->in_msg = ceph_alloc_msg(con, &con->in_hdr, &skip);
                if (skip) {
                        /* skip this message */
-                       dout("alloc_msg returned NULL, skipping message\n");
+                       dout("alloc_msg said skip message\n");
                        con->in_base_pos = -front_len - middle_len - data_len -
                                sizeof(m->footer);
                        con->in_tag = CEPH_MSGR_TAG_READY;
                        con->in_seq++;
                        return 0;
                }
-               if (IS_ERR(con->in_msg)) {
-                       ret = PTR_ERR(con->in_msg);
-                       con->in_msg = NULL;
+               if (!con->in_msg) {
                        con->error_msg =
                                "error allocating memory for incoming message";
-                       return ret;
+                       return -ENOMEM;
                }
                m = con->in_msg;
                m->front.iov_len = 0;    /* haven't read it yet */
@@ -1514,14 +1509,14 @@ static void process_message(struct ceph_connection *con)
 
        /* if first message, set peer_name */
        if (con->peer_name.type == 0)
-               con->peer_name = msg->hdr.src.name;
+               con->peer_name = msg->hdr.src;
 
        con->in_seq++;
        mutex_unlock(&con->mutex);
 
        dout("===== %p %llu from %s%lld %d=%s len %d+%d (%u %u %u) =====\n",
             msg, le64_to_cpu(msg->hdr.seq),
-            ENTITY_NAME(msg->hdr.src.name),
+            ENTITY_NAME(msg->hdr.src),
             le16_to_cpu(msg->hdr.type),
             ceph_msg_type_name(le16_to_cpu(msg->hdr.type)),
             le32_to_cpu(msg->hdr.front_len),
@@ -1546,7 +1541,6 @@ static int try_write(struct ceph_connection *con)
        dout("try_write start %p state %lu nref %d\n", con, con->state,
             atomic_read(&con->nref));
 
-       mutex_lock(&con->mutex);
 more:
        dout("try_write out_kvec_bytes %d\n", con->out_kvec_bytes);
 
@@ -1639,7 +1633,6 @@ do_next:
 done:
        ret = 0;
 out:
-       mutex_unlock(&con->mutex);
        dout("try_write done on %p\n", con);
        return ret;
 }
@@ -1651,7 +1644,6 @@ out:
  */
 static int try_read(struct ceph_connection *con)
 {
-       struct ceph_messenger *msgr;
        int ret = -1;
 
        if (!con->sock)
@@ -1661,9 +1653,6 @@ static int try_read(struct ceph_connection *con)
                return 0;
 
        dout("try_read start on %p\n", con);
-       msgr = con->msgr;
-
-       mutex_lock(&con->mutex);
 
 more:
        dout("try_read tag %d in_base_pos %d\n", (int)con->in_tag,
@@ -1758,7 +1747,6 @@ more:
 done:
        ret = 0;
 out:
-       mutex_unlock(&con->mutex);
        dout("try_read done on %p\n", con);
        return ret;
 
@@ -1830,6 +1818,8 @@ more:
        dout("con_work %p start, clearing QUEUED\n", con);
        clear_bit(QUEUED, &con->state);
 
+       mutex_lock(&con->mutex);
+
        if (test_bit(CLOSED, &con->state)) { /* e.g. if we are replaced */
                dout("con_work CLOSED\n");
                con_close_socket(con);
@@ -1844,11 +1834,16 @@ more:
        if (test_and_clear_bit(SOCK_CLOSED, &con->state) ||
            try_read(con) < 0 ||
            try_write(con) < 0) {
+               mutex_unlock(&con->mutex);
                backoff = 1;
                ceph_fault(con);     /* error/fault path */
+               goto done_unlocked;
        }
 
 done:
+       mutex_unlock(&con->mutex);
+
+done_unlocked:
        clear_bit(BUSY, &con->state);
        dout("con->state=%lu\n", con->state);
        if (test_bit(QUEUED, &con->state)) {
@@ -1947,7 +1942,7 @@ struct ceph_messenger *ceph_messenger_create(struct ceph_entity_addr *myaddr)
 
        /* the zero page is needed if a request is "canceled" while the message
         * is being written over the socket */
-       msgr->zero_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+       msgr->zero_page = __page_cache_alloc(GFP_KERNEL | __GFP_ZERO);
        if (!msgr->zero_page) {
                kfree(msgr);
                return ERR_PTR(-ENOMEM);
@@ -1987,9 +1982,7 @@ void ceph_con_send(struct ceph_connection *con, struct ceph_msg *msg)
        }
 
        /* set src+dst */
-       msg->hdr.src.name = con->msgr->inst.name;
-       msg->hdr.src.addr = con->msgr->my_enc_addr;
-       msg->hdr.orig_src = msg->hdr.src;
+       msg->hdr.src = con->msgr->inst.name;
 
        BUG_ON(msg->front.iov_len != le32_to_cpu(msg->hdr.front_len));
 
@@ -2083,12 +2076,11 @@ void ceph_con_keepalive(struct ceph_connection *con)
  * construct a new message with given type, size
  * the new msg has a ref count of 1.
  */
-struct ceph_msg *ceph_msg_new(int type, int front_len,
-                             int page_len, int page_off, struct page **pages)
+struct ceph_msg *ceph_msg_new(int type, int front_len, gfp_t flags)
 {
        struct ceph_msg *m;
 
-       m = kmalloc(sizeof(*m), GFP_NOFS);
+       m = kmalloc(sizeof(*m), flags);
        if (m == NULL)
                goto out;
        kref_init(&m->kref);
@@ -2100,8 +2092,8 @@ struct ceph_msg *ceph_msg_new(int type, int front_len,
        m->hdr.version = 0;
        m->hdr.front_len = cpu_to_le32(front_len);
        m->hdr.middle_len = 0;
-       m->hdr.data_len = cpu_to_le32(page_len);
-       m->hdr.data_off = cpu_to_le16(page_off);
+       m->hdr.data_len = 0;
+       m->hdr.data_off = 0;
        m->hdr.reserved = 0;
        m->footer.front_crc = 0;
        m->footer.middle_crc = 0;
@@ -2115,11 +2107,11 @@ struct ceph_msg *ceph_msg_new(int type, int front_len,
        /* front */
        if (front_len) {
                if (front_len > PAGE_CACHE_SIZE) {
-                       m->front.iov_base = __vmalloc(front_len, GFP_NOFS,
+                       m->front.iov_base = __vmalloc(front_len, flags,
                                                      PAGE_KERNEL);
                        m->front_is_vmalloc = true;
                } else {
-                       m->front.iov_base = kmalloc(front_len, GFP_NOFS);
+                       m->front.iov_base = kmalloc(front_len, flags);
                }
                if (m->front.iov_base == NULL) {
                        pr_err("msg_new can't allocate %d bytes\n",
@@ -2135,19 +2127,18 @@ struct ceph_msg *ceph_msg_new(int type, int front_len,
        m->middle = NULL;
 
        /* data */
-       m->nr_pages = calc_pages_for(page_off, page_len);
-       m->pages = pages;
+       m->nr_pages = 0;
+       m->pages = NULL;
        m->pagelist = NULL;
 
-       dout("ceph_msg_new %p page %d~%d -> %d\n", m, page_off, page_len,
-            m->nr_pages);
+       dout("ceph_msg_new %p front %d\n", m, front_len);
        return m;
 
 out2:
        ceph_msg_put(m);
 out:
-       pr_err("msg_new can't create type %d len %d\n", type, front_len);
-       return ERR_PTR(-ENOMEM);
+       pr_err("msg_new can't create type %d front %d\n", type, front_len);
+       return NULL;
 }
 
 /*
@@ -2190,29 +2181,25 @@ static struct ceph_msg *ceph_alloc_msg(struct ceph_connection *con,
                mutex_unlock(&con->mutex);
                msg = con->ops->alloc_msg(con, hdr, skip);
                mutex_lock(&con->mutex);
-               if (IS_ERR(msg))
-                       return msg;
-
-               if (*skip)
+               if (!msg || *skip)
                        return NULL;
        }
        if (!msg) {
                *skip = 0;
-               msg = ceph_msg_new(type, front_len, 0, 0, NULL);
+               msg = ceph_msg_new(type, front_len, GFP_NOFS);
                if (!msg) {
                        pr_err("unable to allocate msg type %d len %d\n",
                               type, front_len);
-                       return ERR_PTR(-ENOMEM);
+                       return NULL;
                }
        }
        memcpy(&msg->hdr, &con->in_hdr, sizeof(con->in_hdr));
 
-       if (middle_len) {
+       if (middle_len && !msg->middle) {
                ret = ceph_alloc_middle(con, msg);
-
                if (ret < 0) {
                        ceph_msg_put(msg);
-                       return msg;
+                       return NULL;
                }
        }
 
index a5caf91cc97178039689b1f0efc49ef42e56d981..76fbc957bc137dab063cdd69abcc1b432800aa51 100644 (file)
@@ -49,10 +49,8 @@ struct ceph_connection_operations {
                                        int *skip);
 };
 
-extern const char *ceph_name_type_str(int t);
-
 /* use format string %s%d */
-#define ENTITY_NAME(n) ceph_name_type_str((n).type), le64_to_cpu((n).num)
+#define ENTITY_NAME(n) ceph_entity_type_name((n).type), le64_to_cpu((n).num)
 
 struct ceph_messenger {
        struct ceph_entity_inst inst;    /* my name+address */
@@ -144,6 +142,7 @@ struct ceph_connection {
        struct ceph_entity_addr peer_addr; /* peer address */
        struct ceph_entity_name peer_name; /* peer name */
        struct ceph_entity_addr peer_addr_for_me;
+       unsigned peer_features;
        u32 connect_seq;      /* identify the most recent connection
                                 attempt for this connection, client */
        u32 peer_global_seq;  /* peer's global seq for this connection */
@@ -158,7 +157,6 @@ struct ceph_connection {
        struct list_head out_queue;
        struct list_head out_sent;   /* sending or sent but unacked */
        u64 out_seq;                 /* last message queued for send */
-       u64 out_seq_sent;            /* last message sent */
        bool out_keepalive_pending;
 
        u64 in_seq, in_seq_acked;  /* last message received, acked */
@@ -215,6 +213,7 @@ extern int ceph_parse_ips(const char *c, const char *end,
 
 extern int ceph_msgr_init(void);
 extern void ceph_msgr_exit(void);
+extern void ceph_msgr_flush(void);
 
 extern struct ceph_messenger *ceph_messenger_create(
        struct ceph_entity_addr *myaddr);
@@ -234,9 +233,7 @@ extern void ceph_con_keepalive(struct ceph_connection *con);
 extern struct ceph_connection *ceph_con_get(struct ceph_connection *con);
 extern void ceph_con_put(struct ceph_connection *con);
 
-extern struct ceph_msg *ceph_msg_new(int type, int front_len,
-                                    int page_len, int page_off,
-                                    struct page **pages);
+extern struct ceph_msg *ceph_msg_new(int type, int front_len, gfp_t flags);
 extern void ceph_msg_kfree(struct ceph_msg *m);
 
 
index 8fdc011ca956c64e5feb33285ff989fa8d792bdd..21c62e9b7d1d6d4c816d252a3155706d25752ccf 100644 (file)
@@ -28,7 +28,7 @@
  * resend any outstanding requests.
  */
 
-const static struct ceph_connection_operations mon_con_ops;
+static const struct ceph_connection_operations mon_con_ops;
 
 static int __validate_auth(struct ceph_mon_client *monc);
 
@@ -104,6 +104,7 @@ static void __send_prepared_auth_request(struct ceph_mon_client *monc, int len)
        monc->pending_auth = 1;
        monc->m_auth->front.iov_len = len;
        monc->m_auth->hdr.front_len = cpu_to_le32(len);
+       ceph_con_revoke(monc->con, monc->m_auth);
        ceph_msg_get(monc->m_auth);  /* keep our ref */
        ceph_con_send(monc->con, monc->m_auth);
 }
@@ -187,16 +188,12 @@ static void __send_subscribe(struct ceph_mon_client *monc)
             monc->want_next_osdmap);
        if ((__sub_expired(monc) && !monc->sub_sent) ||
            monc->want_next_osdmap == 1) {
-               struct ceph_msg *msg;
+               struct ceph_msg *msg = monc->m_subscribe;
                struct ceph_mon_subscribe_item *i;
                void *p, *end;
 
-               msg = ceph_msg_new(CEPH_MSG_MON_SUBSCRIBE, 96, 0, 0, NULL);
-               if (!msg)
-                       return;
-
                p = msg->front.iov_base;
-               end = p + msg->front.iov_len;
+               end = p + msg->front_max;
 
                dout("__send_subscribe to 'mdsmap' %u+\n",
                     (unsigned)monc->have_mdsmap);
@@ -226,7 +223,8 @@ static void __send_subscribe(struct ceph_mon_client *monc)
 
                msg->front.iov_len = p - msg->front.iov_base;
                msg->hdr.front_len = cpu_to_le32(msg->front.iov_len);
-               ceph_con_send(monc->con, msg);
+               ceph_con_revoke(monc->con, msg);
+               ceph_con_send(monc->con, ceph_msg_get(msg));
 
                monc->sub_sent = jiffies | 1;  /* never 0 */
        }
@@ -353,14 +351,14 @@ out:
 /*
  * statfs
  */
-static struct ceph_mon_statfs_request *__lookup_statfs(
+static struct ceph_mon_generic_request *__lookup_generic_req(
        struct ceph_mon_client *monc, u64 tid)
 {
-       struct ceph_mon_statfs_request *req;
-       struct rb_node *n = monc->statfs_request_tree.rb_node;
+       struct ceph_mon_generic_request *req;
+       struct rb_node *n = monc->generic_request_tree.rb_node;
 
        while (n) {
-               req = rb_entry(n, struct ceph_mon_statfs_request, node);
+               req = rb_entry(n, struct ceph_mon_generic_request, node);
                if (tid < req->tid)
                        n = n->rb_left;
                else if (tid > req->tid)
@@ -371,16 +369,16 @@ static struct ceph_mon_statfs_request *__lookup_statfs(
        return NULL;
 }
 
-static void __insert_statfs(struct ceph_mon_client *monc,
-                           struct ceph_mon_statfs_request *new)
+static void __insert_generic_request(struct ceph_mon_client *monc,
+                           struct ceph_mon_generic_request *new)
 {
-       struct rb_node **p = &monc->statfs_request_tree.rb_node;
+       struct rb_node **p = &monc->generic_request_tree.rb_node;
        struct rb_node *parent = NULL;
-       struct ceph_mon_statfs_request *req = NULL;
+       struct ceph_mon_generic_request *req = NULL;
 
        while (*p) {
                parent = *p;
-               req = rb_entry(parent, struct ceph_mon_statfs_request, node);
+               req = rb_entry(parent, struct ceph_mon_generic_request, node);
                if (new->tid < req->tid)
                        p = &(*p)->rb_left;
                else if (new->tid > req->tid)
@@ -390,113 +388,157 @@ static void __insert_statfs(struct ceph_mon_client *monc,
        }
 
        rb_link_node(&new->node, parent, p);
-       rb_insert_color(&new->node, &monc->statfs_request_tree);
+       rb_insert_color(&new->node, &monc->generic_request_tree);
+}
+
+static void release_generic_request(struct kref *kref)
+{
+       struct ceph_mon_generic_request *req =
+               container_of(kref, struct ceph_mon_generic_request, kref);
+
+       if (req->reply)
+               ceph_msg_put(req->reply);
+       if (req->request)
+               ceph_msg_put(req->request);
+}
+
+static void put_generic_request(struct ceph_mon_generic_request *req)
+{
+       kref_put(&req->kref, release_generic_request);
+}
+
+static void get_generic_request(struct ceph_mon_generic_request *req)
+{
+       kref_get(&req->kref);
+}
+
+static struct ceph_msg *get_generic_reply(struct ceph_connection *con,
+                                        struct ceph_msg_header *hdr,
+                                        int *skip)
+{
+       struct ceph_mon_client *monc = con->private;
+       struct ceph_mon_generic_request *req;
+       u64 tid = le64_to_cpu(hdr->tid);
+       struct ceph_msg *m;
+
+       mutex_lock(&monc->mutex);
+       req = __lookup_generic_req(monc, tid);
+       if (!req) {
+               dout("get_generic_reply %lld dne\n", tid);
+               *skip = 1;
+               m = NULL;
+       } else {
+               dout("get_generic_reply %lld got %p\n", tid, req->reply);
+               m = ceph_msg_get(req->reply);
+               /*
+                * we don't need to track the connection reading into
+                * this reply because we only have one open connection
+                * at a time, ever.
+                */
+       }
+       mutex_unlock(&monc->mutex);
+       return m;
 }
 
 static void handle_statfs_reply(struct ceph_mon_client *monc,
                                struct ceph_msg *msg)
 {
-       struct ceph_mon_statfs_request *req;
+       struct ceph_mon_generic_request *req;
        struct ceph_mon_statfs_reply *reply = msg->front.iov_base;
-       u64 tid;
+       u64 tid = le64_to_cpu(msg->hdr.tid);
 
        if (msg->front.iov_len != sizeof(*reply))
                goto bad;
-       tid = le64_to_cpu(msg->hdr.tid);
        dout("handle_statfs_reply %p tid %llu\n", msg, tid);
 
        mutex_lock(&monc->mutex);
-       req = __lookup_statfs(monc, tid);
+       req = __lookup_generic_req(monc, tid);
        if (req) {
-               *req->buf = reply->st;
+               *(struct ceph_statfs *)req->buf = reply->st;
                req->result = 0;
+               get_generic_request(req);
        }
        mutex_unlock(&monc->mutex);
-       if (req)
+       if (req) {
                complete(&req->completion);
+               put_generic_request(req);
+       }
        return;
 
 bad:
-       pr_err("corrupt statfs reply, no tid\n");
+       pr_err("corrupt generic reply, no tid\n");
        ceph_msg_dump(msg);
 }
 
 /*
- * (re)send a statfs request
+ * Do a synchronous statfs().
  */
-static int send_statfs(struct ceph_mon_client *monc,
-                      struct ceph_mon_statfs_request *req)
+int ceph_monc_do_statfs(struct ceph_mon_client *monc, struct ceph_statfs *buf)
 {
-       struct ceph_msg *msg;
+       struct ceph_mon_generic_request *req;
        struct ceph_mon_statfs *h;
+       int err;
 
-       dout("send_statfs tid %llu\n", req->tid);
-       msg = ceph_msg_new(CEPH_MSG_STATFS, sizeof(*h), 0, 0, NULL);
-       if (IS_ERR(msg))
-               return PTR_ERR(msg);
-       req->request = msg;
-       msg->hdr.tid = cpu_to_le64(req->tid);
-       h = msg->front.iov_base;
+       req = kzalloc(sizeof(*req), GFP_NOFS);
+       if (!req)
+               return -ENOMEM;
+
+       kref_init(&req->kref);
+       req->buf = buf;
+       init_completion(&req->completion);
+
+       err = -ENOMEM;
+       req->request = ceph_msg_new(CEPH_MSG_STATFS, sizeof(*h), GFP_NOFS);
+       if (!req->request)
+               goto out;
+       req->reply = ceph_msg_new(CEPH_MSG_STATFS_REPLY, 1024, GFP_NOFS);
+       if (!req->reply)
+               goto out;
+
+       /* fill out request */
+       h = req->request->front.iov_base;
        h->monhdr.have_version = 0;
        h->monhdr.session_mon = cpu_to_le16(-1);
        h->monhdr.session_mon_tid = 0;
        h->fsid = monc->monmap->fsid;
-       ceph_con_send(monc->con, msg);
-       return 0;
-}
-
-/*
- * Do a synchronous statfs().
- */
-int ceph_monc_do_statfs(struct ceph_mon_client *monc, struct ceph_statfs *buf)
-{
-       struct ceph_mon_statfs_request req;
-       int err;
-
-       req.buf = buf;
-       init_completion(&req.completion);
-
-       /* allocate memory for reply */
-       err = ceph_msgpool_resv(&monc->msgpool_statfs_reply, 1);
-       if (err)
-               return err;
 
        /* register request */
        mutex_lock(&monc->mutex);
-       req.tid = ++monc->last_tid;
-       req.last_attempt = jiffies;
-       req.delay = BASE_DELAY_INTERVAL;
-       __insert_statfs(monc, &req);
-       monc->num_statfs_requests++;
+       req->tid = ++monc->last_tid;
+       req->request->hdr.tid = cpu_to_le64(req->tid);
+       __insert_generic_request(monc, req);
+       monc->num_generic_requests++;
        mutex_unlock(&monc->mutex);
 
        /* send request and wait */
-       err = send_statfs(monc, &req);
-       if (!err)
-               err = wait_for_completion_interruptible(&req.completion);
+       ceph_con_send(monc->con, ceph_msg_get(req->request));
+       err = wait_for_completion_interruptible(&req->completion);
 
        mutex_lock(&monc->mutex);
-       rb_erase(&req.node, &monc->statfs_request_tree);
-       monc->num_statfs_requests--;
-       ceph_msgpool_resv(&monc->msgpool_statfs_reply, -1);
+       rb_erase(&req->node, &monc->generic_request_tree);
+       monc->num_generic_requests--;
        mutex_unlock(&monc->mutex);
 
        if (!err)
-               err = req.result;
+               err = req->result;
+
+out:
+       kref_put(&req->kref, release_generic_request);
        return err;
 }
 
 /*
  * Resend pending statfs requests.
  */
-static void __resend_statfs(struct ceph_mon_client *monc)
+static void __resend_generic_request(struct ceph_mon_client *monc)
 {
-       struct ceph_mon_statfs_request *req;
+       struct ceph_mon_generic_request *req;
        struct rb_node *p;
 
-       for (p = rb_first(&monc->statfs_request_tree); p; p = rb_next(p)) {
-               req = rb_entry(p, struct ceph_mon_statfs_request, node);
-               send_statfs(monc, req);
+       for (p = rb_first(&monc->generic_request_tree); p; p = rb_next(p)) {
+               req = rb_entry(p, struct ceph_mon_generic_request, node);
+               ceph_con_revoke(monc->con, req->request);
+               ceph_con_send(monc->con, ceph_msg_get(req->request));
        }
 }
 
@@ -586,26 +628,26 @@ int ceph_monc_init(struct ceph_mon_client *monc, struct ceph_client *cl)
                CEPH_ENTITY_TYPE_AUTH | CEPH_ENTITY_TYPE_MON |
                CEPH_ENTITY_TYPE_OSD | CEPH_ENTITY_TYPE_MDS;
 
-       /* msg pools */
-       err = ceph_msgpool_init(&monc->msgpool_subscribe_ack,
-                              sizeof(struct ceph_mon_subscribe_ack), 1, false);
-       if (err < 0)
+       /* msgs */
+       err = -ENOMEM;
+       monc->m_subscribe_ack = ceph_msg_new(CEPH_MSG_MON_SUBSCRIBE_ACK,
+                                    sizeof(struct ceph_mon_subscribe_ack),
+                                    GFP_NOFS);
+       if (!monc->m_subscribe_ack)
                goto out_monmap;
-       err = ceph_msgpool_init(&monc->msgpool_statfs_reply,
-                               sizeof(struct ceph_mon_statfs_reply), 0, false);
-       if (err < 0)
-               goto out_pool1;
-       err = ceph_msgpool_init(&monc->msgpool_auth_reply, 4096, 1, false);
-       if (err < 0)
-               goto out_pool2;
-
-       monc->m_auth = ceph_msg_new(CEPH_MSG_AUTH, 4096, 0, 0, NULL);
+
+       monc->m_subscribe = ceph_msg_new(CEPH_MSG_MON_SUBSCRIBE, 96, GFP_NOFS);
+       if (!monc->m_subscribe)
+               goto out_subscribe_ack;
+
+       monc->m_auth_reply = ceph_msg_new(CEPH_MSG_AUTH_REPLY, 4096, GFP_NOFS);
+       if (!monc->m_auth_reply)
+               goto out_subscribe;
+
+       monc->m_auth = ceph_msg_new(CEPH_MSG_AUTH, 4096, GFP_NOFS);
        monc->pending_auth = 0;
-       if (IS_ERR(monc->m_auth)) {
-               err = PTR_ERR(monc->m_auth);
-               monc->m_auth = NULL;
-               goto out_pool3;
-       }
+       if (!monc->m_auth)
+               goto out_auth_reply;
 
        monc->cur_mon = -1;
        monc->hunting = true;
@@ -613,8 +655,8 @@ int ceph_monc_init(struct ceph_mon_client *monc, struct ceph_client *cl)
        monc->sub_sent = 0;
 
        INIT_DELAYED_WORK(&monc->delayed_work, delayed_work);
-       monc->statfs_request_tree = RB_ROOT;
-       monc->num_statfs_requests = 0;
+       monc->generic_request_tree = RB_ROOT;
+       monc->num_generic_requests = 0;
        monc->last_tid = 0;
 
        monc->have_mdsmap = 0;
@@ -622,12 +664,12 @@ int ceph_monc_init(struct ceph_mon_client *monc, struct ceph_client *cl)
        monc->want_next_osdmap = 1;
        return 0;
 
-out_pool3:
-       ceph_msgpool_destroy(&monc->msgpool_auth_reply);
-out_pool2:
-       ceph_msgpool_destroy(&monc->msgpool_subscribe_ack);
-out_pool1:
-       ceph_msgpool_destroy(&monc->msgpool_statfs_reply);
+out_auth_reply:
+       ceph_msg_put(monc->m_auth_reply);
+out_subscribe:
+       ceph_msg_put(monc->m_subscribe);
+out_subscribe_ack:
+       ceph_msg_put(monc->m_subscribe_ack);
 out_monmap:
        kfree(monc->monmap);
 out:
@@ -651,9 +693,9 @@ void ceph_monc_stop(struct ceph_mon_client *monc)
        ceph_auth_destroy(monc->auth);
 
        ceph_msg_put(monc->m_auth);
-       ceph_msgpool_destroy(&monc->msgpool_subscribe_ack);
-       ceph_msgpool_destroy(&monc->msgpool_statfs_reply);
-       ceph_msgpool_destroy(&monc->msgpool_auth_reply);
+       ceph_msg_put(monc->m_auth_reply);
+       ceph_msg_put(monc->m_subscribe);
+       ceph_msg_put(monc->m_subscribe_ack);
 
        kfree(monc->monmap);
 }
@@ -662,8 +704,11 @@ static void handle_auth_reply(struct ceph_mon_client *monc,
                              struct ceph_msg *msg)
 {
        int ret;
+       int was_auth = 0;
 
        mutex_lock(&monc->mutex);
+       if (monc->auth->ops)
+               was_auth = monc->auth->ops->is_authenticated(monc->auth);
        monc->pending_auth = 0;
        ret = ceph_handle_auth_reply(monc->auth, msg->front.iov_base,
                                     msg->front.iov_len,
@@ -674,14 +719,14 @@ static void handle_auth_reply(struct ceph_mon_client *monc,
                wake_up(&monc->client->auth_wq);
        } else if (ret > 0) {
                __send_prepared_auth_request(monc, ret);
-       } else if (monc->auth->ops->is_authenticated(monc->auth)) {
+       } else if (!was_auth && monc->auth->ops->is_authenticated(monc->auth)) {
                dout("authenticated, starting session\n");
 
                monc->client->msgr->inst.name.type = CEPH_ENTITY_TYPE_CLIENT;
                monc->client->msgr->inst.name.num = monc->auth->global_id;
 
                __send_subscribe(monc);
-               __resend_statfs(monc);
+               __resend_generic_request(monc);
        }
        mutex_unlock(&monc->mutex);
 }
@@ -770,18 +815,17 @@ static struct ceph_msg *mon_alloc_msg(struct ceph_connection *con,
 
        switch (type) {
        case CEPH_MSG_MON_SUBSCRIBE_ACK:
-               m = ceph_msgpool_get(&monc->msgpool_subscribe_ack, front_len);
+               m = ceph_msg_get(monc->m_subscribe_ack);
                break;
        case CEPH_MSG_STATFS_REPLY:
-               m = ceph_msgpool_get(&monc->msgpool_statfs_reply, front_len);
-               break;
+               return get_generic_reply(con, hdr, skip);
        case CEPH_MSG_AUTH_REPLY:
-               m = ceph_msgpool_get(&monc->msgpool_auth_reply, front_len);
+               m = ceph_msg_get(monc->m_auth_reply);
                break;
        case CEPH_MSG_MON_MAP:
        case CEPH_MSG_MDS_MAP:
        case CEPH_MSG_OSD_MAP:
-               m = ceph_msg_new(type, front_len, 0, 0, NULL);
+               m = ceph_msg_new(type, front_len, GFP_NOFS);
                break;
        }
 
@@ -826,7 +870,7 @@ out:
        mutex_unlock(&monc->mutex);
 }
 
-const static struct ceph_connection_operations mon_con_ops = {
+static const struct ceph_connection_operations mon_con_ops = {
        .get = ceph_con_get,
        .put = ceph_con_put,
        .dispatch = dispatch,
index b958ad5afa061e92a0031a0fd03ac77433dbd17d..174d794321d0af7cf709e4ff7395fedc381aba81 100644 (file)
@@ -2,10 +2,10 @@
 #define _FS_CEPH_MON_CLIENT_H
 
 #include <linux/completion.h>
+#include <linux/kref.h>
 #include <linux/rbtree.h>
 
 #include "messenger.h"
-#include "msgpool.h"
 
 struct ceph_client;
 struct ceph_mount_args;
@@ -22,7 +22,7 @@ struct ceph_monmap {
 };
 
 struct ceph_mon_client;
-struct ceph_mon_statfs_request;
+struct ceph_mon_generic_request;
 
 
 /*
@@ -40,17 +40,19 @@ struct ceph_mon_request {
 };
 
 /*
- * statfs() is done a bit differently because we need to get data back
+ * ceph_mon_generic_request is being used for the statfs and poolop requests
+ * which are bening done a bit differently because we need to get data back
  * to the caller
  */
-struct ceph_mon_statfs_request {
+struct ceph_mon_generic_request {
+       struct kref kref;
        u64 tid;
        struct rb_node node;
        int result;
-       struct ceph_statfs *buf;
+       void *buf;
        struct completion completion;
-       unsigned long last_attempt, delay; /* jiffies */
        struct ceph_msg *request;  /* original request */
+       struct ceph_msg *reply;    /* and reply */
 };
 
 struct ceph_mon_client {
@@ -61,7 +63,7 @@ struct ceph_mon_client {
        struct delayed_work delayed_work;
 
        struct ceph_auth_client *auth;
-       struct ceph_msg *m_auth;
+       struct ceph_msg *m_auth, *m_auth_reply, *m_subscribe, *m_subscribe_ack;
        int pending_auth;
 
        bool hunting;
@@ -70,14 +72,9 @@ struct ceph_mon_client {
        struct ceph_connection *con;
        bool have_fsid;
 
-       /* msg pools */
-       struct ceph_msgpool msgpool_subscribe_ack;
-       struct ceph_msgpool msgpool_statfs_reply;
-       struct ceph_msgpool msgpool_auth_reply;
-
-       /* pending statfs requests */
-       struct rb_root statfs_request_tree;
-       int num_statfs_requests;
+       /* pending generic requests */
+       struct rb_root generic_request_tree;
+       int num_generic_requests;
        u64 last_tid;
 
        /* mds/osd map */
index ca3b44a89f2d3e2a3eaaaeb99d263ce5b62353fd..dd65a6438131c5f08cbe97085b6b1ba3f671076d 100644 (file)
 
 #include "msgpool.h"
 
-/*
- * We use msg pools to preallocate memory for messages we expect to
- * receive over the wire, to avoid getting ourselves into OOM
- * conditions at unexpected times.  We take use a few different
- * strategies:
- *
- *  - for request/response type interactions, we preallocate the
- * memory needed for the response when we generate the request.
- *
- *  - for messages we can receive at any time from the MDS, we preallocate
- * a pool of messages we can re-use.
- *
- *  - for writeback, we preallocate some number of messages to use for
- * requests and their replies, so that we always make forward
- * progress.
- *
- * The msgpool behaves like a mempool_t, but keeps preallocated
- * ceph_msgs strung together on a list_head instead of using a pointer
- * vector.  This avoids vector reallocation when we adjust the number
- * of preallocated items (which happens frequently).
- */
+static void *alloc_fn(gfp_t gfp_mask, void *arg)
+{
+       struct ceph_msgpool *pool = arg;
+       void *p;
 
+       p = ceph_msg_new(0, pool->front_len, gfp_mask);
+       if (!p)
+               pr_err("msgpool %s alloc failed\n", pool->name);
+       return p;
+}
 
-/*
- * Allocate or release as necessary to meet our target pool size.
- */
-static int __fill_msgpool(struct ceph_msgpool *pool)
+static void free_fn(void *element, void *arg)
 {
-       struct ceph_msg *msg;
-
-       while (pool->num < pool->min) {
-               dout("fill_msgpool %p %d/%d allocating\n", pool, pool->num,
-                    pool->min);
-               spin_unlock(&pool->lock);
-               msg = ceph_msg_new(0, pool->front_len, 0, 0, NULL);
-               spin_lock(&pool->lock);
-               if (IS_ERR(msg))
-                       return PTR_ERR(msg);
-               msg->pool = pool;
-               list_add(&msg->list_head, &pool->msgs);
-               pool->num++;
-       }
-       while (pool->num > pool->min) {
-               msg = list_first_entry(&pool->msgs, struct ceph_msg, list_head);
-               dout("fill_msgpool %p %d/%d releasing %p\n", pool, pool->num,
-                    pool->min, msg);
-               list_del_init(&msg->list_head);
-               pool->num--;
-               ceph_msg_kfree(msg);
-       }
-       return 0;
+       ceph_msg_put(element);
 }
 
 int ceph_msgpool_init(struct ceph_msgpool *pool,
-                     int front_len, int min, bool blocking)
+                     int front_len, int size, bool blocking, const char *name)
 {
-       int ret;
-
-       dout("msgpool_init %p front_len %d min %d\n", pool, front_len, min);
-       spin_lock_init(&pool->lock);
        pool->front_len = front_len;
-       INIT_LIST_HEAD(&pool->msgs);
-       pool->num = 0;
-       pool->min = min;
-       pool->blocking = blocking;
-       init_waitqueue_head(&pool->wait);
-
-       spin_lock(&pool->lock);
-       ret = __fill_msgpool(pool);
-       spin_unlock(&pool->lock);
-       return ret;
+       pool->pool = mempool_create(size, alloc_fn, free_fn, pool);
+       if (!pool->pool)
+               return -ENOMEM;
+       pool->name = name;
+       return 0;
 }
 
 void ceph_msgpool_destroy(struct ceph_msgpool *pool)
 {
-       dout("msgpool_destroy %p\n", pool);
-       spin_lock(&pool->lock);
-       pool->min = 0;
-       __fill_msgpool(pool);
-       spin_unlock(&pool->lock);
+       mempool_destroy(pool->pool);
 }
 
-int ceph_msgpool_resv(struct ceph_msgpool *pool, int delta)
+struct ceph_msg *ceph_msgpool_get(struct ceph_msgpool *pool,
+                                 int front_len)
 {
-       int ret;
-
-       spin_lock(&pool->lock);
-       dout("msgpool_resv %p delta %d\n", pool, delta);
-       pool->min += delta;
-       ret = __fill_msgpool(pool);
-       spin_unlock(&pool->lock);
-       return ret;
-}
-
-struct ceph_msg *ceph_msgpool_get(struct ceph_msgpool *pool, int front_len)
-{
-       wait_queue_t wait;
-       struct ceph_msg *msg;
-
-       if (front_len && front_len > pool->front_len) {
-               pr_err("msgpool_get pool %p need front %d, pool size is %d\n",
-                      pool, front_len, pool->front_len);
+       if (front_len > pool->front_len) {
+               pr_err("msgpool_get pool %s need front %d, pool size is %d\n",
+                      pool->name, front_len, pool->front_len);
                WARN_ON(1);
 
                /* try to alloc a fresh message */
-               msg = ceph_msg_new(0, front_len, 0, 0, NULL);
-               if (!IS_ERR(msg))
-                       return msg;
-       }
-
-       if (!front_len)
-               front_len = pool->front_len;
-
-       if (pool->blocking) {
-               /* mempool_t behavior; first try to alloc */
-               msg = ceph_msg_new(0, front_len, 0, 0, NULL);
-               if (!IS_ERR(msg))
-                       return msg;
+               return ceph_msg_new(0, front_len, GFP_NOFS);
        }
 
-       while (1) {
-               spin_lock(&pool->lock);
-               if (likely(pool->num)) {
-                       msg = list_entry(pool->msgs.next, struct ceph_msg,
-                                        list_head);
-                       list_del_init(&msg->list_head);
-                       pool->num--;
-                       dout("msgpool_get %p got %p, now %d/%d\n", pool, msg,
-                            pool->num, pool->min);
-                       spin_unlock(&pool->lock);
-                       return msg;
-               }
-               pr_err("msgpool_get %p now %d/%d, %s\n", pool, pool->num,
-                      pool->min, pool->blocking ? "waiting" : "may fail");
-               spin_unlock(&pool->lock);
-
-               if (!pool->blocking) {
-                       WARN_ON(1);
-
-                       /* maybe we can allocate it now? */
-                       msg = ceph_msg_new(0, front_len, 0, 0, NULL);
-                       if (!IS_ERR(msg))
-                               return msg;
-
-                       pr_err("msgpool_get %p empty + alloc failed\n", pool);
-                       return ERR_PTR(-ENOMEM);
-               }
-
-               init_wait(&wait);
-               prepare_to_wait(&pool->wait, &wait, TASK_UNINTERRUPTIBLE);
-               schedule();
-               finish_wait(&pool->wait, &wait);
-       }
+       return mempool_alloc(pool->pool, GFP_NOFS);
 }
 
 void ceph_msgpool_put(struct ceph_msgpool *pool, struct ceph_msg *msg)
 {
-       spin_lock(&pool->lock);
-       if (pool->num < pool->min) {
-               /* reset msg front_len; user may have changed it */
-               msg->front.iov_len = pool->front_len;
-               msg->hdr.front_len = cpu_to_le32(pool->front_len);
+       /* reset msg front_len; user may have changed it */
+       msg->front.iov_len = pool->front_len;
+       msg->hdr.front_len = cpu_to_le32(pool->front_len);
 
-               kref_set(&msg->kref, 1);  /* retake a single ref */
-               list_add(&msg->list_head, &pool->msgs);
-               pool->num++;
-               dout("msgpool_put %p reclaim %p, now %d/%d\n", pool, msg,
-                    pool->num, pool->min);
-               spin_unlock(&pool->lock);
-               wake_up(&pool->wait);
-       } else {
-               dout("msgpool_put %p drop %p, at %d/%d\n", pool, msg,
-                    pool->num, pool->min);
-               spin_unlock(&pool->lock);
-               ceph_msg_kfree(msg);
-       }
+       kref_init(&msg->kref);  /* retake single ref */
 }
index bc834bfcd7207f42c26b335551e860effd2e6087..a362605f93682a8ffe213fc8a3bc7d06f4cc3187 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _FS_CEPH_MSGPOOL
 #define _FS_CEPH_MSGPOOL
 
+#include <linux/mempool.h>
 #include "messenger.h"
 
 /*
@@ -8,18 +9,15 @@
  * avoid unexpected OOM conditions.
  */
 struct ceph_msgpool {
-       spinlock_t lock;
+       const char *name;
+       mempool_t *pool;
        int front_len;          /* preallocated payload size */
-       struct list_head msgs;  /* msgs in the pool; each has 1 ref */
-       int num, min;           /* cur, min # msgs in the pool */
-       bool blocking;
-       wait_queue_head_t wait;
 };
 
 extern int ceph_msgpool_init(struct ceph_msgpool *pool,
-                            int front_len, int size, bool blocking);
+                            int front_len, int size, bool blocking,
+                            const char *name);
 extern void ceph_msgpool_destroy(struct ceph_msgpool *pool);
-extern int ceph_msgpool_resv(struct ceph_msgpool *, int delta);
 extern struct ceph_msg *ceph_msgpool_get(struct ceph_msgpool *,
                                         int front_len);
 extern void ceph_msgpool_put(struct ceph_msgpool *, struct ceph_msg *);
index 8aaab414f3f8ab84dae8d08cbe7161f9fa425eed..892a0298dfdfddc385873412894193237cdb32c2 100644 (file)
@@ -50,7 +50,6 @@ struct ceph_entity_name {
 #define CEPH_ENTITY_TYPE_MDS    0x02
 #define CEPH_ENTITY_TYPE_OSD    0x04
 #define CEPH_ENTITY_TYPE_CLIENT 0x08
-#define CEPH_ENTITY_TYPE_ADMIN  0x10
 #define CEPH_ENTITY_TYPE_AUTH   0x20
 
 #define CEPH_ENTITY_TYPE_ANY    0xFF
@@ -120,7 +119,7 @@ struct ceph_msg_connect_reply {
 /*
  * message header
  */
-struct ceph_msg_header {
+struct ceph_msg_header_old {
        __le64 seq;       /* message seq# for this session */
        __le64 tid;       /* transaction id */
        __le16 type;      /* message type */
@@ -138,6 +137,24 @@ struct ceph_msg_header {
        __le32 crc;       /* header crc32c */
 } __attribute__ ((packed));
 
+struct ceph_msg_header {
+       __le64 seq;       /* message seq# for this session */
+       __le64 tid;       /* transaction id */
+       __le16 type;      /* message type */
+       __le16 priority;  /* priority.  higher value == higher priority */
+       __le16 version;   /* version of message encoding */
+
+       __le32 front_len; /* bytes in main payload */
+       __le32 middle_len;/* bytes in middle payload */
+       __le32 data_len;  /* bytes of data payload */
+       __le16 data_off;  /* sender: include full offset;
+                            receiver: mask against ~PAGE_MASK */
+
+       struct ceph_entity_name src;
+       __le32 reserved;
+       __le32 crc;       /* header crc32c */
+} __attribute__ ((packed));
+
 #define CEPH_MSG_PRIO_LOW     64
 #define CEPH_MSG_PRIO_DEFAULT 127
 #define CEPH_MSG_PRIO_HIGH    196
index 3514f71ff85f79a866fb57699ade4f831d02d859..d25b4add85b4135249c77cbffc71bb2010170df5 100644 (file)
@@ -16,7 +16,7 @@
 #define OSD_OP_FRONT_LEN       4096
 #define OSD_OPREPLY_FRONT_LEN  512
 
-const static struct ceph_connection_operations osd_con_ops;
+static const struct ceph_connection_operations osd_con_ops;
 static int __kick_requests(struct ceph_osd_client *osdc,
                          struct ceph_osd *kickosd);
 
@@ -147,7 +147,7 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc,
                req = kzalloc(sizeof(*req), GFP_NOFS);
        }
        if (req == NULL)
-               return ERR_PTR(-ENOMEM);
+               return NULL;
 
        req->r_osdc = osdc;
        req->r_mempool = use_mempool;
@@ -164,10 +164,10 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc,
                msg = ceph_msgpool_get(&osdc->msgpool_op_reply, 0);
        else
                msg = ceph_msg_new(CEPH_MSG_OSD_OPREPLY,
-                                  OSD_OPREPLY_FRONT_LEN, 0, 0, NULL);
-       if (IS_ERR(msg)) {
+                                  OSD_OPREPLY_FRONT_LEN, GFP_NOFS);
+       if (!msg) {
                ceph_osdc_put_request(req);
-               return ERR_PTR(PTR_ERR(msg));
+               return NULL;
        }
        req->r_reply = msg;
 
@@ -178,10 +178,10 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc,
        if (use_mempool)
                msg = ceph_msgpool_get(&osdc->msgpool_op, 0);
        else
-               msg = ceph_msg_new(CEPH_MSG_OSD_OP, msg_size, 0, 0, NULL);
-       if (IS_ERR(msg)) {
+               msg = ceph_msg_new(CEPH_MSG_OSD_OP, msg_size, GFP_NOFS);
+       if (!msg) {
                ceph_osdc_put_request(req);
-               return ERR_PTR(PTR_ERR(msg));
+               return NULL;
        }
        msg->hdr.type = cpu_to_le16(CEPH_MSG_OSD_OP);
        memset(msg->front.iov_base, 0, msg->front.iov_len);
@@ -361,8 +361,13 @@ static void put_osd(struct ceph_osd *osd)
 {
        dout("put_osd %p %d -> %d\n", osd, atomic_read(&osd->o_ref),
             atomic_read(&osd->o_ref) - 1);
-       if (atomic_dec_and_test(&osd->o_ref))
+       if (atomic_dec_and_test(&osd->o_ref)) {
+               struct ceph_auth_client *ac = osd->o_osdc->client->monc.auth;
+
+               if (osd->o_authorizer)
+                       ac->ops->destroy_authorizer(ac, osd->o_authorizer);
                kfree(osd);
+       }
 }
 
 /*
@@ -715,7 +720,7 @@ static void handle_timeout(struct work_struct *work)
         * should mark the osd as failed and we should find out about
         * it from an updated osd map.
         */
-       while (!list_empty(&osdc->req_lru)) {
+       while (timeout && !list_empty(&osdc->req_lru)) {
                req = list_entry(osdc->req_lru.next, struct ceph_osd_request,
                                 r_req_lru_item);
 
@@ -1078,6 +1083,7 @@ done:
        if (newmap)
                kick_requests(osdc, NULL);
        up_read(&osdc->map_sem);
+       wake_up(&osdc->client->auth_wq);
        return;
 
 bad:
@@ -1087,45 +1093,6 @@ bad:
        return;
 }
 
-
-/*
- * A read request prepares specific pages that data is to be read into.
- * When a message is being read off the wire, we call prepare_pages to
- * find those pages.
- *  0 = success, -1 failure.
- */
-static int __prepare_pages(struct ceph_connection *con,
-                        struct ceph_msg_header *hdr,
-                        struct ceph_osd_request *req,
-                        u64 tid,
-                        struct ceph_msg *m)
-{
-       struct ceph_osd *osd = con->private;
-       struct ceph_osd_client *osdc;
-       int ret = -1;
-       int data_len = le32_to_cpu(hdr->data_len);
-       unsigned data_off = le16_to_cpu(hdr->data_off);
-
-       int want = calc_pages_for(data_off & ~PAGE_MASK, data_len);
-
-       if (!osd)
-               return -1;
-
-       osdc = osd->o_osdc;
-
-       dout("__prepare_pages on msg %p tid %llu, has %d pages, want %d\n", m,
-            tid, req->r_num_pages, want);
-       if (unlikely(req->r_num_pages < want))
-               goto out;
-       m->pages = req->r_pages;
-       m->nr_pages = req->r_num_pages;
-       ret = 0; /* success */
-out:
-       BUG_ON(ret < 0 || m->nr_pages < want);
-
-       return ret;
-}
-
 /*
  * Register request, send initial attempt.
  */
@@ -1252,11 +1219,13 @@ int ceph_osdc_init(struct ceph_osd_client *osdc, struct ceph_client *client)
        if (!osdc->req_mempool)
                goto out;
 
-       err = ceph_msgpool_init(&osdc->msgpool_op, OSD_OP_FRONT_LEN, 10, true);
+       err = ceph_msgpool_init(&osdc->msgpool_op, OSD_OP_FRONT_LEN, 10, true,
+                               "osd_op");
        if (err < 0)
                goto out_mempool;
        err = ceph_msgpool_init(&osdc->msgpool_op_reply,
-                               OSD_OPREPLY_FRONT_LEN, 10, true);
+                               OSD_OPREPLY_FRONT_LEN, 10, true,
+                               "osd_op_reply");
        if (err < 0)
                goto out_msgpool;
        return 0;
@@ -1302,8 +1271,8 @@ int ceph_osdc_readpages(struct ceph_osd_client *osdc,
                                    CEPH_OSD_OP_READ, CEPH_OSD_FLAG_READ,
                                    NULL, 0, truncate_seq, truncate_size, NULL,
                                    false, 1);
-       if (IS_ERR(req))
-               return PTR_ERR(req);
+       if (!req)
+               return -ENOMEM;
 
        /* it may be a short read due to an object boundary */
        req->r_pages = pages;
@@ -1345,8 +1314,8 @@ int ceph_osdc_writepages(struct ceph_osd_client *osdc, struct ceph_vino vino,
                                    snapc, do_sync,
                                    truncate_seq, truncate_size, mtime,
                                    nofail, 1);
-       if (IS_ERR(req))
-               return PTR_ERR(req);
+       if (!req)
+               return -ENOMEM;
 
        /* it may be a short write due to an object boundary */
        req->r_pages = pages;
@@ -1394,7 +1363,8 @@ static void dispatch(struct ceph_connection *con, struct ceph_msg *msg)
 }
 
 /*
- * lookup and return message for incoming reply
+ * lookup and return message for incoming reply.  set up reply message
+ * pages.
  */
 static struct ceph_msg *get_reply(struct ceph_connection *con,
                                  struct ceph_msg_header *hdr,
@@ -1407,7 +1377,6 @@ static struct ceph_msg *get_reply(struct ceph_connection *con,
        int front = le32_to_cpu(hdr->front_len);
        int data_len = le32_to_cpu(hdr->data_len);
        u64 tid;
-       int err;
 
        tid = le64_to_cpu(hdr->tid);
        mutex_lock(&osdc->request_mutex);
@@ -1425,13 +1394,14 @@ static struct ceph_msg *get_reply(struct ceph_connection *con,
                     req->r_reply, req->r_con_filling_msg);
                ceph_con_revoke_message(req->r_con_filling_msg, req->r_reply);
                ceph_con_put(req->r_con_filling_msg);
+               req->r_con_filling_msg = NULL;
        }
 
        if (front > req->r_reply->front.iov_len) {
                pr_warning("get_reply front %d > preallocated %d\n",
                           front, (int)req->r_reply->front.iov_len);
-               m = ceph_msg_new(CEPH_MSG_OSD_OPREPLY, front, 0, 0, NULL);
-               if (IS_ERR(m))
+               m = ceph_msg_new(CEPH_MSG_OSD_OPREPLY, front, GFP_NOFS);
+               if (!m)
                        goto out;
                ceph_msg_put(req->r_reply);
                req->r_reply = m;
@@ -1439,12 +1409,19 @@ static struct ceph_msg *get_reply(struct ceph_connection *con,
        m = ceph_msg_get(req->r_reply);
 
        if (data_len > 0) {
-               err = __prepare_pages(con, hdr, req, tid, m);
-               if (err < 0) {
+               unsigned data_off = le16_to_cpu(hdr->data_off);
+               int want = calc_pages_for(data_off & ~PAGE_MASK, data_len);
+
+               if (unlikely(req->r_num_pages < want)) {
+                       pr_warning("tid %lld reply %d > expected %d pages\n",
+                                  tid, want, m->nr_pages);
                        *skip = 1;
                        ceph_msg_put(m);
-                       m = ERR_PTR(err);
+                       m = NULL;
+                       goto out;
                }
+               m->pages = req->r_pages;
+               m->nr_pages = req->r_num_pages;
        }
        *skip = 0;
        req->r_con_filling_msg = ceph_con_get(con);
@@ -1466,7 +1443,7 @@ static struct ceph_msg *alloc_msg(struct ceph_connection *con,
 
        switch (type) {
        case CEPH_MSG_OSD_MAP:
-               return ceph_msg_new(type, front, 0, 0, NULL);
+               return ceph_msg_new(type, front, GFP_NOFS);
        case CEPH_MSG_OSD_OPREPLY:
                return get_reply(con, hdr, skip);
        default:
@@ -1552,7 +1529,7 @@ static int invalidate_authorizer(struct ceph_connection *con)
        return ceph_monc_validate_auth(&osdc->client->monc);
 }
 
-const static struct ceph_connection_operations osd_con_ops = {
+static const struct ceph_connection_operations osd_con_ops = {
        .get = get_osd_con,
        .put = put_osd_con,
        .dispatch = dispatch,
index cfdd8f4388b7a44a0419e34ead12e9368b35b935..ddc656fb5c059aa865aac8b45550d33c7e1635da 100644 (file)
@@ -706,7 +706,7 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end,
                     len, *p, end);
                newcrush = crush_decode(*p, min(*p+len, end));
                if (IS_ERR(newcrush))
-                       return ERR_PTR(PTR_ERR(newcrush));
+                       return ERR_CAST(newcrush);
        }
 
        /* new flags? */
index 5f8dbf7c745a7c7a1864ff97cd646a497a9e08e6..b6859f47d364ba2134121d48fa6cc720f3b6b1a4 100644 (file)
@@ -20,7 +20,7 @@ int ceph_pagelist_release(struct ceph_pagelist *pl)
 
 static int ceph_pagelist_addpage(struct ceph_pagelist *pl)
 {
-       struct page *page = alloc_page(GFP_NOFS);
+       struct page *page = __page_cache_alloc(GFP_NOFS);
        if (!page)
                return -ENOMEM;
        pl->room += PAGE_SIZE;
index fd56451a871f4b506263f6299feeff889cd6389c..8fcc023056c7642787f33b1aeb35c93ce26492b0 100644 (file)
@@ -101,8 +101,8 @@ struct ceph_pg_pool {
        __le64 snap_seq;          /* seq for per-pool snapshot */
        __le32 snap_epoch;        /* epoch of last snap */
        __le32 num_snaps;
-       __le32 num_removed_snap_intervals;
-       __le64 uid;
+       __le32 num_removed_snap_intervals; /* if non-empty, NO per-pool snaps */
+       __le64 auid;               /* who owns the pg */
 } __attribute__ ((packed));
 
 /*
@@ -208,6 +208,7 @@ enum {
        /* read */
        CEPH_OSD_OP_GETXATTR  = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_ATTR | 1,
        CEPH_OSD_OP_GETXATTRS = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_ATTR | 2,
+       CEPH_OSD_OP_CMPXATTR  = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_ATTR | 3,
 
        /* write */
        CEPH_OSD_OP_SETXATTR  = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_ATTR | 1,
@@ -305,6 +306,22 @@ enum {
 #define EOLDSNAPC    ERESTART  /* ORDERSNAP flag set; writer has old snapc*/
 #define EBLACKLISTED ESHUTDOWN /* blacklisted */
 
+/* xattr comparison */
+enum {
+       CEPH_OSD_CMPXATTR_OP_NOP = 0,
+       CEPH_OSD_CMPXATTR_OP_EQ  = 1,
+       CEPH_OSD_CMPXATTR_OP_NE  = 2,
+       CEPH_OSD_CMPXATTR_OP_GT  = 3,
+       CEPH_OSD_CMPXATTR_OP_GTE = 4,
+       CEPH_OSD_CMPXATTR_OP_LT  = 5,
+       CEPH_OSD_CMPXATTR_OP_LTE = 6
+};
+
+enum {
+       CEPH_OSD_CMPXATTR_MODE_STRING = 1,
+       CEPH_OSD_CMPXATTR_MODE_U64    = 2
+};
+
 /*
  * an individual object operation.  each may be accompanied by some data
  * payload
@@ -321,6 +338,8 @@ struct ceph_osd_op {
                struct {
                        __le32 name_len;
                        __le32 value_len;
+                       __u8 cmp_op;       /* CEPH_OSD_CMPXATTR_OP_* */
+                       __u8 cmp_mode;     /* CEPH_OSD_CMPXATTR_MODE_* */
                } __attribute__ ((packed)) xattr;
                struct {
                        __u8 class_len;
index d5114db704532bf1c41ec2a17fcb25ecb24f6e9c..c0b26b6badba7f53d0d8b32be33c165fb762922e 100644 (file)
@@ -512,7 +512,7 @@ int __ceph_finish_cap_snap(struct ceph_inode_info *ci,
                            struct ceph_cap_snap *capsnap)
 {
        struct inode *inode = &ci->vfs_inode;
-       struct ceph_mds_client *mdsc = &ceph_client(inode->i_sb)->mdsc;
+       struct ceph_mds_client *mdsc = &ceph_sb_to_client(inode->i_sb)->mdsc;
 
        BUG_ON(capsnap->writing);
        capsnap->size = inode->i_size;
index 110857ba9269c2862a1aebd5ac5763e848a27613..4e0bee240b9dbf10c9a14e9c13ac6a4867d1d0c2 100644 (file)
@@ -8,14 +8,11 @@
 #include <linux/module.h>
 #include <linux/mount.h>
 #include <linux/parser.h>
-#include <linux/rwsem.h>
 #include <linux/sched.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/statfs.h>
 #include <linux/string.h>
-#include <linux/version.h>
-#include <linux/vmalloc.h>
 
 #include "decode.h"
 #include "super.h"
@@ -107,12 +104,40 @@ static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf)
 static int ceph_syncfs(struct super_block *sb, int wait)
 {
        dout("sync_fs %d\n", wait);
-       ceph_osdc_sync(&ceph_client(sb)->osdc);
-       ceph_mdsc_sync(&ceph_client(sb)->mdsc);
+       ceph_osdc_sync(&ceph_sb_to_client(sb)->osdc);
+       ceph_mdsc_sync(&ceph_sb_to_client(sb)->mdsc);
        dout("sync_fs %d done\n", wait);
        return 0;
 }
 
+static int default_congestion_kb(void)
+{
+       int congestion_kb;
+
+       /*
+        * Copied from NFS
+        *
+        * congestion size, scale with available memory.
+        *
+        *  64MB:    8192k
+        * 128MB:   11585k
+        * 256MB:   16384k
+        * 512MB:   23170k
+        *   1GB:   32768k
+        *   2GB:   46340k
+        *   4GB:   65536k
+        *   8GB:   92681k
+        *  16GB:  131072k
+        *
+        * This allows larger machines to have larger/more transfers.
+        * Limit the default to 256M
+        */
+       congestion_kb = (16*int_sqrt(totalram_pages)) << (PAGE_SHIFT-10);
+       if (congestion_kb > 256*1024)
+               congestion_kb = 256*1024;
+
+       return congestion_kb;
+}
 
 /**
  * ceph_show_options - Show mount options in /proc/mounts
@@ -138,6 +163,35 @@ static int ceph_show_options(struct seq_file *m, struct vfsmount *mnt)
                seq_puts(m, ",nocrc");
        if (args->flags & CEPH_OPT_NOASYNCREADDIR)
                seq_puts(m, ",noasyncreaddir");
+
+       if (args->mount_timeout != CEPH_MOUNT_TIMEOUT_DEFAULT)
+               seq_printf(m, ",mount_timeout=%d", args->mount_timeout);
+       if (args->osd_idle_ttl != CEPH_OSD_IDLE_TTL_DEFAULT)
+               seq_printf(m, ",osd_idle_ttl=%d", args->osd_idle_ttl);
+       if (args->osd_timeout != CEPH_OSD_TIMEOUT_DEFAULT)
+               seq_printf(m, ",osdtimeout=%d", args->osd_timeout);
+       if (args->osd_keepalive_timeout != CEPH_OSD_KEEPALIVE_DEFAULT)
+               seq_printf(m, ",osdkeepalivetimeout=%d",
+                        args->osd_keepalive_timeout);
+       if (args->wsize)
+               seq_printf(m, ",wsize=%d", args->wsize);
+       if (args->rsize != CEPH_MOUNT_RSIZE_DEFAULT)
+               seq_printf(m, ",rsize=%d", args->rsize);
+       if (args->congestion_kb != default_congestion_kb())
+               seq_printf(m, ",write_congestion_kb=%d", args->congestion_kb);
+       if (args->caps_wanted_delay_min != CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT)
+               seq_printf(m, ",caps_wanted_delay_min=%d",
+                        args->caps_wanted_delay_min);
+       if (args->caps_wanted_delay_max != CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT)
+               seq_printf(m, ",caps_wanted_delay_max=%d",
+                          args->caps_wanted_delay_max);
+       if (args->cap_release_safety != CEPH_CAP_RELEASE_SAFETY_DEFAULT)
+               seq_printf(m, ",cap_release_safety=%d",
+                          args->cap_release_safety);
+       if (args->max_readdir != CEPH_MAX_READDIR_DEFAULT)
+               seq_printf(m, ",readdir_max_entries=%d", args->max_readdir);
+       if (args->max_readdir_bytes != CEPH_MAX_READDIR_BYTES_DEFAULT)
+               seq_printf(m, ",readdir_max_bytes=%d", args->max_readdir_bytes);
        if (strcmp(args->snapdir_name, CEPH_SNAPDIRNAME_DEFAULT))
                seq_printf(m, ",snapdirname=%s", args->snapdir_name);
        if (args->name)
@@ -161,35 +215,6 @@ static void ceph_inode_init_once(void *foo)
        inode_init_once(&ci->vfs_inode);
 }
 
-static int default_congestion_kb(void)
-{
-       int congestion_kb;
-
-       /*
-        * Copied from NFS
-        *
-        * congestion size, scale with available memory.
-        *
-        *  64MB:    8192k
-        * 128MB:   11585k
-        * 256MB:   16384k
-        * 512MB:   23170k
-        *   1GB:   32768k
-        *   2GB:   46340k
-        *   4GB:   65536k
-        *   8GB:   92681k
-        *  16GB:  131072k
-        *
-        * This allows larger machines to have larger/more transfers.
-        * Limit the default to 256M
-        */
-       congestion_kb = (16*int_sqrt(totalram_pages)) << (PAGE_SHIFT-10);
-       if (congestion_kb > 256*1024)
-               congestion_kb = 256*1024;
-
-       return congestion_kb;
-}
-
 static int __init init_caches(void)
 {
        ceph_inode_cachep = kmem_cache_create("ceph_inode_info",
@@ -308,7 +333,9 @@ enum {
        Opt_osd_idle_ttl,
        Opt_caps_wanted_delay_min,
        Opt_caps_wanted_delay_max,
+       Opt_cap_release_safety,
        Opt_readdir_max_entries,
+       Opt_readdir_max_bytes,
        Opt_congestion_kb,
        Opt_last_int,
        /* int args above */
@@ -339,7 +366,9 @@ static match_table_t arg_tokens = {
        {Opt_osd_idle_ttl, "osd_idle_ttl=%d"},
        {Opt_caps_wanted_delay_min, "caps_wanted_delay_min=%d"},
        {Opt_caps_wanted_delay_max, "caps_wanted_delay_max=%d"},
+       {Opt_cap_release_safety, "cap_release_safety=%d"},
        {Opt_readdir_max_entries, "readdir_max_entries=%d"},
+       {Opt_readdir_max_bytes, "readdir_max_bytes=%d"},
        {Opt_congestion_kb, "write_congestion_kb=%d"},
        /* int args above */
        {Opt_snapdirname, "snapdirname=%s"},
@@ -388,8 +417,9 @@ static struct ceph_mount_args *parse_mount_args(int flags, char *options,
        args->caps_wanted_delay_max = CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT;
        args->rsize = CEPH_MOUNT_RSIZE_DEFAULT;
        args->snapdir_name = kstrdup(CEPH_SNAPDIRNAME_DEFAULT, GFP_KERNEL);
-       args->cap_release_safety = CEPH_CAPS_PER_RELEASE * 4;
-       args->max_readdir = 1024;
+       args->cap_release_safety = CEPH_CAP_RELEASE_SAFETY_DEFAULT;
+       args->max_readdir = CEPH_MAX_READDIR_DEFAULT;
+       args->max_readdir_bytes = CEPH_MAX_READDIR_BYTES_DEFAULT;
        args->congestion_kb = default_congestion_kb();
 
        /* ip1[:port1][,ip2[:port2]...]:/subdir/in/fs */
@@ -497,6 +527,9 @@ static struct ceph_mount_args *parse_mount_args(int flags, char *options,
                case Opt_readdir_max_entries:
                        args->max_readdir = intval;
                        break;
+               case Opt_readdir_max_bytes:
+                       args->max_readdir_bytes = intval;
+                       break;
                case Opt_congestion_kb:
                        args->congestion_kb = intval;
                        break;
@@ -636,9 +669,17 @@ static void ceph_destroy_client(struct ceph_client *client)
 
        /* unmount */
        ceph_mdsc_stop(&client->mdsc);
-       ceph_monc_stop(&client->monc);
        ceph_osdc_stop(&client->osdc);
 
+       /*
+        * make sure mds and osd connections close out before destroying
+        * the auth module, which is needed to free those connections'
+        * ceph_authorizers.
+        */
+       ceph_msgr_flush();
+
+       ceph_monc_stop(&client->monc);
+
        ceph_adjust_min_caps(-client->min_caps);
 
        ceph_debugfs_client_cleanup(client);
@@ -682,9 +723,10 @@ int ceph_check_fsid(struct ceph_client *client, struct ceph_fsid *fsid)
 /*
  * true if we have the mon map (and have thus joined the cluster)
  */
-static int have_mon_map(struct ceph_client *client)
+static int have_mon_and_osd_map(struct ceph_client *client)
 {
-       return client->monc.monmap && client->monc.monmap->epoch;
+       return client->monc.monmap && client->monc.monmap->epoch &&
+              client->osdc.osdmap && client->osdc.osdmap->epoch;
 }
 
 /*
@@ -704,7 +746,7 @@ static struct dentry *open_root_dentry(struct ceph_client *client,
        dout("open_root_inode opening '%s'\n", path);
        req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_GETATTR, USE_ANY_MDS);
        if (IS_ERR(req))
-               return ERR_PTR(PTR_ERR(req));
+               return ERR_CAST(req);
        req->r_path1 = kstrdup(path, GFP_NOFS);
        req->r_ino1.ino = CEPH_INO_ROOT;
        req->r_ino1.snap = CEPH_NOSNAP;
@@ -762,7 +804,7 @@ static int ceph_mount(struct ceph_client *client, struct vfsmount *mnt,
        if (err < 0)
                goto out;
 
-       while (!have_mon_map(client)) {
+       while (!have_mon_and_osd_map(client)) {
                err = -EIO;
                if (timeout && time_after_eq(jiffies, started + timeout))
                        goto out;
@@ -770,8 +812,8 @@ static int ceph_mount(struct ceph_client *client, struct vfsmount *mnt,
                /* wait */
                dout("mount waiting for mon_map\n");
                err = wait_event_interruptible_timeout(client->auth_wq,
-                              have_mon_map(client) || (client->auth_err < 0),
-                              timeout);
+                      have_mon_and_osd_map(client) || (client->auth_err < 0),
+                      timeout);
                if (err == -EINTR || err == -ERESTARTSYS)
                        goto out;
                if (client->auth_err < 0) {
@@ -884,6 +926,8 @@ static int ceph_compare_super(struct super_block *sb, void *data)
 /*
  * construct our own bdi so we can control readahead, etc.
  */
+static atomic_long_t bdi_seq = ATOMIC_INIT(0);
+
 static int ceph_register_bdi(struct super_block *sb, struct ceph_client *client)
 {
        int err;
@@ -893,7 +937,8 @@ static int ceph_register_bdi(struct super_block *sb, struct ceph_client *client)
                client->backing_dev_info.ra_pages =
                        (client->mount_args->rsize + PAGE_CACHE_SIZE - 1)
                        >> PAGE_SHIFT;
-       err = bdi_register_dev(&client->backing_dev_info, sb->s_dev);
+       err = bdi_register(&client->backing_dev_info, NULL, "ceph-%d",
+                          atomic_long_inc_return(&bdi_seq));
        if (!err)
                sb->s_bdi = &client->backing_dev_info;
        return err;
@@ -932,9 +977,9 @@ static int ceph_get_sb(struct file_system_type *fs_type,
                goto out;
        }
 
-       if (ceph_client(sb) != client) {
+       if (ceph_sb_to_client(sb) != client) {
                ceph_destroy_client(client);
-               client = ceph_client(sb);
+               client = ceph_sb_to_client(sb);
                dout("get_sb got existing client %p\n", client);
        } else {
                dout("get_sb using new client %p\n", client);
@@ -952,8 +997,7 @@ static int ceph_get_sb(struct file_system_type *fs_type,
 
 out_splat:
        ceph_mdsc_close_sessions(&client->mdsc);
-       up_write(&sb->s_umount);
-       deactivate_super(sb);
+       deactivate_locked_super(sb);
        goto out_final;
 
 out:
index 13513b80d87f6854511ef8bd77784f596791afba..10a4a406e887506b4d104e8052f9dd50b07fba5f 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/fs.h>
 #include <linux/mempool.h>
 #include <linux/pagemap.h>
-#include <linux/slab.h>
 #include <linux/wait.h>
 #include <linux/writeback.h>
 #include <linux/slab.h>
 
 struct ceph_mount_args {
        int sb_flags;
+       int flags;
+       struct ceph_fsid fsid;
+       struct ceph_entity_addr my_addr;
        int num_mon;
        struct ceph_entity_addr *mon_addr;
-       int flags;
        int mount_timeout;
        int osd_idle_ttl;
-       int caps_wanted_delay_min, caps_wanted_delay_max;
-       struct ceph_fsid fsid;
-       struct ceph_entity_addr my_addr;
-       int wsize;
-       int rsize;            /* max readahead */
-       int max_readdir;      /* max readdir size */
-       int congestion_kb;      /* max readdir size */
        int osd_timeout;
        int osd_keepalive_timeout;
+       int wsize;
+       int rsize;            /* max readahead */
+       int congestion_kb;    /* max writeback in flight */
+       int caps_wanted_delay_min, caps_wanted_delay_max;
+       int cap_release_safety;
+       int max_readdir;       /* max readdir result (entires) */
+       int max_readdir_bytes; /* max readdir result (bytes) */
        char *snapdir_name;   /* default ".snap" */
        char *name;
        char *secret;
-       int cap_release_safety;
 };
 
 /*
@@ -80,13 +80,14 @@ struct ceph_mount_args {
 #define CEPH_OSD_KEEPALIVE_DEFAULT  5
 #define CEPH_OSD_IDLE_TTL_DEFAULT    60
 #define CEPH_MOUNT_RSIZE_DEFAULT    (512*1024) /* readahead */
+#define CEPH_MAX_READDIR_DEFAULT    1024
+#define CEPH_MAX_READDIR_BYTES_DEFAULT    (512*1024)
 
 #define CEPH_MSG_MAX_FRONT_LEN (16*1024*1024)
 #define CEPH_MSG_MAX_DATA_LEN  (16*1024*1024)
 
 #define CEPH_SNAPDIRNAME_DEFAULT ".snap"
 #define CEPH_AUTH_NAME_DEFAULT   "guest"
-
 /*
  * Delay telling the MDS we no longer want caps, in case we reopen
  * the file.  Delay a minimum amount of time, even if we send a cap
@@ -96,6 +97,7 @@ struct ceph_mount_args {
 #define CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT      5  /* cap release delay */
 #define CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT     60  /* cap release delay */
 
+#define CEPH_CAP_RELEASE_SAFETY_DEFAULT        (CEPH_CAPS_PER_RELEASE * 4)
 
 /* mount state */
 enum {
@@ -160,12 +162,6 @@ struct ceph_client {
 #endif
 };
 
-static inline struct ceph_client *ceph_client(struct super_block *sb)
-{
-       return sb->s_fs_info;
-}
-
-
 /*
  * File i/o capability.  This tracks shared state with the metadata
  * server that allows us to cache or writeback attributes or to read
@@ -814,7 +810,7 @@ extern void ceph_put_cap(struct ceph_cap *cap);
 
 extern void ceph_queue_caps_release(struct inode *inode);
 extern int ceph_write_inode(struct inode *inode, struct writeback_control *wbc);
-extern int ceph_fsync(struct file *file, struct dentry *dentry, int datasync);
+extern int ceph_fsync(struct file *file, int datasync);
 extern void ceph_kick_flushing_caps(struct ceph_mds_client *mdsc,
                                    struct ceph_mds_session *session);
 extern int ceph_get_cap_mds(struct inode *inode);
@@ -871,6 +867,7 @@ extern struct dentry *ceph_finish_lookup(struct ceph_mds_request *req,
 extern void ceph_dentry_lru_add(struct dentry *dn);
 extern void ceph_dentry_lru_touch(struct dentry *dn);
 extern void ceph_dentry_lru_del(struct dentry *dn);
+extern void ceph_invalidate_dentry_lease(struct dentry *dentry);
 
 /*
  * our d_ops vary depending on whether the inode is live,
index 2845422907fc7cd3c01360c3d2be99a35a455361..68aeebc696817ad537f7cac9997b093b5287a5cd 100644 (file)
@@ -7,7 +7,8 @@
 
 static bool ceph_is_valid_xattr(const char *name)
 {
-       return !strncmp(name, XATTR_SECURITY_PREFIX,
+       return !strncmp(name, "ceph.", 5) ||
+              !strncmp(name, XATTR_SECURITY_PREFIX,
                        XATTR_SECURITY_PREFIX_LEN) ||
               !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) ||
               !strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);
@@ -76,14 +77,14 @@ static size_t ceph_vxattrcb_rctime(struct ceph_inode_info *ci, char *val,
 }
 
 static struct ceph_vxattr_cb ceph_dir_vxattrs[] = {
-       { true, "user.ceph.dir.entries", ceph_vxattrcb_entries},
-       { true, "user.ceph.dir.files", ceph_vxattrcb_files},
-       { true, "user.ceph.dir.subdirs", ceph_vxattrcb_subdirs},
-       { true, "user.ceph.dir.rentries", ceph_vxattrcb_rentries},
-       { true, "user.ceph.dir.rfiles", ceph_vxattrcb_rfiles},
-       { true, "user.ceph.dir.rsubdirs", ceph_vxattrcb_rsubdirs},
-       { true, "user.ceph.dir.rbytes", ceph_vxattrcb_rbytes},
-       { true, "user.ceph.dir.rctime", ceph_vxattrcb_rctime},
+       { true, "ceph.dir.entries", ceph_vxattrcb_entries},
+       { true, "ceph.dir.files", ceph_vxattrcb_files},
+       { true, "ceph.dir.subdirs", ceph_vxattrcb_subdirs},
+       { true, "ceph.dir.rentries", ceph_vxattrcb_rentries},
+       { true, "ceph.dir.rfiles", ceph_vxattrcb_rfiles},
+       { true, "ceph.dir.rsubdirs", ceph_vxattrcb_rsubdirs},
+       { true, "ceph.dir.rbytes", ceph_vxattrcb_rbytes},
+       { true, "ceph.dir.rctime", ceph_vxattrcb_rctime},
        { true, NULL, NULL }
 };
 
@@ -107,7 +108,7 @@ static size_t ceph_vxattrcb_layout(struct ceph_inode_info *ci, char *val,
 }
 
 static struct ceph_vxattr_cb ceph_file_vxattrs[] = {
-       { true, "user.ceph.layout", ceph_vxattrcb_layout},
+       { true, "ceph.layout", ceph_vxattrcb_layout},
        { NULL, NULL }
 };
 
@@ -186,12 +187,6 @@ static int __set_xattr(struct ceph_inode_info *ci,
                ci->i_xattrs.names_size -= xattr->name_len;
                ci->i_xattrs.vals_size -= xattr->val_len;
        }
-       if (!xattr) {
-               pr_err("__set_xattr ENOMEM on %p %llx.%llx xattr %s=%s\n",
-                      &ci->vfs_inode, ceph_vinop(&ci->vfs_inode), name,
-                      xattr->val);
-               return -ENOMEM;
-       }
        ci->i_xattrs.names_size += name_len;
        ci->i_xattrs.vals_size += val_len;
        if (val)
@@ -574,7 +569,7 @@ ssize_t ceph_listxattr(struct dentry *dentry, char *names, size_t size)
             ci->i_xattrs.version, ci->i_xattrs.index_version);
 
        if (__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 1) &&
-           (ci->i_xattrs.index_version > ci->i_xattrs.version)) {
+           (ci->i_xattrs.index_version >= ci->i_xattrs.version)) {
                goto list_xattr;
        } else {
                spin_unlock(&inode->i_lock);
@@ -622,7 +617,7 @@ out:
 static int ceph_sync_setxattr(struct dentry *dentry, const char *name,
                              const char *value, size_t size, int flags)
 {
-       struct ceph_client *client = ceph_client(dentry->d_sb);
+       struct ceph_client *client = ceph_sb_to_client(dentry->d_sb);
        struct inode *inode = dentry->d_inode;
        struct ceph_inode_info *ci = ceph_inode(inode);
        struct inode *parent_inode = dentry->d_parent->d_inode;
@@ -641,7 +636,7 @@ static int ceph_sync_setxattr(struct dentry *dentry, const char *name,
                        return -ENOMEM;
                err = -ENOMEM;
                for (i = 0; i < nr_pages; i++) {
-                       pages[i] = alloc_page(GFP_NOFS);
+                       pages[i] = __page_cache_alloc(GFP_NOFS);
                        if (!pages[i]) {
                                nr_pages = i;
                                goto out;
@@ -779,7 +774,7 @@ out:
 
 static int ceph_send_removexattr(struct dentry *dentry, const char *name)
 {
-       struct ceph_client *client = ceph_client(dentry->d_sb);
+       struct ceph_client *client = ceph_sb_to_client(dentry->d_sb);
        struct ceph_mds_client *mdsc = &client->mdsc;
        struct inode *inode = dentry->d_inode;
        struct inode *parent_inode = dentry->d_parent->d_inode;
index 0242ff9cbf41f5bb6bcc3b44a32347427ae8b539..a7eb65c84b1c16725110b8732163968bc9caef24 100644 (file)
@@ -84,7 +84,7 @@ extern ssize_t cifs_user_read(struct file *file, char __user *read_data,
 extern ssize_t cifs_user_write(struct file *file, const char __user *write_data,
                         size_t write_size, loff_t *poffset);
 extern int cifs_lock(struct file *, int, struct file_lock *);
-extern int cifs_fsync(struct file *, struct dentry *, int);
+extern int cifs_fsync(struct file *, int);
 extern int cifs_flush(struct file *, fl_owner_t id);
 extern int cifs_file_mmap(struct file * , struct vm_area_struct *);
 extern const struct file_operations cifs_dir_ops;
index a83541ec97131af495e339dfa1e0a482d98dee72..f1ff785b22924d8ccb736fd7794f8c424c2b32c0 100644 (file)
@@ -1676,7 +1676,7 @@ static int cifs_write_end(struct file *file, struct address_space *mapping,
        return rc;
 }
 
-int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
+int cifs_fsync(struct file *file, int datasync)
 {
        int xid;
        int rc = 0;
@@ -1688,7 +1688,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
        xid = GetXid();
 
        cFYI(1, "Sync file - name: %s datasync: 0x%x",
-               dentry->d_name.name, datasync);
+               file->f_path.dentry->d_name.name, datasync);
 
        rc = filemap_write_and_wait(inode->i_mapping);
        if (rc == 0) {
index d99860a33890d7ae9a0734b17c5fc4e0263eebdf..6b443ff43a19dd829b1d35877d144e37b2fce918 100644 (file)
@@ -11,8 +11,7 @@ extern int coda_fake_statfs;
 
 void coda_destroy_inodecache(void);
 int coda_init_inodecache(void);
-int coda_fsync(struct file *coda_file, struct dentry *coda_dentry,
-              int datasync);
+int coda_fsync(struct file *coda_file, int datasync);
 void coda_sysctl_init(void);
 void coda_sysctl_clean(void);
 
index 4c813f2cdc52dcaa7074322ffaeb11d34e4c8726..ad3cd2abeeb48e561cadf63f65f9ae8d105dd621 100644 (file)
@@ -202,10 +202,10 @@ int coda_release(struct inode *coda_inode, struct file *coda_file)
        return 0;
 }
 
-int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync)
+int coda_fsync(struct file *coda_file, int datasync)
 {
        struct file *host_file;
-       struct inode *coda_inode = coda_dentry->d_inode;
+       struct inode *coda_inode = coda_file->f_path.dentry->d_inode;
        struct coda_file_info *cfi;
        int err = 0;
 
@@ -217,7 +217,7 @@ int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync)
        BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
        host_file = cfi->cfi_container;
 
-       err = vfs_fsync(host_file, host_file->f_path.dentry, datasync);
+       err = vfs_fsync(host_file, datasync);
        if ( !err && !datasync ) {
                lock_kernel();
                err = venus_fsync(coda_inode->i_sb, coda_i2f(coda_inode));
index 773f2ce9aa068e48a865c677cf07c717d408777b..ca25d96d45c9a51caa6d63d33f6670eaa769fcbc 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Pioctl operations for Coda.
- * Original version: (C) 1996 Peter Braam 
+ * Original version: (C) 1996 Peter Braam
  * Rewritten for Linux 2.1: (C) 1997 Carnegie Mellon University
  *
  * Carnegie Mellon encourages users of this code to contribute improvements
 #include <linux/coda_fs_i.h>
 #include <linux/coda_psdev.h>
 
+#include <linux/smp_lock.h>
+
 /* pioctl ops */
 static int coda_ioctl_permission(struct inode *inode, int mask);
-static int coda_pioctl(struct inode * inode, struct file * filp, 
-                       unsigned int cmd, unsigned long user_data);
+static long coda_pioctl(struct file *filp, unsigned int cmd,
+                       unsigned long user_data);
 
 /* exported from this file */
-const struct inode_operations coda_ioctl_inode_operations =
-{
+const struct inode_operations coda_ioctl_inode_operations = {
        .permission     = coda_ioctl_permission,
        .setattr        = coda_setattr,
 };
 
 const struct file_operations coda_ioctl_operations = {
        .owner          = THIS_MODULE,
-       .ioctl          = coda_pioctl,
+       .unlocked_ioctl = coda_pioctl,
 };
 
 /* the coda pioctl inode ops */
@@ -46,48 +47,53 @@ static int coda_ioctl_permission(struct inode *inode, int mask)
        return (mask & MAY_EXEC) ? -EACCES : 0;
 }
 
-static int coda_pioctl(struct inode * inode, struct file * filp, 
-                       unsigned int cmd, unsigned long user_data)
+static long coda_pioctl(struct file *filp, unsigned int cmd,
+                       unsigned long user_data)
 {
        struct path path;
-        int error;
+       int error;
        struct PioctlData data;
-        struct inode *target_inode = NULL;
-        struct coda_inode_info *cnp;
+       struct inode *inode = filp->f_dentry->d_inode;
+       struct inode *target_inode = NULL;
+       struct coda_inode_info *cnp;
 
-        /* get the Pioctl data arguments from user space */
-        if (copy_from_user(&data, (void __user *)user_data, sizeof(data))) {
-           return -EINVAL;
-       }
-       
-        /* 
-         * Look up the pathname. Note that the pathname is in 
-         * user memory, and namei takes care of this
-         */
-        if (data.follow) {
-                error = user_path(data.path, &path);
-       } else {
-               error = user_lpath(data.path, &path);
+       lock_kernel();
+
+       /* get the Pioctl data arguments from user space */
+       if (copy_from_user(&data, (void __user *)user_data, sizeof(data))) {
+               error = -EINVAL;
+               goto out;
        }
-               
-       if ( error ) {
-               return error;
-        } else {
+
+       /*
+        * Look up the pathname. Note that the pathname is in
+        * user memory, and namei takes care of this
+        */
+       if (data.follow)
+               error = user_path(data.path, &path);
+       else
+               error = user_lpath(data.path, &path);
+
+       if (error)
+               goto out;
+       else
                target_inode = path.dentry->d_inode;
-       }
-       
+
        /* return if it is not a Coda inode */
-       if ( target_inode->i_sb != inode->i_sb ) {
+       if (target_inode->i_sb != inode->i_sb) {
                path_put(&path);
-               return  -EINVAL;
+               error = -EINVAL;
+               goto out;
        }
 
        /* now proceed to make the upcall */
-        cnp = ITOC(target_inode);
+       cnp = ITOC(target_inode);
 
        error = venus_pioctl(inode->i_sb, &(cnp->c_fid), cmd, &data);
 
        path_put(&path);
-        return error;
-}
 
+out:
+       unlock_kernel();
+       return error;
+}
index be4392ca20983345ae180a450fd0497442b135a8..66b9cf79c5ba2b5fa25e81e9f4c681d65e2ebe0b 100644 (file)
@@ -73,8 +73,7 @@ static unsigned int coda_psdev_poll(struct file *file, poll_table * wait)
        return mask;
 }
 
-static int coda_psdev_ioctl(struct inode * inode, struct file * filp, 
-                           unsigned int cmd, unsigned long arg)
+static long coda_psdev_ioctl(struct file * filp, unsigned int cmd, unsigned long arg)
 {
        unsigned int data;
 
@@ -344,7 +343,7 @@ static const struct file_operations coda_psdev_fops = {
        .read           = coda_psdev_read,
        .write          = coda_psdev_write,
        .poll           = coda_psdev_poll,
-       .ioctl          = coda_psdev_ioctl,
+       .unlocked_ioctl = coda_psdev_ioctl,
        .open           = coda_psdev_open,
        .release        = coda_psdev_release,
 };
index 05448730f840be408e6bd7079df8c8ef26b03fd9..f0b391c50552dc986f93afe1e4c56ce3b777a600 100644 (file)
@@ -568,6 +568,79 @@ out:
        return ret;
 }
 
+/* A write operation does a read from user space and vice versa */
+#define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ)
+
+ssize_t compat_rw_copy_check_uvector(int type,
+               const struct compat_iovec __user *uvector, unsigned long nr_segs,
+               unsigned long fast_segs, struct iovec *fast_pointer,
+               struct iovec **ret_pointer)
+{
+       compat_ssize_t tot_len;
+       struct iovec *iov = *ret_pointer = fast_pointer;
+       ssize_t ret = 0;
+       int seg;
+
+       /*
+        * SuS says "The readv() function *may* fail if the iovcnt argument
+        * was less than or equal to 0, or greater than {IOV_MAX}.  Linux has
+        * traditionally returned zero for zero segments, so...
+        */
+       if (nr_segs == 0)
+               goto out;
+
+       ret = -EINVAL;
+       if (nr_segs > UIO_MAXIOV || nr_segs < 0)
+               goto out;
+       if (nr_segs > fast_segs) {
+               ret = -ENOMEM;
+               iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
+               if (iov == NULL) {
+                       *ret_pointer = fast_pointer;
+                       goto out;
+               }
+       }
+       *ret_pointer = iov;
+
+       /*
+        * Single unix specification:
+        * We should -EINVAL if an element length is not >= 0 and fitting an
+        * ssize_t.  The total length is fitting an ssize_t
+        *
+        * Be careful here because iov_len is a size_t not an ssize_t
+        */
+       tot_len = 0;
+       ret = -EINVAL;
+       for (seg = 0; seg < nr_segs; seg++) {
+               compat_ssize_t tmp = tot_len;
+               compat_uptr_t buf;
+               compat_ssize_t len;
+
+               if (__get_user(len, &uvector->iov_len) ||
+                  __get_user(buf, &uvector->iov_base)) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+               if (len < 0)    /* size_t not fitting in compat_ssize_t .. */
+                       goto out;
+               tot_len += len;
+               if (tot_len < tmp) /* maths overflow on the compat_ssize_t */
+                       goto out;
+               if (!access_ok(vrfy_dir(type), buf, len)) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+               iov->iov_base = compat_ptr(buf);
+               iov->iov_len = (compat_size_t) len;
+               uvector++;
+               iov++;
+       }
+       ret = tot_len;
+
+out:
+       return ret;
+}
+
 static inline long
 copy_iocb(long nr, u32 __user *ptr32, struct iocb __user * __user *ptr64)
 {
@@ -600,7 +673,7 @@ compat_sys_io_submit(aio_context_t ctx_id, int nr, u32 __user *iocb)
        iocb64 = compat_alloc_user_space(nr * sizeof(*iocb64));
        ret = copy_iocb(nr, iocb, iocb64);
        if (!ret)
-               ret = sys_io_submit(ctx_id, nr, iocb64);
+               ret = do_io_submit(ctx_id, nr, iocb64, 1);
        return ret;
 }
 
@@ -1077,70 +1150,21 @@ static ssize_t compat_do_readv_writev(int type, struct file *file,
 {
        compat_ssize_t tot_len;
        struct iovec iovstack[UIO_FASTIOV];
-       struct iovec *iov=iovstack, *vector;
+       struct iovec *iov;
        ssize_t ret;
-       int seg;
        io_fn_t fn;
        iov_fn_t fnv;
 
-       /*
-        * SuS says "The readv() function *may* fail if the iovcnt argument
-        * was less than or equal to 0, or greater than {IOV_MAX}.  Linux has
-        * traditionally returned zero for zero segments, so...
-        */
-       ret = 0;
-       if (nr_segs == 0)
-               goto out;
-
-       /*
-        * First get the "struct iovec" from user memory and
-        * verify all the pointers
-        */
        ret = -EINVAL;
-       if ((nr_segs > UIO_MAXIOV) || (nr_segs <= 0))
-               goto out;
        if (!file->f_op)
                goto out;
-       if (nr_segs > UIO_FASTIOV) {
-               ret = -ENOMEM;
-               iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
-               if (!iov)
-                       goto out;
-       }
+
        ret = -EFAULT;
        if (!access_ok(VERIFY_READ, uvector, nr_segs*sizeof(*uvector)))
                goto out;
 
-       /*
-        * Single unix specification:
-        * We should -EINVAL if an element length is not >= 0 and fitting an
-        * ssize_t.  The total length is fitting an ssize_t
-        *
-        * Be careful here because iov_len is a size_t not an ssize_t
-        */
-       tot_len = 0;
-       vector = iov;
-       ret = -EINVAL;
-       for (seg = 0 ; seg < nr_segs; seg++) {
-               compat_ssize_t tmp = tot_len;
-               compat_ssize_t len;
-               compat_uptr_t buf;
-
-               if (__get_user(len, &uvector->iov_len) ||
-                   __get_user(buf, &uvector->iov_base)) {
-                       ret = -EFAULT;
-                       goto out;
-               }
-               if (len < 0)    /* size_t not fitting an compat_ssize_t .. */
-                       goto out;
-               tot_len += len;
-               if (tot_len < tmp) /* maths overflow on the compat_ssize_t */
-                       goto out;
-               vector->iov_base = compat_ptr(buf);
-               vector->iov_len = (compat_size_t) len;
-               uvector++;
-               vector++;
-       }
+       tot_len = compat_rw_copy_check_uvector(type, uvector, nr_segs,
+                                              UIO_FASTIOV, iovstack, &iov);
        if (tot_len == 0) {
                ret = 0;
                goto out;
index c8af2d91174b42b6ce33f0bfac759910589be268..41645142b88b4698300cc89bbad15c613e10d6fd 100644 (file)
@@ -72,16 +72,11 @@ int configfs_setattr(struct dentry * dentry, struct iattr * iattr)
        if (!sd)
                return -EINVAL;
 
-       sd_iattr = sd->s_iattr;
-
-       error = inode_change_ok(inode, iattr);
-       if (error)
-               return error;
-
-       error = inode_setattr(inode, iattr);
+       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 */
                sd_iattr = kzalloc(sizeof(struct iattr), GFP_KERNEL);
index f1358e5c3a59b3b5f2551980956f84e09355378e..d96047b4a633a86cb7ae711cb29362ac6cda061a 100644 (file)
@@ -536,7 +536,7 @@ restart:
  */
 static void prune_dcache(int count)
 {
-       struct super_block *sb;
+       struct super_block *sb, *n;
        int w_count;
        int unused = dentry_stat.nr_unused;
        int prune_ratio;
@@ -545,13 +545,14 @@ static void prune_dcache(int count)
        if (unused == 0 || count == 0)
                return;
        spin_lock(&dcache_lock);
-restart:
        if (count >= unused)
                prune_ratio = 1;
        else
                prune_ratio = unused / count;
        spin_lock(&sb_lock);
-       list_for_each_entry(sb, &super_blocks, s_list) {
+       list_for_each_entry_safe(sb, n, &super_blocks, s_list) {
+               if (list_empty(&sb->s_instances))
+                       continue;
                if (sb->s_nr_dentry_unused == 0)
                        continue;
                sb->s_count++;
@@ -590,14 +591,10 @@ restart:
                }
                spin_lock(&sb_lock);
                count -= pruned;
-               /*
-                * restart only when sb is no longer on the list and
-                * we have more work to do.
-                */
-               if (__put_super_and_need_restart(sb) && count > 0) {
-                       spin_unlock(&sb_lock);
-                       goto restart;
-               }
+               __put_super(sb);
+               /* more work left to do? */
+               if (count <= 0)
+                       break;
        }
        spin_unlock(&sb_lock);
        spin_unlock(&dcache_lock);
@@ -1529,6 +1526,7 @@ void d_delete(struct dentry * dentry)
        spin_lock(&dentry->d_lock);
        isdir = S_ISDIR(dentry->d_inode->i_mode);
        if (atomic_read(&dentry->d_count) == 1) {
+               dentry->d_flags &= ~DCACHE_CANT_MOUNT;
                dentry_iput(dentry);
                fsnotify_nameremove(dentry, isdir);
                return;
index 4d74fc72c195daf72e9d9b8ec9a56e62a51f0227..0210898458b27286e403266e705ec1cd3396218b 100644 (file)
@@ -277,8 +277,10 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set, "0x%08llx\n"
 DEFINE_SIMPLE_ATTRIBUTE(fops_x32_ro, debugfs_u32_get, NULL, "0x%08llx\n");
 DEFINE_SIMPLE_ATTRIBUTE(fops_x32_wo, NULL, debugfs_u32_set, "0x%08llx\n");
 
+DEFINE_SIMPLE_ATTRIBUTE(fops_x64, debugfs_u64_get, debugfs_u64_set, "0x%016llx\n");
+
 /*
- * debugfs_create_x{8,16,32} - create a debugfs file that is used to read and write an unsigned {8,16,32}-bit value
+ * debugfs_create_x{8,16,32,64} - create a debugfs file that is used to read and write an unsigned {8,16,32,64}-bit value
  *
  * These functions are exactly the same as the above functions (but use a hex
  * output for the decimal challenged). For details look at the above unsigned
@@ -357,6 +359,23 @@ struct dentry *debugfs_create_x32(const char *name, mode_t mode,
 }
 EXPORT_SYMBOL_GPL(debugfs_create_x32);
 
+/**
+ * debugfs_create_x64 - create a debugfs file that is used to read and write an unsigned 64-bit value
+ * @name: a pointer to a string containing the name of the file to create.
+ * @mode: the permission that the file should have
+ * @parent: a pointer to the parent dentry for this file.  This should be a
+ *          directory dentry if set.  If this parameter is %NULL, then the
+ *          file will be created in the root of the debugfs filesystem.
+ * @value: a pointer to the variable that the file should read to and write
+ *         from.
+ */
+struct dentry *debugfs_create_x64(const char *name, mode_t mode,
+                                struct dentry *parent, u64 *value)
+{
+       return debugfs_create_file(name, mode, parent, value, &fops_x64);
+}
+EXPORT_SYMBOL_GPL(debugfs_create_x64);
+
 
 static int debugfs_size_t_set(void *data, u64 val)
 {
index 0120247b41c0d6661e112fa4e0c34f7eade0a887..8b3ffd5b5235eebf6e5f711efa1673776f80e6e9 100644 (file)
@@ -384,18 +384,15 @@ static int devpts_get_sb(struct file_system_type *fs_type,
                s->s_flags |= MS_ACTIVE;
        }
 
-       simple_set_mnt(mnt, s);
-
        memcpy(&(DEVPTS_SB(s))->mount_opts, &opts, sizeof(opts));
 
        error = mknod_ptmx(s);
        if (error)
-               goto out_dput;
+               goto out_undo_sget;
 
-       return 0;
+       simple_set_mnt(mnt, s);
 
-out_dput:
-       dput(s->s_root); /* undo dget() in simple_set_mnt() */
+       return 0;
 
 out_undo_sget:
        deactivate_locked_super(s);
index e82adc2debb73de9ae9ca916e65c6e2bed317ef2..7600aacf531dc8ed16ccfb727878d13834a16503 100644 (file)
@@ -82,6 +82,8 @@ struct dio {
        int reap_counter;               /* rate limit reaping */
        get_block_t *get_block;         /* block mapping function */
        dio_iodone_t *end_io;           /* IO completion function */
+       dio_submit_t *submit_io;        /* IO submition function */
+       loff_t logical_offset_in_bio;   /* current first logical block in bio */
        sector_t final_block_in_bio;    /* current final block in bio + 1 */
        sector_t next_block_for_io;     /* next block to be put under IO,
                                           in dio_blocks units */
@@ -96,6 +98,7 @@ struct dio {
        unsigned cur_page_offset;       /* Offset into it, in bytes */
        unsigned cur_page_len;          /* Nr of bytes at cur_page_offset */
        sector_t cur_page_block;        /* Where it starts */
+       loff_t cur_page_fs_offset;      /* Offset in file */
 
        /* BIO completion state */
        spinlock_t bio_lock;            /* protects BIO fields below */
@@ -300,6 +303,26 @@ static void dio_bio_end_io(struct bio *bio, int error)
        spin_unlock_irqrestore(&dio->bio_lock, flags);
 }
 
+/**
+ * dio_end_io - handle the end io action for the given bio
+ * @bio: The direct io bio thats being completed
+ * @error: Error if there was one
+ *
+ * This is meant to be called by any filesystem that uses their own dio_submit_t
+ * so that the DIO specific endio actions are dealt with after the filesystem
+ * has done it's completion work.
+ */
+void dio_end_io(struct bio *bio, int error)
+{
+       struct dio *dio = bio->bi_private;
+
+       if (dio->is_async)
+               dio_bio_end_aio(bio, error);
+       else
+               dio_bio_end_io(bio, error);
+}
+EXPORT_SYMBOL_GPL(dio_end_io);
+
 static int
 dio_bio_alloc(struct dio *dio, struct block_device *bdev,
                sector_t first_sector, int nr_vecs)
@@ -316,6 +339,7 @@ dio_bio_alloc(struct dio *dio, struct block_device *bdev,
                bio->bi_end_io = dio_bio_end_io;
 
        dio->bio = bio;
+       dio->logical_offset_in_bio = dio->cur_page_fs_offset;
        return 0;
 }
 
@@ -340,10 +364,15 @@ static void dio_bio_submit(struct dio *dio)
        if (dio->is_async && dio->rw == READ)
                bio_set_pages_dirty(bio);
 
-       submit_bio(dio->rw, bio);
+       if (dio->submit_io)
+               dio->submit_io(dio->rw, bio, dio->inode,
+                              dio->logical_offset_in_bio);
+       else
+               submit_bio(dio->rw, bio);
 
        dio->bio = NULL;
        dio->boundary = 0;
+       dio->logical_offset_in_bio = 0;
 }
 
 /*
@@ -603,10 +632,26 @@ static int dio_send_cur_page(struct dio *dio)
        int ret = 0;
 
        if (dio->bio) {
+               loff_t cur_offset = dio->block_in_file << dio->blkbits;
+               loff_t bio_next_offset = dio->logical_offset_in_bio +
+                       dio->bio->bi_size;
+
                /*
-                * See whether this new request is contiguous with the old
+                * See whether this new request is contiguous with the old.
+                *
+                * Btrfs cannot handl having logically non-contiguous requests
+                * submitted.  For exmple if you have
+                *
+                * Logical:  [0-4095][HOLE][8192-12287]
+                * Phyiscal: [0-4095]      [4096-8181]
+                *
+                * We cannot submit those pages together as one BIO.  So if our
+                * current logical offset in the file does not equal what would
+                * be the next logical offset in the bio, submit the bio we
+                * have.
                 */
-               if (dio->final_block_in_bio != dio->cur_page_block)
+               if (dio->final_block_in_bio != dio->cur_page_block ||
+                   cur_offset != bio_next_offset)
                        dio_bio_submit(dio);
                /*
                 * Submit now if the underlying fs is about to perform a
@@ -701,6 +746,7 @@ submit_page_section(struct dio *dio, struct page *page,
        dio->cur_page_offset = offset;
        dio->cur_page_len = len;
        dio->cur_page_block = blocknr;
+       dio->cur_page_fs_offset = dio->block_in_file << dio->blkbits;
 out:
        return ret;
 }
@@ -935,7 +981,7 @@ static ssize_t
 direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, 
        const struct iovec *iov, loff_t offset, unsigned long nr_segs, 
        unsigned blkbits, get_block_t get_block, dio_iodone_t end_io,
-       struct dio *dio)
+       dio_submit_t submit_io, struct dio *dio)
 {
        unsigned long user_addr; 
        unsigned long flags;
@@ -952,6 +998,7 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
 
        dio->get_block = get_block;
        dio->end_io = end_io;
+       dio->submit_io = submit_io;
        dio->final_block_in_bio = -1;
        dio->next_block_for_io = -1;
 
@@ -1008,7 +1055,7 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
                }
        } /* end iovec loop */
 
-       if (ret == -ENOTBLK && (rw & WRITE)) {
+       if (ret == -ENOTBLK) {
                /*
                 * The remaining part of the request will be
                 * be handled by buffered I/O when we return
@@ -1087,30 +1134,11 @@ 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(int rw, struct kiocb *iocb, struct inode *inode,
+__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,
-       int flags)
+       dio_submit_t submit_io, int flags)
 {
        int seg;
        size_t size;
@@ -1197,11 +1225,49 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
                (end > i_size_read(inode)));
 
        retval = direct_io_worker(rw, iocb, inode, iov, offset,
-                               nr_segs, blkbits, get_block, end_io, dio);
+                               nr_segs, blkbits, get_block, end_io,
+                               submit_io, dio);
+
+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.
@@ -1209,12 +1275,13 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
        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);
                }
        }
 
-out:
        return retval;
 }
 EXPORT_SYMBOL(__blockdev_direct_IO);
index 31f4b0e6d72c333bf1633ef51118ad6ccfc31069..83c4f600786a84cde81efde7fe6163ea66df9d04 100644 (file)
@@ -12,7 +12,7 @@
 /* A global variable is a bit ugly, but it keeps the code simple */
 int sysctl_drop_caches;
 
-static void drop_pagecache_sb(struct super_block *sb)
+static void drop_pagecache_sb(struct super_block *sb, void *unused)
 {
        struct inode *inode, *toput_inode = NULL;
 
@@ -33,26 +33,6 @@ static void drop_pagecache_sb(struct super_block *sb)
        iput(toput_inode);
 }
 
-static void drop_pagecache(void)
-{
-       struct super_block *sb;
-
-       spin_lock(&sb_lock);
-restart:
-       list_for_each_entry(sb, &super_blocks, s_list) {
-               sb->s_count++;
-               spin_unlock(&sb_lock);
-               down_read(&sb->s_umount);
-               if (sb->s_root)
-                       drop_pagecache_sb(sb);
-               up_read(&sb->s_umount);
-               spin_lock(&sb_lock);
-               if (__put_super_and_need_restart(sb))
-                       goto restart;
-       }
-       spin_unlock(&sb_lock);
-}
-
 static void drop_slab(void)
 {
        int nr_objects;
@@ -68,7 +48,7 @@ int drop_caches_sysctl_handler(ctl_table *table, int write,
        proc_dointvec_minmax(table, write, buffer, length, ppos);
        if (write) {
                if (sysctl_drop_caches & 1)
-                       drop_pagecache();
+                       iterate_supers(drop_pagecache_sb, NULL);
                if (sysctl_drop_caches & 2)
                        drop_slab();
        }
index bfc2e0f78f0019a7cac763c19336bdf287559d15..0032a9f5a3a92045658baf77d736ee07c83525cc 100644 (file)
@@ -731,15 +731,14 @@ int ecryptfs_write_lower(struct inode *ecryptfs_inode, char *data,
 int ecryptfs_write_lower_page_segment(struct inode *ecryptfs_inode,
                                      struct page *page_for_lower,
                                      size_t offset_in_page, size_t size);
-int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset,
-                  size_t size);
+int ecryptfs_write(struct inode *inode, char *data, loff_t offset, size_t size);
 int ecryptfs_read_lower(char *data, loff_t offset, size_t size,
                        struct inode *ecryptfs_inode);
 int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs,
                                     pgoff_t page_index,
                                     size_t offset_in_page, size_t size,
                                     struct inode *ecryptfs_inode);
-struct page *ecryptfs_get_locked_page(struct file *file, loff_t index);
+struct page *ecryptfs_get_locked_page(struct inode *inode, loff_t index);
 int ecryptfs_exorcise_daemon(struct ecryptfs_daemon *daemon);
 int ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon, uid_t euid,
                                 struct user_namespace *user_ns);
index e7440a6f5ebf0cffb9e9bee7a770b80553e72b15..e8fcf4e2ed7d1c7022e386d499348d10b29f55cf 100644 (file)
@@ -274,11 +274,9 @@ static int ecryptfs_release(struct inode *inode, struct file *file)
 }
 
 static int
-ecryptfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+ecryptfs_fsync(struct file *file, int datasync)
 {
-       return vfs_fsync(ecryptfs_file_to_lower(file),
-                        ecryptfs_dentry_to_lower(dentry),
-                        datasync);
+       return vfs_fsync(ecryptfs_file_to_lower(file), datasync);
 }
 
 static int ecryptfs_fasync(int fd, struct file *file, int flag)
index e2d4418affac91df98e3e70c01f577c4c10e57cf..31ef5252f0fe2f38d94d79b847285965c3ea8626 100644 (file)
@@ -142,19 +142,10 @@ out:
 static int grow_file(struct dentry *ecryptfs_dentry)
 {
        struct inode *ecryptfs_inode = ecryptfs_dentry->d_inode;
-       struct file fake_file;
-       struct ecryptfs_file_info tmp_file_info;
        char zero_virt[] = { 0x00 };
        int rc = 0;
 
-       memset(&fake_file, 0, sizeof(fake_file));
-       fake_file.f_path.dentry = ecryptfs_dentry;
-       memset(&tmp_file_info, 0, sizeof(tmp_file_info));
-       ecryptfs_set_file_private(&fake_file, &tmp_file_info);
-       ecryptfs_set_file_lower(
-               &fake_file,
-               ecryptfs_inode_to_private(ecryptfs_inode)->lower_file);
-       rc = ecryptfs_write(&fake_file, zero_virt, 0, 1);
+       rc = ecryptfs_write(ecryptfs_inode, zero_virt, 0, 1);
        i_size_write(ecryptfs_inode, 0);
        rc = ecryptfs_write_inode_size_to_metadata(ecryptfs_inode);
        ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat.flags |=
@@ -784,8 +775,6 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia,
 {
        int rc = 0;
        struct inode *inode = dentry->d_inode;
-       struct dentry *lower_dentry;
-       struct file fake_ecryptfs_file;
        struct ecryptfs_crypt_stat *crypt_stat;
        loff_t i_size = i_size_read(inode);
        loff_t lower_size_before_truncate;
@@ -796,23 +785,6 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia,
                goto out;
        }
        crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat;
-       /* Set up a fake ecryptfs file, this is used to interface with
-        * the file in the underlying filesystem so that the
-        * truncation has an effect there as well. */
-       memset(&fake_ecryptfs_file, 0, sizeof(fake_ecryptfs_file));
-       fake_ecryptfs_file.f_path.dentry = dentry;
-       /* Released at out_free: label */
-       ecryptfs_set_file_private(&fake_ecryptfs_file,
-                                 kmem_cache_alloc(ecryptfs_file_info_cache,
-                                                  GFP_KERNEL));
-       if (unlikely(!ecryptfs_file_to_private(&fake_ecryptfs_file))) {
-               rc = -ENOMEM;
-               goto out;
-       }
-       lower_dentry = ecryptfs_dentry_to_lower(dentry);
-       ecryptfs_set_file_lower(
-               &fake_ecryptfs_file,
-               ecryptfs_inode_to_private(dentry->d_inode)->lower_file);
        /* Switch on growing or shrinking file */
        if (ia->ia_size > i_size) {
                char zero[] = { 0x00 };
@@ -822,7 +794,7 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia,
                 * this triggers code that will fill in 0's throughout
                 * the intermediate portion of the previous end of the
                 * file and the new and of the file */
-               rc = ecryptfs_write(&fake_ecryptfs_file, zero,
+               rc = ecryptfs_write(inode, zero,
                                    (ia->ia_size - 1), 1);
        } else { /* ia->ia_size < i_size_read(inode) */
                /* We're chopping off all the pages down to the page
@@ -833,12 +805,12 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia,
                                    - (ia->ia_size & ~PAGE_CACHE_MASK));
 
                if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) {
-                       rc = vmtruncate(inode, ia->ia_size);
+                       rc = simple_setsize(inode, ia->ia_size);
                        if (rc)
-                               goto out_free;
+                               goto out;
                        lower_ia->ia_size = ia->ia_size;
                        lower_ia->ia_valid |= ATTR_SIZE;
-                       goto out_free;
+                       goto out;
                }
                if (num_zeros) {
                        char *zeros_virt;
@@ -846,25 +818,25 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia,
                        zeros_virt = kzalloc(num_zeros, GFP_KERNEL);
                        if (!zeros_virt) {
                                rc = -ENOMEM;
-                               goto out_free;
+                               goto out;
                        }
-                       rc = ecryptfs_write(&fake_ecryptfs_file, zeros_virt,
+                       rc = ecryptfs_write(inode, zeros_virt,
                                            ia->ia_size, num_zeros);
                        kfree(zeros_virt);
                        if (rc) {
                                printk(KERN_ERR "Error attempting to zero out "
                                       "the remainder of the end page on "
                                       "reducing truncate; rc = [%d]\n", rc);
-                               goto out_free;
+                               goto out;
                        }
                }
-               vmtruncate(inode, ia->ia_size);
+               simple_setsize(inode, ia->ia_size);
                rc = ecryptfs_write_inode_size_to_metadata(inode);
                if (rc) {
                        printk(KERN_ERR "Problem with "
                               "ecryptfs_write_inode_size_to_metadata; "
                               "rc = [%d]\n", rc);
-                       goto out_free;
+                       goto out;
                }
                /* We are reducing the size of the ecryptfs file, and need to
                 * know if we need to reduce the size of the lower file. */
@@ -878,10 +850,6 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia,
                } else
                        lower_ia->ia_valid &= ~ATTR_SIZE;
        }
-out_free:
-       if (ecryptfs_file_to_private(&fake_ecryptfs_file))
-               kmem_cache_free(ecryptfs_file_info_cache,
-                               ecryptfs_file_to_private(&fake_ecryptfs_file));
 out:
        return rc;
 }
index 760983d0f25eafd2addd76d35c571f45d25d45d3..cbd4e18adb204438d45b865469d38b7af97a9904 100644 (file)
@@ -281,7 +281,7 @@ static void ecryptfs_init_mount_crypt_stat(
  *
  * Returns zero on success; non-zero on error
  */
-static int ecryptfs_parse_options(struct super_block *sb, char *options)
+static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options)
 {
        char *p;
        int rc = 0;
@@ -293,7 +293,7 @@ static int ecryptfs_parse_options(struct super_block *sb, char *options)
        int fn_cipher_key_bytes;
        int fn_cipher_key_bytes_set = 0;
        struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
-               &ecryptfs_superblock_to_private(sb)->mount_crypt_stat;
+               &sbi->mount_crypt_stat;
        substring_t args[MAX_OPT_ARGS];
        int token;
        char *sig_src;
@@ -483,68 +483,7 @@ out:
 }
 
 struct kmem_cache *ecryptfs_sb_info_cache;
-
-/**
- * ecryptfs_fill_super
- * @sb: The ecryptfs super block
- * @raw_data: The options passed to mount
- * @silent: Not used but required by function prototype
- *
- * Sets up what we can of the sb, rest is done in ecryptfs_read_super
- *
- * Returns zero on success; non-zero otherwise
- */
-static int
-ecryptfs_fill_super(struct super_block *sb, void *raw_data, int silent)
-{
-       struct ecryptfs_sb_info *esi;
-       int rc = 0;
-
-       /* Released in ecryptfs_put_super() */
-       ecryptfs_set_superblock_private(sb,
-                                       kmem_cache_zalloc(ecryptfs_sb_info_cache,
-                                                        GFP_KERNEL));
-       esi = ecryptfs_superblock_to_private(sb);
-       if (!esi) {
-               ecryptfs_printk(KERN_WARNING, "Out of memory\n");
-               rc = -ENOMEM;
-               goto out;
-       }
-
-       rc = bdi_setup_and_register(&esi->bdi, "ecryptfs", BDI_CAP_MAP_COPY);
-       if (rc)
-               goto out;
-
-       sb->s_bdi = &esi->bdi;
-       sb->s_op = &ecryptfs_sops;
-       /* Released through deactivate_super(sb) from get_sb_nodev */
-       sb->s_root = d_alloc(NULL, &(const struct qstr) {
-                            .hash = 0,.name = "/",.len = 1});
-       if (!sb->s_root) {
-               ecryptfs_printk(KERN_ERR, "d_alloc failed\n");
-               rc = -ENOMEM;
-               goto out;
-       }
-       sb->s_root->d_op = &ecryptfs_dops;
-       sb->s_root->d_sb = sb;
-       sb->s_root->d_parent = sb->s_root;
-       /* Released in d_release when dput(sb->s_root) is called */
-       /* through deactivate_super(sb) from get_sb_nodev() */
-       ecryptfs_set_dentry_private(sb->s_root,
-                                   kmem_cache_zalloc(ecryptfs_dentry_info_cache,
-                                                    GFP_KERNEL));
-       if (!ecryptfs_dentry_to_private(sb->s_root)) {
-               ecryptfs_printk(KERN_ERR,
-                               "dentry_info_cache alloc failed\n");
-               rc = -ENOMEM;
-               goto out;
-       }
-       rc = 0;
-out:
-       /* Should be able to rely on deactivate_super called from
-        * get_sb_nodev */
-       return rc;
-}
+static struct file_system_type ecryptfs_fs_type;
 
 /**
  * ecryptfs_read_super
@@ -565,6 +504,13 @@ static int ecryptfs_read_super(struct super_block *sb, const char *dev_name)
                ecryptfs_printk(KERN_WARNING, "path_lookup() failed\n");
                goto out;
        }
+       if (path.dentry->d_sb->s_type == &ecryptfs_fs_type) {
+               rc = -EINVAL;
+               printk(KERN_ERR "Mount on filesystem of type "
+                       "eCryptfs explicitly disallowed due to "
+                       "known incompatibilities\n");
+               goto out_free;
+       }
        ecryptfs_set_superblock_lower(sb, path.dentry->d_sb);
        sb->s_maxbytes = path.dentry->d_sb->s_maxbytes;
        sb->s_blocksize = path.dentry->d_sb->s_blocksize;
@@ -588,11 +534,8 @@ out:
  * @dev_name: The path to mount over
  * @raw_data: The options passed into the kernel
  *
- * The whole ecryptfs_get_sb process is broken into 4 functions:
+ * The whole ecryptfs_get_sb process is broken into 3 functions:
  * ecryptfs_parse_options(): handle options passed to ecryptfs, if any
- * ecryptfs_fill_super(): used by get_sb_nodev, fills out the super_block
- *                        with as much information as it can before needing
- *                        the lower filesystem.
  * ecryptfs_read_super(): this accesses the lower filesystem and uses
  *                        ecryptfs_interpose to perform most of the linking
  * ecryptfs_interpose(): links the lower filesystem into ecryptfs (inode.c)
@@ -601,30 +544,78 @@ static int ecryptfs_get_sb(struct file_system_type *fs_type, int flags,
                        const char *dev_name, void *raw_data,
                        struct vfsmount *mnt)
 {
+       struct super_block *s;
+       struct ecryptfs_sb_info *sbi;
+       struct ecryptfs_dentry_info *root_info;
+       const char *err = "Getting sb failed";
        int rc;
-       struct super_block *sb;
 
-       rc = get_sb_nodev(fs_type, flags, raw_data, ecryptfs_fill_super, mnt);
-       if (rc < 0) {
-               printk(KERN_ERR "Getting sb failed; rc = [%d]\n", rc);
+       sbi = kmem_cache_zalloc(ecryptfs_sb_info_cache, GFP_KERNEL);
+       if (!sbi) {
+               rc = -ENOMEM;
                goto out;
        }
-       sb = mnt->mnt_sb;
-       rc = ecryptfs_parse_options(sb, raw_data);
+
+       rc = ecryptfs_parse_options(sbi, raw_data);
        if (rc) {
-               printk(KERN_ERR "Error parsing options; rc = [%d]\n", rc);
-               goto out_abort;
+               err = "Error parsing options";
+               goto out;
+       }
+
+       s = sget(fs_type, NULL, set_anon_super, NULL);
+       if (IS_ERR(s)) {
+               rc = PTR_ERR(s);
+               goto out;
        }
-       rc = ecryptfs_read_super(sb, dev_name);
+
+       s->s_flags = flags;
+       rc = bdi_setup_and_register(&sbi->bdi, "ecryptfs", BDI_CAP_MAP_COPY);
        if (rc) {
-               printk(KERN_ERR "Reading sb failed; rc = [%d]\n", rc);
-               goto out_abort;
+               deactivate_locked_super(s);
+               goto out;
        }
-       goto out;
-out_abort:
-       dput(sb->s_root); /* aka mnt->mnt_root, as set by get_sb_nodev() */
-       deactivate_locked_super(sb);
+
+       ecryptfs_set_superblock_private(s, sbi);
+       s->s_bdi = &sbi->bdi;
+
+       /* ->kill_sb() will take care of sbi after that point */
+       sbi = NULL;
+       s->s_op = &ecryptfs_sops;
+
+       rc = -ENOMEM;
+       s->s_root = d_alloc(NULL, &(const struct qstr) {
+                            .hash = 0,.name = "/",.len = 1});
+       if (!s->s_root) {
+               deactivate_locked_super(s);
+               goto out;
+       }
+       s->s_root->d_op = &ecryptfs_dops;
+       s->s_root->d_sb = s;
+       s->s_root->d_parent = s->s_root;
+
+       root_info = kmem_cache_zalloc(ecryptfs_dentry_info_cache, GFP_KERNEL);
+       if (!root_info) {
+               deactivate_locked_super(s);
+               goto out;
+       }
+       /* ->kill_sb() will take care of root_info */
+       ecryptfs_set_dentry_private(s->s_root, root_info);
+       s->s_flags |= MS_ACTIVE;
+       rc = ecryptfs_read_super(s, dev_name);
+       if (rc) {
+               deactivate_locked_super(s);
+               err = "Reading sb failed";
+               goto out;
+       }
+       simple_set_mnt(mnt, s);
+       return 0;
+
 out:
+       if (sbi) {
+               ecryptfs_destroy_mount_crypt_stat(&sbi->mount_crypt_stat);
+               kmem_cache_free(ecryptfs_sb_info_cache, sbi);
+       }
+       printk(KERN_ERR "%s; rc = [%d]\n", err, rc);
        return rc;
 }
 
@@ -633,11 +624,16 @@ out:
  * @sb: The ecryptfs super block
  *
  * Used to bring the superblock down and free the private data.
- * Private data is free'd in ecryptfs_put_super()
  */
 static void ecryptfs_kill_block_super(struct super_block *sb)
 {
-       generic_shutdown_super(sb);
+       struct ecryptfs_sb_info *sb_info = ecryptfs_superblock_to_private(sb);
+       kill_anon_super(sb);
+       if (!sb_info)
+               return;
+       ecryptfs_destroy_mount_crypt_stat(&sb_info->mount_crypt_stat);
+       bdi_destroy(&sb_info->bdi);
+       kmem_cache_free(ecryptfs_sb_info_cache, sb_info);
 }
 
 static struct file_system_type ecryptfs_fs_type = {
index 2ee9a3a7b68c4f69be50770a79bf849a79663cbe..b1d82756544be763e9841a21a0c63c7bdc20db82 100644 (file)
  * Returns locked and up-to-date page (if ok), with increased
  * refcnt.
  */
-struct page *ecryptfs_get_locked_page(struct file *file, loff_t index)
+struct page *ecryptfs_get_locked_page(struct inode *inode, loff_t index)
 {
-       struct dentry *dentry;
-       struct inode *inode;
-       struct address_space *mapping;
-       struct page *page;
-
-       dentry = file->f_path.dentry;
-       inode = dentry->d_inode;
-       mapping = inode->i_mapping;
-       page = read_mapping_page(mapping, index, (void *)file);
+       struct page *page = read_mapping_page(inode->i_mapping, index, NULL);
        if (!IS_ERR(page))
                lock_page(page);
        return page;
@@ -198,7 +190,7 @@ out:
 static int ecryptfs_readpage(struct file *file, struct page *page)
 {
        struct ecryptfs_crypt_stat *crypt_stat =
-               &ecryptfs_inode_to_private(file->f_path.dentry->d_inode)->crypt_stat;
+               &ecryptfs_inode_to_private(page->mapping->host)->crypt_stat;
        int rc = 0;
 
        if (!crypt_stat
@@ -300,8 +292,7 @@ static int ecryptfs_write_begin(struct file *file,
 
        if (!PageUptodate(page)) {
                struct ecryptfs_crypt_stat *crypt_stat =
-                       &ecryptfs_inode_to_private(
-                               file->f_path.dentry->d_inode)->crypt_stat;
+                       &ecryptfs_inode_to_private(mapping->host)->crypt_stat;
 
                if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)
                    || (crypt_stat->flags & ECRYPTFS_NEW_FILE)) {
@@ -487,7 +478,7 @@ static int ecryptfs_write_end(struct file *file,
        unsigned to = from + copied;
        struct inode *ecryptfs_inode = mapping->host;
        struct ecryptfs_crypt_stat *crypt_stat =
-               &ecryptfs_inode_to_private(file->f_path.dentry->d_inode)->crypt_stat;
+               &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat;
        int rc;
 
        if (crypt_stat->flags & ECRYPTFS_NEW_FILE) {
index 0cc4fafd6552c3d8ddef02e38a81dad96eb6ff6f..db184ef15d3d8c012ce4586d7abf276efbf6eb8a 100644 (file)
@@ -93,7 +93,7 @@ int ecryptfs_write_lower_page_segment(struct inode *ecryptfs_inode,
 
 /**
  * ecryptfs_write
- * @ecryptfs_file: The eCryptfs file into which to write
+ * @ecryptfs_inode: The eCryptfs file into which to write
  * @data: Virtual address where data to write is located
  * @offset: Offset in the eCryptfs file at which to begin writing the
  *          data from @data
@@ -109,12 +109,11 @@ int ecryptfs_write_lower_page_segment(struct inode *ecryptfs_inode,
  *
  * Returns zero on success; non-zero otherwise
  */
-int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset,
+int ecryptfs_write(struct inode *ecryptfs_inode, char *data, loff_t offset,
                   size_t size)
 {
        struct page *ecryptfs_page;
        struct ecryptfs_crypt_stat *crypt_stat;
-       struct inode *ecryptfs_inode = ecryptfs_file->f_dentry->d_inode;
        char *ecryptfs_page_virt;
        loff_t ecryptfs_file_size = i_size_read(ecryptfs_inode);
        loff_t data_offset = 0;
@@ -145,7 +144,7 @@ int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset,
                        if (num_bytes > total_remaining_zeros)
                                num_bytes = total_remaining_zeros;
                }
-               ecryptfs_page = ecryptfs_get_locked_page(ecryptfs_file,
+               ecryptfs_page = ecryptfs_get_locked_page(ecryptfs_inode,
                                                         ecryptfs_page_idx);
                if (IS_ERR(ecryptfs_page)) {
                        rc = PTR_ERR(ecryptfs_page);
@@ -302,10 +301,10 @@ int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs,
 int ecryptfs_read(char *data, loff_t offset, size_t size,
                  struct file *ecryptfs_file)
 {
+       struct inode *ecryptfs_inode = ecryptfs_file->f_dentry->d_inode;
        struct page *ecryptfs_page;
        char *ecryptfs_page_virt;
-       loff_t ecryptfs_file_size =
-               i_size_read(ecryptfs_file->f_dentry->d_inode);
+       loff_t ecryptfs_file_size = i_size_read(ecryptfs_inode);
        loff_t data_offset = 0;
        loff_t pos;
        int rc = 0;
@@ -327,7 +326,7 @@ int ecryptfs_read(char *data, loff_t offset, size_t size,
 
                if (num_bytes > total_remaining_bytes)
                        num_bytes = total_remaining_bytes;
-               ecryptfs_page = ecryptfs_get_locked_page(ecryptfs_file,
+               ecryptfs_page = ecryptfs_get_locked_page(ecryptfs_inode,
                                                         ecryptfs_page_idx);
                if (IS_ERR(ecryptfs_page)) {
                        rc = PTR_ERR(ecryptfs_page);
index 0c0ae491d231ad94568d1c003ced8b21503a6877..0435886e4a9f4afd49308ea7040db9b7d9ed52a3 100644 (file)
@@ -108,27 +108,6 @@ void ecryptfs_init_inode(struct inode *inode, struct inode *lower_inode)
        inode->i_mapping->a_ops = &ecryptfs_aops;
 }
 
-/**
- * ecryptfs_put_super
- * @sb: Pointer to the ecryptfs super block
- *
- * Final actions when unmounting a file system.
- * This will handle deallocation and release of our private data.
- */
-static void ecryptfs_put_super(struct super_block *sb)
-{
-       struct ecryptfs_sb_info *sb_info = ecryptfs_superblock_to_private(sb);
-
-       lock_kernel();
-
-       ecryptfs_destroy_mount_crypt_stat(&sb_info->mount_crypt_stat);
-       bdi_destroy(&sb_info->bdi);
-       kmem_cache_free(ecryptfs_sb_info_cache, sb_info);
-       ecryptfs_set_superblock_private(sb, NULL);
-
-       unlock_kernel();
-}
-
 /**
  * ecryptfs_statfs
  * @sb: The ecryptfs super block
@@ -203,7 +182,6 @@ const struct super_operations ecryptfs_sops = {
        .alloc_inode = ecryptfs_alloc_inode,
        .destroy_inode = ecryptfs_destroy_inode,
        .drop_inode = generic_delete_inode,
-       .put_super = ecryptfs_put_super,
        .statfs = ecryptfs_statfs,
        .remount_fs = NULL,
        .clear_inode = ecryptfs_clear_inode,
index e6e94c626c2cbebb7699597271a953b65e611e6e..e19de6a80339b3ceeae267283962f271ac6c5e55 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -242,9 +242,10 @@ static int __bprm_mm_init(struct linux_binprm *bprm)
         * use STACK_TOP because that can depend on attributes which aren't
         * configured yet.
         */
+       BUG_ON(VM_STACK_FLAGS & VM_STACK_INCOMPLETE_SETUP);
        vma->vm_end = STACK_TOP_MAX;
        vma->vm_start = vma->vm_end - PAGE_SIZE;
-       vma->vm_flags = VM_STACK_FLAGS;
+       vma->vm_flags = VM_STACK_FLAGS | VM_STACK_INCOMPLETE_SETUP;
        vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
        INIT_LIST_HEAD(&vma->anon_vma_chain);
        err = insert_vm_struct(mm, vma);
@@ -616,6 +617,7 @@ int setup_arg_pages(struct linux_binprm *bprm,
        else if (executable_stack == EXSTACK_DISABLE_X)
                vm_flags &= ~VM_EXEC;
        vm_flags |= mm->def_flags;
+       vm_flags |= VM_STACK_INCOMPLETE_SETUP;
 
        ret = mprotect_fixup(vma, &prev, vma->vm_start, vma->vm_end,
                        vm_flags);
@@ -630,6 +632,9 @@ int setup_arg_pages(struct linux_binprm *bprm,
                        goto out_unlock;
        }
 
+       /* mprotect_fixup is overkill to remove the temporary stack flags */
+       vma->vm_flags &= ~VM_STACK_INCOMPLETE_SETUP;
+
        stack_expand = 131072UL; /* randomly 32*4k (or 2*64k) pages */
        stack_size = vma->vm_end - vma->vm_start;
        /*
@@ -763,7 +768,6 @@ static int de_thread(struct task_struct *tsk)
        struct signal_struct *sig = tsk->signal;
        struct sighand_struct *oldsighand = tsk->sighand;
        spinlock_t *lock = &oldsighand->siglock;
-       int count;
 
        if (thread_group_empty(tsk))
                goto no_thread_group;
@@ -780,13 +784,13 @@ static int de_thread(struct task_struct *tsk)
                spin_unlock_irq(lock);
                return -EAGAIN;
        }
+
        sig->group_exit_task = tsk;
-       zap_other_threads(tsk);
+       sig->notify_count = zap_other_threads(tsk);
+       if (!thread_group_leader(tsk))
+               sig->notify_count--;
 
-       /* Account for the thread group leader hanging around: */
-       count = thread_group_leader(tsk) ? 1 : 2;
-       sig->notify_count = count;
-       while (atomic_read(&sig->count) > count) {
+       while (sig->notify_count) {
                __set_current_state(TASK_UNINTERRUPTIBLE);
                spin_unlock_irq(lock);
                schedule();
@@ -1657,12 +1661,15 @@ static int coredump_wait(int exit_code, struct core_state *core_state)
        struct task_struct *tsk = current;
        struct mm_struct *mm = tsk->mm;
        struct completion *vfork_done;
-       int core_waiters;
+       int core_waiters = -EBUSY;
 
        init_completion(&core_state->startup);
        core_state->dumper.task = tsk;
        core_state->dumper.next = NULL;
-       core_waiters = zap_threads(tsk, mm, core_state, exit_code);
+
+       down_write(&mm->mmap_sem);
+       if (!mm->core_state)
+               core_waiters = zap_threads(tsk, mm, core_state, exit_code);
        up_write(&mm->mmap_sem);
 
        if (unlikely(core_waiters < 0))
@@ -1782,21 +1789,61 @@ static void wait_for_dump_helpers(struct file *file)
 }
 
 
+/*
+ * uhm_pipe_setup
+ * helper function to customize the process used
+ * to collect the core in userspace.  Specifically
+ * it sets up a pipe and installs it as fd 0 (stdin)
+ * for the process.  Returns 0 on success, or
+ * PTR_ERR on failure.
+ * Note that it also sets the core limit to 1.  This
+ * is a special value that we use to trap recursive
+ * core dumps
+ */
+static int umh_pipe_setup(struct subprocess_info *info)
+{
+       struct file *rp, *wp;
+       struct fdtable *fdt;
+       struct coredump_params *cp = (struct coredump_params *)info->data;
+       struct files_struct *cf = current->files;
+
+       wp = create_write_pipe(0);
+       if (IS_ERR(wp))
+               return PTR_ERR(wp);
+
+       rp = create_read_pipe(wp, 0);
+       if (IS_ERR(rp)) {
+               free_write_pipe(wp);
+               return PTR_ERR(rp);
+       }
+
+       cp->file = wp;
+
+       sys_close(0);
+       fd_install(0, rp);
+       spin_lock(&cf->file_lock);
+       fdt = files_fdtable(cf);
+       FD_SET(0, fdt->open_fds);
+       FD_CLR(0, fdt->close_on_exec);
+       spin_unlock(&cf->file_lock);
+
+       /* and disallow core files too */
+       current->signal->rlim[RLIMIT_CORE] = (struct rlimit){1, 1};
+
+       return 0;
+}
+
 void do_coredump(long signr, int exit_code, struct pt_regs *regs)
 {
        struct core_state core_state;
        char corename[CORENAME_MAX_SIZE + 1];
        struct mm_struct *mm = current->mm;
        struct linux_binfmt * binfmt;
-       struct inode * inode;
        const struct cred *old_cred;
        struct cred *cred;
        int retval = 0;
        int flag = 0;
-       int ispipe = 0;
-       char **helper_argv = NULL;
-       int helper_argc = 0;
-       int dump_count = 0;
+       int ispipe;
        static atomic_t core_dump_count = ATOMIC_INIT(0);
        struct coredump_params cprm = {
                .signr = signr,
@@ -1815,23 +1862,12 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
        binfmt = mm->binfmt;
        if (!binfmt || !binfmt->core_dump)
                goto fail;
-
-       cred = prepare_creds();
-       if (!cred) {
-               retval = -ENOMEM;
+       if (!__get_dumpable(cprm.mm_flags))
                goto fail;
-       }
 
-       down_write(&mm->mmap_sem);
-       /*
-        * If another thread got here first, or we are not dumpable, bail out.
-        */
-       if (mm->core_state || !__get_dumpable(cprm.mm_flags)) {
-               up_write(&mm->mmap_sem);
-               put_cred(cred);
+       cred = prepare_creds();
+       if (!cred)
                goto fail;
-       }
-
        /*
         *      We cannot trust fsuid as being the "true" uid of the
         *      process nor do we know its entire history. We only know it
@@ -1844,10 +1880,8 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
        }
 
        retval = coredump_wait(exit_code, &core_state);
-       if (retval < 0) {
-               put_cred(cred);
-               goto fail;
-       }
+       if (retval < 0)
+               goto fail_creds;
 
        old_cred = override_creds(cred);
 
@@ -1865,19 +1899,19 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
        ispipe = format_corename(corename, signr);
        unlock_kernel();
 
-       if ((!ispipe) && (cprm.limit < binfmt->min_coredump))
-               goto fail_unlock;
-
        if (ispipe) {
-               if (cprm.limit == 0) {
+               int dump_count;
+               char **helper_argv;
+
+               if (cprm.limit == 1) {
                        /*
                         * Normally core limits are irrelevant to pipes, since
                         * we're not writing to the file system, but we use
-                        * cprm.limit of 0 here as a speacial value. Any
-                        * non-zero limit gets set to RLIM_INFINITY below, but
+                        * cprm.limit of 1 here as a speacial value. Any
+                        * non-1 limit gets set to RLIM_INFINITY below, but
                         * a limit of 0 skips the dump.  This is a consistent
                         * way to catch recursive crashes.  We can still crash
-                        * if the core_pattern binary sets RLIM_CORE =  !0
+                        * if the core_pattern binary sets RLIM_CORE =  !1
                         * but it runs as root, and can do lots of stupid things
                         * Note that we use task_tgid_vnr here to grab the pid
                         * of the process group leader.  That way we get the
@@ -1885,11 +1919,12 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
                         * core_pattern process dies.
                         */
                        printk(KERN_WARNING
-                               "Process %d(%s) has RLIMIT_CORE set to 0\n",
+                               "Process %d(%s) has RLIMIT_CORE set to 1\n",
                                task_tgid_vnr(current), current->comm);
                        printk(KERN_WARNING "Aborting core\n");
                        goto fail_unlock;
                }
+               cprm.limit = RLIM_INFINITY;
 
                dump_count = atomic_inc_return(&core_dump_count);
                if (core_pipe_limit && (core_pipe_limit < dump_count)) {
@@ -1899,71 +1934,74 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
                        goto fail_dropcount;
                }
 
-               helper_argv = argv_split(GFP_KERNEL, corename+1, &helper_argc);
+               helper_argv = argv_split(GFP_KERNEL, corename+1, NULL);
                if (!helper_argv) {
                        printk(KERN_WARNING "%s failed to allocate memory\n",
                               __func__);
                        goto fail_dropcount;
                }
 
-               cprm.limit = RLIM_INFINITY;
-
-               /* SIGPIPE can happen, but it's just never processed */
-               if (call_usermodehelper_pipe(helper_argv[0], helper_argv, NULL,
-                               &cprm.file)) {
+               retval = call_usermodehelper_fns(helper_argv[0], helper_argv,
+                                       NULL, UMH_WAIT_EXEC, umh_pipe_setup,
+                                       NULL, &cprm);
+               argv_free(helper_argv);
+               if (retval) {
                        printk(KERN_INFO "Core dump to %s pipe failed\n",
                               corename);
-                       goto fail_dropcount;
+                       goto close_fail;
                }
-       } else
+       } else {
+               struct inode *inode;
+
+               if (cprm.limit < binfmt->min_coredump)
+                       goto fail_unlock;
+
                cprm.file = filp_open(corename,
                                 O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag,
                                 0600);
-       if (IS_ERR(cprm.file))
-               goto fail_dropcount;
-       inode = cprm.file->f_path.dentry->d_inode;
-       if (inode->i_nlink > 1)
-               goto close_fail;        /* multiple links - don't dump */
-       if (!ispipe && d_unhashed(cprm.file->f_path.dentry))
-               goto close_fail;
-
-       /* AK: actually i see no reason to not allow this for named pipes etc.,
-          but keep the previous behaviour for now. */
-       if (!ispipe && !S_ISREG(inode->i_mode))
-               goto close_fail;
-       /*
-        * Dont allow local users get cute and trick others to coredump
-        * into their pre-created files:
-        * Note, this is not relevant for pipes
-        */
-       if (!ispipe && (inode->i_uid != current_fsuid()))
-               goto close_fail;
-       if (!cprm.file->f_op)
-               goto close_fail;
-       if (!cprm.file->f_op->write)
-               goto close_fail;
-       if (!ispipe &&
-           do_truncate(cprm.file->f_path.dentry, 0, 0, cprm.file) != 0)
-               goto close_fail;
+               if (IS_ERR(cprm.file))
+                       goto fail_unlock;
 
-       retval = binfmt->core_dump(&cprm);
+               inode = cprm.file->f_path.dentry->d_inode;
+               if (inode->i_nlink > 1)
+                       goto close_fail;
+               if (d_unhashed(cprm.file->f_path.dentry))
+                       goto close_fail;
+               /*
+                * AK: actually i see no reason to not allow this for named
+                * pipes etc, but keep the previous behaviour for now.
+                */
+               if (!S_ISREG(inode->i_mode))
+                       goto close_fail;
+               /*
+                * Dont allow local users get cute and trick others to coredump
+                * into their pre-created files.
+                */
+               if (inode->i_uid != current_fsuid())
+                       goto close_fail;
+               if (!cprm.file->f_op || !cprm.file->f_op->write)
+                       goto close_fail;
+               if (do_truncate(cprm.file->f_path.dentry, 0, 0, cprm.file))
+                       goto close_fail;
+       }
 
+       retval = binfmt->core_dump(&cprm);
        if (retval)
                current->signal->group_exit_code |= 0x80;
-close_fail:
+
        if (ispipe && core_pipe_limit)
                wait_for_dump_helpers(cprm.file);
-       filp_close(cprm.file, NULL);
+close_fail:
+       if (cprm.file)
+               filp_close(cprm.file, NULL);
 fail_dropcount:
-       if (dump_count)
+       if (ispipe)
                atomic_dec(&core_dump_count);
 fail_unlock:
-       if (helper_argv)
-               argv_free(helper_argv);
-
+       coredump_finish(mm);
        revert_creds(old_cred);
+fail_creds:
        put_cred(cred);
-       coredump_finish(mm);
 fail:
        return;
 }
index 4cfab1cc75c03a0bb7654e5c8150c2009fe4aa11..d91e9d829bc1bcc52cce4c4965d375a3eb7d356f 100644 (file)
@@ -608,7 +608,7 @@ int exofs_make_empty(struct inode *inode, struct inode *parent)
        de->inode_no = cpu_to_le64(parent->i_ino);
        memcpy(de->name, PARENT_DIR, sizeof(PARENT_DIR));
        exofs_set_de_type(de, inode);
-       kunmap_atomic(page, KM_USER0);
+       kunmap_atomic(kaddr, KM_USER0);
        err = exofs_commit_chunk(page, 0, chunk_size);
 fail:
        page_cache_release(page);
index 839b9dc1e70f3f6663a428e2d48938f6aadfcb0c..fef6899be397b6cd0f7694938859208e842632db 100644 (file)
@@ -40,12 +40,11 @@ static int exofs_release_file(struct inode *inode, struct file *filp)
        return 0;
 }
 
-static int exofs_file_fsync(struct file *filp, struct dentry *dentry,
-                           int datasync)
+static int exofs_file_fsync(struct file *filp, int datasync)
 {
        int ret;
        struct address_space *mapping = filp->f_mapping;
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = mapping->host;
        struct super_block *sb;
 
        ret = filemap_write_and_wait(mapping);
@@ -66,7 +65,7 @@ static int exofs_file_fsync(struct file *filp, struct dentry *dentry,
 
 static int exofs_flush(struct file *file, fl_owner_t id)
 {
-       exofs_file_fsync(file, file->f_path.dentry, 1);
+       exofs_file_fsync(file, 1);
        /* TODO: Flush the OSD target */
        return 0;
 }
index 76d2a79ef93e887900928f4dc8115ada961a0e29..4bb6ef822e46d8daba3b312afbb4258aab7ea1ee 100644 (file)
@@ -755,6 +755,21 @@ static int exofs_write_end(struct file *file, struct address_space *mapping,
        return ret;
 }
 
+static int exofs_releasepage(struct page *page, gfp_t gfp)
+{
+       EXOFS_DBGMSG("page 0x%lx\n", page->index);
+       WARN_ON(1);
+       return try_to_free_buffers(page);
+}
+
+static void exofs_invalidatepage(struct page *page, unsigned long offset)
+{
+       EXOFS_DBGMSG("page_has_buffers=>%d\n", page_has_buffers(page));
+       WARN_ON(1);
+
+       block_invalidatepage(page, offset);
+}
+
 const struct address_space_operations exofs_aops = {
        .readpage       = exofs_readpage,
        .readpages      = exofs_readpages,
@@ -762,6 +777,21 @@ const struct address_space_operations exofs_aops = {
        .writepages     = exofs_writepages,
        .write_begin    = exofs_write_begin_export,
        .write_end      = exofs_write_end,
+       .releasepage    = exofs_releasepage,
+       .set_page_dirty = __set_page_dirty_nobuffers,
+       .invalidatepage = exofs_invalidatepage,
+
+       /* Not implemented Yet */
+       .bmap           = NULL, /* TODO: use osd's OSD_ACT_READ_MAP */
+       .direct_IO      = NULL, /* TODO: Should be trivial to do */
+
+       /* With these NULL has special meaning or default is not exported */
+       .sync_page      = NULL,
+       .get_xip_mem    = NULL,
+       .migratepage    = NULL,
+       .launder_page   = NULL,
+       .is_partially_uptodate = NULL,
+       .error_remove_page = NULL,
 };
 
 /******************************************************************************
@@ -1123,16 +1153,7 @@ struct inode *exofs_new_inode(struct inode *dir, int mode)
        sbi = sb->s_fs_info;
 
        sb->s_dirt = 1;
-       inode->i_uid = current->cred->fsuid;
-       if (dir->i_mode & S_ISGID) {
-               inode->i_gid = dir->i_gid;
-               if (S_ISDIR(mode))
-                       mode |= S_ISGID;
-       } else {
-               inode->i_gid = current->cred->fsgid;
-       }
-       inode->i_mode = mode;
-
+       inode_init_owner(inode, dir, mode);
        inode->i_ino = sbi->s_nextid++;
        inode->i_blkbits = EXOFS_BLKSHIFT;
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
index a99e54318c3d3570c8953b7bde1625e1060254de..ca7e2a0ed98a7ec9cbab179178db11f87a8cb9b6 100644 (file)
@@ -420,7 +420,7 @@ release_and_out:
        return error;
 }
 
-struct xattr_handler ext2_xattr_acl_access_handler = {
+const struct xattr_handler ext2_xattr_acl_access_handler = {
        .prefix = POSIX_ACL_XATTR_ACCESS,
        .flags  = ACL_TYPE_ACCESS,
        .list   = ext2_xattr_list_acl_access,
@@ -428,7 +428,7 @@ struct xattr_handler ext2_xattr_acl_access_handler = {
        .set    = ext2_xattr_set_acl,
 };
 
-struct xattr_handler ext2_xattr_acl_default_handler = {
+const struct xattr_handler ext2_xattr_acl_default_handler = {
        .prefix = POSIX_ACL_XATTR_DEFAULT,
        .flags  = ACL_TYPE_DEFAULT,
        .list   = ext2_xattr_list_acl_default,
index 0b038e47ad2fa1b86f88c04768c7ebab1cb78a09..52b34f1d27383b1189ef61d1a45ce650782ad0f7 100644 (file)
@@ -122,7 +122,6 @@ extern int ext2_write_inode (struct inode *, struct writeback_control *);
 extern void ext2_delete_inode (struct inode *);
 extern int ext2_sync_inode (struct inode *);
 extern int ext2_get_block(struct inode *, sector_t, struct buffer_head *, int);
-extern void ext2_truncate (struct inode *);
 extern int ext2_setattr (struct dentry *, struct iattr *);
 extern void ext2_set_inode_flags(struct inode *inode);
 extern void ext2_get_inode_flags(struct ext2_inode_info *);
@@ -155,7 +154,7 @@ extern void ext2_write_super (struct super_block *);
 extern const struct file_operations ext2_dir_operations;
 
 /* file.c */
-extern int ext2_fsync(struct file *file, struct dentry *dentry, int datasync);
+extern int ext2_fsync(struct file *file, int datasync);
 extern const struct inode_operations ext2_file_inode_operations;
 extern const struct file_operations ext2_file_operations;
 extern const struct file_operations ext2_xip_file_operations;
index 5d198d0697fbe969d4a5c268374c8d15874ad97e..49eec9456c5b3dc47dbf4fa102e0c81c656beda5 100644 (file)
@@ -40,13 +40,13 @@ static int ext2_release_file (struct inode * inode, struct file * filp)
        return 0;
 }
 
-int ext2_fsync(struct file *file, struct dentry *dentry, int datasync)
+int ext2_fsync(struct file *file, int datasync)
 {
        int ret;
-       struct super_block *sb = dentry->d_inode->i_sb;
+       struct super_block *sb = file->f_mapping->host->i_sb;
        struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping;
 
-       ret = simple_fsync(file, dentry, datasync);
+       ret = generic_file_fsync(file, datasync);
        if (ret == -EIO || test_and_clear_bit(AS_EIO, &mapping->flags)) {
                /* We don't really know where the IO error happened... */
                ext2_error(sb, __func__,
@@ -95,7 +95,6 @@ const struct file_operations ext2_xip_file_operations = {
 #endif
 
 const struct inode_operations ext2_file_inode_operations = {
-       .truncate       = ext2_truncate,
 #ifdef CONFIG_EXT2_FS_XATTR
        .setxattr       = generic_setxattr,
        .getxattr       = generic_getxattr,
index f0c5286f93420bcace66816f5491b7f35729de36..938dbc739d00e9c1e7695e25b76f24c34727738b 100644 (file)
@@ -549,16 +549,12 @@ got:
 
        sb->s_dirt = 1;
        mark_buffer_dirty(bh2);
-       inode->i_uid = current_fsuid();
-       if (test_opt (sb, GRPID))
+       if (test_opt(sb, GRPID)) {
+               inode->i_mode = mode;
+               inode->i_uid = current_fsuid();
                inode->i_gid = dir->i_gid;
-       else if (dir->i_mode & S_ISGID) {
-               inode->i_gid = dir->i_gid;
-               if (S_ISDIR(mode))
-                       mode |= S_ISGID;
        } else
-               inode->i_gid = current_fsgid();
-       inode->i_mode = mode;
+               inode_init_owner(inode, dir, mode);
 
        inode->i_ino = ino;
        inode->i_blocks = 0;
index 527c46d9bc1f035148ab5cb8598954feac481ede..19214435b75213cbbd6b4ba557194476e30654bd 100644 (file)
@@ -54,6 +54,18 @@ static inline int ext2_inode_is_fast_symlink(struct inode *inode)
                inode->i_blocks - ea_blocks == 0);
 }
 
+static void ext2_truncate_blocks(struct inode *inode, loff_t offset);
+
+static void ext2_write_failed(struct address_space *mapping, loff_t to)
+{
+       struct inode *inode = mapping->host;
+
+       if (to > inode->i_size) {
+               truncate_pagecache(inode, to, inode->i_size);
+               ext2_truncate_blocks(inode, inode->i_size);
+       }
+}
+
 /*
  * Called at the last iput() if i_nlink is zero.
  */
@@ -71,7 +83,7 @@ void ext2_delete_inode (struct inode * inode)
 
        inode->i_size = 0;
        if (inode->i_blocks)
-               ext2_truncate (inode);
+               ext2_truncate_blocks(inode, 0);
        ext2_free_inode (inode);
 
        return;
@@ -757,8 +769,8 @@ 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(file, mapping, pos, len, flags, pagep, fsdata,
-                                                       ext2_get_block);
+       return block_write_begin_newtrunc(file, mapping, pos, len, flags,
+                                       pagep, fsdata, ext2_get_block);
 }
 
 static int
@@ -766,8 +778,25 @@ ext2_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 __ext2_write_begin(file, mapping, pos, len, flags, pagep,fsdata);
+       ret = __ext2_write_begin(file, mapping, pos, len, flags, pagep, fsdata);
+       if (ret < 0)
+               ext2_write_failed(mapping, pos + len);
+       return ret;
+}
+
+static int ext2_write_end(struct file *file, struct address_space *mapping,
+                       loff_t pos, unsigned len, unsigned copied,
+                       struct page *page, void *fsdata)
+{
+       int ret;
+
+       ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
+       if (ret < len)
+               ext2_write_failed(mapping, pos + len);
+       return ret;
 }
 
 static int
@@ -775,13 +804,18 @@ ext2_nobh_write_begin(struct file *file, struct address_space *mapping,
                loff_t pos, unsigned len, unsigned flags,
                struct page **pagep, void **fsdata)
 {
+       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.
         */
-       return nobh_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
-                                                       ext2_get_block);
+       ret = nobh_write_begin_newtrunc(file, mapping, pos, len, flags, pagep,
+                                               fsdata, ext2_get_block);
+       if (ret < 0)
+               ext2_write_failed(mapping, pos + len);
+       return ret;
 }
 
 static int ext2_nobh_writepage(struct page *page,
@@ -800,10 +834,15 @@ ext2_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
                        loff_t offset, unsigned long nr_segs)
 {
        struct file *file = iocb->ki_filp;
-       struct inode *inode = file->f_mapping->host;
-
-       return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
-                               offset, nr_segs, ext2_get_block, NULL);
+       struct address_space *mapping = file->f_mapping;
+       struct inode *inode = mapping->host;
+       ssize_t ret;
+
+       ret = blockdev_direct_IO_newtrunc(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));
+       return ret;
 }
 
 static int
@@ -818,7 +857,7 @@ const struct address_space_operations ext2_aops = {
        .writepage              = ext2_writepage,
        .sync_page              = block_sync_page,
        .write_begin            = ext2_write_begin,
-       .write_end              = generic_write_end,
+       .write_end              = ext2_write_end,
        .bmap                   = ext2_bmap,
        .direct_IO              = ext2_direct_IO,
        .writepages             = ext2_writepages,
@@ -1027,7 +1066,7 @@ static void ext2_free_branches(struct inode *inode, __le32 *p, __le32 *q, int de
                ext2_free_data(inode, p, q);
 }
 
-void ext2_truncate(struct inode *inode)
+static void __ext2_truncate_blocks(struct inode *inode, loff_t offset)
 {
        __le32 *i_data = EXT2_I(inode)->i_data;
        struct ext2_inode_info *ei = EXT2_I(inode);
@@ -1039,27 +1078,8 @@ void ext2_truncate(struct inode *inode)
        int n;
        long iblock;
        unsigned blocksize;
-
-       if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
-           S_ISLNK(inode->i_mode)))
-               return;
-       if (ext2_inode_is_fast_symlink(inode))
-               return;
-       if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
-               return;
-
        blocksize = inode->i_sb->s_blocksize;
-       iblock = (inode->i_size + blocksize-1)
-                                       >> EXT2_BLOCK_SIZE_BITS(inode->i_sb);
-
-       if (mapping_is_xip(inode->i_mapping))
-               xip_truncate_page(inode->i_mapping, inode->i_size);
-       else if (test_opt(inode->i_sb, NOBH))
-               nobh_truncate_page(inode->i_mapping,
-                               inode->i_size, ext2_get_block);
-       else
-               block_truncate_page(inode->i_mapping,
-                               inode->i_size, ext2_get_block);
+       iblock = (offset + blocksize-1) >> EXT2_BLOCK_SIZE_BITS(inode->i_sb);
 
        n = ext2_block_to_path(inode, iblock, offsets, NULL);
        if (n == 0)
@@ -1127,6 +1147,62 @@ do_indirects:
        ext2_discard_reservation(inode);
 
        mutex_unlock(&ei->truncate_mutex);
+}
+
+static void ext2_truncate_blocks(struct inode *inode, loff_t offset)
+{
+       /*
+        * XXX: it seems like a bug here that we don't allow
+        * IS_APPEND inode to have blocks-past-i_size trimmed off.
+        * review and fix this.
+        *
+        * Also would be nice to be able to handle IO errors and such,
+        * but that's probably too much to ask.
+        */
+       if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+           S_ISLNK(inode->i_mode)))
+               return;
+       if (ext2_inode_is_fast_symlink(inode))
+               return;
+       if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+               return;
+       __ext2_truncate_blocks(inode, offset);
+}
+
+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;
+       if (ext2_inode_is_fast_symlink(inode))
+               return -EINVAL;
+       if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+               return -EPERM;
+
+       if (mapping_is_xip(inode->i_mapping))
+               error = xip_truncate_page(inode->i_mapping, newsize);
+       else if (test_opt(inode->i_sb, NOBH))
+               error = nobh_truncate_page(inode->i_mapping,
+                               newsize, ext2_get_block);
+       else
+               error = block_truncate_page(inode->i_mapping,
+                               newsize, ext2_get_block);
+       if (error)
+               return error;
+
+       oldsize = inode->i_size;
+       i_size_write(inode, newsize);
+       truncate_pagecache(inode, oldsize, newsize);
+
+       __ext2_truncate_blocks(inode, newsize);
+
        inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
        if (inode_needs_sync(inode)) {
                sync_mapping_buffers(inode->i_mapping);
@@ -1134,6 +1210,8 @@ do_indirects:
        } else {
                mark_inode_dirty(inode);
        }
+
+       return 0;
 }
 
 static struct ext2_inode *ext2_get_inode(struct super_block *sb, ino_t ino,
@@ -1474,8 +1552,15 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr)
                if (error)
                        return error;
        }
-       error = inode_setattr(inode, iattr);
-       if (!error && (iattr->ia_valid & ATTR_MODE))
+       if (iattr->ia_valid & ATTR_SIZE) {
+               error = ext2_setsize(inode, iattr->ia_size);
+               if (error)
+                       return error;
+       }
+       generic_setattr(inode, iattr);
+       if (iattr->ia_valid & ATTR_MODE)
                error = ext2_acl_chmod(inode);
+       mark_inode_dirty(inode);
+
        return error;
 }
index 71e9eb1fa69680e6a029f90064d485c28070c0bc..7ff43f4a59cd4c0af8cd71b0ccd2b37123dbf448 100644 (file)
@@ -119,6 +119,8 @@ static void ext2_put_super (struct super_block * sb)
        int i;
        struct ext2_sb_info *sbi = EXT2_SB(sb);
 
+       dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);
+
        if (sb->s_dirt)
                ext2_write_super(sb);
 
@@ -1063,6 +1065,12 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_op = &ext2_sops;
        sb->s_export_op = &ext2_export_ops;
        sb->s_xattr = ext2_xattr_handlers;
+
+#ifdef CONFIG_QUOTA
+       sb->dq_op = &dquot_operations;
+       sb->s_qcop = &dquot_quotactl_ops;
+#endif
+
        root = ext2_iget(sb, EXT2_ROOT_INO);
        if (IS_ERR(root)) {
                ret = PTR_ERR(root);
@@ -1241,6 +1249,7 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
                        spin_unlock(&sbi->s_lock);
                        return 0;
                }
+
                /*
                 * OK, we are remounting a valid rw partition rdonly, so set
                 * the rdonly flag and then mark the partition as valid again.
@@ -1248,6 +1257,13 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
                es->s_state = cpu_to_le16(sbi->s_mount_state);
                es->s_mtime = cpu_to_le32(get_seconds());
                spin_unlock(&sbi->s_lock);
+
+               err = dquot_suspend(sb, -1);
+               if (err < 0) {
+                       spin_lock(&sbi->s_lock);
+                       goto restore_opts;
+               }
+
                ext2_sync_super(sb, es, 1);
        } else {
                __le32 ret = EXT2_HAS_RO_COMPAT_FEATURE(sb,
@@ -1269,8 +1285,12 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
                if (!ext2_setup_super (sb, es, 0))
                        sb->s_flags &= ~MS_RDONLY;
                spin_unlock(&sbi->s_lock);
+
                ext2_write_super(sb);
+
+               dquot_resume(sb, -1);
        }
+
        return 0;
 restore_opts:
        sbi->s_mount_opt = old_opts.s_mount_opt;
index 3b96045a00ce3c6d804d5b119b7fc74801d3bc46..7c3915780b19dd049586dc2e027822d12fd47826 100644 (file)
@@ -101,7 +101,7 @@ static void ext2_xattr_rehash(struct ext2_xattr_header *,
 
 static struct mb_cache *ext2_xattr_cache;
 
-static struct xattr_handler *ext2_xattr_handler_map[] = {
+static const struct xattr_handler *ext2_xattr_handler_map[] = {
        [EXT2_XATTR_INDEX_USER]              = &ext2_xattr_user_handler,
 #ifdef CONFIG_EXT2_FS_POSIX_ACL
        [EXT2_XATTR_INDEX_POSIX_ACL_ACCESS]  = &ext2_xattr_acl_access_handler,
@@ -113,7 +113,7 @@ static struct xattr_handler *ext2_xattr_handler_map[] = {
 #endif
 };
 
-struct xattr_handler *ext2_xattr_handlers[] = {
+const struct xattr_handler *ext2_xattr_handlers[] = {
        &ext2_xattr_user_handler,
        &ext2_xattr_trusted_handler,
 #ifdef CONFIG_EXT2_FS_POSIX_ACL
@@ -126,10 +126,10 @@ struct xattr_handler *ext2_xattr_handlers[] = {
        NULL
 };
 
-static inline struct xattr_handler *
+static inline const struct xattr_handler *
 ext2_xattr_handler(int name_index)
 {
-       struct xattr_handler *handler = NULL;
+       const struct xattr_handler *handler = NULL;
 
        if (name_index > 0 && name_index < ARRAY_SIZE(ext2_xattr_handler_map))
                handler = ext2_xattr_handler_map[name_index];
@@ -298,7 +298,7 @@ bad_block:  ext2_error(inode->i_sb, "ext2_xattr_list",
        /* list the attribute names */
        for (entry = FIRST_ENTRY(bh); !IS_LAST_ENTRY(entry);
             entry = EXT2_XATTR_NEXT(entry)) {
-               struct xattr_handler *handler =
+               const struct xattr_handler *handler =
                        ext2_xattr_handler(entry->e_name_index);
 
                if (handler) {
index bf8175b2ced95ed1cb69ed541f76437dbe2f29f0..a1a1c2184616594c240151b115460856b53cfccf 100644 (file)
@@ -55,11 +55,11 @@ struct ext2_xattr_entry {
 
 # ifdef CONFIG_EXT2_FS_XATTR
 
-extern struct xattr_handler ext2_xattr_user_handler;
-extern struct xattr_handler ext2_xattr_trusted_handler;
-extern struct xattr_handler ext2_xattr_acl_access_handler;
-extern struct xattr_handler ext2_xattr_acl_default_handler;
-extern struct xattr_handler ext2_xattr_security_handler;
+extern const struct xattr_handler ext2_xattr_user_handler;
+extern const struct xattr_handler ext2_xattr_trusted_handler;
+extern const struct xattr_handler ext2_xattr_acl_access_handler;
+extern const struct xattr_handler ext2_xattr_acl_default_handler;
+extern const struct xattr_handler ext2_xattr_security_handler;
 
 extern ssize_t ext2_listxattr(struct dentry *, char *, size_t);
 
@@ -72,7 +72,7 @@ extern void ext2_xattr_put_super(struct super_block *);
 extern int init_ext2_xattr(void);
 extern void exit_ext2_xattr(void);
 
-extern struct xattr_handler *ext2_xattr_handlers[];
+extern const struct xattr_handler *ext2_xattr_handlers[];
 
 # else  /* CONFIG_EXT2_FS_XATTR */
 
index b118c6383c6d0d05647cf66011eeec4298b1f927..3004e15d5da53a711e064981aeaab3cba7334e8c 100644 (file)
@@ -67,7 +67,7 @@ ext2_init_security(struct inode *inode, struct inode *dir)
        return err;
 }
 
-struct xattr_handler ext2_xattr_security_handler = {
+const struct xattr_handler ext2_xattr_security_handler = {
        .prefix = XATTR_SECURITY_PREFIX,
        .list   = ext2_xattr_security_list,
        .get    = ext2_xattr_security_get,
index 2a26d71f47713031764c3ed19d82881f6d0a6712..667e46a8d62dcf71652cce3676f1e80486824899 100644 (file)
@@ -50,7 +50,7 @@ ext2_xattr_trusted_set(struct dentry *dentry, const char *name,
                              value, size, flags);
 }
 
-struct xattr_handler ext2_xattr_trusted_handler = {
+const struct xattr_handler ext2_xattr_trusted_handler = {
        .prefix = XATTR_TRUSTED_PREFIX,
        .list   = ext2_xattr_trusted_list,
        .get    = ext2_xattr_trusted_get,
index 3f6caf3684b47ebc42c1dfd310067eb07d18b8c0..099d20f47163efe808af86746ff2a5184faa3f56 100644 (file)
@@ -54,7 +54,7 @@ ext2_xattr_user_set(struct dentry *dentry, const char *name,
                              name, value, size, flags);
 }
 
-struct xattr_handler ext2_xattr_user_handler = {
+const struct xattr_handler ext2_xattr_user_handler = {
        .prefix = XATTR_USER_PREFIX,
        .list   = ext2_xattr_user_list,
        .get    = ext2_xattr_user_get,
index 82ba34158661f89a323cda8e86c85d9b8652cbe9..01552abbca3c0f9c47549ed6be812074a7632f1d 100644 (file)
@@ -456,7 +456,7 @@ release_and_out:
        return error;
 }
 
-struct xattr_handler ext3_xattr_acl_access_handler = {
+const struct xattr_handler ext3_xattr_acl_access_handler = {
        .prefix = POSIX_ACL_XATTR_ACCESS,
        .flags  = ACL_TYPE_ACCESS,
        .list   = ext3_xattr_list_acl_access,
@@ -464,7 +464,7 @@ struct xattr_handler ext3_xattr_acl_access_handler = {
        .set    = ext3_xattr_set_acl,
 };
 
-struct xattr_handler ext3_xattr_acl_default_handler = {
+const struct xattr_handler ext3_xattr_acl_default_handler = {
        .prefix = POSIX_ACL_XATTR_DEFAULT,
        .flags  = ACL_TYPE_DEFAULT,
        .list   = ext3_xattr_list_acl_default,
index 373fa90c796a0821c23cd441c0a238a1a52cfb69..e2e72c367cf671e0d13abf0015225d7162709d54 100644 (file)
@@ -297,7 +297,7 @@ static void free_rb_tree_fname(struct rb_root *root)
                        kfree (old);
                }
                if (!parent)
-                       root->rb_node = NULL;
+                       *root = RB_ROOT;
                else if (parent->rb_left == n)
                        parent->rb_left = NULL;
                else if (parent->rb_right == n)
index fcf7487734b68d24d851014f3556aa4f199fe7a3..d7e9f74dc3a6d7e6b02f65d9b54fb9a22ca2d764 100644 (file)
@@ -43,9 +43,9 @@
  * inode to disk.
  */
 
-int ext3_sync_file(struct file * file, struct dentry *dentry, int datasync)
+int ext3_sync_file(struct file *file, int datasync)
 {
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = file->f_mapping->host;
        struct ext3_inode_info *ei = EXT3_I(inode);
        journal_t *journal = EXT3_SB(inode->i_sb)->s_journal;
        int ret, needs_barrier = 0;
index 0d0e97ed3ff6029659837f1394a4827506eb1704..498021eb88fb46477a68518698ba71a236804def 100644 (file)
@@ -538,16 +538,13 @@ got:
        if (S_ISDIR(mode))
                percpu_counter_inc(&sbi->s_dirs_counter);
 
-       inode->i_uid = current_fsuid();
-       if (test_opt (sb, GRPID))
-               inode->i_gid = dir->i_gid;
-       else if (dir->i_mode & S_ISGID) {
+
+       if (test_opt(sb, GRPID)) {
+               inode->i_mode = mode;
+               inode->i_uid = current_fsuid();
                inode->i_gid = dir->i_gid;
-               if (S_ISDIR(mode))
-                       mode |= S_ISGID;
        } else
-               inode->i_gid = current_fsgid();
-       inode->i_mode = mode;
+               inode_init_owner(inode, dir, mode);
 
        inode->i_ino = ino;
        /* This is the optimal IO size (for stat), not the fs block size */
index 0fc1293d0e96140b07f232b0934b161931599fbe..6c953bb255e760d4109cb35871a42827f69c4a77 100644 (file)
@@ -410,6 +410,8 @@ static void ext3_put_super (struct super_block * sb)
        struct ext3_super_block *es = sbi->s_es;
        int i, err;
 
+       dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);
+
        lock_kernel();
 
        ext3_xattr_put_super(sb);
@@ -748,7 +750,7 @@ static int ext3_release_dquot(struct dquot *dquot);
 static int ext3_mark_dquot_dirty(struct dquot *dquot);
 static int ext3_write_info(struct super_block *sb, int type);
 static int ext3_quota_on(struct super_block *sb, int type, int format_id,
-                               char *path, int remount);
+                               char *path);
 static int ext3_quota_on_mount(struct super_block *sb, int type);
 static ssize_t ext3_quota_read(struct super_block *sb, int type, char *data,
                               size_t len, loff_t off);
@@ -767,12 +769,12 @@ static const struct dquot_operations ext3_quota_operations = {
 
 static const struct quotactl_ops ext3_qctl_operations = {
        .quota_on       = ext3_quota_on,
-       .quota_off      = vfs_quota_off,
-       .quota_sync     = vfs_quota_sync,
-       .get_info       = vfs_get_dqinfo,
-       .set_info       = vfs_set_dqinfo,
-       .get_dqblk      = vfs_get_dqblk,
-       .set_dqblk      = vfs_set_dqblk
+       .quota_off      = dquot_quota_off,
+       .quota_sync     = dquot_quota_sync,
+       .get_info       = dquot_get_dqinfo,
+       .set_info       = dquot_set_dqinfo,
+       .get_dqblk      = dquot_get_dqblk,
+       .set_dqblk      = dquot_set_dqblk
 };
 #endif
 
@@ -1527,7 +1529,7 @@ static void ext3_orphan_cleanup (struct super_block * sb,
        /* Turn quotas off */
        for (i = 0; i < MAXQUOTAS; i++) {
                if (sb_dqopt(sb)->files[i])
-                       vfs_quota_off(sb, i, 0);
+                       dquot_quota_off(sb, i);
        }
 #endif
        sb->s_flags = s_flags; /* Restore MS_RDONLY status */
@@ -2551,6 +2553,7 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
        ext3_fsblk_t n_blocks_count = 0;
        unsigned long old_sb_flags;
        struct ext3_mount_options old_opts;
+       int enable_quota = 0;
        int err;
 #ifdef CONFIG_QUOTA
        int i;
@@ -2597,6 +2600,10 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
                }
 
                if (*flags & MS_RDONLY) {
+                       err = dquot_suspend(sb, -1);
+                       if (err < 0)
+                               goto restore_opts;
+
                        /*
                         * First of all, the unconditional stuff we have to do
                         * to disable replay of the journal when we next remount
@@ -2651,6 +2658,7 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
                                goto restore_opts;
                        if (!ext3_setup_super (sb, es, 0))
                                sb->s_flags &= ~MS_RDONLY;
+                       enable_quota = 1;
                }
        }
 #ifdef CONFIG_QUOTA
@@ -2662,6 +2670,9 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
 #endif
        unlock_super(sb);
        unlock_kernel();
+
+       if (enable_quota)
+               dquot_resume(sb, -1);
        return 0;
 restore_opts:
        sb->s_flags = old_sb_flags;
@@ -2851,24 +2862,21 @@ static int ext3_write_info(struct super_block *sb, int type)
  */
 static int ext3_quota_on_mount(struct super_block *sb, int type)
 {
-       return vfs_quota_on_mount(sb, EXT3_SB(sb)->s_qf_names[type],
-                       EXT3_SB(sb)->s_jquota_fmt, type);
+       return dquot_quota_on_mount(sb, EXT3_SB(sb)->s_qf_names[type],
+                                       EXT3_SB(sb)->s_jquota_fmt, type);
 }
 
 /*
  * Standard function to be called on quota_on
  */
 static int ext3_quota_on(struct super_block *sb, int type, int format_id,
-                        char *name, int remount)
+                        char *name)
 {
        int err;
        struct path path;
 
        if (!test_opt(sb, QUOTA))
                return -EINVAL;
-       /* When remounting, no checks are needed and in fact, name is NULL */
-       if (remount)
-               return vfs_quota_on(sb, type, format_id, name, remount);
 
        err = kern_path(name, LOOKUP_FOLLOW, &path);
        if (err)
@@ -2906,7 +2914,7 @@ static int ext3_quota_on(struct super_block *sb, int type, int format_id,
                }
        }
 
-       err = vfs_quota_on_path(sb, type, format_id, &path);
+       err = dquot_quota_on_path(sb, type, format_id, &path);
        path_put(&path);
        return err;
 }
index 534a94c3a93338a843cd050ef99ee03f9304d4a2..71fb8d65e54cbc74c3b79ec44fecfcdfa53766b0 100644 (file)
@@ -104,7 +104,7 @@ static int ext3_xattr_list(struct dentry *dentry, char *buffer,
 
 static struct mb_cache *ext3_xattr_cache;
 
-static struct xattr_handler *ext3_xattr_handler_map[] = {
+static const struct xattr_handler *ext3_xattr_handler_map[] = {
        [EXT3_XATTR_INDEX_USER]              = &ext3_xattr_user_handler,
 #ifdef CONFIG_EXT3_FS_POSIX_ACL
        [EXT3_XATTR_INDEX_POSIX_ACL_ACCESS]  = &ext3_xattr_acl_access_handler,
@@ -116,7 +116,7 @@ static struct xattr_handler *ext3_xattr_handler_map[] = {
 #endif
 };
 
-struct xattr_handler *ext3_xattr_handlers[] = {
+const struct xattr_handler *ext3_xattr_handlers[] = {
        &ext3_xattr_user_handler,
        &ext3_xattr_trusted_handler,
 #ifdef CONFIG_EXT3_FS_POSIX_ACL
@@ -129,10 +129,10 @@ struct xattr_handler *ext3_xattr_handlers[] = {
        NULL
 };
 
-static inline struct xattr_handler *
+static inline const struct xattr_handler *
 ext3_xattr_handler(int name_index)
 {
-       struct xattr_handler *handler = NULL;
+       const struct xattr_handler *handler = NULL;
 
        if (name_index > 0 && name_index < ARRAY_SIZE(ext3_xattr_handler_map))
                handler = ext3_xattr_handler_map[name_index];
@@ -338,7 +338,7 @@ ext3_xattr_list_entries(struct dentry *dentry, struct ext3_xattr_entry *entry,
        size_t rest = buffer_size;
 
        for (; !IS_LAST_ENTRY(entry); entry = EXT3_XATTR_NEXT(entry)) {
-               struct xattr_handler *handler =
+               const struct xattr_handler *handler =
                        ext3_xattr_handler(entry->e_name_index);
 
                if (handler) {
index 148a4dfc82abf220fb45a71c7de5425cddb0025f..377fe720116995caa90f94821bfe808e2c0e4b9b 100644 (file)
@@ -58,11 +58,11 @@ struct ext3_xattr_entry {
 
 # ifdef CONFIG_EXT3_FS_XATTR
 
-extern struct xattr_handler ext3_xattr_user_handler;
-extern struct xattr_handler ext3_xattr_trusted_handler;
-extern struct xattr_handler ext3_xattr_acl_access_handler;
-extern struct xattr_handler ext3_xattr_acl_default_handler;
-extern struct xattr_handler ext3_xattr_security_handler;
+extern const struct xattr_handler ext3_xattr_user_handler;
+extern const struct xattr_handler ext3_xattr_trusted_handler;
+extern const struct xattr_handler ext3_xattr_acl_access_handler;
+extern const struct xattr_handler ext3_xattr_acl_default_handler;
+extern const struct xattr_handler ext3_xattr_security_handler;
 
 extern ssize_t ext3_listxattr(struct dentry *, char *, size_t);
 
@@ -76,7 +76,7 @@ extern void ext3_xattr_put_super(struct super_block *);
 extern int init_ext3_xattr(void);
 extern void exit_ext3_xattr(void);
 
-extern struct xattr_handler *ext3_xattr_handlers[];
+extern const struct xattr_handler *ext3_xattr_handlers[];
 
 # else  /* CONFIG_EXT3_FS_XATTR */
 
index 3af91f476dff738f36eb5949c6d40487de4386f9..03a99bfc59f90f1f7331251e70e71ce9f94253af 100644 (file)
@@ -69,7 +69,7 @@ ext3_init_security(handle_t *handle, struct inode *inode, struct inode *dir)
        return err;
 }
 
-struct xattr_handler ext3_xattr_security_handler = {
+const struct xattr_handler ext3_xattr_security_handler = {
        .prefix = XATTR_SECURITY_PREFIX,
        .list   = ext3_xattr_security_list,
        .get    = ext3_xattr_security_get,
index e5562845ed9624f57d3ce8bd80c87cd4e2113f68..dc8edda9ffe0e1247c3e10c8e2960a81f911f823 100644 (file)
@@ -51,7 +51,7 @@ ext3_xattr_trusted_set(struct dentry *dentry, const char *name,
                              value, size, flags);
 }
 
-struct xattr_handler ext3_xattr_trusted_handler = {
+const struct xattr_handler ext3_xattr_trusted_handler = {
        .prefix = XATTR_TRUSTED_PREFIX,
        .list   = ext3_xattr_trusted_list,
        .get    = ext3_xattr_trusted_get,
index 3bcfe9ee0a68bfe35191ffc1e29df26ef3f0c964..7a321974d584ad1d3c87c23ec5a8b6644f3b9466 100644 (file)
@@ -54,7 +54,7 @@ ext3_xattr_user_set(struct dentry *dentry, const char *name,
                              name, value, size, flags);
 }
 
-struct xattr_handler ext3_xattr_user_handler = {
+const struct xattr_handler ext3_xattr_user_handler = {
        .prefix = XATTR_USER_PREFIX,
        .list   = ext3_xattr_user_list,
        .get    = ext3_xattr_user_get,
index 8a2a29d35a6fe57598d306b06df5eed01489cc7b..feaf498feaa68ee709ea216de5ef87b85d209bcd 100644 (file)
@@ -454,7 +454,7 @@ release_and_out:
        return error;
 }
 
-struct xattr_handler ext4_xattr_acl_access_handler = {
+const struct xattr_handler ext4_xattr_acl_access_handler = {
        .prefix = POSIX_ACL_XATTR_ACCESS,
        .flags  = ACL_TYPE_ACCESS,
        .list   = ext4_xattr_list_acl_access,
@@ -462,7 +462,7 @@ struct xattr_handler ext4_xattr_acl_access_handler = {
        .set    = ext4_xattr_set_acl,
 };
 
-struct xattr_handler ext4_xattr_acl_default_handler = {
+const struct xattr_handler ext4_xattr_acl_default_handler = {
        .prefix = POSIX_ACL_XATTR_DEFAULT,
        .flags  = ACL_TYPE_DEFAULT,
        .list   = ext4_xattr_list_acl_default,
index d2f37a5516c76c68ed5ddc6c47471ef4f16d9df3..95b7594c76f909d5b029e9d80001f90ef99e45a4 100644 (file)
@@ -591,14 +591,15 @@ ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode,
        ret = ext4_mb_new_blocks(handle, &ar, errp);
        if (count)
                *count = ar.len;
-
        /*
-        * Account for the allocated meta blocks
+        * Account for the allocated meta blocks.  We will never
+        * fail EDQUOT for metdata, but we do account for it.
         */
        if (!(*errp) && EXT4_I(inode)->i_delalloc_reserved_flag) {
                spin_lock(&EXT4_I(inode)->i_block_reservation_lock);
                EXT4_I(inode)->i_allocated_meta_blocks += ar.len;
                spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
+               dquot_alloc_block_nofail(inode, ar.len);
        }
        return ret;
 }
index 538c48655084594482d94c3ff38e949f4cb6ffd7..5b6973fbf1bdde32bb1c2a4b6ff73a9d2df9d692 100644 (file)
@@ -72,9 +72,9 @@ static int add_system_zone(struct ext4_sb_info *sbi,
                else if (start_blk >= (entry->start_blk + entry->count))
                        n = &(*n)->rb_right;
                else {
-                       if (start_blk + count > (entry->start_blk + 
+                       if (start_blk + count > (entry->start_blk +
                                                 entry->count))
-                               entry->count = (start_blk + count - 
+                               entry->count = (start_blk + count -
                                                entry->start_blk);
                        new_node = *n;
                        new_entry = rb_entry(new_node, struct ext4_system_zone,
index 86cb6d86a04806d260d0078efff6c45d4eb9d633..ea5e6cb7e2a5e345b514d10b5f39a54ec021dbfe 100644 (file)
@@ -83,11 +83,10 @@ int ext4_check_dir_entry(const char *function, struct inode *dir,
                error_msg = "inode out of bounds";
 
        if (error_msg != NULL)
-               __ext4_error(dir->i_sb, function,
-                       "bad entry in directory #%lu: %s - block=%llu"
+               ext4_error_inode(function, dir,
+                       "bad entry in directory: %s - block=%llu"
                        "offset=%u(%u), inode=%u, rec_len=%d, name_len=%d",
-                       dir->i_ino, error_msg, 
-                       (unsigned long long) bh->b_blocknr,     
+                       error_msg, (unsigned long long) bh->b_blocknr,
                        (unsigned) (offset%bh->b_size), offset,
                        le32_to_cpu(de->inode),
                        rlen, de->name_len);
@@ -111,7 +110,7 @@ static int ext4_readdir(struct file *filp,
 
        if (EXT4_HAS_COMPAT_FEATURE(inode->i_sb,
                                    EXT4_FEATURE_COMPAT_DIR_INDEX) &&
-           ((EXT4_I(inode)->i_flags & EXT4_INDEX_FL) ||
+           ((ext4_test_inode_flag(inode, EXT4_INODE_INDEX)) ||
             ((inode->i_size >> sb->s_blocksize_bits) == 1))) {
                err = ext4_dx_readdir(filp, dirent, filldir);
                if (err != ERR_BAD_DX_DIR) {
@@ -122,20 +121,20 @@ static int ext4_readdir(struct file *filp,
                 * We don't set the inode dirty flag since it's not
                 * critical that it get flushed back to the disk.
                 */
-               EXT4_I(filp->f_path.dentry->d_inode)->i_flags &= ~EXT4_INDEX_FL;
+               ext4_clear_inode_flag(filp->f_path.dentry->d_inode, EXT4_INODE_INDEX);
        }
        stored = 0;
        offset = filp->f_pos & (sb->s_blocksize - 1);
 
        while (!error && !stored && filp->f_pos < inode->i_size) {
-               ext4_lblk_t blk = filp->f_pos >> EXT4_BLOCK_SIZE_BITS(sb);
-               struct buffer_head map_bh;
+               struct ext4_map_blocks map;
                struct buffer_head *bh = NULL;
 
-               map_bh.b_state = 0;
-               err = ext4_get_blocks(NULL, inode, blk, 1, &map_bh, 0);
+               map.m_lblk = filp->f_pos >> EXT4_BLOCK_SIZE_BITS(sb);
+               map.m_len = 1;
+               err = ext4_map_blocks(NULL, inode, &map, 0);
                if (err > 0) {
-                       pgoff_t index = map_bh.b_blocknr >>
+                       pgoff_t index = map.m_pblk >>
                                        (PAGE_CACHE_SHIFT - inode->i_blkbits);
                        if (!ra_has_index(&filp->f_ra, index))
                                page_cache_sync_readahead(
@@ -143,7 +142,7 @@ static int ext4_readdir(struct file *filp,
                                        &filp->f_ra, filp,
                                        index, 1);
                        filp->f_ra.prev_pos = (loff_t)index << PAGE_CACHE_SHIFT;
-                       bh = ext4_bread(NULL, inode, blk, 0, &err);
+                       bh = ext4_bread(NULL, inode, map.m_lblk, 0, &err);
                }
 
                /*
@@ -152,9 +151,8 @@ static int ext4_readdir(struct file *filp,
                 */
                if (!bh) {
                        if (!dir_has_error) {
-                               ext4_error(sb, "directory #%lu "
+                               EXT4_ERROR_INODE(inode, "directory "
                                           "contains a hole at offset %Lu",
-                                          inode->i_ino,
                                           (unsigned long long) filp->f_pos);
                                dir_has_error = 1;
                        }
index bf938cf7c5f0f273330dc02223e5ddc88dc28b86..19a4de57128ad7e493ec7843050d1fccc7bda8a4 100644 (file)
@@ -29,6 +29,9 @@
 #include <linux/wait.h>
 #include <linux/blockgroup_lock.h>
 #include <linux/percpu_counter.h>
+#ifdef __KERNEL__
+#include <linux/compat.h>
+#endif
 
 /*
  * The fourth extended filesystem constants/structures
 #endif
 
 #define EXT4_ERROR_INODE(inode, fmt, a...) \
-       ext4_error_inode(__func__, (inode), (fmt), ## a);
+       ext4_error_inode(__func__, (inode), (fmt), ## a)
 
 #define EXT4_ERROR_FILE(file, fmt, a...)       \
-       ext4_error_file(__func__, (file), (fmt), ## a);
+       ext4_error_file(__func__, (file), (fmt), ## a)
 
 /* data type for block offset of block group */
 typedef int ext4_grpblk_t;
@@ -72,7 +75,7 @@ typedef __u32 ext4_lblk_t;
 typedef unsigned int ext4_group_t;
 
 /*
- * Flags used in mballoc's allocation_context flags field.  
+ * Flags used in mballoc's allocation_context flags field.
  *
  * Also used to show what's going on for debugging purposes when the
  * flag field is exported via the traceport interface
@@ -125,6 +128,29 @@ struct ext4_allocation_request {
        unsigned int flags;
 };
 
+/*
+ * Logical to physical block mapping, used by ext4_map_blocks()
+ *
+ * This structure is used to pass requests into ext4_map_blocks() as
+ * well as to store the information returned by ext4_map_blocks().  It
+ * takes less room on the stack than a struct buffer_head.
+ */
+#define EXT4_MAP_NEW           (1 << BH_New)
+#define EXT4_MAP_MAPPED                (1 << BH_Mapped)
+#define EXT4_MAP_UNWRITTEN     (1 << BH_Unwritten)
+#define EXT4_MAP_BOUNDARY      (1 << BH_Boundary)
+#define EXT4_MAP_UNINIT                (1 << BH_Uninit)
+#define EXT4_MAP_FLAGS         (EXT4_MAP_NEW | EXT4_MAP_MAPPED |\
+                                EXT4_MAP_UNWRITTEN | EXT4_MAP_BOUNDARY |\
+                                EXT4_MAP_UNINIT)
+
+struct ext4_map_blocks {
+       ext4_fsblk_t m_pblk;
+       ext4_lblk_t m_lblk;
+       unsigned int m_len;
+       unsigned int m_flags;
+};
+
 /*
  * For delayed allocation tracking
  */
@@ -321,6 +347,83 @@ static inline __u32 ext4_mask_flags(umode_t mode, __u32 flags)
                return flags & EXT4_OTHER_FLMASK;
 }
 
+/*
+ * Inode flags used for atomic set/get
+ */
+enum {
+       EXT4_INODE_SECRM        = 0,    /* Secure deletion */
+       EXT4_INODE_UNRM         = 1,    /* Undelete */
+       EXT4_INODE_COMPR        = 2,    /* Compress file */
+       EXT4_INODE_SYNC         = 3,    /* Synchronous updates */
+       EXT4_INODE_IMMUTABLE    = 4,    /* Immutable file */
+       EXT4_INODE_APPEND       = 5,    /* writes to file may only append */
+       EXT4_INODE_NODUMP       = 6,    /* do not dump file */
+       EXT4_INODE_NOATIME      = 7,    /* do not update atime */
+/* Reserved for compression usage... */
+       EXT4_INODE_DIRTY        = 8,
+       EXT4_INODE_COMPRBLK     = 9,    /* One or more compressed clusters */
+       EXT4_INODE_NOCOMPR      = 10,   /* Don't compress */
+       EXT4_INODE_ECOMPR       = 11,   /* Compression error */
+/* End compression flags --- maybe not all used */
+       EXT4_INODE_INDEX        = 12,   /* hash-indexed directory */
+       EXT4_INODE_IMAGIC       = 13,   /* AFS directory */
+       EXT4_INODE_JOURNAL_DATA = 14,   /* file data should be journaled */
+       EXT4_INODE_NOTAIL       = 15,   /* file tail should not be merged */
+       EXT4_INODE_DIRSYNC      = 16,   /* dirsync behaviour (directories only) */
+       EXT4_INODE_TOPDIR       = 17,   /* Top of directory hierarchies*/
+       EXT4_INODE_HUGE_FILE    = 18,   /* Set to each huge file */
+       EXT4_INODE_EXTENTS      = 19,   /* Inode uses extents */
+       EXT4_INODE_EA_INODE     = 21,   /* Inode used for large EA */
+       EXT4_INODE_EOFBLOCKS    = 22,   /* Blocks allocated beyond EOF */
+       EXT4_INODE_RESERVED     = 31,   /* reserved for ext4 lib */
+};
+
+#define TEST_FLAG_VALUE(FLAG) (EXT4_##FLAG##_FL == (1 << EXT4_INODE_##FLAG))
+#define CHECK_FLAG_VALUE(FLAG) if (!TEST_FLAG_VALUE(FLAG)) { \
+       printk(KERN_EMERG "EXT4 flag fail: " #FLAG ": %d %d\n", \
+               EXT4_##FLAG##_FL, EXT4_INODE_##FLAG); BUG_ON(1); }
+
+/*
+ * Since it's pretty easy to mix up bit numbers and hex values, and we
+ * can't do a compile-time test for ENUM values, we use a run-time
+ * test to make sure that EXT4_XXX_FL is consistent with respect to
+ * EXT4_INODE_XXX.  If all is well the printk and BUG_ON will all drop
+ * out so it won't cost any extra space in the compiled kernel image.
+ * But it's important that these values are the same, since we are
+ * using EXT4_INODE_XXX to test for the flag values, but EXT4_XX_FL
+ * must be consistent with the values of FS_XXX_FL defined in
+ * include/linux/fs.h and the on-disk values found in ext2, ext3, and
+ * ext4 filesystems, and of course the values defined in e2fsprogs.
+ *
+ * It's not paranoia if the Murphy's Law really *is* out to get you.  :-)
+ */
+static inline void ext4_check_flag_values(void)
+{
+       CHECK_FLAG_VALUE(SECRM);
+       CHECK_FLAG_VALUE(UNRM);
+       CHECK_FLAG_VALUE(COMPR);
+       CHECK_FLAG_VALUE(SYNC);
+       CHECK_FLAG_VALUE(IMMUTABLE);
+       CHECK_FLAG_VALUE(APPEND);
+       CHECK_FLAG_VALUE(NODUMP);
+       CHECK_FLAG_VALUE(NOATIME);
+       CHECK_FLAG_VALUE(DIRTY);
+       CHECK_FLAG_VALUE(COMPRBLK);
+       CHECK_FLAG_VALUE(NOCOMPR);
+       CHECK_FLAG_VALUE(ECOMPR);
+       CHECK_FLAG_VALUE(INDEX);
+       CHECK_FLAG_VALUE(IMAGIC);
+       CHECK_FLAG_VALUE(JOURNAL_DATA);
+       CHECK_FLAG_VALUE(NOTAIL);
+       CHECK_FLAG_VALUE(DIRSYNC);
+       CHECK_FLAG_VALUE(TOPDIR);
+       CHECK_FLAG_VALUE(HUGE_FILE);
+       CHECK_FLAG_VALUE(EXTENTS);
+       CHECK_FLAG_VALUE(EA_INODE);
+       CHECK_FLAG_VALUE(EOFBLOCKS);
+       CHECK_FLAG_VALUE(RESERVED);
+}
+
 /* Used to pass group descriptor data when online resize is done */
 struct ext4_new_group_input {
        __u32 group;            /* Group number for this data */
@@ -332,6 +435,18 @@ struct ext4_new_group_input {
        __u16 unused;
 };
 
+#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
+struct compat_ext4_new_group_input {
+       u32 group;
+       compat_u64 block_bitmap;
+       compat_u64 inode_bitmap;
+       compat_u64 inode_table;
+       u32 blocks_count;
+       u16 reserved_blocks;
+       u16 unused;
+};
+#endif
+
 /* The struct ext4_new_group_input in kernel space, with free_blocks_count */
 struct ext4_new_group_data {
        __u32 group;
@@ -355,7 +470,7 @@ struct ext4_new_group_data {
 #define EXT4_GET_BLOCKS_CREATE_UNINIT_EXT      (EXT4_GET_BLOCKS_UNINIT_EXT|\
                                                 EXT4_GET_BLOCKS_CREATE)
        /* Caller is from the delayed allocation writeout path,
-          so set the magic i_delalloc_reserve_flag after taking the 
+          so set the magic i_delalloc_reserve_flag after taking the
           inode allocation semaphore for */
 #define EXT4_GET_BLOCKS_DELALLOC_RESERVE       0x0004
        /* caller is from the direct IO path, request to creation of an
@@ -398,6 +513,7 @@ struct ext4_new_group_data {
 #define EXT4_IOC_ALLOC_DA_BLKS         _IO('f', 12)
 #define EXT4_IOC_MOVE_EXT              _IOWR('f', 15, struct move_extent)
 
+#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
 /*
  * ioctl commands in 32 bit emulation
  */
@@ -408,11 +524,13 @@ struct ext4_new_group_data {
 #define EXT4_IOC32_GETRSVSZ            _IOR('f', 5, int)
 #define EXT4_IOC32_SETRSVSZ            _IOW('f', 6, int)
 #define EXT4_IOC32_GROUP_EXTEND                _IOW('f', 7, unsigned int)
+#define EXT4_IOC32_GROUP_ADD           _IOW('f', 8, struct compat_ext4_new_group_input)
 #ifdef CONFIG_JBD2_DEBUG
 #define EXT4_IOC32_WAIT_FOR_READONLY   _IOR('f', 99, int)
 #endif
 #define EXT4_IOC32_GETVERSION_OLD      FS_IOC32_GETVERSION
 #define EXT4_IOC32_SETVERSION_OLD      FS_IOC32_SETVERSION
+#endif
 
 
 /*
@@ -616,9 +734,8 @@ struct ext4_ext_cache {
  */
 struct ext4_inode_info {
        __le32  i_data[15];     /* unconverted */
-       __u32   i_flags;
-       ext4_fsblk_t    i_file_acl;
        __u32   i_dtime;
+       ext4_fsblk_t    i_file_acl;
 
        /*
         * i_block_group is the number of the block group which contains
@@ -629,6 +746,7 @@ struct ext4_inode_info {
         */
        ext4_group_t    i_block_group;
        unsigned long   i_state_flags;          /* Dynamic state flags */
+       unsigned long   i_flags;
 
        ext4_lblk_t             i_dir_start_lookup;
 #ifdef CONFIG_EXT4_FS_XATTR
@@ -1062,22 +1180,25 @@ enum {
        EXT4_STATE_DA_ALLOC_CLOSE,      /* Alloc DA blks on close */
        EXT4_STATE_EXT_MIGRATE,         /* Inode is migrating */
        EXT4_STATE_DIO_UNWRITTEN,       /* need convert on dio done*/
+       EXT4_STATE_NEWENTRY,            /* File just added to dir */
 };
 
-static inline int ext4_test_inode_state(struct inode *inode, int bit)
-{
-       return test_bit(bit, &EXT4_I(inode)->i_state_flags);
-}
-
-static inline void ext4_set_inode_state(struct inode *inode, int bit)
-{
-       set_bit(bit, &EXT4_I(inode)->i_state_flags);
+#define EXT4_INODE_BIT_FNS(name, field)                                        \
+static inline int ext4_test_inode_##name(struct inode *inode, int bit) \
+{                                                                      \
+       return test_bit(bit, &EXT4_I(inode)->i_##field);                \
+}                                                                      \
+static inline void ext4_set_inode_##name(struct inode *inode, int bit) \
+{                                                                      \
+       set_bit(bit, &EXT4_I(inode)->i_##field);                        \
+}                                                                      \
+static inline void ext4_clear_inode_##name(struct inode *inode, int bit) \
+{                                                                      \
+       clear_bit(bit, &EXT4_I(inode)->i_##field);                      \
 }
 
-static inline void ext4_clear_inode_state(struct inode *inode, int bit)
-{
-       clear_bit(bit, &EXT4_I(inode)->i_state_flags);
-}
+EXT4_INODE_BIT_FNS(flag, flags)
+EXT4_INODE_BIT_FNS(state, state_flags)
 #else
 /* Assume that user mode programs are passing in an ext4fs superblock, not
  * a kernel struct super_block.  This will allow us to call the feature-test
@@ -1264,7 +1385,7 @@ struct ext4_dir_entry_2 {
 
 #define is_dx(dir) (EXT4_HAS_COMPAT_FEATURE(dir->i_sb, \
                                      EXT4_FEATURE_COMPAT_DIR_INDEX) && \
-                     (EXT4_I(dir)->i_flags & EXT4_INDEX_FL))
+                   ext4_test_inode_flag((dir), EXT4_INODE_INDEX))
 #define EXT4_DIR_LINK_MAX(dir) (!is_dx(dir) && (dir)->i_nlink >= EXT4_LINK_MAX)
 #define EXT4_DIR_LINK_EMPTY(dir) ((dir)->i_nlink == 2 || (dir)->i_nlink == 1)
 
@@ -1398,7 +1519,7 @@ extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
 extern void ext4_htree_free_dir_info(struct dir_private_info *p);
 
 /* fsync.c */
-extern int ext4_sync_file(struct file *, struct dentry *, int);
+extern int ext4_sync_file(struct file *, int);
 
 /* hash.c */
 extern int ext4fs_dirhash(const char *name, int len, struct
@@ -1678,6 +1799,7 @@ struct ext4_group_info {
        ext4_grpblk_t   bb_first_free;  /* first free block */
        ext4_grpblk_t   bb_free;        /* total free blocks */
        ext4_grpblk_t   bb_fragments;   /* nr of freespace fragments */
+       ext4_grpblk_t   bb_largest_free_order;/* order of largest frag in BG */
        struct          list_head bb_prealloc_list;
 #ifdef DOUBLE_CHECK
        void            *bb_bitmap;
@@ -1772,9 +1894,8 @@ extern int ext4_ext_tree_init(handle_t *handle, struct inode *);
 extern int ext4_ext_writepage_trans_blocks(struct inode *, int);
 extern int ext4_ext_index_trans_blocks(struct inode *inode, int nrblocks,
                                       int chunk);
-extern int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
-                              ext4_lblk_t iblock, unsigned int max_blocks,
-                              struct buffer_head *bh_result, int flags);
+extern int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
+                              struct ext4_map_blocks *map, int flags);
 extern void ext4_ext_truncate(struct inode *);
 extern void ext4_ext_init(struct super_block *);
 extern void ext4_ext_release(struct super_block *);
@@ -1782,6 +1903,8 @@ extern long ext4_fallocate(struct inode *inode, int mode, loff_t offset,
                          loff_t len);
 extern int ext4_convert_unwritten_extents(struct inode *inode, loff_t offset,
                          ssize_t len);
+extern int ext4_map_blocks(handle_t *handle, struct inode *inode,
+                          struct ext4_map_blocks *map, int flags);
 extern int ext4_get_blocks(handle_t *handle, struct inode *inode,
                           sector_t block, unsigned int max_blocks,
                           struct buffer_head *bh, int flags);
index b79ad5126468867efb31cab9835517e38e3bce04..dade0c024797f7fed6082ea4dff6de927d698afd 100644 (file)
@@ -273,7 +273,7 @@ static inline int ext4_should_journal_data(struct inode *inode)
                return 1;
        if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
                return 1;
-       if (EXT4_I(inode)->i_flags & EXT4_JOURNAL_DATA_FL)
+       if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA))
                return 1;
        return 0;
 }
@@ -284,7 +284,7 @@ static inline int ext4_should_order_data(struct inode *inode)
                return 0;
        if (!S_ISREG(inode->i_mode))
                return 0;
-       if (EXT4_I(inode)->i_flags & EXT4_JOURNAL_DATA_FL)
+       if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA))
                return 0;
        if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA)
                return 1;
@@ -297,7 +297,7 @@ static inline int ext4_should_writeback_data(struct inode *inode)
                return 0;
        if (EXT4_JOURNAL(inode) == NULL)
                return 1;
-       if (EXT4_I(inode)->i_flags & EXT4_JOURNAL_DATA_FL)
+       if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA))
                return 0;
        if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)
                return 1;
@@ -321,7 +321,7 @@ static inline int ext4_should_dioread_nolock(struct inode *inode)
                return 0;
        if (!S_ISREG(inode->i_mode))
                return 0;
-       if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL))
+       if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
                return 0;
        if (ext4_should_journal_data(inode))
                return 0;
index 236b834b4ca811913f98caf6c9a264844fe8f7de..377309c1af65fe91be76bef857fe39288551ae9d 100644 (file)
@@ -107,11 +107,8 @@ static int ext4_ext_truncate_extend_restart(handle_t *handle,
        if (err <= 0)
                return err;
        err = ext4_truncate_restart_trans(handle, inode, needed);
-       /*
-        * We have dropped i_data_sem so someone might have cached again
-        * an extent we are going to truncate.
-        */
-       ext4_ext_invalidate_cache(inode);
+       if (err == 0)
+               err = -EAGAIN;
 
        return err;
 }
@@ -185,10 +182,10 @@ static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode,
        if (flex_size >= EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME) {
                /*
                 * If there are at least EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME
-                * block groups per flexgroup, reserve the first block 
-                * group for directories and special files.  Regular 
+                * block groups per flexgroup, reserve the first block
+                * group for directories and special files.  Regular
                 * files will start at the second block group.  This
-                * tends to speed up directory access and improves 
+                * tends to speed up directory access and improves
                 * fsck times.
                 */
                block_group &= ~(flex_size-1);
@@ -439,10 +436,10 @@ static int __ext4_ext_check(const char *function, struct inode *inode,
        return 0;
 
 corrupted:
-       __ext4_error(inode->i_sb, function,
-                       "bad header/extent in inode #%lu: %s - magic %x, "
+       ext4_error_inode(function, inode,
+                       "bad header/extent: %s - magic %x, "
                        "entries %u, max %u(%u), depth %u(%u)",
-                       inode->i_ino, error_msg, le16_to_cpu(eh->eh_magic),
+                       error_msg, le16_to_cpu(eh->eh_magic),
                        le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max),
                        max, le16_to_cpu(eh->eh_depth), depth);
 
@@ -1622,9 +1619,7 @@ int ext4_ext_try_to_merge(struct inode *inode,
                merge_done = 1;
                WARN_ON(eh->eh_entries == 0);
                if (!eh->eh_entries)
-                       ext4_error(inode->i_sb,
-                                  "inode#%lu, eh->eh_entries = 0!",
-                                  inode->i_ino);
+                       EXT4_ERROR_INODE(inode, "eh->eh_entries = 0!");
        }
 
        return merge_done;
@@ -2039,7 +2034,7 @@ ext4_ext_in_cache(struct inode *inode, ext4_lblk_t block,
        struct ext4_ext_cache *cex;
        int ret = EXT4_EXT_CACHE_NO;
 
-       /* 
+       /*
         * We borrow i_block_reservation_lock to protect i_cached_extent
         */
        spin_lock(&EXT4_I(inode)->i_block_reservation_lock);
@@ -2361,7 +2356,7 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start)
        int depth = ext_depth(inode);
        struct ext4_ext_path *path;
        handle_t *handle;
-       int i = 0, err = 0;
+       int i, err;
 
        ext_debug("truncate since %u\n", start);
 
@@ -2370,23 +2365,26 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start)
        if (IS_ERR(handle))
                return PTR_ERR(handle);
 
+again:
        ext4_ext_invalidate_cache(inode);
 
        /*
         * We start scanning from right side, freeing all the blocks
         * after i_size and walking into the tree depth-wise.
         */
+       depth = ext_depth(inode);
        path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 1), GFP_NOFS);
        if (path == NULL) {
                ext4_journal_stop(handle);
                return -ENOMEM;
        }
+       path[0].p_depth = depth;
        path[0].p_hdr = ext_inode_hdr(inode);
        if (ext4_ext_check(inode, path[0].p_hdr, depth)) {
                err = -EIO;
                goto out;
        }
-       path[0].p_depth = depth;
+       i = err = 0;
 
        while (i >= 0 && err == 0) {
                if (i == depth) {
@@ -2480,6 +2478,8 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start)
 out:
        ext4_ext_drop_refs(path);
        kfree(path);
+       if (err == -EAGAIN)
+               goto again;
        ext4_journal_stop(handle);
 
        return err;
@@ -2544,7 +2544,7 @@ static void bi_complete(struct bio *bio, int error)
 /* FIXME!! we need to try to merge to left or right after zero-out  */
 static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex)
 {
-       int ret = -EIO;
+       int ret;
        struct bio *bio;
        int blkbits, blocksize;
        sector_t ee_pblock;
@@ -2568,6 +2568,9 @@ static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex)
                        len = ee_len;
 
                bio = bio_alloc(GFP_NOIO, len);
+               if (!bio)
+                       return -ENOMEM;
+
                bio->bi_sector = ee_pblock;
                bio->bi_bdev   = inode->i_sb->s_bdev;
 
@@ -2595,22 +2598,20 @@ static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex)
                submit_bio(WRITE, bio);
                wait_for_completion(&event);
 
-               if (test_bit(BIO_UPTODATE, &bio->bi_flags))
-                       ret = 0;
-               else {
-                       ret = -EIO;
-                       break;
+               if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) {
+                       bio_put(bio);
+                       return -EIO;
                }
                bio_put(bio);
                ee_len    -= done;
                ee_pblock += done  << (blkbits - 9);
        }
-       return ret;
+       return 0;
 }
 
 #define EXT4_EXT_ZERO_LEN 7
 /*
- * This function is called by ext4_ext_get_blocks() if someone tries to write
+ * This function is called by ext4_ext_map_blocks() if someone tries to write
  * to an uninitialized extent. It may result in splitting the uninitialized
  * extent into multiple extents (upto three - one initialized and two
  * uninitialized).
@@ -2620,39 +2621,55 @@ static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex)
  *   c> Splits in three extents: Somone is writing in middle of the extent
  */
 static int ext4_ext_convert_to_initialized(handle_t *handle,
-                                               struct inode *inode,
-                                               struct ext4_ext_path *path,
-                                               ext4_lblk_t iblock,
-                                               unsigned int max_blocks)
+                                          struct inode *inode,
+                                          struct ext4_map_blocks *map,
+                                          struct ext4_ext_path *path)
 {
        struct ext4_extent *ex, newex, orig_ex;
        struct ext4_extent *ex1 = NULL;
        struct ext4_extent *ex2 = NULL;
        struct ext4_extent *ex3 = NULL;
        struct ext4_extent_header *eh;
-       ext4_lblk_t ee_block;
+       ext4_lblk_t ee_block, eof_block;
        unsigned int allocated, ee_len, depth;
        ext4_fsblk_t newblock;
        int err = 0;
        int ret = 0;
+       int may_zeroout;
+
+       ext_debug("ext4_ext_convert_to_initialized: inode %lu, logical"
+               "block %llu, max_blocks %u\n", inode->i_ino,
+               (unsigned long long)map->m_lblk, map->m_len);
+
+       eof_block = (inode->i_size + inode->i_sb->s_blocksize - 1) >>
+               inode->i_sb->s_blocksize_bits;
+       if (eof_block < map->m_lblk + map->m_len)
+               eof_block = map->m_lblk + map->m_len;
 
        depth = ext_depth(inode);
        eh = path[depth].p_hdr;
        ex = path[depth].p_ext;
        ee_block = le32_to_cpu(ex->ee_block);
        ee_len = ext4_ext_get_actual_len(ex);
-       allocated = ee_len - (iblock - ee_block);
-       newblock = iblock - ee_block + ext_pblock(ex);
+       allocated = ee_len - (map->m_lblk - ee_block);
+       newblock = map->m_lblk - ee_block + ext_pblock(ex);
+
        ex2 = ex;
        orig_ex.ee_block = ex->ee_block;
        orig_ex.ee_len   = cpu_to_le16(ee_len);
        ext4_ext_store_pblock(&orig_ex, ext_pblock(ex));
 
+       /*
+        * It is safe to convert extent to initialized via explicit
+        * zeroout only if extent is fully insde i_size or new_size.
+        */
+       may_zeroout = ee_block + ee_len <= eof_block;
+
        err = ext4_ext_get_access(handle, inode, path + depth);
        if (err)
                goto out;
        /* If extent has less than 2*EXT4_EXT_ZERO_LEN zerout directly */
-       if (ee_len <= 2*EXT4_EXT_ZERO_LEN) {
+       if (ee_len <= 2*EXT4_EXT_ZERO_LEN && may_zeroout) {
                err =  ext4_ext_zeroout(inode, &orig_ex);
                if (err)
                        goto fix_extent_len;
@@ -2665,10 +2682,10 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
                return allocated;
        }
 
-       /* ex1: ee_block to iblock - 1 : uninitialized */
-       if (iblock > ee_block) {
+       /* ex1: ee_block to map->m_lblk - 1 : uninitialized */
+       if (map->m_lblk > ee_block) {
                ex1 = ex;
-               ex1->ee_len = cpu_to_le16(iblock - ee_block);
+               ex1->ee_len = cpu_to_le16(map->m_lblk - ee_block);
                ext4_ext_mark_uninitialized(ex1);
                ex2 = &newex;
        }
@@ -2677,15 +2694,15 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
         * we insert ex3, if ex1 is NULL. This is to avoid temporary
         * overlap of blocks.
         */
-       if (!ex1 && allocated > max_blocks)
-               ex2->ee_len = cpu_to_le16(max_blocks);
+       if (!ex1 && allocated > map->m_len)
+               ex2->ee_len = cpu_to_le16(map->m_len);
        /* ex3: to ee_block + ee_len : uninitialised */
-       if (allocated > max_blocks) {
+       if (allocated > map->m_len) {
                unsigned int newdepth;
                /* If extent has less than EXT4_EXT_ZERO_LEN zerout directly */
-               if (allocated <= EXT4_EXT_ZERO_LEN) {
+               if (allocated <= EXT4_EXT_ZERO_LEN && may_zeroout) {
                        /*
-                        * iblock == ee_block is handled by the zerouout
+                        * map->m_lblk == ee_block is handled by the zerouout
                         * at the beginning.
                         * Mark first half uninitialized.
                         * Mark second half initialized and zero out the
@@ -2698,7 +2715,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
                        ext4_ext_dirty(handle, inode, path + depth);
 
                        ex3 = &newex;
-                       ex3->ee_block = cpu_to_le32(iblock);
+                       ex3->ee_block = cpu_to_le32(map->m_lblk);
                        ext4_ext_store_pblock(ex3, newblock);
                        ex3->ee_len = cpu_to_le16(allocated);
                        err = ext4_ext_insert_extent(handle, inode, path,
@@ -2711,7 +2728,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
                                ex->ee_len   = orig_ex.ee_len;
                                ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
                                ext4_ext_dirty(handle, inode, path + depth);
-                               /* blocks available from iblock */
+                               /* blocks available from map->m_lblk */
                                return allocated;
 
                        } else if (err)
@@ -2733,8 +2750,8 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
                                 */
                                depth = ext_depth(inode);
                                ext4_ext_drop_refs(path);
-                               path = ext4_ext_find_extent(inode,
-                                                               iblock, path);
+                               path = ext4_ext_find_extent(inode, map->m_lblk,
+                                                           path);
                                if (IS_ERR(path)) {
                                        err = PTR_ERR(path);
                                        return err;
@@ -2754,12 +2771,12 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
                        return allocated;
                }
                ex3 = &newex;
-               ex3->ee_block = cpu_to_le32(iblock + max_blocks);
-               ext4_ext_store_pblock(ex3, newblock + max_blocks);
-               ex3->ee_len = cpu_to_le16(allocated - max_blocks);
+               ex3->ee_block = cpu_to_le32(map->m_lblk + map->m_len);
+               ext4_ext_store_pblock(ex3, newblock + map->m_len);
+               ex3->ee_len = cpu_to_le16(allocated - map->m_len);
                ext4_ext_mark_uninitialized(ex3);
                err = ext4_ext_insert_extent(handle, inode, path, ex3, 0);
-               if (err == -ENOSPC) {
+               if (err == -ENOSPC && may_zeroout) {
                        err =  ext4_ext_zeroout(inode, &orig_ex);
                        if (err)
                                goto fix_extent_len;
@@ -2769,7 +2786,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
                        ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
                        ext4_ext_dirty(handle, inode, path + depth);
                        /* zeroed the full extent */
-                       /* blocks available from iblock */
+                       /* blocks available from map->m_lblk */
                        return allocated;
 
                } else if (err)
@@ -2783,11 +2800,13 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
                 * update the extent length after successful insert of the
                 * split extent
                 */
-               orig_ex.ee_len = cpu_to_le16(ee_len -
-                                               ext4_ext_get_actual_len(ex3));
+               ee_len -= ext4_ext_get_actual_len(ex3);
+               orig_ex.ee_len = cpu_to_le16(ee_len);
+               may_zeroout = ee_block + ee_len <= eof_block;
+
                depth = newdepth;
                ext4_ext_drop_refs(path);
-               path = ext4_ext_find_extent(inode, iblock, path);
+               path = ext4_ext_find_extent(inode, map->m_lblk, path);
                if (IS_ERR(path)) {
                        err = PTR_ERR(path);
                        goto out;
@@ -2801,14 +2820,14 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
                if (err)
                        goto out;
 
-               allocated = max_blocks;
+               allocated = map->m_len;
 
                /* If extent has less than EXT4_EXT_ZERO_LEN and we are trying
                 * to insert a extent in the middle zerout directly
                 * otherwise give the extent a chance to merge to left
                 */
                if (le16_to_cpu(orig_ex.ee_len) <= EXT4_EXT_ZERO_LEN &&
-                                                       iblock != ee_block) {
+                       map->m_lblk != ee_block && may_zeroout) {
                        err =  ext4_ext_zeroout(inode, &orig_ex);
                        if (err)
                                goto fix_extent_len;
@@ -2818,7 +2837,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
                        ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
                        ext4_ext_dirty(handle, inode, path + depth);
                        /* zero out the first half */
-                       /* blocks available from iblock */
+                       /* blocks available from map->m_lblk */
                        return allocated;
                }
        }
@@ -2829,12 +2848,12 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
         */
        if (ex1 && ex1 != ex) {
                ex1 = ex;
-               ex1->ee_len = cpu_to_le16(iblock - ee_block);
+               ex1->ee_len = cpu_to_le16(map->m_lblk - ee_block);
                ext4_ext_mark_uninitialized(ex1);
                ex2 = &newex;
        }
-       /* ex2: iblock to iblock + maxblocks-1 : initialised */
-       ex2->ee_block = cpu_to_le32(iblock);
+       /* ex2: map->m_lblk to map->m_lblk + maxblocks-1 : initialised */
+       ex2->ee_block = cpu_to_le32(map->m_lblk);
        ext4_ext_store_pblock(ex2, newblock);
        ex2->ee_len = cpu_to_le16(allocated);
        if (ex2 != ex)
@@ -2877,7 +2896,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
        goto out;
 insert:
        err = ext4_ext_insert_extent(handle, inode, path, &newex, 0);
-       if (err == -ENOSPC) {
+       if (err == -ENOSPC && may_zeroout) {
                err =  ext4_ext_zeroout(inode, &orig_ex);
                if (err)
                        goto fix_extent_len;
@@ -2904,7 +2923,7 @@ fix_extent_len:
 }
 
 /*
- * This function is called by ext4_ext_get_blocks() from
+ * This function is called by ext4_ext_map_blocks() from
  * ext4_get_blocks_dio_write() when DIO to write
  * to an uninitialized extent.
  *
@@ -2927,9 +2946,8 @@ fix_extent_len:
  */
 static int ext4_split_unwritten_extents(handle_t *handle,
                                        struct inode *inode,
+                                       struct ext4_map_blocks *map,
                                        struct ext4_ext_path *path,
-                                       ext4_lblk_t iblock,
-                                       unsigned int max_blocks,
                                        int flags)
 {
        struct ext4_extent *ex, newex, orig_ex;
@@ -2937,41 +2955,55 @@ static int ext4_split_unwritten_extents(handle_t *handle,
        struct ext4_extent *ex2 = NULL;
        struct ext4_extent *ex3 = NULL;
        struct ext4_extent_header *eh;
-       ext4_lblk_t ee_block;
+       ext4_lblk_t ee_block, eof_block;
        unsigned int allocated, ee_len, depth;
        ext4_fsblk_t newblock;
        int err = 0;
+       int may_zeroout;
+
+       ext_debug("ext4_split_unwritten_extents: inode %lu, logical"
+               "block %llu, max_blocks %u\n", inode->i_ino,
+               (unsigned long long)map->m_lblk, map->m_len);
+
+       eof_block = (inode->i_size + inode->i_sb->s_blocksize - 1) >>
+               inode->i_sb->s_blocksize_bits;
+       if (eof_block < map->m_lblk + map->m_len)
+               eof_block = map->m_lblk + map->m_len;
 
-       ext_debug("ext4_split_unwritten_extents: inode %lu,"
-                 "iblock %llu, max_blocks %u\n", inode->i_ino,
-                 (unsigned long long)iblock, max_blocks);
        depth = ext_depth(inode);
        eh = path[depth].p_hdr;
        ex = path[depth].p_ext;
        ee_block = le32_to_cpu(ex->ee_block);
        ee_len = ext4_ext_get_actual_len(ex);
-       allocated = ee_len - (iblock - ee_block);
-       newblock = iblock - ee_block + ext_pblock(ex);
+       allocated = ee_len - (map->m_lblk - ee_block);
+       newblock = map->m_lblk - ee_block + ext_pblock(ex);
+
        ex2 = ex;
        orig_ex.ee_block = ex->ee_block;
        orig_ex.ee_len   = cpu_to_le16(ee_len);
        ext4_ext_store_pblock(&orig_ex, ext_pblock(ex));
 
+       /*
+        * It is safe to convert extent to initialized via explicit
+        * zeroout only if extent is fully insde i_size or new_size.
+        */
+       may_zeroout = ee_block + ee_len <= eof_block;
+
        /*
         * If the uninitialized extent begins at the same logical
         * block where the write begins, and the write completely
         * covers the extent, then we don't need to split it.
         */
-       if ((iblock == ee_block) && (allocated <= max_blocks))
+       if ((map->m_lblk == ee_block) && (allocated <= map->m_len))
                return allocated;
 
        err = ext4_ext_get_access(handle, inode, path + depth);
        if (err)
                goto out;
-       /* ex1: ee_block to iblock - 1 : uninitialized */
-       if (iblock > ee_block) {
+       /* ex1: ee_block to map->m_lblk - 1 : uninitialized */
+       if (map->m_lblk > ee_block) {
                ex1 = ex;
-               ex1->ee_len = cpu_to_le16(iblock - ee_block);
+               ex1->ee_len = cpu_to_le16(map->m_lblk - ee_block);
                ext4_ext_mark_uninitialized(ex1);
                ex2 = &newex;
        }
@@ -2980,18 +3012,18 @@ static int ext4_split_unwritten_extents(handle_t *handle,
         * we insert ex3, if ex1 is NULL. This is to avoid temporary
         * overlap of blocks.
         */
-       if (!ex1 && allocated > max_blocks)
-               ex2->ee_len = cpu_to_le16(max_blocks);
+       if (!ex1 && allocated > map->m_len)
+               ex2->ee_len = cpu_to_le16(map->m_len);
        /* ex3: to ee_block + ee_len : uninitialised */
-       if (allocated > max_blocks) {
+       if (allocated > map->m_len) {
                unsigned int newdepth;
                ex3 = &newex;
-               ex3->ee_block = cpu_to_le32(iblock + max_blocks);
-               ext4_ext_store_pblock(ex3, newblock + max_blocks);
-               ex3->ee_len = cpu_to_le16(allocated - max_blocks);
+               ex3->ee_block = cpu_to_le32(map->m_lblk + map->m_len);
+               ext4_ext_store_pblock(ex3, newblock + map->m_len);
+               ex3->ee_len = cpu_to_le16(allocated - map->m_len);
                ext4_ext_mark_uninitialized(ex3);
                err = ext4_ext_insert_extent(handle, inode, path, ex3, flags);
-               if (err == -ENOSPC) {
+               if (err == -ENOSPC && may_zeroout) {
                        err =  ext4_ext_zeroout(inode, &orig_ex);
                        if (err)
                                goto fix_extent_len;
@@ -3001,7 +3033,7 @@ static int ext4_split_unwritten_extents(handle_t *handle,
                        ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
                        ext4_ext_dirty(handle, inode, path + depth);
                        /* zeroed the full extent */
-                       /* blocks available from iblock */
+                       /* blocks available from map->m_lblk */
                        return allocated;
 
                } else if (err)
@@ -3015,11 +3047,13 @@ static int ext4_split_unwritten_extents(handle_t *handle,
                 * update the extent length after successful insert of the
                 * split extent
                 */
-               orig_ex.ee_len = cpu_to_le16(ee_len -
-                                               ext4_ext_get_actual_len(ex3));
+               ee_len -= ext4_ext_get_actual_len(ex3);
+               orig_ex.ee_len = cpu_to_le16(ee_len);
+               may_zeroout = ee_block + ee_len <= eof_block;
+
                depth = newdepth;
                ext4_ext_drop_refs(path);
-               path = ext4_ext_find_extent(inode, iblock, path);
+               path = ext4_ext_find_extent(inode, map->m_lblk, path);
                if (IS_ERR(path)) {
                        err = PTR_ERR(path);
                        goto out;
@@ -3033,7 +3067,7 @@ static int ext4_split_unwritten_extents(handle_t *handle,
                if (err)
                        goto out;
 
-               allocated = max_blocks;
+               allocated = map->m_len;
        }
        /*
         * If there was a change of depth as part of the
@@ -3042,15 +3076,15 @@ static int ext4_split_unwritten_extents(handle_t *handle,
         */
        if (ex1 && ex1 != ex) {
                ex1 = ex;
-               ex1->ee_len = cpu_to_le16(iblock - ee_block);
+               ex1->ee_len = cpu_to_le16(map->m_lblk - ee_block);
                ext4_ext_mark_uninitialized(ex1);
                ex2 = &newex;
        }
        /*
-        * ex2: iblock to iblock + maxblocks-1 : to be direct IO written,
-        * uninitialised still.
+        * ex2: map->m_lblk to map->m_lblk + map->m_len-1 : to be written
+        * using direct I/O, uninitialised still.
         */
-       ex2->ee_block = cpu_to_le32(iblock);
+       ex2->ee_block = cpu_to_le32(map->m_lblk);
        ext4_ext_store_pblock(ex2, newblock);
        ex2->ee_len = cpu_to_le16(allocated);
        ext4_ext_mark_uninitialized(ex2);
@@ -3062,7 +3096,7 @@ static int ext4_split_unwritten_extents(handle_t *handle,
        goto out;
 insert:
        err = ext4_ext_insert_extent(handle, inode, path, &newex, flags);
-       if (err == -ENOSPC) {
+       if (err == -ENOSPC && may_zeroout) {
                err =  ext4_ext_zeroout(inode, &orig_ex);
                if (err)
                        goto fix_extent_len;
@@ -3152,10 +3186,9 @@ static void unmap_underlying_metadata_blocks(struct block_device *bdev,
 
 static int
 ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,
-                       ext4_lblk_t iblock, unsigned int max_blocks,
+                       struct ext4_map_blocks *map,
                        struct ext4_ext_path *path, int flags,
-                       unsigned int allocated, struct buffer_head *bh_result,
-                       ext4_fsblk_t newblock)
+                       unsigned int allocated, ext4_fsblk_t newblock)
 {
        int ret = 0;
        int err = 0;
@@ -3163,15 +3196,14 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,
 
        ext_debug("ext4_ext_handle_uninitialized_extents: inode %lu, logical"
                  "block %llu, max_blocks %u, flags %d, allocated %u",
-                 inode->i_ino, (unsigned long long)iblock, max_blocks,
+                 inode->i_ino, (unsigned long long)map->m_lblk, map->m_len,
                  flags, allocated);
        ext4_ext_show_leaf(inode, path);
 
        /* get_block() before submit the IO, split the extent */
        if ((flags & EXT4_GET_BLOCKS_PRE_IO)) {
-               ret = ext4_split_unwritten_extents(handle,
-                                               inode, path, iblock,
-                                               max_blocks, flags);
+               ret = ext4_split_unwritten_extents(handle, inode, map,
+                                                  path, flags);
                /*
                 * Flag the inode(non aio case) or end_io struct (aio case)
                 * that this IO needs to convertion to written when IO is
@@ -3182,7 +3214,7 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,
                else
                        ext4_set_inode_state(inode, EXT4_STATE_DIO_UNWRITTEN);
                if (ext4_should_dioread_nolock(inode))
-                       set_buffer_uninit(bh_result);
+                       map->m_flags |= EXT4_MAP_UNINIT;
                goto out;
        }
        /* IO end_io complete, convert the filled extent to written */
@@ -3210,14 +3242,12 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,
                 * the buffer head will be unmapped so that
                 * a read from the block returns 0s.
                 */
-               set_buffer_unwritten(bh_result);
+               map->m_flags |= EXT4_MAP_UNWRITTEN;
                goto out1;
        }
 
        /* buffered write, writepage time, convert*/
-       ret = ext4_ext_convert_to_initialized(handle, inode,
-                                               path, iblock,
-                                               max_blocks);
+       ret = ext4_ext_convert_to_initialized(handle, inode, map, path);
        if (ret >= 0)
                ext4_update_inode_fsync_trans(handle, inode, 1);
 out:
@@ -3226,7 +3256,7 @@ out:
                goto out2;
        } else
                allocated = ret;
-       set_buffer_new(bh_result);
+       map->m_flags |= EXT4_MAP_NEW;
        /*
         * if we allocated more blocks than requested
         * we need to make sure we unmap the extra block
@@ -3234,11 +3264,11 @@ out:
         * unmapped later when we find the buffer_head marked
         * new.
         */
-       if (allocated > max_blocks) {
+       if (allocated > map->m_len) {
                unmap_underlying_metadata_blocks(inode->i_sb->s_bdev,
-                                       newblock + max_blocks,
-                                       allocated - max_blocks);
-               allocated = max_blocks;
+                                       newblock + map->m_len,
+                                       allocated - map->m_len);
+               allocated = map->m_len;
        }
 
        /*
@@ -3252,13 +3282,13 @@ out:
                ext4_da_update_reserve_space(inode, allocated, 0);
 
 map_out:
-       set_buffer_mapped(bh_result);
+       map->m_flags |= EXT4_MAP_MAPPED;
 out1:
-       if (allocated > max_blocks)
-               allocated = max_blocks;
+       if (allocated > map->m_len)
+               allocated = map->m_len;
        ext4_ext_show_leaf(inode, path);
-       bh_result->b_bdev = inode->i_sb->s_bdev;
-       bh_result->b_blocknr = newblock;
+       map->m_pblk = newblock;
+       map->m_len = allocated;
 out2:
        if (path) {
                ext4_ext_drop_refs(path);
@@ -3284,26 +3314,23 @@ out2:
  *
  * return < 0, error case.
  */
-int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
-                       ext4_lblk_t iblock,
-                       unsigned int max_blocks, struct buffer_head *bh_result,
-                       int flags)
+int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
+                       struct ext4_map_blocks *map, int flags)
 {
        struct ext4_ext_path *path = NULL;
        struct ext4_extent_header *eh;
        struct ext4_extent newex, *ex, *last_ex;
        ext4_fsblk_t newblock;
-       int err = 0, depth, ret, cache_type;
+       int i, err = 0, depth, ret, cache_type;
        unsigned int allocated = 0;
        struct ext4_allocation_request ar;
        ext4_io_end_t *io = EXT4_I(inode)->cur_aio_dio;
 
-       __clear_bit(BH_New, &bh_result->b_state);
        ext_debug("blocks %u/%u requested for inode %lu\n",
-                       iblock, max_blocks, inode->i_ino);
+                 map->m_lblk, map->m_len, inode->i_ino);
 
        /* check in cache */
-       cache_type = ext4_ext_in_cache(inode, iblock, &newex);
+       cache_type = ext4_ext_in_cache(inode, map->m_lblk, &newex);
        if (cache_type) {
                if (cache_type == EXT4_EXT_CACHE_GAP) {
                        if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) {
@@ -3316,12 +3343,12 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
                        /* we should allocate requested block */
                } else if (cache_type == EXT4_EXT_CACHE_EXTENT) {
                        /* block is already allocated */
-                       newblock = iblock
+                       newblock = map->m_lblk
                                   - le32_to_cpu(newex.ee_block)
                                   + ext_pblock(&newex);
                        /* number of remaining blocks in the extent */
                        allocated = ext4_ext_get_actual_len(&newex) -
-                                       (iblock - le32_to_cpu(newex.ee_block));
+                               (map->m_lblk - le32_to_cpu(newex.ee_block));
                        goto out;
                } else {
                        BUG();
@@ -3329,7 +3356,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
        }
 
        /* find extent for this block */
-       path = ext4_ext_find_extent(inode, iblock, NULL);
+       path = ext4_ext_find_extent(inode, map->m_lblk, NULL);
        if (IS_ERR(path)) {
                err = PTR_ERR(path);
                path = NULL;
@@ -3345,8 +3372,9 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
         */
        if (unlikely(path[depth].p_ext == NULL && depth != 0)) {
                EXT4_ERROR_INODE(inode, "bad extent address "
-                                "iblock: %d, depth: %d pblock %lld",
-                                iblock, depth, path[depth].p_block);
+                                "lblock: %lu, depth: %d pblock %lld",
+                                (unsigned long) map->m_lblk, depth,
+                                path[depth].p_block);
                err = -EIO;
                goto out2;
        }
@@ -3364,12 +3392,12 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
                 */
                ee_len = ext4_ext_get_actual_len(ex);
                /* if found extent covers block, simply return it */
-               if (in_range(iblock, ee_block, ee_len)) {
-                       newblock = iblock - ee_block + ee_start;
+               if (in_range(map->m_lblk, ee_block, ee_len)) {
+                       newblock = map->m_lblk - ee_block + ee_start;
                        /* number of remaining blocks in the extent */
-                       allocated = ee_len - (iblock - ee_block);
-                       ext_debug("%u fit into %u:%d -> %llu\n", iblock,
-                                       ee_block, ee_len, newblock);
+                       allocated = ee_len - (map->m_lblk - ee_block);
+                       ext_debug("%u fit into %u:%d -> %llu\n", map->m_lblk,
+                                 ee_block, ee_len, newblock);
 
                        /* Do not put uninitialized extent in the cache */
                        if (!ext4_ext_is_uninitialized(ex)) {
@@ -3379,8 +3407,8 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
                                goto out;
                        }
                        ret = ext4_ext_handle_uninitialized_extents(handle,
-                                       inode, iblock, max_blocks, path,
-                                       flags, allocated, bh_result, newblock);
+                                       inode, map, path, flags, allocated,
+                                       newblock);
                        return ret;
                }
        }
@@ -3394,7 +3422,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
                 * put just found gap into cache to speed up
                 * subsequent requests
                 */
-               ext4_ext_put_gap_in_cache(inode, path, iblock);
+               ext4_ext_put_gap_in_cache(inode, path, map->m_lblk);
                goto out2;
        }
        /*
@@ -3402,11 +3430,11 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
         */
 
        /* find neighbour allocated blocks */
-       ar.lleft = iblock;
+       ar.lleft = map->m_lblk;
        err = ext4_ext_search_left(inode, path, &ar.lleft, &ar.pleft);
        if (err)
                goto out2;
-       ar.lright = iblock;
+       ar.lright = map->m_lblk;
        err = ext4_ext_search_right(inode, path, &ar.lright, &ar.pright);
        if (err)
                goto out2;
@@ -3417,26 +3445,26 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
         * EXT_INIT_MAX_LEN and for an uninitialized extent this limit is
         * EXT_UNINIT_MAX_LEN.
         */
-       if (max_blocks > EXT_INIT_MAX_LEN &&
+       if (map->m_len > EXT_INIT_MAX_LEN &&
            !(flags & EXT4_GET_BLOCKS_UNINIT_EXT))
-               max_blocks = EXT_INIT_MAX_LEN;
-       else if (max_blocks > EXT_UNINIT_MAX_LEN &&
+               map->m_len = EXT_INIT_MAX_LEN;
+       else if (map->m_len > EXT_UNINIT_MAX_LEN &&
                 (flags & EXT4_GET_BLOCKS_UNINIT_EXT))
-               max_blocks = EXT_UNINIT_MAX_LEN;
+               map->m_len = EXT_UNINIT_MAX_LEN;
 
-       /* Check if we can really insert (iblock)::(iblock+max_blocks) extent */
-       newex.ee_block = cpu_to_le32(iblock);
-       newex.ee_len = cpu_to_le16(max_blocks);
+       /* Check if we can really insert (m_lblk)::(m_lblk + m_len) extent */
+       newex.ee_block = cpu_to_le32(map->m_lblk);
+       newex.ee_len = cpu_to_le16(map->m_len);
        err = ext4_ext_check_overlap(inode, &newex, path);
        if (err)
                allocated = ext4_ext_get_actual_len(&newex);
        else
-               allocated = max_blocks;
+               allocated = map->m_len;
 
        /* allocate new block */
        ar.inode = inode;
-       ar.goal = ext4_ext_find_goal(inode, path, iblock);
-       ar.logical = iblock;
+       ar.goal = ext4_ext_find_goal(inode, path, map->m_lblk);
+       ar.logical = map->m_lblk;
        ar.len = allocated;
        if (S_ISREG(inode->i_mode))
                ar.flags = EXT4_MB_HINT_DATA;
@@ -3470,21 +3498,33 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
                                                     EXT4_STATE_DIO_UNWRITTEN);
                }
                if (ext4_should_dioread_nolock(inode))
-                       set_buffer_uninit(bh_result);
+                       map->m_flags |= EXT4_MAP_UNINIT;
        }
 
-       if (unlikely(EXT4_I(inode)->i_flags & EXT4_EOFBLOCKS_FL)) {
+       if (unlikely(ext4_test_inode_flag(inode, EXT4_INODE_EOFBLOCKS))) {
                if (unlikely(!eh->eh_entries)) {
                        EXT4_ERROR_INODE(inode,
-                                        "eh->eh_entries == 0 ee_block %d",
-                                        ex->ee_block);
+                                        "eh->eh_entries == 0 and "
+                                        "EOFBLOCKS_FL set");
                        err = -EIO;
                        goto out2;
                }
                last_ex = EXT_LAST_EXTENT(eh);
-               if (iblock + ar.len > le32_to_cpu(last_ex->ee_block)
-                   + ext4_ext_get_actual_len(last_ex))
-                       EXT4_I(inode)->i_flags &= ~EXT4_EOFBLOCKS_FL;
+               /*
+                * If the current leaf block was reached by looking at
+                * the last index block all the way down the tree, and
+                * we are extending the inode beyond the last extent
+                * in the current leaf block, then clear the
+                * EOFBLOCKS_FL flag.
+                */
+               for (i = depth-1; i >= 0; i--) {
+                       if (path[i].p_idx != EXT_LAST_INDEX(path[i].p_hdr))
+                               break;
+               }
+               if ((i < 0) &&
+                   (map->m_lblk + ar.len > le32_to_cpu(last_ex->ee_block) +
+                    ext4_ext_get_actual_len(last_ex)))
+                       ext4_clear_inode_flag(inode, EXT4_INODE_EOFBLOCKS);
        }
        err = ext4_ext_insert_extent(handle, inode, path, &newex, flags);
        if (err) {
@@ -3500,9 +3540,9 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
        /* previous routine could use block we allocated */
        newblock = ext_pblock(&newex);
        allocated = ext4_ext_get_actual_len(&newex);
-       if (allocated > max_blocks)
-               allocated = max_blocks;
-       set_buffer_new(bh_result);
+       if (allocated > map->m_len)
+               allocated = map->m_len;
+       map->m_flags |= EXT4_MAP_NEW;
 
        /*
         * Update reserved blocks/metadata blocks after successful
@@ -3516,18 +3556,18 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
         * when it is _not_ an uninitialized extent.
         */
        if ((flags & EXT4_GET_BLOCKS_UNINIT_EXT) == 0) {
-               ext4_ext_put_in_cache(inode, iblock, allocated, newblock,
+               ext4_ext_put_in_cache(inode, map->m_lblk, allocated, newblock,
                                                EXT4_EXT_CACHE_EXTENT);
                ext4_update_inode_fsync_trans(handle, inode, 1);
        } else
                ext4_update_inode_fsync_trans(handle, inode, 0);
 out:
-       if (allocated > max_blocks)
-               allocated = max_blocks;
+       if (allocated > map->m_len)
+               allocated = map->m_len;
        ext4_ext_show_leaf(inode, path);
-       set_buffer_mapped(bh_result);
-       bh_result->b_bdev = inode->i_sb->s_bdev;
-       bh_result->b_blocknr = newblock;
+       map->m_flags |= EXT4_MAP_MAPPED;
+       map->m_pblk = newblock;
+       map->m_len = allocated;
 out2:
        if (path) {
                ext4_ext_drop_refs(path);
@@ -3625,7 +3665,7 @@ static void ext4_falloc_update_inode(struct inode *inode,
                 * can proceed even if the new size is the same as i_size.
                 */
                if (new_size > i_size_read(inode))
-                       EXT4_I(inode)->i_flags |= EXT4_EOFBLOCKS_FL;
+                       ext4_set_inode_flag(inode, EXT4_INODE_EOFBLOCKS);
        }
 
 }
@@ -3640,55 +3680,57 @@ static void ext4_falloc_update_inode(struct inode *inode,
 long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len)
 {
        handle_t *handle;
-       ext4_lblk_t block;
        loff_t new_size;
        unsigned int max_blocks;
        int ret = 0;
        int ret2 = 0;
        int retries = 0;
-       struct buffer_head map_bh;
+       struct ext4_map_blocks map;
        unsigned int credits, blkbits = inode->i_blkbits;
 
        /*
         * currently supporting (pre)allocate mode for extent-based
         * files _only_
         */
-       if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL))
+       if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
                return -EOPNOTSUPP;
 
        /* preallocation to directories is currently not supported */
        if (S_ISDIR(inode->i_mode))
                return -ENODEV;
 
-       block = offset >> blkbits;
+       map.m_lblk = offset >> blkbits;
        /*
         * We can't just convert len to max_blocks because
         * If blocksize = 4096 offset = 3072 and len = 2048
         */
        max_blocks = (EXT4_BLOCK_ALIGN(len + offset, blkbits) >> blkbits)
-                                                       - block;
+               - map.m_lblk;
        /*
         * credits to insert 1 extent into extent tree
         */
        credits = ext4_chunk_trans_blocks(inode, max_blocks);
        mutex_lock(&inode->i_mutex);
+       ret = inode_newsize_ok(inode, (len + offset));
+       if (ret) {
+               mutex_unlock(&inode->i_mutex);
+               return ret;
+       }
 retry:
        while (ret >= 0 && ret < max_blocks) {
-               block = block + ret;
-               max_blocks = max_blocks - ret;
+               map.m_lblk = map.m_lblk + ret;
+               map.m_len = max_blocks = max_blocks - ret;
                handle = ext4_journal_start(inode, credits);
                if (IS_ERR(handle)) {
                        ret = PTR_ERR(handle);
                        break;
                }
-               map_bh.b_state = 0;
-               ret = ext4_get_blocks(handle, inode, block,
-                                     max_blocks, &map_bh,
+               ret = ext4_map_blocks(handle, inode, &map,
                                      EXT4_GET_BLOCKS_CREATE_UNINIT_EXT);
                if (ret <= 0) {
 #ifdef EXT4FS_DEBUG
                        WARN_ON(ret <= 0);
-                       printk(KERN_ERR "%s: ext4_ext_get_blocks "
+                       printk(KERN_ERR "%s: ext4_ext_map_blocks "
                                    "returned error inode#%lu, block=%u, "
                                    "max_blocks=%u", __func__,
                                    inode->i_ino, block, max_blocks);
@@ -3697,14 +3739,14 @@ retry:
                        ret2 = ext4_journal_stop(handle);
                        break;
                }
-               if ((block + ret) >= (EXT4_BLOCK_ALIGN(offset + len,
+               if ((map.m_lblk + ret) >= (EXT4_BLOCK_ALIGN(offset + len,
                                                blkbits) >> blkbits))
                        new_size = offset + len;
                else
-                       new_size = (block + ret) << blkbits;
+                       new_size = (map.m_lblk + ret) << blkbits;
 
                ext4_falloc_update_inode(inode, mode, new_size,
-                                               buffer_new(&map_bh));
+                                        (map.m_flags & EXT4_MAP_NEW));
                ext4_mark_inode_dirty(handle, inode);
                ret2 = ext4_journal_stop(handle);
                if (ret2)
@@ -3733,42 +3775,39 @@ int ext4_convert_unwritten_extents(struct inode *inode, loff_t offset,
                                    ssize_t len)
 {
        handle_t *handle;
-       ext4_lblk_t block;
        unsigned int max_blocks;
        int ret = 0;
        int ret2 = 0;
-       struct buffer_head map_bh;
+       struct ext4_map_blocks map;
        unsigned int credits, blkbits = inode->i_blkbits;
 
-       block = offset >> blkbits;
+       map.m_lblk = offset >> blkbits;
        /*
         * We can't just convert len to max_blocks because
         * If blocksize = 4096 offset = 3072 and len = 2048
         */
-       max_blocks = (EXT4_BLOCK_ALIGN(len + offset, blkbits) >> blkbits)
-                                                       - block;
+       max_blocks = ((EXT4_BLOCK_ALIGN(len + offset, blkbits) >> blkbits) -
+                     map.m_lblk);
        /*
         * credits to insert 1 extent into extent tree
         */
        credits = ext4_chunk_trans_blocks(inode, max_blocks);
        while (ret >= 0 && ret < max_blocks) {
-               block = block + ret;
-               max_blocks = max_blocks - ret;
+               map.m_lblk += ret;
+               map.m_len = (max_blocks -= ret);
                handle = ext4_journal_start(inode, credits);
                if (IS_ERR(handle)) {
                        ret = PTR_ERR(handle);
                        break;
                }
-               map_bh.b_state = 0;
-               ret = ext4_get_blocks(handle, inode, block,
-                                     max_blocks, &map_bh,
+               ret = ext4_map_blocks(handle, inode, &map,
                                      EXT4_GET_BLOCKS_IO_CONVERT_EXT);
                if (ret <= 0) {
                        WARN_ON(ret <= 0);
-                       printk(KERN_ERR "%s: ext4_ext_get_blocks "
+                       printk(KERN_ERR "%s: ext4_ext_map_blocks "
                                    "returned error inode#%lu, block=%u, "
                                    "max_blocks=%u", __func__,
-                                   inode->i_ino, block, max_blocks);
+                                   inode->i_ino, map.m_lblk, map.m_len);
                }
                ext4_mark_inode_dirty(handle, inode);
                ret2 = ext4_journal_stop(handle);
@@ -3898,7 +3937,7 @@ int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
        int error = 0;
 
        /* fallback to generic here if not in extents fmt */
-       if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL))
+       if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
                return generic_block_fiemap(inode, fieinfo, start, len,
                        ext4_get_block);
 
index d0776e410f340c8f60ad822321c6396436de4c98..5313ae4cda2d2149d58efc5f228e4973f1e8f33f 100644 (file)
@@ -66,7 +66,7 @@ ext4_file_write(struct kiocb *iocb, const struct iovec *iov,
         * is smaller than s_maxbytes, which is for extent-mapped files.
         */
 
-       if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)) {
+       if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) {
                struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
                size_t length = iov_length(iov, nr_segs);
 
index ef3d980e67cb5e57fd5c28302167f6d8bc2ef20a..592adf2e546e0726f3d0b6fd34165dd3c769a815 100644 (file)
 
 #include <trace/events/ext4.h>
 
+/*
+ * If we're not journaling and this is a just-created file, we have to
+ * sync our parent directory (if it was freshly created) since
+ * otherwise it will only be written by writeback, leaving a huge
+ * window during which a crash may lose the file.  This may apply for
+ * the parent directory's parent as well, and so on recursively, if
+ * they are also freshly created.
+ */
+static void ext4_sync_parent(struct inode *inode)
+{
+       struct dentry *dentry = NULL;
+
+       while (inode && ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY)) {
+               ext4_clear_inode_state(inode, EXT4_STATE_NEWENTRY);
+               dentry = list_entry(inode->i_dentry.next,
+                                   struct dentry, d_alias);
+               if (!dentry || !dentry->d_parent || !dentry->d_parent->d_inode)
+                       break;
+               inode = dentry->d_parent->d_inode;
+               sync_mapping_buffers(inode->i_mapping);
+       }
+}
+
 /*
  * akpm: A new design for ext4_sync_file().
  *
@@ -48,9 +71,9 @@
  * i_mutex lock is held when entering and exiting this function
  */
 
-int ext4_sync_file(struct file *file, struct dentry *dentry, int datasync)
+int ext4_sync_file(struct file *file, int datasync)
 {
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = file->f_mapping->host;
        struct ext4_inode_info *ei = EXT4_I(inode);
        journal_t *journal = EXT4_SB(inode->i_sb)->s_journal;
        int ret;
@@ -58,7 +81,7 @@ int ext4_sync_file(struct file *file, struct dentry *dentry, int datasync)
 
        J_ASSERT(ext4_journal_current_handle() == NULL);
 
-       trace_ext4_sync_file(file, dentry, datasync);
+       trace_ext4_sync_file(file, datasync);
 
        if (inode->i_sb->s_flags & MS_RDONLY)
                return 0;
@@ -66,9 +89,13 @@ int ext4_sync_file(struct file *file, struct dentry *dentry, int datasync)
        ret = flush_completed_IO(inode);
        if (ret < 0)
                return ret;
-       
-       if (!journal)
-               return simple_fsync(file, dentry, datasync);
+
+       if (!journal) {
+               ret = generic_file_fsync(file, datasync);
+               if (!ret && !list_empty(&inode->i_dentry))
+                       ext4_sync_parent(inode);
+               return ret;
+       }
 
        /*
         * data=writeback,ordered:
@@ -102,7 +129,7 @@ int ext4_sync_file(struct file *file, struct dentry *dentry, int datasync)
                    (journal->j_flags & JBD2_BARRIER))
                        blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL,
                                        NULL, BLKDEV_IFL_WAIT);
-               jbd2_log_wait_commit(journal, commit_tid);
+               ret = jbd2_log_wait_commit(journal, commit_tid);
        } else if (journal->j_flags & JBD2_BARRIER)
                blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL,
                        BLKDEV_IFL_WAIT);
index 57f6eef6ccd6c03afbd4c35d0fa364f4e350bbf8..25c4b3173fd935f1550ce89116344a72f9f02374 100644 (file)
@@ -240,56 +240,49 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
        if (fatal)
                goto error_return;
 
-       /* Ok, now we can actually update the inode bitmaps.. */
-       cleared = ext4_clear_bit_atomic(ext4_group_lock_ptr(sb, block_group),
-                                       bit, bitmap_bh->b_data);
-       if (!cleared)
-               ext4_error(sb, "bit already cleared for inode %lu", ino);
-       else {
-               gdp = ext4_get_group_desc(sb, block_group, &bh2);
-
+       fatal = -ESRCH;
+       gdp = ext4_get_group_desc(sb, block_group, &bh2);
+       if (gdp) {
                BUFFER_TRACE(bh2, "get_write_access");
                fatal = ext4_journal_get_write_access(handle, bh2);
-               if (fatal) goto error_return;
-
-               if (gdp) {
-                       ext4_lock_group(sb, block_group);
-                       count = ext4_free_inodes_count(sb, gdp) + 1;
-                       ext4_free_inodes_set(sb, gdp, count);
-                       if (is_directory) {
-                               count = ext4_used_dirs_count(sb, gdp) - 1;
-                               ext4_used_dirs_set(sb, gdp, count);
-                               if (sbi->s_log_groups_per_flex) {
-                                       ext4_group_t f;
-
-                                       f = ext4_flex_group(sbi, block_group);
-                                       atomic_dec(&sbi->s_flex_groups[f].used_dirs);
-                               }
+       }
+       ext4_lock_group(sb, block_group);
+       cleared = ext4_clear_bit(bit, bitmap_bh->b_data);
+       if (fatal || !cleared) {
+               ext4_unlock_group(sb, block_group);
+               goto out;
+       }
 
-                       }
-                       gdp->bg_checksum = ext4_group_desc_csum(sbi,
-                                                       block_group, gdp);
-                       ext4_unlock_group(sb, block_group);
-                       percpu_counter_inc(&sbi->s_freeinodes_counter);
-                       if (is_directory)
-                               percpu_counter_dec(&sbi->s_dirs_counter);
-
-                       if (sbi->s_log_groups_per_flex) {
-                               ext4_group_t f;
-
-                               f = ext4_flex_group(sbi, block_group);
-                               atomic_inc(&sbi->s_flex_groups[f].free_inodes);
-                       }
-               }
-               BUFFER_TRACE(bh2, "call ext4_handle_dirty_metadata");
-               err = ext4_handle_dirty_metadata(handle, NULL, bh2);
-               if (!fatal) fatal = err;
+       count = ext4_free_inodes_count(sb, gdp) + 1;
+       ext4_free_inodes_set(sb, gdp, count);
+       if (is_directory) {
+               count = ext4_used_dirs_count(sb, gdp) - 1;
+               ext4_used_dirs_set(sb, gdp, count);
+               percpu_counter_dec(&sbi->s_dirs_counter);
        }
-       BUFFER_TRACE(bitmap_bh, "call ext4_handle_dirty_metadata");
-       err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh);
-       if (!fatal)
-               fatal = err;
-       sb->s_dirt = 1;
+       gdp->bg_checksum = ext4_group_desc_csum(sbi, block_group, gdp);
+       ext4_unlock_group(sb, block_group);
+
+       percpu_counter_inc(&sbi->s_freeinodes_counter);
+       if (sbi->s_log_groups_per_flex) {
+               ext4_group_t f = ext4_flex_group(sbi, block_group);
+
+               atomic_inc(&sbi->s_flex_groups[f].free_inodes);
+               if (is_directory)
+                       atomic_dec(&sbi->s_flex_groups[f].used_dirs);
+       }
+       BUFFER_TRACE(bh2, "call ext4_handle_dirty_metadata");
+       fatal = ext4_handle_dirty_metadata(handle, NULL, bh2);
+out:
+       if (cleared) {
+               BUFFER_TRACE(bitmap_bh, "call ext4_handle_dirty_metadata");
+               err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh);
+               if (!fatal)
+                       fatal = err;
+               sb->s_dirt = 1;
+       } else
+               ext4_error(sb, "bit already cleared for inode %lu", ino);
+
 error_return:
        brelse(bitmap_bh);
        ext4_std_error(sb, fatal);
@@ -499,7 +492,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent,
 
        if (S_ISDIR(mode) &&
            ((parent == sb->s_root->d_inode) ||
-            (EXT4_I(parent)->i_flags & EXT4_TOPDIR_FL))) {
+            (ext4_test_inode_flag(parent, EXT4_INODE_TOPDIR)))) {
                int best_ndir = inodes_per_group;
                int ret = -1;
 
@@ -979,16 +972,12 @@ got:
                atomic_dec(&sbi->s_flex_groups[flex_group].free_inodes);
        }
 
-       inode->i_uid = current_fsuid();
-       if (test_opt(sb, GRPID))
-               inode->i_gid = dir->i_gid;
-       else if (dir->i_mode & S_ISGID) {
+       if (test_opt(sb, GRPID)) {
+               inode->i_mode = mode;
+               inode->i_uid = current_fsuid();
                inode->i_gid = dir->i_gid;
-               if (S_ISDIR(mode))
-                       mode |= S_ISGID;
        } else
-               inode->i_gid = current_fsgid();
-       inode->i_mode = mode;
+               inode_init_owner(inode, dir, mode);
 
        inode->i_ino = ino + group * EXT4_INODES_PER_GROUP(sb);
        /* This is the optimal IO size (for stat), not the fs block size */
@@ -1045,7 +1034,7 @@ got:
        if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
                /* set extent flag only for directory, file and normal symlink*/
                if (S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode)) {
-                       EXT4_I(inode)->i_flags |= EXT4_EXTENTS_FL;
+                       ext4_set_inode_flag(inode, EXT4_INODE_EXTENTS);
                        ext4_ext_tree_init(handle, inode);
                }
        }
index 3e0f6af9d08d9a6faf3bea7c25087b94b8b883b0..19df61c321fdfa62e53e53c3af69c0cc41c090e7 100644 (file)
@@ -149,7 +149,7 @@ int ext4_truncate_restart_trans(handle_t *handle, struct inode *inode,
        int ret;
 
        /*
-        * Drop i_data_sem to avoid deadlock with ext4_get_blocks At this
+        * Drop i_data_sem to avoid deadlock with ext4_map_blocks.  At this
         * moment, get_block can be called only for blocks inside i_size since
         * page cache has been already dropped and writes are blocked by
         * i_mutex. So we can safely drop the i_data_sem here.
@@ -348,9 +348,8 @@ static int __ext4_check_blockref(const char *function, struct inode *inode,
                if (blk &&
                    unlikely(!ext4_data_block_valid(EXT4_SB(inode->i_sb),
                                                    blk, 1))) {
-                       __ext4_error(inode->i_sb, function,
-                                  "invalid block reference %u "
-                                  "in inode #%lu", blk, inode->i_ino);
+                       ext4_error_inode(function, inode,
+                                        "invalid block reference %u", blk);
                        return -EIO;
                }
        }
@@ -785,7 +784,7 @@ failed:
        /* Allocation failed, free what we already allocated */
        ext4_free_blocks(handle, inode, 0, new_blocks[0], 1, 0);
        for (i = 1; i <= n ; i++) {
-               /* 
+               /*
                 * branch[i].bh is newly allocated, so there is no
                 * need to revoke the block, which is why we don't
                 * need to set EXT4_FREE_BLOCKS_METADATA.
@@ -875,7 +874,7 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode,
 
 err_out:
        for (i = 1; i <= num; i++) {
-               /* 
+               /*
                 * branch[i].bh is newly allocated, so there is no
                 * need to revoke the block, which is why we don't
                 * need to set EXT4_FREE_BLOCKS_METADATA.
@@ -890,9 +889,9 @@ err_out:
 }
 
 /*
- * The ext4_ind_get_blocks() function handles non-extents inodes
+ * The ext4_ind_map_blocks() function handles non-extents inodes
  * (i.e., using the traditional indirect/double-indirect i_blocks
- * scheme) for ext4_get_blocks().
+ * scheme) for ext4_map_blocks().
  *
  * Allocation strategy is simple: if we have to allocate something, we will
  * have to go the whole way to leaf. So let's do it before attaching anything
@@ -917,9 +916,8 @@ err_out:
  * down_read(&EXT4_I(inode)->i_data_sem) if not allocating file system
  * blocks.
  */
-static int ext4_ind_get_blocks(handle_t *handle, struct inode *inode,
-                              ext4_lblk_t iblock, unsigned int maxblocks,
-                              struct buffer_head *bh_result,
+static int ext4_ind_map_blocks(handle_t *handle, struct inode *inode,
+                              struct ext4_map_blocks *map,
                               int flags)
 {
        int err = -EIO;
@@ -933,9 +931,9 @@ static int ext4_ind_get_blocks(handle_t *handle, struct inode *inode,
        int count = 0;
        ext4_fsblk_t first_block = 0;
 
-       J_ASSERT(!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL));
+       J_ASSERT(!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)));
        J_ASSERT(handle != NULL || (flags & EXT4_GET_BLOCKS_CREATE) == 0);
-       depth = ext4_block_to_path(inode, iblock, offsets,
+       depth = ext4_block_to_path(inode, map->m_lblk, offsets,
                                   &blocks_to_boundary);
 
        if (depth == 0)
@@ -946,10 +944,9 @@ static int ext4_ind_get_blocks(handle_t *handle, struct inode *inode,
        /* Simplest case - block found, no allocation needed */
        if (!partial) {
                first_block = le32_to_cpu(chain[depth - 1].key);
-               clear_buffer_new(bh_result);
                count++;
                /*map more blocks*/
-               while (count < maxblocks && count <= blocks_to_boundary) {
+               while (count < map->m_len && count <= blocks_to_boundary) {
                        ext4_fsblk_t blk;
 
                        blk = le32_to_cpu(*(chain[depth-1].p + count));
@@ -969,7 +966,7 @@ static int ext4_ind_get_blocks(handle_t *handle, struct inode *inode,
        /*
         * Okay, we need to do block allocation.
        */
-       goal = ext4_find_goal(inode, iblock, partial);
+       goal = ext4_find_goal(inode, map->m_lblk, partial);
 
        /* the number of blocks need to allocate for [d,t]indirect blocks */
        indirect_blks = (chain + depth) - partial - 1;
@@ -979,11 +976,11 @@ static int ext4_ind_get_blocks(handle_t *handle, struct inode *inode,
         * direct blocks to allocate for this branch.
         */
        count = ext4_blks_to_allocate(partial, indirect_blks,
-                                       maxblocks, blocks_to_boundary);
+                                     map->m_len, blocks_to_boundary);
        /*
         * Block out ext4_truncate while we alter the tree
         */
-       err = ext4_alloc_branch(handle, inode, iblock, indirect_blks,
+       err = ext4_alloc_branch(handle, inode, map->m_lblk, indirect_blks,
                                &count, goal,
                                offsets + (partial - chain), partial);
 
@@ -995,18 +992,20 @@ static int ext4_ind_get_blocks(handle_t *handle, struct inode *inode,
         * may need to return -EAGAIN upwards in the worst case.  --sct
         */
        if (!err)
-               err = ext4_splice_branch(handle, inode, iblock,
+               err = ext4_splice_branch(handle, inode, map->m_lblk,
                                         partial, indirect_blks, count);
        if (err)
                goto cleanup;
 
-       set_buffer_new(bh_result);
+       map->m_flags |= EXT4_MAP_NEW;
 
        ext4_update_inode_fsync_trans(handle, inode, 1);
 got_it:
-       map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key));
+       map->m_flags |= EXT4_MAP_MAPPED;
+       map->m_pblk = le32_to_cpu(chain[depth-1].key);
+       map->m_len = count;
        if (count > blocks_to_boundary)
-               set_buffer_boundary(bh_result);
+               map->m_flags |= EXT4_MAP_BOUNDARY;
        err = count;
        /* Clean up and exit */
        partial = chain + depth - 1;    /* the whole chain */
@@ -1016,7 +1015,6 @@ cleanup:
                brelse(partial->bh);
                partial--;
        }
-       BUFFER_TRACE(bh_result, "returned");
 out:
        return err;
 }
@@ -1061,7 +1059,7 @@ static int ext4_indirect_calc_metadata_amount(struct inode *inode,
  */
 static int ext4_calc_metadata_amount(struct inode *inode, sector_t lblock)
 {
-       if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)
+       if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
                return ext4_ext_calc_metadata_amount(inode, lblock);
 
        return ext4_indirect_calc_metadata_amount(inode, lblock);
@@ -1076,7 +1074,6 @@ void ext4_da_update_reserve_space(struct inode *inode,
 {
        struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
        struct ext4_inode_info *ei = EXT4_I(inode);
-       int mdb_free = 0, allocated_meta_blocks = 0;
 
        spin_lock(&ei->i_block_reservation_lock);
        trace_ext4_da_update_reserve_space(inode, used);
@@ -1091,11 +1088,10 @@ void ext4_da_update_reserve_space(struct inode *inode,
 
        /* Update per-inode reservations */
        ei->i_reserved_data_blocks -= used;
-       used += ei->i_allocated_meta_blocks;
        ei->i_reserved_meta_blocks -= ei->i_allocated_meta_blocks;
-       allocated_meta_blocks = ei->i_allocated_meta_blocks;
+       percpu_counter_sub(&sbi->s_dirtyblocks_counter,
+                          used + ei->i_allocated_meta_blocks);
        ei->i_allocated_meta_blocks = 0;
-       percpu_counter_sub(&sbi->s_dirtyblocks_counter, used);
 
        if (ei->i_reserved_data_blocks == 0) {
                /*
@@ -1103,30 +1099,23 @@ void ext4_da_update_reserve_space(struct inode *inode,
                 * only when we have written all of the delayed
                 * allocation blocks.
                 */
-               mdb_free = ei->i_reserved_meta_blocks;
+               percpu_counter_sub(&sbi->s_dirtyblocks_counter,
+                                  ei->i_reserved_meta_blocks);
                ei->i_reserved_meta_blocks = 0;
                ei->i_da_metadata_calc_len = 0;
-               percpu_counter_sub(&sbi->s_dirtyblocks_counter, mdb_free);
        }
        spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
 
-       /* Update quota subsystem */
-       if (quota_claim) {
+       /* Update quota subsystem for data blocks */
+       if (quota_claim)
                dquot_claim_block(inode, used);
-               if (mdb_free)
-                       dquot_release_reservation_block(inode, mdb_free);
-       } else {
+       else {
                /*
                 * We did fallocate with an offset that is already delayed
                 * allocated. So on delayed allocated writeback we should
-                * not update the quota for allocated blocks. But then
-                * converting an fallocate region to initialized region would
-                * have caused a metadata allocation. So claim quota for
-                * that
+                * not re-claim the quota for fallocated blocks.
                 */
-               if (allocated_meta_blocks)
-                       dquot_claim_block(inode, allocated_meta_blocks);
-               dquot_release_reservation_block(inode, mdb_free + used);
+               dquot_release_reservation_block(inode, used);
        }
 
        /*
@@ -1139,15 +1128,15 @@ void ext4_da_update_reserve_space(struct inode *inode,
                ext4_discard_preallocations(inode);
 }
 
-static int check_block_validity(struct inode *inode, const char *msg,
-                               sector_t logical, sector_t phys, int len)
+static int check_block_validity(struct inode *inode, const char *func,
+                               struct ext4_map_blocks *map)
 {
-       if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), phys, len)) {
-               __ext4_error(inode->i_sb, msg,
-                          "inode #%lu logical block %llu mapped to %llu "
-                          "(size %d)", inode->i_ino,
-                          (unsigned long long) logical,
-                          (unsigned long long) phys, len);
+       if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), map->m_pblk,
+                                  map->m_len)) {
+               ext4_error_inode(func, inode,
+                          "lblock %lu mapped to illegal pblock %llu "
+                          "(length %d)", (unsigned long) map->m_lblk,
+                                map->m_pblk, map->m_len);
                return -EIO;
        }
        return 0;
@@ -1212,15 +1201,15 @@ static pgoff_t ext4_num_dirty_pages(struct inode *inode, pgoff_t idx,
 }
 
 /*
- * The ext4_get_blocks() function tries to look up the requested blocks,
+ * The ext4_map_blocks() function tries to look up the requested blocks,
  * and returns if the blocks are already mapped.
  *
  * Otherwise it takes the write lock of the i_data_sem and allocate blocks
  * and store the allocated blocks in the result buffer head and mark it
  * mapped.
  *
- * If file type is extents based, it will call ext4_ext_get_blocks(),
- * Otherwise, call with ext4_ind_get_blocks() to handle indirect mapping
+ * If file type is extents based, it will call ext4_ext_map_blocks(),
+ * Otherwise, call with ext4_ind_map_blocks() to handle indirect mapping
  * based files
  *
  * On success, it returns the number of blocks being mapped or allocate.
@@ -1233,35 +1222,29 @@ static pgoff_t ext4_num_dirty_pages(struct inode *inode, pgoff_t idx,
  *
  * It returns the error in case of allocation failure.
  */
-int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block,
-                   unsigned int max_blocks, struct buffer_head *bh,
-                   int flags)
+int ext4_map_blocks(handle_t *handle, struct inode *inode,
+                   struct ext4_map_blocks *map, int flags)
 {
        int retval;
 
-       clear_buffer_mapped(bh);
-       clear_buffer_unwritten(bh);
-
-       ext_debug("ext4_get_blocks(): inode %lu, flag %d, max_blocks %u,"
-                 "logical block %lu\n", inode->i_ino, flags, max_blocks,
-                 (unsigned long)block);
+       map->m_flags = 0;
+       ext_debug("ext4_map_blocks(): inode %lu, flag %d, max_blocks %u,"
+                 "logical block %lu\n", inode->i_ino, flags, map->m_len,
+                 (unsigned long) map->m_lblk);
        /*
         * Try to see if we can get the block without requesting a new
         * file system block.
         */
        down_read((&EXT4_I(inode)->i_data_sem));
-       if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) {
-               retval =  ext4_ext_get_blocks(handle, inode, block, max_blocks,
-                               bh, 0);
+       if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
+               retval = ext4_ext_map_blocks(handle, inode, map, 0);
        } else {
-               retval = ext4_ind_get_blocks(handle, inode, block, max_blocks,
-                                            bh, 0);
+               retval = ext4_ind_map_blocks(handle, inode, map, 0);
        }
        up_read((&EXT4_I(inode)->i_data_sem));
 
-       if (retval > 0 && buffer_mapped(bh)) {
-               int ret = check_block_validity(inode, "file system corruption",
-                                              block, bh->b_blocknr, retval);
+       if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) {
+               int ret = check_block_validity(inode, __func__, map);
                if (ret != 0)
                        return ret;
        }
@@ -1277,7 +1260,7 @@ int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block,
         * ext4_ext_get_block() returns th create = 0
         * with buffer head unmapped.
         */
-       if (retval > 0 && buffer_mapped(bh))
+       if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED)
                return retval;
 
        /*
@@ -1290,7 +1273,7 @@ int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block,
         * of BH_Unwritten and BH_Mapped flags being simultaneously
         * set on the buffer_head.
         */
-       clear_buffer_unwritten(bh);
+       map->m_flags &= ~EXT4_MAP_UNWRITTEN;
 
        /*
         * New blocks allocate and/or writing to uninitialized extent
@@ -1312,14 +1295,12 @@ int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block,
         * We need to check for EXT4 here because migrate
         * could have changed the inode type in between
         */
-       if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) {
-               retval =  ext4_ext_get_blocks(handle, inode, block, max_blocks,
-                                             bh, flags);
+       if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
+               retval = ext4_ext_map_blocks(handle, inode, map, flags);
        } else {
-               retval = ext4_ind_get_blocks(handle, inode, block,
-                                            max_blocks, bh, flags);
+               retval = ext4_ind_map_blocks(handle, inode, map, flags);
 
-               if (retval > 0 && buffer_new(bh)) {
+               if (retval > 0 && map->m_flags & EXT4_MAP_NEW) {
                        /*
                         * We allocated new blocks which will result in
                         * i_data's format changing.  Force the migrate
@@ -1342,10 +1323,10 @@ int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block,
                EXT4_I(inode)->i_delalloc_reserved_flag = 0;
 
        up_write((&EXT4_I(inode)->i_data_sem));
-       if (retval > 0 && buffer_mapped(bh)) {
-               int ret = check_block_validity(inode, "file system "
-                                              "corruption after allocation",
-                                              block, bh->b_blocknr, retval);
+       if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) {
+               int ret = check_block_validity(inode,
+                                              "ext4_map_blocks_after_alloc",
+                                              map);
                if (ret != 0)
                        return ret;
        }
@@ -1355,109 +1336,109 @@ int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block,
 /* Maximum number of blocks we map for direct IO at once. */
 #define DIO_MAX_BLOCKS 4096
 
-int ext4_get_block(struct inode *inode, sector_t iblock,
-                  struct buffer_head *bh_result, int create)
+static int _ext4_get_block(struct inode *inode, sector_t iblock,
+                          struct buffer_head *bh, int flags)
 {
        handle_t *handle = ext4_journal_current_handle();
+       struct ext4_map_blocks map;
        int ret = 0, started = 0;
-       unsigned max_blocks = bh_result->b_size >> inode->i_blkbits;
        int dio_credits;
 
-       if (create && !handle) {
+       map.m_lblk = iblock;
+       map.m_len = bh->b_size >> inode->i_blkbits;
+
+       if (flags && !handle) {
                /* Direct IO write... */
-               if (max_blocks > DIO_MAX_BLOCKS)
-                       max_blocks = DIO_MAX_BLOCKS;
-               dio_credits = ext4_chunk_trans_blocks(inode, max_blocks);
+               if (map.m_len > DIO_MAX_BLOCKS)
+                       map.m_len = DIO_MAX_BLOCKS;
+               dio_credits = ext4_chunk_trans_blocks(inode, map.m_len);
                handle = ext4_journal_start(inode, dio_credits);
                if (IS_ERR(handle)) {
                        ret = PTR_ERR(handle);
-                       goto out;
+                       return ret;
                }
                started = 1;
        }
 
-       ret = ext4_get_blocks(handle, inode, iblock, max_blocks, bh_result,
-                             create ? EXT4_GET_BLOCKS_CREATE : 0);
+       ret = ext4_map_blocks(handle, inode, &map, flags);
        if (ret > 0) {
-               bh_result->b_size = (ret << inode->i_blkbits);
+               map_bh(bh, inode->i_sb, map.m_pblk);
+               bh->b_state = (bh->b_state & ~EXT4_MAP_FLAGS) | map.m_flags;
+               bh->b_size = inode->i_sb->s_blocksize * map.m_len;
                ret = 0;
        }
        if (started)
                ext4_journal_stop(handle);
-out:
        return ret;
 }
 
+int ext4_get_block(struct inode *inode, sector_t iblock,
+                  struct buffer_head *bh, int create)
+{
+       return _ext4_get_block(inode, iblock, bh,
+                              create ? EXT4_GET_BLOCKS_CREATE : 0);
+}
+
 /*
  * `handle' can be NULL if create is zero
  */
 struct buffer_head *ext4_getblk(handle_t *handle, struct inode *inode,
                                ext4_lblk_t block, int create, int *errp)
 {
-       struct buffer_head dummy;
+       struct ext4_map_blocks map;
+       struct buffer_head *bh;
        int fatal = 0, err;
-       int flags = 0;
 
        J_ASSERT(handle != NULL || create == 0);
 
-       dummy.b_state = 0;
-       dummy.b_blocknr = -1000;
-       buffer_trace_init(&dummy.b_history);
-       if (create)
-               flags |= EXT4_GET_BLOCKS_CREATE;
-       err = ext4_get_blocks(handle, inode, block, 1, &dummy, flags);
-       /*
-        * ext4_get_blocks() returns number of blocks mapped. 0 in
-        * case of a HOLE.
-        */
-       if (err > 0) {
-               if (err > 1)
-                       WARN_ON(1);
-               err = 0;
+       map.m_lblk = block;
+       map.m_len = 1;
+       err = ext4_map_blocks(handle, inode, &map,
+                             create ? EXT4_GET_BLOCKS_CREATE : 0);
+
+       if (err < 0)
+               *errp = err;
+       if (err <= 0)
+               return NULL;
+       *errp = 0;
+
+       bh = sb_getblk(inode->i_sb, map.m_pblk);
+       if (!bh) {
+               *errp = -EIO;
+               return NULL;
        }
-       *errp = err;
-       if (!err && buffer_mapped(&dummy)) {
-               struct buffer_head *bh;
-               bh = sb_getblk(inode->i_sb, dummy.b_blocknr);
-               if (!bh) {
-                       *errp = -EIO;
-                       goto err;
-               }
-               if (buffer_new(&dummy)) {
-                       J_ASSERT(create != 0);
-                       J_ASSERT(handle != NULL);
+       if (map.m_flags & EXT4_MAP_NEW) {
+               J_ASSERT(create != 0);
+               J_ASSERT(handle != NULL);
 
-                       /*
-                        * Now that we do not always journal data, we should
-                        * keep in mind whether this should always journal the
-                        * new buffer as metadata.  For now, regular file
-                        * writes use ext4_get_block instead, so it's not a
-                        * problem.
-                        */
-                       lock_buffer(bh);
-                       BUFFER_TRACE(bh, "call get_create_access");
-                       fatal = ext4_journal_get_create_access(handle, bh);
-                       if (!fatal && !buffer_uptodate(bh)) {
-                               memset(bh->b_data, 0, inode->i_sb->s_blocksize);
-                               set_buffer_uptodate(bh);
-                       }
-                       unlock_buffer(bh);
-                       BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
-                       err = ext4_handle_dirty_metadata(handle, inode, bh);
-                       if (!fatal)
-                               fatal = err;
-               } else {
-                       BUFFER_TRACE(bh, "not a new buffer");
-               }
-               if (fatal) {
-                       *errp = fatal;
-                       brelse(bh);
-                       bh = NULL;
+               /*
+                * Now that we do not always journal data, we should
+                * keep in mind whether this should always journal the
+                * new buffer as metadata.  For now, regular file
+                * writes use ext4_get_block instead, so it's not a
+                * problem.
+                */
+               lock_buffer(bh);
+               BUFFER_TRACE(bh, "call get_create_access");
+               fatal = ext4_journal_get_create_access(handle, bh);
+               if (!fatal && !buffer_uptodate(bh)) {
+                       memset(bh->b_data, 0, inode->i_sb->s_blocksize);
+                       set_buffer_uptodate(bh);
                }
-               return bh;
+               unlock_buffer(bh);
+               BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
+               err = ext4_handle_dirty_metadata(handle, inode, bh);
+               if (!fatal)
+                       fatal = err;
+       } else {
+               BUFFER_TRACE(bh, "not a new buffer");
        }
-err:
-       return NULL;
+       if (fatal) {
+               *errp = fatal;
+               brelse(bh);
+               bh = NULL;
+       }
+       return bh;
 }
 
 struct buffer_head *ext4_bread(handle_t *handle, struct inode *inode,
@@ -1860,7 +1841,7 @@ static int ext4_da_reserve_space(struct inode *inode, sector_t lblock)
        int retries = 0;
        struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
        struct ext4_inode_info *ei = EXT4_I(inode);
-       unsigned long md_needed, md_reserved;
+       unsigned long md_needed;
        int ret;
 
        /*
@@ -1870,22 +1851,24 @@ static int ext4_da_reserve_space(struct inode *inode, sector_t lblock)
         */
 repeat:
        spin_lock(&ei->i_block_reservation_lock);
-       md_reserved = ei->i_reserved_meta_blocks;
        md_needed = ext4_calc_metadata_amount(inode, lblock);
        trace_ext4_da_reserve_space(inode, md_needed);
        spin_unlock(&ei->i_block_reservation_lock);
 
        /*
-        * Make quota reservation here to prevent quota overflow
-        * later. Real quota accounting is done at pages writeout
-        * time.
+        * We will charge metadata quota at writeout time; this saves
+        * us from metadata over-estimation, though we may go over by
+        * a small amount in the end.  Here we just reserve for data.
         */
-       ret = dquot_reserve_block(inode, md_needed + 1);
+       ret = dquot_reserve_block(inode, 1);
        if (ret)
                return ret;
-
+       /*
+        * We do still charge estimated metadata to the sb though;
+        * we cannot afford to run out of free blocks.
+        */
        if (ext4_claim_free_blocks(sbi, md_needed + 1)) {
-               dquot_release_reservation_block(inode, md_needed + 1);
+               dquot_release_reservation_block(inode, 1);
                if (ext4_should_retry_alloc(inode->i_sb, &retries)) {
                        yield();
                        goto repeat;
@@ -1910,6 +1893,7 @@ static void ext4_da_release_space(struct inode *inode, int to_free)
 
        spin_lock(&EXT4_I(inode)->i_block_reservation_lock);
 
+       trace_ext4_da_release_space(inode, to_free);
        if (unlikely(to_free > ei->i_reserved_data_blocks)) {
                /*
                 * if there aren't enough reserved blocks, then the
@@ -1932,12 +1916,13 @@ static void ext4_da_release_space(struct inode *inode, int to_free)
                 * only when we have written all of the delayed
                 * allocation blocks.
                 */
-               to_free += ei->i_reserved_meta_blocks;
+               percpu_counter_sub(&sbi->s_dirtyblocks_counter,
+                                  ei->i_reserved_meta_blocks);
                ei->i_reserved_meta_blocks = 0;
                ei->i_da_metadata_calc_len = 0;
        }
 
-       /* update fs dirty blocks counter */
+       /* update fs dirty data blocks counter */
        percpu_counter_sub(&sbi->s_dirtyblocks_counter, to_free);
 
        spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
@@ -2042,28 +2027,23 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd)
 /*
  * mpage_put_bnr_to_bhs - walk blocks and assign them actual numbers
  *
- * @mpd->inode - inode to walk through
- * @exbh->b_blocknr - first block on a disk
- * @exbh->b_size - amount of space in bytes
- * @logical - first logical block to start assignment with
- *
  * the function goes through all passed space and put actual disk
  * block numbers into buffer heads, dropping BH_Delay and BH_Unwritten
  */
-static void mpage_put_bnr_to_bhs(struct mpage_da_data *mpd, sector_t logical,
-                                struct buffer_head *exbh)
+static void mpage_put_bnr_to_bhs(struct mpage_da_data *mpd,
+                                struct ext4_map_blocks *map)
 {
        struct inode *inode = mpd->inode;
        struct address_space *mapping = inode->i_mapping;
-       int blocks = exbh->b_size >> inode->i_blkbits;
-       sector_t pblock = exbh->b_blocknr, cur_logical;
+       int blocks = map->m_len;
+       sector_t pblock = map->m_pblk, cur_logical;
        struct buffer_head *head, *bh;
        pgoff_t index, end;
        struct pagevec pvec;
        int nr_pages, i;
 
-       index = logical >> (PAGE_CACHE_SHIFT - inode->i_blkbits);
-       end = (logical + blocks - 1) >> (PAGE_CACHE_SHIFT - inode->i_blkbits);
+       index = map->m_lblk >> (PAGE_CACHE_SHIFT - inode->i_blkbits);
+       end = (map->m_lblk + blocks - 1) >> (PAGE_CACHE_SHIFT - inode->i_blkbits);
        cur_logical = index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
 
        pagevec_init(&pvec, 0);
@@ -2090,17 +2070,16 @@ static void mpage_put_bnr_to_bhs(struct mpage_da_data *mpd, sector_t logical,
 
                        /* skip blocks out of the range */
                        do {
-                               if (cur_logical >= logical)
+                               if (cur_logical >= map->m_lblk)
                                        break;
                                cur_logical++;
                        } while ((bh = bh->b_this_page) != head);
 
                        do {
-                               if (cur_logical >= logical + blocks)
+                               if (cur_logical >= map->m_lblk + blocks)
                                        break;
 
-                               if (buffer_delay(bh) ||
-                                               buffer_unwritten(bh)) {
+                               if (buffer_delay(bh) || buffer_unwritten(bh)) {
 
                                        BUG_ON(bh->b_bdev != inode->i_sb->s_bdev);
 
@@ -2119,7 +2098,7 @@ static void mpage_put_bnr_to_bhs(struct mpage_da_data *mpd, sector_t logical,
                                } else if (buffer_mapped(bh))
                                        BUG_ON(bh->b_blocknr != pblock);
 
-                               if (buffer_uninit(exbh))
+                               if (map->m_flags & EXT4_MAP_UNINIT)
                                        set_buffer_uninit(bh);
                                cur_logical++;
                                pblock++;
@@ -2130,21 +2109,6 @@ static void mpage_put_bnr_to_bhs(struct mpage_da_data *mpd, sector_t logical,
 }
 
 
-/*
- * __unmap_underlying_blocks - just a helper function to unmap
- * set of blocks described by @bh
- */
-static inline void __unmap_underlying_blocks(struct inode *inode,
-                                            struct buffer_head *bh)
-{
-       struct block_device *bdev = inode->i_sb->s_bdev;
-       int blocks, i;
-
-       blocks = bh->b_size >> inode->i_blkbits;
-       for (i = 0; i < blocks; i++)
-               unmap_underlying_metadata(bdev, bh->b_blocknr + i);
-}
-
 static void ext4_da_block_invalidatepages(struct mpage_da_data *mpd,
                                        sector_t logical, long blk_cnt)
 {
@@ -2206,7 +2170,7 @@ static void ext4_print_free_blocks(struct inode *inode)
 static int mpage_da_map_blocks(struct mpage_da_data *mpd)
 {
        int err, blks, get_blocks_flags;
-       struct buffer_head new;
+       struct ext4_map_blocks map;
        sector_t next = mpd->b_blocknr;
        unsigned max_blocks = mpd->b_size >> mpd->inode->i_blkbits;
        loff_t disksize = EXT4_I(mpd->inode)->i_disksize;
@@ -2247,15 +2211,15 @@ static int mpage_da_map_blocks(struct mpage_da_data *mpd)
         * EXT4_GET_BLOCKS_DELALLOC_RESERVE so the delalloc accounting
         * variables are updated after the blocks have been allocated.
         */
-       new.b_state = 0;
+       map.m_lblk = next;
+       map.m_len = max_blocks;
        get_blocks_flags = EXT4_GET_BLOCKS_CREATE;
        if (ext4_should_dioread_nolock(mpd->inode))
                get_blocks_flags |= EXT4_GET_BLOCKS_IO_CREATE_EXT;
        if (mpd->b_state & (1 << BH_Delay))
                get_blocks_flags |= EXT4_GET_BLOCKS_DELALLOC_RESERVE;
 
-       blks = ext4_get_blocks(handle, mpd->inode, next, max_blocks,
-                              &new, get_blocks_flags);
+       blks = ext4_map_blocks(handle, mpd->inode, &map, get_blocks_flags);
        if (blks < 0) {
                err = blks;
                /*
@@ -2282,7 +2246,7 @@ static int mpage_da_map_blocks(struct mpage_da_data *mpd)
                ext4_msg(mpd->inode->i_sb, KERN_CRIT,
                         "delayed block allocation failed for inode %lu at "
                         "logical offset %llu with max blocks %zd with "
-                        "error %d\n", mpd->inode->i_ino,
+                        "error %d", mpd->inode->i_ino,
                         (unsigned long long) next,
                         mpd->b_size >> mpd->inode->i_blkbits, err);
                printk(KERN_CRIT "This should not happen!!  "
@@ -2297,10 +2261,13 @@ static int mpage_da_map_blocks(struct mpage_da_data *mpd)
        }
        BUG_ON(blks == 0);
 
-       new.b_size = (blks << mpd->inode->i_blkbits);
+       if (map.m_flags & EXT4_MAP_NEW) {
+               struct block_device *bdev = mpd->inode->i_sb->s_bdev;
+               int i;
 
-       if (buffer_new(&new))
-               __unmap_underlying_blocks(mpd->inode, &new);
+               for (i = 0; i < map.m_len; i++)
+                       unmap_underlying_metadata(bdev, map.m_pblk + i);
+       }
 
        /*
         * If blocks are delayed marked, we need to
@@ -2308,7 +2275,7 @@ static int mpage_da_map_blocks(struct mpage_da_data *mpd)
         */
        if ((mpd->b_state & (1 << BH_Delay)) ||
            (mpd->b_state & (1 << BH_Unwritten)))
-               mpage_put_bnr_to_bhs(mpd, next, &new);
+               mpage_put_bnr_to_bhs(mpd, &map);
 
        if (ext4_should_order_data(mpd->inode)) {
                err = ext4_jbd2_file_inode(handle, mpd->inode);
@@ -2349,8 +2316,17 @@ static void mpage_add_bh_to_extent(struct mpage_da_data *mpd,
        sector_t next;
        int nrblocks = mpd->b_size >> mpd->inode->i_blkbits;
 
+       /*
+        * XXX Don't go larger than mballoc is willing to allocate
+        * This is a stopgap solution.  We eventually need to fold
+        * mpage_da_submit_io() into this function and then call
+        * ext4_get_blocks() multiple times in a loop
+        */
+       if (nrblocks >= 8*1024*1024/mpd->inode->i_sb->s_blocksize)
+               goto flush_it;
+
        /* check if thereserved journal credits might overflow */
-       if (!(EXT4_I(mpd->inode)->i_flags & EXT4_EXTENTS_FL)) {
+       if (!(ext4_test_inode_flag(mpd->inode, EXT4_INODE_EXTENTS))) {
                if (nrblocks >= EXT4_MAX_TRANS_DATA) {
                        /*
                         * With non-extent format we are limited by the journal
@@ -2423,17 +2399,6 @@ static int __mpage_da_writepage(struct page *page,
        struct buffer_head *bh, *head;
        sector_t logical;
 
-       if (mpd->io_done) {
-               /*
-                * Rest of the page in the page_vec
-                * redirty then and skip then. We will
-                * try to write them again after
-                * starting a new transaction
-                */
-               redirty_page_for_writepage(wbc, page);
-               unlock_page(page);
-               return MPAGE_DA_EXTENT_TAIL;
-       }
        /*
         * Can we merge this page to current extent?
         */
@@ -2528,8 +2493,9 @@ static int __mpage_da_writepage(struct page *page,
  * initialized properly.
  */
 static int ext4_da_get_block_prep(struct inode *inode, sector_t iblock,
-                                 struct buffer_head *bh_result, int create)
+                                 struct buffer_head *bh, int create)
 {
+       struct ext4_map_blocks map;
        int ret = 0;
        sector_t invalid_block = ~((sector_t) 0xffff);
 
@@ -2537,16 +2503,22 @@ static int ext4_da_get_block_prep(struct inode *inode, sector_t iblock,
                invalid_block = ~0;
 
        BUG_ON(create == 0);
-       BUG_ON(bh_result->b_size != inode->i_sb->s_blocksize);
+       BUG_ON(bh->b_size != inode->i_sb->s_blocksize);
+
+       map.m_lblk = iblock;
+       map.m_len = 1;
 
        /*
         * first, we need to know whether the block is allocated already
         * preallocated blocks are unmapped but should treated
         * the same as allocated blocks.
         */
-       ret = ext4_get_blocks(NULL, inode, iblock, 1,  bh_result, 0);
-       if ((ret == 0) && !buffer_delay(bh_result)) {
-               /* the block isn't (pre)allocated yet, let's reserve space */
+       ret = ext4_map_blocks(NULL, inode, &map, 0);
+       if (ret < 0)
+               return ret;
+       if (ret == 0) {
+               if (buffer_delay(bh))
+                       return 0; /* Not sure this could or should happen */
                /*
                 * XXX: __block_prepare_write() unmaps passed block,
                 * is it OK?
@@ -2556,26 +2528,26 @@ static int ext4_da_get_block_prep(struct inode *inode, sector_t iblock,
                        /* not enough space to reserve */
                        return ret;
 
-               map_bh(bh_result, inode->i_sb, invalid_block);
-               set_buffer_new(bh_result);
-               set_buffer_delay(bh_result);
-       } else if (ret > 0) {
-               bh_result->b_size = (ret << inode->i_blkbits);
-               if (buffer_unwritten(bh_result)) {
-                       /* A delayed write to unwritten bh should
-                        * be marked new and mapped.  Mapped ensures
-                        * that we don't do get_block multiple times
-                        * when we write to the same offset and new
-                        * ensures that we do proper zero out for
-                        * partial write.
-                        */
-                       set_buffer_new(bh_result);
-                       set_buffer_mapped(bh_result);
-               }
-               ret = 0;
+               map_bh(bh, inode->i_sb, invalid_block);
+               set_buffer_new(bh);
+               set_buffer_delay(bh);
+               return 0;
        }
 
-       return ret;
+       map_bh(bh, inode->i_sb, map.m_pblk);
+       bh->b_state = (bh->b_state & ~EXT4_MAP_FLAGS) | map.m_flags;
+
+       if (buffer_unwritten(bh)) {
+               /* A delayed write to unwritten bh should be marked
+                * new and mapped.  Mapped ensures that we don't do
+                * get_block multiple times when we write to the same
+                * offset and new ensures that we do proper zero out
+                * for partial write.
+                */
+               set_buffer_new(bh);
+               set_buffer_mapped(bh);
+       }
+       return 0;
 }
 
 /*
@@ -2597,21 +2569,8 @@ static int ext4_da_get_block_prep(struct inode *inode, sector_t iblock,
 static int noalloc_get_block_write(struct inode *inode, sector_t iblock,
                                   struct buffer_head *bh_result, int create)
 {
-       int ret = 0;
-       unsigned max_blocks = bh_result->b_size >> inode->i_blkbits;
-
        BUG_ON(bh_result->b_size != inode->i_sb->s_blocksize);
-
-       /*
-        * we don't want to do block allocation in writepage
-        * so call get_block_wrap with create = 0
-        */
-       ret = ext4_get_blocks(NULL, inode, iblock, max_blocks, bh_result, 0);
-       if (ret > 0) {
-               bh_result->b_size = (ret << inode->i_blkbits);
-               ret = 0;
-       }
-       return ret;
+       return _ext4_get_block(inode, iblock, bh_result, 0);
 }
 
 static int bget_one(handle_t *handle, struct buffer_head *bh)
@@ -2821,13 +2780,131 @@ static int ext4_da_writepages_trans_blocks(struct inode *inode)
         * number of contiguous block. So we will limit
         * number of contiguous block to a sane value
         */
-       if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) &&
+       if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) &&
            (max_blocks > EXT4_MAX_TRANS_DATA))
                max_blocks = EXT4_MAX_TRANS_DATA;
 
        return ext4_chunk_trans_blocks(inode, max_blocks);
 }
 
+/*
+ * write_cache_pages_da - walk the list of dirty pages of the given
+ * address space and call the callback function (which usually writes
+ * the pages).
+ *
+ * This is a forked version of write_cache_pages().  Differences:
+ *     Range cyclic is ignored.
+ *     no_nrwrite_index_update is always presumed true
+ */
+static int write_cache_pages_da(struct address_space *mapping,
+                               struct writeback_control *wbc,
+                               struct mpage_da_data *mpd)
+{
+       int ret = 0;
+       int done = 0;
+       struct pagevec pvec;
+       int nr_pages;
+       pgoff_t index;
+       pgoff_t end;            /* Inclusive */
+       long nr_to_write = wbc->nr_to_write;
+
+       pagevec_init(&pvec, 0);
+       index = wbc->range_start >> PAGE_CACHE_SHIFT;
+       end = wbc->range_end >> PAGE_CACHE_SHIFT;
+
+       while (!done && (index <= end)) {
+               int i;
+
+               nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
+                             PAGECACHE_TAG_DIRTY,
+                             min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1);
+               if (nr_pages == 0)
+                       break;
+
+               for (i = 0; i < nr_pages; i++) {
+                       struct page *page = pvec.pages[i];
+
+                       /*
+                        * At this point, the page may be truncated or
+                        * invalidated (changing page->mapping to NULL), or
+                        * even swizzled back from swapper_space to tmpfs file
+                        * mapping. However, page->index will not change
+                        * because we have a reference on the page.
+                        */
+                       if (page->index > end) {
+                               done = 1;
+                               break;
+                       }
+
+                       lock_page(page);
+
+                       /*
+                        * Page truncated or invalidated. We can freely skip it
+                        * then, even for data integrity operations: the page
+                        * has disappeared concurrently, so there could be no
+                        * real expectation of this data interity operation
+                        * even if there is now a new, dirty page at the same
+                        * pagecache address.
+                        */
+                       if (unlikely(page->mapping != mapping)) {
+continue_unlock:
+                               unlock_page(page);
+                               continue;
+                       }
+
+                       if (!PageDirty(page)) {
+                               /* someone wrote it for us */
+                               goto continue_unlock;
+                       }
+
+                       if (PageWriteback(page)) {
+                               if (wbc->sync_mode != WB_SYNC_NONE)
+                                       wait_on_page_writeback(page);
+                               else
+                                       goto continue_unlock;
+                       }
+
+                       BUG_ON(PageWriteback(page));
+                       if (!clear_page_dirty_for_io(page))
+                               goto continue_unlock;
+
+                       ret = __mpage_da_writepage(page, wbc, mpd);
+                       if (unlikely(ret)) {
+                               if (ret == AOP_WRITEPAGE_ACTIVATE) {
+                                       unlock_page(page);
+                                       ret = 0;
+                               } else {
+                                       done = 1;
+                                       break;
+                               }
+                       }
+
+                       if (nr_to_write > 0) {
+                               nr_to_write--;
+                               if (nr_to_write == 0 &&
+                                   wbc->sync_mode == WB_SYNC_NONE) {
+                                       /*
+                                        * We stop writing back only if we are
+                                        * not doing integrity sync. In case of
+                                        * integrity sync we have to keep going
+                                        * because someone may be concurrently
+                                        * dirtying pages, and we might have
+                                        * synced a lot of newly appeared dirty
+                                        * pages, but have not synced all of the
+                                        * old dirty pages.
+                                        */
+                                       done = 1;
+                                       break;
+                               }
+                       }
+               }
+               pagevec_release(&pvec);
+               cond_resched();
+       }
+       return ret;
+}
+
+
 static int ext4_da_writepages(struct address_space *mapping,
                              struct writeback_control *wbc)
 {
@@ -2836,7 +2913,6 @@ static int ext4_da_writepages(struct address_space *mapping,
        handle_t *handle = NULL;
        struct mpage_da_data mpd;
        struct inode *inode = mapping->host;
-       int no_nrwrite_index_update;
        int pages_written = 0;
        long pages_skipped;
        unsigned int max_pages;
@@ -2916,12 +2992,6 @@ static int ext4_da_writepages(struct address_space *mapping,
        mpd.wbc = wbc;
        mpd.inode = mapping->host;
 
-       /*
-        * we don't want write_cache_pages to update
-        * nr_to_write and writeback_index
-        */
-       no_nrwrite_index_update = wbc->no_nrwrite_index_update;
-       wbc->no_nrwrite_index_update = 1;
        pages_skipped = wbc->pages_skipped;
 
 retry:
@@ -2941,7 +3011,7 @@ retry:
                if (IS_ERR(handle)) {
                        ret = PTR_ERR(handle);
                        ext4_msg(inode->i_sb, KERN_CRIT, "%s: jbd2_start: "
-                              "%ld pages, ino %lu; err %d\n", __func__,
+                              "%ld pages, ino %lu; err %d", __func__,
                                wbc->nr_to_write, inode->i_ino, ret);
                        goto out_writepages;
                }
@@ -2963,8 +3033,7 @@ retry:
                mpd.io_done = 0;
                mpd.pages_written = 0;
                mpd.retval = 0;
-               ret = write_cache_pages(mapping, wbc, __mpage_da_writepage,
-                                       &mpd);
+               ret = write_cache_pages_da(mapping, wbc, &mpd);
                /*
                 * If we have a contiguous extent of pages and we
                 * haven't done the I/O yet, map the blocks and submit
@@ -3016,7 +3085,7 @@ retry:
        if (pages_skipped != wbc->pages_skipped)
                ext4_msg(inode->i_sb, KERN_CRIT,
                         "This should not happen leaving %s "
-                        "with nr_to_write = %ld ret = %d\n",
+                        "with nr_to_write = %ld ret = %d",
                         __func__, wbc->nr_to_write, ret);
 
        /* Update index */
@@ -3030,8 +3099,6 @@ retry:
                mapping->writeback_index = index;
 
 out_writepages:
-       if (!no_nrwrite_index_update)
-               wbc->no_nrwrite_index_update = 0;
        wbc->nr_to_write -= nr_to_writebump;
        wbc->range_start = range_start;
        trace_ext4_da_writepages_result(inode, wbc, ret, pages_written);
@@ -3076,7 +3143,7 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping,
                               loff_t pos, unsigned len, unsigned flags,
                               struct page **pagep, void **fsdata)
 {
-       int ret, retries = 0, quota_retries = 0;
+       int ret, retries = 0;
        struct page *page;
        pgoff_t index;
        unsigned from, to;
@@ -3135,22 +3202,6 @@ retry:
 
        if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
                goto retry;
-
-       if ((ret == -EDQUOT) &&
-           EXT4_I(inode)->i_reserved_meta_blocks &&
-           (quota_retries++ < 3)) {
-               /*
-                * Since we often over-estimate the number of meta
-                * data blocks required, we may sometimes get a
-                * spurios out of quota error even though there would
-                * be enough space once we write the data blocks and
-                * find out how many meta data blocks were _really_
-                * required.  So try forcing the inode write to see if
-                * that helps.
-                */
-               write_inode_now(inode, (quota_retries == 3));
-               goto retry;
-       }
 out:
        return ret;
 }
@@ -3546,46 +3597,18 @@ out:
        return ret;
 }
 
+/*
+ * ext4_get_block used when preparing for a DIO write or buffer write.
+ * We allocate an uinitialized extent if blocks haven't been allocated.
+ * The extent will be converted to initialized after the IO is complete.
+ */
 static int ext4_get_block_write(struct inode *inode, sector_t iblock,
                   struct buffer_head *bh_result, int create)
 {
-       handle_t *handle = ext4_journal_current_handle();
-       int ret = 0;
-       unsigned max_blocks = bh_result->b_size >> inode->i_blkbits;
-       int dio_credits;
-       int started = 0;
-
        ext4_debug("ext4_get_block_write: inode %lu, create flag %d\n",
                   inode->i_ino, create);
-       /*
-        * ext4_get_block in prepare for a DIO write or buffer write.
-        * We allocate an uinitialized extent if blocks haven't been allocated.
-        * The extent will be converted to initialized after IO complete.
-        */
-       create = EXT4_GET_BLOCKS_IO_CREATE_EXT;
-
-       if (!handle) {
-               if (max_blocks > DIO_MAX_BLOCKS)
-                       max_blocks = DIO_MAX_BLOCKS;
-               dio_credits = ext4_chunk_trans_blocks(inode, max_blocks);
-               handle = ext4_journal_start(inode, dio_credits);
-               if (IS_ERR(handle)) {
-                       ret = PTR_ERR(handle);
-                       goto out;
-               }
-               started = 1;
-       }
-
-       ret = ext4_get_blocks(handle, inode, iblock, max_blocks, bh_result,
-                             create);
-       if (ret > 0) {
-               bh_result->b_size = (ret << inode->i_blkbits);
-               ret = 0;
-       }
-       if (started)
-               ext4_journal_stop(handle);
-out:
-       return ret;
+       return _ext4_get_block(inode, iblock, bh_result,
+                              EXT4_GET_BLOCKS_IO_CREATE_EXT);
 }
 
 static void dump_completed_IO(struct inode * inode)
@@ -3973,7 +3996,7 @@ static ssize_t ext4_direct_IO(int rw, struct kiocb *iocb,
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_mapping->host;
 
-       if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)
+       if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
                return ext4_ext_direct_IO(rw, iocb, iov, offset, nr_segs);
 
        return ext4_ind_direct_IO(rw, iocb, iov, offset, nr_segs);
@@ -4302,10 +4325,9 @@ static int ext4_clear_blocks(handle_t *handle, struct inode *inode,
 
        if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), block_to_free,
                                   count)) {
-               ext4_error(inode->i_sb, "inode #%lu: "
-                          "attempt to clear blocks %llu len %lu, invalid",
-                          inode->i_ino, (unsigned long long) block_to_free,
-                          count);
+               EXT4_ERROR_INODE(inode, "attempt to clear invalid "
+                                "blocks %llu len %lu",
+                                (unsigned long long) block_to_free, count);
                return 1;
        }
 
@@ -4410,11 +4432,10 @@ static void ext4_free_data(handle_t *handle, struct inode *inode,
                if ((EXT4_JOURNAL(inode) == NULL) || bh2jh(this_bh))
                        ext4_handle_dirty_metadata(handle, inode, this_bh);
                else
-                       ext4_error(inode->i_sb,
-                                  "circular indirect block detected, "
-                                  "inode=%lu, block=%llu",
-                                  inode->i_ino,
-                                  (unsigned long long) this_bh->b_blocknr);
+                       EXT4_ERROR_INODE(inode,
+                                        "circular indirect block detected at "
+                                        "block %llu",
+                               (unsigned long long) this_bh->b_blocknr);
        }
 }
 
@@ -4452,11 +4473,10 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode,
 
                        if (!ext4_data_block_valid(EXT4_SB(inode->i_sb),
                                                   nr, 1)) {
-                               ext4_error(inode->i_sb,
-                                          "indirect mapped block in inode "
-                                          "#%lu invalid (level %d, blk #%lu)",
-                                          inode->i_ino, depth,
-                                          (unsigned long) nr);
+                               EXT4_ERROR_INODE(inode,
+                                                "invalid indirect mapped "
+                                                "block %lu (level %d)",
+                                                (unsigned long) nr, depth);
                                break;
                        }
 
@@ -4468,9 +4488,9 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode,
                         * (should be rare).
                         */
                        if (!bh) {
-                               ext4_error(inode->i_sb,
-                                          "Read failure, inode=%lu, block=%llu",
-                                          inode->i_ino, nr);
+                               EXT4_ERROR_INODE(inode,
+                                                "Read failure block=%llu",
+                                                (unsigned long long) nr);
                                continue;
                        }
 
@@ -4612,12 +4632,12 @@ void ext4_truncate(struct inode *inode)
        if (!ext4_can_truncate(inode))
                return;
 
-       EXT4_I(inode)->i_flags &= ~EXT4_EOFBLOCKS_FL;
+       ext4_clear_inode_flag(inode, EXT4_INODE_EOFBLOCKS);
 
        if (inode->i_size == 0 && !test_opt(inode->i_sb, NO_AUTO_DA_ALLOC))
                ext4_set_inode_state(inode, EXT4_STATE_DA_ALLOC_CLOSE);
 
-       if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) {
+       if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
                ext4_ext_truncate(inode);
                return;
        }
@@ -4785,8 +4805,8 @@ static int __ext4_get_inode_loc(struct inode *inode,
 
        bh = sb_getblk(sb, block);
        if (!bh) {
-               ext4_error(sb, "unable to read inode block - "
-                          "inode=%lu, block=%llu", inode->i_ino, block);
+               EXT4_ERROR_INODE(inode, "unable to read inode block - "
+                                "block %llu", block);
                return -EIO;
        }
        if (!buffer_uptodate(bh)) {
@@ -4884,8 +4904,8 @@ make_io:
                submit_bh(READ_META, bh);
                wait_on_buffer(bh);
                if (!buffer_uptodate(bh)) {
-                       ext4_error(sb, "unable to read inode block - inode=%lu,"
-                                  " block=%llu", inode->i_ino, block);
+                       EXT4_ERROR_INODE(inode, "unable to read inode "
+                                        "block %llu", block);
                        brelse(bh);
                        return -EIO;
                }
@@ -5096,8 +5116,8 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
        ret = 0;
        if (ei->i_file_acl &&
            !ext4_data_block_valid(EXT4_SB(sb), ei->i_file_acl, 1)) {
-               ext4_error(sb, "bad extended attribute block %llu inode #%lu",
-                          ei->i_file_acl, inode->i_ino);
+               EXT4_ERROR_INODE(inode, "bad extended attribute block %llu",
+                                ei->i_file_acl);
                ret = -EIO;
                goto bad_inode;
        } else if (ei->i_flags & EXT4_EXTENTS_FL) {
@@ -5142,8 +5162,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
                           new_decode_dev(le32_to_cpu(raw_inode->i_block[1])));
        } else {
                ret = -EIO;
-               ext4_error(inode->i_sb, "bogus i_mode (%o) for inode=%lu",
-                          inode->i_mode, inode->i_ino);
+               EXT4_ERROR_INODE(inode, "bogus i_mode (%o)", inode->i_mode);
                goto bad_inode;
        }
        brelse(iloc.bh);
@@ -5381,9 +5400,9 @@ int ext4_write_inode(struct inode *inode, struct writeback_control *wbc)
                if (wbc->sync_mode == WB_SYNC_ALL)
                        sync_dirty_buffer(iloc.bh);
                if (buffer_req(iloc.bh) && !buffer_uptodate(iloc.bh)) {
-                       ext4_error(inode->i_sb, "IO error syncing inode, "
-                                  "inode=%lu, block=%llu", inode->i_ino,
-                                  (unsigned long long)iloc.bh->b_blocknr);
+                       EXT4_ERROR_INODE(inode,
+                               "IO error syncing inode (block=%llu)",
+                               (unsigned long long) iloc.bh->b_blocknr);
                        err = -EIO;
                }
                brelse(iloc.bh);
@@ -5455,7 +5474,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
        }
 
        if (attr->ia_valid & ATTR_SIZE) {
-               if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)) {
+               if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) {
                        struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
 
                        if (attr->ia_size > sbi->s_bitmap_maxbytes) {
@@ -5468,7 +5487,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
        if (S_ISREG(inode->i_mode) &&
            attr->ia_valid & ATTR_SIZE &&
            (attr->ia_size < inode->i_size ||
-            (EXT4_I(inode)->i_flags & EXT4_EOFBLOCKS_FL))) {
+            (ext4_test_inode_flag(inode, EXT4_INODE_EOFBLOCKS)))) {
                handle_t *handle;
 
                handle = ext4_journal_start(inode, 3);
@@ -5500,7 +5519,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
                        }
                }
                /* ext4_truncate will clear the flag */
-               if ((EXT4_I(inode)->i_flags & EXT4_EOFBLOCKS_FL))
+               if ((ext4_test_inode_flag(inode, EXT4_INODE_EOFBLOCKS)))
                        ext4_truncate(inode);
        }
 
@@ -5576,7 +5595,7 @@ static int ext4_indirect_trans_blocks(struct inode *inode, int nrblocks,
 
 static int ext4_index_trans_blocks(struct inode *inode, int nrblocks, int chunk)
 {
-       if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL))
+       if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
                return ext4_indirect_trans_blocks(inode, nrblocks, chunk);
        return ext4_ext_index_trans_blocks(inode, nrblocks, chunk);
 }
@@ -5911,9 +5930,9 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
         */
 
        if (val)
-               EXT4_I(inode)->i_flags |= EXT4_JOURNAL_DATA_FL;
+               ext4_set_inode_flag(inode, EXT4_INODE_JOURNAL_DATA);
        else
-               EXT4_I(inode)->i_flags &= ~EXT4_JOURNAL_DATA_FL;
+               ext4_clear_inode_flag(inode, EXT4_INODE_JOURNAL_DATA);
        ext4_set_aops(inode);
 
        jbd2_journal_unlock_updates(journal);
index 016d0249294ff15d3442061d38050df24b09e50e..bf5ae883b1bdc30ff55cbc616bab7c24f9d57dbb 100644 (file)
@@ -258,7 +258,7 @@ setversion_out:
                if (me.moved_len > 0)
                        file_remove_suid(donor_filp);
 
-               if (copy_to_user((struct move_extent __user *)arg, 
+               if (copy_to_user((struct move_extent __user *)arg,
                                 &me, sizeof(me)))
                        err = -EFAULT;
 mext_out:
@@ -373,7 +373,30 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case EXT4_IOC32_SETRSVSZ:
                cmd = EXT4_IOC_SETRSVSZ;
                break;
-       case EXT4_IOC_GROUP_ADD:
+       case EXT4_IOC32_GROUP_ADD: {
+               struct compat_ext4_new_group_input __user *uinput;
+               struct ext4_new_group_input input;
+               mm_segment_t old_fs;
+               int err;
+
+               uinput = compat_ptr(arg);
+               err = get_user(input.group, &uinput->group);
+               err |= get_user(input.block_bitmap, &uinput->block_bitmap);
+               err |= get_user(input.inode_bitmap, &uinput->inode_bitmap);
+               err |= get_user(input.inode_table, &uinput->inode_table);
+               err |= get_user(input.blocks_count, &uinput->blocks_count);
+               err |= get_user(input.reserved_blocks,
+                               &uinput->reserved_blocks);
+               if (err)
+                       return -EFAULT;
+               old_fs = get_fs();
+               set_fs(KERNEL_DS);
+               err = ext4_ioctl(file, EXT4_IOC_GROUP_ADD,
+                                (unsigned long) &input);
+               set_fs(old_fs);
+               return err;
+       }
+       case EXT4_IOC_MOVE_EXT:
                break;
        default:
                return -ENOIOCTLCMD;
index b423a364dca3c16cf8268861f3107f275c32474e..12b3bc026a683cd7b321fbae0e32839e8764e571 100644 (file)
@@ -658,6 +658,27 @@ static void ext4_mb_mark_free_simple(struct super_block *sb,
        }
 }
 
+/*
+ * Cache the order of the largest free extent we have available in this block
+ * group.
+ */
+static void
+mb_set_largest_free_order(struct super_block *sb, struct ext4_group_info *grp)
+{
+       int i;
+       int bits;
+
+       grp->bb_largest_free_order = -1; /* uninit */
+
+       bits = sb->s_blocksize_bits + 1;
+       for (i = bits; i >= 0; i--) {
+               if (grp->bb_counters[i] > 0) {
+                       grp->bb_largest_free_order = i;
+                       break;
+               }
+       }
+}
+
 static noinline_for_stack
 void ext4_mb_generate_buddy(struct super_block *sb,
                                void *buddy, void *bitmap, ext4_group_t group)
@@ -700,6 +721,7 @@ void ext4_mb_generate_buddy(struct super_block *sb,
                 */
                grp->bb_free = free;
        }
+       mb_set_largest_free_order(sb, grp);
 
        clear_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &(grp->bb_state));
 
@@ -725,6 +747,9 @@ void ext4_mb_generate_buddy(struct super_block *sb,
  * contain blocks_per_page (PAGE_CACHE_SIZE / blocksize)  blocks.
  * So it can have information regarding groups_per_page which
  * is blocks_per_page/2
+ *
+ * Locking note:  This routine takes the block group lock of all groups
+ * for this page; do not hold this lock when calling this routine!
  */
 
 static int ext4_mb_init_cache(struct page *page, char *incore)
@@ -865,6 +890,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
                        BUG_ON(incore == NULL);
                        mb_debug(1, "put buddy for group %u in page %lu/%x\n",
                                group, page->index, i * blocksize);
+                       trace_ext4_mb_buddy_bitmap_load(sb, group);
                        grinfo = ext4_get_group_info(sb, group);
                        grinfo->bb_fragments = 0;
                        memset(grinfo->bb_counters, 0,
@@ -882,6 +908,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
                        BUG_ON(incore != NULL);
                        mb_debug(1, "put bitmap for group %u in page %lu/%x\n",
                                group, page->index, i * blocksize);
+                       trace_ext4_mb_bitmap_load(sb, group);
 
                        /* see comments in ext4_mb_put_pa() */
                        ext4_lock_group(sb, group);
@@ -910,6 +937,11 @@ out:
        return err;
 }
 
+/*
+ * Locking note:  This routine calls ext4_mb_init_cache(), which takes the
+ * block group lock of all groups for this page; do not hold the BG lock when
+ * calling this routine!
+ */
 static noinline_for_stack
 int ext4_mb_init_group(struct super_block *sb, ext4_group_t group)
 {
@@ -1004,6 +1036,11 @@ err:
        return ret;
 }
 
+/*
+ * Locking note:  This routine calls ext4_mb_init_cache(), which takes the
+ * block group lock of all groups for this page; do not hold the BG lock when
+ * calling this routine!
+ */
 static noinline_for_stack int
 ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group,
                                        struct ext4_buddy *e4b)
@@ -1150,7 +1187,7 @@ err:
        return ret;
 }
 
-static void ext4_mb_release_desc(struct ext4_buddy *e4b)
+static void ext4_mb_unload_buddy(struct ext4_buddy *e4b)
 {
        if (e4b->bd_bitmap_page)
                page_cache_release(e4b->bd_bitmap_page);
@@ -1299,6 +1336,7 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b,
                        buddy = buddy2;
                } while (1);
        }
+       mb_set_largest_free_order(sb, e4b->bd_info);
        mb_check_buddy(e4b);
 }
 
@@ -1427,6 +1465,7 @@ static int mb_mark_used(struct ext4_buddy *e4b, struct ext4_free_extent *ex)
                e4b->bd_info->bb_counters[ord]++;
                e4b->bd_info->bb_counters[ord]++;
        }
+       mb_set_largest_free_order(e4b->bd_sb, e4b->bd_info);
 
        mb_set_bits(EXT4_MB_BITMAP(e4b), ex->fe_start, len0);
        mb_check_buddy(e4b);
@@ -1617,7 +1656,7 @@ int ext4_mb_try_best_found(struct ext4_allocation_context *ac,
        }
 
        ext4_unlock_group(ac->ac_sb, group);
-       ext4_mb_release_desc(e4b);
+       ext4_mb_unload_buddy(e4b);
 
        return 0;
 }
@@ -1672,7 +1711,7 @@ int ext4_mb_find_by_goal(struct ext4_allocation_context *ac,
                ext4_mb_use_best_found(ac, e4b);
        }
        ext4_unlock_group(ac->ac_sb, group);
-       ext4_mb_release_desc(e4b);
+       ext4_mb_unload_buddy(e4b);
 
        return 0;
 }
@@ -1821,16 +1860,22 @@ void ext4_mb_scan_aligned(struct ext4_allocation_context *ac,
        }
 }
 
+/* This is now called BEFORE we load the buddy bitmap. */
 static int ext4_mb_good_group(struct ext4_allocation_context *ac,
                                ext4_group_t group, int cr)
 {
        unsigned free, fragments;
-       unsigned i, bits;
        int flex_size = ext4_flex_bg_size(EXT4_SB(ac->ac_sb));
        struct ext4_group_info *grp = ext4_get_group_info(ac->ac_sb, group);
 
        BUG_ON(cr < 0 || cr >= 4);
-       BUG_ON(EXT4_MB_GRP_NEED_INIT(grp));
+
+       /* We only do this if the grp has never been initialized */
+       if (unlikely(EXT4_MB_GRP_NEED_INIT(grp))) {
+               int ret = ext4_mb_init_group(ac->ac_sb, group);
+               if (ret)
+                       return 0;
+       }
 
        free = grp->bb_free;
        fragments = grp->bb_fragments;
@@ -1843,17 +1888,16 @@ static int ext4_mb_good_group(struct ext4_allocation_context *ac,
        case 0:
                BUG_ON(ac->ac_2order == 0);
 
+               if (grp->bb_largest_free_order < ac->ac_2order)
+                       return 0;
+
                /* Avoid using the first bg of a flexgroup for data files */
                if ((ac->ac_flags & EXT4_MB_HINT_DATA) &&
                    (flex_size >= EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME) &&
                    ((group % flex_size) == 0))
                        return 0;
 
-               bits = ac->ac_sb->s_blocksize_bits + 1;
-               for (i = ac->ac_2order; i <= bits; i++)
-                       if (grp->bb_counters[i] > 0)
-                               return 1;
-               break;
+               return 1;
        case 1:
                if ((free / fragments) >= ac->ac_g_ex.fe_len)
                        return 1;
@@ -1964,7 +2008,7 @@ ext4_mb_regular_allocator(struct ext4_allocation_context *ac)
        sbi = EXT4_SB(sb);
        ngroups = ext4_get_groups_count(sb);
        /* non-extent files are limited to low blocks/groups */
-       if (!(EXT4_I(ac->ac_inode)->i_flags & EXT4_EXTENTS_FL))
+       if (!(ext4_test_inode_flag(ac->ac_inode, EXT4_INODE_EXTENTS)))
                ngroups = sbi->s_blockfile_groups;
 
        BUG_ON(ac->ac_status == AC_STATUS_FOUND);
@@ -2024,15 +2068,11 @@ repeat:
                group = ac->ac_g_ex.fe_group;
 
                for (i = 0; i < ngroups; group++, i++) {
-                       struct ext4_group_info *grp;
-                       struct ext4_group_desc *desc;
-
                        if (group == ngroups)
                                group = 0;
 
-                       /* quick check to skip empty groups */
-                       grp = ext4_get_group_info(sb, group);
-                       if (grp->bb_free == 0)
+                       /* This now checks without needing the buddy page */
+                       if (!ext4_mb_good_group(ac, group, cr))
                                continue;
 
                        err = ext4_mb_load_buddy(sb, group, &e4b);
@@ -2040,15 +2080,18 @@ repeat:
                                goto out;
 
                        ext4_lock_group(sb, group);
+
+                       /*
+                        * We need to check again after locking the
+                        * block group
+                        */
                        if (!ext4_mb_good_group(ac, group, cr)) {
-                               /* someone did allocation from this group */
                                ext4_unlock_group(sb, group);
-                               ext4_mb_release_desc(&e4b);
+                               ext4_mb_unload_buddy(&e4b);
                                continue;
                        }
 
                        ac->ac_groups_scanned++;
-                       desc = ext4_get_group_desc(sb, group, NULL);
                        if (cr == 0)
                                ext4_mb_simple_scan_group(ac, &e4b);
                        else if (cr == 1 &&
@@ -2058,7 +2101,7 @@ repeat:
                                ext4_mb_complex_scan_group(ac, &e4b);
 
                        ext4_unlock_group(sb, group);
-                       ext4_mb_release_desc(&e4b);
+                       ext4_mb_unload_buddy(&e4b);
 
                        if (ac->ac_status != AC_STATUS_CONTINUE)
                                break;
@@ -2148,7 +2191,7 @@ static int ext4_mb_seq_groups_show(struct seq_file *seq, void *v)
        ext4_lock_group(sb, group);
        memcpy(&sg, ext4_get_group_info(sb, group), i);
        ext4_unlock_group(sb, group);
-       ext4_mb_release_desc(&e4b);
+       ext4_mb_unload_buddy(&e4b);
 
        seq_printf(seq, "#%-5u: %-5u %-5u %-5u [", group, sg.info.bb_free,
                        sg.info.bb_fragments, sg.info.bb_first_free);
@@ -2255,6 +2298,7 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group,
        INIT_LIST_HEAD(&meta_group_info[i]->bb_prealloc_list);
        init_rwsem(&meta_group_info[i]->alloc_sem);
        meta_group_info[i]->bb_free_root = RB_ROOT;
+       meta_group_info[i]->bb_largest_free_order = -1;  /* uninit */
 
 #ifdef DOUBLE_CHECK
        {
@@ -2536,6 +2580,7 @@ static void release_blocks_on_commit(journal_t *journal, transaction_t *txn)
                         entry->count, entry->group, entry);
 
                if (test_opt(sb, DISCARD)) {
+                       int ret;
                        ext4_fsblk_t discard_block;
 
                        discard_block = entry->start_blk +
@@ -2543,7 +2588,12 @@ static void release_blocks_on_commit(journal_t *journal, transaction_t *txn)
                        trace_ext4_discard_blocks(sb,
                                        (unsigned long long)discard_block,
                                        entry->count);
-                       sb_issue_discard(sb, discard_block, entry->count);
+                       ret = sb_issue_discard(sb, discard_block, entry->count);
+                       if (ret == EOPNOTSUPP) {
+                               ext4_warning(sb,
+                                       "discard not supported, disabling");
+                               clear_opt(EXT4_SB(sb)->s_mount_opt, DISCARD);
+                       }
                }
 
                err = ext4_mb_load_buddy(sb, entry->group, &e4b);
@@ -2568,7 +2618,7 @@ static void release_blocks_on_commit(journal_t *journal, transaction_t *txn)
                }
                ext4_unlock_group(sb, entry->group);
                kmem_cache_free(ext4_free_ext_cachep, entry);
-               ext4_mb_release_desc(&e4b);
+               ext4_mb_unload_buddy(&e4b);
        }
 
        mb_debug(1, "freed %u blocks in %u structures\n", count, count2);
@@ -2641,7 +2691,7 @@ int __init init_ext4_mballoc(void)
 
 void exit_ext4_mballoc(void)
 {
-       /* 
+       /*
         * Wait for completion of call_rcu()'s on ext4_pspace_cachep
         * before destroying the slab cache.
         */
@@ -2981,7 +3031,7 @@ static void ext4_mb_collect_stats(struct ext4_allocation_context *ac)
        if (sbi->s_mb_stats && ac->ac_g_ex.fe_len > 1) {
                atomic_inc(&sbi->s_bal_reqs);
                atomic_add(ac->ac_b_ex.fe_len, &sbi->s_bal_allocated);
-               if (ac->ac_o_ex.fe_len >= ac->ac_g_ex.fe_len)
+               if (ac->ac_b_ex.fe_len >= ac->ac_o_ex.fe_len)
                        atomic_inc(&sbi->s_bal_success);
                atomic_add(ac->ac_found, &sbi->s_bal_ex_scanned);
                if (ac->ac_g_ex.fe_start == ac->ac_b_ex.fe_start &&
@@ -3123,7 +3173,7 @@ ext4_mb_use_preallocated(struct ext4_allocation_context *ac)
                        continue;
 
                /* non-extent files can't have physical blocks past 2^32 */
-               if (!(EXT4_I(ac->ac_inode)->i_flags & EXT4_EXTENTS_FL) &&
+               if (!(ext4_test_inode_flag(ac->ac_inode, EXT4_INODE_EXTENTS)) &&
                        pa->pa_pstart + pa->pa_len > EXT4_MAX_BLOCK_FILE_PHYS)
                        continue;
 
@@ -3280,7 +3330,7 @@ static void ext4_mb_put_pa(struct ext4_allocation_context *ac,
        spin_unlock(&pa->pa_lock);
 
        grp_blk = pa->pa_pstart;
-       /* 
+       /*
         * If doing group-based preallocation, pa_pstart may be in the
         * next group when pa is used up
         */
@@ -3697,7 +3747,7 @@ out:
        ext4_unlock_group(sb, group);
        if (ac)
                kmem_cache_free(ext4_ac_cachep, ac);
-       ext4_mb_release_desc(&e4b);
+       ext4_mb_unload_buddy(&e4b);
        put_bh(bitmap_bh);
        return free;
 }
@@ -3801,7 +3851,7 @@ repeat:
                if (bitmap_bh == NULL) {
                        ext4_error(sb, "Error reading block bitmap for %u",
                                        group);
-                       ext4_mb_release_desc(&e4b);
+                       ext4_mb_unload_buddy(&e4b);
                        continue;
                }
 
@@ -3810,7 +3860,7 @@ repeat:
                ext4_mb_release_inode_pa(&e4b, bitmap_bh, pa, ac);
                ext4_unlock_group(sb, group);
 
-               ext4_mb_release_desc(&e4b);
+               ext4_mb_unload_buddy(&e4b);
                put_bh(bitmap_bh);
 
                list_del(&pa->u.pa_tmp_list);
@@ -4074,7 +4124,7 @@ ext4_mb_discard_lg_preallocations(struct super_block *sb,
                ext4_mb_release_group_pa(&e4b, pa, ac);
                ext4_unlock_group(sb, group);
 
-               ext4_mb_release_desc(&e4b);
+               ext4_mb_unload_buddy(&e4b);
                list_del(&pa->u.pa_tmp_list);
                call_rcu(&(pa)->u.pa_rcu, ext4_mb_pa_callback);
        }
@@ -4484,12 +4534,12 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
                        if (!bh)
                                tbh = sb_find_get_block(inode->i_sb,
                                                        block + i);
-                       ext4_forget(handle, flags & EXT4_FREE_BLOCKS_METADATA, 
+                       ext4_forget(handle, flags & EXT4_FREE_BLOCKS_METADATA,
                                    inode, tbh, block + i);
                }
        }
 
-       /* 
+       /*
         * We need to make sure we don't reuse the freed block until
         * after the transaction is committed, which we can do by
         * treating the block as metadata, below.  We make an
@@ -4610,7 +4660,7 @@ do_more:
                atomic_add(count, &sbi->s_flex_groups[flex_group].free_blocks);
        }
 
-       ext4_mb_release_desc(&e4b);
+       ext4_mb_unload_buddy(&e4b);
 
        freed += count;
 
index 34dcfc52ef44b4f228fc6403460f294dbc13a95b..6f3a27ec30bfb1b9951a9053ae6721e135762f5d 100644 (file)
@@ -475,7 +475,7 @@ int ext4_ext_migrate(struct inode *inode)
         */
        if (!EXT4_HAS_INCOMPAT_FEATURE(inode->i_sb,
                                       EXT4_FEATURE_INCOMPAT_EXTENTS) ||
-           (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL))
+           (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
                return -EINVAL;
 
        if (S_ISLNK(inode->i_mode) && inode->i_blocks == 0)
index d1fc662cc311070c19742a5cb7522f167c8a4774..3a6c92ac131c449b61f58194087fe376dbd0f32f 100644 (file)
@@ -482,6 +482,7 @@ mext_leaf_block(handle_t *handle, struct inode *orig_inode,
        int depth = ext_depth(orig_inode);
        int ret;
 
+       start_ext.ee_block = end_ext.ee_block = 0;
        o_start = o_end = oext = orig_path[depth].p_ext;
        oext_alen = ext4_ext_get_actual_len(oext);
        start_ext.ee_len = end_ext.ee_len = 0;
@@ -529,7 +530,7 @@ mext_leaf_block(handle_t *handle, struct inode *orig_inode,
         * new_ext       |-------|
         */
        if (le32_to_cpu(oext->ee_block) + oext_alen - 1 < new_ext_end) {
-               ext4_error(orig_inode->i_sb,
+               EXT4_ERROR_INODE(orig_inode,
                        "new_ext_end(%u) should be less than or equal to "
                        "oext->ee_block(%u) + oext_alen(%d) - 1",
                        new_ext_end, le32_to_cpu(oext->ee_block),
@@ -692,12 +693,12 @@ mext_replace_branches(handle_t *handle, struct inode *orig_inode,
        while (1) {
                /* The extent for donor must be found. */
                if (!dext) {
-                       ext4_error(donor_inode->i_sb,
+                       EXT4_ERROR_INODE(donor_inode,
                                   "The extent for donor must be found");
                        *err = -EIO;
                        goto out;
                } else if (donor_off != le32_to_cpu(tmp_dext.ee_block)) {
-                       ext4_error(donor_inode->i_sb,
+                       EXT4_ERROR_INODE(donor_inode,
                                "Donor offset(%u) and the first block of donor "
                                "extent(%u) should be equal",
                                donor_off,
@@ -976,11 +977,11 @@ mext_check_arguments(struct inode *orig_inode,
        }
 
        /* Ext4 move extent supports only extent based file */
-       if (!(EXT4_I(orig_inode)->i_flags & EXT4_EXTENTS_FL)) {
+       if (!(ext4_test_inode_flag(orig_inode, EXT4_INODE_EXTENTS))) {
                ext4_debug("ext4 move extent: orig file is not extents "
                        "based file [ino:orig %lu]\n", orig_inode->i_ino);
                return -EOPNOTSUPP;
-       } else if (!(EXT4_I(donor_inode)->i_flags & EXT4_EXTENTS_FL)) {
+       } else if (!(ext4_test_inode_flag(donor_inode, EXT4_INODE_EXTENTS))) {
                ext4_debug("ext4 move extent: donor file is not extents "
                        "based file [ino:donor %lu]\n", donor_inode->i_ino);
                return -EOPNOTSUPP;
@@ -1354,7 +1355,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp,
                        if (ret1 < 0)
                                break;
                        if (*moved_len > len) {
-                               ext4_error(orig_inode->i_sb,
+                               EXT4_ERROR_INODE(orig_inode,
                                        "We replaced blocks too much! "
                                        "sum of replaced: %llu requested: %llu",
                                        *moved_len, len);
index 0c070fabd10862beb71e17b51b96f99ae173a240..a43e6617b35119e6bb46815e4f73aa2a518a4e30 100644 (file)
@@ -187,7 +187,7 @@ unsigned int ext4_rec_len_from_disk(__le16 dlen, unsigned blocksize)
                return blocksize;
        return (len & 65532) | ((len & 3) << 16);
 }
-  
+
 __le16 ext4_rec_len_to_disk(unsigned len, unsigned blocksize)
 {
        if ((len > blocksize) || (blocksize > (1 << 18)) || (len & 3))
@@ -197,7 +197,7 @@ __le16 ext4_rec_len_to_disk(unsigned len, unsigned blocksize)
        if (len == blocksize) {
                if (blocksize == 65536)
                        return cpu_to_le16(EXT4_MAX_REC_LEN);
-               else 
+               else
                        return cpu_to_le16(0);
        }
        return cpu_to_le16((len & 65532) | ((len >> 16) & 3));
@@ -349,7 +349,7 @@ struct stats dx_show_entries(struct dx_hash_info *hinfo, struct inode *dir,
                brelse(bh);
        }
        if (bcount)
-               printk(KERN_DEBUG "%snames %u, fullness %u (%u%%)\n", 
+               printk(KERN_DEBUG "%snames %u, fullness %u (%u%%)\n",
                       levels ? "" : "   ", names, space/bcount,
                       (space/bcount)*100/blocksize);
        return (struct stats) { names, space, bcount};
@@ -653,10 +653,10 @@ int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
        int ret, err;
        __u32 hashval;
 
-       dxtrace(printk(KERN_DEBUG "In htree_fill_tree, start hash: %x:%x\n", 
+       dxtrace(printk(KERN_DEBUG "In htree_fill_tree, start hash: %x:%x\n",
                       start_hash, start_minor_hash));
        dir = dir_file->f_path.dentry->d_inode;
-       if (!(EXT4_I(dir)->i_flags & EXT4_INDEX_FL)) {
+       if (!(ext4_test_inode_flag(dir, EXT4_INODE_INDEX))) {
                hinfo.hash_version = EXT4_SB(dir->i_sb)->s_def_hash_version;
                if (hinfo.hash_version <= DX_HASH_TEA)
                        hinfo.hash_version +=
@@ -801,7 +801,7 @@ static void ext4_update_dx_flag(struct inode *inode)
 {
        if (!EXT4_HAS_COMPAT_FEATURE(inode->i_sb,
                                     EXT4_FEATURE_COMPAT_DIR_INDEX))
-               EXT4_I(inode)->i_flags &= ~EXT4_INDEX_FL;
+               ext4_clear_inode_flag(inode, EXT4_INODE_INDEX);
 }
 
 /*
@@ -943,8 +943,8 @@ restart:
                wait_on_buffer(bh);
                if (!buffer_uptodate(bh)) {
                        /* read error, skip block & hope for the best */
-                       ext4_error(sb, "reading directory #%lu offset %lu",
-                                  dir->i_ino, (unsigned long)block);
+                       EXT4_ERROR_INODE(dir, "reading directory lblock %lu",
+                                        (unsigned long) block);
                        brelse(bh);
                        goto next;
                }
@@ -1066,15 +1066,15 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, stru
                __u32 ino = le32_to_cpu(de->inode);
                brelse(bh);
                if (!ext4_valid_inum(dir->i_sb, ino)) {
-                       ext4_error(dir->i_sb, "bad inode number: %u", ino);
+                       EXT4_ERROR_INODE(dir, "bad inode number: %u", ino);
                        return ERR_PTR(-EIO);
                }
                inode = ext4_iget(dir->i_sb, ino);
                if (unlikely(IS_ERR(inode))) {
                        if (PTR_ERR(inode) == -ESTALE) {
-                               ext4_error(dir->i_sb,
-                                               "deleted inode referenced: %u",
-                                               ino);
+                               EXT4_ERROR_INODE(dir,
+                                                "deleted inode referenced: %u",
+                                                ino);
                                return ERR_PTR(-EIO);
                        } else {
                                return ERR_CAST(inode);
@@ -1104,8 +1104,8 @@ struct dentry *ext4_get_parent(struct dentry *child)
        brelse(bh);
 
        if (!ext4_valid_inum(child->d_inode->i_sb, ino)) {
-               ext4_error(child->d_inode->i_sb,
-                          "bad inode number: %u", ino);
+               EXT4_ERROR_INODE(child->d_inode,
+                                "bad parent inode number: %u", ino);
                return ERR_PTR(-EIO);
        }
 
@@ -1141,7 +1141,7 @@ dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count,
        unsigned rec_len = 0;
 
        while (count--) {
-               struct ext4_dir_entry_2 *de = (struct ext4_dir_entry_2 *) 
+               struct ext4_dir_entry_2 *de = (struct ext4_dir_entry_2 *)
                                                (from + (map->offs<<2));
                rec_len = EXT4_DIR_REC_LEN(de->name_len);
                memcpy (to, de, rec_len);
@@ -1404,9 +1404,7 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
        de = (struct ext4_dir_entry_2 *)((char *)fde +
                ext4_rec_len_from_disk(fde->rec_len, blocksize));
        if ((char *) de >= (((char *) root) + blocksize)) {
-               ext4_error(dir->i_sb,
-                          "invalid rec_len for '..' in inode %lu",
-                          dir->i_ino);
+               EXT4_ERROR_INODE(dir, "invalid rec_len for '..'");
                brelse(bh);
                return -EIO;
        }
@@ -1418,7 +1416,7 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
                brelse(bh);
                return retval;
        }
-       EXT4_I(dir)->i_flags |= EXT4_INDEX_FL;
+       ext4_set_inode_flag(dir, EXT4_INODE_INDEX);
        data1 = bh2->b_data;
 
        memcpy (data1, de, len);
@@ -1491,7 +1489,7 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
                retval = ext4_dx_add_entry(handle, dentry, inode);
                if (!retval || (retval != ERR_BAD_DX_DIR))
                        return retval;
-               EXT4_I(dir)->i_flags &= ~EXT4_INDEX_FL;
+               ext4_clear_inode_flag(dir, EXT4_INODE_INDEX);
                dx_fallback++;
                ext4_mark_inode_dirty(handle, dir);
        }
@@ -1519,6 +1517,8 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
        de->rec_len = ext4_rec_len_to_disk(blocksize, blocksize);
        retval = add_dirent_to_buf(handle, dentry, inode, de, bh);
        brelse(bh);
+       if (retval == 0)
+               ext4_set_inode_state(inode, EXT4_STATE_NEWENTRY);
        return retval;
 }
 
@@ -1915,9 +1915,8 @@ static int empty_dir(struct inode *inode)
        if (inode->i_size < EXT4_DIR_REC_LEN(1) + EXT4_DIR_REC_LEN(2) ||
            !(bh = ext4_bread(NULL, inode, 0, 0, &err))) {
                if (err)
-                       ext4_error(inode->i_sb,
-                                  "error %d reading directory #%lu offset 0",
-                                  err, inode->i_ino);
+                       EXT4_ERROR_INODE(inode,
+                               "error %d reading directory lblock 0", err);
                else
                        ext4_warning(inode->i_sb,
                                     "bad directory (dir #%lu) - no data block",
@@ -1941,17 +1940,17 @@ static int empty_dir(struct inode *inode)
        de = ext4_next_entry(de1, sb->s_blocksize);
        while (offset < inode->i_size) {
                if (!bh ||
-                       (void *) de >= (void *) (bh->b_data+sb->s_blocksize)) {
+                   (void *) de >= (void *) (bh->b_data+sb->s_blocksize)) {
+                       unsigned int lblock;
                        err = 0;
                        brelse(bh);
-                       bh = ext4_bread(NULL, inode,
-                               offset >> EXT4_BLOCK_SIZE_BITS(sb), 0, &err);
+                       lblock = offset >> EXT4_BLOCK_SIZE_BITS(sb);
+                       bh = ext4_bread(NULL, inode, lblock, 0, &err);
                        if (!bh) {
                                if (err)
-                                       ext4_error(sb,
-                                                  "error %d reading directory"
-                                                  " #%lu offset %u",
-                                                  err, inode->i_ino, offset);
+                                       EXT4_ERROR_INODE(inode,
+                                               "error %d reading directory "
+                                               "lblock %u", err, lblock);
                                offset += sb->s_blocksize;
                                continue;
                        }
@@ -2297,7 +2296,7 @@ retry:
                }
        } else {
                /* clear the extent format for fast symlink */
-               EXT4_I(inode)->i_flags &= ~EXT4_EXTENTS_FL;
+               ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS);
                inode->i_op = &ext4_fast_symlink_inode_operations;
                memcpy((char *)&EXT4_I(inode)->i_data, symname, l);
                inode->i_size = l-1;
index 5692c48754a0a278b384f40da3f5d7891fea9ff3..6df797eb9aeb60ab1504298f266edb0977d10be9 100644 (file)
@@ -911,7 +911,8 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
        percpu_counter_add(&sbi->s_freeinodes_counter,
                           EXT4_INODES_PER_GROUP(sb));
 
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
+       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG) &&
+           sbi->s_log_groups_per_flex) {
                ext4_group_t flex_group;
                flex_group = ext4_flex_group(sbi, input->group);
                atomic_add(input->free_blocks_count,
index e14d22c170d542f3d65b7b50065f0256e0c940b3..4e8983a9811b2205773809fad4306f4a79eef8c5 100644 (file)
@@ -241,6 +241,7 @@ handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks)
        if (sb->s_flags & MS_RDONLY)
                return ERR_PTR(-EROFS);
 
+       vfs_check_frozen(sb, SB_FREEZE_WRITE);
        /* Special case here: if the journal has aborted behind our
         * backs (eg. EIO in the commit thread), then we still need to
         * take the FS itself readonly cleanly. */
@@ -645,6 +646,8 @@ static void ext4_put_super(struct super_block *sb)
        struct ext4_super_block *es = sbi->s_es;
        int i, err;
 
+       dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);
+
        flush_workqueue(sbi->dio_unwritten_wq);
        destroy_workqueue(sbi->dio_unwritten_wq);
 
@@ -941,6 +944,8 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
        seq_puts(seq, test_opt(sb, BARRIER) ? "1" : "0");
        if (test_opt(sb, JOURNAL_ASYNC_COMMIT))
                seq_puts(seq, ",journal_async_commit");
+       else if (test_opt(sb, JOURNAL_CHECKSUM))
+               seq_puts(seq, ",journal_checksum");
        if (test_opt(sb, NOBH))
                seq_puts(seq, ",nobh");
        if (test_opt(sb, I_VERSION))
@@ -1059,7 +1064,7 @@ static int ext4_release_dquot(struct dquot *dquot);
 static int ext4_mark_dquot_dirty(struct dquot *dquot);
 static int ext4_write_info(struct super_block *sb, int type);
 static int ext4_quota_on(struct super_block *sb, int type, int format_id,
-                               char *path, int remount);
+                               char *path);
 static int ext4_quota_on_mount(struct super_block *sb, int type);
 static ssize_t ext4_quota_read(struct super_block *sb, int type, char *data,
                               size_t len, loff_t off);
@@ -1081,12 +1086,12 @@ static const struct dquot_operations ext4_quota_operations = {
 
 static const struct quotactl_ops ext4_qctl_operations = {
        .quota_on       = ext4_quota_on,
-       .quota_off      = vfs_quota_off,
-       .quota_sync     = vfs_quota_sync,
-       .get_info       = vfs_get_dqinfo,
-       .set_info       = vfs_set_dqinfo,
-       .get_dqblk      = vfs_get_dqblk,
-       .set_dqblk      = vfs_set_dqblk
+       .quota_off      = dquot_quota_off,
+       .quota_sync     = dquot_quota_sync,
+       .get_info       = dquot_get_dqinfo,
+       .set_info       = dquot_set_dqinfo,
+       .get_dqblk      = dquot_get_dqblk,
+       .set_dqblk      = dquot_set_dqblk
 };
 #endif
 
@@ -2051,7 +2056,7 @@ static void ext4_orphan_cleanup(struct super_block *sb,
        /* Turn quotas off */
        for (i = 0; i < MAXQUOTAS; i++) {
                if (sb_dqopt(sb)->files[i])
-                       vfs_quota_off(sb, i, 0);
+                       dquot_quota_off(sb, i);
        }
 #endif
        sb->s_flags = s_flags; /* Restore MS_RDONLY status */
@@ -2213,7 +2218,7 @@ static unsigned long ext4_get_stripe_size(struct ext4_sb_info *sbi)
 struct ext4_attr {
        struct attribute attr;
        ssize_t (*show)(struct ext4_attr *, struct ext4_sb_info *, char *);
-       ssize_t (*store)(struct ext4_attr *, struct ext4_sb_info *, 
+       ssize_t (*store)(struct ext4_attr *, struct ext4_sb_info *,
                         const char *, size_t);
        int offset;
 };
@@ -2430,6 +2435,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                                __releases(kernel_lock)
                                __acquires(kernel_lock)
 {
+       char *orig_data = kstrdup(data, GFP_KERNEL);
        struct buffer_head *bh;
        struct ext4_super_block *es = NULL;
        struct ext4_sb_info *sbi;
@@ -2793,24 +2799,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        get_random_bytes(&sbi->s_next_generation, sizeof(u32));
        spin_lock_init(&sbi->s_next_gen_lock);
 
-       err = percpu_counter_init(&sbi->s_freeblocks_counter,
-                       ext4_count_free_blocks(sb));
-       if (!err) {
-               err = percpu_counter_init(&sbi->s_freeinodes_counter,
-                               ext4_count_free_inodes(sb));
-       }
-       if (!err) {
-               err = percpu_counter_init(&sbi->s_dirs_counter,
-                               ext4_count_dirs(sb));
-       }
-       if (!err) {
-               err = percpu_counter_init(&sbi->s_dirtyblocks_counter, 0);
-       }
-       if (err) {
-               ext4_msg(sb, KERN_ERR, "insufficient memory");
-               goto failed_mount3;
-       }
-
        sbi->s_stripe = ext4_get_stripe_size(sbi);
        sbi->s_max_writeback_mb_bump = 128;
 
@@ -2910,6 +2898,20 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        set_task_ioprio(sbi->s_journal->j_task, journal_ioprio);
 
 no_journal:
+       err = percpu_counter_init(&sbi->s_freeblocks_counter,
+                                 ext4_count_free_blocks(sb));
+       if (!err)
+               err = percpu_counter_init(&sbi->s_freeinodes_counter,
+                                         ext4_count_free_inodes(sb));
+       if (!err)
+               err = percpu_counter_init(&sbi->s_dirs_counter,
+                                         ext4_count_dirs(sb));
+       if (!err)
+               err = percpu_counter_init(&sbi->s_dirtyblocks_counter, 0);
+       if (err) {
+               ext4_msg(sb, KERN_ERR, "insufficient memory");
+               goto failed_mount_wq;
+       }
        if (test_opt(sb, NOBH)) {
                if (!(test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)) {
                        ext4_msg(sb, KERN_WARNING, "Ignoring nobh option - "
@@ -3001,7 +3003,7 @@ no_journal:
        err = ext4_setup_system_zone(sb);
        if (err) {
                ext4_msg(sb, KERN_ERR, "failed to initialize system "
-                        "zone (%d)\n", err);
+                        "zone (%d)", err);
                goto failed_mount4;
        }
 
@@ -3040,9 +3042,11 @@ no_journal:
        } else
                descr = "out journal";
 
-       ext4_msg(sb, KERN_INFO, "mounted filesystem with%s", descr);
+       ext4_msg(sb, KERN_INFO, "mounted filesystem with%s. "
+               "Opts: %s", descr, orig_data);
 
        lock_kernel();
+       kfree(orig_data);
        return 0;
 
 cantfind_ext4:
@@ -3059,6 +3063,10 @@ failed_mount_wq:
                jbd2_journal_destroy(sbi->s_journal);
                sbi->s_journal = NULL;
        }
+       percpu_counter_destroy(&sbi->s_freeblocks_counter);
+       percpu_counter_destroy(&sbi->s_freeinodes_counter);
+       percpu_counter_destroy(&sbi->s_dirs_counter);
+       percpu_counter_destroy(&sbi->s_dirtyblocks_counter);
 failed_mount3:
        if (sbi->s_flex_groups) {
                if (is_vmalloc_addr(sbi->s_flex_groups))
@@ -3066,10 +3074,6 @@ failed_mount3:
                else
                        kfree(sbi->s_flex_groups);
        }
-       percpu_counter_destroy(&sbi->s_freeblocks_counter);
-       percpu_counter_destroy(&sbi->s_freeinodes_counter);
-       percpu_counter_destroy(&sbi->s_dirs_counter);
-       percpu_counter_destroy(&sbi->s_dirtyblocks_counter);
 failed_mount2:
        for (i = 0; i < db_count; i++)
                brelse(sbi->s_group_desc[i]);
@@ -3089,6 +3093,7 @@ out_fail:
        kfree(sbi->s_blockgroup_lock);
        kfree(sbi);
        lock_kernel();
+       kfree(orig_data);
        return ret;
 }
 
@@ -3380,7 +3385,7 @@ static int ext4_commit_super(struct super_block *sb, int sync)
        if (!(sb->s_flags & MS_RDONLY))
                es->s_wtime = cpu_to_le32(get_seconds());
        es->s_kbytes_written =
-               cpu_to_le64(EXT4_SB(sb)->s_kbytes_written + 
+               cpu_to_le64(EXT4_SB(sb)->s_kbytes_written +
                            ((part_stat_read(sb->s_bdev->bd_part, sectors[1]) -
                              EXT4_SB(sb)->s_sectors_written_start) >> 1));
        ext4_free_blocks_count_set(es, percpu_counter_sum_positive(
@@ -3485,8 +3490,10 @@ int ext4_force_commit(struct super_block *sb)
                return 0;
 
        journal = EXT4_SB(sb)->s_journal;
-       if (journal)
+       if (journal) {
+               vfs_check_frozen(sb, SB_FREEZE_WRITE);
                ret = ext4_journal_force_commit(journal);
+       }
 
        return ret;
 }
@@ -3535,18 +3542,16 @@ static int ext4_freeze(struct super_block *sb)
         * the journal.
         */
        error = jbd2_journal_flush(journal);
-       if (error < 0) {
-       out:
-               jbd2_journal_unlock_updates(journal);
-               return error;
-       }
+       if (error < 0)
+               goto out;
 
        /* Journal blocked and flushed, clear needs_recovery flag. */
        EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
        error = ext4_commit_super(sb, 1);
-       if (error)
-               goto out;
-       return 0;
+out:
+       /* we rely on s_frozen to stop further updates */
+       jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
+       return error;
 }
 
 /*
@@ -3563,7 +3568,6 @@ static int ext4_unfreeze(struct super_block *sb)
        EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
        ext4_commit_super(sb, 1);
        unlock_super(sb);
-       jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
        return 0;
 }
 
@@ -3574,12 +3578,14 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
        ext4_fsblk_t n_blocks_count = 0;
        unsigned long old_sb_flags;
        struct ext4_mount_options old_opts;
+       int enable_quota = 0;
        ext4_group_t g;
        unsigned int journal_ioprio = DEFAULT_JOURNAL_IOPRIO;
        int err;
 #ifdef CONFIG_QUOTA
        int i;
 #endif
+       char *orig_data = kstrdup(data, GFP_KERNEL);
 
        lock_kernel();
 
@@ -3630,6 +3636,10 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
                }
 
                if (*flags & MS_RDONLY) {
+                       err = dquot_suspend(sb, -1);
+                       if (err < 0)
+                               goto restore_opts;
+
                        /*
                         * First of all, the unconditional stuff we have to do
                         * to disable replay of the journal when we next remount
@@ -3698,6 +3708,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
                                goto restore_opts;
                        if (!ext4_setup_super(sb, es, 0))
                                sb->s_flags &= ~MS_RDONLY;
+                       enable_quota = 1;
                }
        }
        ext4_setup_system_zone(sb);
@@ -3713,6 +3724,11 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
 #endif
        unlock_super(sb);
        unlock_kernel();
+       if (enable_quota)
+               dquot_resume(sb, -1);
+
+       ext4_msg(sb, KERN_INFO, "re-mounted. Opts: %s", orig_data);
+       kfree(orig_data);
        return 0;
 
 restore_opts:
@@ -3734,6 +3750,7 @@ restore_opts:
 #endif
        unlock_super(sb);
        unlock_kernel();
+       kfree(orig_data);
        return err;
 }
 
@@ -3906,24 +3923,21 @@ static int ext4_write_info(struct super_block *sb, int type)
  */
 static int ext4_quota_on_mount(struct super_block *sb, int type)
 {
-       return vfs_quota_on_mount(sb, EXT4_SB(sb)->s_qf_names[type],
-                                 EXT4_SB(sb)->s_jquota_fmt, type);
+       return dquot_quota_on_mount(sb, EXT4_SB(sb)->s_qf_names[type],
+                                       EXT4_SB(sb)->s_jquota_fmt, type);
 }
 
 /*
  * Standard function to be called on quota_on
  */
 static int ext4_quota_on(struct super_block *sb, int type, int format_id,
-                        char *name, int remount)
+                        char *name)
 {
        int err;
        struct path path;
 
        if (!test_opt(sb, QUOTA))
                return -EINVAL;
-       /* When remounting, no checks are needed and in fact, name is NULL */
-       if (remount)
-               return vfs_quota_on(sb, type, format_id, name, remount);
 
        err = kern_path(name, LOOKUP_FOLLOW, &path);
        if (err)
@@ -3962,7 +3976,7 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,
                }
        }
 
-       err = vfs_quota_on_path(sb, type, format_id, &path);
+       err = dquot_quota_on_path(sb, type, format_id, &path);
        path_put(&path);
        return err;
 }
@@ -4141,6 +4155,7 @@ static int __init init_ext4_fs(void)
 {
        int err;
 
+       ext4_check_flag_values();
        err = init_ext4_system_zone();
        if (err)
                return err;
index 00740cb32be3eb739d0b42bcc107a58947edf0ce..ed9354aff2790e0252ed1f3f7257262b1c2112f1 100644 (file)
@@ -34,6 +34,7 @@ const struct inode_operations ext4_symlink_inode_operations = {
        .readlink       = generic_readlink,
        .follow_link    = page_follow_link_light,
        .put_link       = page_put_link,
+       .setattr        = ext4_setattr,
 #ifdef CONFIG_EXT4_FS_XATTR
        .setxattr       = generic_setxattr,
        .getxattr       = generic_getxattr,
@@ -45,6 +46,7 @@ const struct inode_operations ext4_symlink_inode_operations = {
 const struct inode_operations ext4_fast_symlink_inode_operations = {
        .readlink       = generic_readlink,
        .follow_link    = ext4_follow_link,
+       .setattr        = ext4_setattr,
 #ifdef CONFIG_EXT4_FS_XATTR
        .setxattr       = generic_setxattr,
        .getxattr       = generic_getxattr,
index b4c5aa8489d851ea3478c8e25106a0c87846b3f6..04338009793abcfbfa384d1c0f9528cc3236adc6 100644 (file)
@@ -97,7 +97,7 @@ static int ext4_xattr_list(struct dentry *dentry, char *buffer,
 
 static struct mb_cache *ext4_xattr_cache;
 
-static struct xattr_handler *ext4_xattr_handler_map[] = {
+static const struct xattr_handler *ext4_xattr_handler_map[] = {
        [EXT4_XATTR_INDEX_USER]              = &ext4_xattr_user_handler,
 #ifdef CONFIG_EXT4_FS_POSIX_ACL
        [EXT4_XATTR_INDEX_POSIX_ACL_ACCESS]  = &ext4_xattr_acl_access_handler,
@@ -109,7 +109,7 @@ static struct xattr_handler *ext4_xattr_handler_map[] = {
 #endif
 };
 
-struct xattr_handler *ext4_xattr_handlers[] = {
+const struct xattr_handler *ext4_xattr_handlers[] = {
        &ext4_xattr_user_handler,
        &ext4_xattr_trusted_handler,
 #ifdef CONFIG_EXT4_FS_POSIX_ACL
@@ -122,10 +122,10 @@ struct xattr_handler *ext4_xattr_handlers[] = {
        NULL
 };
 
-static inline struct xattr_handler *
+static inline const struct xattr_handler *
 ext4_xattr_handler(int name_index)
 {
-       struct xattr_handler *handler = NULL;
+       const struct xattr_handler *handler = NULL;
 
        if (name_index > 0 && name_index < ARRAY_SIZE(ext4_xattr_handler_map))
                handler = ext4_xattr_handler_map[name_index];
@@ -228,9 +228,8 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name,
                atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount));
        if (ext4_xattr_check_block(bh)) {
 bad_block:
-               ext4_error(inode->i_sb,
-                          "inode %lu: bad block %llu", inode->i_ino,
-                          EXT4_I(inode)->i_file_acl);
+               EXT4_ERROR_INODE(inode, "bad block %llu",
+                                EXT4_I(inode)->i_file_acl);
                error = -EIO;
                goto cleanup;
        }
@@ -332,7 +331,7 @@ ext4_xattr_list_entries(struct dentry *dentry, struct ext4_xattr_entry *entry,
        size_t rest = buffer_size;
 
        for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) {
-               struct xattr_handler *handler =
+               const struct xattr_handler *handler =
                        ext4_xattr_handler(entry->e_name_index);
 
                if (handler) {
@@ -372,9 +371,8 @@ ext4_xattr_block_list(struct dentry *dentry, char *buffer, size_t buffer_size)
        ea_bdebug(bh, "b_count=%d, refcount=%d",
                atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount));
        if (ext4_xattr_check_block(bh)) {
-               ext4_error(inode->i_sb,
-                          "inode %lu: bad block %llu", inode->i_ino,
-                          EXT4_I(inode)->i_file_acl);
+               EXT4_ERROR_INODE(inode, "bad block %llu",
+                                EXT4_I(inode)->i_file_acl);
                error = -EIO;
                goto cleanup;
        }
@@ -666,8 +664,8 @@ ext4_xattr_block_find(struct inode *inode, struct ext4_xattr_info *i,
                        atomic_read(&(bs->bh->b_count)),
                        le32_to_cpu(BHDR(bs->bh)->h_refcount));
                if (ext4_xattr_check_block(bs->bh)) {
-                       ext4_error(sb, "inode %lu: bad block %llu",
-                                  inode->i_ino, EXT4_I(inode)->i_file_acl);
+                       EXT4_ERROR_INODE(inode, "bad block %llu",
+                                        EXT4_I(inode)->i_file_acl);
                        error = -EIO;
                        goto cleanup;
                }
@@ -820,7 +818,7 @@ inserted:
                                                EXT4_I(inode)->i_block_group);
 
                        /* non-extent files can't have physical blocks past 2^32 */
-                       if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL))
+                       if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
                                goal = goal & EXT4_MAX_BLOCK_FILE_PHYS;
 
                        block = ext4_new_meta_blocks(handle, inode,
@@ -828,7 +826,7 @@ inserted:
                        if (error)
                                goto cleanup;
 
-                       if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL))
+                       if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
                                BUG_ON(block > EXT4_MAX_BLOCK_FILE_PHYS);
 
                        ea_idebug(inode, "creating block %d", block);
@@ -880,8 +878,8 @@ cleanup_dquot:
        goto cleanup;
 
 bad_block:
-       ext4_error(inode->i_sb, "inode %lu: bad block %llu",
-                  inode->i_ino, EXT4_I(inode)->i_file_acl);
+       EXT4_ERROR_INODE(inode, "bad block %llu",
+                        EXT4_I(inode)->i_file_acl);
        goto cleanup;
 
 #undef header
@@ -1194,8 +1192,8 @@ retry:
                if (!bh)
                        goto cleanup;
                if (ext4_xattr_check_block(bh)) {
-                       ext4_error(inode->i_sb, "inode %lu: bad block %llu",
-                                  inode->i_ino, EXT4_I(inode)->i_file_acl);
+                       EXT4_ERROR_INODE(inode, "bad block %llu",
+                                        EXT4_I(inode)->i_file_acl);
                        error = -EIO;
                        goto cleanup;
                }
@@ -1372,14 +1370,14 @@ ext4_xattr_delete_inode(handle_t *handle, struct inode *inode)
                goto cleanup;
        bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl);
        if (!bh) {
-               ext4_error(inode->i_sb, "inode %lu: block %llu read error",
-                          inode->i_ino, EXT4_I(inode)->i_file_acl);
+               EXT4_ERROR_INODE(inode, "block %llu read error",
+                                EXT4_I(inode)->i_file_acl);
                goto cleanup;
        }
        if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) ||
            BHDR(bh)->h_blocks != cpu_to_le32(1)) {
-               ext4_error(inode->i_sb, "inode %lu: bad block %llu",
-                          inode->i_ino, EXT4_I(inode)->i_file_acl);
+               EXT4_ERROR_INODE(inode, "bad block %llu",
+                                EXT4_I(inode)->i_file_acl);
                goto cleanup;
        }
        ext4_xattr_release_block(handle, inode, bh);
@@ -1504,9 +1502,8 @@ again:
                }
                bh = sb_bread(inode->i_sb, ce->e_block);
                if (!bh) {
-                       ext4_error(inode->i_sb,
-                               "inode %lu: block %lu read error",
-                               inode->i_ino, (unsigned long) ce->e_block);
+                       EXT4_ERROR_INODE(inode, "block %lu read error",
+                                        (unsigned long) ce->e_block);
                } else if (le32_to_cpu(BHDR(bh)->h_refcount) >=
                                EXT4_XATTR_REFCOUNT_MAX) {
                        ea_idebug(inode, "block %lu refcount %d>=%d",
index 8ede88b18c292d71390e4987ebd6b5f3e5139cb0..518e96e439052fc19681b18da745aa5063209dcd 100644 (file)
@@ -65,11 +65,11 @@ struct ext4_xattr_entry {
 
 # ifdef CONFIG_EXT4_FS_XATTR
 
-extern struct xattr_handler ext4_xattr_user_handler;
-extern struct xattr_handler ext4_xattr_trusted_handler;
-extern struct xattr_handler ext4_xattr_acl_access_handler;
-extern struct xattr_handler ext4_xattr_acl_default_handler;
-extern struct xattr_handler ext4_xattr_security_handler;
+extern const struct xattr_handler ext4_xattr_user_handler;
+extern const struct xattr_handler ext4_xattr_trusted_handler;
+extern const struct xattr_handler ext4_xattr_acl_access_handler;
+extern const struct xattr_handler ext4_xattr_acl_default_handler;
+extern const struct xattr_handler ext4_xattr_security_handler;
 
 extern ssize_t ext4_listxattr(struct dentry *, char *, size_t);
 
@@ -86,7 +86,7 @@ extern int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
 extern int init_ext4_xattr(void);
 extern void exit_ext4_xattr(void);
 
-extern struct xattr_handler *ext4_xattr_handlers[];
+extern const struct xattr_handler *ext4_xattr_handlers[];
 
 # else  /* CONFIG_EXT4_FS_XATTR */
 
index 8b145e98df0771efc2735e38a151fa605f5a8b6f..9b21268e121c1a90f83465fa7a54292c2d8a56f0 100644 (file)
@@ -69,7 +69,7 @@ ext4_init_security(handle_t *handle, struct inode *inode, struct inode *dir)
        return err;
 }
 
-struct xattr_handler ext4_xattr_security_handler = {
+const struct xattr_handler ext4_xattr_security_handler = {
        .prefix = XATTR_SECURITY_PREFIX,
        .list   = ext4_xattr_security_list,
        .get    = ext4_xattr_security_get,
index 15b50edc6587ddccf1751ab25ce162812f8bb507..37e6ebca2cc386a5f0c7cb0e32fe2ccd3b4d63c8 100644 (file)
@@ -51,7 +51,7 @@ ext4_xattr_trusted_set(struct dentry *dentry, const char *name,
                              name, value, size, flags);
 }
 
-struct xattr_handler ext4_xattr_trusted_handler = {
+const struct xattr_handler ext4_xattr_trusted_handler = {
        .prefix = XATTR_TRUSTED_PREFIX,
        .list   = ext4_xattr_trusted_list,
        .get    = ext4_xattr_trusted_get,
index c4ce05746ce122b897a19a3cc5b1dbf70ff0261a..98c375352d0e92f255c67a524708424ba55c4117 100644 (file)
@@ -54,7 +54,7 @@ ext4_xattr_user_set(struct dentry *dentry, const char *name,
                              name, value, size, flags);
 }
 
-struct xattr_handler ext4_xattr_user_handler = {
+const struct xattr_handler ext4_xattr_user_handler = {
        .prefix = XATTR_USER_PREFIX,
        .list   = ext4_xattr_user_list,
        .get    = ext4_xattr_user_get,
index 113f0a1e565d17cb1fc4500496f84e966d89fd91..ae8200f84e395f4e27680d509e28ade20807c82e 100644 (file)
@@ -242,9 +242,10 @@ int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus)
        while (*fclus < cluster) {
                /* prevent the infinite loop of cluster chain */
                if (*fclus > limit) {
-                       fat_fs_error(sb, "%s: detected the cluster chain loop"
-                                    " (i_pos %lld)", __func__,
-                                    MSDOS_I(inode)->i_pos);
+                       fat_fs_error_ratelimit(sb,
+                                       "%s: detected the cluster chain loop"
+                                       " (i_pos %lld)", __func__,
+                                       MSDOS_I(inode)->i_pos);
                        nr = -EIO;
                        goto out;
                }
@@ -253,9 +254,9 @@ int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus)
                if (nr < 0)
                        goto out;
                else if (nr == FAT_ENT_FREE) {
-                       fat_fs_error(sb, "%s: invalid cluster chain"
-                                    " (i_pos %lld)", __func__,
-                                    MSDOS_I(inode)->i_pos);
+                       fat_fs_error_ratelimit(sb, "%s: invalid cluster chain"
+                                              " (i_pos %lld)", __func__,
+                                              MSDOS_I(inode)->i_pos);
                        nr = -EIO;
                        goto out;
                } else if (nr == FAT_ENT_EOF) {
index 530b4ca0151037ae212fe9d2d8ffb827fc970f98..ee42b9e0b16adb954e8fa1b183f01253c32f7b3c 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/buffer_head.h>
 #include <linux/compat.h>
 #include <asm/uaccess.h>
+#include <linux/kernel.h>
 #include "fat.h"
 
 /*
@@ -140,28 +141,22 @@ static int uni16_to_x8(unsigned char *ascii, const wchar_t *uni, int len,
 {
        const wchar_t *ip;
        wchar_t ec;
-       unsigned char *op, nc;
+       unsigned char *op;
        int charlen;
-       int k;
 
        ip = uni;
        op = ascii;
 
        while (*ip && ((len - NLS_MAX_CHARSET_SIZE) > 0)) {
                ec = *ip++;
-               if ( (charlen = nls->uni2char(ec, op, NLS_MAX_CHARSET_SIZE)) > 0) {
+               if ((charlen = nls->uni2char(ec, op, NLS_MAX_CHARSET_SIZE)) > 0) {
                        op += charlen;
                        len -= charlen;
                } else {
                        if (uni_xlate == 1) {
-                               *op = ':';
-                               for (k = 4; k > 0; k--) {
-                                       nc = ec & 0xF;
-                                       op[k] = nc > 9  ? nc + ('a' - 10)
-                                                       : nc + '0';
-                                       ec >>= 4;
-                               }
-                               op += 5;
+                               *op++ = ':';
+                               op = pack_hex_byte(op, ec >> 8);
+                               op = pack_hex_byte(op, ec);
                                len -= 5;
                        } else {
                                *op++ = '?';
@@ -758,9 +753,10 @@ static int fat_ioctl_readdir(struct inode *inode, struct file *filp,
        return ret;
 }
 
-static int fat_dir_ioctl(struct inode *inode, struct file *filp,
-                        unsigned int cmd, unsigned long arg)
+static long fat_dir_ioctl(struct file *filp, unsigned int cmd,
+                         unsigned long arg)
 {
+       struct inode *inode = filp->f_path.dentry->d_inode;
        struct __fat_dirent __user *d1 = (struct __fat_dirent __user *)arg;
        int short_only, both;
 
@@ -774,7 +770,7 @@ static int fat_dir_ioctl(struct inode *inode, struct file *filp,
                both = 1;
                break;
        default:
-               return fat_generic_ioctl(inode, filp, cmd, arg);
+               return fat_generic_ioctl(filp, cmd, arg);
        }
 
        if (!access_ok(VERIFY_WRITE, d1, sizeof(struct __fat_dirent[2])))
@@ -814,7 +810,7 @@ static long fat_compat_dir_ioctl(struct file *filp, unsigned cmd,
                both = 1;
                break;
        default:
-               return -ENOIOCTLCMD;
+               return fat_generic_ioctl(filp, cmd, (unsigned long)arg);
        }
 
        if (!access_ok(VERIFY_WRITE, d1, sizeof(struct compat_dirent[2])))
@@ -836,7 +832,7 @@ const struct file_operations fat_dir_operations = {
        .llseek         = generic_file_llseek,
        .read           = generic_read_dir,
        .readdir        = fat_readdir,
-       .ioctl          = fat_dir_ioctl,
+       .unlocked_ioctl = fat_dir_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = fat_compat_dir_ioctl,
 #endif
index e6efdfa0f6db5d1dbff9fe9e1c24b65af52e0596..27ac25725954281e8ba96ccc1f52fb3ff4dca899 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/nls.h>
 #include <linux/fs.h>
 #include <linux/mutex.h>
+#include <linux/ratelimit.h>
 #include <linux/msdos_fs.h>
 
 /*
@@ -82,6 +83,8 @@ struct msdos_sb_info {
        struct fatent_operations *fatent_ops;
        struct inode *fat_inode;
 
+       struct ratelimit_state ratelimit;
+
        spinlock_t inode_hash_lock;
        struct hlist_head inode_hashtable[FAT_HASH_SIZE];
 };
@@ -298,16 +301,16 @@ extern int fat_free_clusters(struct inode *inode, int cluster);
 extern int fat_count_free_clusters(struct super_block *sb);
 
 /* fat/file.c */
-extern int fat_generic_ioctl(struct inode *inode, struct file *filp,
-                            unsigned int cmd, unsigned long arg);
+extern long fat_generic_ioctl(struct file *filp, unsigned int cmd,
+                             unsigned long arg);
 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 void fat_truncate(struct inode *inode);
+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);
-extern int fat_file_fsync(struct file *file, struct dentry *dentry,
-                         int datasync);
+extern int fat_file_fsync(struct file *file, int datasync);
 
 /* fat/inode.c */
 extern void fat_attach(struct inode *inode, loff_t i_pos);
@@ -322,8 +325,13 @@ extern int fat_fill_super(struct super_block *sb, void *data, int silent,
 extern int fat_flush_inodes(struct super_block *sb, struct inode *i1,
                            struct inode *i2);
 /* fat/misc.c */
-extern void fat_fs_error(struct super_block *s, const char *fmt, ...)
-       __attribute__ ((format (printf, 2, 3))) __cold;
+extern void
+__fat_fs_error(struct super_block *s, int report, const char *fmt, ...)
+       __attribute__ ((format (printf, 3, 4))) __cold;
+#define fat_fs_error(s, fmt, args...)          \
+       __fat_fs_error(s, 1, fmt , ## args)
+#define fat_fs_error_ratelimit(s, fmt, args...) \
+       __fat_fs_error(s, __ratelimit(&MSDOS_SB(s)->ratelimit), fmt , ## args)
 extern int fat_clusters_flush(struct super_block *sb);
 extern int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster);
 extern void fat_time_fat2unix(struct msdos_sb_info *sbi, struct timespec *ts,
index e8c159de236b4cefbdd737ac4ccb04afbc4fae9d..990dfae022e5f8d1996588be029c12aa33b62f8f 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <linux/capability.h>
 #include <linux/module.h>
+#include <linux/compat.h>
 #include <linux/mount.h>
 #include <linux/time.h>
 #include <linux/buffer_head.h>
@@ -114,9 +115,9 @@ out:
        return err;
 }
 
-int fat_generic_ioctl(struct inode *inode, struct file *filp,
-                     unsigned int cmd, unsigned long arg)
+long fat_generic_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
+       struct inode *inode = filp->f_path.dentry->d_inode;
        u32 __user *user_attr = (u32 __user *)arg;
 
        switch (cmd) {
@@ -129,6 +130,15 @@ int fat_generic_ioctl(struct inode *inode, struct file *filp,
        }
 }
 
+#ifdef CONFIG_COMPAT
+static long fat_generic_compat_ioctl(struct file *filp, unsigned int cmd,
+                                     unsigned long arg)
+
+{
+       return fat_generic_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
+}
+#endif
+
 static int fat_file_release(struct inode *inode, struct file *filp)
 {
        if ((filp->f_mode & FMODE_WRITE) &&
@@ -139,12 +149,12 @@ static int fat_file_release(struct inode *inode, struct file *filp)
        return 0;
 }
 
-int fat_file_fsync(struct file *filp, struct dentry *dentry, int datasync)
+int fat_file_fsync(struct file *filp, int datasync)
 {
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = filp->f_mapping->host;
        int res, err;
 
-       res = simple_fsync(filp, dentry, datasync);
+       res = generic_file_fsync(filp, datasync);
        err = sync_mapping_buffers(MSDOS_SB(inode->i_sb)->fat_inode->i_mapping);
 
        return res ? res : err;
@@ -159,7 +169,10 @@ const struct file_operations fat_file_operations = {
        .aio_write      = generic_file_aio_write,
        .mmap           = generic_file_mmap,
        .release        = fat_file_release,
-       .ioctl          = fat_generic_ioctl,
+       .unlocked_ioctl = fat_generic_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = fat_generic_compat_ioctl,
+#endif
        .fsync          = fat_file_fsync,
        .splice_read    = generic_file_splice_read,
 };
@@ -270,7 +283,7 @@ static int fat_free(struct inode *inode, int skip)
        return fat_free_clusters(inode, free_start);
 }
 
-void fat_truncate(struct inode *inode)
+void fat_truncate_blocks(struct inode *inode, loff_t offset)
 {
        struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
        const unsigned int cluster_size = sbi->cluster_size;
@@ -280,10 +293,10 @@ void fat_truncate(struct inode *inode)
         * This protects against truncating a file bigger than it was then
         * trying to write into the hole.
         */
-       if (MSDOS_I(inode)->mmu_private > inode->i_size)
-               MSDOS_I(inode)->mmu_private = inode->i_size;
+       if (MSDOS_I(inode)->mmu_private > offset)
+               MSDOS_I(inode)->mmu_private = offset;
 
-       nr_clusters = (inode->i_size + (cluster_size - 1)) >> sbi->cluster_bits;
+       nr_clusters = (offset + (cluster_size - 1)) >> sbi->cluster_bits;
 
        fat_free(inode, nr_clusters);
        fat_flush_inodes(inode->i_sb, inode, NULL);
@@ -351,6 +364,18 @@ 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)
@@ -365,7 +390,8 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
        /*
         * Expand the file. Since inode_setattr() updates ->i_size
         * before calling the ->truncate(), but FAT needs to fill the
-        * hole before it.
+        * 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) {
@@ -414,15 +440,20 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
                        attr->ia_valid &= ~ATTR_MODE;
        }
 
-       if (attr->ia_valid)
-               error = inode_setattr(inode, attr);
+       if (attr->ia_valid & ATTR_SIZE) {
+               error = fat_setsize(inode, attr->ia_size);
+               if (error)
+                       goto out;
+       }
+
+       generic_setattr(inode, attr);
+       mark_inode_dirty(inode);
 out:
        return error;
 }
 EXPORT_SYMBOL_GPL(fat_setattr);
 
 const struct inode_operations fat_file_inode_operations = {
-       .truncate       = fat_truncate,
        .setattr        = fat_setattr,
        .getattr        = fat_getattr,
 };
index 0ce143bd7d56a9c387db5dbf6c16624d4cd02e1a..7bf45aee56d7631a0e6873744724f2fe382eeef5 100644 (file)
@@ -142,14 +142,29 @@ static int fat_readpages(struct file *file, struct address_space *mapping,
        return mpage_readpages(mapping, pages, nr_pages, fat_get_block);
 }
 
+static void fat_write_failed(struct address_space *mapping, loff_t to)
+{
+       struct inode *inode = mapping->host;
+
+       if (to > inode->i_size) {
+               truncate_pagecache(inode, to, inode->i_size);
+               fat_truncate_blocks(inode, inode->i_size);
+       }
+}
+
 static int fat_write_begin(struct file *file, struct address_space *mapping,
                        loff_t pos, unsigned len, unsigned flags,
                        struct page **pagep, void **fsdata)
 {
+       int err;
+
        *pagep = NULL;
-       return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
-                               fat_get_block,
+       err = cont_write_begin_newtrunc(file, mapping, pos, len, flags,
+                               pagep, fsdata, fat_get_block,
                                &MSDOS_I(mapping->host)->mmu_private);
+       if (err < 0)
+               fat_write_failed(mapping, pos + len);
+       return err;
 }
 
 static int fat_write_end(struct file *file, struct address_space *mapping,
@@ -159,6 +174,8 @@ static int fat_write_end(struct file *file, struct address_space *mapping,
        struct inode *inode = mapping->host;
        int err;
        err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata);
+       if (err < len)
+               fat_write_failed(mapping, pos + len);
        if (!(err < 0) && !(MSDOS_I(inode)->i_attrs & ATTR_ARCH)) {
                inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
                MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
@@ -172,7 +189,9 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb,
                             loff_t offset, unsigned long nr_segs)
 {
        struct file *file = iocb->ki_filp;
-       struct inode *inode = file->f_mapping->host;
+       struct address_space *mapping = file->f_mapping;
+       struct inode *inode = mapping->host;
+       ssize_t ret;
 
        if (rw == WRITE) {
                /*
@@ -193,8 +212,12 @@ 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().
         */
-       return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
-                                 offset, nr_segs, fat_get_block, NULL);
+       ret = blockdev_direct_IO_newtrunc(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));
+
+       return ret;
 }
 
 static sector_t _fat_bmap(struct address_space *mapping, sector_t block)
@@ -429,7 +452,7 @@ static void fat_delete_inode(struct inode *inode)
 {
        truncate_inode_pages(&inode->i_data, 0);
        inode->i_size = 0;
-       fat_truncate(inode);
+       fat_truncate_blocks(inode, 0);
        clear_inode(inode);
 }
 
@@ -1250,6 +1273,8 @@ int fat_fill_super(struct super_block *sb, void *data, int silent,
        sb->s_op = &fat_sops;
        sb->s_export_op = &fat_export_ops;
        sbi->dir_ops = fs_dir_inode_ops;
+       ratelimit_state_init(&sbi->ratelimit, DEFAULT_RATELIMIT_INTERVAL,
+                            DEFAULT_RATELIMIT_BURST);
 
        error = parse_options(data, isvfat, silent, &debug, &sbi->options);
        if (error)
@@ -1497,10 +1522,8 @@ out_fail:
                iput(fat_inode);
        if (root_inode)
                iput(root_inode);
-       if (sbi->nls_io)
-               unload_nls(sbi->nls_io);
-       if (sbi->nls_disk)
-               unload_nls(sbi->nls_disk);
+       unload_nls(sbi->nls_io);
+       unload_nls(sbi->nls_disk);
        if (sbi->options.iocharset != fat_default_iocharset)
                kfree(sbi->options.iocharset);
        sb->s_fs_info = NULL;
index d3da05f2646587a09e52bc4243d3ac7fd82588fa..1fa23f6ffba5b39a9921bc6f0b5eac0bfd46fecb 100644 (file)
  * In case the file system is remounted read-only, it can be made writable
  * again by remounting it.
  */
-void fat_fs_error(struct super_block *s, const char *fmt, ...)
+void __fat_fs_error(struct super_block *s, int report, const char *fmt, ...)
 {
        struct fat_mount_options *opts = &MSDOS_SB(s)->options;
        va_list args;
 
-       printk(KERN_ERR "FAT: Filesystem error (dev %s)\n", s->s_id);
+       if (report) {
+               printk(KERN_ERR "FAT: Filesystem error (dev %s)\n", s->s_id);
 
-       printk(KERN_ERR "    ");
-       va_start(args, fmt);
-       vprintk(fmt, args);
-       va_end(args);
-       printk("\n");
+               printk(KERN_ERR "    ");
+               va_start(args, fmt);
+               vprintk(fmt, args);
+               va_end(args);
+               printk("\n");
+       }
 
        if (opts->errors == FAT_ERRORS_PANIC)
-               panic("    FAT fs panic from previous error\n");
+               panic("FAT: fs panic from previous error\n");
        else if (opts->errors == FAT_ERRORS_RO && !(s->s_flags & MS_RDONLY)) {
                s->s_flags |= MS_RDONLY;
-               printk(KERN_ERR "    File system has been set read-only\n");
+               printk(KERN_ERR "FAT: Filesystem has been set read-only\n");
        }
 }
-EXPORT_SYMBOL_GPL(fat_fs_error);
+EXPORT_SYMBOL_GPL(__fat_fs_error);
 
 /* Flushes the number of free clusters on FAT32 */
 /* XXX: Need to write one per FSINFO block.  Currently only writes 1 */
index 32d12b78bac8e2c05a80dc53386b355bdc10ef73..5c7d10ead4ad774981f294428bd1ef7fa9e4cccf 100644 (file)
@@ -194,14 +194,6 @@ struct file *alloc_file(struct path *path, fmode_t mode,
 }
 EXPORT_SYMBOL(alloc_file);
 
-void fput(struct file *file)
-{
-       if (atomic_long_dec_and_test(&file->f_count))
-               __fput(file);
-}
-
-EXPORT_SYMBOL(fput);
-
 /**
  * drop_file_write_access - give up ability to write to a file
  * @file: the file to which we will stop writing
@@ -227,10 +219,9 @@ void drop_file_write_access(struct file *file)
 }
 EXPORT_SYMBOL_GPL(drop_file_write_access);
 
-/* __fput is called from task context when aio completion releases the last
- * last use of a struct file *.  Do not use otherwise.
+/* the real guts of fput() - releasing the last reference to file
  */
-void __fput(struct file *file)
+static void __fput(struct file *file)
 {
        struct dentry *dentry = file->f_path.dentry;
        struct vfsmount *mnt = file->f_path.mnt;
@@ -268,6 +259,14 @@ void __fput(struct file *file)
        mntput(mnt);
 }
 
+void fput(struct file *file)
+{
+       if (atomic_long_dec_and_test(&file->f_count))
+               __fput(file);
+}
+
+EXPORT_SYMBOL(fput);
+
 struct file *fget(unsigned int fd)
 {
        struct file *file;
index aee049cb9f84782640d365a90156f423d2a37b46..0ec7bb2c95c6afd035a9484b0a39347f9f8f61c1 100644 (file)
@@ -57,6 +57,8 @@ const struct inode_operations vxfs_dir_inode_ops = {
 };
 
 const struct file_operations vxfs_dir_operations = {
+       .llseek =               generic_file_llseek,
+       .read =                 generic_read_dir,
        .readdir =              vxfs_readdir,
 };
 
index 437a7431b4ea6e0ac7fface79d2029d3bc9aaf27..ea8592b906968913499b9847f35389a31e5dc1a3 100644 (file)
@@ -42,10 +42,10 @@ struct wb_writeback_args {
        long nr_pages;
        struct super_block *sb;
        enum writeback_sync_modes sync_mode;
-       int for_kupdate:1;
-       int range_cyclic:1;
-       int for_background:1;
-       int sb_pinned:1;
+       unsigned int for_kupdate:1;
+       unsigned int range_cyclic:1;
+       unsigned int for_background:1;
+       unsigned int sb_pinned:1;
 };
 
 /*
@@ -409,11 +409,11 @@ static void inode_wait_for_writeback(struct inode *inode)
        wait_queue_head_t *wqh;
 
        wqh = bit_waitqueue(&inode->i_state, __I_SYNC);
-       do {
+        while (inode->i_state & I_SYNC) {
                spin_unlock(&inode_lock);
                __wait_on_bit(wqh, &wq, inode_wait, TASK_UNINTERRUPTIBLE);
                spin_lock(&inode_lock);
-       } while (inode->i_state & I_SYNC);
+       }
 }
 
 /*
index 1e1f286dd70eeb0ea7e98b46012e378280e0cf58..4a8eb31c53381f74fca4a1dfad3ed0f19ef4ed3b 100644 (file)
@@ -103,7 +103,7 @@ static struct fscache_object *fscache_objlist_lookup(loff_t *_pos)
        /* banners (can't represent line 0 by pos 0 as that would involve
         * returning a NULL pointer) */
        if (pos == 0)
-               return (struct fscache_object *) ++(*_pos);
+               return (struct fscache_object *)(long)++(*_pos);
        if (pos < 3)
                return (struct fscache_object *)pos;
 
index eb7e9423691feeefdffd269e4489d8e6cf6ad21c..e53df5ebb2b89904046e8a06808f68cd25fd6b5d 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/slab.h>
 
 MODULE_ALIAS_MISCDEV(FUSE_MINOR);
+MODULE_ALIAS("devname:fuse");
 
 static struct kmem_cache *fuse_req_cachep;
 
index 4787ae6c5c1c5aac632c871502ca4a99823dd3bb..3cdc5f78a406357a7e4bcbffe5783facd35c7236 100644 (file)
@@ -1156,10 +1156,9 @@ static int fuse_dir_release(struct inode *inode, struct file *file)
        return 0;
 }
 
-static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
+static int fuse_dir_fsync(struct file *file, int datasync)
 {
-       /* nfsd can call this with no file */
-       return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
+       return fuse_fsync_common(file, datasync, 1);
 }
 
 static bool update_mtime(unsigned ivalid)
index a9f5e137f1d31547f86bbfdb87df11c07daf963f..b5fd6f9905e4eaaefeabaabc2472cc28c95b5781 100644 (file)
@@ -351,10 +351,9 @@ static void fuse_sync_writes(struct inode *inode)
        fuse_release_nowrite(inode);
 }
 
-int fuse_fsync_common(struct file *file, struct dentry *de, int datasync,
-                     int isdir)
+int fuse_fsync_common(struct file *file, int datasync, int isdir)
 {
-       struct inode *inode = de->d_inode;
+       struct inode *inode = file->f_mapping->host;
        struct fuse_conn *fc = get_fuse_conn(inode);
        struct fuse_file *ff = file->private_data;
        struct fuse_req *req;
@@ -403,9 +402,9 @@ int fuse_fsync_common(struct file *file, struct dentry *de, int datasync,
        return err;
 }
 
-static int fuse_fsync(struct file *file, struct dentry *de, int datasync)
+static int fuse_fsync(struct file *file, int datasync)
 {
-       return fuse_fsync_common(file, de, datasync, 0);
+       return fuse_fsync_common(file, datasync, 0);
 }
 
 void fuse_read_fill(struct fuse_req *req, struct file *file, loff_t pos,
index 01cc462ff45d5ccdf0bc0bc0526e493ed60fc729..2c0d14a86779358309222d3f7b6a5719eda5a82c 100644 (file)
@@ -568,8 +568,7 @@ void fuse_release_common(struct file *file, int opcode);
 /**
  * Send FSYNC or FSYNCDIR request
  */
-int fuse_fsync_common(struct file *file, struct dentry *de, int datasync,
-                     int isdir);
+int fuse_fsync_common(struct file *file, int datasync, int isdir);
 
 /**
  * Notify poll wakeup
index fe5df5457656e43fa2757a37b322c106b63af17f..99800e564157ed5d3bb78b6e80c6d7f5b7d32051 100644 (file)
@@ -201,7 +201,7 @@ generic_check_acl(struct inode *inode, int mask)
        return -EAGAIN;
 }
 
-struct xattr_handler generic_acl_access_handler = {
+const struct xattr_handler generic_acl_access_handler = {
        .prefix = POSIX_ACL_XATTR_ACCESS,
        .flags  = ACL_TYPE_ACCESS,
        .list   = generic_acl_list,
@@ -209,7 +209,7 @@ struct xattr_handler generic_acl_access_handler = {
        .set    = generic_acl_set,
 };
 
-struct xattr_handler generic_acl_default_handler = {
+const struct xattr_handler generic_acl_default_handler = {
        .prefix = POSIX_ACL_XATTR_DEFAULT,
        .flags  = ACL_TYPE_DEFAULT,
        .list   = generic_acl_list,
index 87ee309d4c24d10e6dcac60f7d8bca17558553b2..48171f4c943dbb2523a22011a25aca402fe3e6e5 100644 (file)
@@ -236,10 +236,14 @@ static int gfs2_xattr_system_get(struct dentry *dentry, const char *name,
                                 void *buffer, size_t size, int xtype)
 {
        struct inode *inode = dentry->d_inode;
+       struct gfs2_sbd *sdp = GFS2_SB(inode);
        struct posix_acl *acl;
        int type;
        int error;
 
+       if (!sdp->sd_args.ar_posix_acl)
+               return -EOPNOTSUPP;
+
        type = gfs2_acl_type(name);
        if (type < 0)
                return type;
@@ -335,7 +339,7 @@ out:
        return error;
 }
 
-struct xattr_handler gfs2_xattr_system_handler = {
+const struct xattr_handler gfs2_xattr_system_handler = {
        .prefix = XATTR_SYSTEM_PREFIX,
        .flags  = GFS2_EATYPE_SYS,
        .get    = gfs2_xattr_system_get,
index 9306a2e6620c7111b55ed5ee5f9bf9a5c13cca2e..b522b0cb39eaa12798649c2a8bd2b1e952a746f9 100644 (file)
@@ -19,6 +19,6 @@
 extern int gfs2_check_acl(struct inode *inode, int mask);
 extern int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode);
 extern int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr);
-extern struct xattr_handler gfs2_xattr_system_handler;
+extern const struct xattr_handler gfs2_xattr_system_handler;
 
 #endif /* __ACL_DOT_H__ */
index a739a0a480670698cb06ed9106a9f710981f3a96..9f8b52500d63551c4111370bc59b357cb177f60a 100644 (file)
@@ -700,8 +700,14 @@ out:
                return 0;
 
        page_cache_release(page);
+
+       /*
+        * XXX(hch): 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)
-               vmtruncate(&ip->i_inode, ip->i_inode.i_size);
+               simple_setsize(&ip->i_inode, ip->i_inode.i_size);
 out_endtrans:
        gfs2_trans_end(sdp);
 out_trans_fail:
index e6dd2aec6f822fe1ffa6cc8d442bd1dd03ca496f..ed9a94f0ef159c369b6bd3a3598e1cd4d42fb697 100644 (file)
@@ -218,6 +218,11 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
        if (error)
                goto out_drop_write;
 
+       error = -EACCES;
+       if (!is_owner_or_cap(inode))
+               goto out;
+
+       error = 0;
        flags = ip->i_diskflags;
        new_flags = (flags & ~mask) | (reqflags & mask);
        if ((new_flags ^ flags) == 0)
@@ -275,8 +280,10 @@ static int gfs2_set_flags(struct file *filp, u32 __user *ptr)
 {
        struct inode *inode = filp->f_path.dentry->d_inode;
        u32 fsflags, gfsflags;
+
        if (get_user(fsflags, ptr))
                return -EFAULT;
+
        gfsflags = fsflags_cvt(fsflags_to_gfs2, fsflags);
        if (!S_ISDIR(inode->i_mode)) {
                if (gfsflags & GFS2_DIF_INHERIT_JDATA)
@@ -547,9 +554,9 @@ static int gfs2_close(struct inode *inode, struct file *file)
  * Returns: errno
  */
 
-static int gfs2_fsync(struct file *file, struct dentry *dentry, int datasync)
+static int gfs2_fsync(struct file *file, int datasync)
 {
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = file->f_mapping->host;
        int sync_state = inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC);
        int ret = 0;
 
index 51d8061fa07ac79667148b6fec357feff8b6088f..b5612cbb62a51b75dc97699490658ce6939a4118 100644 (file)
@@ -242,34 +242,38 @@ fail:
 }
 
 /**
- * gfs2_unlinked_inode_lookup - Lookup an unlinked inode for reclamation
+ * gfs2_process_unlinked_inode - Lookup an unlinked inode for reclamation
+ *                               and try to reclaim it by doing iput.
+ *
+ * This function assumes no rgrp locks are currently held.
+ *
  * @sb: The super block
  * no_addr: The inode number
- * @@inode: A pointer to the inode found, if any
  *
- * Returns: 0 and *inode if no errors occurred.  If an error occurs,
- *          the resulting *inode may or may not be NULL.
  */
 
-int gfs2_unlinked_inode_lookup(struct super_block *sb, u64 no_addr,
-                              struct inode **inode)
+void gfs2_process_unlinked_inode(struct super_block *sb, u64 no_addr)
 {
        struct gfs2_sbd *sdp;
        struct gfs2_inode *ip;
        struct gfs2_glock *io_gl;
        int error;
        struct gfs2_holder gh;
+       struct inode *inode;
 
-       *inode = gfs2_iget_skip(sb, no_addr);
+       inode = gfs2_iget_skip(sb, no_addr);
 
-       if (!(*inode))
-               return -ENOBUFS;
+       if (!inode)
+               return;
 
-       if (!((*inode)->i_state & I_NEW))
-               return -ENOBUFS;
+       /* If it's not a new inode, someone's using it, so leave it alone. */
+       if (!(inode->i_state & I_NEW)) {
+               iput(inode);
+               return;
+       }
 
-       ip = GFS2_I(*inode);
-       sdp = GFS2_SB(*inode);
+       ip = GFS2_I(inode);
+       sdp = GFS2_SB(inode);
        ip->i_no_formal_ino = -1;
 
        error = gfs2_glock_get(sdp, no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl);
@@ -284,15 +288,13 @@ int gfs2_unlinked_inode_lookup(struct super_block *sb, u64 no_addr,
        set_bit(GIF_INVALID, &ip->i_flags);
        error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, LM_FLAG_TRY | GL_EXACT,
                                   &ip->i_iopen_gh);
-       if (unlikely(error)) {
-               if (error == GLR_TRYFAILED)
-                       error = 0;
+       if (unlikely(error))
                goto fail_iopen;
-       }
+
        ip->i_iopen_gh.gh_gl->gl_object = ip;
        gfs2_glock_put(io_gl);
 
-       (*inode)->i_mode = DT2IF(DT_UNKNOWN);
+       inode->i_mode = DT2IF(DT_UNKNOWN);
 
        /*
         * We must read the inode in order to work out its type in
@@ -303,16 +305,17 @@ int gfs2_unlinked_inode_lookup(struct super_block *sb, u64 no_addr,
         */
        error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, LM_FLAG_TRY,
                                   &gh);
-       if (unlikely(error)) {
-               if (error == GLR_TRYFAILED)
-                       error = 0;
+       if (unlikely(error))
                goto fail_glock;
-       }
+
        /* Inode is now uptodate */
        gfs2_glock_dq_uninit(&gh);
-       gfs2_set_iop(*inode);
+       gfs2_set_iop(inode);
+
+       /* The iput will cause it to be deleted. */
+       iput(inode);
+       return;
 
-       return 0;
 fail_glock:
        gfs2_glock_dq(&ip->i_iopen_gh);
 fail_iopen:
@@ -321,7 +324,8 @@ fail_put:
        ip->i_gl->gl_object = NULL;
        gfs2_glock_put(ip->i_gl);
 fail:
-       return error;
+       iget_failed(inode);
+       return;
 }
 
 static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
index e161461d4c5798bc8e2b2cccd4dcc8cb3446912a..300ada3f21de0cf5fc22677283343a76caf8200e 100644 (file)
@@ -84,8 +84,7 @@ static inline void gfs2_inum_out(const struct gfs2_inode *ip,
 extern void gfs2_set_iop(struct inode *inode);
 extern struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type, 
                                       u64 no_addr, u64 no_formal_ino);
-extern int gfs2_unlinked_inode_lookup(struct super_block *sb, u64 no_addr,
-                                     struct inode **inode);
+extern void gfs2_process_unlinked_inode(struct super_block *sb, u64 no_addr);
 extern struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr);
 
 extern int gfs2_inode_refresh(struct gfs2_inode *ip);
index b593f0e28f259aee410dad764e77ba71056c06e0..6a857e24f9477f7fe8fbdb710220d8d05964a95e 100644 (file)
@@ -696,7 +696,7 @@ static void gfs2_ordered_wait(struct gfs2_sbd *sdp)
  *
  */
 
-void __gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
+void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
 {
        struct gfs2_ail *ai;
 
index eb570b4ad443ca54fc2e3cac93876d01e09d484c..0d007f92023411b00015a74d247095e8f7354f37 100644 (file)
@@ -47,28 +47,21 @@ static inline void gfs2_log_pointers_init(struct gfs2_sbd *sdp,
        sdp->sd_log_head = sdp->sd_log_tail = value;
 }
 
-unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct,
+extern unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct,
                            unsigned int ssize);
 
-int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks);
-void gfs2_log_incr_head(struct gfs2_sbd *sdp);
+extern int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks);
+extern void gfs2_log_incr_head(struct gfs2_sbd *sdp);
 
-struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp);
-struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp,
+extern struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp);
+extern struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp,
                                      struct buffer_head *real);
-void __gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl);
+extern void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl);
+extern void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans);
+extern void gfs2_remove_from_ail(struct gfs2_bufdata *bd);
 
-static inline void gfs2_log_flush(struct gfs2_sbd *sbd, struct gfs2_glock *gl)
-{
-       if (!gl || test_bit(GLF_LFLUSH, &gl->gl_flags))
-               __gfs2_log_flush(sbd, gl);
-}
-
-void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans);
-void gfs2_remove_from_ail(struct gfs2_bufdata *bd);
-
-void gfs2_log_shutdown(struct gfs2_sbd *sdp);
-void gfs2_meta_syncfs(struct gfs2_sbd *sdp);
-int gfs2_logd(void *data);
+extern void gfs2_log_shutdown(struct gfs2_sbd *sdp);
+extern void gfs2_meta_syncfs(struct gfs2_sbd *sdp);
+extern int gfs2_logd(void *data);
 
 #endif /* __LOG_DOT_H__ */
index 4e64352d49de1b442c5d627eb4ce3adba8c94f92..98cdd05f3316f17b98a82bf11d95805168445aee 100644 (file)
@@ -1071,6 +1071,9 @@ int gfs2_permission(struct inode *inode, int mask)
        return error;
 }
 
+/*
+ * XXX: should be changed to have proper ordering by opencoding simple_setsize
+ */
 static int setattr_size(struct inode *inode, struct iattr *attr)
 {
        struct gfs2_inode *ip = GFS2_I(inode);
@@ -1081,7 +1084,7 @@ 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 = vmtruncate(inode, attr->ia_size);
+               error = simple_setsize(inode, attr->ia_size);
                gfs2_trans_end(sdp);
                if (error) 
                        return error;
index 117fa4171f62958b966a6c781240d293d5491823..171a744f8e45d172f4e43eb793ae4e08dba8ba23 100644 (file)
@@ -1192,7 +1192,6 @@ int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
        struct gfs2_alloc *al = ip->i_alloc;
-       struct inode *inode;
        int error = 0;
        u64 last_unlinked = NO_BLOCK, unlinked;
 
@@ -1210,22 +1209,27 @@ try_again:
        if (error)
                return error;
 
+       /* Find an rgrp suitable for allocation.  If it encounters any unlinked
+          dinodes along the way, error will equal -EAGAIN and unlinked will
+          contains it block address. We then need to look up that inode and
+          try to free it, and try the allocation again. */
        error = get_local_rgrp(ip, &unlinked, &last_unlinked);
        if (error) {
                if (ip != GFS2_I(sdp->sd_rindex))
                        gfs2_glock_dq_uninit(&al->al_ri_gh);
                if (error != -EAGAIN)
                        return error;
-               error = gfs2_unlinked_inode_lookup(ip->i_inode.i_sb,
-                                                  unlinked, &inode);
-               if (inode)
-                       iput(inode);
+
+               gfs2_process_unlinked_inode(ip->i_inode.i_sb, unlinked);
+               /* regardless of whether or not gfs2_process_unlinked_inode
+                  was successful, we don't want to repeat it again. */
+               last_unlinked = unlinked;
                gfs2_log_flush(sdp, NULL);
-               if (error == GLR_TRYFAILED)
-                       error = 0;
+               error = 0;
+
                goto try_again;
        }
-
+       /* no error, so we have the rgrp set in the inode's allocation. */
        al->al_file = file;
        al->al_line = line;
 
index 3df60f2d84e36b31058102ba836af87d2463f1d9..a0464680af0b8cec6b7fdf2c69099ba740933dce 100644 (file)
@@ -54,7 +54,7 @@ extern struct file_system_type gfs2meta_fs_type;
 extern const struct export_operations gfs2_export_ops;
 extern const struct super_operations gfs2_super_ops;
 extern const struct dentry_operations gfs2_dops;
-extern struct xattr_handler *gfs2_xattr_handlers[];
+extern const struct xattr_handler *gfs2_xattr_handlers[];
 
 #endif /* __SUPER_DOT_H__ */
 
index c2ebdf2c01d4fb2d4018e76fe8506d8ce04bd155..82f93da00d1b4e2373bea8b36f691dc39ae0a8d2 100644 (file)
@@ -1535,21 +1535,21 @@ out_alloc:
        return error;
 }
 
-static struct xattr_handler gfs2_xattr_user_handler = {
+static const struct xattr_handler gfs2_xattr_user_handler = {
        .prefix = XATTR_USER_PREFIX,
        .flags  = GFS2_EATYPE_USR,
        .get    = gfs2_xattr_get,
        .set    = gfs2_xattr_set,
 };
 
-static struct xattr_handler gfs2_xattr_security_handler = {
+static const struct xattr_handler gfs2_xattr_security_handler = {
        .prefix = XATTR_SECURITY_PREFIX,
        .flags  = GFS2_EATYPE_SECURITY,
        .get    = gfs2_xattr_get,
        .set    = gfs2_xattr_set,
 };
 
-struct xattr_handler *gfs2_xattr_handlers[] = {
+const struct xattr_handler *gfs2_xattr_handlers[] = {
        &gfs2_xattr_user_handler,
        &gfs2_xattr_security_handler,
        &gfs2_xattr_system_handler,
index 5f4023678251b9b9ee8da40e27eff7f6c33e4a63..764fd1bdca882da08028e34b133930d9d155a364 100644 (file)
@@ -494,7 +494,7 @@ const struct inode_operations hfsplus_dir_inode_operations = {
 const struct file_operations hfsplus_dir_operations = {
        .read           = generic_read_dir,
        .readdir        = hfsplus_readdir,
-       .ioctl          = hfsplus_ioctl,
+       .unlocked_ioctl = hfsplus_ioctl,
        .llseek         = generic_file_llseek,
        .release        = hfsplus_dir_release,
 };
index 5c10d803d9df1ea10dd20b4c0c5b122b36b85e18..6505c30ad965412e4b499c57c20eac1af3054603 100644 (file)
@@ -337,8 +337,7 @@ struct inode *hfsplus_new_inode(struct super_block *, int);
 void hfsplus_delete_inode(struct inode *);
 
 /* ioctl.c */
-int hfsplus_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
-                 unsigned long arg);
+long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
 int hfsplus_setxattr(struct dentry *dentry, const char *name,
                     const void *value, size_t size, int flags);
 ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name,
index 1bcf597c05625c8023ddf6074d9efe2aca6b8e1e..9bbb82924a2297a64cc8ba70322e5e63dc1e130c 100644 (file)
@@ -285,7 +285,7 @@ static const struct file_operations hfsplus_file_operations = {
        .fsync          = file_fsync,
        .open           = hfsplus_file_open,
        .release        = hfsplus_file_release,
-       .ioctl          = hfsplus_ioctl,
+       .unlocked_ioctl = hfsplus_ioctl,
 };
 
 struct inode *hfsplus_new_inode(struct super_block *sb, int mode)
index f457d2ca51ab8e68a3e60cd9028620fa029f8f18..ac405f09902651838979e322931ba7a1f1441633 100644 (file)
 #include <linux/mount.h>
 #include <linux/sched.h>
 #include <linux/xattr.h>
+#include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 #include "hfsplus_fs.h"
 
-int hfsplus_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
-                 unsigned long arg)
+long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
+       struct inode *inode = filp->f_path.dentry->d_inode;
        unsigned int flags;
 
+       lock_kernel();
        switch (cmd) {
        case HFSPLUS_IOC_EXT2_GETFLAGS:
                flags = 0;
@@ -38,8 +40,10 @@ int hfsplus_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
        case HFSPLUS_IOC_EXT2_SETFLAGS: {
                int err = 0;
                err = mnt_want_write(filp->f_path.mnt);
-               if (err)
+               if (err) {
+                       unlock_kernel();
                        return err;
+               }
 
                if (!is_owner_or_cap(inode)) {
                        err = -EACCES;
@@ -85,9 +89,11 @@ int hfsplus_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                mark_inode_dirty(inode);
 setflags_out:
                mnt_drop_write(filp->f_path.mnt);
+               unlock_kernel();
                return err;
        }
        default:
+               unlock_kernel();
                return -ENOTTY;
        }
 }
index 3a029d8f4cf1d564f0e64c7f1ead796a193769d5..87ac1891a18584a05d56b88572a66b440c7b4766 100644 (file)
@@ -411,9 +411,9 @@ int hostfs_file_open(struct inode *ino, struct file *file)
        return 0;
 }
 
-int hostfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+int hostfs_fsync(struct file *file, int datasync)
 {
-       return fsync_file(HOSTFS_I(dentry->d_inode)->fd, datasync);
+       return fsync_file(HOSTFS_I(file->f_mapping->host)->fd, datasync);
 }
 
 static const struct file_operations hostfs_file_fops = {
index 3efabff00367672a5a7bb722984590c14346338a..a9ae9bfa752f5a032d411a8def0216027dca54bf 100644 (file)
@@ -19,9 +19,9 @@ static int hpfs_file_release(struct inode *inode, struct file *file)
        return 0;
 }
 
-int hpfs_file_fsync(struct file *file, struct dentry *dentry, int datasync)
+int hpfs_file_fsync(struct file *file, int datasync)
 {
-       /*return file_fsync(file, dentry);*/
+       /*return file_fsync(file, datasync);*/
        return 0; /* Don't fsync :-) */
 }
 
index 97bf738cd5d65117b4610a707738dd9accd8c2eb..75f9d43248511843334923c2f38b7f1e36d47245 100644 (file)
@@ -268,7 +268,7 @@ void hpfs_set_ea(struct inode *, struct fnode *, const char *,
 
 /* file.c */
 
-int hpfs_file_fsync(struct file *, struct dentry *, int);
+int hpfs_file_fsync(struct file *, int);
 extern const struct file_operations hpfs_file_ops;
 extern const struct inode_operations hpfs_file_iops;
 extern const struct address_space_operations hpfs_aops;
index 2e4dfa8593da4c047a1a9028f6d8f8ce2b8b78bd..826c3f9d29ac665f11f66d2c83c1922041629137 100644 (file)
@@ -587,7 +587,7 @@ static int hppfs_readdir(struct file *file, void *ent, filldir_t filldir)
        return err;
 }
 
-static int hppfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+static int hppfs_fsync(struct file *file, int datasync)
 {
        return 0;
 }
index a0bbd3d1b41a29338fe9cef80e8da032f44b15fe..a4e9a7ec3691a4066deb8948da3aacd12606b896 100644 (file)
@@ -688,7 +688,7 @@ static void init_once(void *foo)
 const struct file_operations hugetlbfs_file_operations = {
        .read                   = hugetlbfs_read,
        .mmap                   = hugetlbfs_file_mmap,
-       .fsync                  = simple_sync_file,
+       .fsync                  = noop_fsync,
        .get_unmapped_area      = hugetlb_get_unmapped_area,
 };
 
index 258ec22bb298ff1c285a0dba581236c2a0d332bf..2bee20ae3d65ba74f970129ec8d147ab7cd4fe50 100644 (file)
@@ -286,11 +286,9 @@ static void init_once(void *foo)
  */
 void __iget(struct inode *inode)
 {
-       if (atomic_read(&inode->i_count)) {
-               atomic_inc(&inode->i_count);
+       if (atomic_inc_return(&inode->i_count) != 1)
                return;
-       }
-       atomic_inc(&inode->i_count);
+
        if (!(inode->i_state & (I_DIRTY|I_SYNC)))
                list_move(&inode->i_list, &inode_in_use);
        inodes_stat.nr_unused--;
@@ -1608,3 +1606,23 @@ void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
                                  inode->i_ino);
 }
 EXPORT_SYMBOL(init_special_inode);
+
+/**
+ * Init uid,gid,mode for new inode according to posix standards
+ * @inode: New inode
+ * @dir: Directory inode
+ * @mode: mode of the new inode
+ */
+void inode_init_owner(struct inode *inode, const struct inode *dir,
+                       mode_t mode)
+{
+       inode->i_uid = current_fsuid();
+       if (dir && dir->i_mode & S_ISGID) {
+               inode->i_gid = dir->i_gid;
+               if (S_ISDIR(mode))
+                       mode |= S_ISGID;
+       } else
+               inode->i_gid = current_fsgid();
+       inode->i_mode = mode;
+}
+EXPORT_SYMBOL(inode_init_owner);
index 8a03a5447bdf392a826b088f7329c68af32f3d2e..6b706bc60a66bbb3cecb7477f2ea72e0a091aa84 100644 (file)
@@ -87,6 +87,8 @@ extern struct file *get_empty_filp(void);
  * super.c
  */
 extern int do_remount_sb(struct super_block *, int, void *, int);
+extern void __put_super(struct super_block *sb);
+extern void put_super(struct super_block *sb);
 
 /*
  * open.c
index 7faefb4da93915be59bfe6a8ab2a9b37014b9b52..2d140a713861badfb1c9b936c683805dab30853a 100644 (file)
@@ -525,15 +525,8 @@ static int ioctl_fsfreeze(struct file *filp)
        if (sb->s_op->freeze_fs == NULL)
                return -EOPNOTSUPP;
 
-       /* If a blockdevice-backed filesystem isn't specified, return. */
-       if (sb->s_bdev == NULL)
-               return -EINVAL;
-
        /* Freeze */
-       sb = freeze_bdev(sb->s_bdev);
-       if (IS_ERR(sb))
-               return PTR_ERR(sb);
-       return 0;
+       return freeze_super(sb);
 }
 
 static int ioctl_fsthaw(struct file *filp)
@@ -543,12 +536,8 @@ static int ioctl_fsthaw(struct file *filp)
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       /* If a blockdevice-backed filesystem isn't specified, return EINVAL. */
-       if (sb->s_bdev == NULL)
-               return -EINVAL;
-
        /* Thaw */
-       return thaw_bdev(sb->s_bdev, sb);
+       return thaw_super(sb);
 }
 
 /*
index b9ab69b3a482ce86bcbefd9f7703d0079f516bce..e0aca9a0ac68b9f5a75764a570df2c3d0bd81a72 100644 (file)
@@ -272,6 +272,7 @@ static int isofs_readdir(struct file *filp,
 
 const struct file_operations isofs_dir_operations =
 {
+       .llseek = generic_file_llseek,
        .read = generic_read_dir,
        .readdir = isofs_readdir,
 };
index bfc70f57900fddb0d63039fb0a2cd662abf963ff..e214d68620ac167fb5ddeb71775ead1b6063a571 100644 (file)
@@ -1311,7 +1311,6 @@ int jbd2_journal_stop(handle_t *handle)
        if (handle->h_sync)
                transaction->t_synchronous_commit = 1;
        current->journal_info = NULL;
-       spin_lock(&journal->j_state_lock);
        spin_lock(&transaction->t_handle_lock);
        transaction->t_outstanding_credits -= handle->h_buffer_credits;
        transaction->t_updates--;
@@ -1340,8 +1339,7 @@ int jbd2_journal_stop(handle_t *handle)
                jbd_debug(2, "transaction too old, requesting commit for "
                                        "handle %p\n", handle);
                /* This is non-blocking */
-               __jbd2_log_start_commit(journal, transaction->t_tid);
-               spin_unlock(&journal->j_state_lock);
+               jbd2_log_start_commit(journal, transaction->t_tid);
 
                /*
                 * Special case: JBD2_SYNC synchronous updates require us
@@ -1351,7 +1349,6 @@ int jbd2_journal_stop(handle_t *handle)
                        err = jbd2_log_wait_commit(journal, tid);
        } else {
                spin_unlock(&transaction->t_handle_lock);
-               spin_unlock(&journal->j_state_lock);
        }
 
        lock_map_release(&handle->h_lockdep_map);
index 7cdc3196476ace72ef11fb53bbe80fb86b3dfbeb..a33aab6b5e683cf988932fdd9f732f5381751541 100644 (file)
@@ -419,7 +419,7 @@ static int jffs2_acl_setxattr(struct dentry *dentry, const char *name,
        return rc;
 }
 
-struct xattr_handler jffs2_acl_access_xattr_handler = {
+const struct xattr_handler jffs2_acl_access_xattr_handler = {
        .prefix = POSIX_ACL_XATTR_ACCESS,
        .flags  = ACL_TYPE_DEFAULT,
        .list   = jffs2_acl_access_listxattr,
@@ -427,7 +427,7 @@ struct xattr_handler jffs2_acl_access_xattr_handler = {
        .set    = jffs2_acl_setxattr,
 };
 
-struct xattr_handler jffs2_acl_default_xattr_handler = {
+const struct xattr_handler jffs2_acl_default_xattr_handler = {
        .prefix = POSIX_ACL_XATTR_DEFAULT,
        .flags  = ACL_TYPE_DEFAULT,
        .list   = jffs2_acl_default_listxattr,
index f0ba63e3c36bcc607fb879a1beb219133902f09f..5e42de8d954126a46664125678cdd037a76470a7 100644 (file)
@@ -31,8 +31,8 @@ extern int jffs2_acl_chmod(struct inode *);
 extern int jffs2_init_acl_pre(struct inode *, struct inode *, int *);
 extern int jffs2_init_acl_post(struct inode *);
 
-extern struct xattr_handler jffs2_acl_access_xattr_handler;
-extern struct xattr_handler jffs2_acl_default_xattr_handler;
+extern const struct xattr_handler jffs2_acl_access_xattr_handler;
+extern const struct xattr_handler jffs2_acl_default_xattr_handler;
 
 #else
 
index e7291c161a1989c2abeb55659eb67b80fdc1a8d0..8134970244376526710bd99922d823a699306170 100644 (file)
@@ -26,9 +26,9 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
                        struct page **pagep, void **fsdata);
 static int jffs2_readpage (struct file *filp, struct page *pg);
 
-int jffs2_fsync(struct file *filp, struct dentry *dentry, int datasync)
+int jffs2_fsync(struct file *filp, int datasync)
 {
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = filp->f_mapping->host;
        struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
 
        /* Trigger GC to flush any pending writes for this inode */
index 86e0821fc989303d6ccd297e74c18606d45db3ba..8bc2c80ab159592dbcf8f43050566ac64de009b0 100644 (file)
@@ -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 vmtruncate() without f->sem held, since
+       /* We have to do the simple_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) {
-               vmtruncate(inode, iattr->ia_size);      
+               simple_setsize(inode, iattr->ia_size);
                inode->i_blocks = (inode->i_size + 511) >> 9;
        }       
 
index 035a767f958b078baa407c84e90050b20f77eca2..4791aacf30849d93ef8ff6875b0c41c651d3c204 100644 (file)
@@ -158,7 +158,7 @@ extern const struct inode_operations jffs2_dir_inode_operations;
 extern const struct file_operations jffs2_file_operations;
 extern const struct inode_operations jffs2_file_inode_operations;
 extern const struct address_space_operations jffs2_file_address_operations;
-int jffs2_fsync(struct file *, struct dentry *, int);
+int jffs2_fsync(struct file *, int);
 int jffs2_do_readpage_unlock (struct inode *inode, struct page *pg);
 
 /* ioctl.c */
index eaccee05858357d1ceb82503010ff3481c07f835..239f51216a68ee6e9ec1f4dc156ff513b686bc85 100644 (file)
@@ -77,7 +77,7 @@ static size_t jffs2_security_listxattr(struct dentry *dentry, char *list,
        return retlen;
 }
 
-struct xattr_handler jffs2_security_xattr_handler = {
+const struct xattr_handler jffs2_security_xattr_handler = {
        .prefix = XATTR_SECURITY_PREFIX,
        .list = jffs2_security_listxattr,
        .set = jffs2_security_setxattr,
index 9e75c62c85d6c4005e7b4ae8bab7c9a18e69bec3..a2d58c96f1b455e55429415d0fc1497dceb9fcaa 100644 (file)
@@ -904,7 +904,7 @@ struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c,
  * do_jffs2_setxattr(inode, xprefix, xname, buffer, size, flags)
  *   is an implementation of setxattr handler on jffs2.
  * -------------------------------------------------- */
-struct xattr_handler *jffs2_xattr_handlers[] = {
+const struct xattr_handler *jffs2_xattr_handlers[] = {
        &jffs2_user_xattr_handler,
 #ifdef CONFIG_JFFS2_FS_SECURITY
        &jffs2_security_xattr_handler,
@@ -917,8 +917,8 @@ struct xattr_handler *jffs2_xattr_handlers[] = {
        NULL
 };
 
-static struct xattr_handler *xprefix_to_handler(int xprefix) {
-       struct xattr_handler *ret;
+static const struct xattr_handler *xprefix_to_handler(int xprefix) {
+       const struct xattr_handler *ret;
 
        switch (xprefix) {
        case JFFS2_XPREFIX_USER:
@@ -955,7 +955,7 @@ ssize_t jffs2_listxattr(struct dentry *dentry, char *buffer, size_t size)
        struct jffs2_inode_cache *ic = f->inocache;
        struct jffs2_xattr_ref *ref, **pref;
        struct jffs2_xattr_datum *xd;
-       struct xattr_handler *xhandle;
+       const struct xattr_handler *xhandle;
        ssize_t len, rc;
        int retry = 0;
 
index 6e3b5ddfb7ab01c0f3c133198dda659675a4654d..cf4f5759b42b407ba614d1c40fd67b9db511e01a 100644 (file)
@@ -93,9 +93,9 @@ extern int do_jffs2_getxattr(struct inode *inode, int xprefix, const char *xname
 extern int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname,
                             const char *buffer, size_t size, int flags);
 
-extern struct xattr_handler *jffs2_xattr_handlers[];
-extern struct xattr_handler jffs2_user_xattr_handler;
-extern struct xattr_handler jffs2_trusted_xattr_handler;
+extern const struct xattr_handler *jffs2_xattr_handlers[];
+extern const struct xattr_handler jffs2_user_xattr_handler;
+extern const struct xattr_handler jffs2_trusted_xattr_handler;
 
 extern ssize_t jffs2_listxattr(struct dentry *, char *, size_t);
 #define jffs2_getxattr         generic_getxattr
@@ -122,7 +122,7 @@ extern ssize_t jffs2_listxattr(struct dentry *, char *, size_t);
 
 #ifdef CONFIG_JFFS2_FS_SECURITY
 extern int jffs2_init_security(struct inode *inode, struct inode *dir);
-extern struct xattr_handler jffs2_security_xattr_handler;
+extern const struct xattr_handler jffs2_security_xattr_handler;
 #else
 #define jffs2_init_security(inode,dir) (0)
 #endif /* CONFIG_JFFS2_FS_SECURITY */
index 3e5a5e356e058f276bba8dc2f133be73c7a0bb72..1c868194c5045b7ef2399ba89206038ddf534419 100644 (file)
@@ -47,7 +47,7 @@ static size_t jffs2_trusted_listxattr(struct dentry *dentry, char *list,
        return retlen;
 }
 
-struct xattr_handler jffs2_trusted_xattr_handler = {
+const struct xattr_handler jffs2_trusted_xattr_handler = {
        .prefix = XATTR_TRUSTED_PREFIX,
        .list = jffs2_trusted_listxattr,
        .set = jffs2_trusted_setxattr,
index 8544af67dffe66b5f36dd5ebabec416a355a90bb..916b5c96603942b718759dbda4b54b72223679a1 100644 (file)
@@ -47,7 +47,7 @@ static size_t jffs2_user_listxattr(struct dentry *dentry, char *list,
        return retlen;
 }
 
-struct xattr_handler jffs2_user_xattr_handler = {
+const struct xattr_handler jffs2_user_xattr_handler = {
        .prefix = XATTR_USER_PREFIX,
        .list = jffs2_user_listxattr,
        .set = jffs2_user_setxattr,
index 85d9ec6592250231fd4c299fd7cabe3a7ec9049e..127263cc865715de2d3f42f6658320ac89a5106e 100644 (file)
@@ -27,9 +27,9 @@
 #include "jfs_acl.h"
 #include "jfs_debug.h"
 
-int jfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+int jfs_fsync(struct file *file, int datasync)
 {
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = file->f_mapping->host;
        int rc = 0;
 
        if (!(inode->i_state & I_DIRTY) ||
index 829921b677651b166c5d788ddff640d14d63944c..2686531e235ab0e484e50bbdca018a5a55ef4b1d 100644 (file)
@@ -98,14 +98,7 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
                goto fail_unlock;
        }
 
-       inode->i_uid = current_fsuid();
-       if (parent->i_mode & S_ISGID) {
-               inode->i_gid = parent->i_gid;
-               if (S_ISDIR(mode))
-                       mode |= S_ISGID;
-       } else
-               inode->i_gid = current_fsgid();
-
+       inode_init_owner(inode, parent, mode);
        /*
         * New inodes need to save sane values on disk when
         * uid & gid mount options are used
@@ -121,7 +114,6 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
        if (rc)
                goto fail_drop;
 
-       inode->i_mode = mode;
        /* inherit flags from parent */
        jfs_inode->mode2 = JFS_IP(parent)->mode2 & JFS_FL_INHERIT;
 
@@ -134,7 +126,7 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
                if (S_ISLNK(mode))
                        jfs_inode->mode2 &= ~(JFS_IMMUTABLE_FL|JFS_APPEND_FL);
        }
-       jfs_inode->mode2 |= mode;
+       jfs_inode->mode2 |= inode->i_mode;
 
        inode->i_blocks = 0;
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
index 9e6bda30a6e86671abc5b878cecc6c7441c7376d..11042b1f44b5fbd0e60f856e01595144d53213aa 100644 (file)
@@ -21,7 +21,7 @@
 struct fid;
 
 extern struct inode *ialloc(struct inode *, umode_t);
-extern int jfs_fsync(struct file *, struct dentry *, int);
+extern int jfs_fsync(struct file *, int);
 extern long jfs_ioctl(struct file *, unsigned int, unsigned long);
 extern long jfs_compat_ioctl(struct file *, unsigned int, unsigned long);
 extern struct inode *jfs_iget(struct super_block *, unsigned long);
index b66832ac33ac5d5869d90084227a321174e0b95d..b38f96bef8292ffe040eaa8b55b8f156bcad3702 100644 (file)
@@ -179,6 +179,8 @@ static void jfs_put_super(struct super_block *sb)
 
        jfs_info("In jfs_put_super");
 
+       dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);
+
        lock_kernel();
 
        rc = jfs_umount(sb);
@@ -396,10 +398,20 @@ static int jfs_remount(struct super_block *sb, int *flags, char *data)
 
                JFS_SBI(sb)->flag = flag;
                ret = jfs_mount_rw(sb, 1);
+
+               /* mark the fs r/w for quota activity */
+               sb->s_flags &= ~MS_RDONLY;
+
                unlock_kernel();
+               dquot_resume(sb, -1);
                return ret;
        }
        if ((!(sb->s_flags & MS_RDONLY)) && (*flags & MS_RDONLY)) {
+               rc = dquot_suspend(sb, -1);
+               if (rc < 0) {
+                       unlock_kernel();
+                       return rc;
+               }
                rc = jfs_umount_rw(sb);
                JFS_SBI(sb)->flag = flag;
                unlock_kernel();
@@ -469,6 +481,10 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
         */
        sb->s_op = &jfs_super_operations;
        sb->s_export_op = &jfs_export_operations;
+#ifdef CONFIG_QUOTA
+       sb->dq_op = &dquot_operations;
+       sb->s_qcop = &dquot_quotactl_ops;
+#endif
 
        /*
         * Initialize direct-mapping inode/address-space
index 232bea425b09155a1f116981e4e53283a1738bbc..09e1016eb774556c0e69a5a4129da275410565c5 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/slab.h>
 #include <linux/mount.h>
 #include <linux/vfs.h>
+#include <linux/quotaops.h>
 #include <linux/mutex.h>
 #include <linux/exportfs.h>
 #include <linux/writeback.h>
@@ -58,11 +59,6 @@ struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, struct na
        return NULL;
 }
 
-int simple_sync_file(struct file * file, struct dentry *dentry, int datasync)
-{
-       return 0;
-}
 int dcache_dir_open(struct inode *inode, struct file *file)
 {
        static struct qstr cursor_name = {.len = 1, .name = "."};
@@ -190,7 +186,7 @@ const struct file_operations simple_dir_operations = {
        .llseek         = dcache_dir_lseek,
        .read           = generic_read_dir,
        .readdir        = dcache_readdir,
-       .fsync          = simple_sync_file,
+       .fsync          = noop_fsync,
 };
 
 const struct inode_operations simple_dir_inode_operations = {
@@ -330,6 +326,81 @@ int simple_rename(struct inode *old_dir, struct dentry *old_dentry,
        return 0;
 }
 
+/**
+ * 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
+ * @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).
+ */
+int simple_setattr(struct dentry *dentry, struct iattr *iattr)
+{
+       struct inode *inode = dentry->d_inode;
+       int error;
+
+       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;
+}
+EXPORT_SYMBOL(simple_setattr);
+
 int simple_readpage(struct file *file, struct page *page)
 {
        clear_highpage(page);
@@ -851,13 +922,22 @@ struct dentry *generic_fh_to_parent(struct super_block *sb, struct fid *fid,
 }
 EXPORT_SYMBOL_GPL(generic_fh_to_parent);
 
-int simple_fsync(struct file *file, struct dentry *dentry, int datasync)
+/**
+ * generic_file_fsync - generic fsync implementation for simple filesystems
+ * @file:      file to synchronize
+ * @datasync:  only synchronize essential metadata if true
+ *
+ * This is a generic implementation of the fsync method for simple
+ * filesystems which track all non-inode metadata in the buffers list
+ * hanging off the address_space structure.
+ */
+int generic_file_fsync(struct file *file, int datasync)
 {
        struct writeback_control wbc = {
                .sync_mode = WB_SYNC_ALL,
                .nr_to_write = 0, /* metadata-only; caller takes care of data */
        };
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = file->f_mapping->host;
        int err;
        int ret;
 
@@ -872,7 +952,15 @@ int simple_fsync(struct file *file, struct dentry *dentry, int datasync)
                ret = err;
        return ret;
 }
-EXPORT_SYMBOL(simple_fsync);
+EXPORT_SYMBOL(generic_file_fsync);
+
+/*
+ * No-op implementation of ->fsync for in-memory filesystems.
+ */
+int noop_fsync(struct file *file, int datasync)
+{
+       return 0;
+}
 
 EXPORT_SYMBOL(dcache_dir_close);
 EXPORT_SYMBOL(dcache_dir_lseek);
@@ -895,7 +983,7 @@ EXPORT_SYMBOL(simple_release_fs);
 EXPORT_SYMBOL(simple_rename);
 EXPORT_SYMBOL(simple_rmdir);
 EXPORT_SYMBOL(simple_statfs);
-EXPORT_SYMBOL(simple_sync_file);
+EXPORT_SYMBOL(noop_fsync);
 EXPORT_SYMBOL(simple_unlink);
 EXPORT_SYMBOL(simple_read_from_buffer);
 EXPORT_SYMBOL(simple_write_to_buffer);
index 0de52407187042f9fd0a1a1d59049a0ce93c1b55..abe1cafbd4c263f4191217a591d3d5f4f258a841 100644 (file)
@@ -219,9 +219,9 @@ int logfs_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
        }
 }
 
-int logfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+int logfs_fsync(struct file *file, int datasync)
 {
-       struct super_block *sb = dentry->d_inode->i_sb;
+       struct super_block *sb = file->f_mapping->host->i_sb;
 
        logfs_write_anchor(sb);
        return 0;
index 755a92e8daa774b109d55b89346f09525552e160..f602e230e16282aa00d10c26c93b6c5cec0015ac 100644 (file)
@@ -358,14 +358,7 @@ struct inode *logfs_new_inode(struct inode *dir, int mode)
        inode->i_mode = mode;
        logfs_set_ino_generation(sb, inode);
 
-       inode->i_uid = current_fsuid();
-       inode->i_gid = current_fsgid();
-       if (dir->i_mode & S_ISGID) {
-               inode->i_gid = dir->i_gid;
-               if (S_ISDIR(mode))
-                       inode->i_mode |= S_ISGID;
-       }
-
+       inode_init_owner(inode, dir, mode);
        logfs_inode_setops(inode);
        insert_inode_hash(inode);
 
index 1a9db84f8d8fff266a2e43eb0a02fb2a567a8a38..c838c4d721110db6d1c99df7880b7ccedd0ba89f 100644 (file)
@@ -506,7 +506,7 @@ 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);
-int logfs_fsync(struct file *file, struct dentry *dentry, int datasync);
+int logfs_fsync(struct file *file, int datasync);
 
 /* gc.c */
 u32 get_best_cand(struct super_block *sb, struct candidate_list *list, u32 *ec);
index 6ac693faae494929ced6e7e8c2a77eb3559d1888..482779fe4e7cfc2e52104f0ae77815dbcf9de4ef 100644 (file)
@@ -221,7 +221,7 @@ void minix_free_inode(struct inode * inode)
        clear_inode(inode);             /* clear in-memory copy */
 }
 
-struct inode * minix_new_inode(const struct inode * dir, int * error)
+struct inode *minix_new_inode(const struct inode *dir, int mode, int *error)
 {
        struct super_block *sb = dir->i_sb;
        struct minix_sb_info *sbi = minix_sb(sb);
@@ -263,8 +263,7 @@ struct inode * minix_new_inode(const struct inode * dir, int * error)
                iput(inode);
                return NULL;
        }
-       inode->i_uid = current_fsuid();
-       inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current_fsgid();
+       inode_init_owner(inode, dir, mode);
        inode->i_ino = j;
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
        inode->i_blocks = 0;
index 6198731d7fcd4750132be0b77693bf91c91a7f29..91969589131c562d0dfaddc4d3f1905611262a23 100644 (file)
@@ -22,7 +22,7 @@ const struct file_operations minix_dir_operations = {
        .llseek         = generic_file_llseek,
        .read           = generic_read_dir,
        .readdir        = minix_readdir,
-       .fsync          = simple_fsync,
+       .fsync          = generic_file_fsync,
 };
 
 static inline void dir_put_page(struct page *page)
@@ -72,11 +72,8 @@ static struct page * dir_get_page(struct inode *dir, unsigned long n)
 {
        struct address_space *mapping = dir->i_mapping;
        struct page *page = read_mapping_page(mapping, n, NULL);
-       if (!IS_ERR(page)) {
+       if (!IS_ERR(page))
                kmap(page);
-               if (!PageUptodate(page))
-                       goto fail;
-       }
        return page;
 
 fail:
index 3eec3e607a87837415b21c1c383dad0ec8d711e8..d5320ff23faf28c38678cd12dfb25f1db24ca4d4 100644 (file)
@@ -19,7 +19,7 @@ const struct file_operations minix_file_operations = {
        .write          = do_sync_write,
        .aio_write      = generic_file_aio_write,
        .mmap           = generic_file_mmap,
-       .fsync          = simple_fsync,
+       .fsync          = generic_file_fsync,
        .splice_read    = generic_file_splice_read,
 };
 
index f2301096936923d3d17f01332484e7b2866e7b4f..13487ad168944e37eb8871161c3077d50b5a271c 100644 (file)
@@ -20,6 +20,9 @@ static inline block_t *i_data(struct inode *inode)
        return (block_t *)minix_i(inode)->u.i2_data;
 }
 
+#define DIRCOUNT 7
+#define INDIRCOUNT(sb) (1 << ((sb)->s_blocksize_bits - 2))
+
 static int block_to_path(struct inode * inode, long block, int offsets[DEPTH])
 {
        int n = 0;
@@ -34,21 +37,21 @@ static int block_to_path(struct inode * inode, long block, int offsets[DEPTH])
                        printk("MINIX-fs: block_to_path: "
                               "block %ld too big on dev %s\n",
                                block, bdevname(sb->s_bdev, b));
-       } else if (block < 7) {
+       } else if (block < DIRCOUNT) {
                offsets[n++] = block;
-       } else if ((block -= 7) < 256) {
-               offsets[n++] = 7;
+       } else if ((block -= DIRCOUNT) < INDIRCOUNT(sb)) {
+               offsets[n++] = DIRCOUNT;
                offsets[n++] = block;
-       } else if ((block -= 256) < 256*256) {
-               offsets[n++] = 8;
-               offsets[n++] = block>>8;
-               offsets[n++] = block & 255;
+       } else if ((block -= INDIRCOUNT(sb)) < INDIRCOUNT(sb) * INDIRCOUNT(sb)) {
+               offsets[n++] = DIRCOUNT + 1;
+               offsets[n++] = block / INDIRCOUNT(sb);
+               offsets[n++] = block % INDIRCOUNT(sb);
        } else {
-               block -= 256*256;
-               offsets[n++] = 9;
-               offsets[n++] = block>>16;
-               offsets[n++] = (block>>8) & 255;
-               offsets[n++] = block & 255;
+               block -= INDIRCOUNT(sb) * INDIRCOUNT(sb);
+               offsets[n++] = DIRCOUNT + 2;
+               offsets[n++] = (block / INDIRCOUNT(sb)) / INDIRCOUNT(sb);
+               offsets[n++] = (block / INDIRCOUNT(sb)) % INDIRCOUNT(sb);
+               offsets[n++] = block % INDIRCOUNT(sb);
        }
        return n;
 }
index 9dcf95b42116014b26d95aa2ba451ab205cd95cc..111f34ee9e3b09702f63a045e6ff555c4c1059f5 100644 (file)
@@ -46,7 +46,7 @@ struct minix_sb_info {
 extern struct inode *minix_iget(struct super_block *, unsigned long);
 extern struct minix_inode * minix_V1_raw_inode(struct super_block *, ino_t, struct buffer_head **);
 extern struct minix2_inode * minix_V2_raw_inode(struct super_block *, ino_t, struct buffer_head **);
-extern struct inode * minix_new_inode(const struct inode * dir, int * error);
+extern struct inode * minix_new_inode(const struct inode *, int, int *);
 extern void minix_free_inode(struct inode * inode);
 extern unsigned long minix_count_free_inodes(struct minix_sb_info *sbi);
 extern int minix_new_block(struct inode * inode);
index 32b131cd6121d2599d84ee60af29ceac261453d9..e20ee85955d1c77c3a410da2c82893cd38acce8e 100644 (file)
@@ -46,10 +46,9 @@ static int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, dev_
        if (!old_valid_dev(rdev))
                return -EINVAL;
 
-       inode = minix_new_inode(dir, &error);
+       inode = minix_new_inode(dir, mode, &error);
 
        if (inode) {
-               inode->i_mode = mode;
                minix_set_inode(inode, rdev);
                mark_inode_dirty(inode);
                error = add_nondir(dentry, inode);
@@ -73,11 +72,10 @@ static int minix_symlink(struct inode * dir, struct dentry *dentry,
        if (i > dir->i_sb->s_blocksize)
                goto out;
 
-       inode = minix_new_inode(dir, &err);
+       inode = minix_new_inode(dir, S_IFLNK | 0777, &err);
        if (!inode)
                goto out;
 
-       inode->i_mode = S_IFLNK | 0777;
        minix_set_inode(inode, 0);
        err = page_symlink(inode, symname, i);
        if (err)
@@ -117,13 +115,10 @@ static int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode)
 
        inode_inc_link_count(dir);
 
-       inode = minix_new_inode(dir, &err);
+       inode = minix_new_inode(dir, mode, &err);
        if (!inode)
                goto out_dir;
 
-       inode->i_mode = S_IFDIR | mode;
-       if (dir->i_mode & S_ISGID)
-               inode->i_mode |= S_ISGID;
        minix_set_inode(inode, 0);
 
        inode_inc_link_count(inode);
index b86b96fe1dc33926eb242a2a2e21061fe46145a5..868d0cb9d473a92ccdcbe640ac44f4daf24cce62 100644 (file)
@@ -523,9 +523,10 @@ static void path_put_conditional(struct path *path, struct nameidata *nd)
 static inline void path_to_nameidata(struct path *path, struct nameidata *nd)
 {
        dput(nd->path.dentry);
-       if (nd->path.mnt != path->mnt)
+       if (nd->path.mnt != path->mnt) {
                mntput(nd->path.mnt);
-       nd->path.mnt = path->mnt;
+               nd->path.mnt = path->mnt;
+       }
        nd->path.dentry = path->dentry;
 }
 
@@ -1620,6 +1621,7 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
        case LAST_DOTDOT:
                follow_dotdot(nd);
                dir = nd->path.dentry;
+       case LAST_DOT:
                if (nd->path.mnt->mnt_sb->s_type->fs_flags & FS_REVAL_DOT) {
                        if (!dir->d_op->d_revalidate(dir, nd)) {
                                error = -ESTALE;
@@ -1627,7 +1629,6 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
                        }
                }
                /* fallthrough */
-       case LAST_DOT:
        case LAST_ROOT:
                if (open_flag & O_CREAT)
                        goto exit;
index 7edfcd4d5e524b5ad1ace0f64a11f508437ef5c9..9578cbe0cd589ad00ce590d60172c2433d16688e 100644 (file)
@@ -49,9 +49,10 @@ extern int ncp_symlink(struct inode *, struct dentry *, const char *);
                      
 const struct file_operations ncp_dir_operations =
 {
+       .llseek         = generic_file_llseek,
        .read           = generic_read_dir,
        .readdir        = ncp_readdir,
-       .ioctl          = ncp_ioctl,
+       .unlocked_ioctl = ncp_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = ncp_compat_ioctl,
 #endif
index 1daabb90e0a54bba1a3c65146fb7098b3fdb8218..3639cc5cbdae58d8961308c77caf70f2535db579 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/ncp_fs.h>
 #include "ncplib_kernel.h"
 
-static int ncp_fsync(struct file *file, struct dentry *dentry, int datasync)
+static int ncp_fsync(struct file *file, int datasync)
 {
        return 0;
 }
@@ -295,7 +295,7 @@ const struct file_operations ncp_file_operations =
        .llseek         = ncp_remote_llseek,
        .read           = ncp_file_read,
        .write          = ncp_file_write,
-       .ioctl          = ncp_ioctl,
+       .unlocked_ioctl = ncp_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = ncp_compat_ioctl,
 #endif
index 60a5e2864ea8b9b97e41de53875480959e17400f..023c03d020707a88e5930b8d92d89ce2c5845d20 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/smp_lock.h>
 #include <linux/vmalloc.h>
 #include <linux/sched.h>
+#include <linux/smp_lock.h>
 
 #include <linux/ncp_fs.h>
 
@@ -261,9 +262,9 @@ ncp_get_charsets(struct ncp_server* server, struct ncp_nls_ioctl __user *arg)
 }
 #endif /* CONFIG_NCPFS_NLS */
 
-static int __ncp_ioctl(struct inode *inode, struct file *filp,
-             unsigned int cmd, unsigned long arg)
+static long __ncp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
+       struct inode *inode = filp->f_dentry->d_inode;
        struct ncp_server *server = NCP_SERVER(inode);
        int result;
        struct ncp_ioctl_request request;
@@ -841,11 +842,11 @@ static int ncp_ioctl_need_write(unsigned int cmd)
        }
 }
 
-int ncp_ioctl(struct inode *inode, struct file *filp,
-             unsigned int cmd, unsigned long arg)
+long ncp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
-       int ret;
+       long ret;
 
+       lock_kernel();
        if (ncp_ioctl_need_write(cmd)) {
                /*
                 * inside the ioctl(), any failures which
@@ -853,24 +854,28 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
                 * -EACCESS, so it seems consistent to keep
                 *  that here.
                 */
-               if (mnt_want_write(filp->f_path.mnt))
-                       return -EACCES;
+               if (mnt_want_write(filp->f_path.mnt)) {
+                       ret = -EACCES;
+                       goto out;
+               }
        }
-       ret = __ncp_ioctl(inode, filp, cmd, arg);
+       ret = __ncp_ioctl(filp, cmd, arg);
        if (ncp_ioctl_need_write(cmd))
                mnt_drop_write(filp->f_path.mnt);
+
+out:
+       unlock_kernel();
        return ret;
 }
 
 #ifdef CONFIG_COMPAT
 long ncp_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-       struct inode *inode = file->f_path.dentry->d_inode;
-       int ret;
+       long ret;
 
        lock_kernel();
        arg = (unsigned long) compat_ptr(arg);
-       ret = ncp_ioctl(inode, file, cmd, arg);
+       ret = ncp_ioctl(file, cmd, arg);
        unlock_kernel();
        return ret;
 }
index ee9a179ebdf3a83ae93dfc3c4ff40820aeafa6be..782b431ef91c9f521f18d5eeba5a33fbceb5b612 100644 (file)
@@ -53,7 +53,7 @@ static int nfs_link(struct dentry *, struct inode *, struct dentry *);
 static int nfs_mknod(struct inode *, struct dentry *, int, dev_t);
 static int nfs_rename(struct inode *, struct dentry *,
                      struct inode *, struct dentry *);
-static int nfs_fsync_dir(struct file *, struct dentry *, int);
+static int nfs_fsync_dir(struct file *, int);
 static loff_t nfs_llseek_dir(struct file *, loff_t, int);
 
 const struct file_operations nfs_dir_operations = {
@@ -641,8 +641,10 @@ out:
  * All directory operations under NFS are synchronous, so fsync()
  * is a dummy operation.
  */
-static int nfs_fsync_dir(struct file *filp, struct dentry *dentry, int datasync)
+static int nfs_fsync_dir(struct file *filp, int datasync)
 {
+       struct dentry *dentry = filp->f_path.dentry;
+
        dfprintk(FILE, "NFS: fsync dir(%s/%s) datasync %d\n",
                        dentry->d_parent->d_name.name, dentry->d_name.name,
                        datasync);
@@ -1741,6 +1743,7 @@ remove_lru_entry:
                        clear_bit(NFS_INO_ACL_LRU_SET, &nfsi->flags);
                        smp_mb__after_clear_bit();
                }
+               spin_unlock(&inode->i_lock);
        }
        spin_unlock(&nfs_access_lru_lock);
        nfs_access_free_list(&head);
index cac96bcc91e42f6f5a1fbf818f46254c2649e5fc..36a5e74f51b48ce00fdcb824874d7bcecdb7b8f0 100644 (file)
@@ -53,7 +53,7 @@ static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe,
 static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov,
                                unsigned long nr_segs, loff_t pos);
 static int  nfs_file_flush(struct file *, fl_owner_t id);
-static int  nfs_file_fsync(struct file *, struct dentry *dentry, int datasync);
+static int  nfs_file_fsync(struct file *, int datasync);
 static int nfs_check_flags(int flags);
 static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl);
 static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl);
@@ -322,8 +322,9 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
  * whether any write errors occurred for this process.
  */
 static int
-nfs_file_fsync(struct file *file, struct dentry *dentry, int datasync)
+nfs_file_fsync(struct file *file, int datasync)
 {
+       struct dentry *dentry = file->f_path.dentry;
        struct nfs_open_context *ctx = nfs_file_open_context(file);
        struct inode *inode = dentry->d_inode;
 
index 2f8b1157daa2cf279d4e5562300e250c3bec6c9e..04214fc5c30457ea290a2a15e0f87a5f184aea65 100644 (file)
@@ -1060,7 +1060,7 @@ static int nfs_parse_mount_options(char *raw,
                                goto out_nomem;
                        rc = strict_strtoul(string, 10, &option);
                        kfree(string);
-                       if (rc != 0 || option > USHORT_MAX)
+                       if (rc != 0 || option > USHRT_MAX)
                                goto out_invalid_value;
                        mnt->nfs_server.port = option;
                        break;
@@ -1181,7 +1181,7 @@ static int nfs_parse_mount_options(char *raw,
                                goto out_nomem;
                        rc = strict_strtoul(string, 10, &option);
                        kfree(string);
-                       if (rc != 0 || option > USHORT_MAX)
+                       if (rc != 0 || option > USHRT_MAX)
                                goto out_invalid_value;
                        mnt->mount_server.port = option;
                        break;
index 3aea3ca98ab788c5dae67c0769ff723eb9b94217..91679e2631ee0ebaff79cd96fd6e3019ca5a49d8 100644 (file)
@@ -1386,7 +1386,7 @@ static int nfs_commit_inode(struct inode *inode, int how)
        int res = 0;
 
        if (!nfs_commit_set_lock(NFS_I(inode), may_wait))
-               goto out;
+               goto out_mark_dirty;
        spin_lock(&inode->i_lock);
        res = nfs_scan_commit(inode, &head, 0, 0);
        spin_unlock(&inode->i_lock);
@@ -1398,9 +1398,18 @@ static int nfs_commit_inode(struct inode *inode, int how)
                        wait_on_bit(&NFS_I(inode)->flags, NFS_INO_COMMIT,
                                        nfs_wait_bit_killable,
                                        TASK_KILLABLE);
+               else
+                       goto out_mark_dirty;
        } else
                nfs_commit_clear_lock(NFS_I(inode));
-out:
+       return res;
+       /* Note: If we exit without ensuring that the commit is complete,
+        * we must mark the inode as dirty. Otherwise, future calls to
+        * sync_inode() with the WB_SYNC_ALL flag set will fail to ensure
+        * that the data is on the disk.
+        */
+out_mark_dirty:
+       __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
        return res;
 }
 
@@ -1509,14 +1518,17 @@ int nfs_wb_page(struct inode *inode, struct page *page)
        };
        int ret;
 
-       while(PagePrivate(page)) {
+       for (;;) {
                wait_on_page_writeback(page);
                if (clear_page_dirty_for_io(page)) {
                        ret = nfs_writepage_locked(page, &wbc);
                        if (ret < 0)
                                goto out_error;
+                       continue;
                }
-               ret = sync_inode(inode, &wbc);
+               if (!PagePrivate(page))
+                       break;
+               ret = nfs_commit_inode(inode, FLUSH_SYNC);
                if (ret < 0)
                        goto out_error;
        }
index 7a9ae3254a4b2f858bce392ed5f719ae2ef126e7..7e26caab2a262befd2c74af594d076e0ebb40121 100644 (file)
@@ -44,8 +44,7 @@
 #define NFSDDBG_FACILITY                NFSDDBG_PROC
 
 /* Globals */
-static struct path rec_dir;
-static int rec_dir_init = 0;
+static struct file *rec_file;
 
 static int
 nfs4_save_creds(const struct cred **original_creds)
@@ -117,33 +116,28 @@ out_no_tfm:
        return status;
 }
 
-static void
-nfsd4_sync_rec_dir(void)
-{
-       vfs_fsync(NULL, rec_dir.dentry, 0);
-}
-
 int
 nfsd4_create_clid_dir(struct nfs4_client *clp)
 {
        const struct cred *original_cred;
        char *dname = clp->cl_recdir;
-       struct dentry *dentry;
+       struct dentry *dir, *dentry;
        int status;
 
        dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname);
 
-       if (!rec_dir_init || clp->cl_firststate)
+       if (!rec_file || clp->cl_firststate)
                return 0;
 
        status = nfs4_save_creds(&original_cred);
        if (status < 0)
                return status;
 
+       dir = rec_file->f_path.dentry;
        /* lock the parent */
-       mutex_lock(&rec_dir.dentry->d_inode->i_mutex);
+       mutex_lock(&dir->d_inode->i_mutex);
 
-       dentry = lookup_one_len(dname, rec_dir.dentry, HEXDIR_LEN-1);
+       dentry = lookup_one_len(dname, dir, HEXDIR_LEN-1);
        if (IS_ERR(dentry)) {
                status = PTR_ERR(dentry);
                goto out_unlock;
@@ -153,18 +147,18 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
                dprintk("NFSD: nfsd4_create_clid_dir: DIRECTORY EXISTS\n");
                goto out_put;
        }
-       status = mnt_want_write(rec_dir.mnt);
+       status = mnt_want_write(rec_file->f_path.mnt);
        if (status)
                goto out_put;
-       status = vfs_mkdir(rec_dir.dentry->d_inode, dentry, S_IRWXU);
-       mnt_drop_write(rec_dir.mnt);
+       status = vfs_mkdir(dir->d_inode, dentry, S_IRWXU);
+       mnt_drop_write(rec_file->f_path.mnt);
 out_put:
        dput(dentry);
 out_unlock:
-       mutex_unlock(&rec_dir.dentry->d_inode->i_mutex);
+       mutex_unlock(&dir->d_inode->i_mutex);
        if (status == 0) {
                clp->cl_firststate = 1;
-               nfsd4_sync_rec_dir();
+               vfs_fsync(rec_file, 0);
        }
        nfs4_reset_creds(original_cred);
        dprintk("NFSD: nfsd4_create_clid_dir returns %d\n", status);
@@ -206,14 +200,14 @@ nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f)
        struct dentry *dentry;
        int status;
 
-       if (!rec_dir_init)
+       if (!rec_file)
                return 0;
 
        status = nfs4_save_creds(&original_cred);
        if (status < 0)
                return status;
 
-       filp = dentry_open(dget(dir), mntget(rec_dir.mnt), O_RDONLY,
+       filp = dentry_open(dget(dir), mntget(rec_file->f_path.mnt), O_RDONLY,
                           current_cred());
        status = PTR_ERR(filp);
        if (IS_ERR(filp))
@@ -250,13 +244,14 @@ out:
 static int
 nfsd4_unlink_clid_dir(char *name, int namlen)
 {
-       struct dentry *dentry;
+       struct dentry *dir, *dentry;
        int status;
 
        dprintk("NFSD: nfsd4_unlink_clid_dir. name %.*s\n", namlen, name);
 
-       mutex_lock_nested(&rec_dir.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
-       dentry = lookup_one_len(name, rec_dir.dentry, namlen);
+       dir = rec_file->f_path.dentry;
+       mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
+       dentry = lookup_one_len(name, dir, namlen);
        if (IS_ERR(dentry)) {
                status = PTR_ERR(dentry);
                goto out_unlock;
@@ -264,11 +259,11 @@ nfsd4_unlink_clid_dir(char *name, int namlen)
        status = -ENOENT;
        if (!dentry->d_inode)
                goto out;
-       status = vfs_rmdir(rec_dir.dentry->d_inode, dentry);
+       status = vfs_rmdir(dir->d_inode, dentry);
 out:
        dput(dentry);
 out_unlock:
-       mutex_unlock(&rec_dir.dentry->d_inode->i_mutex);
+       mutex_unlock(&dir->d_inode->i_mutex);
        return status;
 }
 
@@ -278,10 +273,10 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp)
        const struct cred *original_cred;
        int status;
 
-       if (!rec_dir_init || !clp->cl_firststate)
+       if (!rec_file || !clp->cl_firststate)
                return;
 
-       status = mnt_want_write(rec_dir.mnt);
+       status = mnt_want_write(rec_file->f_path.mnt);
        if (status)
                goto out;
        clp->cl_firststate = 0;
@@ -293,8 +288,8 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp)
        status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1);
        nfs4_reset_creds(original_cred);
        if (status == 0)
-               nfsd4_sync_rec_dir();
-       mnt_drop_write(rec_dir.mnt);
+               vfs_fsync(rec_file, 0);
+       mnt_drop_write(rec_file->f_path.mnt);
 out:
        if (status)
                printk("NFSD: Failed to remove expired client state directory"
@@ -323,19 +318,19 @@ void
 nfsd4_recdir_purge_old(void) {
        int status;
 
-       if (!rec_dir_init)
+       if (!rec_file)
                return;
-       status = mnt_want_write(rec_dir.mnt);
+       status = mnt_want_write(rec_file->f_path.mnt);
        if (status)
                goto out;
-       status = nfsd4_list_rec_dir(rec_dir.dentry, purge_old);
+       status = nfsd4_list_rec_dir(rec_file->f_path.dentry, purge_old);
        if (status == 0)
-               nfsd4_sync_rec_dir();
-       mnt_drop_write(rec_dir.mnt);
+               vfs_fsync(rec_file, 0);
+       mnt_drop_write(rec_file->f_path.mnt);
 out:
        if (status)
                printk("nfsd4: failed to purge old clients from recovery"
-                       " directory %s\n", rec_dir.dentry->d_name.name);
+                       " directory %s\n", rec_file->f_path.dentry->d_name.name);
 }
 
 static int
@@ -355,10 +350,13 @@ int
 nfsd4_recdir_load(void) {
        int status;
 
-       status = nfsd4_list_rec_dir(rec_dir.dentry, load_recdir);
+       if (!rec_file)
+               return 0;
+
+       status = nfsd4_list_rec_dir(rec_file->f_path.dentry, load_recdir);
        if (status)
                printk("nfsd4: failed loading clients from recovery"
-                       " directory %s\n", rec_dir.dentry->d_name.name);
+                       " directory %s\n", rec_file->f_path.dentry->d_name.name);
        return status;
 }
 
@@ -375,7 +373,7 @@ nfsd4_init_recdir(char *rec_dirname)
        printk("NFSD: Using %s as the NFSv4 state recovery directory\n",
                        rec_dirname);
 
-       BUG_ON(rec_dir_init);
+       BUG_ON(rec_file);
 
        status = nfs4_save_creds(&original_cred);
        if (status < 0) {
@@ -385,22 +383,21 @@ nfsd4_init_recdir(char *rec_dirname)
                return;
        }
 
-       status = kern_path(rec_dirname, LOOKUP_FOLLOW | LOOKUP_DIRECTORY,
-                       &rec_dir);
-       if (status)
+       rec_file = filp_open(rec_dirname, O_RDONLY | O_DIRECTORY, 0);
+       if (IS_ERR(rec_file)) {
                printk("NFSD: unable to find recovery directory %s\n",
                                rec_dirname);
+               rec_file = NULL;
+       }
 
-       if (!status)
-               rec_dir_init = 1;
        nfs4_reset_creds(original_cred);
 }
 
 void
 nfsd4_shutdown_recdir(void)
 {
-       if (!rec_dir_init)
+       if (!rec_file)
                return;
-       rec_dir_init = 0;
-       path_put(&rec_dir);
+       fput(rec_file);
+       rec_file = NULL;
 }
index bc3194ea01f531aac10b52d59a363f1f8369ac0b..508941c23af7fa425864eed3d3a173cd8a4a4474 100644 (file)
@@ -998,7 +998,7 @@ static ssize_t __write_ports_addxprt(char *buf)
        if (sscanf(buf, "%15s %4u", transport, &port) != 2)
                return -EINVAL;
 
-       if (port < 1 || port > USHORT_MAX)
+       if (port < 1 || port > USHRT_MAX)
                return -EINVAL;
 
        err = nfsd_create_serv();
@@ -1040,7 +1040,7 @@ static ssize_t __write_ports_delxprt(char *buf)
        if (sscanf(&buf[1], "%15s %4u", transport, &port) != 2)
                return -EINVAL;
 
-       if (port < 1 || port > USHORT_MAX || nfsd_serv == NULL)
+       if (port < 1 || port > USHRT_MAX || nfsd_serv == NULL)
                return -EINVAL;
 
        xprt = svc_find_xprt(nfsd_serv, transport, AF_UNSPEC, port);
index 23c06f77f4cab11b9ccc775698bd6c9cd1111e80..ebbf3b6b24577128c3182072d34933770d56e644 100644 (file)
@@ -999,7 +999,7 @@ static int wait_for_concurrent_writes(struct file *file)
 
        if (inode->i_state & I_DIRTY) {
                dprintk("nfsd: write sync %d\n", task_pid_nr(current));
-               err = vfs_fsync(file, file->f_path.dentry, 0);
+               err = vfs_fsync(file, 0);
        }
        last_ino = inode->i_ino;
        last_dev = inode->i_sb->s_dev;
@@ -1175,8 +1175,7 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
        if (err)
                goto out;
        if (EX_ISSYNC(fhp->fh_export)) {
-               int err2 = vfs_fsync_range(file, file->f_path.dentry,
-                               offset, end, 0);
+               int err2 = vfs_fsync_range(file, offset, end, 0);
 
                if (err2 != -EINVAL)
                        err = nfserrno(err2);
index 30292df443cea081b6b4c94690f41aaf8cad01ec..c9a30d7ff6fc340f1b8df37ba03e6e5441f6a5af 100644 (file)
@@ -27,7 +27,7 @@
 #include "nilfs.h"
 #include "segment.h"
 
-int nilfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
+int nilfs_sync_file(struct file *file, int datasync)
 {
        /*
         * Called from fsync() system call
@@ -37,7 +37,7 @@ int nilfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
         * This function should be implemented when the writeback function
         * will be implemented.
         */
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = file->f_mapping->host;
        int err;
 
        if (!nilfs_inode_dirty(inode))
index 5e226d4b41d386661b454bedb6bd22ef25837f6f..39e038ac8fcbaf18b9611ac3f29a751b798d2b4f 100644 (file)
@@ -280,16 +280,7 @@ struct inode *nilfs_new_inode(struct inode *dir, int mode)
        /* reference count of i_bh inherits from nilfs_mdt_read_block() */
 
        atomic_inc(&sbi->s_inodes_count);
-
-       inode->i_uid = current_fsuid();
-       if (dir->i_mode & S_ISGID) {
-               inode->i_gid = dir->i_gid;
-               if (S_ISDIR(mode))
-                       mode |= S_ISGID;
-       } else
-               inode->i_gid = current_fsgid();
-
-       inode->i_mode = mode;
+       inode_init_owner(inode, dir, mode);
        inode->i_ino = ino;
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 
index 8723e5bfd0717921ccbcfa526ed874d5eea2b8ea..47d6d7928122b7049b409c4eb8ca0c48e3bb8512 100644 (file)
@@ -228,7 +228,7 @@ extern void nilfs_set_link(struct inode *, struct nilfs_dir_entry *,
                           struct page *, struct inode *);
 
 /* file.c */
-extern int nilfs_sync_file(struct file *, struct dentry *, int);
+extern int nilfs_sync_file(struct file *, int);
 
 /* ioctl.c */
 long nilfs_ioctl(struct file *, unsigned int, unsigned long);
index 40b1cf914ccb592adf37d0760360d083b171ea7a..27b75ebc7460947806315124517519119ac4c53b 100644 (file)
@@ -110,14 +110,10 @@ EXPORT_SYMBOL_GPL(get_inotify_watch);
 int pin_inotify_watch(struct inotify_watch *watch)
 {
        struct super_block *sb = watch->inode->i_sb;
-       spin_lock(&sb_lock);
-       if (sb->s_count >= S_BIAS) {
-               atomic_inc(&sb->s_active);
-               spin_unlock(&sb_lock);
+       if (atomic_inc_not_zero(&sb->s_active)) {
                atomic_inc(&watch->count);
                return 1;
        }
-       spin_unlock(&sb_lock);
        return 0;
 }
 
@@ -515,34 +511,8 @@ EXPORT_SYMBOL_GPL(inotify_init_watch);
  * 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 almost certainly wait until the superblock is shut
- * down and the watch in question is pining for fjords.  That's fine, but
- * there is a problem - we might have hit the window between ->s_active
- * getting to 0 / ->s_count - below S_BIAS (i.e. the moment when superblock
- * is past the point of no return and is heading for shutdown) and the
- * moment when deactivate_super() acquires ->s_umount.  We could just do
- * drop_super() yield() and retry, but that's rather antisocial and this
- * stuff is luser-triggerable.  OTOH, having grabbed ->s_umount and having
- * found that we'd got there first (i.e. that ->s_root is non-NULL) we know
- * that we won't race with inotify_umount_inodes().  So we could grab a
- * reference to watch and do the rest as above, just with drop_super() instead
- * of deactivate_super(), right?  Wrong.  We had to drop ih->mutex before we
- * could grab ->s_umount.  So the watch could've been gone already.
- *
- * That still can be dealt with - we need to save watch->wd, do idr_find()
- * and compare its result with our pointer.  If they match, we either have
- * the damn thing still alive or we'd lost not one but two races at once,
- * the watch had been killed and a new one got created with the same ->wd
- * at the same address.  That couldn't have happened in inotify_destroy(),
- * but inotify_rm_wd() could run into that.  Still, "new one got created"
- * is not a problem - we have every right to kill it or leave it alone,
- * whatever's more convenient.
- *
- * So we can use idr_find(...) == watch && watch->inode->i_sb == sb as
- * "grab it and kill it" check.  If it's been our original watch, we are
- * fine, if it's a newcomer - nevermind, just pretend that we'd won the
- * race and kill the fscker anyway; we are safe since we know that its
- * superblock won't be going away.
+ * ->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.
@@ -556,57 +526,31 @@ EXPORT_SYMBOL_GPL(inotify_init_watch);
  * 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()
- * 2 - remove it, drop the reference and drop_super(); we tried hard to avoid
- * that variant, since it involved a lot of PITA, but that's the best that
- * could've been done.
  */
 static int pin_to_kill(struct inotify_handle *ih, struct inotify_watch *watch)
 {
        struct super_block *sb = watch->inode->i_sb;
-       s32 wd = watch->wd;
 
-       spin_lock(&sb_lock);
-       if (sb->s_count >= S_BIAS) {
-               atomic_inc(&sb->s_active);
-               spin_unlock(&sb_lock);
+       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);
-       if (likely(!sb->s_root)) {
-               /* fs is already shut down; the watch is dead */
-               drop_super(sb);
-               return 0;
-       }
-       /* raced with the final deactivate_super() */
-       mutex_lock(&ih->mutex);
-       if (idr_find(&ih->idr, wd) != watch || watch->inode->i_sb != sb) {
-               /* the watch is dead */
-               mutex_unlock(&ih->mutex);
-               drop_super(sb);
-               return 0;
-       }
-       /* still alive or freed and reused with the same sb and wd; kill */
-       get_inotify_watch(watch);
-       mutex_unlock(&ih->mutex);
-       return 2;
+       /* fs is already shut down; the watch is dead */
+       drop_super(sb);
+       return 0;
 }
 
-static void unpin_and_kill(struct inotify_watch *watch, int how)
+static void unpin_and_kill(struct inotify_watch *watch)
 {
        struct super_block *sb = watch->inode->i_sb;
        put_inotify_watch(watch);
-       switch (how) {
-       case 1:
-               deactivate_super(sb);
-               break;
-       case 2:
-               drop_super(sb);
-       }
+       deactivate_super(sb);
 }
 
 /**
@@ -628,7 +572,6 @@ void inotify_destroy(struct inotify_handle *ih)
                struct list_head *watches;
                struct super_block *sb;
                struct inode *inode;
-               int how;
 
                mutex_lock(&ih->mutex);
                watches = &ih->watches;
@@ -638,8 +581,7 @@ void inotify_destroy(struct inotify_handle *ih)
                }
                watch = list_first_entry(watches, struct inotify_watch, h_list);
                sb = watch->inode->i_sb;
-               how = pin_to_kill(ih, watch);
-               if (!how)
+               if (!pin_to_kill(ih, watch))
                        continue;
 
                inode = watch->inode;
@@ -654,7 +596,7 @@ void inotify_destroy(struct inotify_handle *ih)
 
                mutex_unlock(&ih->mutex);
                mutex_unlock(&inode->inotify_mutex);
-               unpin_and_kill(watch, how);
+               unpin_and_kill(watch);
        }
 
        /* free this handle: the put matching the get in inotify_init() */
@@ -857,7 +799,6 @@ int inotify_rm_wd(struct inotify_handle *ih, u32 wd)
        struct inotify_watch *watch;
        struct super_block *sb;
        struct inode *inode;
-       int how;
 
        mutex_lock(&ih->mutex);
        watch = idr_find(&ih->idr, wd);
@@ -866,8 +807,7 @@ int inotify_rm_wd(struct inotify_handle *ih, u32 wd)
                return -EINVAL;
        }
        sb = watch->inode->i_sb;
-       how = pin_to_kill(ih, watch);
-       if (!how)
+       if (!pin_to_kill(ih, watch))
                return 0;
 
        inode = watch->inode;
@@ -881,7 +821,7 @@ int inotify_rm_wd(struct inotify_handle *ih, u32 wd)
 
        mutex_unlock(&ih->mutex);
        mutex_unlock(&inode->inotify_mutex);
-       unpin_and_kill(watch, how);
+       unpin_and_kill(watch);
 
        return 0;
 }
index fe44d3feee4a1b06222600e6028abfca4d5c0df0..0f48e7c5d9e1a7d35fad15b6231107ee5bf7100b 100644 (file)
@@ -1527,10 +1527,9 @@ static int ntfs_dir_open(struct inode *vi, struct file *filp)
  * this problem for now.  We do write the $BITMAP attribute if it is present
  * which is the important one for a directory so things are not too bad.
  */
-static int ntfs_dir_fsync(struct file *filp, struct dentry *dentry,
-               int datasync)
+static int ntfs_dir_fsync(struct file *filp, int datasync)
 {
-       struct inode *bmp_vi, *vi = dentry->d_inode;
+       struct inode *bmp_vi, *vi = filp->f_mapping->host;
        int err, ret;
        ntfs_attr na;
 
index 8804f093ba7512d309f6b94e7080cb0eb561ef74..113ebd9f25a47ea2c0527c67ef07906e37475b78 100644 (file)
@@ -98,9 +98,6 @@ static int ntfs_file_open(struct inode *vi, struct file *filp)
  * the page at all.  For a more detailed explanation see ntfs_truncate() in
  * fs/ntfs/inode.c.
  *
- * @cached_page and @lru_pvec are just optimizations for dealing with multiple
- * pages.
- *
  * Return 0 on success and -errno on error.  In the case that an error is
  * encountered it is possible that the initialized size will already have been
  * incremented some way towards @new_init_size but it is guaranteed that if
@@ -110,8 +107,7 @@ static int ntfs_file_open(struct inode *vi, struct file *filp)
  * Locking: i_mutex on the vfs inode corrseponsind to the ntfs inode @ni must be
  *         held by the caller.
  */
-static int ntfs_attr_extend_initialized(ntfs_inode *ni, const s64 new_init_size,
-               struct page **cached_page, struct pagevec *lru_pvec)
+static int ntfs_attr_extend_initialized(ntfs_inode *ni, const s64 new_init_size)
 {
        s64 old_init_size;
        loff_t old_i_size;
@@ -403,18 +399,13 @@ static inline void ntfs_fault_in_pages_readable_iovec(const struct iovec *iov,
  * Obtain @nr_pages locked page cache pages from the mapping @mapping and
  * starting at index @index.
  *
- * If a page is newly created, increment its refcount and add it to the
- * caller's lru-buffering pagevec @lru_pvec.
- *
- * This is the same as mm/filemap.c::__grab_cache_page(), except that @nr_pages
- * are obtained at once instead of just one page and that 0 is returned on
- * success and -errno on error.
+ * If a page is newly created, add it to lru list
  *
  * Note, the page locks are obtained in ascending page index order.
  */
 static inline int __ntfs_grab_cache_pages(struct address_space *mapping,
                pgoff_t index, const unsigned nr_pages, struct page **pages,
-               struct page **cached_page, struct pagevec *lru_pvec)
+               struct page **cached_page)
 {
        int err, nr;
 
@@ -430,7 +421,7 @@ static inline int __ntfs_grab_cache_pages(struct address_space *mapping,
                                        goto err_out;
                                }
                        }
-                       err = add_to_page_cache(*cached_page, mapping, index,
+                       err = add_to_page_cache_lru(*cached_page, mapping, index,
                                        GFP_KERNEL);
                        if (unlikely(err)) {
                                if (err == -EEXIST)
@@ -438,9 +429,6 @@ static inline int __ntfs_grab_cache_pages(struct address_space *mapping,
                                goto err_out;
                        }
                        pages[nr] = *cached_page;
-                       page_cache_get(*cached_page);
-                       if (unlikely(!pagevec_add(lru_pvec, *cached_page)))
-                               __pagevec_lru_add_file(lru_pvec);
                        *cached_page = NULL;
                }
                index++;
@@ -1800,7 +1788,6 @@ static ssize_t ntfs_file_buffered_write(struct kiocb *iocb,
        ssize_t status, written;
        unsigned nr_pages;
        int err;
-       struct pagevec lru_pvec;
 
        ntfs_debug("Entering for i_ino 0x%lx, attribute type 0x%x, "
                        "pos 0x%llx, count 0x%lx.",
@@ -1912,7 +1899,6 @@ static ssize_t ntfs_file_buffered_write(struct kiocb *iocb,
                        }
                }
        }
-       pagevec_init(&lru_pvec, 0);
        written = 0;
        /*
         * If the write starts beyond the initialized size, extend it up to the
@@ -1925,8 +1911,7 @@ static ssize_t ntfs_file_buffered_write(struct kiocb *iocb,
        ll = ni->initialized_size;
        read_unlock_irqrestore(&ni->size_lock, flags);
        if (pos > ll) {
-               err = ntfs_attr_extend_initialized(ni, pos, &cached_page,
-                               &lru_pvec);
+               err = ntfs_attr_extend_initialized(ni, pos);
                if (err < 0) {
                        ntfs_error(vol->sb, "Cannot perform write to inode "
                                        "0x%lx, attribute type 0x%x, because "
@@ -2012,7 +1997,7 @@ static ssize_t ntfs_file_buffered_write(struct kiocb *iocb,
                        ntfs_fault_in_pages_readable_iovec(iov, iov_ofs, bytes);
                /* Get and lock @do_pages starting at index @start_idx. */
                status = __ntfs_grab_cache_pages(mapping, start_idx, do_pages,
-                               pages, &cached_page, &lru_pvec);
+                               pages, &cached_page);
                if (unlikely(status))
                        break;
                /*
@@ -2077,7 +2062,6 @@ err_out:
        *ppos = pos;
        if (cached_page)
                page_cache_release(cached_page);
-       pagevec_lru_add_file(&lru_pvec);
        ntfs_debug("Done.  Returning %s (written 0x%lx, status %li).",
                        written ? "written" : "status", (unsigned long)written,
                        (long)status);
@@ -2149,7 +2133,6 @@ static ssize_t ntfs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
 /**
  * ntfs_file_fsync - sync a file to disk
  * @filp:      file to be synced
- * @dentry:    dentry describing the file to sync
  * @datasync:  if non-zero only flush user data and not metadata
  *
  * Data integrity sync of a file to disk.  Used for fsync, fdatasync, and msync
@@ -2165,19 +2148,15 @@ static ssize_t ntfs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
  * Also, if @datasync is true, we do not wait on the inode to be written out
  * but we always wait on the page cache pages to be written out.
  *
- * Note: In the past @filp could be NULL so we ignore it as we don't need it
- * anyway.
- *
  * Locking: Caller must hold i_mutex on the inode.
  *
  * TODO: We should probably also write all attribute/index inodes associated
  * with this inode but since we have no simple way of getting to them we ignore
  * this problem for now.
  */
-static int ntfs_file_fsync(struct file *filp, struct dentry *dentry,
-               int datasync)
+static int ntfs_file_fsync(struct file *filp, int datasync)
 {
-       struct inode *vi = dentry->d_inode;
+       struct inode *vi = filp->f_mapping->host;
        int err, ret = 0;
 
        ntfs_debug("Entering for inode 0x%lx.", vi->i_ino);
index e13fc9e8fcdc02bc55964f673b51d228cb6811cc..da702294d7e75b1e995fcd0c73a6562e264a3561 100644 (file)
@@ -489,7 +489,7 @@ cleanup:
        return ret;
 }
 
-struct xattr_handler ocfs2_xattr_acl_access_handler = {
+const struct xattr_handler ocfs2_xattr_acl_access_handler = {
        .prefix = POSIX_ACL_XATTR_ACCESS,
        .flags  = ACL_TYPE_ACCESS,
        .list   = ocfs2_xattr_list_acl_access,
@@ -497,7 +497,7 @@ struct xattr_handler ocfs2_xattr_acl_access_handler = {
        .set    = ocfs2_xattr_set_acl,
 };
 
-struct xattr_handler ocfs2_xattr_acl_default_handler = {
+const struct xattr_handler ocfs2_xattr_acl_default_handler = {
        .prefix = POSIX_ACL_XATTR_DEFAULT,
        .flags  = ACL_TYPE_DEFAULT,
        .list   = ocfs2_xattr_list_acl_default,
index b7428c5d0d3b54f9eceac8460c73e4a098a45a67..ec6d123395932b69b6a67ba0b5256be02b811c6f 100644 (file)
@@ -403,7 +403,7 @@ void ocfs2_block_check_compute(void *data, size_t blocksize,
         * No ecc'd ocfs2 structure is larger than 4K, so ecc will be no
         * larger than 16 bits.
         */
-       BUG_ON(ecc > USHORT_MAX);
+       BUG_ON(ecc > USHRT_MAX);
 
        bc->bc_crc32e = cpu_to_le32(crc);
        bc->bc_ecc = cpu_to_le16((u16)ecc);
@@ -508,7 +508,7 @@ void ocfs2_block_check_compute_bhs(struct buffer_head **bhs, int nr,
         * No ecc'd ocfs2 structure is larger than 4K, so ecc will be no
         * larger than 16 bits.
         */
-       BUG_ON(ecc > USHORT_MAX);
+       BUG_ON(ecc > USHRT_MAX);
 
        bc->bc_crc32e = cpu_to_le32(crc);
        bc->bc_ecc = cpu_to_le16((u16)ecc);
index 97e54b9e654bbb05526fe077138d26c131019174..6a13ea64c44773fc239ad55a5237422ddee18e94 100644 (file)
@@ -175,13 +175,12 @@ static int ocfs2_dir_release(struct inode *inode, struct file *file)
        return 0;
 }
 
-static int ocfs2_sync_file(struct file *file,
-                          struct dentry *dentry,
-                          int datasync)
+static int ocfs2_sync_file(struct file *file, int datasync)
 {
        int err = 0;
        journal_t *journal;
-       struct inode *inode = dentry->d_inode;
+       struct dentry *dentry = file->f_path.dentry;
+       struct inode *inode = file->f_mapping->host;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 
        mlog_entry("(0x%p, 0x%p, %d, '%.*s')\n", file, dentry, datasync,
@@ -1053,7 +1052,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
        }
 
        /*
-        * This will intentionally not wind up calling vmtruncate(),
+        * This will intentionally not wind up calling simple_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
@@ -2119,9 +2118,13 @@ relock:
                         * direct 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.
+                        *
+                        * XXX(hch): 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)
-                               vmtruncate(inode, inode->i_size);
+                               simple_setsize(inode, inode->i_size);
                        ret = written;
                        goto out_dio;
                }
index db5dd3ed4df4a5553d7cc7179bbf3a48232825d4..f171b51a74f78d6e268b5d743a24df4e702f9643 100644 (file)
@@ -204,14 +204,7 @@ static struct inode *ocfs2_get_init_inode(struct inode *dir, int mode)
                inode->i_nlink = 2;
        else
                inode->i_nlink = 1;
-       inode->i_uid = current_fsuid();
-       if (dir->i_mode & S_ISGID) {
-               inode->i_gid = dir->i_gid;
-               if (S_ISDIR(mode))
-                       mode |= S_ISGID;
-       } else
-               inode->i_gid = current_fsgid();
-       inode->i_mode = mode;
+       inode_init_owner(inode, dir, mode);
        dquot_initialize(inode);
        return inode;
 }
index 2c26ce251cb3c3910ef887ef5e3e38d42ab3f392..0eaa929a4dbf2cec50d059affc8c664bf9a1f1d2 100644 (file)
@@ -879,13 +879,15 @@ static int ocfs2_susp_quotas(struct ocfs2_super *osb, int unsuspend)
                if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, feature[type]))
                        continue;
                if (unsuspend)
-                       status = vfs_quota_enable(
-                                       sb_dqopt(sb)->files[type],
-                                       type, QFMT_OCFS2,
-                                       DQUOT_SUSPENDED);
-               else
-                       status = vfs_quota_disable(sb, type,
-                                                  DQUOT_SUSPENDED);
+                       status = dquot_resume(sb, type);
+               else {
+                       struct ocfs2_mem_dqinfo *oinfo;
+
+                       /* Cancel periodic syncing before suspending */
+                       oinfo = sb_dqinfo(sb, type)->dqi_priv;
+                       cancel_delayed_work_sync(&oinfo->dqi_sync_work);
+                       status = dquot_suspend(sb, type);
+               }
                if (status < 0)
                        break;
        }
@@ -916,8 +918,8 @@ static int ocfs2_enable_quotas(struct ocfs2_super *osb)
                        status = -ENOENT;
                        goto out_quota_off;
                }
-               status = vfs_quota_enable(inode[type], type, QFMT_OCFS2,
-                                               DQUOT_USAGE_ENABLED);
+               status = dquot_enable(inode[type], type, QFMT_OCFS2,
+                                     DQUOT_USAGE_ENABLED);
                if (status < 0)
                        goto out_quota_off;
        }
@@ -952,8 +954,8 @@ static void ocfs2_disable_quotas(struct ocfs2_super *osb)
                /* Turn off quotas. This will remove all dquot structures from
                 * memory and so they will be automatically synced to global
                 * quota files */
-               vfs_quota_disable(sb, type, DQUOT_USAGE_ENABLED |
-                                           DQUOT_LIMITS_ENABLED);
+               dquot_disable(sb, type, DQUOT_USAGE_ENABLED |
+                                       DQUOT_LIMITS_ENABLED);
                if (!inode)
                        continue;
                iput(inode);
@@ -962,7 +964,7 @@ static void ocfs2_disable_quotas(struct ocfs2_super *osb)
 
 /* Handle quota on quotactl */
 static int ocfs2_quota_on(struct super_block *sb, int type, int format_id,
-                         char *path, int remount)
+                         char *path)
 {
        unsigned int feature[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA,
                                             OCFS2_FEATURE_RO_COMPAT_GRPQUOTA};
@@ -970,30 +972,24 @@ static int ocfs2_quota_on(struct super_block *sb, int type, int format_id,
        if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, feature[type]))
                return -EINVAL;
 
-       if (remount)
-               return 0;       /* Just ignore it has been handled in
-                                * ocfs2_remount() */
-       return vfs_quota_enable(sb_dqopt(sb)->files[type], type,
-                                   format_id, DQUOT_LIMITS_ENABLED);
+       return dquot_enable(sb_dqopt(sb)->files[type], type,
+                           format_id, DQUOT_LIMITS_ENABLED);
 }
 
 /* Handle quota off quotactl */
-static int ocfs2_quota_off(struct super_block *sb, int type, int remount)
+static int ocfs2_quota_off(struct super_block *sb, int type)
 {
-       if (remount)
-               return 0;       /* Ignore now and handle later in
-                                * ocfs2_remount() */
-       return vfs_quota_disable(sb, type, DQUOT_LIMITS_ENABLED);
+       return dquot_disable(sb, type, DQUOT_LIMITS_ENABLED);
 }
 
 static const struct quotactl_ops ocfs2_quotactl_ops = {
        .quota_on       = ocfs2_quota_on,
        .quota_off      = ocfs2_quota_off,
-       .quota_sync     = vfs_quota_sync,
-       .get_info       = vfs_get_dqinfo,
-       .set_info       = vfs_set_dqinfo,
-       .get_dqblk      = vfs_get_dqblk,
-       .set_dqblk      = vfs_set_dqblk,
+       .quota_sync     = dquot_quota_sync,
+       .get_info       = dquot_get_dqinfo,
+       .set_info       = dquot_set_dqinfo,
+       .get_dqblk      = dquot_get_dqblk,
+       .set_dqblk      = dquot_set_dqblk,
 };
 
 static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
index 98ee6c44102d398b935229604e3c7bf4a86bbbf8..e97b34842cfea0d188f85476a56c4a0eb0af5ce0 100644 (file)
@@ -97,7 +97,7 @@ static struct ocfs2_xattr_def_value_root def_xv = {
        .xv.xr_list.l_count = cpu_to_le16(1),
 };
 
-struct xattr_handler *ocfs2_xattr_handlers[] = {
+const struct xattr_handler *ocfs2_xattr_handlers[] = {
        &ocfs2_xattr_user_handler,
        &ocfs2_xattr_acl_access_handler,
        &ocfs2_xattr_acl_default_handler,
@@ -106,7 +106,7 @@ struct xattr_handler *ocfs2_xattr_handlers[] = {
        NULL
 };
 
-static struct xattr_handler *ocfs2_xattr_handler_map[OCFS2_XATTR_MAX] = {
+static const struct xattr_handler *ocfs2_xattr_handler_map[OCFS2_XATTR_MAX] = {
        [OCFS2_XATTR_INDEX_USER]        = &ocfs2_xattr_user_handler,
        [OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS]
                                        = &ocfs2_xattr_acl_access_handler,
@@ -540,7 +540,7 @@ static int ocfs2_read_xattr_block(struct inode *inode, u64 xb_blkno,
 
 static inline const char *ocfs2_xattr_prefix(int name_index)
 {
-       struct xattr_handler *handler = NULL;
+       const struct xattr_handler *handler = NULL;
 
        if (name_index > 0 && name_index < OCFS2_XATTR_MAX)
                handler = ocfs2_xattr_handler_map[name_index];
@@ -7213,7 +7213,7 @@ int ocfs2_init_security_set(handle_t *handle,
                                     xattr_ac, data_ac);
 }
 
-struct xattr_handler ocfs2_xattr_security_handler = {
+const struct xattr_handler ocfs2_xattr_security_handler = {
        .prefix = XATTR_SECURITY_PREFIX,
        .list   = ocfs2_xattr_security_list,
        .get    = ocfs2_xattr_security_get,
@@ -7257,7 +7257,7 @@ static int ocfs2_xattr_trusted_set(struct dentry *dentry, const char *name,
                               name, value, size, flags);
 }
 
-struct xattr_handler ocfs2_xattr_trusted_handler = {
+const struct xattr_handler ocfs2_xattr_trusted_handler = {
        .prefix = XATTR_TRUSTED_PREFIX,
        .list   = ocfs2_xattr_trusted_list,
        .get    = ocfs2_xattr_trusted_get,
@@ -7313,7 +7313,7 @@ static int ocfs2_xattr_user_set(struct dentry *dentry, const char *name,
                               name, value, size, flags);
 }
 
-struct xattr_handler ocfs2_xattr_user_handler = {
+const struct xattr_handler ocfs2_xattr_user_handler = {
        .prefix = XATTR_USER_PREFIX,
        .list   = ocfs2_xattr_user_list,
        .get    = ocfs2_xattr_user_get,
index abd72a47f5209b31809f1c51b74bb1f3f93175be..aa64bb37a65bd73a61d8f61e6ba6fd970f67686e 100644 (file)
@@ -37,12 +37,12 @@ struct ocfs2_security_xattr_info {
        size_t value_len;
 };
 
-extern struct xattr_handler ocfs2_xattr_user_handler;
-extern struct xattr_handler ocfs2_xattr_trusted_handler;
-extern struct xattr_handler ocfs2_xattr_security_handler;
-extern struct xattr_handler ocfs2_xattr_acl_access_handler;
-extern struct xattr_handler ocfs2_xattr_acl_default_handler;
-extern struct xattr_handler *ocfs2_xattr_handlers[];
+extern const struct xattr_handler ocfs2_xattr_user_handler;
+extern const struct xattr_handler ocfs2_xattr_trusted_handler;
+extern const struct xattr_handler ocfs2_xattr_security_handler;
+extern const struct xattr_handler ocfs2_xattr_acl_access_handler;
+extern const struct xattr_handler ocfs2_xattr_acl_default_handler;
+extern const struct xattr_handler *ocfs2_xattr_handlers[];
 
 ssize_t ocfs2_listxattr(struct dentry *, char *, size_t);
 int ocfs2_xattr_get_nolock(struct inode *, struct buffer_head *, int,
index 399487c093646a86ea910756d127d53e4e813668..6e7a3291bbe8df21a5b5213939e757a9333c6917 100644 (file)
@@ -329,7 +329,7 @@ const struct file_operations omfs_file_operations = {
        .aio_read = generic_file_aio_read,
        .aio_write = generic_file_aio_write,
        .mmap = generic_file_mmap,
-       .fsync = simple_fsync,
+       .fsync = generic_file_fsync,
        .splice_read = generic_file_splice_read,
 };
 
index b44bb835e8eaa3e8767193fe0a1296d3ee7eefde..089839a6cc6404e46715df5543d4be0d9162c702 100644 (file)
@@ -37,9 +37,7 @@ struct inode *omfs_new_inode(struct inode *dir, int mode)
                goto fail;
 
        inode->i_ino = new_block;
-       inode->i_mode = mode;
-       inode->i_uid = current_fsuid();
-       inode->i_gid = current_fsgid();
+       inode_init_owner(inode, NULL, mode);
        inode->i_mapping->a_ops = &omfs_aops;
 
        inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
index 74e5cd9f718e8b43eb17e8dad2f28074591fbaaf..5463266db9e6312d906082073733c2a04440b40b 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -17,7 +17,6 @@
 #include <linux/securebits.h>
 #include <linux/security.h>
 #include <linux/mount.h>
-#include <linux/vfs.h>
 #include <linux/fcntl.h>
 #include <linux/slab.h>
 #include <asm/uaccess.h>
 
 #include "internal.h"
 
-int vfs_statfs(struct dentry *dentry, struct kstatfs *buf)
-{
-       int retval = -ENODEV;
-
-       if (dentry) {
-               retval = -ENOSYS;
-               if (dentry->d_sb->s_op->statfs) {
-                       memset(buf, 0, sizeof(*buf));
-                       retval = security_sb_statfs(dentry);
-                       if (retval)
-                               return retval;
-                       retval = dentry->d_sb->s_op->statfs(dentry, buf);
-                       if (retval == 0 && buf->f_frsize == 0)
-                               buf->f_frsize = buf->f_bsize;
-               }
-       }
-       return retval;
-}
-
-EXPORT_SYMBOL(vfs_statfs);
-
-static int vfs_statfs_native(struct dentry *dentry, struct statfs *buf)
-{
-       struct kstatfs st;
-       int retval;
-
-       retval = vfs_statfs(dentry, &st);
-       if (retval)
-               return retval;
-
-       if (sizeof(*buf) == sizeof(st))
-               memcpy(buf, &st, sizeof(st));
-       else {
-               if (sizeof buf->f_blocks == 4) {
-                       if ((st.f_blocks | st.f_bfree | st.f_bavail |
-                            st.f_bsize | st.f_frsize) &
-                           0xffffffff00000000ULL)
-                               return -EOVERFLOW;
-                       /*
-                        * f_files and f_ffree may be -1; it's okay to stuff
-                        * that into 32 bits
-                        */
-                       if (st.f_files != -1 &&
-                           (st.f_files & 0xffffffff00000000ULL))
-                               return -EOVERFLOW;
-                       if (st.f_ffree != -1 &&
-                           (st.f_ffree & 0xffffffff00000000ULL))
-                               return -EOVERFLOW;
-               }
-
-               buf->f_type = st.f_type;
-               buf->f_bsize = st.f_bsize;
-               buf->f_blocks = st.f_blocks;
-               buf->f_bfree = st.f_bfree;
-               buf->f_bavail = st.f_bavail;
-               buf->f_files = st.f_files;
-               buf->f_ffree = st.f_ffree;
-               buf->f_fsid = st.f_fsid;
-               buf->f_namelen = st.f_namelen;
-               buf->f_frsize = st.f_frsize;
-               memset(buf->f_spare, 0, sizeof(buf->f_spare));
-       }
-       return 0;
-}
-
-static int vfs_statfs64(struct dentry *dentry, struct statfs64 *buf)
-{
-       struct kstatfs st;
-       int retval;
-
-       retval = vfs_statfs(dentry, &st);
-       if (retval)
-               return retval;
-
-       if (sizeof(*buf) == sizeof(st))
-               memcpy(buf, &st, sizeof(st));
-       else {
-               buf->f_type = st.f_type;
-               buf->f_bsize = st.f_bsize;
-               buf->f_blocks = st.f_blocks;
-               buf->f_bfree = st.f_bfree;
-               buf->f_bavail = st.f_bavail;
-               buf->f_files = st.f_files;
-               buf->f_ffree = st.f_ffree;
-               buf->f_fsid = st.f_fsid;
-               buf->f_namelen = st.f_namelen;
-               buf->f_frsize = st.f_frsize;
-               memset(buf->f_spare, 0, sizeof(buf->f_spare));
-       }
-       return 0;
-}
-
-SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, buf)
-{
-       struct path path;
-       int error;
-
-       error = user_path(pathname, &path);
-       if (!error) {
-               struct statfs tmp;
-               error = vfs_statfs_native(path.dentry, &tmp);
-               if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
-                       error = -EFAULT;
-               path_put(&path);
-       }
-       return error;
-}
-
-SYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct statfs64 __user *, buf)
-{
-       struct path path;
-       long error;
-
-       if (sz != sizeof(*buf))
-               return -EINVAL;
-       error = user_path(pathname, &path);
-       if (!error) {
-               struct statfs64 tmp;
-               error = vfs_statfs64(path.dentry, &tmp);
-               if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
-                       error = -EFAULT;
-               path_put(&path);
-       }
-       return error;
-}
-
-SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf)
-{
-       struct file * file;
-       struct statfs tmp;
-       int error;
-
-       error = -EBADF;
-       file = fget(fd);
-       if (!file)
-               goto out;
-       error = vfs_statfs_native(file->f_path.dentry, &tmp);
-       if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
-               error = -EFAULT;
-       fput(file);
-out:
-       return error;
-}
-
-SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user *, buf)
-{
-       struct file * file;
-       struct statfs64 tmp;
-       int error;
-
-       if (sz != sizeof(*buf))
-               return -EINVAL;
-
-       error = -EBADF;
-       file = fget(fd);
-       if (!file)
-               goto out;
-       error = vfs_statfs64(file->f_path.dentry, &tmp);
-       if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
-               error = -EFAULT;
-       fput(file);
-out:
-       return error;
-}
-
 int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
        struct file *filp)
 {
index 9e346c19bbbaf8ef1ed3995b40d54719d261c799..9efb2cfe2410338914108bbc0f0abb20a61781a0 100644 (file)
@@ -626,7 +626,7 @@ int efi_partition(struct parsed_partitions *state)
                /* If this is a RAID volume, tell md */
                if (!efi_guidcmp(ptes[i].partition_type_guid,
                                 PARTITION_LINUX_RAID_GUID))
-                       state->parts[i+1].flags = 1;
+                       state->parts[i + 1].flags = ADDPART_FLAG_RAID;
        }
        kfree(ptes);
        kfree(gpt);
index 3ceca05b668cad1ac8d25578486dd676faa0fad1..648c9d8f33571489f36efde827c15fe0e67c3b5d 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/slab.h>
 #include <linux/pagemap.h>
 #include <linux/stringify.h>
+#include <linux/kernel.h>
 #include "ldm.h"
 #include "check.h"
 #include "msdos.h"
@@ -77,17 +78,16 @@ static int ldm_parse_hexbyte (const u8 *src)
        int h;
 
        /* high part */
-       if      ((x = src[0] - '0') <= '9'-'0') h = x;
-       else if ((x = src[0] - 'a') <= 'f'-'a') h = x+10;
-       else if ((x = src[0] - 'A') <= 'F'-'A') h = x+10;
-       else return -1;
-       h <<= 4;
+       x = h = hex_to_bin(src[0]);
+       if (h < 0)
+               return -1;
 
        /* low part */
-       if ((x = src[1] - '0') <= '9'-'0') return h | x;
-       if ((x = src[1] - 'a') <= 'f'-'a') return h | (x+10);
-       if ((x = src[1] - 'A') <= 'F'-'A') return h | (x+10);
-       return -1;
+       h = hex_to_bin(src[1]);
+       if (h < 0)
+               return -1;
+
+       return (x << 4) + h;
 }
 
 /**
index 13e27b0082f27bb743a4589e2265dcaa65c8fec8..74465ff7c263488bb7d64d486bc77512a7946966 100644 (file)
@@ -75,7 +75,7 @@ int mac_partition(struct parsed_partitions *state)
                        be32_to_cpu(part->block_count) * (secsize/512));
 
                if (!strnicmp(part->type, "Linux_RAID", 10))
-                       state->parts[slot].flags = 1;
+                       state->parts[slot].flags = ADDPART_FLAG_RAID;
 #ifdef CONFIG_PPC_PMAC
                /*
                 * If this is the first bootable partition, tell the
index 645a68d8c0553cfc6826c4e019869c88bd60776b..15bfb7b1e04480470e389a075f9a3c155111d6aa 100644 (file)
@@ -498,7 +498,7 @@ int msdos_partition(struct parsed_partitions *state)
                }
                put_partition(state, slot, start, size);
                if (SYS_IND(p) == LINUX_RAID_PARTITION)
-                       state->parts[slot].flags = 1;
+                       state->parts[slot].flags = ADDPART_FLAG_RAID;
                if (SYS_IND(p) == DM6_PARTITION)
                        printk("[DM]");
                if (SYS_IND(p) == EZD_PARTITION)
index d79872eba09a56a03ade25f28a9d9cc8c8b86cb8..60da077400f1ddcc7c97abf3bc524912cc22c579 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -1169,14 +1169,18 @@ long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg)
 
        switch (cmd) {
        case F_SETPIPE_SZ:
-               if (!capable(CAP_SYS_ADMIN) && arg > pipe_max_pages)
-                       return -EINVAL;
+               if (!capable(CAP_SYS_ADMIN) && arg > pipe_max_pages) {
+                       ret = -EINVAL;
+                       goto out;
+               }
                /*
                 * The pipe needs to be at least 2 pages large to
                 * guarantee POSIX behaviour.
                 */
-               if (arg < 2)
-                       return -EINVAL;
+               if (arg < 2) {
+                       ret = -EINVAL;
+                       goto out;
+               }
                ret = pipe_set_size(pipe, arg);
                break;
        case F_GETPIPE_SZ:
@@ -1187,6 +1191,7 @@ long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg)
                break;
        }
 
+out:
        mutex_unlock(&pipe->inode->i_mutex);
        return ret;
 }
index 885ab5513ac5cfe10e18c4fba149ddf478252f40..9b58d38bc911e27faccc7ed9ffb2c53f0885df4a 100644 (file)
@@ -267,7 +267,7 @@ static inline void task_sig(struct seq_file *m, struct task_struct *p)
                shpending = p->signal->shared_pending.signal;
                blocked = p->blocked;
                collect_sigign_sigcatch(p, &ignored, &caught);
-               num_threads = atomic_read(&p->signal->count);
+               num_threads = get_nr_threads(p);
                rcu_read_lock();  /* FIXME: is this correct? */
                qsize = atomic_read(&__task_cred(p)->user->sigpending);
                rcu_read_unlock();
@@ -410,7 +410,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
                        tty_nr = new_encode_dev(tty_devnum(sig->tty));
                }
 
-               num_threads = atomic_read(&sig->count);
+               num_threads = get_nr_threads(task);
                collect_sigign_sigcatch(task, &sigign, &sigcatch);
 
                cmin_flt = sig->cmin_flt;
index c7f9f23449dc402a16ff1b36eb817fe63f02a779..acb7ef80ea4fcc4987b0b2159f70d599f659c31e 100644 (file)
@@ -166,18 +166,6 @@ static int get_fs_path(struct task_struct *task, struct path *path, bool root)
        return result;
 }
 
-static int get_nr_threads(struct task_struct *tsk)
-{
-       unsigned long flags;
-       int count = 0;
-
-       if (lock_task_sighand(tsk, &flags)) {
-               count = atomic_read(&tsk->signal->count);
-               unlock_task_sighand(tsk, &flags);
-       }
-       return count;
-}
-
 static int proc_cwd_link(struct inode *inode, struct path *path)
 {
        struct task_struct *task = get_proc_task(inode);
@@ -2444,7 +2432,7 @@ static struct dentry *proc_base_instantiate(struct inode *dir,
        const struct pid_entry *p = ptr;
        struct inode *inode;
        struct proc_inode *ei;
-       struct dentry *error = ERR_PTR(-EINVAL);
+       struct dentry *error;
 
        /* Allocate the inode */
        error = ERR_PTR(-ENOMEM);
@@ -2794,7 +2782,7 @@ out:
 
 struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
 {
-       struct dentry *result = ERR_PTR(-ENOENT);
+       struct dentry *result;
        struct task_struct *task;
        unsigned tgid;
        struct pid_namespace *ns;
index 43c127490606d1a3ab3c47bee8309b92176d5f3c..2791907744edffdc25719cebe93f15b0d0e23242 100644 (file)
@@ -343,21 +343,6 @@ static DEFINE_SPINLOCK(proc_inum_lock); /* protects the above */
 /*
  * Return an inode number between PROC_DYNAMIC_FIRST and
  * 0xffffffff, or zero on failure.
- *
- * Current inode allocations in the proc-fs (hex-numbers):
- *
- * 00000000            reserved
- * 00000001-00000fff   static entries  (goners)
- *      001            root-ino
- *
- * 00001000-00001fff   unused
- * 0001xxxx-7fffxxxx   pid-dir entries for pid 1-7fff
- * 80000000-efffffff   unused
- * f0000000-ffffffff   dynamic entries
- *
- * Goal:
- *     Once we split the thing into several virtual filesystems,
- *     we will get rid of magical ranges (and this comment, BTW).
  */
 static unsigned int get_inode_number(void)
 {
index c837a77351beb933e8c8f4d2a7e356fcfb48b823..6f37c391468d168ebcc5d1f366e244163f504f88 100644 (file)
@@ -588,7 +588,7 @@ static struct kcore_list kcore_text;
  */
 static void __init proc_kcore_text_init(void)
 {
-       kclist_add(&kcore_text, _stext, _end - _stext, KCORE_TEXT);
+       kclist_add(&kcore_text, _text, _end - _text, KCORE_TEXT);
 }
 #else
 static void __init proc_kcore_text_init(void)
index 757c069f2a65132584272d3fc1ccd22ea012d737..4258384ed22d9afa22fe579dd7c4242039e8ab8e 100644 (file)
@@ -110,7 +110,6 @@ void __init proc_root_init(void)
        if (err)
                return;
        proc_mnt = kern_mount_data(&proc_fs_type, &init_pid_ns);
-       err = PTR_ERR(proc_mnt);
        if (IS_ERR(proc_mnt)) {
                unregister_filesystem(&proc_fs_type);
                return;
index 47f5b145f56eee5aaefc3b52aac8fa78b978b692..aea1d3f1ffb5e761471f90a2f80096ac16031c62 100644 (file)
@@ -634,6 +634,7 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
        return err;
 }
 
+#ifdef CONFIG_HUGETLB_PAGE
 static u64 huge_pte_to_pagemap_entry(pte_t pte, int offset)
 {
        u64 pme = 0;
@@ -664,6 +665,7 @@ static int pagemap_hugetlb_range(pte_t *pte, unsigned long hmask,
 
        return err;
 }
+#endif /* HUGETLB_PAGE */
 
 /*
  * /proc/pid/pagemap - an array mapping virtual pages to pfns
@@ -733,7 +735,9 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
 
        pagemap_walk.pmd_entry = pagemap_pte_range;
        pagemap_walk.pte_hole = pagemap_pte_hole;
+#ifdef CONFIG_HUGETLB_PAGE
        pagemap_walk.hugetlb_entry = pagemap_hugetlb_range;
+#endif
        pagemap_walk.mm = mm;
        pagemap_walk.private = &pm;
 
index 6f30c3d5bcbfbfe5923f3cccc3223c9c4d3bba68..6e8fc62b40a8c4142351ebc5c23a958c9d9b412e 100644 (file)
@@ -77,9 +77,10 @@ out:
 
 const struct file_operations qnx4_dir_operations =
 {
+       .llseek         = generic_file_llseek,
        .read           = generic_read_dir,
        .readdir        = qnx4_readdir,
-       .fsync          = simple_fsync,
+       .fsync          = generic_file_fsync,
 };
 
 const struct inode_operations qnx4_dir_inode_operations =
index 655a4c52b8c30036a63f8b73857006c97f16de14..12c233da1b6b77e6c06d80b1bd18dbca93b65c78 100644 (file)
@@ -228,10 +228,6 @@ static struct hlist_head *dquot_hash;
 
 struct dqstats dqstats;
 EXPORT_SYMBOL(dqstats);
-#ifdef CONFIG_SMP
-struct dqstats *dqstats_pcpu;
-EXPORT_SYMBOL(dqstats_pcpu);
-#endif
 
 static qsize_t inode_get_rsv_space(struct inode *inode);
 static void __dquot_initialize(struct inode *inode, int type);
@@ -584,7 +580,7 @@ out:
 }
 EXPORT_SYMBOL(dquot_scan_active);
 
-int vfs_quota_sync(struct super_block *sb, int type, int wait)
+int dquot_quota_sync(struct super_block *sb, int type, int wait)
 {
        struct list_head *dirty;
        struct dquot *dquot;
@@ -656,7 +652,7 @@ int vfs_quota_sync(struct super_block *sb, int type, int wait)
 
        return 0;
 }
-EXPORT_SYMBOL(vfs_quota_sync);
+EXPORT_SYMBOL(dquot_quota_sync);
 
 /* Free unused dquots from cache */
 static void prune_dqcache(int count)
@@ -676,27 +672,10 @@ static void prune_dqcache(int count)
        }
 }
 
-static int dqstats_read(unsigned int type)
-{
-       int count = 0;
-#ifdef CONFIG_SMP
-       int cpu;
-       for_each_possible_cpu(cpu)
-               count += per_cpu_ptr(dqstats_pcpu, cpu)->stat[type];
-       /* Statistics reading is racy, but absolute accuracy isn't required */
-       if (count < 0)
-               count = 0;
-#else
-       count = dqstats.stat[type];
-#endif
-       return count;
-}
-
 /*
  * This is called from kswapd when we think we need some
  * more memory
  */
-
 static int shrink_dqcache_memory(int nr, gfp_t gfp_mask)
 {
        if (nr) {
@@ -704,7 +683,9 @@ static int shrink_dqcache_memory(int nr, gfp_t gfp_mask)
                prune_dqcache(nr);
                spin_unlock(&dq_list_lock);
        }
-       return (dqstats_read(DQST_FREE_DQUOTS)/100) * sysctl_vfs_cache_pressure;
+       return ((unsigned)
+               percpu_counter_read_positive(&dqstats.counter[DQST_FREE_DQUOTS])
+               /100) * sysctl_vfs_cache_pressure;
 }
 
 static struct shrinker dqcache_shrinker = {
@@ -1514,11 +1495,13 @@ static void inode_decr_space(struct inode *inode, qsize_t number, int reserve)
 /*
  * This operation can block, but only after everything is updated
  */
-int __dquot_alloc_space(struct inode *inode, qsize_t number,
-               int warn, int reserve)
+int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags)
 {
        int cnt, ret = 0;
        char warntype[MAXQUOTAS];
+       int warn = flags & DQUOT_SPACE_WARN;
+       int reserve = flags & DQUOT_SPACE_RESERVE;
+       int nofail = flags & DQUOT_SPACE_NOFAIL;
 
        /*
         * First test before acquiring mutex - solves deadlocks when we
@@ -1539,7 +1522,7 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number,
                        continue;
                ret = check_bdq(inode->i_dquot[cnt], number, !warn,
                                warntype+cnt);
-               if (ret) {
+               if (ret && !nofail) {
                        spin_unlock(&dq_data_lock);
                        goto out_flush_warn;
                }
@@ -1638,10 +1621,11 @@ EXPORT_SYMBOL(dquot_claim_space_nodirty);
 /*
  * This operation can block, but only after everything is updated
  */
-void __dquot_free_space(struct inode *inode, qsize_t number, int reserve)
+void __dquot_free_space(struct inode *inode, qsize_t number, int flags)
 {
        unsigned int cnt;
        char warntype[MAXQUOTAS];
+       int reserve = flags & DQUOT_SPACE_RESERVE;
 
        /* First test before acquiring mutex - solves deadlocks when we
          * re-enter the quota code and are already holding the mutex */
@@ -1812,7 +1796,7 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
        if (iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid)
                transfer_to[USRQUOTA] = dqget(sb, iattr->ia_uid, USRQUOTA);
        if (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)
-               transfer_to[GRPQUOTA] = dqget(sb, iattr->ia_uid, GRPQUOTA);
+               transfer_to[GRPQUOTA] = dqget(sb, iattr->ia_gid, GRPQUOTA);
 
        ret = __dquot_transfer(inode, transfer_to);
        dqput_all(transfer_to);
@@ -1847,6 +1831,7 @@ const struct dquot_operations dquot_operations = {
        .alloc_dquot    = dquot_alloc,
        .destroy_dquot  = dquot_destroy,
 };
+EXPORT_SYMBOL(dquot_operations);
 
 /*
  * Generic helper for ->open on filesystems supporting disk quotas.
@@ -1865,7 +1850,7 @@ EXPORT_SYMBOL(dquot_file_open);
 /*
  * Turn quota off on a device. type == -1 ==> quotaoff for all types (umount)
  */
-int vfs_quota_disable(struct super_block *sb, int type, unsigned int flags)
+int dquot_disable(struct super_block *sb, int type, unsigned int flags)
 {
        int cnt, ret = 0;
        struct quota_info *dqopt = sb_dqopt(sb);
@@ -1995,14 +1980,15 @@ put_inodes:
                }
        return ret;
 }
-EXPORT_SYMBOL(vfs_quota_disable);
+EXPORT_SYMBOL(dquot_disable);
 
-int vfs_quota_off(struct super_block *sb, int type, int remount)
+int dquot_quota_off(struct super_block *sb, int type)
 {
-       return vfs_quota_disable(sb, type, remount ? DQUOT_SUSPENDED :
-                                (DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED));
+       return dquot_disable(sb, type,
+                            DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);
 }
-EXPORT_SYMBOL(vfs_quota_off);
+EXPORT_SYMBOL(dquot_quota_off);
+
 /*
  *     Turn quotas on on a device
  */
@@ -2120,36 +2106,43 @@ out_fmt:
 }
 
 /* Reenable quotas on remount RW */
-static int vfs_quota_on_remount(struct super_block *sb, int type)
+int dquot_resume(struct super_block *sb, int type)
 {
        struct quota_info *dqopt = sb_dqopt(sb);
        struct inode *inode;
-       int ret;
+       int ret = 0, cnt;
        unsigned int flags;
 
-       mutex_lock(&dqopt->dqonoff_mutex);
-       if (!sb_has_quota_suspended(sb, type)) {
+       for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+               if (type != -1 && cnt != type)
+                       continue;
+
+               mutex_lock(&dqopt->dqonoff_mutex);
+               if (!sb_has_quota_suspended(sb, cnt)) {
+                       mutex_unlock(&dqopt->dqonoff_mutex);
+                       continue;
+               }
+               inode = dqopt->files[cnt];
+               dqopt->files[cnt] = NULL;
+               spin_lock(&dq_state_lock);
+               flags = dqopt->flags & dquot_state_flag(DQUOT_USAGE_ENABLED |
+                                                       DQUOT_LIMITS_ENABLED,
+                                                       cnt);
+               dqopt->flags &= ~dquot_state_flag(DQUOT_STATE_FLAGS, cnt);
+               spin_unlock(&dq_state_lock);
                mutex_unlock(&dqopt->dqonoff_mutex);
-               return 0;
-       }
-       inode = dqopt->files[type];
-       dqopt->files[type] = NULL;
-       spin_lock(&dq_state_lock);
-       flags = dqopt->flags & dquot_state_flag(DQUOT_USAGE_ENABLED |
-                                               DQUOT_LIMITS_ENABLED, type);
-       dqopt->flags &= ~dquot_state_flag(DQUOT_STATE_FLAGS, type);
-       spin_unlock(&dq_state_lock);
-       mutex_unlock(&dqopt->dqonoff_mutex);
 
-       flags = dquot_generic_flag(flags, type);
-       ret = vfs_load_quota_inode(inode, type, dqopt->info[type].dqi_fmt_id,
-                                  flags);
-       iput(inode);
+               flags = dquot_generic_flag(flags, cnt);
+               ret = vfs_load_quota_inode(inode, cnt,
+                               dqopt->info[cnt].dqi_fmt_id, flags);
+               iput(inode);
+       }
 
        return ret;
 }
+EXPORT_SYMBOL(dquot_resume);
 
-int vfs_quota_on_path(struct super_block *sb, int type, int format_id,
+int dquot_quota_on_path(struct super_block *sb, int type, int format_id,
                      struct path *path)
 {
        int error = security_quota_on(path->dentry);
@@ -2164,40 +2157,36 @@ int vfs_quota_on_path(struct super_block *sb, int type, int format_id,
                                             DQUOT_LIMITS_ENABLED);
        return error;
 }
-EXPORT_SYMBOL(vfs_quota_on_path);
+EXPORT_SYMBOL(dquot_quota_on_path);
 
-int vfs_quota_on(struct super_block *sb, int type, int format_id, char *name,
-                int remount)
+int dquot_quota_on(struct super_block *sb, int type, int format_id, char *name)
 {
        struct path path;
        int error;
 
-       if (remount)
-               return vfs_quota_on_remount(sb, type);
-
        error = kern_path(name, LOOKUP_FOLLOW, &path);
        if (!error) {
-               error = vfs_quota_on_path(sb, type, format_id, &path);
+               error = dquot_quota_on_path(sb, type, format_id, &path);
                path_put(&path);
        }
        return error;
 }
-EXPORT_SYMBOL(vfs_quota_on);
+EXPORT_SYMBOL(dquot_quota_on);
 
 /*
  * More powerful function for turning on quotas allowing setting
  * of individual quota flags
  */
-int vfs_quota_enable(struct inode *inode, int type, int format_id,
-               unsigned int flags)
+int dquot_enable(struct inode *inode, int type, int format_id,
+                unsigned int flags)
 {
        int ret = 0;
        struct super_block *sb = inode->i_sb;
        struct quota_info *dqopt = sb_dqopt(sb);
 
        /* Just unsuspend quotas? */
-       if (flags & DQUOT_SUSPENDED)
-               return vfs_quota_on_remount(sb, type);
+       BUG_ON(flags & DQUOT_SUSPENDED);
+
        if (!flags)
                return 0;
        /* Just updating flags needed? */
@@ -2229,13 +2218,13 @@ out_lock:
 load_quota:
        return vfs_load_quota_inode(inode, type, format_id, flags);
 }
-EXPORT_SYMBOL(vfs_quota_enable);
+EXPORT_SYMBOL(dquot_enable);
 
 /*
  * This function is used when filesystem needs to initialize quotas
  * during mount time.
  */
-int vfs_quota_on_mount(struct super_block *sb, char *qf_name,
+int dquot_quota_on_mount(struct super_block *sb, char *qf_name,
                int format_id, int type)
 {
        struct dentry *dentry;
@@ -2261,24 +2250,7 @@ out:
        dput(dentry);
        return error;
 }
-EXPORT_SYMBOL(vfs_quota_on_mount);
-
-/* Wrapper to turn on quotas when remounting rw */
-int vfs_dq_quota_on_remount(struct super_block *sb)
-{
-       int cnt;
-       int ret = 0, err;
-
-       if (!sb->s_qcop || !sb->s_qcop->quota_on)
-               return -ENOSYS;
-       for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-               err = sb->s_qcop->quota_on(sb, cnt, 0, NULL, 1);
-               if (err < 0 && !ret)
-                       ret = err;
-       }
-       return ret;
-}
-EXPORT_SYMBOL(vfs_dq_quota_on_remount);
+EXPORT_SYMBOL(dquot_quota_on_mount);
 
 static inline qsize_t qbtos(qsize_t blocks)
 {
@@ -2313,8 +2285,8 @@ static void do_get_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
        spin_unlock(&dq_data_lock);
 }
 
-int vfs_get_dqblk(struct super_block *sb, int type, qid_t id,
-                 struct fs_disk_quota *di)
+int dquot_get_dqblk(struct super_block *sb, int type, qid_t id,
+                   struct fs_disk_quota *di)
 {
        struct dquot *dquot;
 
@@ -2326,7 +2298,7 @@ int vfs_get_dqblk(struct super_block *sb, int type, qid_t id,
 
        return 0;
 }
-EXPORT_SYMBOL(vfs_get_dqblk);
+EXPORT_SYMBOL(dquot_get_dqblk);
 
 #define VFS_FS_DQ_MASK \
        (FS_DQ_BCOUNT | FS_DQ_BSOFT | FS_DQ_BHARD | \
@@ -2425,7 +2397,7 @@ static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
        return 0;
 }
 
-int vfs_set_dqblk(struct super_block *sb, int type, qid_t id,
+int dquot_set_dqblk(struct super_block *sb, int type, qid_t id,
                  struct fs_disk_quota *di)
 {
        struct dquot *dquot;
@@ -2441,10 +2413,10 @@ int vfs_set_dqblk(struct super_block *sb, int type, qid_t id,
 out:
        return rc;
 }
-EXPORT_SYMBOL(vfs_set_dqblk);
+EXPORT_SYMBOL(dquot_set_dqblk);
 
 /* Generic routine for getting common part of quota file information */
-int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
+int dquot_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
 {
        struct mem_dqinfo *mi;
   
@@ -2463,10 +2435,10 @@ int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
        mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
        return 0;
 }
-EXPORT_SYMBOL(vfs_get_dqinfo);
+EXPORT_SYMBOL(dquot_get_dqinfo);
 
 /* Generic routine for setting common part of quota file information */
-int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
+int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
 {
        struct mem_dqinfo *mi;
        int err = 0;
@@ -2493,27 +2465,27 @@ out:
        mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
        return err;
 }
-EXPORT_SYMBOL(vfs_set_dqinfo);
+EXPORT_SYMBOL(dquot_set_dqinfo);
 
-const struct quotactl_ops vfs_quotactl_ops = {
-       .quota_on       = vfs_quota_on,
-       .quota_off      = vfs_quota_off,
-       .quota_sync     = vfs_quota_sync,
-       .get_info       = vfs_get_dqinfo,
-       .set_info       = vfs_set_dqinfo,
-       .get_dqblk      = vfs_get_dqblk,
-       .set_dqblk      = vfs_set_dqblk
+const struct quotactl_ops dquot_quotactl_ops = {
+       .quota_on       = dquot_quota_on,
+       .quota_off      = dquot_quota_off,
+       .quota_sync     = dquot_quota_sync,
+       .get_info       = dquot_get_dqinfo,
+       .set_info       = dquot_set_dqinfo,
+       .get_dqblk      = dquot_get_dqblk,
+       .set_dqblk      = dquot_set_dqblk
 };
-
+EXPORT_SYMBOL(dquot_quotactl_ops);
 
 static int do_proc_dqstats(struct ctl_table *table, int write,
                     void __user *buffer, size_t *lenp, loff_t *ppos)
 {
-#ifdef CONFIG_SMP
-       /* Update global table */
        unsigned int type = (int *)table->data - dqstats.stat;
-       dqstats.stat[type] = dqstats_read(type);
-#endif
+
+       /* Update global table */
+       dqstats.stat[type] =
+                       percpu_counter_sum_positive(&dqstats.counter[type]);
        return proc_dointvec(table, write, buffer, lenp, ppos);
 }
 
@@ -2606,7 +2578,7 @@ static ctl_table sys_table[] = {
 
 static int __init dquot_init(void)
 {
-       int i;
+       int i, ret;
        unsigned long nr_hash, order;
 
        printk(KERN_NOTICE "VFS: Disk quotas %s\n", __DQUOT_VERSION__);
@@ -2624,12 +2596,11 @@ static int __init dquot_init(void)
        if (!dquot_hash)
                panic("Cannot create dquot hash table");
 
-#ifdef CONFIG_SMP
-       dqstats_pcpu = alloc_percpu(struct dqstats);
-       if (!dqstats_pcpu)
-               panic("Cannot create dquot stats table");
-#endif
-       memset(&dqstats, 0, sizeof(struct dqstats));
+       for (i = 0; i < _DQST_DQSTAT_LAST; i++) {
+               ret = percpu_counter_init(&dqstats.counter[i], 0);
+               if (ret)
+                       panic("Cannot create dquot stat counters");
+       }
 
        /* Find power-of-two hlist_heads which can fit into allocation */
        nr_hash = (1UL << order) * PAGE_SIZE / sizeof(struct hlist_head);
index cfc78826da90902f770f06dbfd34a5beba431097..b299961e1edbb8ef4dd16d28ccfd5c7cba2bfa28 100644 (file)
@@ -45,36 +45,22 @@ static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
        return security_quotactl(cmd, type, id, sb);
 }
 
+static void quota_sync_one(struct super_block *sb, void *arg)
+{
+       if (sb->s_qcop && sb->s_qcop->quota_sync)
+               sb->s_qcop->quota_sync(sb, *(int *)arg, 1);
+}
+
 static int quota_sync_all(int type)
 {
-       struct super_block *sb;
        int ret;
 
        if (type >= MAXQUOTAS)
                return -EINVAL;
        ret = security_quotactl(Q_SYNC, type, 0, NULL);
-       if (ret)
-               return ret;
-
-       spin_lock(&sb_lock);
-restart:
-       list_for_each_entry(sb, &super_blocks, s_list) {
-               if (!sb->s_qcop || !sb->s_qcop->quota_sync)
-                       continue;
-
-               sb->s_count++;
-               spin_unlock(&sb_lock);
-               down_read(&sb->s_umount);
-               if (sb->s_root)
-                       sb->s_qcop->quota_sync(sb, type, 1);
-               up_read(&sb->s_umount);
-               spin_lock(&sb_lock);
-               if (__put_super_and_need_restart(sb))
-                       goto restart;
-       }
-       spin_unlock(&sb_lock);
-
-       return 0;
+       if (!ret)
+               iterate_supers(quota_sync_one, &type);
+       return ret;
 }
 
 static int quota_quotaon(struct super_block *sb, int type, int cmd, qid_t id,
@@ -87,7 +73,7 @@ static int quota_quotaon(struct super_block *sb, int type, int cmd, qid_t id,
        if (IS_ERR(pathname))
                return PTR_ERR(pathname);
        if (sb->s_qcop->quota_on)
-               ret = sb->s_qcop->quota_on(sb, type, id, pathname, 0);
+               ret = sb->s_qcop->quota_on(sb, type, id, pathname);
        putname(pathname);
        return ret;
 }
@@ -274,7 +260,7 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
        case Q_QUOTAOFF:
                if (!sb->s_qcop->quota_off)
                        return -ENOSYS;
-               return sb->s_qcop->quota_off(sb, type, 0);
+               return sb->s_qcop->quota_off(sb, type);
        case Q_GETFMT:
                return quota_getfmt(sb, type, addr);
        case Q_GETINFO:
index 78f613cb9c7638529f9a587c3d65e69f3154841f..4884ac5ae9bea224517e384588847a44f4f8e462 100644 (file)
@@ -43,12 +43,13 @@ const struct file_operations ramfs_file_operations = {
        .write          = do_sync_write,
        .aio_write      = generic_file_aio_write,
        .mmap           = generic_file_mmap,
-       .fsync          = simple_sync_file,
+       .fsync          = noop_fsync,
        .splice_read    = generic_file_splice_read,
        .splice_write   = generic_file_splice_write,
        .llseek         = generic_file_llseek,
 };
 
 const struct inode_operations ramfs_file_inode_operations = {
+       .setattr        = simple_setattr,
        .getattr        = simple_getattr,
 };
index 5ea4ad81a429c24e5be49fbb1fc7317b4431d91f..d532c20fc1796acb171fe22828f9fec935f53420 100644 (file)
@@ -42,7 +42,7 @@ const struct file_operations ramfs_file_operations = {
        .aio_read               = generic_file_aio_read,
        .write                  = do_sync_write,
        .aio_write              = generic_file_aio_write,
-       .fsync                  = simple_sync_file,
+       .fsync                  = noop_fsync,
        .splice_read            = generic_file_splice_read,
        .splice_write           = generic_file_splice_write,
        .llseek                 = generic_file_llseek,
@@ -146,7 +146,7 @@ static int ramfs_nommu_resize(struct inode *inode, loff_t newsize, loff_t size)
                        return ret;
        }
 
-       ret = vmtruncate(inode, newsize);
+       ret = simple_setsize(inode, newsize);
 
        return ret;
 }
@@ -169,7 +169,8 @@ static int ramfs_nommu_setattr(struct dentry *dentry, struct iattr *ia)
 
        /* pick out size-changing events */
        if (ia->ia_valid & ATTR_SIZE) {
-               loff_t size = i_size_read(inode);
+               loff_t size = inode->i_size;
+
                if (ia->ia_size != size) {
                        ret = ramfs_nommu_resize(inode, ia->ia_size, size);
                        if (ret < 0 || ia->ia_valid == ATTR_SIZE)
@@ -182,7 +183,7 @@ static int ramfs_nommu_setattr(struct dentry *dentry, struct iattr *ia)
                }
        }
 
-       ret = inode_setattr(inode, ia);
+       generic_setattr(inode, ia);
  out:
        ia->ia_valid = old_ia_valid;
        return ret;
index f47cd212dee13000550ffccef05c5ac59d2b1a6c..a5ebae70dc6d4c90213770630f185d56ec6d6009 100644 (file)
@@ -52,14 +52,13 @@ static struct backing_dev_info ramfs_backing_dev_info = {
                          BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP,
 };
 
-struct inode *ramfs_get_inode(struct super_block *sb, int mode, dev_t dev)
+struct inode *ramfs_get_inode(struct super_block *sb,
+                               const struct inode *dir, int mode, dev_t dev)
 {
        struct inode * inode = new_inode(sb);
 
        if (inode) {
-               inode->i_mode = mode;
-               inode->i_uid = current_fsuid();
-               inode->i_gid = current_fsgid();
+               inode_init_owner(inode, dir, mode);
                inode->i_mapping->a_ops = &ramfs_aops;
                inode->i_mapping->backing_dev_info = &ramfs_backing_dev_info;
                mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER);
@@ -95,15 +94,10 @@ struct inode *ramfs_get_inode(struct super_block *sb, int mode, dev_t dev)
 static int
 ramfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
 {
-       struct inode * inode = ramfs_get_inode(dir->i_sb, mode, dev);
+       struct inode * inode = ramfs_get_inode(dir->i_sb, dir, mode, dev);
        int error = -ENOSPC;
 
        if (inode) {
-               if (dir->i_mode & S_ISGID) {
-                       inode->i_gid = dir->i_gid;
-                       if (S_ISDIR(mode))
-                               inode->i_mode |= S_ISGID;
-               }
                d_instantiate(dentry, inode);
                dget(dentry);   /* Extra count - pin the dentry in core */
                error = 0;
@@ -130,13 +124,11 @@ static int ramfs_symlink(struct inode * dir, struct dentry *dentry, const char *
        struct inode *inode;
        int error = -ENOSPC;
 
-       inode = ramfs_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0);
+       inode = ramfs_get_inode(dir->i_sb, dir, S_IFLNK|S_IRWXUGO, 0);
        if (inode) {
                int l = strlen(symname)+1;
                error = page_symlink(inode, symname, l);
                if (!error) {
-                       if (dir->i_mode & S_ISGID)
-                               inode->i_gid = dir->i_gid;
                        d_instantiate(dentry, inode);
                        dget(dentry);
                        dir->i_mtime = dir->i_ctime = CURRENT_TIME;
@@ -241,7 +233,7 @@ int ramfs_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_op                = &ramfs_ops;
        sb->s_time_gran         = 1;
 
-       inode = ramfs_get_inode(sb, S_IFDIR | fsi->mount_opts.mode, 0);
+       inode = ramfs_get_inode(sb, NULL, S_IFDIR | fsi->mount_opts.mode, 0);
        if (!inode) {
                err = -ENOMEM;
                goto fail;
index 113386d6fd2de0bdd12721e65b85a0fcbe8ab7b1..9c0485236e68d4abd02951d99aec5eb4a2905720 100644 (file)
@@ -97,6 +97,23 @@ loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
 }
 EXPORT_SYMBOL(generic_file_llseek);
 
+/**
+ * noop_llseek - No Operation Performed llseek implementation
+ * @file:      file structure to seek on
+ * @offset:    file offset to seek to
+ * @origin:    type of seek
+ *
+ * This is an implementation of ->llseek useable for the rare special case when
+ * userspace expects the seek to succeed but the (device) file is actually not
+ * able to perform the seek. In this case you use noop_llseek() instead of
+ * falling back to the default implementation of ->llseek.
+ */
+loff_t noop_llseek(struct file *file, loff_t offset, int origin)
+{
+       return file->f_pos;
+}
+EXPORT_SYMBOL(noop_llseek);
+
 loff_t no_llseek(struct file *file, loff_t offset, int origin)
 {
        return -ESPIPE;
index 07930449a9583ebee29e5781c3e4dbf9f609aa6f..198dabf1b2bbd7c8964194fe4340d5a12161bb4b 100644 (file)
 extern const struct reiserfs_key MIN_KEY;
 
 static int reiserfs_readdir(struct file *, void *, filldir_t);
-static int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry,
-                             int datasync);
+static int reiserfs_dir_fsync(struct file *filp, int datasync);
 
 const struct file_operations reiserfs_dir_operations = {
+       .llseek = generic_file_llseek,
        .read = generic_read_dir,
        .readdir = reiserfs_readdir,
        .fsync = reiserfs_dir_fsync,
@@ -27,10 +27,9 @@ const struct file_operations reiserfs_dir_operations = {
 #endif
 };
 
-static int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry,
-                             int datasync)
+static int reiserfs_dir_fsync(struct file *filp, int datasync)
 {
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = filp->f_mapping->host;
        int err;
        reiserfs_write_lock(inode->i_sb);
        err = reiserfs_commit_for_inode(inode);
index 9977df9f3a541b34d27b968da7d6ce918d062a33..b82cdd8a45dd88c593f06f67ec8f88515d8b500b 100644 (file)
@@ -134,10 +134,9 @@ static void reiserfs_vfs_truncate_file(struct inode *inode)
  * be removed...
  */
 
-static int reiserfs_sync_file(struct file *filp,
-                             struct dentry *dentry, int datasync)
+static int reiserfs_sync_file(struct file *filp, int datasync)
 {
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = filp->f_mapping->host;
        int err;
        int barrier_done;
 
index d0c43cb99ffc3b87da5e68fbe6d94b5b20970e63..ee78d4a0086a983609749a72ec0fb840615255fd 100644 (file)
@@ -561,23 +561,13 @@ static int drop_new_inode(struct inode *inode)
 */
 static int new_inode_init(struct inode *inode, struct inode *dir, int mode)
 {
-
-       /* the quota init calls have to know who to charge the quota to, so
-        ** we have to set uid and gid here
-        */
-       inode->i_uid = current_fsuid();
-       inode->i_mode = mode;
        /* Make inode invalid - just in case we are going to drop it before
         * the initialization happens */
        INODE_PKEY(inode)->k_objectid = 0;
-
-       if (dir->i_mode & S_ISGID) {
-               inode->i_gid = dir->i_gid;
-               if (S_ISDIR(mode))
-                       inode->i_mode |= S_ISGID;
-       } else {
-               inode->i_gid = current_fsgid();
-       }
+       /* the quota init calls have to know who to charge the quota to, so
+        ** we have to set uid and gid here
+        */
+       inode_init_owner(inode, dir, mode);
        dquot_initialize(inode);
        return 0;
 }
index 59125fb36d42482fd8fc3b6cfc9d63576890ca8e..9822fa15118ba52c743ec38c7def170a58c13a0a 100644 (file)
@@ -158,6 +158,7 @@ static int finish_unfinished(struct super_block *s)
 #ifdef CONFIG_QUOTA
        int i;
        int ms_active_set;
+       int quota_enabled[MAXQUOTAS];
 #endif
 
        /* compose key to look for "save" links */
@@ -179,8 +180,15 @@ static int finish_unfinished(struct super_block *s)
        }
        /* Turn on quotas so that they are updated correctly */
        for (i = 0; i < MAXQUOTAS; i++) {
+               quota_enabled[i] = 1;
                if (REISERFS_SB(s)->s_qf_names[i]) {
-                       int ret = reiserfs_quota_on_mount(s, i);
+                       int ret;
+
+                       if (sb_has_quota_active(s, i)) {
+                               quota_enabled[i] = 0;
+                               continue;
+                       }
+                       ret = reiserfs_quota_on_mount(s, i);
                        if (ret < 0)
                                reiserfs_warning(s, "reiserfs-2500",
                                                 "cannot turn on journaled "
@@ -304,8 +312,8 @@ static int finish_unfinished(struct super_block *s)
 #ifdef CONFIG_QUOTA
        /* Turn quotas off */
        for (i = 0; i < MAXQUOTAS; i++) {
-               if (sb_dqopt(s)->files[i])
-                       vfs_quota_off(s, i, 0);
+               if (sb_dqopt(s)->files[i] && quota_enabled[i])
+                       dquot_quota_off(s, i);
        }
        if (ms_active_set)
                /* Restore the flag back */
@@ -466,6 +474,8 @@ static void reiserfs_put_super(struct super_block *s)
        struct reiserfs_transaction_handle th;
        th.t_trans_id = 0;
 
+       dquot_disable(s, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);
+
        reiserfs_write_lock(s);
 
        if (s->s_dirt)
@@ -620,7 +630,7 @@ static int reiserfs_acquire_dquot(struct dquot *);
 static int reiserfs_release_dquot(struct dquot *);
 static int reiserfs_mark_dquot_dirty(struct dquot *);
 static int reiserfs_write_info(struct super_block *, int);
-static int reiserfs_quota_on(struct super_block *, int, int, char *, int);
+static int reiserfs_quota_on(struct super_block *, int, int, char *);
 
 static const struct dquot_operations reiserfs_quota_operations = {
        .write_dquot = reiserfs_write_dquot,
@@ -634,12 +644,12 @@ static const struct dquot_operations reiserfs_quota_operations = {
 
 static const struct quotactl_ops reiserfs_qctl_operations = {
        .quota_on = reiserfs_quota_on,
-       .quota_off = vfs_quota_off,
-       .quota_sync = vfs_quota_sync,
-       .get_info = vfs_get_dqinfo,
-       .set_info = vfs_set_dqinfo,
-       .get_dqblk = vfs_get_dqblk,
-       .set_dqblk = vfs_set_dqblk,
+       .quota_off = dquot_quota_off,
+       .quota_sync = dquot_quota_sync,
+       .get_info = dquot_get_dqinfo,
+       .set_info = dquot_set_dqinfo,
+       .get_dqblk = dquot_get_dqblk,
+       .set_dqblk = dquot_set_dqblk,
 };
 #endif
 
@@ -1242,6 +1252,11 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
                if (s->s_flags & MS_RDONLY)
                        /* it is read-only already */
                        goto out_ok;
+
+               err = dquot_suspend(s, -1);
+               if (err < 0)
+                       goto out_err;
+
                /* try to remount file system with read-only permissions */
                if (sb_umount_state(rs) == REISERFS_VALID_FS
                    || REISERFS_SB(s)->s_mount_state != REISERFS_VALID_FS) {
@@ -1295,6 +1310,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
        s->s_dirt = 0;
 
        if (!(*mount_flags & MS_RDONLY)) {
+               dquot_resume(s, -1);
                finish_unfinished(s);
                reiserfs_xattr_init(s, *mount_flags);
        }
@@ -2022,15 +2038,15 @@ static int reiserfs_write_info(struct super_block *sb, int type)
  */
 static int reiserfs_quota_on_mount(struct super_block *sb, int type)
 {
-       return vfs_quota_on_mount(sb, REISERFS_SB(sb)->s_qf_names[type],
-                                 REISERFS_SB(sb)->s_jquota_fmt, type);
+       return dquot_quota_on_mount(sb, REISERFS_SB(sb)->s_qf_names[type],
+                                       REISERFS_SB(sb)->s_jquota_fmt, type);
 }
 
 /*
  * Standard function to be called on quota_on
  */
 static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
-                            char *name, int remount)
+                            char *name)
 {
        int err;
        struct path path;
@@ -2039,9 +2055,7 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
 
        if (!(REISERFS_SB(sb)->s_mount_opt & (1 << REISERFS_QUOTA)))
                return -EINVAL;
-       /* No more checks needed? Path and format_id are bogus anyway... */
-       if (remount)
-               return vfs_quota_on(sb, type, format_id, name, 1);
+
        err = kern_path(name, LOOKUP_FOLLOW, &path);
        if (err)
                return err;
@@ -2085,7 +2099,7 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
                if (err)
                        goto out;
        }
-       err = vfs_quota_on_path(sb, type, format_id, &path);
+       err = dquot_quota_on_path(sb, type, format_id, &path);
 out:
        path_put(&path);
        return err;
index e7cc00e636dcb0d8049754c73c2ef397b9b33fc4..8c4cf273c672185fe7cb4c5d0a6e30ddc85e5bf3 100644 (file)
@@ -723,11 +723,11 @@ out:
                        (handler) = *(handlers)++)
 
 /* This is the implementation for the xattr plugin infrastructure */
-static inline struct xattr_handler *
-find_xattr_handler_prefix(struct xattr_handler **handlers,
+static inline const struct xattr_handler *
+find_xattr_handler_prefix(const struct xattr_handler **handlers,
                           const char *name)
 {
-       struct xattr_handler *xah;
+       const struct xattr_handler *xah;
 
        if (!handlers)
                return NULL;
@@ -748,7 +748,7 @@ ssize_t
 reiserfs_getxattr(struct dentry * dentry, const char *name, void *buffer,
                  size_t size)
 {
-       struct xattr_handler *handler;
+       const struct xattr_handler *handler;
 
        handler = find_xattr_handler_prefix(dentry->d_sb->s_xattr, name);
 
@@ -767,7 +767,7 @@ int
 reiserfs_setxattr(struct dentry *dentry, const char *name, const void *value,
                  size_t size, int flags)
 {
-       struct xattr_handler *handler;
+       const struct xattr_handler *handler;
 
        handler = find_xattr_handler_prefix(dentry->d_sb->s_xattr, name);
 
@@ -784,7 +784,7 @@ reiserfs_setxattr(struct dentry *dentry, const char *name, const void *value,
  */
 int reiserfs_removexattr(struct dentry *dentry, const char *name)
 {
-       struct xattr_handler *handler;
+       const struct xattr_handler *handler;
        handler = find_xattr_handler_prefix(dentry->d_sb->s_xattr, name);
 
        if (!handler || get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1)
@@ -807,7 +807,7 @@ static int listxattr_filler(void *buf, const char *name, int namelen,
        size_t size;
        if (name[0] != '.' ||
            (namelen != 1 && (name[1] != '.' || namelen != 2))) {
-               struct xattr_handler *handler;
+               const struct xattr_handler *handler;
                handler = find_xattr_handler_prefix(b->dentry->d_sb->s_xattr,
                                                    name);
                if (!handler)   /* Unsupported xattr name */
@@ -920,7 +920,7 @@ static int create_privroot(struct dentry *dentry) { return 0; }
 #endif
 
 /* Actual operations that are exported to VFS-land */
-struct xattr_handler *reiserfs_xattr_handlers[] = {
+const struct xattr_handler *reiserfs_xattr_handlers[] = {
 #ifdef CONFIG_REISERFS_FS_XATTR
        &reiserfs_xattr_user_handler,
        &reiserfs_xattr_trusted_handler,
index 9cdb759645a958405f054aef790d574bc2f006a2..536d697a8a283102f57053fcbb3338bd784bf559 100644 (file)
@@ -500,7 +500,7 @@ static size_t posix_acl_access_list(struct dentry *dentry, char *list,
        return size;
 }
 
-struct xattr_handler reiserfs_posix_acl_access_handler = {
+const struct xattr_handler reiserfs_posix_acl_access_handler = {
        .prefix = POSIX_ACL_XATTR_ACCESS,
        .flags = ACL_TYPE_ACCESS,
        .get = posix_acl_get,
@@ -520,7 +520,7 @@ static size_t posix_acl_default_list(struct dentry *dentry, char *list,
        return size;
 }
 
-struct xattr_handler reiserfs_posix_acl_default_handler = {
+const struct xattr_handler reiserfs_posix_acl_default_handler = {
        .prefix = POSIX_ACL_XATTR_DEFAULT,
        .flags = ACL_TYPE_DEFAULT,
        .get = posix_acl_get,
index 7271a477c041de88251e0a9faa0286ce539eb392..237c6928d3c69fe6901ea7abf74e4e6b1a220800 100644 (file)
@@ -111,7 +111,7 @@ void reiserfs_security_free(struct reiserfs_security_handle *sec)
        sec->value = NULL;
 }
 
-struct xattr_handler reiserfs_xattr_security_handler = {
+const struct xattr_handler reiserfs_xattr_security_handler = {
        .prefix = XATTR_SECURITY_PREFIX,
        .get = security_get,
        .set = security_set,
index 5b08aaca3dafaf4c8e1d4b89de06d0ec25f6928b..9883736ce3ecd0c4685c6fa3d269b4b6d40fdd96 100644 (file)
@@ -48,7 +48,7 @@ static size_t trusted_list(struct dentry *dentry, char *list, size_t list_size,
        return len;
 }
 
-struct xattr_handler reiserfs_xattr_trusted_handler = {
+const struct xattr_handler reiserfs_xattr_trusted_handler = {
        .prefix = XATTR_TRUSTED_PREFIX,
        .get = trusted_get,
        .set = trusted_set,
index 75d59c49b9114d4f059b96b50b35e9e2f0d7a9c6..45ae1a00013aba1f737b2f8a6e1caffe92cb7a7e 100644 (file)
@@ -44,7 +44,7 @@ static size_t user_list(struct dentry *dentry, char *list, size_t list_size,
        return len;
 }
 
-struct xattr_handler reiserfs_xattr_user_handler = {
+const struct xattr_handler reiserfs_xattr_user_handler = {
        .prefix = XATTR_USER_PREFIX,
        .get = user_get,
        .set = user_set,
index 3e4803b4427e92e3fb4617ab278e4cc30902e52c..00a70cab1f36ea7fc7bd96317d4bccdd8486a736 100644 (file)
@@ -37,9 +37,10 @@ static int smb_link(struct dentry *, struct inode *, struct dentry *);
 
 const struct file_operations smb_dir_operations =
 {
+       .llseek         = generic_file_llseek,
        .read           = generic_read_dir,
        .readdir        = smb_readdir,
-       .ioctl          = smb_ioctl,
+       .unlocked_ioctl = smb_ioctl,
        .open           = smb_dir_open,
 };
 
index dbf6548bbf06b6bc761a38d05232d928ce61b866..8e187a0f94bb28f0e35e751550fa9df47903c76c 100644 (file)
@@ -28,8 +28,9 @@
 #include "proto.h"
 
 static int
-smb_fsync(struct file *file, struct dentry * dentry, int datasync)
+smb_fsync(struct file *file, int datasync)
 {
+       struct dentry *dentry = file->f_path.dentry;
        struct smb_sb_info *server = server_from_dentry(dentry);
        int result;
 
@@ -437,7 +438,7 @@ const struct file_operations smb_file_operations =
        .aio_read       = smb_file_aio_read,
        .write          = do_sync_write,
        .aio_write      = smb_file_aio_write,
-       .ioctl          = smb_ioctl,
+       .unlocked_ioctl = smb_ioctl,
        .mmap           = smb_file_mmap,
        .open           = smb_file_open,
        .release        = smb_file_release,
index dfa1d67f8fca7be9b365dcd1976810aeaf8fe4cb..9551cb6f7fe4dfd1c058405e9c88bf83938fc8ea 100644 (file)
@@ -714,7 +714,7 @@ smb_notify_change(struct dentry *dentry, struct iattr *attr)
                error = server->ops->truncate(inode, attr->ia_size);
                if (error)
                        goto out;
-               error = vmtruncate(inode, attr->ia_size);
+               error = simple_setsize(inode, attr->ia_size);
                if (error)
                        goto out;
                refresh = 1;
index dbae1f8ea26fad19d288e1093025d7b014cb0417..07215312ad397d8dbbf8bceadd4477676a99e929 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/time.h>
 #include <linux/mm.h>
 #include <linux/highuid.h>
+#include <linux/smp_lock.h>
 #include <linux/net.h>
 
 #include <linux/smb_fs.h>
 
 #include "proto.h"
 
-int
-smb_ioctl(struct inode *inode, struct file *filp,
-         unsigned int cmd, unsigned long arg)
+long
+smb_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
-       struct smb_sb_info *server = server_from_inode(inode);
+       struct smb_sb_info *server = server_from_inode(filp->f_path.dentry->d_inode);
        struct smb_conn_opt opt;
        int result = -EINVAL;
 
+       lock_kernel();
        switch (cmd) {
                uid16_t uid16;
                uid_t uid32;
@@ -62,6 +63,7 @@ smb_ioctl(struct inode *inode, struct file *filp,
        default:
                break;
        }
+       unlock_kernel();
 
        return result;
 }
index 03f456c1b7d44cb6e5e7e9167fe9ece483ef2394..05939a6f43e625a28882d01b05a9e74135131de9 100644 (file)
@@ -67,7 +67,7 @@ extern const struct address_space_operations smb_file_aops;
 extern const struct file_operations smb_file_operations;
 extern const struct inode_operations smb_file_inode_operations;
 /* ioctl.c */
-extern int smb_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
+extern long smb_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
 /* smbiod.c */
 extern void smbiod_wake_up(void);
 extern int smbiod_register_server(struct smb_sb_info *server);
index 54350b59046ba26ccf4a4d339ec1fc793b960e69..00b2909bd469e30fc9c074029cd1d2789515f2b8 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/pagemap.h>
 #include <linux/net.h>
 #include <linux/namei.h>
-#include <linux/slab.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
index 25a00d19d68681687d0f9990a661ab8a7321fb75..cc6ce8a84c217d50fb82aef341d26fd56da6e991 100644 (file)
@@ -26,6 +26,17 @@ config SQUASHFS
 
          If unsure, say N.
 
+config SQUASHFS_XATTRS
+       bool "Squashfs XATTR support"
+       depends on SQUASHFS
+       default n
+       help
+         Saying Y here includes support for extended attributes (xattrs).
+         Xattrs are name:value pairs associated with inodes by
+         the kernel or by users (see the attr(5) manual page).
+
+         If unsure, say N.
+
 config SQUASHFS_EMBEDDED
 
        bool "Additional option for memory-constrained systems" 
index df8a19ef870d6db72cca324e4ef4667931b8dbd7..2cee3e9fa452b81219a04145f77c1ba827723a6e 100644 (file)
@@ -5,3 +5,5 @@
 obj-$(CONFIG_SQUASHFS) += squashfs.o
 squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o
 squashfs-y += namei.o super.o symlink.o zlib_wrapper.o decompressor.o
+squashfs-$(CONFIG_SQUASHFS_XATTRS) += xattr.o xattr_id.o
+
index 49daaf669e41809d33b377c40c2f39e0f2e462c7..62e63ad250755ed6d51fd56aa75f2c91f82e74e7 100644 (file)
 
 #include <linux/fs.h>
 #include <linux/vfs.h>
+#include <linux/xattr.h>
 
 #include "squashfs_fs.h"
 #include "squashfs_fs_sb.h"
 #include "squashfs_fs_i.h"
 #include "squashfs.h"
+#include "xattr.h"
 
 /*
  * Initialise VFS inode with the base inode information common to all
@@ -111,6 +113,7 @@ int squashfs_read_inode(struct inode *inode, long long ino)
        int err, type, offset = SQUASHFS_INODE_OFFSET(ino);
        union squashfs_inode squashfs_ino;
        struct squashfs_base_inode *sqshb_ino = &squashfs_ino.base;
+       int xattr_id = SQUASHFS_INVALID_XATTR;
 
        TRACE("Entered squashfs_read_inode\n");
 
@@ -199,8 +202,10 @@ int squashfs_read_inode(struct inode *inode, long long ino)
                        frag_offset = 0;
                }
 
+               xattr_id = le32_to_cpu(sqsh_ino->xattr);
                inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
                inode->i_size = le64_to_cpu(sqsh_ino->file_size);
+               inode->i_op = &squashfs_inode_ops;
                inode->i_fop = &generic_ro_fops;
                inode->i_mode |= S_IFREG;
                inode->i_blocks = ((inode->i_size -
@@ -251,6 +256,7 @@ int squashfs_read_inode(struct inode *inode, long long ino)
                if (err < 0)
                        goto failed_read;
 
+               xattr_id = le32_to_cpu(sqsh_ino->xattr);
                inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
                inode->i_size = le32_to_cpu(sqsh_ino->file_size);
                inode->i_op = &squashfs_dir_inode_ops;
@@ -280,21 +286,33 @@ int squashfs_read_inode(struct inode *inode, long long ino)
 
                inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
                inode->i_size = le32_to_cpu(sqsh_ino->symlink_size);
-               inode->i_op = &page_symlink_inode_operations;
+               inode->i_op = &squashfs_symlink_inode_ops;
                inode->i_data.a_ops = &squashfs_symlink_aops;
                inode->i_mode |= S_IFLNK;
                squashfs_i(inode)->start = block;
                squashfs_i(inode)->offset = offset;
 
+               if (type == SQUASHFS_LSYMLINK_TYPE) {
+                       __le32 xattr;
+
+                       err = squashfs_read_metadata(sb, NULL, &block,
+                                               &offset, inode->i_size);
+                       if (err < 0)
+                               goto failed_read;
+                       err = squashfs_read_metadata(sb, &xattr, &block,
+                                               &offset, sizeof(xattr));
+                       if (err < 0)
+                               goto failed_read;
+                       xattr_id = le32_to_cpu(xattr);
+               }
+
                TRACE("Symbolic link inode %x:%x, start_block %llx, offset "
                                "%x\n", SQUASHFS_INODE_BLK(ino), offset,
                                block, offset);
                break;
        }
        case SQUASHFS_BLKDEV_TYPE:
-       case SQUASHFS_CHRDEV_TYPE:
-       case SQUASHFS_LBLKDEV_TYPE:
-       case SQUASHFS_LCHRDEV_TYPE: {
+       case SQUASHFS_CHRDEV_TYPE: {
                struct squashfs_dev_inode *sqsh_ino = &squashfs_ino.dev;
                unsigned int rdev;
 
@@ -315,10 +333,32 @@ int squashfs_read_inode(struct inode *inode, long long ino)
                                SQUASHFS_INODE_BLK(ino), offset, rdev);
                break;
        }
+       case SQUASHFS_LBLKDEV_TYPE:
+       case SQUASHFS_LCHRDEV_TYPE: {
+               struct squashfs_ldev_inode *sqsh_ino = &squashfs_ino.ldev;
+               unsigned int rdev;
+
+               err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
+                               sizeof(*sqsh_ino));
+               if (err < 0)
+                       goto failed_read;
+
+               if (type == SQUASHFS_LCHRDEV_TYPE)
+                       inode->i_mode |= S_IFCHR;
+               else
+                       inode->i_mode |= S_IFBLK;
+               xattr_id = le32_to_cpu(sqsh_ino->xattr);
+               inode->i_op = &squashfs_inode_ops;
+               inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
+               rdev = le32_to_cpu(sqsh_ino->rdev);
+               init_special_inode(inode, inode->i_mode, new_decode_dev(rdev));
+
+               TRACE("Device inode %x:%x, rdev %x\n",
+                               SQUASHFS_INODE_BLK(ino), offset, rdev);
+               break;
+       }
        case SQUASHFS_FIFO_TYPE:
-       case SQUASHFS_SOCKET_TYPE:
-       case SQUASHFS_LFIFO_TYPE:
-       case SQUASHFS_LSOCKET_TYPE: {
+       case SQUASHFS_SOCKET_TYPE: {
                struct squashfs_ipc_inode *sqsh_ino = &squashfs_ino.ipc;
 
                err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
@@ -334,14 +374,52 @@ int squashfs_read_inode(struct inode *inode, long long ino)
                init_special_inode(inode, inode->i_mode, 0);
                break;
        }
+       case SQUASHFS_LFIFO_TYPE:
+       case SQUASHFS_LSOCKET_TYPE: {
+               struct squashfs_lipc_inode *sqsh_ino = &squashfs_ino.lipc;
+
+               err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
+                               sizeof(*sqsh_ino));
+               if (err < 0)
+                       goto failed_read;
+
+               if (type == SQUASHFS_LFIFO_TYPE)
+                       inode->i_mode |= S_IFIFO;
+               else
+                       inode->i_mode |= S_IFSOCK;
+               xattr_id = le32_to_cpu(sqsh_ino->xattr);
+               inode->i_op = &squashfs_inode_ops;
+               inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
+               init_special_inode(inode, inode->i_mode, 0);
+               break;
+       }
        default:
                ERROR("Unknown inode type %d in squashfs_iget!\n", type);
                return -EINVAL;
        }
 
+       if (xattr_id != SQUASHFS_INVALID_XATTR && msblk->xattr_id_table) {
+               err = squashfs_xattr_lookup(sb, xattr_id,
+                                       &squashfs_i(inode)->xattr_count,
+                                       &squashfs_i(inode)->xattr_size,
+                                       &squashfs_i(inode)->xattr);
+               if (err < 0)
+                       goto failed_read;
+               inode->i_blocks += ((squashfs_i(inode)->xattr_size - 1) >> 9)
+                               + 1;
+       } else
+               squashfs_i(inode)->xattr_count = 0;
+
        return 0;
 
 failed_read:
        ERROR("Unable to read inode 0x%llx\n", ino);
        return err;
 }
+
+
+const struct inode_operations squashfs_inode_ops = {
+       .getxattr = generic_getxattr,
+       .listxattr = squashfs_listxattr
+};
+
index 5266bd8ad932edb3a288217d8992693d649b7112..7a9464d08cf632bef2395baea734c9eae9d8d6a7 100644 (file)
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/dcache.h>
+#include <linux/xattr.h>
 
 #include "squashfs_fs.h"
 #include "squashfs_fs_sb.h"
 #include "squashfs_fs_i.h"
 #include "squashfs.h"
+#include "xattr.h"
 
 /*
  * Lookup name in the directory index, returning the location of the metadata
@@ -237,5 +239,7 @@ failed:
 
 
 const struct inode_operations squashfs_dir_inode_ops = {
-       .lookup = squashfs_lookup
+       .lookup = squashfs_lookup,
+       .getxattr = generic_getxattr,
+       .listxattr = squashfs_listxattr
 };
index fe2587af5512edc3947622a2e949c53c4fa4d539..733a17c42945661d505474cf600b57037e1ff556 100644 (file)
@@ -73,8 +73,11 @@ extern struct inode *squashfs_iget(struct super_block *, long long,
                                unsigned int);
 extern int squashfs_read_inode(struct inode *, long long);
 
+/* xattr.c */
+extern ssize_t squashfs_listxattr(struct dentry *, char *, size_t);
+
 /*
- * Inodes, files and decompressor operations
+ * Inodes, files,  decompressor and xattr operations
  */
 
 /* dir.c */
@@ -86,11 +89,18 @@ extern const struct export_operations squashfs_export_ops;
 /* file.c */
 extern const struct address_space_operations squashfs_aops;
 
+/* inode.c */
+extern const struct inode_operations squashfs_inode_ops;
+
 /* namei.c */
 extern const struct inode_operations squashfs_dir_inode_ops;
 
 /* symlink.c */
 extern const struct address_space_operations squashfs_symlink_aops;
+extern const struct inode_operations squashfs_symlink_inode_ops;
+
+/* xattr.c */
+extern const struct xattr_handler *squashfs_xattr_handlers[];
 
 /* zlib_wrapper.c */
 extern const struct squashfs_decompressor squashfs_zlib_comp_ops;
index 79024245ea00f7fb370e7aa8dbef6819da33854b..8eabb808b78dcd18009565bbc5ed213b1261cb8b 100644 (file)
@@ -46,6 +46,7 @@
 #define SQUASHFS_NAME_LEN              256
 
 #define SQUASHFS_INVALID_FRAG          (0xffffffffU)
+#define SQUASHFS_INVALID_XATTR         (0xffffffffU)
 #define SQUASHFS_INVALID_BLK           (-1LL)
 
 /* Filesystem flags */
 #define SQUASHFS_LFIFO_TYPE            13
 #define SQUASHFS_LSOCKET_TYPE          14
 
+/* Xattr types */
+#define SQUASHFS_XATTR_USER             0
+#define SQUASHFS_XATTR_TRUSTED          1
+#define SQUASHFS_XATTR_SECURITY         2
+#define SQUASHFS_XATTR_VALUE_OOL        256
+#define SQUASHFS_XATTR_PREFIX_MASK      0xff
+
 /* Flag whether block is compressed or uncompressed, bit is set if block is
  * uncompressed */
 #define SQUASHFS_COMPRESSED_BIT                (1 << 15)
 
 #define SQUASHFS_ID_BLOCK_BYTES(A)     (SQUASHFS_ID_BLOCKS(A) *\
                                        sizeof(u64))
+/* xattr id lookup table defines */
+#define SQUASHFS_XATTR_BYTES(A)                ((A) * sizeof(struct squashfs_xattr_id))
+
+#define SQUASHFS_XATTR_BLOCK(A)                (SQUASHFS_XATTR_BYTES(A) / \
+                                       SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_XATTR_BLOCK_OFFSET(A) (SQUASHFS_XATTR_BYTES(A) % \
+                                       SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_XATTR_BLOCKS(A)       ((SQUASHFS_XATTR_BYTES(A) + \
+                                       SQUASHFS_METADATA_SIZE - 1) / \
+                                       SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_XATTR_BLOCK_BYTES(A)  (SQUASHFS_XATTR_BLOCKS(A) *\
+                                       sizeof(u64))
+#define SQUASHFS_XATTR_BLK(A)          ((unsigned int) ((A) >> 16))
+
+#define SQUASHFS_XATTR_OFFSET(A)       ((unsigned int) ((A) & 0xffff))
 
 /* cached data constants for filesystem */
 #define SQUASHFS_CACHED_BLKS           8
@@ -228,7 +254,7 @@ struct squashfs_super_block {
        __le64                  root_inode;
        __le64                  bytes_used;
        __le64                  id_table_start;
-       __le64                  xattr_table_start;
+       __le64                  xattr_id_table_start;
        __le64                  inode_table_start;
        __le64                  directory_table_start;
        __le64                  fragment_table_start;
@@ -261,6 +287,17 @@ struct squashfs_ipc_inode {
        __le32                  nlink;
 };
 
+struct squashfs_lipc_inode {
+       __le16                  inode_type;
+       __le16                  mode;
+       __le16                  uid;
+       __le16                  guid;
+       __le32                  mtime;
+       __le32                  inode_number;
+       __le32                  nlink;
+       __le32                  xattr;
+};
+
 struct squashfs_dev_inode {
        __le16                  inode_type;
        __le16                  mode;
@@ -272,6 +309,18 @@ struct squashfs_dev_inode {
        __le32                  rdev;
 };
 
+struct squashfs_ldev_inode {
+       __le16                  inode_type;
+       __le16                  mode;
+       __le16                  uid;
+       __le16                  guid;
+       __le32                  mtime;
+       __le32                  inode_number;
+       __le32                  nlink;
+       __le32                  rdev;
+       __le32                  xattr;
+};
+
 struct squashfs_symlink_inode {
        __le16                  inode_type;
        __le16                  mode;
@@ -349,12 +398,14 @@ struct squashfs_ldir_inode {
 union squashfs_inode {
        struct squashfs_base_inode              base;
        struct squashfs_dev_inode               dev;
+       struct squashfs_ldev_inode              ldev;
        struct squashfs_symlink_inode           symlink;
        struct squashfs_reg_inode               reg;
        struct squashfs_lreg_inode              lreg;
        struct squashfs_dir_inode               dir;
        struct squashfs_ldir_inode              ldir;
        struct squashfs_ipc_inode               ipc;
+       struct squashfs_lipc_inode              lipc;
 };
 
 struct squashfs_dir_entry {
@@ -377,4 +428,27 @@ struct squashfs_fragment_entry {
        unsigned int            unused;
 };
 
+struct squashfs_xattr_entry {
+       __le16                  type;
+       __le16                  size;
+       char                    data[0];
+};
+
+struct squashfs_xattr_val {
+       __le32                  vsize;
+       char                    value[0];
+};
+
+struct squashfs_xattr_id {
+       __le64                  xattr;
+       __le32                  count;
+       __le32                  size;
+};
+
+struct squashfs_xattr_id_table {
+       __le64                  xattr_table_start;
+       __le32                  xattr_ids;
+       __le32                  unused;
+};
+
 #endif
index fbfca30c0c688a0c17c902db1300e08d6adcbdea..d3e3a37f28a14609c17a4d4da4759e6567346bc4 100644 (file)
@@ -26,6 +26,9 @@
 struct squashfs_inode_info {
        u64             start;
        int             offset;
+       u64             xattr;
+       unsigned int    xattr_size;
+       int             xattr_count;
        union {
                struct {
                        u64             fragment_block;
index 2e77dc547e253df03d94f8dfe0a849358810d082..d9037a5215f00b77044c030b37c1255fe4273a41 100644 (file)
@@ -61,6 +61,7 @@ struct squashfs_sb_info {
        int                                     next_meta_index;
        __le64                                  *id_table;
        __le64                                  *fragment_index;
+       __le64                                  *xattr_id_table;
        struct mutex                            read_data_mutex;
        struct mutex                            meta_index_mutex;
        struct meta_index                       *meta_index;
@@ -68,9 +69,11 @@ struct squashfs_sb_info {
        __le64                                  *inode_lookup_table;
        u64                                     inode_table;
        u64                                     directory_table;
+       u64                                     xattr_table;
        unsigned int                            block_size;
        unsigned short                          block_log;
        long long                               bytes_used;
        unsigned int                            inodes;
+       int                                     xattr_ids;
 };
 #endif
index 48b6f4a385a60ccf40276bb08c0e591edd3561b1..88b4f8606652b8e675621a2f545aff357ea176ae 100644 (file)
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/magic.h>
+#include <linux/xattr.h>
 
 #include "squashfs_fs.h"
 #include "squashfs_fs_sb.h"
 #include "squashfs_fs_i.h"
 #include "squashfs.h"
 #include "decompressor.h"
+#include "xattr.h"
 
 static struct file_system_type squashfs_fs_type;
 static const struct super_operations squashfs_super_ops;
@@ -82,7 +84,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
        long long root_inode;
        unsigned short flags;
        unsigned int fragments;
-       u64 lookup_table_start;
+       u64 lookup_table_start, xattr_id_table_start;
        int err;
 
        TRACE("Entered squashfs_fill_superblock\n");
@@ -139,13 +141,6 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
        if (msblk->decompressor == NULL)
                goto failed_mount;
 
-       /*
-        * Check if there's xattrs in the filesystem.  These are not
-        * supported in this version, so warn that they will be ignored.
-        */
-       if (le64_to_cpu(sblk->xattr_table_start) != SQUASHFS_INVALID_BLK)
-               ERROR("Xattrs in filesystem, these will be ignored\n");
-
        /* Check the filesystem does not extend beyond the end of the
           block device */
        msblk->bytes_used = le64_to_cpu(sblk->bytes_used);
@@ -253,7 +248,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
 allocate_lookup_table:
        lookup_table_start = le64_to_cpu(sblk->lookup_table_start);
        if (lookup_table_start == SQUASHFS_INVALID_BLK)
-               goto allocate_root;
+               goto allocate_xattr_table;
 
        /* Allocate and read inode lookup table */
        msblk->inode_lookup_table = squashfs_read_inode_lookup_table(sb,
@@ -266,6 +261,21 @@ allocate_lookup_table:
 
        sb->s_export_op = &squashfs_export_ops;
 
+allocate_xattr_table:
+       sb->s_xattr = squashfs_xattr_handlers;
+       xattr_id_table_start = le64_to_cpu(sblk->xattr_id_table_start);
+       if (xattr_id_table_start == SQUASHFS_INVALID_BLK)
+               goto allocate_root;
+
+       /* Allocate and read xattr id lookup table */
+       msblk->xattr_id_table = squashfs_read_xattr_id_table(sb,
+               xattr_id_table_start, &msblk->xattr_table, &msblk->xattr_ids);
+       if (IS_ERR(msblk->xattr_id_table)) {
+               err = PTR_ERR(msblk->xattr_id_table);
+               msblk->xattr_id_table = NULL;
+               if (err != -ENOTSUPP)
+                       goto failed_mount;
+       }
 allocate_root:
        root = new_inode(sb);
        if (!root) {
@@ -301,6 +311,7 @@ failed_mount:
        kfree(msblk->inode_lookup_table);
        kfree(msblk->fragment_index);
        kfree(msblk->id_table);
+       kfree(msblk->xattr_id_table);
        kfree(sb->s_fs_info);
        sb->s_fs_info = NULL;
        kfree(sblk);
@@ -355,6 +366,7 @@ static void squashfs_put_super(struct super_block *sb)
                kfree(sbi->fragment_index);
                kfree(sbi->meta_index);
                kfree(sbi->inode_lookup_table);
+               kfree(sbi->xattr_id_table);
                kfree(sb->s_fs_info);
                sb->s_fs_info = NULL;
        }
index 32b911f4ee39e859d9a03d7b68b8ef7e33e11552..ec86434921e18c6a5bd180246439f84b56a5d00b 100644 (file)
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/pagemap.h>
+#include <linux/xattr.h>
 
 #include "squashfs_fs.h"
 #include "squashfs_fs_sb.h"
 #include "squashfs_fs_i.h"
 #include "squashfs.h"
+#include "xattr.h"
 
 static int squashfs_symlink_readpage(struct file *file, struct page *page)
 {
@@ -114,3 +116,12 @@ error_out:
 const struct address_space_operations squashfs_symlink_aops = {
        .readpage = squashfs_symlink_readpage
 };
+
+const struct inode_operations squashfs_symlink_inode_ops = {
+       .readlink = generic_readlink,
+       .follow_link = page_follow_link_light,
+       .put_link = page_put_link,
+       .getxattr = generic_getxattr,
+       .listxattr = squashfs_listxattr
+};
+
diff --git a/fs/squashfs/xattr.c b/fs/squashfs/xattr.c
new file mode 100644 (file)
index 0000000..c7655e8
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * Squashfs - a compressed read only filesystem for Linux
+ *
+ * Copyright (c) 2010
+ * Phillip Lougher <phillip@lougher.demon.co.uk>
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * xattr_id.c
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/vfs.h>
+#include <linux/xattr.h>
+#include <linux/slab.h>
+
+#include "squashfs_fs.h"
+#include "squashfs_fs_sb.h"
+#include "squashfs_fs_i.h"
+#include "squashfs.h"
+
+static const struct xattr_handler *squashfs_xattr_handler(int);
+
+ssize_t squashfs_listxattr(struct dentry *d, char *buffer,
+       size_t buffer_size)
+{
+       struct inode *inode = d->d_inode;
+       struct super_block *sb = inode->i_sb;
+       struct squashfs_sb_info *msblk = sb->s_fs_info;
+       u64 start = SQUASHFS_XATTR_BLK(squashfs_i(inode)->xattr)
+                                                + msblk->xattr_table;
+       int offset = SQUASHFS_XATTR_OFFSET(squashfs_i(inode)->xattr);
+       int count = squashfs_i(inode)->xattr_count;
+       size_t rest = buffer_size;
+       int err;
+
+       /* check that the file system has xattrs */
+       if (msblk->xattr_id_table == NULL)
+               return -EOPNOTSUPP;
+
+       /* loop reading each xattr name */
+       while (count--) {
+               struct squashfs_xattr_entry entry;
+               struct squashfs_xattr_val val;
+               const struct xattr_handler *handler;
+               int name_size, prefix_size = 0;
+
+               err = squashfs_read_metadata(sb, &entry, &start, &offset,
+                                                       sizeof(entry));
+               if (err < 0)
+                       goto failed;
+
+               name_size = le16_to_cpu(entry.size);
+               handler = squashfs_xattr_handler(le16_to_cpu(entry.type));
+               if (handler)
+                       prefix_size = handler->list(d, buffer, rest, NULL,
+                               name_size, handler->flags);
+               if (prefix_size) {
+                       if (buffer) {
+                               if (prefix_size + name_size + 1 > rest) {
+                                       err = -ERANGE;
+                                       goto failed;
+                               }
+                               buffer += prefix_size;
+                       }
+                       err = squashfs_read_metadata(sb, buffer, &start,
+                               &offset, name_size);
+                       if (err < 0)
+                               goto failed;
+                       if (buffer) {
+                               buffer[name_size] = '\0';
+                               buffer += name_size + 1;
+                       }
+                       rest -= prefix_size + name_size + 1;
+               } else  {
+                       /* no handler or insuffficient privileges, so skip */
+                       err = squashfs_read_metadata(sb, NULL, &start,
+                               &offset, name_size);
+                       if (err < 0)
+                               goto failed;
+               }
+
+
+               /* skip remaining xattr entry */
+               err = squashfs_read_metadata(sb, &val, &start, &offset,
+                                               sizeof(val));
+               if (err < 0)
+                       goto failed;
+
+               err = squashfs_read_metadata(sb, NULL, &start, &offset,
+                                               le32_to_cpu(val.vsize));
+               if (err < 0)
+                       goto failed;
+       }
+       err = buffer_size - rest;
+
+failed:
+       return err;
+}
+
+
+static int squashfs_xattr_get(struct inode *inode, int name_index,
+       const char *name, void *buffer, size_t buffer_size)
+{
+       struct super_block *sb = inode->i_sb;
+       struct squashfs_sb_info *msblk = sb->s_fs_info;
+       u64 start = SQUASHFS_XATTR_BLK(squashfs_i(inode)->xattr)
+                                                + msblk->xattr_table;
+       int offset = SQUASHFS_XATTR_OFFSET(squashfs_i(inode)->xattr);
+       int count = squashfs_i(inode)->xattr_count;
+       int name_len = strlen(name);
+       int err, vsize;
+       char *target = kmalloc(name_len, GFP_KERNEL);
+
+       if (target == NULL)
+               return  -ENOMEM;
+
+       /* loop reading each xattr name */
+       for (; count; count--) {
+               struct squashfs_xattr_entry entry;
+               struct squashfs_xattr_val val;
+               int type, prefix, name_size;
+
+               err = squashfs_read_metadata(sb, &entry, &start, &offset,
+                                                       sizeof(entry));
+               if (err < 0)
+                       goto failed;
+
+               name_size = le16_to_cpu(entry.size);
+               type = le16_to_cpu(entry.type);
+               prefix = type & SQUASHFS_XATTR_PREFIX_MASK;
+
+               if (prefix == name_index && name_size == name_len)
+                       err = squashfs_read_metadata(sb, target, &start,
+                                               &offset, name_size);
+               else
+                       err = squashfs_read_metadata(sb, NULL, &start,
+                                               &offset, name_size);
+               if (err < 0)
+                       goto failed;
+
+               if (prefix == name_index && name_size == name_len &&
+                                       strncmp(target, name, name_size) == 0) {
+                       /* found xattr */
+                       if (type & SQUASHFS_XATTR_VALUE_OOL) {
+                               __le64 xattr;
+                               /* val is a reference to the real location */
+                               err = squashfs_read_metadata(sb, &val, &start,
+                                               &offset, sizeof(val));
+                               if (err < 0)
+                                       goto failed;
+                               err = squashfs_read_metadata(sb, &xattr, &start,
+                                        &offset, sizeof(xattr));
+                               if (err < 0)
+                                       goto failed;
+                               xattr = le64_to_cpu(xattr);
+                               start = SQUASHFS_XATTR_BLK(xattr) +
+                                                       msblk->xattr_table;
+                               offset = SQUASHFS_XATTR_OFFSET(xattr);
+                       }
+                       /* read xattr value */
+                       err = squashfs_read_metadata(sb, &val, &start, &offset,
+                                                       sizeof(val));
+                       if (err < 0)
+                               goto failed;
+
+                       vsize = le32_to_cpu(val.vsize);
+                       if (buffer) {
+                               if (vsize > buffer_size) {
+                                       err = -ERANGE;
+                                       goto failed;
+                               }
+                               err = squashfs_read_metadata(sb, buffer, &start,
+                                        &offset, vsize);
+                               if (err < 0)
+                                       goto failed;
+                       }
+                       break;
+               }
+
+               /* no match, skip remaining xattr entry */
+               err = squashfs_read_metadata(sb, &val, &start, &offset,
+                                                       sizeof(val));
+               if (err < 0)
+                       goto failed;
+               err = squashfs_read_metadata(sb, NULL, &start, &offset,
+                                               le32_to_cpu(val.vsize));
+               if (err < 0)
+                       goto failed;
+       }
+       err = count ? vsize : -ENODATA;
+
+failed:
+       kfree(target);
+       return err;
+}
+
+
+/*
+ * User namespace support
+ */
+static size_t squashfs_user_list(struct dentry *d, char *list, size_t list_size,
+       const char *name, size_t name_len, int type)
+{
+       if (list && XATTR_USER_PREFIX_LEN <= list_size)
+               memcpy(list, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);
+       return XATTR_USER_PREFIX_LEN;
+}
+
+static int squashfs_user_get(struct dentry *d, const char *name, void *buffer,
+       size_t size, int type)
+{
+       if (name[0] == '\0')
+               return  -EINVAL;
+
+       return squashfs_xattr_get(d->d_inode, SQUASHFS_XATTR_USER, name,
+               buffer, size);
+}
+
+static const struct xattr_handler squashfs_xattr_user_handler = {
+       .prefix = XATTR_USER_PREFIX,
+       .list   = squashfs_user_list,
+       .get    = squashfs_user_get
+};
+
+/*
+ * Trusted namespace support
+ */
+static size_t squashfs_trusted_list(struct dentry *d, char *list,
+       size_t list_size, const char *name, size_t name_len, int type)
+{
+       if (!capable(CAP_SYS_ADMIN))
+               return 0;
+
+       if (list && XATTR_TRUSTED_PREFIX_LEN <= list_size)
+               memcpy(list, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN);
+       return XATTR_TRUSTED_PREFIX_LEN;
+}
+
+static int squashfs_trusted_get(struct dentry *d, const char *name,
+       void *buffer, size_t size, int type)
+{
+       if (name[0] == '\0')
+               return  -EINVAL;
+
+       return squashfs_xattr_get(d->d_inode, SQUASHFS_XATTR_TRUSTED, name,
+               buffer, size);
+}
+
+static const struct xattr_handler squashfs_xattr_trusted_handler = {
+       .prefix = XATTR_TRUSTED_PREFIX,
+       .list   = squashfs_trusted_list,
+       .get    = squashfs_trusted_get
+};
+
+/*
+ * Security namespace support
+ */
+static size_t squashfs_security_list(struct dentry *d, char *list,
+       size_t list_size, const char *name, size_t name_len, int type)
+{
+       if (list && XATTR_SECURITY_PREFIX_LEN <= list_size)
+               memcpy(list, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN);
+       return XATTR_SECURITY_PREFIX_LEN;
+}
+
+static int squashfs_security_get(struct dentry *d, const char *name,
+       void *buffer, size_t size, int type)
+{
+       if (name[0] == '\0')
+               return  -EINVAL;
+
+       return squashfs_xattr_get(d->d_inode, SQUASHFS_XATTR_SECURITY, name,
+               buffer, size);
+}
+
+static const struct xattr_handler squashfs_xattr_security_handler = {
+       .prefix = XATTR_SECURITY_PREFIX,
+       .list   = squashfs_security_list,
+       .get    = squashfs_security_get
+};
+
+static inline const struct xattr_handler *squashfs_xattr_handler(int type)
+{
+       if (type & ~(SQUASHFS_XATTR_PREFIX_MASK | SQUASHFS_XATTR_VALUE_OOL))
+               /* ignore unrecognised type */
+               return NULL;
+
+       switch (type & SQUASHFS_XATTR_PREFIX_MASK) {
+       case SQUASHFS_XATTR_USER:
+               return &squashfs_xattr_user_handler;
+       case SQUASHFS_XATTR_TRUSTED:
+               return &squashfs_xattr_trusted_handler;
+       case SQUASHFS_XATTR_SECURITY:
+               return &squashfs_xattr_security_handler;
+       default:
+               /* ignore unrecognised type */
+               return NULL;
+       }
+}
+
+const struct xattr_handler *squashfs_xattr_handlers[] = {
+       &squashfs_xattr_user_handler,
+       &squashfs_xattr_trusted_handler,
+       &squashfs_xattr_security_handler,
+       NULL
+};
+
diff --git a/fs/squashfs/xattr.h b/fs/squashfs/xattr.h
new file mode 100644 (file)
index 0000000..9da071a
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Squashfs - a compressed read only filesystem for Linux
+ *
+ * Copyright (c) 2010
+ * Phillip Lougher <phillip@lougher.demon.co.uk>
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * xattr.h
+ */
+
+#ifdef CONFIG_SQUASHFS_XATTRS
+extern __le64 *squashfs_read_xattr_id_table(struct super_block *, u64,
+               u64 *, int *);
+extern int squashfs_xattr_lookup(struct super_block *, unsigned int, int *,
+               int *, unsigned long long *);
+#else
+static inline __le64 *squashfs_read_xattr_id_table(struct super_block *sb,
+               u64 start, u64 *xattr_table_start, int *xattr_ids)
+{
+       ERROR("Xattrs in filesystem, these will be ignored\n");
+       return ERR_PTR(-ENOTSUPP);
+}
+
+static inline int squashfs_xattr_lookup(struct super_block *sb,
+               unsigned int index, int *count, int *size,
+               unsigned long long *xattr)
+{
+       return 0;
+}
+#define squashfs_listxattr NULL
+#define generic_getxattr NULL
+#define squashfs_xattr_handlers NULL
+#endif
diff --git a/fs/squashfs/xattr_id.c b/fs/squashfs/xattr_id.c
new file mode 100644 (file)
index 0000000..cfb4110
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Squashfs - a compressed read only filesystem for Linux
+ *
+ * Copyright (c) 2010
+ * Phillip Lougher <phillip@lougher.demon.co.uk>
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * xattr_id.c
+ */
+
+/*
+ * This file implements code to map the 32-bit xattr id stored in the inode
+ * into the on disk location of the xattr data.
+ */
+
+#include <linux/fs.h>
+#include <linux/vfs.h>
+#include <linux/slab.h>
+
+#include "squashfs_fs.h"
+#include "squashfs_fs_sb.h"
+#include "squashfs_fs_i.h"
+#include "squashfs.h"
+
+/*
+ * Map xattr id using the xattr id look up table
+ */
+int squashfs_xattr_lookup(struct super_block *sb, unsigned int index,
+               int *count, unsigned int *size, unsigned long long *xattr)
+{
+       struct squashfs_sb_info *msblk = sb->s_fs_info;
+       int block = SQUASHFS_XATTR_BLOCK(index);
+       int offset = SQUASHFS_XATTR_BLOCK_OFFSET(index);
+       u64 start_block = le64_to_cpu(msblk->xattr_id_table[block]);
+       struct squashfs_xattr_id id;
+       int err;
+
+       err = squashfs_read_metadata(sb, &id, &start_block, &offset,
+                                                       sizeof(id));
+       if (err < 0)
+               return err;
+
+       *xattr = le64_to_cpu(id.xattr);
+       *size = le32_to_cpu(id.size);
+       *count = le32_to_cpu(id.count);
+       return 0;
+}
+
+
+/*
+ * Read uncompressed xattr id lookup table indexes from disk into memory
+ */
+__le64 *squashfs_read_xattr_id_table(struct super_block *sb, u64 start,
+               u64 *xattr_table_start, int *xattr_ids)
+{
+       unsigned int len;
+       __le64 *xid_table;
+       struct squashfs_xattr_id_table id_table;
+       int err;
+
+       err = squashfs_read_table(sb, &id_table, start, sizeof(id_table));
+       if (err < 0) {
+               ERROR("unable to read xattr id table\n");
+               return ERR_PTR(err);
+       }
+       *xattr_table_start = le64_to_cpu(id_table.xattr_table_start);
+       *xattr_ids = le32_to_cpu(id_table.xattr_ids);
+       len = SQUASHFS_XATTR_BLOCK_BYTES(*xattr_ids);
+
+       TRACE("In read_xattr_index_table, length %d\n", len);
+
+       /* Allocate xattr id lookup table indexes */
+       xid_table = kmalloc(len, GFP_KERNEL);
+       if (xid_table == NULL) {
+               ERROR("Failed to allocate xattr id index table\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       err = squashfs_read_table(sb, xid_table, start + sizeof(id_table), len);
+       if (err < 0) {
+               ERROR("unable to read xattr id index table\n");
+               kfree(xid_table);
+               return ERR_PTR(err);
+       }
+
+       return xid_table;
+}
diff --git a/fs/statfs.c b/fs/statfs.c
new file mode 100644 (file)
index 0000000..4ef021f
--- /dev/null
@@ -0,0 +1,196 @@
+#include <linux/syscalls.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/namei.h>
+#include <linux/statfs.h>
+#include <linux/security.h>
+#include <linux/uaccess.h>
+
+int vfs_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+       int retval = -ENODEV;
+
+       if (dentry) {
+               retval = -ENOSYS;
+               if (dentry->d_sb->s_op->statfs) {
+                       memset(buf, 0, sizeof(*buf));
+                       retval = security_sb_statfs(dentry);
+                       if (retval)
+                               return retval;
+                       retval = dentry->d_sb->s_op->statfs(dentry, buf);
+                       if (retval == 0 && buf->f_frsize == 0)
+                               buf->f_frsize = buf->f_bsize;
+               }
+       }
+       return retval;
+}
+
+EXPORT_SYMBOL(vfs_statfs);
+
+static int vfs_statfs_native(struct dentry *dentry, struct statfs *buf)
+{
+       struct kstatfs st;
+       int retval;
+
+       retval = vfs_statfs(dentry, &st);
+       if (retval)
+               return retval;
+
+       if (sizeof(*buf) == sizeof(st))
+               memcpy(buf, &st, sizeof(st));
+       else {
+               if (sizeof buf->f_blocks == 4) {
+                       if ((st.f_blocks | st.f_bfree | st.f_bavail |
+                            st.f_bsize | st.f_frsize) &
+                           0xffffffff00000000ULL)
+                               return -EOVERFLOW;
+                       /*
+                        * f_files and f_ffree may be -1; it's okay to stuff
+                        * that into 32 bits
+                        */
+                       if (st.f_files != -1 &&
+                           (st.f_files & 0xffffffff00000000ULL))
+                               return -EOVERFLOW;
+                       if (st.f_ffree != -1 &&
+                           (st.f_ffree & 0xffffffff00000000ULL))
+                               return -EOVERFLOW;
+               }
+
+               buf->f_type = st.f_type;
+               buf->f_bsize = st.f_bsize;
+               buf->f_blocks = st.f_blocks;
+               buf->f_bfree = st.f_bfree;
+               buf->f_bavail = st.f_bavail;
+               buf->f_files = st.f_files;
+               buf->f_ffree = st.f_ffree;
+               buf->f_fsid = st.f_fsid;
+               buf->f_namelen = st.f_namelen;
+               buf->f_frsize = st.f_frsize;
+               memset(buf->f_spare, 0, sizeof(buf->f_spare));
+       }
+       return 0;
+}
+
+static int vfs_statfs64(struct dentry *dentry, struct statfs64 *buf)
+{
+       struct kstatfs st;
+       int retval;
+
+       retval = vfs_statfs(dentry, &st);
+       if (retval)
+               return retval;
+
+       if (sizeof(*buf) == sizeof(st))
+               memcpy(buf, &st, sizeof(st));
+       else {
+               buf->f_type = st.f_type;
+               buf->f_bsize = st.f_bsize;
+               buf->f_blocks = st.f_blocks;
+               buf->f_bfree = st.f_bfree;
+               buf->f_bavail = st.f_bavail;
+               buf->f_files = st.f_files;
+               buf->f_ffree = st.f_ffree;
+               buf->f_fsid = st.f_fsid;
+               buf->f_namelen = st.f_namelen;
+               buf->f_frsize = st.f_frsize;
+               memset(buf->f_spare, 0, sizeof(buf->f_spare));
+       }
+       return 0;
+}
+
+SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, buf)
+{
+       struct path path;
+       int error;
+
+       error = user_path(pathname, &path);
+       if (!error) {
+               struct statfs tmp;
+               error = vfs_statfs_native(path.dentry, &tmp);
+               if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
+                       error = -EFAULT;
+               path_put(&path);
+       }
+       return error;
+}
+
+SYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct statfs64 __user *, buf)
+{
+       struct path path;
+       long error;
+
+       if (sz != sizeof(*buf))
+               return -EINVAL;
+       error = user_path(pathname, &path);
+       if (!error) {
+               struct statfs64 tmp;
+               error = vfs_statfs64(path.dentry, &tmp);
+               if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
+                       error = -EFAULT;
+               path_put(&path);
+       }
+       return error;
+}
+
+SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf)
+{
+       struct file *file;
+       struct statfs tmp;
+       int error;
+
+       error = -EBADF;
+       file = fget(fd);
+       if (!file)
+               goto out;
+       error = vfs_statfs_native(file->f_path.dentry, &tmp);
+       if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
+               error = -EFAULT;
+       fput(file);
+out:
+       return error;
+}
+
+SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user *, buf)
+{
+       struct file *file;
+       struct statfs64 tmp;
+       int error;
+
+       if (sz != sizeof(*buf))
+               return -EINVAL;
+
+       error = -EBADF;
+       file = fget(fd);
+       if (!file)
+               goto out;
+       error = vfs_statfs64(file->f_path.dentry, &tmp);
+       if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
+               error = -EFAULT;
+       fput(file);
+out:
+       return error;
+}
+
+SYSCALL_DEFINE2(ustat, unsigned, dev, struct ustat __user *, ubuf)
+{
+       struct super_block *s;
+       struct ustat tmp;
+       struct kstatfs sbuf;
+       int err;
+
+       s = user_get_super(new_decode_dev(dev));
+       if (!s)
+               return -EINVAL;
+
+       err = vfs_statfs(s->s_root, &sbuf);
+       drop_super(s);
+       if (err)
+               return err;
+
+       memset(&tmp,0,sizeof(struct ustat));
+       tmp.f_tfree = sbuf.f_bfree;
+       tmp.f_tinode = sbuf.f_ffree;
+
+       return copy_to_user(ubuf, &tmp, sizeof(struct ustat)) ? -EFAULT : 0;
+}
index 1527e6a0ee358d084a29f542816a91c4418f5ef6..5c35bc7a499e19c97b0f8eba3a91a8224a46ffe4 100644 (file)
 
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/acct.h>
 #include <linux/blkdev.h>
-#include <linux/quotaops.h>
-#include <linux/namei.h>
 #include <linux/mount.h>
 #include <linux/security.h>
-#include <linux/syscalls.h>
-#include <linux/vfs.h>
 #include <linux/writeback.h>           /* for the emergency remount stuff */
 #include <linux/idr.h>
-#include <linux/kobject.h>
 #include <linux/mutex.h>
-#include <linux/file.h>
 #include <linux/backing-dev.h>
-#include <asm/uaccess.h>
 #include "internal.h"
 
 
@@ -93,16 +84,15 @@ static struct super_block *alloc_super(struct file_system_type *type)
                 * subclass.
                 */
                down_write_nested(&s->s_umount, SINGLE_DEPTH_NESTING);
-               s->s_count = S_BIAS;
+               s->s_count = 1;
                atomic_set(&s->s_active, 1);
                mutex_init(&s->s_vfs_rename_mutex);
+               lockdep_set_class(&s->s_vfs_rename_mutex, &type->s_vfs_rename_key);
                mutex_init(&s->s_dquot.dqio_mutex);
                mutex_init(&s->s_dquot.dqonoff_mutex);
                init_rwsem(&s->s_dquot.dqptr_sem);
                init_waitqueue_head(&s->s_wait_unfrozen);
                s->s_maxbytes = MAX_NON_LFS;
-               s->dq_op = sb_dquot_ops;
-               s->s_qcop = sb_quotactl_ops;
                s->s_op = &default_op;
                s->s_time_gran = 1000000000;
        }
@@ -127,39 +117,14 @@ static inline void destroy_super(struct super_block *s)
 /* Superblock refcounting  */
 
 /*
- * Drop a superblock's refcount.  Returns non-zero if the superblock was
- * destroyed.  The caller must hold sb_lock.
+ * Drop a superblock's refcount.  The caller must hold sb_lock.
  */
-static int __put_super(struct super_block *sb)
+void __put_super(struct super_block *sb)
 {
-       int ret = 0;
-
        if (!--sb->s_count) {
+               list_del_init(&sb->s_list);
                destroy_super(sb);
-               ret = 1;
-       }
-       return ret;
-}
-
-/*
- * Drop a superblock's refcount.
- * Returns non-zero if the superblock is about to be destroyed and
- * at least is already removed from super_blocks list, so if we are
- * making a loop through super blocks then we need to restart.
- * The caller must hold sb_lock.
- */
-int __put_super_and_need_restart(struct super_block *sb)
-{
-       /* check for race with generic_shutdown_super() */
-       if (list_empty(&sb->s_list)) {
-               /* super block is removed, need to restart... */
-               __put_super(sb);
-               return 1;
        }
-       /* can't be the last, since s_list is still in use */
-       sb->s_count--;
-       BUG_ON(sb->s_count == 0);
-       return 0;
 }
 
 /**
@@ -178,57 +143,47 @@ void put_super(struct super_block *sb)
 
 
 /**
- *     deactivate_super        -       drop an active reference to superblock
+ *     deactivate_locked_super -       drop an active reference to superblock
  *     @s: superblock to deactivate
  *
- *     Drops an active reference to superblock, acquiring a temprory one if
- *     there is no active references left.  In that case we lock superblock,
+ *     Drops an active reference to superblock, converting it into a temprory
+ *     one if there is no other active references left.  In that case we
  *     tell fs driver to shut it down and drop the temporary reference we
  *     had just acquired.
+ *
+ *     Caller holds exclusive lock on superblock; that lock is released.
  */
-void deactivate_super(struct super_block *s)
+void deactivate_locked_super(struct super_block *s)
 {
        struct file_system_type *fs = s->s_type;
-       if (atomic_dec_and_lock(&s->s_active, &sb_lock)) {
-               s->s_count -= S_BIAS-1;
-               spin_unlock(&sb_lock);
-               vfs_dq_off(s, 0);
-               down_write(&s->s_umount);
+       if (atomic_dec_and_test(&s->s_active)) {
                fs->kill_sb(s);
                put_filesystem(fs);
                put_super(s);
+       } else {
+               up_write(&s->s_umount);
        }
 }
 
-EXPORT_SYMBOL(deactivate_super);
+EXPORT_SYMBOL(deactivate_locked_super);
 
 /**
- *     deactivate_locked_super -       drop an active reference to superblock
+ *     deactivate_super        -       drop an active reference to superblock
  *     @s: superblock to deactivate
  *
- *     Equivalent of up_write(&s->s_umount); deactivate_super(s);, except that
- *     it does not unlock it until it's all over.  As the result, it's safe to
- *     use to dispose of new superblock on ->get_sb() failure exits - nobody
- *     will see the sucker until it's all over.  Equivalent using up_write +
- *     deactivate_super is safe for that purpose only if superblock is either
- *     safe to use or has NULL ->s_root when we unlock.
+ *     Variant of deactivate_locked_super(), except that superblock is *not*
+ *     locked by caller.  If we are going to drop the final active reference,
+ *     lock will be acquired prior to that.
  */
-void deactivate_locked_super(struct super_block *s)
+void deactivate_super(struct super_block *s)
 {
-       struct file_system_type *fs = s->s_type;
-       if (atomic_dec_and_lock(&s->s_active, &sb_lock)) {
-               s->s_count -= S_BIAS-1;
-               spin_unlock(&sb_lock);
-               vfs_dq_off(s, 0);
-               fs->kill_sb(s);
-               put_filesystem(fs);
-               put_super(s);
-       } else {
-               up_write(&s->s_umount);
+        if (!atomic_add_unless(&s->s_active, -1, 1)) {
+               down_write(&s->s_umount);
+               deactivate_locked_super(s);
        }
 }
 
-EXPORT_SYMBOL(deactivate_locked_super);
+EXPORT_SYMBOL(deactivate_super);
 
 /**
  *     grab_super - acquire an active reference
@@ -243,22 +198,17 @@ EXPORT_SYMBOL(deactivate_locked_super);
  */
 static int grab_super(struct super_block *s) __releases(sb_lock)
 {
+       if (atomic_inc_not_zero(&s->s_active)) {
+               spin_unlock(&sb_lock);
+               return 1;
+       }
+       /* it's going away */
        s->s_count++;
        spin_unlock(&sb_lock);
+       /* wait for it to die */
        down_write(&s->s_umount);
-       if (s->s_root) {
-               spin_lock(&sb_lock);
-               if (s->s_count > S_BIAS) {
-                       atomic_inc(&s->s_active);
-                       s->s_count--;
-                       spin_unlock(&sb_lock);
-                       return 1;
-               }
-               spin_unlock(&sb_lock);
-       }
        up_write(&s->s_umount);
        put_super(s);
-       yield();
        return 0;
 }
 
@@ -321,8 +271,7 @@ void generic_shutdown_super(struct super_block *sb)
        }
        spin_lock(&sb_lock);
        /* should be initialized for __put_super_and_need_restart() */
-       list_del_init(&sb->s_list);
-       list_del(&sb->s_instances);
+       list_del_init(&sb->s_instances);
        spin_unlock(&sb_lock);
        up_write(&sb->s_umount);
 }
@@ -357,6 +306,7 @@ retry:
                                up_write(&s->s_umount);
                                destroy_super(s);
                        }
+                       down_write(&old->s_umount);
                        return old;
                }
        }
@@ -408,11 +358,12 @@ EXPORT_SYMBOL(drop_super);
  */
 void sync_supers(void)
 {
-       struct super_block *sb;
+       struct super_block *sb, *n;
 
        spin_lock(&sb_lock);
-restart:
-       list_for_each_entry(sb, &super_blocks, s_list) {
+       list_for_each_entry_safe(sb, n, &super_blocks, s_list) {
+               if (list_empty(&sb->s_instances))
+                       continue;
                if (sb->s_op->write_super && sb->s_dirt) {
                        sb->s_count++;
                        spin_unlock(&sb_lock);
@@ -423,13 +374,42 @@ restart:
                        up_read(&sb->s_umount);
 
                        spin_lock(&sb_lock);
-                       if (__put_super_and_need_restart(sb))
-                               goto restart;
+                       __put_super(sb);
                }
        }
        spin_unlock(&sb_lock);
 }
 
+/**
+ *     iterate_supers - call function for all active superblocks
+ *     @f: function to call
+ *     @arg: argument to pass to it
+ *
+ *     Scans the superblock list and calls given function, passing it
+ *     locked superblock and given argument.
+ */
+void iterate_supers(void (*f)(struct super_block *, void *), void *arg)
+{
+       struct super_block *sb, *n;
+
+       spin_lock(&sb_lock);
+       list_for_each_entry_safe(sb, n, &super_blocks, s_list) {
+               if (list_empty(&sb->s_instances))
+                       continue;
+               sb->s_count++;
+               spin_unlock(&sb_lock);
+
+               down_read(&sb->s_umount);
+               if (sb->s_root)
+                       f(sb, arg);
+               up_read(&sb->s_umount);
+
+               spin_lock(&sb_lock);
+               __put_super(sb);
+       }
+       spin_unlock(&sb_lock);
+}
+
 /**
  *     get_super - get the superblock of a device
  *     @bdev: device to get the superblock for
@@ -438,7 +418,7 @@ restart:
  *     mounted on the device given. %NULL is returned if no match is found.
  */
 
-struct super_block * get_super(struct block_device *bdev)
+struct super_block *get_super(struct block_device *bdev)
 {
        struct super_block *sb;
 
@@ -448,17 +428,20 @@ struct super_block * get_super(struct block_device *bdev)
        spin_lock(&sb_lock);
 rescan:
        list_for_each_entry(sb, &super_blocks, s_list) {
+               if (list_empty(&sb->s_instances))
+                       continue;
                if (sb->s_bdev == bdev) {
                        sb->s_count++;
                        spin_unlock(&sb_lock);
                        down_read(&sb->s_umount);
+                       /* still alive? */
                        if (sb->s_root)
                                return sb;
                        up_read(&sb->s_umount);
-                       /* restart only when sb is no longer on the list */
+                       /* nope, got unmounted */
                        spin_lock(&sb_lock);
-                       if (__put_super_and_need_restart(sb))
-                               goto rescan;
+                       __put_super(sb);
+                       goto rescan;
                }
        }
        spin_unlock(&sb_lock);
@@ -473,7 +456,7 @@ EXPORT_SYMBOL(get_super);
  *
  * Scans the superblock list and finds the superblock of the file system
  * mounted on the device given.  Returns the superblock with an active
- * reference and s_umount held exclusively or %NULL if none was found.
+ * reference or %NULL if none was found.
  */
 struct super_block *get_active_super(struct block_device *bdev)
 {
@@ -482,81 +465,49 @@ struct super_block *get_active_super(struct block_device *bdev)
        if (!bdev)
                return NULL;
 
+restart:
        spin_lock(&sb_lock);
        list_for_each_entry(sb, &super_blocks, s_list) {
-               if (sb->s_bdev != bdev)
+               if (list_empty(&sb->s_instances))
                        continue;
-
-               sb->s_count++;
-               spin_unlock(&sb_lock);
-               down_write(&sb->s_umount);
-               if (sb->s_root) {
-                       spin_lock(&sb_lock);
-                       if (sb->s_count > S_BIAS) {
-                               atomic_inc(&sb->s_active);
-                               sb->s_count--;
-                               spin_unlock(&sb_lock);
+               if (sb->s_bdev == bdev) {
+                       if (grab_super(sb)) /* drops sb_lock */
                                return sb;
-                       }
-                       spin_unlock(&sb_lock);
+                       else
+                               goto restart;
                }
-               up_write(&sb->s_umount);
-               put_super(sb);
-               yield();
-               spin_lock(&sb_lock);
        }
        spin_unlock(&sb_lock);
        return NULL;
 }
  
-struct super_block * user_get_super(dev_t dev)
+struct super_block *user_get_super(dev_t dev)
 {
        struct super_block *sb;
 
        spin_lock(&sb_lock);
 rescan:
        list_for_each_entry(sb, &super_blocks, s_list) {
+               if (list_empty(&sb->s_instances))
+                       continue;
                if (sb->s_dev ==  dev) {
                        sb->s_count++;
                        spin_unlock(&sb_lock);
                        down_read(&sb->s_umount);
+                       /* still alive? */
                        if (sb->s_root)
                                return sb;
                        up_read(&sb->s_umount);
-                       /* restart only when sb is no longer on the list */
+                       /* nope, got unmounted */
                        spin_lock(&sb_lock);
-                       if (__put_super_and_need_restart(sb))
-                               goto rescan;
+                       __put_super(sb);
+                       goto rescan;
                }
        }
        spin_unlock(&sb_lock);
        return NULL;
 }
 
-SYSCALL_DEFINE2(ustat, unsigned, dev, struct ustat __user *, ubuf)
-{
-        struct super_block *s;
-        struct ustat tmp;
-        struct kstatfs sbuf;
-       int err = -EINVAL;
-
-        s = user_get_super(new_decode_dev(dev));
-        if (s == NULL)
-                goto out;
-       err = vfs_statfs(s->s_root, &sbuf);
-       drop_super(s);
-       if (err)
-               goto out;
-
-        memset(&tmp,0,sizeof(struct ustat));
-        tmp.f_tfree = sbuf.f_bfree;
-        tmp.f_tinode = sbuf.f_ffree;
-
-        err = copy_to_user(ubuf,&tmp,sizeof(struct ustat)) ? -EFAULT : 0;
-out:
-       return err;
-}
-
 /**
  *     do_remount_sb - asks filesystem to change mount options.
  *     @sb:    superblock in question
@@ -569,7 +520,7 @@ out:
 int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
 {
        int retval;
-       int remount_rw, remount_ro;
+       int remount_ro;
 
        if (sb->s_frozen != SB_UNFROZEN)
                return -EBUSY;
@@ -585,7 +536,6 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
        sync_filesystem(sb);
 
        remount_ro = (flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY);
-       remount_rw = !(flags & MS_RDONLY) && (sb->s_flags & MS_RDONLY);
 
        /* If we are remounting RDONLY and current sb is read/write,
           make sure there are no rw files opened */
@@ -594,9 +544,6 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
                        mark_files_ro(sb);
                else if (!fs_may_remount_ro(sb))
                        return -EBUSY;
-               retval = vfs_dq_off(sb, 1);
-               if (retval < 0 && retval != -ENOSYS)
-                       return -EBUSY;
        }
 
        if (sb->s_op->remount_fs) {
@@ -605,8 +552,7 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
                        return retval;
        }
        sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);
-       if (remount_rw)
-               vfs_dq_quota_on_remount(sb);
+
        /*
         * Some filesystems modify their metadata via some other path than the
         * bdev buffer cache (eg. use a private mapping, or directories in
@@ -622,24 +568,24 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
 
 static void do_emergency_remount(struct work_struct *work)
 {
-       struct super_block *sb;
+       struct super_block *sb, *n;
 
        spin_lock(&sb_lock);
-       list_for_each_entry(sb, &super_blocks, s_list) {
+       list_for_each_entry_safe(sb, n, &super_blocks, s_list) {
+               if (list_empty(&sb->s_instances))
+                       continue;
                sb->s_count++;
                spin_unlock(&sb_lock);
                down_write(&sb->s_umount);
                if (sb->s_root && sb->s_bdev && !(sb->s_flags & MS_RDONLY)) {
                        /*
-                        * ->remount_fs needs lock_kernel().
-                        *
                         * What lock protects sb->s_flags??
                         */
                        do_remount_sb(sb, MS_RDONLY, NULL, 1);
                }
                up_write(&sb->s_umount);
-               put_super(sb);
                spin_lock(&sb_lock);
+               __put_super(sb);
        }
        spin_unlock(&sb_lock);
        kfree(work);
@@ -990,6 +936,96 @@ out:
 
 EXPORT_SYMBOL_GPL(vfs_kern_mount);
 
+/**
+ * freeze_super - lock the filesystem and force it into a consistent state
+ * @sb: the super to lock
+ *
+ * Syncs the super to make sure the filesystem is consistent and calls the fs's
+ * freeze_fs.  Subsequent calls to this without first thawing the fs will return
+ * -EBUSY.
+ */
+int freeze_super(struct super_block *sb)
+{
+       int ret;
+
+       atomic_inc(&sb->s_active);
+       down_write(&sb->s_umount);
+       if (sb->s_frozen) {
+               deactivate_locked_super(sb);
+               return -EBUSY;
+       }
+
+       if (sb->s_flags & MS_RDONLY) {
+               sb->s_frozen = SB_FREEZE_TRANS;
+               smp_wmb();
+               up_write(&sb->s_umount);
+               return 0;
+       }
+
+       sb->s_frozen = SB_FREEZE_WRITE;
+       smp_wmb();
+
+       sync_filesystem(sb);
+
+       sb->s_frozen = SB_FREEZE_TRANS;
+       smp_wmb();
+
+       sync_blockdev(sb->s_bdev);
+       if (sb->s_op->freeze_fs) {
+               ret = sb->s_op->freeze_fs(sb);
+               if (ret) {
+                       printk(KERN_ERR
+                               "VFS:Filesystem freeze failed\n");
+                       sb->s_frozen = SB_UNFROZEN;
+                       deactivate_locked_super(sb);
+                       return ret;
+               }
+       }
+       up_write(&sb->s_umount);
+       return 0;
+}
+EXPORT_SYMBOL(freeze_super);
+
+/**
+ * thaw_super -- unlock filesystem
+ * @sb: the super to thaw
+ *
+ * Unlocks the filesystem and marks it writeable again after freeze_super().
+ */
+int thaw_super(struct super_block *sb)
+{
+       int error;
+
+       down_write(&sb->s_umount);
+       if (sb->s_frozen == SB_UNFROZEN) {
+               up_write(&sb->s_umount);
+               return -EINVAL;
+       }
+
+       if (sb->s_flags & MS_RDONLY)
+               goto out;
+
+       if (sb->s_op->unfreeze_fs) {
+               error = sb->s_op->unfreeze_fs(sb);
+               if (error) {
+                       printk(KERN_ERR
+                               "VFS:Filesystem thaw failed\n");
+                       sb->s_frozen = SB_FREEZE_TRANS;
+                       up_write(&sb->s_umount);
+                       return error;
+               }
+       }
+
+out:
+       sb->s_frozen = SB_UNFROZEN;
+       smp_wmb();
+       wake_up(&sb->s_wait_unfrozen);
+       deactivate_locked_super(sb);
+
+       return 0;
+}
+EXPORT_SYMBOL(thaw_super);
+
 static struct vfsmount *fs_set_subtype(struct vfsmount *mnt, const char *fstype)
 {
        int err;
index de6a441928325b9059dac2d75c38519876e0be09..c9f83f480ec55ec751d41021c73c9b3aa8c0b99a 100644 (file)
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -77,50 +77,18 @@ int sync_filesystem(struct super_block *sb)
 }
 EXPORT_SYMBOL_GPL(sync_filesystem);
 
+static void sync_one_sb(struct super_block *sb, void *arg)
+{
+       if (!(sb->s_flags & MS_RDONLY) && sb->s_bdi)
+               __sync_filesystem(sb, *(int *)arg);
+}
 /*
  * Sync all the data for all the filesystems (called by sys_sync() and
  * emergency sync)
- *
- * This operation is careful to avoid the livelock which could easily happen
- * if two or more filesystems are being continuously dirtied.  s_need_sync
- * is used only here.  We set it against all filesystems and then clear it as
- * we sync them.  So redirtied filesystems are skipped.
- *
- * But if process A is currently running sync_filesystems and then process B
- * calls sync_filesystems as well, process B will set all the s_need_sync
- * flags again, which will cause process A to resync everything.  Fix that with
- * a local mutex.
  */
 static void sync_filesystems(int wait)
 {
-       struct super_block *sb;
-       static DEFINE_MUTEX(mutex);
-
-       mutex_lock(&mutex);             /* Could be down_interruptible */
-       spin_lock(&sb_lock);
-       list_for_each_entry(sb, &super_blocks, s_list)
-               sb->s_need_sync = 1;
-
-restart:
-       list_for_each_entry(sb, &super_blocks, s_list) {
-               if (!sb->s_need_sync)
-                       continue;
-               sb->s_need_sync = 0;
-               sb->s_count++;
-               spin_unlock(&sb_lock);
-
-               down_read(&sb->s_umount);
-               if (!(sb->s_flags & MS_RDONLY) && sb->s_root && sb->s_bdi)
-                       __sync_filesystem(sb, wait);
-               up_read(&sb->s_umount);
-
-               /* restart only when sb is no longer on the list */
-               spin_lock(&sb_lock);
-               if (__put_super_and_need_restart(sb))
-                       goto restart;
-       }
-       spin_unlock(&sb_lock);
-       mutex_unlock(&mutex);
+       iterate_supers(sync_one_sb, &wait);
 }
 
 /*
@@ -162,12 +130,10 @@ void emergency_sync(void)
 
 /*
  * Generic function to fsync a file.
- *
- * filp may be NULL if called via the msync of a vma.
  */
-int file_fsync(struct file *filp, struct dentry *dentry, int datasync)
+int file_fsync(struct file *filp, int datasync)
 {
-       struct inode * inode = dentry->d_inode;
+       struct inode *inode = filp->f_mapping->host;
        struct super_block * sb;
        int ret, err;
 
@@ -190,7 +156,6 @@ EXPORT_SYMBOL(file_fsync);
 /**
  * vfs_fsync_range - helper to sync a range of data & metadata to disk
  * @file:              file to sync
- * @dentry:            dentry of @file
  * @start:             offset in bytes of the beginning of data range to sync
  * @end:               offset in bytes of the end of data range (inclusive)
  * @datasync:          perform only datasync
@@ -198,32 +163,13 @@ EXPORT_SYMBOL(file_fsync);
  * Write back data in range @start..@end and metadata for @file to disk.  If
  * @datasync is set only metadata needed to access modified file data is
  * written.
- *
- * In case this function is called from nfsd @file may be %NULL and
- * only @dentry is set.  This can only happen when the filesystem
- * implements the export_operations API.
  */
-int vfs_fsync_range(struct file *file, struct dentry *dentry, loff_t start,
-                   loff_t end, int datasync)
+int vfs_fsync_range(struct file *file, loff_t start, loff_t end, int datasync)
 {
-       const struct file_operations *fop;
-       struct address_space *mapping;
+       struct address_space *mapping = file->f_mapping;
        int err, ret;
 
-       /*
-        * Get mapping and operations from the file in case we have
-        * as file, or get the default values for them in case we
-        * don't have a struct file available.  Damn nfsd..
-        */
-       if (file) {
-               mapping = file->f_mapping;
-               fop = file->f_op;
-       } else {
-               mapping = dentry->d_inode->i_mapping;
-               fop = dentry->d_inode->i_fop;
-       }
-
-       if (!fop || !fop->fsync) {
+       if (!file->f_op || !file->f_op->fsync) {
                ret = -EINVAL;
                goto out;
        }
@@ -235,7 +181,7 @@ int vfs_fsync_range(struct file *file, struct dentry *dentry, loff_t start,
         * livelocks in fsync_buffers_list().
         */
        mutex_lock(&mapping->host->i_mutex);
-       err = fop->fsync(file, dentry, datasync);
+       err = file->f_op->fsync(file, datasync);
        if (!ret)
                ret = err;
        mutex_unlock(&mapping->host->i_mutex);
@@ -248,19 +194,14 @@ EXPORT_SYMBOL(vfs_fsync_range);
 /**
  * vfs_fsync - perform a fsync or fdatasync on a file
  * @file:              file to sync
- * @dentry:            dentry of @file
  * @datasync:          only perform a fdatasync operation
  *
  * Write back data and metadata for @file to disk.  If @datasync is
  * set only metadata needed to access modified file data is written.
- *
- * In case this function is called from nfsd @file may be %NULL and
- * only @dentry is set.  This can only happen when the filesystem
- * implements the export_operations API.
  */
-int vfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+int vfs_fsync(struct file *file, int datasync)
 {
-       return vfs_fsync_range(file, dentry, 0, LLONG_MAX, datasync);
+       return vfs_fsync_range(file, 0, LLONG_MAX, datasync);
 }
 EXPORT_SYMBOL(vfs_fsync);
 
@@ -271,7 +212,7 @@ static int do_fsync(unsigned int fd, int datasync)
 
        file = fget(fd);
        if (file) {
-               ret = vfs_fsync(file, file->f_path.dentry, datasync);
+               ret = vfs_fsync(file, datasync);
                fput(file);
        }
        return ret;
@@ -299,8 +240,7 @@ int generic_write_sync(struct file *file, loff_t pos, loff_t count)
 {
        if (!(file->f_flags & O_DSYNC) && !IS_SYNC(file->f_mapping->host))
                return 0;
-       return vfs_fsync_range(file, file->f_path.dentry, pos,
-                              pos + count - 1,
+       return vfs_fsync_range(file, pos, pos + count - 1,
                               (file->f_flags & __O_SYNC) ? 0 : 1);
 }
 EXPORT_SYMBOL(generic_write_sync);
index bbd77e95cf7f7d6babe801fcac345d7cfcd7599f..bde1a4c3679a3c38bb5005a473fce4c8e3037e54 100644 (file)
@@ -117,13 +117,11 @@ int sysfs_setattr(struct dentry *dentry, struct iattr *iattr)
        if (error)
                goto out;
 
-       iattr->ia_valid &= ~ATTR_SIZE; /* ignore size changes */
-
-       error = inode_setattr(inode, iattr);
-       if (error)
-               goto out;
+       /* this ignores size changes */
+       generic_setattr(inode, iattr);
 
        error = sysfs_sd_setattr(sd, iattr);
+
 out:
        mutex_unlock(&sysfs_mutex);
        return error;
index 1dabed286b4cf061a34c8521f5b1e44b81147089..79941e4964a4eda4b1a55255fddbc2b6e1d853ef 100644 (file)
@@ -24,7 +24,7 @@ const struct file_operations sysv_dir_operations = {
        .llseek         = generic_file_llseek,
        .read           = generic_read_dir,
        .readdir        = sysv_readdir,
-       .fsync          = simple_fsync,
+       .fsync          = generic_file_fsync,
 };
 
 static inline void dir_put_page(struct page *page)
index 96340c01f4a7f4757aaaf62830c66b4a122cb134..750cc22349bd67b509da4985f631321a4962f6b3 100644 (file)
@@ -26,7 +26,7 @@ const struct file_operations sysv_file_operations = {
        .write          = do_sync_write,
        .aio_write      = generic_file_aio_write,
        .mmap           = generic_file_mmap,
-       .fsync          = simple_fsync,
+       .fsync          = generic_file_fsync,
        .splice_read    = generic_file_splice_read,
 };
 
index 241e9765cfadfd9f2f9bd1f68fd355e8c5358959..bbd69bdb0fa8cc9ccba41fec291fa13af43f796f 100644 (file)
@@ -159,15 +159,7 @@ struct inode * sysv_new_inode(const struct inode * dir, mode_t mode)
        *sbi->s_sb_fic_count = cpu_to_fs16(sbi, count);
        fs16_add(sbi, sbi->s_sb_total_free_inodes, -1);
        dirty_sb(sb);
-       
-       if (dir->i_mode & S_ISGID) {
-               inode->i_gid = dir->i_gid;
-               if (S_ISDIR(mode))
-                       mode |= S_ISGID;
-       } else
-               inode->i_gid = current_fsgid();
-
-       inode->i_uid = current_fsuid();
+       inode_init_owner(inode, dir, mode);
        inode->i_ino = fs16_to_cpu(sbi, ino);
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
        inode->i_blocks = 0;
@@ -176,7 +168,6 @@ struct inode * sysv_new_inode(const struct inode * dir, mode_t mode)
        insert_inode_hash(inode);
        mark_inode_dirty(inode);
 
-       inode->i_mode = mode;           /* for sysv_write_inode() */
        sysv_write_inode(inode, 0);     /* ensure inode not allocated again */
        mark_inode_dirty(inode);        /* cleared by sysv_write_inode() */
        /* That's it. */
index 4573734d723dd3dc0a9cdccfd135505ec315930c..d4a5380b566955549a2ee8cf005d724a2a53cede 100644 (file)
@@ -43,6 +43,7 @@ static int sysv_sync_fs(struct super_block *sb, int wait)
         * then attach current time stamp.
         * But if the filesystem was marked clean, keep it clean.
         */
+       sb->s_dirt = 0;
        old_time = fs32_to_cpu(sbi, *sbi->s_sb_time);
        if (sbi->s_type == FSTYPE_SYSV4) {
                if (*sbi->s_sb_state == cpu_to_fs32(sbi, 0x7c269d38 - old_time))
index 401e503d44a147da68e4b0a0f2fad7f518949a55..87ebcce72213e2889f66127125908190a4ef213d 100644 (file)
@@ -104,14 +104,7 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
         */
        inode->i_flags |= (S_NOCMTIME);
 
-       inode->i_uid = current_fsuid();
-       if (dir->i_mode & S_ISGID) {
-               inode->i_gid = dir->i_gid;
-               if (S_ISDIR(mode))
-                       mode |= S_ISGID;
-       } else
-               inode->i_gid = current_fsgid();
-       inode->i_mode = mode;
+       inode_init_owner(inode, dir, mode);
        inode->i_mtime = inode->i_atime = inode->i_ctime =
                         ubifs_current_time(inode);
        inode->i_mapping->nrpages = 0;
index 5692cf72b80737e0b87da9a22c58dbe2e52b371b..12f445cee9f7ba90a6b4a33eeb1dc18be5df3a0d 100644 (file)
@@ -967,12 +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 'vmtruncate()', which first changes @inode->i_size, then
+ * we have to call 'simple_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 'vmtruncate()' with
+ * lock. This means that 'do_truncation()' cannot call 'simple_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.
+ *
  * 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
  * are in the middle of 'ubifs_writepage()'? The UBIFS solution is the
@@ -1125,7 +1128,7 @@ static int do_truncation(struct ubifs_info *c, struct inode *inode,
                budgeted = 0;
        }
 
-       err = vmtruncate(inode, new_size);
+       err = simple_setsize(inode, new_size);
        if (err)
                goto out_budg;
 
@@ -1214,7 +1217,7 @@ 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 = vmtruncate(inode, new_size);
+               err = simple_setsize(inode, new_size);
                if (err)
                        goto out;
        }
@@ -1223,7 +1226,7 @@ static int do_setattr(struct ubifs_info *c, struct inode *inode,
        if (attr->ia_valid & ATTR_SIZE) {
                /* Truncation changes inode [mc]time */
                inode->i_mtime = inode->i_ctime = ubifs_current_time(inode);
-               /* 'vmtruncate()' changed @i_size, update @ui_size */
+               /* 'simple_setsize()' changed @i_size, update @ui_size */
                ui->ui_size = inode->i_size;
        }
 
@@ -1304,9 +1307,9 @@ static void *ubifs_follow_link(struct dentry *dentry, struct nameidata *nd)
        return NULL;
 }
 
-int ubifs_fsync(struct file *file, struct dentry *dentry, int datasync)
+int ubifs_fsync(struct file *file, int datasync)
 {
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = file->f_mapping->host;
        struct ubifs_info *c = inode->i_sb->s_fs_info;
        int err;
 
index bd2542dad014c947f27c0145b7985bc8fdcee4e1..2eef553d50c817e6276e994f4aee80971cdf2191 100644 (file)
@@ -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 'vmtruncate()' with @ui_mutex locked, because it would deadlock
+ * cannot call 'simple_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.
@@ -1678,7 +1678,7 @@ const struct ubifs_lprops *ubifs_fast_find_frdi_idx(struct ubifs_info *c);
 int ubifs_calc_dark(const struct ubifs_info *c, int spc);
 
 /* file.c */
-int ubifs_fsync(struct file *file, struct dentry *dentry, int datasync);
+int ubifs_fsync(struct file *file, int datasync);
 int ubifs_setattr(struct dentry *dentry, struct iattr *attr);
 
 /* dir.c */
index 9a9378b4eb5ae2c89495b9025d7be8c5aa04ef5b..b608efaa4cee16426016f8702268967f943b9621 100644 (file)
@@ -21,7 +21,6 @@
 
 #include "udfdecl.h"
 
-#include <linux/quotaops.h>
 #include <linux/buffer_head.h>
 #include <linux/bitops.h>
 
@@ -159,8 +158,6 @@ static void udf_bitmap_free_blocks(struct super_block *sb,
                                udf_debug("byte=%2x\n",
                                        ((char *)bh->b_data)[(bit + i) >> 3]);
                        } else {
-                               if (inode)
-                                       dquot_free_block(inode, 1);
                                udf_add_free_space(sb, sbi->s_partition, 1);
                        }
                }
@@ -210,15 +207,8 @@ static int udf_bitmap_prealloc_blocks(struct super_block *sb,
                bit = block % (sb->s_blocksize << 3);
 
                while (bit < (sb->s_blocksize << 3) && block_count > 0) {
-                       if (!udf_test_bit(bit, bh->b_data))
+                       if (!udf_clear_bit(bit, bh->b_data))
                                goto out;
-                       else if (dquot_prealloc_block(inode, 1))
-                               goto out;
-                       else if (!udf_clear_bit(bit, bh->b_data)) {
-                               udf_debug("bit already cleared for block %d\n", bit);
-                               dquot_free_block(inode, 1);
-                               goto out;
-                       }
                        block_count--;
                        alloc_count++;
                        bit++;
@@ -338,20 +328,6 @@ search_back:
        }
 
 got_block:
-
-       /*
-        * Check quota for allocation of this block.
-        */
-       if (inode) {
-               int ret = dquot_alloc_block(inode, 1);
-
-               if (ret) {
-                       mutex_unlock(&sbi->s_alloc_mutex);
-                       *err = ret;
-                       return 0;
-               }
-       }
-
        newblock = bit + (block_group << (sb->s_blocksize_bits + 3)) -
                (sizeof(struct spaceBitmapDesc) << 3);
 
@@ -401,10 +377,6 @@ static void udf_table_free_blocks(struct super_block *sb,
        }
 
        iinfo = UDF_I(table);
-       /* We do this up front - There are some error conditions that
-          could occure, but.. oh well */
-       if (inode)
-               dquot_free_block(inode, count);
        udf_add_free_space(sb, sbi->s_partition, count);
 
        start = bloc->logicalBlockNum + offset;
@@ -649,10 +621,7 @@ static int udf_table_prealloc_blocks(struct super_block *sb,
                epos.offset -= adsize;
 
                alloc_count = (elen >> sb->s_blocksize_bits);
-               if (inode && dquot_prealloc_block(inode,
-                       alloc_count > block_count ? block_count : alloc_count))
-                       alloc_count = 0;
-               else if (alloc_count > block_count) {
+               if (alloc_count > block_count) {
                        alloc_count = block_count;
                        eloc.logicalBlockNum += alloc_count;
                        elen -= (alloc_count << sb->s_blocksize_bits);
@@ -752,14 +721,6 @@ static int udf_table_new_block(struct super_block *sb,
        newblock = goal_eloc.logicalBlockNum;
        goal_eloc.logicalBlockNum++;
        goal_elen -= sb->s_blocksize;
-       if (inode) {
-               *err = dquot_alloc_block(inode, 1);
-               if (*err) {
-                       brelse(goal_epos.bh);
-                       mutex_unlock(&sbi->s_alloc_mutex);
-                       return 0;
-               }
-       }
 
        if (goal_elen)
                udf_write_aext(table, &goal_epos, &goal_eloc, goal_elen, 1);
index 3a84455c2a7789ef624d7a03b1154b20dbb89d06..51552bf50225aa207835e92c964a3d677d3731f0 100644 (file)
@@ -207,8 +207,9 @@ static int udf_readdir(struct file *filp, void *dirent, filldir_t filldir)
 
 /* readdir and lookup functions */
 const struct file_operations udf_dir_operations = {
+       .llseek                 = generic_file_llseek,
        .read                   = generic_read_dir,
        .readdir                = udf_readdir,
        .unlocked_ioctl         = udf_ioctl,
-       .fsync                  = simple_fsync,
+       .fsync                  = generic_file_fsync,
 };
index baae3a723946e5b89d9a9cb90b576e4716113b7e..94e06d6bddbd1fb973d7bd70b37664c485973529 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/errno.h>
 #include <linux/smp_lock.h>
 #include <linux/pagemap.h>
-#include <linux/quotaops.h>
 #include <linux/buffer_head.h>
 #include <linux/aio.h>
 #include <linux/smp_lock.h>
@@ -219,39 +218,16 @@ const struct file_operations udf_file_operations = {
        .read                   = do_sync_read,
        .aio_read               = generic_file_aio_read,
        .unlocked_ioctl         = udf_ioctl,
-       .open                   = dquot_file_open,
+       .open                   = generic_file_open,
        .mmap                   = generic_file_mmap,
        .write                  = do_sync_write,
        .aio_write              = udf_file_aio_write,
        .release                = udf_release_file,
-       .fsync                  = simple_fsync,
+       .fsync                  = generic_file_fsync,
        .splice_read            = generic_file_splice_read,
        .llseek                 = generic_file_llseek,
 };
 
-int udf_setattr(struct dentry *dentry, struct iattr *iattr)
-{
-       struct inode *inode = dentry->d_inode;
-       int error;
-
-       error = inode_change_ok(inode, iattr);
-       if (error)
-               return error;
-
-       if (is_quota_modification(inode, iattr))
-               dquot_initialize(inode);
-
-       if ((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) ||
-            (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) {
-               error = dquot_transfer(inode, iattr);
-               if (error)
-                       return error;
-       }
-
-       return inode_setattr(inode, iattr);
-}
-
 const struct inode_operations udf_file_inode_operations = {
        .truncate               = udf_truncate,
-       .setattr                = udf_setattr,
 };
index fb68c9cd0c3e59feb556b02593aafd332dbb814b..18cd7111185dc5d9821fbf5015f80aab0ec1794c 100644 (file)
@@ -20,7 +20,6 @@
 
 #include "udfdecl.h"
 #include <linux/fs.h>
-#include <linux/quotaops.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 
@@ -32,13 +31,6 @@ void udf_free_inode(struct inode *inode)
        struct super_block *sb = inode->i_sb;
        struct udf_sb_info *sbi = UDF_SB(sb);
 
-       /*
-        * Note: we must free any quota before locking the superblock,
-        * as writing the quota to disk may need the lock as well.
-        */
-       dquot_free_inode(inode);
-       dquot_drop(inode);
-
        clear_inode(inode);
 
        mutex_lock(&sbi->s_alloc_mutex);
@@ -61,7 +53,7 @@ struct inode *udf_new_inode(struct inode *dir, int mode, int *err)
        struct super_block *sb = dir->i_sb;
        struct udf_sb_info *sbi = UDF_SB(sb);
        struct inode *inode;
-       int block, ret;
+       int block;
        uint32_t start = UDF_I(dir)->i_location.logicalBlockNum;
        struct udf_inode_info *iinfo;
        struct udf_inode_info *dinfo = UDF_I(dir);
@@ -124,15 +116,8 @@ struct inode *udf_new_inode(struct inode *dir, int mode, int *err)
                udf_updated_lvid(sb);
        }
        mutex_unlock(&sbi->s_alloc_mutex);
-       inode->i_mode = mode;
-       inode->i_uid = current_fsuid();
-       if (dir->i_mode & S_ISGID) {
-               inode->i_gid = dir->i_gid;
-               if (S_ISDIR(mode))
-                       mode |= S_ISGID;
-       } else {
-               inode->i_gid = current_fsgid();
-       }
+
+       inode_init_owner(inode, dir, mode);
 
        iinfo->i_location.logicalBlockNum = block;
        iinfo->i_location.partitionReferenceNum =
@@ -153,17 +138,6 @@ struct inode *udf_new_inode(struct inode *dir, int mode, int *err)
        insert_inode_hash(inode);
        mark_inode_dirty(inode);
 
-       dquot_initialize(inode);
-       ret = dquot_alloc_inode(inode);
-       if (ret) {
-               dquot_drop(inode);
-               inode->i_flags |= S_NOQUOTA;
-               inode->i_nlink = 0;
-               iput(inode);
-               *err = ret;
-               return NULL;
-       }
-
        *err = 0;
        return inode;
 }
index 8a3fbd177cab342000164e0a934cc41c5bdec30e..124852bcf6fe0fcfef3559bfbe2af43d0bba8f80 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/pagemap.h>
 #include <linux/buffer_head.h>
 #include <linux/writeback.h>
-#include <linux/quotaops.h>
 #include <linux/slab.h>
 #include <linux/crc-itu-t.h>
 
@@ -71,9 +70,6 @@ static int udf_get_block(struct inode *, sector_t, struct buffer_head *, int);
 
 void udf_delete_inode(struct inode *inode)
 {
-       if (!is_bad_inode(inode))
-               dquot_initialize(inode);
-
        truncate_inode_pages(&inode->i_data, 0);
 
        if (is_bad_inode(inode))
@@ -113,7 +109,6 @@ void udf_clear_inode(struct inode *inode)
                        (unsigned long long)iinfo->i_lenExtents);
        }
 
-       dquot_drop(inode);
        kfree(iinfo->i_ext.i_data);
        iinfo->i_ext.i_data = NULL;
 }
index 75816025f95f5e8e710e92b48cd9751094d45692..bf5fc674193c8bba9e5e31589ba883d49f106270 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/errno.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
-#include <linux/quotaops.h>
 #include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 #include <linux/sched.h>
@@ -563,8 +562,6 @@ static int udf_create(struct inode *dir, struct dentry *dentry, int mode,
        int err;
        struct udf_inode_info *iinfo;
 
-       dquot_initialize(dir);
-
        lock_kernel();
        inode = udf_new_inode(dir, mode, &err);
        if (!inode) {
@@ -579,7 +576,6 @@ static int udf_create(struct inode *dir, struct dentry *dentry, int mode,
                inode->i_data.a_ops = &udf_aops;
        inode->i_op = &udf_file_inode_operations;
        inode->i_fop = &udf_file_operations;
-       inode->i_mode = mode;
        mark_inode_dirty(inode);
 
        fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
@@ -618,8 +614,6 @@ static int udf_mknod(struct inode *dir, struct dentry *dentry, int mode,
        if (!old_valid_dev(rdev))
                return -EINVAL;
 
-       dquot_initialize(dir);
-
        lock_kernel();
        err = -EIO;
        inode = udf_new_inode(dir, mode, &err);
@@ -627,7 +621,6 @@ static int udf_mknod(struct inode *dir, struct dentry *dentry, int mode,
                goto out;
 
        iinfo = UDF_I(inode);
-       inode->i_uid = current_fsuid();
        init_special_inode(inode, mode, rdev);
        fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
        if (!fi) {
@@ -666,15 +659,13 @@ static int udf_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        struct udf_inode_info *dinfo = UDF_I(dir);
        struct udf_inode_info *iinfo;
 
-       dquot_initialize(dir);
-
        lock_kernel();
        err = -EMLINK;
        if (dir->i_nlink >= (256 << sizeof(dir->i_nlink)) - 1)
                goto out;
 
        err = -EIO;
-       inode = udf_new_inode(dir, S_IFDIR, &err);
+       inode = udf_new_inode(dir, S_IFDIR | mode, &err);
        if (!inode)
                goto out;
 
@@ -697,9 +688,6 @@ static int udf_mkdir(struct inode *dir, struct dentry *dentry, int mode)
                        FID_FILE_CHAR_DIRECTORY | FID_FILE_CHAR_PARENT;
        udf_write_fi(inode, &cfi, fi, &fibh, NULL, NULL);
        brelse(fibh.sbh);
-       inode->i_mode = S_IFDIR | mode;
-       if (dir->i_mode & S_ISGID)
-               inode->i_mode |= S_ISGID;
        mark_inode_dirty(inode);
 
        fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
@@ -805,8 +793,6 @@ static int udf_rmdir(struct inode *dir, struct dentry *dentry)
        struct fileIdentDesc *fi, cfi;
        struct kernel_lb_addr tloc;
 
-       dquot_initialize(dir);
-
        retval = -ENOENT;
        lock_kernel();
        fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi);
@@ -853,8 +839,6 @@ static int udf_unlink(struct inode *dir, struct dentry *dentry)
        struct fileIdentDesc cfi;
        struct kernel_lb_addr tloc;
 
-       dquot_initialize(dir);
-
        retval = -ENOENT;
        lock_kernel();
        fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi);
@@ -909,10 +893,8 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
        struct buffer_head *bh;
        struct udf_inode_info *iinfo;
 
-       dquot_initialize(dir);
-
        lock_kernel();
-       inode = udf_new_inode(dir, S_IFLNK, &err);
+       inode = udf_new_inode(dir, S_IFLNK | S_IRWXUGO, &err);
        if (!inode)
                goto out;
 
@@ -923,7 +905,6 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
        }
 
        iinfo = UDF_I(inode);
-       inode->i_mode = S_IFLNK | S_IRWXUGO;
        inode->i_data.a_ops = &udf_symlink_aops;
        inode->i_op = &udf_symlink_inode_operations;
 
@@ -1081,8 +1062,6 @@ static int udf_link(struct dentry *old_dentry, struct inode *dir,
        int err;
        struct buffer_head *bh;
 
-       dquot_initialize(dir);
-
        lock_kernel();
        if (inode->i_nlink >= (256 << sizeof(inode->i_nlink)) - 1) {
                unlock_kernel();
@@ -1145,9 +1124,6 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,
        struct kernel_lb_addr tloc;
        struct udf_inode_info *old_iinfo = UDF_I(old_inode);
 
-       dquot_initialize(old_dir);
-       dquot_initialize(new_dir);
-
        lock_kernel();
        ofi = udf_find_entry(old_dir, &old_dentry->d_name, &ofibh, &ocfi);
        if (ofi) {
@@ -1393,7 +1369,6 @@ const struct export_operations udf_export_ops = {
 const struct inode_operations udf_dir_inode_operations = {
        .lookup                         = udf_lookup,
        .create                         = udf_create,
-       .setattr                        = udf_setattr,
        .link                           = udf_link,
        .unlink                         = udf_unlink,
        .symlink                        = udf_symlink,
@@ -1406,5 +1381,4 @@ const struct inode_operations udf_symlink_inode_operations = {
        .readlink       = generic_readlink,
        .follow_link    = page_follow_link_light,
        .put_link       = page_put_link,
-       .setattr        = udf_setattr,
 };
index 1e4543cbcd276decb1b43942e999b9f2f851b145..612d1e2e285a158bfd1bf7661621565dda955de9 100644 (file)
@@ -557,6 +557,7 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options)
 {
        struct udf_options uopt;
        struct udf_sb_info *sbi = UDF_SB(sb);
+       int error = 0;
 
        uopt.flags = sbi->s_flags;
        uopt.uid   = sbi->s_uid;
@@ -582,17 +583,17 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options)
                        *flags |= MS_RDONLY;
        }
 
-       if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) {
-               unlock_kernel();
-               return 0;
-       }
+       if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
+               goto out_unlock;
+
        if (*flags & MS_RDONLY)
                udf_close_lvid(sb);
        else
                udf_open_lvid(sb);
 
+out_unlock:
        unlock_kernel();
-       return 0;
+       return error;
 }
 
 /* Check Volume Structure Descriptors (ECMA 167 2/9.1) */
@@ -1939,7 +1940,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
        /* Fill in the rest of the superblock */
        sb->s_op = &udf_sb_ops;
        sb->s_export_op = &udf_export_ops;
-       sb->dq_op = NULL;
+
        sb->s_dirt = 0;
        sb->s_magic = UDF_SUPER_MAGIC;
        sb->s_time_gran = 1000;
index 9079ff7d6255fec597e03d6cf29c4688db3ae00d..2bac0354891f7ea4bb1dc9891d12b97fb6f5c35f 100644 (file)
@@ -131,7 +131,6 @@ extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *,
 
 /* file.c */
 extern long udf_ioctl(struct file *, unsigned int, unsigned long);
-extern int udf_setattr(struct dentry *dentry, struct iattr *iattr);
 /* inode.c */
 extern struct inode *udf_iget(struct super_block *, struct kernel_lb_addr *);
 extern int udf_sync_inode(struct inode *);
index 5cfa4d85ccf23b787b58838bbfde2a9f260fda23..048484fb10d28f12722052955abb043ecc0ac096 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/stat.h>
 #include <linux/time.h>
 #include <linux/string.h>
-#include <linux/quotaops.h>
 #include <linux/buffer_head.h>
 #include <linux/capability.h>
 #include <linux/bitops.h>
@@ -85,9 +84,6 @@ void ufs_free_fragments(struct inode *inode, u64 fragment, unsigned count)
                                   "bit already cleared for fragment %u", i);
        }
        
-       dquot_free_block(inode, count);
-
-       
        fs32_add(sb, &ucg->cg_cs.cs_nffree, count);
        uspi->cs_total.cs_nffree += count;
        fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
@@ -195,7 +191,6 @@ do_more:
                ubh_setblock(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
                if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
                        ufs_clusteracct (sb, ucpi, blkno, 1);
-               dquot_free_block(inode, uspi->s_fpb);
 
                fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1);
                uspi->cs_total.cs_nbfree++;
@@ -511,7 +506,6 @@ static u64 ufs_add_fragments(struct inode *inode, u64 fragment,
        struct ufs_cg_private_info * ucpi;
        struct ufs_cylinder_group * ucg;
        unsigned cgno, fragno, fragoff, count, fragsize, i;
-       int ret;
        
        UFSD("ENTER, fragment %llu, oldcount %u, newcount %u\n",
             (unsigned long long)fragment, oldcount, newcount);
@@ -557,11 +551,6 @@ static u64 ufs_add_fragments(struct inode *inode, u64 fragment,
                fs32_add(sb, &ucg->cg_frsum[fragsize - count], 1);
        for (i = oldcount; i < newcount; i++)
                ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i);
-       ret = dquot_alloc_block(inode, count);
-       if (ret) {
-               *err = ret;
-               return 0;
-       }
 
        fs32_sub(sb, &ucg->cg_cs.cs_nffree, count);
        fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
@@ -598,7 +587,6 @@ static u64 ufs_alloc_fragments(struct inode *inode, unsigned cgno,
        struct ufs_cylinder_group * ucg;
        unsigned oldcg, i, j, k, allocsize;
        u64 result;
-       int ret;
        
        UFSD("ENTER, ino %lu, cgno %u, goal %llu, count %u\n",
             inode->i_ino, cgno, (unsigned long long)goal, count);
@@ -667,7 +655,6 @@ cg_found:
                for (i = count; i < uspi->s_fpb; i++)
                        ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, goal + i);
                i = uspi->s_fpb - count;
-               dquot_free_block(inode, i);
 
                fs32_add(sb, &ucg->cg_cs.cs_nffree, i);
                uspi->cs_total.cs_nffree += i;
@@ -679,11 +666,6 @@ cg_found:
        result = ufs_bitmap_search (sb, ucpi, goal, allocsize);
        if (result == INVBLOCK)
                return 0;
-       ret = dquot_alloc_block(inode, count);
-       if (ret) {
-               *err = ret;
-               return 0;
-       }
        for (i = 0; i < count; i++)
                ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, result + i);
        
@@ -718,7 +700,6 @@ static u64 ufs_alloccg_block(struct inode *inode,
        struct ufs_super_block_first * usb1;
        struct ufs_cylinder_group * ucg;
        u64 result, blkno;
-       int ret;
 
        UFSD("ENTER, goal %llu\n", (unsigned long long)goal);
 
@@ -752,11 +733,6 @@ gotit:
        ubh_clrblock (UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
        if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
                ufs_clusteracct (sb, ucpi, blkno, -1);
-       ret = dquot_alloc_block(inode, uspi->s_fpb);
-       if (ret) {
-               *err = ret;
-               return INVBLOCK;
-       }
 
        fs32_sub(sb, &ucg->cg_cs.cs_nbfree, 1);
        uspi->cs_total.cs_nbfree--;
index 317a0d444f6b32e82f79a80c90900e67a3da7f08..ec784756dc6597d97f67444380bcaeb81ac74283 100644 (file)
@@ -666,6 +666,6 @@ not_empty:
 const struct file_operations ufs_dir_operations = {
        .read           = generic_read_dir,
        .readdir        = ufs_readdir,
-       .fsync          = simple_fsync,
+       .fsync          = generic_file_fsync,
        .llseek         = generic_file_llseek,
 };
index a8962cecde5bd6645c13525d4fa0fd8106f5d6dc..33afa20d450982eafb4e1bcc77193cce152270d1 100644 (file)
@@ -24,7 +24,6 @@
  */
 
 #include <linux/fs.h>
-#include <linux/quotaops.h>
 
 #include "ufs_fs.h"
 #include "ufs.h"
@@ -41,7 +40,7 @@ const struct file_operations ufs_file_operations = {
        .write          = do_sync_write,
        .aio_write      = generic_file_aio_write,
        .mmap           = generic_file_mmap,
-       .open           = dquot_file_open,
-       .fsync          = simple_fsync,
+       .open           = generic_file_open,
+       .fsync          = generic_file_fsync,
        .splice_read    = generic_file_splice_read,
 };
index 230ecf6080263144974e7a886c1f74a6dd219290..594480e537d2b3a6c548f4531b48cf0e10e25cd0 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/time.h>
 #include <linux/stat.h>
 #include <linux/string.h>
-#include <linux/quotaops.h>
 #include <linux/buffer_head.h>
 #include <linux/sched.h>
 #include <linux/bitops.h>
@@ -95,9 +94,6 @@ void ufs_free_inode (struct inode * inode)
 
        is_directory = S_ISDIR(inode->i_mode);
 
-       dquot_free_inode(inode);
-       dquot_drop(inode);
-
        clear_inode (inode);
 
        if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_iusedoff, bit))
@@ -303,15 +299,7 @@ cg_found:
        sb->s_dirt = 1;
 
        inode->i_ino = cg * uspi->s_ipg + bit;
-       inode->i_mode = mode;
-       inode->i_uid = current_fsuid();
-       if (dir->i_mode & S_ISGID) {
-               inode->i_gid = dir->i_gid;
-               if (S_ISDIR(mode))
-                       inode->i_mode |= S_ISGID;
-       } else
-               inode->i_gid = current_fsgid();
-
+       inode_init_owner(inode, dir, mode);
        inode->i_blocks = 0;
        inode->i_generation = 0;
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
@@ -355,21 +343,12 @@ cg_found:
 
        unlock_super (sb);
 
-       dquot_initialize(inode);
-       err = dquot_alloc_inode(inode);
-       if (err) {
-               dquot_drop(inode);
-               goto fail_without_unlock;
-       }
-
        UFSD("allocating inode %lu\n", inode->i_ino);
        UFSD("EXIT\n");
        return inode;
 
 fail_remove_inode:
        unlock_super(sb);
-fail_without_unlock:
-       inode->i_flags |= S_NOQUOTA;
        inode->i_nlink = 0;
        iput(inode);
        UFSD("EXIT (FAILED): err %d\n", err);
index cffa756f1047c56dba2255863ebe2146b8dff9b4..73fe773aa03418d3eb1ba4b2e8e71d08ff524e5c 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 #include <linux/writeback.h>
-#include <linux/quotaops.h>
 
 #include "ufs_fs.h"
 #include "ufs.h"
@@ -910,9 +909,6 @@ void ufs_delete_inode (struct inode * inode)
 {
        loff_t old_i_size;
 
-       if (!is_bad_inode(inode))
-               dquot_initialize(inode);
-
        truncate_inode_pages(&inode->i_data, 0);
        if (is_bad_inode(inode))
                goto no_delete;
index eabc02eb12944ae2a876ff6e2bd91ea30a6e960d..b056f02b1fb306c810f4b429ae99417a8f6238e5 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/time.h>
 #include <linux/fs.h>
 #include <linux/smp_lock.h>
-#include <linux/quotaops.h>
 
 #include "ufs_fs.h"
 #include "ufs.h"
@@ -86,8 +85,6 @@ static int ufs_create (struct inode * dir, struct dentry * dentry, int mode,
 
        UFSD("BEGIN\n");
 
-       dquot_initialize(dir);
-
        inode = ufs_new_inode(dir, mode);
        err = PTR_ERR(inode);
 
@@ -112,8 +109,6 @@ static int ufs_mknod (struct inode * dir, struct dentry *dentry, int mode, dev_t
        if (!old_valid_dev(rdev))
                return -EINVAL;
 
-       dquot_initialize(dir);
-
        inode = ufs_new_inode(dir, mode);
        err = PTR_ERR(inode);
        if (!IS_ERR(inode)) {
@@ -138,8 +133,6 @@ static int ufs_symlink (struct inode * dir, struct dentry * dentry,
        if (l > sb->s_blocksize)
                goto out_notlocked;
 
-       dquot_initialize(dir);
-
        lock_kernel();
        inode = ufs_new_inode(dir, S_IFLNK | S_IRWXUGO);
        err = PTR_ERR(inode);
@@ -185,8 +178,6 @@ static int ufs_link (struct dentry * old_dentry, struct inode * dir,
                return -EMLINK;
        }
 
-       dquot_initialize(dir);
-
        inode->i_ctime = CURRENT_TIME_SEC;
        inode_inc_link_count(inode);
        atomic_inc(&inode->i_count);
@@ -204,8 +195,6 @@ static int ufs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
        if (dir->i_nlink >= UFS_LINK_MAX)
                goto out;
 
-       dquot_initialize(dir);
-
        lock_kernel();
        inode_inc_link_count(dir);
 
@@ -250,8 +239,6 @@ static int ufs_unlink(struct inode *dir, struct dentry *dentry)
        struct page *page;
        int err = -ENOENT;
 
-       dquot_initialize(dir);
-
        de = ufs_find_entry(dir, &dentry->d_name, &page);
        if (!de)
                goto out;
@@ -296,9 +283,6 @@ static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry,
        struct ufs_dir_entry *old_de;
        int err = -ENOENT;
 
-       dquot_initialize(old_dir);
-       dquot_initialize(new_dir);
-
        old_de = ufs_find_entry(old_dir, &old_dentry->d_name, &old_page);
        if (!old_de)
                goto out;
index 14743d935a93f88a41691d122cc7f353fe102b17..3ec5a9eb6efb3ff17654c01b6d00ae3d6bb4e44e 100644 (file)
@@ -77,7 +77,6 @@
 
 #include <linux/errno.h>
 #include <linux/fs.h>
-#include <linux/quotaops.h>
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/stat.h>
@@ -918,6 +917,7 @@ again:
        sbi->s_bytesex = BYTESEX_LE;
        switch ((uspi->fs_magic = fs32_to_cpu(sb, usb3->fs_magic))) {
                case UFS_MAGIC:
+               case UFS_MAGIC_BW:
                case UFS2_MAGIC:
                case UFS_MAGIC_LFN:
                case UFS_MAGIC_FEA:
@@ -927,6 +927,7 @@ again:
        sbi->s_bytesex = BYTESEX_BE;
        switch ((uspi->fs_magic = fs32_to_cpu(sb, usb3->fs_magic))) {
                case UFS_MAGIC:
+               case UFS_MAGIC_BW:
                case UFS2_MAGIC:
                case UFS_MAGIC_LFN:
                case UFS_MAGIC_FEA:
@@ -1045,7 +1046,7 @@ magic_found:
         */
        sb->s_op = &ufs_super_ops;
        sb->s_export_op = &ufs_export_ops;
-       sb->dq_op = NULL; /***/
+
        sb->s_magic = fs32_to_cpu(sb, usb3->fs_magic);
 
        uspi->s_sblkno = fs32_to_cpu(sb, usb1->fs_sblkno);
@@ -1435,126 +1436,19 @@ static void destroy_inodecache(void)
        kmem_cache_destroy(ufs_inode_cachep);
 }
 
-static void ufs_clear_inode(struct inode *inode)
-{
-       dquot_drop(inode);
-}
-
-#ifdef CONFIG_QUOTA
-static ssize_t ufs_quota_read(struct super_block *, int, char *,size_t, loff_t);
-static ssize_t ufs_quota_write(struct super_block *, int, const char *, size_t, loff_t);
-#endif
-
 static const struct super_operations ufs_super_ops = {
        .alloc_inode    = ufs_alloc_inode,
        .destroy_inode  = ufs_destroy_inode,
        .write_inode    = ufs_write_inode,
        .delete_inode   = ufs_delete_inode,
-       .clear_inode    = ufs_clear_inode,
        .put_super      = ufs_put_super,
        .write_super    = ufs_write_super,
        .sync_fs        = ufs_sync_fs,
        .statfs         = ufs_statfs,
        .remount_fs     = ufs_remount,
        .show_options   = ufs_show_options,
-#ifdef CONFIG_QUOTA
-       .quota_read     = ufs_quota_read,
-       .quota_write    = ufs_quota_write,
-#endif
 };
 
-#ifdef CONFIG_QUOTA
-
-/* Read data from quotafile - avoid pagecache and such because we cannot afford
- * acquiring the locks... As quota files are never truncated and quota code
- * itself serializes the operations (and noone else should touch the files)
- * we don't have to be afraid of races */
-static ssize_t ufs_quota_read(struct super_block *sb, int type, char *data,
-                              size_t len, loff_t off)
-{
-       struct inode *inode = sb_dqopt(sb)->files[type];
-       sector_t blk = off >> sb->s_blocksize_bits;
-       int err = 0;
-       int offset = off & (sb->s_blocksize - 1);
-       int tocopy;
-       size_t toread;
-       struct buffer_head *bh;
-       loff_t i_size = i_size_read(inode);
-
-       if (off > i_size)
-               return 0;
-       if (off+len > i_size)
-               len = i_size-off;
-       toread = len;
-       while (toread > 0) {
-               tocopy = sb->s_blocksize - offset < toread ?
-                               sb->s_blocksize - offset : toread;
-
-               bh = ufs_bread(inode, blk, 0, &err);
-               if (err)
-                       return err;
-               if (!bh)        /* A hole? */
-                       memset(data, 0, tocopy);
-               else {
-                       memcpy(data, bh->b_data+offset, tocopy);
-                       brelse(bh);
-               }
-               offset = 0;
-               toread -= tocopy;
-               data += tocopy;
-               blk++;
-       }
-       return len;
-}
-
-/* Write to quotafile */
-static ssize_t ufs_quota_write(struct super_block *sb, int type,
-                               const char *data, size_t len, loff_t off)
-{
-       struct inode *inode = sb_dqopt(sb)->files[type];
-       sector_t blk = off >> sb->s_blocksize_bits;
-       int err = 0;
-       int offset = off & (sb->s_blocksize - 1);
-       int tocopy;
-       size_t towrite = len;
-       struct buffer_head *bh;
-
-       mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA);
-       while (towrite > 0) {
-               tocopy = sb->s_blocksize - offset < towrite ?
-                               sb->s_blocksize - offset : towrite;
-
-               bh = ufs_bread(inode, blk, 1, &err);
-               if (!bh)
-                       goto out;
-               lock_buffer(bh);
-               memcpy(bh->b_data+offset, data, tocopy);
-               flush_dcache_page(bh->b_page);
-               set_buffer_uptodate(bh);
-               mark_buffer_dirty(bh);
-               unlock_buffer(bh);
-               brelse(bh);
-               offset = 0;
-               towrite -= tocopy;
-               data += tocopy;
-               blk++;
-       }
-out:
-       if (len == towrite) {
-               mutex_unlock(&inode->i_mutex);
-               return err;
-       }
-       if (inode->i_size < off+len-towrite)
-               i_size_write(inode, off+len-towrite);
-       inode->i_version++;
-       inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
-       mark_inode_dirty(inode);
-       mutex_unlock(&inode->i_mutex);
-       return len - towrite;
-}
-
-#endif
-
 static int ufs_get_sb(struct file_system_type *fs_type,
        int flags, const char *dev_name, void *data, struct vfsmount *mnt)
 {
index f294c44577dced33302a121561a8c65815da4a8c..589e01a465bad16f8708b74de4b0fad11e24676d 100644 (file)
@@ -44,7 +44,6 @@
 #include <linux/buffer_head.h>
 #include <linux/blkdev.h>
 #include <linux/sched.h>
-#include <linux/quotaops.h>
 
 #include "ufs_fs.h"
 #include "ufs.h"
@@ -501,12 +500,10 @@ out:
        return err;
 }
 
-
 /*
- * We don't define our `inode->i_op->truncate', and call it here,
- * because of:
- * - there is no way to know old size
- * - there is no way inform user about error, if it happens in `truncate'
+ * TODO:
+ *     - truncate case should use proper ordering instead of using
+ *       simple_setsize
  */
 int ufs_setattr(struct dentry *dentry, struct iattr *attr)
 {
@@ -518,19 +515,10 @@ int ufs_setattr(struct dentry *dentry, struct iattr *attr)
        if (error)
                return error;
 
-       if (is_quota_modification(inode, attr))
-               dquot_initialize(inode);
-
-       if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
-           (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
-               error = dquot_transfer(inode, attr);
-               if (error)
-                       return error;
-       }
        if (ia_valid & ATTR_SIZE && attr->ia_size != inode->i_size) {
                loff_t old_i_size = inode->i_size;
 
-               error = vmtruncate(inode, attr->ia_size);
+               error = simple_setsize(inode, attr->ia_size);
                if (error)
                        return error;
                error = ufs_truncate(inode, old_i_size);
index 6943ec677c0bef0feaca7efa2cee4202ee9949db..8aba544f9fad80b2a79ca581d6360340cf5e2314 100644 (file)
@@ -48,6 +48,7 @@ typedef __u16 __bitwise __fs16;
 #define UFS_SECTOR_SIZE 512
 #define UFS_SECTOR_BITS 9
 #define UFS_MAGIC  0x00011954
+#define UFS_MAGIC_BW 0x0f242697
 #define UFS2_MAGIC 0x19540119
 #define UFS_CIGAM  0x54190100 /* byteswapped MAGIC */
 
index 46f87e828b484ebabf84422150eb8b9938481971..01bb8135e14aafcc4b8782b749374e6b79049afc 100644 (file)
@@ -590,10 +590,10 @@ strcmp_prefix(const char *a, const char *a_prefix)
 /*
  * Find the xattr_handler with the matching prefix.
  */
-static struct xattr_handler *
-xattr_resolve_name(struct xattr_handler **handlers, const char **name)
+static const struct xattr_handler *
+xattr_resolve_name(const struct xattr_handler **handlers, const char **name)
 {
-       struct xattr_handler *handler;
+       const struct xattr_handler *handler;
 
        if (!*name)
                return NULL;
@@ -614,7 +614,7 @@ xattr_resolve_name(struct xattr_handler **handlers, const char **name)
 ssize_t
 generic_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size)
 {
-       struct xattr_handler *handler;
+       const struct xattr_handler *handler;
 
        handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
        if (!handler)
@@ -629,7 +629,7 @@ generic_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t s
 ssize_t
 generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
 {
-       struct xattr_handler *handler, **handlers = dentry->d_sb->s_xattr;
+       const struct xattr_handler *handler, **handlers = dentry->d_sb->s_xattr;
        unsigned int size = 0;
 
        if (!buffer) {
@@ -659,7 +659,7 @@ generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
 int
 generic_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags)
 {
-       struct xattr_handler *handler;
+       const struct xattr_handler *handler;
 
        if (size == 0)
                value = "";  /* empty EA, do not remove */
@@ -676,7 +676,7 @@ generic_setxattr(struct dentry *dentry, const char *name, const void *value, siz
 int
 generic_removexattr(struct dentry *dentry, const char *name)
 {
-       struct xattr_handler *handler;
+       const struct xattr_handler *handler;
 
        handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
        if (!handler)
index b4769e40e8bc6b409afe5e81ec5adc1b755511a0..c8fb13f83b3f1f95dc642df019a0d14072ed6d15 100644 (file)
@@ -77,6 +77,7 @@ xfs-y                         += xfs_alloc.o \
                                   xfs_itable.o \
                                   xfs_dfrag.o \
                                   xfs_log.o \
+                                  xfs_log_cil.o \
                                   xfs_log_recover.o \
                                   xfs_mount.o \
                                   xfs_mru_cache.o \
index a7bc925c4d603e68b1bc0697be51fcd74a6f44f6..9f769b5b38fc4c4b41e2b7f356889fd1d5f9a1f6 100644 (file)
@@ -440,14 +440,14 @@ xfs_xattr_acl_set(struct dentry *dentry, const char *name,
        return error;
 }
 
-struct xattr_handler xfs_xattr_acl_access_handler = {
+const struct xattr_handler xfs_xattr_acl_access_handler = {
        .prefix = POSIX_ACL_XATTR_ACCESS,
        .flags  = ACL_TYPE_ACCESS,
        .get    = xfs_xattr_acl_get,
        .set    = xfs_xattr_acl_set,
 };
 
-struct xattr_handler xfs_xattr_acl_default_handler = {
+const struct xattr_handler xfs_xattr_acl_default_handler = {
        .prefix = POSIX_ACL_XATTR_DEFAULT,
        .flags  = ACL_TYPE_DEFAULT,
        .get    = xfs_xattr_acl_get,
index f01de3c55c43e8ed7effa08d8b5a324e18c4bd2a..649ade8ef598693e2e57ac66475c1993b57903e3 100644 (file)
@@ -37,6 +37,7 @@
 
 #include "xfs_sb.h"
 #include "xfs_inum.h"
+#include "xfs_log.h"
 #include "xfs_ag.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
@@ -850,6 +851,12 @@ xfs_buf_lock_value(
  *     Note that this in no way locks the underlying pages, so it is only
  *     useful for synchronizing concurrent use of buffer objects, not for
  *     synchronizing independent access to the underlying pages.
+ *
+ *     If we come across a stale, pinned, locked buffer, we know that we
+ *     are being asked to lock a buffer that has been reallocated. Because
+ *     it is pinned, we know that the log has not been pushed to disk and
+ *     hence it will still be locked. Rather than sleeping until someone
+ *     else pushes the log, push it ourselves before trying to get the lock.
  */
 void
 xfs_buf_lock(
@@ -857,6 +864,8 @@ xfs_buf_lock(
 {
        trace_xfs_buf_lock(bp, _RET_IP_);
 
+       if (atomic_read(&bp->b_pin_count) && (bp->b_flags & XBF_STALE))
+               xfs_log_force(bp->b_mount, 0);
        if (atomic_read(&bp->b_io_remaining))
                blk_run_address_space(bp->b_target->bt_mapping);
        down(&bp->b_sema);
index d8fb1b5d6cb5edbf1c28f210c3474692f0ff77a1..257a56b127cf060013569a211de51efd7f2b1306 100644 (file)
@@ -100,10 +100,10 @@ xfs_iozero(
 STATIC int
 xfs_file_fsync(
        struct file             *file,
-       struct dentry           *dentry,
        int                     datasync)
 {
-       struct xfs_inode        *ip = XFS_I(dentry->d_inode);
+       struct inode            *inode = file->f_mapping->host;
+       struct xfs_inode        *ip = XFS_I(inode);
        struct xfs_trans        *tp;
        int                     error = 0;
        int                     log_flushed = 0;
@@ -140,8 +140,8 @@ xfs_file_fsync(
         * might gets cleared when the inode gets written out via the AIL
         * or xfs_iflush_cluster.
         */
-       if (((dentry->d_inode->i_state & I_DIRTY_DATASYNC) ||
-           ((dentry->d_inode->i_state & I_DIRTY_SYNC) && !datasync)) &&
+       if (((inode->i_state & I_DIRTY_DATASYNC) ||
+           ((inode->i_state & I_DIRTY_SYNC) && !datasync)) &&
            ip->i_update_core) {
                /*
                 * Kick off a transaction to log the inode core to get the
@@ -868,7 +868,7 @@ write_retry:
                        mutex_lock(&inode->i_mutex);
                xfs_ilock(ip, iolock);
 
-               error2 = -xfs_file_fsync(file, file->f_path.dentry,
+               error2 = -xfs_file_fsync(file,
                                         (file->f_flags & __O_SYNC) ? 0 : 1);
                if (!error)
                        error = error2;
index e31bf21fe5d33840ce1fbd352e625c2558dde1a2..9ac8aea91529ed403920f746f9d7f52decc2802f 100644 (file)
@@ -19,6 +19,7 @@
 #include "xfs_dmapi.h"
 #include "xfs_sb.h"
 #include "xfs_inum.h"
+#include "xfs_log.h"
 #include "xfs_ag.h"
 #include "xfs_mount.h"
 #include "xfs_quota.h"
index f24dbe5efde3522a8788c4644a8c0085b07ff5f5..f2d1718c9165f104befa17069c7b48cfd93a4b3a 100644 (file)
@@ -119,6 +119,8 @@ mempool_t *xfs_ioend_pool;
 #define MNTOPT_DMAPI   "dmapi"         /* DMI enabled (DMAPI / XDSM) */
 #define MNTOPT_XDSM    "xdsm"          /* DMI enabled (DMAPI / XDSM) */
 #define MNTOPT_DMI     "dmi"           /* DMI enabled (DMAPI / XDSM) */
+#define MNTOPT_DELAYLOG   "delaylog"   /* Delayed loging enabled */
+#define MNTOPT_NODELAYLOG "nodelaylog" /* Delayed loging disabled */
 
 /*
  * Table driven mount option parser.
@@ -374,6 +376,13 @@ xfs_parseargs(
                        mp->m_flags |= XFS_MOUNT_DMAPI;
                } else if (!strcmp(this_char, MNTOPT_DMI)) {
                        mp->m_flags |= XFS_MOUNT_DMAPI;
+               } else if (!strcmp(this_char, MNTOPT_DELAYLOG)) {
+                       mp->m_flags |= XFS_MOUNT_DELAYLOG;
+                       cmn_err(CE_WARN,
+                               "Enabling EXPERIMENTAL delayed logging feature "
+                               "- use at your own risk.\n");
+               } else if (!strcmp(this_char, MNTOPT_NODELAYLOG)) {
+                       mp->m_flags &= ~XFS_MOUNT_DELAYLOG;
                } else if (!strcmp(this_char, "ihashsize")) {
                        cmn_err(CE_WARN,
        "XFS: ihashsize no longer used, option is deprecated.");
@@ -535,6 +544,7 @@ xfs_showargs(
                { XFS_MOUNT_FILESTREAMS,        "," MNTOPT_FILESTREAM },
                { XFS_MOUNT_DMAPI,              "," MNTOPT_DMAPI },
                { XFS_MOUNT_GRPID,              "," MNTOPT_GRPID },
+               { XFS_MOUNT_DELAYLOG,           "," MNTOPT_DELAYLOG },
                { 0, NULL }
        };
        static struct proc_xfs_info xfs_info_unset[] = {
@@ -1755,7 +1765,7 @@ xfs_init_zones(void)
         * but it is much faster.
         */
        xfs_buf_item_zone = kmem_zone_init((sizeof(xfs_buf_log_item_t) +
-                               (((XFS_MAX_BLOCKSIZE / XFS_BLI_CHUNK) /
+                               (((XFS_MAX_BLOCKSIZE / XFS_BLF_CHUNK) /
                                  NBWORD) * sizeof(int))), "xfs_buf_item");
        if (!xfs_buf_item_zone)
                goto out_destroy_trans_zone;
index 233d4b9881b11b52bd1d2fb3d5df83865d320186..519618e9279eda5c4d81ca398679d835ff77df28 100644 (file)
@@ -85,7 +85,7 @@ extern __uint64_t xfs_max_file_offset(unsigned int);
 extern void xfs_blkdev_issue_flush(struct xfs_buftarg *);
 
 extern const struct export_operations xfs_export_operations;
-extern struct xattr_handler *xfs_xattr_handlers[];
+extern const struct xattr_handler *xfs_xattr_handlers[];
 extern const struct quotactl_ops xfs_quotactl_operations;
 
 #define XFS_M(sb)              ((struct xfs_mount *)((sb)->s_fs_info))
index 8a319cfd290120d6e5b874b1f2cce4dea9de9809..ff6bc797baf290a03ee411a05c8733ecb4ed030c 100644 (file)
@@ -1059,83 +1059,112 @@ TRACE_EVENT(xfs_bunmap,
 
 );
 
+#define XFS_BUSY_SYNC \
+       { 0,    "async" }, \
+       { 1,    "sync" }
+
 TRACE_EVENT(xfs_alloc_busy,
-       TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agblock_t agbno,
-                xfs_extlen_t len, int slot),
-       TP_ARGS(mp, agno, agbno, len, slot),
+       TP_PROTO(struct xfs_trans *trans, xfs_agnumber_t agno,
+                xfs_agblock_t agbno, xfs_extlen_t len, int sync),
+       TP_ARGS(trans, agno, agbno, len, sync),
        TP_STRUCT__entry(
                __field(dev_t, dev)
+               __field(struct xfs_trans *, tp)
+               __field(int, tid)
                __field(xfs_agnumber_t, agno)
                __field(xfs_agblock_t, agbno)
                __field(xfs_extlen_t, len)
-               __field(int, slot)
+               __field(int, sync)
        ),
        TP_fast_assign(
-               __entry->dev = mp->m_super->s_dev;
+               __entry->dev = trans->t_mountp->m_super->s_dev;
+               __entry->tp = trans;
+               __entry->tid = trans->t_ticket->t_tid;
                __entry->agno = agno;
                __entry->agbno = agbno;
                __entry->len = len;
-               __entry->slot = slot;
+               __entry->sync = sync;
        ),
-       TP_printk("dev %d:%d agno %u agbno %u len %u slot %d",
+       TP_printk("dev %d:%d trans 0x%p tid 0x%x agno %u agbno %u len %u %s",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->tp,
+                 __entry->tid,
                  __entry->agno,
                  __entry->agbno,
                  __entry->len,
-                 __entry->slot)
+                 __print_symbolic(__entry->sync, XFS_BUSY_SYNC))
 
 );
 
-#define XFS_BUSY_STATES \
-       { 0,    "found" }, \
-       { 1,    "missing" }
-
 TRACE_EVENT(xfs_alloc_unbusy,
        TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno,
-                int slot, int found),
-       TP_ARGS(mp, agno, slot, found),
+                xfs_agblock_t agbno, xfs_extlen_t len),
+       TP_ARGS(mp, agno, agbno, len),
        TP_STRUCT__entry(
                __field(dev_t, dev)
                __field(xfs_agnumber_t, agno)
-               __field(int, slot)
-               __field(int, found)
+               __field(xfs_agblock_t, agbno)
+               __field(xfs_extlen_t, len)
        ),
        TP_fast_assign(
                __entry->dev = mp->m_super->s_dev;
                __entry->agno = agno;
-               __entry->slot = slot;
-               __entry->found = found;
+               __entry->agbno = agbno;
+               __entry->len = len;
        ),
-       TP_printk("dev %d:%d agno %u slot %d %s",
+       TP_printk("dev %d:%d agno %u agbno %u len %u",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
                  __entry->agno,
-                 __entry->slot,
-                 __print_symbolic(__entry->found, XFS_BUSY_STATES))
+                 __entry->agbno,
+                 __entry->len)
 );
 
+#define XFS_BUSY_STATES \
+       { 0,    "missing" }, \
+       { 1,    "found" }
+
 TRACE_EVENT(xfs_alloc_busysearch,
-       TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agblock_t agbno,
-                xfs_extlen_t len, xfs_lsn_t lsn),
-       TP_ARGS(mp, agno, agbno, len, lsn),
+       TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno,
+                xfs_agblock_t agbno, xfs_extlen_t len, int found),
+       TP_ARGS(mp, agno, agbno, len, found),
        TP_STRUCT__entry(
                __field(dev_t, dev)
                __field(xfs_agnumber_t, agno)
                __field(xfs_agblock_t, agbno)
                __field(xfs_extlen_t, len)
-               __field(xfs_lsn_t, lsn)
+               __field(int, found)
        ),
        TP_fast_assign(
                __entry->dev = mp->m_super->s_dev;
                __entry->agno = agno;
                __entry->agbno = agbno;
                __entry->len = len;
-               __entry->lsn = lsn;
+               __entry->found = found;
        ),
-       TP_printk("dev %d:%d agno %u agbno %u len %u force lsn 0x%llx",
+       TP_printk("dev %d:%d agno %u agbno %u len %u %s",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
                  __entry->agno,
                  __entry->agbno,
                  __entry->len,
+                 __print_symbolic(__entry->found, XFS_BUSY_STATES))
+);
+
+TRACE_EVENT(xfs_trans_commit_lsn,
+       TP_PROTO(struct xfs_trans *trans),
+       TP_ARGS(trans),
+       TP_STRUCT__entry(
+               __field(dev_t, dev)
+               __field(struct xfs_trans *, tp)
+               __field(xfs_lsn_t, lsn)
+       ),
+       TP_fast_assign(
+               __entry->dev = trans->t_mountp->m_super->s_dev;
+               __entry->tp = trans;
+               __entry->lsn = trans->t_commit_lsn;
+       ),
+       TP_printk("dev %d:%d trans 0x%p commit_lsn 0x%llx",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->tp,
                  __entry->lsn)
 );
 
index fa01b9daba6b0b66ad12450d185840da66374b69..87d3e03878c8da30b762d19263ec3e1cbe02aa24 100644 (file)
@@ -72,28 +72,28 @@ xfs_xattr_set(struct dentry *dentry, const char *name, const void *value,
                                (void *)value, size, xflags);
 }
 
-static struct xattr_handler xfs_xattr_user_handler = {
+static const struct xattr_handler xfs_xattr_user_handler = {
        .prefix = XATTR_USER_PREFIX,
        .flags  = 0, /* no flags implies user namespace */
        .get    = xfs_xattr_get,
        .set    = xfs_xattr_set,
 };
 
-static struct xattr_handler xfs_xattr_trusted_handler = {
+static const struct xattr_handler xfs_xattr_trusted_handler = {
        .prefix = XATTR_TRUSTED_PREFIX,
        .flags  = ATTR_ROOT,
        .get    = xfs_xattr_get,
        .set    = xfs_xattr_set,
 };
 
-static struct xattr_handler xfs_xattr_security_handler = {
+static const struct xattr_handler xfs_xattr_security_handler = {
        .prefix = XATTR_SECURITY_PREFIX,
        .flags  = ATTR_SECURE,
        .get    = xfs_xattr_get,
        .set    = xfs_xattr_set,
 };
 
-struct xattr_handler *xfs_xattr_handlers[] = {
+const struct xattr_handler *xfs_xattr_handlers[] = {
        &xfs_xattr_user_handler,
        &xfs_xattr_trusted_handler,
        &xfs_xattr_security_handler,
index b89ec5df012958261fd7f1ea05173080503d4410..585e7633dfc75b176df3989186628385b857bf8e 100644 (file)
@@ -344,9 +344,9 @@ xfs_qm_init_dquot_blk(
        for (i = 0; i < q->qi_dqperchunk; i++, d++, curid++)
                xfs_qm_dqinit_core(curid, type, d);
        xfs_trans_dquot_buf(tp, bp,
-                           (type & XFS_DQ_USER ? XFS_BLI_UDQUOT_BUF :
-                           ((type & XFS_DQ_PROJ) ? XFS_BLI_PDQUOT_BUF :
-                            XFS_BLI_GDQUOT_BUF)));
+                           (type & XFS_DQ_USER ? XFS_BLF_UDQUOT_BUF :
+                           ((type & XFS_DQ_PROJ) ? XFS_BLF_PDQUOT_BUF :
+                            XFS_BLF_GDQUOT_BUF)));
        xfs_trans_log_buf(tp, bp, 0, BBTOB(q->qi_dqchunklen) - 1);
 }
 
index d13eeba2c8f8a725821a145d8843eb4efa21a787..0135e2a669d78924c2e4261450ad5d17676371b8 100644 (file)
@@ -49,8 +49,8 @@ extern int xfs_acl_chmod(struct inode *inode);
 extern int posix_acl_access_exists(struct inode *inode);
 extern int posix_acl_default_exists(struct inode *inode);
 
-extern struct xattr_handler xfs_xattr_acl_access_handler;
-extern struct xattr_handler xfs_xattr_acl_default_handler;
+extern const struct xattr_handler xfs_xattr_acl_access_handler;
+extern const struct xattr_handler xfs_xattr_acl_default_handler;
 #else
 # define xfs_check_acl                                 NULL
 # define xfs_get_acl(inode, type)                      NULL
index abb8222b88c9a06e90c00784a60564170ba253da..401f364ad36ce52022cabf6ccafa9d58de39dcd2 100644 (file)
@@ -175,14 +175,20 @@ typedef struct xfs_agfl {
 } xfs_agfl_t;
 
 /*
- * Busy block/extent entry.  Used in perag to mark blocks that have been freed
- * but whose transactions aren't committed to disk yet.
+ * Busy block/extent entry.  Indexed by a rbtree in perag to mark blocks that
+ * have been freed but whose transactions aren't committed to disk yet.
+ *
+ * Note that we use the transaction ID to record the transaction, not the
+ * transaction structure itself. See xfs_alloc_busy_insert() for details.
  */
-typedef struct xfs_perag_busy {
-       xfs_agblock_t   busy_start;
-       xfs_extlen_t    busy_length;
-       struct xfs_trans *busy_tp;      /* transaction that did the free */
-} xfs_perag_busy_t;
+struct xfs_busy_extent {
+       struct rb_node  rb_node;        /* ag by-bno indexed search tree */
+       struct list_head list;          /* transaction busy extent list */
+       xfs_agnumber_t  agno;
+       xfs_agblock_t   bno;
+       xfs_extlen_t    length;
+       xlog_tid_t      tid;            /* transaction that created this */
+};
 
 /*
  * Per-ag incore structure, copies of information in agf and agi,
@@ -216,7 +222,8 @@ typedef struct xfs_perag {
        xfs_agino_t     pagl_leftrec;
        xfs_agino_t     pagl_rightrec;
 #ifdef __KERNEL__
-       spinlock_t      pagb_lock;      /* lock for pagb_list */
+       spinlock_t      pagb_lock;      /* lock for pagb_tree */
+       struct rb_root  pagb_tree;      /* ordered tree of busy extents */
 
        atomic_t        pagf_fstrms;    /* # of filestreams active in this AG */
 
@@ -226,7 +233,6 @@ typedef struct xfs_perag {
        int             pag_ici_reclaimable;    /* reclaimable inodes */
 #endif
        int             pagb_count;     /* pagb slots in use */
-       xfs_perag_busy_t pagb_list[XFS_PAGB_NUM_SLOTS]; /* unstable blocks */
 } xfs_perag_t;
 
 /*
index 94cddbfb25604abed1495b488799b13e10bbead0..a7fbe8a99b12bf2c360ea19372a380ae5d27c855 100644 (file)
 #define        XFSA_FIXUP_BNO_OK       1
 #define        XFSA_FIXUP_CNT_OK       2
 
-STATIC void
-xfs_alloc_search_busy(xfs_trans_t *tp,
-                   xfs_agnumber_t agno,
-                   xfs_agblock_t bno,
-                   xfs_extlen_t len);
+static int
+xfs_alloc_busy_search(struct xfs_mount *mp, xfs_agnumber_t agno,
+                   xfs_agblock_t bno, xfs_extlen_t len);
 
 /*
  * Prototypes for per-ag allocation routines
@@ -540,9 +538,16 @@ xfs_alloc_ag_vextent(
                                be32_to_cpu(agf->agf_length));
                        xfs_alloc_log_agf(args->tp, args->agbp,
                                                XFS_AGF_FREEBLKS);
-                       /* search the busylist for these blocks */
-                       xfs_alloc_search_busy(args->tp, args->agno,
-                                       args->agbno, args->len);
+                       /*
+                        * Search the busylist for these blocks and mark the
+                        * transaction as synchronous if blocks are found. This
+                        * avoids the need to block due to a synchronous log
+                        * force to ensure correct ordering as the synchronous
+                        * transaction will guarantee that for us.
+                        */
+                       if (xfs_alloc_busy_search(args->mp, args->agno,
+                                               args->agbno, args->len))
+                               xfs_trans_set_sync(args->tp);
                }
                if (!args->isfl)
                        xfs_trans_mod_sb(args->tp,
@@ -1693,7 +1698,7 @@ xfs_free_ag_extent(
         * when the iclog commits to disk.  If a busy block is allocated,
         * the iclog is pushed up to the LSN that freed the block.
         */
-       xfs_alloc_mark_busy(tp, agno, bno, len);
+       xfs_alloc_busy_insert(tp, agno, bno, len);
        return 0;
 
  error0:
@@ -1989,14 +1994,20 @@ xfs_alloc_get_freelist(
        *bnop = bno;
 
        /*
-        * As blocks are freed, they are added to the per-ag busy list
-        * and remain there until the freeing transaction is committed to
-        * disk.  Now that we have allocated blocks, this list must be
-        * searched to see if a block is being reused.  If one is, then
-        * the freeing transaction must be pushed to disk NOW by forcing
-        * to disk all iclogs up that transaction's LSN.
+        * As blocks are freed, they are added to the per-ag busy list and
+        * remain there until the freeing transaction is committed to disk.
+        * Now that we have allocated blocks, this list must be searched to see
+        * if a block is being reused.  If one is, then the freeing transaction
+        * must be pushed to disk before this transaction.
+        *
+        * We do this by setting the current transaction to a sync transaction
+        * which guarantees that the freeing transaction is on disk before this
+        * transaction. This is done instead of a synchronous log force here so
+        * that we don't sit and wait with the AGF locked in the transaction
+        * during the log force.
         */
-       xfs_alloc_search_busy(tp, be32_to_cpu(agf->agf_seqno), bno, 1);
+       if (xfs_alloc_busy_search(mp, be32_to_cpu(agf->agf_seqno), bno, 1))
+               xfs_trans_set_sync(tp);
        return 0;
 }
 
@@ -2201,7 +2212,7 @@ xfs_alloc_read_agf(
                        be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNTi]);
                spin_lock_init(&pag->pagb_lock);
                pag->pagb_count = 0;
-               memset(pag->pagb_list, 0, sizeof(pag->pagb_list));
+               pag->pagb_tree = RB_ROOT;
                pag->pagf_init = 1;
        }
 #ifdef DEBUG
@@ -2479,127 +2490,263 @@ error0:
  * list is reused, the transaction that freed it must be forced to disk
  * before continuing to use the block.
  *
- * xfs_alloc_mark_busy - add to the per-ag busy list
- * xfs_alloc_clear_busy - remove an item from the per-ag busy list
+ * xfs_alloc_busy_insert - add to the per-ag busy list
+ * xfs_alloc_busy_clear - remove an item from the per-ag busy list
+ * xfs_alloc_busy_search - search for a busy extent
+ */
+
+/*
+ * Insert a new extent into the busy tree.
+ *
+ * The busy extent tree is indexed by the start block of the busy extent.
+ * there can be multiple overlapping ranges in the busy extent tree but only
+ * ever one entry at a given start block. The reason for this is that
+ * multi-block extents can be freed, then smaller chunks of that extent
+ * allocated and freed again before the first transaction commit is on disk.
+ * If the exact same start block is freed a second time, we have to wait for
+ * that busy extent to pass out of the tree before the new extent is inserted.
+ * There are two main cases we have to handle here.
+ *
+ * The first case is a transaction that triggers a "free - allocate - free"
+ * cycle. This can occur during btree manipulations as a btree block is freed
+ * to the freelist, then allocated from the free list, then freed again. In
+ * this case, the second extxpnet free is what triggers the duplicate and as
+ * such the transaction IDs should match. Because the extent was allocated in
+ * this transaction, the transaction must be marked as synchronous. This is
+ * true for all cases where the free/alloc/free occurs in the one transaction,
+ * hence the addition of the ASSERT(tp->t_flags & XFS_TRANS_SYNC) to this case.
+ * This serves to catch violations of the second case quite effectively.
+ *
+ * The second case is where the free/alloc/free occur in different
+ * transactions. In this case, the thread freeing the extent the second time
+ * can't mark the extent busy immediately because it is already tracked in a
+ * transaction that may be committing.  When the log commit for the existing
+ * busy extent completes, the busy extent will be removed from the tree. If we
+ * allow the second busy insert to continue using that busy extent structure,
+ * it can be freed before this transaction is safely in the log.  Hence our
+ * only option in this case is to force the log to remove the existing busy
+ * extent from the list before we insert the new one with the current
+ * transaction ID.
+ *
+ * The problem we are trying to avoid in the free-alloc-free in separate
+ * transactions is most easily described with a timeline:
+ *
+ *      Thread 1       Thread 2        Thread 3        xfslogd
+ *     xact alloc
+ *     free X
+ *     mark busy
+ *     commit xact
+ *     free xact
+ *                     xact alloc
+ *                     alloc X
+ *                     busy search
+ *                     mark xact sync
+ *                     commit xact
+ *                     free xact
+ *                     force log
+ *                     checkpoint starts
+ *                     ....
+ *                                     xact alloc
+ *                                     free X
+ *                                     mark busy
+ *                                     finds match
+ *                                     *** KABOOM! ***
+ *                                     ....
+ *                                                     log IO completes
+ *                                                     unbusy X
+ *                     checkpoint completes
+ *
+ * By issuing a log force in thread 3 @ "KABOOM", the thread will block until
+ * the checkpoint completes, and the busy extent it matched will have been
+ * removed from the tree when it is woken. Hence it can then continue safely.
+ *
+ * However, to ensure this matching process is robust, we need to use the
+ * transaction ID for identifying transaction, as delayed logging results in
+ * the busy extent and transaction lifecycles being different. i.e. the busy
+ * extent is active for a lot longer than the transaction.  Hence the
+ * transaction structure can be freed and reallocated, then mark the same
+ * extent busy again in the new transaction. In this case the new transaction
+ * will have a different tid but can have the same address, and hence we need
+ * to check against the tid.
+ *
+ * Future: for delayed logging, we could avoid the log force if the extent was
+ * first freed in the current checkpoint sequence. This, however, requires the
+ * ability to pin the current checkpoint in memory until this transaction
+ * commits to ensure that both the original free and the current one combine
+ * logically into the one checkpoint. If the checkpoint sequences are
+ * different, however, we still need to wait on a log force.
  */
 void
-xfs_alloc_mark_busy(xfs_trans_t *tp,
-                   xfs_agnumber_t agno,
-                   xfs_agblock_t bno,
-                   xfs_extlen_t len)
+xfs_alloc_busy_insert(
+       struct xfs_trans        *tp,
+       xfs_agnumber_t          agno,
+       xfs_agblock_t           bno,
+       xfs_extlen_t            len)
 {
-       xfs_perag_busy_t        *bsy;
+       struct xfs_busy_extent  *new;
+       struct xfs_busy_extent  *busyp;
        struct xfs_perag        *pag;
-       int                     n;
+       struct rb_node          **rbp;
+       struct rb_node          *parent;
+       int                     match;
 
-       pag = xfs_perag_get(tp->t_mountp, agno);
-       spin_lock(&pag->pagb_lock);
 
-       /* search pagb_list for an open slot */
-       for (bsy = pag->pagb_list, n = 0;
-            n < XFS_PAGB_NUM_SLOTS;
-            bsy++, n++) {
-               if (bsy->busy_tp == NULL) {
-                       break;
-               }
+       new = kmem_zalloc(sizeof(struct xfs_busy_extent), KM_MAYFAIL);
+       if (!new) {
+               /*
+                * No Memory!  Since it is now not possible to track the free
+                * block, make this a synchronous transaction to insure that
+                * the block is not reused before this transaction commits.
+                */
+               trace_xfs_alloc_busy(tp, agno, bno, len, 1);
+               xfs_trans_set_sync(tp);
+               return;
        }
 
-       trace_xfs_alloc_busy(tp->t_mountp, agno, bno, len, n);
+       new->agno = agno;
+       new->bno = bno;
+       new->length = len;
+       new->tid = xfs_log_get_trans_ident(tp);
 
-       if (n < XFS_PAGB_NUM_SLOTS) {
-               bsy = &pag->pagb_list[n];
-               pag->pagb_count++;
-               bsy->busy_start = bno;
-               bsy->busy_length = len;
-               bsy->busy_tp = tp;
-               xfs_trans_add_busy(tp, agno, n);
-       } else {
+       INIT_LIST_HEAD(&new->list);
+
+       /* trace before insert to be able to see failed inserts */
+       trace_xfs_alloc_busy(tp, agno, bno, len, 0);
+
+       pag = xfs_perag_get(tp->t_mountp, new->agno);
+restart:
+       spin_lock(&pag->pagb_lock);
+       rbp = &pag->pagb_tree.rb_node;
+       parent = NULL;
+       busyp = NULL;
+       match = 0;
+       while (*rbp && match >= 0) {
+               parent = *rbp;
+               busyp = rb_entry(parent, struct xfs_busy_extent, rb_node);
+
+               if (new->bno < busyp->bno) {
+                       /* may overlap, but exact start block is lower */
+                       rbp = &(*rbp)->rb_left;
+                       if (new->bno + new->length > busyp->bno)
+                               match = busyp->tid == new->tid ? 1 : -1;
+               } else if (new->bno > busyp->bno) {
+                       /* may overlap, but exact start block is higher */
+                       rbp = &(*rbp)->rb_right;
+                       if (bno < busyp->bno + busyp->length)
+                               match = busyp->tid == new->tid ? 1 : -1;
+               } else {
+                       match = busyp->tid == new->tid ? 1 : -1;
+                       break;
+               }
+       }
+       if (match < 0) {
+               /* overlap marked busy in different transaction */
+               spin_unlock(&pag->pagb_lock);
+               xfs_log_force(tp->t_mountp, XFS_LOG_SYNC);
+               goto restart;
+       }
+       if (match > 0) {
                /*
-                * The busy list is full!  Since it is now not possible to
-                * track the free block, make this a synchronous transaction
-                * to insure that the block is not reused before this
-                * transaction commits.
+                * overlap marked busy in same transaction. Update if exact
+                * start block match, otherwise combine the busy extents into
+                * a single range.
                 */
-               xfs_trans_set_sync(tp);
-       }
+               if (busyp->bno == new->bno) {
+                       busyp->length = max(busyp->length, new->length);
+                       spin_unlock(&pag->pagb_lock);
+                       ASSERT(tp->t_flags & XFS_TRANS_SYNC);
+                       xfs_perag_put(pag);
+                       kmem_free(new);
+                       return;
+               }
+               rb_erase(&busyp->rb_node, &pag->pagb_tree);
+               new->length = max(busyp->bno + busyp->length,
+                                       new->bno + new->length) -
+                               min(busyp->bno, new->bno);
+               new->bno = min(busyp->bno, new->bno);
+       } else
+               busyp = NULL;
 
+       rb_link_node(&new->rb_node, parent, rbp);
+       rb_insert_color(&new->rb_node, &pag->pagb_tree);
+
+       list_add(&new->list, &tp->t_busy);
        spin_unlock(&pag->pagb_lock);
        xfs_perag_put(pag);
+       kmem_free(busyp);
 }
 
-void
-xfs_alloc_clear_busy(xfs_trans_t *tp,
-                    xfs_agnumber_t agno,
-                    int idx)
+/*
+ * Search for a busy extent within the range of the extent we are about to
+ * allocate.  You need to be holding the busy extent tree lock when calling
+ * xfs_alloc_busy_search(). This function returns 0 for no overlapping busy
+ * extent, -1 for an overlapping but not exact busy extent, and 1 for an exact
+ * match. This is done so that a non-zero return indicates an overlap that
+ * will require a synchronous transaction, but it can still be
+ * used to distinguish between a partial or exact match.
+ */
+static int
+xfs_alloc_busy_search(
+       struct xfs_mount        *mp,
+       xfs_agnumber_t          agno,
+       xfs_agblock_t           bno,
+       xfs_extlen_t            len)
 {
        struct xfs_perag        *pag;
-       xfs_perag_busy_t        *list;
+       struct rb_node          *rbp;
+       struct xfs_busy_extent  *busyp;
+       int                     match = 0;
 
-       ASSERT(idx < XFS_PAGB_NUM_SLOTS);
-       pag = xfs_perag_get(tp->t_mountp, agno);
+       pag = xfs_perag_get(mp, agno);
        spin_lock(&pag->pagb_lock);
-       list = pag->pagb_list;
 
-       trace_xfs_alloc_unbusy(tp->t_mountp, agno, idx, list[idx].busy_tp == tp);
-
-       if (list[idx].busy_tp == tp) {
-               list[idx].busy_tp = NULL;
-               pag->pagb_count--;
+       rbp = pag->pagb_tree.rb_node;
+
+       /* find closest start bno overlap */
+       while (rbp) {
+               busyp = rb_entry(rbp, struct xfs_busy_extent, rb_node);
+               if (bno < busyp->bno) {
+                       /* may overlap, but exact start block is lower */
+                       if (bno + len > busyp->bno)
+                               match = -1;
+                       rbp = rbp->rb_left;
+               } else if (bno > busyp->bno) {
+                       /* may overlap, but exact start block is higher */
+                       if (bno < busyp->bno + busyp->length)
+                               match = -1;
+                       rbp = rbp->rb_right;
+               } else {
+                       /* bno matches busyp, length determines exact match */
+                       match = (busyp->length == len) ? 1 : -1;
+                       break;
+               }
        }
-
        spin_unlock(&pag->pagb_lock);
+       trace_xfs_alloc_busysearch(mp, agno, bno, len, !!match);
        xfs_perag_put(pag);
+       return match;
 }
 
-
-/*
- * If we find the extent in the busy list, force the log out to get the
- * extent out of the busy list so the caller can use it straight away.
- */
-STATIC void
-xfs_alloc_search_busy(xfs_trans_t *tp,
-                   xfs_agnumber_t agno,
-                   xfs_agblock_t bno,
-                   xfs_extlen_t len)
+void
+xfs_alloc_busy_clear(
+       struct xfs_mount        *mp,
+       struct xfs_busy_extent  *busyp)
 {
        struct xfs_perag        *pag;
-       xfs_perag_busy_t        *bsy;
-       xfs_agblock_t           uend, bend;
-       xfs_lsn_t               lsn = 0;
-       int                     cnt;
 
-       pag = xfs_perag_get(tp->t_mountp, agno);
-       spin_lock(&pag->pagb_lock);
-       cnt = pag->pagb_count;
+       trace_xfs_alloc_unbusy(mp, busyp->agno, busyp->bno,
+                                               busyp->length);
 
-       /*
-        * search pagb_list for this slot, skipping open slots. We have to
-        * search the entire array as there may be multiple overlaps and
-        * we have to get the most recent LSN for the log force to push out
-        * all the transactions that span the range.
-        */
-       uend = bno + len - 1;
-       for (cnt = 0; cnt < pag->pagb_count; cnt++) {
-               bsy = &pag->pagb_list[cnt];
-               if (!bsy->busy_tp)
-                       continue;
+       ASSERT(xfs_alloc_busy_search(mp, busyp->agno, busyp->bno,
+                                               busyp->length) == 1);
 
-               bend = bsy->busy_start + bsy->busy_length - 1;
-               if (bno > bend || uend < bsy->busy_start)
-                       continue;
+       list_del_init(&busyp->list);
 
-               /* (start1,length1) within (start2, length2) */
-               if (XFS_LSN_CMP(bsy->busy_tp->t_commit_lsn, lsn) > 0)
-                       lsn = bsy->busy_tp->t_commit_lsn;
-       }
+       pag = xfs_perag_get(mp, busyp->agno);
+       spin_lock(&pag->pagb_lock);
+       rb_erase(&busyp->rb_node, &pag->pagb_tree);
        spin_unlock(&pag->pagb_lock);
        xfs_perag_put(pag);
-       trace_xfs_alloc_busysearch(tp->t_mountp, agno, bno, len, lsn);
 
-       /*
-        * If a block was found, force the log through the LSN of the
-        * transaction that freed the block
-        */
-       if (lsn)
-               xfs_log_force_lsn(tp->t_mountp, lsn, XFS_LOG_SYNC);
+       kmem_free(busyp);
 }
index 599bffa39784d4f425304036d152072115f77b26..6d05199b667cea3c72576750924a8ee8a63effcc 100644 (file)
@@ -22,6 +22,7 @@ struct xfs_buf;
 struct xfs_mount;
 struct xfs_perag;
 struct xfs_trans;
+struct xfs_busy_extent;
 
 /*
  * Freespace allocation types.  Argument to xfs_alloc_[v]extent.
@@ -119,15 +120,13 @@ xfs_alloc_longest_free_extent(struct xfs_mount *mp,
 #ifdef __KERNEL__
 
 void
-xfs_alloc_mark_busy(xfs_trans_t *tp,
+xfs_alloc_busy_insert(xfs_trans_t *tp,
                xfs_agnumber_t agno,
                xfs_agblock_t bno,
                xfs_extlen_t len);
 
 void
-xfs_alloc_clear_busy(xfs_trans_t *tp,
-               xfs_agnumber_t ag,
-               int idx);
+xfs_alloc_busy_clear(struct xfs_mount *mp, struct xfs_busy_extent *busyp);
 
 #endif /* __KERNEL__ */
 
index b726e10d2c1c18bafa355663d822f8b9ef441d67..83f4942187594ac4b998712dc66b2385b083963e 100644 (file)
@@ -134,7 +134,7 @@ xfs_allocbt_free_block(
         * disk. If a busy block is allocated, the iclog is pushed up to the
         * LSN that freed the block.
         */
-       xfs_alloc_mark_busy(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1);
+       xfs_alloc_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1);
        xfs_trans_agbtree_delta(cur->bc_tp, -1);
        return 0;
 }
index 240340a4727b9b17080f7f50810a456f8eafaf0f..02a80984aa05f13189f4c99f186f1f098fa02e3d 100644 (file)
@@ -64,7 +64,7 @@ xfs_buf_item_log_debug(
        nbytes = last - first + 1;
        bfset(bip->bli_logged, first, nbytes);
        for (x = 0; x < nbytes; x++) {
-               chunk_num = byte >> XFS_BLI_SHIFT;
+               chunk_num = byte >> XFS_BLF_SHIFT;
                word_num = chunk_num >> BIT_TO_WORD_SHIFT;
                bit_num = chunk_num & (NBWORD - 1);
                wordp = &(bip->bli_format.blf_data_map[word_num]);
@@ -166,7 +166,7 @@ xfs_buf_item_size(
                 * cancel flag in it.
                 */
                trace_xfs_buf_item_size_stale(bip);
-               ASSERT(bip->bli_format.blf_flags & XFS_BLI_CANCEL);
+               ASSERT(bip->bli_format.blf_flags & XFS_BLF_CANCEL);
                return 1;
        }
 
@@ -197,9 +197,9 @@ xfs_buf_item_size(
                } else if (next_bit != last_bit + 1) {
                        last_bit = next_bit;
                        nvecs++;
-               } else if (xfs_buf_offset(bp, next_bit * XFS_BLI_CHUNK) !=
-                          (xfs_buf_offset(bp, last_bit * XFS_BLI_CHUNK) +
-                           XFS_BLI_CHUNK)) {
+               } else if (xfs_buf_offset(bp, next_bit * XFS_BLF_CHUNK) !=
+                          (xfs_buf_offset(bp, last_bit * XFS_BLF_CHUNK) +
+                           XFS_BLF_CHUNK)) {
                        last_bit = next_bit;
                        nvecs++;
                } else {
@@ -254,6 +254,20 @@ xfs_buf_item_format(
        vecp++;
        nvecs = 1;
 
+       /*
+        * If it is an inode buffer, transfer the in-memory state to the
+        * format flags and clear the in-memory state. We do not transfer
+        * this state if the inode buffer allocation has not yet been committed
+        * to the log as setting the XFS_BLI_INODE_BUF flag will prevent
+        * correct replay of the inode allocation.
+        */
+       if (bip->bli_flags & XFS_BLI_INODE_BUF) {
+               if (!((bip->bli_flags & XFS_BLI_INODE_ALLOC_BUF) &&
+                     xfs_log_item_in_current_chkpt(&bip->bli_item)))
+                       bip->bli_format.blf_flags |= XFS_BLF_INODE_BUF;
+               bip->bli_flags &= ~XFS_BLI_INODE_BUF;
+       }
+
        if (bip->bli_flags & XFS_BLI_STALE) {
                /*
                 * The buffer is stale, so all we need to log
@@ -261,7 +275,7 @@ xfs_buf_item_format(
                 * cancel flag in it.
                 */
                trace_xfs_buf_item_format_stale(bip);
-               ASSERT(bip->bli_format.blf_flags & XFS_BLI_CANCEL);
+               ASSERT(bip->bli_format.blf_flags & XFS_BLF_CANCEL);
                bip->bli_format.blf_size = nvecs;
                return;
        }
@@ -294,28 +308,28 @@ xfs_buf_item_format(
                 * keep counting and scanning.
                 */
                if (next_bit == -1) {
-                       buffer_offset = first_bit * XFS_BLI_CHUNK;
+                       buffer_offset = first_bit * XFS_BLF_CHUNK;
                        vecp->i_addr = xfs_buf_offset(bp, buffer_offset);
-                       vecp->i_len = nbits * XFS_BLI_CHUNK;
+                       vecp->i_len = nbits * XFS_BLF_CHUNK;
                        vecp->i_type = XLOG_REG_TYPE_BCHUNK;
                        nvecs++;
                        break;
                } else if (next_bit != last_bit + 1) {
-                       buffer_offset = first_bit * XFS_BLI_CHUNK;
+                       buffer_offset = first_bit * XFS_BLF_CHUNK;
                        vecp->i_addr = xfs_buf_offset(bp, buffer_offset);
-                       vecp->i_len = nbits * XFS_BLI_CHUNK;
+                       vecp->i_len = nbits * XFS_BLF_CHUNK;
                        vecp->i_type = XLOG_REG_TYPE_BCHUNK;
                        nvecs++;
                        vecp++;
                        first_bit = next_bit;
                        last_bit = next_bit;
                        nbits = 1;
-               } else if (xfs_buf_offset(bp, next_bit << XFS_BLI_SHIFT) !=
-                          (xfs_buf_offset(bp, last_bit << XFS_BLI_SHIFT) +
-                           XFS_BLI_CHUNK)) {
-                       buffer_offset = first_bit * XFS_BLI_CHUNK;
+               } else if (xfs_buf_offset(bp, next_bit << XFS_BLF_SHIFT) !=
+                          (xfs_buf_offset(bp, last_bit << XFS_BLF_SHIFT) +
+                           XFS_BLF_CHUNK)) {
+                       buffer_offset = first_bit * XFS_BLF_CHUNK;
                        vecp->i_addr = xfs_buf_offset(bp, buffer_offset);
-                       vecp->i_len = nbits * XFS_BLI_CHUNK;
+                       vecp->i_len = nbits * XFS_BLF_CHUNK;
                        vecp->i_type = XLOG_REG_TYPE_BCHUNK;
 /* You would think we need to bump the nvecs here too, but we do not
  * this number is used by recovery, and it gets confused by the boundary
@@ -341,10 +355,15 @@ xfs_buf_item_format(
 }
 
 /*
- * This is called to pin the buffer associated with the buf log
- * item in memory so it cannot be written out.  Simply call bpin()
- * on the buffer to do this.
+ * This is called to pin the buffer associated with the buf log item in memory
+ * so it cannot be written out.  Simply call bpin() on the buffer to do this.
+ *
+ * We also always take a reference to the buffer log item here so that the bli
+ * is held while the item is pinned in memory. This means that we can
+ * unconditionally drop the reference count a transaction holds when the
+ * transaction is completed.
  */
+
 STATIC void
 xfs_buf_item_pin(
        xfs_buf_log_item_t      *bip)
@@ -356,6 +375,7 @@ xfs_buf_item_pin(
        ASSERT(atomic_read(&bip->bli_refcount) > 0);
        ASSERT((bip->bli_flags & XFS_BLI_LOGGED) ||
               (bip->bli_flags & XFS_BLI_STALE));
+       atomic_inc(&bip->bli_refcount);
        trace_xfs_buf_item_pin(bip);
        xfs_bpin(bp);
 }
@@ -393,7 +413,7 @@ xfs_buf_item_unpin(
                ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
                ASSERT(!(XFS_BUF_ISDELAYWRITE(bp)));
                ASSERT(XFS_BUF_ISSTALE(bp));
-               ASSERT(bip->bli_format.blf_flags & XFS_BLI_CANCEL);
+               ASSERT(bip->bli_format.blf_flags & XFS_BLF_CANCEL);
                trace_xfs_buf_item_unpin_stale(bip);
 
                /*
@@ -489,20 +509,23 @@ xfs_buf_item_trylock(
 }
 
 /*
- * Release the buffer associated with the buf log item.
- * If there is no dirty logged data associated with the
- * buffer recorded in the buf log item, then free the
- * buf log item and remove the reference to it in the
- * buffer.
+ * Release the buffer associated with the buf log item.  If there is no dirty
+ * logged data associated with the buffer recorded in the buf log item, then
+ * free the buf log item and remove the reference to it in the buffer.
+ *
+ * This call ignores the recursion count.  It is only called when the buffer
+ * should REALLY be unlocked, regardless of the recursion count.
  *
- * This call ignores the recursion count.  It is only called
- * when the buffer should REALLY be unlocked, regardless
- * of the recursion count.
+ * We unconditionally drop the transaction's reference to the log item. If the
+ * item was logged, then another reference was taken when it was pinned, so we
+ * can safely drop the transaction reference now.  This also allows us to avoid
+ * potential races with the unpin code freeing the bli by not referencing the
+ * bli after we've dropped the reference count.
  *
- * If the XFS_BLI_HOLD flag is set in the buf log item, then
- * free the log item if necessary but do not unlock the buffer.
- * This is for support of xfs_trans_bhold(). Make sure the
- * XFS_BLI_HOLD field is cleared if we don't free the item.
+ * If the XFS_BLI_HOLD flag is set in the buf log item, then free the log item
+ * if necessary but do not unlock the buffer.  This is for support of
+ * xfs_trans_bhold(). Make sure the XFS_BLI_HOLD field is cleared if we don't
+ * free the item.
  */
 STATIC void
 xfs_buf_item_unlock(
@@ -514,73 +537,54 @@ xfs_buf_item_unlock(
 
        bp = bip->bli_buf;
 
-       /*
-        * Clear the buffer's association with this transaction.
-        */
+       /* Clear the buffer's association with this transaction. */
        XFS_BUF_SET_FSPRIVATE2(bp, NULL);
 
        /*
-        * If this is a transaction abort, don't return early.
-        * Instead, allow the brelse to happen.
-        * Normally it would be done for stale (cancelled) buffers
-        * at unpin time, but we'll never go through the pin/unpin
-        * cycle if we abort inside commit.
+        * If this is a transaction abort, don't return early.  Instead, allow
+        * the brelse to happen.  Normally it would be done for stale
+        * (cancelled) buffers at unpin time, but we'll never go through the
+        * pin/unpin cycle if we abort inside commit.
         */
        aborted = (bip->bli_item.li_flags & XFS_LI_ABORTED) != 0;
 
        /*
-        * If the buf item is marked stale, then don't do anything.
-        * We'll unlock the buffer and free the buf item when the
-        * buffer is unpinned for the last time.
+        * Before possibly freeing the buf item, determine if we should
+        * release the buffer at the end of this routine.
         */
-       if (bip->bli_flags & XFS_BLI_STALE) {
-               bip->bli_flags &= ~XFS_BLI_LOGGED;
-               trace_xfs_buf_item_unlock_stale(bip);
-               ASSERT(bip->bli_format.blf_flags & XFS_BLI_CANCEL);
-               if (!aborted)
-                       return;
-       }
+       hold = bip->bli_flags & XFS_BLI_HOLD;
+
+       /* Clear the per transaction state. */
+       bip->bli_flags &= ~(XFS_BLI_LOGGED | XFS_BLI_HOLD);
 
        /*
-        * Drop the transaction's reference to the log item if
-        * it was not logged as part of the transaction.  Otherwise
-        * we'll drop the reference in xfs_buf_item_unpin() when
-        * the transaction is really through with the buffer.
+        * If the buf item is marked stale, then don't do anything.  We'll
+        * unlock the buffer and free the buf item when the buffer is unpinned
+        * for the last time.
         */
-       if (!(bip->bli_flags & XFS_BLI_LOGGED)) {
-               atomic_dec(&bip->bli_refcount);
-       } else {
-               /*
-                * Clear the logged flag since this is per
-                * transaction state.
-                */
-               bip->bli_flags &= ~XFS_BLI_LOGGED;
+       if (bip->bli_flags & XFS_BLI_STALE) {
+               trace_xfs_buf_item_unlock_stale(bip);
+               ASSERT(bip->bli_format.blf_flags & XFS_BLF_CANCEL);
+               if (!aborted) {
+                       atomic_dec(&bip->bli_refcount);
+                       return;
+               }
        }
 
-       /*
-        * Before possibly freeing the buf item, determine if we should
-        * release the buffer at the end of this routine.
-        */
-       hold = bip->bli_flags & XFS_BLI_HOLD;
        trace_xfs_buf_item_unlock(bip);
 
        /*
-        * If the buf item isn't tracking any data, free it.
-        * Otherwise, if XFS_BLI_HOLD is set clear it.
+        * If the buf item isn't tracking any data, free it, otherwise drop the
+        * reference we hold to it.
         */
        if (xfs_bitmap_empty(bip->bli_format.blf_data_map,
-                            bip->bli_format.blf_map_size)) {
+                            bip->bli_format.blf_map_size))
                xfs_buf_item_relse(bp);
-       } else if (hold) {
-               bip->bli_flags &= ~XFS_BLI_HOLD;
-       }
+       else
+               atomic_dec(&bip->bli_refcount);
 
-       /*
-        * Release the buffer if XFS_BLI_HOLD was not set.
-        */
-       if (!hold) {
+       if (!hold)
                xfs_buf_relse(bp);
-       }
 }
 
 /*
@@ -717,12 +721,12 @@ xfs_buf_item_init(
        }
 
        /*
-        * chunks is the number of XFS_BLI_CHUNK size pieces
+        * chunks is the number of XFS_BLF_CHUNK size pieces
         * the buffer can be divided into. Make sure not to
         * truncate any pieces.  map_size is the size of the
         * bitmap needed to describe the chunks of the buffer.
         */
-       chunks = (int)((XFS_BUF_COUNT(bp) + (XFS_BLI_CHUNK - 1)) >> XFS_BLI_SHIFT);
+       chunks = (int)((XFS_BUF_COUNT(bp) + (XFS_BLF_CHUNK - 1)) >> XFS_BLF_SHIFT);
        map_size = (int)((chunks + NBWORD) >> BIT_TO_WORD_SHIFT);
 
        bip = (xfs_buf_log_item_t*)kmem_zone_zalloc(xfs_buf_item_zone,
@@ -790,8 +794,8 @@ xfs_buf_item_log(
        /*
         * Convert byte offsets to bit numbers.
         */
-       first_bit = first >> XFS_BLI_SHIFT;
-       last_bit = last >> XFS_BLI_SHIFT;
+       first_bit = first >> XFS_BLF_SHIFT;
+       last_bit = last >> XFS_BLF_SHIFT;
 
        /*
         * Calculate the total number of bits to be set.
index df4454511f734cc5e0df9bdc40688bdb0eb92bd0..f20bb472d582f1e5b711c1593958b3593ad2167c 100644 (file)
@@ -41,22 +41,22 @@ typedef struct xfs_buf_log_format {
  * This flag indicates that the buffer contains on disk inodes
  * and requires special recovery handling.
  */
-#define        XFS_BLI_INODE_BUF       0x1
+#define        XFS_BLF_INODE_BUF       0x1
 /*
  * This flag indicates that the buffer should not be replayed
  * during recovery because its blocks are being freed.
  */
-#define        XFS_BLI_CANCEL          0x2
+#define        XFS_BLF_CANCEL          0x2
 /*
  * This flag indicates that the buffer contains on disk
  * user or group dquots and may require special recovery handling.
  */
-#define        XFS_BLI_UDQUOT_BUF      0x4
-#define XFS_BLI_PDQUOT_BUF     0x8
-#define        XFS_BLI_GDQUOT_BUF      0x10
+#define        XFS_BLF_UDQUOT_BUF      0x4
+#define XFS_BLF_PDQUOT_BUF     0x8
+#define        XFS_BLF_GDQUOT_BUF      0x10
 
-#define        XFS_BLI_CHUNK           128
-#define        XFS_BLI_SHIFT           7
+#define        XFS_BLF_CHUNK           128
+#define        XFS_BLF_SHIFT           7
 #define        BIT_TO_WORD_SHIFT       5
 #define        NBWORD                  (NBBY * sizeof(unsigned int))
 
@@ -69,6 +69,7 @@ typedef struct xfs_buf_log_format {
 #define        XFS_BLI_LOGGED          0x08
 #define        XFS_BLI_INODE_ALLOC_BUF 0x10
 #define XFS_BLI_STALE_INODE    0x20
+#define        XFS_BLI_INODE_BUF       0x40
 
 #define XFS_BLI_FLAGS \
        { XFS_BLI_HOLD,         "HOLD" }, \
@@ -76,7 +77,8 @@ typedef struct xfs_buf_log_format {
        { XFS_BLI_STALE,        "STALE" }, \
        { XFS_BLI_LOGGED,       "LOGGED" }, \
        { XFS_BLI_INODE_ALLOC_BUF, "INODE_ALLOC" }, \
-       { XFS_BLI_STALE_INODE,  "STALE_INODE" }
+       { XFS_BLI_STALE_INODE,  "STALE_INODE" }, \
+       { XFS_BLI_INODE_BUF,    "INODE_BUF" }
 
 
 #ifdef __KERNEL__
index ef96175c0744579c7a9413ecf7547cb7fa2c0f66..047b8a8e5c294856f861251a4cbfa7a7ec0d00fc 100644 (file)
@@ -170,7 +170,7 @@ xfs_cmn_err(int panic_tag, int level, xfs_mount_t *mp, char *fmt, ...)
        va_list ap;
 
 #ifdef DEBUG
-       xfs_panic_mask |= XFS_PTAG_SHUTDOWN_CORRUPT;
+       xfs_panic_mask |= (XFS_PTAG_SHUTDOWN_CORRUPT | XFS_PTAG_LOGRES);
 #endif
 
        if (xfs_panic_mask && (xfs_panic_mask & panic_tag)
index 3038dd52c72aae8abf5b10cb344fc8235f4b1ba5..5215abc8023aadf15014c8f475ed529508695e30 100644 (file)
@@ -54,9 +54,6 @@ STATIC xlog_t *  xlog_alloc_log(xfs_mount_t   *mp,
 STATIC int      xlog_space_left(xlog_t *log, int cycle, int bytes);
 STATIC int      xlog_sync(xlog_t *log, xlog_in_core_t *iclog);
 STATIC void     xlog_dealloc_log(xlog_t *log);
-STATIC int      xlog_write(struct log *log, struct xfs_log_vec *log_vector,
-                           struct xlog_ticket *tic, xfs_lsn_t *start_lsn,
-                           xlog_in_core_t **commit_iclog, uint flags);
 
 /* local state machine functions */
 STATIC void xlog_state_done_syncing(xlog_in_core_t *iclog, int);
@@ -86,14 +83,6 @@ STATIC int xlog_regrant_write_log_space(xlog_t               *log,
 STATIC void xlog_ungrant_log_space(xlog_t       *log,
                                   xlog_ticket_t *ticket);
 
-
-/* local ticket functions */
-STATIC xlog_ticket_t   *xlog_ticket_alloc(xlog_t *log,
-                                        int    unit_bytes,
-                                        int    count,
-                                        char   clientid,
-                                        uint   flags);
-
 #if defined(DEBUG)
 STATIC void    xlog_verify_dest_ptr(xlog_t *log, char *ptr);
 STATIC void    xlog_verify_grant_head(xlog_t *log, int equals);
@@ -360,6 +349,15 @@ xfs_log_reserve(
                ASSERT(flags & XFS_LOG_PERM_RESERV);
                internal_ticket = *ticket;
 
+               /*
+                * this is a new transaction on the ticket, so we need to
+                * change the transaction ID so that the next transaction has a
+                * different TID in the log. Just add one to the existing tid
+                * so that we can see chains of rolling transactions in the log
+                * easily.
+                */
+               internal_ticket->t_tid++;
+
                trace_xfs_log_reserve(log, internal_ticket);
 
                xlog_grant_push_ail(mp, internal_ticket->t_unit_res);
@@ -367,7 +365,8 @@ xfs_log_reserve(
        } else {
                /* may sleep if need to allocate more tickets */
                internal_ticket = xlog_ticket_alloc(log, unit_bytes, cnt,
-                                                 client, flags);
+                                                 client, flags,
+                                                 KM_SLEEP|KM_MAYFAIL);
                if (!internal_ticket)
                        return XFS_ERROR(ENOMEM);
                internal_ticket->t_trans_type = t_type;
@@ -452,6 +451,13 @@ xfs_log_mount(
        /* Normal transactions can now occur */
        mp->m_log->l_flags &= ~XLOG_ACTIVE_RECOVERY;
 
+       /*
+        * Now the log has been fully initialised and we know were our
+        * space grant counters are, we can initialise the permanent ticket
+        * needed for delayed logging to work.
+        */
+       xlog_cil_init_post_recovery(mp->m_log);
+
        return 0;
 
 out_destroy_ail:
@@ -658,6 +664,10 @@ xfs_log_item_init(
        item->li_ailp = mp->m_ail;
        item->li_type = type;
        item->li_ops = ops;
+       item->li_lv = NULL;
+
+       INIT_LIST_HEAD(&item->li_ail);
+       INIT_LIST_HEAD(&item->li_cil);
 }
 
 /*
@@ -1168,6 +1178,9 @@ xlog_alloc_log(xfs_mount_t        *mp,
        *iclogp = log->l_iclog;                 /* complete ring */
        log->l_iclog->ic_prev = prev_iclog;     /* re-write 1st prev ptr */
 
+       error = xlog_cil_init(log);
+       if (error)
+               goto out_free_iclog;
        return log;
 
 out_free_iclog:
@@ -1494,6 +1507,8 @@ xlog_dealloc_log(xlog_t *log)
        xlog_in_core_t  *iclog, *next_iclog;
        int             i;
 
+       xlog_cil_destroy(log);
+
        iclog = log->l_iclog;
        for (i=0; i<log->l_iclog_bufs; i++) {
                sv_destroy(&iclog->ic_force_wait);
@@ -1536,8 +1551,10 @@ xlog_state_finish_copy(xlog_t            *log,
  * print out info relating to regions written which consume
  * the reservation
  */
-STATIC void
-xlog_print_tic_res(xfs_mount_t *mp, xlog_ticket_t *ticket)
+void
+xlog_print_tic_res(
+       struct xfs_mount        *mp,
+       struct xlog_ticket      *ticket)
 {
        uint i;
        uint ophdr_spc = ticket->t_res_num_ophdrs * (uint)sizeof(xlog_op_header_t);
@@ -1637,6 +1654,10 @@ xlog_print_tic_res(xfs_mount_t *mp, xlog_ticket_t *ticket)
                            "bad-rtype" : res_type_str[r_type-1]),
                            ticket->t_res_arr[i].r_len);
        }
+
+       xfs_cmn_err(XFS_PTAG_LOGRES, CE_ALERT, mp,
+               "xfs_log_write: reservation ran out. Need to up reservation");
+       xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
 }
 
 /*
@@ -1865,7 +1886,7 @@ xlog_write_copy_finish(
  *     we don't update ic_offset until the end when we know exactly how many
  *     bytes have been written out.
  */
-STATIC int
+int
 xlog_write(
        struct log              *log,
        struct xfs_log_vec      *log_vector,
@@ -1889,22 +1910,26 @@ xlog_write(
        *start_lsn = 0;
 
        len = xlog_write_calc_vec_length(ticket, log_vector);
-       if (ticket->t_curr_res < len) {
-               xlog_print_tic_res(log->l_mp, ticket);
-#ifdef DEBUG
-               xlog_panic(
-       "xfs_log_write: reservation ran out. Need to up reservation");
-#else
-               /* Customer configurable panic */
-               xfs_cmn_err(XFS_PTAG_LOGRES, CE_ALERT, log->l_mp,
-       "xfs_log_write: reservation ran out. Need to up reservation");
+       if (log->l_cilp) {
+               /*
+                * Region headers and bytes are already accounted for.
+                * We only need to take into account start records and
+                * split regions in this function.
+                */
+               if (ticket->t_flags & XLOG_TIC_INITED)
+                       ticket->t_curr_res -= sizeof(xlog_op_header_t);
 
-               /* If we did not panic, shutdown the filesystem */
-               xfs_force_shutdown(log->l_mp, SHUTDOWN_CORRUPT_INCORE);
-#endif
-       }
+               /*
+                * Commit record headers need to be accounted for. These
+                * come in as separate writes so are easy to detect.
+                */
+               if (flags & (XLOG_COMMIT_TRANS | XLOG_UNMOUNT_TRANS))
+                       ticket->t_curr_res -= sizeof(xlog_op_header_t);
+       } else
+               ticket->t_curr_res -= len;
 
-       ticket->t_curr_res -= len;
+       if (ticket->t_curr_res < 0)
+               xlog_print_tic_res(log->l_mp, ticket);
 
        index = 0;
        lv = log_vector;
@@ -3000,6 +3025,8 @@ _xfs_log_force(
 
        XFS_STATS_INC(xs_log_force);
 
+       xlog_cil_push(log, 1);
+
        spin_lock(&log->l_icloglock);
 
        iclog = log->l_iclog;
@@ -3149,6 +3176,12 @@ _xfs_log_force_lsn(
 
        XFS_STATS_INC(xs_log_force);
 
+       if (log->l_cilp) {
+               lsn = xlog_cil_push_lsn(log, lsn);
+               if (lsn == NULLCOMMITLSN)
+                       return 0;
+       }
+
 try_again:
        spin_lock(&log->l_icloglock);
        iclog = log->l_iclog;
@@ -3313,22 +3346,30 @@ xfs_log_ticket_get(
        return ticket;
 }
 
+xlog_tid_t
+xfs_log_get_trans_ident(
+       struct xfs_trans        *tp)
+{
+       return tp->t_ticket->t_tid;
+}
+
 /*
  * Allocate and initialise a new log ticket.
  */
-STATIC xlog_ticket_t *
+xlog_ticket_t *
 xlog_ticket_alloc(
        struct log      *log,
        int             unit_bytes,
        int             cnt,
        char            client,
-       uint            xflags)
+       uint            xflags,
+       int             alloc_flags)
 {
        struct xlog_ticket *tic;
        uint            num_headers;
        int             iclog_space;
 
-       tic = kmem_zone_zalloc(xfs_log_ticket_zone, KM_SLEEP|KM_MAYFAIL);
+       tic = kmem_zone_zalloc(xfs_log_ticket_zone, alloc_flags);
        if (!tic)
                return NULL;
 
@@ -3647,6 +3688,11 @@ xlog_state_ioerror(
  *     c. nothing new gets queued up after (a) and (b) are done.
  *     d. if !logerror, flush the iclogs to disk, then seal them off
  *        for business.
+ *
+ * Note: for delayed logging the !logerror case needs to flush the regions
+ * held in memory out to the iclogs before flushing them to disk. This needs
+ * to be done before the log is marked as shutdown, otherwise the flush to the
+ * iclogs will fail.
  */
 int
 xfs_log_force_umount(
@@ -3680,6 +3726,16 @@ xfs_log_force_umount(
                return 1;
        }
        retval = 0;
+
+       /*
+        * Flush the in memory commit item list before marking the log as
+        * being shut down. We need to do it in this order to ensure all the
+        * completed transactions are flushed to disk with the xfs_log_force()
+        * call below.
+        */
+       if (!logerror && (mp->m_flags & XFS_MOUNT_DELAYLOG))
+               xlog_cil_push(log, 1);
+
        /*
         * We must hold both the GRANT lock and the LOG lock,
         * before we mark the filesystem SHUTDOWN and wake
index 229d1f36ba9a8b18f392ee0c7f8ae85f4b207c37..04c78e642cc83b237ed0c5d6258f82e0ccdcad26 100644 (file)
@@ -19,7 +19,6 @@
 #define __XFS_LOG_H__
 
 /* get lsn fields */
-
 #define CYCLE_LSN(lsn) ((uint)((lsn)>>32))
 #define BLOCK_LSN(lsn) ((uint)(lsn))
 
@@ -114,6 +113,9 @@ struct xfs_log_vec {
        struct xfs_log_vec      *lv_next;       /* next lv in build list */
        int                     lv_niovecs;     /* number of iovecs in lv */
        struct xfs_log_iovec    *lv_iovecp;     /* iovec array */
+       struct xfs_log_item     *lv_item;       /* owner */
+       char                    *lv_buf;        /* formatted buffer */
+       int                     lv_buf_len;     /* size of formatted buffer */
 };
 
 /*
@@ -134,6 +136,7 @@ struct xlog_in_core;
 struct xlog_ticket;
 struct xfs_log_item;
 struct xfs_item_ops;
+struct xfs_trans;
 
 void   xfs_log_item_init(struct xfs_mount      *mp,
                        struct xfs_log_item     *item,
@@ -187,9 +190,16 @@ int          xfs_log_need_covered(struct xfs_mount *mp);
 
 void     xlog_iodone(struct xfs_buf *);
 
-struct xlog_ticket * xfs_log_ticket_get(struct xlog_ticket *ticket);
+struct xlog_ticket *xfs_log_ticket_get(struct xlog_ticket *ticket);
 void     xfs_log_ticket_put(struct xlog_ticket *ticket);
 
+xlog_tid_t xfs_log_get_trans_ident(struct xfs_trans *tp);
+
+int    xfs_log_commit_cil(struct xfs_mount *mp, struct xfs_trans *tp,
+                               struct xfs_log_vec *log_vector,
+                               xfs_lsn_t *commit_lsn, int flags);
+bool   xfs_log_item_in_current_chkpt(struct xfs_log_item *lip);
+
 #endif
 
 
diff --git a/fs/xfs/xfs_log_cil.c b/fs/xfs/xfs_log_cil.c
new file mode 100644 (file)
index 0000000..bb17cc0
--- /dev/null
@@ -0,0 +1,725 @@
+/*
+ * Copyright (c) 2010 Red Hat, Inc. 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.
+ *
+ * This program is distributed in the hope that it would 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 the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "xfs.h"
+#include "xfs_fs.h"
+#include "xfs_types.h"
+#include "xfs_bit.h"
+#include "xfs_log.h"
+#include "xfs_inum.h"
+#include "xfs_trans.h"
+#include "xfs_trans_priv.h"
+#include "xfs_log_priv.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "xfs_dir2.h"
+#include "xfs_dmapi.h"
+#include "xfs_mount.h"
+#include "xfs_error.h"
+#include "xfs_alloc.h"
+
+/*
+ * Perform initial CIL structure initialisation. If the CIL is not
+ * enabled in this filesystem, ensure the log->l_cilp is null so
+ * we can check this conditional to determine if we are doing delayed
+ * logging or not.
+ */
+int
+xlog_cil_init(
+       struct log      *log)
+{
+       struct xfs_cil  *cil;
+       struct xfs_cil_ctx *ctx;
+
+       log->l_cilp = NULL;
+       if (!(log->l_mp->m_flags & XFS_MOUNT_DELAYLOG))
+               return 0;
+
+       cil = kmem_zalloc(sizeof(*cil), KM_SLEEP|KM_MAYFAIL);
+       if (!cil)
+               return ENOMEM;
+
+       ctx = kmem_zalloc(sizeof(*ctx), KM_SLEEP|KM_MAYFAIL);
+       if (!ctx) {
+               kmem_free(cil);
+               return ENOMEM;
+       }
+
+       INIT_LIST_HEAD(&cil->xc_cil);
+       INIT_LIST_HEAD(&cil->xc_committing);
+       spin_lock_init(&cil->xc_cil_lock);
+       init_rwsem(&cil->xc_ctx_lock);
+       sv_init(&cil->xc_commit_wait, SV_DEFAULT, "cilwait");
+
+       INIT_LIST_HEAD(&ctx->committing);
+       INIT_LIST_HEAD(&ctx->busy_extents);
+       ctx->sequence = 1;
+       ctx->cil = cil;
+       cil->xc_ctx = ctx;
+
+       cil->xc_log = log;
+       log->l_cilp = cil;
+       return 0;
+}
+
+void
+xlog_cil_destroy(
+       struct log      *log)
+{
+       if (!log->l_cilp)
+               return;
+
+       if (log->l_cilp->xc_ctx) {
+               if (log->l_cilp->xc_ctx->ticket)
+                       xfs_log_ticket_put(log->l_cilp->xc_ctx->ticket);
+               kmem_free(log->l_cilp->xc_ctx);
+       }
+
+       ASSERT(list_empty(&log->l_cilp->xc_cil));
+       kmem_free(log->l_cilp);
+}
+
+/*
+ * Allocate a new ticket. Failing to get a new ticket makes it really hard to
+ * recover, so we don't allow failure here. Also, we allocate in a context that
+ * we don't want to be issuing transactions from, so we need to tell the
+ * allocation code this as well.
+ *
+ * We don't reserve any space for the ticket - we are going to steal whatever
+ * space we require from transactions as they commit. To ensure we reserve all
+ * the space required, we need to set the current reservation of the ticket to
+ * zero so that we know to steal the initial transaction overhead from the
+ * first transaction commit.
+ */
+static struct xlog_ticket *
+xlog_cil_ticket_alloc(
+       struct log      *log)
+{
+       struct xlog_ticket *tic;
+
+       tic = xlog_ticket_alloc(log, 0, 1, XFS_TRANSACTION, 0,
+                               KM_SLEEP|KM_NOFS);
+       tic->t_trans_type = XFS_TRANS_CHECKPOINT;
+
+       /*
+        * set the current reservation to zero so we know to steal the basic
+        * transaction overhead reservation from the first transaction commit.
+        */
+       tic->t_curr_res = 0;
+       return tic;
+}
+
+/*
+ * After the first stage of log recovery is done, we know where the head and
+ * tail of the log are. We need this log initialisation done before we can
+ * initialise the first CIL checkpoint context.
+ *
+ * Here we allocate a log ticket to track space usage during a CIL push.  This
+ * ticket is passed to xlog_write() directly so that we don't slowly leak log
+ * space by failing to account for space used by log headers and additional
+ * region headers for split regions.
+ */
+void
+xlog_cil_init_post_recovery(
+       struct log      *log)
+{
+       if (!log->l_cilp)
+               return;
+
+       log->l_cilp->xc_ctx->ticket = xlog_cil_ticket_alloc(log);
+       log->l_cilp->xc_ctx->sequence = 1;
+       log->l_cilp->xc_ctx->commit_lsn = xlog_assign_lsn(log->l_curr_cycle,
+                                                               log->l_curr_block);
+}
+
+/*
+ * Insert the log item into the CIL and calculate the difference in space
+ * consumed by the item. Add the space to the checkpoint ticket and calculate
+ * if the change requires additional log metadata. If it does, take that space
+ * as well. Remove the amount of space we addded to the checkpoint ticket from
+ * the current transaction ticket so that the accounting works out correctly.
+ *
+ * If this is the first time the item is being placed into the CIL in this
+ * context, pin it so it can't be written to disk until the CIL is flushed to
+ * the iclog and the iclog written to disk.
+ */
+static void
+xlog_cil_insert(
+       struct log              *log,
+       struct xlog_ticket      *ticket,
+       struct xfs_log_item     *item,
+       struct xfs_log_vec      *lv)
+{
+       struct xfs_cil          *cil = log->l_cilp;
+       struct xfs_log_vec      *old = lv->lv_item->li_lv;
+       struct xfs_cil_ctx      *ctx = cil->xc_ctx;
+       int                     len;
+       int                     diff_iovecs;
+       int                     iclog_space;
+
+       if (old) {
+               /* existing lv on log item, space used is a delta */
+               ASSERT(!list_empty(&item->li_cil));
+               ASSERT(old->lv_buf && old->lv_buf_len && old->lv_niovecs);
+
+               len = lv->lv_buf_len - old->lv_buf_len;
+               diff_iovecs = lv->lv_niovecs - old->lv_niovecs;
+               kmem_free(old->lv_buf);
+               kmem_free(old);
+       } else {
+               /* new lv, must pin the log item */
+               ASSERT(!lv->lv_item->li_lv);
+               ASSERT(list_empty(&item->li_cil));
+
+               len = lv->lv_buf_len;
+               diff_iovecs = lv->lv_niovecs;
+               IOP_PIN(lv->lv_item);
+
+       }
+       len += diff_iovecs * sizeof(xlog_op_header_t);
+
+       /* attach new log vector to log item */
+       lv->lv_item->li_lv = lv;
+
+       spin_lock(&cil->xc_cil_lock);
+       list_move_tail(&item->li_cil, &cil->xc_cil);
+       ctx->nvecs += diff_iovecs;
+
+       /*
+        * If this is the first time the item is being committed to the CIL,
+        * store the sequence number on the log item so we can tell
+        * in future commits whether this is the first checkpoint the item is
+        * being committed into.
+        */
+       if (!item->li_seq)
+               item->li_seq = ctx->sequence;
+
+       /*
+        * Now transfer enough transaction reservation to the context ticket
+        * for the checkpoint. The context ticket is special - the unit
+        * reservation has to grow as well as the current reservation as we
+        * steal from tickets so we can correctly determine the space used
+        * during the transaction commit.
+        */
+       if (ctx->ticket->t_curr_res == 0) {
+               /* first commit in checkpoint, steal the header reservation */
+               ASSERT(ticket->t_curr_res >= ctx->ticket->t_unit_res + len);
+               ctx->ticket->t_curr_res = ctx->ticket->t_unit_res;
+               ticket->t_curr_res -= ctx->ticket->t_unit_res;
+       }
+
+       /* do we need space for more log record headers? */
+       iclog_space = log->l_iclog_size - log->l_iclog_hsize;
+       if (len > 0 && (ctx->space_used / iclog_space !=
+                               (ctx->space_used + len) / iclog_space)) {
+               int hdrs;
+
+               hdrs = (len + iclog_space - 1) / iclog_space;
+               /* need to take into account split region headers, too */
+               hdrs *= log->l_iclog_hsize + sizeof(struct xlog_op_header);
+               ctx->ticket->t_unit_res += hdrs;
+               ctx->ticket->t_curr_res += hdrs;
+               ticket->t_curr_res -= hdrs;
+               ASSERT(ticket->t_curr_res >= len);
+       }
+       ticket->t_curr_res -= len;
+       ctx->space_used += len;
+
+       spin_unlock(&cil->xc_cil_lock);
+}
+
+/*
+ * Format log item into a flat buffers
+ *
+ * For delayed logging, we need to hold a formatted buffer containing all the
+ * changes on the log item. This enables us to relog the item in memory and
+ * write it out asynchronously without needing to relock the object that was
+ * modified at the time it gets written into the iclog.
+ *
+ * This function builds a vector for the changes in each log item in the
+ * transaction. It then works out the length of the buffer needed for each log
+ * item, allocates them and formats the vector for the item into the buffer.
+ * The buffer is then attached to the log item are then inserted into the
+ * Committed Item List for tracking until the next checkpoint is written out.
+ *
+ * We don't set up region headers during this process; we simply copy the
+ * regions into the flat buffer. We can do this because we still have to do a
+ * formatting step to write the regions into the iclog buffer.  Writing the
+ * ophdrs during the iclog write means that we can support splitting large
+ * regions across iclog boundares without needing a change in the format of the
+ * item/region encapsulation.
+ *
+ * Hence what we need to do now is change the rewrite the vector array to point
+ * to the copied region inside the buffer we just allocated. This allows us to
+ * format the regions into the iclog as though they are being formatted
+ * directly out of the objects themselves.
+ */
+static void
+xlog_cil_format_items(
+       struct log              *log,
+       struct xfs_log_vec      *log_vector,
+       struct xlog_ticket      *ticket,
+       xfs_lsn_t               *start_lsn)
+{
+       struct xfs_log_vec *lv;
+
+       if (start_lsn)
+               *start_lsn = log->l_cilp->xc_ctx->sequence;
+
+       ASSERT(log_vector);
+       for (lv = log_vector; lv; lv = lv->lv_next) {
+               void    *ptr;
+               int     index;
+               int     len = 0;
+
+               /* build the vector array and calculate it's length */
+               IOP_FORMAT(lv->lv_item, lv->lv_iovecp);
+               for (index = 0; index < lv->lv_niovecs; index++)
+                       len += lv->lv_iovecp[index].i_len;
+
+               lv->lv_buf_len = len;
+               lv->lv_buf = kmem_zalloc(lv->lv_buf_len, KM_SLEEP|KM_NOFS);
+               ptr = lv->lv_buf;
+
+               for (index = 0; index < lv->lv_niovecs; index++) {
+                       struct xfs_log_iovec *vec = &lv->lv_iovecp[index];
+
+                       memcpy(ptr, vec->i_addr, vec->i_len);
+                       vec->i_addr = ptr;
+                       ptr += vec->i_len;
+               }
+               ASSERT(ptr == lv->lv_buf + lv->lv_buf_len);
+
+               xlog_cil_insert(log, ticket, lv->lv_item, lv);
+       }
+}
+
+static void
+xlog_cil_free_logvec(
+       struct xfs_log_vec      *log_vector)
+{
+       struct xfs_log_vec      *lv;
+
+       for (lv = log_vector; lv; ) {
+               struct xfs_log_vec *next = lv->lv_next;
+               kmem_free(lv->lv_buf);
+               kmem_free(lv);
+               lv = next;
+       }
+}
+
+/*
+ * Commit a transaction with the given vector to the Committed Item List.
+ *
+ * To do this, we need to format the item, pin it in memory if required and
+ * account for the space used by the transaction. Once we have done that we
+ * need to release the unused reservation for the transaction, attach the
+ * transaction to the checkpoint context so we carry the busy extents through
+ * to checkpoint completion, and then unlock all the items in the transaction.
+ *
+ * For more specific information about the order of operations in
+ * xfs_log_commit_cil() please refer to the comments in
+ * xfs_trans_commit_iclog().
+ *
+ * Called with the context lock already held in read mode to lock out
+ * background commit, returns without it held once background commits are
+ * allowed again.
+ */
+int
+xfs_log_commit_cil(
+       struct xfs_mount        *mp,
+       struct xfs_trans        *tp,
+       struct xfs_log_vec      *log_vector,
+       xfs_lsn_t               *commit_lsn,
+       int                     flags)
+{
+       struct log              *log = mp->m_log;
+       int                     log_flags = 0;
+       int                     push = 0;
+
+       if (flags & XFS_TRANS_RELEASE_LOG_RES)
+               log_flags = XFS_LOG_REL_PERM_RESERV;
+
+       if (XLOG_FORCED_SHUTDOWN(log)) {
+               xlog_cil_free_logvec(log_vector);
+               return XFS_ERROR(EIO);
+       }
+
+       /* lock out background commit */
+       down_read(&log->l_cilp->xc_ctx_lock);
+       xlog_cil_format_items(log, log_vector, tp->t_ticket, commit_lsn);
+
+       /* check we didn't blow the reservation */
+       if (tp->t_ticket->t_curr_res < 0)
+               xlog_print_tic_res(log->l_mp, tp->t_ticket);
+
+       /* attach the transaction to the CIL if it has any busy extents */
+       if (!list_empty(&tp->t_busy)) {
+               spin_lock(&log->l_cilp->xc_cil_lock);
+               list_splice_init(&tp->t_busy,
+                                       &log->l_cilp->xc_ctx->busy_extents);
+               spin_unlock(&log->l_cilp->xc_cil_lock);
+       }
+
+       tp->t_commit_lsn = *commit_lsn;
+       xfs_log_done(mp, tp->t_ticket, NULL, log_flags);
+       xfs_trans_unreserve_and_mod_sb(tp);
+
+       /* check for background commit before unlock */
+       if (log->l_cilp->xc_ctx->space_used > XLOG_CIL_SPACE_LIMIT(log))
+               push = 1;
+       up_read(&log->l_cilp->xc_ctx_lock);
+
+       /*
+        * We need to push CIL every so often so we don't cache more than we
+        * can fit in the log. The limit really is that a checkpoint can't be
+        * more than half the log (the current checkpoint is not allowed to
+        * overwrite the previous checkpoint), but commit latency and memory
+        * usage limit this to a smaller size in most cases.
+        */
+       if (push)
+               xlog_cil_push(log, 0);
+       return 0;
+}
+
+/*
+ * Mark all items committed and clear busy extents. We free the log vector
+ * chains in a separate pass so that we unpin the log items as quickly as
+ * possible.
+ */
+static void
+xlog_cil_committed(
+       void    *args,
+       int     abort)
+{
+       struct xfs_cil_ctx      *ctx = args;
+       struct xfs_log_vec      *lv;
+       int                     abortflag = abort ? XFS_LI_ABORTED : 0;
+       struct xfs_busy_extent  *busyp, *n;
+
+       /* unpin all the log items */
+       for (lv = ctx->lv_chain; lv; lv = lv->lv_next ) {
+               xfs_trans_item_committed(lv->lv_item, ctx->start_lsn,
+                                                       abortflag);
+       }
+
+       list_for_each_entry_safe(busyp, n, &ctx->busy_extents, list)
+               xfs_alloc_busy_clear(ctx->cil->xc_log->l_mp, busyp);
+
+       spin_lock(&ctx->cil->xc_cil_lock);
+       list_del(&ctx->committing);
+       spin_unlock(&ctx->cil->xc_cil_lock);
+
+       xlog_cil_free_logvec(ctx->lv_chain);
+       kmem_free(ctx);
+}
+
+/*
+ * Push the Committed Item List to the log. If the push_now flag is not set,
+ * then it is a background flush and so we can chose to ignore it.
+ */
+int
+xlog_cil_push(
+       struct log              *log,
+       int                     push_now)
+{
+       struct xfs_cil          *cil = log->l_cilp;
+       struct xfs_log_vec      *lv;
+       struct xfs_cil_ctx      *ctx;
+       struct xfs_cil_ctx      *new_ctx;
+       struct xlog_in_core     *commit_iclog;
+       struct xlog_ticket      *tic;
+       int                     num_lv;
+       int                     num_iovecs;
+       int                     len;
+       int                     error = 0;
+       struct xfs_trans_header thdr;
+       struct xfs_log_iovec    lhdr;
+       struct xfs_log_vec      lvhdr = { NULL };
+       xfs_lsn_t               commit_lsn;
+
+       if (!cil)
+               return 0;
+
+       new_ctx = kmem_zalloc(sizeof(*new_ctx), KM_SLEEP|KM_NOFS);
+       new_ctx->ticket = xlog_cil_ticket_alloc(log);
+
+       /* lock out transaction commit, but don't block on background push */
+       if (!down_write_trylock(&cil->xc_ctx_lock)) {
+               if (!push_now)
+                       goto out_free_ticket;
+               down_write(&cil->xc_ctx_lock);
+       }
+       ctx = cil->xc_ctx;
+
+       /* check if we've anything to push */
+       if (list_empty(&cil->xc_cil))
+               goto out_skip;
+
+       /* check for spurious background flush */
+       if (!push_now && cil->xc_ctx->space_used < XLOG_CIL_SPACE_LIMIT(log))
+               goto out_skip;
+
+       /*
+        * pull all the log vectors off the items in the CIL, and
+        * remove the items from the CIL. We don't need the CIL lock
+        * here because it's only needed on the transaction commit
+        * side which is currently locked out by the flush lock.
+        */
+       lv = NULL;
+       num_lv = 0;
+       num_iovecs = 0;
+       len = 0;
+       while (!list_empty(&cil->xc_cil)) {
+               struct xfs_log_item     *item;
+               int                     i;
+
+               item = list_first_entry(&cil->xc_cil,
+                                       struct xfs_log_item, li_cil);
+               list_del_init(&item->li_cil);
+               if (!ctx->lv_chain)
+                       ctx->lv_chain = item->li_lv;
+               else
+                       lv->lv_next = item->li_lv;
+               lv = item->li_lv;
+               item->li_lv = NULL;
+
+               num_lv++;
+               num_iovecs += lv->lv_niovecs;
+               for (i = 0; i < lv->lv_niovecs; i++)
+                       len += lv->lv_iovecp[i].i_len;
+       }
+
+       /*
+        * initialise the new context and attach it to the CIL. Then attach
+        * the current context to the CIL committing lsit so it can be found
+        * during log forces to extract the commit lsn of the sequence that
+        * needs to be forced.
+        */
+       INIT_LIST_HEAD(&new_ctx->committing);
+       INIT_LIST_HEAD(&new_ctx->busy_extents);
+       new_ctx->sequence = ctx->sequence + 1;
+       new_ctx->cil = cil;
+       cil->xc_ctx = new_ctx;
+
+       /*
+        * The switch is now done, so we can drop the context lock and move out
+        * of a shared context. We can't just go straight to the commit record,
+        * though - we need to synchronise with previous and future commits so
+        * that the commit records are correctly ordered in the log to ensure
+        * that we process items during log IO completion in the correct order.
+        *
+        * For example, if we get an EFI in one checkpoint and the EFD in the
+        * next (e.g. due to log forces), we do not want the checkpoint with
+        * the EFD to be committed before the checkpoint with the EFI.  Hence
+        * we must strictly order the commit records of the checkpoints so
+        * that: a) the checkpoint callbacks are attached to the iclogs in the
+        * correct order; and b) the checkpoints are replayed in correct order
+        * in log recovery.
+        *
+        * Hence we need to add this context to the committing context list so
+        * that higher sequences will wait for us to write out a commit record
+        * before they do.
+        */
+       spin_lock(&cil->xc_cil_lock);
+       list_add(&ctx->committing, &cil->xc_committing);
+       spin_unlock(&cil->xc_cil_lock);
+       up_write(&cil->xc_ctx_lock);
+
+       /*
+        * Build a checkpoint transaction header and write it to the log to
+        * begin the transaction. We need to account for the space used by the
+        * transaction header here as it is not accounted for in xlog_write().
+        *
+        * The LSN we need to pass to the log items on transaction commit is
+        * the LSN reported by the first log vector write. If we use the commit
+        * record lsn then we can move the tail beyond the grant write head.
+        */
+       tic = ctx->ticket;
+       thdr.th_magic = XFS_TRANS_HEADER_MAGIC;
+       thdr.th_type = XFS_TRANS_CHECKPOINT;
+       thdr.th_tid = tic->t_tid;
+       thdr.th_num_items = num_iovecs;
+       lhdr.i_addr = (xfs_caddr_t)&thdr;
+       lhdr.i_len = sizeof(xfs_trans_header_t);
+       lhdr.i_type = XLOG_REG_TYPE_TRANSHDR;
+       tic->t_curr_res -= lhdr.i_len + sizeof(xlog_op_header_t);
+
+       lvhdr.lv_niovecs = 1;
+       lvhdr.lv_iovecp = &lhdr;
+       lvhdr.lv_next = ctx->lv_chain;
+
+       error = xlog_write(log, &lvhdr, tic, &ctx->start_lsn, NULL, 0);
+       if (error)
+               goto out_abort;
+
+       /*
+        * now that we've written the checkpoint into the log, strictly
+        * order the commit records so replay will get them in the right order.
+        */
+restart:
+       spin_lock(&cil->xc_cil_lock);
+       list_for_each_entry(new_ctx, &cil->xc_committing, committing) {
+               /*
+                * Higher sequences will wait for this one so skip them.
+                * Don't wait for own own sequence, either.
+                */
+               if (new_ctx->sequence >= ctx->sequence)
+                       continue;
+               if (!new_ctx->commit_lsn) {
+                       /*
+                        * It is still being pushed! Wait for the push to
+                        * complete, then start again from the beginning.
+                        */
+                       sv_wait(&cil->xc_commit_wait, 0, &cil->xc_cil_lock, 0);
+                       goto restart;
+               }
+       }
+       spin_unlock(&cil->xc_cil_lock);
+
+       commit_lsn = xfs_log_done(log->l_mp, tic, &commit_iclog, 0);
+       if (error || commit_lsn == -1)
+               goto out_abort;
+
+       /* attach all the transactions w/ busy extents to iclog */
+       ctx->log_cb.cb_func = xlog_cil_committed;
+       ctx->log_cb.cb_arg = ctx;
+       error = xfs_log_notify(log->l_mp, commit_iclog, &ctx->log_cb);
+       if (error)
+               goto out_abort;
+
+       /*
+        * now the checkpoint commit is complete and we've attached the
+        * callbacks to the iclog we can assign the commit LSN to the context
+        * and wake up anyone who is waiting for the commit to complete.
+        */
+       spin_lock(&cil->xc_cil_lock);
+       ctx->commit_lsn = commit_lsn;
+       sv_broadcast(&cil->xc_commit_wait);
+       spin_unlock(&cil->xc_cil_lock);
+
+       /* release the hounds! */
+       return xfs_log_release_iclog(log->l_mp, commit_iclog);
+
+out_skip:
+       up_write(&cil->xc_ctx_lock);
+out_free_ticket:
+       xfs_log_ticket_put(new_ctx->ticket);
+       kmem_free(new_ctx);
+       return 0;
+
+out_abort:
+       xlog_cil_committed(ctx, XFS_LI_ABORTED);
+       return XFS_ERROR(EIO);
+}
+
+/*
+ * Conditionally push the CIL based on the sequence passed in.
+ *
+ * We only need to push if we haven't already pushed the sequence
+ * number given. Hence the only time we will trigger a push here is
+ * if the push sequence is the same as the current context.
+ *
+ * We return the current commit lsn to allow the callers to determine if a
+ * iclog flush is necessary following this call.
+ *
+ * XXX: Initially, just push the CIL unconditionally and return whatever
+ * commit lsn is there. It'll be empty, so this is broken for now.
+ */
+xfs_lsn_t
+xlog_cil_push_lsn(
+       struct log      *log,
+       xfs_lsn_t       push_seq)
+{
+       struct xfs_cil          *cil = log->l_cilp;
+       struct xfs_cil_ctx      *ctx;
+       xfs_lsn_t               commit_lsn = NULLCOMMITLSN;
+
+restart:
+       down_write(&cil->xc_ctx_lock);
+       ASSERT(push_seq <= cil->xc_ctx->sequence);
+
+       /* check to see if we need to force out the current context */
+       if (push_seq == cil->xc_ctx->sequence) {
+               up_write(&cil->xc_ctx_lock);
+               xlog_cil_push(log, 1);
+               goto restart;
+       }
+
+       /*
+        * See if we can find a previous sequence still committing.
+        * We can drop the flush lock as soon as we have the cil lock
+        * because we are now only comparing contexts protected by
+        * the cil lock.
+        *
+        * We need to wait for all previous sequence commits to complete
+        * before allowing the force of push_seq to go ahead. Hence block
+        * on commits for those as well.
+        */
+       spin_lock(&cil->xc_cil_lock);
+       up_write(&cil->xc_ctx_lock);
+       list_for_each_entry(ctx, &cil->xc_committing, committing) {
+               if (ctx->sequence > push_seq)
+                       continue;
+               if (!ctx->commit_lsn) {
+                       /*
+                        * It is still being pushed! Wait for the push to
+                        * complete, then start again from the beginning.
+                        */
+                       sv_wait(&cil->xc_commit_wait, 0, &cil->xc_cil_lock, 0);
+                       goto restart;
+               }
+               if (ctx->sequence != push_seq)
+                       continue;
+               /* found it! */
+               commit_lsn = ctx->commit_lsn;
+       }
+       spin_unlock(&cil->xc_cil_lock);
+       return commit_lsn;
+}
+
+/*
+ * Check if the current log item was first committed in this sequence.
+ * We can't rely on just the log item being in the CIL, we have to check
+ * the recorded commit sequence number.
+ *
+ * Note: for this to be used in a non-racy manner, it has to be called with
+ * CIL flushing locked out. As a result, it should only be used during the
+ * transaction commit process when deciding what to format into the item.
+ */
+bool
+xfs_log_item_in_current_chkpt(
+       struct xfs_log_item *lip)
+{
+       struct xfs_cil_ctx *ctx;
+
+       if (!(lip->li_mountp->m_flags & XFS_MOUNT_DELAYLOG))
+               return false;
+       if (list_empty(&lip->li_cil))
+               return false;
+
+       ctx = lip->li_mountp->m_log->l_cilp->xc_ctx;
+
+       /*
+        * li_seq is written on the first commit of a log item to record the
+        * first checkpoint it is written to. Hence if it is different to the
+        * current sequence, we're in a new checkpoint.
+        */
+       if (XFS_LSN_CMP(lip->li_seq, ctx->sequence) != 0)
+               return false;
+       return true;
+}
index 9cf6951544510ea416ceae0383c5acb7fecccd8a..8c072618965caf80476a562e7e38cae026089f88 100644 (file)
@@ -152,8 +152,6 @@ static inline uint xlog_get_client_id(__be32 i)
 #define        XLOG_RECOVERY_NEEDED    0x4     /* log was recovered */
 #define XLOG_IO_ERROR          0x8     /* log hit an I/O error, and being
                                           shutdown */
-typedef __uint32_t xlog_tid_t;
-
 
 #ifdef __KERNEL__
 /*
@@ -378,6 +376,99 @@ typedef struct xlog_in_core {
 #define ic_header      ic_data->hic_header
 } xlog_in_core_t;
 
+/*
+ * The CIL context is used to aggregate per-transaction details as well be
+ * passed to the iclog for checkpoint post-commit processing.  After being
+ * passed to the iclog, another context needs to be allocated for tracking the
+ * next set of transactions to be aggregated into a checkpoint.
+ */
+struct xfs_cil;
+
+struct xfs_cil_ctx {
+       struct xfs_cil          *cil;
+       xfs_lsn_t               sequence;       /* chkpt sequence # */
+       xfs_lsn_t               start_lsn;      /* first LSN of chkpt commit */
+       xfs_lsn_t               commit_lsn;     /* chkpt commit record lsn */
+       struct xlog_ticket      *ticket;        /* chkpt ticket */
+       int                     nvecs;          /* number of regions */
+       int                     space_used;     /* aggregate size of regions */
+       struct list_head        busy_extents;   /* busy extents in chkpt */
+       struct xfs_log_vec      *lv_chain;      /* logvecs being pushed */
+       xfs_log_callback_t      log_cb;         /* completion callback hook. */
+       struct list_head        committing;     /* ctx committing list */
+};
+
+/*
+ * Committed Item List structure
+ *
+ * This structure is used to track log items that have been committed but not
+ * yet written into the log. It is used only when the delayed logging mount
+ * option is enabled.
+ *
+ * This structure tracks the list of committing checkpoint contexts so
+ * we can avoid the problem of having to hold out new transactions during a
+ * flush until we have a the commit record LSN of the checkpoint. We can
+ * traverse the list of committing contexts in xlog_cil_push_lsn() to find a
+ * sequence match and extract the commit LSN directly from there. If the
+ * checkpoint is still in the process of committing, we can block waiting for
+ * the commit LSN to be determined as well. This should make synchronous
+ * operations almost as efficient as the old logging methods.
+ */
+struct xfs_cil {
+       struct log              *xc_log;
+       struct list_head        xc_cil;
+       spinlock_t              xc_cil_lock;
+       struct xfs_cil_ctx      *xc_ctx;
+       struct rw_semaphore     xc_ctx_lock;
+       struct list_head        xc_committing;
+       sv_t                    xc_commit_wait;
+};
+
+/*
+ * The amount of log space we should the CIL to aggregate is difficult to size.
+ * Whatever we chose we have to make we can get a reservation for the log space
+ * effectively, that it is large enough to capture sufficient relogging to
+ * reduce log buffer IO significantly, but it is not too large for the log or
+ * induces too much latency when writing out through the iclogs. We track both
+ * space consumed and the number of vectors in the checkpoint context, so we
+ * need to decide which to use for limiting.
+ *
+ * Every log buffer we write out during a push needs a header reserved, which
+ * is at least one sector and more for v2 logs. Hence we need a reservation of
+ * at least 512 bytes per 32k of log space just for the LR headers. That means
+ * 16KB of reservation per megabyte of delayed logging space we will consume,
+ * plus various headers.  The number of headers will vary based on the num of
+ * io vectors, so limiting on a specific number of vectors is going to result
+ * in transactions of varying size. IOWs, it is more consistent to track and
+ * limit space consumed in the log rather than by the number of objects being
+ * logged in order to prevent checkpoint ticket overruns.
+ *
+ * Further, use of static reservations through the log grant mechanism is
+ * problematic. It introduces a lot of complexity (e.g. reserve grant vs write
+ * grant) and a significant deadlock potential because regranting write space
+ * can block on log pushes. Hence if we have to regrant log space during a log
+ * push, we can deadlock.
+ *
+ * However, we can avoid this by use of a dynamic "reservation stealing"
+ * technique during transaction commit whereby unused reservation space in the
+ * transaction ticket is transferred to the CIL ctx commit ticket to cover the
+ * space needed by the checkpoint transaction. This means that we never need to
+ * specifically reserve space for the CIL checkpoint transaction, nor do we
+ * need to regrant space once the checkpoint completes. This also means the
+ * checkpoint transaction ticket is specific to the checkpoint context, rather
+ * than the CIL itself.
+ *
+ * With dynamic reservations, we can basically make up arbitrary limits for the
+ * checkpoint size so long as they don't violate any other size rules.  Hence
+ * the initial maximum size for the checkpoint transaction will be set to a
+ * quarter of the log or 8MB, which ever is smaller. 8MB is an arbitrary limit
+ * right now based on the latency of writing out a large amount of data through
+ * the circular iclog buffers.
+ */
+
+#define XLOG_CIL_SPACE_LIMIT(log)      \
+       (min((log->l_logsize >> 2), (8 * 1024 * 1024)))
+
 /*
  * The reservation head lsn is not made up of a cycle number and block number.
  * Instead, it uses a cycle number and byte number.  Logs don't expect to
@@ -388,6 +479,7 @@ typedef struct log {
        /* The following fields don't need locking */
        struct xfs_mount        *l_mp;          /* mount point */
        struct xfs_ail          *l_ailp;        /* AIL log is working with */
+       struct xfs_cil          *l_cilp;        /* CIL log is working with */
        struct xfs_buf          *l_xbuf;        /* extra buffer for log
                                                 * wrapping */
        struct xfs_buftarg      *l_targ;        /* buftarg of log */
@@ -438,14 +530,17 @@ typedef struct log {
 
 #define XLOG_FORCED_SHUTDOWN(log)      ((log)->l_flags & XLOG_IO_ERROR)
 
-
 /* common routines */
 extern xfs_lsn_t xlog_assign_tail_lsn(struct xfs_mount *mp);
 extern int      xlog_recover(xlog_t *log);
 extern int      xlog_recover_finish(xlog_t *log);
 extern void     xlog_pack_data(xlog_t *log, xlog_in_core_t *iclog, int);
 
-extern kmem_zone_t     *xfs_log_ticket_zone;
+extern kmem_zone_t *xfs_log_ticket_zone;
+struct xlog_ticket *xlog_ticket_alloc(struct log *log, int unit_bytes,
+                               int count, char client, uint xflags,
+                               int alloc_flags);
+
 
 static inline void
 xlog_write_adv_cnt(void **ptr, int *len, int *off, size_t bytes)
@@ -455,6 +550,21 @@ xlog_write_adv_cnt(void **ptr, int *len, int *off, size_t bytes)
        *off += bytes;
 }
 
+void   xlog_print_tic_res(struct xfs_mount *mp, struct xlog_ticket *ticket);
+int    xlog_write(struct log *log, struct xfs_log_vec *log_vector,
+                               struct xlog_ticket *tic, xfs_lsn_t *start_lsn,
+                               xlog_in_core_t **commit_iclog, uint flags);
+
+/*
+ * Committed Item List interfaces
+ */
+int    xlog_cil_init(struct log *log);
+void   xlog_cil_init_post_recovery(struct log *log);
+void   xlog_cil_destroy(struct log *log);
+
+int    xlog_cil_push(struct log *log, int push_now);
+xfs_lsn_t xlog_cil_push_lsn(struct log *log, xfs_lsn_t push_sequence);
+
 /*
  * Unmount record type is used as a pseudo transaction type for the ticket.
  * It's value must be outside the range of XFS_TRANS_* values.
index 0de08e366315033765870b758073d8794fb1b1e9..14a69aec2c0b28c00d1824c7ae16fce497ff308c 100644 (file)
@@ -1576,7 +1576,7 @@ xlog_recover_reorder_trans(
 
                switch (ITEM_TYPE(item)) {
                case XFS_LI_BUF:
-                       if (!(buf_f->blf_flags & XFS_BLI_CANCEL)) {
+                       if (!(buf_f->blf_flags & XFS_BLF_CANCEL)) {
                                trace_xfs_log_recover_item_reorder_head(log,
                                                        trans, item, pass);
                                list_move(&item->ri_list, &trans->r_itemq);
@@ -1638,7 +1638,7 @@ xlog_recover_do_buffer_pass1(
        /*
         * If this isn't a cancel buffer item, then just return.
         */
-       if (!(flags & XFS_BLI_CANCEL)) {
+       if (!(flags & XFS_BLF_CANCEL)) {
                trace_xfs_log_recover_buf_not_cancel(log, buf_f);
                return;
        }
@@ -1696,7 +1696,7 @@ xlog_recover_do_buffer_pass1(
  * Check to see whether the buffer being recovered has a corresponding
  * entry in the buffer cancel record table.  If it does then return 1
  * so that it will be cancelled, otherwise return 0.  If the buffer is
- * actually a buffer cancel item (XFS_BLI_CANCEL is set), then decrement
+ * actually a buffer cancel item (XFS_BLF_CANCEL is set), then decrement
  * the refcount on the entry in the table and remove it from the table
  * if this is the last reference.
  *
@@ -1721,7 +1721,7 @@ xlog_check_buffer_cancelled(
                 * There is nothing in the table built in pass one,
                 * so this buffer must not be cancelled.
                 */
-               ASSERT(!(flags & XFS_BLI_CANCEL));
+               ASSERT(!(flags & XFS_BLF_CANCEL));
                return 0;
        }
 
@@ -1733,7 +1733,7 @@ xlog_check_buffer_cancelled(
                 * There is no corresponding entry in the table built
                 * in pass one, so this buffer has not been cancelled.
                 */
-               ASSERT(!(flags & XFS_BLI_CANCEL));
+               ASSERT(!(flags & XFS_BLF_CANCEL));
                return 0;
        }
 
@@ -1752,7 +1752,7 @@ xlog_check_buffer_cancelled(
                         * one in the table and remove it if this is the
                         * last reference.
                         */
-                       if (flags & XFS_BLI_CANCEL) {
+                       if (flags & XFS_BLF_CANCEL) {
                                bcp->bc_refcount--;
                                if (bcp->bc_refcount == 0) {
                                        if (prevp == NULL) {
@@ -1772,7 +1772,7 @@ xlog_check_buffer_cancelled(
         * We didn't find a corresponding entry in the table, so
         * return 0 so that the buffer is NOT cancelled.
         */
-       ASSERT(!(flags & XFS_BLI_CANCEL));
+       ASSERT(!(flags & XFS_BLF_CANCEL));
        return 0;
 }
 
@@ -1874,8 +1874,8 @@ xlog_recover_do_inode_buffer(
                        nbits = xfs_contig_bits(data_map, map_size,
                                                         bit);
                        ASSERT(nbits > 0);
-                       reg_buf_offset = bit << XFS_BLI_SHIFT;
-                       reg_buf_bytes = nbits << XFS_BLI_SHIFT;
+                       reg_buf_offset = bit << XFS_BLF_SHIFT;
+                       reg_buf_bytes = nbits << XFS_BLF_SHIFT;
                        item_index++;
                }
 
@@ -1889,7 +1889,7 @@ xlog_recover_do_inode_buffer(
                }
 
                ASSERT(item->ri_buf[item_index].i_addr != NULL);
-               ASSERT((item->ri_buf[item_index].i_len % XFS_BLI_CHUNK) == 0);
+               ASSERT((item->ri_buf[item_index].i_len % XFS_BLF_CHUNK) == 0);
                ASSERT((reg_buf_offset + reg_buf_bytes) <= XFS_BUF_COUNT(bp));
 
                /*
@@ -1955,9 +1955,9 @@ xlog_recover_do_reg_buffer(
                nbits = xfs_contig_bits(data_map, map_size, bit);
                ASSERT(nbits > 0);
                ASSERT(item->ri_buf[i].i_addr != NULL);
-               ASSERT(item->ri_buf[i].i_len % XFS_BLI_CHUNK == 0);
+               ASSERT(item->ri_buf[i].i_len % XFS_BLF_CHUNK == 0);
                ASSERT(XFS_BUF_COUNT(bp) >=
-                      ((uint)bit << XFS_BLI_SHIFT)+(nbits<<XFS_BLI_SHIFT));
+                      ((uint)bit << XFS_BLF_SHIFT)+(nbits<<XFS_BLF_SHIFT));
 
                /*
                 * Do a sanity check if this is a dquot buffer. Just checking
@@ -1966,7 +1966,7 @@ xlog_recover_do_reg_buffer(
                 */
                error = 0;
                if (buf_f->blf_flags &
-                  (XFS_BLI_UDQUOT_BUF|XFS_BLI_PDQUOT_BUF|XFS_BLI_GDQUOT_BUF)) {
+                  (XFS_BLF_UDQUOT_BUF|XFS_BLF_PDQUOT_BUF|XFS_BLF_GDQUOT_BUF)) {
                        if (item->ri_buf[i].i_addr == NULL) {
                                cmn_err(CE_ALERT,
                                        "XFS: NULL dquot in %s.", __func__);
@@ -1987,9 +1987,9 @@ xlog_recover_do_reg_buffer(
                }
 
                memcpy(xfs_buf_offset(bp,
-                       (uint)bit << XFS_BLI_SHIFT),    /* dest */
+                       (uint)bit << XFS_BLF_SHIFT),    /* dest */
                        item->ri_buf[i].i_addr,         /* source */
-                       nbits<<XFS_BLI_SHIFT);          /* length */
+                       nbits<<XFS_BLF_SHIFT);          /* length */
  next:
                i++;
                bit += nbits;
@@ -2148,11 +2148,11 @@ xlog_recover_do_dquot_buffer(
        }
 
        type = 0;
-       if (buf_f->blf_flags & XFS_BLI_UDQUOT_BUF)
+       if (buf_f->blf_flags & XFS_BLF_UDQUOT_BUF)
                type |= XFS_DQ_USER;
-       if (buf_f->blf_flags & XFS_BLI_PDQUOT_BUF)
+       if (buf_f->blf_flags & XFS_BLF_PDQUOT_BUF)
                type |= XFS_DQ_PROJ;
-       if (buf_f->blf_flags & XFS_BLI_GDQUOT_BUF)
+       if (buf_f->blf_flags & XFS_BLF_GDQUOT_BUF)
                type |= XFS_DQ_GROUP;
        /*
         * This type of quotas was turned off, so ignore this buffer
@@ -2173,7 +2173,7 @@ xlog_recover_do_dquot_buffer(
  * here which overlaps that may be stale.
  *
  * When meta-data buffers are freed at run time we log a buffer item
- * with the XFS_BLI_CANCEL bit set to indicate that previous copies
+ * with the XFS_BLF_CANCEL bit set to indicate that previous copies
  * of the buffer in the log should not be replayed at recovery time.
  * This is so that if the blocks covered by the buffer are reused for
  * file data before we crash we don't end up replaying old, freed
@@ -2207,7 +2207,7 @@ xlog_recover_do_buffer_trans(
        if (pass == XLOG_RECOVER_PASS1) {
                /*
                 * In this pass we're only looking for buf items
-                * with the XFS_BLI_CANCEL bit set.
+                * with the XFS_BLF_CANCEL bit set.
                 */
                xlog_recover_do_buffer_pass1(log, buf_f);
                return 0;
@@ -2244,7 +2244,7 @@ xlog_recover_do_buffer_trans(
 
        mp = log->l_mp;
        buf_flags = XBF_LOCK;
-       if (!(flags & XFS_BLI_INODE_BUF))
+       if (!(flags & XFS_BLF_INODE_BUF))
                buf_flags |= XBF_MAPPED;
 
        bp = xfs_buf_read(mp->m_ddev_targp, blkno, len, buf_flags);
@@ -2257,10 +2257,10 @@ xlog_recover_do_buffer_trans(
        }
 
        error = 0;
-       if (flags & XFS_BLI_INODE_BUF) {
+       if (flags & XFS_BLF_INODE_BUF) {
                error = xlog_recover_do_inode_buffer(mp, item, bp, buf_f);
        } else if (flags &
-                 (XFS_BLI_UDQUOT_BUF|XFS_BLI_PDQUOT_BUF|XFS_BLI_GDQUOT_BUF)) {
+                 (XFS_BLF_UDQUOT_BUF|XFS_BLF_PDQUOT_BUF|XFS_BLF_GDQUOT_BUF)) {
                xlog_recover_do_dquot_buffer(mp, log, item, bp, buf_f);
        } else {
                xlog_recover_do_reg_buffer(mp, item, bp, buf_f);
index 75d749207258b7208acdea39347e45395236e607..1c55ccbb379d0b2a7dc744cb3c869ce51ed5b14f 100644 (file)
@@ -28,7 +28,7 @@
 #define XLOG_RHASH(tid)        \
        ((((__uint32_t)tid)>>XLOG_RHASH_SHIFT) & (XLOG_RHASH_SIZE-1))
 
-#define XLOG_MAX_REGIONS_IN_ITEM   (XFS_MAX_BLOCKSIZE / XFS_BLI_CHUNK / 2 + 1)
+#define XLOG_MAX_REGIONS_IN_ITEM   (XFS_MAX_BLOCKSIZE / XFS_BLF_CHUNK / 2 + 1)
 
 
 /*
index 9ff48a16a7ee6334a2ab310dee58f5dc5a6ba323..1d2c7eed4eda6e3fb545f6b3dd4e0fb30515ea5f 100644 (file)
@@ -268,6 +268,7 @@ typedef struct xfs_mount {
 #define XFS_MOUNT_WSYNC                (1ULL << 0)     /* for nfs - all metadata ops
                                                   must be synchronous except
                                                   for space allocations */
+#define XFS_MOUNT_DELAYLOG     (1ULL << 1)     /* delayed logging is enabled */
 #define XFS_MOUNT_DMAPI                (1ULL << 2)     /* dmapi is enabled */
 #define XFS_MOUNT_WAS_CLEAN    (1ULL << 3)
 #define XFS_MOUNT_FS_SHUTDOWN  (1ULL << 4)     /* atomic stop of all filesystem
index be578ecb4af2d756dc09538f5cc955df019ef70f..ce558efa2ea02a8ba9fd1f8b2bb2bad121a64071 100644 (file)
@@ -44,6 +44,7 @@
 #include "xfs_trans_priv.h"
 #include "xfs_trans_space.h"
 #include "xfs_inode_item.h"
+#include "xfs_trace.h"
 
 kmem_zone_t    *xfs_trans_zone;
 
@@ -243,9 +244,8 @@ _xfs_trans_alloc(
        tp->t_type = type;
        tp->t_mountp = mp;
        tp->t_items_free = XFS_LIC_NUM_SLOTS;
-       tp->t_busy_free = XFS_LBC_NUM_SLOTS;
        xfs_lic_init(&(tp->t_items));
-       XFS_LBC_INIT(&(tp->t_busy));
+       INIT_LIST_HEAD(&tp->t_busy);
        return tp;
 }
 
@@ -255,8 +255,13 @@ _xfs_trans_alloc(
  */
 STATIC void
 xfs_trans_free(
-       xfs_trans_t     *tp)
+       struct xfs_trans        *tp)
 {
+       struct xfs_busy_extent  *busyp, *n;
+
+       list_for_each_entry_safe(busyp, n, &tp->t_busy, list)
+               xfs_alloc_busy_clear(tp->t_mountp, busyp);
+
        atomic_dec(&tp->t_mountp->m_active_trans);
        xfs_trans_free_dqinfo(tp);
        kmem_zone_free(xfs_trans_zone, tp);
@@ -285,9 +290,8 @@ xfs_trans_dup(
        ntp->t_type = tp->t_type;
        ntp->t_mountp = tp->t_mountp;
        ntp->t_items_free = XFS_LIC_NUM_SLOTS;
-       ntp->t_busy_free = XFS_LBC_NUM_SLOTS;
        xfs_lic_init(&(ntp->t_items));
-       XFS_LBC_INIT(&(ntp->t_busy));
+       INIT_LIST_HEAD(&ntp->t_busy);
 
        ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);
        ASSERT(tp->t_ticket != NULL);
@@ -423,7 +427,6 @@ undo_blocks:
        return error;
 }
 
-
 /*
  * Record the indicated change to the given field for application
  * to the file system's superblock when the transaction commits.
@@ -652,7 +655,7 @@ xfs_trans_apply_sb_deltas(
  * XFS_TRANS_SB_DIRTY will not be set when the transaction is updated but we
  * still need to update the incore superblock with the changes.
  */
-STATIC void
+void
 xfs_trans_unreserve_and_mod_sb(
        xfs_trans_t     *tp)
 {
@@ -880,7 +883,7 @@ xfs_trans_fill_vecs(
  * they could be immediately flushed and we'd have to race with the flusher
  * trying to pull the item from the AIL as we add it.
  */
-static void
+void
 xfs_trans_item_committed(
        struct xfs_log_item     *lip,
        xfs_lsn_t               commit_lsn,
@@ -930,26 +933,6 @@ xfs_trans_item_committed(
        IOP_UNPIN(lip);
 }
 
-/* Clear all the per-AG busy list items listed in this transaction */
-static void
-xfs_trans_clear_busy_extents(
-       struct xfs_trans        *tp)
-{
-       xfs_log_busy_chunk_t    *lbcp;
-       xfs_log_busy_slot_t     *lbsp;
-       int                     i;
-
-       for (lbcp = &tp->t_busy; lbcp != NULL; lbcp = lbcp->lbc_next) {
-               i = 0;
-               for (lbsp = lbcp->lbc_busy; i < lbcp->lbc_unused; i++, lbsp++) {
-                       if (XFS_LBC_ISFREE(lbcp, i))
-                               continue;
-                       xfs_alloc_clear_busy(tp, lbsp->lbc_ag, lbsp->lbc_idx);
-               }
-       }
-       xfs_trans_free_busy(tp);
-}
-
 /*
  * This is typically called by the LM when a transaction has been fully
  * committed to disk.  It needs to unpin the items which have
@@ -984,7 +967,6 @@ xfs_trans_committed(
                kmem_free(licp);
        }
 
-       xfs_trans_clear_busy_extents(tp);
        xfs_trans_free(tp);
 }
 
@@ -1012,8 +994,7 @@ xfs_trans_uncommit(
        xfs_trans_unreserve_and_mod_sb(tp);
        xfs_trans_unreserve_and_mod_dquots(tp);
 
-       xfs_trans_free_items(tp, flags);
-       xfs_trans_free_busy(tp);
+       xfs_trans_free_items(tp, NULLCOMMITLSN, flags);
        xfs_trans_free(tp);
 }
 
@@ -1075,6 +1056,8 @@ xfs_trans_commit_iclog(
        *commit_lsn = xfs_log_done(mp, tp->t_ticket, &commit_iclog, log_flags);
 
        tp->t_commit_lsn = *commit_lsn;
+       trace_xfs_trans_commit_lsn(tp);
+
        if (nvec > XFS_TRANS_LOGVEC_COUNT)
                kmem_free(log_vector);
 
@@ -1161,6 +1144,93 @@ xfs_trans_commit_iclog(
        return xfs_log_release_iclog(mp, commit_iclog);
 }
 
+/*
+ * Walk the log items and allocate log vector structures for
+ * each item large enough to fit all the vectors they require.
+ * Note that this format differs from the old log vector format in
+ * that there is no transaction header in these log vectors.
+ */
+STATIC struct xfs_log_vec *
+xfs_trans_alloc_log_vecs(
+       xfs_trans_t     *tp)
+{
+       xfs_log_item_desc_t     *lidp;
+       struct xfs_log_vec      *lv = NULL;
+       struct xfs_log_vec      *ret_lv = NULL;
+
+       lidp = xfs_trans_first_item(tp);
+
+       /* Bail out if we didn't find a log item.  */
+       if (!lidp) {
+               ASSERT(0);
+               return NULL;
+       }
+
+       while (lidp != NULL) {
+               struct xfs_log_vec *new_lv;
+
+               /* Skip items which aren't dirty in this transaction. */
+               if (!(lidp->lid_flags & XFS_LID_DIRTY)) {
+                       lidp = xfs_trans_next_item(tp, lidp);
+                       continue;
+               }
+
+               /* Skip items that do not have any vectors for writing */
+               lidp->lid_size = IOP_SIZE(lidp->lid_item);
+               if (!lidp->lid_size) {
+                       lidp = xfs_trans_next_item(tp, lidp);
+                       continue;
+               }
+
+               new_lv = kmem_zalloc(sizeof(*new_lv) +
+                               lidp->lid_size * sizeof(struct xfs_log_iovec),
+                               KM_SLEEP);
+
+               /* The allocated iovec region lies beyond the log vector. */
+               new_lv->lv_iovecp = (struct xfs_log_iovec *)&new_lv[1];
+               new_lv->lv_niovecs = lidp->lid_size;
+               new_lv->lv_item = lidp->lid_item;
+               if (!ret_lv)
+                       ret_lv = new_lv;
+               else
+                       lv->lv_next = new_lv;
+               lv = new_lv;
+               lidp = xfs_trans_next_item(tp, lidp);
+       }
+
+       return ret_lv;
+}
+
+static int
+xfs_trans_commit_cil(
+       struct xfs_mount        *mp,
+       struct xfs_trans        *tp,
+       xfs_lsn_t               *commit_lsn,
+       int                     flags)
+{
+       struct xfs_log_vec      *log_vector;
+       int                     error;
+
+       /*
+        * Get each log item to allocate a vector structure for
+        * the log item to to pass to the log write code. The
+        * CIL commit code will format the vector and save it away.
+        */
+       log_vector = xfs_trans_alloc_log_vecs(tp);
+       if (!log_vector)
+               return ENOMEM;
+
+       error = xfs_log_commit_cil(mp, tp, log_vector, commit_lsn, flags);
+       if (error)
+               return error;
+
+       current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
+
+       /* xfs_trans_free_items() unlocks them first */
+       xfs_trans_free_items(tp, *commit_lsn, 0);
+       xfs_trans_free(tp);
+       return 0;
+}
 
 /*
  * xfs_trans_commit
@@ -1221,7 +1291,11 @@ _xfs_trans_commit(
                xfs_trans_apply_sb_deltas(tp);
        xfs_trans_apply_dquot_deltas(tp);
 
-       error = xfs_trans_commit_iclog(mp, tp, &commit_lsn, flags);
+       if (mp->m_flags & XFS_MOUNT_DELAYLOG)
+               error = xfs_trans_commit_cil(mp, tp, &commit_lsn, flags);
+       else
+               error = xfs_trans_commit_iclog(mp, tp, &commit_lsn, flags);
+
        if (error == ENOMEM) {
                xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR);
                error = XFS_ERROR(EIO);
@@ -1259,8 +1333,7 @@ out_unreserve:
                        error = XFS_ERROR(EIO);
        }
        current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
-       xfs_trans_free_items(tp, error ? XFS_TRANS_ABORT : 0);
-       xfs_trans_free_busy(tp);
+       xfs_trans_free_items(tp, NULLCOMMITLSN, error ? XFS_TRANS_ABORT : 0);
        xfs_trans_free(tp);
 
        XFS_STATS_INC(xs_trans_empty);
@@ -1338,8 +1411,7 @@ xfs_trans_cancel(
        /* mark this thread as no longer being in a transaction */
        current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
 
-       xfs_trans_free_items(tp, flags);
-       xfs_trans_free_busy(tp);
+       xfs_trans_free_items(tp, NULLCOMMITLSN, flags);
        xfs_trans_free(tp);
 }
 
index c62beee0921ea102e1c6ba27869fd93f062e3c65..8c69e7824f68439d01d0b27009f961dbd8e0c947 100644 (file)
@@ -106,7 +106,8 @@ typedef struct xfs_trans_header {
 #define        XFS_TRANS_GROWFSRT_FREE         39
 #define        XFS_TRANS_SWAPEXT               40
 #define        XFS_TRANS_SB_COUNT              41
-#define        XFS_TRANS_TYPE_MAX              41
+#define        XFS_TRANS_CHECKPOINT            42
+#define        XFS_TRANS_TYPE_MAX              42
 /* new transaction types need to be reflected in xfs_logprint(8) */
 
 #define XFS_TRANS_TYPES \
@@ -148,6 +149,7 @@ typedef struct xfs_trans_header {
        { XFS_TRANS_GROWFSRT_FREE,      "GROWFSRT_FREE" }, \
        { XFS_TRANS_SWAPEXT,            "SWAPEXT" }, \
        { XFS_TRANS_SB_COUNT,           "SB_COUNT" }, \
+       { XFS_TRANS_CHECKPOINT,         "CHECKPOINT" }, \
        { XFS_TRANS_DUMMY1,             "DUMMY1" }, \
        { XFS_TRANS_DUMMY2,             "DUMMY2" }, \
        { XLOG_UNMOUNT_REC_TYPE,        "UNMOUNT" }
@@ -813,6 +815,7 @@ struct xfs_log_item_desc;
 struct xfs_mount;
 struct xfs_trans;
 struct xfs_dquot_acct;
+struct xfs_busy_extent;
 
 typedef struct xfs_log_item {
        struct list_head                li_ail;         /* AIL pointers */
@@ -828,6 +831,11 @@ typedef struct xfs_log_item {
                                                        /* buffer item iodone */
                                                        /* callback func */
        struct xfs_item_ops             *li_ops;        /* function list */
+
+       /* delayed logging */
+       struct list_head                li_cil;         /* CIL pointers */
+       struct xfs_log_vec              *li_lv;         /* active log vector */
+       xfs_lsn_t                       li_seq;         /* CIL commit seq */
 } xfs_log_item_t;
 
 #define        XFS_LI_IN_AIL   0x1
@@ -871,34 +879,6 @@ typedef struct xfs_item_ops {
 #define        XFS_ITEM_LOCKED         2
 #define XFS_ITEM_PUSHBUF       3
 
-/*
- * This structure is used to maintain a list of block ranges that have been
- * freed in the transaction.  The ranges are listed in the perag[] busy list
- * between when they're freed and the transaction is committed to disk.
- */
-
-typedef struct xfs_log_busy_slot {
-       xfs_agnumber_t          lbc_ag;
-       ushort                  lbc_idx;        /* index in perag.busy[] */
-} xfs_log_busy_slot_t;
-
-#define XFS_LBC_NUM_SLOTS      31
-typedef struct xfs_log_busy_chunk {
-       struct xfs_log_busy_chunk       *lbc_next;
-       uint                            lbc_free;       /* free slots bitmask */
-       ushort                          lbc_unused;     /* first unused */
-       xfs_log_busy_slot_t             lbc_busy[XFS_LBC_NUM_SLOTS];
-} xfs_log_busy_chunk_t;
-
-#define        XFS_LBC_MAX_SLOT        (XFS_LBC_NUM_SLOTS - 1)
-#define        XFS_LBC_FREEMASK        ((1U << XFS_LBC_NUM_SLOTS) - 1)
-
-#define        XFS_LBC_INIT(cp)        ((cp)->lbc_free = XFS_LBC_FREEMASK)
-#define        XFS_LBC_CLAIM(cp, slot) ((cp)->lbc_free &= ~(1 << (slot)))
-#define        XFS_LBC_SLOT(cp, slot)  (&((cp)->lbc_busy[(slot)]))
-#define        XFS_LBC_VACANCY(cp)     (((cp)->lbc_free) & XFS_LBC_FREEMASK)
-#define        XFS_LBC_ISFREE(cp, slot) ((cp)->lbc_free & (1 << (slot)))
-
 /*
  * This is the type of function which can be given to xfs_trans_callback()
  * to be called upon the transaction's commit to disk.
@@ -950,8 +930,7 @@ typedef struct xfs_trans {
        unsigned int            t_items_free;   /* log item descs free */
        xfs_log_item_chunk_t    t_items;        /* first log item desc chunk */
        xfs_trans_header_t      t_header;       /* header for in-log trans */
-       unsigned int            t_busy_free;    /* busy descs free */
-       xfs_log_busy_chunk_t    t_busy;         /* busy/async free blocks */
+       struct list_head        t_busy;         /* list of busy extents */
        unsigned long           t_pflags;       /* saved process flags state */
 } xfs_trans_t;
 
@@ -1025,9 +1004,6 @@ int               _xfs_trans_commit(xfs_trans_t *,
 void           xfs_trans_cancel(xfs_trans_t *, int);
 int            xfs_trans_ail_init(struct xfs_mount *);
 void           xfs_trans_ail_destroy(struct xfs_mount *);
-xfs_log_busy_slot_t *xfs_trans_add_busy(xfs_trans_t *tp,
-                                       xfs_agnumber_t ag,
-                                       xfs_extlen_t idx);
 
 extern kmem_zone_t     *xfs_trans_zone;
 
index 9cd809025f3a3934d18b3b74dba11b00f2d27e18..63d81a22f4fd60c6d6abc93538c37e6480c8fd3b 100644 (file)
@@ -114,7 +114,7 @@ _xfs_trans_bjoin(
        xfs_buf_item_init(bp, tp->t_mountp);
        bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *);
        ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
-       ASSERT(!(bip->bli_format.blf_flags & XFS_BLI_CANCEL));
+       ASSERT(!(bip->bli_format.blf_flags & XFS_BLF_CANCEL));
        ASSERT(!(bip->bli_flags & XFS_BLI_LOGGED));
        if (reset_recur)
                bip->bli_recur = 0;
@@ -511,7 +511,7 @@ xfs_trans_brelse(xfs_trans_t        *tp,
        bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *);
        ASSERT(bip->bli_item.li_type == XFS_LI_BUF);
        ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
-       ASSERT(!(bip->bli_format.blf_flags & XFS_BLI_CANCEL));
+       ASSERT(!(bip->bli_format.blf_flags & XFS_BLF_CANCEL));
        ASSERT(atomic_read(&bip->bli_refcount) > 0);
 
        /*
@@ -619,7 +619,7 @@ xfs_trans_bhold(xfs_trans_t *tp,
 
        bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *);
        ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
-       ASSERT(!(bip->bli_format.blf_flags & XFS_BLI_CANCEL));
+       ASSERT(!(bip->bli_format.blf_flags & XFS_BLF_CANCEL));
        ASSERT(atomic_read(&bip->bli_refcount) > 0);
        bip->bli_flags |= XFS_BLI_HOLD;
        trace_xfs_trans_bhold(bip);
@@ -641,7 +641,7 @@ xfs_trans_bhold_release(xfs_trans_t *tp,
 
        bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *);
        ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
-       ASSERT(!(bip->bli_format.blf_flags & XFS_BLI_CANCEL));
+       ASSERT(!(bip->bli_format.blf_flags & XFS_BLF_CANCEL));
        ASSERT(atomic_read(&bip->bli_refcount) > 0);
        ASSERT(bip->bli_flags & XFS_BLI_HOLD);
        bip->bli_flags &= ~XFS_BLI_HOLD;
@@ -704,7 +704,7 @@ xfs_trans_log_buf(xfs_trans_t       *tp,
                bip->bli_flags &= ~XFS_BLI_STALE;
                ASSERT(XFS_BUF_ISSTALE(bp));
                XFS_BUF_UNSTALE(bp);
-               bip->bli_format.blf_flags &= ~XFS_BLI_CANCEL;
+               bip->bli_format.blf_flags &= ~XFS_BLF_CANCEL;
        }
 
        lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)bip);
@@ -762,8 +762,8 @@ xfs_trans_binval(
                ASSERT(!(XFS_BUF_ISDELAYWRITE(bp)));
                ASSERT(XFS_BUF_ISSTALE(bp));
                ASSERT(!(bip->bli_flags & (XFS_BLI_LOGGED | XFS_BLI_DIRTY)));
-               ASSERT(!(bip->bli_format.blf_flags & XFS_BLI_INODE_BUF));
-               ASSERT(bip->bli_format.blf_flags & XFS_BLI_CANCEL);
+               ASSERT(!(bip->bli_format.blf_flags & XFS_BLF_INODE_BUF));
+               ASSERT(bip->bli_format.blf_flags & XFS_BLF_CANCEL);
                ASSERT(lidp->lid_flags & XFS_LID_DIRTY);
                ASSERT(tp->t_flags & XFS_TRANS_DIRTY);
                return;
@@ -774,7 +774,7 @@ xfs_trans_binval(
         * in the buf log item.  The STALE flag will be used in
         * xfs_buf_item_unpin() to determine if it should clean up
         * when the last reference to the buf item is given up.
-        * We set the XFS_BLI_CANCEL flag in the buf log format structure
+        * We set the XFS_BLF_CANCEL flag in the buf log format structure
         * and log the buf item.  This will be used at recovery time
         * to determine that copies of the buffer in the log before
         * this should not be replayed.
@@ -792,9 +792,9 @@ xfs_trans_binval(
        XFS_BUF_UNDELAYWRITE(bp);
        XFS_BUF_STALE(bp);
        bip->bli_flags |= XFS_BLI_STALE;
-       bip->bli_flags &= ~(XFS_BLI_LOGGED | XFS_BLI_DIRTY);
-       bip->bli_format.blf_flags &= ~XFS_BLI_INODE_BUF;
-       bip->bli_format.blf_flags |= XFS_BLI_CANCEL;
+       bip->bli_flags &= ~(XFS_BLI_INODE_BUF | XFS_BLI_LOGGED | XFS_BLI_DIRTY);
+       bip->bli_format.blf_flags &= ~XFS_BLF_INODE_BUF;
+       bip->bli_format.blf_flags |= XFS_BLF_CANCEL;
        memset((char *)(bip->bli_format.blf_data_map), 0,
              (bip->bli_format.blf_map_size * sizeof(uint)));
        lidp->lid_flags |= XFS_LID_DIRTY;
@@ -802,16 +802,16 @@ xfs_trans_binval(
 }
 
 /*
- * This call is used to indicate that the buffer contains on-disk
- * inodes which must be handled specially during recovery.  They
- * require special handling because only the di_next_unlinked from
- * the inodes in the buffer should be recovered.  The rest of the
- * data in the buffer is logged via the inodes themselves.
+ * This call is used to indicate that the buffer contains on-disk inodes which
+ * must be handled specially during recovery.  They require special handling
+ * because only the di_next_unlinked from the inodes in the buffer should be
+ * recovered.  The rest of the data in the buffer is logged via the inodes
+ * themselves.
  *
- * All we do is set the XFS_BLI_INODE_BUF flag in the buffer's log
- * format structure so that we'll know what to do at recovery time.
+ * All we do is set the XFS_BLI_INODE_BUF flag in the items flags so it can be
+ * transferred to the buffer's log format structure so that we'll know what to
+ * do at recovery time.
  */
-/* ARGSUSED */
 void
 xfs_trans_inode_buf(
        xfs_trans_t     *tp,
@@ -826,7 +826,7 @@ xfs_trans_inode_buf(
        bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *);
        ASSERT(atomic_read(&bip->bli_refcount) > 0);
 
-       bip->bli_format.blf_flags |= XFS_BLI_INODE_BUF;
+       bip->bli_flags |= XFS_BLI_INODE_BUF;
 }
 
 /*
@@ -908,9 +908,9 @@ xfs_trans_dquot_buf(
        ASSERT(XFS_BUF_ISBUSY(bp));
        ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp);
        ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL);
-       ASSERT(type == XFS_BLI_UDQUOT_BUF ||
-              type == XFS_BLI_PDQUOT_BUF ||
-              type == XFS_BLI_GDQUOT_BUF);
+       ASSERT(type == XFS_BLF_UDQUOT_BUF ||
+              type == XFS_BLF_PDQUOT_BUF ||
+              type == XFS_BLF_GDQUOT_BUF);
 
        bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *);
        ASSERT(atomic_read(&bip->bli_refcount) > 0);
index eb3fc57f9eef681d73e39e07e3546cb45c350929..f11d37d06dcc1cfde42290d17ca885a07a85cb75 100644 (file)
@@ -299,6 +299,7 @@ xfs_trans_next_item(xfs_trans_t *tp, xfs_log_item_desc_t *lidp)
 void
 xfs_trans_free_items(
        xfs_trans_t     *tp,
+       xfs_lsn_t       commit_lsn,
        int             flags)
 {
        xfs_log_item_chunk_t    *licp;
@@ -311,7 +312,7 @@ xfs_trans_free_items(
         * Special case the embedded chunk so we don't free it below.
         */
        if (!xfs_lic_are_all_free(licp)) {
-               (void) xfs_trans_unlock_chunk(licp, 1, abort, NULLCOMMITLSN);
+               (void) xfs_trans_unlock_chunk(licp, 1, abort, commit_lsn);
                xfs_lic_all_free(licp);
                licp->lic_unused = 0;
        }
@@ -322,7 +323,7 @@ xfs_trans_free_items(
         */
        while (licp != NULL) {
                ASSERT(!xfs_lic_are_all_free(licp));
-               (void) xfs_trans_unlock_chunk(licp, 1, abort, NULLCOMMITLSN);
+               (void) xfs_trans_unlock_chunk(licp, 1, abort, commit_lsn);
                next_licp = licp->lic_next;
                kmem_free(licp);
                licp = next_licp;
@@ -438,112 +439,3 @@ xfs_trans_unlock_chunk(
 
        return freed;
 }
-
-
-/*
- * This is called to add the given busy item to the transaction's
- * list of busy items.  It must find a free busy item descriptor
- * or allocate a new one and add the item to that descriptor.
- * The function returns a pointer to busy descriptor used to point
- * to the new busy entry.  The log busy entry will now point to its new
- * descriptor with its ???? field.
- */
-xfs_log_busy_slot_t *
-xfs_trans_add_busy(xfs_trans_t *tp, xfs_agnumber_t ag, xfs_extlen_t idx)
-{
-       xfs_log_busy_chunk_t    *lbcp;
-       xfs_log_busy_slot_t     *lbsp;
-       int                     i=0;
-
-       /*
-        * If there are no free descriptors, allocate a new chunk
-        * of them and put it at the front of the chunk list.
-        */
-       if (tp->t_busy_free == 0) {
-               lbcp = (xfs_log_busy_chunk_t*)
-                      kmem_alloc(sizeof(xfs_log_busy_chunk_t), KM_SLEEP);
-               ASSERT(lbcp != NULL);
-               /*
-                * Initialize the chunk, and then
-                * claim the first slot in the newly allocated chunk.
-                */
-               XFS_LBC_INIT(lbcp);
-               XFS_LBC_CLAIM(lbcp, 0);
-               lbcp->lbc_unused = 1;
-               lbsp = XFS_LBC_SLOT(lbcp, 0);
-
-               /*
-                * Link in the new chunk and update the free count.
-                */
-               lbcp->lbc_next = tp->t_busy.lbc_next;
-               tp->t_busy.lbc_next = lbcp;
-               tp->t_busy_free = XFS_LIC_NUM_SLOTS - 1;
-
-               /*
-                * Initialize the descriptor and the generic portion
-                * of the log item.
-                *
-                * Point the new slot at this item and return it.
-                * Also point the log item at its currently active
-                * descriptor and set the item's mount pointer.
-                */
-               lbsp->lbc_ag = ag;
-               lbsp->lbc_idx = idx;
-               return lbsp;
-       }
-
-       /*
-        * Find the free descriptor. It is somewhere in the chunklist
-        * of descriptors.
-        */
-       lbcp = &tp->t_busy;
-       while (lbcp != NULL) {
-               if (XFS_LBC_VACANCY(lbcp)) {
-                       if (lbcp->lbc_unused <= XFS_LBC_MAX_SLOT) {
-                               i = lbcp->lbc_unused;
-                               break;
-                       } else {
-                               /* out-of-order vacancy */
-                               cmn_err(CE_DEBUG, "OOO vacancy lbcp 0x%p\n", lbcp);
-                               ASSERT(0);
-                       }
-               }
-               lbcp = lbcp->lbc_next;
-       }
-       ASSERT(lbcp != NULL);
-       /*
-        * If we find a free descriptor, claim it,
-        * initialize it, and return it.
-        */
-       XFS_LBC_CLAIM(lbcp, i);
-       if (lbcp->lbc_unused <= i) {
-               lbcp->lbc_unused = i + 1;
-       }
-       lbsp = XFS_LBC_SLOT(lbcp, i);
-       tp->t_busy_free--;
-       lbsp->lbc_ag = ag;
-       lbsp->lbc_idx = idx;
-       return lbsp;
-}
-
-
-/*
- * xfs_trans_free_busy
- * Free all of the busy lists from a transaction
- */
-void
-xfs_trans_free_busy(xfs_trans_t *tp)
-{
-       xfs_log_busy_chunk_t    *lbcp;
-       xfs_log_busy_chunk_t    *lbcq;
-
-       lbcp = tp->t_busy.lbc_next;
-       while (lbcp != NULL) {
-               lbcq = lbcp->lbc_next;
-               kmem_free(lbcp);
-               lbcp = lbcq;
-       }
-
-       XFS_LBC_INIT(&tp->t_busy);
-       tp->t_busy.lbc_unused = 0;
-}
index 73e2ad3974328ed9a62a81663feab3aacd0f730d..c6e4f2c8de6e8049a760b1510eb42beb54a295ae 100644 (file)
@@ -35,13 +35,14 @@ struct xfs_log_item_desc    *xfs_trans_find_item(struct xfs_trans *,
 struct xfs_log_item_desc       *xfs_trans_first_item(struct xfs_trans *);
 struct xfs_log_item_desc       *xfs_trans_next_item(struct xfs_trans *,
                                             struct xfs_log_item_desc *);
-void                           xfs_trans_free_items(struct xfs_trans *, int);
-void                           xfs_trans_unlock_items(struct xfs_trans *,
-                                                       xfs_lsn_t);
-void                           xfs_trans_free_busy(xfs_trans_t *tp);
-xfs_log_busy_slot_t            *xfs_trans_add_busy(xfs_trans_t *tp,
-                                                   xfs_agnumber_t ag,
-                                                   xfs_extlen_t idx);
+
+void   xfs_trans_unlock_items(struct xfs_trans *tp, xfs_lsn_t commit_lsn);
+void   xfs_trans_free_items(struct xfs_trans *tp, xfs_lsn_t commit_lsn,
+                               int flags);
+
+void   xfs_trans_item_committed(struct xfs_log_item *lip,
+                               xfs_lsn_t commit_lsn, int aborted);
+void   xfs_trans_unreserve_and_mod_sb(struct xfs_trans *tp);
 
 /*
  * AIL traversal cursor.
index b09904555d07c43b4cdd4c336c177614702b665d..320775295e323f406d4e8b85018556f00c764e6c 100644 (file)
@@ -75,6 +75,8 @@ typedef       __uint32_t      xfs_dahash_t;   /* dir/attr hash value */
 
 typedef __uint16_t     xfs_prid_t;     /* prid_t truncated to 16bits in XFS */
 
+typedef __uint32_t     xlog_tid_t;     /* transaction ID type */
+
 /*
  * These types are 64 bits on disk but are either 32 or 64 bits in memory.
  * Disk based types:
index 7bf83ddf82e03278c27d54cc9f20dd5360fbe31d..baacd98e7cc6244b795b5db1b09b440292ee3dac 100644 (file)
@@ -373,7 +373,7 @@ struct acpi_pci_root {
        struct acpi_pci_id id;
        struct pci_bus *bus;
        u16 segment;
-       u8 bus_nr;
+       struct resource secondary;      /* downstream bus range */
 
        u32 osc_support_set;    /* _OSC state of support bits */
        u32 osc_control_set;    /* _OSC state of control bits */
index 4f7b44866b762351ca4bfacdbcb65cacec13d010..23d78b4d088b70eeb95f5ab9737fded3044ec910 100644 (file)
@@ -104,8 +104,7 @@ int acpi_pci_bind_root(struct acpi_device *device);
 
 /* Arch-defined function to add a bus to the system */
 
-struct pci_bus *pci_acpi_scan_root(struct acpi_device *device, int domain,
-                                  int bus);
+struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root);
 void pci_acpi_crs_quirks(void);
 
 /* --------------------------------------------------------------------------
diff --git a/include/acpi/acpi_hest.h b/include/acpi/acpi_hest.h
deleted file mode 100644 (file)
index 63194d0..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef __ACPI_HEST_H
-#define __ACPI_HEST_H
-
-#include <linux/pci.h>
-
-#ifdef CONFIG_ACPI
-extern int acpi_hest_firmware_first_pci(struct pci_dev *pci);
-#else
-static inline int acpi_hest_firmware_first_pci(struct pci_dev *pci) { return 0; }
-#endif
-
-#endif
diff --git a/include/acpi/apei.h b/include/acpi/apei.h
new file mode 100644 (file)
index 0000000..b336502
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * apei.h - ACPI Platform Error Interface
+ */
+
+#ifndef ACPI_APEI_H
+#define ACPI_APEI_H
+
+#include <linux/acpi.h>
+#include <linux/cper.h>
+#include <asm/ioctls.h>
+
+#define APEI_ERST_INVALID_RECORD_ID    0xffffffffffffffffULL
+
+#define APEI_ERST_CLEAR_RECORD         _IOW('E', 1, u64)
+#define APEI_ERST_GET_RECORD_COUNT     _IOR('E', 2, u32)
+
+#ifdef __KERNEL__
+
+extern int hest_disable;
+extern int erst_disable;
+
+typedef int (*apei_hest_func_t)(struct acpi_hest_header *hest_hdr, void *data);
+int apei_hest_parse(apei_hest_func_t func, void *data);
+
+int erst_write(const struct cper_record_header *record);
+ssize_t erst_get_record_count(void);
+int erst_get_next_record_id(u64 *record_id);
+ssize_t erst_read(u64 record_id, struct cper_record_header *record,
+                 size_t buflen);
+ssize_t erst_read_next(struct cper_record_header *record, size_t buflen);
+int erst_clear(u64 record_id);
+
+#endif
+#endif
diff --git a/include/acpi/atomicio.h b/include/acpi/atomicio.h
new file mode 100644 (file)
index 0000000..8b9fb4b
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef ACPI_ATOMIC_IO_H
+#define ACPI_ATOMIC_IO_H
+
+int acpi_pre_map_gar(struct acpi_generic_address *reg);
+int acpi_post_unmap_gar(struct acpi_generic_address *reg);
+
+int acpi_atomic_read(u64 *val, struct acpi_generic_address *reg);
+int acpi_atomic_write(u64 val, struct acpi_generic_address *reg);
+
+#endif
diff --git a/include/acpi/hed.h b/include/acpi/hed.h
new file mode 100644 (file)
index 0000000..46e1249
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * hed.h - ACPI Hardware Error Device
+ *
+ * Copyright (C) 2009, Intel Corp.
+ *     Author: Huang Ying <ying.huang@intel.com>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#ifndef ACPI_HED_H
+#define ACPI_HED_H
+
+#include <linux/notifier.h>
+
+int register_acpi_hed_notifier(struct notifier_block *nb);
+void unregister_acpi_hed_notifier(struct notifier_block *nb);
+
+#endif
index 86825ddbe14e50a2ba76c5f112fc1edc9f3875d2..da565a48240e5ad93df5233273bb58301e940752 100644 (file)
@@ -52,17 +52,6 @@ struct acpi_power_register {
        u64 address;
 } __attribute__ ((packed));
 
-struct acpi_processor_cx_policy {
-       u32 count;
-       struct acpi_processor_cx *state;
-       struct {
-               u32 time;
-               u32 ticks;
-               u32 count;
-               u32 bm;
-       } threshold;
-};
-
 struct acpi_processor_cx {
        u8 valid;
        u8 type;
@@ -74,8 +63,6 @@ struct acpi_processor_cx {
        u32 power;
        u32 usage;
        u64 time;
-       struct acpi_processor_cx_policy promotion;
-       struct acpi_processor_cx_policy demotion;
        char desc[ACPI_CX_DESC_LEN];
 };
 
index cf7be3dd157bec5572a2b9f3220e4e1274d5f27b..551793c9b6e8c25b2b1d3e36a4fe8ffcb4a0f24a 100644 (file)
@@ -1,12 +1,28 @@
 #ifndef __ACPI_VIDEO_H
 #define __ACPI_VIDEO_H
 
+#define ACPI_VIDEO_DISPLAY_CRT  1
+#define ACPI_VIDEO_DISPLAY_TV   2
+#define ACPI_VIDEO_DISPLAY_DVI  3
+#define ACPI_VIDEO_DISPLAY_LCD  4
+
+#define ACPI_VIDEO_DISPLAY_LEGACY_MONITOR 0x0100
+#define ACPI_VIDEO_DISPLAY_LEGACY_PANEL   0x0110
+#define ACPI_VIDEO_DISPLAY_LEGACY_TV      0x0200
+
 #if (defined CONFIG_ACPI_VIDEO || defined CONFIG_ACPI_VIDEO_MODULE)
 extern int acpi_video_register(void);
 extern void acpi_video_unregister(void);
+extern int acpi_video_get_edid(struct acpi_device *device, int type,
+                              int device_id, void **edid);
 #else
 static inline int acpi_video_register(void) { return 0; }
 static inline void acpi_video_unregister(void) { return; }
+static inline int acpi_video_get_edid(struct acpi_device *device, int type,
+                                     int device_id, void **edid)
+{
+       return -ENODEV;
+}
 #endif
 
 #endif
index c33749f95b325ceca7aa3c3e9fb2803145101356..058129e9b04c75f8cf7d5c24a9f1fa5b0cbe7bed 100644 (file)
@@ -30,8 +30,7 @@
  * atomic_read - read atomic variable
  * @v: pointer of type atomic_t
  *
- * Atomically reads the value of @v.  Note that the guaranteed
- * useful range of an atomic_t is only 24 bits.
+ * Atomically reads the value of @v.
  */
 #define atomic_read(v) (*(volatile int *)&(v)->counter)
 
@@ -40,8 +39,7 @@
  * @v: pointer of type atomic_t
  * @i: required value
  *
- * Atomically sets the value of @v to @i.  Note that the guaranteed
- * useful range of an atomic_t is only 24 bits.
+ * Atomically sets the value of @v to @i.
  */
 #define atomic_set(v, i) (((v)->counter) = (i))
 
@@ -53,7 +51,6 @@
  * @v: pointer of type atomic_t
  *
  * Atomically adds @i to @v and returns the result
- * Note that the guaranteed useful range of an atomic_t is only 24 bits.
  */
 static inline int atomic_add_return(int i, atomic_t *v)
 {
@@ -75,7 +72,6 @@ static inline int atomic_add_return(int i, atomic_t *v)
  * @v: pointer of type atomic_t
  *
  * Atomically subtracts @i from @v and returns the result
- * Note that the guaranteed useful range of an atomic_t is only 24 bits.
  */
 static inline int atomic_sub_return(int i, atomic_t *v)
 {
index 18c435d7c082e387fdeca7a436e1e98f7ee3c2e3..c2c9ba032d4688c80cf7b3e1546da8a558068ec5 100644 (file)
@@ -25,7 +25,10 @@ struct bug_entry {
 };
 #endif         /* __ASSEMBLY__ */
 
-#define BUGFLAG_WARNING        (1<<0)
+#define BUGFLAG_WARNING                (1 << 0)
+#define BUGFLAG_TAINT(taint)   (BUGFLAG_WARNING | ((taint) << 8))
+#define BUG_GET_TAINT(bug)     ((bug)->flags >> 8)
+
 #endif /* CONFIG_GENERIC_BUG */
 
 /*
@@ -56,17 +59,25 @@ struct bug_entry {
  * appear at runtime.  Use the versions with printk format strings
  * to provide better diagnostics.
  */
-#ifndef __WARN
+#ifndef __WARN_TAINT
 #ifndef __ASSEMBLY__
 extern void warn_slowpath_fmt(const char *file, const int line,
                const char *fmt, ...) __attribute__((format(printf, 3, 4)));
+extern void warn_slowpath_fmt_taint(const char *file, const int line,
+                                   unsigned taint, const char *fmt, ...)
+       __attribute__((format(printf, 4, 5)));
 extern void warn_slowpath_null(const char *file, const int line);
 #define WANT_WARN_ON_SLOWPATH
 #endif
 #define __WARN()               warn_slowpath_null(__FILE__, __LINE__)
 #define __WARN_printf(arg...)  warn_slowpath_fmt(__FILE__, __LINE__, arg)
+#define __WARN_printf_taint(taint, arg...)                             \
+       warn_slowpath_fmt_taint(__FILE__, __LINE__, taint, arg)
 #else
+#define __WARN()               __WARN_TAINT(TAINT_WARN)
 #define __WARN_printf(arg...)  do { printk(arg); __WARN(); } while (0)
+#define __WARN_printf_taint(taint, arg...)                             \
+       do { printk(arg); __WARN_TAINT(taint); } while (0)
 #endif
 
 #ifndef WARN_ON
@@ -87,6 +98,13 @@ extern void warn_slowpath_null(const char *file, const int line);
 })
 #endif
 
+#define WARN_TAINT(condition, taint, format...) ({                     \
+       int __ret_warn_on = !!(condition);                              \
+       if (unlikely(__ret_warn_on))                                    \
+               __WARN_printf_taint(taint, format);                     \
+       unlikely(__ret_warn_on);                                        \
+})
+
 #else /* !CONFIG_BUG */
 #ifndef HAVE_ARCH_BUG
 #define BUG() do {} while(0)
@@ -110,6 +128,8 @@ extern void warn_slowpath_null(const char *file, const int line);
 })
 #endif
 
+#define WARN_TAINT(condition, taint, format...) WARN_ON(condition)
+
 #endif
 
 #define WARN_ON_ONCE(condition)        ({                              \
@@ -132,6 +152,16 @@ extern void warn_slowpath_null(const char *file, const int line);
        unlikely(__ret_warn_once);                              \
 })
 
+#define WARN_TAINT_ONCE(condition, taint, format...)   ({      \
+       static bool __warned;                                   \
+       int __ret_warn_once = !!(condition);                    \
+                                                               \
+       if (unlikely(__ret_warn_once))                          \
+               if (WARN_TAINT(!__warned, taint, format))       \
+                       __warned = true;                        \
+       unlikely(__ret_warn_once);                              \
+})
+
 #define WARN_ON_RATELIMIT(condition, state)                    \
                WARN_ON((condition) && __ratelimit(state))
 
index 69206957b72c52efe1f9fe7d2479cfc931d7d7b7..0c80bb38773f142ef829dcbc190c60f2cf6ccff8 100644 (file)
@@ -123,15 +123,7 @@ static inline void dma_sync_single_range_for_cpu(struct device *dev,
                                                 size_t size,
                                                 enum dma_data_direction dir)
 {
-       struct dma_map_ops *ops = get_dma_ops(dev);
-
-       BUG_ON(!valid_dma_direction(dir));
-       if (ops->sync_single_range_for_cpu) {
-               ops->sync_single_range_for_cpu(dev, addr, offset, size, dir);
-               debug_dma_sync_single_range_for_cpu(dev, addr, offset, size, dir);
-
-       } else
-               dma_sync_single_for_cpu(dev, addr + offset, size, dir);
+       dma_sync_single_for_cpu(dev, addr + offset, size, dir);
 }
 
 static inline void dma_sync_single_range_for_device(struct device *dev,
@@ -140,15 +132,7 @@ static inline void dma_sync_single_range_for_device(struct device *dev,
                                                    size_t size,
                                                    enum dma_data_direction dir)
 {
-       struct dma_map_ops *ops = get_dma_ops(dev);
-
-       BUG_ON(!valid_dma_direction(dir));
-       if (ops->sync_single_range_for_device) {
-               ops->sync_single_range_for_device(dev, addr, offset, size, dir);
-               debug_dma_sync_single_range_for_device(dev, addr, offset, size, dir);
-
-       } else
-               dma_sync_single_for_device(dev, addr + offset, size, dir);
+       dma_sync_single_for_device(dev, addr + offset, size, dir);
 }
 
 static inline void
index 979c6a57f2f1b48690d46171b21edb5c954f083b..4f3d75e1ad391a669d842c7c58e65b46bfd9cbd4 100644 (file)
@@ -60,7 +60,9 @@ struct module;
  * @names: if set, must be an array of strings to use as alternative
  *      names for the GPIOs in this chip. Any entry in the array
  *      may be NULL if there is no alias for the GPIO, however the
- *      array must be @ngpio entries long.
+ *      array must be @ngpio entries long.  A name can include a single printk
+ *      format specifier for an unsigned int.  It is substituted by the actual
+ *      number of the gpio.
  *
  * A gpio_chip can help platforms abstract various sources of GPIOs so
  * they can all be accessed through a common programing interface.
@@ -88,6 +90,9 @@ struct gpio_chip {
                                                unsigned offset);
        int                     (*direction_output)(struct gpio_chip *chip,
                                                unsigned offset, int value);
+       int                     (*set_debounce)(struct gpio_chip *chip,
+                                               unsigned offset, unsigned debounce);
+
        void                    (*set)(struct gpio_chip *chip,
                                                unsigned offset, int value);
 
@@ -98,7 +103,7 @@ struct gpio_chip {
                                                struct gpio_chip *chip);
        int                     base;
        u16                     ngpio;
-       char                    **names;
+       const char              *const *names;
        unsigned                can_sleep:1;
        unsigned                exported:1;
 };
@@ -121,6 +126,8 @@ extern void gpio_free(unsigned gpio);
 extern int gpio_direction_input(unsigned gpio);
 extern int gpio_direction_output(unsigned gpio, int value);
 
+extern int gpio_set_debounce(unsigned gpio, unsigned debounce);
+
 extern int gpio_get_value_cansleep(unsigned gpio);
 extern void gpio_set_value_cansleep(unsigned gpio, int value);
 
index 97e807c8c8124bd0ba48dfca9ae2b1461d0d7677..0232ccb76f2b18d86b15992c3c6afa45c83a3340 100644 (file)
@@ -29,6 +29,9 @@ KMAP_D(16)    KM_IRQ_PTE,
 KMAP_D(17)     KM_NMI,
 KMAP_D(18)     KM_NMI_PTE,
 KMAP_D(19)     KM_KDB,
+/*
+ * Remember to update debug_kmap_atomic() when adding new kmap types!
+ */
 KMAP_D(20)     KM_TYPE_NR
 };
 
index 8b9454496a7c901edd8723586a98981916faeac8..5de07355fad492b10b15227e7959f7cc08e6b044 100644 (file)
@@ -11,7 +11,9 @@ struct scatterlist {
        unsigned int    offset;
        unsigned int    length;
        dma_addr_t      dma_address;
+#ifdef CONFIG_NEED_SG_DMA_LENGTH
        unsigned int    dma_length;
+#endif
 };
 
 /*
@@ -22,22 +24,11 @@ struct scatterlist {
  * is 0.
  */
 #define sg_dma_address(sg)     ((sg)->dma_address)
-#ifndef sg_dma_len
-/*
- * Normally, you have an iommu on 64 bit machines, but not on 32 bit
- * machines. Architectures that are differnt should override this.
- */
-#if __BITS_PER_LONG == 64
+
+#ifdef CONFIG_NEED_SG_DMA_LENGTH
 #define sg_dma_len(sg)         ((sg)->dma_length)
 #else
 #define sg_dma_len(sg)         ((sg)->length)
-#endif /* 64 bit */
-#endif /* sg_dma_len */
-
-#ifndef ISA_DMA_THRESHOLD
-#define ISA_DMA_THRESHOLD      (~0UL)
 #endif
 
-#define ARCH_HAS_SG_CHAIN
-
 #endif /* __ASM_GENERIC_SCATTERLIST_H */
index 510df36dd5d44f8b40e0ed048bbb7c8fa1ef506f..fd60700503c8545795a031e15147e466154f0051 100644 (file)
@@ -34,6 +34,9 @@
 #ifndef cpu_to_node
 #define cpu_to_node(cpu)       ((void)(cpu),0)
 #endif
+#ifndef cpu_to_mem
+#define cpu_to_mem(cpu)                ((void)(cpu),0)
+#endif
 #ifndef parent_node
 #define parent_node(node)      ((void)(node),0)
 #endif
index 67e652068e0e45b8031cafd2fb236be5e692c7c4..ef779c6fc3d7e89571390a01bbdb3da137bc1af1 100644 (file)
        }                                                               \
                                                                        \
        /* RapidIO route ops */                                         \
-       .rio_route        : AT(ADDR(.rio_route) - LOAD_OFFSET) {        \
-               VMLINUX_SYMBOL(__start_rio_route_ops) = .;              \
-               *(.rio_route_ops)                                       \
-               VMLINUX_SYMBOL(__end_rio_route_ops) = .;                \
+       .rio_ops        : AT(ADDR(.rio_ops) - LOAD_OFFSET) {            \
+               VMLINUX_SYMBOL(__start_rio_switch_ops) = .;             \
+               *(.rio_switch_ops)                                      \
+               VMLINUX_SYMBOL(__end_rio_switch_ops) = .;               \
        }                                                               \
                                                                        \
        TRACEDATA                                                       \
index 3da73f5f0ae997cb54e820cf8fbe3b73cffb5c06..224a38c960d4c01830eb96987325d88aee33a2bf 100644 (file)
@@ -248,11 +248,12 @@ int acpi_check_region(resource_size_t start, resource_size_t n,
 int acpi_check_mem_region(resource_size_t start, resource_size_t n,
                      const char *name);
 
+int acpi_resources_are_enforced(void);
+
 #ifdef CONFIG_PM_SLEEP
 void __init acpi_no_s4_hw_signature(void);
 void __init acpi_old_suspend_ordering(void);
 void __init acpi_s4_no_nvs(void);
-void __init acpi_set_sci_en_on_resume(void);
 #endif /* CONFIG_PM_SLEEP */
 
 struct acpi_osc_context {
index 811dbb369379ff463110289bba1d44b9bb14a2a2..7a8db41552813ff15e6739943ad401cfe5f56b3c 100644 (file)
@@ -212,6 +212,8 @@ extern void kick_iocb(struct kiocb *iocb);
 extern int aio_complete(struct kiocb *iocb, long res, long res2);
 struct mm_struct;
 extern void exit_aio(struct mm_struct *mm);
+extern long do_io_submit(aio_context_t ctx_id, long nr,
+                        struct iocb __user *__user *iocbpp, bool compat);
 #else
 static inline ssize_t wait_on_sync_kiocb(struct kiocb *iocb) { return 0; }
 static inline int aio_put_req(struct kiocb *iocb) { return 0; }
@@ -219,6 +221,9 @@ static inline void kick_iocb(struct kiocb *iocb) { }
 static inline int aio_complete(struct kiocb *iocb, long res, long res2) { return 0; }
 struct mm_struct;
 static inline void exit_aio(struct mm_struct *mm) { }
+static inline long do_io_submit(aio_context_t ctx_id, long nr,
+                               struct iocb __user * __user *iocbpp,
+                               bool compat) { return 0; }
 #endif /* CONFIG_AIO */
 
 static inline struct kiocb *list_kiocb(struct list_head *h)
index e4836c6b3dd75bc925e1d530704cb8834633bb35..abf26cc47a2bc19ff0238a71128d2505c9acc156 100644 (file)
@@ -71,6 +71,7 @@ struct ssp_clock_params {
 
 /**
  * enum ssp_rx_endian - endianess of Rx FIFO Data
+ * this feature is only available in ST versionf of PL022
  */
 enum ssp_rx_endian {
        SSP_RX_MSB,
@@ -181,7 +182,8 @@ enum ssp_microwire_wait_state {
 };
 
 /**
- * enum Microwire - whether Full/Half Duplex
+ * enum ssp_duplex - whether Full/Half Duplex on microwire, only
+ * available in the ST Micro variant.
  * @SSP_MICROWIRE_CHANNEL_FULL_DUPLEX: SSPTXD becomes bi-directional,
  *     SSPRXD not used
  * @SSP_MICROWIRE_CHANNEL_HALF_DUPLEX: SSPTXD is an output, SSPRXD is
@@ -192,6 +194,31 @@ enum ssp_duplex {
        SSP_MICROWIRE_CHANNEL_HALF_DUPLEX
 };
 
+/**
+ * enum ssp_clkdelay - an optional clock delay on the feedback clock
+ * only available in the ST Micro PL023 variant.
+ * @SSP_FEEDBACK_CLK_DELAY_NONE: no delay, the data coming in from the
+ * slave is sampled directly
+ * @SSP_FEEDBACK_CLK_DELAY_1T: the incoming slave data is sampled with
+ * a delay of T-dt
+ * @SSP_FEEDBACK_CLK_DELAY_2T: dito with a delay if 2T-dt
+ * @SSP_FEEDBACK_CLK_DELAY_3T: dito with a delay if 3T-dt
+ * @SSP_FEEDBACK_CLK_DELAY_4T: dito with a delay if 4T-dt
+ * @SSP_FEEDBACK_CLK_DELAY_5T: dito with a delay if 5T-dt
+ * @SSP_FEEDBACK_CLK_DELAY_6T: dito with a delay if 6T-dt
+ * @SSP_FEEDBACK_CLK_DELAY_7T: dito with a delay if 7T-dt
+ */
+enum ssp_clkdelay {
+       SSP_FEEDBACK_CLK_DELAY_NONE,
+       SSP_FEEDBACK_CLK_DELAY_1T,
+       SSP_FEEDBACK_CLK_DELAY_2T,
+       SSP_FEEDBACK_CLK_DELAY_3T,
+       SSP_FEEDBACK_CLK_DELAY_4T,
+       SSP_FEEDBACK_CLK_DELAY_5T,
+       SSP_FEEDBACK_CLK_DELAY_6T,
+       SSP_FEEDBACK_CLK_DELAY_7T
+};
+
 /**
  * CHIP select/deselect commands
  */
@@ -235,6 +262,8 @@ struct pl022_ssp_controller {
  * @ctrl_len: Microwire interface: Control length
  * @wait_state: Microwire interface: Wait state
  * @duplex: Microwire interface: Full/Half duplex
+ * @clkdelay: on the PL023 variant, the delay in feeback clock cycles
+ * before sampling the incoming line
  * @cs_control: function pointer to board-specific function to
  * assert/deassert I/O port to control HW generation of devices chip-select.
  * @dma_xfer_type: Type of DMA xfer (Mem-to-periph or Periph-to-Periph)
@@ -258,6 +287,7 @@ struct pl022_config_chip {
        enum ssp_microwire_ctrl_len ctrl_len;
        enum ssp_microwire_wait_state wait_state;
        enum ssp_duplex duplex;
+       enum ssp_clkdelay clkdelay;
        void (*cs_control) (u32 control);
 };
 
index 16ed0284d780c2177e0f5a4b617a9fcb4a316d41..1b9ba193b7893784088b54b00667ce5fbc808e44 100644 (file)
@@ -203,6 +203,9 @@ 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*);
@@ -214,6 +217,9 @@ 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 *);
@@ -224,7 +230,10 @@ int block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
 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 *, struct dentry *, int);
+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,
                                struct page **, void **, get_block_t*);
index 8f78073d7caaa278017232112f0d3da05aa0d4c0..0c621604baa1d7ff8185029d4eaade8ccad82d64 100644 (file)
@@ -397,7 +397,7 @@ struct cftype {
         * This callback must be implemented, if you want provide
         * notification functionality.
         */
-       int (*unregister_event)(struct cgroup *cgrp, struct cftype *cft,
+       void (*unregister_event)(struct cgroup *cgrp, struct cftype *cft,
                        struct eventfd_ctx *eventfd);
 };
 
diff --git a/include/linux/compaction.h b/include/linux/compaction.h
new file mode 100644 (file)
index 0000000..5ac5155
--- /dev/null
@@ -0,0 +1,89 @@
+#ifndef _LINUX_COMPACTION_H
+#define _LINUX_COMPACTION_H
+
+/* Return values for compact_zone() and try_to_compact_pages() */
+/* compaction didn't start as it was not possible or direct reclaim was more suitable */
+#define COMPACT_SKIPPED                0
+/* compaction should continue to another pageblock */
+#define COMPACT_CONTINUE       1
+/* direct compaction partially compacted a zone and there are suitable pages */
+#define COMPACT_PARTIAL                2
+/* The full zone was compacted */
+#define COMPACT_COMPLETE       3
+
+#ifdef CONFIG_COMPACTION
+extern int sysctl_compact_memory;
+extern int sysctl_compaction_handler(struct ctl_table *table, int write,
+                       void __user *buffer, size_t *length, loff_t *ppos);
+extern int sysctl_extfrag_threshold;
+extern int sysctl_extfrag_handler(struct ctl_table *table, int write,
+                       void __user *buffer, size_t *length, loff_t *ppos);
+
+extern int fragmentation_index(struct zone *zone, unsigned int order);
+extern unsigned long try_to_compact_pages(struct zonelist *zonelist,
+                       int order, gfp_t gfp_mask, nodemask_t *mask);
+
+/* Do not skip compaction more than 64 times */
+#define COMPACT_MAX_DEFER_SHIFT 6
+
+/*
+ * Compaction is deferred when compaction fails to result in a page
+ * allocation success. 1 << compact_defer_limit compactions are skipped up
+ * to a limit of 1 << COMPACT_MAX_DEFER_SHIFT
+ */
+static inline void defer_compaction(struct zone *zone)
+{
+       zone->compact_considered = 0;
+       zone->compact_defer_shift++;
+
+       if (zone->compact_defer_shift > COMPACT_MAX_DEFER_SHIFT)
+               zone->compact_defer_shift = COMPACT_MAX_DEFER_SHIFT;
+}
+
+/* Returns true if compaction should be skipped this time */
+static inline bool compaction_deferred(struct zone *zone)
+{
+       unsigned long defer_limit = 1UL << zone->compact_defer_shift;
+
+       /* Avoid possible overflow */
+       if (++zone->compact_considered > defer_limit)
+               zone->compact_considered = defer_limit;
+
+       return zone->compact_considered < (1UL << zone->compact_defer_shift);
+}
+
+#else
+static inline unsigned long try_to_compact_pages(struct zonelist *zonelist,
+                       int order, gfp_t gfp_mask, nodemask_t *nodemask)
+{
+       return COMPACT_CONTINUE;
+}
+
+static inline void defer_compaction(struct zone *zone)
+{
+}
+
+static inline bool compaction_deferred(struct zone *zone)
+{
+       return 1;
+}
+
+#endif /* CONFIG_COMPACTION */
+
+#if defined(CONFIG_COMPACTION) && defined(CONFIG_SYSFS) && defined(CONFIG_NUMA)
+extern int compaction_register_node(struct node *node);
+extern void compaction_unregister_node(struct node *node);
+
+#else
+
+static inline int compaction_register_node(struct node *node)
+{
+       return 0;
+}
+
+static inline void compaction_unregister_node(struct node *node)
+{
+}
+#endif /* CONFIG_COMPACTION && CONFIG_SYSFS && CONFIG_NUMA */
+
+#endif /* _LINUX_COMPACTION_H */
index 717c691ecd8e3acd03c51d9d8f42efc2ec489af9..168f7daa7bdeb8d05e30895a82460310b6924dce 100644 (file)
@@ -356,5 +356,9 @@ asmlinkage long compat_sys_newfstatat(unsigned int dfd, char __user * filename,
 asmlinkage long compat_sys_openat(unsigned int dfd, const char __user *filename,
                                  int flags, int mode);
 
+extern ssize_t compat_rw_copy_check_uvector(int type,
+               const struct compat_iovec __user *uvector, unsigned long nr_segs,
+               unsigned long fast_segs, struct iovec *fast_pointer,
+               struct iovec **ret_pointer);
 #endif /* CONFIG_COMPAT */
 #endif /* _LINUX_COMPAT_H */
index 4a6b604ef7e4ae323d9f71fe2569ef5ed318b70c..51e3145196f6f77e852cca9b5f141155bbf10685 100644 (file)
@@ -83,6 +83,8 @@ extern unsigned long wait_for_completion_timeout(struct completion *x,
                                                   unsigned long timeout);
 extern unsigned long wait_for_completion_interruptible_timeout(
                        struct completion *x, unsigned long timeout);
+extern unsigned long wait_for_completion_killable_timeout(
+                       struct completion *x, unsigned long timeout);
 extern bool try_wait_for_completion(struct completion *x);
 extern bool completion_done(struct completion *x);
 
diff --git a/include/linux/cper.h b/include/linux/cper.h
new file mode 100644 (file)
index 0000000..4b38f90
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * UEFI Common Platform Error Record
+ *
+ * Copyright (C) 2010, Intel Corp.
+ *     Author: Huang Ying <ying.huang@intel.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef LINUX_CPER_H
+#define LINUX_CPER_H
+
+#include <linux/uuid.h>
+
+/* CPER record signature and the size */
+#define CPER_SIG_RECORD                                "CPER"
+#define CPER_SIG_SIZE                          4
+/* Used in signature_end field in struct cper_record_header */
+#define CPER_SIG_END                           0xffffffff
+
+/*
+ * CPER record header revision, used in revision field in struct
+ * cper_record_header
+ */
+#define CPER_RECORD_REV                                0x0100
+
+/*
+ * Severity difinition for error_severity in struct cper_record_header
+ * and section_severity in struct cper_section_descriptor
+ */
+#define CPER_SER_RECOVERABLE                   0x0
+#define CPER_SER_FATAL                         0x1
+#define CPER_SER_CORRECTED                     0x2
+#define CPER_SER_INFORMATIONAL                 0x3
+
+/*
+ * Validation bits difinition for validation_bits in struct
+ * cper_record_header. If set, corresponding fields in struct
+ * cper_record_header contain valid information.
+ *
+ * corresponds platform_id
+ */
+#define CPER_VALID_PLATFORM_ID                 0x0001
+/* corresponds timestamp */
+#define CPER_VALID_TIMESTAMP                   0x0002
+/* corresponds partition_id */
+#define CPER_VALID_PARTITION_ID                        0x0004
+
+/*
+ * Notification type used to generate error record, used in
+ * notification_type in struct cper_record_header
+ *
+ * Corrected Machine Check
+ */
+#define CPER_NOTIFY_CMC                                                        \
+       UUID_LE(0x2DCE8BB1, 0xBDD7, 0x450e, 0xB9, 0xAD, 0x9C, 0xF4,     \
+               0xEB, 0xD4, 0xF8, 0x90)
+/* Corrected Platform Error */
+#define CPER_NOTIFY_CPE                                                        \
+       UUID_LE(0x4E292F96, 0xD843, 0x4a55, 0xA8, 0xC2, 0xD4, 0x81,     \
+               0xF2, 0x7E, 0xBE, 0xEE)
+/* Machine Check Exception */
+#define CPER_NOTIFY_MCE                                                        \
+       UUID_LE(0xE8F56FFE, 0x919C, 0x4cc5, 0xBA, 0x88, 0x65, 0xAB,     \
+               0xE1, 0x49, 0x13, 0xBB)
+/* PCI Express Error */
+#define CPER_NOTIFY_PCIE                                               \
+       UUID_LE(0xCF93C01F, 0x1A16, 0x4dfc, 0xB8, 0xBC, 0x9C, 0x4D,     \
+               0xAF, 0x67, 0xC1, 0x04)
+/* INIT Record (for IPF) */
+#define CPER_NOTIFY_INIT                                               \
+       UUID_LE(0xCC5263E8, 0x9308, 0x454a, 0x89, 0xD0, 0x34, 0x0B,     \
+               0xD3, 0x9B, 0xC9, 0x8E)
+/* Non-Maskable Interrupt */
+#define CPER_NOTIFY_NMI                                                        \
+       UUID_LE(0x5BAD89FF, 0xB7E6, 0x42c9, 0x81, 0x4A, 0xCF, 0x24,     \
+               0x85, 0xD6, 0xE9, 0x8A)
+/* BOOT Error Record */
+#define CPER_NOTIFY_BOOT                                               \
+       UUID_LE(0x3D61A466, 0xAB40, 0x409a, 0xA6, 0x98, 0xF3, 0x62,     \
+               0xD4, 0x64, 0xB3, 0x8F)
+/* DMA Remapping Error */
+#define CPER_NOTIFY_DMAR                                               \
+       UUID_LE(0x667DD791, 0xC6B3, 0x4c27, 0x8A, 0x6B, 0x0F, 0x8E,     \
+               0x72, 0x2D, 0xEB, 0x41)
+
+/*
+ * Flags bits definitions for flags in struct cper_record_header
+ * If set, the error has been recovered
+ */
+#define CPER_HW_ERROR_FLAGS_RECOVERED          0x1
+/* If set, the error is for previous boot */
+#define CPER_HW_ERROR_FLAGS_PREVERR            0x2
+/* If set, the error is injected for testing */
+#define CPER_HW_ERROR_FLAGS_SIMULATED          0x4
+
+/*
+ * CPER section header revision, used in revision field in struct
+ * cper_section_descriptor
+ */
+#define CPER_SEC_REV                           0x0100
+
+/*
+ * Validation bits difinition for validation_bits in struct
+ * cper_section_descriptor. If set, corresponding fields in struct
+ * cper_section_descriptor contain valid information.
+ *
+ * corresponds fru_id
+ */
+#define CPER_SEC_VALID_FRU_ID                  0x1
+/* corresponds fru_text */
+#define CPER_SEC_VALID_FRU_TEXT                        0x2
+
+/*
+ * Flags bits definitions for flags in struct cper_section_descriptor
+ *
+ * If set, the section is associated with the error condition
+ * directly, and should be focused on
+ */
+#define CPER_SEC_PRIMARY                       0x0001
+/*
+ * If set, the error was not contained within the processor or memory
+ * hierarchy and the error may have propagated to persistent storage
+ * or network
+ */
+#define CPER_SEC_CONTAINMENT_WARNING           0x0002
+/* If set, the component must be re-initialized or re-enabled prior to use */
+#define CPER_SEC_RESET                         0x0004
+/* If set, Linux may choose to discontinue use of the resource */
+#define CPER_SEC_ERROR_THRESHOLD_EXCEEDED      0x0008
+/*
+ * If set, resource could not be queried for error information due to
+ * conflicts with other system software or resources. Some fields of
+ * the section will be invalid
+ */
+#define CPER_SEC_RESOURCE_NOT_ACCESSIBLE       0x0010
+/*
+ * If set, action has been taken to ensure error containment (such as
+ * poisoning data), but the error has not been fully corrected and the
+ * data has not been consumed. Linux may choose to take further
+ * corrective action before the data is consumed
+ */
+#define CPER_SEC_LATENT_ERROR                  0x0020
+
+/*
+ * Section type definitions, used in section_type field in struct
+ * cper_section_descriptor
+ *
+ * Processor Generic
+ */
+#define CPER_SEC_PROC_GENERIC                                          \
+       UUID_LE(0x9876CCAD, 0x47B4, 0x4bdb, 0xB6, 0x5E, 0x16, 0xF1,     \
+               0x93, 0xC4, 0xF3, 0xDB)
+/* Processor Specific: X86/X86_64 */
+#define CPER_SEC_PROC_IA                                               \
+       UUID_LE(0xDC3EA0B0, 0xA144, 0x4797, 0xB9, 0x5B, 0x53, 0xFA,     \
+               0x24, 0x2B, 0x6E, 0x1D)
+/* Processor Specific: IA64 */
+#define CPER_SEC_PROC_IPF                                              \
+       UUID_LE(0xE429FAF1, 0x3CB7, 0x11D4, 0x0B, 0xCA, 0x07, 0x00,     \
+               0x80, 0xC7, 0x3C, 0x88, 0x81)
+/* Platform Memory */
+#define CPER_SEC_PLATFORM_MEM                                          \
+       UUID_LE(0xA5BC1114, 0x6F64, 0x4EDE, 0xB8, 0x63, 0x3E, 0x83,     \
+               0xED, 0x7C, 0x83, 0xB1)
+#define CPER_SEC_PCIE                                                  \
+       UUID_LE(0xD995E954, 0xBBC1, 0x430F, 0xAD, 0x91, 0xB4, 0x4D,     \
+               0xCB, 0x3C, 0x6F, 0x35)
+/* Firmware Error Record Reference */
+#define CPER_SEC_FW_ERR_REC_REF                                                \
+       UUID_LE(0x81212A96, 0x09ED, 0x4996, 0x94, 0x71, 0x8D, 0x72,     \
+               0x9C, 0x8E, 0x69, 0xED)
+/* PCI/PCI-X Bus */
+#define CPER_SEC_PCI_X_BUS                                             \
+       UUID_LE(0xC5753963, 0x3B84, 0x4095, 0xBF, 0x78, 0xED, 0xDA,     \
+               0xD3, 0xF9, 0xC9, 0xDD)
+/* PCI Component/Device */
+#define CPER_SEC_PCI_DEV                                               \
+       UUID_LE(0xEB5E4685, 0xCA66, 0x4769, 0xB6, 0xA2, 0x26, 0x06,     \
+               0x8B, 0x00, 0x13, 0x26)
+#define CPER_SEC_DMAR_GENERIC                                          \
+       UUID_LE(0x5B51FEF7, 0xC79D, 0x4434, 0x8F, 0x1B, 0xAA, 0x62,     \
+               0xDE, 0x3E, 0x2C, 0x64)
+/* Intel VT for Directed I/O specific DMAr */
+#define CPER_SEC_DMAR_VT                                               \
+       UUID_LE(0x71761D37, 0x32B2, 0x45cd, 0xA7, 0xD0, 0xB0, 0xFE,     \
+               0xDD, 0x93, 0xE8, 0xCF)
+/* IOMMU specific DMAr */
+#define CPER_SEC_DMAR_IOMMU                                            \
+       UUID_LE(0x036F84E1, 0x7F37, 0x428c, 0xA7, 0x9E, 0x57, 0x5F,     \
+               0xDF, 0xAA, 0x84, 0xEC)
+
+/*
+ * All tables and structs must be byte-packed to match CPER
+ * specification, since the tables are provided by the system BIOS
+ */
+#pragma pack(1)
+
+struct cper_record_header {
+       char    signature[CPER_SIG_SIZE];       /* must be CPER_SIG_RECORD */
+       __u16   revision;                       /* must be CPER_RECORD_REV */
+       __u32   signature_end;                  /* must be CPER_SIG_END */
+       __u16   section_count;
+       __u32   error_severity;
+       __u32   validation_bits;
+       __u32   record_length;
+       __u64   timestamp;
+       uuid_le platform_id;
+       uuid_le partition_id;
+       uuid_le creator_id;
+       uuid_le notification_type;
+       __u64   record_id;
+       __u32   flags;
+       __u64   persistence_information;
+       __u8    reserved[12];                   /* must be zero */
+};
+
+struct cper_section_descriptor {
+       __u32   section_offset;         /* Offset in bytes of the
+                                        *  section body from the base
+                                        *  of the record header */
+       __u32   section_length;
+       __u16   revision;               /* must be CPER_RECORD_REV */
+       __u8    validation_bits;
+       __u8    reserved;               /* must be zero */
+       __u32   flags;
+       uuid_le section_type;
+       uuid_le fru_id;
+       __u32   section_severity;
+       __u8    fru_text[20];
+};
+
+/* Generic Processor Error Section */
+struct cper_sec_proc_generic {
+       __u64   validation_bits;
+       __u8    proc_type;
+       __u8    proc_isa;
+       __u8    proc_error_type;
+       __u8    operation;
+       __u8    flags;
+       __u8    level;
+       __u16   reserved;
+       __u64   cpu_version;
+       char    cpu_brand[128];
+       __u64   proc_id;
+       __u64   target_addr;
+       __u64   requestor_id;
+       __u64   responder_id;
+       __u64   ip;
+};
+
+/* IA32/X64 Processor Error Section */
+struct cper_sec_proc_ia {
+       __u64   validation_bits;
+       __u8    lapic_id;
+       __u8    cpuid[48];
+};
+
+/* IA32/X64 Processor Error Infomation Structure */
+struct cper_ia_err_info {
+       uuid_le err_type;
+       __u64   validation_bits;
+       __u64   check_info;
+       __u64   target_id;
+       __u64   requestor_id;
+       __u64   responder_id;
+       __u64   ip;
+};
+
+/* IA32/X64 Processor Context Information Structure */
+struct cper_ia_proc_ctx {
+       __u16   reg_ctx_type;
+       __u16   reg_arr_size;
+       __u32   msr_addr;
+       __u64   mm_reg_addr;
+};
+
+/* Memory Error Section */
+struct cper_sec_mem_err {
+       __u64   validation_bits;
+       __u64   error_status;
+       __u64   physical_addr;
+       __u64   physical_addr_mask;
+       __u16   node;
+       __u16   card;
+       __u16   module;
+       __u16   bank;
+       __u16   device;
+       __u16   row;
+       __u16   column;
+       __u16   bit_pos;
+       __u64   requestor_id;
+       __u64   responder_id;
+       __u64   target_id;
+       __u8    error_type;
+};
+
+/* Reset to default packing */
+#pragma pack()
+
+u64 cper_next_record_id(void);
+
+#endif
index dcf77fa826b5a3a0fcac47cdf7c5eaccf67f0521..55215cce50052583c93dcbc9771ed5c8e833bbc4 100644 (file)
@@ -125,6 +125,7 @@ struct cpuidle_driver {
 #ifdef CONFIG_CPU_IDLE
 
 extern int cpuidle_register_driver(struct cpuidle_driver *drv);
+struct cpuidle_driver *cpuidle_get_driver(void);
 extern void cpuidle_unregister_driver(struct cpuidle_driver *drv);
 extern int cpuidle_register_device(struct cpuidle_device *dev);
 extern void cpuidle_unregister_device(struct cpuidle_device *dev);
@@ -137,16 +138,17 @@ extern void cpuidle_disable_device(struct cpuidle_device *dev);
 #else
 
 static inline int cpuidle_register_driver(struct cpuidle_driver *drv)
-{return 0;}
+{return -ENODEV; }
+static inline struct cpuidle_driver *cpuidle_get_driver(void) {return NULL; }
 static inline void cpuidle_unregister_driver(struct cpuidle_driver *drv) { }
 static inline int cpuidle_register_device(struct cpuidle_device *dev)
-{return 0;}
+{return -ENODEV; }
 static inline void cpuidle_unregister_device(struct cpuidle_device *dev) { }
 
 static inline void cpuidle_pause_and_lock(void) { }
 static inline void cpuidle_resume_and_unlock(void) { }
 static inline int cpuidle_enable_device(struct cpuidle_device *dev)
-{return 0;}
+{return -ENODEV; }
 static inline void cpuidle_disable_device(struct cpuidle_device *dev) { }
 
 #endif
index a73454aec33312359c4233fa4ec7e0598dbbe345..457ed765a116a4c06ecd192e0165cf5af096c818 100644 (file)
@@ -69,6 +69,7 @@ extern void cpuset_task_status_allowed(struct seq_file *m,
                                        struct task_struct *task);
 
 extern int cpuset_mem_spread_node(void);
+extern int cpuset_slab_spread_node(void);
 
 static inline int cpuset_do_page_mem_spread(void)
 {
@@ -86,9 +87,44 @@ extern void rebuild_sched_domains(void);
 
 extern void cpuset_print_task_mems_allowed(struct task_struct *p);
 
+/*
+ * reading current mems_allowed and mempolicy in the fastpath must protected
+ * by get_mems_allowed()
+ */
+static inline void get_mems_allowed(void)
+{
+       current->mems_allowed_change_disable++;
+
+       /*
+        * ensure that reading mems_allowed and mempolicy happens after the
+        * update of ->mems_allowed_change_disable.
+        *
+        * the write-side task finds ->mems_allowed_change_disable is not 0,
+        * and knows the read-side task is reading mems_allowed or mempolicy,
+        * so it will clear old bits lazily.
+        */
+       smp_mb();
+}
+
+static inline void put_mems_allowed(void)
+{
+       /*
+        * ensure that reading mems_allowed and mempolicy before reducing
+        * mems_allowed_change_disable.
+        *
+        * the write-side task will know that the read-side task is still
+        * reading mems_allowed or mempolicy, don't clears old bits in the
+        * nodemask.
+        */
+       smp_mb();
+       --ACCESS_ONCE(current->mems_allowed_change_disable);
+}
+
 static inline void set_mems_allowed(nodemask_t nodemask)
 {
+       task_lock(current);
        current->mems_allowed = nodemask;
+       task_unlock(current);
 }
 
 #else /* !CONFIG_CPUSETS */
@@ -159,6 +195,11 @@ static inline int cpuset_mem_spread_node(void)
        return 0;
 }
 
+static inline int cpuset_slab_spread_node(void)
+{
+       return 0;
+}
+
 static inline int cpuset_do_page_mem_spread(void)
 {
        return 0;
@@ -187,6 +228,14 @@ static inline void set_mems_allowed(nodemask_t nodemask)
 {
 }
 
+static inline void get_mems_allowed(void)
+{
+}
+
+static inline void put_mems_allowed(void)
+{
+}
+
 #endif /* !CONFIG_CPUSETS */
 
 #endif /* _LINUX_CPUSET_H */
index 52507c3e1387581b0e33b6435b26642bdb722d08..75c0fa8813088c31148be71b7cbff77670b6e5d0 100644 (file)
@@ -156,7 +156,6 @@ extern int copy_creds(struct task_struct *, unsigned long);
 extern struct cred *cred_alloc_blank(void);
 extern struct cred *prepare_creds(void);
 extern struct cred *prepare_exec_creds(void);
-extern struct cred *prepare_usermodehelper_creds(void);
 extern int commit_creds(struct cred *);
 extern void abort_creds(struct cred *);
 extern const struct cred *override_creds(const struct cred *);
index 24d2e30f1b4649ad69e44ab25813b4f85c11b352..a6a7a1c83f54c1f7430b7d4306f31aaabc126eaa 100644 (file)
  * as arm where pointers are 32-bit aligned but there are data types such as
  * u64 which require 64-bit alignment.
  */
-#if defined(ARCH_KMALLOC_MINALIGN)
 #define CRYPTO_MINALIGN ARCH_KMALLOC_MINALIGN
-#elif defined(ARCH_SLAB_MINALIGN)
-#define CRYPTO_MINALIGN ARCH_SLAB_MINALIGN
-#else
-#define CRYPTO_MINALIGN __alignof__(unsigned long long)
-#endif
 
 #define CRYPTO_MINALIGN_ATTR __attribute__ ((__aligned__(CRYPTO_MINALIGN)))
 
index fc1b930f246cddd7c196ff698d38a2419e842058..e7d9b20ddc5b98c6e5ae5b89ee2a2b72716d9e76 100644 (file)
@@ -63,6 +63,8 @@ struct dentry *debugfs_create_x16(const char *name, mode_t mode,
                                  struct dentry *parent, u16 *value);
 struct dentry *debugfs_create_x32(const char *name, mode_t mode,
                                  struct dentry *parent, u32 *value);
+struct dentry *debugfs_create_x64(const char *name, mode_t mode,
+                                 struct dentry *parent, u64 *value);
 struct dentry *debugfs_create_size_t(const char *name, mode_t mode,
                                     struct dentry *parent, size_t *value);
 struct dentry *debugfs_create_bool(const char *name, mode_t mode,
index 7bb9f426f3e67c83985c322c2dc26ec8f5edd50f..0713e10571dd61eb0abf1388e0c415ba6d143b6d 100644 (file)
@@ -33,6 +33,7 @@ struct class;
 struct class_private;
 struct bus_type;
 struct bus_type_private;
+struct device_node;
 
 struct bus_attribute {
        struct attribute        attr;
@@ -127,6 +128,10 @@ struct device_driver {
 
        bool suppress_bind_attrs;       /* disables bind/unbind via sysfs */
 
+#if defined(CONFIG_OF)
+       const struct of_device_id       *of_match_table;
+#endif
+
        int (*probe) (struct device *dev);
        int (*remove) (struct device *dev);
        void (*shutdown) (struct device *dev);
@@ -435,6 +440,9 @@ struct device {
                                             override */
        /* arch specific additions */
        struct dev_archdata     archdata;
+#ifdef CONFIG_OF
+       struct device_node      *of_node;
+#endif
 
        dev_t                   devt;   /* dev_t, creates the sysfs "dev" */
 
index ca32ed78b05719db06704a0c99e037fc859bbe83..89b7e1a605b8113ac90e7f4bd51f73d595988ade 100644 (file)
@@ -40,16 +40,6 @@ struct dma_map_ops {
        void (*sync_single_for_device)(struct device *dev,
                                       dma_addr_t dma_handle, size_t size,
                                       enum dma_data_direction dir);
-       void (*sync_single_range_for_cpu)(struct device *dev,
-                                         dma_addr_t dma_handle,
-                                         unsigned long offset,
-                                         size_t size,
-                                         enum dma_data_direction dir);
-       void (*sync_single_range_for_device)(struct device *dev,
-                                            dma_addr_t dma_handle,
-                                            unsigned long offset,
-                                            size_t size,
-                                            enum dma_data_direction dir);
        void (*sync_sg_for_cpu)(struct device *dev,
                                struct scatterlist *sg, int nents,
                                enum dma_data_direction dir);
@@ -105,21 +95,6 @@ static inline int is_device_dma_capable(struct device *dev)
 #include <asm-generic/dma-mapping-broken.h>
 #endif
 
-/* for backwards compatibility, removed soon */
-static inline void __deprecated dma_sync_single(struct device *dev,
-                                               dma_addr_t addr, size_t size,
-                                               enum dma_data_direction dir)
-{
-       dma_sync_single_for_cpu(dev, addr, size, dir);
-}
-
-static inline void __deprecated dma_sync_sg(struct device *dev,
-                                           struct scatterlist *sg, int nelems,
-                                           enum dma_data_direction dir)
-{
-       dma_sync_sg_for_cpu(dev, sg, nelems, dir);
-}
-
 static inline u64 dma_get_mask(struct device *dev)
 {
        if (dev && dev->dma_mask && *dev->dma_mask)
diff --git a/include/linux/ds2782_battery.h b/include/linux/ds2782_battery.h
new file mode 100644 (file)
index 0000000..b4e281f
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __LINUX_DS2782_BATTERY_H
+#define __LINUX_DS2782_BATTERY_H
+
+struct ds278x_platform_data {
+       int rsns;
+};
+
+#endif
index f8c2e17675002ec1508742ad629610a3e76f19da..b3cd4de9432b68007342098ad7dbb662cbc1fce0 100644 (file)
@@ -28,7 +28,7 @@ struct _ddebug {
        /*
         * The flags field controls the behaviour at the callsite.
         * The bits here are changed dynamically when the user
-        * writes commands to <debugfs>/dynamic_debug/ddebug
+        * writes commands to <debugfs>/dynamic_debug/control
         */
 #define _DPRINTK_FLAGS_PRINT   (1<<0)  /* printk() a message using the format */
 #define _DPRINTK_FLAGS_DEFAULT 0
index e687bc3ba4da0ec0830b507784bebb7ab8a5a918..394a3e0e4a6be1f566d5346dd586cf7fd06ba19d 100644 (file)
@@ -150,8 +150,6 @@ static inline int elf_core_copy_task_xfpregs(struct task_struct *t, elf_fpxregse
 }
 #endif
 
-#endif /* __KERNEL__ */
-
 /*
  * These functions parameterize elf_core_dump in fs/binfmt_elf.c to write out
  * extra segments containing the gate DSO contents.  Dumping its
@@ -168,4 +166,6 @@ extern int
 elf_core_write_extra_data(struct file *file, size_t *size, unsigned long limit);
 extern size_t elf_core_extra_data_size(void);
 
+#endif /* __KERNEL__ */
+
 #endif /* _LINUX_ELFCORE_H */
index 1b12642636c7a121f3a3797676cf8d4746ca13a9..448afc12c78afe6157929010a7fba01a6d63ba8e 100644 (file)
 
 #define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
 
-static inline void *ERR_PTR(long error)
+static inline void * __must_check ERR_PTR(long error)
 {
        return (void *) error;
 }
 
-static inline long PTR_ERR(const void *ptr)
+static inline long __must_check PTR_ERR(const void *ptr)
 {
        return (long) ptr;
 }
 
-static inline long IS_ERR(const void *ptr)
+static inline long __must_check IS_ERR(const void *ptr)
 {
        return IS_ERR_VALUE((unsigned long)ptr);
 }
 
-static inline long IS_ERR_OR_NULL(const void *ptr)
+static inline long __must_check IS_ERR_OR_NULL(const void *ptr)
 {
        return !ptr || IS_ERR_VALUE((unsigned long)ptr);
 }
@@ -46,7 +46,7 @@ static inline long IS_ERR_OR_NULL(const void *ptr)
  * Explicitly cast an error-valued pointer to another pointer type in such a
  * way as to make it clear that's what's going on.
  */
-static inline void *ERR_CAST(const void *ptr)
+static inline void * __must_check ERR_CAST(const void *ptr)
 {
        /* cast away the const */
        return (void *) ptr;
index 5f494b4650977fcb9aac65aa7153320fb1c6f487..7fc62d4550b207ac682021ad01bd9ff3b644d788 100644 (file)
@@ -868,7 +868,7 @@ extern int ext3_htree_store_dirent(struct file *dir_file, __u32 hash,
 extern void ext3_htree_free_dir_info(struct dir_private_info *p);
 
 /* fsync.c */
-extern int ext3_sync_file (struct file *, struct dentry *, int);
+extern int ext3_sync_file(struct file *, int);
 
 /* hash.c */
 extern int ext3fs_dirhash(const char *name, int len, struct
index 1296af45169d9fd9a0614aab8353d98042a94409..907ace3a64c8abef33aff5a1d7e3bc3c72337a54 100644 (file)
@@ -4,8 +4,6 @@
 #include <linux/types.h>
 #include <linux/i2c.h>
 
-struct dentry;
-
 /* Definitions of frame buffers                                                */
 
 #define FB_MAX                 32      /* sufficient for now */
@@ -37,7 +35,7 @@ struct dentry;
 #define FBIOGET_HWCINFO         0x4616
 #define FBIOPUT_MODEINFO        0x4617
 #define FBIOGET_DISPINFO        0x4618
-
+#define FBIO_WAITFORVSYNC      _IOW('F', 0x20, __u32)
 
 #define FB_TYPE_PACKED_PIXELS          0       /* Packed Pixels        */
 #define FB_TYPE_PLANES                 1       /* Non interleaved planes */
@@ -1017,8 +1015,7 @@ extern void fb_deferred_io_open(struct fb_info *info,
                                struct inode *inode,
                                struct file *file);
 extern void fb_deferred_io_cleanup(struct fb_info *info);
-extern int fb_deferred_io_fsync(struct file *file, struct dentry *dentry,
-                               int datasync);
+extern int fb_deferred_io_fsync(struct file *file, int datasync);
 
 static inline bool fb_be_math(struct fb_info *info)
 {
diff --git a/include/linux/fec.h b/include/linux/fec.h
new file mode 100644 (file)
index 0000000..5d3523d
--- /dev/null
@@ -0,0 +1,21 @@
+/* include/linux/fec.h
+ *
+ * Copyright (c) 2009 Orex Computed Radiography
+ *   Baruch Siach <baruch@tkos.co.il>
+ *
+ * Header file for the FEC platform data
+ *
+ * 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 __LINUX_FEC_H__
+#define __LINUX_FEC_H__
+
+#include <linux/phy.h>
+
+struct fec_platform_data {
+       phy_interface_t phy;
+};
+
+#endif
index 5555508fd5171f6c7a546c2d7364876223e7c9cc..b1e12970f617b919ad71b48ee44deaa306b6f05b 100644 (file)
@@ -11,7 +11,6 @@
 
 struct file;
 
-extern void __fput(struct file *);
 extern void fput(struct file *);
 extern void drop_file_write_access(struct file *file);
 
index 4bd94bf5e739253d17e5fb6ff3416e17966e8d09..72e2b8ac2a5a997b8d055e72d81d7358cddf6dce 100644 (file)
 #define CSR_DESCRIPTOR         0x01
 #define CSR_VENDOR             0x03
 #define CSR_HARDWARE_VERSION   0x04
-#define CSR_NODE_CAPABILITIES  0x0c
 #define CSR_UNIT               0x11
 #define CSR_SPECIFIER_ID       0x12
 #define CSR_VERSION            0x13
 #define CSR_DEPENDENT_INFO     0x14
 #define CSR_MODEL              0x17
-#define CSR_INSTANCE           0x18
 #define CSR_DIRECTORY_ID       0x20
 
 struct fw_csr_iterator {
@@ -89,7 +87,6 @@ struct fw_card {
        int current_tlabel;
        u64 tlabel_mask;
        struct list_head transaction_list;
-       struct timer_list flush_timer;
        unsigned long reset_jiffies;
 
        unsigned long long guid;
@@ -290,6 +287,8 @@ struct fw_transaction {
        int tlabel;
        int timestamp;
        struct list_head link;
+       struct fw_card *card;
+       struct timer_list split_timeout_timer;
 
        struct fw_packet packet;
 
index 1775d362732d4512f0062609d4689cdfc9310111..3428393942a642f877dc065d86c05044305af399 100644 (file)
@@ -954,6 +954,7 @@ extern spinlock_t files_lock;
 #define file_list_unlock() spin_unlock(&files_lock);
 
 #define get_file(x)    atomic_long_inc(&(x)->f_count)
+#define fput_atomic(x) atomic_long_add_unless(&(x)->f_count, -1, 1)
 #define file_count(x)  atomic_long_read(&(x)->f_count)
 
 #ifdef CONFIG_DEBUG_WRITECOUNT
@@ -1315,8 +1316,6 @@ extern int send_sigurg(struct fown_struct *fown);
 extern struct list_head super_blocks;
 extern spinlock_t sb_lock;
 
-#define sb_entry(list)  list_entry((list), struct super_block, s_list)
-#define S_BIAS (1<<30)
 struct super_block {
        struct list_head        s_list;         /* Keep this first */
        dev_t                   s_dev;          /* search index; _not_ kdev_t */
@@ -1335,12 +1334,11 @@ struct super_block {
        struct rw_semaphore     s_umount;
        struct mutex            s_lock;
        int                     s_count;
-       int                     s_need_sync;
        atomic_t                s_active;
 #ifdef CONFIG_SECURITY
        void                    *s_security;
 #endif
-       struct xattr_handler    **s_xattr;
+       const struct xattr_handler **s_xattr;
 
        struct list_head        s_inodes;       /* all inodes */
        struct hlist_head       s_anon;         /* anonymous dentries for (nfs) exporting */
@@ -1432,7 +1430,8 @@ extern void dentry_unhash(struct dentry *dentry);
  * VFS file helper functions.
  */
 extern int file_permission(struct file *, int);
-
+extern void inode_init_owner(struct inode *inode, const struct inode *dir,
+                       mode_t mode);
 /*
  * VFS FS_IOC_FIEMAP helper definitions.
  */
@@ -1499,7 +1498,7 @@ struct file_operations {
        int (*open) (struct inode *, struct file *);
        int (*flush) (struct file *, fl_owner_t id);
        int (*release) (struct inode *, struct file *);
-       int (*fsync) (struct file *, struct dentry *, int datasync);
+       int (*fsync) (struct file *, int datasync);
        int (*aio_fsync) (struct kiocb *, int datasync);
        int (*fasync) (int, struct file *, int);
        int (*lock) (struct file *, int, struct file_lock *);
@@ -1745,6 +1744,7 @@ struct file_system_type {
 
        struct lock_class_key s_lock_key;
        struct lock_class_key s_umount_key;
+       struct lock_class_key s_vfs_rename_key;
 
        struct lock_class_key i_lock_key;
        struct lock_class_key i_mutex_key;
@@ -1782,8 +1782,6 @@ extern int get_sb_pseudo(struct file_system_type *, char *,
        const struct super_operations *ops, unsigned long,
        struct vfsmount *mnt);
 extern void simple_set_mnt(struct vfsmount *mnt, struct super_block *sb);
-int __put_super_and_need_restart(struct super_block *sb);
-void put_super(struct super_block *sb);
 
 /* Alas, no aliases. Too much hassle with bringing module.h everywhere */
 #define fops_get(fops) \
@@ -1803,6 +1801,8 @@ extern void drop_collected_mounts(struct vfsmount *);
 extern int iterate_mounts(int (*)(struct vfsmount *, void *), void *,
                          struct vfsmount *);
 extern int vfs_statfs(struct dentry *, struct kstatfs *);
+extern int freeze_super(struct super_block *super);
+extern int thaw_super(struct super_block *super);
 
 extern int current_umask(void);
 
@@ -2088,9 +2088,9 @@ extern int __filemap_fdatawrite_range(struct address_space *mapping,
 extern int filemap_fdatawrite_range(struct address_space *mapping,
                                loff_t start, loff_t end);
 
-extern int vfs_fsync_range(struct file *file, struct dentry *dentry,
-                          loff_t start, loff_t end, int datasync);
-extern int vfs_fsync(struct file *file, struct dentry *dentry, int datasync);
+extern int vfs_fsync_range(struct file *file, loff_t start, loff_t end,
+                          int datasync);
+extern int vfs_fsync(struct file *file, int datasync);
 extern int generic_write_sync(struct file *file, loff_t pos, loff_t count);
 extern void sync_supers(void);
 extern void emergency_sync(void);
@@ -2213,7 +2213,7 @@ extern int generic_segment_checks(const struct iovec *iov,
 /* fs/block_dev.c */
 extern ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov,
                                unsigned long nr_segs, loff_t pos);
-extern int blkdev_fsync(struct file *filp, struct dentry *dentry, int datasync);
+extern int blkdev_fsync(struct file *filp, int datasync);
 
 /* fs/splice.c */
 extern ssize_t generic_file_splice_read(struct file *, loff_t *,
@@ -2229,6 +2229,7 @@ extern long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
 
 extern void
 file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping);
+extern loff_t noop_llseek(struct file *file, loff_t offset, int origin);
 extern loff_t no_llseek(struct file *file, loff_t offset, int origin);
 extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin);
 extern loff_t generic_file_llseek_unlocked(struct file *file, loff_t offset,
@@ -2251,10 +2252,19 @@ static inline int xip_truncate_page(struct address_space *mapping, loff_t from)
 #endif
 
 #ifdef CONFIG_BLOCK
+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,
-       int lock_type);
+       dio_submit_t submit_io, int lock_type);
 
 enum {
        /* need locking between buffered and direct access */
@@ -2264,13 +2274,31 @@ 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);
+}
+
+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,
        dio_iodone_t end_io)
 {
        return __blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset,
-                                   nr_segs, get_block, end_io,
+                                   nr_segs, get_block, end_io, NULL,
                                    DIO_LOCKING | DIO_SKIP_HOLES);
 }
 
@@ -2280,7 +2308,7 @@ static inline ssize_t blockdev_direct_IO_no_locking(int rw, struct kiocb *iocb,
        dio_iodone_t end_io)
 {
        return __blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset,
-                               nr_segs, get_block, end_io, 0);
+                                   nr_segs, get_block, end_io, NULL, 0);
 }
 #endif
 
@@ -2330,18 +2358,21 @@ extern struct super_block *get_super(struct block_device *);
 extern struct super_block *get_active_super(struct block_device *bdev);
 extern struct super_block *user_get_super(dev_t);
 extern void drop_super(struct super_block *sb);
+extern void iterate_supers(void (*)(struct super_block *, void *), void *);
 
 extern int dcache_dir_open(struct inode *, struct file *);
 extern int dcache_dir_close(struct inode *, struct file *);
 extern loff_t dcache_dir_lseek(struct file *, loff_t, int);
 extern int dcache_readdir(struct file *, void *, filldir_t);
+extern int simple_setattr(struct dentry *, struct iattr *);
 extern int simple_getattr(struct vfsmount *, struct dentry *, struct kstat *);
 extern int simple_statfs(struct dentry *, struct kstatfs *);
 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_sync_file(struct file *, struct dentry *, int);
+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);
 extern int simple_write_begin(struct file *file, struct address_space *mapping,
@@ -2366,7 +2397,7 @@ extern ssize_t simple_read_from_buffer(void __user *to, size_t count,
 extern ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos,
                const void __user *from, size_t count);
 
-extern int simple_fsync(struct file *, struct dentry *, int);
+extern int generic_file_fsync(struct file *, int);
 
 #ifdef CONFIG_MIGRATION
 extern int buffer_migrate_page(struct address_space *,
@@ -2377,7 +2408,8 @@ 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 *, struct iattr *);
+extern int __must_check inode_setattr(struct inode *, const struct iattr *);
+extern void generic_setattr(struct inode *inode, const struct iattr *attr);
 
 extern void file_update_time(struct file *file);
 
index c082f223e2fe6501355e2c855e2ae55653ffd8dc..3167f2df4126c12e195be536c687c577212da651 100644 (file)
@@ -73,18 +73,25 @@ struct trace_iterator {
 };
 
 
+struct trace_event;
+
 typedef enum print_line_t (*trace_print_func)(struct trace_iterator *iter,
-                                             int flags);
-struct trace_event {
-       struct hlist_node       node;
-       struct list_head        list;
-       int                     type;
+                                     int flags, struct trace_event *event);
+
+struct trace_event_functions {
        trace_print_func        trace;
        trace_print_func        raw;
        trace_print_func        hex;
        trace_print_func        binary;
 };
 
+struct trace_event {
+       struct hlist_node               node;
+       struct list_head                list;
+       int                             type;
+       struct trace_event_functions    *funcs;
+};
+
 extern int register_ftrace_event(struct trace_event *event);
 extern int unregister_ftrace_event(struct trace_event *event);
 
@@ -116,28 +123,70 @@ void tracing_record_cmdline(struct task_struct *tsk);
 
 struct event_filter;
 
+enum trace_reg {
+       TRACE_REG_REGISTER,
+       TRACE_REG_UNREGISTER,
+       TRACE_REG_PERF_REGISTER,
+       TRACE_REG_PERF_UNREGISTER,
+};
+
+struct ftrace_event_call;
+
+struct ftrace_event_class {
+       char                    *system;
+       void                    *probe;
+#ifdef CONFIG_PERF_EVENTS
+       void                    *perf_probe;
+#endif
+       int                     (*reg)(struct ftrace_event_call *event,
+                                      enum trace_reg type);
+       int                     (*define_fields)(struct ftrace_event_call *);
+       struct list_head        *(*get_fields)(struct ftrace_event_call *);
+       struct list_head        fields;
+       int                     (*raw_init)(struct ftrace_event_call *);
+};
+
+enum {
+       TRACE_EVENT_FL_ENABLED_BIT,
+       TRACE_EVENT_FL_FILTERED_BIT,
+};
+
+enum {
+       TRACE_EVENT_FL_ENABLED  = (1 << TRACE_EVENT_FL_ENABLED_BIT),
+       TRACE_EVENT_FL_FILTERED = (1 << TRACE_EVENT_FL_FILTERED_BIT),
+};
+
 struct ftrace_event_call {
        struct list_head        list;
+       struct ftrace_event_class *class;
        char                    *name;
-       char                    *system;
        struct dentry           *dir;
-       struct trace_event      *event;
-       int                     enabled;
-       int                     (*regfunc)(struct ftrace_event_call *);
-       void                    (*unregfunc)(struct ftrace_event_call *);
-       int                     id;
+       struct trace_event      event;
        const char              *print_fmt;
-       int                     (*raw_init)(struct ftrace_event_call *);
-       int                     (*define_fields)(struct ftrace_event_call *);
-       struct list_head        fields;
-       int                     filter_active;
        struct event_filter     *filter;
        void                    *mod;
        void                    *data;
 
+       /*
+        * 32 bit flags:
+        *   bit 1:             enabled
+        *   bit 2:             filter_active
+        *
+        * Changes to flags must hold the event_mutex.
+        *
+        * Note: Reads of flags do not hold the event_mutex since
+        * they occur in critical sections. But the way flags
+        * is currently used, these changes do no affect the code
+        * except that when a change is made, it may have a slight
+        * delay in propagating the changes to other CPUs due to
+        * caching and such.
+        */
+       unsigned int            flags;
+
+#ifdef CONFIG_PERF_EVENTS
        int                     perf_refcount;
-       int                     (*perf_event_enable)(struct ftrace_event_call *);
-       void                    (*perf_event_disable)(struct ftrace_event_call *);
+       struct hlist_head       *perf_events;
+#endif
 };
 
 #define PERF_MAX_TRACE_SIZE    2048
@@ -194,24 +243,22 @@ struct perf_event;
 
 DECLARE_PER_CPU(struct pt_regs, perf_trace_regs);
 
-extern int perf_trace_enable(int event_id);
-extern void perf_trace_disable(int event_id);
-extern int ftrace_profile_set_filter(struct perf_event *event, int event_id,
+extern int  perf_trace_init(struct perf_event *event);
+extern void perf_trace_destroy(struct perf_event *event);
+extern int  perf_trace_enable(struct perf_event *event);
+extern void perf_trace_disable(struct perf_event *event);
+extern int  ftrace_profile_set_filter(struct perf_event *event, int event_id,
                                     char *filter_str);
 extern void ftrace_profile_free_filter(struct perf_event *event);
-extern void *
-perf_trace_buf_prepare(int size, unsigned short type, int *rctxp,
-                        unsigned long *irq_flags);
+extern void *perf_trace_buf_prepare(int size, unsigned short type,
+                                   struct pt_regs *regs, int *rctxp);
 
 static inline void
 perf_trace_buf_submit(void *raw_data, int size, int rctx, u64 addr,
-                      u64 count, unsigned long irq_flags, struct pt_regs *regs)
+                      u64 count, struct pt_regs *regs, void *head)
 {
-       struct trace_entry *entry = raw_data;
-
-       perf_tp_event(entry->type, addr, count, raw_data, size, regs);
+       perf_tp_event(addr, count, raw_data, size, regs, head);
        perf_swevent_put_recursion_context(rctx);
-       local_irq_restore(irq_flags);
 }
 #endif
 
index ca666d18ed6769418d1de90e45b690ec9e9eae36..574bea4013b618d0816d2280ced3670fa4e75bd4 100644 (file)
@@ -5,8 +5,8 @@
 
 struct inode;
 
-extern struct xattr_handler generic_acl_access_handler;
-extern struct xattr_handler generic_acl_default_handler;
+extern const struct xattr_handler generic_acl_access_handler;
+extern const struct xattr_handler generic_acl_default_handler;
 
 int generic_acl_init(struct inode *, struct inode *);
 int generic_acl_chmod(struct inode *);
index 4c6d41333f985a56807d19a67134e926e58b3542..975609cb8548504f20fd09e91476197a39dfbef1 100644 (file)
@@ -15,7 +15,7 @@ struct vm_area_struct;
  * Zone modifiers (see linux/mmzone.h - low three bits)
  *
  * Do not put any conditional on these. If necessary modify the definitions
- * without the underscores and use the consistently. The definitions here may
+ * without the underscores and use them consistently. The definitions here may
  * be used in bit comparisons.
  */
 #define __GFP_DMA      ((__force gfp_t)0x01u)
@@ -101,7 +101,7 @@ struct vm_area_struct;
                        __GFP_NORETRY|__GFP_NOMEMALLOC)
 
 /* Control slab gfp mask during early boot */
-#define GFP_BOOT_MASK __GFP_BITS_MASK & ~(__GFP_WAIT|__GFP_IO|__GFP_FS)
+#define GFP_BOOT_MASK (__GFP_BITS_MASK & ~(__GFP_WAIT|__GFP_IO|__GFP_FS))
 
 /* Control allocation constraints */
 #define GFP_CONSTRAINT_MASK (__GFP_HARDWALL|__GFP_THISNODE)
@@ -152,12 +152,12 @@ static inline int allocflags_to_migratetype(gfp_t gfp_flags)
  * GFP_ZONE_TABLE is a word size bitstring that is used for looking up the
  * zone to use given the lowest 4 bits of gfp_t. Entries are ZONE_SHIFT long
  * and there are 16 of them to cover all possible combinations of
- * __GFP_DMA, __GFP_DMA32, __GFP_MOVABLE and __GFP_HIGHMEM
+ * __GFP_DMA, __GFP_DMA32, __GFP_MOVABLE and __GFP_HIGHMEM.
  *
  * The zone fallback order is MOVABLE=>HIGHMEM=>NORMAL=>DMA32=>DMA.
  * But GFP_MOVABLE is not only a zone specifier but also an allocation
  * policy. Therefore __GFP_MOVABLE plus another zone selector is valid.
- * Only 1bit of the lowest 3 bit (DMA,DMA32,HIGHMEM) can be set to "1".
+ * Only 1 bit of the lowest 3 bits (DMA,DMA32,HIGHMEM) can be set to "1".
  *
  *       bit       result
  *       =================
@@ -187,7 +187,7 @@ static inline int allocflags_to_migratetype(gfp_t gfp_flags)
 
 #define GFP_ZONE_TABLE ( \
        (ZONE_NORMAL << 0 * ZONES_SHIFT)                                \
-       | (OPT_ZONE_DMA << __GFP_DMA * ZONES_SHIFT)                     \
+       | (OPT_ZONE_DMA << __GFP_DMA * ZONES_SHIFT)                     \
        | (OPT_ZONE_HIGHMEM << __GFP_HIGHMEM * ZONES_SHIFT)             \
        | (OPT_ZONE_DMA32 << __GFP_DMA32 * ZONES_SHIFT)                 \
        | (ZONE_NORMAL << __GFP_MOVABLE * ZONES_SHIFT)                  \
@@ -197,7 +197,7 @@ static inline int allocflags_to_migratetype(gfp_t gfp_flags)
 )
 
 /*
- * GFP_ZONE_BAD is a bitmap for all combination of __GFP_DMA, __GFP_DMA32
+ * GFP_ZONE_BAD is a bitmap for all combinations of __GFP_DMA, __GFP_DMA32
  * __GFP_HIGHMEM and __GFP_MOVABLE that are not permitted. One flag per
  * entry starting with bit 0. Bit is set if the combination is not
  * allowed.
@@ -320,17 +320,17 @@ void *alloc_pages_exact(size_t size, gfp_t gfp_mask);
 void free_pages_exact(void *virt, size_t size);
 
 #define __get_free_page(gfp_mask) \
-               __get_free_pages((gfp_mask),0)
+               __get_free_pages((gfp_mask), 0)
 
 #define __get_dma_pages(gfp_mask, order) \
-               __get_free_pages((gfp_mask) | GFP_DMA,(order))
+               __get_free_pages((gfp_mask) | GFP_DMA, (order))
 
 extern void __free_pages(struct page *page, unsigned int order);
 extern void free_pages(unsigned long addr, unsigned int order);
 extern void free_hot_cold_page(struct page *page, int cold);
 
 #define __free_page(page) __free_pages((page), 0)
-#define free_page(addr) free_pages((addr),0)
+#define free_page(addr) free_pages((addr), 0)
 
 void page_alloc_init(void);
 void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp);
index 4e949a5b5b85d810938561328210598ac2055512..03f616b78cfa8b857e727ea220a60c05a87bb89f 100644 (file)
@@ -51,6 +51,11 @@ static inline int gpio_direction_output(unsigned gpio, int value)
        return -ENOSYS;
 }
 
+static inline int gpio_set_debounce(unsigned gpio, unsigned debounce)
+{
+       return -ENOSYS;
+}
+
 static inline int gpio_get_value(unsigned gpio)
 {
        /* GPIO can never have been requested or set as {in,out}put */
index 74152c08ad0753be98d05b627eb4a035a68624c9..caafd0561aa1353c88a2ef56bcde5ec026fd7e8c 100644 (file)
@@ -27,7 +27,7 @@ static inline void invalidate_kernel_vmap_range(void *vaddr, int size)
 
 #include <asm/kmap_types.h>
 
-#if defined(CONFIG_DEBUG_HIGHMEM) && defined(CONFIG_TRACE_IRQFLAGS_SUPPORT)
+#ifdef CONFIG_DEBUG_HIGHMEM
 
 void debug_kmap_atomic(enum km_type type);
 
index 6ed1d59bfb1e642789e25d47af65fb36c6921f2e..21067b4185366b419a6c7af504ff1a711642457b 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/device.h>      /* for struct device */
 #include <linux/sched.h>       /* for completion */
 #include <linux/mutex.h>
+#include <linux/of.h>          /* for struct device_node */
 
 extern struct bus_type i2c_bus_type;
 
@@ -251,6 +252,9 @@ struct i2c_board_info {
        unsigned short  addr;
        void            *platform_data;
        struct dev_archdata     *archdata;
+#ifdef CONFIG_OF
+       struct device_node *of_node;
+#endif
        int             irq;
 };
 
diff --git a/include/linux/i2c/adp8860.h b/include/linux/i2c/adp8860.h
new file mode 100644 (file)
index 0000000..0b4d398
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Definitions and platform data for Analog Devices
+ * Backlight drivers ADP8860
+ *
+ * Copyright 2009-2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __LINUX_I2C_ADP8860_H
+#define __LINUX_I2C_ADP8860_H
+
+#include <linux/leds.h>
+#include <linux/types.h>
+
+#define ID_ADP8860             8860
+
+#define ADP8860_MAX_BRIGHTNESS 0x7F
+#define FLAG_OFFT_SHIFT 8
+
+/*
+ * LEDs subdevice platform data
+ */
+
+#define ADP8860_LED_DIS_BLINK  (0 << FLAG_OFFT_SHIFT)
+#define ADP8860_LED_OFFT_600ms (1 << FLAG_OFFT_SHIFT)
+#define ADP8860_LED_OFFT_1200ms        (2 << FLAG_OFFT_SHIFT)
+#define ADP8860_LED_OFFT_1800ms        (3 << FLAG_OFFT_SHIFT)
+
+#define ADP8860_LED_ONT_200ms  0
+#define ADP8860_LED_ONT_600ms  1
+#define ADP8860_LED_ONT_800ms  2
+#define ADP8860_LED_ONT_1200ms 3
+
+#define ADP8860_LED_D7         (7)
+#define ADP8860_LED_D6         (6)
+#define ADP8860_LED_D5         (5)
+#define ADP8860_LED_D4         (4)
+#define ADP8860_LED_D3         (3)
+#define ADP8860_LED_D2         (2)
+#define ADP8860_LED_D1         (1)
+
+/*
+ * Backlight subdevice platform data
+ */
+
+#define ADP8860_BL_D7          (1 << 6)
+#define ADP8860_BL_D6          (1 << 5)
+#define ADP8860_BL_D5          (1 << 4)
+#define ADP8860_BL_D4          (1 << 3)
+#define ADP8860_BL_D3          (1 << 2)
+#define ADP8860_BL_D2          (1 << 1)
+#define ADP8860_BL_D1          (1 << 0)
+
+#define ADP8860_FADE_T_DIS     0       /* Fade Timer Disabled */
+#define ADP8860_FADE_T_300ms   1       /* 0.3 Sec */
+#define ADP8860_FADE_T_600ms   2
+#define ADP8860_FADE_T_900ms   3
+#define ADP8860_FADE_T_1200ms  4
+#define ADP8860_FADE_T_1500ms  5
+#define ADP8860_FADE_T_1800ms  6
+#define ADP8860_FADE_T_2100ms  7
+#define ADP8860_FADE_T_2400ms  8
+#define ADP8860_FADE_T_2700ms  9
+#define ADP8860_FADE_T_3000ms  10
+#define ADP8860_FADE_T_3500ms  11
+#define ADP8860_FADE_T_4000ms  12
+#define ADP8860_FADE_T_4500ms  13
+#define ADP8860_FADE_T_5000ms  14
+#define ADP8860_FADE_T_5500ms  15      /* 5.5 Sec */
+
+#define ADP8860_FADE_LAW_LINEAR        0
+#define ADP8860_FADE_LAW_SQUARE        1
+#define ADP8860_FADE_LAW_CUBIC1        2
+#define ADP8860_FADE_LAW_CUBIC2        3
+
+#define ADP8860_BL_AMBL_FILT_80ms      0       /* Light sensor filter time */
+#define ADP8860_BL_AMBL_FILT_160ms     1
+#define ADP8860_BL_AMBL_FILT_320ms     2
+#define ADP8860_BL_AMBL_FILT_640ms     3
+#define ADP8860_BL_AMBL_FILT_1280ms    4
+#define ADP8860_BL_AMBL_FILT_2560ms    5
+#define ADP8860_BL_AMBL_FILT_5120ms    6
+#define ADP8860_BL_AMBL_FILT_10240ms   7       /* 10.24 sec */
+
+/*
+ * Blacklight current 0..30mA
+ */
+#define ADP8860_BL_CUR_mA(I)           ((I * 127) / 30)
+
+/*
+ * L2 comparator current 0..1106uA
+ */
+#define ADP8860_L2_COMP_CURR_uA(I)     ((I * 255) / 1106)
+
+/*
+ * L3 comparator current 0..138uA
+ */
+#define ADP8860_L3_COMP_CURR_uA(I)     ((I * 255) / 138)
+
+struct adp8860_backlight_platform_data {
+       u8 bl_led_assign;       /* 1 = Backlight 0 = Individual LED */
+
+       u8 bl_fade_in;          /* Backlight Fade-In Timer */
+       u8 bl_fade_out;         /* Backlight Fade-Out Timer */
+       u8 bl_fade_law;         /* fade-on/fade-off transfer characteristic */
+
+       u8 en_ambl_sens;        /* 1 = enable ambient light sensor */
+       u8 abml_filt;           /* Light sensor filter time */
+
+       u8 l1_daylight_max;     /* use BL_CUR_mA(I) 0 <= I <= 30 mA */
+       u8 l1_daylight_dim;     /* typ = 0, use BL_CUR_mA(I) 0 <= I <= 30 mA */
+       u8 l2_office_max;       /* use BL_CUR_mA(I) 0 <= I <= 30 mA */
+       u8 l2_office_dim;       /* typ = 0, use BL_CUR_mA(I) 0 <= I <= 30 mA */
+       u8 l3_dark_max;         /* use BL_CUR_mA(I) 0 <= I <= 30 mA */
+       u8 l3_dark_dim;         /* typ = 0, use BL_CUR_mA(I) 0 <= I <= 30 mA */
+
+       u8 l2_trip;             /* use L2_COMP_CURR_uA(I) 0 <= I <= 1106 uA */
+       u8 l2_hyst;             /* use L2_COMP_CURR_uA(I) 0 <= I <= 1106 uA */
+       u8 l3_trip;             /* use L3_COMP_CURR_uA(I) 0 <= I <= 551 uA */
+       u8 l3_hyst;             /* use L3_COMP_CURR_uA(I) 0 <= I <= 551 uA */
+
+       /**
+        * Independent Current Sinks / LEDS
+        * Sinks not assigned to the Backlight can be exposed to
+        * user space using the LEDS CLASS interface
+        */
+
+       int num_leds;
+       struct led_info *leds;
+       u8 led_fade_in;         /* LED Fade-In Timer */
+       u8 led_fade_out;        /* LED Fade-Out Timer */
+       u8 led_fade_law;        /* fade-on/fade-off transfer characteristic */
+       u8 led_on_time;
+
+       /**
+        * Gain down disable. Setting this option does not allow the
+        * charge pump to switch to lower gains. NOT AVAILABLE on ADP8860
+        * 1 = the charge pump doesn't switch down in gain until all LEDs are 0.
+        *  The charge pump switches up in gain as needed. This feature is
+        *  useful if the ADP8863 charge pump is used to drive an external load.
+        *  This feature must be used when utilizing small fly capacitors
+        *  (0402 or smaller).
+        * 0 = the charge pump automatically switches up and down in gain.
+        *  This provides optimal efficiency, but is not suitable for driving
+        *  loads that are not connected through the ADP8863 diode drivers.
+        *  Additionally, the charge pump fly capacitors should be low ESR
+        * and sized 0603 or greater.
+        */
+
+       u8 gdwn_dis;
+};
+
+#endif /* __LINUX_I2C_ADP8860_H */
index e10336631c62d40e51989ce305282ae731c8d580..c04bac8bf2feb45cdfe18f959476c4efd6693755 100644 (file)
@@ -7,6 +7,9 @@ struct max732x_platform_data {
        /* number of the first GPIO */
        unsigned        gpio_base;
 
+       /* interrupt base */
+       int             irq_base;
+
        void            *context;       /* param to setup/teardown */
 
        int             (*setup)(struct i2c_client *client,
index d5c5a60c8a0b1a2d513b8c19e060c4b8d1d94bd5..139ba52667c89cf9f02cc1ce16cb53bc81a77f0b 100644 (file)
@@ -24,7 +24,7 @@ struct pca953x_platform_data {
        int             (*teardown)(struct i2c_client *client,
                                unsigned gpio, unsigned ngpio,
                                void *context);
-       char            **names;
+       const char      *const *names;
 };
 
 #endif /* _LINUX_PCA953X_H */
index b6d448048ae251af4c3b7f29bd62801b1c43de07..7b02aa5ce9b4d30c803840376182797e15f9c3dc 100644 (file)
@@ -516,8 +516,8 @@ struct ide_drive_s {
         u8     current_speed;  /* current transfer rate set */
        u8      desired_speed;  /* desired transfer rate set */
        u8      pio_mode;       /* for ->set_pio_mode _only_ */
-       u8      dma_mode;       /* for ->dma_pio_mode _only_ */
-        u8     dn;             /* now wide spread use */
+       u8      dma_mode;       /* for ->set_dma_mode _only_ */
+       u8      dn;             /* now wide spread use */
        u8      acoustic;       /* acoustic management */
        u8      media;          /* disk, cdrom, tape, floppy, ... */
        u8      ready_stat;     /* min status value for drive ready */
index 7996fc2c9ba9ee4fc0b573e4e07dffcc0c028c9b..2beaa13492beb5dffdb90c0041d942a3785181e1 100644 (file)
@@ -16,7 +16,7 @@ extern struct files_struct init_files;
 extern struct fs_struct init_fs;
 
 #define INIT_SIGNALS(sig) {                                            \
-       .count          = ATOMIC_INIT(1),                               \
+       .nr_threads     = 1,                                            \
        .wait_chldexit  = __WAIT_QUEUE_HEAD_INITIALIZER(sig.wait_chldexit),\
        .shared_pending = {                                             \
                .list = LIST_HEAD_INIT(sig.shared_pending.list),        \
@@ -35,7 +35,7 @@ extern struct nsproxy init_nsproxy;
 
 #define INIT_SIGHAND(sighand) {                                                \
        .count          = ATOMIC_INIT(1),                               \
-       .action         = { { { .sa_handler = NULL, } }, },             \
+       .action         = { { { .sa_handler = SIG_DFL, } }, },          \
        .siglock        = __SPIN_LOCK_UNLOCKED(sighand.siglock),        \
        .signalfd_wqh   = __WAIT_QUEUE_HEAD_INITIALIZER(sighand.signalfd_wqh),  \
 }
@@ -45,9 +45,9 @@ extern struct group_info init_groups;
 #define INIT_STRUCT_PID {                                              \
        .count          = ATOMIC_INIT(1),                               \
        .tasks          = {                                             \
-               { .first = &init_task.pids[PIDTYPE_PID].node },         \
-               { .first = &init_task.pids[PIDTYPE_PGID].node },        \
-               { .first = &init_task.pids[PIDTYPE_SID].node },         \
+               { .first = NULL },                                      \
+               { .first = NULL },                                      \
+               { .first = NULL },                                      \
        },                                                              \
        .level          = 0,                                            \
        .numbers        = { {                                           \
@@ -61,7 +61,7 @@ extern struct group_info init_groups;
 {                                                              \
        .node = {                                               \
                .next = NULL,                                   \
-               .pprev = &init_struct_pid.tasks[type].first,    \
+               .pprev = NULL,                                  \
        },                                                      \
        .pid = &init_struct_pid,                                \
 }
@@ -163,6 +163,7 @@ extern struct cred init_cred;
                [PIDTYPE_PGID] = INIT_PID_LINK(PIDTYPE_PGID),           \
                [PIDTYPE_SID]  = INIT_PID_LINK(PIDTYPE_SID),            \
        },                                                              \
+       .thread_group   = LIST_HEAD_INIT(tsk.thread_group),             \
        .dirties = INIT_PROP_LOCAL_SINGLE(dirties),                     \
        INIT_IDS                                                        \
        INIT_PERF_EVENTS(tsk)                                           \
index 83524e4f3290ab1cff44a8fc7a1e229bb2940b6f..6fcc9101beeb3e907b9b4c030fef7db9b7f9e334 100644 (file)
@@ -1155,7 +1155,7 @@ struct input_dev {
 
        int sync;
 
-       int abs[ABS_MAX + 1];
+       int abs[ABS_CNT];
        int rep[REP_MAX + 1];
 
        unsigned long key[BITS_TO_LONGS(KEY_CNT)];
@@ -1163,11 +1163,11 @@ struct input_dev {
        unsigned long snd[BITS_TO_LONGS(SND_CNT)];
        unsigned long sw[BITS_TO_LONGS(SW_CNT)];
 
-       int absmax[ABS_MAX + 1];
-       int absmin[ABS_MAX + 1];
-       int absfuzz[ABS_MAX + 1];
-       int absflat[ABS_MAX + 1];
-       int absres[ABS_MAX + 1];
+       int absmax[ABS_CNT];
+       int absmin[ABS_CNT];
+       int absfuzz[ABS_CNT];
+       int absflat[ABS_CNT];
+       int absres[ABS_CNT];
 
        int (*open)(struct input_dev *dev);
        void (*close)(struct input_dev *dev);
index 26fad187d6610f3179dc3bf6b4b1b43820e1783a..b22790268b64d5457a62994d1974ede5fe5351aa 100644 (file)
@@ -52,6 +52,7 @@ struct resource_list {
 
 #define IORESOURCE_MEM_64      0x00100000
 #define IORESOURCE_WINDOW      0x00200000      /* forwarded by bridge */
+#define IORESOURCE_MUXED       0x00400000      /* Resource is software muxed */
 
 #define IORESOURCE_EXCLUSIVE   0x08000000      /* Userland may not map this resource */
 #define IORESOURCE_DISABLED    0x10000000
@@ -143,7 +144,8 @@ static inline unsigned long resource_type(const struct resource *res)
 }
 
 /* Convenience shorthand with allocation */
-#define request_region(start,n,name)   __request_region(&ioport_resource, (start), (n), (name), 0)
+#define request_region(start,n,name)           __request_region(&ioport_resource, (start), (n), (name), 0)
+#define request_muxed_region(start,n,name)     __request_region(&ioport_resource, (start), (n), (name), IORESOURCE_MUXED)
 #define __request_mem_region(start,n,name, excl) __request_region(&iomem_resource, (start), (n), (name), excl)
 #define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name), 0)
 #define request_mem_region_exclusive(start,n,name) \
index cd5a269fdb5e3a5280002c6dd767ee4efe331a48..e2d28b026a8ca3fb362341decd8f1a6f64904ea5 100644 (file)
  */
 
 #ifdef __KERNEL__
+#include <linux/mod_devicetable.h>
 
 #define DEVICE_COUNT_COMPATIBLE 4
 
-#define ISAPNP_ANY_ID          0xffff
 #define ISAPNP_CARD_DEVS       8
 
 #define ISAPNP_CARD_ID(_va, _vb, _vc, _device) \
@@ -74,12 +74,6 @@ struct isapnp_card_id {
 #define ISAPNP_DEVICE_SINGLE_END \
                .card_vendor = 0, .card_device = 0
 
-struct isapnp_device_id {
-       unsigned short card_vendor, card_device;
-       unsigned short vendor, function;
-       unsigned long driver_data;      /* data private to the driver */
-};
-
 #if defined(CONFIG_ISAPNP) || (defined(CONFIG_ISAPNP_MODULE) && defined(MODULE))
 
 #define __ISAPNP__
index 9d88b29ddf5556bef668c09d4503c659b471dd7a..e8b92f67f10d96db8b7daff25b08a97dcc99d803 100644 (file)
@@ -33,6 +33,5 @@ struct ivtvfb_dma_frame {
 };
 
 #define IVTVFB_IOC_DMA_FRAME   _IOW('V', BASE_VIDIOC_PRIVATE+0, struct ivtvfb_dma_frame)
-#define FBIO_WAITFORVSYNC      _IOW('F', 0x20, __u32)
 
 #endif
index 9e20c29c1e1401d1f814476087436d93fdb83ba0..47199b13e0eb9c1f102acd1e188a23be5c53b1cc 100644 (file)
@@ -64,8 +64,8 @@ struct js_event {
 #define JSIOCSCORR             _IOW('j', 0x21, struct js_corr)                 /* set correction values */
 #define JSIOCGCORR             _IOR('j', 0x22, struct js_corr)                 /* get correction values */
 
-#define JSIOCSAXMAP            _IOW('j', 0x31, __u8[ABS_MAX + 1])              /* set axis mapping */
-#define JSIOCGAXMAP            _IOR('j', 0x32, __u8[ABS_MAX + 1])              /* get axis mapping */
+#define JSIOCSAXMAP            _IOW('j', 0x31, __u8[ABS_CNT])                  /* set axis mapping */
+#define JSIOCGAXMAP            _IOR('j', 0x32, __u8[ABS_CNT])                  /* get axis mapping */
 #define JSIOCSBTNMAP           _IOW('j', 0x33, __u16[KEY_MAX - BTN_MISC + 1])  /* set button mapping */
 #define JSIOCGBTNMAP           _IOR('j', 0x34, __u16[KEY_MAX - BTN_MISC + 1])  /* get button mapping */
 
index fc33af9118520e6a04376fbe96b9d7a85d9e478d..8317ec4b9f3b4bbe615109073e7bd8ad9b946c1b 100644 (file)
@@ -24,9 +24,9 @@
 extern const char linux_banner[];
 extern const char linux_proc_banner[];
 
-#define USHORT_MAX     ((u16)(~0U))
-#define SHORT_MAX      ((s16)(USHORT_MAX>>1))
-#define SHORT_MIN      (-SHORT_MAX - 1)
+#define USHRT_MAX      ((u16)(~0U))
+#define SHRT_MAX       ((s16)(USHRT_MAX>>1))
+#define SHRT_MIN       ((s16)(-SHRT_MAX - 1))
 #define INT_MAX                ((int)(~0U>>1))
 #define INT_MIN                (-INT_MAX - 1)
 #define UINT_MAX       (~0U)
@@ -346,6 +346,7 @@ extern enum system_states {
 #define TAINT_OVERRIDDEN_ACPI_TABLE    8
 #define TAINT_WARN                     9
 #define TAINT_CRAP                     10
+#define TAINT_FIRMWARE_WORKAROUND      11
 
 extern void dump_stack(void) __cold;
 
@@ -374,6 +375,8 @@ static inline char *pack_hex_byte(char *buf, u8 byte)
        return buf;
 }
 
+extern int hex_to_bin(char ch);
+
 #ifndef pr_fmt
 #define pr_fmt(fmt) fmt
 #endif
@@ -388,6 +391,7 @@ static inline char *pack_hex_byte(char *buf, u8 byte)
         printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
 #define pr_warning(fmt, ...) \
         printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_warn pr_warning
 #define pr_notice(fmt, ...) \
         printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)
 #define pr_info(fmt, ...) \
@@ -422,14 +426,13 @@ static inline char *pack_hex_byte(char *buf, u8 byte)
  * no local ratelimit_state used in the !PRINTK case
  */
 #ifdef CONFIG_PRINTK
-#define printk_ratelimited(fmt, ...)  ({               \
-       static struct ratelimit_state _rs = {           \
-               .interval = DEFAULT_RATELIMIT_INTERVAL, \
-               .burst = DEFAULT_RATELIMIT_BURST,       \
-       };                                              \
-                                                       \
-       if (__ratelimit(&_rs))                          \
-               printk(fmt, ##__VA_ARGS__);             \
+#define printk_ratelimited(fmt, ...)  ({                               \
+       static DEFINE_RATELIMIT_STATE(_rs,                              \
+                                     DEFAULT_RATELIMIT_INTERVAL,       \
+                                     DEFAULT_RATELIMIT_BURST);         \
+                                                                       \
+       if (__ratelimit(&_rs))                                          \
+               printk(fmt, ##__VA_ARGS__);                             \
 })
 #else
 /* No effect, but we still get type checking even in the !PRINTK case: */
@@ -446,6 +449,7 @@ static inline char *pack_hex_byte(char *buf, u8 byte)
        printk_ratelimited(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
 #define pr_warning_ratelimited(fmt, ...) \
        printk_ratelimited(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_warn_ratelimited pr_warning_ratelimited
 #define pr_notice_ratelimited(fmt, ...) \
        printk_ratelimited(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)
 #define pr_info_ratelimited(fmt, ...) \
index facb27fe7de00a570d959d49f1c114bc16103a02..6efd7a78de6aaaa6d74c526ba44f5fafa81e1fad 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/stddef.h>
 #include <linux/errno.h>
 #include <linux/compiler.h>
+#include <linux/workqueue.h>
 
 #define KMOD_PATH_LEN 256
 
@@ -45,19 +46,6 @@ static inline int request_module_nowait(const char *name, ...) { return -ENOSYS;
 
 struct key;
 struct file;
-struct subprocess_info;
-
-/* Allocate a subprocess_info structure */
-struct subprocess_info *call_usermodehelper_setup(char *path, char **argv,
-                                                 char **envp, gfp_t gfp_mask);
-
-/* Set various pieces of state into the subprocess_info structure */
-void call_usermodehelper_setkeys(struct subprocess_info *info,
-                                struct key *session_keyring);
-int call_usermodehelper_stdinpipe(struct subprocess_info *sub_info,
-                                 struct file **filp);
-void call_usermodehelper_setcleanup(struct subprocess_info *info,
-                                   void (*cleanup)(char **argv, char **envp));
 
 enum umh_wait {
        UMH_NO_WAIT = -1,       /* don't wait at all */
@@ -65,6 +53,29 @@ enum umh_wait {
        UMH_WAIT_PROC = 1,      /* wait for the process to complete */
 };
 
+struct subprocess_info {
+       struct work_struct work;
+       struct completion *complete;
+       char *path;
+       char **argv;
+       char **envp;
+       enum umh_wait wait;
+       int retval;
+       int (*init)(struct subprocess_info *info);
+       void (*cleanup)(struct subprocess_info *info);
+       void *data;
+};
+
+/* Allocate a subprocess_info structure */
+struct subprocess_info *call_usermodehelper_setup(char *path, char **argv,
+                                                 char **envp, gfp_t gfp_mask);
+
+/* Set various pieces of state into the subprocess_info structure */
+void call_usermodehelper_setfns(struct subprocess_info *info,
+                   int (*init)(struct subprocess_info *info),
+                   void (*cleanup)(struct subprocess_info *info),
+                   void *data);
+
 /* Actually execute the sub-process */
 int call_usermodehelper_exec(struct subprocess_info *info, enum umh_wait wait);
 
@@ -73,38 +84,33 @@ int call_usermodehelper_exec(struct subprocess_info *info, enum umh_wait wait);
 void call_usermodehelper_freeinfo(struct subprocess_info *info);
 
 static inline int
-call_usermodehelper(char *path, char **argv, char **envp, enum umh_wait wait)
+call_usermodehelper_fns(char *path, char **argv, char **envp,
+                       enum umh_wait wait,
+                       int (*init)(struct subprocess_info *info),
+                       void (*cleanup)(struct subprocess_info *), void *data)
 {
        struct subprocess_info *info;
        gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL;
 
        info = call_usermodehelper_setup(path, argv, envp, gfp_mask);
+
        if (info == NULL)
                return -ENOMEM;
+
+       call_usermodehelper_setfns(info, init, cleanup, data);
+
        return call_usermodehelper_exec(info, wait);
 }
 
 static inline int
-call_usermodehelper_keys(char *path, char **argv, char **envp,
-                        struct key *session_keyring, enum umh_wait wait)
+call_usermodehelper(char *path, char **argv, char **envp, enum umh_wait wait)
 {
-       struct subprocess_info *info;
-       gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL;
-
-       info = call_usermodehelper_setup(path, argv, envp, gfp_mask);
-       if (info == NULL)
-               return -ENOMEM;
-
-       call_usermodehelper_setkeys(info, session_keyring);
-       return call_usermodehelper_exec(info, wait);
+       return call_usermodehelper_fns(path, argv, envp, wait,
+                                      NULL, NULL, NULL);
 }
 
 extern void usermodehelper_init(void);
 
-struct file;
-extern int call_usermodehelper_pipe(char *path, char *argv[], char *envp[],
-                                   struct file **filp);
-
 extern int usermodehelper_disable(void);
 extern void usermodehelper_enable(void);
 
index 60df9c84ecae2e0606d1ffc3cc8c9ec7d79785d9..23ea022539000cc46ff430d97fe54d3ff3c4d9ed 100644 (file)
@@ -160,6 +160,7 @@ struct kvm_pit_config {
 #define KVM_EXIT_DCR              15
 #define KVM_EXIT_NMI              16
 #define KVM_EXIT_INTERNAL_ERROR   17
+#define KVM_EXIT_OSI              18
 
 /* For KVM_EXIT_INTERNAL_ERROR */
 #define KVM_INTERNAL_ERROR_EMULATION 1
@@ -259,6 +260,10 @@ struct kvm_run {
                        __u32 ndata;
                        __u64 data[16];
                } internal;
+               /* KVM_EXIT_OSI */
+               struct {
+                       __u64 gprs[32];
+               } osi;
                /* Fix the size of the union. */
                char padding[256];
        };
@@ -400,6 +405,15 @@ struct kvm_ioeventfd {
        __u8  pad[36];
 };
 
+/* for KVM_ENABLE_CAP */
+struct kvm_enable_cap {
+       /* in */
+       __u32 cap;
+       __u32 flags;
+       __u64 args[4];
+       __u8  pad[64];
+};
+
 #define KVMIO 0xAE
 
 /*
@@ -501,7 +515,15 @@ struct kvm_ioeventfd {
 #define KVM_CAP_HYPERV_VAPIC 45
 #define KVM_CAP_HYPERV_SPIN 46
 #define KVM_CAP_PCI_SEGMENT 47
+#define KVM_CAP_PPC_PAIRED_SINGLES 48
+#define KVM_CAP_INTR_SHADOW 49
+#ifdef __KVM_HAVE_DEBUGREGS
+#define KVM_CAP_DEBUGREGS 50
+#endif
 #define KVM_CAP_X86_ROBUST_SINGLESTEP 51
+#define KVM_CAP_PPC_OSI 52
+#define KVM_CAP_PPC_UNSET_IRQ 53
+#define KVM_CAP_ENABLE_CAP 54
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -688,6 +710,10 @@ struct kvm_clock_data {
 /* Available with KVM_CAP_VCPU_EVENTS */
 #define KVM_GET_VCPU_EVENTS       _IOR(KVMIO,  0x9f, struct kvm_vcpu_events)
 #define KVM_SET_VCPU_EVENTS       _IOW(KVMIO,  0xa0, struct kvm_vcpu_events)
+/* Available with KVM_CAP_DEBUGREGS */
+#define KVM_GET_DEBUGREGS         _IOR(KVMIO,  0xa1, struct kvm_debugregs)
+#define KVM_SET_DEBUGREGS         _IOW(KVMIO,  0xa2, struct kvm_debugregs)
+#define KVM_ENABLE_CAP            _IOW(KVMIO,  0xa3, struct kvm_enable_cap)
 
 #define KVM_DEV_ASSIGN_ENABLE_IOMMU    (1 << 0)
 
index 169d07758ee53046c7f6740f3466aa78921e1342..7cb116afa1cdbd9c48998b4d26bc1974c011636b 100644 (file)
@@ -105,6 +105,12 @@ struct kvm_vcpu {
        struct kvm_vcpu_arch arch;
 };
 
+/*
+ * Some of the bitops functions do not support too long bitmaps.
+ * This number must be determined not to exceed such limits.
+ */
+#define KVM_MEM_MAX_NR_PAGES ((1UL << 31) - 1)
+
 struct kvm_memory_slot {
        gfn_t base_gfn;
        unsigned long npages;
@@ -237,17 +243,23 @@ void kvm_vcpu_uninit(struct kvm_vcpu *vcpu);
 void vcpu_load(struct kvm_vcpu *vcpu);
 void vcpu_put(struct kvm_vcpu *vcpu);
 
-int kvm_init(void *opaque, unsigned int vcpu_size,
+int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align,
                  struct module *module);
 void kvm_exit(void);
 
 void kvm_get_kvm(struct kvm *kvm);
 void kvm_put_kvm(struct kvm *kvm);
 
+static inline struct kvm_memslots *kvm_memslots(struct kvm *kvm)
+{
+       return rcu_dereference_check(kvm->memslots,
+                       srcu_read_lock_held(&kvm->srcu)
+                       || lockdep_is_held(&kvm->slots_lock));
+}
+
 #define HPA_MSB ((sizeof(hpa_t) * 8) - 1)
 #define HPA_ERR_MASK ((hpa_t)1 << HPA_MSB)
 static inline int is_error_hpa(hpa_t hpa) { return hpa >> HPA_MSB; }
-struct page *gva_to_page(struct kvm_vcpu *vcpu, gva_t gva);
 
 extern struct page *bad_page;
 extern pfn_t bad_pfn;
index c67fecafff909ccb2c7dc1084de264d2192c845c..8877123f2d6e61dd8b22da7c9b8994f13d05e7f9 100644 (file)
@@ -69,6 +69,29 @@ struct lcd_device {
        struct device dev;
 };
 
+struct lcd_platform_data {
+       /* reset lcd panel device. */
+       int (*reset)(struct lcd_device *ld);
+       /* on or off to lcd panel. if 'enable' is 0 then
+          lcd power off and 1, lcd power on. */
+       int (*power_on)(struct lcd_device *ld, int enable);
+
+       /* it indicates whether lcd panel was enabled
+          from bootloader or not. */
+       int lcd_enabled;
+       /* it means delay for stable time when it becomes low to high
+          or high to low that is dependent on whether reset gpio is
+          low active or high active. */
+       unsigned int reset_delay;
+       /* stable time needing to become lcd power on. */
+       unsigned int power_on_delay;
+       /* stable time needing to become lcd power off. */
+       unsigned int power_off_delay;
+
+       /* it could be used for any purpose. */
+       void *pdata;
+};
+
 static inline void lcd_set_power(struct lcd_device *ld, int power)
 {
        mutex_lock(&ld->update_lock);
index d8bf9665e70cc09b40d781a82c638e1b95dd82af..ba6986a11663a417625a259a612019df46f0ad97 100644 (file)
@@ -149,14 +149,18 @@ struct gpio_led {
        unsigned        default_state : 2;
        /* default_state should be one of LEDS_GPIO_DEFSTATE_(ON|OFF|KEEP) */
 };
-#define LEDS_GPIO_DEFSTATE_OFF 0
-#define LEDS_GPIO_DEFSTATE_ON  1
-#define LEDS_GPIO_DEFSTATE_KEEP        2
+#define LEDS_GPIO_DEFSTATE_OFF         0
+#define LEDS_GPIO_DEFSTATE_ON          1
+#define LEDS_GPIO_DEFSTATE_KEEP                2
 
 struct gpio_led_platform_data {
        int             num_leds;
        struct gpio_led *leds;
-       int             (*gpio_blink_set)(unsigned gpio,
+
+#define GPIO_LED_NO_BLINK_LOW  0       /* No blink GPIO state low */
+#define GPIO_LED_NO_BLINK_HIGH 1       /* No blink GPIO state high */
+#define GPIO_LED_BLINK         2       /* Plase, blink */
+       int             (*gpio_blink_set)(unsigned gpio, int state,
                                        unsigned long *delay_on,
                                        unsigned long *delay_off);
 };
index ee84e7e120394b9ae58d76e67e7a0b9220325efd..3bad2701bfa6349ff9ff8e0314f2b6cb3985e1f2 100644 (file)
@@ -386,6 +386,7 @@ enum {
        ATA_HORKAGE_1_5_GBPS    = (1 << 13),    /* force 1.5 Gbps */
        ATA_HORKAGE_NOSETXFER   = (1 << 14),    /* skip SETXFER, SATA only */
        ATA_HORKAGE_BROKEN_FPDMA_AA     = (1 << 15),    /* skip AA */
+       ATA_HORKAGE_DUMP_ID     = (1 << 16),    /* dump IDENTIFY data */
 
         /* DMA mask for user DMA control: User visible values; DO NOT
            renumber */
@@ -513,7 +514,9 @@ struct ata_ioports {
        void __iomem            *command_addr;
        void __iomem            *altstatus_addr;
        void __iomem            *ctl_addr;
+#ifdef CONFIG_ATA_BMDMA
        void __iomem            *bmdma_addr;
+#endif /* CONFIG_ATA_BMDMA */
        void __iomem            *scr_addr;
 };
 #endif /* CONFIG_ATA_SFF */
@@ -721,8 +724,10 @@ struct ata_port {
        u8                      ctl;    /* cache of ATA control register */
        u8                      last_ctl;       /* Cache last written value */
        struct delayed_work     sff_pio_task;
+#ifdef CONFIG_ATA_BMDMA
        struct ata_bmdma_prd    *bmdma_prd;     /* BMDMA SG list */
        dma_addr_t              bmdma_prd_dma;  /* and its DMA mapping */
+#endif /* CONFIG_ATA_BMDMA */
 #endif /* CONFIG_ATA_SFF */
 
        unsigned int            pio_mask;
@@ -856,10 +861,12 @@ struct ata_port_operations {
        void (*sff_irq_clear)(struct ata_port *);
        void (*sff_drain_fifo)(struct ata_queued_cmd *qc);
 
+#ifdef CONFIG_ATA_BMDMA
        void (*bmdma_setup)(struct ata_queued_cmd *qc);
        void (*bmdma_start)(struct ata_queued_cmd *qc);
        void (*bmdma_stop)(struct ata_queued_cmd *qc);
        u8   (*bmdma_status)(struct ata_port *ap);
+#endif /* CONFIG_ATA_BMDMA */
 #endif /* CONFIG_ATA_SFF */
 
        ssize_t (*em_show)(struct ata_port *ap, char *buf);
@@ -1555,7 +1562,6 @@ extern void sata_pmp_error_handler(struct ata_port *ap);
 #ifdef CONFIG_ATA_SFF
 
 extern const struct ata_port_operations ata_sff_port_ops;
-extern const struct ata_port_operations ata_bmdma_port_ops;
 extern const struct ata_port_operations ata_bmdma32_port_ops;
 
 /* PIO only, sg_tablesize and dma_boundary limits can be removed */
@@ -1564,11 +1570,6 @@ extern const struct ata_port_operations ata_bmdma32_port_ops;
        .sg_tablesize           = LIBATA_MAX_PRD,               \
        .dma_boundary           = ATA_DMA_BOUNDARY
 
-#define ATA_BMDMA_SHT(drv_name)                                        \
-       ATA_BASE_SHT(drv_name),                                 \
-       .sg_tablesize           = LIBATA_MAX_PRD,               \
-       .dma_boundary           = ATA_DMA_BOUNDARY
-
 extern void ata_sff_dev_select(struct ata_port *ap, unsigned int device);
 extern u8 ata_sff_check_status(struct ata_port *ap);
 extern void ata_sff_pause(struct ata_port *ap);
@@ -1593,7 +1594,7 @@ extern int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
 extern void ata_sff_queue_pio_task(struct ata_port *ap, unsigned long delay);
 extern unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc);
 extern bool ata_sff_qc_fill_rtf(struct ata_queued_cmd *qc);
-extern unsigned int ata_sff_host_intr(struct ata_port *ap,
+extern unsigned int ata_sff_port_intr(struct ata_port *ap,
                                      struct ata_queued_cmd *qc);
 extern irqreturn_t ata_sff_interrupt(int irq, void *dev_instance);
 extern void ata_sff_lost_interrupt(struct ata_port *ap);
@@ -1625,11 +1626,24 @@ extern int ata_pci_sff_init_one(struct pci_dev *pdev,
                struct scsi_host_template *sht, void *host_priv, int hflags);
 #endif /* CONFIG_PCI */
 
+#ifdef CONFIG_ATA_BMDMA
+
+extern const struct ata_port_operations ata_bmdma_port_ops;
+
+#define ATA_BMDMA_SHT(drv_name)                                        \
+       ATA_BASE_SHT(drv_name),                                 \
+       .sg_tablesize           = LIBATA_MAX_PRD,               \
+       .dma_boundary           = ATA_DMA_BOUNDARY
+
 extern void ata_bmdma_qc_prep(struct ata_queued_cmd *qc);
 extern unsigned int ata_bmdma_qc_issue(struct ata_queued_cmd *qc);
 extern void ata_bmdma_dumb_qc_prep(struct ata_queued_cmd *qc);
+extern unsigned int ata_bmdma_port_intr(struct ata_port *ap,
+                                     struct ata_queued_cmd *qc);
+extern irqreturn_t ata_bmdma_interrupt(int irq, void *dev_instance);
 extern void ata_bmdma_error_handler(struct ata_port *ap);
 extern void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc);
+extern void ata_bmdma_irq_clear(struct ata_port *ap);
 extern void ata_bmdma_setup(struct ata_queued_cmd *qc);
 extern void ata_bmdma_start(struct ata_queued_cmd *qc);
 extern void ata_bmdma_stop(struct ata_queued_cmd *qc);
@@ -1640,7 +1654,15 @@ extern int ata_bmdma_port_start32(struct ata_port *ap);
 #ifdef CONFIG_PCI
 extern int ata_pci_bmdma_clear_simplex(struct pci_dev *pdev);
 extern void ata_pci_bmdma_init(struct ata_host *host);
+extern int ata_pci_bmdma_prepare_host(struct pci_dev *pdev,
+                                     const struct ata_port_info * const * ppi,
+                                     struct ata_host **r_host);
+extern int ata_pci_bmdma_init_one(struct pci_dev *pdev,
+                                 const struct ata_port_info * const * ppi,
+                                 struct scsi_host_template *sht,
+                                 void *host_priv, int hflags);
 #endif /* CONFIG_PCI */
+#endif /* CONFIG_ATA_BMDMA */
 
 /**
  *     ata_sff_busy_wait - Wait for a port status register
index f1ca0dcc162877513d922ee69e3b9ee2465df1d8..0e8a346424bb6d4d1ec162ff26fb933f4fce92ef 100644 (file)
@@ -25,12 +25,14 @@ struct lis3lv02d_platform_data {
 #define LIS3_IRQ1_FF_WU_12     (3 << 0)
 #define LIS3_IRQ1_DATA_READY   (4 << 0)
 #define LIS3_IRQ1_CLICK                (7 << 0)
+#define LIS3_IRQ1_MASK         (7 << 0)
 #define LIS3_IRQ2_DISABLE      (0 << 3)
 #define LIS3_IRQ2_FF_WU_1      (1 << 3)
 #define LIS3_IRQ2_FF_WU_2      (2 << 3)
 #define LIS3_IRQ2_FF_WU_12     (3 << 3)
 #define LIS3_IRQ2_DATA_READY   (4 << 3)
 #define LIS3_IRQ2_CLICK                (7 << 3)
+#define LIS3_IRQ2_MASK         (7 << 3)
 #define LIS3_IRQ_OPEN_DRAIN    (1 << 6)
 #define LIS3_IRQ_ACTIVE_LOW    (1 << 7)
        unsigned char irq_cfg;
@@ -43,6 +45,15 @@ struct lis3lv02d_platform_data {
 #define LIS3_WAKEUP_Z_HI       (1 << 5)
        unsigned char wakeup_flags;
        unsigned char wakeup_thresh;
+       unsigned char wakeup_flags2;
+       unsigned char wakeup_thresh2;
+#define LIS3_HIPASS_CUTFF_8HZ   0
+#define LIS3_HIPASS_CUTFF_4HZ   1
+#define LIS3_HIPASS_CUTFF_2HZ   2
+#define LIS3_HIPASS_CUTFF_1HZ   3
+#define LIS3_HIPASS1_DISABLE    (1 << 2)
+#define LIS3_HIPASS2_DISABLE    (1 << 3)
+       unsigned char hipass_ctrl;
 #define LIS3_NO_MAP            0
 #define LIS3_DEV_X             1
 #define LIS3_DEV_Y             2
@@ -58,6 +69,7 @@ struct lis3lv02d_platform_data {
        /* Limits for selftest are specified in chip data sheet */
        s16 st_min_limits[3]; /* min pass limit x, y, z */
        s16 st_max_limits[3]; /* max pass limit x, y, z */
+       int irq2;
 };
 
 #endif /* __LIS3LV02D_H_ */
index 2203121a43e9a0730bf25e2f336f78bda365a683..8c22a89386426359f9a268e2c9d8e831ca3fe66a 100644 (file)
@@ -4,6 +4,7 @@
 #include <asm/ioctl.h>
 #include <linux/types.h>
 #include <linux/videodev2.h>
+#include <linux/fb.h>
 
 struct matroxioc_output_mode {
        __u32   output;         /* which output */
@@ -37,7 +38,5 @@ enum matroxfb_ctrl_id {
   MATROXFB_CID_LAST
 };
 
-#define FBIO_WAITFORVSYNC      _IOW('F', 0x20, __u32)
-
 #endif
 
index 44301c6affa8b06d831cb0e48b5b28fc22d96687..9411d32840b055cfc5b445a670e43e8a0173f585 100644 (file)
@@ -25,6 +25,13 @@ struct page_cgroup;
 struct page;
 struct mm_struct;
 
+extern unsigned long mem_cgroup_isolate_pages(unsigned long nr_to_scan,
+                                       struct list_head *dst,
+                                       unsigned long *scanned, int order,
+                                       int mode, struct zone *z,
+                                       struct mem_cgroup *mem_cont,
+                                       int active, int file);
+
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR
 /*
  * All "charge" functions with gfp_mask should use GFP_KERNEL or
@@ -64,12 +71,6 @@ extern void mem_cgroup_uncharge_cache_page(struct page *page);
 extern int mem_cgroup_shmem_charge_fallback(struct page *page,
                        struct mm_struct *mm, gfp_t gfp_mask);
 
-extern unsigned long mem_cgroup_isolate_pages(unsigned long nr_to_scan,
-                                       struct list_head *dst,
-                                       unsigned long *scanned, int order,
-                                       int mode, struct zone *z,
-                                       struct mem_cgroup *mem_cont,
-                                       int active, int file);
 extern void mem_cgroup_out_of_memory(struct mem_cgroup *mem, gfp_t gfp_mask);
 int task_in_mem_cgroup(struct task_struct *task, const struct mem_cgroup *mem);
 
@@ -89,7 +90,8 @@ int mm_match_cgroup(const struct mm_struct *mm, const struct mem_cgroup *cgroup)
 extern struct cgroup_subsys_state *mem_cgroup_css(struct mem_cgroup *mem);
 
 extern int
-mem_cgroup_prepare_migration(struct page *page, struct mem_cgroup **ptr);
+mem_cgroup_prepare_migration(struct page *page,
+       struct page *newpage, struct mem_cgroup **ptr);
 extern void mem_cgroup_end_migration(struct mem_cgroup *mem,
        struct page *oldpage, struct page *newpage);
 
@@ -226,7 +228,8 @@ static inline struct cgroup_subsys_state *mem_cgroup_css(struct mem_cgroup *mem)
 }
 
 static inline int
-mem_cgroup_prepare_migration(struct page *page, struct mem_cgroup **ptr)
+mem_cgroup_prepare_migration(struct page *page, struct page *newpage,
+       struct mem_cgroup **ptr)
 {
        return 0;
 }
index 35b07b773e6cbf90589b90b69897bc2043f7495d..864035fb8f8a83e547efbdd161093117bac94bc2 100644 (file)
@@ -202,6 +202,7 @@ static inline int is_mem_section_removable(unsigned long pfn,
 }
 #endif /* CONFIG_MEMORY_HOTREMOVE */
 
+extern int mem_online_node(int nid);
 extern int add_memory(int nid, u64 start, u64 size);
 extern int arch_add_memory(int nid, u64 start, u64 size);
 extern int remove_memory(u64 start, u64 size);
index 1cc966cd3e5fff90b3cf893a2f91a6ec8747b0f7..7b9ef6bf45aa3c6648bf344f2fff53335a976820 100644 (file)
@@ -23,6 +23,13 @@ enum {
        MPOL_MAX,       /* always last member of enum */
 };
 
+enum mpol_rebind_step {
+       MPOL_REBIND_ONCE,       /* do rebind work at once(not by two step) */
+       MPOL_REBIND_STEP1,      /* first step(set all the newly nodes) */
+       MPOL_REBIND_STEP2,      /* second step(clean all the disallowed nodes)*/
+       MPOL_REBIND_NSTEP,
+};
+
 /* Flags for set_mempolicy */
 #define MPOL_F_STATIC_NODES    (1 << 15)
 #define MPOL_F_RELATIVE_NODES  (1 << 14)
@@ -51,6 +58,7 @@ enum {
  */
 #define MPOL_F_SHARED  (1 << 0)        /* identify shared policies */
 #define MPOL_F_LOCAL   (1 << 1)        /* preferred local allocation */
+#define MPOL_F_REBINDING (1 << 2)      /* identify policies in rebinding */
 
 #ifdef __KERNEL__
 
@@ -193,8 +201,8 @@ struct mempolicy *mpol_shared_policy_lookup(struct shared_policy *sp,
 
 extern void numa_default_policy(void);
 extern void numa_policy_init(void);
-extern void mpol_rebind_task(struct task_struct *tsk,
-                                       const nodemask_t *new);
+extern void mpol_rebind_task(struct task_struct *tsk, const nodemask_t *new,
+                               enum mpol_rebind_step step);
 extern void mpol_rebind_mm(struct mm_struct *mm, nodemask_t *new);
 extern void mpol_fix_fork_child_flag(struct task_struct *p);
 
@@ -308,7 +316,8 @@ static inline void numa_default_policy(void)
 }
 
 static inline void mpol_rebind_task(struct task_struct *tsk,
-                                       const nodemask_t *new)
+                               const nodemask_t *new,
+                               enum mpol_rebind_step step)
 {
 }
 
index 73f92c5feea2a7d48110e4b474dcd9d0c91c4a10..e3c4ff8c3e38776e092c7310d9180ce52386d734 100644 (file)
@@ -132,6 +132,7 @@ enum {
        PM8607_ID_LDO9,
        PM8607_ID_LDO10,
        PM8607_ID_LDO12,
+       PM8607_ID_LDO13,
        PM8607_ID_LDO14,
 
        PM8607_ID_RG_MAX,
@@ -309,7 +310,7 @@ struct pm860x_chip {
 
 };
 
-#define PM8607_MAX_REGULATOR   15      /* 3 Bucks, 12 LDOs */
+#define PM8607_MAX_REGULATOR   PM8607_ID_RG_MAX        /* 3 Bucks, 13 LDOs */
 
 enum {
        GI2C_PORT = 0,
index 8895d9d8879cb12b164d28f5f22da38905d122cb..4a894f688549f28a25bb7af2dce91b76bf3146f1 100644 (file)
@@ -64,6 +64,70 @@ static inline int mc13783_ackirq(struct mc13783 *mc13783, int irq)
                                        MC13783_ADC0_TSMOD1 | \
                                        MC13783_ADC0_TSMOD2)
 
+struct mc13783_led_platform_data {
+#define MC13783_LED_MD         0
+#define MC13783_LED_AD         1
+#define MC13783_LED_KP         2
+#define MC13783_LED_R1         3
+#define MC13783_LED_G1         4
+#define MC13783_LED_B1         5
+#define MC13783_LED_R2         6
+#define MC13783_LED_G2         7
+#define MC13783_LED_B2         8
+#define MC13783_LED_R3         9
+#define MC13783_LED_G3         10
+#define MC13783_LED_B3         11
+#define MC13783_LED_MAX MC13783_LED_B3
+       int id;
+       const char *name;
+       const char *default_trigger;
+
+/* Three or two bits current selection depending on the led */
+       char max_current;
+};
+
+struct mc13783_leds_platform_data {
+       int num_leds;
+       struct mc13783_led_platform_data *led;
+
+#define MC13783_LED_TRIODE_MD  (1 << 0)
+#define MC13783_LED_TRIODE_AD  (1 << 1)
+#define MC13783_LED_TRIODE_KP  (1 << 2)
+#define MC13783_LED_BOOST_EN   (1 << 3)
+#define MC13783_LED_TC1HALF    (1 << 4)
+#define MC13783_LED_SLEWLIMTC  (1 << 5)
+#define MC13783_LED_SLEWLIMBL  (1 << 6)
+#define MC13783_LED_TRIODE_TC1 (1 << 7)
+#define MC13783_LED_TRIODE_TC2 (1 << 8)
+#define MC13783_LED_TRIODE_TC3 (1 << 9)
+       int flags;
+
+#define MC13783_LED_AB_DISABLED                0
+#define MC13783_LED_AB_MD1             1
+#define MC13783_LED_AB_MD12            2
+#define MC13783_LED_AB_MD123           3
+#define MC13783_LED_AB_MD1234          4
+#define MC13783_LED_AB_MD1234_AD1      5
+#define MC13783_LED_AB_MD1234_AD12     6
+#define MC13783_LED_AB_MD1_AD          7
+       char abmode;
+
+#define MC13783_LED_ABREF_200MV        0
+#define MC13783_LED_ABREF_400MV        1
+#define MC13783_LED_ABREF_600MV        2
+#define MC13783_LED_ABREF_800MV        3
+       char abref;
+
+#define MC13783_LED_PERIOD_10MS                0
+#define MC13783_LED_PERIOD_100MS       1
+#define MC13783_LED_PERIOD_500MS       2
+#define MC13783_LED_PERIOD_2S          3
+       char bl_period;
+       char tc1_period;
+       char tc2_period;
+       char tc3_period;
+};
+
 /* to be cleaned up */
 struct regulator_init_data;
 
@@ -80,12 +144,14 @@ struct mc13783_regulator_platform_data {
 struct mc13783_platform_data {
        int num_regulators;
        struct mc13783_regulator_init_data *regulators;
+       struct mc13783_leds_platform_data *leds;
 
 #define MC13783_USE_TOUCHSCREEN (1 << 0)
 #define MC13783_USE_CODEC      (1 << 1)
 #define MC13783_USE_ADC                (1 << 2)
 #define MC13783_USE_RTC                (1 << 3)
 #define MC13783_USE_REGULATOR  (1 << 4)
+#define MC13783_USE_LED                (1 << 5)
        unsigned int flags;
 };
 
diff --git a/include/linux/mfd/pcf50633/backlight.h b/include/linux/mfd/pcf50633/backlight.h
new file mode 100644 (file)
index 0000000..83747e2
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ *  Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
+ *      PCF50633 backlight device driver
+ *
+ *  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.
+ *
+ *  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.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __LINUX_MFD_PCF50633_BACKLIGHT
+#define __LINUX_MFD_PCF50633_BACKLIGHT
+
+/*
+* @default_brightness: Backlight brightness is initialized to this value
+*
+* Brightness to be used after the driver has been probed.
+* Valid range 0-63.
+*
+* @default_brightness_limit: The actual brightness is limited by this value
+*
+* Brightness limit to be used after the driver has been probed. This is useful
+* when it is not known how much power is available for the backlight during
+* probe.
+* Valid range 0-63. Can be changed later with pcf50633_bl_set_brightness_limit.
+*
+* @ramp_time: Display ramp time when changing brightness
+*
+* When changing the backlights brightness the change is not instant, instead
+* it fades smooth from one state to another. This value specifies how long
+* the fade should take. The lower the value the higher the fade time.
+* Valid range 0-255
+*/
+struct pcf50633_bl_platform_data {
+       unsigned int    default_brightness;
+       unsigned int    default_brightness_limit;
+       uint8_t         ramp_time;
+};
+
+
+struct pcf50633;
+
+int pcf50633_bl_set_brightness_limit(struct pcf50633 *pcf, unsigned int limit);
+
+#endif
+
index 3398bd9aab1199a859559bc5acf7d99300cf6e5c..ad411a78870ce042b99dd35d2e3f25fc10657c16 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
 #include <linux/power_supply.h>
+#include <linux/mfd/pcf50633/backlight.h>
 
 struct pcf50633;
 
@@ -43,6 +44,8 @@ struct pcf50633_platform_data {
        void (*force_shutdown)(struct pcf50633 *);
 
        u8 resumers[5];
+
+       struct pcf50633_bl_platform_data *backlight_data;
 };
 
 struct pcf50633_irq {
@@ -152,6 +155,7 @@ struct pcf50633 {
        struct platform_device *mbc_pdev;
        struct platform_device *adc_pdev;
        struct platform_device *input_pdev;
+       struct platform_device *bl_pdev;
        struct platform_device *regulator_pdev[PCF50633_NUM_REGULATORS];
 };
 
index 3bcd7163485c7b37ace3f4aaad05d97e7bfa6ca0..49067802a6d77e0ec347d3ef8a102b9ccd1a0352 100644 (file)
@@ -1,7 +1,13 @@
 #ifndef __SH_MOBILE_SDHI_H__
 #define __SH_MOBILE_SDHI_H__
 
+#include <linux/types.h>
+
 struct sh_mobile_sdhi_info {
+       int dma_slave_tx;
+       int dma_slave_rx;
+       unsigned long tmio_flags;
+       u32 tmio_ocr_mask;      /* available MMC voltages */
        void (*set_pwr)(struct platform_device *pdev, int state);
 };
 
index c3f7dff8effc08691c691f72657d904e9bd604ab..f07425bc3dcdef6fa37f8bc8f7237e0e41971727 100644 (file)
                tmio_iowrite16((val) >> 16, (base) + ((reg + 2) << (shift))); \
        } while (0)
 
+/* tmio MMC platform flags */
+#define TMIO_MMC_WRPROTECT_DISABLE     (1 << 0)
+
 int tmio_core_mmc_enable(void __iomem *cnf, int shift, unsigned long base);
 int tmio_core_mmc_resume(void __iomem *cnf, int shift, unsigned long base);
 void tmio_core_mmc_pwr(void __iomem *cnf, int shift, int state);
 void tmio_core_mmc_clk_div(void __iomem *cnf, int shift, int state);
 
+struct tmio_mmc_dma {
+       void *chan_priv_tx;
+       void *chan_priv_rx;
+};
+
 /*
  * data for the MMC controller
  */
 struct tmio_mmc_data {
        unsigned int                    hclk;
        unsigned long                   capabilities;
+       unsigned long                   flags;
+       u32                             ocr_mask;       /* available voltages */
+       struct tmio_mmc_dma             *dma;
        void (*set_pwr)(struct platform_device *host, int state);
        void (*set_clk_div)(struct platform_device *host, int state);
 };
index 7f085c97c799dac22dadaf9844ae31424e14816d..7238231b8dd40194e980dad7683c854fd88a6047 100644 (file)
@@ -9,7 +9,7 @@ typedef struct page *new_page_t(struct page *, unsigned long private, int **);
 #ifdef CONFIG_MIGRATION
 #define PAGE_MIGRATION 1
 
-extern int putback_lru_pages(struct list_head *l);
+extern void putback_lru_pages(struct list_head *l);
 extern int migrate_page(struct address_space *,
                        struct page *, struct page *);
 extern int migrate_pages(struct list_head *l, new_page_t x,
@@ -19,17 +19,19 @@ extern int fail_migrate_page(struct address_space *,
                        struct page *, struct page *);
 
 extern int migrate_prep(void);
+extern int migrate_prep_local(void);
 extern int migrate_vmas(struct mm_struct *mm,
                const nodemask_t *from, const nodemask_t *to,
                unsigned long flags);
 #else
 #define PAGE_MIGRATION 0
 
-static inline int putback_lru_pages(struct list_head *l) { return 0; }
+static inline void putback_lru_pages(struct list_head *l) {}
 static inline int migrate_pages(struct list_head *l, new_page_t x,
                unsigned long private, int offlining) { return -ENOSYS; }
 
 static inline int migrate_prep(void) { return -ENOSYS; }
+static inline int migrate_prep_local(void) { return -ENOSYS; }
 
 static inline int migrate_vmas(struct mm_struct *mm,
                const nodemask_t *from, const nodemask_t *to,
index 8b5f7cc0fba6cd9f5f69f5521d00c788c2fe0dc9..b631c46cffd9c4fe52cf7c5bb5a5db7c88223d0a 100644 (file)
@@ -31,6 +31,8 @@
 #define FUSE_MINOR             229
 #define KVM_MINOR              232
 #define VHOST_NET_MINOR                233
+#define BTRFS_MINOR            234
+#define AUTOFS_MINOR           235
 #define MISC_DYNAMIC_MINOR     255
 
 struct device;
index fb19bb92b809d81564cf03af26f5a568f2994629..b969efb03787ee69546995ad378ac54b6bc37e3b 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/debug_locks.h>
 #include <linux/mm_types.h>
 #include <linux/range.h>
+#include <linux/pfn.h>
 
 struct mempolicy;
 struct anon_vma;
@@ -106,6 +107,9 @@ extern unsigned int kobjsize(const void *objp);
 #define VM_PFN_AT_MMAP 0x40000000      /* PFNMAP vma that is fully mapped at mmap time */
 #define VM_MERGEABLE   0x80000000      /* KSM may merge identical pages */
 
+/* Bits set in the VMA until the stack is in its final location */
+#define VM_STACK_INCOMPLETE_SETUP      (VM_RAND_READ | VM_SEQ_READ)
+
 #ifndef VM_STACK_DEFAULT_FLAGS         /* arch can override this */
 #define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS
 #endif
@@ -334,6 +338,7 @@ void put_page(struct page *page);
 void put_pages_list(struct list_head *pages);
 
 void split_page(struct page *page, unsigned int order);
+int split_free_page(struct page *page);
 
 /*
  * Compound pages have a destructor function.  Provide a
@@ -591,7 +596,7 @@ static inline void set_page_links(struct page *page, enum zone_type zone,
 
 static __always_inline void *lowmem_page_address(struct page *page)
 {
-       return __va(page_to_pfn(page) << PAGE_SHIFT);
+       return __va(PFN_PHYS(page_to_pfn(page)));
 }
 
 #if defined(CONFIG_HIGHMEM) && !defined(WANT_PAGE_VIRTUAL)
index 43eaf5ca58481a732a96e80507ead6246ed3d9c2..f65913c9f5a4001f5e53207c5f4a04e61f332ff7 100644 (file)
@@ -108,6 +108,9 @@ struct mmc_host_ops {
        int     (*get_cd)(struct mmc_host *host);
 
        void    (*enable_sdio_irq)(struct mmc_host *host, int enable);
+
+       /* optional callback for HC quirks */
+       void    (*init_card)(struct mmc_host *host, struct mmc_card *card);
 };
 
 struct mmc_card;
@@ -227,7 +230,7 @@ static inline void *mmc_priv(struct mmc_host *host)
 #define mmc_classdev(x)        (&(x)->class_dev)
 #define mmc_hostname(x)        (dev_name(&(x)->class_dev))
 
-extern int mmc_suspend_host(struct mmc_host *, pm_message_t);
+extern int mmc_suspend_host(struct mmc_host *);
 extern int mmc_resume_host(struct mmc_host *);
 
 extern void mmc_power_save_host(struct mmc_host *host);
diff --git a/include/linux/mmc/sdhci-spear.h b/include/linux/mmc/sdhci-spear.h
new file mode 100644 (file)
index 0000000..9188c97
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * include/linux/mmc/sdhci-spear.h
+ *
+ * SDHCI declarations specific to ST SPEAr platform
+ *
+ * Copyright (C) 2010 ST Microelectronics
+ * Viresh Kumar<viresh.kumar@st.com>
+ *
+ * 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.
+ */
+
+#ifndef MMC_SDHCI_SPEAR_H
+#define MMC_SDHCI_SPEAR_H
+
+#include <linux/platform_device.h>
+/*
+ * struct sdhci_plat_data: spear sdhci platform data structure
+ *
+ * @card_power_gpio: gpio pin for enabling/disabling power to sdhci socket
+ * @power_active_high: if set, enable power to sdhci socket by setting
+ *                     card_power_gpio
+ * @power_always_enb: If set, then enable power on probe, otherwise enable only
+ *                     on card insertion and disable on card removal.
+ * card_int_gpio: gpio pin used for card detection
+ */
+struct sdhci_plat_data {
+       int card_power_gpio;
+       int power_active_high;
+       int power_always_enb;
+       int card_int_gpio;
+};
+
+/* This function is used to set platform_data field of pdev->dev */
+static inline void
+sdhci_set_plat_data(struct platform_device *pdev, struct sdhci_plat_data *data)
+{
+       pdev->dev.platform_data = data;
+}
+
+#endif /* MMC_SDHCI_SPEAR_H */
index c6c0cceba5fe735a0719cdfc615a6cf89171b186..31baaf82f4583a06d5144ef0b304d5ecbc907563 100644 (file)
@@ -145,6 +145,9 @@ extern void sdio_writew(struct sdio_func *func, u16 b,
 extern void sdio_writel(struct sdio_func *func, u32 b,
        unsigned int addr, int *err_ret);
 
+extern u8 sdio_writeb_readb(struct sdio_func *func, u8 write_byte,
+       unsigned int addr, int *err_ret);
+
 extern int sdio_memcpy_toio(struct sdio_func *func, unsigned int addr,
        void *src, int count);
 extern int sdio_writesb(struct sdio_func *func, unsigned int addr,
diff --git a/include/linux/mmc/sh_mmcif.h b/include/linux/mmc/sh_mmcif.h
new file mode 100644 (file)
index 0000000..aafe832
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * include/linux/mmc/sh_mmcif.h
+ *
+ * platform data for eMMC driver
+ *
+ * Copyright (C) 2010 Renesas Solutions 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; either version 2 of the License.
+ *
+ */
+
+#ifndef __SH_MMCIF_H__
+#define __SH_MMCIF_H__
+
+/*
+ * MMCIF : CE_CLK_CTRL [19:16]
+ * 1000 : Peripheral clock / 512
+ * 0111 : Peripheral clock / 256
+ * 0110 : Peripheral clock / 128
+ * 0101 : Peripheral clock / 64
+ * 0100 : Peripheral clock / 32
+ * 0011 : Peripheral clock / 16
+ * 0010 : Peripheral clock / 8
+ * 0001 : Peripheral clock / 4
+ * 0000 : Peripheral clock / 2
+ * 1111 : Peripheral clock (sup_pclk set '1')
+ */
+
+struct sh_mmcif_plat_data {
+       void (*set_pwr)(struct platform_device *pdev, int state);
+       void (*down_pwr)(struct platform_device *pdev);
+       u8      sup_pclk;       /* 1 :SH7757, 0: SH7724/SH7372 */
+       unsigned long caps;
+       u32     ocr;
+};
+
+#endif /* __SH_MMCIF_H__ */
index cf9e458e96b0e4237260a533cad7a7c8e9d26f1a..b4d109e389b806f205aa1575135001e09a864bf5 100644 (file)
@@ -321,6 +321,15 @@ struct zone {
        unsigned long           *pageblock_flags;
 #endif /* CONFIG_SPARSEMEM */
 
+#ifdef CONFIG_COMPACTION
+       /*
+        * On compaction failure, 1<<compact_defer_shift compactions
+        * are skipped before trying again. The number attempted since
+        * last failure is tracked with compact_considered.
+        */
+       unsigned int            compact_considered;
+       unsigned int            compact_defer_shift;
+#endif
 
        ZONE_PADDING(_pad1_)
 
@@ -641,9 +650,10 @@ typedef struct pglist_data {
 
 #include <linux/memory_hotplug.h>
 
+extern struct mutex zonelists_mutex;
 void get_zone_counts(unsigned long *active, unsigned long *inactive,
                        unsigned long *free);
-void build_all_zonelists(void);
+void build_all_zonelists(void *data);
 void wakeup_kswapd(struct zone *zone, int order);
 int zone_watermark_ok(struct zone *z, int order, unsigned long mark,
                int classzone_idx, int alloc_flags);
@@ -661,6 +671,12 @@ void memory_present(int nid, unsigned long start, unsigned long end);
 static inline void memory_present(int nid, unsigned long start, unsigned long end) {}
 #endif
 
+#ifdef CONFIG_HAVE_MEMORYLESS_NODES
+int local_memory_node(int node_id);
+#else
+static inline int local_memory_node(int node_id) { return node_id; };
+#endif
+
 #ifdef CONFIG_NEED_NODE_MEMMAP_SIZE
 unsigned long __init node_memmap_size_bytes(int, unsigned long, unsigned long);
 #endif
@@ -972,7 +988,7 @@ struct mem_section {
 #endif
 
 #define SECTION_NR_TO_ROOT(sec)        ((sec) / SECTIONS_PER_ROOT)
-#define NR_SECTION_ROOTS       (NR_MEM_SECTIONS / SECTIONS_PER_ROOT)
+#define NR_SECTION_ROOTS       DIV_ROUND_UP(NR_MEM_SECTIONS, SECTIONS_PER_ROOT)
 #define SECTION_ROOT_MASK      (SECTIONS_PER_ROOT - 1)
 
 #ifdef CONFIG_SPARSEMEM_EXTREME
index 007fbaafead0843aa3f125e805549926be249b01..48c007dae4765851ae1657b6bcce3dc4b8fe542f 100644 (file)
@@ -509,4 +509,11 @@ struct zorro_device_id {
 
 #define ZORRO_DEVICE_MODALIAS_FMT      "zorro:i%08X"
 
+#define ISAPNP_ANY_ID          0xffff
+struct isapnp_device_id {
+       unsigned short card_vendor, card_device;
+       unsigned short vendor, function;
+       kernel_ulong_t driver_data;     /* data private to the driver */
+};
+
 #endif /* LINUX_MOD_DEVICETABLE_H */
index 30b06c89394482f86955dfa69f8a9f912e98388d..4522aed00906c81f885eae6ed5c0ecd9f399bde8 100644 (file)
@@ -210,7 +210,7 @@ int ncp_date_dos2unix(__le16 time, __le16 date);
 void ncp_date_unix2dos(int unix_date, __le16 * time, __le16 * date);
 
 /* linux/fs/ncpfs/ioctl.c */
-int ncp_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+long ncp_ioctl(struct file *, unsigned int, unsigned long);
 long ncp_compat_ioctl(struct file *, unsigned int, unsigned long);
 
 /* linux/fs/ncpfs/sock.c */
index a1bff65181669f36fe2b16a8990072e30ef74314..40291f3750247dfa12102178a6aed457e7735516 100644 (file)
@@ -1407,17 +1407,25 @@ struct softnet_data {
        struct softnet_data     *rps_ipi_next;
        unsigned int            cpu;
        unsigned int            input_queue_head;
+       unsigned int            input_queue_tail;
 #endif
        unsigned                dropped;
        struct sk_buff_head     input_pkt_queue;
        struct napi_struct      backlog;
 };
 
-static inline void input_queue_head_add(struct softnet_data *sd,
-                                       unsigned int len)
+static inline void input_queue_head_incr(struct softnet_data *sd)
 {
 #ifdef CONFIG_RPS
-       sd->input_queue_head += len;
+       sd->input_queue_head++;
+#endif
+}
+
+static inline void input_queue_tail_incr_save(struct softnet_data *sd,
+                                             unsigned int *qtail)
+{
+#ifdef CONFIG_RPS
+       *qtail = ++sd->input_queue_tail;
 #endif
 }
 
@@ -2326,7 +2334,7 @@ do {                                                              \
 #define netif_vdbg(priv, type, dev, format, args...)           \
 ({                                                             \
        if (0)                                                  \
-               netif_printk(KERN_DEBUG, dev, format, ##args);  \
+               netif_printk(priv, type, KERN_DEBUG, dev, format, ##args); \
        0;                                                      \
 })
 #endif
index c2ee5d8550cf13bc84ac69fde5733b3ddf631577..c00cc0c4d0b7c29614bbafdfabe73828a04a0fbd 100644 (file)
@@ -333,7 +333,7 @@ struct xt_target {
        /* Called when user tries to insert an entry of this type:
            hook_mask is a bitmask of hooks from which it can be
            called. */
-       /* Should return true or false, or an error code (-Exxxx). */
+       /* Should return 0 on success or an error code otherwise (-Exxxx). */
        int (*checkentry)(const struct xt_tgchk_param *);
 
        /* Called when entry of this type deleted. */
index 7c36096223340a1d674b253430e5128b71f7abaa..540703b555cb2be4bbea2d8e7f0b84d96ca3b474 100644 (file)
@@ -164,7 +164,10 @@ extern int __srcu_notifier_call_chain(struct srcu_notifier_head *nh,
 /* Encapsulate (negative) errno value (in particular, NOTIFY_BAD <=> EPERM). */
 static inline int notifier_from_errno(int err)
 {
-       return NOTIFY_STOP_MASK | (NOTIFY_OK - err);
+       if (err)
+               return NOTIFY_STOP_MASK | (NOTIFY_OK - err);
+
+       return NOTIFY_OK;
 }
 
 /* Restore (negative) errno value from notify return value. */
index d3a74e00a3e13455b7ad7f6eec81d58727e40386..11651facc5f179237500ea4d43e3bcc76bfe270d 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _LINUX_OF_DEVICE_H
 #define _LINUX_OF_DEVICE_H
 
+#ifdef CONFIG_OF_DEVICE
 #include <linux/device.h>
 #include <linux/of.h>
 #include <linux/mod_devicetable.h>
@@ -10,7 +11,7 @@
 #define        to_of_device(d) container_of(d, struct of_device, dev)
 
 extern const struct of_device_id *of_match_device(
-       const struct of_device_id *matches, const struct of_device *dev);
+       const struct of_device_id *matches, const struct device *dev);
 
 extern struct of_device *of_dev_get(struct of_device *dev);
 extern void of_dev_put(struct of_device *dev);
@@ -26,5 +27,6 @@ static inline void of_device_free(struct of_device *dev)
 
 extern ssize_t of_device_get_modalias(struct of_device *ofdev,
                                        char *str, ssize_t len);
+#endif /* CONFIG_OF_DEVICE */
 
 #endif /* _LINUX_OF_DEVICE_H */
index a1ca92ccb0ff65dc06241ab2ac7bb04bf44c7f92..71e1a916d3fa9d6fbd6876a7aacc695711123a40 100644 (file)
@@ -57,6 +57,7 @@ struct boot_param_header {
        __be32  dt_struct_size;         /* size of the DT structure block */
 };
 
+#if defined(CONFIG_OF_FLATTREE)
 /* TBD: Temporary export of fdt globals - remove when code fully merged */
 extern int __initdata dt_root_addr_cells;
 extern int __initdata dt_root_size_cells;
@@ -98,6 +99,9 @@ extern int early_init_dt_scan_root(unsigned long node, const char *uname,
 /* Other Prototypes */
 extern void unflatten_device_tree(void);
 extern void early_init_devtree(void *);
+#else /* CONFIG_OF_FLATTREE */
+static inline void unflatten_device_tree(void) {}
+#endif /* CONFIG_OF_FLATTREE */
 
 #endif /* __ASSEMBLY__ */
 #endif /* _LINUX_OF_FDT_H */
index 908406651330e700bbea64084599d023fa77cad7..1643d3761eb4134897b956bed7844b05814fd662 100644 (file)
@@ -11,6 +11,7 @@
  *
  */
 
+#ifdef CONFIG_OF_DEVICE
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/mod_devicetable.h>
@@ -30,10 +31,6 @@ extern struct bus_type of_platform_bus_type;
  */
 struct of_platform_driver
 {
-       const char              *name;
-       const struct of_device_id       *match_table;
-       struct module           *owner;
-
        int     (*probe)(struct of_device* dev,
                         const struct of_device_id *match);
        int     (*remove)(struct of_device* dev);
@@ -66,5 +63,6 @@ static inline void of_unregister_platform_driver(struct of_platform_driver *drv)
 extern struct of_device *of_find_device_by_node(struct device_node *np);
 
 extern int of_bus_type_init(struct bus_type *bus, const char *name);
+#endif /* CONFIG_OF_DEVICE */
 
 #endif /* _LINUX_OF_PLATFORM_H */
index aef22ae2af473f4113bf19560d1b441395a458da..5bb13b3db84d46ee155784a26acfd850e94c91ff 100644 (file)
@@ -40,6 +40,7 @@ enum {
        PCG_USED, /* this object is in use. */
        PCG_ACCT_LRU, /* page has been accounted for */
        PCG_FILE_MAPPED, /* page is accounted as "mapped" */
+       PCG_MIGRATION, /* under page migration */
 };
 
 #define TESTPCGFLAG(uname, lname)                      \
@@ -79,6 +80,10 @@ SETPCGFLAG(FileMapped, FILE_MAPPED)
 CLEARPCGFLAG(FileMapped, FILE_MAPPED)
 TESTPCGFLAG(FileMapped, FILE_MAPPED)
 
+SETPCGFLAG(Migration, MIGRATION)
+CLEARPCGFLAG(Migration, MIGRATION)
+TESTPCGFLAG(Migration, MIGRATION)
+
 static inline int page_cgroup_nid(struct page_cgroup *pc)
 {
        return page_to_nid(pc->page);
index a788fa12ff310b7831587ebc4565e01d5e76d726..6a471aba3b07aced498219d4e39498e6d577bfc0 100644 (file)
@@ -311,7 +311,8 @@ struct pci_dev {
        unsigned int    is_virtfn:1;
        unsigned int    reset_fn:1;
        unsigned int    is_hotplug_bridge:1;
-       unsigned int    aer_firmware_first:1;
+       unsigned int    __aer_firmware_first_valid:1;
+       unsigned int    __aer_firmware_first:1;
        pci_dev_flags_t dev_flags;
        atomic_t        enable_cnt;     /* pci_enable_device has been called */
 
@@ -334,6 +335,16 @@ struct pci_dev {
 #endif
 };
 
+static inline struct pci_dev *pci_physfn(struct pci_dev *dev)
+{
+#ifdef CONFIG_PCI_IOV
+       if (dev->is_virtfn)
+               dev = dev->physfn;
+#endif
+
+       return dev;
+}
+
 extern struct pci_dev *alloc_pci_dev(void);
 
 #define pci_dev_b(n) list_entry(n, struct pci_dev, bus_list)
index 9f688d243b8628d40aa4039f5a8c5fd2c9cad61d..ae66851870becb2e496d7994f7a11a548aac16d8 100644 (file)
 #define PCI_DEVICE_ID_INTEL_82845_HB   0x1a30
 #define PCI_DEVICE_ID_INTEL_IOAT       0x1a38
 #define PCI_DEVICE_ID_INTEL_CPT_SMBUS  0x1c22
-#define PCI_DEVICE_ID_INTEL_CPT_LPC1   0x1c42
-#define PCI_DEVICE_ID_INTEL_CPT_LPC2   0x1c43
+#define PCI_DEVICE_ID_INTEL_CPT_LPC_MIN        0x1c41
+#define PCI_DEVICE_ID_INTEL_CPT_LPC_MAX        0x1c5f
 #define PCI_DEVICE_ID_INTEL_82801AA_0  0x2410
 #define PCI_DEVICE_ID_INTEL_82801AA_1  0x2411
 #define PCI_DEVICE_ID_INTEL_82801AA_3  0x2413
index c4c3d68be19ad150561d9e885bd35cb0d0825993..455b9ccdfca7679349dc4786d3de6ed6493e3c1e 100644 (file)
 #define PCI_ERR_ROOT_FIRST_FATAL       0x00000010      /* First Fatal */
 #define PCI_ERR_ROOT_NONFATAL_RCV      0x00000020      /* Non-Fatal Received */
 #define PCI_ERR_ROOT_FATAL_RCV         0x00000040      /* Fatal Received */
-#define PCI_ERR_ROOT_COR_SRC   52
-#define PCI_ERR_ROOT_SRC       54
+#define PCI_ERR_ROOT_ERR_SRC   52      /* Error Source Identification */
 
 /* Virtual Channel */
 #define PCI_VC_PORT_REG1       4
index d4cf7a2ceb3edfc7779cb4f10c76de5825288317..c9e4d814ff7795414b028ee7ebcd7ed46fcdddef 100644 (file)
@@ -24,6 +24,8 @@ struct pda_power_pdata {
        int (*is_usb_online)(void);
        void (*set_charge)(int flags);
        void (*exit)(struct device *dev);
+       int (*suspend)(pm_message_t state);
+       int (*resume)(void);
 
        char **supplied_to;
        size_t num_supplicants;
index 3fd5c82e0e184c0690d8e62a2a459ad2dea279da..fb6c91eac7e3eb7cef23b2be992a0ed6eece85a0 100644 (file)
@@ -485,6 +485,7 @@ struct perf_guest_info_callbacks {
 #include <linux/ftrace.h>
 #include <linux/cpu.h>
 #include <asm/atomic.h>
+#include <asm/local.h>
 
 #define PERF_MAX_STACK_DEPTH           255
 
@@ -587,21 +588,19 @@ struct perf_mmap_data {
        struct rcu_head                 rcu_head;
 #ifdef CONFIG_PERF_USE_VMALLOC
        struct work_struct              work;
+       int                             page_order;     /* allocation order  */
 #endif
-       int                             data_order;
        int                             nr_pages;       /* nr of data pages  */
        int                             writable;       /* are we writable   */
        int                             nr_locked;      /* nr pages mlocked  */
 
        atomic_t                        poll;           /* POLL_ for wakeups */
-       atomic_t                        events;         /* event_id limit       */
 
-       atomic_long_t                   head;           /* write position    */
-       atomic_long_t                   done_head;      /* completed head    */
-
-       atomic_t                        lock;           /* concurrent writes */
-       atomic_t                        wakeup;         /* needs a wakeup    */
-       atomic_t                        lost;           /* nr records lost   */
+       local_t                         head;           /* write position    */
+       local_t                         nest;           /* nested writers    */
+       local_t                         events;         /* event limit       */
+       local_t                         wakeup;         /* wakeup stamp      */
+       local_t                         lost;           /* nr records lost   */
 
        long                            watermark;      /* wakeup watermark  */
 
@@ -728,6 +727,7 @@ struct perf_event {
        perf_overflow_handler_t         overflow_handler;
 
 #ifdef CONFIG_EVENT_TRACING
+       struct ftrace_event_call        *tp_event;
        struct event_filter             *filter;
 #endif
 
@@ -803,11 +803,12 @@ struct perf_cpu_context {
 struct perf_output_handle {
        struct perf_event               *event;
        struct perf_mmap_data           *data;
-       unsigned long                   head;
-       unsigned long                   offset;
+       unsigned long                   wakeup;
+       unsigned long                   size;
+       void                            *addr;
+       int                             page;
        int                             nmi;
        int                             sample;
-       int                             locked;
 };
 
 #ifdef CONFIG_PERF_EVENTS
@@ -993,8 +994,9 @@ static inline bool perf_paranoid_kernel(void)
 }
 
 extern void perf_event_init(void);
-extern void perf_tp_event(int event_id, u64 addr, u64 count, void *record,
-                         int entry_size, struct pt_regs *regs);
+extern void perf_tp_event(u64 addr, u64 count, void *record,
+                         int entry_size, struct pt_regs *regs,
+                         struct hlist_head *head);
 extern void perf_bp_event(struct perf_event *event, void *data);
 
 #ifndef perf_misc_flags
index ebd2b8fb00d0269bb1850630d55e50c50a652d06..30083a896f3628418fa42114a582dc18396c66e9 100644 (file)
@@ -114,6 +114,7 @@ enum power_supply_property {
        POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
        POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
        POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
+       POWER_SUPPLY_PROP_TYPE, /* use power_supply.type instead */
        /* Properties of type `const char *' */
        POWER_SUPPLY_PROP_MODEL_NAME,
        POWER_SUPPLY_PROP_MANUFACTURER,
@@ -144,6 +145,11 @@ struct power_supply {
        int (*get_property)(struct power_supply *psy,
                            enum power_supply_property psp,
                            union power_supply_propval *val);
+       int (*set_property)(struct power_supply *psy,
+                           enum power_supply_property psp,
+                           const union power_supply_propval *val);
+       int (*property_is_writeable)(struct power_supply *psy,
+                                    enum power_supply_property psp);
        void (*external_power_changed)(struct power_supply *psy);
        void (*set_charged)(struct power_supply *psy);
 
index 7126a15467f19a1238cabdc3b9eccc237b9d0ad9..94c1f03b50eb959302044572fecb1872295ba116 100644 (file)
@@ -174,8 +174,7 @@ enum {
 #include <linux/rwsem.h>
 #include <linux/spinlock.h>
 #include <linux/wait.h>
-#include <linux/percpu.h>
-#include <linux/smp.h>
+#include <linux/percpu_counter.h>
 
 #include <linux/dqblk_xfs.h>
 #include <linux/dqblk_v1.h>
@@ -254,6 +253,7 @@ enum {
 
 struct dqstats {
        int stat[_DQST_DQSTAT_LAST];
+       struct percpu_counter counter[_DQST_DQSTAT_LAST];
 };
 
 extern struct dqstats *dqstats_pcpu;
@@ -261,20 +261,12 @@ extern struct dqstats dqstats;
 
 static inline void dqstats_inc(unsigned int type)
 {
-#ifdef CONFIG_SMP
-       per_cpu_ptr(dqstats_pcpu, smp_processor_id())->stat[type]++;
-#else
-       dqstats.stat[type]++;
-#endif
+       percpu_counter_inc(&dqstats.counter[type]);
 }
 
 static inline void dqstats_dec(unsigned int type)
 {
-#ifdef CONFIG_SMP
-       per_cpu_ptr(dqstats_pcpu, smp_processor_id())->stat[type]--;
-#else
-       dqstats.stat[type]--;
-#endif
+       percpu_counter_dec(&dqstats.counter[type]);
 }
 
 #define DQ_MOD_B       0       /* dquot modified since read */
@@ -332,8 +324,8 @@ struct dquot_operations {
 
 /* Operations handling requests from userspace */
 struct quotactl_ops {
-       int (*quota_on)(struct super_block *, int, int, char *, int);
-       int (*quota_off)(struct super_block *, int, int);
+       int (*quota_on)(struct super_block *, int, int, char *);
+       int (*quota_off)(struct super_block *, int);
        int (*quota_sync)(struct super_block *, int, int);
        int (*get_info)(struct super_block *, int, struct if_dqinfo *);
        int (*set_info)(struct super_block *, int, struct if_dqinfo *);
index 370abb1e99cbda13b2615e8353cf5d8a67e41caf..aa36793b48bd11b80b4b33765c7b7d074a899e7f 100644 (file)
@@ -9,6 +9,10 @@
 
 #include <linux/fs.h>
 
+#define DQUOT_SPACE_WARN       0x1
+#define DQUOT_SPACE_RESERVE    0x2
+#define DQUOT_SPACE_NOFAIL     0x4
+
 static inline struct quota_info *sb_dqopt(struct super_block *sb)
 {
        return &sb->s_dquot;
@@ -41,15 +45,22 @@ int dquot_scan_active(struct super_block *sb,
 struct dquot *dquot_alloc(struct super_block *sb, int type);
 void dquot_destroy(struct dquot *dquot);
 
-int __dquot_alloc_space(struct inode *inode, qsize_t number,
-               int warn, int reserve);
-void __dquot_free_space(struct inode *inode, qsize_t number, int reserve);
+int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags);
+void __dquot_free_space(struct inode *inode, qsize_t number, int flags);
 
 int dquot_alloc_inode(const struct inode *inode);
 
 int dquot_claim_space_nodirty(struct inode *inode, qsize_t number);
 void dquot_free_inode(const struct inode *inode);
 
+int dquot_disable(struct super_block *sb, int type, unsigned int flags);
+/* Suspend quotas on remount RO */
+static inline int dquot_suspend(struct super_block *sb, int type)
+{
+       return dquot_disable(sb, type, DQUOT_SUSPENDED);
+}
+int dquot_resume(struct super_block *sb, int type);
+
 int dquot_commit(struct dquot *dquot);
 int dquot_acquire(struct dquot *dquot);
 int dquot_release(struct dquot *dquot);
@@ -58,27 +69,25 @@ int dquot_mark_dquot_dirty(struct dquot *dquot);
 
 int dquot_file_open(struct inode *inode, struct file *file);
 
-int vfs_quota_on(struct super_block *sb, int type, int format_id,
-       char *path, int remount);
-int vfs_quota_enable(struct inode *inode, int type, int format_id,
+int dquot_quota_on(struct super_block *sb, int type, int format_id,
+       char *path);
+int dquot_enable(struct inode *inode, int type, int format_id,
        unsigned int flags);
-int vfs_quota_on_path(struct super_block *sb, int type, int format_id,
+int dquot_quota_on_path(struct super_block *sb, int type, int format_id,
        struct path *path);
-int vfs_quota_on_mount(struct super_block *sb, char *qf_name,
+int dquot_quota_on_mount(struct super_block *sb, char *qf_name,
        int format_id, int type);
-int vfs_quota_off(struct super_block *sb, int type, int remount);
-int vfs_quota_disable(struct super_block *sb, int type, unsigned int flags);
-int vfs_quota_sync(struct super_block *sb, int type, int wait);
-int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
-int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
-int vfs_get_dqblk(struct super_block *sb, int type, qid_t id,
+int dquot_quota_off(struct super_block *sb, int type);
+int dquot_quota_sync(struct super_block *sb, int type, int wait);
+int dquot_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
+int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
+int dquot_get_dqblk(struct super_block *sb, int type, qid_t id,
                struct fs_disk_quota *di);
-int vfs_set_dqblk(struct super_block *sb, int type, qid_t id,
+int dquot_set_dqblk(struct super_block *sb, int type, qid_t id,
                struct fs_disk_quota *di);
 
 int __dquot_transfer(struct inode *inode, struct dquot **transfer_to);
 int dquot_transfer(struct inode *inode, struct iattr *iattr);
-int vfs_dq_quota_on_remount(struct super_block *sb);
 
 static inline struct mem_dqinfo *sb_dqinfo(struct super_block *sb, int type)
 {
@@ -145,20 +154,7 @@ static inline unsigned sb_any_quota_active(struct super_block *sb)
  * Operations supported for diskquotas.
  */
 extern const struct dquot_operations dquot_operations;
-extern const struct quotactl_ops vfs_quotactl_ops;
-
-#define sb_dquot_ops (&dquot_operations)
-#define sb_quotactl_ops (&vfs_quotactl_ops)
-
-/* Cannot be called inside a transaction */
-static inline int vfs_dq_off(struct super_block *sb, int remount)
-{
-       int ret = -ENOSYS;
-
-       if (sb->s_qcop && sb->s_qcop->quota_off)
-               ret = sb->s_qcop->quota_off(sb, -1, remount);
-       return ret;
-}
+extern const struct quotactl_ops dquot_quotactl_ops;
 
 #else
 
@@ -203,12 +199,6 @@ static inline int sb_any_quota_active(struct super_block *sb)
        return 0;
 }
 
-/*
- * NO-OP when quota not configured.
- */
-#define sb_dquot_ops                           (NULL)
-#define sb_quotactl_ops                                (NULL)
-
 static inline void dquot_initialize(struct inode *inode)
 {
 }
@@ -226,39 +216,45 @@ static inline void dquot_free_inode(const struct inode *inode)
 {
 }
 
-static inline int vfs_dq_off(struct super_block *sb, int remount)
+static inline int dquot_transfer(struct inode *inode, struct iattr *iattr)
 {
        return 0;
 }
 
-static inline int vfs_dq_quota_on_remount(struct super_block *sb)
+static inline int __dquot_alloc_space(struct inode *inode, qsize_t number,
+               int flags)
 {
+       if (!(flags & DQUOT_SPACE_RESERVE))
+               inode_add_bytes(inode, number);
        return 0;
 }
 
-static inline int dquot_transfer(struct inode *inode, struct iattr *iattr)
+static inline void __dquot_free_space(struct inode *inode, qsize_t number,
+               int flags)
+{
+       if (!(flags & DQUOT_SPACE_RESERVE))
+               inode_sub_bytes(inode, number);
+}
+
+static inline int dquot_claim_space_nodirty(struct inode *inode, qsize_t number)
 {
+       inode_add_bytes(inode, number);
        return 0;
 }
 
-static inline int __dquot_alloc_space(struct inode *inode, qsize_t number,
-               int warn, int reserve)
+static inline int dquot_disable(struct super_block *sb, int type,
+               unsigned int flags)
 {
-       if (!reserve)
-               inode_add_bytes(inode, number);
        return 0;
 }
 
-static inline void __dquot_free_space(struct inode *inode, qsize_t number,
-               int reserve)
+static inline int dquot_suspend(struct super_block *sb, int type)
 {
-       if (!reserve)
-               inode_sub_bytes(inode, number);
+       return 0;
 }
 
-static inline int dquot_claim_space_nodirty(struct inode *inode, qsize_t number)
+static inline int dquot_resume(struct super_block *sb, int type)
 {
-       inode_add_bytes(inode, number);
        return 0;
 }
 
@@ -268,7 +264,13 @@ static inline int dquot_claim_space_nodirty(struct inode *inode, qsize_t number)
 
 static inline int dquot_alloc_space_nodirty(struct inode *inode, qsize_t nr)
 {
-       return __dquot_alloc_space(inode, nr, 1, 0);
+       return __dquot_alloc_space(inode, nr, DQUOT_SPACE_WARN);
+}
+
+static inline void dquot_alloc_space_nofail(struct inode *inode, qsize_t nr)
+{
+       __dquot_alloc_space(inode, nr, DQUOT_SPACE_WARN|DQUOT_SPACE_NOFAIL);
+       mark_inode_dirty(inode);
 }
 
 static inline int dquot_alloc_space(struct inode *inode, qsize_t nr)
@@ -286,6 +288,11 @@ static inline int dquot_alloc_block_nodirty(struct inode *inode, qsize_t nr)
        return dquot_alloc_space_nodirty(inode, nr << inode->i_blkbits);
 }
 
+static inline void dquot_alloc_block_nofail(struct inode *inode, qsize_t nr)
+{
+       dquot_alloc_space_nofail(inode, nr << inode->i_blkbits);
+}
+
 static inline int dquot_alloc_block(struct inode *inode, qsize_t nr)
 {
        return dquot_alloc_space(inode, nr << inode->i_blkbits);
@@ -293,7 +300,7 @@ static inline int dquot_alloc_block(struct inode *inode, qsize_t nr)
 
 static inline int dquot_prealloc_block_nodirty(struct inode *inode, qsize_t nr)
 {
-       return __dquot_alloc_space(inode, nr << inode->i_blkbits, 0, 0);
+       return __dquot_alloc_space(inode, nr << inode->i_blkbits, 0);
 }
 
 static inline int dquot_prealloc_block(struct inode *inode, qsize_t nr)
@@ -308,7 +315,8 @@ static inline int dquot_prealloc_block(struct inode *inode, qsize_t nr)
 
 static inline int dquot_reserve_block(struct inode *inode, qsize_t nr)
 {
-       return __dquot_alloc_space(inode, nr << inode->i_blkbits, 1, 1);
+       return __dquot_alloc_space(inode, nr << inode->i_blkbits,
+                               DQUOT_SPACE_WARN|DQUOT_SPACE_RESERVE);
 }
 
 static inline int dquot_claim_block(struct inode *inode, qsize_t nr)
@@ -345,7 +353,7 @@ static inline void dquot_free_block(struct inode *inode, qsize_t nr)
 static inline void dquot_release_reservation_block(struct inode *inode,
                qsize_t nr)
 {
-       __dquot_free_space(inode, nr << inode->i_blkbits, 1);
+       __dquot_free_space(inode, nr << inode->i_blkbits, DQUOT_SPACE_RESERVE);
 }
 
 #endif /* _LINUX_QUOTAOPS_ */
index 8600508c77a6e541ad30b54e152dd057f5cb6fc7..e7320b5e82fb4ac956f1cd0951488ddf1bc44637 100644 (file)
@@ -1,7 +1,8 @@
 #ifndef _LINUX_RAMFS_H
 #define _LINUX_RAMFS_H
 
-struct inode *ramfs_get_inode(struct super_block *sb, int mode, dev_t dev);
+struct inode *ramfs_get_inode(struct super_block *sb, const struct inode *dir,
+        int mode, dev_t dev);
 extern int ramfs_get_sb(struct file_system_type *fs_type,
         int flags, const char *dev_name, void *data, struct vfsmount *mnt);
 
index 25d02fe5c9b5a6561e19bd3410a4132ea98dffd8..fb7ab9de5f360878805779e489d1d35a2f205fa0 100644 (file)
@@ -40,6 +40,10 @@ struct rand_pool_info {
        __u32   buf[0];
 };
 
+struct rnd_state {
+       __u32 s1, s2, s3;
+};
+
 /* Exported functions */
 
 #ifdef __KERNEL__
@@ -74,6 +78,30 @@ unsigned long randomize_range(unsigned long start, unsigned long end, unsigned l
 u32 random32(void);
 void srandom32(u32 seed);
 
+u32 prandom32(struct rnd_state *);
+
+/*
+ * Handle minimum values for seeds
+ */
+static inline u32 __seed(u32 x, u32 m)
+{
+       return (x < m) ? x + m : x;
+}
+
+/**
+ * prandom32_seed - set seed for prandom32().
+ * @state: pointer to state structure to receive the seed.
+ * @seed: arbitrary 64-bit value to use as a seed.
+ */
+static inline void prandom32_seed(struct rnd_state *state, u64 seed)
+{
+       u32 i = (seed >> 32) ^ (seed << 10) ^ seed;
+
+       state->s1 = __seed(i, 1);
+       state->s2 = __seed(i, 7);
+       state->s3 = __seed(i, 15);
+}
+
 #endif /* __KERNEL___ */
 
 #endif /* _LINUX_RANDOM_H */
index 668cf1bef030ee2c38ca0de23575f815babea9d6..8f69d09a41a50265977c4e89c2ad13672d98a816 100644 (file)
@@ -2,7 +2,7 @@
 #define _LINUX_RATELIMIT_H
 
 #include <linux/param.h>
-#include <linux/spinlock_types.h>
+#include <linux/spinlock.h>
 
 #define DEFAULT_RATELIMIT_INTERVAL     (5 * HZ)
 #define DEFAULT_RATELIMIT_BURST                10
@@ -25,6 +25,17 @@ struct ratelimit_state {
                .burst          = burst_init,                           \
        }
 
+static inline void ratelimit_state_init(struct ratelimit_state *rs,
+                                       int interval, int burst)
+{
+       spin_lock_init(&rs->lock);
+       rs->interval = interval;
+       rs->burst = burst;
+       rs->printed = 0;
+       rs->missed = 0;
+       rs->begin = 0;
+}
+
 extern int ___ratelimit(struct ratelimit_state *rs, const char *func);
 #define __ratelimit(state) ___ratelimit(state, __func__)
 
index 234a8476cba8a5acadb627236819e89333838eec..e2980287245e8cb28275dae09fcc33373fa6c538 100644 (file)
@@ -157,7 +157,11 @@ struct regulator_consumer_supply {
  *
  * Initialisation constraints, our supply and consumers supplies.
  *
- * @supply_regulator_dev: Parent regulator (if any).
+ * @supply_regulator: Parent regulator.  Specified using the regulator name
+ *                    as it appears in the name field in sysfs, which can
+ *                    be explicitly set using the constraints field 'name'.
+ * @supply_regulator_dev: Parent regulator (if any) - DEPRECATED in favour
+ *                        of supply_regulator.
  *
  * @constraints: Constraints.  These must be specified for the regulator to
  *               be usable.
@@ -168,7 +172,8 @@ struct regulator_consumer_supply {
  * @driver_data: Data passed to regulator_init.
  */
 struct regulator_init_data {
-       struct device *supply_regulator_dev; /* or NULL for LINE */
+       const char *supply_regulator;        /* or NULL for system supply */
+       struct device *supply_regulator_dev; /* or NULL for system supply */
 
        struct regulation_constraints constraints;
 
index b4448853900ed85a17ff24a9ce074ab5f890572f..3fd8c4506bbb32ef4347784e7a4c529883348bcb 100644 (file)
@@ -53,8 +53,8 @@ int reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
                                 struct inode *dir, struct dentry *dentry,
                                 struct inode *inode);
 int reiserfs_cache_default_acl(struct inode *dir);
-extern struct xattr_handler reiserfs_posix_acl_default_handler;
-extern struct xattr_handler reiserfs_posix_acl_access_handler;
+extern const struct xattr_handler reiserfs_posix_acl_default_handler;
+extern const struct xattr_handler reiserfs_posix_acl_access_handler;
 
 #else
 
index 7fa02b4af838513b9a609122db0772654cdc2f91..b2cf2089769b5a699d28910af6c92c177e8ecef0 100644 (file)
@@ -58,9 +58,9 @@ int reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *,
                              struct inode *, const char *, const void *,
                              size_t, int);
 
-extern struct xattr_handler reiserfs_xattr_user_handler;
-extern struct xattr_handler reiserfs_xattr_trusted_handler;
-extern struct xattr_handler reiserfs_xattr_security_handler;
+extern const struct xattr_handler reiserfs_xattr_user_handler;
+extern const struct xattr_handler reiserfs_xattr_trusted_handler;
+extern const struct xattr_handler reiserfs_xattr_security_handler;
 #ifdef CONFIG_REISERFS_FS_SECURITY
 int reiserfs_security_init(struct inode *dir, struct inode *inode,
                           struct reiserfs_security_handle *sec);
index dc0c75556c63c763da2f29e1173606b0502ae78b..bd6eb0ed34a7d743f370295390fd440f5234b2e1 100644 (file)
 #define RIO_INB_MBOX_RESOURCE  1
 #define RIO_OUTB_MBOX_RESOURCE 2
 
+#define RIO_PW_MSG_SIZE                64
+
 extern struct bus_type rio_bus_type;
 extern struct list_head rio_devices;   /* list of all devices */
 
 struct rio_mport;
+union rio_pw_msg;
 
 /**
  * struct rio_dev - RIO device info
@@ -85,11 +88,15 @@ struct rio_mport;
  * @swpinfo: Switch port info
  * @src_ops: Source operation capabilities
  * @dst_ops: Destination operation capabilities
+ * @comp_tag: RIO component tag
+ * @phys_efptr: RIO device extended features pointer
+ * @em_efptr: RIO Error Management features pointer
  * @dma_mask: Mask of bits of RIO address this device implements
  * @rswitch: Pointer to &struct rio_switch if valid for this device
  * @driver: Driver claiming this device
  * @dev: Device model device
  * @riores: RIO resources this device owns
+ * @pwcback: port-write callback function for this device
  * @destid: Network destination ID
  */
 struct rio_dev {
@@ -107,11 +114,15 @@ struct rio_dev {
        u32 swpinfo;            /* Only used for switches */
        u32 src_ops;
        u32 dst_ops;
+       u32 comp_tag;
+       u32 phys_efptr;
+       u32 em_efptr;
        u64 dma_mask;
        struct rio_switch *rswitch;     /* RIO switch info */
        struct rio_driver *driver;      /* RIO driver claiming this device */
        struct device dev;      /* LDM device structure */
        struct resource riores[RIO_MAX_DEV_RESOURCES];
+       int (*pwcback) (struct rio_dev *rdev, union rio_pw_msg *msg, int step);
        u16 destid;
 };
 
@@ -211,8 +222,14 @@ struct rio_net {
  * @hopcount: Hopcount to this switch
  * @destid: Associated destid in the path
  * @route_table: Copy of switch routing table
+ * @port_ok: Status of each port (one bit per port) - OK=1 or UNINIT=0
  * @add_entry: Callback for switch-specific route add function
  * @get_entry: Callback for switch-specific route get function
+ * @clr_table: Callback for switch-specific clear route table function
+ * @set_domain: Callback for switch-specific domain setting function
+ * @get_domain: Callback for switch-specific domain get function
+ * @em_init: Callback for switch-specific error management initialization function
+ * @em_handle: Callback for switch-specific error management handler function
  */
 struct rio_switch {
        struct list_head node;
@@ -220,10 +237,19 @@ struct rio_switch {
        u16 hopcount;
        u16 destid;
        u8 *route_table;
+       u32 port_ok;
        int (*add_entry) (struct rio_mport * mport, u16 destid, u8 hopcount,
                          u16 table, u16 route_destid, u8 route_port);
        int (*get_entry) (struct rio_mport * mport, u16 destid, u8 hopcount,
                          u16 table, u16 route_destid, u8 * route_port);
+       int (*clr_table) (struct rio_mport *mport, u16 destid, u8 hopcount,
+                         u16 table);
+       int (*set_domain) (struct rio_mport *mport, u16 destid, u8 hopcount,
+                          u8 sw_domain);
+       int (*get_domain) (struct rio_mport *mport, u16 destid, u8 hopcount,
+                          u8 *sw_domain);
+       int (*em_init) (struct rio_dev *dev);
+       int (*em_handle) (struct rio_dev *dev, u8 swport);
 };
 
 /* Low-level architecture-dependent routines */
@@ -235,6 +261,7 @@ struct rio_switch {
  * @cread: Callback to perform network read of config space.
  * @cwrite: Callback to perform network write of config space.
  * @dsend: Callback to send a doorbell message.
+ * @pwenable: Callback to enable/disable port-write message handling.
  */
 struct rio_ops {
        int (*lcread) (struct rio_mport *mport, int index, u32 offset, int len,
@@ -246,6 +273,7 @@ struct rio_ops {
        int (*cwrite) (struct rio_mport *mport, int index, u16 destid,
                        u8 hopcount, u32 offset, int len, u32 data);
        int (*dsend) (struct rio_mport *mport, int index, u16 destid, u16 data);
+       int (*pwenable) (struct rio_mport *mport, int enable);
 };
 
 #define RIO_RESOURCE_MEM       0x00000100
@@ -302,21 +330,28 @@ struct rio_device_id {
 };
 
 /**
- * struct rio_route_ops - Per-switch route operations
+ * struct rio_switch_ops - Per-switch operations
  * @vid: RIO vendor ID
  * @did: RIO device ID
- * @add_hook: Callback that adds a route entry
- * @get_hook: Callback that gets a route entry
+ * @init_hook: Callback that performs switch device initialization
  *
- * Defines the operations that are necessary to manipulate the route
- * tables for a particular RIO switch device.
+ * Defines the operations that are necessary to initialize/control
+ * a particular RIO switch device.
  */
-struct rio_route_ops {
+struct rio_switch_ops {
        u16 vid, did;
-       int (*add_hook) (struct rio_mport * mport, u16 destid, u8 hopcount,
-                        u16 table, u16 route_destid, u8 route_port);
-       int (*get_hook) (struct rio_mport * mport, u16 destid, u8 hopcount,
-                        u16 table, u16 route_destid, u8 * route_port);
+       int (*init_hook) (struct rio_dev *rdev, int do_enum);
+};
+
+union rio_pw_msg {
+       struct {
+               u32 comptag;    /* Component Tag CSR */
+               u32 errdetect;  /* Port N Error Detect CSR */
+               u32 is_port;    /* Implementation specific + PortID */
+               u32 ltlerrdet;  /* LTL Error Detect CSR */
+               u32 padding[12];
+       } em;
+       u32 raw[RIO_PW_MSG_SIZE/sizeof(u32)];
 };
 
 /* Architecture and hardware-specific functions */
index c93a58a4003324bf6d147836d0c6a1ccaac350e5..edc55da717b30e13ae712ea4ec7ca5a1220d5fa3 100644 (file)
@@ -413,6 +413,12 @@ void rio_release_regions(struct rio_dev *);
 int rio_request_region(struct rio_dev *, int, char *);
 void rio_release_region(struct rio_dev *, int);
 
+/* Port-Write management */
+extern int rio_request_inb_pwrite(struct rio_dev *,
+                       int (*)(struct rio_dev *, union rio_pw_msg*, int));
+extern int rio_release_inb_pwrite(struct rio_dev *);
+extern int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg);
+
 /* LDM support */
 int rio_register_driver(struct rio_driver *);
 void rio_unregister_driver(struct rio_driver *);
index 919d4e07d54e5c528369bb399d8c57e064f9dbbc..db50e1c288b7b48be7e3bbd6fad70b934f42e588 100644 (file)
 
 #define RIO_VID_TUNDRA                 0x000d
 #define RIO_DID_TSI500                 0x0500
+#define RIO_DID_TSI568                 0x0568
+#define RIO_DID_TSI572                 0x0572
+#define RIO_DID_TSI574                 0x0574
+#define RIO_DID_TSI576                 0x0578 /* Same ID as Tsi578 */
+#define RIO_DID_TSI577                 0x0577
+#define RIO_DID_TSI578                 0x0578
+
+#define RIO_VID_IDT                    0x0038
+#define RIO_DID_IDT70K200              0x0310
+#define RIO_DID_IDTCPS8                        0x035c
+#define RIO_DID_IDTCPS12               0x035d
+#define RIO_DID_IDTCPS16               0x035b
+#define RIO_DID_IDTCPS6Q               0x035f
+#define RIO_DID_IDTCPS10Q              0x035e
 
 #endif                         /* LINUX_RIO_IDS_H */
index 326540f9b54e4c4ad253acbbd932eb663c0e6012..aedee0489fb41991b8b018b57a449a867b039434 100644 (file)
@@ -39,6 +39,8 @@
 #define  RIO_PEF_INB_MBOX2             0x00200000      /* [II] Mailbox 2 */
 #define  RIO_PEF_INB_MBOX3             0x00100000      /* [II] Mailbox 3 */
 #define  RIO_PEF_INB_DOORBELL          0x00080000      /* [II] Doorbells */
+#define  RIO_PEF_EXT_RT                        0x00000200      /* [III, 1.3] Extended route table support */
+#define  RIO_PEF_STD_RT                        0x00000100      /* [III, 1.3] Standard route table support */
 #define  RIO_PEF_CTLS                  0x00000010      /* [III] CTLS */
 #define  RIO_PEF_EXT_FEATURES          0x00000008      /* [I] EFT_PTR valid */
 #define  RIO_PEF_ADDR_66               0x00000004      /* [I] 66 bits */
 #define  RIO_OPS_ATOMIC_CLR            0x00000010      /* [I] Atomic clr op */
 #define  RIO_OPS_PORT_WRITE            0x00000004      /* [I] Port-write op */
 
-                                       /* 0x20-0x3c *//* Reserved */
+                                       /* 0x20-0x30 *//* Reserved */
+
+#define        RIO_SWITCH_RT_LIMIT     0x34    /* [III, 1.3] Switch Route Table Destination ID Limit CAR */
+#define         RIO_RT_MAX_DESTID              0x0000ffff
 
 #define RIO_MBOX_CSR           0x40    /* [II] Mailbox CSR */
 #define  RIO_MBOX0_AVAIL               0x80000000      /* [II] Mbox 0 avail */
 #define RIO_HOST_DID_LOCK_CSR  0x68    /* [III] Host Base Device ID Lock CSR */
 #define RIO_COMPONENT_TAG_CSR  0x6c    /* [III] Component Tag CSR */
 
-                                       /* 0x70-0xf8 *//* Reserved */
+#define RIO_STD_RTE_CONF_DESTID_SEL_CSR        0x70
+#define RIO_STD_RTE_CONF_PORT_SEL_CSR  0x74
+#define RIO_STD_RTE_DEFAULT_PORT       0x78
+
+                                       /* 0x7c-0xf8 *//* Reserved */
                                        /* 0x100-0xfff8 *//* [I] Extended Features Space */
                                        /* 0x10000-0xfffff8 *//* [I] Implementation-defined Space */
 
 #define RIO_EFB_PAR_EP_ID      0x0001  /* [IV] LP/LVDS EP Devices */
 #define RIO_EFB_PAR_EP_REC_ID  0x0002  /* [IV] LP/LVDS EP Recovery Devices */
 #define RIO_EFB_PAR_EP_FREE_ID 0x0003  /* [IV] LP/LVDS EP Free Devices */
+#define RIO_EFB_SER_EP_ID_V13P 0x0001  /* [VI] LP/Serial EP Devices, RapidIO Spec ver 1.3 and above */
+#define RIO_EFB_SER_EP_REC_ID_V13P     0x0002  /* [VI] LP/Serial EP Recovery Devices, RapidIO Spec ver 1.3 and above */
+#define RIO_EFB_SER_EP_FREE_ID_V13P    0x0003  /* [VI] LP/Serial EP Free Devices, RapidIO Spec ver 1.3 and above */
 #define RIO_EFB_SER_EP_ID      0x0004  /* [VI] LP/Serial EP Devices */
 #define RIO_EFB_SER_EP_REC_ID  0x0005  /* [VI] LP/Serial EP Recovery Devices */
 #define RIO_EFB_SER_EP_FREE_ID 0x0006  /* [VI] LP/Serial EP Free Devices */
+#define RIO_EFB_SER_EP_FREC_ID 0x0009  /* [VI] LP/Serial EP Free Recovery Devices */
+#define RIO_EFB_ERR_MGMNT      0x0007  /* [VIII] Error Management Extensions */
 
 /*
  * Physical 8/16 LP-LVDS
 #define RIO_PORT_MNT_HEADER            0x0000
 #define RIO_PORT_REQ_CTL_CSR           0x0020
 #define RIO_PORT_RSP_CTL_CSR           0x0024  /* 0x0001/0x0002 */
+#define RIO_PORT_LINKTO_CTL_CSR                0x0020  /* Serial */
+#define RIO_PORT_RSPTO_CTL_CSR         0x0024  /* Serial */
 #define RIO_PORT_GEN_CTL_CSR           0x003c
 #define  RIO_PORT_GEN_HOST             0x80000000
 #define  RIO_PORT_GEN_MASTER           0x40000000
 #define  RIO_PORT_GEN_DISCOVERED       0x20000000
 #define RIO_PORT_N_MNT_REQ_CSR(x)      (0x0040 + x*0x20)       /* 0x0002 */
 #define RIO_PORT_N_MNT_RSP_CSR(x)      (0x0044 + x*0x20)       /* 0x0002 */
+#define  RIO_PORT_N_MNT_RSP_RVAL       0x80000000 /* Response Valid */
+#define  RIO_PORT_N_MNT_RSP_ASTAT      0x000003e0 /* ackID Status */
+#define  RIO_PORT_N_MNT_RSP_LSTAT      0x0000001f /* Link Status */
 #define RIO_PORT_N_ACK_STS_CSR(x)      (0x0048 + x*0x20)       /* 0x0002 */
-#define RIO_PORT_N_ERR_STS_CSR(x)      (0x58 + x*0x20)
-#define PORT_N_ERR_STS_PORT_OK 0x00000002
-#define RIO_PORT_N_CTL_CSR(x)          (0x5c + x*0x20)
+#define  RIO_PORT_N_ACK_CLEAR          0x80000000
+#define  RIO_PORT_N_ACK_INBOUND                0x1f000000
+#define  RIO_PORT_N_ACK_OUTSTAND       0x00001f00
+#define  RIO_PORT_N_ACK_OUTBOUND       0x0000001f
+#define RIO_PORT_N_ERR_STS_CSR(x)      (0x0058 + x*0x20)
+#define  RIO_PORT_N_ERR_STS_PW_OUT_ES  0x00010000 /* Output Error-stopped */
+#define  RIO_PORT_N_ERR_STS_PW_INP_ES  0x00000100 /* Input Error-stopped */
+#define  RIO_PORT_N_ERR_STS_PW_PEND    0x00000010 /* Port-Write Pending */
+#define  RIO_PORT_N_ERR_STS_PORT_ERR   0x00000004
+#define  RIO_PORT_N_ERR_STS_PORT_OK    0x00000002
+#define  RIO_PORT_N_ERR_STS_PORT_UNINIT        0x00000001
+#define  RIO_PORT_N_ERR_STS_CLR_MASK   0x07120204
+#define RIO_PORT_N_CTL_CSR(x)          (0x005c + x*0x20)
+#define  RIO_PORT_N_CTL_PWIDTH         0xc0000000
+#define  RIO_PORT_N_CTL_PWIDTH_1       0x00000000
+#define  RIO_PORT_N_CTL_PWIDTH_4       0x40000000
+#define  RIO_PORT_N_CTL_P_TYP_SER      0x00000001
+#define  RIO_PORT_N_CTL_LOCKOUT                0x00000002
+#define  RIO_PORT_N_CTL_EN_RX_SER      0x00200000
+#define  RIO_PORT_N_CTL_EN_TX_SER      0x00400000
+#define  RIO_PORT_N_CTL_EN_RX_PAR      0x08000000
+#define  RIO_PORT_N_CTL_EN_TX_PAR      0x40000000
+
+/*
+ * Error Management Extensions (RapidIO 1.3+, Part 8)
+ *
+ * Extended Features Block ID=0x0007
+ */
+
+/* General EM Registers (Common for all Ports) */
+
+#define RIO_EM_EFB_HEADER      0x000   /* Error Management Extensions Block Header */
+#define RIO_EM_LTL_ERR_DETECT  0x008   /* Logical/Transport Layer Error Detect CSR */
+#define RIO_EM_LTL_ERR_EN      0x00c   /* Logical/Transport Layer Error Enable CSR */
+#define RIO_EM_LTL_HIADDR_CAP  0x010   /* Logical/Transport Layer High Address Capture CSR */
+#define RIO_EM_LTL_ADDR_CAP    0x014   /* Logical/Transport Layer Address Capture CSR */
+#define RIO_EM_LTL_DEVID_CAP   0x018   /* Logical/Transport Layer Device ID Capture CSR */
+#define RIO_EM_LTL_CTRL_CAP    0x01c   /* Logical/Transport Layer Control Capture CSR */
+#define RIO_EM_PW_TGT_DEVID    0x028   /* Port-write Target deviceID CSR */
+#define RIO_EM_PKT_TTL         0x02c   /* Packet Time-to-live CSR */
+
+/* Per-Port EM Registers */
+
+#define RIO_EM_PN_ERR_DETECT(x)        (0x040 + x*0x40) /* Port N Error Detect CSR */
+#define  REM_PED_IMPL_SPEC             0x80000000
+#define  REM_PED_LINK_TO               0x00000001
+#define RIO_EM_PN_ERRRATE_EN(x) (0x044 + x*0x40) /* Port N Error Rate Enable CSR */
+#define RIO_EM_PN_ATTRIB_CAP(x)        (0x048 + x*0x40) /* Port N Attributes Capture CSR */
+#define RIO_EM_PN_PKT_CAP_0(x) (0x04c + x*0x40) /* Port N Packet/Control Symbol Capture 0 CSR */
+#define RIO_EM_PN_PKT_CAP_1(x) (0x050 + x*0x40) /* Port N Packet Capture 1 CSR */
+#define RIO_EM_PN_PKT_CAP_2(x) (0x054 + x*0x40) /* Port N Packet Capture 2 CSR */
+#define RIO_EM_PN_PKT_CAP_3(x) (0x058 + x*0x40) /* Port N Packet Capture 3 CSR */
+#define RIO_EM_PN_ERRRATE(x)   (0x068 + x*0x40) /* Port N Error Rate CSR */
+#define RIO_EM_PN_ERRRATE_TR(x) (0x06c + x*0x40) /* Port N Error Rate Threshold CSR */
 
 #endif                         /* LINUX_RIO_REGS_H */
index d25bd224d3707532198b1012dc2f4f158ca01875..77216742c178013b9444884b4f4dd05d337a4620 100644 (file)
  */
 struct anon_vma {
        spinlock_t lock;        /* Serialize access to vma list */
-#ifdef CONFIG_KSM
-       atomic_t ksm_refcount;
+#if defined(CONFIG_KSM) || defined(CONFIG_MIGRATION)
+
+       /*
+        * The external_refcount is taken by either KSM or page migration
+        * to take a reference to an anon_vma when there is no
+        * guarantee that the vma of page tables will exist for
+        * the duration of the operation. A caller that takes
+        * the reference is responsible for clearing up the
+        * anon_vma if they are the last user on release
+        */
+       atomic_t external_refcount;
 #endif
        /*
         * NOTE: the LSB of the head.next is set by
@@ -61,22 +70,22 @@ struct anon_vma_chain {
 };
 
 #ifdef CONFIG_MMU
-#ifdef CONFIG_KSM
-static inline void ksm_refcount_init(struct anon_vma *anon_vma)
+#if defined(CONFIG_KSM) || defined(CONFIG_MIGRATION)
+static inline void anonvma_external_refcount_init(struct anon_vma *anon_vma)
 {
-       atomic_set(&anon_vma->ksm_refcount, 0);
+       atomic_set(&anon_vma->external_refcount, 0);
 }
 
-static inline int ksm_refcount(struct anon_vma *anon_vma)
+static inline int anonvma_external_refcount(struct anon_vma *anon_vma)
 {
-       return atomic_read(&anon_vma->ksm_refcount);
+       return atomic_read(&anon_vma->external_refcount);
 }
 #else
-static inline void ksm_refcount_init(struct anon_vma *anon_vma)
+static inline void anonvma_external_refcount_init(struct anon_vma *anon_vma)
 {
 }
 
-static inline int ksm_refcount(struct anon_vma *anon_vma)
+static inline int anonvma_external_refcount(struct anon_vma *anon_vma)
 {
        return 0;
 }
index b55e988988b589dca9ead5726e1f3ac52df4f98e..f118809c953ff137b2a97e0d9e674b2836ee331a 100644 (file)
@@ -268,7 +268,6 @@ extern void init_idle(struct task_struct *idle, int cpu);
 extern void init_idle_bootup_task(struct task_struct *idle);
 
 extern int runqueue_is_locked(int cpu);
-extern void task_rq_unlock_wait(struct task_struct *p);
 
 extern cpumask_var_t nohz_cpu_mask;
 #if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ)
@@ -384,7 +383,7 @@ struct user_namespace;
  * 1-3 now and depends on arch. We use "5" as safe margin, here.
  */
 #define MAPCOUNT_ELF_CORE_MARGIN       (5)
-#define DEFAULT_MAX_MAP_COUNT  (USHORT_MAX - MAPCOUNT_ELF_CORE_MARGIN)
+#define DEFAULT_MAX_MAP_COUNT  (USHRT_MAX - MAPCOUNT_ELF_CORE_MARGIN)
 
 extern int sysctl_max_map_count;
 
@@ -527,8 +526,9 @@ struct thread_group_cputimer {
  * the locking of signal_struct.
  */
 struct signal_struct {
-       atomic_t                count;
+       atomic_t                sigcnt;
        atomic_t                live;
+       int                     nr_threads;
 
        wait_queue_head_t       wait_chldexit;  /* for wait4() */
 
@@ -1421,7 +1421,9 @@ struct task_struct {
 #endif
 #ifdef CONFIG_CPUSETS
        nodemask_t mems_allowed;        /* Protected by alloc_lock */
+       int mems_allowed_change_disable;
        int cpuset_mem_spread_rotor;
+       int cpuset_slab_spread_rotor;
 #endif
 #ifdef CONFIG_CGROUPS
        /* Control Group info protected by css_set_lock */
@@ -2034,7 +2036,7 @@ extern int do_notify_parent(struct task_struct *, int);
 extern void __wake_up_parent(struct task_struct *p, struct task_struct *parent);
 extern void force_sig(int, struct task_struct *);
 extern int send_sig(int, struct task_struct *, int);
-extern void zap_other_threads(struct task_struct *p);
+extern int zap_other_threads(struct task_struct *p);
 extern struct sigqueue *sigqueue_alloc(void);
 extern void sigqueue_free(struct sigqueue *);
 extern int send_sigqueue(struct sigqueue *,  struct task_struct *, int group);
@@ -2099,7 +2101,6 @@ extern void flush_thread(void);
 extern void exit_thread(void);
 
 extern void exit_files(struct task_struct *);
-extern void __cleanup_signal(struct signal_struct *);
 extern void __cleanup_sighand(struct sighand_struct *);
 
 extern void exit_itimers(struct signal_struct *);
@@ -2146,6 +2147,11 @@ extern bool current_is_single_threaded(void);
 #define while_each_thread(g, t) \
        while ((t = next_thread(t)) != g)
 
+static inline int get_nr_threads(struct task_struct *tsk)
+{
+       return tsk->signal->nr_threads;
+}
+
 /* de_thread depends on thread_group_leader not being a pid based check */
 #define thread_group_leader(p) (p == p->group_leader)
 
@@ -2392,10 +2398,6 @@ static inline void thread_group_cputime_init(struct signal_struct *sig)
        spin_lock_init(&sig->cputimer.lock);
 }
 
-static inline void thread_group_cputime_free(struct signal_struct *sig)
-{
-}
-
 /*
  * Reevaluate whether the task has signals pending delivery.
  * Wake the task if so.
diff --git a/include/linux/sdhci-pltfm.h b/include/linux/sdhci-pltfm.h
new file mode 100644 (file)
index 0000000..0239bd7
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Platform data declarations for the sdhci-pltfm driver.
+ *
+ * Copyright (c) 2010 MontaVista Software, LLC.
+ *
+ * Author: Anton Vorontsov <avorontsov@ru.mvista.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 _SDHCI_PLTFM_H
+#define _SDHCI_PLTFM_H
+
+struct sdhci_ops;
+struct sdhci_host;
+
+/**
+ * struct sdhci_pltfm_data - SDHCI platform-specific information & hooks
+ * @ops: optional pointer to the platform-provided SDHCI ops
+ * @quirks: optional SDHCI quirks
+ * @init: optional hook that is called during device probe, before the
+ *        driver tries to access any SDHCI registers
+ * @exit: optional hook that is called during device removal
+ */
+struct sdhci_pltfm_data {
+       struct sdhci_ops *ops;
+       unsigned int quirks;
+       int (*init)(struct sdhci_host *host);
+       void (*exit)(struct sdhci_host *host);
+};
+
+#endif /* _SDHCI_PLTFM_H */
index 8a4adbef8a0fd65b13964b780418b6d7dd84c154..f2961afa2f6657e9bbf9c79cd25b0d2c2648d86d 100644 (file)
@@ -79,6 +79,7 @@ struct  seminfo {
 #ifdef __KERNEL__
 #include <asm/atomic.h>
 #include <linux/rcupdate.h>
+#include <linux/cache.h>
 
 struct task_struct;
 
@@ -91,7 +92,8 @@ struct sem {
 
 /* One sem_array data structure for each set of semaphores in the system. */
 struct sem_array {
-       struct kern_ipc_perm    sem_perm;       /* permissions .. see ipc.h */
+       struct kern_ipc_perm    ____cacheline_aligned_in_smp
+                               sem_perm;       /* permissions .. see ipc.h */
        time_t                  sem_otime;      /* last semop time */
        time_t                  sem_ctime;      /* last change time */
        struct sem              *sem_base;      /* ptr to first semaphore in array */
index 9a6f7607174e8eddb1d23d86c2a8dafa0acbdea6..0299b4ce63dbd4b96faf4265043a75ccfacc6183 100644 (file)
@@ -73,6 +73,8 @@
 #define SFI_SIG_SPIB           "SPIB"
 #define SFI_SIG_I2CB           "I2CB"
 #define SFI_SIG_GPEM           "GPEM"
+#define SFI_SIG_DEVS           "DEVS"
+#define SFI_SIG_GPIO           "GPIO"
 
 #define SFI_SIGNATURE_SIZE     4
 #define SFI_OEM_ID_SIZE                6
@@ -145,6 +147,27 @@ struct sfi_rtc_table_entry {
        u32     irq;
 } __packed;
 
+struct sfi_device_table_entry {
+       u8      type;           /* bus type, I2C, SPI or ...*/
+#define SFI_DEV_TYPE_SPI       0
+#define SFI_DEV_TYPE_I2C       1
+#define SFI_DEV_TYPE_UART      2
+#define SFI_DEV_TYPE_HSI       3
+#define SFI_DEV_TYPE_IPC       4
+
+       u8      host_num;       /* attached to host 0, 1...*/
+       u16     addr;
+       u8      irq;
+       u32     max_freq;
+       char    name[16];
+} __packed;
+
+struct sfi_gpio_table_entry {
+       char    controller_name[16];
+       u16     pin_no;
+       char    pin_name[16];
+} __packed;
+
 struct sfi_spi_table_entry {
        u16     host_num;       /* attached to host 0, 1...*/
        u16     cs;             /* chip select */
@@ -166,7 +189,6 @@ struct sfi_gpe_table_entry {
        u16     phys_id;        /* physical GPE id */
 } __packed;
 
-
 typedef int (*sfi_table_handler) (struct sfi_table_header *table);
 
 #ifdef CONFIG_SFI
index ca6b2b31799197463220b53179b4a1cd41ead85e..1812dac8c496b8694d18b45c372b86c411cf0400 100644 (file)
 #include <linux/compiler.h>
 #include <linux/kmemtrace.h>
 
+#ifndef ARCH_KMALLOC_MINALIGN
+/*
+ * Enforce a minimum alignment for the kmalloc caches.
+ * Usually, the kmalloc caches are cache_line_size() aligned, except when
+ * DEBUG and FORCED_DEBUG are enabled, then they are BYTES_PER_WORD aligned.
+ * Some archs want to perform DMA into kmalloc caches and need a guaranteed
+ * alignment larger than the alignment of a 64-bit integer.
+ * ARCH_KMALLOC_MINALIGN allows that.
+ * Note that increasing this value may disable some debug features.
+ */
+#define ARCH_KMALLOC_MINALIGN __alignof__(unsigned long long)
+#endif
+
+#ifndef ARCH_SLAB_MINALIGN
+/*
+ * Enforce a minimum alignment for all caches.
+ * Intended for archs that get misalignment faults even for BYTES_PER_WORD
+ * aligned buffers. Includes ARCH_KMALLOC_MINALIGN.
+ * If possible: Do not enable this flag for CONFIG_DEBUG_SLAB, it disables
+ * some debug features.
+ */
+#define ARCH_SLAB_MINALIGN 0
+#endif
+
 /*
  * struct kmem_cache
  *
index 0ec00b39d006471e585a11e74759ff832f6f028b..62667f72c2ef795c128b58d75a141e65beb16a35 100644 (file)
@@ -1,6 +1,14 @@
 #ifndef __LINUX_SLOB_DEF_H
 #define __LINUX_SLOB_DEF_H
 
+#ifndef ARCH_KMALLOC_MINALIGN
+#define ARCH_KMALLOC_MINALIGN __alignof__(unsigned long)
+#endif
+
+#ifndef ARCH_SLAB_MINALIGN
+#define ARCH_SLAB_MINALIGN __alignof__(unsigned long)
+#endif
+
 void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
 
 static __always_inline void *kmem_cache_alloc(struct kmem_cache *cachep,
index 0249d4175bacbb9d7b2a3a86758b8dfd0807a1e7..55695c8d2f8ad954a7575ac11961d1254347b1b3 100644 (file)
@@ -116,6 +116,14 @@ struct kmem_cache {
 
 #define KMALLOC_SHIFT_LOW ilog2(KMALLOC_MIN_SIZE)
 
+#ifndef ARCH_KMALLOC_MINALIGN
+#define ARCH_KMALLOC_MINALIGN __alignof__(unsigned long long)
+#endif
+
+#ifndef ARCH_SLAB_MINALIGN
+#define ARCH_SLAB_MINALIGN __alignof__(unsigned long long)
+#endif
+
 /*
  * Maximum kmalloc object size handled by SLUB. Larger object allocations
  * are passed through to the page allocator. The page allocator "fastpath"
index 3274c507b8a9e4ea870f4a6ab84136b407fa3643..f987a2bee16a8bde6137047582de72654a39e952 100644 (file)
@@ -1,24 +1,6 @@
 #ifndef        __SPI_BITBANG_H
 #define        __SPI_BITBANG_H
 
-/*
- * Mix this utility code with some glue code to get one of several types of
- * simple SPI master driver.  Two do polled word-at-a-time I/O:
- *
- *   - GPIO/parport bitbangers.  Provide chipselect() and txrx_word[](),
- *     expanding the per-word routines from the inline templates below.
- *
- *   - Drivers for controllers resembling bare shift registers.  Provide
- *     chipselect() and txrx_word[](), with custom setup()/cleanup() methods
- *     that use your controller's clock and chipselect registers.
- *
- * Some hardware works well with requests at spi_transfer scope:
- *
- *   - Drivers leveraging smarter hardware, with fifos or DMA; or for half
- *     duplex (MicroWire) controllers.  Provide chipselect() and txrx_bufs(),
- *     and custom setup()/cleanup() methods.
- */
-
 #include <linux/workqueue.h>
 
 struct spi_bitbang {
@@ -68,86 +50,3 @@ extern int spi_bitbang_start(struct spi_bitbang *spi);
 extern int spi_bitbang_stop(struct spi_bitbang *spi);
 
 #endif /* __SPI_BITBANG_H */
-
-/*-------------------------------------------------------------------------*/
-
-#ifdef EXPAND_BITBANG_TXRX
-
-/*
- * The code that knows what GPIO pins do what should have declared four
- * functions, ideally as inlines, before #defining EXPAND_BITBANG_TXRX
- * and including this header:
- *
- *  void setsck(struct spi_device *, int is_on);
- *  void setmosi(struct spi_device *, int is_on);
- *  int getmiso(struct spi_device *);
- *  void spidelay(unsigned);
- *
- * setsck()'s is_on parameter is a zero/nonzero boolean.
- *
- * setmosi()'s is_on parameter is a zero/nonzero boolean.
- *
- * getmiso() is required to return 0 or 1 only. Any other value is invalid
- * and will result in improper operation.
- *
- * A non-inlined routine would call bitbang_txrx_*() routines.  The
- * main loop could easily compile down to a handful of instructions,
- * especially if the delay is a NOP (to run at peak speed).
- *
- * Since this is software, the timings may not be exactly what your board's
- * chips need ... there may be several reasons you'd need to tweak timings
- * in these routines, not just make to make it faster or slower to match a
- * particular CPU clock rate.
- */
-
-static inline u32
-bitbang_txrx_be_cpha0(struct spi_device *spi,
-               unsigned nsecs, unsigned cpol,
-               u32 word, u8 bits)
-{
-       /* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */
-
-       /* clock starts at inactive polarity */
-       for (word <<= (32 - bits); likely(bits); bits--) {
-
-               /* setup MSB (to slave) on trailing edge */
-               setmosi(spi, word & (1 << 31));
-               spidelay(nsecs);        /* T(setup) */
-
-               setsck(spi, !cpol);
-               spidelay(nsecs);
-
-               /* sample MSB (from slave) on leading edge */
-               word <<= 1;
-               word |= getmiso(spi);
-               setsck(spi, cpol);
-       }
-       return word;
-}
-
-static inline u32
-bitbang_txrx_be_cpha1(struct spi_device *spi,
-               unsigned nsecs, unsigned cpol,
-               u32 word, u8 bits)
-{
-       /* if (cpol == 0) this is SPI_MODE_1; else this is SPI_MODE_3 */
-
-       /* clock starts at inactive polarity */
-       for (word <<= (32 - bits); likely(bits); bits--) {
-
-               /* setup MSB (to slave) on leading edge */
-               setsck(spi, !cpol);
-               setmosi(spi, word & (1 << 31));
-               spidelay(nsecs); /* T(setup) */
-
-               setsck(spi, cpol);
-               spidelay(nsecs);
-
-               /* sample MSB (from slave) on trailing edge */
-               word <<= 1;
-               word |= getmiso(spi);
-       }
-       return word;
-}
-
-#endif /* EXPAND_BITBANG_TXRX */
index ec2b7a42b45f683cc885ed7001a444f3349681da..ff4acea9bbdb075e866d12770072e377d280d3ef 100644 (file)
@@ -152,6 +152,7 @@ enum {
 };
 
 #define SWAP_CLUSTER_MAX 32
+#define COMPACT_CLUSTER_MAX SWAP_CLUSTER_MAX
 
 #define SWAP_MAP_MAX   0x3e    /* Max duplication count, in first swap_map */
 #define SWAP_MAP_BAD   0x3f    /* Note pageblock is bad, in first swap_map */
@@ -224,20 +225,15 @@ static inline void lru_cache_add_anon(struct page *page)
        __lru_cache_add(page, LRU_INACTIVE_ANON);
 }
 
-static inline void lru_cache_add_active_anon(struct page *page)
-{
-       __lru_cache_add(page, LRU_ACTIVE_ANON);
-}
-
 static inline void lru_cache_add_file(struct page *page)
 {
        __lru_cache_add(page, LRU_INACTIVE_FILE);
 }
 
-static inline void lru_cache_add_active_file(struct page *page)
-{
-       __lru_cache_add(page, LRU_ACTIVE_FILE);
-}
+/* LRU Isolation modes. */
+#define ISOLATE_INACTIVE 0     /* Isolate inactive pages. */
+#define ISOLATE_ACTIVE 1       /* Isolate active pages. */
+#define ISOLATE_BOTH 2         /* Isolate both active and inactive pages. */
 
 /* linux/mm/vmscan.c */
 extern unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
@@ -286,6 +282,11 @@ extern void kswapd_stop(int nid);
 extern int shmem_unuse(swp_entry_t entry, struct page *page);
 #endif /* CONFIG_MMU */
 
+#ifdef CONFIG_CGROUP_MEM_RES_CTLR
+extern void mem_cgroup_get_shmem_target(struct inode *inode, pgoff_t pgoff,
+                                       struct page **pagep, swp_entry_t *ent);
+#endif
+
 extern void swap_unplug_io_fn(struct backing_dev_info *, struct page *);
 
 #ifdef CONFIG_SWAP
index febedcf67c7ec38464add407881e0351f6352ca5..81a4e213c6cf9bd934792d0135836cc9ef8d4d36 100644 (file)
@@ -73,16 +73,6 @@ extern void
 swiotlb_sync_sg_for_device(struct device *hwdev, struct scatterlist *sg,
                           int nelems, enum dma_data_direction dir);
 
-extern void
-swiotlb_sync_single_range_for_cpu(struct device *hwdev, dma_addr_t dev_addr,
-                                 unsigned long offset, size_t size,
-                                 enum dma_data_direction dir);
-
-extern void
-swiotlb_sync_single_range_for_device(struct device *hwdev, dma_addr_t dev_addr,
-                                    unsigned long offset, size_t size,
-                                    enum dma_data_direction dir);
-
 extern int
 swiotlb_dma_mapping_error(struct device *hwdev, dma_addr_t dma_addr);
 
index 057929b0a6514963b66098e9f3ff58129937ffa5..a1a86a53bc735c13cdda531309aa6c8158231909 100644 (file)
@@ -103,22 +103,6 @@ struct perf_event_attr;
 #define __SC_TEST5(t5, a5, ...)        __SC_TEST(t5); __SC_TEST4(__VA_ARGS__)
 #define __SC_TEST6(t6, a6, ...)        __SC_TEST(t6); __SC_TEST5(__VA_ARGS__)
 
-#ifdef CONFIG_PERF_EVENTS
-
-#define TRACE_SYS_ENTER_PERF_INIT(sname)                                      \
-       .perf_event_enable = perf_sysenter_enable,                             \
-       .perf_event_disable = perf_sysenter_disable,
-
-#define TRACE_SYS_EXIT_PERF_INIT(sname)                                               \
-       .perf_event_enable = perf_sysexit_enable,                              \
-       .perf_event_disable = perf_sysexit_disable,
-#else
-#define TRACE_SYS_ENTER_PERF(sname)
-#define TRACE_SYS_ENTER_PERF_INIT(sname)
-#define TRACE_SYS_EXIT_PERF(sname)
-#define TRACE_SYS_EXIT_PERF_INIT(sname)
-#endif /* CONFIG_PERF_EVENTS */
-
 #ifdef CONFIG_FTRACE_SYSCALLS
 #define __SC_STR_ADECL1(t, a)          #a
 #define __SC_STR_ADECL2(t, a, ...)     #a, __SC_STR_ADECL1(__VA_ARGS__)
@@ -134,54 +118,43 @@ struct perf_event_attr;
 #define __SC_STR_TDECL5(t, a, ...)     #t, __SC_STR_TDECL4(__VA_ARGS__)
 #define __SC_STR_TDECL6(t, a, ...)     #t, __SC_STR_TDECL5(__VA_ARGS__)
 
+extern struct ftrace_event_class event_class_syscall_enter;
+extern struct ftrace_event_class event_class_syscall_exit;
+extern struct trace_event_functions enter_syscall_print_funcs;
+extern struct trace_event_functions exit_syscall_print_funcs;
+
 #define SYSCALL_TRACE_ENTER_EVENT(sname)                               \
-       static const struct syscall_metadata __syscall_meta_##sname;    \
+       static struct syscall_metadata __syscall_meta_##sname;          \
        static struct ftrace_event_call                                 \
        __attribute__((__aligned__(4))) event_enter_##sname;            \
-       static struct trace_event enter_syscall_print_##sname = {       \
-               .trace                  = print_syscall_enter,          \
-       };                                                              \
        static struct ftrace_event_call __used                          \
          __attribute__((__aligned__(4)))                               \
          __attribute__((section("_ftrace_events")))                    \
          event_enter_##sname = {                                       \
                .name                   = "sys_enter"#sname,            \
-               .system                 = "syscalls",                   \
-               .event                  = &enter_syscall_print_##sname, \
-               .raw_init               = init_syscall_trace,           \
-               .define_fields          = syscall_enter_define_fields,  \
-               .regfunc                = reg_event_syscall_enter,      \
-               .unregfunc              = unreg_event_syscall_enter,    \
+               .class                  = &event_class_syscall_enter,   \
+               .event.funcs            = &enter_syscall_print_funcs,   \
                .data                   = (void *)&__syscall_meta_##sname,\
-               TRACE_SYS_ENTER_PERF_INIT(sname)                        \
        }
 
 #define SYSCALL_TRACE_EXIT_EVENT(sname)                                        \
-       static const struct syscall_metadata __syscall_meta_##sname;    \
+       static struct syscall_metadata __syscall_meta_##sname;          \
        static struct ftrace_event_call                                 \
        __attribute__((__aligned__(4))) event_exit_##sname;             \
-       static struct trace_event exit_syscall_print_##sname = {        \
-               .trace                  = print_syscall_exit,           \
-       };                                                              \
        static struct ftrace_event_call __used                          \
          __attribute__((__aligned__(4)))                               \
          __attribute__((section("_ftrace_events")))                    \
          event_exit_##sname = {                                        \
                .name                   = "sys_exit"#sname,             \
-               .system                 = "syscalls",                   \
-               .event                  = &exit_syscall_print_##sname,  \
-               .raw_init               = init_syscall_trace,           \
-               .define_fields          = syscall_exit_define_fields,   \
-               .regfunc                = reg_event_syscall_exit,       \
-               .unregfunc              = unreg_event_syscall_exit,     \
+               .class                  = &event_class_syscall_exit,    \
+               .event.funcs            = &exit_syscall_print_funcs,    \
                .data                   = (void *)&__syscall_meta_##sname,\
-               TRACE_SYS_EXIT_PERF_INIT(sname)                 \
        }
 
 #define SYSCALL_METADATA(sname, nb)                            \
        SYSCALL_TRACE_ENTER_EVENT(sname);                       \
        SYSCALL_TRACE_EXIT_EVENT(sname);                        \
-       static const struct syscall_metadata __used             \
+       static struct syscall_metadata __used                   \
          __attribute__((__aligned__(4)))                       \
          __attribute__((section("__syscalls_metadata")))       \
          __syscall_meta_##sname = {                            \
@@ -191,12 +164,14 @@ struct perf_event_attr;
                .args           = args_##sname,                 \
                .enter_event    = &event_enter_##sname,         \
                .exit_event     = &event_exit_##sname,          \
+               .enter_fields   = LIST_HEAD_INIT(__syscall_meta_##sname.enter_fields), \
+               .exit_fields    = LIST_HEAD_INIT(__syscall_meta_##sname.exit_fields), \
        };
 
 #define SYSCALL_DEFINE0(sname)                                 \
        SYSCALL_TRACE_ENTER_EVENT(_##sname);                    \
        SYSCALL_TRACE_EXIT_EVENT(_##sname);                     \
-       static const struct syscall_metadata __used             \
+       static struct syscall_metadata __used                   \
          __attribute__((__aligned__(4)))                       \
          __attribute__((section("__syscalls_metadata")))       \
          __syscall_meta__##sname = {                           \
@@ -204,6 +179,8 @@ struct perf_event_attr;
                .nb_args        = 0,                            \
                .enter_event    = &event_enter__##sname,        \
                .exit_event     = &event_exit__##sname,         \
+               .enter_fields   = LIST_HEAD_INIT(__syscall_meta__##sname.enter_fields), \
+               .exit_fields    = LIST_HEAD_INIT(__syscall_meta__##sname.exit_fields), \
        };                                                      \
        asmlinkage long sys_##sname(void)
 #else
index bf2a0c7488780b6096d2c5ccf93716fdea5b5b89..1dba6ee55203fec99992d211eb169938fcec918e 100644 (file)
@@ -150,6 +150,7 @@ extern int tboot_force_iommu(void);
 
 #else
 
+#define tboot_enabled()                        0
 #define tboot_probe()                  do { } while (0)
 #define tboot_shutdown(shutdown_type)  do { } while (0)
 #define tboot_sleep(sleep_state, pm1a_control, pm1b_control)   \
index 052b12bec8bdabf7a4c8b7af652eb83550c01a93..383ab9592becae78187d8be345e397a6c816765e 100644 (file)
 #define PID_MAX_LIMIT (CONFIG_BASE_SMALL ? PAGE_SIZE * 8 : \
        (sizeof(long) > 4 ? 4 * 1024 * 1024 : PID_MAX_DEFAULT))
 
+/*
+ * Define a minimum number of pids per cpu.  Heuristically based
+ * on original pid max of 32k for 32 cpus.  Also, increase the
+ * minimum settable value for pid_max on the running system based
+ * on similar defaults.  See kernel/pid.c:pidmap_init() for details.
+ */
+#define PIDS_PER_CPU_DEFAULT   1024
+#define PIDS_PER_CPU_MIN       8
+
 #endif
index 5b81156780b17f8bf52608ca7b8230dd638a530a..c44df50a05ab5a81e42b1a37299fb9e790298fc3 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/bitops.h>
 #include <linux/mmzone.h>
 #include <linux/smp.h>
+#include <linux/percpu.h>
 #include <asm/topology.h>
 
 #ifndef node_has_online_mem
@@ -203,8 +204,114 @@ int arch_update_cpu_topology(void);
 #ifndef SD_NODE_INIT
 #error Please define an appropriate SD_NODE_INIT in include/asm/topology.h!!!
 #endif
+
 #endif /* CONFIG_NUMA */
 
+#ifdef CONFIG_USE_PERCPU_NUMA_NODE_ID
+DECLARE_PER_CPU(int, numa_node);
+
+#ifndef numa_node_id
+/* Returns the number of the current Node. */
+static inline int numa_node_id(void)
+{
+       return __this_cpu_read(numa_node);
+}
+#endif
+
+#ifndef cpu_to_node
+static inline int cpu_to_node(int cpu)
+{
+       return per_cpu(numa_node, cpu);
+}
+#endif
+
+#ifndef set_numa_node
+static inline void set_numa_node(int node)
+{
+       percpu_write(numa_node, node);
+}
+#endif
+
+#ifndef set_cpu_numa_node
+static inline void set_cpu_numa_node(int cpu, int node)
+{
+       per_cpu(numa_node, cpu) = node;
+}
+#endif
+
+#else  /* !CONFIG_USE_PERCPU_NUMA_NODE_ID */
+
+/* Returns the number of the current Node. */
+#ifndef numa_node_id
+static inline int numa_node_id(void)
+{
+       return cpu_to_node(raw_smp_processor_id());
+}
+#endif
+
+#endif /* [!]CONFIG_USE_PERCPU_NUMA_NODE_ID */
+
+#ifdef CONFIG_HAVE_MEMORYLESS_NODES
+
+/*
+ * N.B., Do NOT reference the '_numa_mem_' per cpu variable directly.
+ * It will not be defined when CONFIG_HAVE_MEMORYLESS_NODES is not defined.
+ * Use the accessor functions set_numa_mem(), numa_mem_id() and cpu_to_mem().
+ */
+DECLARE_PER_CPU(int, _numa_mem_);
+
+#ifndef set_numa_mem
+static inline void set_numa_mem(int node)
+{
+       percpu_write(_numa_mem_, node);
+}
+#endif
+
+#ifndef numa_mem_id
+/* Returns the number of the nearest Node with memory */
+static inline int numa_mem_id(void)
+{
+       return __this_cpu_read(_numa_mem_);
+}
+#endif
+
+#ifndef cpu_to_mem
+static inline int cpu_to_mem(int cpu)
+{
+       return per_cpu(_numa_mem_, cpu);
+}
+#endif
+
+#ifndef set_cpu_numa_mem
+static inline void set_cpu_numa_mem(int cpu, int node)
+{
+       per_cpu(_numa_mem_, cpu) = node;
+}
+#endif
+
+#else  /* !CONFIG_HAVE_MEMORYLESS_NODES */
+
+static inline void set_numa_mem(int node) {}
+
+static inline void set_cpu_numa_mem(int cpu, int node) {}
+
+#ifndef numa_mem_id
+/* Returns the number of the nearest Node with memory */
+static inline int numa_mem_id(void)
+{
+       return numa_node_id();
+}
+#endif
+
+#ifndef cpu_to_mem
+static inline int cpu_to_mem(int cpu)
+{
+       return cpu_to_node(cpu);
+}
+#endif
+
+#endif /* [!]CONFIG_HAVE_MEMORYLESS_NODES */
+
 #ifndef topology_physical_package_id
 #define topology_physical_package_id(cpu)      ((void)(cpu), -1)
 #endif
@@ -218,9 +325,4 @@ int arch_update_cpu_topology(void);
 #define topology_core_cpumask(cpu)             cpumask_of(cpu)
 #endif
 
-/* Returns the number of the current Node. */
-#ifndef numa_node_id
-#define numa_node_id()         (cpu_to_node(raw_smp_processor_id()))
-#endif
-
 #endif /* _LINUX_TOPOLOGY_H */
index 1d85f9a6a19926af57cfe58081822109d99a98f0..9a59d1f98cd4114948129d8e9ad95b77da27ec6d 100644 (file)
 struct module;
 struct tracepoint;
 
+struct tracepoint_func {
+       void *func;
+       void *data;
+};
+
 struct tracepoint {
        const char *name;               /* Tracepoint name */
        int state;                      /* State. */
        void (*regfunc)(void);
        void (*unregfunc)(void);
-       void **funcs;
+       struct tracepoint_func *funcs;
 } __attribute__((aligned(32)));                /*
                                         * Aligned on 32 bytes because it is
                                         * globally visible and gcc happily
@@ -37,16 +42,19 @@ struct tracepoint {
  * Connect a probe to a tracepoint.
  * Internal API, should not be used directly.
  */
-extern int tracepoint_probe_register(const char *name, void *probe);
+extern int tracepoint_probe_register(const char *name, void *probe, void *data);
 
 /*
  * Disconnect a probe from a tracepoint.
  * Internal API, should not be used directly.
  */
-extern int tracepoint_probe_unregister(const char *name, void *probe);
+extern int
+tracepoint_probe_unregister(const char *name, void *probe, void *data);
 
-extern int tracepoint_probe_register_noupdate(const char *name, void *probe);
-extern int tracepoint_probe_unregister_noupdate(const char *name, void *probe);
+extern int tracepoint_probe_register_noupdate(const char *name, void *probe,
+                                             void *data);
+extern int tracepoint_probe_unregister_noupdate(const char *name, void *probe,
+                                               void *data);
 extern void tracepoint_probe_update_all(void);
 
 struct tracepoint_iter {
@@ -102,17 +110,27 @@ static inline void tracepoint_update_probe_range(struct tracepoint *begin,
 /*
  * it_func[0] is never NULL because there is at least one element in the array
  * when the array itself is non NULL.
+ *
+ * Note, the proto and args passed in includes "__data" as the first parameter.
+ * The reason for this is to handle the "void" prototype. If a tracepoint
+ * has a "void" prototype, then it is invalid to declare a function
+ * as "(void *, void)". The DECLARE_TRACE_NOARGS() will pass in just
+ * "void *data", where as the DECLARE_TRACE() will pass in "void *data, proto".
  */
 #define __DO_TRACE(tp, proto, args)                                    \
        do {                                                            \
-               void **it_func;                                         \
+               struct tracepoint_func *it_func_ptr;                    \
+               void *it_func;                                          \
+               void *__data;                                           \
                                                                        \
                rcu_read_lock_sched_notrace();                          \
-               it_func = rcu_dereference_sched((tp)->funcs);           \
-               if (it_func) {                                          \
+               it_func_ptr = rcu_dereference_sched((tp)->funcs);       \
+               if (it_func_ptr) {                                      \
                        do {                                            \
-                               ((void(*)(proto))(*it_func))(args);     \
-                       } while (*(++it_func));                         \
+                               it_func = (it_func_ptr)->func;          \
+                               __data = (it_func_ptr)->data;           \
+                               ((void(*)(proto))(it_func))(args);      \
+                       } while ((++it_func_ptr)->func);                \
                }                                                       \
                rcu_read_unlock_sched_notrace();                        \
        } while (0)
@@ -122,24 +140,32 @@ static inline void tracepoint_update_probe_range(struct tracepoint *begin,
  * not add unwanted padding between the beginning of the section and the
  * structure. Force alignment to the same alignment as the section start.
  */
-#define DECLARE_TRACE(name, proto, args)                               \
+#define __DECLARE_TRACE(name, proto, args, data_proto, data_args)      \
        extern struct tracepoint __tracepoint_##name;                   \
        static inline void trace_##name(proto)                          \
        {                                                               \
                if (unlikely(__tracepoint_##name.state))                \
                        __DO_TRACE(&__tracepoint_##name,                \
-                               TP_PROTO(proto), TP_ARGS(args));        \
+                               TP_PROTO(data_proto),                   \
+                               TP_ARGS(data_args));                    \
+       }                                                               \
+       static inline int                                               \
+       register_trace_##name(void (*probe)(data_proto), void *data)    \
+       {                                                               \
+               return tracepoint_probe_register(#name, (void *)probe,  \
+                                                data);                 \
        }                                                               \
-       static inline int register_trace_##name(void (*probe)(proto))   \
+       static inline int                                               \
+       unregister_trace_##name(void (*probe)(data_proto), void *data)  \
        {                                                               \
-               return tracepoint_probe_register(#name, (void *)probe); \
+               return tracepoint_probe_unregister(#name, (void *)probe, \
+                                                  data);               \
        }                                                               \
-       static inline int unregister_trace_##name(void (*probe)(proto)) \
+       static inline void                                              \
+       check_trace_callback_type_##name(void (*cb)(data_proto))        \
        {                                                               \
-               return tracepoint_probe_unregister(#name, (void *)probe);\
        }
 
-
 #define DEFINE_TRACE_FN(name, reg, unreg)                              \
        static const char __tpstrtab_##name[]                           \
        __attribute__((section("__tracepoints_strings"))) = #name;      \
@@ -156,18 +182,23 @@ static inline void tracepoint_update_probe_range(struct tracepoint *begin,
        EXPORT_SYMBOL(__tracepoint_##name)
 
 #else /* !CONFIG_TRACEPOINTS */
-#define DECLARE_TRACE(name, proto, args)                               \
-       static inline void _do_trace_##name(struct tracepoint *tp, proto) \
-       { }                                                             \
+#define __DECLARE_TRACE(name, proto, args, data_proto, data_args)      \
        static inline void trace_##name(proto)                          \
        { }                                                             \
-       static inline int register_trace_##name(void (*probe)(proto))   \
+       static inline int                                               \
+       register_trace_##name(void (*probe)(data_proto),                \
+                             void *data)                               \
        {                                                               \
                return -ENOSYS;                                         \
        }                                                               \
-       static inline int unregister_trace_##name(void (*probe)(proto)) \
+       static inline int                                               \
+       unregister_trace_##name(void (*probe)(data_proto),              \
+                               void *data)                             \
        {                                                               \
                return -ENOSYS;                                         \
+       }                                                               \
+       static inline void check_trace_callback_type_##name(void (*cb)(data_proto)) \
+       {                                                               \
        }
 
 #define DEFINE_TRACE_FN(name, reg, unreg)
@@ -176,6 +207,29 @@ static inline void tracepoint_update_probe_range(struct tracepoint *begin,
 #define EXPORT_TRACEPOINT_SYMBOL(name)
 
 #endif /* CONFIG_TRACEPOINTS */
+
+/*
+ * The need for the DECLARE_TRACE_NOARGS() is to handle the prototype
+ * (void). "void" is a special value in a function prototype and can
+ * not be combined with other arguments. Since the DECLARE_TRACE()
+ * macro adds a data element at the beginning of the prototype,
+ * we need a way to differentiate "(void *data, proto)" from
+ * "(void *data, void)". The second prototype is invalid.
+ *
+ * DECLARE_TRACE_NOARGS() passes "void" as the tracepoint prototype
+ * and "void *__data" as the callback prototype.
+ *
+ * DECLARE_TRACE() passes "proto" as the tracepoint protoype and
+ * "void *__data, proto" as the callback prototype.
+ */
+#define DECLARE_TRACE_NOARGS(name)                                     \
+               __DECLARE_TRACE(name, void, , void *__data, __data)
+
+#define DECLARE_TRACE(name, proto, args)                               \
+               __DECLARE_TRACE(name, PARAMS(proto), PARAMS(args),      \
+                               PARAMS(void *__data, proto),            \
+                               PARAMS(__data, args))
+
 #endif /* DECLARE_TRACE */
 
 #ifndef TRACE_EVENT
index 15ddd4483b09b9b94b47a9130bc0579c31468c74..60c81da77f0f36b94bde7d83562db55dfa707d92 100644 (file)
@@ -166,11 +166,11 @@ struct uinput_ff_erase {
 struct uinput_user_dev {
        char name[UINPUT_MAX_NAME_SIZE];
        struct input_id id;
-        int ff_effects_max;
-        int absmax[ABS_MAX + 1];
-        int absmin[ABS_MAX + 1];
-        int absfuzz[ABS_MAX + 1];
-        int absflat[ABS_MAX + 1];
+       int ff_effects_max;
+       int absmax[ABS_CNT];
+       int absmin[ABS_CNT];
+       int absfuzz[ABS_CNT];
+       int absflat[ABS_CNT];
 };
 #endif /* __UINPUT_H_ */
 
index 2389f93a28b568fa47a73bf83dc70b9f590fe433..92f1d99f0f172c377dee4a33a7c6587d7e562bba 100644 (file)
@@ -105,6 +105,22 @@ struct uac_as_header_descriptor_v2 {
        __u8 iChannelNames;
 } __attribute__((packed));
 
+/* 4.10.1.2 Class-Specific AS Isochronous Audio Data Endpoint Descriptor */
+
+struct uac2_iso_endpoint_descriptor {
+       __u8  bLength;                  /* in bytes: 8 */
+       __u8  bDescriptorType;          /* USB_DT_CS_ENDPOINT */
+       __u8  bDescriptorSubtype;       /* EP_GENERAL */
+       __u8  bmAttributes;
+       __u8  bmControls;
+       __u8  bLockDelayUnits;
+       __le16 wLockDelay;
+} __attribute__((packed));
+
+#define UAC2_CONTROL_PITCH             (3 << 0)
+#define UAC2_CONTROL_DATA_OVERRUN      (3 << 2)
+#define UAC2_CONTROL_DATA_UNDERRUN     (3 << 4)
+
 /* 6.1 Interrupt Data Message */
 
 #define UAC2_INTERRUPT_DATA_MSG_VENDOR (1 << 0)
diff --git a/include/linux/uuid.h b/include/linux/uuid.h
new file mode 100644 (file)
index 0000000..5b7efbf
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * UUID/GUID definition
+ *
+ * Copyright (C) 2010, Intel Corp.
+ *     Huang Ying <ying.huang@intel.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _LINUX_UUID_H_
+#define _LINUX_UUID_H_
+
+#include <linux/types.h>
+#include <linux/string.h>
+
+typedef struct {
+       __u8 b[16];
+} uuid_le;
+
+typedef struct {
+       __u8 b[16];
+} uuid_be;
+
+#define UUID_LE(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7)               \
+((uuid_le)                                                             \
+{{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \
+   (b) & 0xff, ((b) >> 8) & 0xff,                                      \
+   (c) & 0xff, ((c) >> 8) & 0xff,                                      \
+   (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }})
+
+#define UUID_BE(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7)               \
+((uuid_be)                                                             \
+{{ ((a) >> 24) & 0xff, ((a) >> 16) & 0xff, ((a) >> 8) & 0xff, (a) & 0xff, \
+   ((b) >> 8) & 0xff, (b) & 0xff,                                      \
+   ((c) >> 8) & 0xff, (c) & 0xff,                                      \
+   (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }})
+
+#define NULL_UUID_LE                                                   \
+       UUID_LE(0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00,     \
+               0x00, 0x00, 0x00, 0x00)
+
+#define NULL_UUID_BE                                                   \
+       UUID_BE(0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00,     \
+               0x00, 0x00, 0x00, 0x00)
+
+static inline int uuid_le_cmp(const uuid_le u1, const uuid_le u2)
+{
+       return memcmp(&u1, &u2, sizeof(uuid_le));
+}
+
+static inline int uuid_be_cmp(const uuid_be u1, const uuid_be u2)
+{
+       return memcmp(&u1, &u2, sizeof(uuid_be));
+}
+
+extern void uuid_le_gen(uuid_le *u);
+extern void uuid_be_gen(uuid_be *u);
+
+#endif
index 40d1709bdbf4a8b0cc01a7caa132ff0c09c54fda..aff5b4f740417ee39cc3b42c8c70bfe351fc4564 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/spinlock.h>
 #include <linux/device.h>
 #include <linux/mod_devicetable.h>
+#include <linux/gfp.h>
 
 /**
  * virtqueue - a queue to register buffers for sending or receiving.
@@ -14,7 +15,6 @@
  * @callback: the function to call when buffers are consumed (can be NULL).
  * @name: the name of this virtqueue (mainly for debugging)
  * @vdev: the virtio device this queue was created for.
- * @vq_ops: the operations for this virtqueue (see below).
  * @priv: a pointer for the virtqueue implementation to use.
  */
 struct virtqueue {
@@ -22,60 +22,71 @@ struct virtqueue {
        void (*callback)(struct virtqueue *vq);
        const char *name;
        struct virtio_device *vdev;
-       struct virtqueue_ops *vq_ops;
        void *priv;
 };
 
 /**
- * virtqueue_ops - operations for virtqueue abstraction layer
- * @add_buf: expose buffer to other end
+ * operations for virtqueue
+ * virtqueue_add_buf: expose buffer to other end
  *     vq: the struct virtqueue we're talking about.
  *     sg: the description of the buffer(s).
  *     out_num: the number of sg readable by other side
  *     in_num: the number of sg which are writable (after readable ones)
  *     data: the token identifying the buffer.
+ *     gfp: how to do memory allocations (if necessary).
  *      Returns remaining capacity of queue (sg segments) or a negative error.
- * @kick: update after add_buf
+ * virtqueue_kick: update after add_buf
  *     vq: the struct virtqueue
  *     After one or more add_buf calls, invoke this to kick the other side.
- * @get_buf: get the next used buffer
+ * virtqueue_get_buf: get the next used buffer
  *     vq: the struct virtqueue we're talking about.
  *     len: the length written into the buffer
  *     Returns NULL or the "data" token handed to add_buf.
- * @disable_cb: disable callbacks
+ * virtqueue_disable_cb: disable callbacks
  *     vq: the struct virtqueue we're talking about.
  *     Note that this is not necessarily synchronous, hence unreliable and only
  *     useful as an optimization.
- * @enable_cb: restart callbacks after disable_cb.
+ * virtqueue_enable_cb: restart callbacks after disable_cb.
  *     vq: the struct virtqueue we're talking about.
  *     This re-enables callbacks; it returns "false" if there are pending
  *     buffers in the queue, to detect a possible race between the driver
  *     checking for more work, and enabling callbacks.
- * @detach_unused_buf: detach first unused buffer
+ * virtqueue_detach_unused_buf: detach first unused buffer
  *     vq: the struct virtqueue we're talking about.
  *     Returns NULL or the "data" token handed to add_buf
  *
  * Locking rules are straightforward: the driver is responsible for
  * locking.  No two operations may be invoked simultaneously, with the exception
- * of @disable_cb.
+ * of virtqueue_disable_cb.
  *
  * All operations can be called in any context.
  */
-struct virtqueue_ops {
-       int (*add_buf)(struct virtqueue *vq,
-                      struct scatterlist sg[],
-                      unsigned int out_num,
-                      unsigned int in_num,
-                      void *data);
 
-       void (*kick)(struct virtqueue *vq);
+int virtqueue_add_buf_gfp(struct virtqueue *vq,
+                         struct scatterlist sg[],
+                         unsigned int out_num,
+                         unsigned int in_num,
+                         void *data,
+                         gfp_t gfp);
 
-       void *(*get_buf)(struct virtqueue *vq, unsigned int *len);
+static inline int virtqueue_add_buf(struct virtqueue *vq,
+                                   struct scatterlist sg[],
+                                   unsigned int out_num,
+                                   unsigned int in_num,
+                                   void *data)
+{
+       return virtqueue_add_buf_gfp(vq, sg, out_num, in_num, data, GFP_ATOMIC);
+}
 
-       void (*disable_cb)(struct virtqueue *vq);
-       bool (*enable_cb)(struct virtqueue *vq);
-       void *(*detach_unused_buf)(struct virtqueue *vq);
-};
+void virtqueue_kick(struct virtqueue *vq);
+
+void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len);
+
+void virtqueue_disable_cb(struct virtqueue *vq);
+
+bool virtqueue_enable_cb(struct virtqueue *vq);
+
+void *virtqueue_detach_unused_buf(struct virtqueue *vq);
 
 /**
  * virtio_device - representation of a device using virtio
index e52029e98919bb38401dd1848de418277ba271a9..167720d695ed00bb94b9174381de80f13fd6d009 100644 (file)
@@ -17,6 +17,8 @@
 #define VIRTIO_BLK_F_FLUSH     9       /* Cache flush command support */
 #define VIRTIO_BLK_F_TOPOLOGY  10      /* Topology information is available */
 
+#define VIRTIO_BLK_ID_BYTES    20      /* ID string length */
+
 struct virtio_blk_config {
        /* The capacity (in 512-byte sectors). */
        __u64 capacity;
@@ -67,6 +69,9 @@ struct virtio_blk_config {
 /* Cache flush command */
 #define VIRTIO_BLK_T_FLUSH     4
 
+/* Get device ID command */
+#define VIRTIO_BLK_T_GET_ID    8
+
 /* Barrier before this op. */
 #define VIRTIO_BLK_T_BARRIER   0x80000000
 
index 92228a8fbcbc8f688afa343252fdeb381baf23fc..a85064db8f94f165b57556b44c7aaceac144d6bb 100644 (file)
 
 /* Feature bits */
 #define VIRTIO_CONSOLE_F_SIZE  0       /* Does host provide console size? */
+#define VIRTIO_CONSOLE_F_MULTIPORT 1   /* Does host provide multiple ports? */
+
+#define VIRTIO_CONSOLE_BAD_ID          (~(u32)0)
 
 struct virtio_console_config {
        /* colums of the screens */
        __u16 cols;
        /* rows of the screens */
        __u16 rows;
+       /* max. number of ports this device can hold */
+       __u32 max_nr_ports;
 } __attribute__((packed));
 
+/*
+ * A message that's passed between the Host and the Guest for a
+ * particular port.
+ */
+struct virtio_console_control {
+       __u32 id;               /* Port number */
+       __u16 event;            /* The kind of control event (see below) */
+       __u16 value;            /* Extra information for the key */
+};
+
+/* Some events for control messages */
+#define VIRTIO_CONSOLE_DEVICE_READY    0
+#define VIRTIO_CONSOLE_PORT_ADD                1
+#define VIRTIO_CONSOLE_PORT_REMOVE     2
+#define VIRTIO_CONSOLE_PORT_READY      3
+#define VIRTIO_CONSOLE_CONSOLE_PORT    4
+#define VIRTIO_CONSOLE_RESIZE          5
+#define VIRTIO_CONSOLE_PORT_OPEN       6
+#define VIRTIO_CONSOLE_PORT_NAME       7
+
 #ifdef __KERNEL__
 int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int));
 #endif /* __KERNEL__ */
index 117f0dd8ad03fa3780b86b8feedbdbb1603c1576..7f43ccdc1d38c0eb919efe4891e1b91ec19c3705 100644 (file)
@@ -43,6 +43,10 @@ enum vm_event_item { PGPGIN, PGPGOUT, PSWPIN, PSWPOUT,
                KSWAPD_LOW_WMARK_HIT_QUICKLY, KSWAPD_HIGH_WMARK_HIT_QUICKLY,
                KSWAPD_SKIP_CONGESTION_WAIT,
                PAGEOUTRUN, ALLOCSTALL, PGROTATED,
+#ifdef CONFIG_COMPACTION
+               COMPACTBLOCKS, COMPACTPAGES, COMPACTPAGEFAILED,
+               COMPACTSTALL, COMPACTFAIL, COMPACTSUCCESS,
+#endif
 #ifdef CONFIG_HUGETLB_PAGE
                HTLB_BUDDY_PGALLOC, HTLB_BUDDY_PGALLOC_FAIL,
 #endif
index fb9b7e6e1e2d74f5750248efff6cb9cc956b2a18..0cfa1e9c4cc152239895304d67c6d1500cff7044 100644 (file)
@@ -37,7 +37,7 @@ struct inode;
 struct dentry;
 
 struct xattr_handler {
-       char *prefix;
+       const char *prefix;
        int flags;      /* fs private flags passed back to the handlers */
        size_t (*list)(struct dentry *dentry, char *list, size_t list_size,
                       const char *name, size_t name_len, int handler_flags);
diff --git a/include/linux/z2_battery.h b/include/linux/z2_battery.h
new file mode 100644 (file)
index 0000000..7b97504
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _LINUX_Z2_BATTERY_H
+#define _LINUX_Z2_BATTERY_H
+
+struct z2_battery_info {
+       int      batt_I2C_bus;
+       int      batt_I2C_addr;
+       int      batt_I2C_reg;
+       int      charge_gpio;
+       int      min_voltage;
+       int      max_voltage;
+       int      batt_div;
+       int      batt_mult;
+       int      batt_tech;
+       char    *batt_name;
+};
+
+#endif
index a7fb54808a236a2feaf48895823450a976fd6a19..156c26bb8bd7d0f71057b0ec5d6f3802e4792054 100644 (file)
@@ -86,6 +86,10 @@ do { \
 
 /**
  * enum p9_msg_t - 9P message types
+ * @P9_TSTATFS: file system status request
+ * @P9_RSTATFS: file system status response
+ * @P9_TRENAME: rename request
+ * @P9_RRENAME: rename response
  * @P9_TVERSION: version handshake request
  * @P9_RVERSION: version handshake response
  * @P9_TAUTH: request to establish authentication channel
@@ -125,6 +129,10 @@ do { \
  */
 
 enum p9_msg_t {
+       P9_TSTATFS = 8,
+       P9_RSTATFS,
+       P9_TRENAME = 20,
+       P9_RRENAME,
        P9_TVERSION = 100,
        P9_RVERSION,
        P9_TAUTH = 102,
@@ -350,6 +358,31 @@ struct p9_wstat {
 };
 
 /* Structures for Protocol Operations */
+struct p9_tstatfs {
+       u32 fid;
+};
+
+struct p9_rstatfs {
+       u32 type;
+       u32 bsize;
+       u64 blocks;
+       u64 bfree;
+       u64 bavail;
+       u64 files;
+       u64 ffree;
+       u64 fsid;
+       u32 namelen;
+};
+
+struct p9_trename {
+       u32 fid;
+       u32 newdirfid;
+       struct p9_str name;
+};
+
+struct p9_rrename {
+};
+
 struct p9_tversion {
        u32 msize;
        struct p9_str version;
index 4f3760afc20fb52d19a09f679f3e16313fed707d..7dd3ed85c782a928c42cecf878bb3e7bea8f4462 100644 (file)
@@ -195,6 +195,8 @@ struct p9_fid {
        struct list_head dlist; /* list of all fids attached to a dentry */
 };
 
+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 *);
 struct p9_client *p9_client_create(const char *dev_name, char *options);
 void p9_client_destroy(struct p9_client *clnt);
index 997603f2bf4c86e656e6013ecf40cc159d271b4a..9402543fc20d2dc65cec9f0100397aee71b4dbf9 100644 (file)
@@ -94,8 +94,8 @@ struct cfctrl_request_info {
        enum cfctrl_cmd cmd;
        u8 channel_id;
        struct cfctrl_link_param param;
-       struct cfctrl_request_info *next;
        struct cflayer *client_layer;
+       struct list_head list;
 };
 
 struct cfctrl {
@@ -103,7 +103,7 @@ struct cfctrl {
        struct cfctrl_rsp res;
        atomic_t req_seq_no;
        atomic_t rsp_seq_no;
-       struct cfctrl_request_info *first_req;
+       struct list_head list;
        /* Protects from simultaneous access to first_req list */
        spinlock_t info_list_lock;
 #ifndef CAIF_NO_LOOP
diff --git a/include/net/cls_cgroup.h b/include/net/cls_cgroup.h
new file mode 100644 (file)
index 0000000..726cc35
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * cls_cgroup.h                        Control Group Classifier
+ *
+ * Authors:    Thomas Graf <tgraf@suug.ch>
+ *
+ * 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 _NET_CLS_CGROUP_H
+#define _NET_CLS_CGROUP_H
+
+#include <linux/cgroup.h>
+#include <linux/hardirq.h>
+#include <linux/rcupdate.h>
+
+#ifdef CONFIG_CGROUPS
+struct cgroup_cls_state
+{
+       struct cgroup_subsys_state css;
+       u32 classid;
+};
+
+#ifdef CONFIG_NET_CLS_CGROUP
+static inline u32 task_cls_classid(struct task_struct *p)
+{
+       if (in_interrupt())
+               return 0;
+
+       return container_of(task_subsys_state(p, net_cls_subsys_id),
+                           struct cgroup_cls_state, css)->classid;
+}
+#else
+extern int net_cls_subsys_id;
+
+static inline u32 task_cls_classid(struct task_struct *p)
+{
+       int id;
+       u32 classid = 0;
+
+       if (in_interrupt())
+               return 0;
+
+       rcu_read_lock();
+       id = rcu_dereference(net_cls_subsys_id);
+       if (id >= 0)
+               classid = container_of(task_subsys_state(p, id),
+                                      struct cgroup_cls_state, css)->classid;
+       rcu_read_unlock();
+
+       return classid;
+}
+#endif
+#else
+static inline u32 task_cls_classid(struct task_struct *p)
+{
+       return 0;
+}
+#endif
+#endif  /* _NET_CLS_CGROUP_H */
index 63548f0a44b17e933fa37cbe8283fdb93bbb179a..452f229c380aea77f0adc5e018ef2972d7fcd368 100644 (file)
@@ -358,11 +358,11 @@ enum ip_defrag_users {
        IP_DEFRAG_LOCAL_DELIVER,
        IP_DEFRAG_CALL_RA_CHAIN,
        IP_DEFRAG_CONNTRACK_IN,
-       __IP_DEFRAG_CONNTRACK_IN_END    = IP_DEFRAG_CONNTRACK_IN + USHORT_MAX,
+       __IP_DEFRAG_CONNTRACK_IN_END    = IP_DEFRAG_CONNTRACK_IN + USHRT_MAX,
        IP_DEFRAG_CONNTRACK_OUT,
-       __IP_DEFRAG_CONNTRACK_OUT_END   = IP_DEFRAG_CONNTRACK_OUT + USHORT_MAX,
+       __IP_DEFRAG_CONNTRACK_OUT_END   = IP_DEFRAG_CONNTRACK_OUT + USHRT_MAX,
        IP_DEFRAG_CONNTRACK_BRIDGE_IN,
-       __IP_DEFRAG_CONNTRACK_BRIDGE_IN = IP_DEFRAG_CONNTRACK_BRIDGE_IN + USHORT_MAX,
+       __IP_DEFRAG_CONNTRACK_BRIDGE_IN = IP_DEFRAG_CONNTRACK_BRIDGE_IN + USHRT_MAX,
        IP_DEFRAG_VS_IN,
        IP_DEFRAG_VS_OUT,
        IP_DEFRAG_VS_FWD
index eba5cc00325aff321d81366b3e47c2895c265a9c..2600b69757b8c63d6ab8c570b9f0e26f195468c4 100644 (file)
@@ -354,11 +354,11 @@ struct inet_frag_queue;
 enum ip6_defrag_users {
        IP6_DEFRAG_LOCAL_DELIVER,
        IP6_DEFRAG_CONNTRACK_IN,
-       __IP6_DEFRAG_CONNTRACK_IN       = IP6_DEFRAG_CONNTRACK_IN + USHORT_MAX,
+       __IP6_DEFRAG_CONNTRACK_IN       = IP6_DEFRAG_CONNTRACK_IN + USHRT_MAX,
        IP6_DEFRAG_CONNTRACK_OUT,
-       __IP6_DEFRAG_CONNTRACK_OUT      = IP6_DEFRAG_CONNTRACK_OUT + USHORT_MAX,
+       __IP6_DEFRAG_CONNTRACK_OUT      = IP6_DEFRAG_CONNTRACK_OUT + USHRT_MAX,
        IP6_DEFRAG_CONNTRACK_BRIDGE_IN,
-       __IP6_DEFRAG_CONNTRACK_BRIDGE_IN = IP6_DEFRAG_CONNTRACK_BRIDGE_IN + USHORT_MAX,
+       __IP6_DEFRAG_CONNTRACK_BRIDGE_IN = IP6_DEFRAG_CONNTRACK_BRIDGE_IN + USHRT_MAX,
 };
 
 struct ip6_create_arg {
index 5be900d19660543adfbd040bc9abfe42f1e78fdb..de22cbfef23224c6aed205de5179c59644f5384c 100644 (file)
@@ -815,6 +815,7 @@ enum ieee80211_key_flags {
  *     encrypted in hardware.
  * @alg: The key algorithm.
  * @flags: key flags, see &enum ieee80211_key_flags.
+ * @ap_addr: AP's MAC address
  * @keyidx: the key index (0-3)
  * @keylen: key material length
  * @key: key material. For ALG_TKIP the key is encoded as a 256-bit (32 byte)
@@ -831,7 +832,6 @@ struct ieee80211_key_conf {
        u8 iv_len;
        u8 hw_key_idx;
        u8 flags;
-       u8 *ap_addr;
        s8 keyidx;
        u8 keylen;
        u8 key[0];
@@ -1638,6 +1638,8 @@ enum ieee80211_ampdu_mlme_action {
  *     Returns a negative error code on failure.
  *     The callback must be atomic.
  *
+ * @get_survey: Return per-channel survey information
+ *
  * @rfkill_poll: Poll rfkill hardware state. If you need this, you also
  *     need to set wiphy->rfkill_poll to %true before registration,
  *     and need to call wiphy_rfkill_set_hw_state() in the callback.
index dffde8e6920eb43c37184692fa6d49d054938366..3d7524fba1946d2993033f44b8330f210eaa4bb4 100644 (file)
@@ -61,7 +61,7 @@ static inline int nf_conntrack_confirm(struct sk_buff *skb)
        int ret = NF_ACCEPT;
 
        if (ct && ct != &nf_conntrack_untracked) {
-               if (!nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct))
+               if (!nf_ct_is_confirmed(ct))
                        ret = __nf_conntrack_confirm(skb);
                if (likely(ret == NF_ACCEPT))
                        nf_ct_deliver_cached_events(ct);
index 6173c619913ae51b5bdb2c010f544ce451fe99c7..4b860116e096c9e83d6d3cf289d0bec1bd3750d3 100644 (file)
@@ -876,7 +876,7 @@ struct sctp_transport {
 
        /* Reference counting. */
        atomic_t refcnt;
-       int      dead:1,
+       __u32    dead:1,
                /* RTO-Pending : A flag used to track if one of the DATA
                 *              chunks sent to this address is currently being
                 *              used to compute a RTT. If this flag is 0,
index 5697caf8cc76044efb9fc61dc9b7c931d74d95fa..ca241ea148758a555d123343e2fe8639f7dd5bd3 100644 (file)
@@ -312,7 +312,7 @@ struct sock {
        void                    *sk_security;
 #endif
        __u32                   sk_mark;
-       /* XXX 4 bytes hole on 64 bit */
+       u32                     sk_classid;
        void                    (*sk_state_change)(struct sock *sk);
        void                    (*sk_data_ready)(struct sock *sk, int bytes);
        void                    (*sk_write_space)(struct sock *sk);
@@ -1026,15 +1026,23 @@ extern void release_sock(struct sock *sk);
                                SINGLE_DEPTH_NESTING)
 #define bh_unlock_sock(__sk)   spin_unlock(&((__sk)->sk_lock.slock))
 
-static inline void lock_sock_bh(struct sock *sk)
+extern bool lock_sock_fast(struct sock *sk);
+/**
+ * unlock_sock_fast - complement of lock_sock_fast
+ * @sk: socket
+ * @slow: slow mode
+ *
+ * fast unlock socket for user context.
+ * If slow mode is on, we call regular release_sock()
+ */
+static inline void unlock_sock_fast(struct sock *sk, bool slow)
 {
-       spin_lock_bh(&sk->sk_lock.slock);
+       if (slow)
+               release_sock(sk);
+       else
+               spin_unlock_bh(&sk->sk_lock.slock);
 }
 
-static inline void unlock_sock_bh(struct sock *sk)
-{
-       spin_unlock_bh(&sk->sk_lock.slock);
-}
 
 extern struct sock             *sk_alloc(struct net *net, int family,
                                          gfp_t priority,
@@ -1074,6 +1082,14 @@ extern void *sock_kmalloc(struct sock *sk, int size,
 extern void sock_kfree_s(struct sock *sk, void *mem, int size);
 extern void sk_send_sigurg(struct sock *sk);
 
+#ifdef CONFIG_CGROUPS
+extern void sock_update_classid(struct sock *sk);
+#else
+static inline void sock_update_classid(struct sock *sk)
+{
+}
+#endif
+
 /*
  * Functions to fill in entries in struct proto_ops when a protocol
  * does not implement a particular function.
@@ -1404,7 +1420,7 @@ static inline int sk_has_allocations(const struct sock *sk)
 
 /**
  * wq_has_sleeper - check if there are any waiting processes
- * @sk: struct socket_wq
+ * @wq: struct socket_wq
  *
  * Returns true if socket_wq has waiting processes
  *
index 310d31474034ac634077f9dfb8cf58c254cd8314..f3e8f3c07725149d43ede426d1ebbb0b6cbd9aa8 100644 (file)
@@ -1172,7 +1172,9 @@ struct ib_client {
 struct ib_device *ib_alloc_device(size_t size);
 void ib_dealloc_device(struct ib_device *device);
 
-int ib_register_device   (struct ib_device *device);
+int ib_register_device(struct ib_device *device,
+                      int (*port_callback)(struct ib_device *,
+                                           u8, struct kobject *));
 void ib_unregister_device(struct ib_device *device);
 
 int ib_register_client   (struct ib_client *client);
index 2aa6aa3e8f613e038df5a595c4952ae721f14102..f5b1ba90e952f71535d13b8c0a7d9a68782d5a07 100644 (file)
@@ -353,7 +353,7 @@ TRACE_EVENT(ext4_discard_blocks,
                  jbd2_dev_to_name(__entry->dev), __entry->blk, __entry->count)
 );
 
-TRACE_EVENT(ext4_mb_new_inode_pa,
+DECLARE_EVENT_CLASS(ext4__mb_new_pa,
        TP_PROTO(struct ext4_allocation_context *ac,
                 struct ext4_prealloc_space *pa),
 
@@ -381,32 +381,20 @@ TRACE_EVENT(ext4_mb_new_inode_pa,
                  __entry->pa_pstart, __entry->pa_len, __entry->pa_lstart)
 );
 
-TRACE_EVENT(ext4_mb_new_group_pa,
+DEFINE_EVENT(ext4__mb_new_pa, ext4_mb_new_inode_pa,
+
        TP_PROTO(struct ext4_allocation_context *ac,
                 struct ext4_prealloc_space *pa),
 
-       TP_ARGS(ac, pa),
-
-       TP_STRUCT__entry(
-               __field(        dev_t,  dev                     )
-               __field(        ino_t,  ino                     )
-               __field(        __u64,  pa_pstart               )
-               __field(        __u32,  pa_len                  )
-               __field(        __u64,  pa_lstart               )
+       TP_ARGS(ac, pa)
+);
 
-       ),
+DEFINE_EVENT(ext4__mb_new_pa, ext4_mb_new_group_pa,
 
-       TP_fast_assign(
-               __entry->dev            = ac->ac_sb->s_dev;
-               __entry->ino            = ac->ac_inode->i_ino;
-               __entry->pa_pstart      = pa->pa_pstart;
-               __entry->pa_len         = pa->pa_len;
-               __entry->pa_lstart      = pa->pa_lstart;
-       ),
+       TP_PROTO(struct ext4_allocation_context *ac,
+                struct ext4_prealloc_space *pa),
 
-       TP_printk("dev %s ino %lu pstart %llu len %u lstart %llu",
-                 jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino,
-                 __entry->pa_pstart, __entry->pa_len, __entry->pa_lstart)
+       TP_ARGS(ac, pa)
 );
 
 TRACE_EVENT(ext4_mb_release_inode_pa,
@@ -618,9 +606,9 @@ TRACE_EVENT(ext4_free_blocks,
 );
 
 TRACE_EVENT(ext4_sync_file,
-       TP_PROTO(struct file *file, struct dentry *dentry, int datasync),
+       TP_PROTO(struct file *file, int datasync),
 
-       TP_ARGS(file, dentry, datasync),
+       TP_ARGS(file, datasync),
 
        TP_STRUCT__entry(
                __field(        dev_t,  dev                     )
@@ -630,6 +618,8 @@ TRACE_EVENT(ext4_sync_file,
        ),
 
        TP_fast_assign(
+               struct dentry *dentry = file->f_path.dentry;
+
                __entry->dev            = dentry->d_inode->i_sb->s_dev;
                __entry->ino            = dentry->d_inode->i_ino;
                __entry->datasync       = datasync;
@@ -790,7 +780,7 @@ TRACE_EVENT(ext4_mballoc_prealloc,
                  __entry->result_len, __entry->result_logical)
 );
 
-TRACE_EVENT(ext4_mballoc_discard,
+DECLARE_EVENT_CLASS(ext4__mballoc,
        TP_PROTO(struct ext4_allocation_context *ac),
 
        TP_ARGS(ac),
@@ -819,33 +809,18 @@ TRACE_EVENT(ext4_mballoc_discard,
                  __entry->result_len, __entry->result_logical)
 );
 
-TRACE_EVENT(ext4_mballoc_free,
+DEFINE_EVENT(ext4__mballoc, ext4_mballoc_discard,
+
        TP_PROTO(struct ext4_allocation_context *ac),
 
-       TP_ARGS(ac),
+       TP_ARGS(ac)
+);
 
-       TP_STRUCT__entry(
-               __field(        dev_t,  dev                     )
-               __field(        ino_t,  ino                     )
-               __field(        __u32,  result_logical          )
-               __field(          int,  result_start            )
-               __field(        __u32,  result_group            )
-               __field(          int,  result_len              )
-       ),
+DEFINE_EVENT(ext4__mballoc, ext4_mballoc_free,
 
-       TP_fast_assign(
-               __entry->dev            = ac->ac_inode->i_sb->s_dev;
-               __entry->ino            = ac->ac_inode->i_ino;
-               __entry->result_logical = ac->ac_b_ex.fe_logical;
-               __entry->result_start   = ac->ac_b_ex.fe_start;
-               __entry->result_group   = ac->ac_b_ex.fe_group;
-               __entry->result_len     = ac->ac_b_ex.fe_len;
-       ),
+       TP_PROTO(struct ext4_allocation_context *ac),
 
-       TP_printk("dev %s inode %lu extent %u/%d/%u@%u ",
-                 jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino,
-                 __entry->result_group, __entry->result_start,
-                 __entry->result_len, __entry->result_logical)
+       TP_ARGS(ac)
 );
 
 TRACE_EVENT(ext4_forget,
@@ -974,6 +949,39 @@ TRACE_EVENT(ext4_da_release_space,
                  __entry->reserved_meta_blocks, __entry->allocated_meta_blocks)
 );
 
+DECLARE_EVENT_CLASS(ext4__bitmap_load,
+       TP_PROTO(struct super_block *sb, unsigned long group),
+
+       TP_ARGS(sb, group),
+
+       TP_STRUCT__entry(
+               __field(        dev_t,  dev                     )
+               __field(        __u32,  group                   )
+
+       ),
+
+       TP_fast_assign(
+               __entry->dev    = sb->s_dev;
+               __entry->group  = group;
+       ),
+
+       TP_printk("dev %s group %u",
+                 jbd2_dev_to_name(__entry->dev), __entry->group)
+);
+
+DEFINE_EVENT(ext4__bitmap_load, ext4_mb_bitmap_load,
+
+       TP_PROTO(struct super_block *sb, unsigned long group),
+
+       TP_ARGS(sb, group)
+);
+
+DEFINE_EVENT(ext4__bitmap_load, ext4_mb_buddy_bitmap_load,
+
+       TP_PROTO(struct super_block *sb, unsigned long group),
+
+       TP_ARGS(sb, group)
+);
 
 #endif /* _TRACE_EXT4_H */
 
index b17d49dfc3ef7dc55946726d432162f1f5b0501d..6dd3a51ab1cb2e09a092434ebe3aa545d69124dc 100644 (file)
@@ -5,7 +5,6 @@
 
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM kvm
-#define TRACE_INCLUDE_FILE kvm
 
 #if defined(__KVM_HAVE_IOAPIC)
 TRACE_EVENT(kvm_set_irq,
index 88c59c13ea7bdfd58edb7ec715fe8764288366ae..3d685d1f2a03f0099f159ac96eb648eed107a0a7 100644 (file)
                struct trace_entry      ent;                            \
                tstruct                                                 \
                char                    __data[0];                      \
-       };
+       };                                                              \
+                                                                       \
+       static struct ftrace_event_class event_class_##name;
+
 #undef DEFINE_EVENT
 #define DEFINE_EVENT(template, name, proto, args)      \
-       static struct ftrace_event_call                 \
+       static struct ftrace_event_call __used          \
        __attribute__((__aligned__(4))) event_##name
 
 #undef DEFINE_EVENT_PRINT
  *
  *     entry = iter->ent;
  *
- *     if (entry->type != event_<call>.id) {
+ *     if (entry->type != event_<call>->event.type) {
  *             WARN_ON_ONCE(1);
  *             return TRACE_TYPE_UNHANDLED;
  *     }
 #undef DECLARE_EVENT_CLASS
 #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
 static notrace enum print_line_t                                       \
-ftrace_raw_output_id_##call(int event_id, const char *name,            \
-                           struct trace_iterator *iter, int flags)     \
+ftrace_raw_output_##call(struct trace_iterator *iter, int flags,       \
+                        struct trace_event *trace_event)               \
 {                                                                      \
+       struct ftrace_event_call *event;                                \
        struct trace_seq *s = &iter->seq;                               \
        struct ftrace_raw_##call *field;                                \
        struct trace_entry *entry;                                      \
        struct trace_seq *p;                                            \
        int ret;                                                        \
                                                                        \
+       event = container_of(trace_event, struct ftrace_event_call,     \
+                            event);                                    \
+                                                                       \
        entry = iter->ent;                                              \
                                                                        \
-       if (entry->type != event_id) {                                  \
+       if (entry->type != event->event.type) {                         \
                WARN_ON_ONCE(1);                                        \
                return TRACE_TYPE_UNHANDLED;                            \
        }                                                               \
@@ -226,7 +233,7 @@ ftrace_raw_output_id_##call(int event_id, const char *name,         \
                                                                        \
        p = &get_cpu_var(ftrace_event_seq);                             \
        trace_seq_init(p);                                              \
-       ret = trace_seq_printf(s, "%s: ", name);                        \
+       ret = trace_seq_printf(s, "%s: ", event->name);                 \
        if (ret)                                                        \
                ret = trace_seq_printf(s, print);                       \
        put_cpu();                                                      \
@@ -234,21 +241,16 @@ ftrace_raw_output_id_##call(int event_id, const char *name,               \
                return TRACE_TYPE_PARTIAL_LINE;                         \
                                                                        \
        return TRACE_TYPE_HANDLED;                                      \
-}
-
-#undef DEFINE_EVENT
-#define DEFINE_EVENT(template, name, proto, args)                      \
-static notrace enum print_line_t                                       \
-ftrace_raw_output_##name(struct trace_iterator *iter, int flags)       \
-{                                                                      \
-       return ftrace_raw_output_id_##template(event_##name.id,         \
-                                              #name, iter, flags);     \
-}
+}                                                                      \
+static struct trace_event_functions ftrace_event_type_funcs_##call = { \
+       .trace                  = ftrace_raw_output_##call,             \
+};
 
 #undef DEFINE_EVENT_PRINT
 #define DEFINE_EVENT_PRINT(template, call, proto, args, print)         \
 static notrace enum print_line_t                                       \
-ftrace_raw_output_##call(struct trace_iterator *iter, int flags)       \
+ftrace_raw_output_##call(struct trace_iterator *iter, int flags,       \
+                        struct trace_event *event)                     \
 {                                                                      \
        struct trace_seq *s = &iter->seq;                               \
        struct ftrace_raw_##template *field;                            \
@@ -258,7 +260,7 @@ ftrace_raw_output_##call(struct trace_iterator *iter, int flags)    \
                                                                        \
        entry = iter->ent;                                              \
                                                                        \
-       if (entry->type != event_##call.id) {                           \
+       if (entry->type != event_##call.event.type) {                   \
                WARN_ON_ONCE(1);                                        \
                return TRACE_TYPE_UNHANDLED;                            \
        }                                                               \
@@ -275,7 +277,10 @@ ftrace_raw_output_##call(struct trace_iterator *iter, int flags)   \
                return TRACE_TYPE_PARTIAL_LINE;                         \
                                                                        \
        return TRACE_TYPE_HANDLED;                                      \
-}
+}                                                                      \
+static struct trace_event_functions ftrace_event_type_funcs_##call = { \
+       .trace                  = ftrace_raw_output_##call,             \
+};
 
 #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
 
@@ -381,80 +386,18 @@ static inline notrace int ftrace_get_offsets_##call(                      \
 
 #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
 
-#ifdef CONFIG_PERF_EVENTS
-
-/*
- * Generate the functions needed for tracepoint perf_event support.
- *
- * NOTE: The insertion profile callback (ftrace_profile_<call>) is defined later
- *
- * static int ftrace_profile_enable_<call>(void)
- * {
- *     return register_trace_<call>(ftrace_profile_<call>);
- * }
- *
- * static void ftrace_profile_disable_<call>(void)
- * {
- *     unregister_trace_<call>(ftrace_profile_<call>);
- * }
- *
- */
-
-#undef DECLARE_EVENT_CLASS
-#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print)
-
-#undef DEFINE_EVENT
-#define DEFINE_EVENT(template, name, proto, args)                      \
-                                                                       \
-static void perf_trace_##name(proto);                                  \
-                                                                       \
-static notrace int                                                     \
-perf_trace_enable_##name(struct ftrace_event_call *unused)             \
-{                                                                      \
-       return register_trace_##name(perf_trace_##name);                \
-}                                                                      \
-                                                                       \
-static notrace void                                                    \
-perf_trace_disable_##name(struct ftrace_event_call *unused)            \
-{                                                                      \
-       unregister_trace_##name(perf_trace_##name);                     \
-}
-
-#undef DEFINE_EVENT_PRINT
-#define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
-       DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
-
-#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
-
-#endif /* CONFIG_PERF_EVENTS */
-
 /*
  * Stage 4 of the trace events.
  *
  * Override the macros in <trace/trace_events.h> to include the following:
  *
- * static void ftrace_event_<call>(proto)
- * {
- *     event_trace_printk(_RET_IP_, "<call>: " <fmt>);
- * }
- *
- * static int ftrace_reg_event_<call>(struct ftrace_event_call *unused)
- * {
- *     return register_trace_<call>(ftrace_event_<call>);
- * }
- *
- * static void ftrace_unreg_event_<call>(struct ftrace_event_call *unused)
- * {
- *     unregister_trace_<call>(ftrace_event_<call>);
- * }
- *
- *
  * For those macros defined with TRACE_EVENT:
  *
  * static struct ftrace_event_call event_<call>;
  *
- * static void ftrace_raw_event_<call>(proto)
+ * static void ftrace_raw_event_<call>(void *__data, proto)
  * {
+ *     struct ftrace_event_call *event_call = __data;
  *     struct ftrace_data_offsets_<call> __maybe_unused __data_offsets;
  *     struct ring_buffer_event *event;
  *     struct ftrace_raw_<call> *entry; <-- defined in stage 1
@@ -469,7 +412,7 @@ perf_trace_disable_##name(struct ftrace_event_call *unused)         \
  *     __data_size = ftrace_get_offsets_<call>(&__data_offsets, args);
  *
  *     event = trace_current_buffer_lock_reserve(&buffer,
- *                               event_<call>.id,
+ *                               event_<call>->event.type,
  *                               sizeof(*entry) + __data_size,
  *                               irq_flags, pc);
  *     if (!event)
@@ -484,43 +427,42 @@ perf_trace_disable_##name(struct ftrace_event_call *unused)               \
  *                                                event, irq_flags, pc);
  * }
  *
- * static int ftrace_raw_reg_event_<call>(struct ftrace_event_call *unused)
- * {
- *     return register_trace_<call>(ftrace_raw_event_<call>);
- * }
- *
- * static void ftrace_unreg_event_<call>(struct ftrace_event_call *unused)
- * {
- *     unregister_trace_<call>(ftrace_raw_event_<call>);
- * }
- *
  * static struct trace_event ftrace_event_type_<call> = {
  *     .trace                  = ftrace_raw_output_<call>, <-- stage 2
  * };
  *
  * static const char print_fmt_<call>[] = <TP_printk>;
  *
+ * static struct ftrace_event_class __used event_class_<template> = {
+ *     .system                 = "<system>",
+ *     .define_fields          = ftrace_define_fields_<call>,
+ *     .fields                 = LIST_HEAD_INIT(event_class_##call.fields),
+ *     .raw_init               = trace_event_raw_init,
+ *     .probe                  = ftrace_raw_event_##call,
+ * };
+ *
  * static struct ftrace_event_call __used
  * __attribute__((__aligned__(4)))
  * __attribute__((section("_ftrace_events"))) event_<call> = {
  *     .name                   = "<call>",
- *     .system                 = "<system>",
- *     .raw_init               = trace_event_raw_init,
- *     .regfunc                = ftrace_reg_event_<call>,
- *     .unregfunc              = ftrace_unreg_event_<call>,
+ *     .class                  = event_class_<template>,
+ *     .event                  = &ftrace_event_type_<call>,
  *     .print_fmt              = print_fmt_<call>,
- *     .define_fields          = ftrace_define_fields_<call>,
- * }
+ * };
  *
  */
 
 #ifdef CONFIG_PERF_EVENTS
 
+#define _TRACE_PERF_PROTO(call, proto)                                 \
+       static notrace void                                             \
+       perf_trace_##call(void *__data, proto);
+
 #define _TRACE_PERF_INIT(call)                                         \
-       .perf_event_enable = perf_trace_enable_##call,                  \
-       .perf_event_disable = perf_trace_disable_##call,
+       .perf_probe             = perf_trace_##call,
 
 #else
+#define _TRACE_PERF_PROTO(call, proto)
 #define _TRACE_PERF_INIT(call)
 #endif /* CONFIG_PERF_EVENTS */
 
@@ -554,9 +496,9 @@ perf_trace_disable_##name(struct ftrace_event_call *unused)         \
 #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
                                                                        \
 static notrace void                                                    \
-ftrace_raw_event_id_##call(struct ftrace_event_call *event_call,       \
-                                      proto)                           \
+ftrace_raw_event_##call(void *__data, proto)                           \
 {                                                                      \
+       struct ftrace_event_call *event_call = __data;                  \
        struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\
        struct ring_buffer_event *event;                                \
        struct ftrace_raw_##call *entry;                                \
@@ -571,7 +513,7 @@ ftrace_raw_event_id_##call(struct ftrace_event_call *event_call,    \
        __data_size = ftrace_get_offsets_##call(&__data_offsets, args); \
                                                                        \
        event = trace_current_buffer_lock_reserve(&buffer,              \
-                                event_call->id,                        \
+                                event_call->event.type,                \
                                 sizeof(*entry) + __data_size,          \
                                 irq_flags, pc);                        \
        if (!event)                                                     \
@@ -586,34 +528,21 @@ ftrace_raw_event_id_##call(struct ftrace_event_call *event_call,  \
                trace_nowake_buffer_unlock_commit(buffer,               \
                                                  event, irq_flags, pc); \
 }
+/*
+ * The ftrace_test_probe is compiled out, it is only here as a build time check
+ * to make sure that if the tracepoint handling changes, the ftrace probe will
+ * fail to compile unless it too is updated.
+ */
 
 #undef DEFINE_EVENT
 #define DEFINE_EVENT(template, call, proto, args)                      \
-                                                                       \
-static notrace void ftrace_raw_event_##call(proto)                     \
-{                                                                      \
-       ftrace_raw_event_id_##template(&event_##call, args);            \
-}                                                                      \
-                                                                       \
-static notrace int                                                     \
-ftrace_raw_reg_event_##call(struct ftrace_event_call *unused)          \
+static inline void ftrace_test_probe_##call(void)                      \
 {                                                                      \
-       return register_trace_##call(ftrace_raw_event_##call);          \
-}                                                                      \
-                                                                       \
-static notrace void                                                    \
-ftrace_raw_unreg_event_##call(struct ftrace_event_call *unused)                \
-{                                                                      \
-       unregister_trace_##call(ftrace_raw_event_##call);               \
-}                                                                      \
-                                                                       \
-static struct trace_event ftrace_event_type_##call = {                 \
-       .trace                  = ftrace_raw_output_##call,             \
-};
+       check_trace_callback_type_##call(ftrace_raw_event_##template);  \
+}
 
 #undef DEFINE_EVENT_PRINT
-#define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
-       DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
+#define DEFINE_EVENT_PRINT(template, name, proto, args, print)
 
 #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
 
@@ -630,7 +559,16 @@ static struct trace_event ftrace_event_type_##call = {                     \
 
 #undef DECLARE_EVENT_CLASS
 #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
-static const char print_fmt_##call[] = print;
+_TRACE_PERF_PROTO(call, PARAMS(proto));                                        \
+static const char print_fmt_##call[] = print;                          \
+static struct ftrace_event_class __used event_class_##call = {         \
+       .system                 = __stringify(TRACE_SYSTEM),            \
+       .define_fields          = ftrace_define_fields_##call,          \
+       .fields                 = LIST_HEAD_INIT(event_class_##call.fields),\
+       .raw_init               = trace_event_raw_init,                 \
+       .probe                  = ftrace_raw_event_##call,              \
+       _TRACE_PERF_INIT(call)                                          \
+};
 
 #undef DEFINE_EVENT
 #define DEFINE_EVENT(template, call, proto, args)                      \
@@ -639,15 +577,10 @@ static struct ftrace_event_call __used                                    \
 __attribute__((__aligned__(4)))                                                \
 __attribute__((section("_ftrace_events"))) event_##call = {            \
        .name                   = #call,                                \
-       .system                 = __stringify(TRACE_SYSTEM),            \
-       .event                  = &ftrace_event_type_##call,            \
-       .raw_init               = trace_event_raw_init,                 \
-       .regfunc                = ftrace_raw_reg_event_##call,          \
-       .unregfunc              = ftrace_raw_unreg_event_##call,        \
+       .class                  = &event_class_##template,              \
+       .event.funcs            = &ftrace_event_type_funcs_##template,  \
        .print_fmt              = print_fmt_##template,                 \
-       .define_fields          = ftrace_define_fields_##template,      \
-       _TRACE_PERF_INIT(call)                                  \
-}
+};
 
 #undef DEFINE_EVENT_PRINT
 #define DEFINE_EVENT_PRINT(template, call, proto, args, print)         \
@@ -658,14 +591,9 @@ static struct ftrace_event_call __used                                     \
 __attribute__((__aligned__(4)))                                                \
 __attribute__((section("_ftrace_events"))) event_##call = {            \
        .name                   = #call,                                \
-       .system                 = __stringify(TRACE_SYSTEM),            \
-       .event                  = &ftrace_event_type_##call,            \
-       .raw_init               = trace_event_raw_init,                 \
-       .regfunc                = ftrace_raw_reg_event_##call,          \
-       .unregfunc              = ftrace_raw_unreg_event_##call,        \
+       .class                  = &event_class_##template,              \
+       .event.funcs            = &ftrace_event_type_funcs_##call,      \
        .print_fmt              = print_fmt_##call,                     \
-       .define_fields          = ftrace_define_fields_##template,      \
-       _TRACE_PERF_INIT(call)                                  \
 }
 
 #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
@@ -765,17 +693,20 @@ __attribute__((section("_ftrace_events"))) event_##call = {               \
 #undef DECLARE_EVENT_CLASS
 #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
 static notrace void                                                    \
-perf_trace_templ_##call(struct ftrace_event_call *event_call,          \
-                       struct pt_regs *__regs, proto)                  \
+perf_trace_##call(void *__data, proto)                                 \
 {                                                                      \
+       struct ftrace_event_call *event_call = __data;                  \
        struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\
        struct ftrace_raw_##call *entry;                                \
+       struct pt_regs __regs;                                          \
        u64 __addr = 0, __count = 1;                                    \
-       unsigned long irq_flags;                                        \
+       struct hlist_head *head;                                        \
        int __entry_size;                                               \
        int __data_size;                                                \
        int rctx;                                                       \
                                                                        \
+       perf_fetch_caller_regs(&__regs, 1);                             \
+                                                                       \
        __data_size = ftrace_get_offsets_##call(&__data_offsets, args); \
        __entry_size = ALIGN(__data_size + sizeof(*entry) + sizeof(u32),\
                             sizeof(u64));                              \
@@ -784,32 +715,34 @@ perf_trace_templ_##call(struct ftrace_event_call *event_call,             \
        if (WARN_ONCE(__entry_size > PERF_MAX_TRACE_SIZE,               \
                      "profile buffer not large enough"))               \
                return;                                                 \
+                                                                       \
        entry = (struct ftrace_raw_##call *)perf_trace_buf_prepare(     \
-               __entry_size, event_call->id, &rctx, &irq_flags);       \
+               __entry_size, event_call->event.type, &__regs, &rctx);  \
        if (!entry)                                                     \
                return;                                                 \
+                                                                       \
        tstruct                                                         \
                                                                        \
        { assign; }                                                     \
                                                                        \
+       head = per_cpu_ptr(event_call->perf_events, smp_processor_id());\
        perf_trace_buf_submit(entry, __entry_size, rctx, __addr,        \
-                              __count, irq_flags, __regs);             \
+               __count, &__regs, head);                                \
 }
 
+/*
+ * This part is compiled out, it is only here as a build time check
+ * to make sure that if the tracepoint handling changes, the
+ * perf probe will fail to compile unless it too is updated.
+ */
 #undef DEFINE_EVENT
 #define DEFINE_EVENT(template, call, proto, args)                      \
-static notrace void perf_trace_##call(proto)                           \
+static inline void perf_test_probe_##call(void)                                \
 {                                                                      \
-       struct ftrace_event_call *event_call = &event_##call;           \
-       struct pt_regs *__regs = &get_cpu_var(perf_trace_regs);         \
-                                                                       \
-       perf_fetch_caller_regs(__regs, 1);                              \
-                                                                       \
-       perf_trace_templ_##template(event_call, __regs, args);          \
-                                                                       \
-       put_cpu_var(perf_trace_regs);                                   \
+       check_trace_callback_type_##call(perf_trace_##template);        \
 }
 
+
 #undef DEFINE_EVENT_PRINT
 #define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
        DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
index e5e5f48dbfb3f0a378cd1cc4dcfdcc15b7eb308e..257e08960d7b7f1c232ca6cef97f1cac3f0737e5 100644 (file)
@@ -25,6 +25,8 @@ struct syscall_metadata {
        int             nb_args;
        const char      **types;
        const char      **args;
+       struct list_head enter_fields;
+       struct list_head exit_fields;
 
        struct ftrace_event_call *enter_event;
        struct ftrace_event_call *exit_event;
@@ -34,16 +36,16 @@ struct syscall_metadata {
 extern unsigned long arch_syscall_addr(int nr);
 extern int init_syscall_trace(struct ftrace_event_call *call);
 
-extern int syscall_enter_define_fields(struct ftrace_event_call *call);
-extern int syscall_exit_define_fields(struct ftrace_event_call *call);
 extern int reg_event_syscall_enter(struct ftrace_event_call *call);
 extern void unreg_event_syscall_enter(struct ftrace_event_call *call);
 extern int reg_event_syscall_exit(struct ftrace_event_call *call);
 extern void unreg_event_syscall_exit(struct ftrace_event_call *call);
 extern int
 ftrace_format_syscall(struct ftrace_event_call *call, struct trace_seq *s);
-enum print_line_t print_syscall_enter(struct trace_iterator *iter, int flags);
-enum print_line_t print_syscall_exit(struct trace_iterator *iter, int flags);
+enum print_line_t print_syscall_enter(struct trace_iterator *iter, int flags,
+                                     struct trace_event *event);
+enum print_line_t print_syscall_exit(struct trace_iterator *iter, int flags,
+                                    struct trace_event *event);
 #endif
 
 #ifdef CONFIG_PERF_EVENTS
index 89d43b3d4cb9e3fe713fe5b8eaeb2de0616eb9fa..6316cdabf73f5756a300ef501fe5a1aa11acef53 100644 (file)
@@ -99,6 +99,7 @@ struct lcd_sync_arg {
 #define FBIPUT_COLOR           _IOW('F', 6, int)
 #define FBIPUT_HSYNC           _IOW('F', 9, int)
 #define FBIPUT_VSYNC           _IOW('F', 10, int)
+#define FBIO_WAITFORVSYNC      _IOW('F', 0x20, u_int32_t)
 
 #endif  /* ifndef DA8XX_FB_H */
 
index 2cc893fc1f8515364ce480a5c6c827a1dc58428e..288205457713bab6191e42e7a8f99bd01861ec51 100644 (file)
@@ -34,8 +34,6 @@ enum { LCDC_CLK_BUS, LCDC_CLK_PERIPHERAL, LCDC_CLK_EXTERNAL };
 #define LCDC_FLAGS_HSCNT (1 << 3) /* Disable HSYNC during VBLANK */
 #define LCDC_FLAGS_DWCNT (1 << 4) /* Disable dotclock during blanking */
 
-#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
-
 struct sh_mobile_lcdc_sys_bus_cfg {
        unsigned long ldmt2r;
        unsigned long ldmt3r;
index 22881b5e95e3b00e010b407310539fbd4e1a8a57..3bdb152f412f32b8edeeb1036a24f934988b5be2 100644 (file)
@@ -567,7 +567,7 @@ asmlinkage void __init start_kernel(void)
        setup_per_cpu_areas();
        smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */
 
-       build_all_zonelists();
+       build_all_zonelists(NULL);
        page_alloc_init();
 
        printk(KERN_NOTICE "Kernel command line: %s\n", boot_command_line);
index 9547cb7ac3135b9ba8964d13018f5ab6340552c9..747b65507a91c3d7a03022f17797e742a6ee53e0 100644 (file)
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -345,19 +345,19 @@ copy_msqid_to_user(void __user *buf, struct msqid64_ds *in, int version)
                out.msg_rtime           = in->msg_rtime;
                out.msg_ctime           = in->msg_ctime;
 
-               if (in->msg_cbytes > USHORT_MAX)
-                       out.msg_cbytes  = USHORT_MAX;
+               if (in->msg_cbytes > USHRT_MAX)
+                       out.msg_cbytes  = USHRT_MAX;
                else
                        out.msg_cbytes  = in->msg_cbytes;
                out.msg_lcbytes         = in->msg_cbytes;
 
-               if (in->msg_qnum > USHORT_MAX)
-                       out.msg_qnum    = USHORT_MAX;
+               if (in->msg_qnum > USHRT_MAX)
+                       out.msg_qnum    = USHRT_MAX;
                else
                        out.msg_qnum    = in->msg_qnum;
 
-               if (in->msg_qbytes > USHORT_MAX)
-                       out.msg_qbytes  = USHORT_MAX;
+               if (in->msg_qbytes > USHRT_MAX)
+                       out.msg_qbytes  = USHRT_MAX;
                else
                        out.msg_qbytes  = in->msg_qbytes;
                out.msg_lqbytes         = in->msg_qbytes;
index dbef95b1594122c2a6276d504d206805d39879f7..506c8491a8d131761432aa306e51eef441863887 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -3,56 +3,6 @@
  * Copyright (C) 1992 Krishna Balasubramanian
  * Copyright (C) 1995 Eric Schenk, Bruno Haible
  *
- * IMPLEMENTATION NOTES ON CODE REWRITE (Eric Schenk, January 1995):
- * This code underwent a massive rewrite in order to solve some problems
- * with the original code. In particular the original code failed to
- * wake up processes that were waiting for semval to go to 0 if the
- * value went to 0 and was then incremented rapidly enough. In solving
- * this problem I have also modified the implementation so that it
- * processes pending operations in a FIFO manner, thus give a guarantee
- * that processes waiting for a lock on the semaphore won't starve
- * unless another locking process fails to unlock.
- * In addition the following two changes in behavior have been introduced:
- * - The original implementation of semop returned the value
- *   last semaphore element examined on success. This does not
- *   match the manual page specifications, and effectively
- *   allows the user to read the semaphore even if they do not
- *   have read permissions. The implementation now returns 0
- *   on success as stated in the manual page.
- * - There is some confusion over whether the set of undo adjustments
- *   to be performed at exit should be done in an atomic manner.
- *   That is, if we are attempting to decrement the semval should we queue
- *   up and wait until we can do so legally?
- *   The original implementation attempted to do this.
- *   The current implementation does not do so. This is because I don't
- *   think it is the right thing (TM) to do, and because I couldn't
- *   see a clean way to get the old behavior with the new design.
- *   The POSIX standard and SVID should be consulted to determine
- *   what behavior is mandated.
- *
- * Further notes on refinement (Christoph Rohland, December 1998):
- * - The POSIX standard says, that the undo adjustments simply should
- *   redo. So the current implementation is o.K.
- * - The previous code had two flaws:
- *   1) It actively gave the semaphore to the next waiting process
- *      sleeping on the semaphore. Since this process did not have the
- *      cpu this led to many unnecessary context switches and bad
- *      performance. Now we only check which process should be able to
- *      get the semaphore and if this process wants to reduce some
- *      semaphore value we simply wake it up without doing the
- *      operation. So it has to try to get it later. Thus e.g. the
- *      running process may reacquire the semaphore during the current
- *      time slice. If it only waits for zero or increases the semaphore,
- *      we do the operation in advance and wake it up.
- *   2) It did not wake up all zero waiting processes. We try to do
- *      better but only get the semops right which only wait for zero or
- *      increase. If there are decrement operations in the operations
- *      array we do the same as before.
- *
- * With the incarnation of O(1) scheduler, it becomes unnecessary to perform
- * check/retry algorithm for waking up blocked processes as the new scheduler
- * is better at handling thread switch than the old one.
- *
  * /proc/sysvipc/sem support (c) 1999 Dragos Acostachioaie <dragos@iname.com>
  *
  * SMP-threaded, sysctl's added
@@ -61,6 +11,8 @@
  * (c) 2001 Red Hat Inc
  * Lockless wakeup
  * (c) 2003 Manfred Spraul <manfred@colorfullife.com>
+ * Further wakeup optimizations, documentation
+ * (c) 2010 Manfred Spraul <manfred@colorfullife.com>
  *
  * support for audit of ipc object properties and permission changes
  * Dustin Kirkland <dustin.kirkland@us.ibm.com>
  * namespaces support
  * OpenVZ, SWsoft Inc.
  * Pavel Emelianov <xemul@openvz.org>
+ *
+ * Implementation notes: (May 2010)
+ * This file implements System V semaphores.
+ *
+ * User space visible behavior:
+ * - FIFO ordering for semop() operations (just FIFO, not starvation
+ *   protection)
+ * - multiple semaphore operations that alter the same semaphore in
+ *   one semop() are handled.
+ * - sem_ctime (time of last semctl()) is updated in the IPC_SET, SETVAL and
+ *   SETALL calls.
+ * - two Linux specific semctl() commands: SEM_STAT, SEM_INFO.
+ * - undo adjustments at process exit are limited to 0..SEMVMX.
+ * - namespace are supported.
+ * - SEMMSL, SEMMNS, SEMOPM and SEMMNI can be configured at runtine by writing
+ *   to /proc/sys/kernel/sem.
+ * - statistics about the usage are reported in /proc/sysvipc/sem.
+ *
+ * Internals:
+ * - scalability:
+ *   - all global variables are read-mostly.
+ *   - semop() calls and semctl(RMID) are synchronized by RCU.
+ *   - most operations do write operations (actually: spin_lock calls) to
+ *     the per-semaphore array structure.
+ *   Thus: Perfect SMP scaling between independent semaphore arrays.
+ *         If multiple semaphores in one array are used, then cache line
+ *         trashing on the semaphore array spinlock will limit the scaling.
+ * - semncnt and semzcnt are calculated on demand in count_semncnt() and
+ *   count_semzcnt()
+ * - the task that performs a successful semop() scans the list of all
+ *   sleeping tasks and completes any pending operations that can be fulfilled.
+ *   Semaphores are actively given to waiting tasks (necessary for FIFO).
+ *   (see update_queue())
+ * - To improve the scalability, the actual wake-up calls are performed after
+ *   dropping all locks. (see wake_up_sem_queue_prepare(),
+ *   wake_up_sem_queue_do())
+ * - All work is done by the waker, the woken up task does not have to do
+ *   anything - not even acquiring a lock or dropping a refcount.
+ * - A woken up task may not even touch the semaphore array anymore, it may
+ *   have been destroyed already by a semctl(RMID).
+ * - The synchronizations between wake-ups due to a timeout/signal and a
+ *   wake-up due to a completed semaphore operation is achieved by using an
+ *   intermediate state (IN_WAKEUP).
+ * - UNDO values are stored in an array (one per process and per
+ *   semaphore array, lazily allocated). For backwards compatibility, multiple
+ *   modes for the UNDO variables are supported (per process, per thread)
+ *   (see copy_semundo, CLONE_SYSVSEM)
+ * - There are two lists of the pending operations: a per-array list
+ *   and per-semaphore list (stored in the array). This allows to achieve FIFO
+ *   ordering without always scanning all pending operations.
+ *   The worst-case behavior is nevertheless O(N^2) for N wakeups.
  */
 
 #include <linux/slab.h>
@@ -381,7 +384,6 @@ static int try_atomic_semop (struct sem_array * sma, struct sembuf * sops,
                sop--;
        }
        
-       sma->sem_otime = get_seconds();
        return 0;
 
 out_of_range:
@@ -404,25 +406,51 @@ undo:
        return result;
 }
 
-/*
- * Wake up a process waiting on the sem queue with a given error.
- * The queue is invalid (may not be accessed) after the function returns.
+/** wake_up_sem_queue_prepare(q, error): Prepare wake-up
+ * @q: queue entry that must be signaled
+ * @error: Error value for the signal
+ *
+ * Prepare the wake-up of the queue entry q.
  */
-static void wake_up_sem_queue(struct sem_queue *q, int error)
+static void wake_up_sem_queue_prepare(struct list_head *pt,
+                               struct sem_queue *q, int error)
 {
-       /*
-        * Hold preempt off so that we don't get preempted and have the
-        * wakee busy-wait until we're scheduled back on. We're holding
-        * locks here so it may not strictly be needed, however if the
-        * locks become preemptible then this prevents such a problem.
-        */
-       preempt_disable();
+       if (list_empty(pt)) {
+               /*
+                * Hold preempt off so that we don't get preempted and have the
+                * wakee busy-wait until we're scheduled back on.
+                */
+               preempt_disable();
+       }
        q->status = IN_WAKEUP;
-       wake_up_process(q->sleeper);
-       /* hands-off: q can disappear immediately after writing q->status. */
-       smp_wmb();
-       q->status = error;
-       preempt_enable();
+       q->pid = error;
+
+       list_add_tail(&q->simple_list, pt);
+}
+
+/**
+ * wake_up_sem_queue_do(pt) - do the actual wake-up
+ * @pt: list of tasks to be woken up
+ *
+ * Do the actual wake-up.
+ * The function is called without any locks held, thus the semaphore array
+ * could be destroyed already and the tasks can disappear as soon as the
+ * status is set to the actual return code.
+ */
+static void wake_up_sem_queue_do(struct list_head *pt)
+{
+       struct sem_queue *q, *t;
+       int did_something;
+
+       did_something = !list_empty(pt);
+       list_for_each_entry_safe(q, t, pt, simple_list) {
+               wake_up_process(q->sleeper);
+               /* q can disappear immediately after writing q->status. */
+               smp_wmb();
+               q->status = q->pid;
+       }
+       if (did_something)
+               preempt_enable();
 }
 
 static void unlink_queue(struct sem_array *sma, struct sem_queue *q)
@@ -434,22 +462,90 @@ static void unlink_queue(struct sem_array *sma, struct sem_queue *q)
                sma->complex_count--;
 }
 
+/** check_restart(sma, q)
+ * @sma: semaphore array
+ * @q: the operation that just completed
+ *
+ * update_queue is O(N^2) when it restarts scanning the whole queue of
+ * waiting operations. Therefore this function checks if the restart is
+ * really necessary. It is called after a previously waiting operation
+ * was completed.
+ */
+static int check_restart(struct sem_array *sma, struct sem_queue *q)
+{
+       struct sem *curr;
+       struct sem_queue *h;
+
+       /* if the operation didn't modify the array, then no restart */
+       if (q->alter == 0)
+               return 0;
+
+       /* pending complex operations are too difficult to analyse */
+       if (sma->complex_count)
+               return 1;
+
+       /* we were a sleeping complex operation. Too difficult */
+       if (q->nsops > 1)
+               return 1;
+
+       curr = sma->sem_base + q->sops[0].sem_num;
+
+       /* No-one waits on this queue */
+       if (list_empty(&curr->sem_pending))
+               return 0;
+
+       /* the new semaphore value */
+       if (curr->semval) {
+               /* It is impossible that someone waits for the new value:
+                * - q is a previously sleeping simple operation that
+                *   altered the array. It must be a decrement, because
+                *   simple increments never sleep.
+                * - The value is not 0, thus wait-for-zero won't proceed.
+                * - If there are older (higher priority) decrements
+                *   in the queue, then they have observed the original
+                *   semval value and couldn't proceed. The operation
+                *   decremented to value - thus they won't proceed either.
+                */
+               BUG_ON(q->sops[0].sem_op >= 0);
+               return 0;
+       }
+       /*
+        * semval is 0. Check if there are wait-for-zero semops.
+        * They must be the first entries in the per-semaphore simple queue
+        */
+       h = list_first_entry(&curr->sem_pending, struct sem_queue, simple_list);
+       BUG_ON(h->nsops != 1);
+       BUG_ON(h->sops[0].sem_num != q->sops[0].sem_num);
+
+       /* Yes, there is a wait-for-zero semop. Restart */
+       if (h->sops[0].sem_op == 0)
+               return 1;
+
+       /* Again - no-one is waiting for the new value. */
+       return 0;
+}
+
 
 /**
  * update_queue(sma, semnum): Look for tasks that can be completed.
  * @sma: semaphore array.
  * @semnum: semaphore that was modified.
+ * @pt: list head for the tasks that must be woken up.
  *
  * update_queue must be called after a semaphore in a semaphore array
  * was modified. If multiple semaphore were modified, then @semnum
  * must be set to -1.
+ * The tasks that must be woken up are added to @pt. The return code
+ * is stored in q->pid.
+ * The function return 1 if at least one semop was completed successfully.
  */
-static void update_queue(struct sem_array *sma, int semnum)
+static int update_queue(struct sem_array *sma, int semnum, struct list_head *pt)
 {
        struct sem_queue *q;
        struct list_head *walk;
        struct list_head *pending_list;
        int offset;
+       int semop_completed = 0;
 
        /* if there are complex operations around, then knowing the semaphore
         * that was modified doesn't help us. Assume that multiple semaphores
@@ -469,7 +565,7 @@ static void update_queue(struct sem_array *sma, int semnum)
 again:
        walk = pending_list->next;
        while (walk != pending_list) {
-               int error, alter;
+               int error, restart;
 
                q = (struct sem_queue *)((char *)walk - offset);
                walk = walk->next;
@@ -494,22 +590,58 @@ again:
 
                unlink_queue(sma, q);
 
-               /*
-                * The next operation that must be checked depends on the type
-                * of the completed operation:
-                * - if the operation modified the array, then restart from the
-                *   head of the queue and check for threads that might be
-                *   waiting for the new semaphore values.
-                * - if the operation didn't modify the array, then just
-                *   continue.
-                */
-               alter = q->alter;
-               wake_up_sem_queue(q, error);
-               if (alter && !error)
+               if (error) {
+                       restart = 0;
+               } else {
+                       semop_completed = 1;
+                       restart = check_restart(sma, q);
+               }
+
+               wake_up_sem_queue_prepare(pt, q, error);
+               if (restart)
                        goto again;
        }
+       return semop_completed;
+}
+
+/**
+ * do_smart_update(sma, sops, nsops, otime, pt) - optimized update_queue
+ * @sma: semaphore array
+ * @sops: operations that were performed
+ * @nsops: number of operations
+ * @otime: force setting otime
+ * @pt: list head of the tasks that must be woken up.
+ *
+ * do_smart_update() does the required called to update_queue, based on the
+ * actual changes that were performed on the semaphore array.
+ * Note that the function does not do the actual wake-up: the caller is
+ * responsible for calling wake_up_sem_queue_do(@pt).
+ * It is safe to perform this call after dropping all locks.
+ */
+static void do_smart_update(struct sem_array *sma, struct sembuf *sops, int nsops,
+                       int otime, struct list_head *pt)
+{
+       int i;
+
+       if (sma->complex_count || sops == NULL) {
+               if (update_queue(sma, -1, pt))
+                       otime = 1;
+               goto done;
+       }
+
+       for (i = 0; i < nsops; i++) {
+               if (sops[i].sem_op > 0 ||
+                       (sops[i].sem_op < 0 &&
+                               sma->sem_base[sops[i].sem_num].semval == 0))
+                       if (update_queue(sma, sops[i].sem_num, pt))
+                               otime = 1;
+       }
+done:
+       if (otime)
+               sma->sem_otime = get_seconds();
 }
 
+
 /* The following counts are associated to each semaphore:
  *   semncnt        number of tasks waiting on semval being nonzero
  *   semzcnt        number of tasks waiting on semval being zero
@@ -572,6 +704,7 @@ static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
        struct sem_undo *un, *tu;
        struct sem_queue *q, *tq;
        struct sem_array *sma = container_of(ipcp, struct sem_array, sem_perm);
+       struct list_head tasks;
 
        /* Free the existing undo structures for this semaphore set.  */
        assert_spin_locked(&sma->sem_perm.lock);
@@ -585,15 +718,17 @@ static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
        }
 
        /* Wake up all pending processes and let them fail with EIDRM. */
+       INIT_LIST_HEAD(&tasks);
        list_for_each_entry_safe(q, tq, &sma->sem_pending, list) {
                unlink_queue(sma, q);
-               wake_up_sem_queue(q, -EIDRM);
+               wake_up_sem_queue_prepare(&tasks, q, -EIDRM);
        }
 
        /* Remove the semaphore set from the IDR */
        sem_rmid(ns, sma);
        sem_unlock(sma);
 
+       wake_up_sem_queue_do(&tasks);
        ns->used_sems -= sma->sem_nsems;
        security_sem_free(sma);
        ipc_rcu_putref(sma);
@@ -715,11 +850,13 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
        ushort fast_sem_io[SEMMSL_FAST];
        ushort* sem_io = fast_sem_io;
        int nsems;
+       struct list_head tasks;
 
        sma = sem_lock_check(ns, semid);
        if (IS_ERR(sma))
                return PTR_ERR(sma);
 
+       INIT_LIST_HEAD(&tasks);
        nsems = sma->sem_nsems;
 
        err = -EACCES;
@@ -807,7 +944,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                }
                sma->sem_ctime = get_seconds();
                /* maybe some queued-up processes were waiting for this */
-               update_queue(sma, -1);
+               do_smart_update(sma, NULL, 0, 0, &tasks);
                err = 0;
                goto out_unlock;
        }
@@ -849,13 +986,15 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                curr->sempid = task_tgid_vnr(current);
                sma->sem_ctime = get_seconds();
                /* maybe some queued-up processes were waiting for this */
-               update_queue(sma, semnum);
+               do_smart_update(sma, NULL, 0, 0, &tasks);
                err = 0;
                goto out_unlock;
        }
        }
 out_unlock:
        sem_unlock(sma);
+       wake_up_sem_queue_do(&tasks);
+
 out_free:
        if(sem_io != fast_sem_io)
                ipc_free(sem_io, sizeof(ushort)*nsems);
@@ -1069,7 +1208,7 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
        /* step 1: figure out the size of the semaphore array */
        sma = sem_lock_check(ns, semid);
        if (IS_ERR(sma))
-               return ERR_PTR(PTR_ERR(sma));
+               return ERR_CAST(sma);
 
        nsems = sma->sem_nsems;
        sem_getref_and_unlock(sma);
@@ -1129,6 +1268,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
        struct sem_queue queue;
        unsigned long jiffies_left = 0;
        struct ipc_namespace *ns;
+       struct list_head tasks;
 
        ns = current->nsproxy->ipc_ns;
 
@@ -1177,6 +1317,8 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
        } else
                un = NULL;
 
+       INIT_LIST_HEAD(&tasks);
+
        sma = sem_lock_check(ns, semid);
        if (IS_ERR(sma)) {
                if (un)
@@ -1225,7 +1367,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
        error = try_atomic_semop (sma, sops, nsops, un, task_tgid_vnr(current));
        if (error <= 0) {
                if (alter && error == 0)
-                       update_queue(sma, (nsops == 1) ? sops[0].sem_num : -1);
+                       do_smart_update(sma, sops, nsops, 1, &tasks);
 
                goto out_unlock_free;
        }
@@ -1302,6 +1444,8 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
 
 out_unlock_free:
        sem_unlock(sma);
+
+       wake_up_sem_queue_do(&tasks);
 out_free:
        if(sops != fast_sops)
                kfree(sops);
@@ -1362,6 +1506,7 @@ void exit_sem(struct task_struct *tsk)
        for (;;) {
                struct sem_array *sma;
                struct sem_undo *un;
+               struct list_head tasks;
                int semid;
                int i;
 
@@ -1425,10 +1570,11 @@ void exit_sem(struct task_struct *tsk)
                                semaphore->sempid = task_tgid_vnr(current);
                        }
                }
-               sma->sem_otime = get_seconds();
                /* maybe some queued-up processes were waiting for this */
-               update_queue(sma, -1);
+               INIT_LIST_HEAD(&tasks);
+               do_smart_update(sma, NULL, 0, 1, &tasks);
                sem_unlock(sma);
+               wake_up_sem_queue_do(&tasks);
 
                call_rcu(&un->rcu, free_un);
        }
index 1a314c89f93cfbffa46d14e00641708147b1a918..52ed77eb9713a932804cc8bb2b430ce4cdff4750 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -273,16 +273,13 @@ static int shm_release(struct inode *ino, struct file *file)
        return 0;
 }
 
-static int shm_fsync(struct file *file, struct dentry *dentry, int datasync)
+static int shm_fsync(struct file *file, int datasync)
 {
-       int (*fsync) (struct file *, struct dentry *, int datasync);
        struct shm_file_data *sfd = shm_file_data(file);
-       int ret = -EINVAL;
 
-       fsync = sfd->file->f_op->fsync;
-       if (fsync)
-               ret = fsync(sfd->file, sfd->file->f_path.dentry, datasync);
-       return ret;
+       if (!sfd->file->f_op->fsync)
+               return -EINVAL;
+       return sfd->file->f_op->fsync(sfd->file, datasync);
 }
 
 static unsigned long shm_get_unmapped_area(struct file *file,
index 79ce84e890f72b153ca4f77ee7abeec3a6aed496..69a0cc13d9669847cce05fd67fc2203ffdeacb9e 100644 (file)
@@ -124,8 +124,8 @@ void ipc_init_ids(struct ipc_ids *ids)
        ids->seq = 0;
        {
                int seq_limit = INT_MAX/SEQ_MULTIPLIER;
-               if (seq_limit > USHORT_MAX)
-                       ids->seq_max = USHORT_MAX;
+               if (seq_limit > USHRT_MAX)
+                       ids->seq_max = USHRT_MAX;
                 else
                        ids->seq_max = seq_limit;
        }
index 291775021b2e79ea696df3081bd3d0ec100ed9f1..422cb19f156ef9b7a6f5ab8968ade8a618ea5d88 100644 (file)
@@ -2994,7 +2994,6 @@ static void cgroup_event_remove(struct work_struct *work)
                        remove);
        struct cgroup *cgrp = event->cgrp;
 
-       /* TODO: check return code */
        event->cft->unregister_event(cgrp, event->cft, event->eventfd);
 
        eventfd_ctx_put(event->eventfd);
index 545777574779da71ef8e3fcc3935e0e41fa266ca..8b92539b4754274528fdc380d45baf6d481001b1 100644 (file)
 /* Serializes the updates to cpu_online_mask, cpu_present_mask */
 static DEFINE_MUTEX(cpu_add_remove_lock);
 
+/*
+ * The following two API's must be used when attempting
+ * to serialize the updates to cpu_online_mask, cpu_present_mask.
+ */
+void cpu_maps_update_begin(void)
+{
+       mutex_lock(&cpu_add_remove_lock);
+}
+
+void cpu_maps_update_done(void)
+{
+       mutex_unlock(&cpu_add_remove_lock);
+}
+
 static __cpuinitdata RAW_NOTIFIER_HEAD(cpu_chain);
 
 /* If set, cpu_up and cpu_down will return -EBUSY and do nothing.
@@ -27,6 +41,8 @@ static __cpuinitdata RAW_NOTIFIER_HEAD(cpu_chain);
  */
 static int cpu_hotplug_disabled;
 
+#ifdef CONFIG_HOTPLUG_CPU
+
 static struct {
        struct task_struct *active_writer;
        struct mutex lock; /* Synchronizes accesses to refcount, */
@@ -41,8 +57,6 @@ static struct {
        .refcount = 0,
 };
 
-#ifdef CONFIG_HOTPLUG_CPU
-
 void get_online_cpus(void)
 {
        might_sleep();
@@ -67,22 +81,6 @@ void put_online_cpus(void)
 }
 EXPORT_SYMBOL_GPL(put_online_cpus);
 
-#endif /* CONFIG_HOTPLUG_CPU */
-
-/*
- * The following two API's must be used when attempting
- * to serialize the updates to cpu_online_mask, cpu_present_mask.
- */
-void cpu_maps_update_begin(void)
-{
-       mutex_lock(&cpu_add_remove_lock);
-}
-
-void cpu_maps_update_done(void)
-{
-       mutex_unlock(&cpu_add_remove_lock);
-}
-
 /*
  * This ensures that the hotplug operation can begin only when the
  * refcount goes to zero.
@@ -124,6 +122,12 @@ static void cpu_hotplug_done(void)
        cpu_hotplug.active_writer = NULL;
        mutex_unlock(&cpu_hotplug.lock);
 }
+
+#else /* #if CONFIG_HOTPLUG_CPU */
+static void cpu_hotplug_begin(void) {}
+static void cpu_hotplug_done(void) {}
+#endif /* #esle #if CONFIG_HOTPLUG_CPU */
+
 /* Need to know about CPUs going up/down? */
 int __ref register_cpu_notifier(struct notifier_block *nb)
 {
@@ -134,8 +138,29 @@ int __ref register_cpu_notifier(struct notifier_block *nb)
        return ret;
 }
 
+static int __cpu_notify(unsigned long val, void *v, int nr_to_call,
+                       int *nr_calls)
+{
+       int ret;
+
+       ret = __raw_notifier_call_chain(&cpu_chain, val, v, nr_to_call,
+                                       nr_calls);
+
+       return notifier_to_errno(ret);
+}
+
+static int cpu_notify(unsigned long val, void *v)
+{
+       return __cpu_notify(val, v, -1, NULL);
+}
+
 #ifdef CONFIG_HOTPLUG_CPU
 
+static void cpu_notify_nofail(unsigned long val, void *v)
+{
+       BUG_ON(cpu_notify(val, v));
+}
+
 EXPORT_SYMBOL(register_cpu_notifier);
 
 void __ref unregister_cpu_notifier(struct notifier_block *nb)
@@ -181,8 +206,7 @@ static int __ref take_cpu_down(void *_param)
        if (err < 0)
                return err;
 
-       raw_notifier_call_chain(&cpu_chain, CPU_DYING | param->mod,
-                               param->hcpu);
+       cpu_notify(CPU_DYING | param->mod, param->hcpu);
 
        if (task_cpu(param->caller) == cpu)
                move_task_off_dead_cpu(cpu, param->caller);
@@ -212,17 +236,14 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
 
        cpu_hotplug_begin();
        set_cpu_active(cpu, false);
-       err = __raw_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE | mod,
-                                       hcpu, -1, &nr_calls);
-       if (err == NOTIFY_BAD) {
+       err = __cpu_notify(CPU_DOWN_PREPARE | mod, hcpu, -1, &nr_calls);
+       if (err) {
                set_cpu_active(cpu, true);
 
                nr_calls--;
-               __raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED | mod,
-                                         hcpu, nr_calls, NULL);
+               __cpu_notify(CPU_DOWN_FAILED | mod, hcpu, nr_calls, NULL);
                printk("%s: attempt to take down CPU %u failed\n",
                                __func__, cpu);
-               err = -EINVAL;
                goto out_release;
        }
 
@@ -230,9 +251,7 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
        if (err) {
                set_cpu_active(cpu, true);
                /* CPU didn't die: tell everyone.  Can't complain. */
-               if (raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED | mod,
-                                           hcpu) == NOTIFY_BAD)
-                       BUG();
+               cpu_notify_nofail(CPU_DOWN_FAILED | mod, hcpu);
 
                goto out_release;
        }
@@ -246,19 +265,14 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
        __cpu_die(cpu);
 
        /* CPU is completely dead: tell everyone.  Too late to complain. */
-       if (raw_notifier_call_chain(&cpu_chain, CPU_DEAD | mod,
-                                   hcpu) == NOTIFY_BAD)
-               BUG();
+       cpu_notify_nofail(CPU_DEAD | mod, hcpu);
 
        check_for_tasks(cpu);
 
 out_release:
        cpu_hotplug_done();
-       if (!err) {
-               if (raw_notifier_call_chain(&cpu_chain, CPU_POST_DEAD | mod,
-                                           hcpu) == NOTIFY_BAD)
-                       BUG();
-       }
+       if (!err)
+               cpu_notify_nofail(CPU_POST_DEAD | mod, hcpu);
        return err;
 }
 
@@ -293,13 +307,11 @@ static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)
                return -EINVAL;
 
        cpu_hotplug_begin();
-       ret = __raw_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE | mod, hcpu,
-                                                       -1, &nr_calls);
-       if (ret == NOTIFY_BAD) {
+       ret = __cpu_notify(CPU_UP_PREPARE | mod, hcpu, -1, &nr_calls);
+       if (ret) {
                nr_calls--;
                printk("%s: attempt to bring up CPU %u failed\n",
                                __func__, cpu);
-               ret = -EINVAL;
                goto out_notify;
        }
 
@@ -312,12 +324,11 @@ static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)
        set_cpu_active(cpu, true);
 
        /* Now call notifier in preparation. */
-       raw_notifier_call_chain(&cpu_chain, CPU_ONLINE | mod, hcpu);
+       cpu_notify(CPU_ONLINE | mod, hcpu);
 
 out_notify:
        if (ret != 0)
-               __raw_notifier_call_chain(&cpu_chain,
-                               CPU_UP_CANCELED | mod, hcpu, nr_calls, NULL);
+               __cpu_notify(CPU_UP_CANCELED | mod, hcpu, nr_calls, NULL);
        cpu_hotplug_done();
 
        return ret;
@@ -326,6 +337,12 @@ out_notify:
 int __cpuinit cpu_up(unsigned int cpu)
 {
        int err = 0;
+
+#ifdef CONFIG_MEMORY_HOTPLUG
+       int nid;
+       pg_data_t       *pgdat;
+#endif
+
        if (!cpu_possible(cpu)) {
                printk(KERN_ERR "can't online cpu %d because it is not "
                        "configured as may-hotadd at boot time\n", cpu);
@@ -336,6 +353,28 @@ int __cpuinit cpu_up(unsigned int cpu)
                return -EINVAL;
        }
 
+#ifdef CONFIG_MEMORY_HOTPLUG
+       nid = cpu_to_node(cpu);
+       if (!node_online(nid)) {
+               err = mem_online_node(nid);
+               if (err)
+                       return err;
+       }
+
+       pgdat = NODE_DATA(nid);
+       if (!pgdat) {
+               printk(KERN_ERR
+                       "Can't online cpu %d due to NULL pgdat\n", cpu);
+               return -ENOMEM;
+       }
+
+       if (pgdat->node_zonelists->_zonerefs->zone == NULL) {
+               mutex_lock(&zonelists_mutex);
+               build_all_zonelists(NULL);
+               mutex_unlock(&zonelists_mutex);
+       }
+#endif
+
        cpu_maps_update_begin();
 
        if (cpu_hotplug_disabled) {
@@ -355,7 +394,7 @@ static cpumask_var_t frozen_cpus;
 
 int disable_nonboot_cpus(void)
 {
-       int cpu, first_cpu, error;
+       int cpu, first_cpu, error = 0;
 
        cpu_maps_update_begin();
        first_cpu = cpumask_first(cpu_online_mask);
@@ -453,7 +492,7 @@ void __cpuinit notify_cpu_starting(unsigned int cpu)
        if (frozen_cpus != NULL && cpumask_test_cpu(cpu, frozen_cpus))
                val = CPU_STARTING_FROZEN;
 #endif /* CONFIG_PM_SLEEP_SMP */
-       raw_notifier_call_chain(&cpu_chain, val, (void *)(long)cpu);
+       cpu_notify(val, (void *)(long)cpu);
 }
 
 #endif /* CONFIG_SMP */
index 9a50c5f6e727f3f77ec5dcf2d5f993fc62717ce9..02b9611eadde3ebe638b9c24ffbbb5ec8ada5c06 100644 (file)
@@ -946,16 +946,62 @@ static void cpuset_migrate_mm(struct mm_struct *mm, const nodemask_t *from,
  * In order to avoid seeing no nodes if the old and new nodes are disjoint,
  * we structure updates as setting all new allowed nodes, then clearing newly
  * disallowed ones.
- *
- * Called with task's alloc_lock held
  */
 static void cpuset_change_task_nodemask(struct task_struct *tsk,
                                        nodemask_t *newmems)
 {
+repeat:
+       /*
+        * Allow tasks that have access to memory reserves because they have
+        * been OOM killed to get memory anywhere.
+        */
+       if (unlikely(test_thread_flag(TIF_MEMDIE)))
+               return;
+       if (current->flags & PF_EXITING) /* Let dying task have memory */
+               return;
+
+       task_lock(tsk);
        nodes_or(tsk->mems_allowed, tsk->mems_allowed, *newmems);
-       mpol_rebind_task(tsk, &tsk->mems_allowed);
-       mpol_rebind_task(tsk, newmems);
+       mpol_rebind_task(tsk, newmems, MPOL_REBIND_STEP1);
+
+
+       /*
+        * ensure checking ->mems_allowed_change_disable after setting all new
+        * allowed nodes.
+        *
+        * the read-side task can see an nodemask with new allowed nodes and
+        * old allowed nodes. and if it allocates page when cpuset clears newly
+        * disallowed ones continuous, it can see the new allowed bits.
+        *
+        * And if setting all new allowed nodes is after the checking, setting
+        * all new allowed nodes and clearing newly disallowed ones will be done
+        * continuous, and the read-side task may find no node to alloc page.
+        */
+       smp_mb();
+
+       /*
+        * Allocation of memory is very fast, we needn't sleep when waiting
+        * for the read-side.
+        */
+       while (ACCESS_ONCE(tsk->mems_allowed_change_disable)) {
+               task_unlock(tsk);
+               if (!task_curr(tsk))
+                       yield();
+               goto repeat;
+       }
+
+       /*
+        * ensure checking ->mems_allowed_change_disable before clearing all new
+        * disallowed nodes.
+        *
+        * if clearing newly disallowed bits before the checking, the read-side
+        * task may find no node to alloc page.
+        */
+       smp_mb();
+
+       mpol_rebind_task(tsk, newmems, MPOL_REBIND_STEP2);
        tsk->mems_allowed = *newmems;
+       task_unlock(tsk);
 }
 
 /*
@@ -978,9 +1024,7 @@ static void cpuset_change_nodemask(struct task_struct *p,
        cs = cgroup_cs(scan->cg);
        guarantee_online_mems(cs, newmems);
 
-       task_lock(p);
        cpuset_change_task_nodemask(p, newmems);
-       task_unlock(p);
 
        NODEMASK_FREE(newmems);
 
@@ -1383,9 +1427,7 @@ static void cpuset_attach_task(struct task_struct *tsk, nodemask_t *to,
        err = set_cpus_allowed_ptr(tsk, cpus_attach);
        WARN_ON_ONCE(err);
 
-       task_lock(tsk);
        cpuset_change_task_nodemask(tsk, to);
-       task_unlock(tsk);
        cpuset_update_task_spread_flag(cs, tsk);
 
 }
@@ -2427,7 +2469,8 @@ void cpuset_unlock(void)
 }
 
 /**
- * cpuset_mem_spread_node() - On which node to begin search for a page
+ * cpuset_mem_spread_node() - On which node to begin search for a file page
+ * cpuset_slab_spread_node() - On which node to begin search for a slab page
  *
  * If a task is marked PF_SPREAD_PAGE or PF_SPREAD_SLAB (as for
  * tasks in a cpuset with is_spread_page or is_spread_slab set),
@@ -2452,16 +2495,27 @@ void cpuset_unlock(void)
  * See kmem_cache_alloc_node().
  */
 
-int cpuset_mem_spread_node(void)
+static int cpuset_spread_node(int *rotor)
 {
        int node;
 
-       node = next_node(current->cpuset_mem_spread_rotor, current->mems_allowed);
+       node = next_node(*rotor, current->mems_allowed);
        if (node == MAX_NUMNODES)
                node = first_node(current->mems_allowed);
-       current->cpuset_mem_spread_rotor = node;
+       *rotor = node;
        return node;
 }
+
+int cpuset_mem_spread_node(void)
+{
+       return cpuset_spread_node(&current->cpuset_mem_spread_rotor);
+}
+
+int cpuset_slab_spread_node(void)
+{
+       return cpuset_spread_node(&current->cpuset_slab_spread_rotor);
+}
+
 EXPORT_SYMBOL_GPL(cpuset_mem_spread_node);
 
 /**
index 2c24870c55d1279995379980766dd792f8671ebd..a2d5504fbcc24abb44c44a158521617933df4367 100644 (file)
@@ -346,66 +346,6 @@ struct cred *prepare_exec_creds(void)
        return new;
 }
 
-/*
- * prepare new credentials for the usermode helper dispatcher
- */
-struct cred *prepare_usermodehelper_creds(void)
-{
-#ifdef CONFIG_KEYS
-       struct thread_group_cred *tgcred = NULL;
-#endif
-       struct cred *new;
-
-#ifdef CONFIG_KEYS
-       tgcred = kzalloc(sizeof(*new->tgcred), GFP_ATOMIC);
-       if (!tgcred)
-               return NULL;
-#endif
-
-       new = kmem_cache_alloc(cred_jar, GFP_ATOMIC);
-       if (!new)
-               goto free_tgcred;
-
-       kdebug("prepare_usermodehelper_creds() alloc %p", new);
-
-       memcpy(new, &init_cred, sizeof(struct cred));
-
-       atomic_set(&new->usage, 1);
-       set_cred_subscribers(new, 0);
-       get_group_info(new->group_info);
-       get_uid(new->user);
-
-#ifdef CONFIG_KEYS
-       new->thread_keyring = NULL;
-       new->request_key_auth = NULL;
-       new->jit_keyring = KEY_REQKEY_DEFL_DEFAULT;
-
-       atomic_set(&tgcred->usage, 1);
-       spin_lock_init(&tgcred->lock);
-       new->tgcred = tgcred;
-#endif
-
-#ifdef CONFIG_SECURITY
-       new->security = NULL;
-#endif
-       if (security_prepare_creds(new, &init_cred, GFP_ATOMIC) < 0)
-               goto error;
-       validate_creds(new);
-
-       BUG_ON(atomic_read(&new->usage) != 1);
-       return new;
-
-error:
-       put_cred(new);
-       return NULL;
-
-free_tgcred:
-#ifdef CONFIG_KEYS
-       kfree(tgcred);
-#endif
-       return NULL;
-}
-
 /*
  * Copy credentials for the new process created by fork()
  *
index eabca5a73a85b70d8d1d9f2ea95c05ae6c27c1e2..ceffc67b564ae28eb6b46be67bfcf4f0ab7e8c6a 100644 (file)
 
 static void exit_mm(struct task_struct * tsk);
 
-static void __unhash_process(struct task_struct *p)
+static void __unhash_process(struct task_struct *p, bool group_dead)
 {
        nr_threads--;
        detach_pid(p, PIDTYPE_PID);
-       if (thread_group_leader(p)) {
+       if (group_dead) {
                detach_pid(p, PIDTYPE_PGID);
                detach_pid(p, PIDTYPE_SID);
 
@@ -79,10 +79,9 @@ static void __unhash_process(struct task_struct *p)
 static void __exit_signal(struct task_struct *tsk)
 {
        struct signal_struct *sig = tsk->signal;
+       bool group_dead = thread_group_leader(tsk);
        struct sighand_struct *sighand;
-
-       BUG_ON(!sig);
-       BUG_ON(!atomic_read(&sig->count));
+       struct tty_struct *uninitialized_var(tty);
 
        sighand = rcu_dereference_check(tsk->sighand,
                                        rcu_read_lock_held() ||
@@ -90,14 +89,16 @@ static void __exit_signal(struct task_struct *tsk)
        spin_lock(&sighand->siglock);
 
        posix_cpu_timers_exit(tsk);
-       if (atomic_dec_and_test(&sig->count))
+       if (group_dead) {
                posix_cpu_timers_exit_group(tsk);
-       else {
+               tty = sig->tty;
+               sig->tty = NULL;
+       } else {
                /*
                 * If there is any task waiting for the group exit
                 * then notify it:
                 */
-               if (sig->group_exit_task && atomic_read(&sig->count) == sig->notify_count)
+               if (sig->notify_count > 0 && !--sig->notify_count)
                        wake_up_process(sig->group_exit_task);
 
                if (tsk == sig->curr_target)
@@ -123,32 +124,24 @@ static void __exit_signal(struct task_struct *tsk)
                sig->oublock += task_io_get_oublock(tsk);
                task_io_accounting_add(&sig->ioac, &tsk->ioac);
                sig->sum_sched_runtime += tsk->se.sum_exec_runtime;
-               sig = NULL; /* Marker for below. */
        }
 
-       __unhash_process(tsk);
+       sig->nr_threads--;
+       __unhash_process(tsk, group_dead);
 
        /*
         * Do this under ->siglock, we can race with another thread
         * doing sigqueue_free() if we have SIGQUEUE_PREALLOC signals.
         */
        flush_sigqueue(&tsk->pending);
-
-       tsk->signal = NULL;
        tsk->sighand = NULL;
        spin_unlock(&sighand->siglock);
 
        __cleanup_sighand(sighand);
        clear_tsk_thread_flag(tsk,TIF_SIGPENDING);
-       if (sig) {
+       if (group_dead) {
                flush_sigqueue(&sig->shared_pending);
-               taskstats_tgid_free(sig);
-               /*
-                * Make sure ->signal can't go away under rq->lock,
-                * see account_group_exec_runtime().
-                */
-               task_rq_unlock_wait(tsk);
-               __cleanup_signal(sig);
+               tty_kref_put(tty);
        }
 }
 
@@ -856,12 +849,9 @@ static void exit_notify(struct task_struct *tsk, int group_dead)
 
        tsk->exit_state = signal == DEATH_REAP ? EXIT_DEAD : EXIT_ZOMBIE;
 
-       /* mt-exec, de_thread() is waiting for us */
-       if (thread_group_leader(tsk) &&
-           tsk->signal->group_exit_task &&
-           tsk->signal->notify_count < 0)
+       /* mt-exec, de_thread() is waiting for group leader */
+       if (unlikely(tsk->signal->notify_count < 0))
                wake_up_process(tsk->signal->group_exit_task);
-
        write_unlock_irq(&tasklist_lock);
 
        tracehook_report_death(tsk, signal, cookie, group_dead);
@@ -1002,8 +992,10 @@ NORET_TYPE void do_exit(long code)
 
        exit_notify(tsk, group_dead);
 #ifdef CONFIG_NUMA
+       task_lock(tsk);
        mpol_put(tsk->mempolicy);
        tsk->mempolicy = NULL;
+       task_unlock(tsk);
 #endif
 #ifdef CONFIG_FUTEX
        if (unlikely(current->pi_state_cache))
index 4d57d9e3a6e992a9d0a3514138008a0d8aefaeff..b6cce14ba0470e641bd45c68ca2067c4ee70d38c 100644 (file)
@@ -165,6 +165,18 @@ void free_task(struct task_struct *tsk)
 }
 EXPORT_SYMBOL(free_task);
 
+static inline void free_signal_struct(struct signal_struct *sig)
+{
+       taskstats_tgid_free(sig);
+       kmem_cache_free(signal_cachep, sig);
+}
+
+static inline void put_signal_struct(struct signal_struct *sig)
+{
+       if (atomic_dec_and_test(&sig->sigcnt))
+               free_signal_struct(sig);
+}
+
 void __put_task_struct(struct task_struct *tsk)
 {
        WARN_ON(!tsk->exit_state);
@@ -173,6 +185,7 @@ void __put_task_struct(struct task_struct *tsk)
 
        exit_creds(tsk);
        delayacct_tsk_free(tsk);
+       put_signal_struct(tsk->signal);
 
        if (!profile_handoff_task(tsk))
                free_task(tsk);
@@ -864,8 +877,9 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
        if (!sig)
                return -ENOMEM;
 
-       atomic_set(&sig->count, 1);
+       sig->nr_threads = 1;
        atomic_set(&sig->live, 1);
+       atomic_set(&sig->sigcnt, 1);
        init_waitqueue_head(&sig->wait_chldexit);
        if (clone_flags & CLONE_NEWPID)
                sig->flags |= SIGNAL_UNKILLABLE;
@@ -889,13 +903,6 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
        return 0;
 }
 
-void __cleanup_signal(struct signal_struct *sig)
-{
-       thread_group_cputime_free(sig);
-       tty_kref_put(sig->tty);
-       kmem_cache_free(signal_cachep, sig);
-}
-
 static void copy_flags(unsigned long clone_flags, struct task_struct *p)
 {
        unsigned long new_flags = p->flags;
@@ -1245,8 +1252,9 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        }
 
        if (clone_flags & CLONE_THREAD) {
-               atomic_inc(&current->signal->count);
+               current->signal->nr_threads++;
                atomic_inc(&current->signal->live);
+               atomic_inc(&current->signal->sigcnt);
                p->group_leader = current->group_leader;
                list_add_tail_rcu(&p->thread_group, &p->group_leader->thread_group);
        }
@@ -1259,7 +1267,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
                                p->nsproxy->pid_ns->child_reaper = p;
 
                        p->signal->leader_pid = pid;
-                       tty_kref_put(p->signal->tty);
                        p->signal->tty = tty_kref_get(current->signal->tty);
                        attach_pid(p, PIDTYPE_PGID, task_pgrp(current));
                        attach_pid(p, PIDTYPE_SID, task_session(current));
@@ -1292,7 +1299,7 @@ bad_fork_cleanup_mm:
                mmput(p->mm);
 bad_fork_cleanup_signal:
        if (!(clone_flags & CLONE_THREAD))
-               __cleanup_signal(p->signal);
+               free_signal_struct(p->signal);
 bad_fork_cleanup_sighand:
        __cleanup_sighand(p->sighand);
 bad_fork_cleanup_fs:
@@ -1327,6 +1334,16 @@ noinline struct pt_regs * __cpuinit __attribute__((weak)) idle_regs(struct pt_re
        return regs;
 }
 
+static inline void init_idle_pids(struct pid_link *links)
+{
+       enum pid_type type;
+
+       for (type = PIDTYPE_PID; type < PIDTYPE_MAX; ++type) {
+               INIT_HLIST_NODE(&links[type].node); /* not really needed */
+               links[type].pid = &init_struct_pid;
+       }
+}
+
 struct task_struct * __cpuinit fork_idle(int cpu)
 {
        struct task_struct *task;
@@ -1334,8 +1351,10 @@ struct task_struct * __cpuinit fork_idle(int cpu)
 
        task = copy_process(CLONE_VM, 0, idle_regs(&regs), 0, NULL,
                            &init_struct_pid, 0);
-       if (!IS_ERR(task))
+       if (!IS_ERR(task)) {
+               init_idle_pids(task->pids);
                init_idle(task, cpu);
+       }
 
        return task;
 }
@@ -1506,14 +1525,6 @@ static void check_unshare_flags(unsigned long *flags_ptr)
        if (*flags_ptr & CLONE_VM)
                *flags_ptr |= CLONE_SIGHAND;
 
-       /*
-        * If unsharing signal handlers and the task was created
-        * using CLONE_THREAD, then must unshare the thread
-        */
-       if ((*flags_ptr & CLONE_SIGHAND) &&
-           (atomic_read(&current->signal->count) > 1))
-               *flags_ptr |= CLONE_THREAD;
-
        /*
         * If unsharing namespace, must also unshare filesystem information.
         */
index b9b134b3508889933c4f337d46849237732c2c95..5c69e996bd0f0fcba57586800924b8d2989cda1b 100644 (file)
@@ -89,7 +89,7 @@ static void hrtimer_get_softirq_time(struct hrtimer_cpu_base *base)
 
        do {
                seq = read_seqbegin(&xtime_lock);
-               xts = current_kernel_time();
+               xts = __current_kernel_time();
                tom = wall_to_monotonic;
        } while (read_seqretry(&xtime_lock, seq));
 
index bf0e231d970236278380019513b19188132bb62a..6e9b19667a8d2fdff6ac3c0bf76d32d8c1fc4d87 100644 (file)
@@ -116,27 +116,16 @@ int __request_module(bool wait, const char *fmt, ...)
 
        trace_module_request(module_name, wait, _RET_IP_);
 
-       ret = call_usermodehelper(modprobe_path, argv, envp,
-                       wait ? UMH_WAIT_PROC : UMH_WAIT_EXEC);
+       ret = call_usermodehelper_fns(modprobe_path, argv, envp,
+                       wait ? UMH_WAIT_PROC : UMH_WAIT_EXEC,
+                       NULL, NULL, NULL);
+
        atomic_dec(&kmod_concurrent);
        return ret;
 }
 EXPORT_SYMBOL(__request_module);
 #endif /* CONFIG_MODULES */
 
-struct subprocess_info {
-       struct work_struct work;
-       struct completion *complete;
-       struct cred *cred;
-       char *path;
-       char **argv;
-       char **envp;
-       enum umh_wait wait;
-       int retval;
-       struct file *stdin;
-       void (*cleanup)(char **argv, char **envp);
-};
-
 /*
  * This is the task which runs the usermode application
  */
@@ -145,36 +134,10 @@ static int ____call_usermodehelper(void *data)
        struct subprocess_info *sub_info = data;
        int retval;
 
-       BUG_ON(atomic_read(&sub_info->cred->usage) != 1);
-
-       /* Unblock all signals */
        spin_lock_irq(&current->sighand->siglock);
        flush_signal_handlers(current, 1);
-       sigemptyset(&current->blocked);
-       recalc_sigpending();
        spin_unlock_irq(&current->sighand->siglock);
 
-       /* Install the credentials */
-       commit_creds(sub_info->cred);
-       sub_info->cred = NULL;
-
-       /* Install input pipe when needed */
-       if (sub_info->stdin) {
-               struct files_struct *f = current->files;
-               struct fdtable *fdt;
-               /* no races because files should be private here */
-               sys_close(0);
-               fd_install(0, sub_info->stdin);
-               spin_lock(&f->file_lock);
-               fdt = files_fdtable(f);
-               FD_SET(0, fdt->open_fds);
-               FD_CLR(0, fdt->close_on_exec);
-               spin_unlock(&f->file_lock);
-
-               /* and disallow core files too */
-               current->signal->rlim[RLIMIT_CORE] = (struct rlimit){0, 0};
-       }
-
        /* We can run anywhere, unlike our parent keventd(). */
        set_cpus_allowed_ptr(current, cpu_all_mask);
 
@@ -184,9 +147,16 @@ static int ____call_usermodehelper(void *data)
         */
        set_user_nice(current, 0);
 
+       if (sub_info->init) {
+               retval = sub_info->init(sub_info);
+               if (retval)
+                       goto fail;
+       }
+
        retval = kernel_execve(sub_info->path, sub_info->argv, sub_info->envp);
 
        /* Exec failed? */
+fail:
        sub_info->retval = retval;
        do_exit(0);
 }
@@ -194,9 +164,7 @@ static int ____call_usermodehelper(void *data)
 void call_usermodehelper_freeinfo(struct subprocess_info *info)
 {
        if (info->cleanup)
-               (*info->cleanup)(info->argv, info->envp);
-       if (info->cred)
-               put_cred(info->cred);
+               (*info->cleanup)(info);
        kfree(info);
 }
 EXPORT_SYMBOL(call_usermodehelper_freeinfo);
@@ -207,16 +175,16 @@ static int wait_for_helper(void *data)
        struct subprocess_info *sub_info = data;
        pid_t pid;
 
-       /* Install a handler: if SIGCLD isn't handled sys_wait4 won't
-        * populate the status, but will return -ECHILD. */
-       allow_signal(SIGCHLD);
+       /* If SIGCLD is ignored sys_wait4 won't populate the status. */
+       spin_lock_irq(&current->sighand->siglock);
+       current->sighand->action[SIGCHLD-1].sa.sa_handler = SIG_DFL;
+       spin_unlock_irq(&current->sighand->siglock);
 
        pid = kernel_thread(____call_usermodehelper, sub_info, SIGCHLD);
        if (pid < 0) {
                sub_info->retval = pid;
        } else {
-               int ret;
-
+               int ret = -ECHILD;
                /*
                 * Normally it is bogus to call wait4() from in-kernel because
                 * wait4() wants to write the exit code to a userspace address.
@@ -237,10 +205,7 @@ static int wait_for_helper(void *data)
                        sub_info->retval = ret;
        }
 
-       if (sub_info->wait == UMH_NO_WAIT)
-               call_usermodehelper_freeinfo(sub_info);
-       else
-               complete(sub_info->complete);
+       complete(sub_info->complete);
        return 0;
 }
 
@@ -249,15 +214,13 @@ static void __call_usermodehelper(struct work_struct *work)
 {
        struct subprocess_info *sub_info =
                container_of(work, struct subprocess_info, work);
-       pid_t pid;
        enum umh_wait wait = sub_info->wait;
-
-       BUG_ON(atomic_read(&sub_info->cred->usage) != 1);
+       pid_t pid;
 
        /* CLONE_VFORK: wait until the usermode helper has execve'd
         * successfully We need the data structures to stay around
         * until that is done.  */
-       if (wait == UMH_WAIT_PROC || wait == UMH_NO_WAIT)
+       if (wait == UMH_WAIT_PROC)
                pid = kernel_thread(wait_for_helper, sub_info,
                                    CLONE_FS | CLONE_FILES | SIGCHLD);
        else
@@ -266,15 +229,16 @@ static void __call_usermodehelper(struct work_struct *work)
 
        switch (wait) {
        case UMH_NO_WAIT:
+               call_usermodehelper_freeinfo(sub_info);
                break;
 
        case UMH_WAIT_PROC:
                if (pid > 0)
                        break;
-               sub_info->retval = pid;
                /* FALLTHROUGH */
-
        case UMH_WAIT_EXEC:
+               if (pid < 0)
+                       sub_info->retval = pid;
                complete(sub_info->complete);
        }
 }
@@ -376,80 +340,37 @@ struct subprocess_info *call_usermodehelper_setup(char *path, char **argv,
        sub_info->path = path;
        sub_info->argv = argv;
        sub_info->envp = envp;
-       sub_info->cred = prepare_usermodehelper_creds();
-       if (!sub_info->cred) {
-               kfree(sub_info);
-               return NULL;
-       }
-
   out:
        return sub_info;
 }
 EXPORT_SYMBOL(call_usermodehelper_setup);
 
 /**
- * call_usermodehelper_setkeys - set the session keys for usermode helper
- * @info: a subprocess_info returned by call_usermodehelper_setup
- * @session_keyring: the session keyring for the process
- */
-void call_usermodehelper_setkeys(struct subprocess_info *info,
-                                struct key *session_keyring)
-{
-#ifdef CONFIG_KEYS
-       struct thread_group_cred *tgcred = info->cred->tgcred;
-       key_put(tgcred->session_keyring);
-       tgcred->session_keyring = key_get(session_keyring);
-#else
-       BUG();
-#endif
-}
-EXPORT_SYMBOL(call_usermodehelper_setkeys);
-
-/**
- * call_usermodehelper_setcleanup - set a cleanup function
+ * call_usermodehelper_setfns - set a cleanup/init function
  * @info: a subprocess_info returned by call_usermodehelper_setup
  * @cleanup: a cleanup function
+ * @init: an init function
+ * @data: arbitrary context sensitive data
  *
- * The cleanup function is just befor ethe subprocess_info is about to
+ * The init function is used to customize the helper process prior to
+ * exec.  A non-zero return code causes the process to error out, exit,
+ * and return the failure to the calling process
+ *
+ * The cleanup function is just before ethe subprocess_info is about to
  * be freed.  This can be used for freeing the argv and envp.  The
  * Function must be runnable in either a process context or the
  * context in which call_usermodehelper_exec is called.
  */
-void call_usermodehelper_setcleanup(struct subprocess_info *info,
-                                   void (*cleanup)(char **argv, char **envp))
+void call_usermodehelper_setfns(struct subprocess_info *info,
+                   int (*init)(struct subprocess_info *info),
+                   void (*cleanup)(struct subprocess_info *info),
+                   void *data)
 {
        info->cleanup = cleanup;
+       info->init = init;
+       info->data = data;
 }
-EXPORT_SYMBOL(call_usermodehelper_setcleanup);
-
-/**
- * call_usermodehelper_stdinpipe - set up a pipe to be used for stdin
- * @sub_info: a subprocess_info returned by call_usermodehelper_setup
- * @filp: set to the write-end of a pipe
- *
- * This constructs a pipe, and sets the read end to be the stdin of the
- * subprocess, and returns the write-end in *@filp.
- */
-int call_usermodehelper_stdinpipe(struct subprocess_info *sub_info,
-                                 struct file **filp)
-{
-       struct file *f;
-
-       f = create_write_pipe(0);
-       if (IS_ERR(f))
-               return PTR_ERR(f);
-       *filp = f;
-
-       f = create_read_pipe(f, 0);
-       if (IS_ERR(f)) {
-               free_write_pipe(*filp);
-               return PTR_ERR(f);
-       }
-       sub_info->stdin = f;
-
-       return 0;
-}
-EXPORT_SYMBOL(call_usermodehelper_stdinpipe);
+EXPORT_SYMBOL(call_usermodehelper_setfns);
 
 /**
  * call_usermodehelper_exec - start a usermode application
@@ -469,9 +390,6 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info,
        DECLARE_COMPLETION_ONSTACK(done);
        int retval = 0;
 
-       BUG_ON(atomic_read(&sub_info->cred->usage) != 1);
-       validate_creds(sub_info->cred);
-
        helper_lock();
        if (sub_info->path[0] == '\0')
                goto out;
@@ -498,41 +416,6 @@ unlock:
 }
 EXPORT_SYMBOL(call_usermodehelper_exec);
 
-/**
- * call_usermodehelper_pipe - call a usermode helper process with a pipe stdin
- * @path: path to usermode executable
- * @argv: arg vector for process
- * @envp: environment for process
- * @filp: set to the write-end of a pipe
- *
- * This is a simple wrapper which executes a usermode-helper function
- * with a pipe as stdin.  It is implemented entirely in terms of
- * lower-level call_usermodehelper_* functions.
- */
-int call_usermodehelper_pipe(char *path, char **argv, char **envp,
-                            struct file **filp)
-{
-       struct subprocess_info *sub_info;
-       int ret;
-
-       sub_info = call_usermodehelper_setup(path, argv, envp, GFP_KERNEL);
-       if (sub_info == NULL)
-               return -ENOMEM;
-
-       ret = call_usermodehelper_stdinpipe(sub_info, filp);
-       if (ret < 0) {
-               call_usermodehelper_freeinfo(sub_info);
-               return ret;
-       }
-
-       ret = call_usermodehelper_exec(sub_info, UMH_WAIT_EXEC);
-       if (ret < 0)    /* Failed to execute helper, close pipe */
-               filp_close(*filp, NULL);
-
-       return ret;
-}
-EXPORT_SYMBOL(call_usermodehelper_pipe);
-
 void __init usermodehelper_init(void)
 {
        khelper_wq = create_singlethread_workqueue("khelper");
index 3c4fc4bb4b82341da0c65d5b37e5f476ab7753f6..333fbcc969783a7cca1728f141c870be7b24e918 100644 (file)
@@ -180,8 +180,6 @@ extern const struct kernel_symbol __start___ksymtab_gpl[];
 extern const struct kernel_symbol __stop___ksymtab_gpl[];
 extern const struct kernel_symbol __start___ksymtab_gpl_future[];
 extern const struct kernel_symbol __stop___ksymtab_gpl_future[];
-extern const struct kernel_symbol __start___ksymtab_gpl_future[];
-extern const struct kernel_symbol __stop___ksymtab_gpl_future[];
 extern const unsigned long __start___kcrctab[];
 extern const unsigned long __start___kcrctab_gpl[];
 extern const unsigned long __start___kcrctab_gpl_future[];
index b1c9857f8402d8ae66ae651153b917239d08d512..fdd8ae609ce337433b7c25c50eb20cd2ac9a16e7 100644 (file)
@@ -659,7 +659,7 @@ static int padata_cpu_callback(struct notifier_block *nfb,
                err = __padata_add_cpu(pinst, cpu);
                mutex_unlock(&pinst->lock);
                if (err)
-                       return NOTIFY_BAD;
+                       return notifier_from_errno(err);
                break;
 
        case CPU_DOWN_PREPARE:
@@ -670,7 +670,7 @@ static int padata_cpu_callback(struct notifier_block *nfb,
                err = __padata_remove_cpu(pinst, cpu);
                mutex_unlock(&pinst->lock);
                if (err)
-                       return NOTIFY_BAD;
+                       return notifier_from_errno(err);
                break;
 
        case CPU_UP_CANCELED:
index 13d966b4c14a26f381a563aafe8721bc278a941d..3b16cd93fa7de21977a53f863bae9b6462e355d1 100644 (file)
@@ -87,6 +87,7 @@ NORET_TYPE void panic(const char * fmt, ...)
         */
        preempt_disable();
 
+       console_verbose();
        bust_spinlocks(1);
        va_start(args, fmt);
        vsnprintf(buf, sizeof(buf), fmt, args);
@@ -178,6 +179,7 @@ static const struct tnt tnts[] = {
        { TAINT_OVERRIDDEN_ACPI_TABLE,  'A', ' ' },
        { TAINT_WARN,                   'W', ' ' },
        { TAINT_CRAP,                   'C', ' ' },
+       { TAINT_FIRMWARE_WORKAROUND,    'I', ' ' },
 };
 
 /**
@@ -194,6 +196,7 @@ static const struct tnt tnts[] = {
  *  'A' - ACPI table overridden.
  *  'W' - Taint on warning.
  *  'C' - modules from drivers/staging are loaded.
+ *  'I' - Working around severe firmware bug.
  *
  *     The string is overwritten by the next call to print_tainted().
  */
@@ -365,7 +368,8 @@ struct slowpath_args {
        va_list args;
 };
 
-static void warn_slowpath_common(const char *file, int line, void *caller, struct slowpath_args *args)
+static void warn_slowpath_common(const char *file, int line, void *caller,
+                                unsigned taint, struct slowpath_args *args)
 {
        const char *board;
 
@@ -381,7 +385,7 @@ static void warn_slowpath_common(const char *file, int line, void *caller, struc
        print_modules();
        dump_stack();
        print_oops_end_marker();
-       add_taint(TAINT_WARN);
+       add_taint(taint);
 }
 
 void warn_slowpath_fmt(const char *file, int line, const char *fmt, ...)
@@ -390,14 +394,29 @@ void warn_slowpath_fmt(const char *file, int line, const char *fmt, ...)
 
        args.fmt = fmt;
        va_start(args.args, fmt);
-       warn_slowpath_common(file, line, __builtin_return_address(0), &args);
+       warn_slowpath_common(file, line, __builtin_return_address(0),
+                            TAINT_WARN, &args);
        va_end(args.args);
 }
 EXPORT_SYMBOL(warn_slowpath_fmt);
 
+void warn_slowpath_fmt_taint(const char *file, int line,
+                            unsigned taint, const char *fmt, ...)
+{
+       struct slowpath_args args;
+
+       args.fmt = fmt;
+       va_start(args.args, fmt);
+       warn_slowpath_common(file, line, __builtin_return_address(0),
+                            taint, &args);
+       va_end(args.args);
+}
+EXPORT_SYMBOL(warn_slowpath_fmt_taint);
+
 void warn_slowpath_null(const char *file, int line)
 {
-       warn_slowpath_common(file, line, __builtin_return_address(0), NULL);
+       warn_slowpath_common(file, line, __builtin_return_address(0),
+                            TAINT_WARN, NULL);
 }
 EXPORT_SYMBOL(warn_slowpath_null);
 #endif
index a4fa381db3c2de81b93d1f57708706d18d9702d3..bd7ce8ca5bb9d7aff449674f1a8a24cdf1604be0 100644 (file)
@@ -2297,11 +2297,6 @@ unlock:
        rcu_read_unlock();
 }
 
-static unsigned long perf_data_size(struct perf_mmap_data *data)
-{
-       return data->nr_pages << (PAGE_SHIFT + data->data_order);
-}
-
 #ifndef CONFIG_PERF_USE_VMALLOC
 
 /*
@@ -2320,6 +2315,19 @@ perf_mmap_to_page(struct perf_mmap_data *data, unsigned long pgoff)
        return virt_to_page(data->data_pages[pgoff - 1]);
 }
 
+static void *perf_mmap_alloc_page(int cpu)
+{
+       struct page *page;
+       int node;
+
+       node = (cpu == -1) ? cpu : cpu_to_node(cpu);
+       page = alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0);
+       if (!page)
+               return NULL;
+
+       return page_address(page);
+}
+
 static struct perf_mmap_data *
 perf_mmap_data_alloc(struct perf_event *event, int nr_pages)
 {
@@ -2336,17 +2344,16 @@ perf_mmap_data_alloc(struct perf_event *event, int nr_pages)
        if (!data)
                goto fail;
 
-       data->user_page = (void *)get_zeroed_page(GFP_KERNEL);
+       data->user_page = perf_mmap_alloc_page(event->cpu);
        if (!data->user_page)
                goto fail_user_page;
 
        for (i = 0; i < nr_pages; i++) {
-               data->data_pages[i] = (void *)get_zeroed_page(GFP_KERNEL);
+               data->data_pages[i] = perf_mmap_alloc_page(event->cpu);
                if (!data->data_pages[i])
                        goto fail_data_pages;
        }
 
-       data->data_order = 0;
        data->nr_pages = nr_pages;
 
        return data;
@@ -2382,6 +2389,11 @@ static void perf_mmap_data_free(struct perf_mmap_data *data)
        kfree(data);
 }
 
+static inline int page_order(struct perf_mmap_data *data)
+{
+       return 0;
+}
+
 #else
 
 /*
@@ -2390,10 +2402,15 @@ static void perf_mmap_data_free(struct perf_mmap_data *data)
  * Required for architectures that have d-cache aliasing issues.
  */
 
+static inline int page_order(struct perf_mmap_data *data)
+{
+       return data->page_order;
+}
+
 static struct page *
 perf_mmap_to_page(struct perf_mmap_data *data, unsigned long pgoff)
 {
-       if (pgoff > (1UL << data->data_order))
+       if (pgoff > (1UL << page_order(data)))
                return NULL;
 
        return vmalloc_to_page((void *)data->user_page + pgoff * PAGE_SIZE);
@@ -2413,7 +2430,7 @@ static void perf_mmap_data_free_work(struct work_struct *work)
        int i, nr;
 
        data = container_of(work, struct perf_mmap_data, work);
-       nr = 1 << data->data_order;
+       nr = 1 << page_order(data);
 
        base = data->user_page;
        for (i = 0; i < nr + 1; i++)
@@ -2452,7 +2469,7 @@ perf_mmap_data_alloc(struct perf_event *event, int nr_pages)
 
        data->user_page = all_buf;
        data->data_pages[0] = all_buf + PAGE_SIZE;
-       data->data_order = ilog2(nr_pages);
+       data->page_order = ilog2(nr_pages);
        data->nr_pages = 1;
 
        return data;
@@ -2466,6 +2483,11 @@ fail:
 
 #endif
 
+static unsigned long perf_data_size(struct perf_mmap_data *data)
+{
+       return data->nr_pages << (PAGE_SHIFT + page_order(data));
+}
+
 static int perf_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
        struct perf_event *event = vma->vm_file->private_data;
@@ -2506,8 +2528,6 @@ perf_mmap_data_init(struct perf_event *event, struct perf_mmap_data *data)
 {
        long max_size = perf_data_size(data);
 
-       atomic_set(&data->lock, -1);
-
        if (event->attr.watermark) {
                data->watermark = min_t(long, max_size,
                                        event->attr.wakeup_watermark);
@@ -2580,6 +2600,14 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma)
        long user_extra, extra;
        int ret = 0;
 
+       /*
+        * Don't allow mmap() of inherited per-task counters. This would
+        * create a performance issue due to all children writing to the
+        * same buffer.
+        */
+       if (event->cpu == -1 && event->attr.inherit)
+               return -EINVAL;
+
        if (!(vma->vm_flags & VM_SHARED))
                return -EINVAL;
 
@@ -2885,120 +2913,80 @@ static void perf_output_wakeup(struct perf_output_handle *handle)
 }
 
 /*
- * Curious locking construct.
- *
  * We need to ensure a later event_id doesn't publish a head when a former
- * event_id isn't done writing. However since we need to deal with NMIs we
+ * event isn't done writing. However since we need to deal with NMIs we
  * cannot fully serialize things.
  *
- * What we do is serialize between CPUs so we only have to deal with NMI
- * nesting on a single CPU.
- *
  * We only publish the head (and generate a wakeup) when the outer-most
- * event_id completes.
+ * event completes.
  */
-static void perf_output_lock(struct perf_output_handle *handle)
+static void perf_output_get_handle(struct perf_output_handle *handle)
 {
        struct perf_mmap_data *data = handle->data;
-       int cur, cpu = get_cpu();
-
-       handle->locked = 0;
 
-       for (;;) {
-               cur = atomic_cmpxchg(&data->lock, -1, cpu);
-               if (cur == -1) {
-                       handle->locked = 1;
-                       break;
-               }
-               if (cur == cpu)
-                       break;
-
-               cpu_relax();
-       }
+       preempt_disable();
+       local_inc(&data->nest);
+       handle->wakeup = local_read(&data->wakeup);
 }
 
-static void perf_output_unlock(struct perf_output_handle *handle)
+static void perf_output_put_handle(struct perf_output_handle *handle)
 {
        struct perf_mmap_data *data = handle->data;
        unsigned long head;
-       int cpu;
-
-       data->done_head = data->head;
-
-       if (!handle->locked)
-               goto out;
 
 again:
-       /*
-        * The xchg implies a full barrier that ensures all writes are done
-        * before we publish the new head, matched by a rmb() in userspace when
-        * reading this position.
-        */
-       while ((head = atomic_long_xchg(&data->done_head, 0)))
-               data->user_page->data_head = head;
+       head = local_read(&data->head);
 
        /*
-        * NMI can happen here, which means we can miss a done_head update.
+        * IRQ/NMI can happen here, which means we can miss a head update.
         */
 
-       cpu = atomic_xchg(&data->lock, -1);
-       WARN_ON_ONCE(cpu != smp_processor_id());
+       if (!local_dec_and_test(&data->nest))
+               goto out;
 
        /*
-        * Therefore we have to validate we did not indeed do so.
+        * Publish the known good head. Rely on the full barrier implied
+        * by atomic_dec_and_test() order the data->head read and this
+        * write.
         */
-       if (unlikely(atomic_long_read(&data->done_head))) {
-               /*
-                * Since we had it locked, we can lock it again.
-                */
-               while (atomic_cmpxchg(&data->lock, -1, cpu) != -1)
-                       cpu_relax();
+       data->user_page->data_head = head;
 
+       /*
+        * Now check if we missed an update, rely on the (compiler)
+        * barrier in atomic_dec_and_test() to re-read data->head.
+        */
+       if (unlikely(head != local_read(&data->head))) {
+               local_inc(&data->nest);
                goto again;
        }
 
-       if (atomic_xchg(&data->wakeup, 0))
+       if (handle->wakeup != local_read(&data->wakeup))
                perf_output_wakeup(handle);
-out:
-       put_cpu();
+
+ out:
+       preempt_enable();
 }
 
-void perf_output_copy(struct perf_output_handle *handle,
+__always_inline void perf_output_copy(struct perf_output_handle *handle,
                      const void *buf, unsigned int len)
 {
-       unsigned int pages_mask;
-       unsigned long offset;
-       unsigned int size;
-       void **pages;
-
-       offset          = handle->offset;
-       pages_mask      = handle->data->nr_pages - 1;
-       pages           = handle->data->data_pages;
-
        do {
-               unsigned long page_offset;
-               unsigned long page_size;
-               int nr;
+               unsigned long size = min_t(unsigned long, handle->size, len);
 
-               nr          = (offset >> PAGE_SHIFT) & pages_mask;
-               page_size   = 1UL << (handle->data->data_order + PAGE_SHIFT);
-               page_offset = offset & (page_size - 1);
-               size        = min_t(unsigned int, page_size - page_offset, len);
+               memcpy(handle->addr, buf, size);
 
-               memcpy(pages[nr] + page_offset, buf, size);
+               len -= size;
+               handle->addr += size;
+               handle->size -= size;
+               if (!handle->size) {
+                       struct perf_mmap_data *data = handle->data;
 
-               len         -= size;
-               buf         += size;
-               offset      += size;
+                       handle->page++;
+                       handle->page &= data->nr_pages - 1;
+                       handle->addr = data->data_pages[handle->page];
+                       handle->size = PAGE_SIZE << page_order(data);
+               }
        } while (len);
-
-       handle->offset = offset;
-
-       /*
-        * Check we didn't copy past our reservation window, taking the
-        * possible unsigned int wrap into account.
-        */
-       WARN_ON_ONCE(((long)(handle->head - handle->offset)) < 0);
 }
 
 int perf_output_begin(struct perf_output_handle *handle,
@@ -3036,13 +3024,13 @@ int perf_output_begin(struct perf_output_handle *handle,
        handle->sample  = sample;
 
        if (!data->nr_pages)
-               goto fail;
+               goto out;
 
-       have_lost = atomic_read(&data->lost);
+       have_lost = local_read(&data->lost);
        if (have_lost)
                size += sizeof(lost_event);
 
-       perf_output_lock(handle);
+       perf_output_get_handle(handle);
 
        do {
                /*
@@ -3052,24 +3040,28 @@ int perf_output_begin(struct perf_output_handle *handle,
                 */
                tail = ACCESS_ONCE(data->user_page->data_tail);
                smp_rmb();
-               offset = head = atomic_long_read(&data->head);
+               offset = head = local_read(&data->head);
                head += size;
                if (unlikely(!perf_output_space(data, tail, offset, head)))
                        goto fail;
-       } while (atomic_long_cmpxchg(&data->head, offset, head) != offset);
+       } while (local_cmpxchg(&data->head, offset, head) != offset);
 
-       handle->offset  = offset;
-       handle->head    = head;
+       if (head - local_read(&data->wakeup) > data->watermark)
+               local_add(data->watermark, &data->wakeup);
 
-       if (head - tail > data->watermark)
-               atomic_set(&data->wakeup, 1);
+       handle->page = offset >> (PAGE_SHIFT + page_order(data));
+       handle->page &= data->nr_pages - 1;
+       handle->size = offset & ((PAGE_SIZE << page_order(data)) - 1);
+       handle->addr = data->data_pages[handle->page];
+       handle->addr += handle->size;
+       handle->size = (PAGE_SIZE << page_order(data)) - handle->size;
 
        if (have_lost) {
                lost_event.header.type = PERF_RECORD_LOST;
                lost_event.header.misc = 0;
                lost_event.header.size = sizeof(lost_event);
                lost_event.id          = event->id;
-               lost_event.lost        = atomic_xchg(&data->lost, 0);
+               lost_event.lost        = local_xchg(&data->lost, 0);
 
                perf_output_put(handle, lost_event);
        }
@@ -3077,8 +3069,8 @@ int perf_output_begin(struct perf_output_handle *handle,
        return 0;
 
 fail:
-       atomic_inc(&data->lost);
-       perf_output_unlock(handle);
+       local_inc(&data->lost);
+       perf_output_put_handle(handle);
 out:
        rcu_read_unlock();
 
@@ -3093,14 +3085,14 @@ void perf_output_end(struct perf_output_handle *handle)
        int wakeup_events = event->attr.wakeup_events;
 
        if (handle->sample && wakeup_events) {
-               int events = atomic_inc_return(&data->events);
+               int events = local_inc_return(&data->events);
                if (events >= wakeup_events) {
-                       atomic_sub(wakeup_events, &data->events);
-                       atomic_set(&data->wakeup, 1);
+                       local_sub(wakeup_events, &data->events);
+                       local_inc(&data->wakeup);
                }
        }
 
-       perf_output_unlock(handle);
+       perf_output_put_handle(handle);
        rcu_read_unlock();
 }
 
@@ -3436,22 +3428,13 @@ static void perf_event_task_output(struct perf_event *event,
 {
        struct perf_output_handle handle;
        struct task_struct *task = task_event->task;
-       unsigned long flags;
        int size, ret;
 
-       /*
-        * If this CPU attempts to acquire an rq lock held by a CPU spinning
-        * in perf_output_lock() from interrupt context, it's game over.
-        */
-       local_irq_save(flags);
-
        size  = task_event->event_id.header.size;
        ret = perf_output_begin(&handle, event, size, 0, 0);
 
-       if (ret) {
-               local_irq_restore(flags);
+       if (ret)
                return;
-       }
 
        task_event->event_id.pid = perf_event_pid(event, task);
        task_event->event_id.ppid = perf_event_pid(event, current);
@@ -3462,7 +3445,6 @@ static void perf_event_task_output(struct perf_event *event,
        perf_output_put(&handle, task_event->event_id);
 
        perf_output_end(&handle);
-       local_irq_restore(flags);
 }
 
 static int perf_event_task_match(struct perf_event *event)
@@ -4020,9 +4002,6 @@ static void perf_swevent_add(struct perf_event *event, u64 nr,
        perf_swevent_overflow(event, 0, nmi, data, regs);
 }
 
-static int perf_tp_event_match(struct perf_event *event,
-                               struct perf_sample_data *data);
-
 static int perf_exclude_event(struct perf_event *event,
                              struct pt_regs *regs)
 {
@@ -4052,10 +4031,6 @@ static int perf_swevent_match(struct perf_event *event,
        if (perf_exclude_event(event, regs))
                return 0;
 
-       if (event->attr.type == PERF_TYPE_TRACEPOINT &&
-           !perf_tp_event_match(event, data))
-               return 0;
-
        return 1;
 }
 
@@ -4066,19 +4041,46 @@ static inline u64 swevent_hash(u64 type, u32 event_id)
        return hash_64(val, SWEVENT_HLIST_BITS);
 }
 
-static struct hlist_head *
-find_swevent_head(struct perf_cpu_context *ctx, u64 type, u32 event_id)
+static inline struct hlist_head *
+__find_swevent_head(struct swevent_hlist *hlist, u64 type, u32 event_id)
 {
-       u64 hash;
-       struct swevent_hlist *hlist;
+       u64 hash = swevent_hash(type, event_id);
 
-       hash = swevent_hash(type, event_id);
+       return &hlist->heads[hash];
+}
+
+/* For the read side: events when they trigger */
+static inline struct hlist_head *
+find_swevent_head_rcu(struct perf_cpu_context *ctx, u64 type, u32 event_id)
+{
+       struct swevent_hlist *hlist;
 
        hlist = rcu_dereference(ctx->swevent_hlist);
        if (!hlist)
                return NULL;
 
-       return &hlist->heads[hash];
+       return __find_swevent_head(hlist, type, event_id);
+}
+
+/* For the event head insertion and removal in the hlist */
+static inline struct hlist_head *
+find_swevent_head(struct perf_cpu_context *ctx, struct perf_event *event)
+{
+       struct swevent_hlist *hlist;
+       u32 event_id = event->attr.config;
+       u64 type = event->attr.type;
+
+       /*
+        * Event scheduling is always serialized against hlist allocation
+        * and release. Which makes the protected version suitable here.
+        * The context lock guarantees that.
+        */
+       hlist = rcu_dereference_protected(ctx->swevent_hlist,
+                                         lockdep_is_held(&event->ctx->lock));
+       if (!hlist)
+               return NULL;
+
+       return __find_swevent_head(hlist, type, event_id);
 }
 
 static void do_perf_sw_event(enum perf_type_id type, u32 event_id,
@@ -4095,7 +4097,7 @@ static void do_perf_sw_event(enum perf_type_id type, u32 event_id,
 
        rcu_read_lock();
 
-       head = find_swevent_head(cpuctx, type, event_id);
+       head = find_swevent_head_rcu(cpuctx, type, event_id);
 
        if (!head)
                goto end;
@@ -4110,7 +4112,7 @@ end:
 
 int perf_swevent_get_recursion_context(void)
 {
-       struct perf_cpu_context *cpuctx = &get_cpu_var(perf_cpu_context);
+       struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context);
        int rctx;
 
        if (in_nmi())
@@ -4122,10 +4124,8 @@ int perf_swevent_get_recursion_context(void)
        else
                rctx = 0;
 
-       if (cpuctx->recursion[rctx]) {
-               put_cpu_var(perf_cpu_context);
+       if (cpuctx->recursion[rctx])
                return -1;
-       }
 
        cpuctx->recursion[rctx]++;
        barrier();
@@ -4139,7 +4139,6 @@ void perf_swevent_put_recursion_context(int rctx)
        struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context);
        barrier();
        cpuctx->recursion[rctx]--;
-       put_cpu_var(perf_cpu_context);
 }
 EXPORT_SYMBOL_GPL(perf_swevent_put_recursion_context);
 
@@ -4150,6 +4149,7 @@ void __perf_sw_event(u32 event_id, u64 nr, int nmi,
        struct perf_sample_data data;
        int rctx;
 
+       preempt_disable_notrace();
        rctx = perf_swevent_get_recursion_context();
        if (rctx < 0)
                return;
@@ -4159,6 +4159,7 @@ void __perf_sw_event(u32 event_id, u64 nr, int nmi,
        do_perf_sw_event(PERF_TYPE_SOFTWARE, event_id, nr, nmi, &data, regs);
 
        perf_swevent_put_recursion_context(rctx);
+       preempt_enable_notrace();
 }
 
 static void perf_swevent_read(struct perf_event *event)
@@ -4178,7 +4179,7 @@ static int perf_swevent_enable(struct perf_event *event)
                perf_swevent_set_period(event);
        }
 
-       head = find_swevent_head(cpuctx, event->attr.type, event->attr.config);
+       head = find_swevent_head(cpuctx, event);
        if (WARN_ON_ONCE(!head))
                return -EINVAL;
 
@@ -4366,6 +4367,14 @@ static const struct pmu perf_ops_task_clock = {
        .read           = task_clock_perf_event_read,
 };
 
+/* Deref the hlist from the update side */
+static inline struct swevent_hlist *
+swevent_hlist_deref(struct perf_cpu_context *cpuctx)
+{
+       return rcu_dereference_protected(cpuctx->swevent_hlist,
+                                        lockdep_is_held(&cpuctx->hlist_mutex));
+}
+
 static void swevent_hlist_release_rcu(struct rcu_head *rcu_head)
 {
        struct swevent_hlist *hlist;
@@ -4376,12 +4385,11 @@ static void swevent_hlist_release_rcu(struct rcu_head *rcu_head)
 
 static void swevent_hlist_release(struct perf_cpu_context *cpuctx)
 {
-       struct swevent_hlist *hlist;
+       struct swevent_hlist *hlist = swevent_hlist_deref(cpuctx);
 
-       if (!cpuctx->swevent_hlist)
+       if (!hlist)
                return;
 
-       hlist = cpuctx->swevent_hlist;
        rcu_assign_pointer(cpuctx->swevent_hlist, NULL);
        call_rcu(&hlist->rcu_head, swevent_hlist_release_rcu);
 }
@@ -4418,7 +4426,7 @@ static int swevent_hlist_get_cpu(struct perf_event *event, int cpu)
 
        mutex_lock(&cpuctx->hlist_mutex);
 
-       if (!cpuctx->swevent_hlist && cpu_online(cpu)) {
+       if (!swevent_hlist_deref(cpuctx) && cpu_online(cpu)) {
                struct swevent_hlist *hlist;
 
                hlist = kzalloc(sizeof(*hlist), GFP_KERNEL);
@@ -4467,10 +4475,46 @@ static int swevent_hlist_get(struct perf_event *event)
 
 #ifdef CONFIG_EVENT_TRACING
 
-void perf_tp_event(int event_id, u64 addr, u64 count, void *record,
-                  int entry_size, struct pt_regs *regs)
+static const struct pmu perf_ops_tracepoint = {
+       .enable         = perf_trace_enable,
+       .disable        = perf_trace_disable,
+       .read           = perf_swevent_read,
+       .unthrottle     = perf_swevent_unthrottle,
+};
+
+static int perf_tp_filter_match(struct perf_event *event,
+                               struct perf_sample_data *data)
+{
+       void *record = data->raw->data;
+
+       if (likely(!event->filter) || filter_match_preds(event->filter, record))
+               return 1;
+       return 0;
+}
+
+static int perf_tp_event_match(struct perf_event *event,
+                               struct perf_sample_data *data,
+                               struct pt_regs *regs)
+{
+       /*
+        * All tracepoints are from kernel-space.
+        */
+       if (event->attr.exclude_kernel)
+               return 0;
+
+       if (!perf_tp_filter_match(event, data))
+               return 0;
+
+       return 1;
+}
+
+void perf_tp_event(u64 addr, u64 count, void *record, int entry_size,
+                  struct pt_regs *regs, struct hlist_head *head)
 {
        struct perf_sample_data data;
+       struct perf_event *event;
+       struct hlist_node *node;
+
        struct perf_raw_record raw = {
                .size = entry_size,
                .data = record,
@@ -4479,26 +4523,18 @@ void perf_tp_event(int event_id, u64 addr, u64 count, void *record,
        perf_sample_data_init(&data, addr);
        data.raw = &raw;
 
-       /* Trace events already protected against recursion */
-       do_perf_sw_event(PERF_TYPE_TRACEPOINT, event_id, count, 1,
-                        &data, regs);
+       rcu_read_lock();
+       hlist_for_each_entry_rcu(event, node, head, hlist_entry) {
+               if (perf_tp_event_match(event, &data, regs))
+                       perf_swevent_add(event, count, 1, &data, regs);
+       }
+       rcu_read_unlock();
 }
 EXPORT_SYMBOL_GPL(perf_tp_event);
 
-static int perf_tp_event_match(struct perf_event *event,
-                               struct perf_sample_data *data)
-{
-       void *record = data->raw->data;
-
-       if (likely(!event->filter) || filter_match_preds(event->filter, record))
-               return 1;
-       return 0;
-}
-
 static void tp_perf_event_destroy(struct perf_event *event)
 {
-       perf_trace_disable(event->attr.config);
-       swevent_hlist_put(event);
+       perf_trace_destroy(event);
 }
 
 static const struct pmu *tp_perf_event_init(struct perf_event *event)
@@ -4514,17 +4550,13 @@ static const struct pmu *tp_perf_event_init(struct perf_event *event)
                        !capable(CAP_SYS_ADMIN))
                return ERR_PTR(-EPERM);
 
-       if (perf_trace_enable(event->attr.config))
+       err = perf_trace_init(event);
+       if (err)
                return NULL;
 
        event->destroy = tp_perf_event_destroy;
-       err = swevent_hlist_get(event);
-       if (err) {
-               perf_trace_disable(event->attr.config);
-               return ERR_PTR(err);
-       }
 
-       return &perf_ops_generic;
+       return &perf_ops_tracepoint;
 }
 
 static int perf_event_set_filter(struct perf_event *event, void __user *arg)
@@ -4552,12 +4584,6 @@ static void perf_event_free_filter(struct perf_event *event)
 
 #else
 
-static int perf_tp_event_match(struct perf_event *event,
-                               struct perf_sample_data *data)
-{
-       return 1;
-}
-
 static const struct pmu *tp_perf_event_init(struct perf_event *event)
 {
        return NULL;
@@ -4894,6 +4920,13 @@ static int perf_event_set_output(struct perf_event *event, int output_fd)
        int fput_needed = 0;
        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)
                goto set;
 
@@ -4914,6 +4947,18 @@ static int perf_event_set_output(struct perf_event *event, int output_fd)
        if (event->data)
                goto out;
 
+       /*
+        * Don't allow cross-cpu buffers
+        */
+       if (output_event->cpu != event->cpu)
+               goto out;
+
+       /*
+        * If its not a per-cpu buffer, it must be the same task.
+        */
+       if (output_event->cpu == -1 && output_event->ctx != event->ctx)
+               goto out;
+
        atomic_long_inc(&output_file->f_count);
 
 set:
@@ -4954,8 +4999,8 @@ SYSCALL_DEFINE5(perf_event_open,
        struct perf_event_context *ctx;
        struct file *event_file = NULL;
        struct file *group_file = NULL;
+       int event_fd;
        int fput_needed = 0;
-       int fput_needed2 = 0;
        int err;
 
        /* for future expandability... */
@@ -4976,12 +5021,18 @@ SYSCALL_DEFINE5(perf_event_open,
                        return -EINVAL;
        }
 
+       event_fd = get_unused_fd_flags(O_RDWR);
+       if (event_fd < 0)
+               return event_fd;
+
        /*
         * Get the target context (task or percpu):
         */
        ctx = find_get_context(pid, cpu);
-       if (IS_ERR(ctx))
-               return PTR_ERR(ctx);
+       if (IS_ERR(ctx)) {
+               err = PTR_ERR(ctx);
+               goto err_fd;
+       }
 
        /*
         * Look up the group leader (we will attach this event to it):
@@ -5021,13 +5072,11 @@ SYSCALL_DEFINE5(perf_event_open,
        if (IS_ERR(event))
                goto err_put_context;
 
-       err = anon_inode_getfd("[perf_event]", &perf_fops, event, O_RDWR);
-       if (err < 0)
-               goto err_free_put_context;
-
-       event_file = fget_light(err, &fput_needed2);
-       if (!event_file)
+       event_file = anon_inode_getfile("[perf_event]", &perf_fops, event, O_RDWR);
+       if (IS_ERR(event_file)) {
+               err = PTR_ERR(event_file);
                goto err_free_put_context;
+       }
 
        if (flags & PERF_FLAG_FD_OUTPUT) {
                err = perf_event_set_output(event, group_fd);
@@ -5048,19 +5097,19 @@ SYSCALL_DEFINE5(perf_event_open,
        list_add_tail(&event->owner_entry, &current->perf_event_list);
        mutex_unlock(&current->perf_event_mutex);
 
-err_fput_free_put_context:
-       fput_light(event_file, fput_needed2);
+       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:
-       if (err < 0)
-               free_event(event);
-
+       free_event(event);
 err_put_context:
-       if (err < 0)
-               put_ctx(ctx);
-
        fput_light(group_file, fput_needed);
-
+       put_ctx(ctx);
+err_fd:
+       put_unused_fd(event_fd);
        return err;
 }
 
index aebb30d9c233df40876afa35ef21cc5c306590a1..e9fd8c132d265011e00d75d00e589d83e1d6ce1c 100644 (file)
@@ -513,6 +513,13 @@ void __init pidhash_init(void)
 
 void __init pidmap_init(void)
 {
+       /* bump default and minimum pid_max based on number of cpus */
+       pid_max = min(pid_max_max, max_t(int, pid_max,
+                               PIDS_PER_CPU_DEFAULT * num_possible_cpus()));
+       pid_max_min = max_t(int, pid_max_min,
+                               PIDS_PER_CPU_MIN * num_possible_cpus());
+       pr_info("pid_max: default: %u minimum: %u\n", pid_max, pid_max_min);
+
        init_pid_ns.pidmap[0].page = kzalloc(PAGE_SIZE, GFP_KERNEL);
        /* Reserve PID 0. We never call free_pidmap(0) */
        set_bit(0, init_pid_ns.pidmap[0].page);
index 00bb252f29a29210270bc47167755f9bd8b307e0..9829646d399c5bf0304aa863f78f6f43ae1e4d5e 100644 (file)
@@ -363,7 +363,7 @@ int posix_cpu_clock_get(const clockid_t which_clock, struct timespec *tp)
                                }
                        } else {
                                read_lock(&tasklist_lock);
-                               if (thread_group_leader(p) && p->signal) {
+                               if (thread_group_leader(p) && p->sighand) {
                                        error =
                                            cpu_clock_sample_group(which_clock,
                                                                   p, &rtn);
@@ -439,7 +439,7 @@ int posix_cpu_timer_del(struct k_itimer *timer)
 
        if (likely(p != NULL)) {
                read_lock(&tasklist_lock);
-               if (unlikely(p->signal == NULL)) {
+               if (unlikely(p->sighand == NULL)) {
                        /*
                         * We raced with the reaping of the task.
                         * The deletion should have cleared us off the list.
@@ -691,10 +691,10 @@ int posix_cpu_timer_set(struct k_itimer *timer, int flags,
        read_lock(&tasklist_lock);
        /*
         * We need the tasklist_lock to protect against reaping that
-        * clears p->signal.  If p has just been reaped, we can no
+        * clears p->sighand.  If p has just been reaped, we can no
         * longer get any information about it at all.
         */
-       if (unlikely(p->signal == NULL)) {
+       if (unlikely(p->sighand == NULL)) {
                read_unlock(&tasklist_lock);
                put_task_struct(p);
                timer->it.cpu.task = NULL;
@@ -863,7 +863,7 @@ void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec *itp)
                clear_dead = p->exit_state;
        } else {
                read_lock(&tasklist_lock);
-               if (unlikely(p->signal == NULL)) {
+               if (unlikely(p->sighand == NULL)) {
                        /*
                         * The process has been reaped.
                         * We can't even collect a sample any more.
@@ -1199,7 +1199,7 @@ void posix_cpu_timer_schedule(struct k_itimer *timer)
                spin_lock(&p->sighand->siglock);
        } else {
                read_lock(&tasklist_lock);
-               if (unlikely(p->signal == NULL)) {
+               if (unlikely(p->sighand == NULL)) {
                        /*
                         * The process has been reaped.
                         * We can't even collect a sample any more.
index 00d1fda58ab6a270c42b7ad252e21ff36b4dce96..ad723420acc3e765b12cf393f3cd22a754d80206 100644 (file)
@@ -559,14 +559,7 @@ SYSCALL_DEFINE3(timer_create, const clockid_t, which_clock,
        new_timer->it_id = (timer_t) new_timer_id;
        new_timer->it_clock = which_clock;
        new_timer->it_overrun = -1;
-       error = CLOCK_DISPATCH(which_clock, timer_create, (new_timer));
-       if (error)
-               goto out;
 
-       /*
-        * return the timer_id now.  The next step is hard to
-        * back out if there is an error.
-        */
        if (copy_to_user(created_timer_id,
                         &new_timer_id, sizeof (new_timer_id))) {
                error = -EFAULT;
@@ -597,6 +590,10 @@ SYSCALL_DEFINE3(timer_create, const clockid_t, which_clock,
        new_timer->sigq->info.si_tid   = new_timer->it_id;
        new_timer->sigq->info.si_code  = SI_TIMER;
 
+       error = CLOCK_DISPATCH(which_clock, timer_create, (new_timer));
+       if (error)
+               goto out;
+
        spin_lock_irq(&current->sighand->siglock);
        new_timer->it_signal = current->signal;
        list_add(&new_timer->list, &current->signal->posix_timers);
index dfadc5b729f194905ded52faef8b2d2564dfd2ce..b22a899934cc4fe1669f4599f50ce8f54ca46632 100644 (file)
@@ -365,14 +365,14 @@ static int __cpuinit profile_cpu_callback(struct notifier_block *info,
        switch (action) {
        case CPU_UP_PREPARE:
        case CPU_UP_PREPARE_FROZEN:
-               node = cpu_to_node(cpu);
+               node = cpu_to_mem(cpu);
                per_cpu(cpu_profile_flip, cpu) = 0;
                if (!per_cpu(cpu_profile_hits, cpu)[1]) {
                        page = alloc_pages_exact_node(node,
                                        GFP_KERNEL | __GFP_ZERO,
                                        0);
                        if (!page)
-                               return NOTIFY_BAD;
+                               return notifier_from_errno(-ENOMEM);
                        per_cpu(cpu_profile_hits, cpu)[1] = page_address(page);
                }
                if (!per_cpu(cpu_profile_hits, cpu)[0]) {
@@ -388,7 +388,7 @@ out_free:
                page = virt_to_page(per_cpu(cpu_profile_hits, cpu)[1]);
                per_cpu(cpu_profile_hits, cpu)[1] = NULL;
                __free_page(page);
-               return NOTIFY_BAD;
+               return notifier_from_errno(-ENOMEM);
        case CPU_ONLINE:
        case CPU_ONLINE_FROZEN:
                if (prof_cpu_mask != NULL)
@@ -567,7 +567,7 @@ static int create_hash_tables(void)
        int cpu;
 
        for_each_online_cpu(cpu) {
-               int node = cpu_to_node(cpu);
+               int node = cpu_to_mem(cpu);
                struct page *page;
 
                page = alloc_pages_exact_node(node,
index 6af9cdd558b7b28b5d7e44cc78e3e7cced8582d5..74a3d693c196810f9eed784a2825ea50a7f9db83 100644 (file)
@@ -594,6 +594,32 @@ int ptrace_request(struct task_struct *child, long request,
                ret = ptrace_detach(child, data);
                break;
 
+#ifdef CONFIG_BINFMT_ELF_FDPIC
+       case PTRACE_GETFDPIC: {
+               struct mm_struct *mm = get_task_mm(child);
+               unsigned long tmp = 0;
+
+               ret = -ESRCH;
+               if (!mm)
+                       break;
+
+               switch (addr) {
+               case PTRACE_GETFDPIC_EXEC:
+                       tmp = mm->context.exec_fdpic_loadmap;
+                       break;
+               case PTRACE_GETFDPIC_INTERP:
+                       tmp = mm->context.interp_fdpic_loadmap;
+                       break;
+               default:
+                       break;
+               }
+               mmput(mm);
+
+               ret = put_user(tmp, (unsigned long __user *) data);
+               break;
+       }
+#endif
+
 #ifdef PTRACE_SINGLESTEP
        case PTRACE_SINGLESTEP:
 #endif
index 4268287148c17c34543194ce9ab987d83ee65410..c7cf397fb92958bbcbd2772e13a8d4a4d9c00b6d 100644 (file)
@@ -539,7 +539,7 @@ static int __cpuinit relay_hotcpu_callback(struct notifier_block *nb,
                                        "relay_hotcpu_callback: cpu %d buffer "
                                        "creation failed\n", hotcpu);
                                mutex_unlock(&relay_channels_mutex);
-                               return NOTIFY_BAD;
+                               return notifier_from_errno(-ENOMEM);
                        }
                }
                mutex_unlock(&relay_channels_mutex);
index 9c358e26353427b5a553e900014359c80c4eced2..7b36976e5dea84d11b73fcd5d4ae8963ce4c9aa7 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/spinlock.h>
 #include <linux/fs.h>
 #include <linux/proc_fs.h>
+#include <linux/sched.h>
 #include <linux/seq_file.h>
 #include <linux/device.h>
 #include <linux/pfn.h>
@@ -681,6 +682,8 @@ resource_size_t resource_alignment(struct resource *res)
  * release_region releases a matching busy region.
  */
 
+static DECLARE_WAIT_QUEUE_HEAD(muxed_resource_wait);
+
 /**
  * __request_region - create a new busy resource region
  * @parent: parent resource descriptor
@@ -693,6 +696,7 @@ struct resource * __request_region(struct resource *parent,
                                   resource_size_t start, resource_size_t n,
                                   const char *name, int flags)
 {
+       DECLARE_WAITQUEUE(wait, current);
        struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
 
        if (!res)
@@ -717,7 +721,15 @@ struct resource * __request_region(struct resource *parent,
                        if (!(conflict->flags & IORESOURCE_BUSY))
                                continue;
                }
-
+               if (conflict->flags & flags & IORESOURCE_MUXED) {
+                       add_wait_queue(&muxed_resource_wait, &wait);
+                       write_unlock(&resource_lock);
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+                       schedule();
+                       remove_wait_queue(&muxed_resource_wait, &wait);
+                       write_lock(&resource_lock);
+                       continue;
+               }
                /* Uhhuh, that didn't work out.. */
                kfree(res);
                res = NULL;
@@ -791,6 +803,8 @@ void __release_region(struct resource *parent, resource_size_t start,
                                break;
                        *p = res->sibling;
                        write_unlock(&resource_lock);
+                       if (res->flags & IORESOURCE_MUXED)
+                               wake_up(&muxed_resource_wait);
                        kfree(res);
                        return;
                }
index 054a6012de99b7298d5f92c4b137be17a37335f3..d484081425037b5b59ce076c03f524ead13ec37b 100644 (file)
@@ -969,14 +969,6 @@ static struct rq *task_rq_lock(struct task_struct *p, unsigned long *flags)
        }
 }
 
-void task_rq_unlock_wait(struct task_struct *p)
-{
-       struct rq *rq = task_rq(p);
-
-       smp_mb(); /* spin-unlock-wait is not a full memory barrier */
-       raw_spin_unlock_wait(&rq->lock);
-}
-
 static void __task_rq_unlock(struct rq *rq)
        __releases(rq->lock)
 {
@@ -4061,6 +4053,23 @@ int __sched wait_for_completion_killable(struct completion *x)
 }
 EXPORT_SYMBOL(wait_for_completion_killable);
 
+/**
+ * wait_for_completion_killable_timeout: - waits for completion of a task (w/(to,killable))
+ * @x:  holds the state of this particular completion
+ * @timeout:  timeout value in jiffies
+ *
+ * This waits for either a completion of a specific task to be
+ * signaled or for a specified timeout to expire. It can be
+ * interrupted by a kill signal. The timeout is in jiffies.
+ */
+unsigned long __sched
+wait_for_completion_killable_timeout(struct completion *x,
+                                    unsigned long timeout)
+{
+       return wait_for_common(x, timeout, TASK_KILLABLE);
+}
+EXPORT_SYMBOL(wait_for_completion_killable_timeout);
+
 /**
  *     try_wait_for_completion - try to decrement a completion without blocking
  *     @x:     completion structure
index 87a330a7185fd7c145a341e2d417c5778c4538f6..35565395d00d32c7c295d3c36fa722ecdadda097 100644 (file)
@@ -381,15 +381,9 @@ __initcall(init_sched_debug_procfs);
 void proc_sched_show_task(struct task_struct *p, struct seq_file *m)
 {
        unsigned long nr_switches;
-       unsigned long flags;
-       int num_threads = 1;
-
-       if (lock_task_sighand(p, &flags)) {
-               num_threads = atomic_read(&p->signal->count);
-               unlock_task_sighand(p, &flags);
-       }
 
-       SEQ_printf(m, "%s (%d, #threads: %d)\n", p->comm, p->pid, num_threads);
+       SEQ_printf(m, "%s (%d, #threads: %d)\n", p->comm, p->pid,
+                                               get_nr_threads(p));
        SEQ_printf(m,
                "---------------------------------------------------------\n");
 #define __P(F) \
index 825a3f24ad760d88018f21710a882a2b8fe36cb0..906ae5a1779c8104b14b6cb2ee774d29330145a0 100644 (file)
@@ -642,7 +642,7 @@ static inline bool si_fromuser(const struct siginfo *info)
 static int check_kill_permission(int sig, struct siginfo *info,
                                 struct task_struct *t)
 {
-       const struct cred *cred = current_cred(), *tcred;
+       const struct cred *cred, *tcred;
        struct pid *sid;
        int error;
 
@@ -656,8 +656,10 @@ static int check_kill_permission(int sig, struct siginfo *info,
        if (error)
                return error;
 
+       cred = current_cred();
        tcred = __task_cred(t);
-       if ((cred->euid ^ tcred->suid) &&
+       if (!same_thread_group(current, t) &&
+           (cred->euid ^ tcred->suid) &&
            (cred->euid ^ tcred->uid) &&
            (cred->uid  ^ tcred->suid) &&
            (cred->uid  ^ tcred->uid) &&
@@ -1083,23 +1085,24 @@ force_sig_info(int sig, struct siginfo *info, struct task_struct *t)
 /*
  * Nuke all other threads in the group.
  */
-void zap_other_threads(struct task_struct *p)
+int zap_other_threads(struct task_struct *p)
 {
-       struct task_struct *t;
+       struct task_struct *t = p;
+       int count = 0;
 
        p->signal->group_stop_count = 0;
 
-       for (t = next_thread(p); t != p; t = next_thread(t)) {
-               /*
-                * Don't bother with already dead threads
-                */
+       while_each_thread(p, t) {
+               count++;
+
+               /* Don't bother with already dead threads */
                if (t->exit_state)
                        continue;
-
-               /* SIGKILL will be handled before any pending SIGSTOP */
                sigaddset(&t->pending.signal, SIGKILL);
                signal_wake_up(t, 1);
        }
+
+       return count;
 }
 
 struct sighand_struct *lock_task_sighand(struct task_struct *tsk, unsigned long *flags)
index 3fc697336183a79bffd175efdd98a7663ecf3691..75c970c715d399f1385d72e92e0c47c509e568dc 100644 (file)
@@ -52,7 +52,7 @@ hotplug_cfd(struct notifier_block *nfb, unsigned long action, void *hcpu)
        case CPU_UP_PREPARE_FROZEN:
                if (!zalloc_cpumask_var_node(&cfd->cpumask, GFP_KERNEL,
                                cpu_to_node(cpu)))
-                       return NOTIFY_BAD;
+                       return notifier_from_errno(-ENOMEM);
                break;
 
 #ifdef CONFIG_HOTPLUG_CPU
index 0db913a5c60f4751067e668a80cb8d5c054957f0..825e1126008f374e5d9d2650a5bb29fe2106424d 100644 (file)
@@ -808,7 +808,7 @@ static int __cpuinit cpu_callback(struct notifier_block *nfb,
                p = kthread_create(run_ksoftirqd, hcpu, "ksoftirqd/%d", hotcpu);
                if (IS_ERR(p)) {
                        printk("ksoftirqd for %i failed\n", hotcpu);
-                       return NOTIFY_BAD;
+                       return notifier_from_errno(PTR_ERR(p));
                }
                kthread_bind(p, hotcpu);
                per_cpu(ksoftirqd, hotcpu) = p;
index 0d36d889c74d277799ae409f396a49c6d2c15415..e83ddbbaf89d1eb4fed500696c39aa0305ba106e 100644 (file)
@@ -1632,9 +1632,9 @@ SYSCALL_DEFINE3(getcpu, unsigned __user *, cpup, unsigned __user *, nodep,
 
 char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff";
 
-static void argv_cleanup(char **argv, char **envp)
+static void argv_cleanup(struct subprocess_info *info)
 {
-       argv_free(argv);
+       argv_free(info->argv);
 }
 
 /**
@@ -1668,7 +1668,7 @@ int orderly_poweroff(bool force)
                goto out;
        }
 
-       call_usermodehelper_setcleanup(info, argv_cleanup);
+       call_usermodehelper_setfns(info, NULL, argv_cleanup, NULL);
 
        ret = call_usermodehelper_exec(info, UMH_NO_WAIT);
 
index 4c93486b45d1285dc82d65b027cf308dd14c87ff..997080f00e0bcbfca3669af93a97eb5951c17811 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/highuid.h>
 #include <linux/writeback.h>
 #include <linux/ratelimit.h>
+#include <linux/compaction.h>
 #include <linux/hugetlb.h>
 #include <linux/initrd.h>
 #include <linux/key.h>
@@ -262,6 +263,11 @@ static int min_sched_shares_ratelimit = 100000; /* 100 usec */
 static int max_sched_shares_ratelimit = NSEC_PER_SEC; /* 1 second */
 #endif
 
+#ifdef CONFIG_COMPACTION
+static int min_extfrag_threshold;
+static int max_extfrag_threshold = 1000;
+#endif
+
 static struct ctl_table kern_table[] = {
        {
                .procname       = "sched_child_runs_first",
@@ -1121,6 +1127,25 @@ static struct ctl_table vm_table[] = {
                .mode           = 0644,
                .proc_handler   = drop_caches_sysctl_handler,
        },
+#ifdef CONFIG_COMPACTION
+       {
+               .procname       = "compact_memory",
+               .data           = &sysctl_compact_memory,
+               .maxlen         = sizeof(int),
+               .mode           = 0200,
+               .proc_handler   = sysctl_compaction_handler,
+       },
+       {
+               .procname       = "extfrag_threshold",
+               .data           = &sysctl_extfrag_threshold,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = sysctl_extfrag_handler,
+               .extra1         = &min_extfrag_threshold,
+               .extra2         = &max_extfrag_threshold,
+       },
+
+#endif /* CONFIG_COMPACTION */
        {
                .procname       = "min_free_kbytes",
                .data           = &min_free_kbytes,
@@ -2262,6 +2287,8 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
                if (write) {
                        left -= proc_skip_spaces(&kbuf);
 
+                       if (!left)
+                               break;
                        err = proc_get_long(&kbuf, &left, &lval, &neg,
                                             proc_wspace_sep,
                                             sizeof(proc_wspace_sep), NULL);
@@ -2288,7 +2315,7 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
 
        if (!write && !first && left && !err)
                err = proc_put_char(&buffer, &left, '\n');
-       if (write && !err)
+       if (write && !err && left)
                left -= proc_skip_spaces(&kbuf);
 free:
        if (write) {
index 937d31dc8566e1208dd0e14e8618403daa536057..1357c5786064e6c8f030defbbb7f76f690dc3c15 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/file.h>
 #include <linux/ctype.h>
 #include <linux/netdevice.h>
+#include <linux/kernel.h>
 #include <linux/slab.h>
 
 #ifdef CONFIG_SYSCTL_SYSCALL
@@ -1124,11 +1125,6 @@ out:
        return result;
 }
 
-static unsigned hex_value(int ch)
-{
-       return isdigit(ch) ? ch - '0' : ((ch | 0x20) - 'a') + 10;
-}
-
 static ssize_t bin_uuid(struct file *file,
        void __user *oldval, size_t oldlen, void __user *newval, size_t newlen)
 {
@@ -1156,7 +1152,8 @@ static ssize_t bin_uuid(struct file *file,
                        if (!isxdigit(str[0]) || !isxdigit(str[1]))
                                goto out;
 
-                       uuid[i] = (hex_value(str[0]) << 4) | hex_value(str[1]);
+                       uuid[i] = (hex_to_bin(str[0]) << 4) |
+                                       hex_to_bin(str[1]);
                        str += 2;
                        if (*str == '-')
                                str++;
index 50612faa9baf268f95df39c5a518c3b9b4fce606..848b1c2ab09a411858c8bef030ecdfc61b8017e8 100644 (file)
@@ -132,10 +132,10 @@ SYSCALL_DEFINE2(gettimeofday, struct timeval __user *, tv,
  */
 static inline void warp_clock(void)
 {
-       struct timespec delta, adjust;
-       delta.tv_sec = sys_tz.tz_minuteswest * 60;
-       delta.tv_nsec = 0;
-       adjust = timespec_add_safe(current_kernel_time(), delta);
+       struct timespec adjust;
+
+       adjust = current_kernel_time();
+       adjust.tv_sec += sys_tz.tz_minuteswest * 60;
        do_settimeofday(&adjust);
 }
 
index 9199f3c5221526a1f7f60e52a33f7a6554cc0adf..2454172a80d3c6131313007d08f91f12eb85c107 100644 (file)
@@ -750,13 +750,18 @@ unsigned long apply_slack(struct timer_list *timer, unsigned long expires)
        unsigned long expires_limit, mask;
        int bit;
 
-       expires_limit = expires + timer->slack;
+       expires_limit = expires;
 
-       if (timer->slack < 0) /* auto slack: use 0.4% */
-               expires_limit = expires + (expires - jiffies)/256;
+       if (timer->slack >= 0) {
+               expires_limit = expires + timer->slack;
+       } else {
+               unsigned long now = jiffies;
 
+               /* No slack, if already expired else auto slack 0.4% */
+               if (time_after(expires, now))
+                       expires_limit = expires + (expires - now)/256;
+       }
        mask = expires ^ expires_limit;
-
        if (mask == 0)
                return expires;
 
@@ -1679,11 +1684,14 @@ static int __cpuinit timer_cpu_notify(struct notifier_block *self,
                                unsigned long action, void *hcpu)
 {
        long cpu = (long)hcpu;
+       int err;
+
        switch(action) {
        case CPU_UP_PREPARE:
        case CPU_UP_PREPARE_FROZEN:
-               if (init_timers_cpu(cpu) < 0)
-                       return NOTIFY_BAD;
+               err = init_timers_cpu(cpu);
+               if (err < 0)
+                       return notifier_from_errno(err);
                break;
 #ifdef CONFIG_HOTPLUG_CPU
        case CPU_DEAD:
index b3bc91a3f510d089d7ce69ad4b294655dce53ac7..36ea2b65dcdc65a281bef8e7fa1acf0a44434003 100644 (file)
@@ -675,28 +675,33 @@ static void blk_add_trace_rq(struct request_queue *q, struct request *rq,
        }
 }
 
-static void blk_add_trace_rq_abort(struct request_queue *q, struct request *rq)
+static void blk_add_trace_rq_abort(void *ignore,
+                                  struct request_queue *q, struct request *rq)
 {
        blk_add_trace_rq(q, rq, BLK_TA_ABORT);
 }
 
-static void blk_add_trace_rq_insert(struct request_queue *q, struct request *rq)
+static void blk_add_trace_rq_insert(void *ignore,
+                                   struct request_queue *q, struct request *rq)
 {
        blk_add_trace_rq(q, rq, BLK_TA_INSERT);
 }
 
-static void blk_add_trace_rq_issue(struct request_queue *q, struct request *rq)
+static void blk_add_trace_rq_issue(void *ignore,
+                                  struct request_queue *q, struct request *rq)
 {
        blk_add_trace_rq(q, rq, BLK_TA_ISSUE);
 }
 
-static void blk_add_trace_rq_requeue(struct request_queue *q,
+static void blk_add_trace_rq_requeue(void *ignore,
+                                    struct request_queue *q,
                                     struct request *rq)
 {
        blk_add_trace_rq(q, rq, BLK_TA_REQUEUE);
 }
 
-static void blk_add_trace_rq_complete(struct request_queue *q,
+static void blk_add_trace_rq_complete(void *ignore,
+                                     struct request_queue *q,
                                      struct request *rq)
 {
        blk_add_trace_rq(q, rq, BLK_TA_COMPLETE);
@@ -724,34 +729,40 @@ static void blk_add_trace_bio(struct request_queue *q, struct bio *bio,
                        !bio_flagged(bio, BIO_UPTODATE), 0, NULL);
 }
 
-static void blk_add_trace_bio_bounce(struct request_queue *q, struct bio *bio)
+static void blk_add_trace_bio_bounce(void *ignore,
+                                    struct request_queue *q, struct bio *bio)
 {
        blk_add_trace_bio(q, bio, BLK_TA_BOUNCE);
 }
 
-static void blk_add_trace_bio_complete(struct request_queue *q, struct bio *bio)
+static void blk_add_trace_bio_complete(void *ignore,
+                                      struct request_queue *q, struct bio *bio)
 {
        blk_add_trace_bio(q, bio, BLK_TA_COMPLETE);
 }
 
-static void blk_add_trace_bio_backmerge(struct request_queue *q,
+static void blk_add_trace_bio_backmerge(void *ignore,
+                                       struct request_queue *q,
                                        struct bio *bio)
 {
        blk_add_trace_bio(q, bio, BLK_TA_BACKMERGE);
 }
 
-static void blk_add_trace_bio_frontmerge(struct request_queue *q,
+static void blk_add_trace_bio_frontmerge(void *ignore,
+                                        struct request_queue *q,
                                         struct bio *bio)
 {
        blk_add_trace_bio(q, bio, BLK_TA_FRONTMERGE);
 }
 
-static void blk_add_trace_bio_queue(struct request_queue *q, struct bio *bio)
+static void blk_add_trace_bio_queue(void *ignore,
+                                   struct request_queue *q, struct bio *bio)
 {
        blk_add_trace_bio(q, bio, BLK_TA_QUEUE);
 }
 
-static void blk_add_trace_getrq(struct request_queue *q,
+static void blk_add_trace_getrq(void *ignore,
+                               struct request_queue *q,
                                struct bio *bio, int rw)
 {
        if (bio)
@@ -765,7 +776,8 @@ static void blk_add_trace_getrq(struct request_queue *q,
 }
 
 
-static void blk_add_trace_sleeprq(struct request_queue *q,
+static void blk_add_trace_sleeprq(void *ignore,
+                                 struct request_queue *q,
                                  struct bio *bio, int rw)
 {
        if (bio)
@@ -779,7 +791,7 @@ static void blk_add_trace_sleeprq(struct request_queue *q,
        }
 }
 
-static void blk_add_trace_plug(struct request_queue *q)
+static void blk_add_trace_plug(void *ignore, struct request_queue *q)
 {
        struct blk_trace *bt = q->blk_trace;
 
@@ -787,7 +799,7 @@ static void blk_add_trace_plug(struct request_queue *q)
                __blk_add_trace(bt, 0, 0, 0, BLK_TA_PLUG, 0, 0, NULL);
 }
 
-static void blk_add_trace_unplug_io(struct request_queue *q)
+static void blk_add_trace_unplug_io(void *ignore, struct request_queue *q)
 {
        struct blk_trace *bt = q->blk_trace;
 
@@ -800,7 +812,7 @@ static void blk_add_trace_unplug_io(struct request_queue *q)
        }
 }
 
-static void blk_add_trace_unplug_timer(struct request_queue *q)
+static void blk_add_trace_unplug_timer(void *ignore, struct request_queue *q)
 {
        struct blk_trace *bt = q->blk_trace;
 
@@ -813,7 +825,8 @@ static void blk_add_trace_unplug_timer(struct request_queue *q)
        }
 }
 
-static void blk_add_trace_split(struct request_queue *q, struct bio *bio,
+static void blk_add_trace_split(void *ignore,
+                               struct request_queue *q, struct bio *bio,
                                unsigned int pdu)
 {
        struct blk_trace *bt = q->blk_trace;
@@ -839,8 +852,9 @@ static void blk_add_trace_split(struct request_queue *q, struct bio *bio,
  *     it spans a stripe (or similar). Add a trace for that action.
  *
  **/
-static void blk_add_trace_remap(struct request_queue *q, struct bio *bio,
-                                      dev_t dev, sector_t from)
+static void blk_add_trace_remap(void *ignore,
+                               struct request_queue *q, struct bio *bio,
+                               dev_t dev, sector_t from)
 {
        struct blk_trace *bt = q->blk_trace;
        struct blk_io_trace_remap r;
@@ -869,7 +883,8 @@ static void blk_add_trace_remap(struct request_queue *q, struct bio *bio,
  *     Add a trace for that action.
  *
  **/
-static void blk_add_trace_rq_remap(struct request_queue *q,
+static void blk_add_trace_rq_remap(void *ignore,
+                                  struct request_queue *q,
                                   struct request *rq, dev_t dev,
                                   sector_t from)
 {
@@ -921,64 +936,64 @@ static void blk_register_tracepoints(void)
 {
        int ret;
 
-       ret = register_trace_block_rq_abort(blk_add_trace_rq_abort);
+       ret = register_trace_block_rq_abort(blk_add_trace_rq_abort, NULL);
        WARN_ON(ret);
-       ret = register_trace_block_rq_insert(blk_add_trace_rq_insert);
+       ret = register_trace_block_rq_insert(blk_add_trace_rq_insert, NULL);
        WARN_ON(ret);
-       ret = register_trace_block_rq_issue(blk_add_trace_rq_issue);
+       ret = register_trace_block_rq_issue(blk_add_trace_rq_issue, NULL);
        WARN_ON(ret);
-       ret = register_trace_block_rq_requeue(blk_add_trace_rq_requeue);
+       ret = register_trace_block_rq_requeue(blk_add_trace_rq_requeue, NULL);
        WARN_ON(ret);
-       ret = register_trace_block_rq_complete(blk_add_trace_rq_complete);
+       ret = register_trace_block_rq_complete(blk_add_trace_rq_complete, NULL);
        WARN_ON(ret);
-       ret = register_trace_block_bio_bounce(blk_add_trace_bio_bounce);
+       ret = register_trace_block_bio_bounce(blk_add_trace_bio_bounce, NULL);
        WARN_ON(ret);
-       ret = register_trace_block_bio_complete(blk_add_trace_bio_complete);
+       ret = register_trace_block_bio_complete(blk_add_trace_bio_complete, NULL);
        WARN_ON(ret);
-       ret = register_trace_block_bio_backmerge(blk_add_trace_bio_backmerge);
+       ret = register_trace_block_bio_backmerge(blk_add_trace_bio_backmerge, NULL);
        WARN_ON(ret);
-       ret = register_trace_block_bio_frontmerge(blk_add_trace_bio_frontmerge);
+       ret = register_trace_block_bio_frontmerge(blk_add_trace_bio_frontmerge, NULL);
        WARN_ON(ret);
-       ret = register_trace_block_bio_queue(blk_add_trace_bio_queue);
+       ret = register_trace_block_bio_queue(blk_add_trace_bio_queue, NULL);
        WARN_ON(ret);
-       ret = register_trace_block_getrq(blk_add_trace_getrq);
+       ret = register_trace_block_getrq(blk_add_trace_getrq, NULL);
        WARN_ON(ret);
-       ret = register_trace_block_sleeprq(blk_add_trace_sleeprq);
+       ret = register_trace_block_sleeprq(blk_add_trace_sleeprq, NULL);
        WARN_ON(ret);
-       ret = register_trace_block_plug(blk_add_trace_plug);
+       ret = register_trace_block_plug(blk_add_trace_plug, NULL);
        WARN_ON(ret);
-       ret = register_trace_block_unplug_timer(blk_add_trace_unplug_timer);
+       ret = register_trace_block_unplug_timer(blk_add_trace_unplug_timer, NULL);
        WARN_ON(ret);
-       ret = register_trace_block_unplug_io(blk_add_trace_unplug_io);
+       ret = register_trace_block_unplug_io(blk_add_trace_unplug_io, NULL);
        WARN_ON(ret);
-       ret = register_trace_block_split(blk_add_trace_split);
+       ret = register_trace_block_split(blk_add_trace_split, NULL);
        WARN_ON(ret);
-       ret = register_trace_block_remap(blk_add_trace_remap);
+       ret = register_trace_block_remap(blk_add_trace_remap, NULL);
        WARN_ON(ret);
-       ret = register_trace_block_rq_remap(blk_add_trace_rq_remap);
+       ret = register_trace_block_rq_remap(blk_add_trace_rq_remap, NULL);
        WARN_ON(ret);
 }
 
 static void blk_unregister_tracepoints(void)
 {
-       unregister_trace_block_rq_remap(blk_add_trace_rq_remap);
-       unregister_trace_block_remap(blk_add_trace_remap);
-       unregister_trace_block_split(blk_add_trace_split);
-       unregister_trace_block_unplug_io(blk_add_trace_unplug_io);
-       unregister_trace_block_unplug_timer(blk_add_trace_unplug_timer);
-       unregister_trace_block_plug(blk_add_trace_plug);
-       unregister_trace_block_sleeprq(blk_add_trace_sleeprq);
-       unregister_trace_block_getrq(blk_add_trace_getrq);
-       unregister_trace_block_bio_queue(blk_add_trace_bio_queue);
-       unregister_trace_block_bio_frontmerge(blk_add_trace_bio_frontmerge);
-       unregister_trace_block_bio_backmerge(blk_add_trace_bio_backmerge);
-       unregister_trace_block_bio_complete(blk_add_trace_bio_complete);
-       unregister_trace_block_bio_bounce(blk_add_trace_bio_bounce);
-       unregister_trace_block_rq_complete(blk_add_trace_rq_complete);
-       unregister_trace_block_rq_requeue(blk_add_trace_rq_requeue);
-       unregister_trace_block_rq_issue(blk_add_trace_rq_issue);
-       unregister_trace_block_rq_insert(blk_add_trace_rq_insert);
-       unregister_trace_block_rq_abort(blk_add_trace_rq_abort);
+       unregister_trace_block_rq_remap(blk_add_trace_rq_remap, NULL);
+       unregister_trace_block_remap(blk_add_trace_remap, NULL);
+       unregister_trace_block_split(blk_add_trace_split, NULL);
+       unregister_trace_block_unplug_io(blk_add_trace_unplug_io, NULL);
+       unregister_trace_block_unplug_timer(blk_add_trace_unplug_timer, NULL);
+       unregister_trace_block_plug(blk_add_trace_plug, NULL);
+       unregister_trace_block_sleeprq(blk_add_trace_sleeprq, NULL);
+       unregister_trace_block_getrq(blk_add_trace_getrq, NULL);
+       unregister_trace_block_bio_queue(blk_add_trace_bio_queue, NULL);
+       unregister_trace_block_bio_frontmerge(blk_add_trace_bio_frontmerge, NULL);
+       unregister_trace_block_bio_backmerge(blk_add_trace_bio_backmerge, NULL);
+       unregister_trace_block_bio_complete(blk_add_trace_bio_complete, NULL);
+       unregister_trace_block_bio_bounce(blk_add_trace_bio_bounce, NULL);
+       unregister_trace_block_rq_complete(blk_add_trace_rq_complete, NULL);
+       unregister_trace_block_rq_requeue(blk_add_trace_rq_requeue, NULL);
+       unregister_trace_block_rq_issue(blk_add_trace_rq_issue, NULL);
+       unregister_trace_block_rq_insert(blk_add_trace_rq_insert, NULL);
+       unregister_trace_block_rq_abort(blk_add_trace_rq_abort, NULL);
 
        tracepoint_synchronize_unregister();
 }
@@ -1321,7 +1336,7 @@ out:
 }
 
 static enum print_line_t blk_trace_event_print(struct trace_iterator *iter,
-                                              int flags)
+                                              int flags, struct trace_event *event)
 {
        return print_one_line(iter, false);
 }
@@ -1343,7 +1358,8 @@ static int blk_trace_synthesize_old_trace(struct trace_iterator *iter)
 }
 
 static enum print_line_t
-blk_trace_event_print_binary(struct trace_iterator *iter, int flags)
+blk_trace_event_print_binary(struct trace_iterator *iter, int flags,
+                            struct trace_event *event)
 {
        return blk_trace_synthesize_old_trace(iter) ?
                        TRACE_TYPE_HANDLED : TRACE_TYPE_PARTIAL_LINE;
@@ -1381,12 +1397,16 @@ static struct tracer blk_tracer __read_mostly = {
        .set_flag       = blk_tracer_set_flag,
 };
 
-static struct trace_event trace_blk_event = {
-       .type           = TRACE_BLK,
+static struct trace_event_functions trace_blk_event_funcs = {
        .trace          = blk_trace_event_print,
        .binary         = blk_trace_event_print_binary,
 };
 
+static struct trace_event trace_blk_event = {
+       .type           = TRACE_BLK,
+       .funcs          = &trace_blk_event_funcs,
+};
+
 static int __init init_blk_tracer(void)
 {
        if (!register_ftrace_event(&trace_blk_event)) {
index 32837e19e3bdb66535650af0ba8e3597d48a11e8..6d2cb14f9449083c9a2e78f507b9c1255c8e7ca2 100644 (file)
@@ -3234,7 +3234,8 @@ free:
 }
 
 static void
-ftrace_graph_probe_sched_switch(struct task_struct *prev, struct task_struct *next)
+ftrace_graph_probe_sched_switch(void *ignore,
+                       struct task_struct *prev, struct task_struct *next)
 {
        unsigned long long timestamp;
        int index;
@@ -3288,7 +3289,7 @@ static int start_graph_tracing(void)
        } while (ret == -EAGAIN);
 
        if (!ret) {
-               ret = register_trace_sched_switch(ftrace_graph_probe_sched_switch);
+               ret = register_trace_sched_switch(ftrace_graph_probe_sched_switch, NULL);
                if (ret)
                        pr_info("ftrace_graph: Couldn't activate tracepoint"
                                " probe to kernel_sched_switch\n");
@@ -3364,7 +3365,7 @@ void unregister_ftrace_graph(void)
        ftrace_graph_entry = ftrace_graph_entry_stub;
        ftrace_shutdown(FTRACE_STOP_FUNC_RET);
        unregister_pm_notifier(&ftrace_suspend_notifier);
-       unregister_trace_sched_switch(ftrace_graph_probe_sched_switch);
+       unregister_trace_sched_switch(ftrace_graph_probe_sched_switch, NULL);
 
  out:
        mutex_unlock(&ftrace_lock);
index a91da69f153ad0c859997356d53db6548006db7c..bbfc1bb1660b248758c85e2073999d1b5cce258f 100644 (file)
@@ -95,7 +95,8 @@ static inline void kmemtrace_free(enum kmemtrace_type_id type_id,
        trace_wake_up();
 }
 
-static void kmemtrace_kmalloc(unsigned long call_site,
+static void kmemtrace_kmalloc(void *ignore,
+                             unsigned long call_site,
                              const void *ptr,
                              size_t bytes_req,
                              size_t bytes_alloc,
@@ -105,7 +106,8 @@ static void kmemtrace_kmalloc(unsigned long call_site,
                        bytes_req, bytes_alloc, gfp_flags, -1);
 }
 
-static void kmemtrace_kmem_cache_alloc(unsigned long call_site,
+static void kmemtrace_kmem_cache_alloc(void *ignore,
+                                      unsigned long call_site,
                                       const void *ptr,
                                       size_t bytes_req,
                                       size_t bytes_alloc,
@@ -115,7 +117,8 @@ static void kmemtrace_kmem_cache_alloc(unsigned long call_site,
                        bytes_req, bytes_alloc, gfp_flags, -1);
 }
 
-static void kmemtrace_kmalloc_node(unsigned long call_site,
+static void kmemtrace_kmalloc_node(void *ignore,
+                                  unsigned long call_site,
                                   const void *ptr,
                                   size_t bytes_req,
                                   size_t bytes_alloc,
@@ -126,7 +129,8 @@ static void kmemtrace_kmalloc_node(unsigned long call_site,
                        bytes_req, bytes_alloc, gfp_flags, node);
 }
 
-static void kmemtrace_kmem_cache_alloc_node(unsigned long call_site,
+static void kmemtrace_kmem_cache_alloc_node(void *ignore,
+                                           unsigned long call_site,
                                            const void *ptr,
                                            size_t bytes_req,
                                            size_t bytes_alloc,
@@ -137,12 +141,14 @@ static void kmemtrace_kmem_cache_alloc_node(unsigned long call_site,
                        bytes_req, bytes_alloc, gfp_flags, node);
 }
 
-static void kmemtrace_kfree(unsigned long call_site, const void *ptr)
+static void
+kmemtrace_kfree(void *ignore, unsigned long call_site, const void *ptr)
 {
        kmemtrace_free(KMEMTRACE_TYPE_KMALLOC, call_site, ptr);
 }
 
-static void kmemtrace_kmem_cache_free(unsigned long call_site, const void *ptr)
+static void kmemtrace_kmem_cache_free(void *ignore,
+                                     unsigned long call_site, const void *ptr)
 {
        kmemtrace_free(KMEMTRACE_TYPE_CACHE, call_site, ptr);
 }
@@ -151,34 +157,34 @@ static int kmemtrace_start_probes(void)
 {
        int err;
 
-       err = register_trace_kmalloc(kmemtrace_kmalloc);
+       err = register_trace_kmalloc(kmemtrace_kmalloc, NULL);
        if (err)
                return err;
-       err = register_trace_kmem_cache_alloc(kmemtrace_kmem_cache_alloc);
+       err = register_trace_kmem_cache_alloc(kmemtrace_kmem_cache_alloc, NULL);
        if (err)
                return err;
-       err = register_trace_kmalloc_node(kmemtrace_kmalloc_node);
+       err = register_trace_kmalloc_node(kmemtrace_kmalloc_node, NULL);
        if (err)
                return err;
-       err = register_trace_kmem_cache_alloc_node(kmemtrace_kmem_cache_alloc_node);
+       err = register_trace_kmem_cache_alloc_node(kmemtrace_kmem_cache_alloc_node, NULL);
        if (err)
                return err;
-       err = register_trace_kfree(kmemtrace_kfree);
+       err = register_trace_kfree(kmemtrace_kfree, NULL);
        if (err)
                return err;
-       err = register_trace_kmem_cache_free(kmemtrace_kmem_cache_free);
+       err = register_trace_kmem_cache_free(kmemtrace_kmem_cache_free, NULL);
 
        return err;
 }
 
 static void kmemtrace_stop_probes(void)
 {
-       unregister_trace_kmalloc(kmemtrace_kmalloc);
-       unregister_trace_kmem_cache_alloc(kmemtrace_kmem_cache_alloc);
-       unregister_trace_kmalloc_node(kmemtrace_kmalloc_node);
-       unregister_trace_kmem_cache_alloc_node(kmemtrace_kmem_cache_alloc_node);
-       unregister_trace_kfree(kmemtrace_kfree);
-       unregister_trace_kmem_cache_free(kmemtrace_kmem_cache_free);
+       unregister_trace_kmalloc(kmemtrace_kmalloc, NULL);
+       unregister_trace_kmem_cache_alloc(kmemtrace_kmem_cache_alloc, NULL);
+       unregister_trace_kmalloc_node(kmemtrace_kmalloc_node, NULL);
+       unregister_trace_kmem_cache_alloc_node(kmemtrace_kmem_cache_alloc_node, NULL);
+       unregister_trace_kfree(kmemtrace_kfree, NULL);
+       unregister_trace_kmem_cache_free(kmemtrace_kmem_cache_free, NULL);
 }
 
 static int kmem_trace_init(struct trace_array *tr)
@@ -237,7 +243,8 @@ struct kmemtrace_user_event_alloc {
 };
 
 static enum print_line_t
-kmemtrace_print_alloc(struct trace_iterator *iter, int flags)
+kmemtrace_print_alloc(struct trace_iterator *iter, int flags,
+                     struct trace_event *event)
 {
        struct trace_seq *s = &iter->seq;
        struct kmemtrace_alloc_entry *entry;
@@ -257,7 +264,8 @@ kmemtrace_print_alloc(struct trace_iterator *iter, int flags)
 }
 
 static enum print_line_t
-kmemtrace_print_free(struct trace_iterator *iter, int flags)
+kmemtrace_print_free(struct trace_iterator *iter, int flags,
+                    struct trace_event *event)
 {
        struct trace_seq *s = &iter->seq;
        struct kmemtrace_free_entry *entry;
@@ -275,7 +283,8 @@ kmemtrace_print_free(struct trace_iterator *iter, int flags)
 }
 
 static enum print_line_t
-kmemtrace_print_alloc_user(struct trace_iterator *iter, int flags)
+kmemtrace_print_alloc_user(struct trace_iterator *iter, int flags,
+                          struct trace_event *event)
 {
        struct trace_seq *s = &iter->seq;
        struct kmemtrace_alloc_entry *entry;
@@ -309,7 +318,8 @@ kmemtrace_print_alloc_user(struct trace_iterator *iter, int flags)
 }
 
 static enum print_line_t
-kmemtrace_print_free_user(struct trace_iterator *iter, int flags)
+kmemtrace_print_free_user(struct trace_iterator *iter, int flags,
+                         struct trace_event *event)
 {
        struct trace_seq *s = &iter->seq;
        struct kmemtrace_free_entry *entry;
@@ -463,18 +473,26 @@ static enum print_line_t kmemtrace_print_line(struct trace_iterator *iter)
        }
 }
 
-static struct trace_event kmem_trace_alloc = {
-       .type                   = TRACE_KMEM_ALLOC,
+static struct trace_event_functions kmem_trace_alloc_funcs = {
        .trace                  = kmemtrace_print_alloc,
        .binary                 = kmemtrace_print_alloc_user,
 };
 
-static struct trace_event kmem_trace_free = {
-       .type                   = TRACE_KMEM_FREE,
+static struct trace_event kmem_trace_alloc = {
+       .type                   = TRACE_KMEM_ALLOC,
+       .funcs                  = &kmem_trace_alloc_funcs,
+};
+
+static struct trace_event_functions kmem_trace_free_funcs = {
        .trace                  = kmemtrace_print_free,
        .binary                 = kmemtrace_print_free_user,
 };
 
+static struct trace_event kmem_trace_free = {
+       .type                   = TRACE_KMEM_FREE,
+       .funcs                  = &kmem_trace_free_funcs,
+};
+
 static struct tracer kmem_tracer __read_mostly = {
        .name                   = "kmemtrace",
        .init                   = kmem_trace_init,
index 8a76339a9e6521bd7dd448206efb288a50701f8d..55e48511d7c8ea8292b70dbd7cbcec43dc0c10b1 100644 (file)
@@ -1936,7 +1936,7 @@ static enum print_line_t print_trace_fmt(struct trace_iterator *iter)
        }
 
        if (event)
-               return event->trace(iter, sym_flags);
+               return event->funcs->trace(iter, sym_flags, event);
 
        if (!trace_seq_printf(s, "Unknown type %d\n", entry->type))
                goto partial;
@@ -1962,7 +1962,7 @@ static enum print_line_t print_raw_fmt(struct trace_iterator *iter)
 
        event = ftrace_find_event(entry->type);
        if (event)
-               return event->raw(iter, 0);
+               return event->funcs->raw(iter, 0, event);
 
        if (!trace_seq_printf(s, "%d ?\n", entry->type))
                goto partial;
@@ -1989,7 +1989,7 @@ static enum print_line_t print_hex_fmt(struct trace_iterator *iter)
 
        event = ftrace_find_event(entry->type);
        if (event) {
-               enum print_line_t ret = event->hex(iter, 0);
+               enum print_line_t ret = event->funcs->hex(iter, 0, event);
                if (ret != TRACE_TYPE_HANDLED)
                        return ret;
        }
@@ -2014,7 +2014,8 @@ static enum print_line_t print_bin_fmt(struct trace_iterator *iter)
        }
 
        event = ftrace_find_event(entry->type);
-       return event ? event->binary(iter, 0) : TRACE_TYPE_HANDLED;
+       return event ? event->funcs->binary(iter, 0, event) :
+               TRACE_TYPE_HANDLED;
 }
 
 int trace_empty(struct trace_iterator *iter)
index d1ce0bec1b3fb625dc8bc9b50ba22bec891ec01f..2cd96399463f88d51a5683802cc34f74343f881f 100644 (file)
@@ -405,12 +405,12 @@ void ftrace_trace_userstack(struct ring_buffer *buffer, unsigned long flags,
 void __trace_stack(struct trace_array *tr, unsigned long flags, int skip,
                   int pc);
 #else
-static inline void ftrace_trace_stack(struct trace_array *tr,
+static inline void ftrace_trace_stack(struct ring_buffer *buffer,
                                      unsigned long flags, int skip, int pc)
 {
 }
 
-static inline void ftrace_trace_userstack(struct trace_array *tr,
+static inline void ftrace_trace_userstack(struct ring_buffer *buffer,
                                          unsigned long flags, int pc)
 {
 }
@@ -778,12 +778,15 @@ extern void print_subsystem_event_filter(struct event_subsystem *system,
                                         struct trace_seq *s);
 extern int filter_assign_type(const char *type);
 
+struct list_head *
+trace_get_fields(struct ftrace_event_call *event_call);
+
 static inline int
 filter_check_discard(struct ftrace_event_call *call, void *rec,
                     struct ring_buffer *buffer,
                     struct ring_buffer_event *event)
 {
-       if (unlikely(call->filter_active) &&
+       if (unlikely(call->flags & TRACE_EVENT_FL_FILTERED) &&
            !filter_match_preds(call->filter, rec)) {
                ring_buffer_discard_commit(buffer, event);
                return 1;
index b9bc4d47017724a5dc278b910f1b2c4fff443741..8d3538b4ea5f0c93be082c17d92f0ee1787b2fda 100644 (file)
@@ -143,7 +143,7 @@ static void branch_trace_reset(struct trace_array *tr)
 }
 
 static enum print_line_t trace_branch_print(struct trace_iterator *iter,
-                                           int flags)
+                                           int flags, struct trace_event *event)
 {
        struct trace_branch *field;
 
@@ -167,9 +167,13 @@ static void branch_print_header(struct seq_file *s)
                "    |\n");
 }
 
+static struct trace_event_functions trace_branch_funcs = {
+       .trace          = trace_branch_print,
+};
+
 static struct trace_event trace_branch_event = {
        .type           = TRACE_BRANCH,
-       .trace          = trace_branch_print,
+       .funcs          = &trace_branch_funcs,
 };
 
 static struct tracer branch_trace __read_mostly =
index 0565bb42566f6982d6d197857e0b7e07511ab8a7..cb6f365016e48f0c7f7848cbaebb39d45fb80c45 100644 (file)
@@ -9,13 +9,9 @@
 #include <linux/kprobes.h>
 #include "trace.h"
 
-DEFINE_PER_CPU(struct pt_regs, perf_trace_regs);
-EXPORT_PER_CPU_SYMBOL_GPL(perf_trace_regs);
-
 EXPORT_SYMBOL_GPL(perf_arch_fetch_caller_regs);
 
-static char *perf_trace_buf;
-static char *perf_trace_buf_nmi;
+static char *perf_trace_buf[4];
 
 /*
  * Force it to be aligned to unsigned long to avoid misaligned accesses
@@ -27,57 +23,82 @@ typedef typeof(unsigned long [PERF_MAX_TRACE_SIZE / sizeof(unsigned long)])
 /* Count the events in use (per event id, not per instance) */
 static int     total_ref_count;
 
-static int perf_trace_event_enable(struct ftrace_event_call *event)
+static int perf_trace_event_init(struct ftrace_event_call *tp_event,
+                                struct perf_event *p_event)
 {
-       char *buf;
+       struct hlist_head *list;
        int ret = -ENOMEM;
+       int cpu;
 
-       if (event->perf_refcount++ > 0)
+       p_event->tp_event = tp_event;
+       if (tp_event->perf_refcount++ > 0)
                return 0;
 
-       if (!total_ref_count) {
-               buf = (char *)alloc_percpu(perf_trace_t);
-               if (!buf)
-                       goto fail_buf;
+       list = alloc_percpu(struct hlist_head);
+       if (!list)
+               goto fail;
 
-               rcu_assign_pointer(perf_trace_buf, buf);
+       for_each_possible_cpu(cpu)
+               INIT_HLIST_HEAD(per_cpu_ptr(list, cpu));
 
-               buf = (char *)alloc_percpu(perf_trace_t);
-               if (!buf)
-                       goto fail_buf_nmi;
+       tp_event->perf_events = list;
 
-               rcu_assign_pointer(perf_trace_buf_nmi, buf);
-       }
+       if (!total_ref_count) {
+               char *buf;
+               int i;
 
-       ret = event->perf_event_enable(event);
-       if (!ret) {
-               total_ref_count++;
-               return 0;
+               for (i = 0; i < 4; i++) {
+                       buf = (char *)alloc_percpu(perf_trace_t);
+                       if (!buf)
+                               goto fail;
+
+                       perf_trace_buf[i] = buf;
+               }
        }
 
-fail_buf_nmi:
+       if (tp_event->class->reg)
+               ret = tp_event->class->reg(tp_event, TRACE_REG_PERF_REGISTER);
+       else
+               ret = tracepoint_probe_register(tp_event->name,
+                                               tp_event->class->perf_probe,
+                                               tp_event);
+
+       if (ret)
+               goto fail;
+
+       total_ref_count++;
+       return 0;
+
+fail:
        if (!total_ref_count) {
-               free_percpu(perf_trace_buf_nmi);
-               free_percpu(perf_trace_buf);
-               perf_trace_buf_nmi = NULL;
-               perf_trace_buf = NULL;
+               int i;
+
+               for (i = 0; i < 4; i++) {
+                       free_percpu(perf_trace_buf[i]);
+                       perf_trace_buf[i] = NULL;
+               }
+       }
+
+       if (!--tp_event->perf_refcount) {
+               free_percpu(tp_event->perf_events);
+               tp_event->perf_events = NULL;
        }
-fail_buf:
-       event->perf_refcount--;
 
        return ret;
 }
 
-int perf_trace_enable(int event_id)
+int perf_trace_init(struct perf_event *p_event)
 {
-       struct ftrace_event_call *event;
+       struct ftrace_event_call *tp_event;
+       int event_id = p_event->attr.config;
        int ret = -EINVAL;
 
        mutex_lock(&event_mutex);
-       list_for_each_entry(event, &ftrace_events, list) {
-               if (event->id == event_id && event->perf_event_enable &&
-                   try_module_get(event->mod)) {
-                       ret = perf_trace_event_enable(event);
+       list_for_each_entry(tp_event, &ftrace_events, list) {
+               if (tp_event->event.type == event_id &&
+                   tp_event->class && tp_event->class->perf_probe &&
+                   try_module_get(tp_event->mod)) {
+                       ret = perf_trace_event_init(tp_event, p_event);
                        break;
                }
        }
@@ -86,90 +107,78 @@ int perf_trace_enable(int event_id)
        return ret;
 }
 
-static void perf_trace_event_disable(struct ftrace_event_call *event)
+int perf_trace_enable(struct perf_event *p_event)
 {
-       char *buf, *nmi_buf;
-
-       if (--event->perf_refcount > 0)
-               return;
-
-       event->perf_event_disable(event);
+       struct ftrace_event_call *tp_event = p_event->tp_event;
+       struct hlist_head *list;
 
-       if (!--total_ref_count) {
-               buf = perf_trace_buf;
-               rcu_assign_pointer(perf_trace_buf, NULL);
+       list = tp_event->perf_events;
+       if (WARN_ON_ONCE(!list))
+               return -EINVAL;
 
-               nmi_buf = perf_trace_buf_nmi;
-               rcu_assign_pointer(perf_trace_buf_nmi, NULL);
+       list = per_cpu_ptr(list, smp_processor_id());
+       hlist_add_head_rcu(&p_event->hlist_entry, list);
 
-               /*
-                * Ensure every events in profiling have finished before
-                * releasing the buffers
-                */
-               synchronize_sched();
+       return 0;
+}
 
-               free_percpu(buf);
-               free_percpu(nmi_buf);
-       }
+void perf_trace_disable(struct perf_event *p_event)
+{
+       hlist_del_rcu(&p_event->hlist_entry);
 }
 
-void perf_trace_disable(int event_id)
+void perf_trace_destroy(struct perf_event *p_event)
 {
-       struct ftrace_event_call *event;
+       struct ftrace_event_call *tp_event = p_event->tp_event;
+       int i;
 
-       mutex_lock(&event_mutex);
-       list_for_each_entry(event, &ftrace_events, list) {
-               if (event->id == event_id) {
-                       perf_trace_event_disable(event);
-                       module_put(event->mod);
-                       break;
+       if (--tp_event->perf_refcount > 0)
+               return;
+
+       if (tp_event->class->reg)
+               tp_event->class->reg(tp_event, TRACE_REG_PERF_UNREGISTER);
+       else
+               tracepoint_probe_unregister(tp_event->name,
+                                           tp_event->class->perf_probe,
+                                           tp_event);
+
+       free_percpu(tp_event->perf_events);
+       tp_event->perf_events = NULL;
+
+       if (!--total_ref_count) {
+               for (i = 0; i < 4; i++) {
+                       free_percpu(perf_trace_buf[i]);
+                       perf_trace_buf[i] = NULL;
                }
        }
-       mutex_unlock(&event_mutex);
 }
 
 __kprobes void *perf_trace_buf_prepare(int size, unsigned short type,
-                                      int *rctxp, unsigned long *irq_flags)
+                                      struct pt_regs *regs, int *rctxp)
 {
        struct trace_entry *entry;
-       char *trace_buf, *raw_data;
-       int pc, cpu;
+       unsigned long flags;
+       char *raw_data;
+       int pc;
 
        BUILD_BUG_ON(PERF_MAX_TRACE_SIZE % sizeof(unsigned long));
 
        pc = preempt_count();
 
-       /* Protect the per cpu buffer, begin the rcu read side */
-       local_irq_save(*irq_flags);
-
        *rctxp = perf_swevent_get_recursion_context();
        if (*rctxp < 0)
-               goto err_recursion;
-
-       cpu = smp_processor_id();
-
-       if (in_nmi())
-               trace_buf = rcu_dereference_sched(perf_trace_buf_nmi);
-       else
-               trace_buf = rcu_dereference_sched(perf_trace_buf);
-
-       if (!trace_buf)
-               goto err;
+               return NULL;
 
-       raw_data = per_cpu_ptr(trace_buf, cpu);
+       raw_data = per_cpu_ptr(perf_trace_buf[*rctxp], smp_processor_id());
 
        /* zero the dead bytes from align to not leak stack to user */
        memset(&raw_data[size - sizeof(u64)], 0, sizeof(u64));
 
        entry = (struct trace_entry *)raw_data;
-       tracing_generic_entry_update(entry, *irq_flags, pc);
+       local_save_flags(flags);
+       tracing_generic_entry_update(entry, flags, pc);
        entry->type = type;
 
        return raw_data;
-err:
-       perf_swevent_put_recursion_context(*rctxp);
-err_recursion:
-       local_irq_restore(*irq_flags);
-       return NULL;
 }
 EXPORT_SYMBOL_GPL(perf_trace_buf_prepare);
index c697c70433494d6e41e51656a767c9f575cdccba..53cffc0b08014db76d9e87da0d8bbc3c9768bd49 100644 (file)
@@ -29,11 +29,23 @@ DEFINE_MUTEX(event_mutex);
 
 LIST_HEAD(ftrace_events);
 
+struct list_head *
+trace_get_fields(struct ftrace_event_call *event_call)
+{
+       if (!event_call->class->get_fields)
+               return &event_call->class->fields;
+       return event_call->class->get_fields(event_call);
+}
+
 int trace_define_field(struct ftrace_event_call *call, const char *type,
                       const char *name, int offset, int size, int is_signed,
                       int filter_type)
 {
        struct ftrace_event_field *field;
+       struct list_head *head;
+
+       if (WARN_ON(!call->class))
+               return 0;
 
        field = kzalloc(sizeof(*field), GFP_KERNEL);
        if (!field)
@@ -56,7 +68,8 @@ int trace_define_field(struct ftrace_event_call *call, const char *type,
        field->size = size;
        field->is_signed = is_signed;
 
-       list_add(&field->link, &call->fields);
+       head = trace_get_fields(call);
+       list_add(&field->link, head);
 
        return 0;
 
@@ -94,8 +107,10 @@ static int trace_define_common_fields(struct ftrace_event_call *call)
 void trace_destroy_fields(struct ftrace_event_call *call)
 {
        struct ftrace_event_field *field, *next;
+       struct list_head *head;
 
-       list_for_each_entry_safe(field, next, &call->fields, link) {
+       head = trace_get_fields(call);
+       list_for_each_entry_safe(field, next, head, link) {
                list_del(&field->link);
                kfree(field->type);
                kfree(field->name);
@@ -107,11 +122,9 @@ int trace_event_raw_init(struct ftrace_event_call *call)
 {
        int id;
 
-       id = register_ftrace_event(call->event);
+       id = register_ftrace_event(&call->event);
        if (!id)
                return -ENODEV;
-       call->id = id;
-       INIT_LIST_HEAD(&call->fields);
 
        return 0;
 }
@@ -124,23 +137,33 @@ static int ftrace_event_enable_disable(struct ftrace_event_call *call,
 
        switch (enable) {
        case 0:
-               if (call->enabled) {
-                       call->enabled = 0;
+               if (call->flags & TRACE_EVENT_FL_ENABLED) {
+                       call->flags &= ~TRACE_EVENT_FL_ENABLED;
                        tracing_stop_cmdline_record();
-                       call->unregfunc(call);
+                       if (call->class->reg)
+                               call->class->reg(call, TRACE_REG_UNREGISTER);
+                       else
+                               tracepoint_probe_unregister(call->name,
+                                                           call->class->probe,
+                                                           call);
                }
                break;
        case 1:
-               if (!call->enabled) {
+               if (!(call->flags & TRACE_EVENT_FL_ENABLED)) {
                        tracing_start_cmdline_record();
-                       ret = call->regfunc(call);
+                       if (call->class->reg)
+                               ret = call->class->reg(call, TRACE_REG_REGISTER);
+                       else
+                               ret = tracepoint_probe_register(call->name,
+                                                               call->class->probe,
+                                                               call);
                        if (ret) {
                                tracing_stop_cmdline_record();
                                pr_info("event trace: Could not enable event "
                                        "%s\n", call->name);
                                break;
                        }
-                       call->enabled = 1;
+                       call->flags |= TRACE_EVENT_FL_ENABLED;
                }
                break;
        }
@@ -171,15 +194,16 @@ static int __ftrace_set_clr_event(const char *match, const char *sub,
        mutex_lock(&event_mutex);
        list_for_each_entry(call, &ftrace_events, list) {
 
-               if (!call->name || !call->regfunc)
+               if (!call->name || !call->class ||
+                   (!call->class->probe && !call->class->reg))
                        continue;
 
                if (match &&
                    strcmp(match, call->name) != 0 &&
-                   strcmp(match, call->system) != 0)
+                   strcmp(match, call->class->system) != 0)
                        continue;
 
-               if (sub && strcmp(sub, call->system) != 0)
+               if (sub && strcmp(sub, call->class->system) != 0)
                        continue;
 
                if (event && strcmp(event, call->name) != 0)
@@ -297,7 +321,7 @@ t_next(struct seq_file *m, void *v, loff_t *pos)
                 * The ftrace subsystem is for showing formats only.
                 * They can not be enabled or disabled via the event files.
                 */
-               if (call->regfunc)
+               if (call->class && (call->class->probe || call->class->reg))
                        return call;
        }
 
@@ -328,7 +352,7 @@ s_next(struct seq_file *m, void *v, loff_t *pos)
        (*pos)++;
 
        list_for_each_entry_continue(call, &ftrace_events, list) {
-               if (call->enabled)
+               if (call->flags & TRACE_EVENT_FL_ENABLED)
                        return call;
        }
 
@@ -355,8 +379,8 @@ static int t_show(struct seq_file *m, void *v)
 {
        struct ftrace_event_call *call = v;
 
-       if (strcmp(call->system, TRACE_SYSTEM) != 0)
-               seq_printf(m, "%s:", call->system);
+       if (strcmp(call->class->system, TRACE_SYSTEM) != 0)
+               seq_printf(m, "%s:", call->class->system);
        seq_printf(m, "%s\n", call->name);
 
        return 0;
@@ -387,7 +411,7 @@ event_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
        struct ftrace_event_call *call = filp->private_data;
        char *buf;
 
-       if (call->enabled)
+       if (call->flags & TRACE_EVENT_FL_ENABLED)
                buf = "1\n";
        else
                buf = "0\n";
@@ -450,10 +474,11 @@ system_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
 
        mutex_lock(&event_mutex);
        list_for_each_entry(call, &ftrace_events, list) {
-               if (!call->name || !call->regfunc)
+               if (!call->name || !call->class ||
+                   (!call->class->probe && !call->class->reg))
                        continue;
 
-               if (system && strcmp(call->system, system) != 0)
+               if (system && strcmp(call->class->system, system) != 0)
                        continue;
 
                /*
@@ -461,7 +486,7 @@ system_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
                 * or if all events or cleared, or if we have
                 * a mixture.
                 */
-               set |= (1 << !!call->enabled);
+               set |= (1 << !!(call->flags & TRACE_EVENT_FL_ENABLED));
 
                /*
                 * If we have a mixture, no need to look further.
@@ -525,6 +550,7 @@ event_format_read(struct file *filp, char __user *ubuf, size_t cnt,
 {
        struct ftrace_event_call *call = filp->private_data;
        struct ftrace_event_field *field;
+       struct list_head *head;
        struct trace_seq *s;
        int common_field_count = 5;
        char *buf;
@@ -540,10 +566,11 @@ event_format_read(struct file *filp, char __user *ubuf, size_t cnt,
        trace_seq_init(s);
 
        trace_seq_printf(s, "name: %s\n", call->name);
-       trace_seq_printf(s, "ID: %d\n", call->id);
+       trace_seq_printf(s, "ID: %d\n", call->event.type);
        trace_seq_printf(s, "format:\n");
 
-       list_for_each_entry_reverse(field, &call->fields, link) {
+       head = trace_get_fields(call);
+       list_for_each_entry_reverse(field, head, link) {
                /*
                 * Smartly shows the array type(except dynamic array).
                 * Normal:
@@ -613,7 +640,7 @@ event_id_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
                return -ENOMEM;
 
        trace_seq_init(s);
-       trace_seq_printf(s, "%d\n", call->id);
+       trace_seq_printf(s, "%d\n", call->event.type);
 
        r = simple_read_from_buffer(ubuf, cnt, ppos,
                                    s->buffer, s->len);
@@ -919,14 +946,15 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events,
                 const struct file_operations *filter,
                 const struct file_operations *format)
 {
+       struct list_head *head;
        int ret;
 
        /*
         * If the trace point header did not define TRACE_SYSTEM
         * then the system would be called "TRACE_SYSTEM".
         */
-       if (strcmp(call->system, TRACE_SYSTEM) != 0)
-               d_events = event_subsystem_dir(call->system, d_events);
+       if (strcmp(call->class->system, TRACE_SYSTEM) != 0)
+               d_events = event_subsystem_dir(call->class->system, d_events);
 
        call->dir = debugfs_create_dir(call->name, d_events);
        if (!call->dir) {
@@ -935,22 +963,31 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events,
                return -1;
        }
 
-       if (call->regfunc)
+       if (call->class->probe || call->class->reg)
                trace_create_file("enable", 0644, call->dir, call,
                                  enable);
 
-       if (call->id && call->perf_event_enable)
+#ifdef CONFIG_PERF_EVENTS
+       if (call->event.type && (call->class->perf_probe || call->class->reg))
                trace_create_file("id", 0444, call->dir, call,
                                  id);
+#endif
 
-       if (call->define_fields) {
-               ret = trace_define_common_fields(call);
-               if (!ret)
-                       ret = call->define_fields(call);
-               if (ret < 0) {
-                       pr_warning("Could not initialize trace point"
-                                  " events/%s\n", call->name);
-                       return ret;
+       if (call->class->define_fields) {
+               /*
+                * Other events may have the same class. Only update
+                * the fields if they are not already defined.
+                */
+               head = trace_get_fields(call);
+               if (list_empty(head)) {
+                       ret = trace_define_common_fields(call);
+                       if (!ret)
+                               ret = call->class->define_fields(call);
+                       if (ret < 0) {
+                               pr_warning("Could not initialize trace point"
+                                          " events/%s\n", call->name);
+                               return ret;
+                       }
                }
                trace_create_file("filter", 0644, call->dir, call,
                                  filter);
@@ -970,8 +1007,8 @@ static int __trace_add_event_call(struct ftrace_event_call *call)
        if (!call->name)
                return -EINVAL;
 
-       if (call->raw_init) {
-               ret = call->raw_init(call);
+       if (call->class->raw_init) {
+               ret = call->class->raw_init(call);
                if (ret < 0) {
                        if (ret != -ENOSYS)
                                pr_warning("Could not initialize trace "
@@ -1035,13 +1072,13 @@ static void remove_subsystem_dir(const char *name)
 static void __trace_remove_event_call(struct ftrace_event_call *call)
 {
        ftrace_event_enable_disable(call, 0);
-       if (call->event)
-               __unregister_ftrace_event(call->event);
+       if (call->event.funcs)
+               __unregister_ftrace_event(&call->event);
        debugfs_remove_recursive(call->dir);
        list_del(&call->list);
        trace_destroy_fields(call);
        destroy_preds(call);
-       remove_subsystem_dir(call->system);
+       remove_subsystem_dir(call->class->system);
 }
 
 /* Remove an event_call */
@@ -1132,8 +1169,8 @@ static void trace_module_add_events(struct module *mod)
                /* The linker may leave blanks */
                if (!call->name)
                        continue;
-               if (call->raw_init) {
-                       ret = call->raw_init(call);
+               if (call->class->raw_init) {
+                       ret = call->class->raw_init(call);
                        if (ret < 0) {
                                if (ret != -ENOSYS)
                                        pr_warning("Could not initialize trace "
@@ -1286,8 +1323,8 @@ static __init int event_trace_init(void)
                /* The linker may leave blanks */
                if (!call->name)
                        continue;
-               if (call->raw_init) {
-                       ret = call->raw_init(call);
+               if (call->class->raw_init) {
+                       ret = call->class->raw_init(call);
                        if (ret < 0) {
                                if (ret != -ENOSYS)
                                        pr_warning("Could not initialize trace "
@@ -1388,8 +1425,8 @@ static __init void event_trace_self_tests(void)
 
        list_for_each_entry(call, &ftrace_events, list) {
 
-               /* Only test those that have a regfunc */
-               if (!call->regfunc)
+               /* Only test those that have a probe */
+               if (!call->class || !call->class->probe)
                        continue;
 
 /*
@@ -1399,8 +1436,8 @@ static __init void event_trace_self_tests(void)
  * syscalls as we test.
  */
 #ifndef CONFIG_EVENT_TRACE_TEST_SYSCALLS
-               if (call->system &&
-                   strcmp(call->system, "syscalls") == 0)
+               if (call->class->system &&
+                   strcmp(call->class->system, "syscalls") == 0)
                        continue;
 #endif
 
@@ -1410,7 +1447,7 @@ static __init void event_trace_self_tests(void)
                 * If an event is already enabled, someone is using
                 * it and the self test should not be on.
                 */
-               if (call->enabled) {
+               if (call->flags & TRACE_EVENT_FL_ENABLED) {
                        pr_warning("Enabled event during self test!\n");
                        WARN_ON_ONCE(1);
                        continue;
index 58092d844a1fce94b36ecb3763ccfc0fded5d1a4..57bb1bb329997f62bc5805e6a3af8d5ecf64479a 100644 (file)
@@ -500,8 +500,10 @@ static struct ftrace_event_field *
 find_event_field(struct ftrace_event_call *call, char *name)
 {
        struct ftrace_event_field *field;
+       struct list_head *head;
 
-       list_for_each_entry(field, &call->fields, link) {
+       head = trace_get_fields(call);
+       list_for_each_entry(field, head, link) {
                if (!strcmp(field->name, name))
                        return field;
        }
@@ -545,7 +547,7 @@ static void filter_disable_preds(struct ftrace_event_call *call)
        struct event_filter *filter = call->filter;
        int i;
 
-       call->filter_active = 0;
+       call->flags &= ~TRACE_EVENT_FL_FILTERED;
        filter->n_preds = 0;
 
        for (i = 0; i < MAX_FILTER_PRED; i++)
@@ -572,7 +574,7 @@ void destroy_preds(struct ftrace_event_call *call)
 {
        __free_preds(call->filter);
        call->filter = NULL;
-       call->filter_active = 0;
+       call->flags &= ~TRACE_EVENT_FL_FILTERED;
 }
 
 static struct event_filter *__alloc_preds(void)
@@ -611,7 +613,7 @@ static int init_preds(struct ftrace_event_call *call)
        if (call->filter)
                return 0;
 
-       call->filter_active = 0;
+       call->flags &= ~TRACE_EVENT_FL_FILTERED;
        call->filter = __alloc_preds();
        if (IS_ERR(call->filter))
                return PTR_ERR(call->filter);
@@ -625,10 +627,10 @@ static int init_subsystem_preds(struct event_subsystem *system)
        int err;
 
        list_for_each_entry(call, &ftrace_events, list) {
-               if (!call->define_fields)
+               if (!call->class || !call->class->define_fields)
                        continue;
 
-               if (strcmp(call->system, system->name) != 0)
+               if (strcmp(call->class->system, system->name) != 0)
                        continue;
 
                err = init_preds(call);
@@ -644,10 +646,10 @@ static void filter_free_subsystem_preds(struct event_subsystem *system)
        struct ftrace_event_call *call;
 
        list_for_each_entry(call, &ftrace_events, list) {
-               if (!call->define_fields)
+               if (!call->class || !call->class->define_fields)
                        continue;
 
-               if (strcmp(call->system, system->name) != 0)
+               if (strcmp(call->class->system, system->name) != 0)
                        continue;
 
                filter_disable_preds(call);
@@ -1249,10 +1251,10 @@ static int replace_system_preds(struct event_subsystem *system,
        list_for_each_entry(call, &ftrace_events, list) {
                struct event_filter *filter = call->filter;
 
-               if (!call->define_fields)
+               if (!call->class || !call->class->define_fields)
                        continue;
 
-               if (strcmp(call->system, system->name) != 0)
+               if (strcmp(call->class->system, system->name) != 0)
                        continue;
 
                /* try to see if the filter can be applied */
@@ -1266,7 +1268,7 @@ static int replace_system_preds(struct event_subsystem *system,
                if (err)
                        filter_disable_preds(call);
                else {
-                       call->filter_active = 1;
+                       call->flags |= TRACE_EVENT_FL_FILTERED;
                        replace_filter_string(filter, filter_string);
                }
                fail = false;
@@ -1315,7 +1317,7 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
        if (err)
                append_filter_err(ps, call->filter);
        else
-               call->filter_active = 1;
+               call->flags |= TRACE_EVENT_FL_FILTERED;
 out:
        filter_opstack_clear(ps);
        postfix_clear(ps);
@@ -1393,7 +1395,7 @@ int ftrace_profile_set_filter(struct perf_event *event, int event_id,
        mutex_lock(&event_mutex);
 
        list_for_each_entry(call, &ftrace_events, list) {
-               if (call->id == event_id)
+               if (call->event.type == event_id)
                        break;
        }
 
index e091f64ba6ce04dc6437276bbb2cadd4fe39de4f..8536e2a659690f5aa82935ec20eb7d8fa74e3b5f 100644 (file)
@@ -127,7 +127,7 @@ ftrace_define_fields_##name(struct ftrace_event_call *event_call)   \
 
 static int ftrace_raw_init_event(struct ftrace_event_call *call)
 {
-       INIT_LIST_HEAD(&call->fields);
+       INIT_LIST_HEAD(&call->class->fields);
        return 0;
 }
 
@@ -153,17 +153,21 @@ static int ftrace_raw_init_event(struct ftrace_event_call *call)
 #define F_printk(fmt, args...) #fmt ", "  __stringify(args)
 
 #undef FTRACE_ENTRY
-#define FTRACE_ENTRY(call, struct_name, type, tstruct, print)          \
+#define FTRACE_ENTRY(call, struct_name, etype, tstruct, print)         \
+                                                                       \
+struct ftrace_event_class event_class_ftrace_##call = {                        \
+       .system                 = __stringify(TRACE_SYSTEM),            \
+       .define_fields          = ftrace_define_fields_##call,          \
+       .raw_init               = ftrace_raw_init_event,                \
+};                                                                     \
                                                                        \
 struct ftrace_event_call __used                                                \
 __attribute__((__aligned__(4)))                                                \
 __attribute__((section("_ftrace_events"))) event_##call = {            \
        .name                   = #call,                                \
-       .id                     = type,                                 \
-       .system                 = __stringify(TRACE_SYSTEM),            \
-       .raw_init               = ftrace_raw_init_event,                \
+       .event.type             = etype,                                \
+       .class                  = &event_class_ftrace_##call,           \
        .print_fmt              = print,                                \
-       .define_fields          = ftrace_define_fields_##call,          \
 };                                                                     \
 
 #include "trace_entries.h"
index dd11c830eb84f06419c08fff07f4b7252c197eb9..79f4bac99a94a767569a8247091eb7fd196fae7b 100644 (file)
@@ -1025,7 +1025,7 @@ print_graph_comment(struct trace_seq *s, struct trace_entry *ent,
                if (!event)
                        return TRACE_TYPE_UNHANDLED;
 
-               ret = event->trace(iter, sym_flags);
+               ret = event->funcs->trace(iter, sym_flags, event);
                if (ret != TRACE_TYPE_HANDLED)
                        return ret;
        }
@@ -1112,7 +1112,8 @@ print_graph_function(struct trace_iterator *iter)
 }
 
 static enum print_line_t
-print_graph_function_event(struct trace_iterator *iter, int flags)
+print_graph_function_event(struct trace_iterator *iter, int flags,
+                          struct trace_event *event)
 {
        return print_graph_function(iter);
 }
@@ -1225,14 +1226,18 @@ void graph_trace_close(struct trace_iterator *iter)
        }
 }
 
+static struct trace_event_functions graph_functions = {
+       .trace          = print_graph_function_event,
+};
+
 static struct trace_event graph_trace_entry_event = {
        .type           = TRACE_GRAPH_ENT,
-       .trace          = print_graph_function_event,
+       .funcs          = &graph_functions,
 };
 
 static struct trace_event graph_trace_ret_event = {
        .type           = TRACE_GRAPH_RET,
-       .trace          = print_graph_function_event,
+       .funcs          = &graph_functions
 };
 
 static struct tracer graph_trace __read_mostly = {
index a7514326052b658b88e69029a7754e197b7c2f56..faf7cefd15daf985afaadacb1d7a4b466993aa30 100644 (file)
@@ -324,8 +324,8 @@ struct trace_probe {
        unsigned long           nhit;
        unsigned int            flags;  /* For TP_FLAG_* */
        const char              *symbol;        /* symbol name */
+       struct ftrace_event_class       class;
        struct ftrace_event_call        call;
-       struct trace_event              event;
        ssize_t                 size;           /* trace entry size */
        unsigned int            nr_args;
        struct probe_arg        args[];
@@ -404,6 +404,7 @@ static struct trace_probe *alloc_trace_probe(const char *group,
                goto error;
        }
 
+       tp->call.class = &tp->class;
        tp->call.name = kstrdup(event, GFP_KERNEL);
        if (!tp->call.name)
                goto error;
@@ -413,8 +414,8 @@ static struct trace_probe *alloc_trace_probe(const char *group,
                goto error;
        }
 
-       tp->call.system = kstrdup(group, GFP_KERNEL);
-       if (!tp->call.system)
+       tp->class.system = kstrdup(group, GFP_KERNEL);
+       if (!tp->class.system)
                goto error;
 
        INIT_LIST_HEAD(&tp->list);
@@ -443,7 +444,7 @@ static void free_trace_probe(struct trace_probe *tp)
        for (i = 0; i < tp->nr_args; i++)
                free_probe_arg(&tp->args[i]);
 
-       kfree(tp->call.system);
+       kfree(tp->call.class->system);
        kfree(tp->call.name);
        kfree(tp->symbol);
        kfree(tp);
@@ -456,7 +457,7 @@ static struct trace_probe *find_probe_event(const char *event,
 
        list_for_each_entry(tp, &probe_list, list)
                if (strcmp(tp->call.name, event) == 0 &&
-                   strcmp(tp->call.system, group) == 0)
+                   strcmp(tp->call.class->system, group) == 0)
                        return tp;
        return NULL;
 }
@@ -481,7 +482,7 @@ static int register_trace_probe(struct trace_probe *tp)
        mutex_lock(&probe_lock);
 
        /* register as an event */
-       old_tp = find_probe_event(tp->call.name, tp->call.system);
+       old_tp = find_probe_event(tp->call.name, tp->call.class->system);
        if (old_tp) {
                /* delete old event */
                unregister_trace_probe(old_tp);
@@ -904,7 +905,7 @@ static int probes_seq_show(struct seq_file *m, void *v)
        int i;
 
        seq_printf(m, "%c", probe_is_return(tp) ? 'r' : 'p');
-       seq_printf(m, ":%s/%s", tp->call.system, tp->call.name);
+       seq_printf(m, ":%s/%s", tp->call.class->system, tp->call.name);
 
        if (!tp->symbol)
                seq_printf(m, " 0x%p", tp->rp.kp.addr);
@@ -1061,8 +1062,8 @@ static __kprobes void kprobe_trace_func(struct kprobe *kp, struct pt_regs *regs)
 
        size = sizeof(*entry) + tp->size;
 
-       event = trace_current_buffer_lock_reserve(&buffer, call->id, size,
-                                                 irq_flags, pc);
+       event = trace_current_buffer_lock_reserve(&buffer, call->event.type,
+                                                 size, irq_flags, pc);
        if (!event)
                return;
 
@@ -1094,8 +1095,8 @@ static __kprobes void kretprobe_trace_func(struct kretprobe_instance *ri,
 
        size = sizeof(*entry) + tp->size;
 
-       event = trace_current_buffer_lock_reserve(&buffer, call->id, size,
-                                                 irq_flags, pc);
+       event = trace_current_buffer_lock_reserve(&buffer, call->event.type,
+                                                 size, irq_flags, pc);
        if (!event)
                return;
 
@@ -1112,18 +1113,17 @@ static __kprobes void kretprobe_trace_func(struct kretprobe_instance *ri,
 
 /* Event entry printers */
 enum print_line_t
-print_kprobe_event(struct trace_iterator *iter, int flags)
+print_kprobe_event(struct trace_iterator *iter, int flags,
+                  struct trace_event *event)
 {
        struct kprobe_trace_entry_head *field;
        struct trace_seq *s = &iter->seq;
-       struct trace_event *event;
        struct trace_probe *tp;
        u8 *data;
        int i;
 
        field = (struct kprobe_trace_entry_head *)iter->ent;
-       event = ftrace_find_event(field->ent.type);
-       tp = container_of(event, struct trace_probe, event);
+       tp = container_of(event, struct trace_probe, call.event);
 
        if (!trace_seq_printf(s, "%s: (", tp->call.name))
                goto partial;
@@ -1149,18 +1149,17 @@ partial:
 }
 
 enum print_line_t
-print_kretprobe_event(struct trace_iterator *iter, int flags)
+print_kretprobe_event(struct trace_iterator *iter, int flags,
+                     struct trace_event *event)
 {
        struct kretprobe_trace_entry_head *field;
        struct trace_seq *s = &iter->seq;
-       struct trace_event *event;
        struct trace_probe *tp;
        u8 *data;
        int i;
 
        field = (struct kretprobe_trace_entry_head *)iter->ent;
-       event = ftrace_find_event(field->ent.type);
-       tp = container_of(event, struct trace_probe, event);
+       tp = container_of(event, struct trace_probe, call.event);
 
        if (!trace_seq_printf(s, "%s: (", tp->call.name))
                goto partial;
@@ -1217,8 +1216,6 @@ static void probe_event_disable(struct ftrace_event_call *call)
 
 static int probe_event_raw_init(struct ftrace_event_call *event_call)
 {
-       INIT_LIST_HEAD(&event_call->fields);
-
        return 0;
 }
 
@@ -1341,9 +1338,9 @@ static __kprobes void kprobe_perf_func(struct kprobe *kp,
        struct trace_probe *tp = container_of(kp, struct trace_probe, rp.kp);
        struct ftrace_event_call *call = &tp->call;
        struct kprobe_trace_entry_head *entry;
+       struct hlist_head *head;
        u8 *data;
        int size, __size, i;
-       unsigned long irq_flags;
        int rctx;
 
        __size = sizeof(*entry) + tp->size;
@@ -1353,7 +1350,7 @@ static __kprobes void kprobe_perf_func(struct kprobe *kp,
                     "profile buffer not large enough"))
                return;
 
-       entry = perf_trace_buf_prepare(size, call->id, &rctx, &irq_flags);
+       entry = perf_trace_buf_prepare(size, call->event.type, regs, &rctx);
        if (!entry)
                return;
 
@@ -1362,7 +1359,8 @@ 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);
 
-       perf_trace_buf_submit(entry, size, rctx, entry->ip, 1, irq_flags, regs);
+       head = per_cpu_ptr(call->perf_events, smp_processor_id());
+       perf_trace_buf_submit(entry, size, rctx, entry->ip, 1, regs, head);
 }
 
 /* Kretprobe profile handler */
@@ -1372,9 +1370,9 @@ static __kprobes void kretprobe_perf_func(struct kretprobe_instance *ri,
        struct trace_probe *tp = container_of(ri->rp, struct trace_probe, rp);
        struct ftrace_event_call *call = &tp->call;
        struct kretprobe_trace_entry_head *entry;
+       struct hlist_head *head;
        u8 *data;
        int size, __size, i;
-       unsigned long irq_flags;
        int rctx;
 
        __size = sizeof(*entry) + tp->size;
@@ -1384,7 +1382,7 @@ static __kprobes void kretprobe_perf_func(struct kretprobe_instance *ri,
                     "profile buffer not large enough"))
                return;
 
-       entry = perf_trace_buf_prepare(size, call->id, &rctx, &irq_flags);
+       entry = perf_trace_buf_prepare(size, call->event.type, regs, &rctx);
        if (!entry)
                return;
 
@@ -1394,8 +1392,8 @@ 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);
 
-       perf_trace_buf_submit(entry, size, rctx, entry->ret_ip, 1,
-                              irq_flags, regs);
+       head = per_cpu_ptr(call->perf_events, smp_processor_id());
+       perf_trace_buf_submit(entry, size, rctx, entry->ret_ip, 1, regs, head);
 }
 
 static int probe_perf_enable(struct ftrace_event_call *call)
@@ -1425,6 +1423,26 @@ static void probe_perf_disable(struct ftrace_event_call *call)
 }
 #endif /* CONFIG_PERF_EVENTS */
 
+static __kprobes
+int kprobe_register(struct ftrace_event_call *event, enum trace_reg type)
+{
+       switch (type) {
+       case TRACE_REG_REGISTER:
+               return probe_event_enable(event);
+       case TRACE_REG_UNREGISTER:
+               probe_event_disable(event);
+               return 0;
+
+#ifdef CONFIG_PERF_EVENTS
+       case TRACE_REG_PERF_REGISTER:
+               return probe_perf_enable(event);
+       case TRACE_REG_PERF_UNREGISTER:
+               probe_perf_disable(event);
+               return 0;
+#endif
+       }
+       return 0;
+}
 
 static __kprobes
 int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs)
@@ -1454,6 +1472,14 @@ int kretprobe_dispatcher(struct kretprobe_instance *ri, struct pt_regs *regs)
        return 0;       /* We don't tweek kernel, so just return 0 */
 }
 
+static struct trace_event_functions kretprobe_funcs = {
+       .trace          = print_kretprobe_event
+};
+
+static struct trace_event_functions kprobe_funcs = {
+       .trace          = print_kprobe_event
+};
+
 static int register_probe_event(struct trace_probe *tp)
 {
        struct ftrace_event_call *call = &tp->call;
@@ -1461,36 +1487,31 @@ static int register_probe_event(struct trace_probe *tp)
 
        /* Initialize ftrace_event_call */
        if (probe_is_return(tp)) {
-               tp->event.trace = print_kretprobe_event;
-               call->raw_init = probe_event_raw_init;
-               call->define_fields = kretprobe_event_define_fields;
+               INIT_LIST_HEAD(&call->class->fields);
+               call->event.funcs = &kretprobe_funcs;
+               call->class->raw_init = probe_event_raw_init;
+               call->class->define_fields = kretprobe_event_define_fields;
        } else {
-               tp->event.trace = print_kprobe_event;
-               call->raw_init = probe_event_raw_init;
-               call->define_fields = kprobe_event_define_fields;
+               INIT_LIST_HEAD(&call->class->fields);
+               call->event.funcs = &kprobe_funcs;
+               call->class->raw_init = probe_event_raw_init;
+               call->class->define_fields = kprobe_event_define_fields;
        }
        if (set_print_fmt(tp) < 0)
                return -ENOMEM;
-       call->event = &tp->event;
-       call->id = register_ftrace_event(&tp->event);
-       if (!call->id) {
+       ret = register_ftrace_event(&call->event);
+       if (!ret) {
                kfree(call->print_fmt);
                return -ENODEV;
        }
-       call->enabled = 0;
-       call->regfunc = probe_event_enable;
-       call->unregfunc = probe_event_disable;
-
-#ifdef CONFIG_PERF_EVENTS
-       call->perf_event_enable = probe_perf_enable;
-       call->perf_event_disable = probe_perf_disable;
-#endif
+       call->flags = 0;
+       call->class->reg = kprobe_register;
        call->data = tp;
        ret = trace_add_event_call(call);
        if (ret) {
                pr_info("Failed to register kprobe event: %s\n", call->name);
                kfree(call->print_fmt);
-               unregister_ftrace_event(&tp->event);
+               unregister_ftrace_event(&call->event);
        }
        return ret;
 }
index ab13d7008061e7e06f97177a5fe4a51670e23ce9..57c1b45964703d8c0af75c1ffed5c3e31df66737 100644 (file)
@@ -742,6 +742,9 @@ int register_ftrace_event(struct trace_event *event)
        if (WARN_ON(!event))
                goto out;
 
+       if (WARN_ON(!event->funcs))
+               goto out;
+
        INIT_LIST_HEAD(&event->list);
 
        if (!event->type) {
@@ -774,14 +777,14 @@ int register_ftrace_event(struct trace_event *event)
                        goto out;
        }
 
-       if (event->trace == NULL)
-               event->trace = trace_nop_print;
-       if (event->raw == NULL)
-               event->raw = trace_nop_print;
-       if (event->hex == NULL)
-               event->hex = trace_nop_print;
-       if (event->binary == NULL)
-               event->binary = trace_nop_print;
+       if (event->funcs->trace == NULL)
+               event->funcs->trace = trace_nop_print;
+       if (event->funcs->raw == NULL)
+               event->funcs->raw = trace_nop_print;
+       if (event->funcs->hex == NULL)
+               event->funcs->hex = trace_nop_print;
+       if (event->funcs->binary == NULL)
+               event->funcs->binary = trace_nop_print;
 
        key = event->type & (EVENT_HASHSIZE - 1);
 
@@ -823,13 +826,15 @@ EXPORT_SYMBOL_GPL(unregister_ftrace_event);
  * Standard events
  */
 
-enum print_line_t trace_nop_print(struct trace_iterator *iter, int flags)
+enum print_line_t trace_nop_print(struct trace_iterator *iter, int flags,
+                                 struct trace_event *event)
 {
        return TRACE_TYPE_HANDLED;
 }
 
 /* TRACE_FN */
-static enum print_line_t trace_fn_trace(struct trace_iterator *iter, int flags)
+static enum print_line_t trace_fn_trace(struct trace_iterator *iter, int flags,
+                                       struct trace_event *event)
 {
        struct ftrace_entry *field;
        struct trace_seq *s = &iter->seq;
@@ -856,7 +861,8 @@ static enum print_line_t trace_fn_trace(struct trace_iterator *iter, int flags)
        return TRACE_TYPE_PARTIAL_LINE;
 }
 
-static enum print_line_t trace_fn_raw(struct trace_iterator *iter, int flags)
+static enum print_line_t trace_fn_raw(struct trace_iterator *iter, int flags,
+                                     struct trace_event *event)
 {
        struct ftrace_entry *field;
 
@@ -870,7 +876,8 @@ static enum print_line_t trace_fn_raw(struct trace_iterator *iter, int flags)
        return TRACE_TYPE_HANDLED;
 }
 
-static enum print_line_t trace_fn_hex(struct trace_iterator *iter, int flags)
+static enum print_line_t trace_fn_hex(struct trace_iterator *iter, int flags,
+                                     struct trace_event *event)
 {
        struct ftrace_entry *field;
        struct trace_seq *s = &iter->seq;
@@ -883,7 +890,8 @@ static enum print_line_t trace_fn_hex(struct trace_iterator *iter, int flags)
        return TRACE_TYPE_HANDLED;
 }
 
-static enum print_line_t trace_fn_bin(struct trace_iterator *iter, int flags)
+static enum print_line_t trace_fn_bin(struct trace_iterator *iter, int flags,
+                                     struct trace_event *event)
 {
        struct ftrace_entry *field;
        struct trace_seq *s = &iter->seq;
@@ -896,14 +904,18 @@ static enum print_line_t trace_fn_bin(struct trace_iterator *iter, int flags)
        return TRACE_TYPE_HANDLED;
 }
 
-static struct trace_event trace_fn_event = {
-       .type           = TRACE_FN,
+static struct trace_event_functions trace_fn_funcs = {
        .trace          = trace_fn_trace,
        .raw            = trace_fn_raw,
        .hex            = trace_fn_hex,
        .binary         = trace_fn_bin,
 };
 
+static struct trace_event trace_fn_event = {
+       .type           = TRACE_FN,
+       .funcs          = &trace_fn_funcs,
+};
+
 /* TRACE_CTX an TRACE_WAKE */
 static enum print_line_t trace_ctxwake_print(struct trace_iterator *iter,
                                             char *delim)
@@ -932,13 +944,14 @@ static enum print_line_t trace_ctxwake_print(struct trace_iterator *iter,
        return TRACE_TYPE_HANDLED;
 }
 
-static enum print_line_t trace_ctx_print(struct trace_iterator *iter, int flags)
+static enum print_line_t trace_ctx_print(struct trace_iterator *iter, int flags,
+                                        struct trace_event *event)
 {
        return trace_ctxwake_print(iter, "==>");
 }
 
 static enum print_line_t trace_wake_print(struct trace_iterator *iter,
-                                         int flags)
+                                         int flags, struct trace_event *event)
 {
        return trace_ctxwake_print(iter, "  +");
 }
@@ -966,12 +979,14 @@ static int trace_ctxwake_raw(struct trace_iterator *iter, char S)
        return TRACE_TYPE_HANDLED;
 }
 
-static enum print_line_t trace_ctx_raw(struct trace_iterator *iter, int flags)
+static enum print_line_t trace_ctx_raw(struct trace_iterator *iter, int flags,
+                                      struct trace_event *event)
 {
        return trace_ctxwake_raw(iter, 0);
 }
 
-static enum print_line_t trace_wake_raw(struct trace_iterator *iter, int flags)
+static enum print_line_t trace_wake_raw(struct trace_iterator *iter, int flags,
+                                       struct trace_event *event)
 {
        return trace_ctxwake_raw(iter, '+');
 }
@@ -1000,18 +1015,20 @@ static int trace_ctxwake_hex(struct trace_iterator *iter, char S)
        return TRACE_TYPE_HANDLED;
 }
 
-static enum print_line_t trace_ctx_hex(struct trace_iterator *iter, int flags)
+static enum print_line_t trace_ctx_hex(struct trace_iterator *iter, int flags,
+                                      struct trace_event *event)
 {
        return trace_ctxwake_hex(iter, 0);
 }
 
-static enum print_line_t trace_wake_hex(struct trace_iterator *iter, int flags)
+static enum print_line_t trace_wake_hex(struct trace_iterator *iter, int flags,
+                                       struct trace_event *event)
 {
        return trace_ctxwake_hex(iter, '+');
 }
 
 static enum print_line_t trace_ctxwake_bin(struct trace_iterator *iter,
-                                          int flags)
+                                          int flags, struct trace_event *event)
 {
        struct ctx_switch_entry *field;
        struct trace_seq *s = &iter->seq;
@@ -1028,25 +1045,33 @@ static enum print_line_t trace_ctxwake_bin(struct trace_iterator *iter,
        return TRACE_TYPE_HANDLED;
 }
 
-static struct trace_event trace_ctx_event = {
-       .type           = TRACE_CTX,
+static struct trace_event_functions trace_ctx_funcs = {
        .trace          = trace_ctx_print,
        .raw            = trace_ctx_raw,
        .hex            = trace_ctx_hex,
        .binary         = trace_ctxwake_bin,
 };
 
-static struct trace_event trace_wake_event = {
-       .type           = TRACE_WAKE,
+static struct trace_event trace_ctx_event = {
+       .type           = TRACE_CTX,
+       .funcs          = &trace_ctx_funcs,
+};
+
+static struct trace_event_functions trace_wake_funcs = {
        .trace          = trace_wake_print,
        .raw            = trace_wake_raw,
        .hex            = trace_wake_hex,
        .binary         = trace_ctxwake_bin,
 };
 
+static struct trace_event trace_wake_event = {
+       .type           = TRACE_WAKE,
+       .funcs          = &trace_wake_funcs,
+};
+
 /* TRACE_SPECIAL */
 static enum print_line_t trace_special_print(struct trace_iterator *iter,
-                                            int flags)
+                                            int flags, struct trace_event *event)
 {
        struct special_entry *field;
 
@@ -1062,7 +1087,7 @@ static enum print_line_t trace_special_print(struct trace_iterator *iter,
 }
 
 static enum print_line_t trace_special_hex(struct trace_iterator *iter,
-                                          int flags)
+                                          int flags, struct trace_event *event)
 {
        struct special_entry *field;
        struct trace_seq *s = &iter->seq;
@@ -1077,7 +1102,7 @@ static enum print_line_t trace_special_hex(struct trace_iterator *iter,
 }
 
 static enum print_line_t trace_special_bin(struct trace_iterator *iter,
-                                          int flags)
+                                          int flags, struct trace_event *event)
 {
        struct special_entry *field;
        struct trace_seq *s = &iter->seq;
@@ -1091,18 +1116,22 @@ static enum print_line_t trace_special_bin(struct trace_iterator *iter,
        return TRACE_TYPE_HANDLED;
 }
 
-static struct trace_event trace_special_event = {
-       .type           = TRACE_SPECIAL,
+static struct trace_event_functions trace_special_funcs = {
        .trace          = trace_special_print,
        .raw            = trace_special_print,
        .hex            = trace_special_hex,
        .binary         = trace_special_bin,
 };
 
+static struct trace_event trace_special_event = {
+       .type           = TRACE_SPECIAL,
+       .funcs          = &trace_special_funcs,
+};
+
 /* TRACE_STACK */
 
 static enum print_line_t trace_stack_print(struct trace_iterator *iter,
-                                          int flags)
+                                          int flags, struct trace_event *event)
 {
        struct stack_entry *field;
        struct trace_seq *s = &iter->seq;
@@ -1130,17 +1159,21 @@ static enum print_line_t trace_stack_print(struct trace_iterator *iter,
        return TRACE_TYPE_PARTIAL_LINE;
 }
 
-static struct trace_event trace_stack_event = {
-       .type           = TRACE_STACK,
+static struct trace_event_functions trace_stack_funcs = {
        .trace          = trace_stack_print,
        .raw            = trace_special_print,
        .hex            = trace_special_hex,
        .binary         = trace_special_bin,
 };
 
+static struct trace_event trace_stack_event = {
+       .type           = TRACE_STACK,
+       .funcs          = &trace_stack_funcs,
+};
+
 /* TRACE_USER_STACK */
 static enum print_line_t trace_user_stack_print(struct trace_iterator *iter,
-                                               int flags)
+                                               int flags, struct trace_event *event)
 {
        struct userstack_entry *field;
        struct trace_seq *s = &iter->seq;
@@ -1159,17 +1192,22 @@ static enum print_line_t trace_user_stack_print(struct trace_iterator *iter,
        return TRACE_TYPE_PARTIAL_LINE;
 }
 
-static struct trace_event trace_user_stack_event = {
-       .type           = TRACE_USER_STACK,
+static struct trace_event_functions trace_user_stack_funcs = {
        .trace          = trace_user_stack_print,
        .raw            = trace_special_print,
        .hex            = trace_special_hex,
        .binary         = trace_special_bin,
 };
 
+static struct trace_event trace_user_stack_event = {
+       .type           = TRACE_USER_STACK,
+       .funcs          = &trace_user_stack_funcs,
+};
+
 /* TRACE_BPRINT */
 static enum print_line_t
-trace_bprint_print(struct trace_iterator *iter, int flags)
+trace_bprint_print(struct trace_iterator *iter, int flags,
+                  struct trace_event *event)
 {
        struct trace_entry *entry = iter->ent;
        struct trace_seq *s = &iter->seq;
@@ -1194,7 +1232,8 @@ trace_bprint_print(struct trace_iterator *iter, int flags)
 
 
 static enum print_line_t
-trace_bprint_raw(struct trace_iterator *iter, int flags)
+trace_bprint_raw(struct trace_iterator *iter, int flags,
+                struct trace_event *event)
 {
        struct bprint_entry *field;
        struct trace_seq *s = &iter->seq;
@@ -1213,16 +1252,19 @@ trace_bprint_raw(struct trace_iterator *iter, int flags)
        return TRACE_TYPE_PARTIAL_LINE;
 }
 
+static struct trace_event_functions trace_bprint_funcs = {
+       .trace          = trace_bprint_print,
+       .raw            = trace_bprint_raw,
+};
 
 static struct trace_event trace_bprint_event = {
        .type           = TRACE_BPRINT,
-       .trace          = trace_bprint_print,
-       .raw            = trace_bprint_raw,
+       .funcs          = &trace_bprint_funcs,
 };
 
 /* TRACE_PRINT */
 static enum print_line_t trace_print_print(struct trace_iterator *iter,
-                                          int flags)
+                                          int flags, struct trace_event *event)
 {
        struct print_entry *field;
        struct trace_seq *s = &iter->seq;
@@ -1241,7 +1283,8 @@ static enum print_line_t trace_print_print(struct trace_iterator *iter,
        return TRACE_TYPE_PARTIAL_LINE;
 }
 
-static enum print_line_t trace_print_raw(struct trace_iterator *iter, int flags)
+static enum print_line_t trace_print_raw(struct trace_iterator *iter, int flags,
+                                        struct trace_event *event)
 {
        struct print_entry *field;
 
@@ -1256,12 +1299,16 @@ static enum print_line_t trace_print_raw(struct trace_iterator *iter, int flags)
        return TRACE_TYPE_PARTIAL_LINE;
 }
 
-static struct trace_event trace_print_event = {
-       .type           = TRACE_PRINT,
+static struct trace_event_functions trace_print_funcs = {
        .trace          = trace_print_print,
        .raw            = trace_print_raw,
 };
 
+static struct trace_event trace_print_event = {
+       .type           = TRACE_PRINT,
+       .funcs          = &trace_print_funcs,
+};
+
 
 static struct trace_event *events[] __initdata = {
        &trace_fn_event,
index 9d91c72ba38b91c6aacc9011180eed5ef85fa2bd..c038eba0492ba182fd3276e177f8b0fe13d56a55 100644 (file)
@@ -25,7 +25,7 @@ extern void trace_event_read_unlock(void);
 extern struct trace_event *ftrace_find_event(int type);
 
 extern enum print_line_t trace_nop_print(struct trace_iterator *iter,
-                                        int flags);
+                                        int flags, struct trace_event *event);
 extern int
 trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry);
 
index a55fccfede5d34b92b1d25d43b0080d8d45583bf..8f758d070c43777d96fb85515d3161c1eae1c63e 100644 (file)
@@ -50,7 +50,7 @@ tracing_sched_switch_trace(struct trace_array *tr,
 }
 
 static void
-probe_sched_switch(struct task_struct *prev, struct task_struct *next)
+probe_sched_switch(void *ignore, struct task_struct *prev, struct task_struct *next)
 {
        struct trace_array_cpu *data;
        unsigned long flags;
@@ -108,7 +108,7 @@ tracing_sched_wakeup_trace(struct trace_array *tr,
 }
 
 static void
-probe_sched_wakeup(struct task_struct *wakee, int success)
+probe_sched_wakeup(void *ignore, struct task_struct *wakee, int success)
 {
        struct trace_array_cpu *data;
        unsigned long flags;
@@ -138,21 +138,21 @@ static int tracing_sched_register(void)
 {
        int ret;
 
-       ret = register_trace_sched_wakeup(probe_sched_wakeup);
+       ret = register_trace_sched_wakeup(probe_sched_wakeup, NULL);
        if (ret) {
                pr_info("wakeup trace: Couldn't activate tracepoint"
                        " probe to kernel_sched_wakeup\n");
                return ret;
        }
 
-       ret = register_trace_sched_wakeup_new(probe_sched_wakeup);
+       ret = register_trace_sched_wakeup_new(probe_sched_wakeup, NULL);
        if (ret) {
                pr_info("wakeup trace: Couldn't activate tracepoint"
                        " probe to kernel_sched_wakeup_new\n");
                goto fail_deprobe;
        }
 
-       ret = register_trace_sched_switch(probe_sched_switch);
+       ret = register_trace_sched_switch(probe_sched_switch, NULL);
        if (ret) {
                pr_info("sched trace: Couldn't activate tracepoint"
                        " probe to kernel_sched_switch\n");
@@ -161,17 +161,17 @@ static int tracing_sched_register(void)
 
        return ret;
 fail_deprobe_wake_new:
-       unregister_trace_sched_wakeup_new(probe_sched_wakeup);
+       unregister_trace_sched_wakeup_new(probe_sched_wakeup, NULL);
 fail_deprobe:
-       unregister_trace_sched_wakeup(probe_sched_wakeup);
+       unregister_trace_sched_wakeup(probe_sched_wakeup, NULL);
        return ret;
 }
 
 static void tracing_sched_unregister(void)
 {
-       unregister_trace_sched_switch(probe_sched_switch);
-       unregister_trace_sched_wakeup_new(probe_sched_wakeup);
-       unregister_trace_sched_wakeup(probe_sched_wakeup);
+       unregister_trace_sched_switch(probe_sched_switch, NULL);
+       unregister_trace_sched_wakeup_new(probe_sched_wakeup, NULL);
+       unregister_trace_sched_wakeup(probe_sched_wakeup, NULL);
 }
 
 static void tracing_start_sched_switch(void)
index 8052446ceeaa9333ae575edf6f762b665c76ac09..0e73bc2ef8c55a0b8a47ffe19d7b1aad3577de2b 100644 (file)
@@ -98,7 +98,8 @@ static int report_latency(cycle_t delta)
        return 1;
 }
 
-static void probe_wakeup_migrate_task(struct task_struct *task, int cpu)
+static void
+probe_wakeup_migrate_task(void *ignore, struct task_struct *task, int cpu)
 {
        if (task != wakeup_task)
                return;
@@ -107,7 +108,8 @@ static void probe_wakeup_migrate_task(struct task_struct *task, int cpu)
 }
 
 static void notrace
-probe_wakeup_sched_switch(struct task_struct *prev, struct task_struct *next)
+probe_wakeup_sched_switch(void *ignore,
+                         struct task_struct *prev, struct task_struct *next)
 {
        struct trace_array_cpu *data;
        cycle_t T0, T1, delta;
@@ -199,7 +201,7 @@ static void wakeup_reset(struct trace_array *tr)
 }
 
 static void
-probe_wakeup(struct task_struct *p, int success)
+probe_wakeup(void *ignore, struct task_struct *p, int success)
 {
        struct trace_array_cpu *data;
        int cpu = smp_processor_id();
@@ -263,28 +265,28 @@ static void start_wakeup_tracer(struct trace_array *tr)
 {
        int ret;
 
-       ret = register_trace_sched_wakeup(probe_wakeup);
+       ret = register_trace_sched_wakeup(probe_wakeup, NULL);
        if (ret) {
                pr_info("wakeup trace: Couldn't activate tracepoint"
                        " probe to kernel_sched_wakeup\n");
                return;
        }
 
-       ret = register_trace_sched_wakeup_new(probe_wakeup);
+       ret = register_trace_sched_wakeup_new(probe_wakeup, NULL);
        if (ret) {
                pr_info("wakeup trace: Couldn't activate tracepoint"
                        " probe to kernel_sched_wakeup_new\n");
                goto fail_deprobe;
        }
 
-       ret = register_trace_sched_switch(probe_wakeup_sched_switch);
+       ret = register_trace_sched_switch(probe_wakeup_sched_switch, NULL);
        if (ret) {
                pr_info("sched trace: Couldn't activate tracepoint"
                        " probe to kernel_sched_switch\n");
                goto fail_deprobe_wake_new;
        }
 
-       ret = register_trace_sched_migrate_task(probe_wakeup_migrate_task);
+       ret = register_trace_sched_migrate_task(probe_wakeup_migrate_task, NULL);
        if (ret) {
                pr_info("wakeup trace: Couldn't activate tracepoint"
                        " probe to kernel_sched_migrate_task\n");
@@ -311,19 +313,19 @@ static void start_wakeup_tracer(struct trace_array *tr)
 
        return;
 fail_deprobe_wake_new:
-       unregister_trace_sched_wakeup_new(probe_wakeup);
+       unregister_trace_sched_wakeup_new(probe_wakeup, NULL);
 fail_deprobe:
-       unregister_trace_sched_wakeup(probe_wakeup);
+       unregister_trace_sched_wakeup(probe_wakeup, NULL);
 }
 
 static void stop_wakeup_tracer(struct trace_array *tr)
 {
        tracer_enabled = 0;
        unregister_ftrace_function(&trace_ops);
-       unregister_trace_sched_switch(probe_wakeup_sched_switch);
-       unregister_trace_sched_wakeup_new(probe_wakeup);
-       unregister_trace_sched_wakeup(probe_wakeup);
-       unregister_trace_sched_migrate_task(probe_wakeup_migrate_task);
+       unregister_trace_sched_switch(probe_wakeup_sched_switch, NULL);
+       unregister_trace_sched_wakeup_new(probe_wakeup, NULL);
+       unregister_trace_sched_wakeup(probe_wakeup, NULL);
+       unregister_trace_sched_migrate_task(probe_wakeup_migrate_task, NULL);
 }
 
 static int __wakeup_tracer_init(struct trace_array *tr)
index 4d6d711717f2958a9c502f0e53bbb8a89ee41ff7..d2c859cec9ea85b6f2e32c4c016937bee450aacb 100644 (file)
@@ -15,6 +15,54 @@ static int sys_refcount_exit;
 static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls);
 static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls);
 
+static int syscall_enter_register(struct ftrace_event_call *event,
+                                enum trace_reg type);
+static int syscall_exit_register(struct ftrace_event_call *event,
+                                enum trace_reg type);
+
+static int syscall_enter_define_fields(struct ftrace_event_call *call);
+static int syscall_exit_define_fields(struct ftrace_event_call *call);
+
+static struct list_head *
+syscall_get_enter_fields(struct ftrace_event_call *call)
+{
+       struct syscall_metadata *entry = call->data;
+
+       return &entry->enter_fields;
+}
+
+static struct list_head *
+syscall_get_exit_fields(struct ftrace_event_call *call)
+{
+       struct syscall_metadata *entry = call->data;
+
+       return &entry->exit_fields;
+}
+
+struct trace_event_functions enter_syscall_print_funcs = {
+       .trace                  = print_syscall_enter,
+};
+
+struct trace_event_functions exit_syscall_print_funcs = {
+       .trace                  = print_syscall_exit,
+};
+
+struct ftrace_event_class event_class_syscall_enter = {
+       .system                 = "syscalls",
+       .reg                    = syscall_enter_register,
+       .define_fields          = syscall_enter_define_fields,
+       .get_fields             = syscall_get_enter_fields,
+       .raw_init               = init_syscall_trace,
+};
+
+struct ftrace_event_class event_class_syscall_exit = {
+       .system                 = "syscalls",
+       .reg                    = syscall_exit_register,
+       .define_fields          = syscall_exit_define_fields,
+       .get_fields             = syscall_get_exit_fields,
+       .raw_init               = init_syscall_trace,
+};
+
 extern unsigned long __start_syscalls_metadata[];
 extern unsigned long __stop_syscalls_metadata[];
 
@@ -53,7 +101,8 @@ static struct syscall_metadata *syscall_nr_to_meta(int nr)
 }
 
 enum print_line_t
-print_syscall_enter(struct trace_iterator *iter, int flags)
+print_syscall_enter(struct trace_iterator *iter, int flags,
+                   struct trace_event *event)
 {
        struct trace_seq *s = &iter->seq;
        struct trace_entry *ent = iter->ent;
@@ -68,7 +117,7 @@ print_syscall_enter(struct trace_iterator *iter, int flags)
        if (!entry)
                goto end;
 
-       if (entry->enter_event->id != ent->type) {
+       if (entry->enter_event->event.type != ent->type) {
                WARN_ON_ONCE(1);
                goto end;
        }
@@ -105,7 +154,8 @@ end:
 }
 
 enum print_line_t
-print_syscall_exit(struct trace_iterator *iter, int flags)
+print_syscall_exit(struct trace_iterator *iter, int flags,
+                  struct trace_event *event)
 {
        struct trace_seq *s = &iter->seq;
        struct trace_entry *ent = iter->ent;
@@ -123,7 +173,7 @@ print_syscall_exit(struct trace_iterator *iter, int flags)
                return TRACE_TYPE_HANDLED;
        }
 
-       if (entry->exit_event->id != ent->type) {
+       if (entry->exit_event->event.type != ent->type) {
                WARN_ON_ONCE(1);
                return TRACE_TYPE_UNHANDLED;
        }
@@ -205,7 +255,7 @@ static void free_syscall_print_fmt(struct ftrace_event_call *call)
                kfree(call->print_fmt);
 }
 
-int syscall_enter_define_fields(struct ftrace_event_call *call)
+static int syscall_enter_define_fields(struct ftrace_event_call *call)
 {
        struct syscall_trace_enter trace;
        struct syscall_metadata *meta = call->data;
@@ -228,7 +278,7 @@ int syscall_enter_define_fields(struct ftrace_event_call *call)
        return ret;
 }
 
-int syscall_exit_define_fields(struct ftrace_event_call *call)
+static int syscall_exit_define_fields(struct ftrace_event_call *call)
 {
        struct syscall_trace_exit trace;
        int ret;
@@ -243,7 +293,7 @@ int syscall_exit_define_fields(struct ftrace_event_call *call)
        return ret;
 }
 
-void ftrace_syscall_enter(struct pt_regs *regs, long id)
+void ftrace_syscall_enter(void *ignore, struct pt_regs *regs, long id)
 {
        struct syscall_trace_enter *entry;
        struct syscall_metadata *sys_data;
@@ -265,7 +315,7 @@ void ftrace_syscall_enter(struct pt_regs *regs, long id)
        size = sizeof(*entry) + sizeof(unsigned long) * sys_data->nb_args;
 
        event = trace_current_buffer_lock_reserve(&buffer,
-                       sys_data->enter_event->id, size, 0, 0);
+                       sys_data->enter_event->event.type, size, 0, 0);
        if (!event)
                return;
 
@@ -278,7 +328,7 @@ void ftrace_syscall_enter(struct pt_regs *regs, long id)
                trace_current_buffer_unlock_commit(buffer, event, 0, 0);
 }
 
-void ftrace_syscall_exit(struct pt_regs *regs, long ret)
+void ftrace_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
 {
        struct syscall_trace_exit *entry;
        struct syscall_metadata *sys_data;
@@ -297,7 +347,7 @@ void ftrace_syscall_exit(struct pt_regs *regs, long ret)
                return;
 
        event = trace_current_buffer_lock_reserve(&buffer,
-                       sys_data->exit_event->id, sizeof(*entry), 0, 0);
+                       sys_data->exit_event->event.type, sizeof(*entry), 0, 0);
        if (!event)
                return;
 
@@ -320,7 +370,7 @@ int reg_event_syscall_enter(struct ftrace_event_call *call)
                return -ENOSYS;
        mutex_lock(&syscall_trace_lock);
        if (!sys_refcount_enter)
-               ret = register_trace_sys_enter(ftrace_syscall_enter);
+               ret = register_trace_sys_enter(ftrace_syscall_enter, NULL);
        if (!ret) {
                set_bit(num, enabled_enter_syscalls);
                sys_refcount_enter++;
@@ -340,7 +390,7 @@ void unreg_event_syscall_enter(struct ftrace_event_call *call)
        sys_refcount_enter--;
        clear_bit(num, enabled_enter_syscalls);
        if (!sys_refcount_enter)
-               unregister_trace_sys_enter(ftrace_syscall_enter);
+               unregister_trace_sys_enter(ftrace_syscall_enter, NULL);
        mutex_unlock(&syscall_trace_lock);
 }
 
@@ -354,7 +404,7 @@ int reg_event_syscall_exit(struct ftrace_event_call *call)
                return -ENOSYS;
        mutex_lock(&syscall_trace_lock);
        if (!sys_refcount_exit)
-               ret = register_trace_sys_exit(ftrace_syscall_exit);
+               ret = register_trace_sys_exit(ftrace_syscall_exit, NULL);
        if (!ret) {
                set_bit(num, enabled_exit_syscalls);
                sys_refcount_exit++;
@@ -374,7 +424,7 @@ void unreg_event_syscall_exit(struct ftrace_event_call *call)
        sys_refcount_exit--;
        clear_bit(num, enabled_exit_syscalls);
        if (!sys_refcount_exit)
-               unregister_trace_sys_exit(ftrace_syscall_exit);
+               unregister_trace_sys_exit(ftrace_syscall_exit, NULL);
        mutex_unlock(&syscall_trace_lock);
 }
 
@@ -434,11 +484,11 @@ static DECLARE_BITMAP(enabled_perf_exit_syscalls, NR_syscalls);
 static int sys_perf_refcount_enter;
 static int sys_perf_refcount_exit;
 
-static void perf_syscall_enter(struct pt_regs *regs, long id)
+static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id)
 {
        struct syscall_metadata *sys_data;
        struct syscall_trace_enter *rec;
-       unsigned long flags;
+       struct hlist_head *head;
        int syscall_nr;
        int rctx;
        int size;
@@ -461,14 +511,16 @@ static void perf_syscall_enter(struct pt_regs *regs, long id)
                return;
 
        rec = (struct syscall_trace_enter *)perf_trace_buf_prepare(size,
-                               sys_data->enter_event->id, &rctx, &flags);
+                               sys_data->enter_event->event.type, regs, &rctx);
        if (!rec)
                return;
 
        rec->nr = syscall_nr;
        syscall_get_arguments(current, regs, 0, sys_data->nb_args,
                               (unsigned long *)&rec->args);
-       perf_trace_buf_submit(rec, size, rctx, 0, 1, flags, regs);
+
+       head = per_cpu_ptr(sys_data->enter_event->perf_events, smp_processor_id());
+       perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head);
 }
 
 int perf_sysenter_enable(struct ftrace_event_call *call)
@@ -480,7 +532,7 @@ int perf_sysenter_enable(struct ftrace_event_call *call)
 
        mutex_lock(&syscall_trace_lock);
        if (!sys_perf_refcount_enter)
-               ret = register_trace_sys_enter(perf_syscall_enter);
+               ret = register_trace_sys_enter(perf_syscall_enter, NULL);
        if (ret) {
                pr_info("event trace: Could not activate"
                                "syscall entry trace point");
@@ -502,15 +554,15 @@ void perf_sysenter_disable(struct ftrace_event_call *call)
        sys_perf_refcount_enter--;
        clear_bit(num, enabled_perf_enter_syscalls);
        if (!sys_perf_refcount_enter)
-               unregister_trace_sys_enter(perf_syscall_enter);
+               unregister_trace_sys_enter(perf_syscall_enter, NULL);
        mutex_unlock(&syscall_trace_lock);
 }
 
-static void perf_syscall_exit(struct pt_regs *regs, long ret)
+static void perf_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
 {
        struct syscall_metadata *sys_data;
        struct syscall_trace_exit *rec;
-       unsigned long flags;
+       struct hlist_head *head;
        int syscall_nr;
        int rctx;
        int size;
@@ -536,14 +588,15 @@ static void perf_syscall_exit(struct pt_regs *regs, long ret)
                return;
 
        rec = (struct syscall_trace_exit *)perf_trace_buf_prepare(size,
-                               sys_data->exit_event->id, &rctx, &flags);
+                               sys_data->exit_event->event.type, regs, &rctx);
        if (!rec)
                return;
 
        rec->nr = syscall_nr;
        rec->ret = syscall_get_return_value(current, regs);
 
-       perf_trace_buf_submit(rec, size, rctx, 0, 1, flags, regs);
+       head = per_cpu_ptr(sys_data->exit_event->perf_events, smp_processor_id());
+       perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head);
 }
 
 int perf_sysexit_enable(struct ftrace_event_call *call)
@@ -555,7 +608,7 @@ int perf_sysexit_enable(struct ftrace_event_call *call)
 
        mutex_lock(&syscall_trace_lock);
        if (!sys_perf_refcount_exit)
-               ret = register_trace_sys_exit(perf_syscall_exit);
+               ret = register_trace_sys_exit(perf_syscall_exit, NULL);
        if (ret) {
                pr_info("event trace: Could not activate"
                                "syscall exit trace point");
@@ -577,9 +630,50 @@ void perf_sysexit_disable(struct ftrace_event_call *call)
        sys_perf_refcount_exit--;
        clear_bit(num, enabled_perf_exit_syscalls);
        if (!sys_perf_refcount_exit)
-               unregister_trace_sys_exit(perf_syscall_exit);
+               unregister_trace_sys_exit(perf_syscall_exit, NULL);
        mutex_unlock(&syscall_trace_lock);
 }
 
 #endif /* CONFIG_PERF_EVENTS */
 
+static int syscall_enter_register(struct ftrace_event_call *event,
+                                enum trace_reg type)
+{
+       switch (type) {
+       case TRACE_REG_REGISTER:
+               return reg_event_syscall_enter(event);
+       case TRACE_REG_UNREGISTER:
+               unreg_event_syscall_enter(event);
+               return 0;
+
+#ifdef CONFIG_PERF_EVENTS
+       case TRACE_REG_PERF_REGISTER:
+               return perf_sysenter_enable(event);
+       case TRACE_REG_PERF_UNREGISTER:
+               perf_sysenter_disable(event);
+               return 0;
+#endif
+       }
+       return 0;
+}
+
+static int syscall_exit_register(struct ftrace_event_call *event,
+                                enum trace_reg type)
+{
+       switch (type) {
+       case TRACE_REG_REGISTER:
+               return reg_event_syscall_exit(event);
+       case TRACE_REG_UNREGISTER:
+               unreg_event_syscall_exit(event);
+               return 0;
+
+#ifdef CONFIG_PERF_EVENTS
+       case TRACE_REG_PERF_REGISTER:
+               return perf_sysexit_enable(event);
+       case TRACE_REG_PERF_UNREGISTER:
+               perf_sysexit_disable(event);
+               return 0;
+#endif
+       }
+       return 0;
+}
index cc2d2faa7d9e037734f1e4c11e87418c4a3a5400..a7cc3793baf6897d2535737a52322552040d2737 100644 (file)
@@ -49,7 +49,8 @@ static void cpu_workqueue_stat_free(struct kref *kref)
 
 /* Insertion of a work */
 static void
-probe_workqueue_insertion(struct task_struct *wq_thread,
+probe_workqueue_insertion(void *ignore,
+                         struct task_struct *wq_thread,
                          struct work_struct *work)
 {
        int cpu = cpumask_first(&wq_thread->cpus_allowed);
@@ -70,7 +71,8 @@ found:
 
 /* Execution of a work */
 static void
-probe_workqueue_execution(struct task_struct *wq_thread,
+probe_workqueue_execution(void *ignore,
+                         struct task_struct *wq_thread,
                          struct work_struct *work)
 {
        int cpu = cpumask_first(&wq_thread->cpus_allowed);
@@ -90,7 +92,8 @@ found:
 }
 
 /* Creation of a cpu workqueue thread */
-static void probe_workqueue_creation(struct task_struct *wq_thread, int cpu)
+static void probe_workqueue_creation(void *ignore,
+                                    struct task_struct *wq_thread, int cpu)
 {
        struct cpu_workqueue_stats *cws;
        unsigned long flags;
@@ -114,7 +117,8 @@ static void probe_workqueue_creation(struct task_struct *wq_thread, int cpu)
 }
 
 /* Destruction of a cpu workqueue thread */
-static void probe_workqueue_destruction(struct task_struct *wq_thread)
+static void
+probe_workqueue_destruction(void *ignore, struct task_struct *wq_thread)
 {
        /* Workqueue only execute on one cpu */
        int cpu = cpumask_first(&wq_thread->cpus_allowed);
@@ -259,19 +263,19 @@ int __init trace_workqueue_early_init(void)
 {
        int ret, cpu;
 
-       ret = register_trace_workqueue_insertion(probe_workqueue_insertion);
+       ret = register_trace_workqueue_insertion(probe_workqueue_insertion, NULL);
        if (ret)
                goto out;
 
-       ret = register_trace_workqueue_execution(probe_workqueue_execution);
+       ret = register_trace_workqueue_execution(probe_workqueue_execution, NULL);
        if (ret)
                goto no_insertion;
 
-       ret = register_trace_workqueue_creation(probe_workqueue_creation);
+       ret = register_trace_workqueue_creation(probe_workqueue_creation, NULL);
        if (ret)
                goto no_execution;
 
-       ret = register_trace_workqueue_destruction(probe_workqueue_destruction);
+       ret = register_trace_workqueue_destruction(probe_workqueue_destruction, NULL);
        if (ret)
                goto no_creation;
 
@@ -283,11 +287,11 @@ int __init trace_workqueue_early_init(void)
        return 0;
 
 no_creation:
-       unregister_trace_workqueue_creation(probe_workqueue_creation);
+       unregister_trace_workqueue_creation(probe_workqueue_creation, NULL);
 no_execution:
-       unregister_trace_workqueue_execution(probe_workqueue_execution);
+       unregister_trace_workqueue_execution(probe_workqueue_execution, NULL);
 no_insertion:
-       unregister_trace_workqueue_insertion(probe_workqueue_insertion);
+       unregister_trace_workqueue_insertion(probe_workqueue_insertion, NULL);
 out:
        pr_warning("trace_workqueue: unable to trace workqueues\n");
 
index cc89be5bc0f8ef3d8776ed0da0cf021cf6a35003..c77f3eceea250e49b0ff001959f8df9eeb8e0716 100644 (file)
@@ -54,7 +54,7 @@ static struct hlist_head tracepoint_table[TRACEPOINT_TABLE_SIZE];
  */
 struct tracepoint_entry {
        struct hlist_node hlist;
-       void **funcs;
+       struct tracepoint_func *funcs;
        int refcount;   /* Number of times armed. 0 if disarmed. */
        char name[0];
 };
@@ -64,12 +64,12 @@ struct tp_probes {
                struct rcu_head rcu;
                struct list_head list;
        } u;
-       void *probes[0];
+       struct tracepoint_func probes[0];
 };
 
 static inline void *allocate_probes(int count)
 {
-       struct tp_probes *p  = kmalloc(count * sizeof(void *)
+       struct tp_probes *p  = kmalloc(count * sizeof(struct tracepoint_func)
                        + sizeof(struct tp_probes), GFP_KERNEL);
        return p == NULL ? NULL : p->probes;
 }
@@ -79,7 +79,7 @@ static void rcu_free_old_probes(struct rcu_head *head)
        kfree(container_of(head, struct tp_probes, u.rcu));
 }
 
-static inline void release_probes(void *old)
+static inline void release_probes(struct tracepoint_func *old)
 {
        if (old) {
                struct tp_probes *tp_probes = container_of(old,
@@ -95,15 +95,16 @@ static void debug_print_probes(struct tracepoint_entry *entry)
        if (!tracepoint_debug || !entry->funcs)
                return;
 
-       for (i = 0; entry->funcs[i]; i++)
-               printk(KERN_DEBUG "Probe %d : %p\n", i, entry->funcs[i]);
+       for (i = 0; entry->funcs[i].func; i++)
+               printk(KERN_DEBUG "Probe %d : %p\n", i, entry->funcs[i].func);
 }
 
-static void *
-tracepoint_entry_add_probe(struct tracepoint_entry *entry, void *probe)
+static struct tracepoint_func *
+tracepoint_entry_add_probe(struct tracepoint_entry *entry,
+                          void *probe, void *data)
 {
        int nr_probes = 0;
-       void **old, **new;
+       struct tracepoint_func *old, *new;
 
        WARN_ON(!probe);
 
@@ -111,8 +112,9 @@ tracepoint_entry_add_probe(struct tracepoint_entry *entry, void *probe)
        old = entry->funcs;
        if (old) {
                /* (N -> N+1), (N != 0, 1) probes */
-               for (nr_probes = 0; old[nr_probes]; nr_probes++)
-                       if (old[nr_probes] == probe)
+               for (nr_probes = 0; old[nr_probes].func; nr_probes++)
+                       if (old[nr_probes].func == probe &&
+                           old[nr_probes].data == data)
                                return ERR_PTR(-EEXIST);
        }
        /* + 2 : one for new probe, one for NULL func */
@@ -120,9 +122,10 @@ tracepoint_entry_add_probe(struct tracepoint_entry *entry, void *probe)
        if (new == NULL)
                return ERR_PTR(-ENOMEM);
        if (old)
-               memcpy(new, old, nr_probes * sizeof(void *));
-       new[nr_probes] = probe;
-       new[nr_probes + 1] = NULL;
+               memcpy(new, old, nr_probes * sizeof(struct tracepoint_func));
+       new[nr_probes].func = probe;
+       new[nr_probes].data = data;
+       new[nr_probes + 1].func = NULL;
        entry->refcount = nr_probes + 1;
        entry->funcs = new;
        debug_print_probes(entry);
@@ -130,10 +133,11 @@ tracepoint_entry_add_probe(struct tracepoint_entry *entry, void *probe)
 }
 
 static void *
-tracepoint_entry_remove_probe(struct tracepoint_entry *entry, void *probe)
+tracepoint_entry_remove_probe(struct tracepoint_entry *entry,
+                             void *probe, void *data)
 {
        int nr_probes = 0, nr_del = 0, i;
-       void **old, **new;
+       struct tracepoint_func *old, *new;
 
        old = entry->funcs;
 
@@ -142,8 +146,10 @@ tracepoint_entry_remove_probe(struct tracepoint_entry *entry, void *probe)
 
        debug_print_probes(entry);
        /* (N -> M), (N > 1, M >= 0) probes */
-       for (nr_probes = 0; old[nr_probes]; nr_probes++) {
-               if ((!probe || old[nr_probes] == probe))
+       for (nr_probes = 0; old[nr_probes].func; nr_probes++) {
+               if (!probe ||
+                   (old[nr_probes].func == probe &&
+                    old[nr_probes].data == data))
                        nr_del++;
        }
 
@@ -160,10 +166,11 @@ tracepoint_entry_remove_probe(struct tracepoint_entry *entry, void *probe)
                new = allocate_probes(nr_probes - nr_del + 1);
                if (new == NULL)
                        return ERR_PTR(-ENOMEM);
-               for (i = 0; old[i]; i++)
-                       if ((probe && old[i] != probe))
+               for (i = 0; old[i].func; i++)
+                       if (probe &&
+                           (old[i].func != probe || old[i].data != data))
                                new[j++] = old[i];
-               new[nr_probes - nr_del] = NULL;
+               new[nr_probes - nr_del].func = NULL;
                entry->refcount = nr_probes - nr_del;
                entry->funcs = new;
        }
@@ -315,18 +322,19 @@ static void tracepoint_update_probes(void)
        module_update_tracepoints();
 }
 
-static void *tracepoint_add_probe(const char *name, void *probe)
+static struct tracepoint_func *
+tracepoint_add_probe(const char *name, void *probe, void *data)
 {
        struct tracepoint_entry *entry;
-       void *old;
+       struct tracepoint_func *old;
 
        entry = get_tracepoint(name);
        if (!entry) {
                entry = add_tracepoint(name);
                if (IS_ERR(entry))
-                       return entry;
+                       return (struct tracepoint_func *)entry;
        }
-       old = tracepoint_entry_add_probe(entry, probe);
+       old = tracepoint_entry_add_probe(entry, probe, data);
        if (IS_ERR(old) && !entry->refcount)
                remove_tracepoint(entry);
        return old;
@@ -340,12 +348,12 @@ static void *tracepoint_add_probe(const char *name, void *probe)
  * Returns 0 if ok, error value on error.
  * The probe address must at least be aligned on the architecture pointer size.
  */
-int tracepoint_probe_register(const char *name, void *probe)
+int tracepoint_probe_register(const char *name, void *probe, void *data)
 {
-       void *old;
+       struct tracepoint_func *old;
 
        mutex_lock(&tracepoints_mutex);
-       old = tracepoint_add_probe(name, probe);
+       old = tracepoint_add_probe(name, probe, data);
        mutex_unlock(&tracepoints_mutex);
        if (IS_ERR(old))
                return PTR_ERR(old);
@@ -356,15 +364,16 @@ int tracepoint_probe_register(const char *name, void *probe)
 }
 EXPORT_SYMBOL_GPL(tracepoint_probe_register);
 
-static void *tracepoint_remove_probe(const char *name, void *probe)
+static struct tracepoint_func *
+tracepoint_remove_probe(const char *name, void *probe, void *data)
 {
        struct tracepoint_entry *entry;
-       void *old;
+       struct tracepoint_func *old;
 
        entry = get_tracepoint(name);
        if (!entry)
                return ERR_PTR(-ENOENT);
-       old = tracepoint_entry_remove_probe(entry, probe);
+       old = tracepoint_entry_remove_probe(entry, probe, data);
        if (IS_ERR(old))
                return old;
        if (!entry->refcount)
@@ -382,12 +391,12 @@ static void *tracepoint_remove_probe(const char *name, void *probe)
  * itself uses stop_machine(), which insures that every preempt disabled section
  * have finished.
  */
-int tracepoint_probe_unregister(const char *name, void *probe)
+int tracepoint_probe_unregister(const char *name, void *probe, void *data)
 {
-       void *old;
+       struct tracepoint_func *old;
 
        mutex_lock(&tracepoints_mutex);
-       old = tracepoint_remove_probe(name, probe);
+       old = tracepoint_remove_probe(name, probe, data);
        mutex_unlock(&tracepoints_mutex);
        if (IS_ERR(old))
                return PTR_ERR(old);
@@ -418,12 +427,13 @@ static void tracepoint_add_old_probes(void *old)
  *
  * caller must call tracepoint_probe_update_all()
  */
-int tracepoint_probe_register_noupdate(const char *name, void *probe)
+int tracepoint_probe_register_noupdate(const char *name, void *probe,
+                                      void *data)
 {
-       void *old;
+       struct tracepoint_func *old;
 
        mutex_lock(&tracepoints_mutex);
-       old = tracepoint_add_probe(name, probe);
+       old = tracepoint_add_probe(name, probe, data);
        if (IS_ERR(old)) {
                mutex_unlock(&tracepoints_mutex);
                return PTR_ERR(old);
@@ -441,12 +451,13 @@ EXPORT_SYMBOL_GPL(tracepoint_probe_register_noupdate);
  *
  * caller must call tracepoint_probe_update_all()
  */
-int tracepoint_probe_unregister_noupdate(const char *name, void *probe)
+int tracepoint_probe_unregister_noupdate(const char *name, void *probe,
+                                        void *data)
 {
-       void *old;
+       struct tracepoint_func *old;
 
        mutex_lock(&tracepoints_mutex);
-       old = tracepoint_remove_probe(name, probe);
+       old = tracepoint_remove_probe(name, probe, data);
        if (IS_ERR(old)) {
                mutex_unlock(&tracepoints_mutex);
                return PTR_ERR(old);
index 77dabbf64b8fd45acdab9eb33cde54bad83cba62..327d2deb44515b438c8e43cec56415d85b22342d 100644 (file)
@@ -1110,7 +1110,7 @@ static int __devinit workqueue_cpu_callback(struct notifier_block *nfb,
        unsigned int cpu = (unsigned long)hcpu;
        struct cpu_workqueue_struct *cwq;
        struct workqueue_struct *wq;
-       int ret = NOTIFY_OK;
+       int err = 0;
 
        action &= ~CPU_TASKS_FROZEN;
 
@@ -1124,12 +1124,13 @@ undo:
 
                switch (action) {
                case CPU_UP_PREPARE:
-                       if (!create_workqueue_thread(cwq, cpu))
+                       err = create_workqueue_thread(cwq, cpu);
+                       if (!err)
                                break;
                        printk(KERN_ERR "workqueue [%s] for %i failed\n",
                                wq->name, cpu);
                        action = CPU_UP_CANCELED;
-                       ret = NOTIFY_BAD;
+                       err = -ENOMEM;
                        goto undo;
 
                case CPU_ONLINE:
@@ -1150,7 +1151,7 @@ undo:
                cpumask_clear_cpu(cpu, cpu_populated_map);
        }
 
-       return ret;
+       return notifier_from_errno(err);
 }
 
 #ifdef CONFIG_SMP
index d85be90d5888cb8df619039fb4282e77c9a120ff..e722e9d62221d40560176b5f8d2cabdcf74a5e2d 100644 (file)
@@ -898,6 +898,18 @@ config LKDTM
        Documentation on how to use the module can be found in
        Documentation/fault-injection/provoke-crashes.txt
 
+config CPU_NOTIFIER_ERROR_INJECT
+       tristate "CPU notifier error injection module"
+       depends on HOTPLUG_CPU && DEBUG_KERNEL
+       help
+         This option provides a kernel module that can be used to test
+         the error handling of the cpu notifiers
+
+         To compile this code as a module, choose M here: the module will
+         be called cpu-notifier-error-inject.
+
+         If unsure, say N.
+
 config FAULT_INJECTION
        bool "Fault-injection framework"
        depends on DEBUG_KERNEL
@@ -1039,10 +1051,10 @@ config DYNAMIC_DEBUG
 
          Usage:
 
-         Dynamic debugging is controlled via the 'dynamic_debug/ddebug' file,
+         Dynamic debugging is controlled via the 'dynamic_debug/control' file,
          which is contained in the 'debugfs' filesystem. Thus, the debugfs
          filesystem must first be mounted before making use of this feature.
-         We refer the control file as: <debugfs>/dynamic_debug/ddebug. This
+         We refer the control file as: <debugfs>/dynamic_debug/control. This
          file contains a list of the debug statements that can be enabled. The
          format for each line of the file is:
 
@@ -1057,7 +1069,7 @@ config DYNAMIC_DEBUG
 
          From a live system:
 
-               nullarbor:~ # cat <debugfs>/dynamic_debug/ddebug
+               nullarbor:~ # cat <debugfs>/dynamic_debug/control
                # filename:lineno [module]function flags format
                fs/aio.c:222 [aio]__put_ioctx - "__put_ioctx:\040freeing\040%p\012"
                fs/aio.c:248 [aio]ioctx_alloc - "ENOMEM:\040nr_events\040too\040high\012"
@@ -1067,23 +1079,23 @@ config DYNAMIC_DEBUG
 
                // enable the message at line 1603 of file svcsock.c
                nullarbor:~ # echo -n 'file svcsock.c line 1603 +p' >
-                                               <debugfs>/dynamic_debug/ddebug
+                                               <debugfs>/dynamic_debug/control
 
                // enable all the messages in file svcsock.c
                nullarbor:~ # echo -n 'file svcsock.c +p' >
-                                               <debugfs>/dynamic_debug/ddebug
+                                               <debugfs>/dynamic_debug/control
 
                // enable all the messages in the NFS server module
                nullarbor:~ # echo -n 'module nfsd +p' >
-                                               <debugfs>/dynamic_debug/ddebug
+                                               <debugfs>/dynamic_debug/control
 
                // enable all 12 messages in the function svc_process()
                nullarbor:~ # echo -n 'func svc_process +p' >
-                                               <debugfs>/dynamic_debug/ddebug
+                                               <debugfs>/dynamic_debug/control
 
                // disable all 12 messages in the function svc_process()
                nullarbor:~ # echo -n 'func svc_process -p' >
-                                               <debugfs>/dynamic_debug/ddebug
+                                               <debugfs>/dynamic_debug/control
 
          See Documentation/dynamic-debug-howto.txt for additional information.
 
index 9e6d3c29d73a15a7db63728928e234361d48977f..3f1062cbbff47baa14d46b206fe862d5972b89c6 100644 (file)
@@ -21,7 +21,7 @@ lib-y += kobject.o kref.o klist.o
 
 obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
         bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \
-        string_helpers.o gcd.o lcm.o list_sort.o
+        string_helpers.o gcd.o lcm.o list_sort.o uuid.o
 
 ifeq ($(CONFIG_DEBUG_KOBJECT),y)
 CFLAGS_kobject.o += -DDEBUG
@@ -85,6 +85,7 @@ obj-$(CONFIG_AUDIT_GENERIC) += audit.o
 obj-$(CONFIG_SWIOTLB) += swiotlb.o
 obj-$(CONFIG_IOMMU_HELPER) += iommu-helper.o
 obj-$(CONFIG_FAULT_INJECTION) += fault-inject.o
+obj-$(CONFIG_CPU_NOTIFIER_ERROR_INJECT) += cpu-notifier-error-inject.o
 
 lib-$(CONFIG_GENERIC_BUG) += bug.o
 
index 65e482caf5e9e59be94908cc94a7f6e7d364ea78..9087d71537ddef84c011b86988e17202b007a291 100644 (file)
@@ -9,6 +9,7 @@
  * (at your option) any later version.
  */
 #include <linux/init.h>
+#include <linux/kernel.h>
 #include <asm/atomic.h>
 
 #define INIT(c) do { atomic64_set(&v, c); r = c; } while (0)
index 300e41afbf97b976006b9dc6f933e36c62172372..f13daf435211eb17c0ffb3c83f3fffb3dcc03858 100644 (file)
--- a/lib/bug.c
+++ b/lib/bug.c
@@ -165,7 +165,7 @@ enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs)
                               (void *)bugaddr);
 
                show_regs(regs);
-               add_taint(TAINT_WARN);
+               add_taint(BUG_GET_TAINT(bug));
                return BUG_TRAP_TYPE_WARN;
        }
 
diff --git a/lib/cpu-notifier-error-inject.c b/lib/cpu-notifier-error-inject.c
new file mode 100644 (file)
index 0000000..4dc2032
--- /dev/null
@@ -0,0 +1,63 @@
+#include <linux/kernel.h>
+#include <linux/cpu.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+
+static int priority;
+static int cpu_up_prepare_error;
+static int cpu_down_prepare_error;
+
+module_param(priority, int, 0);
+MODULE_PARM_DESC(priority, "specify cpu notifier priority");
+
+module_param(cpu_up_prepare_error, int, 0644);
+MODULE_PARM_DESC(cpu_up_prepare_error,
+               "specify error code to inject CPU_UP_PREPARE action");
+
+module_param(cpu_down_prepare_error, int, 0644);
+MODULE_PARM_DESC(cpu_down_prepare_error,
+               "specify error code to inject CPU_DOWN_PREPARE action");
+
+static int err_inject_cpu_callback(struct notifier_block *nfb,
+                               unsigned long action, void *hcpu)
+{
+       int err = 0;
+
+       switch (action) {
+       case CPU_UP_PREPARE:
+       case CPU_UP_PREPARE_FROZEN:
+               err = cpu_up_prepare_error;
+               break;
+       case CPU_DOWN_PREPARE:
+       case CPU_DOWN_PREPARE_FROZEN:
+               err = cpu_down_prepare_error;
+               break;
+       }
+       if (err)
+               printk(KERN_INFO "Injecting error (%d) at cpu notifier\n", err);
+
+       return notifier_from_errno(err);
+}
+
+static struct notifier_block err_inject_cpu_notifier = {
+       .notifier_call = err_inject_cpu_callback,
+};
+
+static int err_inject_init(void)
+{
+       err_inject_cpu_notifier.priority = priority;
+
+       return register_hotcpu_notifier(&err_inject_cpu_notifier);
+}
+
+static void err_inject_exit(void)
+{
+       unregister_hotcpu_notifier(&err_inject_cpu_notifier);
+}
+
+module_init(err_inject_init);
+module_exit(err_inject_exit);
+
+MODULE_DESCRIPTION("CPU notifier error injection module");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>");
index bc5b936e9142c51eb7c3be5bef8a2e2f7fa3e09b..4855995fcde9dc1b57a853549beb45ada94b013d 100644 (file)
@@ -48,12 +48,20 @@ MODULE_LICENSE("GPL");
 #if CRC_LE_BITS == 8 || CRC_BE_BITS == 8
 
 static inline u32
-crc32_body(u32 crc, unsigned char const *buf, size_t len, const u32 *tab)
+crc32_body(u32 crc, unsigned char const *buf, size_t len, const u32 (*tab)[256])
 {
 # ifdef __LITTLE_ENDIAN
-#  define DO_CRC(x) crc = tab[(crc ^ (x)) & 255 ] ^ (crc >> 8)
+#  define DO_CRC(x) crc = tab[0][(crc ^ (x)) & 255] ^ (crc >> 8)
+#  define DO_CRC4 crc = tab[3][(crc) & 255] ^ \
+               tab[2][(crc >> 8) & 255] ^ \
+               tab[1][(crc >> 16) & 255] ^ \
+               tab[0][(crc >> 24) & 255]
 # else
-#  define DO_CRC(x) crc = tab[((crc >> 24) ^ (x)) & 255] ^ (crc << 8)
+#  define DO_CRC(x) crc = tab[0][((crc >> 24) ^ (x)) & 255] ^ (crc << 8)
+#  define DO_CRC4 crc = tab[0][(crc) & 255] ^ \
+               tab[1][(crc >> 8) & 255] ^ \
+               tab[2][(crc >> 16) & 255] ^ \
+               tab[3][(crc >> 24) & 255]
 # endif
        const u32 *b;
        size_t    rem_len;
@@ -70,10 +78,7 @@ crc32_body(u32 crc, unsigned char const *buf, size_t len, const u32 *tab)
        b = (const u32 *)buf;
        for (--b; len; --len) {
                crc ^= *++b; /* use pre increment for speed */
-               DO_CRC(0);
-               DO_CRC(0);
-               DO_CRC(0);
-               DO_CRC(0);
+               DO_CRC4;
        }
        len = rem_len;
        /* And the last few bytes */
@@ -85,6 +90,7 @@ crc32_body(u32 crc, unsigned char const *buf, size_t len, const u32 *tab)
        }
        return crc;
 #undef DO_CRC
+#undef DO_CRC4
 }
 #endif
 /**
@@ -117,7 +123,7 @@ u32 __pure crc32_le(u32 crc, unsigned char const *p, size_t len)
 u32 __pure crc32_le(u32 crc, unsigned char const *p, size_t len)
 {
 # if CRC_LE_BITS == 8
-       const u32      *tab = crc32table_le;
+       const u32      (*tab)[] = crc32table_le;
 
        crc = __cpu_to_le32(crc);
        crc = crc32_body(crc, p, len, tab);
@@ -174,7 +180,7 @@ u32 __pure crc32_be(u32 crc, unsigned char const *p, size_t len)
 u32 __pure crc32_be(u32 crc, unsigned char const *p, size_t len)
 {
 # if CRC_BE_BITS == 8
-       const u32      *tab = crc32table_be;
+       const u32      (*tab)[] = crc32table_be;
 
        crc = __cpu_to_be32(crc);
        crc = crc32_body(crc, p, len, tab);
index d6b8b9b1abfedf5ca023164b76d81ca06d0622a2..3df8eb17a607932bf8091e89c796c338c323c29b 100644 (file)
@@ -456,7 +456,7 @@ static ssize_t ddebug_proc_write(struct file *file, const char __user *ubuf,
                        __func__, (int)len);
 
        nwords = ddebug_tokenize(tmpbuf, words, MAXWORDS);
-       if (nwords < 0)
+       if (nwords <= 0)
                return -EINVAL;
        if (ddebug_parse_query(words, nwords-1, &query))
                return -EINVAL;
index bea5d97df99162f5bb8b1d3122a60dc07d6bb8b7..85d0e412a04f966a187fac0a5f8c7ff16c9a49c8 100644 (file)
@@ -7,8 +7,8 @@
 #define LE_TABLE_SIZE (1 << CRC_LE_BITS)
 #define BE_TABLE_SIZE (1 << CRC_BE_BITS)
 
-static uint32_t crc32table_le[LE_TABLE_SIZE];
-static uint32_t crc32table_be[BE_TABLE_SIZE];
+static uint32_t crc32table_le[4][LE_TABLE_SIZE];
+static uint32_t crc32table_be[4][BE_TABLE_SIZE];
 
 /**
  * crc32init_le() - allocate and initialize LE table data
@@ -22,12 +22,19 @@ static void crc32init_le(void)
        unsigned i, j;
        uint32_t crc = 1;
 
-       crc32table_le[0] = 0;
+       crc32table_le[0][0] = 0;
 
        for (i = 1 << (CRC_LE_BITS - 1); i; i >>= 1) {
                crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
                for (j = 0; j < LE_TABLE_SIZE; j += 2 * i)
-                       crc32table_le[i + j] = crc ^ crc32table_le[j];
+                       crc32table_le[0][i + j] = crc ^ crc32table_le[0][j];
+       }
+       for (i = 0; i < LE_TABLE_SIZE; i++) {
+               crc = crc32table_le[0][i];
+               for (j = 1; j < 4; j++) {
+                       crc = crc32table_le[0][crc & 0xff] ^ (crc >> 8);
+                       crc32table_le[j][i] = crc;
+               }
        }
 }
 
@@ -39,25 +46,35 @@ static void crc32init_be(void)
        unsigned i, j;
        uint32_t crc = 0x80000000;
 
-       crc32table_be[0] = 0;
+       crc32table_be[0][0] = 0;
 
        for (i = 1; i < BE_TABLE_SIZE; i <<= 1) {
                crc = (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE : 0);
                for (j = 0; j < i; j++)
-                       crc32table_be[i + j] = crc ^ crc32table_be[j];
+                       crc32table_be[0][i + j] = crc ^ crc32table_be[0][j];
+       }
+       for (i = 0; i < BE_TABLE_SIZE; i++) {
+               crc = crc32table_be[0][i];
+               for (j = 1; j < 4; j++) {
+                       crc = crc32table_be[0][(crc >> 24) & 0xff] ^ (crc << 8);
+                       crc32table_be[j][i] = crc;
+               }
        }
 }
 
-static void output_table(uint32_t table[], int len, char *trans)
+static void output_table(uint32_t table[4][256], int len, char *trans)
 {
-       int i;
+       int i, j;
 
-       for (i = 0; i < len - 1; i++) {
-               if (i % ENTRIES_PER_LINE == 0)
-                       printf("\n");
-               printf("%s(0x%8.8xL), ", trans, table[i]);
+       for (j = 0 ; j < 4; j++) {
+               printf("{");
+               for (i = 0; i < len - 1; i++) {
+                       if (i % ENTRIES_PER_LINE == 0)
+                               printf("\n");
+                       printf("%s(0x%8.8xL), ", trans, table[j][i]);
+               }
+               printf("%s(0x%8.8xL)},\n", trans, table[j][len - 1]);
        }
-       printf("%s(0x%8.8xL)\n", trans, table[len - 1]);
 }
 
 int main(int argc, char** argv)
@@ -66,14 +83,14 @@ int main(int argc, char** argv)
 
        if (CRC_LE_BITS > 1) {
                crc32init_le();
-               printf("static const u32 crc32table_le[] = {");
+               printf("static const u32 crc32table_le[4][256] = {");
                output_table(crc32table_le, LE_TABLE_SIZE, "tole");
                printf("};\n");
        }
 
        if (CRC_BE_BITS > 1) {
                crc32init_be();
-               printf("static const u32 crc32table_be[] = {");
+               printf("static const u32 crc32table_be[4][256] = {");
                output_table(crc32table_be, BE_TABLE_SIZE, "tobe");
                printf("};\n");
        }
index 39af2560f765f9815ccb724fecbe38173c986aab..5d7a4802c5623c00056159735bf73d17165ba476 100644 (file)
 const char hex_asc[] = "0123456789abcdef";
 EXPORT_SYMBOL(hex_asc);
 
+/**
+ * hex_to_bin - convert a hex digit to its real value
+ * @ch: ascii character represents hex digit
+ *
+ * hex_to_bin() converts one hex digit to its actual value or -1 in case of bad
+ * input.
+ */
+int hex_to_bin(char ch)
+{
+       if ((ch >= '0') && (ch <= '9'))
+               return ch - '0';
+       ch = tolower(ch);
+       if ((ch >= 'a') && (ch <= 'f'))
+               return ch - 'a' + 10;
+       return -1;
+}
+EXPORT_SYMBOL(hex_to_bin);
+
 /**
  * hex_dump_to_buffer - convert a blob of data to "hex ASCII" in memory
  * @buf: data blob to dump
@@ -34,7 +52,7 @@ EXPORT_SYMBOL(hex_asc);
  *
  * E.g.:
  *   hex_dump_to_buffer(frame->data, frame->len, 16, 1,
- *                     linebuf, sizeof(linebuf), 1);
+ *                     linebuf, sizeof(linebuf), true);
  *
  * example output buffer:
  * 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f  @ABCDEFGHIJKLMNO
@@ -65,8 +83,8 @@ void hex_dump_to_buffer(const void *buf, size_t len, int rowsize,
 
                for (j = 0; j < ngroups; j++)
                        lx += scnprintf(linebuf + lx, linebuflen - lx,
-                               "%s%16.16llx", j ? " " : "",
-                               (unsigned long long)*(ptr8 + j));
+                                       "%s%16.16llx", j ? " " : "",
+                                       (unsigned long long)*(ptr8 + j));
                ascii_column = 17 * ngroups + 2;
                break;
        }
@@ -77,7 +95,7 @@ void hex_dump_to_buffer(const void *buf, size_t len, int rowsize,
 
                for (j = 0; j < ngroups; j++)
                        lx += scnprintf(linebuf + lx, linebuflen - lx,
-                               "%s%8.8x", j ? " " : "", *(ptr4 + j));
+                                       "%s%8.8x", j ? " " : "", *(ptr4 + j));
                ascii_column = 9 * ngroups + 2;
                break;
        }
@@ -88,7 +106,7 @@ void hex_dump_to_buffer(const void *buf, size_t len, int rowsize,
 
                for (j = 0; j < ngroups; j++)
                        lx += scnprintf(linebuf + lx, linebuflen - lx,
-                               "%s%4.4x", j ? " " : "", *(ptr2 + j));
+                                       "%s%4.4x", j ? " " : "", *(ptr2 + j));
                ascii_column = 5 * ngroups + 2;
                break;
        }
@@ -111,9 +129,10 @@ void hex_dump_to_buffer(const void *buf, size_t len, int rowsize,
 
        while (lx < (linebuflen - 1) && lx < (ascii_column - 1))
                linebuf[lx++] = ' ';
-       for (j = 0; (j < len) && (lx + 2) < linebuflen; j++)
-               linebuf[lx++] = (isascii(ptr[j]) && isprint(ptr[j])) ? ptr[j]
-                               : '.';
+       for (j = 0; (j < len) && (lx + 2) < linebuflen; j++) {
+               ch = ptr[j];
+               linebuf[lx++] = (isascii(ch) && isprint(ch)) ? ch : '.';
+       }
 nil:
        linebuf[lx++] = '\0';
 }
@@ -143,7 +162,7 @@ EXPORT_SYMBOL(hex_dump_to_buffer);
  *
  * E.g.:
  *   print_hex_dump(KERN_DEBUG, "raw data: ", DUMP_PREFIX_ADDRESS,
- *             16, 1, frame->data, frame->len, 1);
+ *                 16, 1, frame->data, frame->len, true);
  *
  * Example output using %DUMP_PREFIX_OFFSET and 1-byte mode:
  * 0009ab42: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f  @ABCDEFGHIJKLMNO
@@ -151,12 +170,12 @@ EXPORT_SYMBOL(hex_dump_to_buffer);
  * ffffffff88089af0: 73727170 77767574 7b7a7978 7f7e7d7c  pqrstuvwxyz{|}~.
  */
 void print_hex_dump(const char *level, const char *prefix_str, int prefix_type,
-                       int rowsize, int groupsize,
-                       const void *buf, size_t len, bool ascii)
+                   int rowsize, int groupsize,
+                   const void *buf, size_t len, bool ascii)
 {
        const u8 *ptr = buf;
        int i, linelen, remaining = len;
-       unsigned char linebuf[200];
+       unsigned char linebuf[32 * 3 + 2 + 32 + 1];
 
        if (rowsize != 16 && rowsize != 32)
                rowsize = 16;
@@ -164,13 +183,14 @@ void print_hex_dump(const char *level, const char *prefix_str, int prefix_type,
        for (i = 0; i < len; i += rowsize) {
                linelen = min(remaining, rowsize);
                remaining -= rowsize;
+
                hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize,
-                               linebuf, sizeof(linebuf), ascii);
+                                  linebuf, sizeof(linebuf), ascii);
 
                switch (prefix_type) {
                case DUMP_PREFIX_ADDRESS:
-                       printk("%s%s%*p: %s\n", level, prefix_str,
-                               (int)(2 * sizeof(void *)), ptr + i, linebuf);
+                       printk("%s%s%p: %s\n",
+                              level, prefix_str, ptr + i, linebuf);
                        break;
                case DUMP_PREFIX_OFFSET:
                        printk("%s%s%.8x: %s\n", level, prefix_str, i, linebuf);
@@ -196,9 +216,9 @@ EXPORT_SYMBOL(print_hex_dump);
  * rowsize of 16, groupsize of 1, and ASCII output included.
  */
 void print_hex_dump_bytes(const char *prefix_str, int prefix_type,
-                       const void *buf, size_t len)
+                         const void *buf, size_t len)
 {
        print_hex_dump(KERN_DEBUG, prefix_str, prefix_type, 16, 1,
-                       buf, len, 1);
+                      buf, len, true);
 }
 EXPORT_SYMBOL(print_hex_dump_bytes);
index 422a9d5069cc3389986ebcf98ebc3861e1535180..c1a2069017614e6f95a7c2a892fcca1c9c2a7ff1 100644 (file)
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -445,6 +445,7 @@ EXPORT_SYMBOL(idr_remove);
 void idr_remove_all(struct idr *idp)
 {
        int n, id, max;
+       int bt_mask;
        struct idr_layer *p;
        struct idr_layer *pa[MAX_LEVEL];
        struct idr_layer **paa = &pa[0];
@@ -462,8 +463,10 @@ void idr_remove_all(struct idr *idp)
                        p = p->ary[(id >> n) & IDR_MASK];
                }
 
+               bt_mask = id;
                id += 1 << n;
-               while (n < fls(id)) {
+               /* Get the highest bit that the above add changed from 0->1. */
+               while (n < fls(id ^ bt_mask)) {
                        if (p)
                                free_layer(p);
                        n += IDR_BITS;
index 2a087e0f98633cf00724ef0ef7b411d9f60b609e..05da38bcc2986c296726981483b05dfc5b12109e 100644 (file)
@@ -656,7 +656,7 @@ EXPORT_SYMBOL(radix_tree_next_hole);
  *
  *     Returns: the index of the hole if found, otherwise returns an index
  *     outside of the set specified (in which case 'index - return >= max_scan'
- *     will be true). In rare cases of wrap-around, LONG_MAX will be returned.
+ *     will be true). In rare cases of wrap-around, ULONG_MAX will be returned.
  *
  *     radix_tree_next_hole may be called under rcu_read_lock. However, like
  *     radix_tree_gang_lookup, this will not atomically search a snapshot of
@@ -674,7 +674,7 @@ unsigned long radix_tree_prev_hole(struct radix_tree_root *root,
                if (!radix_tree_lookup(root, index))
                        break;
                index--;
-               if (index == LONG_MAX)
+               if (index == ULONG_MAX)
                        break;
        }
 
index 217d5c4b666d22e4f309ad363c157580c2810bf8..870dc3fc0f0f6c33a5fef027459387964ad58bbc 100644 (file)
 #include <linux/jiffies.h>
 #include <linux/random.h>
 
-struct rnd_state {
-       u32 s1, s2, s3;
-};
-
 static DEFINE_PER_CPU(struct rnd_state, net_rand_state);
 
-static u32 __random32(struct rnd_state *state)
+/**
+ *     prandom32 - seeded pseudo-random number generator.
+ *     @state: pointer to state structure holding seeded state.
+ *
+ *     This is used for pseudo-randomness with no outside seeding.
+ *     For more random results, use random32().
+ */
+u32 prandom32(struct rnd_state *state)
 {
 #define TAUSWORTHE(s,a,b,c,d) ((s&c)<<d) ^ (((s <<a) ^ s)>>b)
 
@@ -55,14 +58,7 @@ static u32 __random32(struct rnd_state *state)
 
        return (state->s1 ^ state->s2 ^ state->s3);
 }
-
-/*
- * Handle minimum values for seeds
- */
-static inline u32 __seed(u32 x, u32 m)
-{
-       return (x < m) ? x + m : x;
-}
+EXPORT_SYMBOL(prandom32);
 
 /**
  *     random32 - pseudo random number generator
@@ -75,7 +71,7 @@ u32 random32(void)
 {
        unsigned long r;
        struct rnd_state *state = &get_cpu_var(net_rand_state);
-       r = __random32(state);
+       r = prandom32(state);
        put_cpu_var(state);
        return r;
 }
@@ -118,12 +114,12 @@ static int __init random32_init(void)
                state->s3 = __seed(LCG(state->s2), 15);
 
                /* "warm it up" */
-               __random32(state);
-               __random32(state);
-               __random32(state);
-               __random32(state);
-               __random32(state);
-               __random32(state);
+               prandom32(state);
+               prandom32(state);
+               prandom32(state);
+               prandom32(state);
+               prandom32(state);
+               prandom32(state);
        }
        return 0;
 }
@@ -147,7 +143,7 @@ static int __init random32_reseed(void)
                state->s3 = __seed(seeds[2], 15);
 
                /* mix it in */
-               __random32(state);
+               prandom32(state);
        }
        return 0;
 }
index 5fddf720da73e42b6568b80f64234e47033bc142..a009055140ecf7a798625d3fee7cd856c0bb8d4c 100644 (file)
@@ -756,37 +756,6 @@ swiotlb_sync_single_for_device(struct device *hwdev, dma_addr_t dev_addr,
 }
 EXPORT_SYMBOL(swiotlb_sync_single_for_device);
 
-/*
- * Same as above, but for a sub-range of the mapping.
- */
-static void
-swiotlb_sync_single_range(struct device *hwdev, dma_addr_t dev_addr,
-                         unsigned long offset, size_t size,
-                         int dir, int target)
-{
-       swiotlb_sync_single(hwdev, dev_addr + offset, size, dir, target);
-}
-
-void
-swiotlb_sync_single_range_for_cpu(struct device *hwdev, dma_addr_t dev_addr,
-                                 unsigned long offset, size_t size,
-                                 enum dma_data_direction dir)
-{
-       swiotlb_sync_single_range(hwdev, dev_addr, offset, size, dir,
-                                 SYNC_FOR_CPU);
-}
-EXPORT_SYMBOL_GPL(swiotlb_sync_single_range_for_cpu);
-
-void
-swiotlb_sync_single_range_for_device(struct device *hwdev, dma_addr_t dev_addr,
-                                    unsigned long offset, size_t size,
-                                    enum dma_data_direction dir)
-{
-       swiotlb_sync_single_range(hwdev, dev_addr, offset, size, dir,
-                                 SYNC_FOR_DEVICE);
-}
-EXPORT_SYMBOL_GPL(swiotlb_sync_single_range_for_device);
-
 /*
  * Map a set of buffers described by scatterlist in streaming mode for DMA.
  * This is the scatter-gather version of the above swiotlb_map_page
diff --git a/lib/uuid.c b/lib/uuid.c
new file mode 100644 (file)
index 0000000..8fadd7c
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Unified UUID/GUID definition
+ *
+ * Copyright (C) 2009, Intel Corp.
+ *     Huang Ying <ying.huang@intel.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/uuid.h>
+#include <linux/random.h>
+
+static void __uuid_gen_common(__u8 b[16])
+{
+       int i;
+       u32 r;
+
+       for (i = 0; i < 4; i++) {
+               r = random32();
+               memcpy(b + i * 4, &r, 4);
+       }
+       /* reversion 0b10 */
+       b[8] = (b[8] & 0x3F) | 0x80;
+}
+
+void uuid_le_gen(uuid_le *lu)
+{
+       __uuid_gen_common(lu->b);
+       /* version 4 : random generation */
+       lu->b[7] = (lu->b[7] & 0x0F) | 0x40;
+}
+EXPORT_SYMBOL_GPL(uuid_le_gen);
+
+void uuid_be_gen(uuid_be *bu)
+{
+       __uuid_gen_common(bu->b);
+       /* version 4 : random generation */
+       bu->b[6] = (bu->b[6] & 0x0F) | 0x40;
+}
+EXPORT_SYMBOL_GPL(uuid_be_gen);
index 46d34b0b74a873290b0cd9fcfff6c19561c91de4..b8a2f549ab0ef5db70ecae07de8ea3be4d67a06d 100644 (file)
@@ -267,7 +267,8 @@ int strict_strtoll(const char *cp, unsigned int base, long long *res)
 }
 EXPORT_SYMBOL(strict_strtoll);
 
-static int skip_atoi(const char **s)
+static noinline_for_stack
+int skip_atoi(const char **s)
 {
        int i = 0;
 
@@ -287,7 +288,8 @@ static int skip_atoi(const char **s)
 /* Formats correctly any integer in [0,99999].
  * Outputs from one to five digits depending on input.
  * On i386 gcc 4.1.2 -O2: ~250 bytes of code. */
-static char *put_dec_trunc(char *buf, unsigned q)
+static noinline_for_stack
+char *put_dec_trunc(char *buf, unsigned q)
 {
        unsigned d3, d2, d1, d0;
        d1 = (q>>4) & 0xf;
@@ -324,7 +326,8 @@ static char *put_dec_trunc(char *buf, unsigned q)
        return buf;
 }
 /* Same with if's removed. Always emits five digits */
-static char *put_dec_full(char *buf, unsigned q)
+static noinline_for_stack
+char *put_dec_full(char *buf, unsigned q)
 {
        /* BTW, if q is in [0,9999], 8-bit ints will be enough, */
        /* but anyway, gcc produces better code with full-sized ints */
@@ -366,7 +369,8 @@ static char *put_dec_full(char *buf, unsigned q)
        return buf;
 }
 /* No inlining helps gcc to use registers better */
-static noinline char *put_dec(char *buf, unsigned long long num)
+static noinline_for_stack
+char *put_dec(char *buf, unsigned long long num)
 {
        while (1) {
                unsigned rem;
@@ -417,8 +421,9 @@ struct printf_spec {
        s16     precision;      /* # of digits/chars */
 };
 
-static char *number(char *buf, char *end, unsigned long long num,
-                       struct printf_spec spec)
+static noinline_for_stack
+char *number(char *buf, char *end, unsigned long long num,
+            struct printf_spec spec)
 {
        /* we are called with base 8, 10 or 16, only, thus don't need "G..."  */
        static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
@@ -537,7 +542,8 @@ static char *number(char *buf, char *end, unsigned long long num,
        return buf;
 }
 
-static char *string(char *buf, char *end, const char *s, struct printf_spec spec)
+static noinline_for_stack
+char *string(char *buf, char *end, const char *s, struct printf_spec spec)
 {
        int len, i;
 
@@ -567,8 +573,9 @@ static char *string(char *buf, char *end, const char *s, struct printf_spec spec
        return buf;
 }
 
-static char *symbol_string(char *buf, char *end, void *ptr,
-                               struct printf_spec spec, char ext)
+static noinline_for_stack
+char *symbol_string(char *buf, char *end, void *ptr,
+                   struct printf_spec spec, char ext)
 {
        unsigned long value = (unsigned long) ptr;
 #ifdef CONFIG_KALLSYMS
@@ -588,8 +595,9 @@ static char *symbol_string(char *buf, char *end, void *ptr,
 #endif
 }
 
-static char *resource_string(char *buf, char *end, struct resource *res,
-                               struct printf_spec spec, const char *fmt)
+static noinline_for_stack
+char *resource_string(char *buf, char *end, struct resource *res,
+                     struct printf_spec spec, const char *fmt)
 {
 #ifndef IO_RSRC_PRINTK_SIZE
 #define IO_RSRC_PRINTK_SIZE    6
@@ -690,8 +698,9 @@ static char *resource_string(char *buf, char *end, struct resource *res,
        return string(buf, end, sym, spec);
 }
 
-static char *mac_address_string(char *buf, char *end, u8 *addr,
-                               struct printf_spec spec, const char *fmt)
+static noinline_for_stack
+char *mac_address_string(char *buf, char *end, u8 *addr,
+                        struct printf_spec spec, const char *fmt)
 {
        char mac_addr[sizeof("xx:xx:xx:xx:xx:xx")];
        char *p = mac_addr;
@@ -714,7 +723,8 @@ static char *mac_address_string(char *buf, char *end, u8 *addr,
        return string(buf, end, mac_addr, spec);
 }
 
-static char *ip4_string(char *p, const u8 *addr, const char *fmt)
+static noinline_for_stack
+char *ip4_string(char *p, const u8 *addr, const char *fmt)
 {
        int i;
        bool leading_zeros = (fmt[0] == 'i');
@@ -763,7 +773,8 @@ static char *ip4_string(char *p, const u8 *addr, const char *fmt)
        return p;
 }
 
-static char *ip6_compressed_string(char *p, const char *addr)
+static noinline_for_stack
+char *ip6_compressed_string(char *p, const char *addr)
 {
        int i, j, range;
        unsigned char zerolength[8];
@@ -843,7 +854,8 @@ static char *ip6_compressed_string(char *p, const char *addr)
        return p;
 }
 
-static char *ip6_string(char *p, const char *addr, const char *fmt)
+static noinline_for_stack
+char *ip6_string(char *p, const char *addr, const char *fmt)
 {
        int i;
 
@@ -858,8 +870,9 @@ static char *ip6_string(char *p, const char *addr, const char *fmt)
        return p;
 }
 
-static char *ip6_addr_string(char *buf, char *end, const u8 *addr,
-                            struct printf_spec spec, const char *fmt)
+static noinline_for_stack
+char *ip6_addr_string(char *buf, char *end, const u8 *addr,
+                     struct printf_spec spec, const char *fmt)
 {
        char ip6_addr[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")];
 
@@ -871,8 +884,9 @@ static char *ip6_addr_string(char *buf, char *end, const u8 *addr,
        return string(buf, end, ip6_addr, spec);
 }
 
-static char *ip4_addr_string(char *buf, char *end, const u8 *addr,
-                            struct printf_spec spec, const char *fmt)
+static noinline_for_stack
+char *ip4_addr_string(char *buf, char *end, const u8 *addr,
+                     struct printf_spec spec, const char *fmt)
 {
        char ip4_addr[sizeof("255.255.255.255")];
 
@@ -881,8 +895,9 @@ static char *ip4_addr_string(char *buf, char *end, const u8 *addr,
        return string(buf, end, ip4_addr, spec);
 }
 
-static char *uuid_string(char *buf, char *end, const u8 *addr,
-                        struct printf_spec spec, const char *fmt)
+static noinline_for_stack
+char *uuid_string(char *buf, char *end, const u8 *addr,
+                 struct printf_spec spec, const char *fmt)
 {
        char uuid[sizeof("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")];
        char *p = uuid;
@@ -970,8 +985,9 @@ static char *uuid_string(char *buf, char *end, const u8 *addr,
  * function pointers are really function descriptors, which contain a
  * pointer to the real address.
  */
-static char *pointer(const char *fmt, char *buf, char *end, void *ptr,
-                       struct printf_spec spec)
+static noinline_for_stack
+char *pointer(const char *fmt, char *buf, char *end, void *ptr,
+             struct printf_spec spec)
 {
        if (!ptr)
                return string(buf, end, "(null)", spec);
@@ -1040,7 +1056,8 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr,
  * @precision: precision of a number
  * @qualifier: qualifier of a number (long, size_t, ...)
  */
-static int format_decode(const char *fmt, struct printf_spec *spec)
+static noinline_for_stack
+int format_decode(const char *fmt, struct printf_spec *spec)
 {
        const char *start = fmt;
 
@@ -1980,7 +1997,7 @@ int vsscanf(const char *buf, const char *fmt, va_list args)
                {
                        char *s = (char *)va_arg(args, char *);
                        if (field_width == -1)
-                               field_width = SHORT_MAX;
+                               field_width = SHRT_MAX;
                        /* first, skip leading white space in buffer */
                        str = skip_spaces(str);
 
index 9c61158308dc910cfad4fdaca71c5a0b4e42b87d..527136b2238496c890583a2d44838bf37f3878e3 100644 (file)
@@ -171,6 +171,15 @@ config SPLIT_PTLOCK_CPUS
        default "999999" if DEBUG_SPINLOCK || DEBUG_LOCK_ALLOC
        default "4"
 
+#
+# support for memory compaction
+config COMPACTION
+       bool "Allow for memory compaction"
+       select MIGRATION
+       depends on EXPERIMENTAL && HUGETLB_PAGE && MMU
+       help
+         Allows the compaction of memory for the allocation of huge pages.
+
 #
 # support for page migration
 #
@@ -180,9 +189,11 @@ config MIGRATION
        depends on NUMA || ARCH_ENABLE_MEMORY_HOTREMOVE
        help
          Allows the migration of the physical location of pages of processes
-         while the virtual addresses are not changed. This is useful for
-         example on NUMA systems to put pages nearer to the processors accessing
-         the page.
+         while the virtual addresses are not changed. This is useful in
+         two situations. The first is on NUMA systems to put pages nearer
+         to the processors accessing. The second is when allocating huge
+         pages as migration can relocate pages to satisfy a huge page
+         allocation instead of reclaiming.
 
 config PHYS_ADDR_T_64BIT
        def_bool 64BIT || ARCH_PHYS_ADDR_T_64BIT
index 6c2a73a54a43c2bb6b412ebf7af56d622315a329..8982504bd03bb783ab8fe2d0dce2c08010f3e66d 100644 (file)
@@ -23,6 +23,7 @@ obj-$(CONFIG_NUMA)    += mempolicy.o
 obj-$(CONFIG_SPARSEMEM)        += sparse.o
 obj-$(CONFIG_SPARSEMEM_VMEMMAP) += sparse-vmemmap.o
 obj-$(CONFIG_SLOB) += slob.o
+obj-$(CONFIG_COMPACTION) += compaction.o
 obj-$(CONFIG_MMU_NOTIFIER) += mmu_notifier.o
 obj-$(CONFIG_KSM) += ksm.o
 obj-$(CONFIG_PAGE_POISONING) += debug-pagealloc.o
diff --git a/mm/compaction.c b/mm/compaction.c
new file mode 100644 (file)
index 0000000..94cce51
--- /dev/null
@@ -0,0 +1,605 @@
+/*
+ * linux/mm/compaction.c
+ *
+ * Memory compaction for the reduction of external fragmentation. Note that
+ * this heavily depends upon page migration to do all the real heavy
+ * lifting
+ *
+ * Copyright IBM Corp. 2007-2010 Mel Gorman <mel@csn.ul.ie>
+ */
+#include <linux/swap.h>
+#include <linux/migrate.h>
+#include <linux/compaction.h>
+#include <linux/mm_inline.h>
+#include <linux/backing-dev.h>
+#include <linux/sysctl.h>
+#include <linux/sysfs.h>
+#include "internal.h"
+
+/*
+ * compact_control is used to track pages being migrated and the free pages
+ * they are being migrated to during memory compaction. The free_pfn starts
+ * at the end of a zone and migrate_pfn begins at the start. Movable pages
+ * are moved to the end of a zone during a compaction run and the run
+ * completes when free_pfn <= migrate_pfn
+ */
+struct compact_control {
+       struct list_head freepages;     /* List of free pages to migrate to */
+       struct list_head migratepages;  /* List of pages being migrated */
+       unsigned long nr_freepages;     /* Number of isolated free pages */
+       unsigned long nr_migratepages;  /* Number of pages to migrate */
+       unsigned long free_pfn;         /* isolate_freepages search base */
+       unsigned long migrate_pfn;      /* isolate_migratepages search base */
+
+       /* Account for isolated anon and file pages */
+       unsigned long nr_anon;
+       unsigned long nr_file;
+
+       unsigned int order;             /* order a direct compactor needs */
+       int migratetype;                /* MOVABLE, RECLAIMABLE etc */
+       struct zone *zone;
+};
+
+static unsigned long release_freepages(struct list_head *freelist)
+{
+       struct page *page, *next;
+       unsigned long count = 0;
+
+       list_for_each_entry_safe(page, next, freelist, lru) {
+               list_del(&page->lru);
+               __free_page(page);
+               count++;
+       }
+
+       return count;
+}
+
+/* Isolate free pages onto a private freelist. Must hold zone->lock */
+static unsigned long isolate_freepages_block(struct zone *zone,
+                               unsigned long blockpfn,
+                               struct list_head *freelist)
+{
+       unsigned long zone_end_pfn, end_pfn;
+       int total_isolated = 0;
+       struct page *cursor;
+
+       /* Get the last PFN we should scan for free pages at */
+       zone_end_pfn = zone->zone_start_pfn + zone->spanned_pages;
+       end_pfn = min(blockpfn + pageblock_nr_pages, zone_end_pfn);
+
+       /* Find the first usable PFN in the block to initialse page cursor */
+       for (; blockpfn < end_pfn; blockpfn++) {
+               if (pfn_valid_within(blockpfn))
+                       break;
+       }
+       cursor = pfn_to_page(blockpfn);
+
+       /* Isolate free pages. This assumes the block is valid */
+       for (; blockpfn < end_pfn; blockpfn++, cursor++) {
+               int isolated, i;
+               struct page *page = cursor;
+
+               if (!pfn_valid_within(blockpfn))
+                       continue;
+
+               if (!PageBuddy(page))
+                       continue;
+
+               /* Found a free page, break it into order-0 pages */
+               isolated = split_free_page(page);
+               total_isolated += isolated;
+               for (i = 0; i < isolated; i++) {
+                       list_add(&page->lru, freelist);
+                       page++;
+               }
+
+               /* If a page was split, advance to the end of it */
+               if (isolated) {
+                       blockpfn += isolated - 1;
+                       cursor += isolated - 1;
+               }
+       }
+
+       return total_isolated;
+}
+
+/* Returns true if the page is within a block suitable for migration to */
+static bool suitable_migration_target(struct page *page)
+{
+
+       int migratetype = get_pageblock_migratetype(page);
+
+       /* Don't interfere with memory hot-remove or the min_free_kbytes blocks */
+       if (migratetype == MIGRATE_ISOLATE || migratetype == MIGRATE_RESERVE)
+               return false;
+
+       /* If the page is a large free page, then allow migration */
+       if (PageBuddy(page) && page_order(page) >= pageblock_order)
+               return true;
+
+       /* If the block is MIGRATE_MOVABLE, allow migration */
+       if (migratetype == MIGRATE_MOVABLE)
+               return true;
+
+       /* Otherwise skip the block */
+       return false;
+}
+
+/*
+ * Based on information in the current compact_control, find blocks
+ * suitable for isolating free pages from and then isolate them.
+ */
+static void isolate_freepages(struct zone *zone,
+                               struct compact_control *cc)
+{
+       struct page *page;
+       unsigned long high_pfn, low_pfn, pfn;
+       unsigned long flags;
+       int nr_freepages = cc->nr_freepages;
+       struct list_head *freelist = &cc->freepages;
+
+       pfn = cc->free_pfn;
+       low_pfn = cc->migrate_pfn + pageblock_nr_pages;
+       high_pfn = low_pfn;
+
+       /*
+        * Isolate free pages until enough are available to migrate the
+        * pages on cc->migratepages. We stop searching if the migrate
+        * and free page scanners meet or enough free pages are isolated.
+        */
+       spin_lock_irqsave(&zone->lock, flags);
+       for (; pfn > low_pfn && cc->nr_migratepages > nr_freepages;
+                                       pfn -= pageblock_nr_pages) {
+               unsigned long isolated;
+
+               if (!pfn_valid(pfn))
+                       continue;
+
+               /*
+                * Check for overlapping nodes/zones. It's possible on some
+                * configurations to have a setup like
+                * node0 node1 node0
+                * i.e. it's possible that all pages within a zones range of
+                * pages do not belong to a single zone.
+                */
+               page = pfn_to_page(pfn);
+               if (page_zone(page) != zone)
+                       continue;
+
+               /* Check the block is suitable for migration */
+               if (!suitable_migration_target(page))
+                       continue;
+
+               /* Found a block suitable for isolating free pages from */
+               isolated = isolate_freepages_block(zone, pfn, freelist);
+               nr_freepages += isolated;
+
+               /*
+                * Record the highest PFN we isolated pages from. When next
+                * looking for free pages, the search will restart here as
+                * page migration may have returned some pages to the allocator
+                */
+               if (isolated)
+                       high_pfn = max(high_pfn, pfn);
+       }
+       spin_unlock_irqrestore(&zone->lock, flags);
+
+       /* split_free_page does not map the pages */
+       list_for_each_entry(page, freelist, lru) {
+               arch_alloc_page(page, 0);
+               kernel_map_pages(page, 1, 1);
+       }
+
+       cc->free_pfn = high_pfn;
+       cc->nr_freepages = nr_freepages;
+}
+
+/* Update the number of anon and file isolated pages in the zone */
+static void acct_isolated(struct zone *zone, struct compact_control *cc)
+{
+       struct page *page;
+       unsigned int count[NR_LRU_LISTS] = { 0, };
+
+       list_for_each_entry(page, &cc->migratepages, lru) {
+               int lru = page_lru_base_type(page);
+               count[lru]++;
+       }
+
+       cc->nr_anon = count[LRU_ACTIVE_ANON] + count[LRU_INACTIVE_ANON];
+       cc->nr_file = count[LRU_ACTIVE_FILE] + count[LRU_INACTIVE_FILE];
+       __mod_zone_page_state(zone, NR_ISOLATED_ANON, cc->nr_anon);
+       __mod_zone_page_state(zone, NR_ISOLATED_FILE, cc->nr_file);
+}
+
+/* Similar to reclaim, but different enough that they don't share logic */
+static bool too_many_isolated(struct zone *zone)
+{
+
+       unsigned long inactive, isolated;
+
+       inactive = zone_page_state(zone, NR_INACTIVE_FILE) +
+                                       zone_page_state(zone, NR_INACTIVE_ANON);
+       isolated = zone_page_state(zone, NR_ISOLATED_FILE) +
+                                       zone_page_state(zone, NR_ISOLATED_ANON);
+
+       return isolated > inactive;
+}
+
+/*
+ * Isolate all pages that can be migrated from the block pointed to by
+ * the migrate scanner within compact_control.
+ */
+static unsigned long isolate_migratepages(struct zone *zone,
+                                       struct compact_control *cc)
+{
+       unsigned long low_pfn, end_pfn;
+       struct list_head *migratelist = &cc->migratepages;
+
+       /* Do not scan outside zone boundaries */
+       low_pfn = max(cc->migrate_pfn, zone->zone_start_pfn);
+
+       /* Only scan within a pageblock boundary */
+       end_pfn = ALIGN(low_pfn + pageblock_nr_pages, pageblock_nr_pages);
+
+       /* Do not cross the free scanner or scan within a memory hole */
+       if (end_pfn > cc->free_pfn || !pfn_valid(low_pfn)) {
+               cc->migrate_pfn = end_pfn;
+               return 0;
+       }
+
+       /*
+        * Ensure that there are not too many pages isolated from the LRU
+        * list by either parallel reclaimers or compaction. If there are,
+        * delay for some time until fewer pages are isolated
+        */
+       while (unlikely(too_many_isolated(zone))) {
+               congestion_wait(BLK_RW_ASYNC, HZ/10);
+
+               if (fatal_signal_pending(current))
+                       return 0;
+       }
+
+       /* Time to isolate some pages for migration */
+       spin_lock_irq(&zone->lru_lock);
+       for (; low_pfn < end_pfn; low_pfn++) {
+               struct page *page;
+               if (!pfn_valid_within(low_pfn))
+                       continue;
+
+               /* Get the page and skip if free */
+               page = pfn_to_page(low_pfn);
+               if (PageBuddy(page))
+                       continue;
+
+               /* Try isolate the page */
+               if (__isolate_lru_page(page, ISOLATE_BOTH, 0) != 0)
+                       continue;
+
+               /* Successfully isolated */
+               del_page_from_lru_list(zone, page, page_lru(page));
+               list_add(&page->lru, migratelist);
+               mem_cgroup_del_lru(page);
+               cc->nr_migratepages++;
+
+               /* Avoid isolating too much */
+               if (cc->nr_migratepages == COMPACT_CLUSTER_MAX)
+                       break;
+       }
+
+       acct_isolated(zone, cc);
+
+       spin_unlock_irq(&zone->lru_lock);
+       cc->migrate_pfn = low_pfn;
+
+       return cc->nr_migratepages;
+}
+
+/*
+ * This is a migrate-callback that "allocates" freepages by taking pages
+ * from the isolated freelists in the block we are migrating to.
+ */
+static struct page *compaction_alloc(struct page *migratepage,
+                                       unsigned long data,
+                                       int **result)
+{
+       struct compact_control *cc = (struct compact_control *)data;
+       struct page *freepage;
+
+       /* Isolate free pages if necessary */
+       if (list_empty(&cc->freepages)) {
+               isolate_freepages(cc->zone, cc);
+
+               if (list_empty(&cc->freepages))
+                       return NULL;
+       }
+
+       freepage = list_entry(cc->freepages.next, struct page, lru);
+       list_del(&freepage->lru);
+       cc->nr_freepages--;
+
+       return freepage;
+}
+
+/*
+ * We cannot control nr_migratepages and nr_freepages fully when migration is
+ * running as migrate_pages() has no knowledge of compact_control. When
+ * migration is complete, we count the number of pages on the lists by hand.
+ */
+static void update_nr_listpages(struct compact_control *cc)
+{
+       int nr_migratepages = 0;
+       int nr_freepages = 0;
+       struct page *page;
+
+       list_for_each_entry(page, &cc->migratepages, lru)
+               nr_migratepages++;
+       list_for_each_entry(page, &cc->freepages, lru)
+               nr_freepages++;
+
+       cc->nr_migratepages = nr_migratepages;
+       cc->nr_freepages = nr_freepages;
+}
+
+static int compact_finished(struct zone *zone,
+                                               struct compact_control *cc)
+{
+       unsigned int order;
+       unsigned long watermark = low_wmark_pages(zone) + (1 << cc->order);
+
+       if (fatal_signal_pending(current))
+               return COMPACT_PARTIAL;
+
+       /* Compaction run completes if the migrate and free scanner meet */
+       if (cc->free_pfn <= cc->migrate_pfn)
+               return COMPACT_COMPLETE;
+
+       /* Compaction run is not finished if the watermark is not met */
+       if (!zone_watermark_ok(zone, cc->order, watermark, 0, 0))
+               return COMPACT_CONTINUE;
+
+       if (cc->order == -1)
+               return COMPACT_CONTINUE;
+
+       /* Direct compactor: Is a suitable page free? */
+       for (order = cc->order; order < MAX_ORDER; order++) {
+               /* Job done if page is free of the right migratetype */
+               if (!list_empty(&zone->free_area[order].free_list[cc->migratetype]))
+                       return COMPACT_PARTIAL;
+
+               /* Job done if allocation would set block type */
+               if (order >= pageblock_order && zone->free_area[order].nr_free)
+                       return COMPACT_PARTIAL;
+       }
+
+       return COMPACT_CONTINUE;
+}
+
+static int compact_zone(struct zone *zone, struct compact_control *cc)
+{
+       int ret;
+
+       /* Setup to move all movable pages to the end of the zone */
+       cc->migrate_pfn = zone->zone_start_pfn;
+       cc->free_pfn = cc->migrate_pfn + zone->spanned_pages;
+       cc->free_pfn &= ~(pageblock_nr_pages-1);
+
+       migrate_prep_local();
+
+       while ((ret = compact_finished(zone, cc)) == COMPACT_CONTINUE) {
+               unsigned long nr_migrate, nr_remaining;
+
+               if (!isolate_migratepages(zone, cc))
+                       continue;
+
+               nr_migrate = cc->nr_migratepages;
+               migrate_pages(&cc->migratepages, compaction_alloc,
+                                               (unsigned long)cc, 0);
+               update_nr_listpages(cc);
+               nr_remaining = cc->nr_migratepages;
+
+               count_vm_event(COMPACTBLOCKS);
+               count_vm_events(COMPACTPAGES, nr_migrate - nr_remaining);
+               if (nr_remaining)
+                       count_vm_events(COMPACTPAGEFAILED, nr_remaining);
+
+               /* Release LRU pages not migrated */
+               if (!list_empty(&cc->migratepages)) {
+                       putback_lru_pages(&cc->migratepages);
+                       cc->nr_migratepages = 0;
+               }
+
+       }
+
+       /* Release free pages and check accounting */
+       cc->nr_freepages -= release_freepages(&cc->freepages);
+       VM_BUG_ON(cc->nr_freepages != 0);
+
+       return ret;
+}
+
+static unsigned long compact_zone_order(struct zone *zone,
+                                               int order, gfp_t gfp_mask)
+{
+       struct compact_control cc = {
+               .nr_freepages = 0,
+               .nr_migratepages = 0,
+               .order = order,
+               .migratetype = allocflags_to_migratetype(gfp_mask),
+               .zone = zone,
+       };
+       INIT_LIST_HEAD(&cc.freepages);
+       INIT_LIST_HEAD(&cc.migratepages);
+
+       return compact_zone(zone, &cc);
+}
+
+int sysctl_extfrag_threshold = 500;
+
+/**
+ * try_to_compact_pages - Direct compact to satisfy a high-order allocation
+ * @zonelist: The zonelist used for the current allocation
+ * @order: The order of the current allocation
+ * @gfp_mask: The GFP mask of the current allocation
+ * @nodemask: The allowed nodes to allocate from
+ *
+ * This is the main entry point for direct page compaction.
+ */
+unsigned long try_to_compact_pages(struct zonelist *zonelist,
+                       int order, gfp_t gfp_mask, nodemask_t *nodemask)
+{
+       enum zone_type high_zoneidx = gfp_zone(gfp_mask);
+       int may_enter_fs = gfp_mask & __GFP_FS;
+       int may_perform_io = gfp_mask & __GFP_IO;
+       unsigned long watermark;
+       struct zoneref *z;
+       struct zone *zone;
+       int rc = COMPACT_SKIPPED;
+
+       /*
+        * Check whether it is worth even starting compaction. The order check is
+        * made because an assumption is made that the page allocator can satisfy
+        * the "cheaper" orders without taking special steps
+        */
+       if (order <= PAGE_ALLOC_COSTLY_ORDER || !may_enter_fs || !may_perform_io)
+               return rc;
+
+       count_vm_event(COMPACTSTALL);
+
+       /* Compact each zone in the list */
+       for_each_zone_zonelist_nodemask(zone, z, zonelist, high_zoneidx,
+                                                               nodemask) {
+               int fragindex;
+               int status;
+
+               /*
+                * Watermarks for order-0 must be met for compaction. Note
+                * the 2UL. This is because during migration, copies of
+                * pages need to be allocated and for a short time, the
+                * footprint is higher
+                */
+               watermark = low_wmark_pages(zone) + (2UL << order);
+               if (!zone_watermark_ok(zone, 0, watermark, 0, 0))
+                       continue;
+
+               /*
+                * fragmentation index determines if allocation failures are
+                * due to low memory or external fragmentation
+                *
+                * index of -1 implies allocations might succeed depending
+                *      on watermarks
+                * index towards 0 implies failure is due to lack of memory
+                * index towards 1000 implies failure is due to fragmentation
+                *
+                * Only compact if a failure would be due to fragmentation.
+                */
+               fragindex = fragmentation_index(zone, order);
+               if (fragindex >= 0 && fragindex <= sysctl_extfrag_threshold)
+                       continue;
+
+               if (fragindex == -1 && zone_watermark_ok(zone, order, watermark, 0, 0)) {
+                       rc = COMPACT_PARTIAL;
+                       break;
+               }
+
+               status = compact_zone_order(zone, order, gfp_mask);
+               rc = max(status, rc);
+
+               if (zone_watermark_ok(zone, order, watermark, 0, 0))
+                       break;
+       }
+
+       return rc;
+}
+
+
+/* Compact all zones within a node */
+static int compact_node(int nid)
+{
+       int zoneid;
+       pg_data_t *pgdat;
+       struct zone *zone;
+
+       if (nid < 0 || nid >= nr_node_ids || !node_online(nid))
+               return -EINVAL;
+       pgdat = NODE_DATA(nid);
+
+       /* Flush pending updates to the LRU lists */
+       lru_add_drain_all();
+
+       for (zoneid = 0; zoneid < MAX_NR_ZONES; zoneid++) {
+               struct compact_control cc = {
+                       .nr_freepages = 0,
+                       .nr_migratepages = 0,
+                       .order = -1,
+               };
+
+               zone = &pgdat->node_zones[zoneid];
+               if (!populated_zone(zone))
+                       continue;
+
+               cc.zone = zone;
+               INIT_LIST_HEAD(&cc.freepages);
+               INIT_LIST_HEAD(&cc.migratepages);
+
+               compact_zone(zone, &cc);
+
+               VM_BUG_ON(!list_empty(&cc.freepages));
+               VM_BUG_ON(!list_empty(&cc.migratepages));
+       }
+
+       return 0;
+}
+
+/* Compact all nodes in the system */
+static int compact_nodes(void)
+{
+       int nid;
+
+       for_each_online_node(nid)
+               compact_node(nid);
+
+       return COMPACT_COMPLETE;
+}
+
+/* The written value is actually unused, all memory is compacted */
+int sysctl_compact_memory;
+
+/* This is the entry point for compacting all nodes via /proc/sys/vm */
+int sysctl_compaction_handler(struct ctl_table *table, int write,
+                       void __user *buffer, size_t *length, loff_t *ppos)
+{
+       if (write)
+               return compact_nodes();
+
+       return 0;
+}
+
+int sysctl_extfrag_handler(struct ctl_table *table, int write,
+                       void __user *buffer, size_t *length, loff_t *ppos)
+{
+       proc_dointvec_minmax(table, write, buffer, length, ppos);
+
+       return 0;
+}
+
+#if defined(CONFIG_SYSFS) && defined(CONFIG_NUMA)
+ssize_t sysfs_compact_node(struct sys_device *dev,
+                       struct sysdev_attribute *attr,
+                       const char *buf, size_t count)
+{
+       compact_node(dev->id);
+
+       return count;
+}
+static SYSDEV_ATTR(compact, S_IWUSR, NULL, sysfs_compact_node);
+
+int compaction_register_node(struct node *node)
+{
+       return sysdev_create_file(&node->sysdev, &attr_compact);
+}
+
+void compaction_unregister_node(struct node *node)
+{
+       return sysdev_remove_file(&node->sysdev, &attr_compact);
+}
+#endif /* CONFIG_SYSFS && CONFIG_NUMA */
index 140ebda9640f64a7f05b58a5d31156cb874a6eb9..45a2d18df849b984421f5e756678964b1ae4e74a 100644 (file)
@@ -441,7 +441,7 @@ int add_to_page_cache_lru(struct page *page, struct address_space *mapping,
        /*
         * Splice_read and readahead add shmem/tmpfs pages into the page cache
         * before shmem_readpage has a chance to mark them as SwapBacked: they
-        * need to go on the active_anon lru below, and mem_cgroup_cache_charge
+        * need to go on the anon lru below, and mem_cgroup_cache_charge
         * (called in add_to_page_cache) needs to know where they're going too.
         */
        if (mapping_cap_swap_backed(mapping))
@@ -452,7 +452,7 @@ int add_to_page_cache_lru(struct page *page, struct address_space *mapping,
                if (page_is_file_cache(page))
                        lru_cache_add_file(page);
                else
-                       lru_cache_add_active_anon(page);
+                       lru_cache_add_anon(page);
        }
        return ret;
 }
@@ -461,9 +461,15 @@ EXPORT_SYMBOL_GPL(add_to_page_cache_lru);
 #ifdef CONFIG_NUMA
 struct page *__page_cache_alloc(gfp_t gfp)
 {
+       int n;
+       struct page *page;
+
        if (cpuset_do_page_mem_spread()) {
-               int n = cpuset_mem_spread_node();
-               return alloc_pages_exact_node(n, gfp, 0);
+               get_mems_allowed();
+               n = cpuset_mem_spread_node();
+               page = alloc_pages_exact_node(n, gfp, 0);
+               put_mems_allowed();
+               return page;
        }
        return alloc_pages(gfp, 0);
 }
@@ -1099,6 +1105,12 @@ page_not_up_to_date_locked:
                }
 
 readpage:
+               /*
+                * A previous I/O error may have been due to temporary
+                * failures, eg. multipath errors.
+                * PG_error will be set again if readpage fails.
+                */
+               ClearPageError(page);
                /* Start the actual read. The read will unlock the page. */
                error = mapping->a_ops->readpage(filp, page);
 
@@ -1263,7 +1275,7 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
 {
        struct file *filp = iocb->ki_filp;
        ssize_t retval;
-       unsigned long seg;
+       unsigned long seg = 0;
        size_t count;
        loff_t *ppos = &iocb->ki_pos;
 
@@ -1290,21 +1302,47 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
                                retval = mapping->a_ops->direct_IO(READ, iocb,
                                                        iov, pos, nr_segs);
                        }
-                       if (retval > 0)
+                       if (retval > 0) {
                                *ppos = pos + retval;
-                       if (retval) {
+                               count -= retval;
+                       }
+
+                       /*
+                        * Btrfs can have a short DIO read if we encounter
+                        * compressed extents, so if there was an error, or if
+                        * we've already read everything we wanted to, or if
+                        * there was a short read because we hit EOF, go ahead
+                        * and return.  Otherwise fallthrough to buffered io for
+                        * the rest of the read.
+                        */
+                       if (retval < 0 || !count || *ppos >= size) {
                                file_accessed(filp);
                                goto out;
                        }
                }
        }
 
+       count = retval;
        for (seg = 0; seg < nr_segs; seg++) {
                read_descriptor_t desc;
+               loff_t offset = 0;
+
+               /*
+                * If we did a short DIO read we need to skip the section of the
+                * iov that we've already read data into.
+                */
+               if (count) {
+                       if (count > iov[seg].iov_len) {
+                               count -= iov[seg].iov_len;
+                               continue;
+                       }
+                       offset = count;
+                       count = 0;
+               }
 
                desc.written = 0;
-               desc.arg.buf = iov[seg].iov_base;
-               desc.count = iov[seg].iov_len;
+               desc.arg.buf = iov[seg].iov_base + offset;
+               desc.count = iov[seg].iov_len - offset;
                if (desc.count == 0)
                        continue;
                desc.error = 0;
index bed8a8bfd01f2ae96a9d3a7d7a64bc512229b445..66baa20f78f5a4265f16ebf6bb0b7d131bf80684 100644 (file)
@@ -422,7 +422,7 @@ void __init page_address_init(void)
 
 #endif /* defined(CONFIG_HIGHMEM) && !defined(WANT_PAGE_VIRTUAL) */
 
-#if defined(CONFIG_DEBUG_HIGHMEM) && defined(CONFIG_TRACE_IRQFLAGS_SUPPORT)
+#ifdef CONFIG_DEBUG_HIGHMEM
 
 void debug_kmap_atomic(enum km_type type)
 {
index 4c9e6bbf3772c771775057404a1e0f314b90045c..54d42b009dbeb5feb15c2fb08ac09239e0bf9feb 100644 (file)
@@ -465,11 +465,13 @@ static struct page *dequeue_huge_page_vma(struct hstate *h,
        struct page *page = NULL;
        struct mempolicy *mpol;
        nodemask_t *nodemask;
-       struct zonelist *zonelist = huge_zonelist(vma, address,
-                                       htlb_alloc_mask, &mpol, &nodemask);
+       struct zonelist *zonelist;
        struct zone *zone;
        struct zoneref *z;
 
+       get_mems_allowed();
+       zonelist = huge_zonelist(vma, address,
+                                       htlb_alloc_mask, &mpol, &nodemask);
        /*
         * A child process with MAP_PRIVATE mappings created by their parent
         * have no page reserves. This check ensures that reservations are
@@ -477,11 +479,11 @@ static struct page *dequeue_huge_page_vma(struct hstate *h,
         */
        if (!vma_has_reserves(vma) &&
                        h->free_huge_pages - h->resv_huge_pages == 0)
-               return NULL;
+               goto err;
 
        /* If reserves cannot be used, ensure enough pages are in the pool */
        if (avoid_reserve && h->free_huge_pages - h->resv_huge_pages == 0)
-               return NULL;
+               goto err;;
 
        for_each_zone_zonelist_nodemask(zone, z, zonelist,
                                                MAX_NR_ZONES - 1, nodemask) {
@@ -500,7 +502,9 @@ static struct page *dequeue_huge_page_vma(struct hstate *h,
                        break;
                }
        }
+err:
        mpol_cond_put(mpol);
+       put_mems_allowed();
        return page;
 }
 
index 956880f2ff4927a3f0a124ce6ecab4bd2d380696..6c3e99b4ae7c0726851ea5281fbb39f90f7b9ea2 100644 (file)
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -318,14 +318,14 @@ static void hold_anon_vma(struct rmap_item *rmap_item,
                          struct anon_vma *anon_vma)
 {
        rmap_item->anon_vma = anon_vma;
-       atomic_inc(&anon_vma->ksm_refcount);
+       atomic_inc(&anon_vma->external_refcount);
 }
 
 static void drop_anon_vma(struct rmap_item *rmap_item)
 {
        struct anon_vma *anon_vma = rmap_item->anon_vma;
 
-       if (atomic_dec_and_lock(&anon_vma->ksm_refcount, &anon_vma->lock)) {
+       if (atomic_dec_and_lock(&anon_vma->external_refcount, &anon_vma->lock)) {
                int empty = list_empty(&anon_vma->head);
                spin_unlock(&anon_vma->lock);
                if (empty)
index c8569bc298ffc77c5a2627b5a4d2fd2a42b91742..c6ece0a5759595bf1ddbbe4a95e4b76713ea4b06 100644 (file)
@@ -149,16 +149,35 @@ struct mem_cgroup_threshold {
        u64 threshold;
 };
 
+/* For threshold */
 struct mem_cgroup_threshold_ary {
        /* An array index points to threshold just below usage. */
-       atomic_t current_threshold;
+       int current_threshold;
        /* Size of entries[] */
        unsigned int size;
        /* Array of thresholds */
        struct mem_cgroup_threshold entries[0];
 };
 
+struct mem_cgroup_thresholds {
+       /* Primary thresholds array */
+       struct mem_cgroup_threshold_ary *primary;
+       /*
+        * Spare threshold array.
+        * This is needed to make mem_cgroup_unregister_event() "never fail".
+        * It must be able to store at least primary->size - 1 entries.
+        */
+       struct mem_cgroup_threshold_ary *spare;
+};
+
+/* for OOM */
+struct mem_cgroup_eventfd_list {
+       struct list_head list;
+       struct eventfd_ctx *eventfd;
+};
+
 static void mem_cgroup_threshold(struct mem_cgroup *mem);
+static void mem_cgroup_oom_notify(struct mem_cgroup *mem);
 
 /*
  * The memory controller data structure. The memory controller controls both
@@ -207,6 +226,8 @@ struct mem_cgroup {
        atomic_t        refcnt;
 
        unsigned int    swappiness;
+       /* OOM-Killer disable */
+       int             oom_kill_disable;
 
        /* set when res.limit == memsw.limit */
        bool            memsw_is_minimum;
@@ -215,17 +236,19 @@ struct mem_cgroup {
        struct mutex thresholds_lock;
 
        /* thresholds for memory usage. RCU-protected */
-       struct mem_cgroup_threshold_ary *thresholds;
+       struct mem_cgroup_thresholdthresholds;
 
        /* thresholds for mem+swap usage. RCU-protected */
-       struct mem_cgroup_threshold_ary *memsw_thresholds;
+       struct mem_cgroup_thresholds memsw_thresholds;
+
+       /* For oom notifier event fd */
+       struct list_head oom_notify;
 
        /*
         * Should we move charges of a task when a task is moved into this
         * mem_cgroup ? And what type of charges should we move ?
         */
        unsigned long   move_charge_at_immigrate;
-
        /*
         * percpu counter.
         */
@@ -239,6 +262,7 @@ struct mem_cgroup {
  */
 enum move_type {
        MOVE_CHARGE_TYPE_ANON,  /* private anonymous page and swap of it */
+       MOVE_CHARGE_TYPE_FILE,  /* file page(including tmpfs) and swap of it */
        NR_MOVE_TYPE,
 };
 
@@ -255,6 +279,18 @@ static struct move_charge_struct {
        .waitq = __WAIT_QUEUE_HEAD_INITIALIZER(mc.waitq),
 };
 
+static bool move_anon(void)
+{
+       return test_bit(MOVE_CHARGE_TYPE_ANON,
+                                       &mc.to->move_charge_at_immigrate);
+}
+
+static bool move_file(void)
+{
+       return test_bit(MOVE_CHARGE_TYPE_FILE,
+                                       &mc.to->move_charge_at_immigrate);
+}
+
 /*
  * Maximum loops in mem_cgroup_hierarchical_reclaim(), used for soft
  * limit reclaim to prevent infinite loops, if they ever occur.
@@ -282,9 +318,12 @@ enum charge_type {
 /* for encoding cft->private value on file */
 #define _MEM                   (0)
 #define _MEMSWAP               (1)
+#define _OOM_TYPE              (2)
 #define MEMFILE_PRIVATE(x, val)        (((x) << 16) | (val))
 #define MEMFILE_TYPE(val)      (((val) >> 16) & 0xffff)
 #define MEMFILE_ATTR(val)      ((val) & 0xffff)
+/* Used for OOM nofiier */
+#define OOM_CONTROL            (0)
 
 /*
  * Reclaim flags for mem_cgroup_hierarchical_reclaim
@@ -1293,14 +1332,62 @@ static void mem_cgroup_oom_unlock(struct mem_cgroup *mem)
 static DEFINE_MUTEX(memcg_oom_mutex);
 static DECLARE_WAIT_QUEUE_HEAD(memcg_oom_waitq);
 
+struct oom_wait_info {
+       struct mem_cgroup *mem;
+       wait_queue_t    wait;
+};
+
+static int memcg_oom_wake_function(wait_queue_t *wait,
+       unsigned mode, int sync, void *arg)
+{
+       struct mem_cgroup *wake_mem = (struct mem_cgroup *)arg;
+       struct oom_wait_info *oom_wait_info;
+
+       oom_wait_info = container_of(wait, struct oom_wait_info, wait);
+
+       if (oom_wait_info->mem == wake_mem)
+               goto wakeup;
+       /* if no hierarchy, no match */
+       if (!oom_wait_info->mem->use_hierarchy || !wake_mem->use_hierarchy)
+               return 0;
+       /*
+        * Both of oom_wait_info->mem and wake_mem are stable under us.
+        * Then we can use css_is_ancestor without taking care of RCU.
+        */
+       if (!css_is_ancestor(&oom_wait_info->mem->css, &wake_mem->css) &&
+           !css_is_ancestor(&wake_mem->css, &oom_wait_info->mem->css))
+               return 0;
+
+wakeup:
+       return autoremove_wake_function(wait, mode, sync, arg);
+}
+
+static void memcg_wakeup_oom(struct mem_cgroup *mem)
+{
+       /* for filtering, pass "mem" as argument. */
+       __wake_up(&memcg_oom_waitq, TASK_NORMAL, 0, mem);
+}
+
+static void memcg_oom_recover(struct mem_cgroup *mem)
+{
+       if (mem->oom_kill_disable && atomic_read(&mem->oom_lock))
+               memcg_wakeup_oom(mem);
+}
+
 /*
  * try to call OOM killer. returns false if we should exit memory-reclaim loop.
  */
 bool mem_cgroup_handle_oom(struct mem_cgroup *mem, gfp_t mask)
 {
-       DEFINE_WAIT(wait);
-       bool locked;
+       struct oom_wait_info owait;
+       bool locked, need_to_kill;
 
+       owait.mem = mem;
+       owait.wait.flags = 0;
+       owait.wait.func = memcg_oom_wake_function;
+       owait.wait.private = current;
+       INIT_LIST_HEAD(&owait.wait.task_list);
+       need_to_kill = true;
        /* At first, try to OOM lock hierarchy under mem.*/
        mutex_lock(&memcg_oom_mutex);
        locked = mem_cgroup_oom_lock(mem);
@@ -1309,32 +1396,23 @@ bool mem_cgroup_handle_oom(struct mem_cgroup *mem, gfp_t mask)
         * accounting. So, UNINTERRUPTIBLE is appropriate. But SIGKILL
         * under OOM is always welcomed, use TASK_KILLABLE here.
         */
-       if (!locked)
-               prepare_to_wait(&memcg_oom_waitq, &wait, TASK_KILLABLE);
+       prepare_to_wait(&memcg_oom_waitq, &owait.wait, TASK_KILLABLE);
+       if (!locked || mem->oom_kill_disable)
+               need_to_kill = false;
+       if (locked)
+               mem_cgroup_oom_notify(mem);
        mutex_unlock(&memcg_oom_mutex);
 
-       if (locked)
+       if (need_to_kill) {
+               finish_wait(&memcg_oom_waitq, &owait.wait);
                mem_cgroup_out_of_memory(mem, mask);
-       else {
+       else {
                schedule();
-               finish_wait(&memcg_oom_waitq, &wait);
+               finish_wait(&memcg_oom_waitq, &owait.wait);
        }
        mutex_lock(&memcg_oom_mutex);
        mem_cgroup_oom_unlock(mem);
-       /*
-        * Here, we use global waitq .....more fine grained waitq ?
-        * Assume following hierarchy.
-        * A/
-        *   01
-        *   02
-        * assume OOM happens both in A and 01 at the same time. Tthey are
-        * mutually exclusive by lock. (kill in 01 helps A.)
-        * When we use per memcg waitq, we have to wake up waiters on A and 02
-        * in addtion to waiters on 01. We use global waitq for avoiding mess.
-        * It will not be a big problem.
-        * (And a task may be moved to other groups while it's waiting for OOM.)
-        */
-       wake_up_all(&memcg_oom_waitq);
+       memcg_wakeup_oom(mem);
        mutex_unlock(&memcg_oom_mutex);
 
        if (test_thread_flag(TIF_MEMDIE) || fatal_signal_pending(current))
@@ -2118,15 +2196,6 @@ __do_uncharge(struct mem_cgroup *mem, const enum charge_type ctype)
        /* If swapout, usage of swap doesn't decrease */
        if (!do_swap_account || ctype == MEM_CGROUP_CHARGE_TYPE_SWAPOUT)
                uncharge_memsw = false;
-       /*
-        * do_batch > 0 when unmapping pages or inode invalidate/truncate.
-        * In those cases, all pages freed continously can be expected to be in
-        * the same cgroup and we have chance to coalesce uncharges.
-        * But we do uncharge one by one if this is killed by OOM(TIF_MEMDIE)
-        * because we want to do uncharge as soon as possible.
-        */
-       if (!current->memcg_batch.do_batch || test_thread_flag(TIF_MEMDIE))
-               goto direct_uncharge;
 
        batch = &current->memcg_batch;
        /*
@@ -2136,6 +2205,17 @@ __do_uncharge(struct mem_cgroup *mem, const enum charge_type ctype)
         */
        if (!batch->memcg)
                batch->memcg = mem;
+       /*
+        * do_batch > 0 when unmapping pages or inode invalidate/truncate.
+        * In those cases, all pages freed continously can be expected to be in
+        * the same cgroup and we have chance to coalesce uncharges.
+        * But we do uncharge one by one if this is killed by OOM(TIF_MEMDIE)
+        * because we want to do uncharge as soon as possible.
+        */
+
+       if (!batch->do_batch || test_thread_flag(TIF_MEMDIE))
+               goto direct_uncharge;
+
        /*
         * In typical case, batch->memcg == mem. This means we can
         * merge a series of uncharges to an uncharge of res_counter.
@@ -2152,6 +2232,8 @@ direct_uncharge:
        res_counter_uncharge(&mem->res, PAGE_SIZE);
        if (uncharge_memsw)
                res_counter_uncharge(&mem->memsw, PAGE_SIZE);
+       if (unlikely(batch->memcg != mem))
+               memcg_oom_recover(mem);
        return;
 }
 
@@ -2188,7 +2270,8 @@ __mem_cgroup_uncharge_common(struct page *page, enum charge_type ctype)
        switch (ctype) {
        case MEM_CGROUP_CHARGE_TYPE_MAPPED:
        case MEM_CGROUP_CHARGE_TYPE_DROP:
-               if (page_mapped(page))
+               /* See mem_cgroup_prepare_migration() */
+               if (page_mapped(page) || PageCgroupMigration(pc))
                        goto unlock_out;
                break;
        case MEM_CGROUP_CHARGE_TYPE_SWAPOUT:
@@ -2288,6 +2371,7 @@ void mem_cgroup_uncharge_end(void)
                res_counter_uncharge(&batch->memcg->res, batch->bytes);
        if (batch->memsw_bytes)
                res_counter_uncharge(&batch->memcg->memsw, batch->memsw_bytes);
+       memcg_oom_recover(batch->memcg);
        /* forget this pointer (for sanity check) */
        batch->memcg = NULL;
 }
@@ -2410,10 +2494,12 @@ static inline int mem_cgroup_move_swap_account(swp_entry_t entry,
  * Before starting migration, account PAGE_SIZE to mem_cgroup that the old
  * page belongs to.
  */
-int mem_cgroup_prepare_migration(struct page *page, struct mem_cgroup **ptr)
+int mem_cgroup_prepare_migration(struct page *page,
+       struct page *newpage, struct mem_cgroup **ptr)
 {
        struct page_cgroup *pc;
        struct mem_cgroup *mem = NULL;
+       enum charge_type ctype;
        int ret = 0;
 
        if (mem_cgroup_disabled())
@@ -2424,69 +2510,125 @@ int mem_cgroup_prepare_migration(struct page *page, struct mem_cgroup **ptr)
        if (PageCgroupUsed(pc)) {
                mem = pc->mem_cgroup;
                css_get(&mem->css);
+               /*
+                * At migrating an anonymous page, its mapcount goes down
+                * to 0 and uncharge() will be called. But, even if it's fully
+                * unmapped, migration may fail and this page has to be
+                * charged again. We set MIGRATION flag here and delay uncharge
+                * until end_migration() is called
+                *
+                * Corner Case Thinking
+                * A)
+                * When the old page was mapped as Anon and it's unmap-and-freed
+                * while migration was ongoing.
+                * If unmap finds the old page, uncharge() of it will be delayed
+                * until end_migration(). If unmap finds a new page, it's
+                * uncharged when it make mapcount to be 1->0. If unmap code
+                * finds swap_migration_entry, the new page will not be mapped
+                * and end_migration() will find it(mapcount==0).
+                *
+                * B)
+                * When the old page was mapped but migraion fails, the kernel
+                * remaps it. A charge for it is kept by MIGRATION flag even
+                * if mapcount goes down to 0. We can do remap successfully
+                * without charging it again.
+                *
+                * C)
+                * The "old" page is under lock_page() until the end of
+                * migration, so, the old page itself will not be swapped-out.
+                * If the new page is swapped out before end_migraton, our
+                * hook to usual swap-out path will catch the event.
+                */
+               if (PageAnon(page))
+                       SetPageCgroupMigration(pc);
        }
        unlock_page_cgroup(pc);
+       /*
+        * If the page is not charged at this point,
+        * we return here.
+        */
+       if (!mem)
+               return 0;
 
        *ptr = mem;
-       if (mem) {
-               ret = __mem_cgroup_try_charge(NULL, GFP_KERNEL, ptr, false);
-               css_put(&mem->css);
+       ret = __mem_cgroup_try_charge(NULL, GFP_KERNEL, ptr, false);
+       css_put(&mem->css);/* drop extra refcnt */
+       if (ret || *ptr == NULL) {
+               if (PageAnon(page)) {
+                       lock_page_cgroup(pc);
+                       ClearPageCgroupMigration(pc);
+                       unlock_page_cgroup(pc);
+                       /*
+                        * The old page may be fully unmapped while we kept it.
+                        */
+                       mem_cgroup_uncharge_page(page);
+               }
+               return -ENOMEM;
        }
+       /*
+        * We charge new page before it's used/mapped. So, even if unlock_page()
+        * is called before end_migration, we can catch all events on this new
+        * page. In the case new page is migrated but not remapped, new page's
+        * mapcount will be finally 0 and we call uncharge in end_migration().
+        */
+       pc = lookup_page_cgroup(newpage);
+       if (PageAnon(page))
+               ctype = MEM_CGROUP_CHARGE_TYPE_MAPPED;
+       else if (page_is_file_cache(page))
+               ctype = MEM_CGROUP_CHARGE_TYPE_CACHE;
+       else
+               ctype = MEM_CGROUP_CHARGE_TYPE_SHMEM;
+       __mem_cgroup_commit_charge(mem, pc, ctype);
        return ret;
 }
 
 /* remove redundant charge if migration failed*/
 void mem_cgroup_end_migration(struct mem_cgroup *mem,
-               struct page *oldpage, struct page *newpage)
+       struct page *oldpage, struct page *newpage)
 {
-       struct page *target, *unused;
+       struct page *used, *unused;
        struct page_cgroup *pc;
-       enum charge_type ctype;
 
        if (!mem)
                return;
+       /* blocks rmdir() */
        cgroup_exclude_rmdir(&mem->css);
        /* at migration success, oldpage->mapping is NULL. */
        if (oldpage->mapping) {
-               target = oldpage;
-               unused = NULL;
+               used = oldpage;
+               unused = newpage;
        } else {
-               target = newpage;
+               used = newpage;
                unused = oldpage;
        }
-
-       if (PageAnon(target))
-               ctype = MEM_CGROUP_CHARGE_TYPE_MAPPED;
-       else if (page_is_file_cache(target))
-               ctype = MEM_CGROUP_CHARGE_TYPE_CACHE;
-       else
-               ctype = MEM_CGROUP_CHARGE_TYPE_SHMEM;
-
-       /* unused page is not on radix-tree now. */
-       if (unused)
-               __mem_cgroup_uncharge_common(unused, ctype);
-
-       pc = lookup_page_cgroup(target);
        /*
-        * __mem_cgroup_commit_charge() check PCG_USED bit of page_cgroup.
-        * So, double-counting is effectively avoided.
+        * We disallowed uncharge of pages under migration because mapcount
+        * of the page goes down to zero, temporarly.
+        * Clear the flag and check the page should be charged.
         */
-       __mem_cgroup_commit_charge(mem, pc, ctype);
+       pc = lookup_page_cgroup(oldpage);
+       lock_page_cgroup(pc);
+       ClearPageCgroupMigration(pc);
+       unlock_page_cgroup(pc);
+
+       if (unused != oldpage)
+               pc = lookup_page_cgroup(unused);
+       __mem_cgroup_uncharge_common(unused, MEM_CGROUP_CHARGE_TYPE_FORCE);
 
+       pc = lookup_page_cgroup(used);
        /*
-        * Both of oldpage and newpage are still under lock_page().
-        * Then, we don't have to care about race in radix-tree.
-        * But we have to be careful that this page is unmapped or not.
-        *
-        * There is a case for !page_mapped(). At the start of
-        * migration, oldpage was mapped. But now, it's zapped.
-        * But we know *target* page is not freed/reused under us.
-        * mem_cgroup_uncharge_page() does all necessary checks.
+        * If a page is a file cache, radix-tree replacement is very atomic
+        * and we can skip this check. When it was an Anon page, its mapcount
+        * goes down to 0. But because we added MIGRATION flage, it's not
+        * uncharged yet. There are several case but page->mapcount check
+        * and USED bit check in mem_cgroup_uncharge_page() will do enough
+        * check. (see prepare_charge() also)
         */
-       if (ctype == MEM_CGROUP_CHARGE_TYPE_MAPPED)
-               mem_cgroup_uncharge_page(target);
+       if (PageAnon(used))
+               mem_cgroup_uncharge_page(used);
        /*
-        * At migration, we may charge account against cgroup which has no tasks
+        * At migration, we may charge account against cgroup which has no
+        * tasks.
         * So, rmdir()->pre_destroy() can be called while we do this charge.
         * In that case, we need to call pre_destroy() again. check it here.
         */
@@ -2524,10 +2666,11 @@ static int mem_cgroup_resize_limit(struct mem_cgroup *memcg,
                                unsigned long long val)
 {
        int retry_count;
-       u64 memswlimit;
+       u64 memswlimit, memlimit;
        int ret = 0;
        int children = mem_cgroup_count_children(memcg);
        u64 curusage, oldusage;
+       int enlarge;
 
        /*
         * For keeping hierarchical_reclaim simple, how long we should retry
@@ -2538,6 +2681,7 @@ static int mem_cgroup_resize_limit(struct mem_cgroup *memcg,
 
        oldusage = res_counter_read_u64(&memcg->res, RES_USAGE);
 
+       enlarge = 0;
        while (retry_count) {
                if (signal_pending(current)) {
                        ret = -EINTR;
@@ -2555,6 +2699,11 @@ static int mem_cgroup_resize_limit(struct mem_cgroup *memcg,
                        mutex_unlock(&set_limit_mutex);
                        break;
                }
+
+               memlimit = res_counter_read_u64(&memcg->res, RES_LIMIT);
+               if (memlimit < val)
+                       enlarge = 1;
+
                ret = res_counter_set_limit(&memcg->res, val);
                if (!ret) {
                        if (memswlimit == val)
@@ -2576,6 +2725,8 @@ static int mem_cgroup_resize_limit(struct mem_cgroup *memcg,
                else
                        oldusage = curusage;
        }
+       if (!ret && enlarge)
+               memcg_oom_recover(memcg);
 
        return ret;
 }
@@ -2584,9 +2735,10 @@ static int mem_cgroup_resize_memsw_limit(struct mem_cgroup *memcg,
                                        unsigned long long val)
 {
        int retry_count;
-       u64 memlimit, oldusage, curusage;
+       u64 memlimit, memswlimit, oldusage, curusage;
        int children = mem_cgroup_count_children(memcg);
        int ret = -EBUSY;
+       int enlarge = 0;
 
        /* see mem_cgroup_resize_res_limit */
        retry_count = children * MEM_CGROUP_RECLAIM_RETRIES;
@@ -2608,6 +2760,9 @@ static int mem_cgroup_resize_memsw_limit(struct mem_cgroup *memcg,
                        mutex_unlock(&set_limit_mutex);
                        break;
                }
+               memswlimit = res_counter_read_u64(&memcg->memsw, RES_LIMIT);
+               if (memswlimit < val)
+                       enlarge = 1;
                ret = res_counter_set_limit(&memcg->memsw, val);
                if (!ret) {
                        if (memlimit == val)
@@ -2630,6 +2785,8 @@ static int mem_cgroup_resize_memsw_limit(struct mem_cgroup *memcg,
                else
                        oldusage = curusage;
        }
+       if (!ret && enlarge)
+               memcg_oom_recover(memcg);
        return ret;
 }
 
@@ -2821,6 +2978,7 @@ move_account:
                        if (ret)
                                break;
                }
+               memcg_oom_recover(mem);
                /* it seems parent cgroup doesn't have enough mem */
                if (ret == -ENOMEM)
                        goto try_to_free;
@@ -3311,9 +3469,9 @@ static void __mem_cgroup_threshold(struct mem_cgroup *memcg, bool swap)
 
        rcu_read_lock();
        if (!swap)
-               t = rcu_dereference(memcg->thresholds);
+               t = rcu_dereference(memcg->thresholds.primary);
        else
-               t = rcu_dereference(memcg->memsw_thresholds);
+               t = rcu_dereference(memcg->memsw_thresholds.primary);
 
        if (!t)
                goto unlock;
@@ -3325,7 +3483,7 @@ static void __mem_cgroup_threshold(struct mem_cgroup *memcg, bool swap)
         * If it's not true, a threshold was crossed after last
         * call of __mem_cgroup_threshold().
         */
-       i = atomic_read(&t->current_threshold);
+       i = t->current_threshold;
 
        /*
         * Iterate backward over array of thresholds starting from
@@ -3349,7 +3507,7 @@ static void __mem_cgroup_threshold(struct mem_cgroup *memcg, bool swap)
                eventfd_signal(t->entries[i].eventfd, 1);
 
        /* Update current_threshold */
-       atomic_set(&t->current_threshold, i - 1);
+       t->current_threshold = i - 1;
 unlock:
        rcu_read_unlock();
 }
@@ -3369,106 +3527,117 @@ static int compare_thresholds(const void *a, const void *b)
        return _a->threshold - _b->threshold;
 }
 
-static int mem_cgroup_register_event(struct cgroup *cgrp, struct cftype *cft,
-               struct eventfd_ctx *eventfd, const char *args)
+static int mem_cgroup_oom_notify_cb(struct mem_cgroup *mem, void *data)
+{
+       struct mem_cgroup_eventfd_list *ev;
+
+       list_for_each_entry(ev, &mem->oom_notify, list)
+               eventfd_signal(ev->eventfd, 1);
+       return 0;
+}
+
+static void mem_cgroup_oom_notify(struct mem_cgroup *mem)
+{
+       mem_cgroup_walk_tree(mem, NULL, mem_cgroup_oom_notify_cb);
+}
+
+static int mem_cgroup_usage_register_event(struct cgroup *cgrp,
+       struct cftype *cft, struct eventfd_ctx *eventfd, const char *args)
 {
        struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
-       struct mem_cgroup_threshold_ary *thresholds, *thresholds_new;
+       struct mem_cgroup_thresholds *thresholds;
+       struct mem_cgroup_threshold_ary *new;
        int type = MEMFILE_TYPE(cft->private);
        u64 threshold, usage;
-       int size;
-       int i, ret;
+       int i, size, ret;
 
        ret = res_counter_memparse_write_strategy(args, &threshold);
        if (ret)
                return ret;
 
        mutex_lock(&memcg->thresholds_lock);
+
        if (type == _MEM)
-               thresholds = memcg->thresholds;
+               thresholds = &memcg->thresholds;
        else if (type == _MEMSWAP)
-               thresholds = memcg->memsw_thresholds;
+               thresholds = &memcg->memsw_thresholds;
        else
                BUG();
 
        usage = mem_cgroup_usage(memcg, type == _MEMSWAP);
 
        /* Check if a threshold crossed before adding a new one */
-       if (thresholds)
+       if (thresholds->primary)
                __mem_cgroup_threshold(memcg, type == _MEMSWAP);
 
-       if (thresholds)
-               size = thresholds->size + 1;
-       else
-               size = 1;
+       size = thresholds->primary ? thresholds->primary->size + 1 : 1;
 
        /* Allocate memory for new array of thresholds */
-       thresholds_new = kmalloc(sizeof(*thresholds_new) +
-                       size * sizeof(struct mem_cgroup_threshold),
+       new = kmalloc(sizeof(*new) + size * sizeof(struct mem_cgroup_threshold),
                        GFP_KERNEL);
-       if (!thresholds_new) {
+       if (!new) {
                ret = -ENOMEM;
                goto unlock;
        }
-       thresholds_new->size = size;
+       new->size = size;
 
        /* Copy thresholds (if any) to new array */
-       if (thresholds)
-               memcpy(thresholds_new->entries, thresholds->entries,
-                               thresholds->size *
+       if (thresholds->primary) {
+               memcpy(new->entries, thresholds->primary->entries, (size - 1) *
                                sizeof(struct mem_cgroup_threshold));
+       }
+
        /* Add new threshold */
-       thresholds_new->entries[size - 1].eventfd = eventfd;
-       thresholds_new->entries[size - 1].threshold = threshold;
+       new->entries[size - 1].eventfd = eventfd;
+       new->entries[size - 1].threshold = threshold;
 
        /* Sort thresholds. Registering of new threshold isn't time-critical */
-       sort(thresholds_new->entries, size,
-                       sizeof(struct mem_cgroup_threshold),
+       sort(new->entries, size, sizeof(struct mem_cgroup_threshold),
                        compare_thresholds, NULL);
 
        /* Find current threshold */
-       atomic_set(&thresholds_new->current_threshold, -1);
+       new->current_threshold = -1;
        for (i = 0; i < size; i++) {
-               if (thresholds_new->entries[i].threshold < usage) {
+               if (new->entries[i].threshold < usage) {
                        /*
-                        * thresholds_new->current_threshold will not be used
-                        * until rcu_assign_pointer(), so it's safe to increment
+                        * new->current_threshold will not be used until
+                        * rcu_assign_pointer(), so it's safe to increment
                         * it here.
                         */
-                       atomic_inc(&thresholds_new->current_threshold);
+                       ++new->current_threshold;
                }
        }
 
-       if (type == _MEM)
-               rcu_assign_pointer(memcg->thresholds, thresholds_new);
-       else
-               rcu_assign_pointer(memcg->memsw_thresholds, thresholds_new);
+       /* Free old spare buffer and save old primary buffer as spare */
+       kfree(thresholds->spare);
+       thresholds->spare = thresholds->primary;
+
+       rcu_assign_pointer(thresholds->primary, new);
 
-       /* To be sure that nobody uses thresholds before freeing it */
+       /* To be sure that nobody uses thresholds */
        synchronize_rcu();
 
-       kfree(thresholds);
 unlock:
        mutex_unlock(&memcg->thresholds_lock);
 
        return ret;
 }
 
-static int mem_cgroup_unregister_event(struct cgroup *cgrp, struct cftype *cft,
-               struct eventfd_ctx *eventfd)
+static void mem_cgroup_usage_unregister_event(struct cgroup *cgrp,
+       struct cftype *cft, struct eventfd_ctx *eventfd)
 {
        struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
-       struct mem_cgroup_threshold_ary *thresholds, *thresholds_new;
+       struct mem_cgroup_thresholds *thresholds;
+       struct mem_cgroup_threshold_ary *new;
        int type = MEMFILE_TYPE(cft->private);
        u64 usage;
-       int size = 0;
-       int i, j, ret;
+       int i, j, size;
 
        mutex_lock(&memcg->thresholds_lock);
        if (type == _MEM)
-               thresholds = memcg->thresholds;
+               thresholds = &memcg->thresholds;
        else if (type == _MEMSWAP)
-               thresholds = memcg->memsw_thresholds;
+               thresholds = &memcg->memsw_thresholds;
        else
                BUG();
 
@@ -3484,59 +3653,136 @@ static int mem_cgroup_unregister_event(struct cgroup *cgrp, struct cftype *cft,
        __mem_cgroup_threshold(memcg, type == _MEMSWAP);
 
        /* Calculate new number of threshold */
-       for (i = 0; i < thresholds->size; i++) {
-               if (thresholds->entries[i].eventfd != eventfd)
+       size = 0;
+       for (i = 0; i < thresholds->primary->size; i++) {
+               if (thresholds->primary->entries[i].eventfd != eventfd)
                        size++;
        }
 
+       new = thresholds->spare;
+
        /* Set thresholds array to NULL if we don't have thresholds */
        if (!size) {
-               thresholds_new = NULL;
-               goto assign;
+               kfree(new);
+               new = NULL;
+               goto swap_buffers;
        }
 
-       /* Allocate memory for new array of thresholds */
-       thresholds_new = kmalloc(sizeof(*thresholds_new) +
-                       size * sizeof(struct mem_cgroup_threshold),
-                       GFP_KERNEL);
-       if (!thresholds_new) {
-               ret = -ENOMEM;
-               goto unlock;
-       }
-       thresholds_new->size = size;
+       new->size = size;
 
        /* Copy thresholds and find current threshold */
-       atomic_set(&thresholds_new->current_threshold, -1);
-       for (i = 0, j = 0; i < thresholds->size; i++) {
-               if (thresholds->entries[i].eventfd == eventfd)
+       new->current_threshold = -1;
+       for (i = 0, j = 0; i < thresholds->primary->size; i++) {
+               if (thresholds->primary->entries[i].eventfd == eventfd)
                        continue;
 
-               thresholds_new->entries[j] = thresholds->entries[i];
-               if (thresholds_new->entries[j].threshold < usage) {
+               new->entries[j] = thresholds->primary->entries[i];
+               if (new->entries[j].threshold < usage) {
                        /*
-                        * thresholds_new->current_threshold will not be used
+                        * new->current_threshold will not be used
                         * until rcu_assign_pointer(), so it's safe to increment
                         * it here.
                         */
-                       atomic_inc(&thresholds_new->current_threshold);
+                       ++new->current_threshold;
                }
                j++;
        }
 
-assign:
-       if (type == _MEM)
-               rcu_assign_pointer(memcg->thresholds, thresholds_new);
-       else
-               rcu_assign_pointer(memcg->memsw_thresholds, thresholds_new);
+swap_buffers:
+       /* Swap primary and spare array */
+       thresholds->spare = thresholds->primary;
+       rcu_assign_pointer(thresholds->primary, new);
 
-       /* To be sure that nobody uses thresholds before freeing it */
+       /* To be sure that nobody uses thresholds */
        synchronize_rcu();
 
-       kfree(thresholds);
-unlock:
        mutex_unlock(&memcg->thresholds_lock);
+}
 
-       return ret;
+static int mem_cgroup_oom_register_event(struct cgroup *cgrp,
+       struct cftype *cft, struct eventfd_ctx *eventfd, const char *args)
+{
+       struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
+       struct mem_cgroup_eventfd_list *event;
+       int type = MEMFILE_TYPE(cft->private);
+
+       BUG_ON(type != _OOM_TYPE);
+       event = kmalloc(sizeof(*event), GFP_KERNEL);
+       if (!event)
+               return -ENOMEM;
+
+       mutex_lock(&memcg_oom_mutex);
+
+       event->eventfd = eventfd;
+       list_add(&event->list, &memcg->oom_notify);
+
+       /* already in OOM ? */
+       if (atomic_read(&memcg->oom_lock))
+               eventfd_signal(eventfd, 1);
+       mutex_unlock(&memcg_oom_mutex);
+
+       return 0;
+}
+
+static void mem_cgroup_oom_unregister_event(struct cgroup *cgrp,
+       struct cftype *cft, struct eventfd_ctx *eventfd)
+{
+       struct mem_cgroup *mem = mem_cgroup_from_cont(cgrp);
+       struct mem_cgroup_eventfd_list *ev, *tmp;
+       int type = MEMFILE_TYPE(cft->private);
+
+       BUG_ON(type != _OOM_TYPE);
+
+       mutex_lock(&memcg_oom_mutex);
+
+       list_for_each_entry_safe(ev, tmp, &mem->oom_notify, list) {
+               if (ev->eventfd == eventfd) {
+                       list_del(&ev->list);
+                       kfree(ev);
+               }
+       }
+
+       mutex_unlock(&memcg_oom_mutex);
+}
+
+static int mem_cgroup_oom_control_read(struct cgroup *cgrp,
+       struct cftype *cft,  struct cgroup_map_cb *cb)
+{
+       struct mem_cgroup *mem = mem_cgroup_from_cont(cgrp);
+
+       cb->fill(cb, "oom_kill_disable", mem->oom_kill_disable);
+
+       if (atomic_read(&mem->oom_lock))
+               cb->fill(cb, "under_oom", 1);
+       else
+               cb->fill(cb, "under_oom", 0);
+       return 0;
+}
+
+/*
+ */
+static int mem_cgroup_oom_control_write(struct cgroup *cgrp,
+       struct cftype *cft, u64 val)
+{
+       struct mem_cgroup *mem = mem_cgroup_from_cont(cgrp);
+       struct mem_cgroup *parent;
+
+       /* cannot set to root cgroup and only 0 and 1 are allowed */
+       if (!cgrp->parent || !((val == 0) || (val == 1)))
+               return -EINVAL;
+
+       parent = mem_cgroup_from_cont(cgrp->parent);
+
+       cgroup_lock();
+       /* oom-kill-disable is a flag for subhierarchy. */
+       if ((parent->use_hierarchy) ||
+           (mem->use_hierarchy && !list_empty(&cgrp->children))) {
+               cgroup_unlock();
+               return -EINVAL;
+       }
+       mem->oom_kill_disable = val;
+       cgroup_unlock();
+       return 0;
 }
 
 static struct cftype mem_cgroup_files[] = {
@@ -3544,8 +3790,8 @@ static struct cftype mem_cgroup_files[] = {
                .name = "usage_in_bytes",
                .private = MEMFILE_PRIVATE(_MEM, RES_USAGE),
                .read_u64 = mem_cgroup_read,
-               .register_event = mem_cgroup_register_event,
-               .unregister_event = mem_cgroup_unregister_event,
+               .register_event = mem_cgroup_usage_register_event,
+               .unregister_event = mem_cgroup_usage_unregister_event,
        },
        {
                .name = "max_usage_in_bytes",
@@ -3594,6 +3840,14 @@ static struct cftype mem_cgroup_files[] = {
                .read_u64 = mem_cgroup_move_charge_read,
                .write_u64 = mem_cgroup_move_charge_write,
        },
+       {
+               .name = "oom_control",
+               .read_map = mem_cgroup_oom_control_read,
+               .write_u64 = mem_cgroup_oom_control_write,
+               .register_event = mem_cgroup_oom_register_event,
+               .unregister_event = mem_cgroup_oom_unregister_event,
+               .private = MEMFILE_PRIVATE(_OOM_TYPE, OOM_CONTROL),
+       },
 };
 
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
@@ -3602,8 +3856,8 @@ static struct cftype memsw_cgroup_files[] = {
                .name = "memsw.usage_in_bytes",
                .private = MEMFILE_PRIVATE(_MEMSWAP, RES_USAGE),
                .read_u64 = mem_cgroup_read,
-               .register_event = mem_cgroup_register_event,
-               .unregister_event = mem_cgroup_unregister_event,
+               .register_event = mem_cgroup_usage_register_event,
+               .unregister_event = mem_cgroup_usage_unregister_event,
        },
        {
                .name = "memsw.max_usage_in_bytes",
@@ -3831,6 +4085,7 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont)
        } else {
                parent = mem_cgroup_from_cont(cont->parent);
                mem->use_hierarchy = parent->use_hierarchy;
+               mem->oom_kill_disable = parent->oom_kill_disable;
        }
 
        if (parent && parent->use_hierarchy) {
@@ -3849,6 +4104,7 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont)
        }
        mem->last_scanned_child = 0;
        spin_lock_init(&mem->reclaim_param_lock);
+       INIT_LIST_HEAD(&mem->oom_notify);
 
        if (parent)
                mem->swappiness = get_swappiness(parent);
@@ -3976,6 +4232,80 @@ enum mc_target_type {
        MC_TARGET_SWAP,
 };
 
+static struct page *mc_handle_present_pte(struct vm_area_struct *vma,
+                                               unsigned long addr, pte_t ptent)
+{
+       struct page *page = vm_normal_page(vma, addr, ptent);
+
+       if (!page || !page_mapped(page))
+               return NULL;
+       if (PageAnon(page)) {
+               /* we don't move shared anon */
+               if (!move_anon() || page_mapcount(page) > 2)
+                       return NULL;
+       } else if (!move_file())
+               /* we ignore mapcount for file pages */
+               return NULL;
+       if (!get_page_unless_zero(page))
+               return NULL;
+
+       return page;
+}
+
+static struct page *mc_handle_swap_pte(struct vm_area_struct *vma,
+                       unsigned long addr, pte_t ptent, swp_entry_t *entry)
+{
+       int usage_count;
+       struct page *page = NULL;
+       swp_entry_t ent = pte_to_swp_entry(ptent);
+
+       if (!move_anon() || non_swap_entry(ent))
+               return NULL;
+       usage_count = mem_cgroup_count_swap_user(ent, &page);
+       if (usage_count > 1) { /* we don't move shared anon */
+               if (page)
+                       put_page(page);
+               return NULL;
+       }
+       if (do_swap_account)
+               entry->val = ent.val;
+
+       return page;
+}
+
+static struct page *mc_handle_file_pte(struct vm_area_struct *vma,
+                       unsigned long addr, pte_t ptent, swp_entry_t *entry)
+{
+       struct page *page = NULL;
+       struct inode *inode;
+       struct address_space *mapping;
+       pgoff_t pgoff;
+
+       if (!vma->vm_file) /* anonymous vma */
+               return NULL;
+       if (!move_file())
+               return NULL;
+
+       inode = vma->vm_file->f_path.dentry->d_inode;
+       mapping = vma->vm_file->f_mapping;
+       if (pte_none(ptent))
+               pgoff = linear_page_index(vma, addr);
+       else /* pte_file(ptent) is true */
+               pgoff = pte_to_pgoff(ptent);
+
+       /* page is moved even if it's not RSS of this task(page-faulted). */
+       if (!mapping_cap_swap_backed(mapping)) { /* normal file */
+               page = find_get_page(mapping, pgoff);
+       } else { /* shmem/tmpfs file. we should take account of swap too. */
+               swp_entry_t ent;
+               mem_cgroup_get_shmem_target(inode, pgoff, &page, &ent);
+               if (do_swap_account)
+                       entry->val = ent.val;
+       }
+
+       return page;
+}
+
 static int is_target_pte_for_mc(struct vm_area_struct *vma,
                unsigned long addr, pte_t ptent, union mc_target *target)
 {
@@ -3983,43 +4313,16 @@ static int is_target_pte_for_mc(struct vm_area_struct *vma,
        struct page_cgroup *pc;
        int ret = 0;
        swp_entry_t ent = { .val = 0 };
-       int usage_count = 0;
-       bool move_anon = test_bit(MOVE_CHARGE_TYPE_ANON,
-                                       &mc.to->move_charge_at_immigrate);
 
-       if (!pte_present(ptent)) {
-               /* TODO: handle swap of shmes/tmpfs */
-               if (pte_none(ptent) || pte_file(ptent))
-                       return 0;
-               else if (is_swap_pte(ptent)) {
-                       ent = pte_to_swp_entry(ptent);
-                       if (!move_anon || non_swap_entry(ent))
-                               return 0;
-                       usage_count = mem_cgroup_count_swap_user(ent, &page);
-               }
-       } else {
-               page = vm_normal_page(vma, addr, ptent);
-               if (!page || !page_mapped(page))
-                       return 0;
-               /*
-                * TODO: We don't move charges of file(including shmem/tmpfs)
-                * pages for now.
-                */
-               if (!move_anon || !PageAnon(page))
-                       return 0;
-               if (!get_page_unless_zero(page))
-                       return 0;
-               usage_count = page_mapcount(page);
-       }
-       if (usage_count > 1) {
-               /*
-                * TODO: We don't move charges of shared(used by multiple
-                * processes) pages for now.
-                */
-               if (page)
-                       put_page(page);
+       if (pte_present(ptent))
+               page = mc_handle_present_pte(vma, addr, ptent);
+       else if (is_swap_pte(ptent))
+               page = mc_handle_swap_pte(vma, addr, ptent, &ent);
+       else if (pte_none(ptent) || pte_file(ptent))
+               page = mc_handle_file_pte(vma, addr, ptent, &ent);
+
+       if (!page && !ent.val)
                return 0;
-       }
        if (page) {
                pc = lookup_page_cgroup(page);
                /*
@@ -4035,8 +4338,8 @@ static int is_target_pte_for_mc(struct vm_area_struct *vma,
                if (!ret || !target)
                        put_page(page);
        }
-       /* throught */
-       if (ent.val && do_swap_account && !ret &&
+       /* There is a swap entry and a page doesn't exist or isn't charged */
+       if (ent.val && !ret &&
                        css_id(&mc.from->css) == lookup_swap_cgroup(ent)) {
                ret = MC_TARGET_SWAP;
                if (target)
@@ -4077,9 +4380,6 @@ static unsigned long mem_cgroup_count_precharge(struct mm_struct *mm)
                };
                if (is_vm_hugetlb_page(vma))
                        continue;
-               /* TODO: We don't move charges of shmem/tmpfs pages for now. */
-               if (vma->vm_flags & VM_SHARED)
-                       continue;
                walk_page_range(vma->vm_start, vma->vm_end,
                                        &mem_cgroup_count_precharge_walk);
        }
@@ -4102,6 +4402,7 @@ static void mem_cgroup_clear_mc(void)
        if (mc.precharge) {
                __mem_cgroup_cancel_charge(mc.to, mc.precharge);
                mc.precharge = 0;
+               memcg_oom_recover(mc.to);
        }
        /*
         * we didn't uncharge from mc.from at mem_cgroup_move_account(), so
@@ -4110,6 +4411,7 @@ static void mem_cgroup_clear_mc(void)
        if (mc.moved_charge) {
                __mem_cgroup_cancel_charge(mc.from, mc.moved_charge);
                mc.moved_charge = 0;
+               memcg_oom_recover(mc.from);
        }
        /* we must fixup refcnts and charges */
        if (mc.moved_swap) {
@@ -4274,9 +4576,6 @@ static void mem_cgroup_move_charge(struct mm_struct *mm)
                };
                if (is_vm_hugetlb_page(vma))
                        continue;
-               /* TODO: We don't move charges of shmem/tmpfs pages for now. */
-               if (vma->vm_flags & VM_SHARED)
-                       continue;
                ret = walk_page_range(vma->vm_start, vma->vm_end,
                                                &mem_cgroup_move_charge_walk);
                if (ret)
index 833952d8b74d3a8ec8a3750bf664dba2d02671ed..119b7ccdf39b8ee542d3f4d695bff3c9d5322987 100644 (file)
@@ -1227,8 +1227,17 @@ int zap_vma_ptes(struct vm_area_struct *vma, unsigned long address,
 }
 EXPORT_SYMBOL_GPL(zap_vma_ptes);
 
-/*
- * Do a quick page-table lookup for a single page.
+/**
+ * follow_page - look up a page descriptor from a user-virtual address
+ * @vma: vm_area_struct mapping @address
+ * @address: virtual address to look up
+ * @flags: flags modifying lookup behaviour
+ *
+ * @flags can have FOLL_ flags set, defined in <linux/mm.h>
+ *
+ * Returns the mapped (struct page *), %NULL if no mapping exists, or
+ * an error pointer if there is a mapping to something not represented
+ * by a page descriptor (see also vm_normal_page()).
  */
 struct page *follow_page(struct vm_area_struct *vma, unsigned long address,
                        unsigned int flags)
index be211a582930d87bba2f959e2729399e364f6ae9..a4cfcdc00455de4be15fcec98c76e45f8de5feab 100644 (file)
@@ -415,12 +415,14 @@ int online_pages(unsigned long pfn, unsigned long nr_pages)
         * This means the page allocator ignores this zone.
         * So, zonelist must be updated after online.
         */
+       mutex_lock(&zonelists_mutex);
        if (!populated_zone(zone))
                need_zonelists_rebuild = 1;
 
        ret = walk_system_ram_range(pfn, nr_pages, &onlined_pages,
                online_pages_range);
        if (ret) {
+               mutex_unlock(&zonelists_mutex);
                printk(KERN_DEBUG "online_pages %lx at %lx failed\n",
                        nr_pages, pfn);
                memory_notify(MEM_CANCEL_ONLINE, &arg);
@@ -429,8 +431,12 @@ int online_pages(unsigned long pfn, unsigned long nr_pages)
 
        zone->present_pages += onlined_pages;
        zone->zone_pgdat->node_present_pages += onlined_pages;
+       if (need_zonelists_rebuild)
+               build_all_zonelists(zone);
+       else
+               zone_pcp_update(zone);
 
-       zone_pcp_update(zone);
+       mutex_unlock(&zonelists_mutex);
        setup_per_zone_wmarks();
        calculate_zone_inactive_ratio(zone);
        if (onlined_pages) {
@@ -438,10 +444,7 @@ int online_pages(unsigned long pfn, unsigned long nr_pages)
                node_set_state(zone_to_nid(zone), N_HIGH_MEMORY);
        }
 
-       if (need_zonelists_rebuild)
-               build_all_zonelists();
-       else
-               vm_total_pages = nr_free_pagecache_pages();
+       vm_total_pages = nr_free_pagecache_pages();
 
        writeback_set_ratelimit();
 
@@ -482,6 +485,29 @@ static void rollback_node_hotadd(int nid, pg_data_t *pgdat)
 }
 
 
+/*
+ * called by cpu_up() to online a node without onlined memory.
+ */
+int mem_online_node(int nid)
+{
+       pg_data_t       *pgdat;
+       int     ret;
+
+       lock_system_sleep();
+       pgdat = hotadd_new_pgdat(nid, 0);
+       if (pgdat) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       node_set_online(nid);
+       ret = register_one_node(nid);
+       BUG_ON(ret);
+
+out:
+       unlock_system_sleep();
+       return ret;
+}
+
 /* we are OK calling __meminit stuff here - we have CONFIG_MEMORY_HOTPLUG */
 int __ref add_memory(int nid, u64 start, u64 size)
 {
index 08f40a2f3fe0aef1819636d5983b3242758463e9..5d6fb339de038945424733d5128846a1a1a7e352 100644 (file)
@@ -119,7 +119,22 @@ struct mempolicy default_policy = {
 
 static const struct mempolicy_operations {
        int (*create)(struct mempolicy *pol, const nodemask_t *nodes);
-       void (*rebind)(struct mempolicy *pol, const nodemask_t *nodes);
+       /*
+        * If read-side task has no lock to protect task->mempolicy, write-side
+        * task will rebind the task->mempolicy by two step. The first step is
+        * setting all the newly nodes, and the second step is cleaning all the
+        * disallowed nodes. In this way, we can avoid finding no node to alloc
+        * page.
+        * If we have a lock to protect task->mempolicy in read-side, we do
+        * rebind directly.
+        *
+        * step:
+        *      MPOL_REBIND_ONCE - do rebind work at once
+        *      MPOL_REBIND_STEP1 - set all the newly nodes
+        *      MPOL_REBIND_STEP2 - clean all the disallowed nodes
+        */
+       void (*rebind)(struct mempolicy *pol, const nodemask_t *nodes,
+                       enum mpol_rebind_step step);
 } mpol_ops[MPOL_MAX];
 
 /* Check that the nodemask contains at least one populated zone */
@@ -127,9 +142,6 @@ static int is_valid_nodemask(const nodemask_t *nodemask)
 {
        int nd, k;
 
-       /* Check that there is something useful in this mask */
-       k = policy_zone;
-
        for_each_node_mask(nd, *nodemask) {
                struct zone *z;
 
@@ -145,7 +157,7 @@ static int is_valid_nodemask(const nodemask_t *nodemask)
 
 static inline int mpol_store_user_nodemask(const struct mempolicy *pol)
 {
-       return pol->flags & (MPOL_F_STATIC_NODES | MPOL_F_RELATIVE_NODES);
+       return pol->flags & MPOL_MODE_FLAGS;
 }
 
 static void mpol_relative_nodemask(nodemask_t *ret, const nodemask_t *orig,
@@ -277,12 +289,19 @@ void __mpol_put(struct mempolicy *p)
        kmem_cache_free(policy_cache, p);
 }
 
-static void mpol_rebind_default(struct mempolicy *pol, const nodemask_t *nodes)
+static void mpol_rebind_default(struct mempolicy *pol, const nodemask_t *nodes,
+                               enum mpol_rebind_step step)
 {
 }
 
-static void mpol_rebind_nodemask(struct mempolicy *pol,
-                                const nodemask_t *nodes)
+/*
+ * step:
+ *     MPOL_REBIND_ONCE  - do rebind work at once
+ *     MPOL_REBIND_STEP1 - set all the newly nodes
+ *     MPOL_REBIND_STEP2 - clean all the disallowed nodes
+ */
+static void mpol_rebind_nodemask(struct mempolicy *pol, const nodemask_t *nodes,
+                                enum mpol_rebind_step step)
 {
        nodemask_t tmp;
 
@@ -291,12 +310,31 @@ static void mpol_rebind_nodemask(struct mempolicy *pol,
        else if (pol->flags & MPOL_F_RELATIVE_NODES)
                mpol_relative_nodemask(&tmp, &pol->w.user_nodemask, nodes);
        else {
-               nodes_remap(tmp, pol->v.nodes, pol->w.cpuset_mems_allowed,
-                           *nodes);
-               pol->w.cpuset_mems_allowed = *nodes;
+               /*
+                * if step == 1, we use ->w.cpuset_mems_allowed to cache the
+                * result
+                */
+               if (step == MPOL_REBIND_ONCE || step == MPOL_REBIND_STEP1) {
+                       nodes_remap(tmp, pol->v.nodes,
+                                       pol->w.cpuset_mems_allowed, *nodes);
+                       pol->w.cpuset_mems_allowed = step ? tmp : *nodes;
+               } else if (step == MPOL_REBIND_STEP2) {
+                       tmp = pol->w.cpuset_mems_allowed;
+                       pol->w.cpuset_mems_allowed = *nodes;
+               } else
+                       BUG();
        }
 
-       pol->v.nodes = tmp;
+       if (nodes_empty(tmp))
+               tmp = *nodes;
+
+       if (step == MPOL_REBIND_STEP1)
+               nodes_or(pol->v.nodes, pol->v.nodes, tmp);
+       else if (step == MPOL_REBIND_ONCE || step == MPOL_REBIND_STEP2)
+               pol->v.nodes = tmp;
+       else
+               BUG();
+
        if (!node_isset(current->il_next, tmp)) {
                current->il_next = next_node(current->il_next, tmp);
                if (current->il_next >= MAX_NUMNODES)
@@ -307,7 +345,8 @@ static void mpol_rebind_nodemask(struct mempolicy *pol,
 }
 
 static void mpol_rebind_preferred(struct mempolicy *pol,
-                                 const nodemask_t *nodes)
+                                 const nodemask_t *nodes,
+                                 enum mpol_rebind_step step)
 {
        nodemask_t tmp;
 
@@ -330,16 +369,45 @@ static void mpol_rebind_preferred(struct mempolicy *pol,
        }
 }
 
-/* Migrate a policy to a different set of nodes */
-static void mpol_rebind_policy(struct mempolicy *pol,
-                              const nodemask_t *newmask)
+/*
+ * mpol_rebind_policy - Migrate a policy to a different set of nodes
+ *
+ * If read-side task has no lock to protect task->mempolicy, write-side
+ * task will rebind the task->mempolicy by two step. The first step is
+ * setting all the newly nodes, and the second step is cleaning all the
+ * disallowed nodes. In this way, we can avoid finding no node to alloc
+ * page.
+ * If we have a lock to protect task->mempolicy in read-side, we do
+ * rebind directly.
+ *
+ * step:
+ *     MPOL_REBIND_ONCE  - do rebind work at once
+ *     MPOL_REBIND_STEP1 - set all the newly nodes
+ *     MPOL_REBIND_STEP2 - clean all the disallowed nodes
+ */
+static void mpol_rebind_policy(struct mempolicy *pol, const nodemask_t *newmask,
+                               enum mpol_rebind_step step)
 {
        if (!pol)
                return;
-       if (!mpol_store_user_nodemask(pol) &&
+       if (!mpol_store_user_nodemask(pol) && step == 0 &&
            nodes_equal(pol->w.cpuset_mems_allowed, *newmask))
                return;
-       mpol_ops[pol->mode].rebind(pol, newmask);
+
+       if (step == MPOL_REBIND_STEP1 && (pol->flags & MPOL_F_REBINDING))
+               return;
+
+       if (step == MPOL_REBIND_STEP2 && !(pol->flags & MPOL_F_REBINDING))
+               BUG();
+
+       if (step == MPOL_REBIND_STEP1)
+               pol->flags |= MPOL_F_REBINDING;
+       else if (step == MPOL_REBIND_STEP2)
+               pol->flags &= ~MPOL_F_REBINDING;
+       else if (step >= MPOL_REBIND_NSTEP)
+               BUG();
+
+       mpol_ops[pol->mode].rebind(pol, newmask, step);
 }
 
 /*
@@ -349,9 +417,10 @@ static void mpol_rebind_policy(struct mempolicy *pol,
  * Called with task's alloc_lock held.
  */
 
-void mpol_rebind_task(struct task_struct *tsk, const nodemask_t *new)
+void mpol_rebind_task(struct task_struct *tsk, const nodemask_t *new,
+                       enum mpol_rebind_step step)
 {
-       mpol_rebind_policy(tsk->mempolicy, new);
+       mpol_rebind_policy(tsk->mempolicy, new, step);
 }
 
 /*
@@ -366,7 +435,7 @@ void mpol_rebind_mm(struct mm_struct *mm, nodemask_t *new)
 
        down_write(&mm->mmap_sem);
        for (vma = mm->mmap; vma; vma = vma->vm_next)
-               mpol_rebind_policy(vma->vm_policy, new);
+               mpol_rebind_policy(vma->vm_policy, new, MPOL_REBIND_ONCE);
        up_write(&mm->mmap_sem);
 }
 
@@ -859,7 +928,7 @@ static int migrate_to_node(struct mm_struct *mm, int source, int dest,
        nodes_clear(nmask);
        node_set(source, nmask);
 
-       check_range(mm, mm->mmap->vm_start, TASK_SIZE, &nmask,
+       check_range(mm, mm->mmap->vm_start, mm->task_size, &nmask,
                        flags | MPOL_MF_DISCONTIG_OK, &pagelist);
 
        if (!list_empty(&pagelist))
@@ -1444,15 +1513,13 @@ static struct zonelist *policy_zonelist(gfp_t gfp, struct mempolicy *policy)
                /*
                 * Normally, MPOL_BIND allocations are node-local within the
                 * allowed nodemask.  However, if __GFP_THISNODE is set and the
-                * current node is part of the mask, we use the zonelist for
+                * current node isn't part of the mask, we use the zonelist for
                 * the first node in the mask instead.
                 */
                if (unlikely(gfp & __GFP_THISNODE) &&
                                unlikely(!node_isset(nd, policy->v.nodes)))
                        nd = first_node(policy->v.nodes);
                break;
-       case MPOL_INTERLEAVE: /* should not happen */
-               break;
        default:
                BUG();
        }
@@ -1572,6 +1639,8 @@ static inline unsigned interleave_nid(struct mempolicy *pol,
  * to the struct mempolicy for conditional unref after allocation.
  * If the effective policy is 'BIND, returns a pointer to the mempolicy's
  * @nodemask for filtering the zonelist.
+ *
+ * Must be protected by get_mems_allowed()
  */
 struct zonelist *huge_zonelist(struct vm_area_struct *vma, unsigned long addr,
                                gfp_t gfp_flags, struct mempolicy **mpol,
@@ -1617,6 +1686,7 @@ bool init_nodemask_of_mempolicy(nodemask_t *mask)
        if (!(mask && current->mempolicy))
                return false;
 
+       task_lock(current);
        mempolicy = current->mempolicy;
        switch (mempolicy->mode) {
        case MPOL_PREFERRED:
@@ -1636,6 +1706,7 @@ bool init_nodemask_of_mempolicy(nodemask_t *mask)
        default:
                BUG();
        }
+       task_unlock(current);
 
        return true;
 }
@@ -1683,13 +1754,17 @@ alloc_page_vma(gfp_t gfp, struct vm_area_struct *vma, unsigned long addr)
 {
        struct mempolicy *pol = get_vma_policy(current, vma, addr);
        struct zonelist *zl;
+       struct page *page;
 
+       get_mems_allowed();
        if (unlikely(pol->mode == MPOL_INTERLEAVE)) {
                unsigned nid;
 
                nid = interleave_nid(pol, vma, addr, PAGE_SHIFT);
                mpol_cond_put(pol);
-               return alloc_page_interleave(gfp, 0, nid);
+               page = alloc_page_interleave(gfp, 0, nid);
+               put_mems_allowed();
+               return page;
        }
        zl = policy_zonelist(gfp, pol);
        if (unlikely(mpol_needs_cond_ref(pol))) {
@@ -1699,12 +1774,15 @@ alloc_page_vma(gfp_t gfp, struct vm_area_struct *vma, unsigned long addr)
                struct page *page =  __alloc_pages_nodemask(gfp, 0,
                                                zl, policy_nodemask(gfp, pol));
                __mpol_put(pol);
+               put_mems_allowed();
                return page;
        }
        /*
         * fast path:  default or task policy
         */
-       return __alloc_pages_nodemask(gfp, 0, zl, policy_nodemask(gfp, pol));
+       page = __alloc_pages_nodemask(gfp, 0, zl, policy_nodemask(gfp, pol));
+       put_mems_allowed();
+       return page;
 }
 
 /**
@@ -1729,18 +1807,23 @@ alloc_page_vma(gfp_t gfp, struct vm_area_struct *vma, unsigned long addr)
 struct page *alloc_pages_current(gfp_t gfp, unsigned order)
 {
        struct mempolicy *pol = current->mempolicy;
+       struct page *page;
 
        if (!pol || in_interrupt() || (gfp & __GFP_THISNODE))
                pol = &default_policy;
 
+       get_mems_allowed();
        /*
         * No reference counting needed for current->mempolicy
         * nor system default_policy
         */
        if (pol->mode == MPOL_INTERLEAVE)
-               return alloc_page_interleave(gfp, order, interleave_nodes(pol));
-       return __alloc_pages_nodemask(gfp, order,
+               page = alloc_page_interleave(gfp, order, interleave_nodes(pol));
+       else
+               page = __alloc_pages_nodemask(gfp, order,
                        policy_zonelist(gfp, pol), policy_nodemask(gfp, pol));
+       put_mems_allowed();
+       return page;
 }
 EXPORT_SYMBOL(alloc_pages_current);
 
@@ -1750,6 +1833,9 @@ EXPORT_SYMBOL(alloc_pages_current);
  * with the mems_allowed returned by cpuset_mems_allowed().  This
  * keeps mempolicies cpuset relative after its cpuset moves.  See
  * further kernel/cpuset.c update_nodemask().
+ *
+ * current's mempolicy may be rebinded by the other task(the task that changes
+ * cpuset's mems), so we needn't do rebind work for current task.
  */
 
 /* Slow path of a mempolicy duplicate */
@@ -1759,13 +1845,24 @@ struct mempolicy *__mpol_dup(struct mempolicy *old)
 
        if (!new)
                return ERR_PTR(-ENOMEM);
+
+       /* task's mempolicy is protected by alloc_lock */
+       if (old == current->mempolicy) {
+               task_lock(current);
+               *new = *old;
+               task_unlock(current);
+       } else
+               *new = *old;
+
        rcu_read_lock();
        if (current_cpuset_is_being_rebound()) {
                nodemask_t mems = cpuset_mems_allowed(current);
-               mpol_rebind_policy(old, &mems);
+               if (new->flags & MPOL_F_REBINDING)
+                       mpol_rebind_policy(new, &mems, MPOL_REBIND_STEP2);
+               else
+                       mpol_rebind_policy(new, &mems, MPOL_REBIND_ONCE);
        }
        rcu_read_unlock();
-       *new = *old;
        atomic_set(&new->refcnt, 1);
        return new;
 }
@@ -1792,16 +1889,6 @@ struct mempolicy *__mpol_cond_copy(struct mempolicy *tompol,
        return tompol;
 }
 
-static int mpol_match_intent(const struct mempolicy *a,
-                            const struct mempolicy *b)
-{
-       if (a->flags != b->flags)
-               return 0;
-       if (!mpol_store_user_nodemask(a))
-               return 1;
-       return nodes_equal(a->w.user_nodemask, b->w.user_nodemask);
-}
-
 /* Slow path of a mempolicy comparison */
 int __mpol_equal(struct mempolicy *a, struct mempolicy *b)
 {
@@ -1809,8 +1896,12 @@ int __mpol_equal(struct mempolicy *a, struct mempolicy *b)
                return 0;
        if (a->mode != b->mode)
                return 0;
-       if (a->mode != MPOL_DEFAULT && !mpol_match_intent(a, b))
+       if (a->flags != b->flags)
                return 0;
+       if (mpol_store_user_nodemask(a))
+               if (!nodes_equal(a->w.user_nodemask, b->w.user_nodemask))
+                       return 0;
+
        switch (a->mode) {
        case MPOL_BIND:
                /* Fall through */
@@ -2006,27 +2097,24 @@ void mpol_shared_policy_init(struct shared_policy *sp, struct mempolicy *mpol)
                        return;
                /* contextualize the tmpfs mount point mempolicy */
                new = mpol_new(mpol->mode, mpol->flags, &mpol->w.user_nodemask);
-               if (IS_ERR(new)) {
-                       mpol_put(mpol); /* drop our ref on sb mpol */
-                       NODEMASK_SCRATCH_FREE(scratch);
-                       return;         /* no valid nodemask intersection */
-               }
+               if (IS_ERR(new))
+                       goto free_scratch; /* no valid nodemask intersection */
 
                task_lock(current);
                ret = mpol_set_nodemask(new, &mpol->w.user_nodemask, scratch);
                task_unlock(current);
                mpol_put(mpol); /* drop our ref on sb mpol */
-               if (ret) {
-                       NODEMASK_SCRATCH_FREE(scratch);
-                       mpol_put(new);
-                       return;
-               }
+               if (ret)
+                       goto put_free;
 
                /* Create pseudo-vma that contains just the policy */
                memset(&pvma, 0, sizeof(struct vm_area_struct));
                pvma.vm_end = TASK_SIZE;        /* policy covers entire file */
                mpol_set_shared_policy(sp, &pvma, new); /* adds ref */
+
+put_free:
                mpol_put(new);                  /* drop initial ref */
+free_scratch:
                NODEMASK_SCRATCH_FREE(scratch);
        }
 }
@@ -2132,9 +2220,15 @@ void numa_default_policy(void)
  * "local" is pseudo-policy:  MPOL_PREFERRED with MPOL_F_LOCAL flag
  * Used only for mpol_parse_str() and mpol_to_str()
  */
-#define MPOL_LOCAL (MPOL_INTERLEAVE + 1)
-static const char * const policy_types[] =
-       { "default", "prefer", "bind", "interleave", "local" };
+#define MPOL_LOCAL MPOL_MAX
+static const char * const policy_modes[] =
+{
+       [MPOL_DEFAULT]    = "default",
+       [MPOL_PREFERRED]  = "prefer",
+       [MPOL_BIND]       = "bind",
+       [MPOL_INTERLEAVE] = "interleave",
+       [MPOL_LOCAL]      = "local"
+};
 
 
 #ifdef CONFIG_TMPFS
@@ -2159,12 +2253,11 @@ static const char * const policy_types[] =
 int mpol_parse_str(char *str, struct mempolicy **mpol, int no_context)
 {
        struct mempolicy *new = NULL;
-       unsigned short uninitialized_var(mode);
+       unsigned short mode;
        unsigned short uninitialized_var(mode_flags);
        nodemask_t nodes;
        char *nodelist = strchr(str, ':');
        char *flags = strchr(str, '=');
-       int i;
        int err = 1;
 
        if (nodelist) {
@@ -2180,13 +2273,12 @@ int mpol_parse_str(char *str, struct mempolicy **mpol, int no_context)
        if (flags)
                *flags++ = '\0';        /* terminate mode string */
 
-       for (i = 0; i <= MPOL_LOCAL; i++) {
-               if (!strcmp(str, policy_types[i])) {
-                       mode = i;
+       for (mode = 0; mode <= MPOL_LOCAL; mode++) {
+               if (!strcmp(str, policy_modes[mode])) {
                        break;
                }
        }
-       if (i > MPOL_LOCAL)
+       if (mode > MPOL_LOCAL)
                goto out;
 
        switch (mode) {
@@ -2250,7 +2342,10 @@ int mpol_parse_str(char *str, struct mempolicy **mpol, int no_context)
        if (IS_ERR(new))
                goto out;
 
-       {
+       if (no_context) {
+               /* save for contextualization */
+               new->w.user_nodemask = nodes;
+       } else {
                int ret;
                NODEMASK_SCRATCH(scratch);
                if (scratch) {
@@ -2266,10 +2361,6 @@ int mpol_parse_str(char *str, struct mempolicy **mpol, int no_context)
                }
        }
        err = 0;
-       if (no_context) {
-               /* save for contextualization */
-               new->w.user_nodemask = nodes;
-       }
 
 out:
        /* Restore string for error message */
@@ -2338,11 +2429,11 @@ int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol, int no_context)
                BUG();
        }
 
-       l = strlen(policy_types[mode]);
+       l = strlen(policy_modes[mode]);
        if (buffer + maxlen < p + l + 1)
                return -ENOSPC;
 
-       strcpy(p, policy_types[mode]);
+       strcpy(p, policy_modes[mode]);
        p += l;
 
        if (flags & MPOL_MODE_FLAGS) {
index d3f3f7f81075eb1eb2e7f5dbe2c0f292a489dacf..4205b1d6049ed2f6a07da22c0a100d52d6ccd0f8 100644 (file)
@@ -40,7 +40,8 @@
 
 /*
  * migrate_prep() needs to be called before we start compiling a list of pages
- * to be migrated using isolate_lru_page().
+ * to be migrated using isolate_lru_page(). If scheduling work on other CPUs is
+ * undesirable, use migrate_prep_local()
  */
 int migrate_prep(void)
 {
@@ -55,26 +56,29 @@ int migrate_prep(void)
        return 0;
 }
 
+/* Do the necessary work of migrate_prep but not if it involves other CPUs */
+int migrate_prep_local(void)
+{
+       lru_add_drain();
+
+       return 0;
+}
+
 /*
  * Add isolated pages on the list back to the LRU under page lock
  * to avoid leaking evictable pages back onto unevictable list.
- *
- * returns the number of pages put back.
  */
-int putback_lru_pages(struct list_head *l)
+void putback_lru_pages(struct list_head *l)
 {
        struct page *page;
        struct page *page2;
-       int count = 0;
 
        list_for_each_entry_safe(page, page2, l, lru) {
                list_del(&page->lru);
                dec_zone_page_state(page, NR_ISOLATED_ANON +
                                page_is_file_cache(page));
                putback_lru_page(page);
-               count++;
        }
-       return count;
 }
 
 /*
@@ -490,7 +494,8 @@ static int fallback_migrate_page(struct address_space *mapping,
  *   < 0 - error code
  *  == 0 - success
  */
-static int move_to_new_page(struct page *newpage, struct page *page)
+static int move_to_new_page(struct page *newpage, struct page *page,
+                                               int remap_swapcache)
 {
        struct address_space *mapping;
        int rc;
@@ -525,10 +530,12 @@ static int move_to_new_page(struct page *newpage, struct page *page)
        else
                rc = fallback_migrate_page(mapping, newpage, page);
 
-       if (!rc)
-               remove_migration_ptes(page, newpage);
-       else
+       if (rc) {
                newpage->mapping = NULL;
+       } else {
+               if (remap_swapcache)
+                       remove_migration_ptes(page, newpage);
+       }
 
        unlock_page(newpage);
 
@@ -545,9 +552,11 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
        int rc = 0;
        int *result = NULL;
        struct page *newpage = get_new_page(page, private, &result);
+       int remap_swapcache = 1;
        int rcu_locked = 0;
        int charge = 0;
        struct mem_cgroup *mem = NULL;
+       struct anon_vma *anon_vma = NULL;
 
        if (!newpage)
                return -ENOMEM;
@@ -581,7 +590,7 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
        }
 
        /* charge against new page */
-       charge = mem_cgroup_prepare_migration(page, &mem);
+       charge = mem_cgroup_prepare_migration(page, newpage, &mem);
        if (charge == -ENOMEM) {
                rc = -ENOMEM;
                goto unlock;
@@ -604,6 +613,34 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
        if (PageAnon(page)) {
                rcu_read_lock();
                rcu_locked = 1;
+
+               /* Determine how to safely use anon_vma */
+               if (!page_mapped(page)) {
+                       if (!PageSwapCache(page))
+                               goto rcu_unlock;
+
+                       /*
+                        * We cannot be sure that the anon_vma of an unmapped
+                        * swapcache page is safe to use because we don't
+                        * know in advance if the VMA that this page belonged
+                        * to still exists. If the VMA and others sharing the
+                        * data have been freed, then the anon_vma could
+                        * already be invalid.
+                        *
+                        * To avoid this possibility, swapcache pages get
+                        * migrated but are not remapped when migration
+                        * completes
+                        */
+                       remap_swapcache = 0;
+               } else {
+                       /*
+                        * Take a reference count on the anon_vma if the
+                        * page is mapped so that it is guaranteed to
+                        * exist when the page is remapped later
+                        */
+                       anon_vma = page_anon_vma(page);
+                       atomic_inc(&anon_vma->external_refcount);
+               }
        }
 
        /*
@@ -638,11 +675,20 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
 
 skip_unmap:
        if (!page_mapped(page))
-               rc = move_to_new_page(newpage, page);
+               rc = move_to_new_page(newpage, page, remap_swapcache);
 
-       if (rc)
+       if (rc && remap_swapcache)
                remove_migration_ptes(page, page);
 rcu_unlock:
+
+       /* Drop an anon_vma reference if we took one */
+       if (anon_vma && atomic_dec_and_lock(&anon_vma->external_refcount, &anon_vma->lock)) {
+               int empty = list_empty(&anon_vma->head);
+               spin_unlock(&anon_vma->lock);
+               if (empty)
+                       anon_vma_free(anon_vma);
+       }
+
        if (rcu_locked)
                rcu_read_unlock();
 uncharge:
index f77433c20279d95c2a87ce7117888e63580c8922..9ac42dc6d7b61481b1eedb8e12b463bd151b1f92 100644 (file)
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
+static void mincore_hugetlb_page_range(struct vm_area_struct *vma,
+                               unsigned long addr, unsigned long end,
+                               unsigned char *vec)
+{
+#ifdef CONFIG_HUGETLB_PAGE
+       struct hstate *h;
+
+       h = hstate_vma(vma);
+       while (1) {
+               unsigned char present;
+               pte_t *ptep;
+               /*
+                * Huge pages are always in RAM for now, but
+                * theoretically it needs to be checked.
+                */
+               ptep = huge_pte_offset(current->mm,
+                                      addr & huge_page_mask(h));
+               present = ptep && !huge_pte_none(huge_ptep_get(ptep));
+               while (1) {
+                       *vec = present;
+                       vec++;
+                       addr += PAGE_SIZE;
+                       if (addr == end)
+                               return;
+                       /* check hugepage border */
+                       if (!(addr & ~huge_page_mask(h)))
+                               break;
+               }
+       }
+#else
+       BUG();
+#endif
+}
+
 /*
  * Later we can get more picky about what "in core" means precisely.
  * For now, simply check to see if the page is in the page cache,
@@ -49,145 +83,150 @@ static unsigned char mincore_page(struct address_space *mapping, pgoff_t pgoff)
        return present;
 }
 
-/*
- * Do a chunk of "sys_mincore()". We've already checked
- * all the arguments, we hold the mmap semaphore: we should
- * just return the amount of info we're asked for.
- */
-static long do_mincore(unsigned long addr, unsigned char *vec, unsigned long pages)
+static void mincore_unmapped_range(struct vm_area_struct *vma,
+                               unsigned long addr, unsigned long end,
+                               unsigned char *vec)
 {
-       pgd_t *pgd;
-       pud_t *pud;
-       pmd_t *pmd;
-       pte_t *ptep;
-       spinlock_t *ptl;
-       unsigned long nr;
+       unsigned long nr = (end - addr) >> PAGE_SHIFT;
        int i;
-       pgoff_t pgoff;
-       struct vm_area_struct *vma = find_vma(current->mm, addr);
 
-       /*
-        * find_vma() didn't find anything above us, or we're
-        * in an unmapped hole in the address space: ENOMEM.
-        */
-       if (!vma || addr < vma->vm_start)
-               return -ENOMEM;
-
-#ifdef CONFIG_HUGETLB_PAGE
-       if (is_vm_hugetlb_page(vma)) {
-               struct hstate *h;
-               unsigned long nr_huge;
-               unsigned char present;
+       if (vma->vm_file) {
+               pgoff_t pgoff;
 
-               i = 0;
-               nr = min(pages, (vma->vm_end - addr) >> PAGE_SHIFT);
-               h = hstate_vma(vma);
-               nr_huge = ((addr + pages * PAGE_SIZE - 1) >> huge_page_shift(h))
-                         - (addr >> huge_page_shift(h)) + 1;
-               nr_huge = min(nr_huge,
-                             (vma->vm_end - addr) >> huge_page_shift(h));
-               while (1) {
-                       /* hugepage always in RAM for now,
-                        * but generally it needs to be check */
-                       ptep = huge_pte_offset(current->mm,
-                                              addr & huge_page_mask(h));
-                       present = !!(ptep &&
-                                    !huge_pte_none(huge_ptep_get(ptep)));
-                       while (1) {
-                               vec[i++] = present;
-                               addr += PAGE_SIZE;
-                               /* reach buffer limit */
-                               if (i == nr)
-                                       return nr;
-                               /* check hugepage border */
-                               if (!((addr & ~huge_page_mask(h))
-                                     >> PAGE_SHIFT))
-                                       break;
-                       }
-               }
-               return nr;
+               pgoff = linear_page_index(vma, addr);
+               for (i = 0; i < nr; i++, pgoff++)
+                       vec[i] = mincore_page(vma->vm_file->f_mapping, pgoff);
+       } else {
+               for (i = 0; i < nr; i++)
+                       vec[i] = 0;
        }
-#endif
-
-       /*
-        * Calculate how many pages there are left in the last level of the
-        * PTE array for our address.
-        */
-       nr = PTRS_PER_PTE - ((addr >> PAGE_SHIFT) & (PTRS_PER_PTE-1));
-
-       /*
-        * Don't overrun this vma
-        */
-       nr = min(nr, (vma->vm_end - addr) >> PAGE_SHIFT);
-
-       /*
-        * Don't return more than the caller asked for
-        */
-       nr = min(nr, pages);
+}
 
-       pgd = pgd_offset(vma->vm_mm, addr);
-       if (pgd_none_or_clear_bad(pgd))
-               goto none_mapped;
-       pud = pud_offset(pgd, addr);
-       if (pud_none_or_clear_bad(pud))
-               goto none_mapped;
-       pmd = pmd_offset(pud, addr);
-       if (pmd_none_or_clear_bad(pmd))
-               goto none_mapped;
+static void mincore_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
+                       unsigned long addr, unsigned long end,
+                       unsigned char *vec)
+{
+       unsigned long next;
+       spinlock_t *ptl;
+       pte_t *ptep;
 
        ptep = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
-       for (i = 0; i < nr; i++, ptep++, addr += PAGE_SIZE) {
-               unsigned char present;
+       do {
                pte_t pte = *ptep;
+               pgoff_t pgoff;
 
-               if (pte_present(pte)) {
-                       present = 1;
-
-               } else if (pte_none(pte)) {
-                       if (vma->vm_file) {
-                               pgoff = linear_page_index(vma, addr);
-                               present = mincore_page(vma->vm_file->f_mapping,
-                                                       pgoff);
-                       } else
-                               present = 0;
-
-               } else if (pte_file(pte)) {
+               next = addr + PAGE_SIZE;
+               if (pte_none(pte))
+                       mincore_unmapped_range(vma, addr, next, vec);
+               else if (pte_present(pte))
+                       *vec = 1;
+               else if (pte_file(pte)) {
                        pgoff = pte_to_pgoff(pte);
-                       present = mincore_page(vma->vm_file->f_mapping, pgoff);
-
+                       *vec = mincore_page(vma->vm_file->f_mapping, pgoff);
                } else { /* pte is a swap entry */
                        swp_entry_t entry = pte_to_swp_entry(pte);
+
                        if (is_migration_entry(entry)) {
                                /* migration entries are always uptodate */
-                               present = 1;
+                               *vec = 1;
                        } else {
 #ifdef CONFIG_SWAP
                                pgoff = entry.val;
-                               present = mincore_page(&swapper_space, pgoff);
+                               *vec = mincore_page(&swapper_space, pgoff);
 #else
                                WARN_ON(1);
-                               present = 1;
+                               *vec = 1;
 #endif
                        }
                }
+               vec++;
+       } while (ptep++, addr = next, addr != end);
+       pte_unmap_unlock(ptep - 1, ptl);
+}
 
-               vec[i] = present;
-       }
-       pte_unmap_unlock(ptep-1, ptl);
+static void mincore_pmd_range(struct vm_area_struct *vma, pud_t *pud,
+                       unsigned long addr, unsigned long end,
+                       unsigned char *vec)
+{
+       unsigned long next;
+       pmd_t *pmd;
 
-       return nr;
+       pmd = pmd_offset(pud, addr);
+       do {
+               next = pmd_addr_end(addr, end);
+               if (pmd_none_or_clear_bad(pmd))
+                       mincore_unmapped_range(vma, addr, next, vec);
+               else
+                       mincore_pte_range(vma, pmd, addr, next, vec);
+               vec += (next - addr) >> PAGE_SHIFT;
+       } while (pmd++, addr = next, addr != end);
+}
 
-none_mapped:
-       if (vma->vm_file) {
-               pgoff = linear_page_index(vma, addr);
-               for (i = 0; i < nr; i++, pgoff++)
-                       vec[i] = mincore_page(vma->vm_file->f_mapping, pgoff);
-       } else {
-               for (i = 0; i < nr; i++)
-                       vec[i] = 0;
+static void mincore_pud_range(struct vm_area_struct *vma, pgd_t *pgd,
+                       unsigned long addr, unsigned long end,
+                       unsigned char *vec)
+{
+       unsigned long next;
+       pud_t *pud;
+
+       pud = pud_offset(pgd, addr);
+       do {
+               next = pud_addr_end(addr, end);
+               if (pud_none_or_clear_bad(pud))
+                       mincore_unmapped_range(vma, addr, next, vec);
+               else
+                       mincore_pmd_range(vma, pud, addr, next, vec);
+               vec += (next - addr) >> PAGE_SHIFT;
+       } while (pud++, addr = next, addr != end);
+}
+
+static void mincore_page_range(struct vm_area_struct *vma,
+                       unsigned long addr, unsigned long end,
+                       unsigned char *vec)
+{
+       unsigned long next;
+       pgd_t *pgd;
+
+       pgd = pgd_offset(vma->vm_mm, addr);
+       do {
+               next = pgd_addr_end(addr, end);
+               if (pgd_none_or_clear_bad(pgd))
+                       mincore_unmapped_range(vma, addr, next, vec);
+               else
+                       mincore_pud_range(vma, pgd, addr, next, vec);
+               vec += (next - addr) >> PAGE_SHIFT;
+       } while (pgd++, addr = next, addr != end);
+}
+
+/*
+ * Do a chunk of "sys_mincore()". We've already checked
+ * all the arguments, we hold the mmap semaphore: we should
+ * just return the amount of info we're asked for.
+ */
+static long do_mincore(unsigned long addr, unsigned long pages, unsigned char *vec)
+{
+       struct vm_area_struct *vma;
+       unsigned long end;
+
+       vma = find_vma(current->mm, addr);
+       if (!vma || addr < vma->vm_start)
+               return -ENOMEM;
+
+       end = min(vma->vm_end, addr + (pages << PAGE_SHIFT));
+
+       if (is_vm_hugetlb_page(vma)) {
+               mincore_hugetlb_page_range(vma, addr, end, vec);
+               return (end - addr) >> PAGE_SHIFT;
        }
 
-       return nr;
+       end = pmd_addr_end(addr, end);
+
+       if (is_vm_hugetlb_page(vma))
+               mincore_hugetlb_page_range(vma, addr, end, vec);
+       else
+               mincore_page_range(vma, addr, end, vec);
+
+       return (end - addr) >> PAGE_SHIFT;
 }
 
 /*
@@ -247,7 +286,7 @@ SYSCALL_DEFINE3(mincore, unsigned long, start, size_t, len,
                 * the temporary buffer size.
                 */
                down_read(&current->mm->mmap_sem);
-               retval = do_mincore(start, tmp, min(pages, PAGE_SIZE));
+               retval = do_mincore(start, min(pages, PAGE_SIZE), tmp);
                up_read(&current->mm->mmap_sem);
 
                if (retval <= 0)
index 4083209b7f02e068b94ac50c16d0739a539bc47b..632df4527c0122062d9332a0d483835274ed62f6 100644 (file)
@@ -82,7 +82,7 @@ SYSCALL_DEFINE3(msync, unsigned long, start, size_t, len, int, flags)
                                (vma->vm_flags & VM_SHARED)) {
                        get_file(file);
                        up_read(&mm->mmap_sem);
-                       error = vfs_fsync(file, file->f_path.dentry, 0);
+                       error = vfs_fsync(file, 0);
                        fput(file);
                        if (error || start >= end)
                                goto out;
index 63fa17d121f027ca5c75f09eab994db346316d2b..b76f3ee0abe015a85f36ff4b2599cff21d3c3efd 100644 (file)
@@ -918,14 +918,6 @@ static int validate_mmap_request(struct file *file,
                        if (!(capabilities & BDI_CAP_MAP_DIRECT))
                                return -ENODEV;
 
-                       if (((prot & PROT_READ)  && !(capabilities & BDI_CAP_READ_MAP))  ||
-                           ((prot & PROT_WRITE) && !(capabilities & BDI_CAP_WRITE_MAP)) ||
-                           ((prot & PROT_EXEC)  && !(capabilities & BDI_CAP_EXEC_MAP))
-                           ) {
-                               printk("MAP_SHARED not completely supported on !MMU\n");
-                               return -EINVAL;
-                       }
-
                        /* we mustn't privatise shared mappings */
                        capabilities &= ~BDI_CAP_MAP_COPY;
                }
@@ -941,6 +933,20 @@ static int validate_mmap_request(struct file *file,
                                capabilities &= ~BDI_CAP_MAP_DIRECT;
                }
 
+               if (capabilities & BDI_CAP_MAP_DIRECT) {
+                       if (((prot & PROT_READ)  && !(capabilities & BDI_CAP_READ_MAP))  ||
+                           ((prot & PROT_WRITE) && !(capabilities & BDI_CAP_WRITE_MAP)) ||
+                           ((prot & PROT_EXEC)  && !(capabilities & BDI_CAP_EXEC_MAP))
+                           ) {
+                               capabilities &= ~BDI_CAP_MAP_DIRECT;
+                               if (flags & MAP_SHARED) {
+                                       printk(KERN_WARNING
+                                              "MAP_SHARED not completely supported on !MMU\n");
+                                       return -EINVAL;
+                               }
+                       }
+               }
+
                /* handle executable mappings and implied executable
                 * mappings */
                if (file->f_path.mnt->mnt_flags & MNT_NOEXEC) {
@@ -996,22 +1002,20 @@ static unsigned long determine_vm_flags(struct file *file,
        unsigned long vm_flags;
 
        vm_flags = calc_vm_prot_bits(prot) | calc_vm_flag_bits(flags);
-       vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
        /* vm_flags |= mm->def_flags; */
 
        if (!(capabilities & BDI_CAP_MAP_DIRECT)) {
                /* attempt to share read-only copies of mapped file chunks */
+               vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
                if (file && !(prot & PROT_WRITE))
                        vm_flags |= VM_MAYSHARE;
-       }
-       else {
+       } else {
                /* overlay a shareable mapping on the backing device or inode
                 * if possible - used for chardevs, ramfs/tmpfs/shmfs and
                 * romfs/cramfs */
+               vm_flags |= VM_MAYSHARE | (capabilities & BDI_CAP_VMFLAGS);
                if (flags & MAP_SHARED)
-                       vm_flags |= VM_MAYSHARE | VM_SHARED;
-               else if ((((vm_flags & capabilities) ^ vm_flags) & BDI_CAP_VMFLAGS) == 0)
-                       vm_flags |= VM_MAYSHARE;
+                       vm_flags |= VM_SHARED;
        }
 
        /* refuse to let anyone share private mappings with this process if
index b68e802a7a7d6961a0c1f7709a9cc606d022371c..709aedfaa014946664f2b83857b749d92f79752f 100644 (file)
@@ -479,12 +479,9 @@ void mem_cgroup_out_of_memory(struct mem_cgroup *mem, gfp_t gfp_mask)
        read_lock(&tasklist_lock);
 retry:
        p = select_bad_process(&points, mem);
-       if (PTR_ERR(p) == -1UL)
+       if (!p || PTR_ERR(p) == -1UL)
                goto out;
 
-       if (!p)
-               p = current;
-
        if (oom_kill_process(p, gfp_mask, 0, points, mem,
                                "Memory cgroup out of memory"))
                goto retry;
index a6326c71b663802fab4972b566a3e510e91bff78..431214b941acec39f68e171e468a59f74b9b749e 100644 (file)
@@ -49,6 +49,7 @@
 #include <linux/debugobjects.h>
 #include <linux/kmemleak.h>
 #include <linux/memory.h>
+#include <linux/compaction.h>
 #include <trace/events/kmem.h>
 #include <linux/ftrace_event.h>
 
 #include <asm/div64.h>
 #include "internal.h"
 
+#ifdef CONFIG_USE_PERCPU_NUMA_NODE_ID
+DEFINE_PER_CPU(int, numa_node);
+EXPORT_PER_CPU_SYMBOL(numa_node);
+#endif
+
+#ifdef CONFIG_HAVE_MEMORYLESS_NODES
+/*
+ * N.B., Do NOT reference the '_numa_mem_' per cpu variable directly.
+ * It will not be defined when CONFIG_HAVE_MEMORYLESS_NODES is not defined.
+ * Use the accessor functions set_numa_mem(), numa_mem_id() and cpu_to_mem()
+ * defined in <linux/topology.h>.
+ */
+DEFINE_PER_CPU(int, _numa_mem_);               /* Kernel "local memory" node */
+EXPORT_PER_CPU_SYMBOL(_numa_mem_);
+#endif
+
 /*
  * Array of node states.
  */
@@ -475,6 +492,8 @@ static inline void __free_one_page(struct page *page,
                int migratetype)
 {
        unsigned long page_idx;
+       unsigned long combined_idx;
+       struct page *buddy;
 
        if (unlikely(PageCompound(page)))
                if (unlikely(destroy_compound_page(page, order)))
@@ -488,9 +507,6 @@ static inline void __free_one_page(struct page *page,
        VM_BUG_ON(bad_range(zone, page));
 
        while (order < MAX_ORDER-1) {
-               unsigned long combined_idx;
-               struct page *buddy;
-
                buddy = __page_find_buddy(page, page_idx, order);
                if (!page_is_buddy(page, buddy, order))
                        break;
@@ -505,8 +521,29 @@ static inline void __free_one_page(struct page *page,
                order++;
        }
        set_page_order(page, order);
-       list_add(&page->lru,
-               &zone->free_area[order].free_list[migratetype]);
+
+       /*
+        * If this is not the largest possible page, check if the buddy
+        * of the next-highest order is free. If it is, it's possible
+        * that pages are being freed that will coalesce soon. In case,
+        * that is happening, add the free page to the tail of the list
+        * so it's less likely to be used soon and more likely to be merged
+        * as a higher order page
+        */
+       if ((order < MAX_ORDER-1) && pfn_valid_within(page_to_pfn(buddy))) {
+               struct page *higher_page, *higher_buddy;
+               combined_idx = __find_combined_index(page_idx, order);
+               higher_page = page + combined_idx - page_idx;
+               higher_buddy = __page_find_buddy(higher_page, combined_idx, order + 1);
+               if (page_is_buddy(higher_page, higher_buddy, order + 1)) {
+                       list_add_tail(&page->lru,
+                               &zone->free_area[order].free_list[migratetype]);
+                       goto out;
+               }
+       }
+
+       list_add(&page->lru, &zone->free_area[order].free_list[migratetype]);
+out:
        zone->free_area[order].nr_free++;
 }
 
@@ -599,20 +636,23 @@ static void free_one_page(struct zone *zone, struct page *page, int order,
        spin_unlock(&zone->lock);
 }
 
-static void __free_pages_ok(struct page *page, unsigned int order)
+static bool free_pages_prepare(struct page *page, unsigned int order)
 {
-       unsigned long flags;
        int i;
        int bad = 0;
-       int wasMlocked = __TestClearPageMlocked(page);
 
        trace_mm_page_free_direct(page, order);
        kmemcheck_free_shadow(page, order);
 
-       for (i = 0 ; i < (1 << order) ; ++i)
-               bad += free_pages_check(page + i);
+       for (i = 0; i < (1 << order); i++) {
+               struct page *pg = page + i;
+
+               if (PageAnon(pg))
+                       pg->mapping = NULL;
+               bad += free_pages_check(pg);
+       }
        if (bad)
-               return;
+               return false;
 
        if (!PageHighMem(page)) {
                debug_check_no_locks_freed(page_address(page),PAGE_SIZE<<order);
@@ -622,6 +662,17 @@ static void __free_pages_ok(struct page *page, unsigned int order)
        arch_free_page(page, order);
        kernel_map_pages(page, 1 << order, 0);
 
+       return true;
+}
+
+static void __free_pages_ok(struct page *page, unsigned int order)
+{
+       unsigned long flags;
+       int wasMlocked = __TestClearPageMlocked(page);
+
+       if (!free_pages_prepare(page, order))
+               return;
+
        local_irq_save(flags);
        if (unlikely(wasMlocked))
                free_page_mlock(page);
@@ -1107,21 +1158,9 @@ void free_hot_cold_page(struct page *page, int cold)
        int migratetype;
        int wasMlocked = __TestClearPageMlocked(page);
 
-       trace_mm_page_free_direct(page, 0);
-       kmemcheck_free_shadow(page, 0);
-
-       if (PageAnon(page))
-               page->mapping = NULL;
-       if (free_pages_check(page))
+       if (!free_pages_prepare(page, 0))
                return;
 
-       if (!PageHighMem(page)) {
-               debug_check_no_locks_freed(page_address(page), PAGE_SIZE);
-               debug_check_no_obj_freed(page_address(page), PAGE_SIZE);
-       }
-       arch_free_page(page, 0);
-       kernel_map_pages(page, 1, 0);
-
        migratetype = get_pageblock_migratetype(page);
        set_page_private(page, migratetype);
        local_irq_save(flags);
@@ -1187,6 +1226,51 @@ void split_page(struct page *page, unsigned int order)
                set_page_refcounted(page + i);
 }
 
+/*
+ * Similar to split_page except the page is already free. As this is only
+ * being used for migration, the migratetype of the block also changes.
+ * As this is called with interrupts disabled, the caller is responsible
+ * for calling arch_alloc_page() and kernel_map_page() after interrupts
+ * are enabled.
+ *
+ * Note: this is probably too low level an operation for use in drivers.
+ * Please consult with lkml before using this in your driver.
+ */
+int split_free_page(struct page *page)
+{
+       unsigned int order;
+       unsigned long watermark;
+       struct zone *zone;
+
+       BUG_ON(!PageBuddy(page));
+
+       zone = page_zone(page);
+       order = page_order(page);
+
+       /* Obey watermarks as if the page was being allocated */
+       watermark = low_wmark_pages(zone) + (1 << order);
+       if (!zone_watermark_ok(zone, 0, watermark, 0, 0))
+               return 0;
+
+       /* Remove page from free list */
+       list_del(&page->lru);
+       zone->free_area[order].nr_free--;
+       rmv_page_order(page);
+       __mod_zone_page_state(zone, NR_FREE_PAGES, -(1UL << order));
+
+       /* Split into individual pages */
+       set_page_refcounted(page);
+       split_page(page, order);
+
+       if (order >= pageblock_order - 1) {
+               struct page *endpage = page + (1 << order) - 1;
+               for (; page < endpage; page += pageblock_nr_pages)
+                       set_pageblock_migratetype(page, MIGRATE_MOVABLE);
+       }
+
+       return 1 << order;
+}
+
 /*
  * Really, prep_compound_page() should be called from __rmqueue_bulk().  But
  * we cheat by calling it from here, in the order > 0 path.  Saves a branch
@@ -1693,6 +1777,62 @@ out:
        return page;
 }
 
+#ifdef CONFIG_COMPACTION
+/* Try memory compaction for high-order allocations before reclaim */
+static struct page *
+__alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
+       struct zonelist *zonelist, enum zone_type high_zoneidx,
+       nodemask_t *nodemask, int alloc_flags, struct zone *preferred_zone,
+       int migratetype, unsigned long *did_some_progress)
+{
+       struct page *page;
+
+       if (!order || compaction_deferred(preferred_zone))
+               return NULL;
+
+       *did_some_progress = try_to_compact_pages(zonelist, order, gfp_mask,
+                                                               nodemask);
+       if (*did_some_progress != COMPACT_SKIPPED) {
+
+               /* Page migration frees to the PCP lists but we want merging */
+               drain_pages(get_cpu());
+               put_cpu();
+
+               page = get_page_from_freelist(gfp_mask, nodemask,
+                               order, zonelist, high_zoneidx,
+                               alloc_flags, preferred_zone,
+                               migratetype);
+               if (page) {
+                       preferred_zone->compact_considered = 0;
+                       preferred_zone->compact_defer_shift = 0;
+                       count_vm_event(COMPACTSUCCESS);
+                       return page;
+               }
+
+               /*
+                * It's bad if compaction run occurs and fails.
+                * The most likely reason is that pages exist,
+                * but not enough to satisfy watermarks.
+                */
+               count_vm_event(COMPACTFAIL);
+               defer_compaction(preferred_zone);
+
+               cond_resched();
+       }
+
+       return NULL;
+}
+#else
+static inline struct page *
+__alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
+       struct zonelist *zonelist, enum zone_type high_zoneidx,
+       nodemask_t *nodemask, int alloc_flags, struct zone *preferred_zone,
+       int migratetype, unsigned long *did_some_progress)
+{
+       return NULL;
+}
+#endif /* CONFIG_COMPACTION */
+
 /* The really slow allocator path where we enter direct reclaim */
 static inline struct page *
 __alloc_pages_direct_reclaim(gfp_t gfp_mask, unsigned int order,
@@ -1879,6 +2019,15 @@ rebalance:
        if (test_thread_flag(TIF_MEMDIE) && !(gfp_mask & __GFP_NOFAIL))
                goto nopage;
 
+       /* Try direct compaction */
+       page = __alloc_pages_direct_compact(gfp_mask, order,
+                                       zonelist, high_zoneidx,
+                                       nodemask,
+                                       alloc_flags, preferred_zone,
+                                       migratetype, &did_some_progress);
+       if (page)
+               goto got_pg;
+
        /* Try direct reclaim and then allocating */
        page = __alloc_pages_direct_reclaim(gfp_mask, order,
                                        zonelist, high_zoneidx,
@@ -1970,10 +2119,13 @@ __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
        if (unlikely(!zonelist->_zonerefs->zone))
                return NULL;
 
+       get_mems_allowed();
        /* The preferred zone is used for statistics later */
        first_zones_zonelist(zonelist, high_zoneidx, nodemask, &preferred_zone);
-       if (!preferred_zone)
+       if (!preferred_zone) {
+               put_mems_allowed();
                return NULL;
+       }
 
        /* First allocation attempt */
        page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, nodemask, order,
@@ -1983,6 +2135,7 @@ __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
                page = __alloc_pages_slowpath(gfp_mask, order,
                                zonelist, high_zoneidx, nodemask,
                                preferred_zone, migratetype);
+       put_mems_allowed();
 
        trace_mm_page_alloc(page, order, gfp_mask, migratetype);
        return page;
@@ -2434,8 +2587,11 @@ int numa_zonelist_order_handler(ctl_table *table, int write,
                        strncpy((char*)table->data, saved_string,
                                NUMA_ZONELIST_ORDER_LEN);
                        user_zonelist_order = oldval;
-               } else if (oldval != user_zonelist_order)
-                       build_all_zonelists();
+               } else if (oldval != user_zonelist_order) {
+                       mutex_lock(&zonelists_mutex);
+                       build_all_zonelists(NULL);
+                       mutex_unlock(&zonelists_mutex);
+               }
        }
 out:
        mutex_unlock(&zl_order_mutex);
@@ -2582,7 +2738,7 @@ static int default_zonelist_order(void)
          * ZONE_DMA and ZONE_DMA32 can be very small area in the system.
         * If they are really small and used heavily, the system can fall
         * into OOM very easily.
-        * This function detect ZONE_DMA/DMA32 size and confgigures zone order.
+        * This function detect ZONE_DMA/DMA32 size and configures zone order.
         */
        /* Is there ZONE_NORMAL ? (ex. ppc has only DMA zone..) */
        low_kmem_size = 0;
@@ -2594,6 +2750,15 @@ static int default_zonelist_order(void)
                                if (zone_type < ZONE_NORMAL)
                                        low_kmem_size += z->present_pages;
                                total_size += z->present_pages;
+                       } else if (zone_type == ZONE_NORMAL) {
+                               /*
+                                * If any node has only lowmem, then node order
+                                * is preferred to allow kernel allocations
+                                * locally; otherwise, they can easily infringe
+                                * on other nodes when there is an abundance of
+                                * lowmem available to allocate from.
+                                */
+                               return ZONELIST_ORDER_NODE;
                        }
                }
        }
@@ -2707,6 +2872,24 @@ static void build_zonelist_cache(pg_data_t *pgdat)
                zlc->z_to_n[z - zonelist->_zonerefs] = zonelist_node_idx(z);
 }
 
+#ifdef CONFIG_HAVE_MEMORYLESS_NODES
+/*
+ * Return node id of node used for "local" allocations.
+ * I.e., first node id of first zone in arg node's generic zonelist.
+ * Used for initializing percpu 'numa_mem', which is used primarily
+ * for kernel allocations, so use GFP_KERNEL flags to locate zonelist.
+ */
+int local_memory_node(int node)
+{
+       struct zone *zone;
+
+       (void)first_zones_zonelist(node_zonelist(node, GFP_KERNEL),
+                                  gfp_zone(GFP_KERNEL),
+                                  NULL,
+                                  &zone);
+       return zone->node;
+}
+#endif
 
 #else  /* CONFIG_NUMA */
 
@@ -2776,9 +2959,16 @@ static void build_zonelist_cache(pg_data_t *pgdat)
  */
 static void setup_pageset(struct per_cpu_pageset *p, unsigned long batch);
 static DEFINE_PER_CPU(struct per_cpu_pageset, boot_pageset);
+static void setup_zone_pageset(struct zone *zone);
+
+/*
+ * Global mutex to protect against size modification of zonelists
+ * as well as to serialize pageset setup for the new populated zone.
+ */
+DEFINE_MUTEX(zonelists_mutex);
 
 /* return values int ....just for stop_machine() */
-static int __build_all_zonelists(void *dummy)
+static __init_refok int __build_all_zonelists(void *data)
 {
        int nid;
        int cpu;
@@ -2793,6 +2983,14 @@ static int __build_all_zonelists(void *dummy)
                build_zonelist_cache(pgdat);
        }
 
+#ifdef CONFIG_MEMORY_HOTPLUG
+       /* Setup real pagesets for the new zone */
+       if (data) {
+               struct zone *zone = data;
+               setup_zone_pageset(zone);
+       }
+#endif
+
        /*
         * Initialize the boot_pagesets that are going to be used
         * for bootstrapping processors. The real pagesets for
@@ -2806,13 +3004,31 @@ static int __build_all_zonelists(void *dummy)
         * needs the percpu allocator in order to allocate its pagesets
         * (a chicken-egg dilemma).
         */
-       for_each_possible_cpu(cpu)
+       for_each_possible_cpu(cpu) {
                setup_pageset(&per_cpu(boot_pageset, cpu), 0);
 
+#ifdef CONFIG_HAVE_MEMORYLESS_NODES
+               /*
+                * We now know the "local memory node" for each node--
+                * i.e., the node of the first zone in the generic zonelist.
+                * Set up numa_mem percpu variable for on-line cpus.  During
+                * boot, only the boot cpu should be on-line;  we'll init the
+                * secondary cpus' numa_mem as they come on-line.  During
+                * node/memory hotplug, we'll fixup all on-line cpus.
+                */
+               if (cpu_online(cpu))
+                       set_cpu_numa_mem(cpu, local_memory_node(cpu_to_node(cpu)));
+#endif
+       }
+
        return 0;
 }
 
-void build_all_zonelists(void)
+/*
+ * Called with zonelists_mutex held always
+ * unless system_state == SYSTEM_BOOTING.
+ */
+void build_all_zonelists(void *data)
 {
        set_zonelist_order();
 
@@ -2823,7 +3039,7 @@ void build_all_zonelists(void)
        } else {
                /* we have to stop all cpus to guarantee there is no user
                   of zonelist */
-               stop_machine(__build_all_zonelists, NULL, NULL);
+               stop_machine(__build_all_zonelists, data, NULL);
                /* cpuset refresh routine should be here */
        }
        vm_total_pages = nr_free_pagecache_pages();
@@ -3146,31 +3362,34 @@ static void setup_pagelist_highmark(struct per_cpu_pageset *p,
                pcp->batch = PAGE_SHIFT * 8;
 }
 
+static __meminit void setup_zone_pageset(struct zone *zone)
+{
+       int cpu;
+
+       zone->pageset = alloc_percpu(struct per_cpu_pageset);
+
+       for_each_possible_cpu(cpu) {
+               struct per_cpu_pageset *pcp = per_cpu_ptr(zone->pageset, cpu);
+
+               setup_pageset(pcp, zone_batchsize(zone));
+
+               if (percpu_pagelist_fraction)
+                       setup_pagelist_highmark(pcp,
+                               (zone->present_pages /
+                                       percpu_pagelist_fraction));
+       }
+}
+
 /*
  * Allocate per cpu pagesets and initialize them.
  * Before this call only boot pagesets were available.
- * Boot pagesets will no longer be used by this processorr
- * after setup_per_cpu_pageset().
  */
 void __init setup_per_cpu_pageset(void)
 {
        struct zone *zone;
-       int cpu;
-
-       for_each_populated_zone(zone) {
-               zone->pageset = alloc_percpu(struct per_cpu_pageset);
-
-               for_each_possible_cpu(cpu) {
-                       struct per_cpu_pageset *pcp = per_cpu_ptr(zone->pageset, cpu);
-
-                       setup_pageset(pcp, zone_batchsize(zone));
 
-                       if (percpu_pagelist_fraction)
-                               setup_pagelist_highmark(pcp,
-                                       (zone->present_pages /
-                                               percpu_pagelist_fraction));
-               }
-       }
+       for_each_populated_zone(zone)
+               setup_zone_pageset(zone);
 }
 
 static noinline __init_refok
index dfa9a1a03a116c7659d0d71134a3450a8d69026f..77506a291a2d4caa90c64839896df7b9176bbaa1 100644 (file)
@@ -523,7 +523,7 @@ EXPORT_SYMBOL_GPL(page_cache_sync_readahead);
  * @req_size: hint: total size of the read which the caller is performing in
  *            pagecache pages
  *
- * page_cache_async_ondemand() should be called when a page is used which
+ * page_cache_async_readahead() should be called when a page is used which
  * has the PG_readahead flag; this is a marker to suggest that the application
  * has used up enough of the readahead window that we should start pulling in
  * more pages.
index 0feeef860a8f5b5d61081234f40e8e149e2696f5..38a336e2eea1e104a654052834ef93e252340d18 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -250,7 +250,7 @@ static void anon_vma_unlink(struct anon_vma_chain *anon_vma_chain)
        list_del(&anon_vma_chain->same_anon_vma);
 
        /* We must garbage collect the anon_vma if it's empty */
-       empty = list_empty(&anon_vma->head) && !ksm_refcount(anon_vma);
+       empty = list_empty(&anon_vma->head) && !anonvma_external_refcount(anon_vma);
        spin_unlock(&anon_vma->lock);
 
        if (empty)
@@ -274,7 +274,7 @@ static void anon_vma_ctor(void *data)
        struct anon_vma *anon_vma = data;
 
        spin_lock_init(&anon_vma->lock);
-       ksm_refcount_init(anon_vma);
+       anonvma_external_refcount_init(anon_vma);
        INIT_LIST_HEAD(&anon_vma->head);
 }
 
@@ -1131,6 +1131,20 @@ static int try_to_unmap_cluster(unsigned long cursor, unsigned int *mapcount,
        return ret;
 }
 
+static bool is_vma_temporary_stack(struct vm_area_struct *vma)
+{
+       int maybe_stack = vma->vm_flags & (VM_GROWSDOWN | VM_GROWSUP);
+
+       if (!maybe_stack)
+               return false;
+
+       if ((vma->vm_flags & VM_STACK_INCOMPLETE_SETUP) ==
+                                               VM_STACK_INCOMPLETE_SETUP)
+               return true;
+
+       return false;
+}
+
 /**
  * try_to_unmap_anon - unmap or unlock anonymous page using the object-based
  * rmap method
@@ -1159,7 +1173,21 @@ static int try_to_unmap_anon(struct page *page, enum ttu_flags flags)
 
        list_for_each_entry(avc, &anon_vma->head, same_anon_vma) {
                struct vm_area_struct *vma = avc->vma;
-               unsigned long address = vma_address(page, vma);
+               unsigned long address;
+
+               /*
+                * During exec, a temporary VMA is setup and later moved.
+                * The VMA is moved under the anon_vma lock but not the
+                * page tables leading to a race where migration cannot
+                * find the migration ptes. Rather than increasing the
+                * locking requirements of exec(), migration skips
+                * temporary VMAs until after exec() completes.
+                */
+               if (PAGE_MIGRATION && (flags & TTU_MIGRATION) &&
+                               is_vma_temporary_stack(vma))
+                       continue;
+
+               address = vma_address(page, vma);
                if (address == -EFAULT)
                        continue;
                ret = try_to_unmap_one(page, vma, address, flags);
@@ -1355,10 +1383,8 @@ static int rmap_walk_anon(struct page *page, int (*rmap_one)(struct page *,
        /*
         * Note: remove_migration_ptes() cannot use page_lock_anon_vma()
         * because that depends on page_mapped(); but not all its usages
-        * are holding mmap_sem, which also gave the necessary guarantee
-        * (that this anon_vma's slab has not already been destroyed).
-        * This needs to be reviewed later: avoiding page_lock_anon_vma()
-        * is risky, and currently limits the usefulness of rmap_walk().
+        * are holding mmap_sem. Users without mmap_sem are required to
+        * take a reference count to prevent the anon_vma disappearing
         */
        anon_vma = page_anon_vma(page);
        if (!anon_vma)
index eef4ebea51581f9aa8a6d2244f8ce5fa57f99c22..7e5030ae18ffd07ab19f070939f357fff3816ab9 100644 (file)
@@ -433,8 +433,6 @@ static swp_entry_t *shmem_swp_alloc(struct shmem_inode_info *info, unsigned long
 
                spin_unlock(&info->lock);
                page = shmem_dir_alloc(mapping_gfp_mask(inode->i_mapping));
-               if (page)
-                       set_page_private(page, 0);
                spin_lock(&info->lock);
 
                if (!page) {
@@ -729,10 +727,11 @@ done2:
        if (inode->i_mapping->nrpages && (info->flags & SHMEM_PAGEIN)) {
                /*
                 * Call truncate_inode_pages again: racing shmem_unuse_inode
-                * may have swizzled a page in from swap since vmtruncate or
-                * generic_delete_inode did it, before we lowered next_index.
-                * Also, though shmem_getpage checks i_size before adding to
-                * cache, no recheck after: so fix the narrow window there too.
+                * may have swizzled a page in from swap since
+                * truncate_pagecache or generic_delete_inode did it, before we
+                * lowered next_index.  Also, though shmem_getpage checks
+                * i_size before adding to cache, no recheck after: so fix the
+                * narrow window there too.
                 *
                 * Recalling truncate_inode_pages_range and unmap_mapping_range
                 * every time for punch_hole (which never got a chance to clear
@@ -762,19 +761,16 @@ done2:
        }
 }
 
-static void shmem_truncate(struct inode *inode)
-{
-       shmem_truncate_range(inode, inode->i_size, (loff_t)-1);
-}
-
 static int shmem_notify_change(struct dentry *dentry, struct iattr *attr)
 {
        struct inode *inode = dentry->d_inode;
-       struct page *page = NULL;
        int error;
 
        if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)) {
-               if (attr->ia_size < inode->i_size) {
+               loff_t newsize = attr->ia_size;
+               struct page *page = NULL;
+
+               if (newsize < inode->i_size) {
                        /*
                         * If truncating down to a partial page, then
                         * if that page is already allocated, hold it
@@ -782,9 +778,9 @@ static int shmem_notify_change(struct dentry *dentry, struct iattr *attr)
                         * truncate_partial_page cannnot miss it were
                         * it assigned to swap.
                         */
-                       if (attr->ia_size & (PAGE_CACHE_SIZE-1)) {
+                       if (newsize & (PAGE_CACHE_SIZE-1)) {
                                (void) shmem_getpage(inode,
-                                       attr->ia_size>>PAGE_CACHE_SHIFT,
+                                       newsize >> PAGE_CACHE_SHIFT,
                                                &page, SGP_READ, NULL);
                                if (page)
                                        unlock_page(page);
@@ -796,24 +792,29 @@ static int shmem_notify_change(struct dentry *dentry, struct iattr *attr)
                         * if it's being fully truncated to zero-length: the
                         * nrpages check is efficient enough in that case.
                         */
-                       if (attr->ia_size) {
+                       if (newsize) {
                                struct shmem_inode_info *info = SHMEM_I(inode);
                                spin_lock(&info->lock);
                                info->flags &= ~SHMEM_PAGEIN;
                                spin_unlock(&info->lock);
                        }
                }
+
+               error = simple_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)
-               error = inode_setattr(inode, attr);
+               generic_setattr(inode, attr);
 #ifdef CONFIG_TMPFS_POSIX_ACL
        if (!error && (attr->ia_valid & ATTR_MODE))
                error = generic_acl_chmod(inode);
 #endif
-       if (page)
-               page_cache_release(page);
        return error;
 }
 
@@ -821,11 +822,11 @@ static void shmem_delete_inode(struct inode *inode)
 {
        struct shmem_inode_info *info = SHMEM_I(inode);
 
-       if (inode->i_op->truncate == shmem_truncate) {
+       if (inode->i_mapping->a_ops == &shmem_aops) {
                truncate_inode_pages(inode->i_mapping, 0);
                shmem_unacct_size(info->flags, inode->i_size);
                inode->i_size = 0;
-               shmem_truncate(inode);
+               shmem_truncate_range(inode, 0, (loff_t)-1);
                if (!list_empty(&info->swaplist)) {
                        mutex_lock(&shmem_swaplist_mutex);
                        list_del_init(&info->swaplist);
@@ -1545,8 +1546,8 @@ static int shmem_mmap(struct file *file, struct vm_area_struct *vma)
        return 0;
 }
 
-static struct inode *shmem_get_inode(struct super_block *sb, int mode,
-                                       dev_t dev, unsigned long flags)
+static struct inode *shmem_get_inode(struct super_block *sb, const struct inode *dir,
+                                    int mode, dev_t dev, unsigned long flags)
 {
        struct inode *inode;
        struct shmem_inode_info *info;
@@ -1557,9 +1558,7 @@ static struct inode *shmem_get_inode(struct super_block *sb, int mode,
 
        inode = new_inode(sb);
        if (inode) {
-               inode->i_mode = mode;
-               inode->i_uid = current_fsuid();
-               inode->i_gid = current_fsgid();
+               inode_init_owner(inode, dir, mode);
                inode->i_blocks = 0;
                inode->i_mapping->backing_dev_info = &shmem_backing_dev_info;
                inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
@@ -1814,7 +1813,7 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
        struct inode *inode;
        int error = -ENOSPC;
 
-       inode = shmem_get_inode(dir->i_sb, mode, dev, VM_NORESERVE);
+       inode = shmem_get_inode(dir->i_sb, dir, mode, dev, VM_NORESERVE);
        if (inode) {
                error = security_inode_init_security(inode, dir, NULL, NULL,
                                                     NULL);
@@ -1833,11 +1832,6 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
 #else
                error = 0;
 #endif
-               if (dir->i_mode & S_ISGID) {
-                       inode->i_gid = dir->i_gid;
-                       if (S_ISDIR(mode))
-                               inode->i_mode |= S_ISGID;
-               }
                dir->i_size += BOGO_DIRENT_SIZE;
                dir->i_ctime = dir->i_mtime = CURRENT_TIME;
                d_instantiate(dentry, inode);
@@ -1957,7 +1951,7 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
        if (len > PAGE_CACHE_SIZE)
                return -ENAMETOOLONG;
 
-       inode = shmem_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0, VM_NORESERVE);
+       inode = shmem_get_inode(dir->i_sb, dir, S_IFLNK|S_IRWXUGO, 0, VM_NORESERVE);
        if (!inode)
                return -ENOSPC;
 
@@ -1992,8 +1986,6 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
                unlock_page(page);
                page_cache_release(page);
        }
-       if (dir->i_mode & S_ISGID)
-               inode->i_gid = dir->i_gid;
        dir->i_size += BOGO_DIRENT_SIZE;
        dir->i_ctime = dir->i_mtime = CURRENT_TIME;
        d_instantiate(dentry, inode);
@@ -2033,7 +2025,6 @@ static const struct inode_operations shmem_symlink_inline_operations = {
 };
 
 static const struct inode_operations shmem_symlink_inode_operations = {
-       .truncate       = shmem_truncate,
        .readlink       = generic_readlink,
        .follow_link    = shmem_follow_link,
        .put_link       = shmem_put_link,
@@ -2071,14 +2062,14 @@ static int shmem_xattr_security_set(struct dentry *dentry, const char *name,
                                          size, flags);
 }
 
-static struct xattr_handler shmem_xattr_security_handler = {
+static const struct xattr_handler shmem_xattr_security_handler = {
        .prefix = XATTR_SECURITY_PREFIX,
        .list   = shmem_xattr_security_list,
        .get    = shmem_xattr_security_get,
        .set    = shmem_xattr_security_set,
 };
 
-static struct xattr_handler *shmem_xattr_handlers[] = {
+static const struct xattr_handler *shmem_xattr_handlers[] = {
        &generic_acl_access_handler,
        &generic_acl_default_handler,
        &shmem_xattr_security_handler,
@@ -2366,7 +2357,7 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_flags |= MS_POSIXACL;
 #endif
 
-       inode = shmem_get_inode(sb, S_IFDIR | sbinfo->mode, 0, VM_NORESERVE);
+       inode = shmem_get_inode(sb, NULL, S_IFDIR | sbinfo->mode, 0, VM_NORESERVE);
        if (!inode)
                goto failed;
        inode->i_uid = sbinfo->uid;
@@ -2444,14 +2435,13 @@ static const struct file_operations shmem_file_operations = {
        .write          = do_sync_write,
        .aio_read       = shmem_file_aio_read,
        .aio_write      = generic_file_aio_write,
-       .fsync          = simple_sync_file,
+       .fsync          = noop_fsync,
        .splice_read    = generic_file_splice_read,
        .splice_write   = generic_file_splice_write,
 #endif
 };
 
 static const struct inode_operations shmem_inode_operations = {
-       .truncate       = shmem_truncate,
        .setattr        = shmem_notify_change,
        .truncate_range = shmem_truncate_range,
 #ifdef CONFIG_TMPFS_POSIX_ACL
@@ -2570,6 +2560,45 @@ out4:
        return error;
 }
 
+#ifdef CONFIG_CGROUP_MEM_RES_CTLR
+/**
+ * mem_cgroup_get_shmem_target - find a page or entry assigned to the shmem file
+ * @inode: the inode to be searched
+ * @pgoff: the offset to be searched
+ * @pagep: the pointer for the found page to be stored
+ * @ent: the pointer for the found swap entry to be stored
+ *
+ * If a page is found, refcount of it is incremented. Callers should handle
+ * these refcount.
+ */
+void mem_cgroup_get_shmem_target(struct inode *inode, pgoff_t pgoff,
+                                       struct page **pagep, swp_entry_t *ent)
+{
+       swp_entry_t entry = { .val = 0 }, *ptr;
+       struct page *page = NULL;
+       struct shmem_inode_info *info = SHMEM_I(inode);
+
+       if ((pgoff << PAGE_CACHE_SHIFT) >= i_size_read(inode))
+               goto out;
+
+       spin_lock(&info->lock);
+       ptr = shmem_swp_entry(info, pgoff, NULL);
+#ifdef CONFIG_SWAP
+       if (ptr && ptr->val) {
+               entry.val = ptr->val;
+               page = find_get_page(&swapper_space, entry.val);
+       } else
+#endif
+               page = find_get_page(inode->i_mapping, pgoff);
+       if (ptr)
+               shmem_swp_unmap(ptr);
+       spin_unlock(&info->lock);
+out:
+       *pagep = page;
+       *ent = entry;
+}
+#endif
+
 #else /* !CONFIG_SHMEM */
 
 /*
@@ -2609,9 +2638,34 @@ int shmem_lock(struct file *file, int lock, struct user_struct *user)
        return 0;
 }
 
+#ifdef CONFIG_CGROUP_MEM_RES_CTLR
+/**
+ * mem_cgroup_get_shmem_target - find a page or entry assigned to the shmem file
+ * @inode: the inode to be searched
+ * @pgoff: the offset to be searched
+ * @pagep: the pointer for the found page to be stored
+ * @ent: the pointer for the found swap entry to be stored
+ *
+ * If a page is found, refcount of it is incremented. Callers should handle
+ * these refcount.
+ */
+void mem_cgroup_get_shmem_target(struct inode *inode, pgoff_t pgoff,
+                                       struct page **pagep, swp_entry_t *ent)
+{
+       struct page *page = NULL;
+
+       if ((pgoff << PAGE_CACHE_SHIFT) >= i_size_read(inode))
+               goto out;
+       page = find_get_page(inode->i_mapping, pgoff);
+out:
+       *pagep = page;
+       *ent = (swp_entry_t){ .val = 0 };
+}
+#endif
+
 #define shmem_vm_ops                           generic_file_vm_ops
 #define shmem_file_operations                  ramfs_file_operations
-#define shmem_get_inode(sb, mode, dev, flags)  ramfs_get_inode(sb, mode, dev)
+#define shmem_get_inode(sb, dir, mode, dev, flags)     ramfs_get_inode(sb, dir, mode, dev)
 #define shmem_acct_size(flags, size)           0
 #define shmem_unacct_size(flags, size)         do {} while (0)
 #define SHMEM_MAX_BYTES                                MAX_LFS_FILESIZE
@@ -2655,7 +2709,7 @@ struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags
        path.mnt = mntget(shm_mnt);
 
        error = -ENOSPC;
-       inode = shmem_get_inode(root->d_sb, S_IFREG | S_IRWXUGO, 0, flags);
+       inode = shmem_get_inode(root->d_sb, NULL, S_IFREG | S_IRWXUGO, 0, flags);
        if (!inode)
                goto put_dentry;
 
index bac0f4fcc216548fae98d352b0787cf509c0f262..e49f8f46f46d6878dba427dae10fc9b5fb153a9f 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
 #include       <linux/reciprocal_div.h>
 #include       <linux/debugobjects.h>
 #include       <linux/kmemcheck.h>
+#include       <linux/memory.h>
 
 #include       <asm/cacheflush.h>
 #include       <asm/tlbflush.h>
 #define        BYTES_PER_WORD          sizeof(void *)
 #define        REDZONE_ALIGN           max(BYTES_PER_WORD, __alignof__(unsigned long long))
 
-#ifndef ARCH_KMALLOC_MINALIGN
-/*
- * Enforce a minimum alignment for the kmalloc caches.
- * Usually, the kmalloc caches are cache_line_size() aligned, except when
- * DEBUG and FORCED_DEBUG are enabled, then they are BYTES_PER_WORD aligned.
- * Some archs want to perform DMA into kmalloc caches and need a guaranteed
- * alignment larger than the alignment of a 64-bit integer.
- * ARCH_KMALLOC_MINALIGN allows that.
- * Note that increasing this value may disable some debug features.
- */
-#define ARCH_KMALLOC_MINALIGN __alignof__(unsigned long long)
-#endif
-
-#ifndef ARCH_SLAB_MINALIGN
-/*
- * Enforce a minimum alignment for all caches.
- * Intended for archs that get misalignment faults even for BYTES_PER_WORD
- * aligned buffers. Includes ARCH_KMALLOC_MINALIGN.
- * If possible: Do not enable this flag for CONFIG_DEBUG_SLAB, it disables
- * some debug features.
- */
-#define ARCH_SLAB_MINALIGN 0
-#endif
-
 #ifndef ARCH_KMALLOC_FLAGS
 #define ARCH_KMALLOC_FLAGS SLAB_HWCACHE_ALIGN
 #endif
@@ -844,7 +821,7 @@ static void init_reap_node(int cpu)
 {
        int node;
 
-       node = next_node(cpu_to_node(cpu), node_online_map);
+       node = next_node(cpu_to_mem(cpu), node_online_map);
        if (node == MAX_NUMNODES)
                node = first_node(node_online_map);
 
@@ -1073,7 +1050,7 @@ static inline int cache_free_alien(struct kmem_cache *cachep, void *objp)
        struct array_cache *alien = NULL;
        int node;
 
-       node = numa_node_id();
+       node = numa_mem_id();
 
        /*
         * Make sure we are not freeing a object from another node to the array
@@ -1102,11 +1079,57 @@ static inline int cache_free_alien(struct kmem_cache *cachep, void *objp)
 }
 #endif
 
+/*
+ * Allocates and initializes nodelists for a node on each slab cache, used for
+ * either memory or cpu hotplug.  If memory is being hot-added, the kmem_list3
+ * will be allocated off-node since memory is not yet online for the new node.
+ * When hotplugging memory or a cpu, existing nodelists are not replaced if
+ * already in use.
+ *
+ * Must hold cache_chain_mutex.
+ */
+static int init_cache_nodelists_node(int node)
+{
+       struct kmem_cache *cachep;
+       struct kmem_list3 *l3;
+       const int memsize = sizeof(struct kmem_list3);
+
+       list_for_each_entry(cachep, &cache_chain, next) {
+               /*
+                * Set up the size64 kmemlist for cpu before we can
+                * begin anything. Make sure some other cpu on this
+                * node has not already allocated this
+                */
+               if (!cachep->nodelists[node]) {
+                       l3 = kmalloc_node(memsize, GFP_KERNEL, node);
+                       if (!l3)
+                               return -ENOMEM;
+                       kmem_list3_init(l3);
+                       l3->next_reap = jiffies + REAPTIMEOUT_LIST3 +
+                           ((unsigned long)cachep) % REAPTIMEOUT_LIST3;
+
+                       /*
+                        * The l3s don't come and go as CPUs come and
+                        * go.  cache_chain_mutex is sufficient
+                        * protection here.
+                        */
+                       cachep->nodelists[node] = l3;
+               }
+
+               spin_lock_irq(&cachep->nodelists[node]->list_lock);
+               cachep->nodelists[node]->free_limit =
+                       (1 + nr_cpus_node(node)) *
+                       cachep->batchcount + cachep->num;
+               spin_unlock_irq(&cachep->nodelists[node]->list_lock);
+       }
+       return 0;
+}
+
 static void __cpuinit cpuup_canceled(long cpu)
 {
        struct kmem_cache *cachep;
        struct kmem_list3 *l3 = NULL;
-       int node = cpu_to_node(cpu);
+       int node = cpu_to_mem(cpu);
        const struct cpumask *mask = cpumask_of_node(node);
 
        list_for_each_entry(cachep, &cache_chain, next) {
@@ -1171,8 +1194,8 @@ static int __cpuinit cpuup_prepare(long cpu)
 {
        struct kmem_cache *cachep;
        struct kmem_list3 *l3 = NULL;
-       int node = cpu_to_node(cpu);
-       const int memsize = sizeof(struct kmem_list3);
+       int node = cpu_to_mem(cpu);
+       int err;
 
        /*
         * We need to do this right in the beginning since
@@ -1180,35 +1203,9 @@ static int __cpuinit cpuup_prepare(long cpu)
         * kmalloc_node allows us to add the slab to the right
         * kmem_list3 and not this cpu's kmem_list3
         */
-
-       list_for_each_entry(cachep, &cache_chain, next) {
-               /*
-                * Set up the size64 kmemlist for cpu before we can
-                * begin anything. Make sure some other cpu on this
-                * node has not already allocated this
-                */
-               if (!cachep->nodelists[node]) {
-                       l3 = kmalloc_node(memsize, GFP_KERNEL, node);
-                       if (!l3)
-                               goto bad;
-                       kmem_list3_init(l3);
-                       l3->next_reap = jiffies + REAPTIMEOUT_LIST3 +
-                           ((unsigned long)cachep) % REAPTIMEOUT_LIST3;
-
-                       /*
-                        * The l3s don't come and go as CPUs come and
-                        * go.  cache_chain_mutex is sufficient
-                        * protection here.
-                        */
-                       cachep->nodelists[node] = l3;
-               }
-
-               spin_lock_irq(&cachep->nodelists[node]->list_lock);
-               cachep->nodelists[node]->free_limit =
-                       (1 + nr_cpus_node(node)) *
-                       cachep->batchcount + cachep->num;
-               spin_unlock_irq(&cachep->nodelists[node]->list_lock);
-       }
+       err = init_cache_nodelists_node(node);
+       if (err < 0)
+               goto bad;
 
        /*
         * Now we can go ahead with allocating the shared arrays and
@@ -1324,18 +1321,82 @@ static int __cpuinit cpuup_callback(struct notifier_block *nfb,
                mutex_unlock(&cache_chain_mutex);
                break;
        }
-       return err ? NOTIFY_BAD : NOTIFY_OK;
+       return notifier_from_errno(err);
 }
 
 static struct notifier_block __cpuinitdata cpucache_notifier = {
        &cpuup_callback, NULL, 0
 };
 
+#if defined(CONFIG_NUMA) && defined(CONFIG_MEMORY_HOTPLUG)
+/*
+ * Drains freelist for a node on each slab cache, used for memory hot-remove.
+ * Returns -EBUSY if all objects cannot be drained so that the node is not
+ * removed.
+ *
+ * Must hold cache_chain_mutex.
+ */
+static int __meminit drain_cache_nodelists_node(int node)
+{
+       struct kmem_cache *cachep;
+       int ret = 0;
+
+       list_for_each_entry(cachep, &cache_chain, next) {
+               struct kmem_list3 *l3;
+
+               l3 = cachep->nodelists[node];
+               if (!l3)
+                       continue;
+
+               drain_freelist(cachep, l3, l3->free_objects);
+
+               if (!list_empty(&l3->slabs_full) ||
+                   !list_empty(&l3->slabs_partial)) {
+                       ret = -EBUSY;
+                       break;
+               }
+       }
+       return ret;
+}
+
+static int __meminit slab_memory_callback(struct notifier_block *self,
+                                       unsigned long action, void *arg)
+{
+       struct memory_notify *mnb = arg;
+       int ret = 0;
+       int nid;
+
+       nid = mnb->status_change_nid;
+       if (nid < 0)
+               goto out;
+
+       switch (action) {
+       case MEM_GOING_ONLINE:
+               mutex_lock(&cache_chain_mutex);
+               ret = init_cache_nodelists_node(nid);
+               mutex_unlock(&cache_chain_mutex);
+               break;
+       case MEM_GOING_OFFLINE:
+               mutex_lock(&cache_chain_mutex);
+               ret = drain_cache_nodelists_node(nid);
+               mutex_unlock(&cache_chain_mutex);
+               break;
+       case MEM_ONLINE:
+       case MEM_OFFLINE:
+       case MEM_CANCEL_ONLINE:
+       case MEM_CANCEL_OFFLINE:
+               break;
+       }
+out:
+       return ret ? notifier_from_errno(ret) : NOTIFY_OK;
+}
+#endif /* CONFIG_NUMA && CONFIG_MEMORY_HOTPLUG */
+
 /*
  * swap the static kmem_list3 with kmalloced memory
  */
-static void init_list(struct kmem_cache *cachep, struct kmem_list3 *list,
-                       int nodeid)
+static void __init init_list(struct kmem_cache *cachep, struct kmem_list3 *list,
+                               int nodeid)
 {
        struct kmem_list3 *ptr;
 
@@ -1418,7 +1479,7 @@ void __init kmem_cache_init(void)
         * 6) Resize the head arrays of the kmalloc caches to their final sizes.
         */
 
-       node = numa_node_id();
+       node = numa_mem_id();
 
        /* 1) create the cache_cache */
        INIT_LIST_HEAD(&cache_chain);
@@ -1580,6 +1641,14 @@ void __init kmem_cache_init_late(void)
         */
        register_cpu_notifier(&cpucache_notifier);
 
+#ifdef CONFIG_NUMA
+       /*
+        * Register a memory hotplug callback that initializes and frees
+        * nodelists.
+        */
+       hotplug_memory_notifier(slab_memory_callback, SLAB_CALLBACK_PRI);
+#endif
+
        /*
         * The reap timers are started later, with a module init call: That part
         * of the kernel is not yet operational.
@@ -2052,7 +2121,7 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep, gfp_t gfp)
                        }
                }
        }
-       cachep->nodelists[numa_node_id()]->next_reap =
+       cachep->nodelists[numa_mem_id()]->next_reap =
                        jiffies + REAPTIMEOUT_LIST3 +
                        ((unsigned long)cachep) % REAPTIMEOUT_LIST3;
 
@@ -2220,8 +2289,8 @@ kmem_cache_create (const char *name, size_t size, size_t align,
        if (ralign < align) {
                ralign = align;
        }
-       /* disable debug if necessary */
-       if (ralign > __alignof__(unsigned long long))
+       /* disable debug if not aligning with REDZONE_ALIGN */
+       if (ralign & (__alignof__(unsigned long long) - 1))
                flags &= ~(SLAB_RED_ZONE | SLAB_STORE_USER);
        /*
         * 4) Store it.
@@ -2247,8 +2316,8 @@ kmem_cache_create (const char *name, size_t size, size_t align,
         */
        if (flags & SLAB_RED_ZONE) {
                /* add space for red zone words */
-               cachep->obj_offset += sizeof(unsigned long long);
-               size += 2 * sizeof(unsigned long long);
+               cachep->obj_offset += align;
+               size += align + sizeof(unsigned long long);
        }
        if (flags & SLAB_STORE_USER) {
                /* user store requires one word storage behind the end of
@@ -2383,7 +2452,7 @@ static void check_spinlock_acquired(struct kmem_cache *cachep)
 {
 #ifdef CONFIG_SMP
        check_irq_off();
-       assert_spin_locked(&cachep->nodelists[numa_node_id()]->list_lock);
+       assert_spin_locked(&cachep->nodelists[numa_mem_id()]->list_lock);
 #endif
 }
 
@@ -2410,7 +2479,7 @@ static void do_drain(void *arg)
 {
        struct kmem_cache *cachep = arg;
        struct array_cache *ac;
-       int node = numa_node_id();
+       int node = numa_mem_id();
 
        check_irq_off();
        ac = cpu_cache_get(cachep);
@@ -2943,7 +3012,7 @@ static void *cache_alloc_refill(struct kmem_cache *cachep, gfp_t flags)
 
 retry:
        check_irq_off();
-       node = numa_node_id();
+       node = numa_mem_id();
        ac = cpu_cache_get(cachep);
        batchcount = ac->batchcount;
        if (!ac->touched && batchcount > BATCHREFILL_LIMIT) {
@@ -3147,11 +3216,13 @@ static void *alternate_node_alloc(struct kmem_cache *cachep, gfp_t flags)
 
        if (in_interrupt() || (flags & __GFP_THISNODE))
                return NULL;
-       nid_alloc = nid_here = numa_node_id();
+       nid_alloc = nid_here = numa_mem_id();
+       get_mems_allowed();
        if (cpuset_do_slab_mem_spread() && (cachep->flags & SLAB_MEM_SPREAD))
-               nid_alloc = cpuset_mem_spread_node();
+               nid_alloc = cpuset_slab_spread_node();
        else if (current->mempolicy)
                nid_alloc = slab_node(current->mempolicy);
+       put_mems_allowed();
        if (nid_alloc != nid_here)
                return ____cache_alloc_node(cachep, flags, nid_alloc);
        return NULL;
@@ -3178,6 +3249,7 @@ static void *fallback_alloc(struct kmem_cache *cache, gfp_t flags)
        if (flags & __GFP_THISNODE)
                return NULL;
 
+       get_mems_allowed();
        zonelist = node_zonelist(slab_node(current->mempolicy), flags);
        local_flags = flags & (GFP_CONSTRAINT_MASK|GFP_RECLAIM_MASK);
 
@@ -3209,7 +3281,7 @@ retry:
                if (local_flags & __GFP_WAIT)
                        local_irq_enable();
                kmem_flagcheck(cache, flags);
-               obj = kmem_getpages(cache, local_flags, numa_node_id());
+               obj = kmem_getpages(cache, local_flags, numa_mem_id());
                if (local_flags & __GFP_WAIT)
                        local_irq_disable();
                if (obj) {
@@ -3233,6 +3305,7 @@ retry:
                        }
                }
        }
+       put_mems_allowed();
        return obj;
 }
 
@@ -3316,6 +3389,7 @@ __cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid,
 {
        unsigned long save_flags;
        void *ptr;
+       int slab_node = numa_mem_id();
 
        flags &= gfp_allowed_mask;
 
@@ -3328,7 +3402,7 @@ __cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid,
        local_irq_save(save_flags);
 
        if (nodeid == -1)
-               nodeid = numa_node_id();
+               nodeid = slab_node;
 
        if (unlikely(!cachep->nodelists[nodeid])) {
                /* Node not bootstrapped yet */
@@ -3336,7 +3410,7 @@ __cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid,
                goto out;
        }
 
-       if (nodeid == numa_node_id()) {
+       if (nodeid == slab_node) {
                /*
                 * Use the locally cached objects if possible.
                 * However ____cache_alloc does not allow fallback
@@ -3380,8 +3454,8 @@ __do_cache_alloc(struct kmem_cache *cache, gfp_t flags)
         * We may just have run out of memory on the local node.
         * ____cache_alloc_node() knows how to locate memory on other nodes
         */
-       if (!objp)
-               objp = ____cache_alloc_node(cache, flags, numa_node_id());
+       if (!objp)
+               objp = ____cache_alloc_node(cache, flags, numa_mem_id());
 
   out:
        return objp;
@@ -3478,7 +3552,7 @@ static void cache_flusharray(struct kmem_cache *cachep, struct array_cache *ac)
 {
        int batchcount;
        struct kmem_list3 *l3;
-       int node = numa_node_id();
+       int node = numa_mem_id();
 
        batchcount = ac->batchcount;
 #if DEBUG
@@ -3912,7 +3986,7 @@ static int do_tune_cpucache(struct kmem_cache *cachep, int limit,
                return -ENOMEM;
 
        for_each_online_cpu(i) {
-               new->new[i] = alloc_arraycache(cpu_to_node(i), limit,
+               new->new[i] = alloc_arraycache(cpu_to_mem(i), limit,
                                                batchcount, gfp);
                if (!new->new[i]) {
                        for (i--; i >= 0; i--)
@@ -3934,9 +4008,9 @@ static int do_tune_cpucache(struct kmem_cache *cachep, int limit,
                struct array_cache *ccold = new->new[i];
                if (!ccold)
                        continue;
-               spin_lock_irq(&cachep->nodelists[cpu_to_node(i)]->list_lock);
-               free_block(cachep, ccold->entry, ccold->avail, cpu_to_node(i));
-               spin_unlock_irq(&cachep->nodelists[cpu_to_node(i)]->list_lock);
+               spin_lock_irq(&cachep->nodelists[cpu_to_mem(i)]->list_lock);
+               free_block(cachep, ccold->entry, ccold->avail, cpu_to_mem(i));
+               spin_unlock_irq(&cachep->nodelists[cpu_to_mem(i)]->list_lock);
                kfree(ccold);
        }
        kfree(new);
@@ -4042,7 +4116,7 @@ static void cache_reap(struct work_struct *w)
 {
        struct kmem_cache *searchp;
        struct kmem_list3 *l3;
-       int node = numa_node_id();
+       int node = numa_mem_id();
        struct delayed_work *work = to_delayed_work(w);
 
        if (!mutex_trylock(&cache_chain_mutex))
@@ -4216,10 +4290,11 @@ static int s_show(struct seq_file *m, void *p)
                unsigned long node_frees = cachep->node_frees;
                unsigned long overflows = cachep->node_overflow;
 
-               seq_printf(m, " : globalstat %7lu %6lu %5lu %4lu \
-                               %4lu %4lu %4lu %4lu %4lu", allocs, high, grown,
-                               reaped, errors, max_freeable, node_allocs,
-                               node_frees, overflows);
+               seq_printf(m, " : globalstat %7lu %6lu %5lu %4lu "
+                          "%4lu %4lu %4lu %4lu %4lu",
+                          allocs, high, grown,
+                          reaped, errors, max_freeable, node_allocs,
+                          node_frees, overflows);
        }
        /* cpu stats */
        {
index 837ebd64cc346875c9f84f2d87ac4b149c137755..23631e2bb57af43c5cb577a75323cc9768798016 100644 (file)
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -467,14 +467,6 @@ out:
  * End of slob allocator proper. Begin kmem_cache_alloc and kmalloc frontend.
  */
 
-#ifndef ARCH_KMALLOC_MINALIGN
-#define ARCH_KMALLOC_MINALIGN __alignof__(unsigned long)
-#endif
-
-#ifndef ARCH_SLAB_MINALIGN
-#define ARCH_SLAB_MINALIGN __alignof__(unsigned long)
-#endif
-
 void *__kmalloc_node(size_t size, gfp_t gfp, int node)
 {
        unsigned int *m;
index d2a54fe71ea22519feada61f181e874685c0a51b..26f0cb9cc5848d1dcae71761700c365e216f38a0 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
 #define SLUB_MERGE_SAME (SLAB_DEBUG_FREE | SLAB_RECLAIM_ACCOUNT | \
                SLAB_CACHE_DMA | SLAB_NOTRACK)
 
-#ifndef ARCH_KMALLOC_MINALIGN
-#define ARCH_KMALLOC_MINALIGN __alignof__(unsigned long long)
-#endif
-
-#ifndef ARCH_SLAB_MINALIGN
-#define ARCH_SLAB_MINALIGN __alignof__(unsigned long long)
-#endif
-
 #define OO_SHIFT       16
 #define OO_MASK                ((1 << OO_SHIFT) - 1)
 #define MAX_OBJS_PER_PAGE      65535 /* since page.objects is u16 */
@@ -1084,7 +1076,7 @@ static inline struct page *alloc_slab_page(gfp_t flags, int node,
        if (node == -1)
                return alloc_pages(flags, order);
        else
-               return alloc_pages_node(node, flags, order);
+               return alloc_pages_exact_node(node, flags, order);
 }
 
 static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
@@ -1368,6 +1360,7 @@ static struct page *get_any_partial(struct kmem_cache *s, gfp_t flags)
                        get_cycles() % 1024 > s->remote_node_defrag_ratio)
                return NULL;
 
+       get_mems_allowed();
        zonelist = node_zonelist(slab_node(current->mempolicy), flags);
        for_each_zone_zonelist(zone, z, zonelist, high_zoneidx) {
                struct kmem_cache_node *n;
@@ -1377,10 +1370,13 @@ static struct page *get_any_partial(struct kmem_cache *s, gfp_t flags)
                if (n && cpuset_zone_allowed_hardwall(zone, flags) &&
                                n->nr_partial > s->min_partial) {
                        page = get_partial_node(n);
-                       if (page)
+                       if (page) {
+                               put_mems_allowed();
                                return page;
+                       }
                }
        }
+       put_mems_allowed();
 #endif
        return NULL;
 }
@@ -2429,9 +2425,11 @@ static void list_slab_objects(struct kmem_cache *s, struct page *page,
 #ifdef CONFIG_SLUB_DEBUG
        void *addr = page_address(page);
        void *p;
-       DECLARE_BITMAP(map, page->objects);
+       long *map = kzalloc(BITS_TO_LONGS(page->objects) * sizeof(long),
+                           GFP_ATOMIC);
 
-       bitmap_zero(map, page->objects);
+       if (!map)
+               return;
        slab_err(s, page, "%s", text);
        slab_lock(page);
        for_each_free_object(p, s, page->freelist)
@@ -2446,6 +2444,7 @@ static void list_slab_objects(struct kmem_cache *s, struct page *page,
                }
        }
        slab_unlock(page);
+       kfree(map);
 #endif
 }
 
@@ -3338,8 +3337,15 @@ void *__kmalloc_node_track_caller(size_t size, gfp_t gfpflags,
        struct kmem_cache *s;
        void *ret;
 
-       if (unlikely(size > SLUB_MAX_SIZE))
-               return kmalloc_large_node(size, gfpflags, node);
+       if (unlikely(size > SLUB_MAX_SIZE)) {
+               ret = kmalloc_large_node(size, gfpflags, node);
+
+               trace_kmalloc_node(caller, ret,
+                                  size, PAGE_SIZE << get_order(size),
+                                  gfpflags, node);
+
+               return ret;
+       }
 
        s = get_slab(size, gfpflags);
 
@@ -3651,10 +3657,10 @@ static int add_location(struct loc_track *t, struct kmem_cache *s,
 }
 
 static void process_slab(struct loc_track *t, struct kmem_cache *s,
-               struct page *page, enum track_item alloc)
+               struct page *page, enum track_item alloc,
+               long *map)
 {
        void *addr = page_address(page);
-       DECLARE_BITMAP(map, page->objects);
        void *p;
 
        bitmap_zero(map, page->objects);
@@ -3673,11 +3679,14 @@ static int list_locations(struct kmem_cache *s, char *buf,
        unsigned long i;
        struct loc_track t = { 0, 0, NULL };
        int node;
+       unsigned long *map = kmalloc(BITS_TO_LONGS(oo_objects(s->max)) *
+                                    sizeof(unsigned long), GFP_KERNEL);
 
-       if (!alloc_loc_track(&t, PAGE_SIZE / sizeof(struct location),
-                       GFP_TEMPORARY))
+       if (!map || !alloc_loc_track(&t, PAGE_SIZE / sizeof(struct location),
+                                    GFP_TEMPORARY)) {
+               kfree(map);
                return sprintf(buf, "Out of memory\n");
-
+       }
        /* Push back cpu slabs */
        flush_all(s);
 
@@ -3691,9 +3700,9 @@ static int list_locations(struct kmem_cache *s, char *buf,
 
                spin_lock_irqsave(&n->list_lock, flags);
                list_for_each_entry(page, &n->partial, lru)
-                       process_slab(&t, s, page, alloc);
+                       process_slab(&t, s, page, alloc, map);
                list_for_each_entry(page, &n->full, lru)
-                       process_slab(&t, s, page, alloc);
+                       process_slab(&t, s, page, alloc, map);
                spin_unlock_irqrestore(&n->list_lock, flags);
        }
 
@@ -3744,6 +3753,7 @@ static int list_locations(struct kmem_cache *s, char *buf,
        }
 
        free_loc_track(&t);
+       kfree(map);
        if (!t.count)
                len += sprintf(buf, "No data\n");
        return len;
index dc0cc4d43ff3ee37f36d70fbde28feef9d56d62e..95ac219af37909c7360ba64892c6f5a369a5ee73 100644 (file)
@@ -382,13 +382,15 @@ static void __init sparse_early_usemaps_alloc_node(unsigned long**usemap_map,
 struct page __init *sparse_mem_map_populate(unsigned long pnum, int nid)
 {
        struct page *map;
+       unsigned long size;
 
        map = alloc_remap(nid, sizeof(struct page) * PAGES_PER_SECTION);
        if (map)
                return map;
 
-       map = alloc_bootmem_pages_node(NODE_DATA(nid),
-                      PAGE_ALIGN(sizeof(struct page) * PAGES_PER_SECTION));
+       size = PAGE_ALIGN(sizeof(struct page) * PAGES_PER_SECTION);
+       map = __alloc_bootmem_node_high(NODE_DATA(nid), size,
+                                        PAGE_SIZE, __pa(MAX_DMA_ADDRESS));
        return map;
 }
 void __init sparse_mem_maps_populate_node(struct page **map_map,
@@ -412,7 +414,8 @@ void __init sparse_mem_maps_populate_node(struct page **map_map,
        }
 
        size = PAGE_ALIGN(size);
-       map = alloc_bootmem_pages_node(NODE_DATA(nodeid), size * map_count);
+       map = __alloc_bootmem_node_high(NODE_DATA(nodeid), size * map_count,
+                                        PAGE_SIZE, __pa(MAX_DMA_ADDRESS));
        if (map) {
                for (pnum = pnum_begin; pnum < pnum_end; pnum++) {
                        if (!present_section_nr(pnum))
index f42675a3615d81ab59e722cc3e3d18b1e1e0525f..937571b8b23370afdcb607ae27a3a897464e46bb 100644 (file)
@@ -548,18 +548,18 @@ EXPORT_SYMBOL(truncate_pagecache);
  * 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.
  */
 int vmtruncate(struct inode *inode, loff_t offset)
 {
-       loff_t oldsize;
        int error;
 
-       error = inode_newsize_ok(inode, offset);
+       error = simple_setsize(inode, offset);
        if (error)
                return error;
-       oldsize = inode->i_size;
-       i_size_write(inode, offset);
-       truncate_pagecache(inode, oldsize, offset);
+
        if (inode->i_op->truncate)
                inode->i_op->truncate(inode);
 
index 3ff3311447f58c2122a5154a85b6cd034d6c7e0e..915dceb487c11b1f1783df86908ba5e6e7317769 100644 (file)
@@ -73,10 +73,14 @@ struct scan_control {
 
        int swappiness;
 
-       int all_unreclaimable;
-
        int order;
 
+       /*
+        * Intend to reclaim enough contenious memory rather than to reclaim
+        * enough amount memory. I.e, it's the mode for high order allocation.
+        */
+       bool lumpy_reclaim_mode;
+
        /* Which cgroup do we reclaim from */
        struct mem_cgroup *mem_cgroup;
 
@@ -85,12 +89,6 @@ struct scan_control {
         * are scanned.
         */
        nodemask_t      *nodemask;
-
-       /* Pluggable isolate pages callback */
-       unsigned long (*isolate_pages)(unsigned long nr, struct list_head *dst,
-                       unsigned long *scanned, int order, int mode,
-                       struct zone *z, struct mem_cgroup *mem_cont,
-                       int active, int file);
 };
 
 #define lru_to_page(_head) (list_entry((_head)->prev, struct page, lru))
@@ -575,7 +573,7 @@ static enum page_references page_check_references(struct page *page,
        referenced_page = TestClearPageReferenced(page);
 
        /* Lumpy reclaim - ignore references */
-       if (sc->order > PAGE_ALLOC_COSTLY_ORDER)
+       if (sc->lumpy_reclaim_mode)
                return PAGEREF_RECLAIM;
 
        /*
@@ -839,11 +837,6 @@ keep:
        return nr_reclaimed;
 }
 
-/* LRU Isolation modes. */
-#define ISOLATE_INACTIVE 0     /* Isolate inactive pages. */
-#define ISOLATE_ACTIVE 1       /* Isolate active pages. */
-#define ISOLATE_BOTH 2         /* Isolate both active and inactive pages. */
-
 /*
  * Attempt to remove the specified page from its LRU.  Only take this page
  * if it is of the appropriate PageActive status.  Pages which are being
@@ -1011,7 +1004,6 @@ static unsigned long isolate_pages_global(unsigned long nr,
                                        struct list_head *dst,
                                        unsigned long *scanned, int order,
                                        int mode, struct zone *z,
-                                       struct mem_cgroup *mem_cont,
                                        int active, int file)
 {
        int lru = LRU_BASE;
@@ -1130,7 +1122,6 @@ static unsigned long shrink_inactive_list(unsigned long max_scan,
        unsigned long nr_scanned = 0;
        unsigned long nr_reclaimed = 0;
        struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(zone, sc);
-       int lumpy_reclaim = 0;
 
        while (unlikely(too_many_isolated(zone, file, sc))) {
                congestion_wait(BLK_RW_ASYNC, HZ/10);
@@ -1140,17 +1131,6 @@ static unsigned long shrink_inactive_list(unsigned long max_scan,
                        return SWAP_CLUSTER_MAX;
        }
 
-       /*
-        * If we need a large contiguous chunk of memory, or have
-        * trouble getting a small set of contiguous pages, we
-        * will reclaim both active and inactive pages.
-        *
-        * We use the same threshold as pageout congestion_wait below.
-        */
-       if (sc->order > PAGE_ALLOC_COSTLY_ORDER)
-               lumpy_reclaim = 1;
-       else if (sc->order && priority < DEF_PRIORITY - 2)
-               lumpy_reclaim = 1;
 
        pagevec_init(&pvec, 1);
 
@@ -1163,15 +1143,15 @@ static unsigned long shrink_inactive_list(unsigned long max_scan,
                unsigned long nr_freed;
                unsigned long nr_active;
                unsigned int count[NR_LRU_LISTS] = { 0, };
-               int mode = lumpy_reclaim ? ISOLATE_BOTH : ISOLATE_INACTIVE;
+               int mode = sc->lumpy_reclaim_mode ? ISOLATE_BOTH : ISOLATE_INACTIVE;
                unsigned long nr_anon;
                unsigned long nr_file;
 
-               nr_taken = sc->isolate_pages(SWAP_CLUSTER_MAX,
-                            &page_list, &nr_scan, sc->order, mode,
-                               zone, sc->mem_cgroup, 0, file);
-
                if (scanning_global_lru(sc)) {
+                       nr_taken = isolate_pages_global(SWAP_CLUSTER_MAX,
+                                                       &page_list, &nr_scan,
+                                                       sc->order, mode,
+                                                       zone, 0, file);
                        zone->pages_scanned += nr_scan;
                        if (current_is_kswapd())
                                __count_zone_vm_events(PGSCAN_KSWAPD, zone,
@@ -1179,6 +1159,16 @@ static unsigned long shrink_inactive_list(unsigned long max_scan,
                        else
                                __count_zone_vm_events(PGSCAN_DIRECT, zone,
                                                       nr_scan);
+               } else {
+                       nr_taken = mem_cgroup_isolate_pages(SWAP_CLUSTER_MAX,
+                                                       &page_list, &nr_scan,
+                                                       sc->order, mode,
+                                                       zone, sc->mem_cgroup,
+                                                       0, file);
+                       /*
+                        * mem_cgroup_isolate_pages() keeps track of
+                        * scanned pages on its own.
+                        */
                }
 
                if (nr_taken == 0)
@@ -1216,7 +1206,7 @@ static unsigned long shrink_inactive_list(unsigned long max_scan,
                 * but that should be acceptable to the caller
                 */
                if (nr_freed < nr_taken && !current_is_kswapd() &&
-                   lumpy_reclaim) {
+                   sc->lumpy_reclaim_mode) {
                        congestion_wait(BLK_RW_ASYNC, HZ/10);
 
                        /*
@@ -1356,16 +1346,23 @@ static void shrink_active_list(unsigned long nr_pages, struct zone *zone,
 
        lru_add_drain();
        spin_lock_irq(&zone->lru_lock);
-       nr_taken = sc->isolate_pages(nr_pages, &l_hold, &pgscanned, sc->order,
-                                       ISOLATE_ACTIVE, zone,
-                                       sc->mem_cgroup, 1, file);
-       /*
-        * zone->pages_scanned is used for detect zone's oom
-        * mem_cgroup remembers nr_scan by itself.
-        */
        if (scanning_global_lru(sc)) {
+               nr_taken = isolate_pages_global(nr_pages, &l_hold,
+                                               &pgscanned, sc->order,
+                                               ISOLATE_ACTIVE, zone,
+                                               1, file);
                zone->pages_scanned += pgscanned;
+       } else {
+               nr_taken = mem_cgroup_isolate_pages(nr_pages, &l_hold,
+                                               &pgscanned, sc->order,
+                                               ISOLATE_ACTIVE, zone,
+                                               sc->mem_cgroup, 1, file);
+               /*
+                * mem_cgroup_isolate_pages() keeps track of
+                * scanned pages on its own.
+                */
        }
+
        reclaim_stat->recent_scanned[file] += nr_taken;
 
        __count_zone_vm_events(PGREFILL, zone, pgscanned);
@@ -1518,22 +1515,53 @@ static unsigned long shrink_list(enum lru_list lru, unsigned long nr_to_scan,
        return shrink_inactive_list(nr_to_scan, zone, sc, priority, file);
 }
 
+/*
+ * Smallish @nr_to_scan's are deposited in @nr_saved_scan,
+ * until we collected @swap_cluster_max pages to scan.
+ */
+static unsigned long nr_scan_try_batch(unsigned long nr_to_scan,
+                                      unsigned long *nr_saved_scan)
+{
+       unsigned long nr;
+
+       *nr_saved_scan += nr_to_scan;
+       nr = *nr_saved_scan;
+
+       if (nr >= SWAP_CLUSTER_MAX)
+               *nr_saved_scan = 0;
+       else
+               nr = 0;
+
+       return nr;
+}
+
 /*
  * Determine how aggressively the anon and file LRU lists should be
  * scanned.  The relative value of each set of LRU lists is determined
  * by looking at the fraction of the pages scanned we did rotate back
  * onto the active list instead of evict.
  *
- * percent[0] specifies how much pressure to put on ram/swap backed
- * memory, while percent[1] determines pressure on the file LRUs.
+ * nr[0] = anon pages to scan; nr[1] = file pages to scan
  */
-static void get_scan_ratio(struct zone *zone, struct scan_control *sc,
-                                       unsigned long *percent)
+static void get_scan_count(struct zone *zone, struct scan_control *sc,
+                                       unsigned long *nr, int priority)
 {
        unsigned long anon, file, free;
        unsigned long anon_prio, file_prio;
        unsigned long ap, fp;
        struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(zone, sc);
+       u64 fraction[2], denominator;
+       enum lru_list l;
+       int noswap = 0;
+
+       /* If we have no swap space, do not bother scanning anon pages. */
+       if (!sc->may_swap || (nr_swap_pages <= 0)) {
+               noswap = 1;
+               fraction[0] = 0;
+               fraction[1] = 1;
+               denominator = 1;
+               goto out;
+       }
 
        anon  = zone_nr_lru_pages(zone, sc, LRU_ACTIVE_ANON) +
                zone_nr_lru_pages(zone, sc, LRU_INACTIVE_ANON);
@@ -1545,9 +1573,10 @@ static void get_scan_ratio(struct zone *zone, struct scan_control *sc,
                /* If we have very few page cache pages,
                   force-scan anon pages. */
                if (unlikely(file + free <= high_wmark_pages(zone))) {
-                       percent[0] = 100;
-                       percent[1] = 0;
-                       return;
+                       fraction[0] = 1;
+                       fraction[1] = 0;
+                       denominator = 1;
+                       goto out;
                }
        }
 
@@ -1594,29 +1623,37 @@ static void get_scan_ratio(struct zone *zone, struct scan_control *sc,
        fp = (file_prio + 1) * (reclaim_stat->recent_scanned[1] + 1);
        fp /= reclaim_stat->recent_rotated[1] + 1;
 
-       /* Normalize to percentages */
-       percent[0] = 100 * ap / (ap + fp + 1);
-       percent[1] = 100 - percent[0];
+       fraction[0] = ap;
+       fraction[1] = fp;
+       denominator = ap + fp + 1;
+out:
+       for_each_evictable_lru(l) {
+               int file = is_file_lru(l);
+               unsigned long scan;
+
+               scan = zone_nr_lru_pages(zone, sc, l);
+               if (priority || noswap) {
+                       scan >>= priority;
+                       scan = div64_u64(scan * fraction[file], denominator);
+               }
+               nr[l] = nr_scan_try_batch(scan,
+                                         &reclaim_stat->nr_saved_scan[l]);
+       }
 }
 
-/*
- * Smallish @nr_to_scan's are deposited in @nr_saved_scan,
- * until we collected @swap_cluster_max pages to scan.
- */
-static unsigned long nr_scan_try_batch(unsigned long nr_to_scan,
-                                      unsigned long *nr_saved_scan)
+static void set_lumpy_reclaim_mode(int priority, struct scan_control *sc)
 {
-       unsigned long nr;
-
-       *nr_saved_scan += nr_to_scan;
-       nr = *nr_saved_scan;
-
-       if (nr >= SWAP_CLUSTER_MAX)
-               *nr_saved_scan = 0;
+       /*
+        * If we need a large contiguous chunk of memory, or have
+        * trouble getting a small set of contiguous pages, we
+        * will reclaim both active and inactive pages.
+        */
+       if (sc->order > PAGE_ALLOC_COSTLY_ORDER)
+               sc->lumpy_reclaim_mode = 1;
+       else if (sc->order && priority < DEF_PRIORITY - 2)
+               sc->lumpy_reclaim_mode = 1;
        else
-               nr = 0;
-
-       return nr;
+               sc->lumpy_reclaim_mode = 0;
 }
 
 /*
@@ -1627,33 +1664,13 @@ static void shrink_zone(int priority, struct zone *zone,
 {
        unsigned long nr[NR_LRU_LISTS];
        unsigned long nr_to_scan;
-       unsigned long percent[2];       /* anon @ 0; file @ 1 */
        enum lru_list l;
        unsigned long nr_reclaimed = sc->nr_reclaimed;
        unsigned long nr_to_reclaim = sc->nr_to_reclaim;
-       struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(zone, sc);
-       int noswap = 0;
-
-       /* If we have no swap space, do not bother scanning anon pages. */
-       if (!sc->may_swap || (nr_swap_pages <= 0)) {
-               noswap = 1;
-               percent[0] = 0;
-               percent[1] = 100;
-       } else
-               get_scan_ratio(zone, sc, percent);
 
-       for_each_evictable_lru(l) {
-               int file = is_file_lru(l);
-               unsigned long scan;
+       get_scan_count(zone, sc, nr, priority);
 
-               scan = zone_nr_lru_pages(zone, sc, l);
-               if (priority || noswap) {
-                       scan >>= priority;
-                       scan = (scan * percent[file]) / 100;
-               }
-               nr[l] = nr_scan_try_batch(scan,
-                                         &reclaim_stat->nr_saved_scan[l]);
-       }
+       set_lumpy_reclaim_mode(priority, sc);
 
        while (nr[LRU_INACTIVE_ANON] || nr[LRU_ACTIVE_FILE] ||
                                        nr[LRU_INACTIVE_FILE]) {
@@ -1707,14 +1724,14 @@ 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 void shrink_zones(int priority, struct zonelist *zonelist,
+static int 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;
 
-       sc->all_unreclaimable = 1;
        for_each_zone_zonelist_nodemask(zone, z, zonelist, high_zoneidx,
                                        sc->nodemask) {
                if (!populated_zone(zone))
@@ -1730,19 +1747,19 @@ static void shrink_zones(int priority, struct zonelist *zonelist,
 
                        if (zone->all_unreclaimable && priority != DEF_PRIORITY)
                                continue;       /* Let kswapd poll it */
-                       sc->all_unreclaimable = 0;
                } else {
                        /*
                         * Ignore cpuset limitation here. We just want to reduce
                         * # of used pages by us regardless of memory shortage.
                         */
-                       sc->all_unreclaimable = 0;
                        mem_cgroup_note_reclaim_priority(sc->mem_cgroup,
                                                        priority);
                }
 
                shrink_zone(priority, zone, sc);
+               progress = 1;
        }
+       return progress;
 }
 
 /*
@@ -1774,6 +1791,7 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
        enum zone_type high_zoneidx = gfp_zone(sc->gfp_mask);
        unsigned long writeback_threshold;
 
+       get_mems_allowed();
        delayacct_freepages_start();
 
        if (scanning_global_lru(sc))
@@ -1795,7 +1813,7 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
                sc->nr_scanned = 0;
                if (!priority)
                        disable_swap_token();
-               shrink_zones(priority, zonelist, sc);
+               ret = shrink_zones(priority, zonelist, sc);
                /*
                 * Don't shrink slabs when reclaiming memory from
                 * over limit cgroups
@@ -1832,7 +1850,7 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
                        congestion_wait(BLK_RW_ASYNC, HZ/10);
        }
        /* top priority shrink_zones still had more to do? don't OOM, then */
-       if (!sc->all_unreclaimable && scanning_global_lru(sc))
+       if (ret && scanning_global_lru(sc))
                ret = sc->nr_reclaimed;
 out:
        /*
@@ -1857,6 +1875,7 @@ out:
                mem_cgroup_record_reclaim_priority(sc->mem_cgroup, priority);
 
        delayacct_freepages_end();
+       put_mems_allowed();
 
        return ret;
 }
@@ -1873,7 +1892,6 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
                .swappiness = vm_swappiness,
                .order = order,
                .mem_cgroup = NULL,
-               .isolate_pages = isolate_pages_global,
                .nodemask = nodemask,
        };
 
@@ -1894,7 +1912,6 @@ unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *mem,
                .swappiness = swappiness,
                .order = 0,
                .mem_cgroup = mem,
-               .isolate_pages = mem_cgroup_isolate_pages,
        };
        nodemask_t nm  = nodemask_of_node(nid);
 
@@ -1928,7 +1945,6 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem_cont,
                .swappiness = swappiness,
                .order = 0,
                .mem_cgroup = mem_cont,
-               .isolate_pages = mem_cgroup_isolate_pages,
                .nodemask = NULL, /* we don't care the placement */
        };
 
@@ -2006,7 +2022,6 @@ static unsigned long balance_pgdat(pg_data_t *pgdat, int order)
                .swappiness = vm_swappiness,
                .order = order,
                .mem_cgroup = NULL,
-               .isolate_pages = isolate_pages_global,
        };
        /*
         * temp_priority is used to remember the scanning priority at which
@@ -2385,7 +2400,6 @@ unsigned long shrink_all_memory(unsigned long nr_to_reclaim)
                .hibernation_mode = 1,
                .swappiness = vm_swappiness,
                .order = 0,
-               .isolate_pages = isolate_pages_global,
        };
        struct zonelist * zonelist = node_zonelist(numa_node_id(), sc.gfp_mask);
        struct task_struct *p = current;
@@ -2570,7 +2584,6 @@ static int __zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order)
                .gfp_mask = gfp_mask,
                .swappiness = vm_swappiness,
                .order = order,
-               .isolate_pages = isolate_pages_global,
        };
        unsigned long slab_reclaimable;
 
index fa12ea3051fb109c18f66ee41da49fd2f7ff4fdb..7759941d4e7760616e1bf89c0ed887f485b473a9 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/cpu.h>
 #include <linux/vmstat.h>
 #include <linux/sched.h>
+#include <linux/math64.h>
 
 #ifdef CONFIG_VM_EVENT_COUNTERS
 DEFINE_PER_CPU(struct vm_event_state, vm_event_states) = {{0}};
@@ -379,7 +380,86 @@ void zone_statistics(struct zone *preferred_zone, struct zone *z)
 }
 #endif
 
-#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_COMPACTION
+struct contig_page_info {
+       unsigned long free_pages;
+       unsigned long free_blocks_total;
+       unsigned long free_blocks_suitable;
+};
+
+/*
+ * Calculate the number of free pages in a zone, how many contiguous
+ * pages are free and how many are large enough to satisfy an allocation of
+ * the target size. Note that this function makes no attempt to estimate
+ * how many suitable free blocks there *might* be if MOVABLE pages were
+ * migrated. Calculating that is possible, but expensive and can be
+ * figured out from userspace
+ */
+static void fill_contig_page_info(struct zone *zone,
+                               unsigned int suitable_order,
+                               struct contig_page_info *info)
+{
+       unsigned int order;
+
+       info->free_pages = 0;
+       info->free_blocks_total = 0;
+       info->free_blocks_suitable = 0;
+
+       for (order = 0; order < MAX_ORDER; order++) {
+               unsigned long blocks;
+
+               /* Count number of free blocks */
+               blocks = zone->free_area[order].nr_free;
+               info->free_blocks_total += blocks;
+
+               /* Count free base pages */
+               info->free_pages += blocks << order;
+
+               /* Count the suitable free blocks */
+               if (order >= suitable_order)
+                       info->free_blocks_suitable += blocks <<
+                                               (order - suitable_order);
+       }
+}
+
+/*
+ * A fragmentation index only makes sense if an allocation of a requested
+ * size would fail. If that is true, the fragmentation index indicates
+ * whether external fragmentation or a lack of memory was the problem.
+ * The value can be used to determine if page reclaim or compaction
+ * should be used
+ */
+static int __fragmentation_index(unsigned int order, struct contig_page_info *info)
+{
+       unsigned long requested = 1UL << order;
+
+       if (!info->free_blocks_total)
+               return 0;
+
+       /* Fragmentation index only makes sense when a request would fail */
+       if (info->free_blocks_suitable)
+               return -1000;
+
+       /*
+        * Index is between 0 and 1 so return within 3 decimal places
+        *
+        * 0 => allocation would fail due to lack of memory
+        * 1 => allocation would fail due to fragmentation
+        */
+       return 1000 - div_u64( (1000+(div_u64(info->free_pages * 1000ULL, requested))), info->free_blocks_total);
+}
+
+/* Same as __fragmentation index but allocs contig_page_info on stack */
+int fragmentation_index(struct zone *zone, unsigned int order)
+{
+       struct contig_page_info info;
+
+       fill_contig_page_info(zone, order, &info);
+       return __fragmentation_index(order, &info);
+}
+#endif
+
+#if defined(CONFIG_PROC_FS) || defined(CONFIG_COMPACTION)
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 
@@ -432,7 +512,9 @@ static void walk_zones_in_node(struct seq_file *m, pg_data_t *pgdat,
                spin_unlock_irqrestore(&zone->lock, flags);
        }
 }
+#endif
 
+#ifdef CONFIG_PROC_FS
 static void frag_show_print(struct seq_file *m, pg_data_t *pgdat,
                                                struct zone *zone)
 {
@@ -693,6 +775,16 @@ static const char * const vmstat_text[] = {
        "allocstall",
 
        "pgrotated",
+
+#ifdef CONFIG_COMPACTION
+       "compact_blocks_moved",
+       "compact_pages_moved",
+       "compact_pagemigrate_failed",
+       "compact_stall",
+       "compact_fail",
+       "compact_success",
+#endif
+
 #ifdef CONFIG_HUGETLB_PAGE
        "htlb_buddy_alloc_success",
        "htlb_buddy_alloc_fail",
@@ -954,3 +1046,162 @@ static int __init setup_vmstat(void)
        return 0;
 }
 module_init(setup_vmstat)
+
+#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_COMPACTION)
+#include <linux/debugfs.h>
+
+static struct dentry *extfrag_debug_root;
+
+/*
+ * Return an index indicating how much of the available free memory is
+ * unusable for an allocation of the requested size.
+ */
+static int unusable_free_index(unsigned int order,
+                               struct contig_page_info *info)
+{
+       /* No free memory is interpreted as all free memory is unusable */
+       if (info->free_pages == 0)
+               return 1000;
+
+       /*
+        * Index should be a value between 0 and 1. Return a value to 3
+        * decimal places.
+        *
+        * 0 => no fragmentation
+        * 1 => high fragmentation
+        */
+       return div_u64((info->free_pages - (info->free_blocks_suitable << order)) * 1000ULL, info->free_pages);
+
+}
+
+static void unusable_show_print(struct seq_file *m,
+                                       pg_data_t *pgdat, struct zone *zone)
+{
+       unsigned int order;
+       int index;
+       struct contig_page_info info;
+
+       seq_printf(m, "Node %d, zone %8s ",
+                               pgdat->node_id,
+                               zone->name);
+       for (order = 0; order < MAX_ORDER; ++order) {
+               fill_contig_page_info(zone, order, &info);
+               index = unusable_free_index(order, &info);
+               seq_printf(m, "%d.%03d ", index / 1000, index % 1000);
+       }
+
+       seq_putc(m, '\n');
+}
+
+/*
+ * Display unusable free space index
+ *
+ * The unusable free space index measures how much of the available free
+ * memory cannot be used to satisfy an allocation of a given size and is a
+ * value between 0 and 1. The higher the value, the more of free memory is
+ * unusable and by implication, the worse the external fragmentation is. This
+ * can be expressed as a percentage by multiplying by 100.
+ */
+static int unusable_show(struct seq_file *m, void *arg)
+{
+       pg_data_t *pgdat = (pg_data_t *)arg;
+
+       /* check memoryless node */
+       if (!node_state(pgdat->node_id, N_HIGH_MEMORY))
+               return 0;
+
+       walk_zones_in_node(m, pgdat, unusable_show_print);
+
+       return 0;
+}
+
+static const struct seq_operations unusable_op = {
+       .start  = frag_start,
+       .next   = frag_next,
+       .stop   = frag_stop,
+       .show   = unusable_show,
+};
+
+static int unusable_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &unusable_op);
+}
+
+static const struct file_operations unusable_file_ops = {
+       .open           = unusable_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
+static void extfrag_show_print(struct seq_file *m,
+                                       pg_data_t *pgdat, struct zone *zone)
+{
+       unsigned int order;
+       int index;
+
+       /* Alloc on stack as interrupts are disabled for zone walk */
+       struct contig_page_info info;
+
+       seq_printf(m, "Node %d, zone %8s ",
+                               pgdat->node_id,
+                               zone->name);
+       for (order = 0; order < MAX_ORDER; ++order) {
+               fill_contig_page_info(zone, order, &info);
+               index = __fragmentation_index(order, &info);
+               seq_printf(m, "%d.%03d ", index / 1000, index % 1000);
+       }
+
+       seq_putc(m, '\n');
+}
+
+/*
+ * Display fragmentation index for orders that allocations would fail for
+ */
+static int extfrag_show(struct seq_file *m, void *arg)
+{
+       pg_data_t *pgdat = (pg_data_t *)arg;
+
+       walk_zones_in_node(m, pgdat, extfrag_show_print);
+
+       return 0;
+}
+
+static const struct seq_operations extfrag_op = {
+       .start  = frag_start,
+       .next   = frag_next,
+       .stop   = frag_stop,
+       .show   = extfrag_show,
+};
+
+static int extfrag_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &extfrag_op);
+}
+
+static const struct file_operations extfrag_file_ops = {
+       .open           = extfrag_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
+static int __init extfrag_debug_init(void)
+{
+       extfrag_debug_root = debugfs_create_dir("extfrag", NULL);
+       if (!extfrag_debug_root)
+               return -ENOMEM;
+
+       if (!debugfs_create_file("unusable_index", 0444,
+                       extfrag_debug_root, NULL, &unusable_file_ops))
+               return -ENOMEM;
+
+       if (!debugfs_create_file("extfrag_index", 0444,
+                       extfrag_debug_root, NULL, &extfrag_file_ops))
+               return -ENOMEM;
+
+       return 0;
+}
+
+module_init(extfrag_debug_init);
+#endif
index 0aa79faa98509a1d91f71cec5c307f3522c2a58d..37c8da07a80b080c6d93f9a2bdd1226873354af8 100644 (file)
@@ -1321,7 +1321,8 @@ static int p9_client_statsize(struct p9_wstat *wst, int proto_version)
        if (wst->muid)
                ret += strlen(wst->muid);
 
-       if (proto_version == p9_proto_2000u) {
+       if ((proto_version == p9_proto_2000u) ||
+               (proto_version == p9_proto_2000L)) {
                ret += 2+4+4+4; /* extension[s] n_uid[4] n_gid[4] n_muid[4] */
                if (wst->extension)
                        ret += strlen(wst->extension);
@@ -1364,3 +1365,70 @@ error:
        return err;
 }
 EXPORT_SYMBOL(p9_client_wstat);
+
+int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb)
+{
+       int err;
+       struct p9_req_t *req;
+       struct p9_client *clnt;
+
+       err = 0;
+       clnt = fid->clnt;
+
+       P9_DPRINTK(P9_DEBUG_9P, ">>> TSTATFS fid %d\n", fid->fid);
+
+       req = p9_client_rpc(clnt, P9_TSTATFS, "d", fid->fid);
+       if (IS_ERR(req)) {
+               err = PTR_ERR(req);
+               goto error;
+       }
+
+       err = p9pdu_readf(req->rc, clnt->proto_version, "ddqqqqqqd", &sb->type,
+               &sb->bsize, &sb->blocks, &sb->bfree, &sb->bavail,
+               &sb->files, &sb->ffree, &sb->fsid, &sb->namelen);
+       if (err) {
+               p9pdu_dump(1, req->rc);
+               p9_free_req(clnt, req);
+               goto error;
+       }
+
+       P9_DPRINTK(P9_DEBUG_9P, "<<< RSTATFS fid %d type 0x%lx bsize %ld "
+               "blocks %llu bfree %llu bavail %llu files %llu ffree %llu "
+               "fsid %llu namelen %ld\n",
+               fid->fid, (long unsigned int)sb->type, (long int)sb->bsize,
+               sb->blocks, sb->bfree, sb->bavail, sb->files,  sb->ffree,
+               sb->fsid, (long int)sb->namelen);
+
+       p9_free_req(clnt, req);
+error:
+       return err;
+}
+EXPORT_SYMBOL(p9_client_statfs);
+
+int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid, char *name)
+{
+       int err;
+       struct p9_req_t *req;
+       struct p9_client *clnt;
+
+       err = 0;
+       clnt = fid->clnt;
+
+       P9_DPRINTK(P9_DEBUG_9P, ">>> TRENAME fid %d newdirfid %d name %s\n",
+                       fid->fid, newdirfid->fid, name);
+
+       req = p9_client_rpc(clnt, P9_TRENAME, "dds", fid->fid,
+                       newdirfid->fid, name);
+       if (IS_ERR(req)) {
+               err = PTR_ERR(req);
+               goto error;
+       }
+
+       P9_DPRINTK(P9_DEBUG_9P, "<<< RRENAME fid %d\n", fid->fid);
+
+       p9_free_req(clnt, req);
+error:
+       return err;
+}
+EXPORT_SYMBOL(p9_client_rename);
+
index e7541d5b011831e6c945d9cfb9163c90f9b1d1fd..149f82160130684701118255d2ec73f31667c72d 100644 (file)
@@ -341,7 +341,8 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
                        }
                        break;
                case '?':
-                       if (proto_version != p9_proto_2000u)
+                       if ((proto_version != p9_proto_2000u) &&
+                               (proto_version != p9_proto_2000L))
                                return 0;
                        break;
                default:
@@ -393,7 +394,7 @@ p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
                                const char *sptr = va_arg(ap, const char *);
                                int16_t len = 0;
                                if (sptr)
-                                       len = MIN(strlen(sptr), USHORT_MAX);
+                                       len = MIN(strlen(sptr), USHRT_MAX);
 
                                errcode = p9pdu_writef(pdu, proto_version,
                                                                "w", len);
@@ -488,7 +489,8 @@ p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
                        }
                        break;
                case '?':
-                       if (proto_version != p9_proto_2000u)
+                       if ((proto_version != p9_proto_2000u) &&
+                               (proto_version != p9_proto_2000L))
                                return 0;
                        break;
                default:
index 7eb78ecc16181cb6d6fc697ac50812882d0c9c8d..dcfbe99ff81c8c0ac56031e1cbbd56bb7ed2fcd4 100644 (file)
@@ -137,7 +137,7 @@ static void req_done(struct virtqueue *vq)
 
        P9_DPRINTK(P9_DEBUG_TRANS, ": request done\n");
 
-       while ((rc = chan->vq->vq_ops->get_buf(chan->vq, &len)) != NULL) {
+       while ((rc = virtqueue_get_buf(chan->vq, &len)) != NULL) {
                P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p\n", rc);
                P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n", rc->tag);
                req = p9_tag_lookup(chan->client, rc->tag);
@@ -209,13 +209,13 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
 
        req->status = REQ_STATUS_SENT;
 
-       if (chan->vq->vq_ops->add_buf(chan->vq, chan->sg, out, in, req->tc) < 0) {
+       if (virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc) < 0) {
                P9_DPRINTK(P9_DEBUG_TRANS,
                        "9p debug: virtio rpc add_buf returned failure");
                return -EIO;
        }
 
-       chan->vq->vq_ops->kick(chan->vq);
+       virtqueue_kick(chan->vq);
 
        P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request kicked\n");
        return 0;
index cd1daf6008bd01b6947b259963347649ea37dea2..ed651786f16b5ab231ab74c3be054cfeab7183ff 100644 (file)
@@ -2,10 +2,8 @@
 # CAIF net configurations
 #
 
-#menu "CAIF Support"
-comment "CAIF Support"
 menuconfig CAIF
-       tristate "Enable CAIF support"
+       tristate "CAIF support"
        select CRC_CCITT
        default n
        ---help---
@@ -45,4 +43,3 @@ config CAIF_NETDEV
        If unsure say Y.
 
 endif
-#endmenu
index c3a70c5c893a8efe0603b5e4a82a4e4ae515b10f..3d0e09584fae59611c1599503356eef19f7c0379 100644 (file)
@@ -60,7 +60,7 @@ struct debug_fs_counter {
        atomic_t num_rx_flow_off;
        atomic_t num_rx_flow_on;
 };
-struct debug_fs_counter cnt;
+static struct debug_fs_counter cnt;
 #define        dbfs_atomic_inc(v) atomic_inc(v)
 #define        dbfs_atomic_dec(v) atomic_dec(v)
 #else
@@ -128,17 +128,17 @@ static void caif_read_unlock(struct sock *sk)
        mutex_unlock(&cf_sk->readlock);
 }
 
-int sk_rcvbuf_lowwater(struct caifsock *cf_sk)
+static int sk_rcvbuf_lowwater(struct caifsock *cf_sk)
 {
        /* A quarter of full buffer is used a low water mark */
        return cf_sk->sk.sk_rcvbuf / 4;
 }
 
-void caif_flow_ctrl(struct sock *sk, int mode)
+static void caif_flow_ctrl(struct sock *sk, int mode)
 {
        struct caifsock *cf_sk;
        cf_sk = container_of(sk, struct caifsock, sk);
-       if (cf_sk->layer.dn)
+       if (cf_sk->layer.dn && cf_sk->layer.dn->modemcmd)
                cf_sk->layer.dn->modemcmd(cf_sk->layer.dn, mode);
 }
 
@@ -146,7 +146,7 @@ void caif_flow_ctrl(struct sock *sk, int mode)
  * Copied from sock.c:sock_queue_rcv_skb(), but changed so packets are
  * not dropped, but CAIF is sending flow off instead.
  */
-int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
+static int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
        int err;
        int skb_len;
@@ -162,9 +162,8 @@ int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
                        atomic_read(&cf_sk->sk.sk_rmem_alloc),
                        sk_rcvbuf_lowwater(cf_sk));
                set_rx_flow_off(cf_sk);
-               if (cf_sk->layer.dn)
-                       cf_sk->layer.dn->modemcmd(cf_sk->layer.dn,
-                                               CAIF_MODEMCMD_FLOW_OFF_REQ);
+               dbfs_atomic_inc(&cnt.num_rx_flow_off);
+               caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_OFF_REQ);
        }
 
        err = sk_filter(sk, skb);
@@ -175,9 +174,8 @@ int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
                trace_printk("CAIF: %s():"
                        " sending flow OFF due to rmem_schedule\n",
                        __func__);
-               if (cf_sk->layer.dn)
-                       cf_sk->layer.dn->modemcmd(cf_sk->layer.dn,
-                                               CAIF_MODEMCMD_FLOW_OFF_REQ);
+               dbfs_atomic_inc(&cnt.num_rx_flow_off);
+               caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_OFF_REQ);
        }
        skb->dev = NULL;
        skb_set_owner_r(skb, sk);
@@ -285,65 +283,51 @@ static void caif_check_flow_release(struct sock *sk)
 {
        struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
 
-       if (cf_sk->layer.dn == NULL || cf_sk->layer.dn->modemcmd == NULL)
-               return;
        if (rx_flow_is_on(cf_sk))
                return;
 
        if (atomic_read(&sk->sk_rmem_alloc) <= sk_rcvbuf_lowwater(cf_sk)) {
                        dbfs_atomic_inc(&cnt.num_rx_flow_on);
                        set_rx_flow_on(cf_sk);
-                       cf_sk->layer.dn->modemcmd(cf_sk->layer.dn,
-                                               CAIF_MODEMCMD_FLOW_ON_REQ);
+                       caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_ON_REQ);
        }
 }
+
 /*
- * Copied from sock.c:sock_queue_rcv_skb(), and added check that user buffer
- * has sufficient size.
+ * Copied from unix_dgram_recvmsg, but removed credit checks,
+ * changed locking, address handling and added MSG_TRUNC.
  */
-
 static int caif_seqpkt_recvmsg(struct kiocb *iocb, struct socket *sock,
-                               struct msghdr *m, size_t buf_len, int flags)
+                               struct msghdr *m, size_t len, int flags)
 
 {
        struct sock *sk = sock->sk;
        struct sk_buff *skb;
-       int ret = 0;
-       int len;
+       int ret;
+       int copylen;
 
-       if (unlikely(!buf_len))
-               return -EINVAL;
+       ret = -EOPNOTSUPP;
+       if (m->msg_flags&MSG_OOB)
+               goto read_error;
 
        skb = skb_recv_datagram(sk, flags, 0 , &ret);
        if (!skb)
                goto read_error;
-
-       len = skb->len;
-
-       if (skb && skb->len > buf_len && !(flags & MSG_PEEK)) {
-               len = buf_len;
-               /*
-                * Push skb back on receive queue if buffer too small.
-                * This has a built-in race where multi-threaded receive
-                * may get packet in wrong order, but multiple read does
-                * not really guarantee ordered delivery anyway.
-                * Let's optimize for speed without taking locks.
-                */
-
-               skb_queue_head(&sk->sk_receive_queue, skb);
-               ret = -EMSGSIZE;
-               goto read_error;
+       copylen = skb->len;
+       if (len < copylen) {
+               m->msg_flags |= MSG_TRUNC;
+               copylen = len;
        }
 
-       ret = skb_copy_datagram_iovec(skb, 0, m->msg_iov, len);
+       ret = skb_copy_datagram_iovec(skb, 0, m->msg_iov, copylen);
        if (ret)
-               goto read_error;
+               goto out_free;
 
+       ret = (flags & MSG_TRUNC) ? skb->len : copylen;
+out_free:
        skb_free_datagram(sk, skb);
-
        caif_check_flow_release(sk);
-
-       return len;
+       return ret;
 
 read_error:
        return ret;
@@ -920,17 +904,17 @@ wait_connect:
        timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
 
        release_sock(sk);
-       err = wait_event_interruptible_timeout(*sk_sleep(sk),
+       err = -ERESTARTSYS;
+       timeo = wait_event_interruptible_timeout(*sk_sleep(sk),
                        sk->sk_state != CAIF_CONNECTING,
                        timeo);
        lock_sock(sk);
-       if (err < 0)
+       if (timeo < 0)
                goto out; /* -ERESTARTSYS */
-       if (err == 0 && sk->sk_state != CAIF_CONNECTED) {
-               err = -ETIMEDOUT;
-               goto out;
-       }
 
+       err = -ETIMEDOUT;
+       if (timeo == 0 && sk->sk_state != CAIF_CONNECTED)
+               goto out;
        if (sk->sk_state != CAIF_CONNECTED) {
                sock->state = SS_UNCONNECTED;
                err = sock_error(sk);
@@ -945,7 +929,6 @@ out:
        return err;
 }
 
-
 /*
  * caif_release() - Disconnect a CAIF Socket
  * Copied and modified af_irda.c:irda_release().
@@ -1019,10 +1002,6 @@ static unsigned int caif_poll(struct file *file,
                (sk->sk_shutdown & RCV_SHUTDOWN))
                mask |= POLLIN | POLLRDNORM;
 
-       /* Connection-based need to check for termination and startup */
-       if (sk->sk_state == CAIF_DISCONNECTED)
-               mask |= POLLHUP;
-
        /*
         * we set writable also when the other side has shut down the
         * connection. This prevents stuck sockets.
@@ -1194,7 +1173,7 @@ static struct net_proto_family caif_family_ops = {
        .owner = THIS_MODULE,
 };
 
-int af_caif_init(void)
+static int af_caif_init(void)
 {
        int err = sock_register(&caif_family_ops);
        if (!err)
index 0ffe1e1ce90164ba9acfa780a3769c4c967f2d48..fcfda98a5e6d3e5eb2f01aa85912acc6982a1e1f 100644 (file)
@@ -44,13 +44,14 @@ struct cflayer *cfctrl_create(void)
        dev_info.id = 0xff;
        memset(this, 0, sizeof(*this));
        cfsrvl_init(&this->serv, 0, &dev_info);
-       spin_lock_init(&this->info_list_lock);
        atomic_set(&this->req_seq_no, 1);
        atomic_set(&this->rsp_seq_no, 1);
        this->serv.layer.receive = cfctrl_recv;
        sprintf(this->serv.layer.name, "ctrl");
        this->serv.layer.ctrlcmd = cfctrl_ctrlcmd;
        spin_lock_init(&this->loop_linkid_lock);
+       spin_lock_init(&this->info_list_lock);
+       INIT_LIST_HEAD(&this->list);
        this->loop_linkid = 1;
        return &this->serv.layer;
 }
@@ -112,20 +113,10 @@ bool cfctrl_req_eq(struct cfctrl_request_info *r1,
 void cfctrl_insert_req(struct cfctrl *ctrl,
                              struct cfctrl_request_info *req)
 {
-       struct cfctrl_request_info *p;
        spin_lock(&ctrl->info_list_lock);
-       req->next = NULL;
        atomic_inc(&ctrl->req_seq_no);
        req->sequence_no = atomic_read(&ctrl->req_seq_no);
-       if (ctrl->first_req == NULL) {
-               ctrl->first_req = req;
-               spin_unlock(&ctrl->info_list_lock);
-               return;
-       }
-       p = ctrl->first_req;
-       while (p->next != NULL)
-               p = p->next;
-       p->next = req;
+       list_add_tail(&req->list, &ctrl->list);
        spin_unlock(&ctrl->info_list_lock);
 }
 
@@ -133,46 +124,28 @@ void cfctrl_insert_req(struct cfctrl *ctrl,
 struct cfctrl_request_info *cfctrl_remove_req(struct cfctrl *ctrl,
                                              struct cfctrl_request_info *req)
 {
-       struct cfctrl_request_info *p;
-       struct cfctrl_request_info *ret;
+       struct cfctrl_request_info *p, *tmp, *first;
 
        spin_lock(&ctrl->info_list_lock);
-       if (ctrl->first_req == NULL) {
-               spin_unlock(&ctrl->info_list_lock);
-               return NULL;
-       }
-
-       if (cfctrl_req_eq(req, ctrl->first_req)) {
-               ret = ctrl->first_req;
-               caif_assert(ctrl->first_req);
-               atomic_set(&ctrl->rsp_seq_no,
-                                ctrl->first_req->sequence_no);
-               ctrl->first_req = ctrl->first_req->next;
-               spin_unlock(&ctrl->info_list_lock);
-               return ret;
-       }
+       first = list_first_entry(&ctrl->list, struct cfctrl_request_info, list);
 
-       p = ctrl->first_req;
-
-       while (p->next != NULL) {
-               if (cfctrl_req_eq(req, p->next)) {
-                       pr_warning("CAIF: %s(): Requests are not "
+       list_for_each_entry_safe(p, tmp, &ctrl->list, list) {
+               if (cfctrl_req_eq(req, p)) {
+                       if (p != first)
+                               pr_warning("CAIF: %s(): Requests are not "
                                        "received in order\n",
                                        __func__);
-                       ret = p->next;
+
                        atomic_set(&ctrl->rsp_seq_no,
-                                       p->next->sequence_no);
-                       p->next = p->next->next;
-                       spin_unlock(&ctrl->info_list_lock);
-                       return ret;
+                                        p->sequence_no);
+                       list_del(&p->list);
+                       goto out;
                }
-               p = p->next;
        }
+       p = NULL;
+out:
        spin_unlock(&ctrl->info_list_lock);
-
-       pr_warning("CAIF: %s(): Request does not match\n",
-                  __func__);
-       return NULL;
+       return p;
 }
 
 struct cfctrl_rsp *cfctrl_get_respfuncs(struct cflayer *layer)
@@ -388,31 +361,18 @@ void cfctrl_getstartreason_req(struct cflayer *layer)
 
 void cfctrl_cancel_req(struct cflayer *layr, struct cflayer *adap_layer)
 {
-       struct cfctrl_request_info *p, *req;
+       struct cfctrl_request_info *p, *tmp;
        struct cfctrl *ctrl = container_obj(layr);
        spin_lock(&ctrl->info_list_lock);
-
-       if (ctrl->first_req == NULL) {
-               spin_unlock(&ctrl->info_list_lock);
-               return;
-       }
-
-       if (ctrl->first_req->client_layer == adap_layer) {
-
-               req = ctrl->first_req;
-               ctrl->first_req = ctrl->first_req->next;
-               kfree(req);
-       }
-
-       p = ctrl->first_req;
-       while (p != NULL && p->next != NULL) {
-               if (p->next->client_layer == adap_layer) {
-
-                       req = p->next;
-                       p->next = p->next->next;
-                       kfree(p->next);
+       pr_warning("CAIF: %s(): enter\n", __func__);
+
+       list_for_each_entry_safe(p, tmp, &ctrl->list, list) {
+               if (p->client_layer == adap_layer) {
+                       pr_warning("CAIF: %s(): cancel req :%d\n", __func__,
+                                       p->sequence_no);
+                       list_del(&p->list);
+                       kfree(p);
                }
-               p = p->next;
        }
 
        spin_unlock(&ctrl->info_list_lock);
@@ -634,7 +594,7 @@ static void cfctrl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
        case _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND:
        case CAIF_CTRLCMD_FLOW_OFF_IND:
                spin_lock(&this->info_list_lock);
-               if (this->first_req != NULL) {
+               if (!list_empty(&this->list)) {
                        pr_debug("CAIF: %s(): Received flow off in "
                                   "control layer", __func__);
                }
index 7372f27f1d328c511374bdb29f7a63751d9fa5bb..80c8d332b2586fb1a4a2ddacca97f20fba9047ae 100644 (file)
@@ -174,10 +174,11 @@ struct cflayer *cfmuxl_remove_uplayer(struct cflayer *layr, u8 id)
        spin_lock(&muxl->receive_lock);
        up = get_up(muxl, id);
        if (up == NULL)
-               return NULL;
+               goto out;
        memset(muxl->up_cache, 0, sizeof(muxl->up_cache));
        list_del(&up->node);
        cfsrvl_put(up);
+out:
        spin_unlock(&muxl->receive_lock);
        return up;
 }
index 83fff2ff665888cc1e8c54a958066a638a1417cd..a6fdf899741a5298fb92733f18ae359b4c0c3fbe 100644 (file)
@@ -238,6 +238,7 @@ int cfpkt_add_head(struct cfpkt *pkt, const void *data2, u16 len)
        struct sk_buff *lastskb;
        u8 *to;
        const u8 *data = data2;
+       int ret;
        if (unlikely(is_erronous(pkt)))
                return -EPROTO;
        if (unlikely(skb_headroom(skb) < len)) {
@@ -246,9 +247,10 @@ int cfpkt_add_head(struct cfpkt *pkt, const void *data2, u16 len)
        }
 
        /* Make sure data is writable */
-       if (unlikely(skb_cow_data(skb, 0, &lastskb) < 0)) {
+       ret = skb_cow_data(skb, 0, &lastskb);
+       if (unlikely(ret < 0)) {
                PKT_ERROR(pkt, "cfpkt_add_head: cow failed\n");
-               return -EPROTO;
+               return ret;
        }
 
        to = skb_push(skb, len);
@@ -316,6 +318,8 @@ EXPORT_SYMBOL(cfpkt_setlen);
 struct cfpkt *cfpkt_create_uplink(const unsigned char *data, unsigned int len)
 {
        struct cfpkt *pkt = cfpkt_create_pfx(len + PKT_POSTFIX, PKT_PREFIX);
+       if (!pkt)
+               return NULL;
        if (unlikely(data != NULL))
                cfpkt_add_body(pkt, data, len);
        return pkt;
@@ -344,12 +348,13 @@ struct cfpkt *cfpkt_append(struct cfpkt *dstpkt,
 
        if (dst->tail + neededtailspace > dst->end) {
                /* Create a dumplicate of 'dst' with more tail space */
+               struct cfpkt *tmppkt;
                dstlen = skb_headlen(dst);
                createlen = dstlen + neededtailspace;
-               tmp = pkt_to_skb(
-                       cfpkt_create(createlen + PKT_PREFIX + PKT_POSTFIX));
-               if (!tmp)
+               tmppkt = cfpkt_create(createlen + PKT_PREFIX + PKT_POSTFIX);
+               if (tmppkt == NULL)
                        return NULL;
+               tmp = pkt_to_skb(tmppkt);
                skb_set_tail_pointer(tmp, dstlen);
                tmp->len = dstlen;
                memcpy(tmp->data, dst->data, dstlen);
@@ -368,6 +373,7 @@ struct cfpkt *cfpkt_split(struct cfpkt *pkt, u16 pos)
 {
        struct sk_buff *skb2;
        struct sk_buff *skb = pkt_to_skb(pkt);
+       struct cfpkt *tmppkt;
        u8 *split = skb->data + pos;
        u16 len2nd = skb_tail_pointer(skb) - split;
 
@@ -381,9 +387,12 @@ struct cfpkt *cfpkt_split(struct cfpkt *pkt, u16 pos)
        }
 
        /* Create a new packet for the second part of the data */
-       skb2 = pkt_to_skb(
-               cfpkt_create_pfx(len2nd + PKT_PREFIX + PKT_POSTFIX,
-                                PKT_PREFIX));
+       tmppkt = cfpkt_create_pfx(len2nd + PKT_PREFIX + PKT_POSTFIX,
+                                 PKT_PREFIX);
+       if (tmppkt == NULL)
+               return NULL;
+       skb2 = pkt_to_skb(tmppkt);
+
 
        if (skb2 == NULL)
                return NULL;
index 06029ea2da2fe7800b6685a9a3da5fe7ef5ddc6a..cb4325a3dc83184f4a4f8e382dbec6b7ac6c21f2 100644 (file)
@@ -67,6 +67,8 @@ static int cfserl_receive(struct cflayer *l, struct cfpkt *newpkt)
                layr->incomplete_frm =
                    cfpkt_append(layr->incomplete_frm, newpkt, expectlen);
                pkt = layr->incomplete_frm;
+               if (pkt == NULL)
+                       return -ENOMEM;
        } else {
                pkt = newpkt;
        }
@@ -154,7 +156,6 @@ static int cfserl_receive(struct cflayer *l, struct cfpkt *newpkt)
                        if (layr->usestx) {
                                if (tail_pkt != NULL)
                                        pkt = cfpkt_append(pkt, tail_pkt, 0);
-
                                /* Start search for next STX if frame failed */
                                continue;
                        } else {
index aff31f34528f8e7748d3a804b736e410787ac34f..6e5b7079a68424ff414a5f33d0500267b59d489e 100644 (file)
@@ -123,6 +123,12 @@ static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
                        struct caif_payload_info *info;
                        u8 flow_off = SRVL_FLOW_OFF;
                        pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE);
+                       if (!pkt) {
+                               pr_warning("CAIF: %s(): Out of memory\n",
+                                       __func__);
+                               return -ENOMEM;
+                       }
+
                        if (cfpkt_add_head(pkt, &flow_off, 1) < 0) {
                                pr_err("CAIF: %s(): Packet is erroneous!\n",
                                        __func__);
index e0097531417aeeced3650a7f166ac648ae2fa798..f5b6f43a4c2e61e34e0d02053458b9a8c4dfdf89 100644 (file)
@@ -229,15 +229,17 @@ EXPORT_SYMBOL(skb_free_datagram);
 
 void skb_free_datagram_locked(struct sock *sk, struct sk_buff *skb)
 {
+       bool slow;
+
        if (likely(atomic_read(&skb->users) == 1))
                smp_rmb();
        else if (likely(!atomic_dec_and_test(&skb->users)))
                return;
 
-       lock_sock_bh(sk);
+       slow = lock_sock_fast(sk);
        skb_orphan(skb);
        sk_mem_reclaim_partial(sk);
-       unlock_sock_bh(sk);
+       unlock_sock_fast(sk, slow);
 
        /* skb is now orphaned, can be freed outside of locked section */
        __kfree_skb(skb);
index d273e4e3ecdc8e1fc4ddd4b8eb6695d4603e410e..1845b08c624e1fa4c9dd398f4b61c2963dbfc1f2 100644 (file)
@@ -954,18 +954,22 @@ int dev_alloc_name(struct net_device *dev, const char *name)
 }
 EXPORT_SYMBOL(dev_alloc_name);
 
-static int dev_get_valid_name(struct net *net, const char *name, char *buf,
-                             bool fmt)
+static int dev_get_valid_name(struct net_device *dev, const char *name, bool fmt)
 {
+       struct net *net;
+
+       BUG_ON(!dev_net(dev));
+       net = dev_net(dev);
+
        if (!dev_valid_name(name))
                return -EINVAL;
 
        if (fmt && strchr(name, '%'))
-               return __dev_alloc_name(net, name, buf);
+               return dev_alloc_name(dev, name);
        else if (__dev_get_by_name(net, name))
                return -EEXIST;
-       else if (buf != name)
-               strlcpy(buf, name, IFNAMSIZ);
+       else if (dev->name != name)
+               strlcpy(dev->name, name, IFNAMSIZ);
 
        return 0;
 }
@@ -997,7 +1001,7 @@ int dev_change_name(struct net_device *dev, const char *newname)
 
        memcpy(oldname, dev->name, IFNAMSIZ);
 
-       err = dev_get_valid_name(net, newname, dev->name, 1);
+       err = dev_get_valid_name(dev, newname, 1);
        if (err < 0)
                return err;
 
@@ -2421,10 +2425,7 @@ static int enqueue_to_backlog(struct sk_buff *skb, int cpu,
                if (skb_queue_len(&sd->input_pkt_queue)) {
 enqueue:
                        __skb_queue_tail(&sd->input_pkt_queue, skb);
-#ifdef CONFIG_RPS
-                       *qtail = sd->input_queue_head +
-                                       skb_queue_len(&sd->input_pkt_queue);
-#endif
+                       input_queue_tail_incr_save(sd, qtail);
                        rps_unlock(sd);
                        local_irq_restore(flags);
                        return NET_RX_SUCCESS;
@@ -2959,7 +2960,7 @@ static void flush_backlog(void *arg)
                if (skb->dev == dev) {
                        __skb_unlink(skb, &sd->input_pkt_queue);
                        kfree_skb(skb);
-                       input_queue_head_add(sd, 1);
+                       input_queue_head_incr(sd);
                }
        }
        rps_unlock(sd);
@@ -2968,6 +2969,7 @@ static void flush_backlog(void *arg)
                if (skb->dev == dev) {
                        __skb_unlink(skb, &sd->process_queue);
                        kfree_skb(skb);
+                       input_queue_head_incr(sd);
                }
        }
 }
@@ -3323,18 +3325,20 @@ static int process_backlog(struct napi_struct *napi, int quota)
                while ((skb = __skb_dequeue(&sd->process_queue))) {
                        local_irq_enable();
                        __netif_receive_skb(skb);
-                       if (++work >= quota)
-                               return work;
                        local_irq_disable();
+                       input_queue_head_incr(sd);
+                       if (++work >= quota) {
+                               local_irq_enable();
+                               return work;
+                       }
                }
 
                rps_lock(sd);
                qlen = skb_queue_len(&sd->input_pkt_queue);
-               if (qlen) {
-                       input_queue_head_add(sd, qlen);
+               if (qlen)
                        skb_queue_splice_tail_init(&sd->input_pkt_queue,
                                                   &sd->process_queue);
-               }
+
                if (qlen < quota - work) {
                        /*
                         * Inline a custom version of __napi_complete().
@@ -4960,7 +4964,7 @@ int register_netdevice(struct net_device *dev)
                }
        }
 
-       ret = dev_get_valid_name(net, dev->name, dev->name, 0);
+       ret = dev_get_valid_name(dev, dev->name, 0);
        if (ret)
                goto err_uninit;
 
@@ -5558,7 +5562,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
                /* We get here if we can't use the current device name */
                if (!pat)
                        goto out;
-               if (dev_get_valid_name(net, pat, dev->name, 1))
+               if (dev_get_valid_name(dev, pat, 1))
                        goto out;
        }
 
@@ -5661,12 +5665,14 @@ static int dev_cpu_callback(struct notifier_block *nfb,
        local_irq_enable();
 
        /* Process offline CPU's input_pkt_queue */
-       while ((skb = __skb_dequeue(&oldsd->input_pkt_queue))) {
+       while ((skb = __skb_dequeue(&oldsd->process_queue))) {
                netif_rx(skb);
-               input_queue_head_add(oldsd, 1);
+               input_queue_head_incr(oldsd);
        }
-       while ((skb = __skb_dequeue(&oldsd->process_queue)))
+       while ((skb = __skb_dequeue(&oldsd->input_pkt_queue))) {
                netif_rx(skb);
+               input_queue_head_incr(oldsd);
+       }
 
        return NOTIFY_OK;
 }
index cf208d8042b198d962a8ccfbd81c0b70acca28c2..ad41529fb60f766ad095de5c40b9d537473314f1 100644 (file)
@@ -172,12 +172,12 @@ out:
        return;
 }
 
-static void trace_kfree_skb_hit(struct sk_buff *skb, void *location)
+static void trace_kfree_skb_hit(void *ignore, struct sk_buff *skb, void *location)
 {
        trace_drop_common(skb, location);
 }
 
-static void trace_napi_poll_hit(struct napi_struct *napi)
+static void trace_napi_poll_hit(void *ignore, struct napi_struct *napi)
 {
        struct dm_hw_stat_delta *new_stat;
 
@@ -225,12 +225,12 @@ static int set_all_monitor_traces(int state)
 
        switch (state) {
        case TRACE_ON:
-               rc |= register_trace_kfree_skb(trace_kfree_skb_hit);
-               rc |= register_trace_napi_poll(trace_napi_poll_hit);
+               rc |= register_trace_kfree_skb(trace_kfree_skb_hit, NULL);
+               rc |= register_trace_napi_poll(trace_napi_poll_hit, NULL);
                break;
        case TRACE_OFF:
-               rc |= unregister_trace_kfree_skb(trace_kfree_skb_hit);
-               rc |= unregister_trace_napi_poll(trace_napi_poll_hit);
+               rc |= unregister_trace_kfree_skb(trace_kfree_skb_hit, NULL);
+               rc |= unregister_trace_napi_poll(trace_napi_poll_hit, NULL);
 
                tracepoint_synchronize_unregister();
 
index bff37908bd55683012353bde62015722f8c515e9..6ba1c0eece039f99f19c0451bf5a52b3b9090a71 100644 (file)
@@ -934,6 +934,7 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
                                kfree_skb(buff);
                                NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);
                        }
+                       skb_dst_force(skb);
                        __skb_queue_tail(&neigh->arp_queue, skb);
                }
                rc = 1;
index e4b9870e4706f7f4cf3e84b798f752c7e972f2fb..1a2af24e9e3d2b3754fa032e261a9480b4d0b7ac 100644 (file)
@@ -650,11 +650,12 @@ static inline int rtnl_vfinfo_size(const struct net_device *dev)
        if (dev->dev.parent && dev_is_pci(dev->dev.parent)) {
 
                int num_vfs = dev_num_vf(dev->dev.parent);
-               size_t size = nlmsg_total_size(sizeof(struct nlattr));
-               size += nlmsg_total_size(num_vfs * sizeof(struct nlattr));
-               size += num_vfs * (sizeof(struct ifla_vf_mac) +
-                                 sizeof(struct ifla_vf_vlan) +
-                                 sizeof(struct ifla_vf_tx_rate));
+               size_t size = nla_total_size(sizeof(struct nlattr));
+               size += nla_total_size(num_vfs * sizeof(struct nlattr));
+               size += num_vfs *
+                       (nla_total_size(sizeof(struct ifla_vf_mac)) +
+                        nla_total_size(sizeof(struct ifla_vf_vlan)) +
+                        nla_total_size(sizeof(struct ifla_vf_tx_rate)));
                return size;
        } else
                return 0;
@@ -722,14 +723,13 @@ static int rtnl_vf_ports_fill(struct sk_buff *skb, struct net_device *dev)
 
        for (vf = 0; vf < dev_num_vf(dev->dev.parent); vf++) {
                vf_port = nla_nest_start(skb, IFLA_VF_PORT);
-               if (!vf_port) {
-                       nla_nest_cancel(skb, vf_ports);
-                       return -EMSGSIZE;
-               }
+               if (!vf_port)
+                       goto nla_put_failure;
                NLA_PUT_U32(skb, IFLA_PORT_VF, vf);
                err = dev->netdev_ops->ndo_get_vf_port(dev, vf, skb);
+               if (err == -EMSGSIZE)
+                       goto nla_put_failure;
                if (err) {
-nla_put_failure:
                        nla_nest_cancel(skb, vf_port);
                        continue;
                }
@@ -739,6 +739,10 @@ nla_put_failure:
        nla_nest_end(skb, vf_ports);
 
        return 0;
+
+nla_put_failure:
+       nla_nest_cancel(skb, vf_ports);
+       return -EMSGSIZE;
 }
 
 static int rtnl_port_self_fill(struct sk_buff *skb, struct net_device *dev)
@@ -753,7 +757,7 @@ static int rtnl_port_self_fill(struct sk_buff *skb, struct net_device *dev)
        err = dev->netdev_ops->ndo_get_vf_port(dev, PORT_SELF_VF, skb);
        if (err) {
                nla_nest_cancel(skb, port_self);
-               return err;
+               return (err == -EMSGSIZE) ? err : 0;
        }
 
        nla_nest_end(skb, port_self);
@@ -1199,8 +1203,10 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
                struct nlattr *attr;
                int rem;
                nla_for_each_nested(attr, tb[IFLA_VFINFO_LIST], rem) {
-                       if (nla_type(attr) != IFLA_VF_INFO)
+                       if (nla_type(attr) != IFLA_VF_INFO) {
+                               err = -EINVAL;
                                goto errout;
+                       }
                        err = do_setvfinfo(dev, attr);
                        if (err < 0)
                                goto errout;
index 66d9c416851e7e64dca9b68fe651cca31511575b..f8abf68e3988f7cd5b4a83eb6a18b3ae25d52afd 100644 (file)
@@ -2722,6 +2722,7 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
        *NAPI_GRO_CB(nskb) = *NAPI_GRO_CB(p);
        skb_shinfo(nskb)->frag_list = p;
        skb_shinfo(nskb)->gso_size = pinfo->gso_size;
+       pinfo->gso_size = 0;
        skb_header_release(p);
        nskb->prev = p;
 
index bf88a167c8f2ce5f008858454c103d762b0575ad..2cf7f9f7e775105ceef0bd630fd981dab2262952 100644 (file)
 #include <linux/net_tstamp.h>
 #include <net/xfrm.h>
 #include <linux/ipsec.h>
+#include <net/cls_cgroup.h>
 
 #include <linux/filter.h>
 
@@ -217,6 +218,11 @@ __u32 sysctl_rmem_default __read_mostly = SK_RMEM_MAX;
 int sysctl_optmem_max __read_mostly = sizeof(unsigned long)*(2*UIO_MAXIOV+512);
 EXPORT_SYMBOL(sysctl_optmem_max);
 
+#if defined(CONFIG_CGROUPS) && !defined(CONFIG_NET_CLS_CGROUP)
+int net_cls_subsys_id = -1;
+EXPORT_SYMBOL_GPL(net_cls_subsys_id);
+#endif
+
 static int sock_set_timeout(long *timeo_p, char __user *optval, int optlen)
 {
        struct timeval tv;
@@ -1050,6 +1056,17 @@ static void sk_prot_free(struct proto *prot, struct sock *sk)
        module_put(owner);
 }
 
+#ifdef CONFIG_CGROUPS
+void sock_update_classid(struct sock *sk)
+{
+       u32 classid = task_cls_classid(current);
+
+       if (classid && classid != sk->sk_classid)
+               sk->sk_classid = classid;
+}
+EXPORT_SYMBOL(sock_update_classid);
+#endif
+
 /**
  *     sk_alloc - All socket objects are allocated here
  *     @net: the applicable net namespace
@@ -1073,6 +1090,8 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority,
                sock_lock_init(sk);
                sock_net_set(sk, get_net(net));
                atomic_set(&sk->sk_wmem_alloc, 1);
+
+               sock_update_classid(sk);
        }
 
        return sk;
@@ -1988,6 +2007,39 @@ void release_sock(struct sock *sk)
 }
 EXPORT_SYMBOL(release_sock);
 
+/**
+ * lock_sock_fast - fast version of lock_sock
+ * @sk: socket
+ *
+ * This version should be used for very small section, where process wont block
+ * return false if fast path is taken
+ *   sk_lock.slock locked, owned = 0, BH disabled
+ * return true if slow path is taken
+ *   sk_lock.slock unlocked, owned = 1, BH enabled
+ */
+bool lock_sock_fast(struct sock *sk)
+{
+       might_sleep();
+       spin_lock_bh(&sk->sk_lock.slock);
+
+       if (!sk->sk_lock.owned)
+               /*
+                * Note : We must disable BH
+                */
+               return false;
+
+       __lock_sock(sk);
+       sk->sk_lock.owned = 1;
+       spin_unlock(&sk->sk_lock.slock);
+       /*
+        * The sk_lock has mutex_lock() semantics here:
+        */
+       mutex_acquire(&sk->sk_lock.dep_map, 0, 0, _RET_IP_);
+       local_bh_enable();
+       return true;
+}
+EXPORT_SYMBOL(lock_sock_fast);
+
 int sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp)
 {
        struct timeval tv;
index 58f7bc1568503e26c755fa7122deb57ce53c832a..6beb6a7d6fbab77ebd161e09a910959dc57805df 100644 (file)
@@ -124,9 +124,9 @@ static int dccp_rcv_closereq(struct sock *sk, struct sk_buff *skb)
        return queued;
 }
 
-static u8 dccp_reset_code_convert(const u8 code)
+static u16 dccp_reset_code_convert(const u8 code)
 {
-       const u8 error_code[] = {
+       const u16 error_code[] = {
        [DCCP_RESET_CODE_CLOSED]             = 0,       /* normal termination */
        [DCCP_RESET_CODE_UNSPECIFIED]        = 0,       /* nothing known */
        [DCCP_RESET_CODE_ABORTED]            = ECONNRESET,
@@ -148,7 +148,7 @@ static u8 dccp_reset_code_convert(const u8 code)
 
 static void dccp_rcv_reset(struct sock *sk, struct sk_buff *skb)
 {
-       u8 err = dccp_reset_code_convert(dccp_hdr_reset(skb)->dccph_reset_code);
+       u16 err = dccp_reset_code_convert(dccp_hdr_reset(skb)->dccph_reset_code);
 
        sk->sk_err = err;
 
index 1b08cae9c65ba21fb1a28c255b810e868acc044a..07395f861d35aa819e154ebc66114472687e7a6a 100644 (file)
@@ -296,7 +296,7 @@ static inline u8 dccp_ndp_len(const u64 ndp)
 {
        if (likely(ndp <= 0xFF))
                return 1;
-       return likely(ndp <= USHORT_MAX) ? 2 : (ndp <= UINT_MAX ? 4 : 6);
+       return likely(ndp <= USHRT_MAX) ? 2 : (ndp <= UINT_MAX ? 4 : 6);
 }
 
 int dccp_insert_option(struct sock *sk, struct sk_buff *skb,
index 3d803a1b9fb69a046205a57be9dcbe2bfb141e72..1627ef2e85229d524727af6c111e3f4aa6507d36 100644 (file)
@@ -147,13 +147,15 @@ struct wpan_phy *wpan_phy_alloc(size_t priv_size)
        struct wpan_phy *phy = kzalloc(sizeof(*phy) + priv_size,
                        GFP_KERNEL);
 
+       if (!phy)
+               goto out;
        mutex_lock(&wpan_phy_mutex);
        phy->idx = wpan_phy_idx++;
        if (unlikely(!wpan_phy_idx_valid(phy->idx))) {
                wpan_phy_idx--;
                mutex_unlock(&wpan_phy_mutex);
                kfree(phy);
-               return NULL;
+               goto out;
        }
        mutex_unlock(&wpan_phy_mutex);
 
@@ -168,6 +170,9 @@ struct wpan_phy *wpan_phy_alloc(size_t priv_size)
        phy->current_page = 0; /* for compatibility */
 
        return phy;
+
+out:
+       return NULL;
 }
 EXPORT_SYMBOL(wpan_phy_alloc);
 
index 45889103b3e2a6e2dc76e5731f8ef2a7e9c821e0..856123fe32f98c97e3364a322fe9899d4b8d1359 100644 (file)
@@ -1911,7 +1911,7 @@ static int __ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
        struct rtattr *mp_head;
 
        /* If cache is unresolved, don't try to parse IIF and OIF */
-       if (c->mfc_parent > MAXVIFS)
+       if (c->mfc_parent >= MAXVIFS)
                return -ENOENT;
 
        if (VIF_EXISTS(mrt, c->mfc_parent))
index 9de6a698f91d6ed861d8dd42c803a49222db7105..58585748bdac7cc7be011c090409e37f492573a4 100644 (file)
@@ -1063,10 +1063,11 @@ static unsigned int first_packet_length(struct sock *sk)
        spin_unlock_bh(&rcvq->lock);
 
        if (!skb_queue_empty(&list_kill)) {
-               lock_sock_bh(sk);
+               bool slow = lock_sock_fast(sk);
+
                __skb_queue_purge(&list_kill);
                sk_mem_reclaim_partial(sk);
-               unlock_sock_bh(sk);
+               unlock_sock_fast(sk, slow);
        }
        return res;
 }
@@ -1123,6 +1124,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        int peeked;
        int err;
        int is_udplite = IS_UDPLITE(sk);
+       bool slow;
 
        /*
         *      Check any passed addresses
@@ -1197,10 +1199,10 @@ out:
        return err;
 
 csum_copy_err:
-       lock_sock_bh(sk);
+       slow = lock_sock_fast(sk);
        if (!skb_kill_datagram(sk, skb, flags))
                UDP_INC_STATS_USER(sock_net(sk), UDP_MIB_INERRORS, is_udplite);
-       unlock_sock_bh(sk);
+       unlock_sock_fast(sk, slow);
 
        if (noblock)
                return -EAGAIN;
@@ -1625,9 +1627,9 @@ int udp_rcv(struct sk_buff *skb)
 
 void udp_destroy_sock(struct sock *sk)
 {
-       lock_sock_bh(sk);
+       bool slow = lock_sock_fast(sk);
        udp_flush_pending_frames(sk);
-       unlock_sock_bh(sk);
+       unlock_sock_fast(sk, slow);
 }
 
 /*
@@ -1686,8 +1688,8 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
                        return -ENOPROTOOPT;
                if (val != 0 && val < 8) /* Illegal coverage: use default (8) */
                        val = 8;
-               else if (val > USHORT_MAX)
-                       val = USHORT_MAX;
+               else if (val > USHRT_MAX)
+                       val = USHRT_MAX;
                up->pcslen = val;
                up->pcflag |= UDPLITE_SEND_CC;
                break;
@@ -1700,8 +1702,8 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
                        return -ENOPROTOOPT;
                if (val != 0 && val < 8) /* Avoid silly minimal values.       */
                        val = 8;
-               else if (val > USHORT_MAX)
-                       val = USHORT_MAX;
+               else if (val > USHRT_MAX)
+                       val = USHRT_MAX;
                up->pcrlen = val;
                up->pcflag |= UDPLITE_RECV_CC;
                break;
index cd963f64e27c882f39c25c2092aa9116b4568bbc..89425af0684cb160d1078fed8f3a56fa852ec58e 100644 (file)
@@ -507,7 +507,7 @@ int ip6_forward(struct sk_buff *skb)
        if (mtu < IPV6_MIN_MTU)
                mtu = IPV6_MIN_MTU;
 
-       if (skb->len > mtu) {
+       if (skb->len > mtu && !skb_is_gso(skb)) {
                /* Again, force OUTPUT device used as source address */
                skb->dev = dst->dev;
                icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
index bd9e7d3e9c8e2fe4779dc42e63273972e5e76cfc..073071f2b75b500207a9c14f823d1d50f56b2aec 100644 (file)
@@ -2017,7 +2017,7 @@ static int __ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
        struct rtattr *mp_head;
 
        /* If cache is unresolved, don't try to parse IIF and OIF */
-       if (c->mf6c_parent > MAXMIFS)
+       if (c->mf6c_parent >= MAXMIFS)
                return -ENOENT;
 
        if (MIF_EXISTS(mrt, c->mf6c_parent))
index 3d7a2c0b836afa6a4b458c724e2118c58d35e959..87be58673b55fffc75e34ec0d6cc1dceafd7de8e 100644 (file)
@@ -328,6 +328,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk,
        int err;
        int is_udplite = IS_UDPLITE(sk);
        int is_udp4;
+       bool slow;
 
        if (addr_len)
                *addr_len=sizeof(struct sockaddr_in6);
@@ -424,7 +425,7 @@ out:
        return err;
 
 csum_copy_err:
-       lock_sock_bh(sk);
+       slow = lock_sock_fast(sk);
        if (!skb_kill_datagram(sk, skb, flags)) {
                if (is_udp4)
                        UDP_INC_STATS_USER(sock_net(sk),
@@ -433,7 +434,7 @@ csum_copy_err:
                        UDP6_INC_STATS_USER(sock_net(sk),
                                        UDP_MIB_INERRORS, is_udplite);
        }
-       unlock_sock_bh(sk);
+       unlock_sock_fast(sk, slow);
 
        if (flags & MSG_DONTWAIT)
                return -EAGAIN;
index c8b4599a752ea0480450c95610b3d914d634573d..9637e45744fa2f818c94aa66e284f2ba0026f65b 100644 (file)
@@ -1619,7 +1619,7 @@ static void iucv_callback_rx(struct iucv_path *path, struct iucv_message *msg)
 save_message:
        save_msg = kzalloc(sizeof(struct sock_msg_q), GFP_ATOMIC | GFP_DMA);
        if (!save_msg)
-               return;
+               goto out_unlock;
        save_msg->path = path;
        save_msg->msg = *msg;
 
index fd8b28361a6415eaf4d98251a7be40fbc478f7bc..f28ad2cc8428b0f02071c44f1e1b793609183bba 100644 (file)
@@ -632,13 +632,14 @@ static int __cpuinit iucv_cpu_notify(struct notifier_block *self,
                iucv_irq_data[cpu] = kmalloc_node(sizeof(struct iucv_irq_data),
                                        GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));
                if (!iucv_irq_data[cpu])
-                       return NOTIFY_BAD;
+                       return notifier_from_errno(-ENOMEM);
+
                iucv_param[cpu] = kmalloc_node(sizeof(union iucv_param),
                                     GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));
                if (!iucv_param[cpu]) {
                        kfree(iucv_irq_data[cpu]);
                        iucv_irq_data[cpu] = NULL;
-                       return NOTIFY_BAD;
+                       return notifier_from_errno(-ENOMEM);
                }
                iucv_param_irq[cpu] = kmalloc_node(sizeof(union iucv_param),
                                        GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));
@@ -647,7 +648,7 @@ static int __cpuinit iucv_cpu_notify(struct notifier_block *self,
                        iucv_param[cpu] = NULL;
                        kfree(iucv_irq_data[cpu]);
                        iucv_irq_data[cpu] = NULL;
-                       return NOTIFY_BAD;
+                       return notifier_from_errno(-ENOMEM);
                }
                break;
        case CPU_UP_CANCELED:
@@ -677,7 +678,7 @@ static int __cpuinit iucv_cpu_notify(struct notifier_block *self,
                cpu_clear(cpu, cpumask);
                if (cpus_empty(cpumask))
                        /* Can't offline last IUCV enabled cpu. */
-                       return NOTIFY_BAD;
+                       return notifier_from_errno(-EINVAL);
                smp_call_function_single(cpu, iucv_retrieve_cpu, NULL, 1);
                if (cpus_empty(iucv_irq_cpumask))
                        smp_call_function_single(first_cpu(iucv_buffer_cpumask),
index 8d4b41787dcf5146b94267a4aff7c8025b4a21c0..e8f6e3b252d8b8ee3ef4210695dfc44283534bc4 100644 (file)
@@ -140,7 +140,6 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
                                     struct ieee80211_sub_if_data,
                                     u.ap);
 
-       key->conf.ap_addr = sdata->dev->dev_addr;
        ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf);
 
        if (!ret) {
index 730197591ab5135e307317d7c9d8e358dae6bceb..ba9360a475b0c15f657017f5ca5b93997a70dd49 100644 (file)
@@ -259,7 +259,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
        skb_queue_head_init(&sta->tx_filtered);
 
        for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
-               sta->last_seq_ctrl[i] = cpu_to_le16(USHORT_MAX);
+               sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX);
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
        printk(KERN_DEBUG "%s: Allocated STA %pM\n",
index 48a5e80957f0cc59748c2d0812c8b50536430b80..df9d45544ca5344be3427383e8a6c0209441a856 100644 (file)
@@ -145,7 +145,7 @@ enum plink_state {
 /**
  * struct sta_ampdu_mlme - STA aggregation information.
  *
- * @tid_state_rx: TID's state in Rx session state machine.
+ * @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
index b83c530c5e0a391c7f09e5ee8950884991377053..eeeb8bc73982275655e37342c214f1fa2669efb2 100644 (file)
@@ -424,6 +424,16 @@ __nf_conntrack_confirm(struct sk_buff *skb)
 
        spin_lock_bh(&nf_conntrack_lock);
 
+       /* We have to check the DYING flag inside the lock to prevent
+          a race against nf_ct_get_next_corpse() possibly called from
+          user context, else we insert an already 'dead' hash, blocking
+          further use of that particular connection -JM */
+
+       if (unlikely(nf_ct_is_dying(ct))) {
+               spin_unlock_bh(&nf_conntrack_lock);
+               return NF_ACCEPT;
+       }
+
        /* See if there's one in the list already, including reverse:
           NAT could have grabbed it without realizing, since we're
           not in the hash.  If there is, we lost race. */
index b20f4275893c8a61b68304c17c44e379e2be9a65..53d892210a049363fa3ab04f6e17b04fa9969bbe 100644 (file)
@@ -1393,10 +1393,8 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff,
 
        nf_ct_refresh(ct, skb, sip_timeout * HZ);
 
-       if (skb_is_nonlinear(skb)) {
-               pr_debug("Copy of skbuff not supported yet.\n");
-               return NF_ACCEPT;
-       }
+       if (unlikely(skb_linearize(skb)))
+               return NF_DROP;
 
        dptr = skb->data + dataoff;
        datalen = skb->len - dataoff;
@@ -1455,10 +1453,8 @@ static int sip_help_udp(struct sk_buff *skb, unsigned int protoff,
 
        nf_ct_refresh(ct, skb, sip_timeout * HZ);
 
-       if (skb_is_nonlinear(skb)) {
-               pr_debug("Copy of skbuff not supported yet.\n");
-               return NF_ACCEPT;
-       }
+       if (unlikely(skb_linearize(skb)))
+               return NF_DROP;
 
        dptr = skb->data + dataoff;
        datalen = skb->len - dataoff;
index d7920d9f49e904c96739e404c523ba97adbaa8dc..859d9fd429c812a560cc3676b1a62c6105026fe7 100644 (file)
@@ -76,7 +76,7 @@ tee_tg_route4(struct sk_buff *skb, const struct xt_tee_tginfo *info)
        if (ip_route_output_key(net, &rt, &fl) != 0)
                return false;
 
-       dst_release(skb_dst(skb));
+       skb_dst_drop(skb);
        skb_dst_set(skb, &rt->u.dst);
        skb->dev      = rt->u.dst.dev;
        skb->protocol = htons(ETH_P_IP);
@@ -157,7 +157,7 @@ tee_tg_route6(struct sk_buff *skb, const struct xt_tee_tginfo *info)
        if (dst == NULL)
                return false;
 
-       dst_release(skb_dst(skb));
+       skb_dst_drop(skb);
        skb_dst_set(skb, dst);
        skb->dev      = dst->dev;
        skb->protocol = htons(ETH_P_IPV6);
index af4d38bc3b2231135a60974a53038d306b110961..7b048a35ca5837368e4ace101a57564eacbb51fc 100644 (file)
@@ -626,6 +626,7 @@ static void pep_sock_close(struct sock *sk, long timeout)
        struct pep_sock *pn = pep_sk(sk);
        int ifindex = 0;
 
+       sock_hold(sk); /* keep a reference after sk_common_release() */
        sk_common_release(sk);
 
        lock_sock(sk);
@@ -644,6 +645,7 @@ static void pep_sock_close(struct sock *sk, long timeout)
 
        if (ifindex)
                gprs_detach(sk);
+       sock_put(sk);
 }
 
 static int pep_wait_connreq(struct sock *sk, int noblock)
index 221180384fd7d466bc0864ae6eca5aee9a6f0e95..78ef2c5e130ba9224512dd3872d86226b36306f3 100644 (file)
 #include <linux/errno.h>
 #include <linux/skbuff.h>
 #include <linux/cgroup.h>
+#include <linux/rcupdate.h>
 #include <net/rtnetlink.h>
 #include <net/pkt_cls.h>
-
-struct cgroup_cls_state
-{
-       struct cgroup_subsys_state css;
-       u32 classid;
-};
+#include <net/sock.h>
+#include <net/cls_cgroup.h>
 
 static struct cgroup_subsys_state *cgrp_create(struct cgroup_subsys *ss,
                                               struct cgroup *cgrp);
@@ -112,6 +109,10 @@ static int cls_cgroup_classify(struct sk_buff *skb, struct tcf_proto *tp,
        struct cls_cgroup_head *head = tp->root;
        u32 classid;
 
+       rcu_read_lock();
+       classid = task_cls_state(current)->classid;
+       rcu_read_unlock();
+
        /*
         * Due to the nature of the classifier it is required to ignore all
         * packets originating from softirq context as accessing `current'
@@ -122,12 +123,12 @@ static int cls_cgroup_classify(struct sk_buff *skb, struct tcf_proto *tp,
         * calls by looking at the number of nested bh disable calls because
         * softirqs always disables bh.
         */
-       if (softirq_count() != SOFTIRQ_OFFSET)
-               return -1;
-
-       rcu_read_lock();
-       classid = task_cls_state(current)->classid;
-       rcu_read_unlock();
+       if (softirq_count() != SOFTIRQ_OFFSET) {
+               /* If there is an sk_classid we'll use that. */
+               if (!skb->sk)
+                       return -1;
+               classid = skb->sk->sk_classid;
+       }
 
        if (!classid)
                return -1;
@@ -289,18 +290,35 @@ static struct tcf_proto_ops cls_cgroup_ops __read_mostly = {
 
 static int __init init_cgroup_cls(void)
 {
-       int ret = register_tcf_proto_ops(&cls_cgroup_ops);
-       if (ret)
-               return ret;
+       int ret;
+
        ret = cgroup_load_subsys(&net_cls_subsys);
        if (ret)
-               unregister_tcf_proto_ops(&cls_cgroup_ops);
+               goto out;
+
+#ifndef CONFIG_NET_CLS_CGROUP
+       /* We can't use rcu_assign_pointer because this is an int. */
+       smp_wmb();
+       net_cls_subsys_id = net_cls_subsys.subsys_id;
+#endif
+
+       ret = register_tcf_proto_ops(&cls_cgroup_ops);
+       if (ret)
+               cgroup_unload_subsys(&net_cls_subsys);
+
+out:
        return ret;
 }
 
 static void __exit exit_cgroup_cls(void)
 {
        unregister_tcf_proto_ops(&cls_cgroup_ops);
+
+#ifndef CONFIG_NET_CLS_CGROUP
+       net_cls_subsys_id = -1;
+       synchronize_rcu();
+#endif
+
        cgroup_unload_subsys(&net_cls_subsys);
 }
 
index fe35c1f338c2b25d7c2a4e4ae19123bf4023f6b5..b9e8c3b7d406aacd9cc2319ddbffe0440cc6c311 100644 (file)
@@ -1195,6 +1195,11 @@ nla_put_failure:
        return -1;
 }
 
+static bool tc_qdisc_dump_ignore(struct Qdisc *q)
+{
+       return (q->flags & TCQ_F_BUILTIN) ? true : false;
+}
+
 static int qdisc_notify(struct net *net, struct sk_buff *oskb,
                        struct nlmsghdr *n, u32 clid,
                        struct Qdisc *old, struct Qdisc *new)
@@ -1206,11 +1211,11 @@ static int qdisc_notify(struct net *net, struct sk_buff *oskb,
        if (!skb)
                return -ENOBUFS;
 
-       if (old && old->handle) {
+       if (old && !tc_qdisc_dump_ignore(old)) {
                if (tc_fill_qdisc(skb, old, clid, pid, n->nlmsg_seq, 0, RTM_DELQDISC) < 0)
                        goto err_out;
        }
-       if (new) {
+       if (new && !tc_qdisc_dump_ignore(new)) {
                if (tc_fill_qdisc(skb, new, clid, pid, n->nlmsg_seq, old ? NLM_F_REPLACE : 0, RTM_NEWQDISC) < 0)
                        goto err_out;
        }
@@ -1223,11 +1228,6 @@ err_out:
        return -EINVAL;
 }
 
-static bool tc_qdisc_dump_ignore(struct Qdisc *q)
-{
-       return (q->flags & TCQ_F_BUILTIN) ? true : false;
-}
-
 static int tc_dump_qdisc_root(struct Qdisc *root, struct sk_buff *skb,
                              struct netlink_callback *cb,
                              int *q_idx_p, int s_q_idx)
index f9f7d0872cacf96cb7e5d4716b5b4c2358b13dae..367d5477d00fee1eb9fcd3eba5e6f31b1383e312 100644 (file)
@@ -94,6 +94,7 @@
 
 #include <net/compat.h>
 #include <net/wext.h>
+#include <net/cls_cgroup.h>
 
 #include <net/sock.h>
 #include <linux/netfilter.h>
@@ -558,6 +559,8 @@ static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock,
        struct sock_iocb *si = kiocb_to_siocb(iocb);
        int err;
 
+       sock_update_classid(sock->sk);
+
        si->sock = sock;
        si->scm = NULL;
        si->msg = msg;
@@ -684,6 +687,8 @@ static inline int __sock_recvmsg_nosec(struct kiocb *iocb, struct socket *sock,
 {
        struct sock_iocb *si = kiocb_to_siocb(iocb);
 
+       sock_update_classid(sock->sk);
+
        si->sock = sock;
        si->scm = NULL;
        si->msg = msg;
@@ -777,6 +782,8 @@ static ssize_t sock_splice_read(struct file *file, loff_t *ppos,
        if (unlikely(!sock->ops->splice_read))
                return -EINVAL;
 
+       sock_update_classid(sock->sk);
+
        return sock->ops->splice_read(sock, ppos, pipe, len, flags);
 }
 
@@ -3069,6 +3076,8 @@ int kernel_setsockopt(struct socket *sock, int level, int optname,
 int kernel_sendpage(struct socket *sock, struct page *page, int offset,
                    size_t size, int flags)
 {
+       sock_update_classid(sock->sk);
+
        if (sock->ops->sendpage)
                return sock->ops->sendpage(sock, page, offset, size, flags);
 
index c2173ebdb33cf91c8cc2c573be98da93f049cc2f..58de76c8540c65dac38999ea4c9a5c2af5303f92 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/sunrpc/cache.h>
 #include <linux/sunrpc/stats.h>
 #include <linux/sunrpc/rpc_pipe_fs.h>
+#include <linux/smp_lock.h>
 
 #define         RPCDBG_FACILITY RPCDBG_CACHE
 
@@ -1545,12 +1546,18 @@ static unsigned int cache_poll_pipefs(struct file *filp, poll_table *wait)
        return cache_poll(filp, wait, cd);
 }
 
-static int cache_ioctl_pipefs(struct inode *inode, struct file *filp,
+static long cache_ioctl_pipefs(struct file *filp,
                              unsigned int cmd, unsigned long arg)
 {
+       struct inode *inode = filp->f_dentry->d_inode;
        struct cache_detail *cd = RPC_I(inode)->private;
+       long ret;
 
-       return cache_ioctl(inode, filp, cmd, arg, cd);
+       lock_kernel();
+       ret = cache_ioctl(inode, filp, cmd, arg, cd);
+       unlock_kernel();
+
+       return ret;
 }
 
 static int cache_open_pipefs(struct inode *inode, struct file *filp)
@@ -1573,7 +1580,7 @@ const struct file_operations cache_file_operations_pipefs = {
        .read           = cache_read_pipefs,
        .write          = cache_write_pipefs,
        .poll           = cache_poll_pipefs,
-       .ioctl          = cache_ioctl_pipefs, /* for FIONREAD */
+       .unlocked_ioctl = cache_ioctl_pipefs, /* for FIONREAD */
        .open           = cache_open_pipefs,
        .release        = cache_release_pipefs,
 };
index 20e30c6f8355dc0bc612bffb44abefee7c3536df..95ccbcf45d3eb64c6ee84c4767c85e7c5a9ee694 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/workqueue.h>
 #include <linux/sunrpc/rpc_pipe_fs.h>
 #include <linux/sunrpc/cache.h>
+#include <linux/smp_lock.h>
 
 static struct vfsmount *rpc_mount __read_mostly;
 static int rpc_mount_count;
@@ -309,8 +310,7 @@ rpc_pipe_poll(struct file *filp, struct poll_table_struct *wait)
 }
 
 static int
-rpc_pipe_ioctl(struct inode *ino, struct file *filp,
-               unsigned int cmd, unsigned long arg)
+rpc_pipe_ioctl_unlocked(struct file *filp, unsigned int cmd, unsigned long arg)
 {
        struct rpc_inode *rpci = RPC_I(filp->f_path.dentry->d_inode);
        int len;
@@ -331,13 +331,25 @@ rpc_pipe_ioctl(struct inode *ino, struct file *filp,
        }
 }
 
+static long
+rpc_pipe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+       long ret;
+
+       lock_kernel();
+       ret = rpc_pipe_ioctl_unlocked(filp, cmd, arg);
+       unlock_kernel();
+
+       return ret;
+}
+
 static const struct file_operations rpc_pipe_fops = {
        .owner          = THIS_MODULE,
        .llseek         = no_llseek,
        .read           = rpc_pipe_read,
        .write          = rpc_pipe_write,
        .poll           = rpc_pipe_poll,
-       .ioctl          = rpc_pipe_ioctl,
+       .unlocked_ioctl = rpc_pipe_ioctl,
        .open           = rpc_pipe_open,
        .release        = rpc_pipe_release,
 };
index 121105355f60e4a90dcb9906e878ea255499358d..dac219a56ae1a7dcf8df9ddff9a128b6caa89dac 100644 (file)
@@ -783,7 +783,7 @@ static int rpcb_dec_getport(struct rpc_rqst *req, __be32 *p,
        port = ntohl(*p);
        dprintk("RPC: %5u PMAP_%s result: %lu\n", task->tk_pid,
                        task->tk_msg.rpc_proc->p_name, port);
-       if (unlikely(port > USHORT_MAX))
+       if (unlikely(port > USHRT_MAX))
                return -EIO;
 
        rpcb->r_port = port;
index 3fc325399ee4da4eaf77d19ace55717e34639798..dcd0132396ba37ad231d23f6af1cc63047fa3d62 100644 (file)
@@ -166,7 +166,6 @@ EXPORT_SYMBOL_GPL(xprt_unregister_transport);
 int xprt_load_transport(const char *transport_name)
 {
        struct xprt_class *t;
-       char module_name[sizeof t->name + 5];
        int result;
 
        result = 0;
@@ -178,9 +177,7 @@ int xprt_load_transport(const char *transport_name)
                }
        }
        spin_unlock(&xprt_list_lock);
-       strcpy(module_name, "xprt");
-       strncat(module_name, transport_name, sizeof t->name);
-       result = request_module(module_name);
+       result = request_module("xprt%s", transport_name);
 out:
        return result;
 }
index b7cd8cccbe72c3dc12320e65af18f22104d5df5d..2a9675136c68e487adcf02849c54680ed7fd0e98 100644 (file)
@@ -2293,6 +2293,7 @@ static struct rpc_xprt *xs_setup_udp(struct xprt_create *args)
        struct sockaddr *addr = args->dstaddr;
        struct rpc_xprt *xprt;
        struct sock_xprt *transport;
+       struct rpc_xprt *ret;
 
        xprt = xs_setup_xprt(args, xprt_udp_slot_table_entries);
        if (IS_ERR(xprt))
@@ -2330,8 +2331,8 @@ static struct rpc_xprt *xs_setup_udp(struct xprt_create *args)
                xs_format_peer_addresses(xprt, "udp", RPCBIND_NETID_UDP6);
                break;
        default:
-               kfree(xprt);
-               return ERR_PTR(-EAFNOSUPPORT);
+               ret = ERR_PTR(-EAFNOSUPPORT);
+               goto out_err;
        }
 
        if (xprt_bound(xprt))
@@ -2346,10 +2347,11 @@ static struct rpc_xprt *xs_setup_udp(struct xprt_create *args)
 
        if (try_module_get(THIS_MODULE))
                return xprt;
-
+       ret = ERR_PTR(-EINVAL);
+out_err:
        kfree(xprt->slot);
        kfree(xprt);
-       return ERR_PTR(-EINVAL);
+       return ret;
 }
 
 static const struct rpc_timeout xs_tcp_default_timeout = {
@@ -2368,6 +2370,7 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args)
        struct sockaddr *addr = args->dstaddr;
        struct rpc_xprt *xprt;
        struct sock_xprt *transport;
+       struct rpc_xprt *ret;
 
        xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries);
        if (IS_ERR(xprt))
@@ -2403,8 +2406,8 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args)
                xs_format_peer_addresses(xprt, "tcp", RPCBIND_NETID_TCP6);
                break;
        default:
-               kfree(xprt);
-               return ERR_PTR(-EAFNOSUPPORT);
+               ret = ERR_PTR(-EAFNOSUPPORT);
+               goto out_err;
        }
 
        if (xprt_bound(xprt))
@@ -2420,10 +2423,11 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args)
 
        if (try_module_get(THIS_MODULE))
                return xprt;
-
+       ret = ERR_PTR(-EINVAL);
+out_err:
        kfree(xprt->slot);
        kfree(xprt);
-       return ERR_PTR(-EINVAL);
+       return ret;
 }
 
 /**
@@ -2437,6 +2441,7 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
        struct rpc_xprt *xprt;
        struct sock_xprt *transport;
        struct svc_sock *bc_sock;
+       struct rpc_xprt *ret;
 
        xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries);
        if (IS_ERR(xprt))
@@ -2476,8 +2481,8 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
                                   RPCBIND_NETID_TCP6);
                break;
        default:
-               kfree(xprt);
-               return ERR_PTR(-EAFNOSUPPORT);
+               ret = ERR_PTR(-EAFNOSUPPORT);
+               goto out_err;
        }
 
        if (xprt_bound(xprt))
@@ -2499,9 +2504,11 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
 
        if (try_module_get(THIS_MODULE))
                return xprt;
+       ret = ERR_PTR(-EINVAL);
+out_err:
        kfree(xprt->slot);
        kfree(xprt);
-       return ERR_PTR(-EINVAL);
+       return ret;
 }
 
 static struct xprt_class       xs_udp_transport = {
index d92d088026bf885e30607f81799781a4c94c2794..b01a6f6397d7be03659547f98f06569011ffac77 100644 (file)
@@ -50,7 +50,7 @@ int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
        struct ieee80211_channel *chan;
        int result;
 
-       if (wdev->iftype == NL80211_IFTYPE_MONITOR)
+       if (wdev && wdev->iftype == NL80211_IFTYPE_MONITOR)
                wdev = NULL;
 
        if (wdev) {
index aaa1aad566cda4fb16ea866d5a078f8346f33340..db71150b8040d07d9590a8229b9070b7461d7279 100644 (file)
@@ -4443,9 +4443,10 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
                if (channel_type != NL80211_CHAN_NO_HT &&
                    channel_type != NL80211_CHAN_HT20 &&
                    channel_type != NL80211_CHAN_HT40PLUS &&
-                   channel_type != NL80211_CHAN_HT40MINUS)
+                   channel_type != NL80211_CHAN_HT40MINUS) {
                        err = -EINVAL;
                        goto out;
+               }
        }
 
        freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
@@ -4717,9 +4718,10 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info)
                if (channel_type != NL80211_CHAN_NO_HT &&
                    channel_type != NL80211_CHAN_HT20 &&
                    channel_type != NL80211_CHAN_HT40PLUS &&
-                   channel_type != NL80211_CHAN_HT40MINUS)
+                   channel_type != NL80211_CHAN_HT40MINUS) {
                        err = -EINVAL;
                        goto out;
+               }
        }
 
        freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
index a026c6d56bd3347898cb1486301aedba37119b03..58401d246bda9defe3a142f1c64c0b048530fd63 100644 (file)
@@ -515,7 +515,7 @@ cfg80211_inform_bss(struct wiphy *wiphy,
 
        privsz = wiphy->bss_priv_size;
 
-       if (WARN_ON(wiphy->signal_type == NL80211_BSS_SIGNAL_UNSPEC &&
+       if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC &&
                        (signal < 0 || signal > 100)))
                return NULL;
 
@@ -571,7 +571,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
                                      u.probe_resp.variable);
        size_t privsz = wiphy->bss_priv_size;
 
-       if (WARN_ON(wiphy->signal_type == NL80211_BSS_SIGNAL_UNSPEC &&
+       if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC &&
                    (signal < 0 || signal > 100)))
                return NULL;
 
index dffdc49878af6532104307430155f4aeb44bf538..4d46be965961fd4f2f6d745243f38b87a43dfd51 100644 (file)
@@ -7,7 +7,5 @@
 DECLARE_TRACE(subsys_event,
        TP_PROTO(struct inode *inode, struct file *file),
        TP_ARGS(inode, file));
-DECLARE_TRACE(subsys_eventb,
-       TP_PROTO(void),
-       TP_ARGS());
+DECLARE_TRACE_NOARGS(subsys_eventb);
 #endif
index 9e60eb6ca2d8a691f4c01adc3592be40eb7e5824..744c0b9652a7815407b95ecbb8ca6553c5e900c0 100644 (file)
@@ -13,7 +13,8 @@
  * Here the caller only guarantees locking for struct file and struct inode.
  * Locking must therefore be done in the probe to use the dentry.
  */
-static void probe_subsys_event(struct inode *inode, struct file *file)
+static void probe_subsys_event(void *ignore,
+                              struct inode *inode, struct file *file)
 {
        path_get(&file->f_path);
        dget(file->f_path.dentry);
@@ -23,7 +24,7 @@ static void probe_subsys_event(struct inode *inode, struct file *file)
        path_put(&file->f_path);
 }
 
-static void probe_subsys_eventb(void)
+static void probe_subsys_eventb(void *ignore)
 {
        printk(KERN_INFO "Event B is encountered\n");
 }
@@ -32,9 +33,9 @@ static int __init tp_sample_trace_init(void)
 {
        int ret;
 
-       ret = register_trace_subsys_event(probe_subsys_event);
+       ret = register_trace_subsys_event(probe_subsys_event, NULL);
        WARN_ON(ret);
-       ret = register_trace_subsys_eventb(probe_subsys_eventb);
+       ret = register_trace_subsys_eventb(probe_subsys_eventb, NULL);
        WARN_ON(ret);
 
        return 0;
@@ -44,8 +45,8 @@ module_init(tp_sample_trace_init);
 
 static void __exit tp_sample_trace_exit(void)
 {
-       unregister_trace_subsys_eventb(probe_subsys_eventb);
-       unregister_trace_subsys_event(probe_subsys_event);
+       unregister_trace_subsys_eventb(probe_subsys_eventb, NULL);
+       unregister_trace_subsys_event(probe_subsys_event, NULL);
        tracepoint_synchronize_unregister();
 }
 
index be2a960573f174991fe26c4ccdfd5794bc61c988..9fcf990e5d4bd01c7095471105b2260028be1919 100644 (file)
@@ -12,7 +12,8 @@
  * Here the caller only guarantees locking for struct file and struct inode.
  * Locking must therefore be done in the probe to use the dentry.
  */
-static void probe_subsys_event(struct inode *inode, struct file *file)
+static void probe_subsys_event(void *ignore,
+                              struct inode *inode, struct file *file)
 {
        printk(KERN_INFO "Event is encountered with inode number %lu\n",
                inode->i_ino);
@@ -22,7 +23,7 @@ static int __init tp_sample_trace_init(void)
 {
        int ret;
 
-       ret = register_trace_subsys_event(probe_subsys_event);
+       ret = register_trace_subsys_event(probe_subsys_event, NULL);
        WARN_ON(ret);
 
        return 0;
@@ -32,7 +33,7 @@ module_init(tp_sample_trace_init);
 
 static void __exit tp_sample_trace_exit(void)
 {
-       unregister_trace_subsys_event(probe_subsys_event);
+       unregister_trace_subsys_event(probe_subsys_event, NULL);
        tracepoint_synchronize_unregister();
 }
 
index f2bbea9007006e0549d1c8ece31274a15153326c..bd88f11b0953d161b259e80b27d6f423b12e8b1c 100755 (executable)
@@ -1382,6 +1382,21 @@ sub process {
                        ERROR("trailing whitespace\n" . $herevet);
                }
 
+# check for Kconfig help text having a real description
+               if ($realfile =~ /Kconfig/ &&
+                   $line =~ /\+?\s*(---)?help(---)?$/) {
+                       my $length = 0;
+                       for (my $l = $linenr; defined($lines[$l]); $l++) {
+                               my $f = $lines[$l];
+                               $f =~ s/#.*//;
+                               $f =~ s/^\s+//;
+                               next if ($f =~ /^$/);
+                               last if ($f =~ /^\s*config\s/);
+                               $length++;
+                       }
+                       WARN("please write a paragraph that describes the config symbol fully\n" . $herecurr) if ($length < 4);
+               }
+
 # check we are in a valid source file if not then ignore this hunk
                next if ($realfile !~ /\.(h|c|s|S|pl|sh)$/);
 
@@ -2586,6 +2601,11 @@ sub process {
                        CHK("architecture specific defines should be avoided\n" .  $herecurr);
                }
 
+# Check that the storage class is at the beginning of a declaration
+               if ($line =~ /\b$Storage\b/ && $line !~ /^.\s*$Storage\b/) {
+                       WARN("storage class should be at the beginning of the declaration\n" . $herecurr)
+               }
+
 # check the location of the inline attribute, that it is between
 # storage class and type.
                if ($line =~ /\b$Type\s+$Inline\b/ ||
index 76af5f9623e3a41027e20c68fcd21610529bf4b4..a932ae52f921b5967b705432d0ef972f60c73c24 100644 (file)
@@ -242,6 +242,7 @@ case "$arg" in
                echo "$output_file" | grep -q "\.gz$" && compr="gzip -9 -f"
                echo "$output_file" | grep -q "\.bz2$" && compr="bzip2 -9 -f"
                echo "$output_file" | grep -q "\.lzma$" && compr="lzma -9 -f"
+               echo "$output_file" | grep -q "\.lzo$" && compr="lzop -9 -f"
                echo "$output_file" | grep -q "\.cpio$" && compr="cat"
                shift
                ;;
index 6f97a13bcee4131aedbbf97a4f9db49c50e519e5..b2281982f52f1a156f3eb5b321d3ec9a5fcaee0f 100755 (executable)
@@ -13,7 +13,7 @@
 use strict;
 
 my $P = $0;
-my $V = '0.23';
+my $V = '0.24';
 
 use Getopt::Long qw(:config no_auto_abbrev);
 
@@ -25,6 +25,7 @@ my $email_list = 1;
 my $email_subscriber_list = 0;
 my $email_git_penguin_chiefs = 0;
 my $email_git = 1;
+my $email_git_all_signature_types = 0;
 my $email_git_blame = 0;
 my $email_git_min_signatures = 1;
 my $email_git_max_maintainers = 5;
@@ -51,9 +52,9 @@ my $help = 0;
 my $exit = 0;
 
 my @penguin_chief = ();
-push(@penguin_chief,"Linus Torvalds:torvalds\@linux-foundation.org");
+push(@penguin_chief, "Linus Torvalds:torvalds\@linux-foundation.org");
 #Andrew wants in on most everything - 2009/01/14
-#push(@penguin_chief,"Andrew Morton:akpm\@linux-foundation.org");
+#push(@penguin_chief, "Andrew Morton:akpm\@linux-foundation.org");
 
 my @penguin_chief_names = ();
 foreach my $chief (@penguin_chief) {
@@ -63,7 +64,16 @@ foreach my $chief (@penguin_chief) {
        push(@penguin_chief_names, $chief_name);
     }
 }
-my $penguin_chiefs = "\(" . join("|",@penguin_chief_names) . "\)";
+my $penguin_chiefs = "\(" . join("|", @penguin_chief_names) . "\)";
+
+# Signature types of people who are either
+#      a) responsible for the code in question, or
+#      b) familiar enough with it to give relevant feedback
+my @signature_tags = ();
+push(@signature_tags, "Signed-off-by:");
+push(@signature_tags, "Reviewed-by:");
+push(@signature_tags, "Acked-by:");
+my $signaturePattern = "\(" . join("|", @signature_tags) . "\)";
 
 # rfc822 email address - preloaded methods go here.
 my $rfc822_lwsp = "(?:(?:\\r\\n)?[ \\t])";
@@ -97,9 +107,34 @@ my %VCS_cmds_hg = (
     "blame_commit_pattern" => "^([0-9a-f]+):"
 );
 
+if (-f "${lk_path}.get_maintainer.conf") {
+    my @conf_args;
+    open(my $conffile, '<', "${lk_path}.get_maintainer.conf")
+       or warn "$P: Can't open .get_maintainer.conf: $!\n";
+    while (<$conffile>) {
+       my $line = $_;
+
+       $line =~ s/\s*\n?$//g;
+       $line =~ s/^\s*//g;
+       $line =~ s/\s+/ /g;
+
+       next if ($line =~ m/^\s*#/);
+       next if ($line =~ m/^\s*$/);
+
+       my @words = split(" ", $line);
+       foreach my $word (@words) {
+           last if ($word =~ m/^#/);
+           push (@conf_args, $word);
+       }
+    }
+    close($conffile);
+    unshift(@ARGV, @conf_args) if @conf_args;
+}
+
 if (!GetOptions(
                'email!' => \$email,
                'git!' => \$email_git,
+               'git-all-signature-types!' => \$email_git_all_signature_types,
                'git-blame!' => \$email_git_blame,
                'git-chief-penguins!' => \$email_git_penguin_chiefs,
                'git-min-signatures=i' => \$email_git_min_signatures,
@@ -180,6 +215,10 @@ if (!top_of_kernel_tree($lk_path)) {
        . "a linux kernel source tree.\n";
 }
 
+if ($email_git_all_signature_types) {
+    $signaturePattern = "(.+?)[Bb][Yy]:";
+}
+
 ## Read MAINTAINERS for type/value pairs
 
 my @typevalue = ();
@@ -497,13 +536,15 @@ version: $V
 MAINTAINER field selection options:
   --email => print email address(es) if any
     --git => include recent git \*-by: signers
+    --git-all-signature-types => include signers regardless of signature type
+        or use only ${signaturePattern} signers (default: $email_git_all_signature_types)
     --git-chief-penguins => include ${penguin_chiefs}
-    --git-min-signatures => number of signatures required (default: 1)
-    --git-max-maintainers => maximum maintainers to add (default: 5)
-    --git-min-percent => minimum percentage of commits required (default: 5)
+    --git-min-signatures => number of signatures required (default: $email_git_min_signatures)
+    --git-max-maintainers => maximum maintainers to add (default: $email_git_max_maintainers)
+    --git-min-percent => minimum percentage of commits required (default: $email_git_min_percent)
     --git-blame => use git blame to find modified commits for patch or file
-    --git-since => git history to use (default: 1-year-ago)
-    --hg-since => hg history to use (default: -365)
+    --git-since => git history to use (default: $email_git_since)
+    --hg-since => hg history to use (default: $email_hg_since)
     --m => include maintainer(s) if any
     --n => include name 'Full Name <addr\@domain.tld>'
     --l => include list(s) if any
@@ -556,6 +597,11 @@ Notes:
           --git-min-signatures, --git-max-maintainers, --git-min-percent, and
           --git-blame
       Use --hg-since not --git-since to control date selection
+  File ".get_maintainer.conf", if it exists in the linux kernel source root
+      directory, can change whatever get_maintainer defaults are desired.
+      Entries in this file can be any command line argument.
+      This file is prepended to any additional command line arguments.
+      Multiple lines and # comments are allowed.
 EOT
 }
 
@@ -964,7 +1010,7 @@ sub vcs_find_signers {
 
     $commits = grep(/$pattern/, @lines);       # of commits
 
-    @lines = grep(/^[-_        a-z]+by:.*\@.*$/i, @lines);
+    @lines = grep(/^[ \t]*${signaturePattern}.*\@.*$/, @lines);
     if (!$email_git_penguin_chiefs) {
        @lines = grep(!/${penguin_chiefs}/i, @lines);
     }
index 9cf2400580a72a586b501c0c5d831473ea49dd77..5758aab0d8bb6c8f401b8e2e8374432007ba172b 100644 (file)
@@ -828,6 +828,19 @@ static int do_zorro_entry(const char *filename, struct zorro_device_id *id,
        return 1;
 }
 
+/* looks like: "pnp:dD" */
+static int do_isapnp_entry(const char *filename,
+                          struct isapnp_device_id *id, char *alias)
+{
+       sprintf(alias, "pnp:d%c%c%c%x%x%x%x*",
+               'A' + ((id->vendor >> 2) & 0x3f) - 1,
+               'A' + (((id->vendor & 3) << 3) | ((id->vendor >> 13) & 7)) - 1,
+               'A' + ((id->vendor >> 8) & 0x1f) - 1,
+               (id->function >> 4) & 0x0f, id->function & 0x0f,
+               (id->function >> 12) & 0x0f, (id->function >> 8) & 0x0f);
+       return 1;
+}
+
 /* Ignore any prefix, eg. some architectures prepend _ */
 static inline int sym_is(const char *symbol, const char *name)
 {
@@ -983,6 +996,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
                do_table(symval, sym->st_size,
                         sizeof(struct zorro_device_id), "zorro",
                         do_zorro_entry, mod);
+       else if (sym_is(symname, "__mod_isapnp_device_table"))
+               do_table(symval, sym->st_size,
+                       sizeof(struct isapnp_device_id), "isa",
+                       do_isapnp_entry, mod);
        free(zeros);
 }
 
index 5d4402a1161aba1110108ece6b6161793746c55b..38783dcf6c61fb6e380131c40c8abbbf1414a5dd 100644 (file)
@@ -124,6 +124,7 @@ extern struct key *find_keyring_by_name(const char *name, bool skip_perm_check);
 extern int install_user_keyrings(void);
 extern int install_thread_keyring_to_cred(struct cred *);
 extern int install_process_keyring_to_cred(struct cred *);
+extern int install_session_keyring_to_cred(struct cred *, struct key *);
 
 extern struct key *request_key_and_link(struct key_type *type,
                                        const char *description,
index 8f4dce1987c492c59a9e2a6870b1bebaeaac09a8..13074b4547433ab20929fa493114b507c9e4389f 100644 (file)
@@ -1269,7 +1269,7 @@ long keyctl_session_to_parent(void)
                goto not_permitted;
 
        /* the parent must be single threaded */
-       if (atomic_read(&parent->signal->count) != 1)
+       if (!thread_group_empty(parent))
                goto not_permitted;
 
        /* the parent and the child must have different session keyrings or
index ef03a82a01352fe942694678735ad79c0b6654ec..d37f713e73ce7ef7937ef8bfe23a96960202c187 100644 (file)
@@ -669,7 +669,7 @@ static void keyring_unlink_rcu_disposal(struct rcu_head *rcu)
        struct keyring_list *klist =
                container_of(rcu, struct keyring_list, rcu);
 
-       if (klist->delkey != USHORT_MAX)
+       if (klist->delkey != USHRT_MAX)
                key_put(klist->keys[klist->delkey]);
        kfree(klist);
 }
@@ -746,7 +746,7 @@ int __key_link_begin(struct key *keyring, const struct key_type *type,
                        max += klist->maxkeys;
 
                ret = -ENFILE;
-               if (max > USHORT_MAX - 1)
+               if (max > USHRT_MAX - 1)
                        goto error_quota;
                size = sizeof(*klist) + sizeof(struct key *) * max;
                if (size > PAGE_SIZE)
@@ -763,7 +763,7 @@ int __key_link_begin(struct key *keyring, const struct key_type *type,
                               sizeof(struct key *) * klist->nkeys);
                        nklist->delkey = klist->nkeys;
                        nklist->nkeys = klist->nkeys + 1;
-                       klist->delkey = USHORT_MAX;
+                       klist->delkey = USHRT_MAX;
                } else {
                        nklist->nkeys = 1;
                        nklist->delkey = 0;
index 20a38fed61b1efb812799bc83ff31db78c1411ac..6b8e4ff4cc68cfebe2bb845dda44d8d4b8542635 100644 (file)
@@ -216,8 +216,7 @@ static int install_process_keyring(void)
 /*
  * install a session keyring directly to a credentials struct
  */
-static int install_session_keyring_to_cred(struct cred *cred,
-                                          struct key *keyring)
+int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
 {
        unsigned long flags;
        struct key *old;
index f656e9c069e3ec31f64d8a4a2ec9d9add862a4cb..f5ec9ac5d57cf6af80f90eb90427ecb98385ae4f 100644 (file)
@@ -58,6 +58,38 @@ void complete_request_key(struct key_construction *cons, int error)
 }
 EXPORT_SYMBOL(complete_request_key);
 
+static int umh_keys_init(struct subprocess_info *info)
+{
+       struct cred *cred = (struct cred*)current_cred();
+       struct key *keyring = info->data;
+       /*
+        * This is called in context of freshly forked kthread before
+        * kernel_execve(), we can just change our ->session_keyring.
+        */
+       return install_session_keyring_to_cred(cred, keyring);
+}
+
+static void umh_keys_cleanup(struct subprocess_info *info)
+{
+       struct key *keyring = info->data;
+       key_put(keyring);
+}
+
+static int call_usermodehelper_keys(char *path, char **argv, char **envp,
+                        struct key *session_keyring, enum umh_wait wait)
+{
+       gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL;
+       struct subprocess_info *info =
+               call_usermodehelper_setup(path, argv, envp, gfp_mask);
+
+       if (!info)
+               return -ENOMEM;
+
+       call_usermodehelper_setfns(info, umh_keys_init, umh_keys_cleanup,
+                                       key_get(session_keyring));
+       return call_usermodehelper_exec(info, wait);
+}
+
 /*
  * request userspace finish the construction of a key
  * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring>"
index a03fd74602b457cdfa18498251ad992695ac14e4..5c9f25ba1c9537faa8e1ea91a482dd8960cb745e 100644 (file)
@@ -126,11 +126,6 @@ __setup("selinux=", selinux_enabled_setup);
 int selinux_enabled = 1;
 #endif
 
-/* Lists of inode and superblock security structures initialized
-   before the policy was loaded. */
-static LIST_HEAD(superblock_security_head);
-static DEFINE_SPINLOCK(sb_security_lock);
-
 static struct kmem_cache *sel_inode_cache;
 
 /**
@@ -266,7 +261,6 @@ static int superblock_alloc_security(struct super_block *sb)
                return -ENOMEM;
 
        mutex_init(&sbsec->lock);
-       INIT_LIST_HEAD(&sbsec->list);
        INIT_LIST_HEAD(&sbsec->isec_head);
        spin_lock_init(&sbsec->isec_lock);
        sbsec->sb = sb;
@@ -281,12 +275,6 @@ static int superblock_alloc_security(struct super_block *sb)
 static void superblock_free_security(struct super_block *sb)
 {
        struct superblock_security_struct *sbsec = sb->s_security;
-
-       spin_lock(&sb_security_lock);
-       if (!list_empty(&sbsec->list))
-               list_del_init(&sbsec->list);
-       spin_unlock(&sb_security_lock);
-
        sb->s_security = NULL;
        kfree(sbsec);
 }
@@ -612,10 +600,6 @@ static int selinux_set_mnt_opts(struct super_block *sb,
                        /* Defer initialization until selinux_complete_init,
                           after the initial policy is loaded and the security
                           server is ready to handle calls. */
-                       spin_lock(&sb_security_lock);
-                       if (list_empty(&sbsec->list))
-                               list_add(&sbsec->list, &superblock_security_head);
-                       spin_unlock(&sb_security_lock);
                        goto out;
                }
                rc = -EINVAL;
@@ -806,16 +790,10 @@ static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
 
        /*
         * if the parent was able to be mounted it clearly had no special lsm
-        * mount options.  thus we can safely put this sb on the list and deal
-        * with it later
+        * mount options.  thus we can safely deal with this superblock later
         */
-       if (!ss_initialized) {
-               spin_lock(&sb_security_lock);
-               if (list_empty(&newsbsec->list))
-                       list_add(&newsbsec->list, &superblock_security_head);
-               spin_unlock(&sb_security_lock);
+       if (!ss_initialized)
                return;
-       }
 
        /* how can we clone if the old one wasn't set up?? */
        BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED));
@@ -5680,35 +5658,18 @@ static __init int selinux_init(void)
        return 0;
 }
 
+static void delayed_superblock_init(struct super_block *sb, void *unused)
+{
+       superblock_doinit(sb, NULL);
+}
+
 void selinux_complete_init(void)
 {
        printk(KERN_DEBUG "SELinux:  Completing initialization.\n");
 
        /* Set up any superblocks initialized prior to the policy load. */
        printk(KERN_DEBUG "SELinux:  Setting up existing superblocks.\n");
-       spin_lock(&sb_lock);
-       spin_lock(&sb_security_lock);
-next_sb:
-       if (!list_empty(&superblock_security_head)) {
-               struct superblock_security_struct *sbsec =
-                               list_entry(superblock_security_head.next,
-                                          struct superblock_security_struct,
-                                          list);
-               struct super_block *sb = sbsec->sb;
-               sb->s_count++;
-               spin_unlock(&sb_security_lock);
-               spin_unlock(&sb_lock);
-               down_read(&sb->s_umount);
-               if (sb->s_root)
-                       superblock_doinit(sb, NULL);
-               drop_super(sb);
-               spin_lock(&sb_lock);
-               spin_lock(&sb_security_lock);
-               list_del_init(&sbsec->list);
-               goto next_sb;
-       }
-       spin_unlock(&sb_security_lock);
-       spin_unlock(&sb_lock);
+       iterate_supers(delayed_superblock_init, NULL);
 }
 
 /* SELinux requires early initialization in order to label
index c4e062336ef3a6d6265d99f750e6ea8c6ba8f8f7..26c7eee1c309b0a2f45a23c8b70d2157841c1670 100644 (file)
@@ -55,7 +55,6 @@ struct file_security_struct {
 
 struct superblock_security_struct {
        struct super_block *sb;         /* back pointer to sb object */
-       struct list_head list;          /* list of superblock_security_struct */
        u32 sid;                        /* SID of file system superblock */
        u32 def_sid;                    /* default SID for labeling */
        u32 mntpoint_sid;               /* SECURITY_FS_USE_MNTPOINT context for files */
index 1cd9b301df0357dd7802626c93731d22c5efc73b..3fd1a7e24928fdbc08e45f727ed34b3625d7effc 100644 (file)
@@ -992,7 +992,7 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
                return -ENODEV;
 
        /* by breaking out we keep a reference */
-       while ((sound = of_get_next_child(sdev->ofdev.node, sound))) {
+       while ((sound = of_get_next_child(sdev->ofdev.dev.of_node, sound))) {
                if (sound->type && strcasecmp(sound->type, "soundchip") == 0)
                        break;
        }
index fa8ab2815a982676d1f3a0ef3c47ebcec8f3ee39..99ca7120e269fc677eddd608150ce86769bfe78c 100644 (file)
@@ -74,11 +74,11 @@ static int soundbus_uevent(struct device *dev, struct kobj_uevent_env *env)
        of = &soundbus_dev->ofdev;
 
        /* stuff we want to pass to /sbin/hotplug */
-       retval = add_uevent_var(env, "OF_NAME=%s", of->node->name);
+       retval = add_uevent_var(env, "OF_NAME=%s", of->dev.of_node->name);
        if (retval)
                return retval;
 
-       retval = add_uevent_var(env, "OF_TYPE=%s", of->node->type);
+       retval = add_uevent_var(env, "OF_TYPE=%s", of->dev.of_node->type);
        if (retval)
                return retval;
 
@@ -86,7 +86,7 @@ static int soundbus_uevent(struct device *dev, struct kobj_uevent_env *env)
         * it's not really legal to split it out with commas. We split it
         * up using a number of environment variables instead. */
 
-       compat = of_get_property(of->node, "compatible", &cplen);
+       compat = of_get_property(of->dev.of_node, "compatible", &cplen);
        while (compat && cplen > 0) {
                int tmp = env->buflen;
                retval = add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat);
@@ -169,7 +169,7 @@ int soundbus_add_one(struct soundbus_dev *dev)
 
        /* sanity checks */
        if (!dev->attach_codec ||
-           !dev->ofdev.node ||
+           !dev->ofdev.dev.of_node ||
            dev->pcmname ||
            dev->pcmid != -1) {
                printk(KERN_ERR "soundbus: adding device failed sanity check!\n");
index 47f854c2001facf5f19f2df68686007972bb7d3f..4dc9b49c02cf78a983e9a38ec02ee24adac399bd 100644 (file)
@@ -42,7 +42,7 @@ int i2sbus_control_add_dev(struct i2sbus_control *c,
 {
        struct device_node *np;
 
-       np = i2sdev->sound.ofdev.node;
+       np = i2sdev->sound.ofdev.dev.of_node;
        i2sdev->enable = pmf_find_function(np, "enable");
        i2sdev->cell_enable = pmf_find_function(np, "cell-enable");
        i2sdev->clock_enable = pmf_find_function(np, "clock-enable");
index 9d6f3b176ed1ac73f20c4e8427403a9970ca0156..67893372173581601fbcd5c71ca9c30cab0b5a7a 100644 (file)
@@ -221,9 +221,9 @@ static int i2sbus_add_dev(struct macio_dev *macio,
 
        mutex_init(&dev->lock);
        spin_lock_init(&dev->low_lock);
-       dev->sound.ofdev.node = np;
-       dev->sound.ofdev.dma_mask = macio->ofdev.dma_mask;
-       dev->sound.ofdev.dev.dma_mask = &dev->sound.ofdev.dma_mask;
+       dev->sound.ofdev.archdata.dma_mask = macio->ofdev.archdata.dma_mask;
+       dev->sound.ofdev.dev.of_node = np;
+       dev->sound.ofdev.dev.dma_mask = &dev->sound.ofdev.archdata.dma_mask;
        dev->sound.ofdev.dev.parent = &macio->ofdev.dev;
        dev->sound.ofdev.dev.release = i2sbus_release_dev;
        dev->sound.attach_codec = i2sbus_attach_codec;
@@ -346,7 +346,7 @@ static int i2sbus_probe(struct macio_dev* dev, const struct of_device_id *match)
                return -ENODEV;
        }
 
-       while ((np = of_get_next_child(dev->ofdev.node, np))) {
+       while ((np = of_get_next_child(dev->ofdev.dev.of_node, np))) {
                if (of_device_is_compatible(np, "i2sbus") ||
                    of_device_is_compatible(np, "i2s-modem")) {
                        got += i2sbus_add_dev(dev, control, np);
index f580942b5c09b0f2392fd11860c0cb14e76cf99b..6496e754f00a2b1bb470f9942cc7d5f1f569b3c9 100644 (file)
@@ -9,7 +9,7 @@ field##_show (struct device *dev, struct device_attribute *attr,        \
               char *buf)                                               \
 {                                                                      \
        struct soundbus_dev *mdev = to_soundbus_device (dev);           \
-       return sprintf (buf, format_string, mdev->ofdev.node->field);   \
+       return sprintf (buf, format_string, mdev->ofdev.dev.of_node->field); \
 }
 
 static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
@@ -25,7 +25,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
                length = strlen(buf);
        } else {
                length = sprintf(buf, "of:N%sT%s\n",
-                                of->node->name, of->node->type);
+                                of->dev.of_node->name, of->dev.of_node->type);
        }
 
        return length;
index a2ff86189d2a583ad208c8e61beed816d3f23a67..e9d98be190c58db786c53ea8adc9770bd808d5ec 100644 (file)
@@ -345,7 +345,9 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
                new_hw_ptr = hw_base + pos;
        }
       __delta:
-       delta = (new_hw_ptr - old_hw_ptr) % runtime->boundary;
+       delta = new_hw_ptr - old_hw_ptr;
+       if (delta < 0)
+               delta += runtime->boundary;
        if (xrun_debug(substream, in_interrupt ?
                        XRUN_DEBUG_PERIODUPDATE : XRUN_DEBUG_HWPTRUPDATE)) {
                char name[16];
@@ -439,8 +441,13 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
                snd_pcm_playback_silence(substream, new_hw_ptr);
 
        if (in_interrupt) {
-               runtime->hw_ptr_interrupt = new_hw_ptr -
-                               (new_hw_ptr % runtime->period_size);
+               delta = new_hw_ptr - runtime->hw_ptr_interrupt;
+               if (delta < 0)
+                       delta += runtime->boundary;
+               delta -= (snd_pcm_uframes_t)delta % runtime->period_size;
+               runtime->hw_ptr_interrupt += delta;
+               if (runtime->hw_ptr_interrupt >= runtime->boundary)
+                       runtime->hw_ptr_interrupt -= runtime->boundary;
        }
        runtime->hw_ptr_base = hw_base;
        runtime->status->hw_ptr = new_hw_ptr;
index 644c2bb17b86270e3c7fd88307858095470b1bb4..303ac04ff6e427066bf95fe0932361efd7a94ea3 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/pm_qos_params.h>
 #include <linux/uio.h>
 #include <linux/dma-mapping.h>
-#include <linux/math64.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/info.h>
@@ -370,38 +369,6 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime)
        return usecs;
 }
 
-static int calc_boundary(struct snd_pcm_runtime *runtime)
-{
-       u_int64_t boundary;
-
-       boundary = (u_int64_t)runtime->buffer_size *
-                  (u_int64_t)runtime->period_size;
-#if BITS_PER_LONG < 64
-       /* try to find lowest common multiple for buffer and period */
-       if (boundary > LONG_MAX - runtime->buffer_size) {
-               u_int32_t remainder = -1;
-               u_int32_t divident = runtime->buffer_size;
-               u_int32_t divisor = runtime->period_size;
-               while (remainder) {
-                       remainder = divident % divisor;
-                       if (remainder) {
-                               divident = divisor;
-                               divisor = remainder;
-                       }
-               }
-               boundary = div_u64(boundary, divisor);
-               if (boundary > LONG_MAX - runtime->buffer_size)
-                       return -ERANGE;
-       }
-#endif
-       if (boundary == 0)
-               return -ERANGE;
-       runtime->boundary = boundary;
-       while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size)
-               runtime->boundary *= 2;
-       return 0;
-}
-
 static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
                             struct snd_pcm_hw_params *params)
 {
@@ -477,9 +444,9 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
        runtime->stop_threshold = runtime->buffer_size;
        runtime->silence_threshold = 0;
        runtime->silence_size = 0;
-       err = calc_boundary(runtime);
-       if (err < 0)
-               goto _error;
+       runtime->boundary = runtime->buffer_size;
+       while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size)
+               runtime->boundary *= 2;
 
        snd_pcm_timer_resolution_change(substream);
        runtime->status->state = SNDRV_PCM_STATE_SETUP;
index 3e763d6a5d67802d6f736e4df0dccfd88eff2224..446cf9748664dde623a5c0320a3746b9e2d8225b 100644 (file)
@@ -516,6 +516,7 @@ get the interrupt driven case to work efficiently */
                        break;
        if (i == 0x5000) {
                printk(KERN_ERR "au1000 AC97: AC97 command read timeout\n");
+               spin_unlock(&au1000->ac97_lock);
                return 0;
        }
 
index 1f47741230641ac90fe4d837d3da21e9c4dbfef0..13c214466d3b9f0edb79dcad50a5ab1124a75529 100644 (file)
@@ -1277,7 +1277,7 @@ static irqreturn_t AtaInterrupt(int irq, void *dummy)
                 * (almost) like on the TT.
                 */
                write_sq_ignore_int = 0;
-               return IRQ_HANDLED;
+               goto out;
        }
 
        if (!write_sq.active) {
@@ -1285,7 +1285,7 @@ static irqreturn_t AtaInterrupt(int irq, void *dummy)
                 * the sq variables, so better don't do anything here.
                 */
                WAKE_UP(write_sq.sync_queue);
-               return IRQ_HANDLED;
+               goto out;
        }
 
        /* Probably ;) one frame is finished. Well, in fact it may be that a
@@ -1322,6 +1322,7 @@ static irqreturn_t AtaInterrupt(int irq, void *dummy)
        /* We are not playing after AtaPlay(), so there
           is nothing to play any more. Wake up a process
           waiting for audio output to drain. */
+out:
        spin_unlock(&dmasound.lock);
        return IRQ_HANDLED;
 }
index 99400de6c0759bba22e27cfcb17cf93bd582d27a..0173bbe62b678dc2d5130d218537ec10f9cc6ce5 100644 (file)
@@ -50,7 +50,7 @@ i.e 3.05.02 is a development version
 #define HPI_VER_RELEASE(v) ((int)(v & 0xFF))
 
 /* Use single digits for versions less that 10 to avoid octal. */
-#define HPI_VER HPI_VERSION_CONSTRUCTOR(4L, 3, 18)
+#define HPI_VER HPI_VERSION_CONSTRUCTOR(4L, 3, 25)
 
 /* Library version as documented in hpi-api-versions.txt */
 #define HPI_LIB_VER  HPI_VERSION_CONSTRUCTOR(9, 0, 0)
@@ -1632,6 +1632,12 @@ u16 hpi_tuner_get_hd_radio_sdk_version(const struct hpi_hsubsys *ph_subsys,
 u16 hpi_tuner_get_hd_radio_signal_quality(const struct hpi_hsubsys *ph_subsys,
        u32 h_control, u32 *pquality);
 
+u16 hpi_tuner_get_hd_radio_signal_blend(const struct hpi_hsubsys *ph_subsys,
+       u32 h_control, u32 *pblend);
+
+u16 hpi_tuner_set_hd_radio_signal_blend(const struct hpi_hsubsys *ph_subsys,
+       u32 h_control, const u32 blend);
+
 /****************************/
 /* PADs control             */
 /****************************/
index 839ecb2e4b643d83f229a311763408d7b3b53bee..12dab5e4892cd898b6cd53944a4bcfd585986527 100644 (file)
@@ -691,9 +691,6 @@ static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
        case 0x6200:
                boot_load_family = HPI_ADAPTER_FAMILY_ASI(0x6200);
                break;
-       case 0x8800:
-               boot_load_family = HPI_ADAPTER_FAMILY_ASI(0x8800);
-               break;
        default:
                return HPI6000_ERROR_UNHANDLED_SUBSYS_ID;
        }
@@ -1775,7 +1772,6 @@ static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,
        u16 error = 0;
        u16 dsp_index = 0;
        u16 num_dsp = ((struct hpi_hw_obj *)pao->priv)->num_dsp;
-       hpios_dsplock_lock(pao);
 
        if (num_dsp < 2)
                dsp_index = 0;
@@ -1796,6 +1792,8 @@ static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,
                        }
                }
        }
+
+       hpios_dsplock_lock(pao);
        error = hpi6000_message_response_sequence(pao, dsp_index, phm, phr);
 
        /* maybe an error response */
index 5e88c1fc2b9e4307b210d67a713769789a69b5c4..e89991ea35439c7ea122777ee3bd284feaa47535 100644 (file)
@@ -965,24 +965,17 @@ static void outstream_write(struct hpi_adapter_obj *pao,
        hpi_init_response(phr, phm->object, phm->function, 0);
        status = &interface->outstream_host_buffer_status[phm->obj_index];
 
-       if (phw->flag_outstream_just_reset[phm->obj_index]) {
-               /* Format can only change after reset. Must tell DSP. */
-               u16 function = phm->function;
-               phw->flag_outstream_just_reset[phm->obj_index] = 0;
-               phm->function = HPI_OSTREAM_SET_FORMAT;
-               hw_message(pao, phm, phr);      /* send the format to the DSP */
-               phm->function = function;
-               if (phr->error)
-                       return;
-       }
-#if 1
        if (phw->flag_outstream_just_reset[phm->obj_index]) {
                /* First OutStremWrite() call following reset will write data to the
-                  adapter's buffers, reducing delay before stream can start
+                  adapter's buffers, reducing delay before stream can start. The DSP
+                  takes care of setting the stream data format using format information
+                  embedded in phm.
                 */
                int partial_write = 0;
                unsigned int original_size = 0;
 
+               phw->flag_outstream_just_reset[phm->obj_index] = 0;
+
                /* Send the first buffer to the DSP the old way. */
                /* Limit size of first transfer - */
                /* expect that this will not usually be triggered. */
@@ -1012,7 +1005,6 @@ static void outstream_write(struct hpi_adapter_obj *pao,
                        original_size - HPI6205_SIZEOF_DATA;
                phm->u.d.u.data.pb_data += HPI6205_SIZEOF_DATA;
        }
-#endif
 
        space_available = outstream_get_space_available(status);
        if (space_available < (long)phm->u.d.u.data.data_size) {
@@ -1369,6 +1361,9 @@ static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
        case HPI_ADAPTER_FAMILY_ASI(0x6500):
                firmware_id = HPI_ADAPTER_FAMILY_ASI(0x6600);
                break;
+       case HPI_ADAPTER_FAMILY_ASI(0x8800):
+               firmware_id = HPI_ADAPTER_FAMILY_ASI(0x8900);
+               break;
        }
        boot_code_id[1] = firmware_id;
 
index f1cd6f1a0d44230fff3239e97b18bc575374beb4..fdd0ce02aa68758e844cd0c9425cb69d85a09099 100644 (file)
@@ -232,6 +232,8 @@ enum HPI_BUSES {
 #define HPI_TUNER_HDRADIO_SDK_VERSION   HPI_CTL_ATTR(TUNER, 13)
 /** HD Radio DSP firmware version. */
 #define HPI_TUNER_HDRADIO_DSP_VERSION   HPI_CTL_ATTR(TUNER, 14)
+/** HD Radio signal blend (force analog, or automatic). */
+#define HPI_TUNER_HDRADIO_BLEND         HPI_CTL_ATTR(TUNER, 15)
 
 /** \} */
 
@@ -478,8 +480,10 @@ Threshold is a -ve number in units of dB/100,
 
 /** First 2 hex digits define the adapter family */
 #define HPI_ADAPTER_FAMILY_MASK         0xff00
+#define HPI_MODULE_FAMILY_MASK          0xfff0
 
 #define HPI_ADAPTER_FAMILY_ASI(f)   (f & HPI_ADAPTER_FAMILY_MASK)
+#define HPI_MODULE_FAMILY_ASI(f)   (f & HPI_MODULE_FAMILY_MASK)
 #define HPI_ADAPTER_ASI(f)   (f)
 
 /******************************************* message types */
@@ -970,6 +974,7 @@ struct hpi_control_union_msg {
                                u32 mode;
                                u32 value;
                        } mode;
+                       u32 blend;
                } tuner;
        } u;
 };
index 565102cae4f818bb0211161551cec7bdbc01f388..fcd64539d9efa4d6fe6614a2ebcf730f47f15b56 100644 (file)
@@ -347,20 +347,15 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache,
                        found = 0;
                break;
        case HPI_CONTROL_TUNER:
-               {
-                       struct hpi_control_cache_single *pCT =
-                               (struct hpi_control_cache_single *)pI;
-                       if (phm->u.c.attribute == HPI_TUNER_FREQ)
-                               phr->u.c.param1 = pCT->u.t.freq_ink_hz;
-                       else if (phm->u.c.attribute == HPI_TUNER_BAND)
-                               phr->u.c.param1 = pCT->u.t.band;
-                       else if ((phm->u.c.attribute == HPI_TUNER_LEVEL)
-                               && (phm->u.c.param1 ==
-                                       HPI_TUNER_LEVEL_AVERAGE))
-                               phr->u.c.param1 = pCT->u.t.level;
-                       else
-                               found = 0;
-               }
+               if (phm->u.c.attribute == HPI_TUNER_FREQ)
+                       phr->u.c.param1 = pC->u.t.freq_ink_hz;
+               else if (phm->u.c.attribute == HPI_TUNER_BAND)
+                       phr->u.c.param1 = pC->u.t.band;
+               else if ((phm->u.c.attribute == HPI_TUNER_LEVEL)
+                       && (phm->u.c.param1 == HPI_TUNER_LEVEL_AVERAGE))
+                       phr->u.c.param1 = pC->u.t.level;
+               else
+                       found = 0;
                break;
        case HPI_CONTROL_AESEBU_RECEIVER:
                if (phm->u.c.attribute == HPI_AESEBURX_ERRORSTATUS)
@@ -503,6 +498,9 @@ void hpi_sync_control_cache(struct hpi_control_cache *p_cache,
        struct hpi_control_cache_single *pC;
        struct hpi_control_cache_info *pI;
 
+       if (phr->error)
+               return;
+
        if (!find_control(phm, p_cache, &pI, &control_index))
                return;
 
@@ -520,8 +518,6 @@ void hpi_sync_control_cache(struct hpi_control_cache *p_cache,
                break;
        case HPI_CONTROL_MULTIPLEXER:
                /* mux does not return its setting on Set command. */
-               if (phr->error)
-                       return;
                if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) {
                        pC->u.x.source_node_type = (u16)phm->u.c.param1;
                        pC->u.x.source_node_index = (u16)phm->u.c.param2;
@@ -529,8 +525,6 @@ void hpi_sync_control_cache(struct hpi_control_cache *p_cache,
                break;
        case HPI_CONTROL_CHANNEL_MODE:
                /* mode does not return its setting on Set command. */
-               if (phr->error)
-                       return;
                if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE)
                        pC->u.m.mode = (u16)phm->u.c.param1;
                break;
@@ -545,20 +539,14 @@ void hpi_sync_control_cache(struct hpi_control_cache *p_cache,
                        pC->u.phantom_power.state = (u16)phm->u.c.param1;
                break;
        case HPI_CONTROL_AESEBU_TRANSMITTER:
-               if (phr->error)
-                       return;
                if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT)
                        pC->u.aes3tx.format = phm->u.c.param1;
                break;
        case HPI_CONTROL_AESEBU_RECEIVER:
-               if (phr->error)
-                       return;
                if (phm->u.c.attribute == HPI_AESEBURX_FORMAT)
                        pC->u.aes3rx.source = phm->u.c.param1;
                break;
        case HPI_CONTROL_SAMPLECLOCK:
-               if (phr->error)
-                       return;
                if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE)
                        pC->u.clk.source = (u16)phm->u.c.param1;
                else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX)
@@ -590,7 +578,7 @@ struct hpi_control_cache *hpi_alloc_control_cache(const u32
 
 void hpi_free_control_cache(struct hpi_control_cache *p_cache)
 {
-       if ((p_cache->init) && (p_cache->p_info)) {
+       if (p_cache->init) {
                kfree(p_cache->p_info);
                p_cache->p_info = NULL;
                p_cache->init = 0;
index eda26b31232445b781d9c0a4fd4a33e6a0e6863f..298eef3e20e95db841347310151bc6b007da3efd 100644 (file)
@@ -2946,6 +2946,20 @@ u16 hpi_tuner_get_hd_radio_signal_quality(const struct hpi_hsubsys *ph_subsys,
                HPI_TUNER_HDRADIO_SIGNAL_QUALITY, 0, 0, pquality, NULL);
 }
 
+u16 hpi_tuner_get_hd_radio_signal_blend(const struct hpi_hsubsys *ph_subsys,
+       u32 h_control, u32 *pblend)
+{
+       return hpi_control_param_get(ph_subsys, h_control,
+               HPI_TUNER_HDRADIO_BLEND, 0, 0, pblend, NULL);
+}
+
+u16 hpi_tuner_set_hd_radio_signal_blend(const struct hpi_hsubsys *ph_subsys,
+       u32 h_control, const u32 blend)
+{
+       return hpi_control_param_set(ph_subsys, h_control,
+               HPI_TUNER_HDRADIO_BLEND, blend, 0);
+}
+
 u16 hpi_tuner_getRDS(const struct hpi_hsubsys *ph_subsys, u32 h_control,
        char *p_data)
 {
@@ -3266,8 +3280,7 @@ u16 hpi_entity_find_next(struct hpi_entity *container_entity,
 
 void hpi_entity_free(struct hpi_entity *entity)
 {
-       if (entity != NULL)
-               kfree(entity);
+       kfree(entity);
 }
 
 static u16 hpi_entity_alloc_and_copy(struct hpi_entity *src,
index de615cfdb9502d627656b0723e248e1d9976ed73..742ee12a9e17749371b9d87540094638666666a8 100644 (file)
@@ -89,26 +89,3 @@ u16 hpios_locked_mem_free(struct consistent_dma_area *p_mem_area)
 void hpios_locked_mem_free_all(void)
 {
 }
-
-void __iomem *hpios_map_io(struct pci_dev *pci_dev, int idx,
-       unsigned int length)
-{
-       HPI_DEBUG_LOG(DEBUG, "mapping %d %s %08llx-%08llx %04llx len 0x%x\n",
-               idx, pci_dev->resource[idx].name,
-               (unsigned long long)pci_resource_start(pci_dev, idx),
-               (unsigned long long)pci_resource_end(pci_dev, idx),
-               (unsigned long long)pci_resource_flags(pci_dev, idx), length);
-
-       if (!(pci_resource_flags(pci_dev, idx) & IORESOURCE_MEM)) {
-               HPI_DEBUG_LOG(ERROR, "not an io memory resource\n");
-               return NULL;
-       }
-
-       if (length > pci_resource_len(pci_dev, idx)) {
-               HPI_DEBUG_LOG(ERROR, "resource too small for requested %d \n",
-                       length);
-               return NULL;
-       }
-
-       return ioremap(pci_resource_start(pci_dev, idx), length);
-}
index a62c3f1e5f091c7ba30b556983c0c3ac90ad5c33..370f39b43f853fb1ad9a50c117e391965df8007f 100644 (file)
@@ -166,13 +166,4 @@ struct hpi_adapter {
        void __iomem *ap_remapped_mem_base[HPI_MAX_ADAPTER_MEM_SPACES];
 };
 
-static inline void hpios_unmap_io(void __iomem *addr,
-       unsigned long size)
-{
-       iounmap(addr);
-}
-
-void __iomem *hpios_map_io(struct pci_dev *pci_dev, int idx,
-       unsigned int length);
-
 #endif
index 67921f93a41e08eefc0a2899537d6a5fe071a4e7..c15002242d98863f945fc026e6c3feb49768aace 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/initval.h>
 #include <sound/pcm.h>
@@ -44,9 +44,6 @@ MODULE_LICENSE("GPL");
 /*********************************
  * DEFINES
  ********************************/
-#define PCI_VENDOR_ID_SAA7146            0x1131
-#define PCI_DEVICE_ID_SAA7146            0x7146
-
 #define CTL_ROUTE_ANALOG 0
 #define CTL_ROUTE_DIGITAL 1
 
@@ -165,7 +162,7 @@ module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable Audiowerk2 soundcard.");
 
 static DEFINE_PCI_DEVICE_TABLE(snd_aw2_ids) = {
-       {PCI_VENDOR_ID_SAA7146, PCI_DEVICE_ID_SAA7146, 0, 0,
+       {PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, 0, 0,
         0, 0, 0},
        {0}
 };
@@ -419,7 +416,7 @@ static int snd_aw2_pcm_playback_open(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
 
-       snd_printdd(KERN_DEBUG "aw2: Playback_open \n");
+       snd_printdd(KERN_DEBUG "aw2: Playback_open\n");
        runtime->hw = snd_aw2_playback_hw;
        return 0;
 }
@@ -435,7 +432,7 @@ static int snd_aw2_pcm_capture_open(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
 
-       snd_printdd(KERN_DEBUG "aw2: Capture_open \n");
+       snd_printdd(KERN_DEBUG "aw2: Capture_open\n");
        runtime->hw = snd_aw2_capture_hw;
        return 0;
 }
index 4b302d86f5f26dbd547c8af4f9dc1705440f5b18..7a9401462c1c698a0a8f21e2135a613d1efb5a0b 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/vmalloc.h>
 #include <linux/init.h>
 #include <linux/mutex.h>
+#include <linux/moduleparam.h>
 
 #include <sound/core.h>
 #include <sound/tlv.h>
 #define EMU10K1_CENTER_LFE_FROM_FRONT
 #endif
 
+static bool high_res_gpr_volume;
+module_param(high_res_gpr_volume, bool, 0444);
+MODULE_PARM_DESC(high_res_gpr_volume, "GPR mixer controls use 31-bit range.");
+
 /*
  *  Tables
  */ 
@@ -296,6 +301,7 @@ static const u32 db_table[101] = {
 
 /* EMU10k1/EMU10k2 DSP control db gain */
 static const DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1);
+static const DECLARE_TLV_DB_LINEAR(snd_emu10k1_db_linear, TLV_DB_GAIN_MUTE, 0);
 
 static const u32 onoff_table[2] = {
        0x00000000, 0x00000001
@@ -1072,10 +1078,17 @@ snd_emu10k1_init_mono_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
        strcpy(ctl->id.name, name);
        ctl->vcount = ctl->count = 1;
        ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
-       ctl->min = 0;
-       ctl->max = 100;
-       ctl->tlv = snd_emu10k1_db_scale1;
-       ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;    
+       if (high_res_gpr_volume) {
+               ctl->min = 0;
+               ctl->max = 0x7fffffff;
+               ctl->tlv = snd_emu10k1_db_linear;
+               ctl->translation = EMU10K1_GPR_TRANSLATION_NONE;
+       } else {
+               ctl->min = 0;
+               ctl->max = 100;
+               ctl->tlv = snd_emu10k1_db_scale1;
+               ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
+       }
 }
 
 static void __devinit
@@ -1087,10 +1100,17 @@ snd_emu10k1_init_stereo_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
        ctl->vcount = ctl->count = 2;
        ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
        ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
-       ctl->min = 0;
-       ctl->max = 100;
-       ctl->tlv = snd_emu10k1_db_scale1;
-       ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
+       if (high_res_gpr_volume) {
+               ctl->min = 0;
+               ctl->max = 0x7fffffff;
+               ctl->tlv = snd_emu10k1_db_linear;
+               ctl->translation = EMU10K1_GPR_TRANSLATION_NONE;
+       } else {
+               ctl->min = 0;
+               ctl->max = 100;
+               ctl->tlv = snd_emu10k1_db_scale1;
+               ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
+       }
 }
 
 static void __devinit
index 170610e1d7da4d8a2a89bf46ae01085743dee840..dc79564fea30d2e17fef0b9abfc51b0ec636c73f 100644 (file)
@@ -1097,6 +1097,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
        struct azx *chip = dev_id;
        struct azx_dev *azx_dev;
        u32 status;
+       u8 sd_status;
        int i, ok;
 
        spin_lock(&chip->reg_lock);
@@ -1110,8 +1111,10 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
        for (i = 0; i < chip->num_streams; i++) {
                azx_dev = &chip->azx_dev[i];
                if (status & azx_dev->sd_int_sta_mask) {
+                       sd_status = azx_sd_readb(azx_dev, SD_STS);
                        azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);
-                       if (!azx_dev->substream || !azx_dev->running)
+                       if (!azx_dev->substream || !azx_dev->running ||
+                           !(sd_status & SD_INT_COMPLETE))
                                continue;
                        /* check whether this IRQ is really acceptable */
                        ok = azx_position_ok(chip, azx_dev);
@@ -2279,12 +2282,16 @@ static int azx_dev_free(struct snd_device *device)
  * white/black-listing for position_fix
  */
 static struct snd_pci_quirk position_fix_list[] __devinitdata = {
+       SND_PCI_QUIRK(0x1025, 0x009f, "Acer Aspire 5110", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1028, 0x01f6, "Dell Latitude 131L", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB),
-       SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", 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),
+       SND_PCI_QUIRK(0x1297, 0x3166, "Shuttle", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1458, 0xa022, "ga-ma770-ud3", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1565, 0x820f, "Biostar Microtech", POS_FIX_LPIB),
index e863649d31f5416702f1fa7077679ad80053561a..2bf2cb5da956af2f2555dc75f96923ccd1dc51be 100644 (file)
@@ -2975,6 +2975,8 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5),
        SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5),
        SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD),
+       SND_PCI_QUIRK(0x17aa, 0x21b3, "Thinkpad Edge 13 (197)", CXT5066_IDEAPAD),
+       SND_PCI_QUIRK(0x17aa, 0x21b4, "Thinkpad Edge", CXT5066_IDEAPAD),
        SND_PCI_QUIRK(0x17aa, 0x3a0d, "ideapad", CXT5066_IDEAPAD),
        SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD),
        {}
index 53538b0f999129ad66937f617a168679e3598aaf..17d4548cc353f72402693b0b39461226467a00d9 100644 (file)
@@ -7025,6 +7025,14 @@ static struct hda_input_mux alc889A_mb31_capture_source = {
        },
 };
 
+static struct hda_input_mux alc889A_imac91_capture_source = {
+       .num_items = 2,
+       .items = {
+               { "Mic", 0x01 },
+               { "Line", 0x2 }, /* Not sure! */
+       },
+};
+
 /*
  * 2ch mode
  */
@@ -7486,15 +7494,8 @@ static struct snd_kcontrol_new alc885_macmini3_mixer[] = {
 };
 
 static struct snd_kcontrol_new alc885_imac91_mixer[] = {
-       HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
-       HDA_BIND_MUTE   ("Line-Out Playback Switch", 0x0c, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE  ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE  ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
-       HDA_CODEC_MUTE  ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
        { } /* end */
 };
 
@@ -7995,61 +7996,56 @@ static struct hda_verb alc885_mbp3_init_verbs[] = {
 
 /* iMac 9,1 */
 static struct hda_verb alc885_imac91_init_verbs[] = {
-       /* Line-Out mixer: unmute input/output amp left and right (volume = 0) */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* Rear mixer */
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* HP Pin: output 0 (0x0c) */
+       /* Internal Speaker Pin (0x0c) */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* HP Pin: Rear */
        {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
        {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
        {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       /* Internal Speakers: output 0 (0x0d) */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
+       /* Line in Rear */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
        {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* Mic (rear) pin: input vref at 80% */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
        /* Front Mic pin: input vref at 80% */
        {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
        {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Line In pin: use output 1 when in LineOut mode */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
-
-       /* FIXME: use matrix-type input source selection */
-       /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
-       /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+       /* Rear mixer */
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* Line-Out mixer: unmute input/output amp left and right (volume = 0) */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* 0x24 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
        {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
        {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
        {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       /* Input mixer2 */
+       /* 0x23 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
        {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
        {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
        {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       /* Input mixer3 */
+       /* 0x22 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
        {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
        {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
        {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       /* ADC1: mute amp left and right */
+       /* 0x07 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
        {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
        {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* ADC2: mute amp left and right */
+       /* 0x08 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
        {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
        {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* ADC3: mute amp left and right */
+       /* 0x09 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
        {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
        {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
-
        { }
 };
 
@@ -8118,7 +8114,7 @@ static void alc885_imac91_setup(struct hda_codec *codec)
        struct alc_spec *spec = codec->spec;
 
        spec->autocfg.hp_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x18;
        spec->autocfg.speaker_pins[1] = 0x1a;
 }
 
@@ -9627,14 +9623,14 @@ static struct alc_config_preset alc882_presets[] = {
                .init_hook = alc885_imac24_init_hook,
        },
        [ALC885_IMAC91] = {
-               .mixers = { alc885_imac91_mixer, alc882_chmode_mixer },
+               .mixers = {alc885_imac91_mixer},
                .init_verbs = { alc885_imac91_init_verbs,
                                alc880_gpio1_init_verbs },
                .num_dacs = ARRAY_SIZE(alc882_dac_nids),
                .dac_nids = alc882_dac_nids,
-               .channel_mode = alc885_mbp_4ch_modes,
-               .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes),
-               .input_mux = &alc882_capture_source,
+               .channel_mode = alc885_mba21_ch_modes,
+               .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
+               .input_mux = &alc889A_imac91_capture_source,
                .dig_out_nid = ALC882_DIGOUT_NID,
                .dig_in_nid = ALC882_DIGIN_NID,
                .unsol_event = alc_automute_amp_unsol_event,
index a0e06d82da1f8c27d50d8a2b1fd5d75927db4ca9..f1e7babd6920048b5238b21e5a31ee936ab4b3a0 100644 (file)
@@ -2078,12 +2078,12 @@ static struct snd_pci_quirk stac927x_cfg_tbl[] = {
        SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2000,
                           "Intel D965", STAC_D965_3ST),
        /* Dell 3 stack systems */
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01ed, "Dell     ", STAC_DELL_3ST),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01f4, "Dell     ", STAC_DELL_3ST),
        /* Dell 3 stack systems with verb table in BIOS */
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01f7, "Dell XPS M1730", STAC_DELL_BIOS),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x0227, "Dell Vostro 1400  ", STAC_DELL_BIOS),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x022e, "Dell     ", STAC_DELL_BIOS),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x022f, "Dell Inspiron 1525", STAC_DELL_BIOS),
index 8ae20208e7befd5cffb291b118080809dd357e4b..0221ca79b3ae59831a15499e263b7ca9cbf1118b 100644 (file)
@@ -426,8 +426,8 @@ static const struct soc_enum wm8350_enum[] = {
        SOC_ENUM_SINGLE(WM8350_INPUT_MIXER_VOLUME, 15, 2, wm8350_lr),
 };
 
-static DECLARE_TLV_DB_LINEAR(pre_amp_tlv, -1200, 3525);
-static DECLARE_TLV_DB_LINEAR(out_pga_tlv, -5700, 600);
+static DECLARE_TLV_DB_SCALE(pre_amp_tlv, -1200, 3525, 0);
+static DECLARE_TLV_DB_SCALE(out_pga_tlv, -5700, 600, 0);
 static DECLARE_TLV_DB_SCALE(dac_pcm_tlv, -7163, 36, 1);
 static DECLARE_TLV_DB_SCALE(adc_pcm_tlv, -12700, 50, 1);
 static DECLARE_TLV_DB_SCALE(out_mix_tlv, -1500, 300, 1);
index 7f5d080536a07379613249fb6c2a25fd1cde27d5..8f294066b0ed3e4edfc382b992e943a6157e1af2 100644 (file)
@@ -107,21 +107,21 @@ static void wm8400_codec_reset(struct snd_soc_codec *codec)
        wm8400_reset_codec_reg_cache(wm8400->wm8400);
 }
 
-static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600);
+static const DECLARE_TLV_DB_SCALE(rec_mix_tlv, -1500, 600, 0);
 
-static const DECLARE_TLV_DB_LINEAR(in_pga_tlv, -1650, 3000);
+static const DECLARE_TLV_DB_SCALE(in_pga_tlv, -1650, 3000, 0);
 
-static const DECLARE_TLV_DB_LINEAR(out_mix_tlv, -2100, 0);
+static const DECLARE_TLV_DB_SCALE(out_mix_tlv, -2100, 0, 0);
 
-static const DECLARE_TLV_DB_LINEAR(out_pga_tlv, -7300, 600);
+static const DECLARE_TLV_DB_SCALE(out_pga_tlv, -7300, 600, 0);
 
-static const DECLARE_TLV_DB_LINEAR(out_omix_tlv, -600, 0);
+static const DECLARE_TLV_DB_SCALE(out_omix_tlv, -600, 0, 0);
 
-static const DECLARE_TLV_DB_LINEAR(out_dac_tlv, -7163, 0);
+static const DECLARE_TLV_DB_SCALE(out_dac_tlv, -7163, 0, 0);
 
-static const DECLARE_TLV_DB_LINEAR(in_adc_tlv, -7163, 1763);
+static const DECLARE_TLV_DB_SCALE(in_adc_tlv, -7163, 1763, 0);
 
-static const DECLARE_TLV_DB_LINEAR(out_sidetone_tlv, -3600, 0);
+static const DECLARE_TLV_DB_SCALE(out_sidetone_tlv, -3600, 0, 0);
 
 static int wm8400_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
         struct snd_ctl_elem_value *ucontrol)
@@ -440,7 +440,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
 /* INMIX dB values */
 static const unsigned int in_mix_tlv[] = {
        TLV_DB_RANGE_HEAD(1),
-       0,7, TLV_DB_LINEAR_ITEM(-1200, 600),
+       0,7, TLV_DB_SCALE_ITEM(-1200, 600, 0),
 };
 
 /* Left In PGA Connections */
index 7b536d923ea9ef970d55fc54db319e18bf613148..c018772cc430ff3baac5767bb12e71efd63670fb 100644 (file)
@@ -111,21 +111,21 @@ static const u16 wm8990_reg[] = {
 
 #define wm8990_reset(c) snd_soc_write(c, WM8990_RESET, 0)
 
-static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600);
+static const DECLARE_TLV_DB_SCALE(rec_mix_tlv, -1500, 600, 0);
 
-static const DECLARE_TLV_DB_LINEAR(in_pga_tlv, -1650, 3000);
+static const DECLARE_TLV_DB_SCALE(in_pga_tlv, -1650, 3000, 0);
 
-static const DECLARE_TLV_DB_LINEAR(out_mix_tlv, 0, -2100);
+static const DECLARE_TLV_DB_SCALE(out_mix_tlv, 0, -2100, 0);
 
-static const DECLARE_TLV_DB_LINEAR(out_pga_tlv, -7300, 600);
+static const DECLARE_TLV_DB_SCALE(out_pga_tlv, -7300, 600, 0);
 
-static const DECLARE_TLV_DB_LINEAR(out_omix_tlv, -600, 0);
+static const DECLARE_TLV_DB_SCALE(out_omix_tlv, -600, 0, 0);
 
-static const DECLARE_TLV_DB_LINEAR(out_dac_tlv, -7163, 0);
+static const DECLARE_TLV_DB_SCALE(out_dac_tlv, -7163, 0, 0);
 
-static const DECLARE_TLV_DB_LINEAR(in_adc_tlv, -7163, 1763);
+static const DECLARE_TLV_DB_SCALE(in_adc_tlv, -7163, 1763, 0);
 
-static const DECLARE_TLV_DB_LINEAR(out_sidetone_tlv, -3600, 0);
+static const DECLARE_TLV_DB_SCALE(out_sidetone_tlv, -3600, 0, 0);
 
 static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
@@ -451,7 +451,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
 /* INMIX dB values */
 static const unsigned int in_mix_tlv[] = {
        TLV_DB_RANGE_HEAD(1),
-       0, 7, TLV_DB_LINEAR_ITEM(-1200, 600),
+       0, 7, TLV_DB_SCALE_ITEM(-1200, 600, 0),
 };
 
 /* Left In PGA Connections */
index d639e55c51241dad15eb984815c69f9461a26797..1d4e7164e80af1c4dfd98c057e42b88f52e448f1 100644 (file)
@@ -380,8 +380,8 @@ int mpc5200_audio_dma_create(struct of_device *op)
        int ret;
 
        /* Fetch the registers and IRQ of the PSC */
-       irq = irq_of_parse_and_map(op->node, 0);
-       if (of_address_to_resource(op->node, 0, &res)) {
+       irq = irq_of_parse_and_map(op->dev.of_node, 0);
+       if (of_address_to_resource(op->dev.of_node, 0, &res)) {
                dev_err(&op->dev, "Missing reg property\n");
                return -ENODEV;
        }
@@ -399,7 +399,7 @@ int mpc5200_audio_dma_create(struct of_device *op)
        }
 
        /* Get the PSC ID */
-       prop = of_get_property(op->node, "cell-index", &size);
+       prop = of_get_property(op->dev.of_node, "cell-index", &size);
        if (!prop || size < sizeof *prop) {
                ret = -ENODEV;
                goto out_free;
index 3dbc7f7cd7b9a01a9b89cc3512a46159cc804133..e2ee220bfb7ea86dcd322da92a5025c0ce026f7e 100644 (file)
@@ -317,12 +317,12 @@ static struct of_device_id psc_ac97_match[] __devinitdata = {
 MODULE_DEVICE_TABLE(of, psc_ac97_match);
 
 static struct of_platform_driver psc_ac97_driver = {
-       .match_table = psc_ac97_match,
        .probe = psc_ac97_of_probe,
        .remove = __devexit_p(psc_ac97_of_remove),
        .driver = {
                .name = "mpc5200-psc-ac97",
                .owner = THIS_MODULE,
+               .of_match_table = psc_ac97_match,
        },
 };
 
index ce8de90fb94ae54d5ce7adbd05735f5395a4d7f7..4f455bd6851ffd87102e6003dfd868b12f5b13f8 100644 (file)
@@ -181,7 +181,7 @@ static int __devinit psc_i2s_of_probe(struct of_device *op,
 
        /* Check for the codec handle.  If it is not present then we
         * are done */
-       if (!of_get_property(op->node, "codec-handle", NULL))
+       if (!of_get_property(op->dev.of_node, "codec-handle", NULL))
                return 0;
 
        /* Due to errata in the dma mode; need to line up enabling
@@ -220,12 +220,12 @@ static struct of_device_id psc_i2s_match[] __devinitdata = {
 MODULE_DEVICE_TABLE(of, psc_i2s_match);
 
 static struct of_platform_driver psc_i2s_driver = {
-       .match_table = psc_i2s_match,
        .probe = psc_i2s_of_probe,
        .remove = __devexit_p(psc_i2s_of_remove),
        .driver = {
                .name = "mpc5200-psc-i2s",
                .owner = THIS_MODULE,
+               .of_match_table = psc_i2s_match,
        },
 };
 
index 83de1c81c8c410e580ae9b2b286cf8a99faca4b0..6a2764ee8203980b25b07227f3aba9978c72e286 100644 (file)
@@ -203,7 +203,7 @@ static struct snd_soc_ops mpc8610_hpcd_ops = {
 static int mpc8610_hpcd_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 device_node *codec_np = NULL;
        struct device_node *guts_np = NULL;
        struct device_node *dma_np = NULL;
@@ -580,9 +580,11 @@ static struct of_device_id mpc8610_hpcd_match[] = {
 MODULE_DEVICE_TABLE(of, mpc8610_hpcd_match);
 
 static struct of_platform_driver mpc8610_hpcd_of_driver = {
-       .owner          = THIS_MODULE,
-       .name           = "mpc8610_hpcd",
-       .match_table    = mpc8610_hpcd_match,
+       .driver = {
+               .name = "mpc8610_hpcd",
+               .owner = THIS_MODULE,
+               .of_match_table = mpc8610_hpcd_match,
+       },
        .probe          = mpc8610_hpcd_probe,
        .remove         = mpc8610_hpcd_remove,
 };
index 2b31ac673ea4d95a05b986d7f6b5059d4e5cd615..05f19c9284f4cad5fe11b851a24602e9884b9eca 100644 (file)
@@ -73,7 +73,8 @@ static void snd_imx_dma_err_callback(int channel, void *data, int err)
 {
        struct snd_pcm_substream *substream = data;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct imx_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data;
+       struct imx_pcm_dma_params *dma_params = 
+               snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct imx_pcm_runtime_data *iprtd = runtime->private_data;
        int ret;
@@ -102,7 +103,7 @@ static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream)
        struct imx_pcm_runtime_data *iprtd = runtime->private_data;
        int ret;
 
-       dma_params = snd_soc_get_dma_data(rtd->dai->cpu_dai, substream);
+       dma_params = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
 
        iprtd->dma = imx_dma_request_by_prio(DRV_NAME, DMA_PRIO_HIGH);
        if (iprtd->dma < 0) {
@@ -212,7 +213,7 @@ static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream)
        struct imx_pcm_runtime_data *iprtd = runtime->private_data;
        int err;
 
-       dma_params = snd_soc_get_dma_data(rtd->dai->cpu_dai, substream);
+       dma_params = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
 
        iprtd->substream = substream;
        iprtd->buf = (unsigned int *)substream->dma_buffer.area;
index c0bfab8fed3d8258730b9577345f8c979740dec2..492b1cae24ccb3dcd3b36681866aca923e78752b 100644 (file)
@@ -71,8 +71,7 @@ struct siu_firmware {
 #include <linux/dmaengine.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
-
-#include <asm/dmaengine.h>
+#include <linux/sh_dma.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
index d86ee1bfc03ae2bc4fbc5843f359c7901591d7bf..eeed5edd722b2df38e4449f8b8e78d815c4fbcfd 100644 (file)
@@ -588,6 +588,8 @@ static int siu_dai_prepare(struct snd_pcm_substream *substream,
                ret = siu_dai_spbstart(port_info);
                if (ret < 0)
                        goto fail;
+       } else {
+               ret = 0;
        }
 
        port_info->play_cap |= self;
index 8f85719212f96283351a9381a2419afc8adf2d96..36170be15aa7453cfacf00505d18d162b369ca32 100644 (file)
@@ -31,7 +31,6 @@
 #include <sound/pcm_params.h>
 #include <sound/soc-dai.h>
 
-#include <asm/dmaengine.h>
 #include <asm/siu.h>
 
 #include "siu.h"
@@ -358,13 +357,13 @@ static int siu_pcm_open(struct snd_pcm_substream *ss)
        if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                siu_stream = &port_info->playback;
                param = &siu_stream->param;
-               param->slave_id = port ? SHDMA_SLAVE_SIUB_TX :
-                       SHDMA_SLAVE_SIUA_TX;
+               param->slave_id = port ? pdata->dma_slave_tx_b :
+                       pdata->dma_slave_tx_a;
        } else {
                siu_stream = &port_info->capture;
                param = &siu_stream->param;
-               param->slave_id = port ? SHDMA_SLAVE_SIUB_RX :
-                       SHDMA_SLAVE_SIUA_RX;
+               param->slave_id = port ? pdata->dma_slave_rx_b :
+                       pdata->dma_slave_rx_a;
        }
 
        param->dma_dev = pdata->dma_dev;
index 574af56ba8a6fa6d4b690f4b2079ea459281712c..71221fd209445b55a09093986a7a330546277381 100644 (file)
@@ -1065,8 +1065,11 @@ static const struct of_device_id amd7930_match[] = {
 };
 
 static struct of_platform_driver amd7930_sbus_driver = {
-       .name           = "audio",
-       .match_table    = amd7930_match,
+       .driver = {
+               .name = "audio",
+               .owner = THIS_MODULE,
+               .of_match_table = amd7930_match,
+       },
        .probe          = amd7930_sbus_probe,
 };
 
index 7dcc06512e8684c60c738f6eb7fe9eeeff499070..fb4c6f2f29e5d1b97a69ec2ccd00d6ff7b750ff4 100644 (file)
@@ -2075,12 +2075,12 @@ static int __devinit cs4231_ebus_probe(struct of_device *op, const struct of_dev
 static int __devinit cs4231_probe(struct of_device *op, const struct of_device_id *match)
 {
 #ifdef EBUS_SUPPORT
-       if (!strcmp(op->node->parent->name, "ebus"))
+       if (!strcmp(op->dev.of_node->parent->name, "ebus"))
                return cs4231_ebus_probe(op, match);
 #endif
 #ifdef SBUS_SUPPORT
-       if (!strcmp(op->node->parent->name, "sbus") ||
-           !strcmp(op->node->parent->name, "sbi"))
+       if (!strcmp(op->dev.of_node->parent->name, "sbus") ||
+           !strcmp(op->dev.of_node->parent->name, "sbi"))
                return cs4231_sbus_probe(op, match);
 #endif
        return -ENODEV;
@@ -2109,8 +2109,11 @@ static const struct of_device_id cs4231_match[] = {
 MODULE_DEVICE_TABLE(of, cs4231_match);
 
 static struct of_platform_driver cs4231_driver = {
-       .name           = "audio",
-       .match_table    = cs4231_match,
+       .driver = {
+               .name = "audio",
+               .owner = THIS_MODULE,
+               .of_match_table = cs4231_match,
+       },
        .probe          = cs4231_probe,
        .remove         = __devexit_p(cs4231_remove),
 };
index 2eab6ce48852233dbf58a44b227e7e522d8bd352..1557bf132e732fe172a383f3f64cec7ca4bb27f4 100644 (file)
@@ -2651,7 +2651,7 @@ static int __devinit dbri_probe(struct of_device *op, const struct of_device_id
 
        printk(KERN_INFO "audio%d at %p (irq %d) is DBRI(%c)+CS4215(%d)\n",
               dev, dbri->regs,
-              dbri->irq, op->node->name[9], dbri->mm.version);
+              dbri->irq, op->dev.of_node->name[9], dbri->mm.version);
        dev++;
 
        return 0;
@@ -2687,8 +2687,11 @@ static const struct of_device_id dbri_match[] = {
 MODULE_DEVICE_TABLE(of, dbri_match);
 
 static struct of_platform_driver dbri_sbus_driver = {
-       .name           = "dbri",
-       .match_table    = dbri_match,
+       .driver = {
+               .name = "dbri",
+               .owner = THIS_MODULE,
+               .of_match_table = dbri_match,
+       },
        .probe          = dbri_probe,
        .remove         = __devexit_p(dbri_remove),
 };
index 36ed703a7416fd68824091a2cd29a507b98babb2..91c804cd278278c639f428ab59d963d6d6804105 100644 (file)
@@ -42,21 +42,12 @@ static int control_info(struct snd_kcontrol *kcontrol,
 
        switch (dev->chip.usb_id) {
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ):
-               if (pos == 0) {
-                       /* current input mode of A8DJ */
-                       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-                       uinfo->value.integer.min = 0;
-                       uinfo->value.integer.max = 2;
-                       return 0;
-               }
-               break;
-
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):
                if (pos == 0) {
-                       /* current input mode of A4DJ */
+                       /* current input mode of A8DJ and A4DJ */
                        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
                        uinfo->value.integer.min = 0;
-                       uinfo->value.integer.max = 1;
+                       uinfo->value.integer.max = 2;
                        return 0;
                }
                break;
@@ -86,14 +77,6 @@ static int control_get(struct snd_kcontrol *kcontrol,
        struct snd_usb_caiaqdev *dev = caiaqdev(chip->card);
        int pos = kcontrol->private_value;
 
-       if (dev->chip.usb_id ==
-               USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ)) {
-               /* A4DJ has only one control */
-               /* do not expose hardware input mode 0 */
-               ucontrol->value.integer.value[0] = dev->control_state[0] - 1;
-               return 0;
-       }
-
        if (pos & CNT_INTVAL)
                ucontrol->value.integer.value[0]
                        = dev->control_state[pos & ~CNT_INTVAL];
@@ -112,20 +95,9 @@ static int control_put(struct snd_kcontrol *kcontrol,
        int pos = kcontrol->private_value;
        unsigned char cmd = EP1_CMD_WRITE_IO;
 
-       switch (dev->chip.usb_id) {
-       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ): {
-               /* A4DJ has only one control */
-               /* do not expose hardware input mode 0 */
-               dev->control_state[0] = ucontrol->value.integer.value[0] + 1;
-               snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO,
-                               dev->control_state, sizeof(dev->control_state));
-               return 1;
-       }
-
-       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
+       if (dev->chip.usb_id ==
+               USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1))
                cmd = EP1_CMD_DIMM_LEDS;
-               break;
-       }
 
        if (pos & CNT_INTVAL) {
                dev->control_state[pos & ~CNT_INTVAL]
index 805271827675a32c3420b2313008e8c09ed10237..cdfb856bddd261c5717fe6845b5a210fa20a7f75 100644 (file)
@@ -36,7 +36,7 @@
 #include "input.h"
 
 MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
-MODULE_DESCRIPTION("caiaq USB audio, version 1.3.20");
+MODULE_DESCRIPTION("caiaq USB audio, version 1.3.21");
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
                         "{Native Instruments, RigKontrol3},"
@@ -320,12 +320,6 @@ static void __devinit setup_card(struct snd_usb_caiaqdev *dev)
                }
 
                break;
-       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):
-               /* Audio 4 DJ - default input mode to phono */
-               dev->control_state[0] = 2;
-               snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO,
-                       dev->control_state, 1);
-               break;
        }
 
        if (dev->spec.num_analog_audio_out +
index 8bbfbfd4c65805dd3087e96631c07f5385db50b5..dcb620796d9ef5c14ba7f52ab3686b1ae0c1969a 100644 (file)
@@ -171,7 +171,7 @@ static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev,
                input_report_abs(input_dev, ABS_HAT0Y, (buf[4] << 8)  | buf[5]);
                input_report_abs(input_dev, ABS_HAT1X, (buf[12] << 8) | buf[13]);
                input_report_abs(input_dev, ABS_HAT1Y, (buf[2] << 8)  | buf[3]);
-               input_report_abs(input_dev, ABS_HAT2X, (buf[15] << 8) | buf[15]);
+               input_report_abs(input_dev, ABS_HAT2X, (buf[14] << 8) | buf[15]);
                input_report_abs(input_dev, ABS_HAT2Y, (buf[0] << 8)  | buf[1]);
                input_report_abs(input_dev, ABS_HAT3X, (buf[10] << 8) | buf[11]);
                input_report_abs(input_dev, ABS_HAT3Y, (buf[6] << 8)  | buf[7]);
index ef07a6d0dd5ff6bff1b5a3f5de51c19d166acd30..28ee1ce3971a7fd063fdfc0f80a8f73696bb9b4b 100644 (file)
@@ -149,6 +149,47 @@ int snd_usb_add_audio_endpoint(struct snd_usb_audio *chip, int stream, struct au
        return 0;
 }
 
+static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
+                                        struct usb_host_interface *alts,
+                                        int protocol, int iface_no)
+{
+       /* parsed with a v1 header here. that's ok as we only look at the
+        * header first which is the same for both versions */
+       struct uac_iso_endpoint_descriptor *csep;
+       struct usb_interface_descriptor *altsd = get_iface_desc(alts);
+       int attributes = 0;
+
+       csep = snd_usb_find_desc(alts->endpoint[0].extra, alts->endpoint[0].extralen, NULL, USB_DT_CS_ENDPOINT);
+
+       /* Creamware Noah has this descriptor after the 2nd endpoint */
+       if (!csep && altsd->bNumEndpoints >= 2)
+               csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT);
+
+       if (!csep || csep->bLength < 7 ||
+           csep->bDescriptorSubtype != UAC_EP_GENERAL) {
+               snd_printk(KERN_WARNING "%d:%u:%d : no or invalid"
+                          " class specific endpoint descriptor\n",
+                          chip->dev->devnum, iface_no,
+                          altsd->bAlternateSetting);
+               return 0;
+       }
+
+       if (protocol == UAC_VERSION_1) {
+               attributes = csep->bmAttributes;
+       } else {
+               struct uac2_iso_endpoint_descriptor *csep2 =
+                       (struct uac2_iso_endpoint_descriptor *) csep;
+
+               attributes = csep->bmAttributes & UAC_EP_CS_ATTR_FILL_MAX;
+
+               /* emulate the endpoint attributes of a v1 device */
+               if (csep2->bmControls & UAC2_CONTROL_PITCH)
+                       attributes |= UAC_EP_CS_ATTR_PITCH_CONTROL;
+       }
+
+       return attributes;
+}
+
 int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
 {
        struct usb_device *dev;
@@ -158,8 +199,8 @@ 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;
-       unsigned char *fmt, *csep;
        int num, protocol;
+       struct uac_format_type_i_continuous_descriptor *fmt;
 
        dev = chip->dev;
 
@@ -256,8 +297,8 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
                                   dev->devnum, iface_no, altno);
                        continue;
                }
-               if (((protocol == UAC_VERSION_1) && (fmt[0] < 8)) ||
-                   ((protocol == UAC_VERSION_2) && (fmt[0] != 6))) {
+               if (((protocol == UAC_VERSION_1) && (fmt->bLength < 8)) ||
+                   ((protocol == UAC_VERSION_2) && (fmt->bLength != 6))) {
                        snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_FORMAT_TYPE desc\n",
                                   dev->devnum, iface_no, altno);
                        continue;
@@ -268,7 +309,9 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
                 * with the previous one, except for a larger packet size, but
                 * is actually a mislabeled two-channel setting; ignore it.
                 */
-               if (fmt[4] == 1 && fmt[5] == 2 && altno == 2 && num == 3 &&
+               if (fmt->bNrChannels == 1 &&
+                   fmt->bSubframeSize == 2 &&
+                   altno == 2 && num == 3 &&
                    fp && fp->altsetting == 1 && fp->channels == 1 &&
                    fp->formats == SNDRV_PCM_FMTBIT_S16_LE &&
                    protocol == UAC_VERSION_1 &&
@@ -276,17 +319,6 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
                                                        fp->maxpacksize * 2)
                        continue;
 
-               csep = snd_usb_find_desc(alts->endpoint[0].extra, alts->endpoint[0].extralen, NULL, USB_DT_CS_ENDPOINT);
-               /* Creamware Noah has this descriptor after the 2nd endpoint */
-               if (!csep && altsd->bNumEndpoints >= 2)
-                       csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT);
-               if (!csep || csep[0] < 7 || csep[2] != UAC_EP_GENERAL) {
-                       snd_printk(KERN_WARNING "%d:%u:%d : no or invalid"
-                                  " class specific endpoint descriptor\n",
-                                  dev->devnum, iface_no, altno);
-                       csep = NULL;
-               }
-
                fp = kzalloc(sizeof(*fp), GFP_KERNEL);
                if (! fp) {
                        snd_printk(KERN_ERR "cannot malloc\n");
@@ -305,7 +337,7 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
                if (snd_usb_get_speed(dev) == USB_SPEED_HIGH)
                        fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1)
                                        * (fp->maxpacksize & 0x7ff);
-               fp->attributes = csep ? csep[3] : 0;
+               fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no);
 
                /* some quirks for attributes here */
 
index b87cf87c4e7bdedd2a924d1d1c8588df76c255e7..fe29d61de19bc80bdc0dbdc2fe209fd3fd71b21e 100644 (file)
@@ -278,12 +278,11 @@ err:
  * parse the format type I and III descriptors
  */
 static int parse_audio_format_i(struct snd_usb_audio *chip,
-                               struct audioformat *fp,
-                               int format, void *_fmt,
+                               struct audioformat *fp, int format,
+                               struct uac_format_type_i_continuous_descriptor *fmt,
                                struct usb_host_interface *iface)
 {
        struct usb_interface_descriptor *altsd = get_iface_desc(iface);
-       struct uac_format_type_i_discrete_descriptor *fmt = _fmt;
        int protocol = altsd->bInterfaceProtocol;
        int pcm_format, ret;
 
@@ -320,7 +319,7 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
        switch (protocol) {
        case UAC_VERSION_1:
                fp->channels = fmt->bNrChannels;
-               ret = parse_audio_format_rates_v1(chip, fp, _fmt, 7);
+               ret = parse_audio_format_rates_v1(chip, fp, (unsigned char *) fmt, 7);
                break;
        case UAC_VERSION_2:
                /* fp->channels is already set in this case */
@@ -392,12 +391,12 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,
 }
 
 int snd_usb_parse_audio_format(struct snd_usb_audio *chip, struct audioformat *fp,
-                      int format, unsigned char *fmt, int stream,
-                      struct usb_host_interface *iface)
+                              int format, struct uac_format_type_i_continuous_descriptor *fmt,
+                              int stream, struct usb_host_interface *iface)
 {
        int err;
 
-       switch (fmt[3]) {
+       switch (fmt->bFormatType) {
        case UAC_FORMAT_TYPE_I:
        case UAC_FORMAT_TYPE_III:
                err = parse_audio_format_i(chip, fp, format, fmt, iface);
@@ -407,10 +406,11 @@ int snd_usb_parse_audio_format(struct snd_usb_audio *chip, struct audioformat *f
                break;
        default:
                snd_printd(KERN_INFO "%d:%u:%d : format type %d is not supported yet\n",
-                          chip->dev->devnum, fp->iface, fp->altsetting, fmt[3]);
-               return -1;
+                          chip->dev->devnum, fp->iface, fp->altsetting,
+                          fmt->bFormatType);
+               return -ENOTSUPP;
        }
-       fp->fmt_type = fmt[3];
+       fp->fmt_type = fmt->bFormatType;
        if (err < 0)
                return err;
 #if 1
@@ -421,10 +421,10 @@ int snd_usb_parse_audio_format(struct snd_usb_audio *chip, struct audioformat *f
        if (chip->usb_id == USB_ID(0x041e, 0x3000) ||
            chip->usb_id == USB_ID(0x041e, 0x3020) ||
            chip->usb_id == USB_ID(0x041e, 0x3061)) {
-               if (fmt[3] == UAC_FORMAT_TYPE_I &&
+               if (fmt->bFormatType == UAC_FORMAT_TYPE_I &&
                    fp->rates != SNDRV_PCM_RATE_48000 &&
                    fp->rates != SNDRV_PCM_RATE_96000)
-                       return -1;
+                       return -ENOTSUPP;
        }
 #endif
        return 0;
index 8298c4e8ddfaf2a6750f49a6129457d9f5f7bd5a..387924f0af85de9b419440b2c043b8b9faa1a8de 100644 (file)
@@ -1,8 +1,9 @@
 #ifndef __USBAUDIO_FORMAT_H
 #define __USBAUDIO_FORMAT_H
 
-int snd_usb_parse_audio_format(struct snd_usb_audio *chip, struct audioformat *fp,
-                              int format, unsigned char *fmt, int stream,
-                              struct usb_host_interface *iface);
+int snd_usb_parse_audio_format(struct snd_usb_audio *chip,
+                              struct audioformat *fp, int format,
+                              struct uac_format_type_i_continuous_descriptor *fmt,
+                              int stream, struct usb_host_interface *iface);
 
 #endif /*  __USBAUDIO_FORMAT_H */
index 8b1e4b124a9f65281fa3bf488c5f17f7c5c34a35..46785643c66dfa507bd41bb8f1368bdba75afd93 100644 (file)
@@ -644,6 +644,105 @@ static struct usb_protocol_ops snd_usbmidi_cme_ops = {
        .output_packet = snd_usbmidi_output_standard_packet,
 };
 
+/*
+ * AKAI MPD16 protocol:
+ *
+ * For control port (endpoint 1):
+ * ==============================
+ * One or more chunks consisting of first byte of (0x10 | msg_len) and then a
+ * SysEx message (msg_len=9 bytes long).
+ *
+ * For data port (endpoint 2):
+ * ===========================
+ * One or more chunks consisting of first byte of (0x20 | msg_len) and then a
+ * MIDI message (msg_len bytes long)
+ *
+ * Messages sent: Active Sense, Note On, Poly Pressure, Control Change.
+ */
+static void snd_usbmidi_akai_input(struct snd_usb_midi_in_endpoint *ep,
+                                  uint8_t *buffer, int buffer_length)
+{
+       unsigned int pos = 0;
+       unsigned int len = (unsigned int)buffer_length;
+       while (pos < len) {
+               unsigned int port = (buffer[pos] >> 4) - 1;
+               unsigned int msg_len = buffer[pos] & 0x0f;
+               pos++;
+               if (pos + msg_len <= len && port < 2)
+                       snd_usbmidi_input_data(ep, 0, &buffer[pos], msg_len);
+               pos += msg_len;
+       }
+}
+
+#define MAX_AKAI_SYSEX_LEN 9
+
+static void snd_usbmidi_akai_output(struct snd_usb_midi_out_endpoint *ep,
+                                   struct urb *urb)
+{
+       uint8_t *msg;
+       int pos, end, count, buf_end;
+       uint8_t tmp[MAX_AKAI_SYSEX_LEN];
+       struct snd_rawmidi_substream *substream = ep->ports[0].substream;
+
+       if (!ep->ports[0].active)
+               return;
+
+       msg = urb->transfer_buffer + urb->transfer_buffer_length;
+       buf_end = ep->max_transfer - MAX_AKAI_SYSEX_LEN - 1;
+
+       /* only try adding more data when there's space for at least 1 SysEx */
+       while (urb->transfer_buffer_length < buf_end) {
+               count = snd_rawmidi_transmit_peek(substream,
+                                                 tmp, MAX_AKAI_SYSEX_LEN);
+               if (!count) {
+                       ep->ports[0].active = 0;
+                       return;
+               }
+               /* try to skip non-SysEx data */
+               for (pos = 0; pos < count && tmp[pos] != 0xF0; pos++)
+                       ;
+
+               if (pos > 0) {
+                       snd_rawmidi_transmit_ack(substream, pos);
+                       continue;
+               }
+
+               /* look for the start or end marker */
+               for (end = 1; end < count && tmp[end] < 0xF0; end++)
+                       ;
+
+               /* next SysEx started before the end of current one */
+               if (end < count && tmp[end] == 0xF0) {
+                       /* it's incomplete - drop it */
+                       snd_rawmidi_transmit_ack(substream, end);
+                       continue;
+               }
+               /* SysEx complete */
+               if (end < count && tmp[end] == 0xF7) {
+                       /* queue it, ack it, and get the next one */
+                       count = end + 1;
+                       msg[0] = 0x10 | count;
+                       memcpy(&msg[1], tmp, count);
+                       snd_rawmidi_transmit_ack(substream, count);
+                       urb->transfer_buffer_length += count + 1;
+                       msg += count + 1;
+                       continue;
+               }
+               /* less than 9 bytes and no end byte - wait for more */
+               if (count < MAX_AKAI_SYSEX_LEN) {
+                       ep->ports[0].active = 0;
+                       return;
+               }
+               /* 9 bytes and no end marker in sight - malformed, skip it */
+               snd_rawmidi_transmit_ack(substream, count);
+       }
+}
+
+static struct usb_protocol_ops snd_usbmidi_akai_ops = {
+       .input = snd_usbmidi_akai_input,
+       .output = snd_usbmidi_akai_output,
+};
+
 /*
  * Novation USB MIDI protocol: number of data bytes is in the first byte
  * (when receiving) (+1!) or in the second byte (when sending); data begins
@@ -1434,6 +1533,11 @@ static struct port_info {
        EXTERNAL_PORT(0x086a, 0x0001, 8, "%s Broadcast"),
        EXTERNAL_PORT(0x086a, 0x0002, 8, "%s Broadcast"),
        EXTERNAL_PORT(0x086a, 0x0003, 4, "%s Broadcast"),
+       /* Akai MPD16 */
+       CONTROL_PORT(0x09e8, 0x0062, 0, "%s Control"),
+       PORT_INFO(0x09e8, 0x0062, 1, "%s MIDI", 0,
+               SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |
+               SNDRV_SEQ_PORT_TYPE_HARDWARE),
        /* Access Music Virus TI */
        EXTERNAL_PORT(0x133e, 0x0815, 0, "%s MIDI"),
        PORT_INFO(0x133e, 0x0815, 1, "%s Synth", 0,
@@ -2035,6 +2139,12 @@ int snd_usbmidi_create(struct snd_card *card,
                umidi->usb_protocol_ops = &snd_usbmidi_cme_ops;
                err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
                break;
+       case QUIRK_MIDI_AKAI:
+               umidi->usb_protocol_ops = &snd_usbmidi_akai_ops;
+               err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
+               /* endpoint 1 is input-only */
+               endpoints[1].out_cables = 0;
+               break;
        default:
                snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type);
                err = -ENXIO;
index 2089ec987c66f17fcefac5259ed0c750e5735247..2fca80b744c0a5476d191512e3e909fa744f8d77 100644 (file)
@@ -37,6 +37,8 @@ struct snd_usb_midi_endpoint_info {
 
 /* for QUIRK_MIDI_CME, data is NULL */
 
+/* for QUIRK_MIDI_AKAI, data is NULL */
+
 int snd_usbmidi_create(struct snd_card *card,
                       struct usb_interface *iface,
                       struct list_head *midi_list,
index 97dd17655104a2bfbde0db95b6b6cab1c61d164f..03ce971e002760e84b2d36565ee0cbfa56bebd50 100644 (file)
@@ -1126,7 +1126,7 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void
        } else {
                struct uac2_feature_unit_descriptor *ftr = _ftr;
                csize = 4;
-               channels = (hdr->bLength - 6) / 4;
+               channels = (hdr->bLength - 6) / 4 - 1;
                bmaControls = ftr->bmaControls;
        }
 
index 2bf0d77d1768020a693973e00eab12dbde70ae18..056587de7be41876047296cba15a8ea96bd384a9 100644 (file)
@@ -120,10 +120,6 @@ static int init_pitch_v1(struct snd_usb_audio *chip, int iface,
 
        ep = get_endpoint(alts, 0)->bEndpointAddress;
 
-       /* if endpoint doesn't have pitch control, bail out */
-       if (!(fmt->attributes & UAC_EP_CS_ATTR_PITCH_CONTROL))
-               return 0;
-
        data[0] = 1;
        if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR,
                                   USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
@@ -137,8 +133,32 @@ static int init_pitch_v1(struct snd_usb_audio *chip, int iface,
        return 0;
 }
 
+static int init_pitch_v2(struct snd_usb_audio *chip, int iface,
+                        struct usb_host_interface *alts,
+                        struct audioformat *fmt)
+{
+       struct usb_device *dev = chip->dev;
+       unsigned char data[1];
+       unsigned int ep;
+       int err;
+
+       ep = get_endpoint(alts, 0)->bEndpointAddress;
+
+       data[0] = 1;
+       if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR,
+                                  USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT,
+                                  UAC2_EP_CS_PITCH << 8, 0,
+                                  data, sizeof(data), 1000)) < 0) {
+               snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH (v2)\n",
+                          dev->devnum, iface, fmt->altsetting);
+               return err;
+       }
+
+       return 0;
+}
+
 /*
- * initialize the picth control and sample rate
+ * initialize the pitch control and sample rate
  */
 int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
                       struct usb_host_interface *alts,
@@ -146,13 +166,16 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
 {
        struct usb_interface_descriptor *altsd = get_iface_desc(alts);
 
+       /* if endpoint doesn't have pitch control, bail out */
+       if (!(fmt->attributes & UAC_EP_CS_ATTR_PITCH_CONTROL))
+               return 0;
+
        switch (altsd->bInterfaceProtocol) {
        case UAC_VERSION_1:
                return init_pitch_v1(chip, iface, alts, fmt);
 
        case UAC_VERSION_2:
-               /* not implemented yet */
-               return 0;
+               return init_pitch_v2(chip, iface, alts, fmt);
        }
 
        return -EINVAL;
index 91ddef31bcbddc5fa512134890ee2e36846dfa3f..f8797f61a24b52d8091f2a20b12b243f458b3865 100644 (file)
@@ -1973,6 +1973,17 @@ YAMAHA_DEVICE(0x7010, "UB99"),
        }
 },
 
+/* AKAI devices */
+{
+       USB_DEVICE(0x09e8, 0x0062),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               .vendor_name = "AKAI",
+               .product_name = "MPD16",
+               .ifnum = 0,
+               .type = QUIRK_MIDI_AKAI,
+       }
+},
+
 /* TerraTec devices */
 {
        USB_DEVICE_VENDOR_SPEC(0x0ccd, 0x0012),
index 136e5b4cf6de4fda961a9f1d61c8543d1069bd76..b45e54c09ba2d91dd4c14432f4f8b246ca6fedbf 100644 (file)
@@ -289,6 +289,7 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip,
                [QUIRK_MIDI_FASTLANE] = create_any_midi_quirk,
                [QUIRK_MIDI_EMAGIC] = create_any_midi_quirk,
                [QUIRK_MIDI_CME] = create_any_midi_quirk,
+               [QUIRK_MIDI_AKAI] = create_any_midi_quirk,
                [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk,
                [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk,
                [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk,
index d679e72a3e5c921184fbea1d0cbffc94393b176b..06ebf24d3a4d504e61840f5abca7a30a87b5d5e1 100644 (file)
@@ -74,6 +74,7 @@ enum quirk_type {
        QUIRK_MIDI_FASTLANE,
        QUIRK_MIDI_EMAGIC,
        QUIRK_MIDI_CME,
+       QUIRK_MIDI_AKAI,
        QUIRK_MIDI_US122L,
        QUIRK_AUDIO_STANDARD_INTERFACE,
        QUIRK_AUDIO_FIXED_ENDPOINT,
index 2cab8e8c33d00df44dd9b215257a856751fefea9..909fa766fa1cfa014041e41ddb76d29555c2469c 100644 (file)
@@ -43,6 +43,9 @@ OPTIONS
 -c::
         scale counter values
 
+-B::
+        print large numbers with thousands' separators according to locale
+
 EXAMPLES
 --------
 
index 77bcc9b130f5b3d6120f8c458b70f3c384ff2672..08278eda31a548cb80cbf512b8f7250e1b7dfe37 100644 (file)
@@ -277,7 +277,7 @@ static void hist_entry__print_hits(struct hist_entry *self)
        printf("%*s: %Lu\n", BITS_PER_LONG / 2, "h->sum", h->sum);
 }
 
-static void annotate_sym(struct hist_entry *he)
+static int hist_entry__tty_annotate(struct hist_entry *he)
 {
        struct map *map = he->ms.map;
        struct dso *dso = map->dso;
@@ -288,7 +288,7 @@ static void annotate_sym(struct hist_entry *he)
        struct objdump_line *pos, *n;
 
        if (hist_entry__annotate(he, &head) < 0)
-               return;
+               return -1;
 
        if (full_paths)
                d_filename = filename;
@@ -317,30 +317,59 @@ static void annotate_sym(struct hist_entry *he)
 
        if (print_line)
                free_source_line(he, len);
+
+       return 0;
 }
 
 static void hists__find_annotations(struct hists *self)
 {
-       struct rb_node *nd;
+       struct rb_node *first = rb_first(&self->entries), *nd = first;
+       int key = KEY_RIGHT;
 
-       for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
+       while (nd) {
                struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
                struct sym_priv *priv;
 
-               if (he->ms.sym == NULL)
-                       continue;
+               if (he->ms.sym == NULL || he->ms.map->dso->annotate_warned)
+                       goto find_next;
 
                priv = symbol__priv(he->ms.sym);
-               if (priv->hist == NULL)
+               if (priv->hist == NULL) {
+find_next:
+                       if (key == KEY_LEFT)
+                               nd = rb_prev(nd);
+                       else
+                               nd = rb_next(nd);
                        continue;
+               }
 
-               annotate_sym(he);
-               /*
-                * Since we have a hist_entry per IP for the same symbol, free
-                * he->ms.sym->hist to signal we already processed this symbol.
-                */
-               free(priv->hist);
-               priv->hist = NULL;
+               if (use_browser) {
+                       key = hist_entry__tui_annotate(he);
+                       if (is_exit_key(key))
+                               break;
+                       switch (key) {
+                       case KEY_RIGHT:
+                       case '\t':
+                               nd = rb_next(nd);
+                               break;
+                       case KEY_LEFT:
+                               if (nd == first)
+                                       continue;
+                               nd = rb_prev(nd);
+                       default:
+                               break;
+                       }
+               } else {
+                       hist_entry__tty_annotate(he);
+                       nd = rb_next(nd);
+                       /*
+                        * Since we have a hist_entry per IP for the same
+                        * symbol, free he->ms.sym->hist to signal we already
+                        * processed this symbol.
+                        */
+                       free(priv->hist);
+                       priv->hist = NULL;
+               }
        }
 }
 
@@ -416,6 +445,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
 {
        argc = parse_options(argc, argv, options, annotate_usage, 0);
 
+       setup_browser();
+
        symbol_conf.priv_size = sizeof(struct sym_priv);
        symbol_conf.try_vmlinux_path = true;
 
@@ -435,8 +466,6 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
                sym_hist_filter = argv[0];
        }
 
-       setup_pager();
-
        if (field_sep && *field_sep == '.') {
                pr_err("'.' is the only non valid --field-separator argument\n");
                return -1;
index 61c6d70732c9888dac776a07731e892723addfbb..e4a4da32a56864a7c1d95ec44a5b603f4f541e92 100644 (file)
@@ -65,8 +65,10 @@ static int parse_probe_event(const char *str)
        int ret;
 
        pr_debug("probe-definition(%d): %s\n", params.nevents, str);
-       if (++params.nevents == MAX_PROBES)
-               die("Too many probes (> %d) are specified.", MAX_PROBES);
+       if (++params.nevents == MAX_PROBES) {
+               pr_err("Too many probes (> %d) were specified.", MAX_PROBES);
+               return -1;
+       }
 
        /* Parse a perf-probe command into event */
        ret = parse_perf_probe_command(str, pev);
@@ -84,7 +86,9 @@ static int parse_probe_event_argv(int argc, const char **argv)
        len = 0;
        for (i = 0; i < argc; i++)
                len += strlen(argv[i]) + 1;
-       buf = xzalloc(len + 1);
+       buf = zalloc(len + 1);
+       if (buf == NULL)
+               return -ENOMEM;
        len = 0;
        for (i = 0; i < argc; i++)
                len += sprintf(&buf[len], "%s ", argv[i]);
index cb46c7d0ea99436863cbfed0c6e9a67f8618e9fe..9bc89050e6f8642cf65cbfbd354c7a8f209cd816 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <unistd.h>
 #include <sched.h>
+#include <sys/mman.h>
 
 enum write_mode_t {
        WRITE_FORCE,
@@ -60,13 +61,8 @@ static bool                  call_graph                      =  false;
 static bool                    inherit_stat                    =  false;
 static bool                    no_samples                      =  false;
 static bool                    sample_address                  =  false;
-static bool                    multiplex                       =  false;
-static int                     multiplex_fd                    =     -1;
 
 static long                    samples                         =      0;
-static struct timeval          last_read;
-static struct timeval          this_read;
-
 static u64                     bytes_written                   =      0;
 
 static struct pollfd           *event_array;
@@ -86,7 +82,7 @@ struct mmap_data {
        unsigned int            prev;
 };
 
-static struct mmap_data                *mmap_array[MAX_NR_CPUS][MAX_COUNTERS];
+static struct mmap_data                mmap_array[MAX_NR_CPUS];
 
 static unsigned long mmap_read_head(struct mmap_data *md)
 {
@@ -146,8 +142,6 @@ static void mmap_read(struct mmap_data *md)
        void *buf;
        int diff;
 
-       gettimeofday(&this_read, NULL);
-
        /*
         * If we're further behind than half the buffer, there's a chance
         * the writer will bite our tail and mess up the samples under us.
@@ -158,23 +152,13 @@ static void mmap_read(struct mmap_data *md)
         */
        diff = head - old;
        if (diff < 0) {
-               struct timeval iv;
-               unsigned long msecs;
-
-               timersub(&this_read, &last_read, &iv);
-               msecs = iv.tv_sec*1000 + iv.tv_usec/1000;
-
-               fprintf(stderr, "WARNING: failed to keep up with mmap data."
-                               "  Last read %lu msecs ago.\n", msecs);
-
+               fprintf(stderr, "WARNING: failed to keep up with mmap data\n");
                /*
                 * head points to a known good entry, start there.
                 */
                old = head;
        }
 
-       last_read = this_read;
-
        if (old != head)
                samples++;
 
@@ -380,27 +364,30 @@ try_again:
                 */
                if (group && group_fd == -1)
                        group_fd = fd[nr_cpu][counter][thread_index];
-               if (multiplex && multiplex_fd == -1)
-                       multiplex_fd = fd[nr_cpu][counter][thread_index];
 
-               if (multiplex && fd[nr_cpu][counter][thread_index] != multiplex_fd) {
-
-                       ret = ioctl(fd[nr_cpu][counter][thread_index], PERF_EVENT_IOC_SET_OUTPUT, multiplex_fd);
-                       assert(ret != -1);
+               if (counter || thread_index) {
+                       ret = ioctl(fd[nr_cpu][counter][thread_index],
+                                       PERF_EVENT_IOC_SET_OUTPUT,
+                                       fd[nr_cpu][0][0]);
+                       if (ret) {
+                               error("failed to set output: %d (%s)\n", errno,
+                                               strerror(errno));
+                               exit(-1);
+                       }
                } else {
-                       event_array[nr_poll].fd = fd[nr_cpu][counter][thread_index];
-                       event_array[nr_poll].events = POLLIN;
-                       nr_poll++;
-
-                       mmap_array[nr_cpu][counter][thread_index].counter = counter;
-                       mmap_array[nr_cpu][counter][thread_index].prev = 0;
-                       mmap_array[nr_cpu][counter][thread_index].mask = mmap_pages*page_size - 1;
-                       mmap_array[nr_cpu][counter][thread_index].base = mmap(NULL, (mmap_pages+1)*page_size,
+                       mmap_array[nr_cpu].counter = counter;
+                       mmap_array[nr_cpu].prev = 0;
+                       mmap_array[nr_cpu].mask = mmap_pages*page_size - 1;
+                       mmap_array[nr_cpu].base = mmap(NULL, (mmap_pages+1)*page_size,
                                PROT_READ|PROT_WRITE, MAP_SHARED, fd[nr_cpu][counter][thread_index], 0);
-                       if (mmap_array[nr_cpu][counter][thread_index].base == MAP_FAILED) {
+                       if (mmap_array[nr_cpu].base == MAP_FAILED) {
                                error("failed to mmap with %d (%s)\n", errno, strerror(errno));
                                exit(-1);
                        }
+
+                       event_array[nr_poll].fd = fd[nr_cpu][counter][thread_index];
+                       event_array[nr_poll].events = POLLIN;
+                       nr_poll++;
                }
 
                if (filter != NULL) {
@@ -501,16 +488,11 @@ static struct perf_event_header finished_round_event = {
 
 static void mmap_read_all(void)
 {
-       int i, counter, thread;
+       int i;
 
        for (i = 0; i < nr_cpu; i++) {
-               for (counter = 0; counter < nr_counters; counter++) {
-                       for (thread = 0; thread < thread_num; thread++) {
-                               if (mmap_array[i][counter][thread].base)
-                                       mmap_read(&mmap_array[i][counter][thread]);
-                       }
-
-               }
+               if (mmap_array[i].base)
+                       mmap_read(&mmap_array[i]);
        }
 
        if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO))
@@ -834,8 +816,6 @@ static const struct option options[] = {
                    "Sample addresses"),
        OPT_BOOLEAN('n', "no-samples", &no_samples,
                    "don't sample"),
-       OPT_BOOLEAN('M', "multiplex", &multiplex,
-                   "multiplex counter output in a single channel"),
        OPT_END()
 };
 
@@ -887,9 +867,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
        for (i = 0; i < MAX_NR_CPUS; i++) {
                for (j = 0; j < MAX_COUNTERS; j++) {
                        fd[i][j] = malloc(sizeof(int)*thread_num);
-                       mmap_array[i][j] = zalloc(
-                               sizeof(struct mmap_data)*thread_num);
-                       if (!fd[i][j] || !mmap_array[i][j])
+                       if (!fd[i][j])
                                return -ENOMEM;
                }
        }
index 1d3c1003b43a2f083e94a0926a0000e159379352..3592057829648a8d3f8ac909f93a10a729640b68 100644 (file)
@@ -116,7 +116,7 @@ static int perf_session__add_hist_entry(struct perf_session *self,
         * so we don't allocated the extra space needed because the stdio
         * code will not use it.
         */
-       if (use_browser)
+       if (use_browser > 0)
                err = hist_entry__inc_addr_samples(he, al->addr);
 out_free_syms:
        free(syms);
@@ -288,6 +288,38 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
        return ret + fprintf(fp, "\n#\n");
 }
 
+static int hists__tty_browse_tree(struct rb_root *tree, const char *help)
+{
+       struct rb_node *next = rb_first(tree);
+
+       while (next) {
+               struct hists *hists = rb_entry(next, struct hists, rb_node);
+               const char *evname = NULL;
+
+               if (rb_first(&hists->entries) != rb_last(&hists->entries))
+                       evname = __event_name(hists->type, hists->config);
+
+               hists__fprintf_nr_sample_events(hists, evname, stdout);
+               hists__fprintf(hists, NULL, false, stdout);
+               fprintf(stdout, "\n\n");
+               next = rb_next(&hists->rb_node);
+       }
+
+       if (sort_order == default_sort_order &&
+           parent_pattern == default_parent_pattern) {
+               fprintf(stdout, "#\n# (%s)\n#\n", help);
+
+               if (show_threads) {
+                       bool style = !strcmp(pretty_printing_style, "raw");
+                       perf_read_values_display(stdout, &show_threads_values,
+                                                style);
+                       perf_read_values_destroy(&show_threads_values);
+               }
+       }
+
+       return 0;
+}
+
 static int __cmd_report(void)
 {
        int ret = -EINVAL;
@@ -330,34 +362,14 @@ static int __cmd_report(void)
                hists = rb_entry(next, struct hists, rb_node);
                hists__collapse_resort(hists);
                hists__output_resort(hists);
-               if (use_browser)
-                       hists__browse(hists, help, input_name);
-               else {
-                       const char *evname = NULL;
-                       if (rb_first(&session->hists.entries) !=
-                           rb_last(&session->hists.entries))
-                               evname = __event_name(hists->type, hists->config);
-
-                       hists__fprintf_nr_sample_events(hists, evname, stdout);
-
-                       hists__fprintf(hists, NULL, false, stdout);
-                       fprintf(stdout, "\n\n");
-               }
-
                next = rb_next(&hists->rb_node);
        }
 
-       if (!use_browser && sort_order == default_sort_order &&
-           parent_pattern == default_parent_pattern) {
-               fprintf(stdout, "#\n# (%s)\n#\n", help);
+       if (use_browser > 0)
+               hists__tui_browse_tree(&session->hists_tree, help);
+       else
+               hists__tty_browse_tree(&session->hists_tree, help);
 
-               if (show_threads) {
-                       bool style = !strcmp(pretty_printing_style, "raw");
-                       perf_read_values_display(stdout, &show_threads_values,
-                                                style);
-                       perf_read_values_destroy(&show_threads_values);
-               }
-       }
 out_delete:
        perf_session__delete(session);
        return ret;
@@ -491,7 +503,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
         * so don't allocate extra space that won't be used in the stdio
         * implementation.
         */
-       if (use_browser)
+       if (use_browser > 0)
                symbol_conf.priv_size = sizeof(struct sym_priv);
 
        if (symbol__init() < 0)
index ff8c413b7e734008a667b093e4ffc41f2f5bf7b5..9a39ca3c3ac4fe77f5ed23c82b8dc8cc973b9f51 100644 (file)
@@ -50,6 +50,7 @@
 
 #include <sys/prctl.h>
 #include <math.h>
+#include <locale.h>
 
 static struct perf_event_attr default_attrs[] = {
 
@@ -80,6 +81,8 @@ static pid_t                  *all_tids                       =  NULL;
 static int                     thread_num                      =  0;
 static pid_t                   child_pid                       = -1;
 static bool                    null_run                        =  false;
+static bool                    big_num                         =  false;
+
 
 static int                     *fd[MAX_NR_CPUS][MAX_COUNTERS];
 
@@ -377,7 +380,7 @@ static void nsec_printout(int counter, double avg)
 {
        double msecs = avg / 1e6;
 
-       fprintf(stderr, " %14.6f  %-24s", msecs, event_name(counter));
+       fprintf(stderr, " %18.6f  %-24s", msecs, event_name(counter));
 
        if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) {
                fprintf(stderr, " # %10.3f CPUs ",
@@ -389,7 +392,10 @@ static void abs_printout(int counter, double avg)
 {
        double total, ratio = 0.0;
 
-       fprintf(stderr, " %14.0f  %-24s", avg, event_name(counter));
+       if (big_num)
+               fprintf(stderr, " %'18.0f  %-24s", avg, event_name(counter));
+       else
+               fprintf(stderr, " %18.0f  %-24s", avg, event_name(counter));
 
        if (MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) {
                total = avg_stats(&runtime_cycles_stats);
@@ -426,7 +432,7 @@ static void print_counter(int counter)
        int scaled = event_scaled[counter];
 
        if (scaled == -1) {
-               fprintf(stderr, " %14s  %-24s\n",
+               fprintf(stderr, " %18s  %-24s\n",
                        "<not counted>", event_name(counter));
                return;
        }
@@ -477,7 +483,7 @@ static void print_stat(int argc, const char **argv)
                print_counter(counter);
 
        fprintf(stderr, "\n");
-       fprintf(stderr, " %14.9f  seconds time elapsed",
+       fprintf(stderr, " %18.9f  seconds time elapsed",
                        avg_stats(&walltime_nsecs_stats)/1e9);
        if (run_count > 1) {
                fprintf(stderr, "   ( +- %7.3f%% )",
@@ -534,6 +540,8 @@ static const struct option options[] = {
                    "repeat command and print average + stddev (max: 100)"),
        OPT_BOOLEAN('n', "null", &null_run,
                    "null run - dont start any counters"),
+       OPT_BOOLEAN('B', "big-num", &big_num,
+                   "print large numbers with thousands\' separators"),
        OPT_END()
 };
 
@@ -542,6 +550,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
        int status;
        int i,j;
 
+       setlocale(LC_ALL, "");
+
        argc = parse_options(argc, argv, options, stat_usage,
                PARSE_OPT_STOP_AT_NON_OPTION);
        if (!argc && target_pid == -1 && target_tid == -1)
index 08e0e5d2b50eb30be37b609c7e3a3f00bd0c8f12..6e4871191138970e57ea0dbeedf185eabb4ce0c1 100644 (file)
 #include "util/parse-events.h"
 #include "util/debugfs.h"
 
-bool use_browser;
-
 const char perf_usage_string[] =
        "perf [--version] [--help] COMMAND [ARGS]";
 
 const char perf_more_info_string[] =
        "See 'perf help COMMAND' for more information on a specific command.";
 
+int use_browser = -1;
 static int use_pager = -1;
+
 struct pager_config {
        const char *cmd;
        int val;
@@ -49,6 +49,24 @@ int check_pager_config(const char *cmd)
        return c.val;
 }
 
+static int tui_command_config(const char *var, const char *value, void *data)
+{
+       struct pager_config *c = data;
+       if (!prefixcmp(var, "tui.") && !strcmp(var + 4, c->cmd))
+               c->val = perf_config_bool(var, value);
+       return 0;
+}
+
+/* returns 0 for "no tui", 1 for "use tui", and -1 for "not specified" */
+static int check_tui_config(const char *cmd)
+{
+       struct pager_config c;
+       c.cmd = cmd;
+       c.val = -1;
+       perf_config(tui_command_config, &c);
+       return c.val;
+}
+
 static void commit_pager_choice(void)
 {
        switch (use_pager) {
@@ -255,6 +273,9 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
        if (p->option & RUN_SETUP)
                prefix = NULL; /* setup_perf_directory(); */
 
+       if (use_browser == -1)
+               use_browser = check_tui_config(p->cmd);
+
        if (use_pager == -1 && p->option & RUN_SETUP)
                use_pager = check_pager_config(p->cmd);
        if (use_pager == -1 && p->option & USE_PAGER)
index a791dd4672615e1315259dc70c23dd9fb2157f1c..0e76affe9c362b3bd67171e8dcfa18f0c0373167 100644 (file)
@@ -1,86 +1,5 @@
 #include "cache.h"
 
-/*
- * Do not use this for inspecting *tracked* content.  When path is a
- * symlink to a directory, we do not want to say it is a directory when
- * dealing with tracked content in the working tree.
- */
-static int is_directory(const char *path)
-{
-       struct stat st;
-       return (!stat(path, &st) && S_ISDIR(st.st_mode));
-}
-
-/* We allow "recursive" symbolic links. Only within reason, though. */
-#define MAXDEPTH 5
-
-const char *make_absolute_path(const char *path)
-{
-       static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1];
-       char cwd[1024] = "";
-       int buf_index = 1, len;
-
-       int depth = MAXDEPTH;
-       char *last_elem = NULL;
-       struct stat st;
-
-       if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
-               die ("Too long path: %.*s", 60, path);
-
-       while (depth--) {
-               if (!is_directory(buf)) {
-                       char *last_slash = strrchr(buf, '/');
-                       if (last_slash) {
-                               *last_slash = '\0';
-                               last_elem = xstrdup(last_slash + 1);
-                       } else {
-                               last_elem = xstrdup(buf);
-                               *buf = '\0';
-                       }
-               }
-
-               if (*buf) {
-                       if (!*cwd && !getcwd(cwd, sizeof(cwd)))
-                               die ("Could not get current working directory");
-
-                       if (chdir(buf))
-                               die ("Could not switch to '%s'", buf);
-               }
-               if (!getcwd(buf, PATH_MAX))
-                       die ("Could not get current working directory");
-
-               if (last_elem) {
-                       len = strlen(buf);
-
-                       if (len + strlen(last_elem) + 2 > PATH_MAX)
-                               die ("Too long path name: '%s/%s'",
-                                               buf, last_elem);
-                       buf[len] = '/';
-                       strcpy(buf + len + 1, last_elem);
-                       free(last_elem);
-                       last_elem = NULL;
-               }
-
-               if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) {
-                       len = readlink(buf, next_buf, PATH_MAX);
-                       if (len < 0)
-                               die ("Invalid symlink: %s", buf);
-                       if (PATH_MAX <= len)
-                               die("symbolic link too long: %s", buf);
-                       next_buf[len] = '\0';
-                       buf = next_buf;
-                       buf_index = 1 - buf_index;
-                       next_buf = bufs[buf_index];
-               } else
-                       break;
-       }
-
-       if (*cwd && chdir(cwd))
-               die ("Could not change back to '%s'", cwd);
-
-       return buf;
-}
-
 static const char *get_pwd_cwd(void)
 {
        static char cwd[PATH_MAX + 1];
index 0f60a39068086b9949ee4aa03b94de2bdc5ea439..70c5cf87d020d9d44750da480face3820d2ded15 100644 (file)
@@ -6,6 +6,8 @@
  * Copyright (C) 2009, 2010 Red Hat Inc.
  * Copyright (C) 2009, 2010 Arnaldo Carvalho de Melo <acme@redhat.com>
  */
+#include "util.h"
+#include <stdio.h>
 #include "build-id.h"
 #include "event.h"
 #include "symbol.h"
@@ -37,3 +39,23 @@ struct perf_event_ops build_id__mark_dso_hit_ops = {
        .mmap   = event__process_mmap,
        .fork   = event__process_task,
 };
+
+char *dso__build_id_filename(struct dso *self, char *bf, size_t size)
+{
+       char build_id_hex[BUILD_ID_SIZE * 2 + 1];
+       const char *home;
+
+       if (!self->has_build_id)
+               return NULL;
+
+       build_id__sprintf(self->build_id, sizeof(self->build_id), build_id_hex);
+       home = getenv("HOME");
+       if (bf == NULL) {
+               if (asprintf(&bf, "%s/%s/.build-id/%.2s/%s", home,
+                            DEBUG_CACHE_DIR, build_id_hex, build_id_hex + 2) < 0)
+                       return NULL;
+       } else
+               snprintf(bf, size, "%s/%s/.build-id/%.2s/%s", home,
+                        DEBUG_CACHE_DIR, build_id_hex, build_id_hex + 2);
+       return bf;
+}
index 1d981d63cf9a0a0d193662636738d7562e0aec2d..5dafb00eaa068ce7e4c0b34d1bad1668021d57f6 100644 (file)
@@ -5,4 +5,6 @@
 
 extern struct perf_event_ops build_id__mark_dso_hit_ops;
 
+char *dso__build_id_filename(struct dso *self, char *bf, size_t size);
+
 #endif
index 4b9aab7f04056ef6d599ba9e2eb8d7d3333d579b..65fe664fddf698e67aa0639169665e64fffbdf61 100644 (file)
 
 #define PERF_DIR_ENVIRONMENT "PERF_DIR"
 #define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE"
-#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf"
-#define DB_ENVIRONMENT "PERF_OBJECT_DIRECTORY"
-#define INDEX_ENVIRONMENT "PERF_INDEX_FILE"
-#define GRAFT_ENVIRONMENT "PERF_GRAFT_FILE"
-#define TEMPLATE_DIR_ENVIRONMENT "PERF_TEMPLATE_DIR"
-#define CONFIG_ENVIRONMENT "PERF_CONFIG"
 #define EXEC_PATH_ENVIRONMENT "PERF_EXEC_PATH"
-#define CEILING_DIRECTORIES_ENVIRONMENT "PERF_CEILING_DIRECTORIES"
-#define PERFATTRIBUTES_FILE ".perfattributes"
-#define INFOATTRIBUTES_FILE "info/attributes"
-#define ATTRIBUTE_MACRO_PREFIX "[attr]"
+#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf"
 #define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR"
 
 typedef int (*config_fn_t)(const char *, const char *, void *);
 extern int perf_default_config(const char *, const char *, void *);
-extern int perf_config_from_file(config_fn_t fn, const char *, void *);
 extern int perf_config(config_fn_t fn, void *);
-extern int perf_parse_ulong(const char *, unsigned long *);
 extern int perf_config_int(const char *, const char *);
-extern unsigned long perf_config_ulong(const char *, const char *);
-extern int perf_config_bool_or_int(const char *, const char *, int *);
 extern int perf_config_bool(const char *, const char *);
-extern int perf_config_string(const char **, const char *, const char *);
-extern int perf_config_set(const char *, const char *);
-extern int perf_config_set_multivar(const char *, const char *, const char *, int);
-extern int perf_config_rename_section(const char *, const char *);
-extern const char *perf_etc_perfconfig(void);
-extern int check_repository_format_version(const char *var, const char *value, void *cb);
-extern int perf_config_system(void);
-extern int perf_config_global(void);
 extern int config_error_nonbool(const char *);
-extern const char *config_exclusive_filename;
-
-#define MAX_PERFNAME (1000)
-extern char perf_default_email[MAX_PERFNAME];
-extern char perf_default_name[MAX_PERFNAME];
-extern int user_ident_explicitly_given;
-
-extern const char *perf_log_output_encoding;
-extern const char *perf_mailmap_file;
-
-/* IO helper functions */
-extern void maybe_flush_or_die(FILE *, const char *);
-extern int copy_fd(int ifd, int ofd);
-extern int copy_file(const char *dst, const char *src, int mode);
-extern ssize_t write_in_full(int fd, const void *buf, size_t count);
-extern void write_or_die(int fd, const void *buf, size_t count);
-extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg);
-extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg);
-extern void fsync_or_die(int fd, const char *);
 
 /* pager.c */
 extern void setup_pager(void);
@@ -70,7 +30,7 @@ extern const char *pager_program;
 extern int pager_in_use(void);
 extern int pager_use_color;
 
-extern bool use_browser;
+extern int use_browser;
 
 #ifdef NO_NEWT_SUPPORT
 static inline void setup_browser(void)
@@ -83,9 +43,6 @@ void setup_browser(void);
 void exit_browser(bool wait_for_ok);
 #endif
 
-extern const char *editor_program;
-extern const char *excludes_file;
-
 char *alias_lookup(const char *alias);
 int split_cmdline(char *cmdline, const char ***argv);
 
@@ -115,22 +72,12 @@ static inline int is_absolute_path(const char *path)
        return path[0] == '/';
 }
 
-const char *make_absolute_path(const char *path);
 const char *make_nonrelative_path(const char *path);
-const char *make_relative_path(const char *abs, const char *base);
-int normalize_path_copy(char *dst, const char *src);
-int longest_ancestor_length(const char *path, const char *prefix_list);
 char *strip_path_suffix(const char *path, const char *suffix);
 
 extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 extern char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
-/* perf_mkstemp() - create tmp file honoring TMPDIR variable */
-extern int perf_mkstemp(char *path, size_t len, const char *template);
 
-extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)
-       __attribute__((format (printf, 3, 4)));
-extern char *perf_snpath(char *buf, size_t n, const char *fmt, ...)
-       __attribute__((format (printf, 3, 4)));
 extern char *perf_pathdup(const char *fmt, ...)
        __attribute__((format (printf, 1, 2)));
 
index 21a52e0a44359aaa582d0745717f388f24fc058c..62b69ad4aa735bc0ec146277661e30f9c0e3d4e9 100644 (file)
@@ -15,6 +15,7 @@
 #include <errno.h>
 #include <math.h>
 
+#include "util.h"
 #include "callchain.h"
 
 bool ip_callchain__valid(struct ip_callchain *chain, event_t *event)
index 1cba1f5504e71ed7747e0263072503643983b1f7..1ca73e4a2723997099973963f8477bdbbafcc909 100644 (file)
@@ -5,7 +5,6 @@
 #include <linux/list.h>
 #include <linux/rbtree.h>
 #include "event.h"
-#include "util.h"
 #include "symbol.h"
 
 enum chain_mode {
index 8784649109ce88de709c08e30eeb06f25aaa04f4..dabe892d0e5374ad8689040e6865a642e161f752 100644 (file)
@@ -16,7 +16,7 @@ static const char *config_file_name;
 static int config_linenr;
 static int config_file_eof;
 
-const char *config_exclusive_filename = NULL;
+static const char *config_exclusive_filename;
 
 static int get_next_char(void)
 {
@@ -291,19 +291,6 @@ static int perf_parse_long(const char *value, long *ret)
        return 0;
 }
 
-int perf_parse_ulong(const char *value, unsigned long *ret)
-{
-       if (value && *value) {
-               char *end;
-               unsigned long val = strtoul(value, &end, 0);
-               if (!parse_unit_factor(end, &val))
-                       return 0;
-               *ret = val;
-               return 1;
-       }
-       return 0;
-}
-
 static void die_bad_config(const char *name)
 {
        if (config_file_name)
@@ -319,15 +306,7 @@ int perf_config_int(const char *name, const char *value)
        return ret;
 }
 
-unsigned long perf_config_ulong(const char *name, const char *value)
-{
-       unsigned long ret;
-       if (!perf_parse_ulong(value, &ret))
-               die_bad_config(name);
-       return ret;
-}
-
-int perf_config_bool_or_int(const char *name, const char *value, int *is_bool)
+static int perf_config_bool_or_int(const char *name, const char *value, int *is_bool)
 {
        *is_bool = 1;
        if (!value)
@@ -348,14 +327,6 @@ int perf_config_bool(const char *name, const char *value)
        return !!perf_config_bool_or_int(name, value, &discard);
 }
 
-int perf_config_string(const char **dest, const char *var, const char *value)
-{
-       if (!value)
-               return config_error_nonbool(var);
-       *dest = strdup(value);
-       return 0;
-}
-
 static int perf_default_core_config(const char *var __used, const char *value __used)
 {
        /* Add other config variables here and to Documentation/config.txt. */
@@ -371,7 +342,7 @@ int perf_default_config(const char *var, const char *value, void *dummy __used)
        return 0;
 }
 
-int perf_config_from_file(config_fn_t fn, const char *filename, void *data)
+static int perf_config_from_file(config_fn_t fn, const char *filename, void *data)
 {
        int ret;
        FILE *f = fopen(filename, "r");
@@ -389,7 +360,7 @@ int perf_config_from_file(config_fn_t fn, const char *filename, void *data)
        return ret;
 }
 
-const char *perf_etc_perfconfig(void)
+static const char *perf_etc_perfconfig(void)
 {
        static const char *system_wide;
        if (!system_wide)
@@ -403,12 +374,12 @@ static int perf_env_bool(const char *k, int def)
        return v ? perf_config_bool(k, v) : def;
 }
 
-int perf_config_system(void)
+static int perf_config_system(void)
 {
        return !perf_env_bool("PERF_CONFIG_NOSYSTEM", 0);
 }
 
-int perf_config_global(void)
+static int perf_config_global(void)
 {
        return !perf_env_bool("PERF_CONFIG_NOGLOBAL", 0);
 }
@@ -449,426 +420,6 @@ int perf_config(config_fn_t fn, void *data)
        return ret;
 }
 
-/*
- * Find all the stuff for perf_config_set() below.
- */
-
-#define MAX_MATCHES 512
-
-static struct {
-       int baselen;
-       char* key;
-       int do_not_match;
-       regex_t* value_regex;
-       int multi_replace;
-       size_t offset[MAX_MATCHES];
-       enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state;
-       int seen;
-} store;
-
-static int matches(const char* key, const char* value)
-{
-       return !strcmp(key, store.key) &&
-               (store.value_regex == NULL ||
-                (store.do_not_match ^
-                 !regexec(store.value_regex, value, 0, NULL, 0)));
-}
-
-static int store_aux(const char* key, const char* value, void *cb __used)
-{
-       int section_len;
-       const char *ep;
-
-       switch (store.state) {
-       case KEY_SEEN:
-               if (matches(key, value)) {
-                       if (store.seen == 1 && store.multi_replace == 0) {
-                               warning("%s has multiple values", key);
-                       } else if (store.seen >= MAX_MATCHES) {
-                               error("too many matches for %s", key);
-                               return 1;
-                       }
-
-                       store.offset[store.seen] = ftell(config_file);
-                       store.seen++;
-               }
-               break;
-       case SECTION_SEEN:
-               /*
-                * What we are looking for is in store.key (both
-                * section and var), and its section part is baselen
-                * long.  We found key (again, both section and var).
-                * We would want to know if this key is in the same
-                * section as what we are looking for.  We already
-                * know we are in the same section as what should
-                * hold store.key.
-                */
-               ep = strrchr(key, '.');
-               section_len = ep - key;
-
-               if ((section_len != store.baselen) ||
-                   memcmp(key, store.key, section_len+1)) {
-                       store.state = SECTION_END_SEEN;
-                       break;
-               }
-
-               /*
-                * Do not increment matches: this is no match, but we
-                * just made sure we are in the desired section.
-                */
-               store.offset[store.seen] = ftell(config_file);
-               /* fallthru */
-       case SECTION_END_SEEN:
-       case START:
-               if (matches(key, value)) {
-                       store.offset[store.seen] = ftell(config_file);
-                       store.state = KEY_SEEN;
-                       store.seen++;
-               } else {
-                       if (strrchr(key, '.') - key == store.baselen &&
-                             !strncmp(key, store.key, store.baselen)) {
-                                       store.state = SECTION_SEEN;
-                                       store.offset[store.seen] = ftell(config_file);
-                       }
-               }
-       default:
-               break;
-       }
-       return 0;
-}
-
-static int store_write_section(int fd, const char* key)
-{
-       const char *dot;
-       int i, success;
-       struct strbuf sb = STRBUF_INIT;
-
-       dot = memchr(key, '.', store.baselen);
-       if (dot) {
-               strbuf_addf(&sb, "[%.*s \"", (int)(dot - key), key);
-               for (i = dot - key + 1; i < store.baselen; i++) {
-                       if (key[i] == '"' || key[i] == '\\')
-                               strbuf_addch(&sb, '\\');
-                       strbuf_addch(&sb, key[i]);
-               }
-               strbuf_addstr(&sb, "\"]\n");
-       } else {
-               strbuf_addf(&sb, "[%.*s]\n", store.baselen, key);
-       }
-
-       success = (write_in_full(fd, sb.buf, sb.len) == (ssize_t)sb.len);
-       strbuf_release(&sb);
-
-       return success;
-}
-
-static int store_write_pair(int fd, const char* key, const char* value)
-{
-       int i, success;
-       int length = strlen(key + store.baselen + 1);
-       const char *quote = "";
-       struct strbuf sb = STRBUF_INIT;
-
-       /*
-        * Check to see if the value needs to be surrounded with a dq pair.
-        * Note that problematic characters are always backslash-quoted; this
-        * check is about not losing leading or trailing SP and strings that
-        * follow beginning-of-comment characters (i.e. ';' and '#') by the
-        * configuration parser.
-        */
-       if (value[0] == ' ')
-               quote = "\"";
-       for (i = 0; value[i]; i++)
-               if (value[i] == ';' || value[i] == '#')
-                       quote = "\"";
-       if (i && value[i - 1] == ' ')
-               quote = "\"";
-
-       strbuf_addf(&sb, "\t%.*s = %s",
-                   length, key + store.baselen + 1, quote);
-
-       for (i = 0; value[i]; i++)
-               switch (value[i]) {
-               case '\n':
-                       strbuf_addstr(&sb, "\\n");
-                       break;
-               case '\t':
-                       strbuf_addstr(&sb, "\\t");
-                       break;
-               case '"':
-               case '\\':
-                       strbuf_addch(&sb, '\\');
-               default:
-                       strbuf_addch(&sb, value[i]);
-                       break;
-               }
-       strbuf_addf(&sb, "%s\n", quote);
-
-       success = (write_in_full(fd, sb.buf, sb.len) == (ssize_t)sb.len);
-       strbuf_release(&sb);
-
-       return success;
-}
-
-static ssize_t find_beginning_of_line(const char* contents, size_t size,
-       size_t offset_, int* found_bracket)
-{
-       size_t equal_offset = size, bracket_offset = size;
-       ssize_t offset;
-
-contline:
-       for (offset = offset_-2; offset > 0
-                       && contents[offset] != '\n'; offset--)
-               switch (contents[offset]) {
-                       case '=': equal_offset = offset; break;
-                       case ']': bracket_offset = offset; break;
-                       default: break;
-               }
-       if (offset > 0 && contents[offset-1] == '\\') {
-               offset_ = offset;
-               goto contline;
-       }
-       if (bracket_offset < equal_offset) {
-               *found_bracket = 1;
-               offset = bracket_offset+1;
-       } else
-               offset++;
-
-       return offset;
-}
-
-int perf_config_set(const char* key, const char* value)
-{
-       return perf_config_set_multivar(key, value, NULL, 0);
-}
-
-/*
- * If value==NULL, unset in (remove from) config,
- * if value_regex!=NULL, disregard key/value pairs where value does not match.
- * if multi_replace==0, nothing, or only one matching key/value is replaced,
- *     else all matching key/values (regardless how many) are removed,
- *     before the new pair is written.
- *
- * Returns 0 on success.
- *
- * This function does this:
- *
- * - it locks the config file by creating ".perf/config.lock"
- *
- * - it then parses the config using store_aux() as validator to find
- *   the position on the key/value pair to replace. If it is to be unset,
- *   it must be found exactly once.
- *
- * - the config file is mmap()ed and the part before the match (if any) is
- *   written to the lock file, then the changed part and the rest.
- *
- * - the config file is removed and the lock file rename()d to it.
- *
- */
-int perf_config_set_multivar(const char* key, const char* value,
-       const char* value_regex, int multi_replace)
-{
-       int i, dot;
-       int fd = -1, in_fd;
-       int ret = 0;
-       char* config_filename;
-       const char* last_dot = strrchr(key, '.');
-
-       if (config_exclusive_filename)
-               config_filename = strdup(config_exclusive_filename);
-       else
-               config_filename = perf_pathdup("config");
-
-       /*
-        * Since "key" actually contains the section name and the real
-        * key name separated by a dot, we have to know where the dot is.
-        */
-
-       if (last_dot == NULL) {
-               error("key does not contain a section: %s", key);
-               ret = 2;
-               goto out_free;
-       }
-       store.baselen = last_dot - key;
-
-       store.multi_replace = multi_replace;
-
-       /*
-        * Validate the key and while at it, lower case it for matching.
-        */
-       store.key = malloc(strlen(key) + 1);
-       dot = 0;
-       for (i = 0; key[i]; i++) {
-               unsigned char c = key[i];
-               if (c == '.')
-                       dot = 1;
-               /* Leave the extended basename untouched.. */
-               if (!dot || i > store.baselen) {
-                       if (!iskeychar(c) || (i == store.baselen+1 && !isalpha(c))) {
-                               error("invalid key: %s", key);
-                               free(store.key);
-                               ret = 1;
-                               goto out_free;
-                       }
-                       c = tolower(c);
-               } else if (c == '\n') {
-                       error("invalid key (newline): %s", key);
-                       free(store.key);
-                       ret = 1;
-                       goto out_free;
-               }
-               store.key[i] = c;
-       }
-       store.key[i] = 0;
-
-       /*
-        * If .perf/config does not exist yet, write a minimal version.
-        */
-       in_fd = open(config_filename, O_RDONLY);
-       if ( in_fd < 0 ) {
-               free(store.key);
-
-               if ( ENOENT != errno ) {
-                       error("opening %s: %s", config_filename,
-                             strerror(errno));
-                       ret = 3; /* same as "invalid config file" */
-                       goto out_free;
-               }
-               /* if nothing to unset, error out */
-               if (value == NULL) {
-                       ret = 5;
-                       goto out_free;
-               }
-
-               store.key = (char*)key;
-               if (!store_write_section(fd, key) ||
-                   !store_write_pair(fd, key, value))
-                       goto write_err_out;
-       } else {
-               struct stat st;
-               char *contents;
-               ssize_t contents_sz, copy_begin, copy_end;
-               int new_line = 0;
-
-               if (value_regex == NULL)
-                       store.value_regex = NULL;
-               else {
-                       if (value_regex[0] == '!') {
-                               store.do_not_match = 1;
-                               value_regex++;
-                       } else
-                               store.do_not_match = 0;
-
-                       store.value_regex = (regex_t*)malloc(sizeof(regex_t));
-                       if (regcomp(store.value_regex, value_regex,
-                                       REG_EXTENDED)) {
-                               error("invalid pattern: %s", value_regex);
-                               free(store.value_regex);
-                               ret = 6;
-                               goto out_free;
-                       }
-               }
-
-               store.offset[0] = 0;
-               store.state = START;
-               store.seen = 0;
-
-               /*
-                * After this, store.offset will contain the *end* offset
-                * of the last match, or remain at 0 if no match was found.
-                * As a side effect, we make sure to transform only a valid
-                * existing config file.
-                */
-               if (perf_config_from_file(store_aux, config_filename, NULL)) {
-                       error("invalid config file %s", config_filename);
-                       free(store.key);
-                       if (store.value_regex != NULL) {
-                               regfree(store.value_regex);
-                               free(store.value_regex);
-                       }
-                       ret = 3;
-                       goto out_free;
-               }
-
-               free(store.key);
-               if (store.value_regex != NULL) {
-                       regfree(store.value_regex);
-                       free(store.value_regex);
-               }
-
-               /* if nothing to unset, or too many matches, error out */
-               if ((store.seen == 0 && value == NULL) ||
-                               (store.seen > 1 && multi_replace == 0)) {
-                       ret = 5;
-                       goto out_free;
-               }
-
-               fstat(in_fd, &st);
-               contents_sz = xsize_t(st.st_size);
-               contents = mmap(NULL, contents_sz, PROT_READ,
-                       MAP_PRIVATE, in_fd, 0);
-               close(in_fd);
-
-               if (store.seen == 0)
-                       store.seen = 1;
-
-               for (i = 0, copy_begin = 0; i < store.seen; i++) {
-                       if (store.offset[i] == 0) {
-                               store.offset[i] = copy_end = contents_sz;
-                       } else if (store.state != KEY_SEEN) {
-                               copy_end = store.offset[i];
-                       } else
-                               copy_end = find_beginning_of_line(
-                                       contents, contents_sz,
-                                       store.offset[i]-2, &new_line);
-
-                       if (copy_end > 0 && contents[copy_end-1] != '\n')
-                               new_line = 1;
-
-                       /* write the first part of the config */
-                       if (copy_end > copy_begin) {
-                               if (write_in_full(fd, contents + copy_begin,
-                                                 copy_end - copy_begin) <
-                                   copy_end - copy_begin)
-                                       goto write_err_out;
-                               if (new_line &&
-                                   write_in_full(fd, "\n", 1) != 1)
-                                       goto write_err_out;
-                       }
-                       copy_begin = store.offset[i];
-               }
-
-               /* write the pair (value == NULL means unset) */
-               if (value != NULL) {
-                       if (store.state == START) {
-                               if (!store_write_section(fd, key))
-                                       goto write_err_out;
-                       }
-                       if (!store_write_pair(fd, key, value))
-                               goto write_err_out;
-               }
-
-               /* write the rest of the config */
-               if (copy_begin < contents_sz)
-                       if (write_in_full(fd, contents + copy_begin,
-                                         contents_sz - copy_begin) <
-                           contents_sz - copy_begin)
-                               goto write_err_out;
-
-               munmap(contents, contents_sz);
-       }
-
-       ret = 0;
-
-out_free:
-       free(config_filename);
-       return ret;
-
-write_err_out:
-       goto out_free;
-
-}
-
 /*
  * Call this to report error for your variable that should not
  * get a boolean value (i.e. "[my] var" means "true").
index 2745605dba11f4d334c15a294326aa0c7ac2bfc9..67eeff571568d5ead2088bdcaee30097dc8d26d8 100644 (file)
@@ -53,8 +53,8 @@ const char *perf_extract_argv0_path(const char *argv0)
                slash--;
 
        if (slash >= argv0) {
-               argv0_path = xstrndup(argv0, slash - argv0);
-               return slash + 1;
+               argv0_path = strndup(argv0, slash - argv0);
+               return argv0_path ? slash + 1 : NULL;
        }
 
        return argv0;
@@ -116,7 +116,7 @@ void setup_path(void)
        strbuf_release(&new_path);
 }
 
-const char **prepare_perf_cmd(const char **argv)
+static const char **prepare_perf_cmd(const char **argv)
 {
        int argc;
        const char **nargv;
index 31647ac92ed1733e71dade59609c310563193b31..bc4b915963f591828de7a4268759cfce73c36d92 100644 (file)
@@ -5,7 +5,6 @@ extern void perf_set_argv_exec_path(const char *exec_path);
 extern const char *perf_extract_argv0_path(const char *path);
 extern const char *perf_exec_path(void);
 extern void setup_path(void);
-extern const char **prepare_perf_cmd(const char **argv);
 extern int execv_perf_cmd(const char **argv); /* NULL terminated */
 extern int execl_perf_cmd(const char *cmd, ...);
 extern const char *system_path(const char *path);
index 8847bec64c54119fc0e006dbd6350b231203dbd9..1f62435f96c2fe6a3ef6a1a82f0f28ddca13652d 100644 (file)
@@ -221,29 +221,38 @@ static int __dsos__write_buildid_table(struct list_head *head, pid_t pid,
        return 0;
 }
 
+static int machine__write_buildid_table(struct machine *self, int fd)
+{
+       int err;
+       u16 kmisc = PERF_RECORD_MISC_KERNEL,
+           umisc = PERF_RECORD_MISC_USER;
+
+       if (!machine__is_host(self)) {
+               kmisc = PERF_RECORD_MISC_GUEST_KERNEL;
+               umisc = PERF_RECORD_MISC_GUEST_USER;
+       }
+
+       err = __dsos__write_buildid_table(&self->kernel_dsos, self->pid,
+                                         kmisc, fd);
+       if (err == 0)
+               err = __dsos__write_buildid_table(&self->user_dsos,
+                                                 self->pid, umisc, fd);
+       return err;
+}
+
 static int dsos__write_buildid_table(struct perf_header *header, int fd)
 {
        struct perf_session *session = container_of(header,
                        struct perf_session, header);
        struct rb_node *nd;
-       int err = 0;
-       u16 kmisc, umisc;
+       int err = machine__write_buildid_table(&session->host_machine, fd);
+
+       if (err)
+               return err;
 
        for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
                struct machine *pos = rb_entry(nd, struct machine, rb_node);
-               if (machine__is_host(pos)) {
-                       kmisc = PERF_RECORD_MISC_KERNEL;
-                       umisc = PERF_RECORD_MISC_USER;
-               } else {
-                       kmisc = PERF_RECORD_MISC_GUEST_KERNEL;
-                       umisc = PERF_RECORD_MISC_GUEST_USER;
-               }
-
-               err = __dsos__write_buildid_table(&pos->kernel_dsos, pos->pid,
-                                                 kmisc, fd);
-               if (err == 0)
-                       err = __dsos__write_buildid_table(&pos->user_dsos,
-                                                         pos->pid, umisc, fd);
+               err = machine__write_buildid_table(pos, fd);
                if (err)
                        break;
        }
@@ -363,12 +372,17 @@ static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
        return err;
 }
 
-static int dsos__cache_build_ids(struct perf_header *self)
+static int machine__cache_build_ids(struct machine *self, const char *debugdir)
+{
+       int ret = __dsos__cache_build_ids(&self->kernel_dsos, debugdir);
+       ret |= __dsos__cache_build_ids(&self->user_dsos, debugdir);
+       return ret;
+}
+
+static int perf_session__cache_build_ids(struct perf_session *self)
 {
-       struct perf_session *session = container_of(self,
-                       struct perf_session, header);
        struct rb_node *nd;
-       int ret = 0;
+       int ret;
        char debugdir[PATH_MAX];
 
        snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"),
@@ -377,25 +391,30 @@ static int dsos__cache_build_ids(struct perf_header *self)
        if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
                return -1;
 
-       for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
+       ret = machine__cache_build_ids(&self->host_machine, debugdir);
+
+       for (nd = rb_first(&self->machines); nd; nd = rb_next(nd)) {
                struct machine *pos = rb_entry(nd, struct machine, rb_node);
-               ret |= __dsos__cache_build_ids(&pos->kernel_dsos, debugdir);
-               ret |= __dsos__cache_build_ids(&pos->user_dsos, debugdir);
+               ret |= machine__cache_build_ids(pos, debugdir);
        }
        return ret ? -1 : 0;
 }
 
-static bool dsos__read_build_ids(struct perf_header *self, bool with_hits)
+static bool machine__read_build_ids(struct machine *self, bool with_hits)
+{
+       bool ret = __dsos__read_build_ids(&self->kernel_dsos, with_hits);
+       ret |= __dsos__read_build_ids(&self->user_dsos, with_hits);
+       return ret;
+}
+
+static bool perf_session__read_build_ids(struct perf_session *self, bool with_hits)
 {
-       bool ret = false;
-       struct perf_session *session = container_of(self,
-                       struct perf_session, header);
        struct rb_node *nd;
+       bool ret = machine__read_build_ids(&self->host_machine, with_hits);
 
-       for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
+       for (nd = rb_first(&self->machines); nd; nd = rb_next(nd)) {
                struct machine *pos = rb_entry(nd, struct machine, rb_node);
-               ret |= __dsos__read_build_ids(&pos->kernel_dsos, with_hits);
-               ret |= __dsos__read_build_ids(&pos->user_dsos, with_hits);
+               ret |= machine__read_build_ids(pos, with_hits);
        }
 
        return ret;
@@ -404,12 +423,14 @@ static bool dsos__read_build_ids(struct perf_header *self, bool with_hits)
 static int perf_header__adds_write(struct perf_header *self, int fd)
 {
        int nr_sections;
+       struct perf_session *session;
        struct perf_file_section *feat_sec;
        int sec_size;
        u64 sec_start;
        int idx = 0, err;
 
-       if (dsos__read_build_ids(self, true))
+       session = container_of(self, struct perf_session, header);
+       if (perf_session__read_build_ids(session, true))
                perf_header__set_feat(self, HEADER_BUILD_ID);
 
        nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
@@ -450,7 +471,7 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
                }
                buildid_sec->size = lseek(fd, 0, SEEK_CUR) -
                                          buildid_sec->offset;
-               dsos__cache_build_ids(self);
+               perf_session__cache_build_ids(session);
        }
 
        lseek(fd, sec_start, SEEK_SET);
@@ -490,7 +511,6 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit)
 
        lseek(fd, sizeof(f_header), SEEK_SET);
 
-
        for (i = 0; i < self->attrs; i++) {
                attr = self->attr[i];
 
index fbb00978b2e2988045f4f970964b7c5826c1cba4..6f2975a0035856a6ea1f7d1b02b3ad47a0d5ef45 100644 (file)
@@ -4,28 +4,6 @@
 #include "levenshtein.h"
 #include "help.h"
 
-/* most GUI terminals set COLUMNS (although some don't export it) */
-static int term_columns(void)
-{
-       char *col_string = getenv("COLUMNS");
-       int n_cols;
-
-       if (col_string && (n_cols = atoi(col_string)) > 0)
-               return n_cols;
-
-#ifdef TIOCGWINSZ
-       {
-               struct winsize ws;
-               if (!ioctl(1, TIOCGWINSZ, &ws)) {
-                       if (ws.ws_col)
-                               return ws.ws_col;
-               }
-       }
-#endif
-
-       return 80;
-}
-
 void add_cmdname(struct cmdnames *cmds, const char *name, size_t len)
 {
        struct cmdname *ent = malloc(sizeof(*ent) + len + 1);
@@ -96,9 +74,13 @@ static void pretty_print_string_list(struct cmdnames *cmds, int longest)
 {
        int cols = 1, rows;
        int space = longest + 1; /* min 1 SP between words */
-       int max_cols = term_columns() - 1; /* don't print *on* the edge */
+       struct winsize win;
+       int max_cols;
        int i, j;
 
+       get_term_dimensions(&win);
+       max_cols = win.ws_col - 1; /* don't print *on* the edge */
+
        if (space < max_cols)
                cols = max_cols / space;
        rows = (cmds->cnt + cols - 1) / cols;
@@ -324,7 +306,7 @@ const char *help_unknown_cmd(const char *cmd)
 
                main_cmds.names[0] = NULL;
                clean_cmdnames(&main_cmds);
-               fprintf(stderr, "WARNING: You called a Git program named '%s', "
+               fprintf(stderr, "WARNING: You called a perf program named '%s', "
                        "which does not exist.\n"
                        "Continuing under the assumption that you meant '%s'\n",
                        cmd, assumed);
index 9a71c94f057ab47536070a6b3b386e7f68bf1982..cbf7eae2ce0909326afa68cb534315df11badeae 100644 (file)
@@ -1,4 +1,5 @@
 #include "util.h"
+#include "build-id.h"
 #include "hist.h"
 #include "session.h"
 #include "sort.h"
@@ -988,22 +989,42 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head)
        struct symbol *sym = self->ms.sym;
        struct map *map = self->ms.map;
        struct dso *dso = map->dso;
-       const char *filename = dso->long_name;
+       char *filename = dso__build_id_filename(dso, NULL, 0);
+       bool free_filename = true;
        char command[PATH_MAX * 2];
        FILE *file;
+       int err = 0;
        u64 len;
 
-       if (!filename)
-               return -1;
+       if (filename == NULL) {
+               if (dso->has_build_id) {
+                       pr_err("Can't annotate %s: not enough memory\n",
+                              sym->name);
+                       return -ENOMEM;
+               }
+               goto fallback;
+       } else if (readlink(filename, command, sizeof(command)) < 0 ||
+                  strstr(command, "[kernel.kallsyms]") ||
+                  access(filename, R_OK)) {
+               free(filename);
+fallback:
+               /*
+                * If we don't have build-ids or the build-id file isn't in the
+                * cache, or is just a kallsyms file, well, lets hope that this
+                * DSO is the same as when 'perf record' ran.
+                */
+               filename = dso->long_name;
+               free_filename = false;
+       }
 
        if (dso->origin == DSO__ORIG_KERNEL) {
                if (dso->annotate_warned)
-                       return 0;
+                       goto out_free_filename;
+               err = -ENOENT;
                dso->annotate_warned = 1;
                pr_err("Can't annotate %s: No vmlinux file was found in the "
-                      "path:\n", sym->name);
-               vmlinux_path__fprintf(stderr);
-               return -1;
+                      "path\n", sym->name);
+               goto out_free_filename;
        }
 
        pr_debug("%s: filename=%s, sym=%s, start=%#Lx, end=%#Lx\n", __func__,
@@ -1025,14 +1046,17 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head)
 
        file = popen(command, "r");
        if (!file)
-               return -1;
+               goto out_free_filename;
 
        while (!feof(file))
                if (hist_entry__parse_objdump_line(self, file, head) < 0)
                        break;
 
        pclose(file);
-       return 0;
+out_free_filename:
+       if (free_filename)
+               free(filename);
+       return err;
 }
 
 void hists__inc_nr_events(struct hists *self, u32 type)
index 6f17dcd8412c6c6e0894aa4b078f7982b10cd69a..83fa33a7b38b53555b166d4b04fc3d51f98bf930 100644 (file)
@@ -98,12 +98,32 @@ void hists__filter_by_thread(struct hists *self, const struct thread *thread);
 #ifdef NO_NEWT_SUPPORT
 static inline int hists__browse(struct hists *self __used,
                                const char *helpline __used,
-                               const char *input_name __used)
+                               const char *ev_name __used)
 {
        return 0;
 }
+
+static inline int hists__tui_browse_tree(struct rb_root *self __used,
+                                        const char *help __used)
+{
+       return 0;
+}
+
+static inline int hist_entry__tui_annotate(struct hist_entry *self __used)
+{
+       return 0;
+}
+#define KEY_LEFT -1
+#define KEY_RIGHT -2
 #else
+#include <newt.h>
 int hists__browse(struct hists *self, const char *helpline,
-                 const char *input_name);
+                 const char *ev_name);
+int hist_entry__tui_annotate(struct hist_entry *self);
+
+#define KEY_LEFT NEWT_KEY_LEFT
+#define KEY_RIGHT NEWT_KEY_RIGHT
+
+int hists__tui_browse_tree(struct rb_root *self, const char *help);
 #endif
 #endif /* __PERF_HIST_H */
index ccb7c5bb269e9a1f36f930a14402559681f3d98d..d54c540f49dbd4902808aaf8b466f3a88e3606bd 100644 (file)
@@ -1,7 +1,15 @@
 #define _GNU_SOURCE
 #include <stdio.h>
 #undef _GNU_SOURCE
-
+/*
+ * slang versions <= 2.0.6 have a "#if HAVE_LONG_LONG" that breaks
+ * the build if it isn't defined. Use the equivalent one that glibc
+ * has on features.h.
+ */
+#include <features.h>
+#ifndef HAVE_LONG_LONG
+#define HAVE_LONG_LONG __GLIBC_HAVE_LONG_LONG
+#endif
 #include <slang.h>
 #include <stdlib.h>
 #include <newt.h>
@@ -227,6 +235,15 @@ static bool dialog_yesno(const char *msg)
        return newtWinChoice(NULL, yes, no, (char *)msg) == 1;
 }
 
+static void ui__error_window(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       newtWinMessagev((char *)"Error", (char *)"Ok", (char *)fmt, ap);
+       va_end(ap);
+}
+
 #define HE_COLORSET_TOP                50
 #define HE_COLORSET_MEDIUM     51
 #define HE_COLORSET_NORMAL     52
@@ -375,8 +392,11 @@ static int ui_browser__run(struct ui_browser *self, const char *title,
        newtFormAddHotKey(self->form, NEWT_KEY_DOWN);
        newtFormAddHotKey(self->form, NEWT_KEY_PGUP);
        newtFormAddHotKey(self->form, NEWT_KEY_PGDN);
+       newtFormAddHotKey(self->form, ' ');
        newtFormAddHotKey(self->form, NEWT_KEY_HOME);
        newtFormAddHotKey(self->form, NEWT_KEY_END);
+       newtFormAddHotKey(self->form, NEWT_KEY_TAB);
+       newtFormAddHotKey(self->form, NEWT_KEY_RIGHT);
 
        if (ui_browser__refresh_entries(self) < 0)
                return -1;
@@ -389,6 +409,8 @@ static int ui_browser__run(struct ui_browser *self, const char *title,
 
                if (es->reason != NEWT_EXIT_HOTKEY)
                        break;
+               if (is_exit_key(es->u.key))
+                       return es->u.key;
                switch (es->u.key) {
                case NEWT_KEY_DOWN:
                        if (self->index == self->nr_entries - 1)
@@ -411,6 +433,7 @@ static int ui_browser__run(struct ui_browser *self, const char *title,
                        }
                        break;
                case NEWT_KEY_PGDN:
+               case ' ':
                        if (self->first_visible_entry_idx + self->height > self->nr_entries - 1)
                                break;
 
@@ -461,12 +484,10 @@ static int ui_browser__run(struct ui_browser *self, const char *title,
                        }
                }
                        break;
-               case NEWT_KEY_ESCAPE:
+               case NEWT_KEY_RIGHT:
                case NEWT_KEY_LEFT:
-               case CTRL('c'):
-               case 'Q':
-               case 'q':
-                       return 0;
+               case NEWT_KEY_TAB:
+                       return es->u.key;
                default:
                        continue;
                }
@@ -658,18 +679,24 @@ static size_t hist_entry__append_browser(struct hist_entry *self,
        return ret;
 }
 
-static void hist_entry__annotate_browser(struct hist_entry *self)
+int hist_entry__tui_annotate(struct hist_entry *self)
 {
        struct ui_browser browser;
        struct newtExitStruct es;
        struct objdump_line *pos, *n;
        LIST_HEAD(head);
+       int ret;
 
        if (self->ms.sym == NULL)
-               return;
+               return -1;
 
-       if (hist_entry__annotate(self, &head) < 0)
-               return;
+       if (self->ms.map->dso->annotate_warned)
+               return -1;
+
+       if (hist_entry__annotate(self, &head) < 0) {
+               ui__error_window(browser__last_msg);
+               return -1;
+       }
 
        ui_helpline__push("Press <- or ESC to exit");
 
@@ -684,7 +711,7 @@ static void hist_entry__annotate_browser(struct hist_entry *self)
        }
 
        browser.width += 18; /* Percentage */
-       ui_browser__run(&browser, self->ms.sym->name, &es);
+       ret = ui_browser__run(&browser, self->ms.sym->name, &es);
        newtFormDestroy(browser.form);
        newtPopWindow();
        list_for_each_entry_safe(pos, n, &head, node) {
@@ -692,6 +719,7 @@ static void hist_entry__annotate_browser(struct hist_entry *self)
                objdump_line__free(pos);
        }
        ui_helpline__pop();
+       return ret;
 }
 
 static const void *newt__symbol_tree_get_current(newtComponent self)
@@ -814,6 +842,8 @@ static int hist_browser__populate(struct hist_browser *self, struct hists *hists
        newtFormAddHotKey(self->form, 'h');
        newtFormAddHotKey(self->form, NEWT_KEY_F1);
        newtFormAddHotKey(self->form, NEWT_KEY_RIGHT);
+       newtFormAddHotKey(self->form, NEWT_KEY_TAB);
+       newtFormAddHotKey(self->form, NEWT_KEY_UNTAB);
        newtFormAddComponents(self->form, self->tree, NULL);
        self->selection = newt__symbol_tree_get_current(self->tree);
 
@@ -845,7 +875,7 @@ static struct thread *hist_browser__selected_thread(struct hist_browser *self)
        return he ? he->thread : NULL;
 }
 
-static int hist_browser__title(char *bf, size_t size, const char *input_name,
+static int hist_browser__title(char *bf, size_t size, const char *ev_name,
                               const struct dso *dso, const struct thread *thread)
 {
        int printed = 0;
@@ -859,18 +889,18 @@ static int hist_browser__title(char *bf, size_t size, const char *input_name,
                printed += snprintf(bf + printed, size - printed,
                                    "%sDSO: %s", thread ? " " : "",
                                    dso->short_name);
-       return printed ?: snprintf(bf, size, "Report: %s", input_name);
+       return printed ?: snprintf(bf, size, "Event: %s", ev_name);
 }
 
-int hists__browse(struct hists *self, const char *helpline, const char *input_name)
+int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
 {
        struct hist_browser *browser = hist_browser__new();
-       struct pstack *fstack = pstack__new(2);
+       struct pstack *fstack;
        const struct thread *thread_filter = NULL;
        const struct dso *dso_filter = NULL;
        struct newtExitStruct es;
        char msg[160];
-       int err = -1;
+       int key = -1;
 
        if (browser == NULL)
                return -1;
@@ -881,7 +911,7 @@ int hists__browse(struct hists *self, const char *helpline, const char *input_na
 
        ui_helpline__push(helpline);
 
-       hist_browser__title(msg, sizeof(msg), input_name,
+       hist_browser__title(msg, sizeof(msg), ev_name,
                            dso_filter, thread_filter);
        if (hist_browser__populate(browser, self, msg) < 0)
                goto out_free_stack;
@@ -899,11 +929,27 @@ int hists__browse(struct hists *self, const char *helpline, const char *input_na
                dso = browser->selection->map ? browser->selection->map->dso : NULL;
 
                if (es.reason == NEWT_EXIT_HOTKEY) {
-                       if (es.u.key == NEWT_KEY_F1)
+                       key = es.u.key;
+
+                       switch (key) {
+                       case NEWT_KEY_F1:
                                goto do_help;
+                       case NEWT_KEY_TAB:
+                       case NEWT_KEY_UNTAB:
+                               /*
+                                * Exit the browser, let hists__browser_tree
+                                * go to the next or previous
+                                */
+                               goto out_free_stack;
+                       default:;
+                       }
 
-                       switch (toupper(es.u.key)) {
+                       key = toupper(key);
+                       switch (key) {
                        case 'A':
+                               if (browser->selection->map == NULL &&
+                                   browser->selection->map->dso->annotate_warned)
+                                       continue;
                                goto do_annotate;
                        case 'D':
                                goto zoom_dso;
@@ -922,14 +968,14 @@ do_help:
                                continue;
                        default:;
                        }
-                       if (toupper(es.u.key) == 'Q' ||
-                           es.u.key == CTRL('c'))
-                               break;
-                       if (es.u.key == NEWT_KEY_ESCAPE) {
-                               if (dialog_yesno("Do you really want to exit?"))
+                       if (is_exit_key(key)) {
+                               if (key == NEWT_KEY_ESCAPE) {
+                                       if (dialog_yesno("Do you really want to exit?"))
+                                               break;
+                                       else
+                                               continue;
+                               } else
                                        break;
-                               else
-                                       continue;
                        }
 
                        if (es.u.key == NEWT_KEY_LEFT) {
@@ -947,6 +993,7 @@ do_help:
                }
 
                if (browser->selection->sym != NULL &&
+                   !browser->selection->map->dso->annotate_warned &&
                    asprintf(&options[nr_options], "Annotate %s",
                             browser->selection->sym->name) > 0)
                        annotate = nr_options++;
@@ -981,6 +1028,7 @@ do_help:
                        struct hist_entry *he;
 do_annotate:
                        if (browser->selection->map->dso->origin == DSO__ORIG_KERNEL) {
+                               browser->selection->map->dso->annotate_warned = 1;
                                ui_helpline__puts("No vmlinux file found, can't "
                                                 "annotate with just a "
                                                 "kallsyms file");
@@ -991,7 +1039,7 @@ do_annotate:
                        if (he == NULL)
                                continue;
 
-                       hist_entry__annotate_browser(he);
+                       hist_entry__tui_annotate(he);
                } else if (choice == zoom_dso) {
 zoom_dso:
                        if (dso_filter) {
@@ -1008,7 +1056,7 @@ zoom_out_dso:
                                pstack__push(fstack, &dso_filter);
                        }
                        hists__filter_by_dso(self, dso_filter);
-                       hist_browser__title(msg, sizeof(msg), input_name,
+                       hist_browser__title(msg, sizeof(msg), ev_name,
                                            dso_filter, thread_filter);
                        if (hist_browser__populate(browser, self, msg) < 0)
                                goto out;
@@ -1027,18 +1075,49 @@ zoom_out_thread:
                                pstack__push(fstack, &thread_filter);
                        }
                        hists__filter_by_thread(self, thread_filter);
-                       hist_browser__title(msg, sizeof(msg), input_name,
+                       hist_browser__title(msg, sizeof(msg), ev_name,
                                            dso_filter, thread_filter);
                        if (hist_browser__populate(browser, self, msg) < 0)
                                goto out;
                }
        }
-       err = 0;
 out_free_stack:
        pstack__delete(fstack);
 out:
        hist_browser__delete(browser);
-       return err;
+       return key;
+}
+
+int hists__tui_browse_tree(struct rb_root *self, const char *help)
+{
+       struct rb_node *first = rb_first(self), *nd = first, *next;
+       int key = 0;
+
+       while (nd) {
+               struct hists *hists = rb_entry(nd, struct hists, rb_node);
+               const char *ev_name = __event_name(hists->type, hists->config);
+
+               key = hists__browse(hists, help, ev_name);
+
+               if (is_exit_key(key))
+                       break;
+
+               switch (key) {
+               case NEWT_KEY_TAB:
+                       next = rb_next(nd);
+                       if (next)
+                               nd = next;
+                       break;
+               case NEWT_KEY_UNTAB:
+                       if (nd == first)
+                               continue;
+                       nd = rb_prev(nd);
+               default:
+                       break;
+               }
+       }
+
+       return key;
 }
 
 static struct newtPercentTreeColors {
@@ -1058,10 +1137,13 @@ static struct newtPercentTreeColors {
 void setup_browser(void)
 {
        struct newtPercentTreeColors *c = &defaultPercentTreeColors;
-       if (!isatty(1))
+
+       if (!isatty(1) || !use_browser || dump_trace) {
+               setup_pager();
                return;
+       }
 
-       use_browser = true;
+       use_browser = 1;
        newtInit();
        newtCls();
        ui_helpline__puts(" ");
@@ -1074,7 +1156,7 @@ void setup_browser(void)
 
 void exit_browser(bool wait_for_ok)
 {
-       if (use_browser) {
+       if (use_browser > 0) {
                if (wait_for_ok) {
                        char title[] = "Fatal Error", ok[] = "Ok";
                        newtWinMessage(title, ok, browser__last_msg);
index fd1f2faaade48542581b481804fb77c739578ce0..58a470d036dd0917c16eda49fb8b1987703ca7b5 100644 (file)
@@ -54,21 +54,6 @@ static char *cleanup_path(char *path)
        return path;
 }
 
-char *mksnpath(char *buf, size_t n, const char *fmt, ...)
-{
-       va_list args;
-       unsigned len;
-
-       va_start(args, fmt);
-       len = vsnprintf(buf, n, fmt, args);
-       va_end(args);
-       if (len >= n) {
-               strlcpy(buf, bad_path, n);
-               return buf;
-       }
-       return cleanup_path(buf);
-}
-
 static char *perf_vsnpath(char *buf, size_t n, const char *fmt, va_list args)
 {
        const char *perf_dir = get_perf_dir();
@@ -89,15 +74,6 @@ bad:
        return buf;
 }
 
-char *perf_snpath(char *buf, size_t n, const char *fmt, ...)
-{
-       va_list args;
-       va_start(args, fmt);
-       (void)perf_vsnpath(buf, n, fmt, args);
-       va_end(args);
-       return buf;
-}
-
 char *perf_pathdup(const char *fmt, ...)
 {
        char path[PATH_MAX];
@@ -143,184 +119,6 @@ char *perf_path(const char *fmt, ...)
        return cleanup_path(pathname);
 }
 
-
-/* perf_mkstemp() - create tmp file honoring TMPDIR variable */
-int perf_mkstemp(char *path, size_t len, const char *template)
-{
-       const char *tmp;
-       size_t n;
-
-       tmp = getenv("TMPDIR");
-       if (!tmp)
-               tmp = "/tmp";
-       n = snprintf(path, len, "%s/%s", tmp, template);
-       if (len <= n) {
-               errno = ENAMETOOLONG;
-               return -1;
-       }
-       return mkstemp(path);
-}
-
-
-const char *make_relative_path(const char *abs_path, const char *base)
-{
-       static char buf[PATH_MAX + 1];
-       int baselen;
-
-       if (!base)
-               return abs_path;
-
-       baselen = strlen(base);
-       if (prefixcmp(abs_path, base))
-               return abs_path;
-       if (abs_path[baselen] == '/')
-               baselen++;
-       else if (base[baselen - 1] != '/')
-               return abs_path;
-
-       strcpy(buf, abs_path + baselen);
-
-       return buf;
-}
-
-/*
- * It is okay if dst == src, but they should not overlap otherwise.
- *
- * Performs the following normalizations on src, storing the result in dst:
- * - Ensures that components are separated by '/' (Windows only)
- * - Squashes sequences of '/'.
- * - Removes "." components.
- * - Removes ".." components, and the components the precede them.
- * Returns failure (non-zero) if a ".." component appears as first path
- * component anytime during the normalization. Otherwise, returns success (0).
- *
- * Note that this function is purely textual.  It does not follow symlinks,
- * verify the existence of the path, or make any system calls.
- */
-int normalize_path_copy(char *dst, const char *src)
-{
-       char *dst0;
-
-       if (has_dos_drive_prefix(src)) {
-               *dst++ = *src++;
-               *dst++ = *src++;
-       }
-       dst0 = dst;
-
-       if (is_dir_sep(*src)) {
-               *dst++ = '/';
-               while (is_dir_sep(*src))
-                       src++;
-       }
-
-       for (;;) {
-               char c = *src;
-
-               /*
-                * A path component that begins with . could be
-                * special:
-                * (1) "." and ends   -- ignore and terminate.
-                * (2) "./"           -- ignore them, eat slash and continue.
-                * (3) ".." and ends  -- strip one and terminate.
-                * (4) "../"          -- strip one, eat slash and continue.
-                */
-               if (c == '.') {
-                       if (!src[1]) {
-                               /* (1) */
-                               src++;
-                       } else if (is_dir_sep(src[1])) {
-                               /* (2) */
-                               src += 2;
-                               while (is_dir_sep(*src))
-                                       src++;
-                               continue;
-                       } else if (src[1] == '.') {
-                               if (!src[2]) {
-                                       /* (3) */
-                                       src += 2;
-                                       goto up_one;
-                               } else if (is_dir_sep(src[2])) {
-                                       /* (4) */
-                                       src += 3;
-                                       while (is_dir_sep(*src))
-                                               src++;
-                                       goto up_one;
-                               }
-                       }
-               }
-
-               /* copy up to the next '/', and eat all '/' */
-               while ((c = *src++) != '\0' && !is_dir_sep(c))
-                       *dst++ = c;
-               if (is_dir_sep(c)) {
-                       *dst++ = '/';
-                       while (is_dir_sep(c))
-                               c = *src++;
-                       src--;
-               } else if (!c)
-                       break;
-               continue;
-
-       up_one:
-               /*
-                * dst0..dst is prefix portion, and dst[-1] is '/';
-                * go up one level.
-                */
-               dst--;  /* go to trailing '/' */
-               if (dst <= dst0)
-                       return -1;
-               /* Windows: dst[-1] cannot be backslash anymore */
-               while (dst0 < dst && dst[-1] != '/')
-                       dst--;
-       }
-       *dst = '\0';
-       return 0;
-}
-
-/*
- * path = Canonical absolute path
- * prefix_list = Colon-separated list of absolute paths
- *
- * Determines, for each path in prefix_list, whether the "prefix" really
- * is an ancestor directory of path.  Returns the length of the longest
- * ancestor directory, excluding any trailing slashes, or -1 if no prefix
- * is an ancestor.  (Note that this means 0 is returned if prefix_list is
- * "/".) "/foo" is not considered an ancestor of "/foobar".  Directories
- * are not considered to be their own ancestors.  path must be in a
- * canonical form: empty components, or "." or ".." components are not
- * allowed.  prefix_list may be null, which is like "".
- */
-int longest_ancestor_length(const char *path, const char *prefix_list)
-{
-       char buf[PATH_MAX+1];
-       const char *ceil, *colon;
-       int len, max_len = -1;
-
-       if (prefix_list == NULL || !strcmp(path, "/"))
-               return -1;
-
-       for (colon = ceil = prefix_list; *colon; ceil = colon+1) {
-               for (colon = ceil; *colon && *colon != PATH_SEP; colon++);
-               len = colon - ceil;
-               if (len == 0 || len > PATH_MAX || !is_absolute_path(ceil))
-                       continue;
-               strlcpy(buf, ceil, len+1);
-               if (normalize_path_copy(buf, buf) < 0)
-                       continue;
-               len = strlen(buf);
-               if (len > 0 && buf[len-1] == '/')
-                       buf[--len] = '\0';
-
-               if (!strncmp(path, buf, len) &&
-                   path[len] == '/' &&
-                   len > max_len) {
-                       max_len = len;
-               }
-       }
-
-       return max_len;
-}
-
 /* strip arbitrary amount of directory separators at end of path */
 static inline int chomp_trailing_dir_sep(const char *path, int len)
 {
@@ -354,5 +152,5 @@ char *strip_path_suffix(const char *path, const char *suffix)
 
        if (path_len && !is_dir_sep(path[path_len - 1]))
                return NULL;
-       return xstrndup(path, chomp_trailing_dir_sep(path, path_len));
+       return strndup(path, chomp_trailing_dir_sep(path, path_len));
 }
index 562b1443e785358c7c72a2fd55df0e76332a7d96..d964cb199c672f96712c4125ba036b7bfe038687 100644 (file)
@@ -668,6 +668,7 @@ static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
        ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1);
        if (ret <= 0 || nops == 0) {
                pf->fb_ops = NULL;
+#if _ELFUTILS_PREREQ(0, 142)
        } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa &&
                   pf->cfi != NULL) {
                Dwarf_Frame *frame;
@@ -677,6 +678,7 @@ static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
                                   (uintmax_t)pf->addr);
                        return -ENOENT;
                }
+#endif
        }
 
        /* Find each argument */
@@ -741,32 +743,36 @@ static int find_lazy_match_lines(struct list_head *head,
                                 const char *fname, const char *pat)
 {
        char *fbuf, *p1, *p2;
-       int fd, ret, line, nlines = 0;
+       int fd, line, nlines = -1;
        struct stat st;
 
        fd = open(fname, O_RDONLY);
        if (fd < 0) {
                pr_warning("Failed to open %s: %s\n", fname, strerror(-fd));
-               return fd;
+               return -errno;
        }
 
-       ret = fstat(fd, &st);
-       if (ret < 0) {
+       if (fstat(fd, &st) < 0) {
                pr_warning("Failed to get the size of %s: %s\n",
                           fname, strerror(errno));
-               return ret;
+               nlines = -errno;
+               goto out_close;
        }
-       fbuf = xmalloc(st.st_size + 2);
-       ret = read(fd, fbuf, st.st_size);
-       if (ret < 0) {
+
+       nlines = -ENOMEM;
+       fbuf = malloc(st.st_size + 2);
+       if (fbuf == NULL)
+               goto out_close;
+       if (read(fd, fbuf, st.st_size) < 0) {
                pr_warning("Failed to read %s: %s\n", fname, strerror(errno));
-               return ret;
+               nlines = -errno;
+               goto out_free_fbuf;
        }
-       close(fd);
        fbuf[st.st_size] = '\n';        /* Dummy line */
        fbuf[st.st_size + 1] = '\0';
        p1 = fbuf;
        line = 1;
+       nlines = 0;
        while ((p2 = strchr(p1, '\n')) != NULL) {
                *p2 = '\0';
                if (strlazymatch(p1, pat)) {
@@ -776,7 +782,10 @@ static int find_lazy_match_lines(struct list_head *head,
                line++;
                p1 = p2 + 1;
        }
+out_free_fbuf:
        free(fbuf);
+out_close:
+       close(fd);
        return nlines;
 }
 
@@ -953,11 +962,15 @@ int find_kprobe_trace_events(int fd, struct perf_probe_event *pev,
        if (!dbg) {
                pr_warning("No dwarf info found in the vmlinux - "
                        "please rebuild with CONFIG_DEBUG_INFO=y.\n");
+               free(pf.tevs);
+               *tevs = NULL;
                return -EBADF;
        }
 
+#if _ELFUTILS_PREREQ(0, 142)
        /* Get the call frame information from this dwarf */
        pf.cfi = dwarf_getcfi(dbg);
+#endif
 
        off = 0;
        line_list__init(&pf.lcache);
index 66f1980e3855477c86602485e43803b98b0032a8..e1f61dcd18ff7ed18bff7a337ddcdf0dc8c68e36 100644 (file)
@@ -29,6 +29,7 @@ extern int find_line_range(int fd, struct line_range *lr);
 
 #include <dwarf.h>
 #include <libdw.h>
+#include <version.h>
 
 struct probe_finder {
        struct perf_probe_event *pev;           /* Target probe event */
@@ -44,7 +45,9 @@ struct probe_finder {
        struct list_head        lcache;         /* Line cache for lazy match */
 
        /* For variable searching */
+#if _ELFUTILS_PREREQ(0, 142)
        Dwarf_CFI               *cfi;           /* Call Frame Information */
+#endif
        Dwarf_Op                *fb_ops;        /* Frame base attribute */
        struct perf_probe_arg   *pvar;          /* Current target variable */
        struct kprobe_trace_arg *tvar;          /* Current result variable */
index 2726fe40eb5dd2483d16ab3064caa91eea92c62e..01f03242b86a17575f332a252c3135df360820a5 100644 (file)
@@ -1,8 +1,6 @@
 #include "cache.h"
 #include "quote.h"
 
-int quote_path_fully = 1;
-
 /* Help to copy the thing properly quoted for the shell safety.
  * any single quote is replaced with '\'', any exclamation point
  * is replaced with '\!', and the whole thing is enclosed in a
@@ -19,7 +17,7 @@ static inline int need_bs_quote(char c)
        return (c == '\'' || c == '!');
 }
 
-void sq_quote_buf(struct strbuf *dst, const char *src)
+static void sq_quote_buf(struct strbuf *dst, const char *src)
 {
        char *to_free = NULL;
 
@@ -41,23 +39,6 @@ void sq_quote_buf(struct strbuf *dst, const char *src)
        free(to_free);
 }
 
-void sq_quote_print(FILE *stream, const char *src)
-{
-       char c;
-
-       fputc('\'', stream);
-       while ((c = *src++)) {
-               if (need_bs_quote(c)) {
-                       fputs("'\\", stream);
-                       fputc(c, stream);
-                       fputc('\'', stream);
-               } else {
-                       fputc(c, stream);
-               }
-       }
-       fputc('\'', stream);
-}
-
 void sq_quote_argv(struct strbuf *dst, const char** argv, size_t maxlen)
 {
        int i;
@@ -71,415 +52,3 @@ void sq_quote_argv(struct strbuf *dst, const char** argv, size_t maxlen)
                        die("Too many or long arguments");
        }
 }
-
-char *sq_dequote_step(char *arg, char **next)
-{
-       char *dst = arg;
-       char *src = arg;
-       char c;
-
-       if (*src != '\'')
-               return NULL;
-       for (;;) {
-               c = *++src;
-               if (!c)
-                       return NULL;
-               if (c != '\'') {
-                       *dst++ = c;
-                       continue;
-               }
-               /* We stepped out of sq */
-               switch (*++src) {
-               case '\0':
-                       *dst = 0;
-                       if (next)
-                               *next = NULL;
-                       return arg;
-               case '\\':
-                       c = *++src;
-                       if (need_bs_quote(c) && *++src == '\'') {
-                               *dst++ = c;
-                               continue;
-                       }
-               /* Fallthrough */
-               default:
-                       if (!next || !isspace(*src))
-                               return NULL;
-                       do {
-                               c = *++src;
-                       } while (isspace(c));
-                       *dst = 0;
-                       *next = src;
-                       return arg;
-               }
-       }
-}
-
-char *sq_dequote(char *arg)
-{
-       return sq_dequote_step(arg, NULL);
-}
-
-int sq_dequote_to_argv(char *arg, const char ***argv, int *nr, int *alloc)
-{
-       char *next = arg;
-
-       if (!*arg)
-               return 0;
-       do {
-               char *dequoted = sq_dequote_step(next, &next);
-               if (!dequoted)
-                       return -1;
-               ALLOC_GROW(*argv, *nr + 1, *alloc);
-               (*argv)[(*nr)++] = dequoted;
-       } while (next);
-
-       return 0;
-}
-
-/* 1 means: quote as octal
- * 0 means: quote as octal if (quote_path_fully)
- * -1 means: never quote
- * c: quote as "\\c"
- */
-#define X8(x)   x, x, x, x, x, x, x, x
-#define X16(x)  X8(x), X8(x)
-static signed char const sq_lookup[256] = {
-       /*           0    1    2    3    4    5    6    7 */
-       /* 0x00 */   1,   1,   1,   1,   1,   1,   1, 'a',
-       /* 0x08 */ 'b', 't', 'n', 'v', 'f', 'r',   1,   1,
-       /* 0x10 */ X16(1),
-       /* 0x20 */  -1,  -1, '"',  -1,  -1,  -1,  -1,  -1,
-       /* 0x28 */ X16(-1), X16(-1), X16(-1),
-       /* 0x58 */  -1,  -1,  -1,  -1,'\\',  -1,  -1,  -1,
-       /* 0x60 */ X16(-1), X8(-1),
-       /* 0x78 */  -1,  -1,  -1,  -1,  -1,  -1,  -1,   1,
-       /* 0x80 */ /* set to 0 */
-};
-
-static inline int sq_must_quote(char c)
-{
-       return sq_lookup[(unsigned char)c] + quote_path_fully > 0;
-}
-
-/*
- * Returns the longest prefix not needing a quote up to maxlen if
- * positive.
- * This stops at the first \0 because it's marked as a character
- * needing an escape.
- */
-static ssize_t next_quote_pos(const char *s, ssize_t maxlen)
-{
-       ssize_t len;
-
-       if (maxlen < 0) {
-               for (len = 0; !sq_must_quote(s[len]); len++);
-       } else {
-               for (len = 0; len < maxlen && !sq_must_quote(s[len]); len++);
-       }
-       return len;
-}
-
-/*
- * C-style name quoting.
- *
- * (1) if sb and fp are both NULL, inspect the input name and counts the
- *     number of bytes that are needed to hold c_style quoted version of name,
- *     counting the double quotes around it but not terminating NUL, and
- *     returns it.
- *     However, if name does not need c_style quoting, it returns 0.
- *
- * (2) if sb or fp are not NULL, it emits the c_style quoted version
- *     of name, enclosed with double quotes if asked and needed only.
- *     Return value is the same as in (1).
- */
-static size_t quote_c_style_counted(const char *name, ssize_t maxlen,
-                                    struct strbuf *sb, FILE *fp, int no_dq)
-{
-#define EMIT(c)                                                        \
-       do {                                                    \
-               if (sb) strbuf_addch(sb, (c));                  \
-               if (fp) fputc((c), fp);                         \
-               count++;                                        \
-       } while (0)
-
-#define EMITBUF(s, l)                                          \
-       do {                                                    \
-               int __ret;                                      \
-               if (sb) strbuf_add(sb, (s), (l));               \
-               if (fp) __ret = fwrite((s), (l), 1, fp);        \
-               count += (l);                                   \
-       } while (0)
-
-       ssize_t len, count = 0;
-       const char *p = name;
-
-       for (;;) {
-               int ch;
-
-               len = next_quote_pos(p, maxlen);
-               if (len == maxlen || !p[len])
-                       break;
-
-               if (!no_dq && p == name)
-                       EMIT('"');
-
-               EMITBUF(p, len);
-               EMIT('\\');
-               p += len;
-               ch = (unsigned char)*p++;
-               if (sq_lookup[ch] >= ' ') {
-                       EMIT(sq_lookup[ch]);
-               } else {
-                       EMIT(((ch >> 6) & 03) + '0');
-                       EMIT(((ch >> 3) & 07) + '0');
-                       EMIT(((ch >> 0) & 07) + '0');
-               }
-       }
-
-       EMITBUF(p, len);
-       if (p == name)   /* no ending quote needed */
-               return 0;
-
-       if (!no_dq)
-               EMIT('"');
-       return count;
-}
-
-size_t quote_c_style(const char *name, struct strbuf *sb, FILE *fp, int nodq)
-{
-       return quote_c_style_counted(name, -1, sb, fp, nodq);
-}
-
-void quote_two_c_style(struct strbuf *sb, const char *prefix, const char *path, int nodq)
-{
-       if (quote_c_style(prefix, NULL, NULL, 0) ||
-           quote_c_style(path, NULL, NULL, 0)) {
-               if (!nodq)
-                       strbuf_addch(sb, '"');
-               quote_c_style(prefix, sb, NULL, 1);
-               quote_c_style(path, sb, NULL, 1);
-               if (!nodq)
-                       strbuf_addch(sb, '"');
-       } else {
-               strbuf_addstr(sb, prefix);
-               strbuf_addstr(sb, path);
-       }
-}
-
-void write_name_quoted(const char *name, FILE *fp, int terminator)
-{
-       if (terminator) {
-               quote_c_style(name, NULL, fp, 0);
-       } else {
-               fputs(name, fp);
-       }
-       fputc(terminator, fp);
-}
-
-void write_name_quotedpfx(const char *pfx, ssize_t pfxlen,
-                         const char *name, FILE *fp, int terminator)
-{
-       int needquote = 0;
-
-       if (terminator) {
-               needquote = next_quote_pos(pfx, pfxlen) < pfxlen
-                       || name[next_quote_pos(name, -1)];
-       }
-       if (needquote) {
-               fputc('"', fp);
-               quote_c_style_counted(pfx, pfxlen, NULL, fp, 1);
-               quote_c_style(name, NULL, fp, 1);
-               fputc('"', fp);
-       } else {
-               int ret;
-
-               ret = fwrite(pfx, pfxlen, 1, fp);
-               fputs(name, fp);
-       }
-       fputc(terminator, fp);
-}
-
-/* quote path as relative to the given prefix */
-char *quote_path_relative(const char *in, int len,
-                         struct strbuf *out, const char *prefix)
-{
-       int needquote;
-
-       if (len < 0)
-               len = strlen(in);
-
-       /* "../" prefix itself does not need quoting, but "in" might. */
-       needquote = (next_quote_pos(in, len) < len);
-       strbuf_setlen(out, 0);
-       strbuf_grow(out, len);
-
-       if (needquote)
-               strbuf_addch(out, '"');
-       if (prefix) {
-               int off = 0;
-               while (off < len && prefix[off] && prefix[off] == in[off])
-                       if (prefix[off] == '/') {
-                               prefix += off + 1;
-                               in += off + 1;
-                               len -= off + 1;
-                               off = 0;
-                       } else
-                               off++;
-
-               for (; *prefix; prefix++)
-                       if (*prefix == '/')
-                               strbuf_addstr(out, "../");
-       }
-
-       quote_c_style_counted (in, len, out, NULL, 1);
-
-       if (needquote)
-               strbuf_addch(out, '"');
-       if (!out->len)
-               strbuf_addstr(out, "./");
-
-       return out->buf;
-}
-
-/*
- * C-style name unquoting.
- *
- * Quoted should point at the opening double quote.
- * + Returns 0 if it was able to unquote the string properly, and appends the
- *   result in the strbuf `sb'.
- * + Returns -1 in case of error, and doesn't touch the strbuf. Though note
- *   that this function will allocate memory in the strbuf, so calling
- *   strbuf_release is mandatory whichever result unquote_c_style returns.
- *
- * Updates endp pointer to point at one past the ending double quote if given.
- */
-int unquote_c_style(struct strbuf *sb, const char *quoted, const char **endp)
-{
-       size_t oldlen = sb->len, len;
-       int ch, ac;
-
-       if (*quoted++ != '"')
-               return -1;
-
-       for (;;) {
-               len = strcspn(quoted, "\"\\");
-               strbuf_add(sb, quoted, len);
-               quoted += len;
-
-               switch (*quoted++) {
-                 case '"':
-                       if (endp)
-                               *endp = quoted;
-                       return 0;
-                 case '\\':
-                       break;
-                 default:
-                       goto error;
-               }
-
-               switch ((ch = *quoted++)) {
-               case 'a': ch = '\a'; break;
-               case 'b': ch = '\b'; break;
-               case 'f': ch = '\f'; break;
-               case 'n': ch = '\n'; break;
-               case 'r': ch = '\r'; break;
-               case 't': ch = '\t'; break;
-               case 'v': ch = '\v'; break;
-
-               case '\\': case '"':
-                       break; /* verbatim */
-
-               /* octal values with first digit over 4 overflow */
-               case '0': case '1': case '2': case '3':
-                                       ac = ((ch - '0') << 6);
-                       if ((ch = *quoted++) < '0' || '7' < ch)
-                               goto error;
-                                       ac |= ((ch - '0') << 3);
-                       if ((ch = *quoted++) < '0' || '7' < ch)
-                               goto error;
-                                       ac |= (ch - '0');
-                                       ch = ac;
-                                       break;
-                               default:
-                       goto error;
-                       }
-               strbuf_addch(sb, ch);
-               }
-
-  error:
-       strbuf_setlen(sb, oldlen);
-       return -1;
-}
-
-/* quoting as a string literal for other languages */
-
-void perl_quote_print(FILE *stream, const char *src)
-{
-       const char sq = '\'';
-       const char bq = '\\';
-       char c;
-
-       fputc(sq, stream);
-       while ((c = *src++)) {
-               if (c == sq || c == bq)
-                       fputc(bq, stream);
-               fputc(c, stream);
-       }
-       fputc(sq, stream);
-}
-
-void python_quote_print(FILE *stream, const char *src)
-{
-       const char sq = '\'';
-       const char bq = '\\';
-       const char nl = '\n';
-       char c;
-
-       fputc(sq, stream);
-       while ((c = *src++)) {
-               if (c == nl) {
-                       fputc(bq, stream);
-                       fputc('n', stream);
-                       continue;
-               }
-               if (c == sq || c == bq)
-                       fputc(bq, stream);
-               fputc(c, stream);
-       }
-       fputc(sq, stream);
-}
-
-void tcl_quote_print(FILE *stream, const char *src)
-{
-       char c;
-
-       fputc('"', stream);
-       while ((c = *src++)) {
-               switch (c) {
-               case '[': case ']':
-               case '{': case '}':
-               case '$': case '\\': case '"':
-                       fputc('\\', stream);
-               default:
-                       fputc(c, stream);
-                       break;
-               case '\f':
-                       fputs("\\f", stream);
-                       break;
-               case '\r':
-                       fputs("\\r", stream);
-                       break;
-               case '\n':
-                       fputs("\\n", stream);
-                       break;
-               case '\t':
-                       fputs("\\t", stream);
-                       break;
-               case '\v':
-                       fputs("\\v", stream);
-                       break;
-               }
-       }
-       fputc('"', stream);
-}
index b6a01973391975193a8d1ef1903674e2dc409016..172889ea234fb7e299a5cd50bba200345b06a5db 100644 (file)
  *
  * Note that the above examples leak memory!  Remember to free result from
  * sq_quote() in a real application.
- *
- * sq_quote_buf() writes to an existing buffer of specified size; it
- * will return the number of characters that would have been written
- * excluding the final null regardless of the buffer size.
  */
 
-extern void sq_quote_print(FILE *stream, const char *src);
-
-extern void sq_quote_buf(struct strbuf *, const char *src);
 extern void sq_quote_argv(struct strbuf *, const char **argv, size_t maxlen);
 
-/* This unwraps what sq_quote() produces in place, but returns
- * NULL if the input does not look like what sq_quote would have
- * produced.
- */
-extern char *sq_dequote(char *);
-
-/*
- * Same as the above, but can be used to unwrap many arguments in the
- * same string separated by space. "next" is changed to point to the
- * next argument that should be passed as first parameter. When there
- * is no more argument to be dequoted, "next" is updated to point to NULL.
- */
-extern char *sq_dequote_step(char *arg, char **next);
-extern int sq_dequote_to_argv(char *arg, const char ***argv, int *nr, int *alloc);
-
-extern int unquote_c_style(struct strbuf *, const char *quoted, const char **endp);
-extern size_t quote_c_style(const char *name, struct strbuf *, FILE *, int no_dq);
-extern void quote_two_c_style(struct strbuf *, const char *, const char *, int);
-
-extern void write_name_quoted(const char *name, FILE *, int terminator);
-extern void write_name_quotedpfx(const char *pfx, ssize_t pfxlen,
-                                 const char *name, FILE *, int terminator);
-
-/* quote path as relative to the given prefix */
-char *quote_path_relative(const char *in, int len,
-                         struct strbuf *out, const char *prefix);
-
-/* quoting as a string literal for other languages */
-extern void perl_quote_print(FILE *stream, const char *src);
-extern void python_quote_print(FILE *stream, const char *src);
-extern void tcl_quote_print(FILE *stream, const char *src);
-
 #endif /* __PERF_QUOTE_H */
index 2b615acf94d7bc69dff1af8ab6439e7c5f93b86b..da8e9b285f5158d24d67d9722265187504bd95d5 100644 (file)
@@ -212,93 +212,3 @@ int run_command_v_opt(const char **argv, int opt)
        prepare_run_command_v_opt(&cmd, argv, opt);
        return run_command(&cmd);
 }
-
-int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const char *const *env)
-{
-       struct child_process cmd;
-       prepare_run_command_v_opt(&cmd, argv, opt);
-       cmd.dir = dir;
-       cmd.env = env;
-       return run_command(&cmd);
-}
-
-int start_async(struct async *async)
-{
-       int pipe_out[2];
-
-       if (pipe(pipe_out) < 0)
-               return error("cannot create pipe: %s", strerror(errno));
-       async->out = pipe_out[0];
-
-       /* Flush stdio before fork() to avoid cloning buffers */
-       fflush(NULL);
-
-       async->pid = fork();
-       if (async->pid < 0) {
-               error("fork (async) failed: %s", strerror(errno));
-               close_pair(pipe_out);
-               return -1;
-       }
-       if (!async->pid) {
-               close(pipe_out[0]);
-               exit(!!async->proc(pipe_out[1], async->data));
-       }
-       close(pipe_out[1]);
-
-       return 0;
-}
-
-int finish_async(struct async *async)
-{
-       int ret = 0;
-
-       if (wait_or_whine(async->pid))
-               ret = error("waitpid (async) failed");
-
-       return ret;
-}
-
-int run_hook(const char *index_file, const char *name, ...)
-{
-       struct child_process hook;
-       const char **argv = NULL, *env[2];
-       char idx[PATH_MAX];
-       va_list args;
-       int ret;
-       size_t i = 0, alloc = 0;
-
-       if (access(perf_path("hooks/%s", name), X_OK) < 0)
-               return 0;
-
-       va_start(args, name);
-       ALLOC_GROW(argv, i + 1, alloc);
-       argv[i++] = perf_path("hooks/%s", name);
-       while (argv[i-1]) {
-               ALLOC_GROW(argv, i + 1, alloc);
-               argv[i++] = va_arg(args, const char *);
-       }
-       va_end(args);
-
-       memset(&hook, 0, sizeof(hook));
-       hook.argv = argv;
-       hook.no_stdin = 1;
-       hook.stdout_to_stderr = 1;
-       if (index_file) {
-               snprintf(idx, sizeof(idx), "PERF_INDEX_FILE=%s", index_file);
-               env[0] = idx;
-               env[1] = NULL;
-               hook.env = env;
-       }
-
-       ret = start_command(&hook);
-       free(argv);
-       if (ret) {
-               warning("Could not spawn %s", argv[0]);
-               return ret;
-       }
-       ret = finish_command(&hook);
-       if (ret == -ERR_RUN_COMMAND_WAITPID_SIGNAL)
-               warning("%s exited due to uncaught signal", argv[0]);
-
-       return ret;
-}
index d79028727ce2c5dfba2317f71c67dcfa7f4f72bf..1ef264d5069c76490e309c082438ca3477111978 100644 (file)
@@ -50,39 +50,9 @@ int start_command(struct child_process *);
 int finish_command(struct child_process *);
 int run_command(struct child_process *);
 
-extern int run_hook(const char *index_file, const char *name, ...);
-
 #define RUN_COMMAND_NO_STDIN 1
 #define RUN_PERF_CMD        2  /*If this is to be perf sub-command */
 #define RUN_COMMAND_STDOUT_TO_STDERR 4
 int run_command_v_opt(const char **argv, int opt);
 
-/*
- * env (the environment) is to be formatted like environ: "VAR=VALUE".
- * To unset an environment variable use just "VAR".
- */
-int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const char *const *env);
-
-/*
- * The purpose of the following functions is to feed a pipe by running
- * a function asynchronously and providing output that the caller reads.
- *
- * It is expected that no synchronization and mutual exclusion between
- * the caller and the feed function is necessary so that the function
- * can run in a thread without interfering with the caller.
- */
-struct async {
-       /*
-        * proc writes to fd and closes it;
-        * returns 0 on success, non-zero on failure
-        */
-       int (*proc)(int fd, void *data);
-       void *data;
-       int out;        /* caller reads from here and closes it */
-       pid_t pid;
-};
-
-int start_async(struct async *async);
-int finish_async(struct async *async);
-
 #endif /* __PERF_RUN_COMMAND_H */
index 25bfca4f10f0ff98a2ef06d90f1362424547e8d3..8f83a1835766e5d1a6e509547d14559529bbba23 100644 (file)
@@ -5,6 +5,7 @@
 #include <byteswap.h>
 #include <unistd.h>
 #include <sys/types.h>
+#include <sys/mman.h>
 
 #include "session.h"
 #include "sort.h"
@@ -894,3 +895,10 @@ size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp)
               __dsos__fprintf(&self->host_machine.user_dsos, fp) +
               machines__fprintf_dsos(&self->machines, fp);
 }
+
+size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp,
+                                         bool with_hits)
+{
+       size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, with_hits);
+       return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits);
+}
index e7fce486ebe23a299d0a3b5a5240de0795a99ebc..55c6881b218d4ccee588877d54afb41120dba521 100644 (file)
@@ -132,12 +132,8 @@ void perf_session__process_machines(struct perf_session *self,
 
 size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp);
 
-static inline
-size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp,
-                                         bool with_hits)
-{
-       return machines__fprintf_dsos_buildid(&self->machines, fp, with_hits);
-}
+size_t perf_session__fprintf_dsos_buildid(struct perf_session *self,
+                                         FILE *fp, bool with_hits);
 
 static inline
 size_t perf_session__fprintf_nr_events(struct perf_session *self, FILE *fp)
index 1118b99e57d3308f333c56f487329a8fef75a7df..ba785e9b18410d0c848c94cfbc1a32a11f9be75b 100644 (file)
@@ -16,7 +16,7 @@ static void check_signum(int sig)
                die("BUG: signal out of range: %d", sig);
 }
 
-int sigchain_push(int sig, sigchain_fun f)
+static int sigchain_push(int sig, sigchain_fun f)
 {
        struct sigchain_signal *s = signals + sig;
        check_signum(sig);
index 1a53c11265fdda78357112f3c3e7bd72a936afe8..959d64eb5557fe69ef13a1b1d2adb7402bc7d807 100644 (file)
@@ -3,7 +3,6 @@
 
 typedef void (*sigchain_fun)(int);
 
-int sigchain_push(int sig, sigchain_fun f);
 int sigchain_pop(int sig);
 
 void sigchain_push_common(sigchain_fun f);
index 5249d5a1b0c203176b08fce72003ea90ce114e74..92e068517c1aa0a83dbc4e227ed0d544d0336b44 100644 (file)
@@ -41,16 +41,6 @@ char *strbuf_detach(struct strbuf *sb, size_t *sz)
        return res;
 }
 
-void strbuf_attach(struct strbuf *sb, void *buf, size_t len, size_t alloc)
-{
-       strbuf_release(sb);
-       sb->buf   = buf;
-       sb->len   = len;
-       sb->alloc = alloc;
-       strbuf_grow(sb, 0);
-       sb->buf[sb->len] = '\0';
-}
-
 void strbuf_grow(struct strbuf *sb, size_t extra)
 {
        if (sb->len + extra + 1 <= sb->len)
@@ -60,94 +50,7 @@ void strbuf_grow(struct strbuf *sb, size_t extra)
        ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);
 }
 
-void strbuf_trim(struct strbuf *sb)
-{
-       char *b = sb->buf;
-       while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1]))
-               sb->len--;
-       while (sb->len > 0 && isspace(*b)) {
-               b++;
-               sb->len--;
-       }
-       memmove(sb->buf, b, sb->len);
-       sb->buf[sb->len] = '\0';
-}
-void strbuf_rtrim(struct strbuf *sb)
-{
-       while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1]))
-               sb->len--;
-       sb->buf[sb->len] = '\0';
-}
-
-void strbuf_ltrim(struct strbuf *sb)
-{
-       char *b = sb->buf;
-       while (sb->len > 0 && isspace(*b)) {
-               b++;
-               sb->len--;
-       }
-       memmove(sb->buf, b, sb->len);
-       sb->buf[sb->len] = '\0';
-}
-
-void strbuf_tolower(struct strbuf *sb)
-{
-       unsigned int i;
-
-       for (i = 0; i < sb->len; i++)
-               sb->buf[i] = tolower(sb->buf[i]);
-}
-
-struct strbuf **strbuf_split(const struct strbuf *sb, int delim)
-{
-       int alloc = 2, pos = 0;
-       char *n, *p;
-       struct strbuf **ret;
-       struct strbuf *t;
-
-       ret = calloc(alloc, sizeof(struct strbuf *));
-       p = n = sb->buf;
-       while (n < sb->buf + sb->len) {
-               int len;
-               n = memchr(n, delim, sb->len - (n - sb->buf));
-               if (pos + 1 >= alloc) {
-                       alloc = alloc * 2;
-                       ret = realloc(ret, sizeof(struct strbuf *) * alloc);
-               }
-               if (!n)
-                       n = sb->buf + sb->len - 1;
-               len = n - p + 1;
-               t = malloc(sizeof(struct strbuf));
-               strbuf_init(t, len);
-               strbuf_add(t, p, len);
-               ret[pos] = t;
-               ret[++pos] = NULL;
-               p = ++n;
-       }
-       return ret;
-}
-
-void strbuf_list_free(struct strbuf **sbs)
-{
-       struct strbuf **s = sbs;
-
-       while (*s) {
-               strbuf_release(*s);
-               free(*s++);
-       }
-       free(sbs);
-}
-
-int strbuf_cmp(const struct strbuf *a, const struct strbuf *b)
-{
-       int len = a->len < b->len ? a->len: b->len;
-       int cmp = memcmp(a->buf, b->buf, len);
-       if (cmp)
-               return cmp;
-       return a->len < b->len ? -1: a->len != b->len;
-}
-
-void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
+static void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
                                   const void *data, size_t dlen)
 {
        if (pos + len < pos)
@@ -166,11 +69,6 @@ void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
        strbuf_setlen(sb, sb->len + dlen - len);
 }
 
-void strbuf_insert(struct strbuf *sb, size_t pos, const void *data, size_t len)
-{
-       strbuf_splice(sb, pos, 0, data, len);
-}
-
 void strbuf_remove(struct strbuf *sb, size_t pos, size_t len)
 {
        strbuf_splice(sb, pos, len, NULL, 0);
@@ -183,13 +81,6 @@ void strbuf_add(struct strbuf *sb, const void *data, size_t len)
        strbuf_setlen(sb, sb->len + len);
 }
 
-void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len)
-{
-       strbuf_grow(sb, len);
-       memcpy(sb->buf + sb->len, sb->buf + pos, len);
-       strbuf_setlen(sb, sb->len + len);
-}
-
 void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
 {
        int len;
@@ -214,57 +105,6 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
        strbuf_setlen(sb, sb->len + len);
 }
 
-void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn,
-                  void *context)
-{
-       for (;;) {
-               const char *percent;
-               size_t consumed;
-
-               percent = strchrnul(format, '%');
-               strbuf_add(sb, format, percent - format);
-               if (!*percent)
-                       break;
-               format = percent + 1;
-
-               consumed = fn(sb, format, context);
-               if (consumed)
-                       format += consumed;
-               else
-                       strbuf_addch(sb, '%');
-       }
-}
-
-size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder,
-               void *context)
-{
-       struct strbuf_expand_dict_entry *e = context;
-       size_t len;
-
-       for (; e->placeholder && (len = strlen(e->placeholder)); e++) {
-               if (!strncmp(placeholder, e->placeholder, len)) {
-                       if (e->value)
-                               strbuf_addstr(sb, e->value);
-                       return len;
-               }
-       }
-       return 0;
-}
-
-size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
-{
-       size_t res;
-       size_t oldalloc = sb->alloc;
-
-       strbuf_grow(sb, size);
-       res = fread(sb->buf + sb->len, 1, size, f);
-       if (res > 0)
-               strbuf_setlen(sb, sb->len + res);
-       else if (oldalloc == 0)
-               strbuf_release(sb);
-       return res;
-}
-
 ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint)
 {
        size_t oldlen = sb->len;
@@ -291,70 +131,3 @@ ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint)
        sb->buf[sb->len] = '\0';
        return sb->len - oldlen;
 }
-
-#define STRBUF_MAXLINK (2*PATH_MAX)
-
-int strbuf_readlink(struct strbuf *sb, const char *path, ssize_t hint)
-{
-       size_t oldalloc = sb->alloc;
-
-       if (hint < 32)
-               hint = 32;
-
-       while (hint < STRBUF_MAXLINK) {
-               ssize_t len;
-
-               strbuf_grow(sb, hint);
-               len = readlink(path, sb->buf, hint);
-               if (len < 0) {
-                       if (errno != ERANGE)
-                               break;
-               } else if (len < hint) {
-                       strbuf_setlen(sb, len);
-                       return 0;
-               }
-
-               /* .. the buffer was too small - try again */
-               hint *= 2;
-       }
-       if (oldalloc == 0)
-               strbuf_release(sb);
-       return -1;
-}
-
-int strbuf_getline(struct strbuf *sb, FILE *fp, int term)
-{
-       int ch;
-
-       strbuf_grow(sb, 0);
-       if (feof(fp))
-               return EOF;
-
-       strbuf_reset(sb);
-       while ((ch = fgetc(fp)) != EOF) {
-               if (ch == term)
-                       break;
-               strbuf_grow(sb, 1);
-               sb->buf[sb->len++] = ch;
-       }
-       if (ch == EOF && sb->len == 0)
-               return EOF;
-
-       sb->buf[sb->len] = '\0';
-       return 0;
-}
-
-int strbuf_read_file(struct strbuf *sb, const char *path, ssize_t hint)
-{
-       int fd, len;
-
-       fd = open(path, O_RDONLY);
-       if (fd < 0)
-               return -1;
-       len = strbuf_read(sb, fd, hint);
-       close(fd);
-       if (len < 0)
-               return -1;
-
-       return len;
-}
index a3d121d6c83e1d64355ef0cc6bc4c8595110a9fd..436ac319f6c76bdf2a2be4b19e60e06dc481f245 100644 (file)
@@ -53,12 +53,6 @@ struct strbuf {
 extern void strbuf_init(struct strbuf *buf, ssize_t hint);
 extern void strbuf_release(struct strbuf *);
 extern char *strbuf_detach(struct strbuf *, size_t *);
-extern void strbuf_attach(struct strbuf *, void *, size_t, size_t);
-static inline void strbuf_swap(struct strbuf *a, struct strbuf *b) {
-       struct strbuf tmp = *a;
-       *a = *b;
-       *b = tmp;
-}
 
 /*----- strbuf size related -----*/
 static inline ssize_t strbuf_avail(const struct strbuf *sb) {
@@ -74,17 +68,6 @@ static inline void strbuf_setlen(struct strbuf *sb, size_t len) {
        sb->len = len;
        sb->buf[len] = '\0';
 }
-#define strbuf_reset(sb)  strbuf_setlen(sb, 0)
-
-/*----- content related -----*/
-extern void strbuf_trim(struct strbuf *);
-extern void strbuf_rtrim(struct strbuf *);
-extern void strbuf_ltrim(struct strbuf *);
-extern int strbuf_cmp(const struct strbuf *, const struct strbuf *);
-extern void strbuf_tolower(struct strbuf *);
-
-extern struct strbuf **strbuf_split(const struct strbuf *, int delim);
-extern void strbuf_list_free(struct strbuf **);
 
 /*----- add data in your buffer -----*/
 static inline void strbuf_addch(struct strbuf *sb, int c) {
@@ -93,45 +76,17 @@ static inline void strbuf_addch(struct strbuf *sb, int c) {
        sb->buf[sb->len] = '\0';
 }
 
-extern void strbuf_insert(struct strbuf *, size_t pos, const void *, size_t);
 extern void strbuf_remove(struct strbuf *, size_t pos, size_t len);
 
-/* splice pos..pos+len with given data */
-extern void strbuf_splice(struct strbuf *, size_t pos, size_t len,
-                          const void *, size_t);
-
 extern void strbuf_add(struct strbuf *, const void *, size_t);
 static inline void strbuf_addstr(struct strbuf *sb, const char *s) {
        strbuf_add(sb, s, strlen(s));
 }
-static inline void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2) {
-       strbuf_add(sb, sb2->buf, sb2->len);
-}
-extern void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len);
-
-typedef size_t (*expand_fn_t) (struct strbuf *sb, const char *placeholder, void *context);
-extern void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn, void *context);
-struct strbuf_expand_dict_entry {
-       const char *placeholder;
-       const char *value;
-};
-extern size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder, void *context);
 
 __attribute__((format(printf,2,3)))
 extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...);
 
-extern size_t strbuf_fread(struct strbuf *, size_t, FILE *);
 /* XXX: if read fails, any partial read is undone */
 extern ssize_t strbuf_read(struct strbuf *, int fd, ssize_t hint);
-extern int strbuf_read_file(struct strbuf *sb, const char *path, ssize_t hint);
-extern int strbuf_readlink(struct strbuf *sb, const char *path, ssize_t hint);
-
-extern int strbuf_getline(struct strbuf *, FILE *, int);
-
-extern void stripspace(struct strbuf *buf, int skip_comments);
-extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env);
-
-extern int strbuf_branchname(struct strbuf *sb, const char *name);
-extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name);
 
 #endif /* __PERF_STRBUF_H */
index a06131f6259a1dd5b65fee74d73a0de33eaa0d03..aaa51ba147dfa7dee9d18ff89cb7ae3e017b5d33 100644 (file)
@@ -11,6 +11,7 @@
 #include <sys/param.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include "build-id.h"
 #include "symbol.h"
 #include "strlist.h"
 
@@ -1131,6 +1132,10 @@ bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
        list_for_each_entry(pos, head, node) {
                if (with_hits && !pos->hit)
                        continue;
+               if (pos->has_build_id) {
+                       have_build_id = true;
+                       continue;
+               }
                if (filename__read_build_id(pos->long_name, pos->build_id,
                                            sizeof(pos->build_id)) > 0) {
                        have_build_id     = true;
@@ -1289,7 +1294,6 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
        int size = PATH_MAX;
        char *name;
        u8 build_id[BUILD_ID_SIZE];
-       char build_id_hex[BUILD_ID_SIZE * 2 + 1];
        int ret = -1;
        int fd;
        struct machine *machine;
@@ -1321,15 +1325,8 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
        }
 
        self->origin = DSO__ORIG_BUILD_ID_CACHE;
-
-       if (self->has_build_id) {
-               build_id__sprintf(self->build_id, sizeof(self->build_id),
-                                 build_id_hex);
-               snprintf(name, size, "%s/%s/.build-id/%.2s/%s",
-                        getenv("HOME"), DEBUG_CACHE_DIR,
-                        build_id_hex, build_id_hex + 2);
+       if (dso__build_id_filename(self, name, size) != NULL)
                goto open_file;
-       }
 more:
        do {
                self->origin++;
@@ -1345,6 +1342,7 @@ more:
                case DSO__ORIG_BUILDID:
                        if (filename__read_build_id(self->long_name, build_id,
                                                    sizeof(build_id))) {
+                               char build_id_hex[BUILD_ID_SIZE * 2 + 1];
                                build_id__sprintf(build_id, sizeof(build_id),
                                                  build_id_hex);
                                snprintf(name, size,
@@ -1933,6 +1931,12 @@ static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
        return ret;
 }
 
+size_t machine__fprintf_dsos_buildid(struct machine *self, FILE *fp, bool with_hits)
+{
+       return __dsos__fprintf_buildid(&self->kernel_dsos, fp, with_hits) +
+              __dsos__fprintf_buildid(&self->user_dsos, fp, with_hits);
+}
+
 size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_hits)
 {
        struct rb_node *nd;
@@ -1940,8 +1944,7 @@ size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_
 
        for (nd = rb_first(self); nd; nd = rb_next(nd)) {
                struct machine *pos = rb_entry(nd, struct machine, rb_node);
-               ret += __dsos__fprintf_buildid(&pos->kernel_dsos, fp, with_hits);
-               ret += __dsos__fprintf_buildid(&pos->user_dsos, fp, with_hits);
+               ret += machine__fprintf_dsos_buildid(pos, fp, with_hits);
        }
        return ret;
 }
index 032469e4187615fb25357fefa047854640a0e88a..5d25b5eb1456123e9f2b53632613c9b8c9a6f255 100644 (file)
@@ -170,6 +170,7 @@ int machine__load_vmlinux_path(struct machine *self, enum map_type type,
 
 size_t __dsos__fprintf(struct list_head *head, FILE *fp);
 
+size_t machine__fprintf_dsos_buildid(struct machine *self, FILE *fp, bool with_hits);
 size_t machines__fprintf_dsos(struct rb_root *self, FILE *fp);
 size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_hits);
 
index cb54cd002f49b3e8abb45e55b8906af3bb66467c..f55cc3a765a12ab55dba204e11e7edb26bcfd0b6 100644 (file)
@@ -53,12 +53,6 @@ static unsigned long page_size;
 static ssize_t calc_data_size;
 static bool repipe;
 
-/* If it fails, the next read will report it */
-static void skip(int size)
-{
-       lseek(input_fd, size, SEEK_CUR);
-}
-
 static int do_read(int fd, void *buf, int size)
 {
        int rsize = size;
@@ -98,6 +92,19 @@ static int read_or_die(void *data, int size)
        return r;
 }
 
+/* If it fails, the next read will report it */
+static void skip(int size)
+{
+       char buf[BUFSIZ];
+       int r;
+
+       while (size) {
+               r = size > BUFSIZ ? BUFSIZ : size;
+               read_or_die(buf, r);
+               size -= r;
+       };
+}
+
 static unsigned int read4(void)
 {
        unsigned int data;
index 406d452956db1f15e1026d97b56a7991e6b4f8c3..b3e86b1e44443909e518573ab0a1d49f8167f151 100644 (file)
@@ -233,7 +233,12 @@ static inline unsigned long long __data2host8(unsigned long long data)
 
 #define data2host2(ptr)                __data2host2(*(unsigned short *)ptr)
 #define data2host4(ptr)                __data2host4(*(unsigned int *)ptr)
-#define data2host8(ptr)                __data2host8(*(unsigned long long *)ptr)
+#define data2host8(ptr)                ({                              \
+       unsigned long long __val;                               \
+                                                               \
+       memcpy(&__val, (ptr), sizeof(unsigned long long));      \
+       __data2host8(__val);                                    \
+})
 
 extern int header_page_ts_offset;
 extern int header_page_ts_size;
index 0795bf304b19495b0b7f88ca366fcace7302f1fa..4e8b6b0c551c87cd98f78857e4205ff3f5cd79d5 100644 (file)
@@ -81,7 +81,7 @@
 #include <inttypes.h>
 #include "../../../include/linux/magic.h"
 #include "types.h"
-
+#include <sys/ttydefaults.h>
 
 #ifndef NO_ICONV
 #include <iconv.h>
@@ -152,7 +152,6 @@ extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2)))
 extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN);
 
 extern int prefixcmp(const char *str, const char *prefix);
-extern time_t tm_to_time_t(const struct tm *tm);
 
 static inline const char *skip_prefix(const char *str, const char *prefix)
 {
@@ -160,119 +159,6 @@ static inline const char *skip_prefix(const char *str, const char *prefix)
        return strncmp(str, prefix, len) ? NULL : str + len;
 }
 
-#if defined(NO_MMAP) || defined(USE_WIN32_MMAP)
-
-#ifndef PROT_READ
-#define PROT_READ 1
-#define PROT_WRITE 2
-#define MAP_PRIVATE 1
-#define MAP_FAILED ((void*)-1)
-#endif
-
-#define mmap git_mmap
-#define munmap git_munmap
-extern void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
-extern int git_munmap(void *start, size_t length);
-
-#else /* NO_MMAP || USE_WIN32_MMAP */
-
-#include <sys/mman.h>
-
-#endif /* NO_MMAP || USE_WIN32_MMAP */
-
-#ifdef NO_MMAP
-
-/* This value must be multiple of (pagesize * 2) */
-#define DEFAULT_PACKED_GIT_WINDOW_SIZE (1 * 1024 * 1024)
-
-#else /* NO_MMAP */
-
-/* This value must be multiple of (pagesize * 2) */
-#define DEFAULT_PACKED_GIT_WINDOW_SIZE \
-       (sizeof(void*) >= 8 \
-               ?  1 * 1024 * 1024 * 1024 \
-               : 32 * 1024 * 1024)
-
-#endif /* NO_MMAP */
-
-#ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
-#define on_disk_bytes(st) ((st).st_size)
-#else
-#define on_disk_bytes(st) ((st).st_blocks * 512)
-#endif
-
-#define DEFAULT_PACKED_GIT_LIMIT \
-       ((1024L * 1024L) * (sizeof(void*) >= 8 ? 8192 : 256))
-
-#ifdef NO_PREAD
-#define pread git_pread
-extern ssize_t git_pread(int fd, void *buf, size_t count, off_t offset);
-#endif
-/*
- * Forward decl that will remind us if its twin in cache.h changes.
- * This function is used in compat/pread.c.  But we can't include
- * cache.h there.
- */
-extern ssize_t read_in_full(int fd, void *buf, size_t count);
-
-#ifdef NO_SETENV
-#define setenv gitsetenv
-extern int gitsetenv(const char *, const char *, int);
-#endif
-
-#ifdef NO_MKDTEMP
-#define mkdtemp gitmkdtemp
-extern char *gitmkdtemp(char *);
-#endif
-
-#ifdef NO_UNSETENV
-#define unsetenv gitunsetenv
-extern void gitunsetenv(const char *);
-#endif
-
-#ifdef NO_STRCASESTR
-#define strcasestr gitstrcasestr
-extern char *gitstrcasestr(const char *haystack, const char *needle);
-#endif
-
-#ifdef NO_STRLCPY
-#define strlcpy gitstrlcpy
-extern size_t gitstrlcpy(char *, const char *, size_t);
-#endif
-
-#ifdef NO_STRTOUMAX
-#define strtoumax gitstrtoumax
-extern uintmax_t gitstrtoumax(const char *, char **, int);
-#endif
-
-#ifdef NO_HSTRERROR
-#define hstrerror githstrerror
-extern const char *githstrerror(int herror);
-#endif
-
-#ifdef NO_MEMMEM
-#define memmem gitmemmem
-void *gitmemmem(const void *haystack, size_t haystacklen,
-                const void *needle, size_t needlelen);
-#endif
-
-#ifdef FREAD_READS_DIRECTORIES
-#ifdef fopen
-#undef fopen
-#endif
-#define fopen(a,b) git_fopen(a,b)
-extern FILE *git_fopen(const char*, const char*);
-#endif
-
-#ifdef SNPRINTF_RETURNS_BOGUS
-#define snprintf git_snprintf
-extern int git_snprintf(char *str, size_t maxsize,
-                       const char *format, ...);
-#define vsnprintf git_vsnprintf
-extern int git_vsnprintf(char *str, size_t maxsize,
-                        const char *format, va_list ap);
-#endif
-
 #ifdef __GLIBC_PREREQ
 #if __GLIBC_PREREQ(2, 1)
 #define HAVE_STRCHRNUL
@@ -293,28 +179,14 @@ static inline char *gitstrchrnul(const char *s, int c)
  * Wrappers:
  */
 extern char *xstrdup(const char *str);
-extern void *xmalloc(size_t size) __attribute__((weak));
-extern void *xmemdupz(const void *data, size_t len);
-extern char *xstrndup(const char *str, size_t len);
 extern void *xrealloc(void *ptr, size_t size) __attribute__((weak));
 
-static inline void *xzalloc(size_t size)
-{
-       void *buf = xmalloc(size);
-
-       return memset(buf, 0, size);
-}
 
 static inline void *zalloc(size_t size)
 {
        return calloc(1, size);
 }
 
-static inline size_t xsize_t(off_t len)
-{
-       return (size_t)len;
-}
-
 static inline int has_extension(const char *filename, const char *ext)
 {
        size_t len = strlen(filename);
@@ -351,8 +223,6 @@ extern unsigned char sane_ctype[256];
 #define isalpha(x) sane_istest(x,GIT_ALPHA)
 #define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
 #define isprint(x) sane_istest(x,GIT_PRINT)
-#define is_glob_special(x) sane_istest(x,GIT_GLOB_SPECIAL)
-#define is_regex_special(x) sane_istest(x,GIT_GLOB_SPECIAL | GIT_REGEX_SPECIAL)
 #define tolower(x) sane_case((unsigned char)(x), 0x20)
 #define toupper(x) sane_case((unsigned char)(x), 0)
 
@@ -363,38 +233,6 @@ static inline int sane_case(int x, int high)
        return x;
 }
 
-static inline int strtoul_ui(char const *s, int base, unsigned int *result)
-{
-       unsigned long ul;
-       char *p;
-
-       errno = 0;
-       ul = strtoul(s, &p, base);
-       if (errno || *p || p == s || (unsigned int) ul != ul)
-               return -1;
-       *result = ul;
-       return 0;
-}
-
-static inline int strtol_i(char const *s, int base, int *result)
-{
-       long ul;
-       char *p;
-
-       errno = 0;
-       ul = strtol(s, &p, base);
-       if (errno || *p || p == s || (int) ul != ul)
-               return -1;
-       *result = ul;
-       return 0;
-}
-
-#ifdef INTERNAL_QSORT
-void git_qsort(void *base, size_t nmemb, size_t size,
-              int(*compar)(const void *, const void *));
-#define qsort git_qsort
-#endif
-
 #ifndef DIR_HAS_BSD_GROUP_SEMANTICS
 # define FORCE_DIR_SET_GID S_ISGID
 #else
@@ -425,6 +263,19 @@ bool strglobmatch(const char *str, const char *pat);
 bool strlazymatch(const char *str, const char *pat);
 unsigned long convert_unit(unsigned long value, char *unit);
 
+#ifndef ESC
+#define ESC 27
+#endif
+
+static inline bool is_exit_key(int key)
+{
+       char up;
+       if (key == CTRL('c') || key == ESC)
+               return true;
+       up = toupper(key);
+       return up == 'Q';
+}
+
 #define _STR(x) #x
 #define STR(x) _STR(x)
 
index bf44ca85d23be29334d69ef6718d9b613f06a9bb..73e900edb5a26ec9429de4946fa1fc2a4edbf11b 100644 (file)
@@ -23,46 +23,6 @@ char *xstrdup(const char *str)
        return ret;
 }
 
-void *xmalloc(size_t size)
-{
-       void *ret = malloc(size);
-       if (!ret && !size)
-               ret = malloc(1);
-       if (!ret) {
-               release_pack_memory(size, -1);
-               ret = malloc(size);
-               if (!ret && !size)
-                       ret = malloc(1);
-               if (!ret)
-                       die("Out of memory, malloc failed");
-       }
-#ifdef XMALLOC_POISON
-       memset(ret, 0xA5, size);
-#endif
-       return ret;
-}
-
-/*
- * xmemdupz() allocates (len + 1) bytes of memory, duplicates "len" bytes of
- * "data" to the allocated memory, zero terminates the allocated memory,
- * and returns a pointer to the allocated memory. If the allocation fails,
- * the program dies.
- */
-void *xmemdupz(const void *data, size_t len)
-{
-       char *p = xmalloc(len + 1);
-       memcpy(p, data, len);
-       p[len] = '\0';
-       return p;
-}
-
-char *xstrndup(const char *str, size_t len)
-{
-       char *p = memchr(str, '\0', len);
-
-       return xmemdupz(str, p ? (size_t)(p - str) : len);
-}
-
 void *xrealloc(void *ptr, size_t size)
 {
        void *ret = realloc(ptr, size);
@@ -78,73 +38,3 @@ void *xrealloc(void *ptr, size_t size)
        }
        return ret;
 }
-
-/*
- * xread() is the same a read(), but it automatically restarts read()
- * operations with a recoverable error (EAGAIN and EINTR). xread()
- * DOES NOT GUARANTEE that "len" bytes is read even if the data is available.
- */
-static ssize_t xread(int fd, void *buf, size_t len)
-{
-       ssize_t nr;
-       while (1) {
-               nr = read(fd, buf, len);
-               if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
-                       continue;
-               return nr;
-       }
-}
-
-/*
- * xwrite() is the same a write(), but it automatically restarts write()
- * operations with a recoverable error (EAGAIN and EINTR). xwrite() DOES NOT
- * GUARANTEE that "len" bytes is written even if the operation is successful.
- */
-static ssize_t xwrite(int fd, const void *buf, size_t len)
-{
-       ssize_t nr;
-       while (1) {
-               nr = write(fd, buf, len);
-               if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
-                       continue;
-               return nr;
-       }
-}
-
-ssize_t read_in_full(int fd, void *buf, size_t count)
-{
-       char *p = buf;
-       ssize_t total = 0;
-
-       while (count > 0) {
-               ssize_t loaded = xread(fd, p, count);
-               if (loaded <= 0)
-                       return total ? total : loaded;
-               count -= loaded;
-               p += loaded;
-               total += loaded;
-       }
-
-       return total;
-}
-
-ssize_t write_in_full(int fd, const void *buf, size_t count)
-{
-       const char *p = buf;
-       ssize_t total = 0;
-
-       while (count > 0) {
-               ssize_t written = xwrite(fd, p, count);
-               if (written < 0)
-                       return -1;
-               if (!written) {
-                       errno = ENOSPC;
-                       return -1;
-               }
-               count -= written;
-               p += written;
-               total += written;
-       }
-
-       return total;
-}
index 1e6a9e4a72cc627fb4d0e4863dabdbc15f709274..6b4b6da0b67d948d8b027622a486a3e1d8b49bc1 100644 (file)
@@ -15,6 +15,9 @@ suffix_$(CONFIG_INITRAMFS_COMPRESSION_BZIP2)  = .bz2
 # Lzma
 suffix_$(CONFIG_INITRAMFS_COMPRESSION_LZMA)   = .lzma
 
+# Lzo
+suffix_$(CONFIG_INITRAMFS_COMPRESSION_LZO)   = .lzo
+
 # Generate builtin.o based on initramfs_data.o
 obj-$(CONFIG_BLK_DEV_INITRD) := initramfs_data$(suffix_y).o
 
@@ -45,7 +48,7 @@ endif
 quiet_cmd_initfs = GEN     $@
       cmd_initfs = $(initramfs) -o $@ $(ramfs-args) $(ramfs-input)
 
-targets := initramfs_data.cpio.gz initramfs_data.cpio.bz2 initramfs_data.cpio.lzma initramfs_data.cpio
+targets := initramfs_data.cpio.gz initramfs_data.cpio.bz2 initramfs_data.cpio.lzma initramfs_data.cpio.lzo initramfs_data.cpio
 # do not try to update files included in initramfs
 $(deps_initramfs): ;
 
diff --git a/usr/initramfs_data.lzo.S b/usr/initramfs_data.lzo.S
new file mode 100644 (file)
index 0000000..5921190
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+  initramfs_data includes the compressed binary that is the
+  filesystem used for early user space.
+  Note: Older versions of "as" (prior to binutils 2.11.90.0.23
+  released on 2001-07-14) dit not support .incbin.
+  If you are forced to use older binutils than that then the
+  following trick can be applied to create the resulting binary:
+
+
+  ld -m elf_i386  --format binary --oformat elf32-i386 -r \
+  -T initramfs_data.scr initramfs_data.cpio.gz -o initramfs_data.o
+   ld -m elf_i386  -r -o built-in.o initramfs_data.o
+
+  initramfs_data.scr looks like this:
+SECTIONS
+{
+       .init.ramfs : { *(.data) }
+}
+
+  The above example is for i386 - the parameters vary from architectures.
+  Eventually look up LDFLAGS_BLOB in an older version of the
+  arch/$(ARCH)/Makefile to see the flags used before .incbin was introduced.
+
+  Using .incbin has the advantage over ld that the correct flags are set
+  in the ELF header, as required by certain architectures.
+*/
+
+.section .init.ramfs,"a"
+.incbin "usr/initramfs_data.cpio.lzo"
index 02ff2b19dbe242a5033da435998a19f1fc4e52ed..4d10b1e047f4e9b3c3c22df98b25be6d23247e12 100644 (file)
@@ -316,12 +316,16 @@ static int assigned_device_enable_host_msix(struct kvm *kvm,
                                kvm_assigned_dev_intr, 0,
                                "kvm_assigned_msix_device",
                                (void *)dev);
-               /* FIXME: free requested_irq's on failure */
                if (r)
-                       return r;
+                       goto err;
        }
 
        return 0;
+err:
+       for (i -= 1; i >= 0; i--)
+               free_irq(dev->host_msix_entries[i].vector, (void *)dev);
+       pci_disable_msix(dev->dev);
+       return r;
 }
 
 #endif
index 36e258029649c719fec91a1feb7306604ae90ab9..53850177163fbda3a9fef4bda83aef31607ca4f4 100644 (file)
@@ -120,8 +120,10 @@ int kvm_coalesced_mmio_init(struct kvm *kvm)
        return ret;
 
 out_free_dev:
+       kvm->coalesced_mmio_dev = NULL;
        kfree(dev);
 out_free_page:
+       kvm->coalesced_mmio_ring = NULL;
        __free_page(page);
 out_err:
        return ret;
@@ -139,7 +141,7 @@ int kvm_vm_ioctl_register_coalesced_mmio(struct kvm *kvm,
        struct kvm_coalesced_mmio_dev *dev = kvm->coalesced_mmio_dev;
 
        if (dev == NULL)
-               return -EINVAL;
+               return -ENXIO;
 
        mutex_lock(&kvm->slots_lock);
        if (dev->nb_zones >= KVM_COALESCED_MMIO_ZONE_MAX) {
@@ -162,7 +164,7 @@ int kvm_vm_ioctl_unregister_coalesced_mmio(struct kvm *kvm,
        struct kvm_coalesced_mmio_zone *z;
 
        if (dev == NULL)
-               return -EINVAL;
+               return -ENXIO;
 
        mutex_lock(&kvm->slots_lock);
 
index 11692b9e8830a6e99538556bfeee2ea9d7d74817..d2f06be63354b1b43555f3e491bf61ce6cac8c6c 100644 (file)
@@ -127,7 +127,7 @@ static int kvm_iommu_map_memslots(struct kvm *kvm)
        int i, r = 0;
        struct kvm_memslots *slots;
 
-       slots = rcu_dereference(kvm->memslots);
+       slots = kvm_memslots(kvm);
 
        for (i = 0; i < slots->nmemslots; i++) {
                r = kvm_iommu_map_pages(kvm, &slots->memslots[i]);
@@ -286,7 +286,7 @@ static int kvm_iommu_unmap_memslots(struct kvm *kvm)
        int i;
        struct kvm_memslots *slots;
 
-       slots = rcu_dereference(kvm->memslots);
+       slots = kvm_memslots(kvm);
 
        for (i = 0; i < slots->nmemslots; i++) {
                kvm_iommu_put_pages(kvm, slots->memslots[i].base_gfn,
index c82ae24926340cfa40ad8c3bbc9f65dd79c32fff..f032806a212f9d8e02faa7823f65262813d82015 100644 (file)
@@ -422,9 +422,6 @@ static struct kvm *kvm_create_vm(void)
        spin_lock(&kvm_lock);
        list_add(&kvm->vm_list, &vm_list);
        spin_unlock(&kvm_lock);
-#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
-       kvm_coalesced_mmio_init(kvm);
-#endif
 out:
        return kvm;
 
@@ -560,6 +557,10 @@ int __kvm_set_memory_region(struct kvm *kvm,
        base_gfn = mem->guest_phys_addr >> PAGE_SHIFT;
        npages = mem->memory_size >> PAGE_SHIFT;
 
+       r = -EINVAL;
+       if (npages > KVM_MEM_MAX_NR_PAGES)
+               goto out;
+
        if (!npages)
                mem->flags &= ~KVM_MEM_LOG_DIRTY_PAGES;
 
@@ -833,7 +834,7 @@ EXPORT_SYMBOL_GPL(kvm_is_error_hva);
 struct kvm_memory_slot *gfn_to_memslot_unaliased(struct kvm *kvm, gfn_t gfn)
 {
        int i;
-       struct kvm_memslots *slots = rcu_dereference(kvm->memslots);
+       struct kvm_memslots *slots = kvm_memslots(kvm);
 
        for (i = 0; i < slots->nmemslots; ++i) {
                struct kvm_memory_slot *memslot = &slots->memslots[i];
@@ -855,7 +856,7 @@ struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn)
 int kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn)
 {
        int i;
-       struct kvm_memslots *slots = rcu_dereference(kvm->memslots);
+       struct kvm_memslots *slots = kvm_memslots(kvm);
 
        gfn = unalias_gfn_instantiation(kvm, gfn);
        for (i = 0; i < KVM_MEMORY_SLOTS; ++i) {
@@ -899,7 +900,7 @@ out:
 int memslot_id(struct kvm *kvm, gfn_t gfn)
 {
        int i;
-       struct kvm_memslots *slots = rcu_dereference(kvm->memslots);
+       struct kvm_memslots *slots = kvm_memslots(kvm);
        struct kvm_memory_slot *memslot = NULL;
 
        gfn = unalias_gfn(kvm, gfn);
@@ -914,6 +915,11 @@ int memslot_id(struct kvm *kvm, gfn_t gfn)
        return memslot - slots->memslots;
 }
 
+static unsigned long gfn_to_hva_memslot(struct kvm_memory_slot *slot, gfn_t gfn)
+{
+       return slot->userspace_addr + (gfn - slot->base_gfn) * PAGE_SIZE;
+}
+
 unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn)
 {
        struct kvm_memory_slot *slot;
@@ -922,7 +928,7 @@ unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn)
        slot = gfn_to_memslot_unaliased(kvm, gfn);
        if (!slot || slot->flags & KVM_MEMSLOT_INVALID)
                return bad_hva();
-       return (slot->userspace_addr + (gfn - slot->base_gfn) * PAGE_SIZE);
+       return gfn_to_hva_memslot(slot, gfn);
 }
 EXPORT_SYMBOL_GPL(gfn_to_hva);
 
@@ -972,11 +978,6 @@ pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn)
 }
 EXPORT_SYMBOL_GPL(gfn_to_pfn);
 
-static unsigned long gfn_to_hva_memslot(struct kvm_memory_slot *slot, gfn_t gfn)
-{
-       return (slot->userspace_addr + (gfn - slot->base_gfn) * PAGE_SIZE);
-}
-
 pfn_t gfn_to_pfn_memslot(struct kvm *kvm,
                         struct kvm_memory_slot *slot, gfn_t gfn)
 {
@@ -1190,13 +1191,8 @@ void mark_page_dirty(struct kvm *kvm, gfn_t gfn)
        memslot = gfn_to_memslot_unaliased(kvm, gfn);
        if (memslot && memslot->dirty_bitmap) {
                unsigned long rel_gfn = gfn - memslot->base_gfn;
-               unsigned long *p = memslot->dirty_bitmap +
-                                       rel_gfn / BITS_PER_LONG;
-               int offset = rel_gfn % BITS_PER_LONG;
 
-               /* avoid RMW */
-               if (!generic_test_le_bit(offset, p))
-                       generic___set_le_bit(offset, p);
+               generic___set_le_bit(rel_gfn, memslot->dirty_bitmap);
        }
 }
 
@@ -1609,7 +1605,6 @@ static long kvm_vm_ioctl(struct file *filp,
                r = -EFAULT;
                if (copy_from_user(&zone, argp, sizeof zone))
                        goto out;
-               r = -ENXIO;
                r = kvm_vm_ioctl_register_coalesced_mmio(kvm, &zone);
                if (r)
                        goto out;
@@ -1621,7 +1616,6 @@ static long kvm_vm_ioctl(struct file *filp,
                r = -EFAULT;
                if (copy_from_user(&zone, argp, sizeof zone))
                        goto out;
-               r = -ENXIO;
                r = kvm_vm_ioctl_unregister_coalesced_mmio(kvm, &zone);
                if (r)
                        goto out;
@@ -1755,12 +1749,19 @@ static struct file_operations kvm_vm_fops = {
 
 static int kvm_dev_ioctl_create_vm(void)
 {
-       int fd;
+       int fd, r;
        struct kvm *kvm;
 
        kvm = kvm_create_vm();
        if (IS_ERR(kvm))
                return PTR_ERR(kvm);
+#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
+       r = kvm_coalesced_mmio_init(kvm);
+       if (r < 0) {
+               kvm_put_kvm(kvm);
+               return r;
+       }
+#endif
        fd = anon_inode_getfd("kvm-vm", &kvm_vm_fops, kvm, O_RDWR);
        if (fd < 0)
                kvm_put_kvm(kvm);
@@ -1928,11 +1929,6 @@ static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
                       cpu);
                hardware_disable(NULL);
                break;
-       case CPU_UP_CANCELED:
-               printk(KERN_INFO "kvm: disabling virtualization on CPU%d\n",
-                      cpu);
-               smp_call_function_single(cpu, hardware_disable, NULL, 1);
-               break;
        case CPU_ONLINE:
                printk(KERN_INFO "kvm: enabling virtualization on CPU%d\n",
                       cpu);
@@ -1991,7 +1987,9 @@ int kvm_io_bus_write(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
                     int len, const void *val)
 {
        int i;
-       struct kvm_io_bus *bus = rcu_dereference(kvm->buses[bus_idx]);
+       struct kvm_io_bus *bus;
+
+       bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu);
        for (i = 0; i < bus->dev_count; i++)
                if (!kvm_iodevice_write(bus->devs[i], addr, len, val))
                        return 0;
@@ -2003,8 +2001,9 @@ int kvm_io_bus_read(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
                    int len, void *val)
 {
        int i;
-       struct kvm_io_bus *bus = rcu_dereference(kvm->buses[bus_idx]);
+       struct kvm_io_bus *bus;
 
+       bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu);
        for (i = 0; i < bus->dev_count; i++)
                if (!kvm_iodevice_read(bus->devs[i], addr, len, val))
                        return 0;
@@ -2179,7 +2178,7 @@ static void kvm_sched_out(struct preempt_notifier *pn,
        kvm_arch_vcpu_put(vcpu);
 }
 
-int kvm_init(void *opaque, unsigned int vcpu_size,
+int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align,
                  struct module *module)
 {
        int r;
@@ -2229,8 +2228,9 @@ int kvm_init(void *opaque, unsigned int vcpu_size,
                goto out_free_4;
 
        /* A kmem cache lets us meet the alignment requirements of fx_save. */
-       kvm_vcpu_cache = kmem_cache_create("kvm_vcpu", vcpu_size,
-                                          __alignof__(struct kvm_vcpu),
+       if (!vcpu_align)
+               vcpu_align = __alignof__(struct kvm_vcpu);
+       kvm_vcpu_cache = kmem_cache_create("kvm_vcpu", vcpu_size, vcpu_align,
                                           0, NULL);
        if (!kvm_vcpu_cache) {
                r = -ENOMEM;
@@ -2279,7 +2279,6 @@ EXPORT_SYMBOL_GPL(kvm_init);
 
 void kvm_exit(void)
 {
-       tracepoint_synchronize_unregister();
        kvm_exit_debug();
        misc_deregister(&kvm_dev);
        kmem_cache_destroy(kvm_vcpu_cache);